Block expressions

This commit is contained in:
Robert Bendun 2022-05-10 16:49:36 +02:00
parent c5260df41c
commit 5bfec0e77a
3 changed files with 106 additions and 3 deletions

View File

@ -29,8 +29,9 @@ void usage()
static Result<void> run(std::string_view source, std::string_view filename) static Result<void> run(std::string_view source, std::string_view filename)
{ {
Try(Parser::parse(source, filename)); auto ast = Try(Parser::parse(source, filename));
std::cout << "successfully parsed: " << source << " \n"; std::cout << "successfully parsed: " << source << " \n";
dump(ast);
return {}; return {};
} }

View File

@ -291,6 +291,7 @@ struct Ast
static Ast binary(Token, Ast lhs, Ast rhs); static Ast binary(Token, Ast lhs, Ast rhs);
static Ast call(std::vector<Ast> call); static Ast call(std::vector<Ast> call);
static Ast sequence(std::vector<Ast> call); static Ast sequence(std::vector<Ast> call);
static Ast block(Ast seq, std::vector<Ast> parameters = {});
enum class Type enum class Type
{ {
@ -298,15 +299,19 @@ struct Ast
Binary, // Binary operator application like `1` + `2` Binary, // Binary operator application like `1` + `2`
Call, // Function call application like `print 42` Call, // Function call application like `print 42`
Sequence, // Several expressions sequences like `42`, `42; 32` Sequence, // Several expressions sequences like `42`, `42; 32`
Block, // Block expressions like `[42; hello]`
}; };
Type type; Type type;
Token token; Token token;
std::vector<Ast> arguments; std::vector<Ast> arguments{};
std::vector<Ast> parameters{};
}; };
bool operator==(Ast const& lhs, Ast const& rhs); bool operator==(Ast const& lhs, Ast const& rhs);
std::ostream& operator<<(std::ostream& os, Ast::Type type);
std::ostream& operator<<(std::ostream& os, Ast const& tree); std::ostream& operator<<(std::ostream& os, Ast const& tree);
void dump(Ast const& ast, unsigned indent = 0);
struct Parser struct Parser
{ {
@ -321,6 +326,7 @@ struct Parser
Result<Ast> parse_expression(); Result<Ast> parse_expression();
Result<Ast> parse_infix_expression(); Result<Ast> parse_infix_expression();
Result<Ast> parse_atomic_expression(); Result<Ast> parse_atomic_expression();
Result<Ast> parse_identifier();
Result<Token> peek() const; Result<Token> peek() const;
Result<Token::Type> peek_type() const; Result<Token::Type> peek_type() const;

View File

@ -60,6 +60,26 @@ Result<Ast> Parser::parse_atomic_expression()
case Token::Type::Numeric: case Token::Type::Numeric:
return Ast::literal(consume()); return Ast::literal(consume());
case Token::Type::Open_Block:
{
consume();
auto start = token_id;
std::vector<Ast> parameters;
if (auto p = parse_one_or_more(*this, &Parser::parse_identifier); p && expect(Token::Type::Variable_Separator)) {
consume();
parameters = std::move(p).value();
} else {
token_id = start;
}
return parse_sequence().and_then([&](Ast ast) -> tl::expected<Ast, Error> {
Try(ensure(Token::Type::Close_Block));
consume();
return Ast::block(ast, std::move(parameters));
});
}
case Token::Type::Open_Paren: case Token::Type::Open_Paren:
consume(); consume();
return parse_expression().and_then([&](Ast ast) -> tl::expected<Ast, Error> { return parse_expression().and_then([&](Ast ast) -> tl::expected<Ast, Error> {
@ -75,6 +95,12 @@ Result<Ast> Parser::parse_atomic_expression()
} }
} }
Result<Ast> Parser::parse_identifier()
{
Try(ensure(Token::Type::Symbol));
return Ast::literal(consume());
}
Result<std::vector<Ast>> parse_one_or_more(Parser &p, Result<Ast> (Parser::*parser)(), std::optional<Token::Type> separator) Result<std::vector<Ast>> parse_one_or_more(Parser &p, Result<Ast> (Parser::*parser)(), std::optional<Token::Type> separator)
{ {
std::vector<Ast> trees; std::vector<Ast> trees;
@ -161,6 +187,18 @@ Ast Ast::sequence(std::vector<Ast> expressions)
return ast; return ast;
} }
Ast Ast::block(Ast seq, std::vector<Ast> parameters)
{
Ast ast;
ast.type = Type::Block;
ast.parameters = std::move(parameters);
if (seq.type == Type::Sequence)
ast.arguments = std::move(seq).arguments;
else
ast.arguments.push_back(std::move(seq));
return ast;
}
Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>)) Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>))
{ {
if (ast.size() == 1) if (ast.size() == 1)
@ -184,6 +222,7 @@ bool operator==(Ast const& lhs, Ast const& rhs)
&& lhs.arguments.size() == rhs.arguments.size() && lhs.arguments.size() == rhs.arguments.size()
&& std::equal(lhs.arguments.begin(), lhs.arguments.end(), rhs.arguments.begin()); && std::equal(lhs.arguments.begin(), lhs.arguments.end(), rhs.arguments.begin());
case Ast::Type::Block:
case Ast::Type::Call: case Ast::Type::Call:
case Ast::Type::Sequence: case Ast::Type::Sequence:
return lhs.arguments.size() == rhs.arguments.size() return lhs.arguments.size() == rhs.arguments.size()
@ -193,9 +232,21 @@ bool operator==(Ast const& lhs, Ast const& rhs)
unreachable(); unreachable();
} }
std::ostream& operator<<(std::ostream& os, Ast::Type type)
{
switch (type) {
case Ast::Type::Binary: return os << "BINARY";
case Ast::Type::Block: return os << "BLOCK";
case Ast::Type::Call: return os << "CALL";
case Ast::Type::Literal: return os << "LITERAL";
case Ast::Type::Sequence: return os << "SEQUENCE";
}
unreachable();
}
std::ostream& operator<<(std::ostream& os, Ast const& tree) std::ostream& operator<<(std::ostream& os, Ast const& tree)
{ {
os << "Ast(" << tree.token.source << ")"; os << "Ast::" << tree.type << "(" << tree.token.source << ")";
if (!tree.arguments.empty()) { if (!tree.arguments.empty()) {
os << " { "; os << " { ";
for (auto const& arg : tree.arguments) { for (auto const& arg : tree.arguments) {
@ -203,5 +254,50 @@ std::ostream& operator<<(std::ostream& os, Ast const& tree)
} }
os << '}'; os << '}';
} }
if (!tree.parameters.empty()) {
os << " with parameters { ";
for (auto const& arg : tree.parameters) {
os << arg << ' ';
}
os << '}';
}
return os; return os;
} }
struct Indent
{
unsigned count;
Indent operator+() { return { count + 2 }; }
operator unsigned() { return count; }
};
std::ostream& operator<<(std::ostream& os, Indent n)
{
while (n.count-- > 0)
os.put(' ');
return os;
}
void dump(Ast const& tree, unsigned indent)
{
Indent i{indent};
std::cout << i << "Ast::" << tree.type << "(" << tree.token.source << ")";
if (!tree.arguments.empty()) {
std::cout << " {\n";
for (auto const& arg : tree.arguments) {
dump(arg, +i);
}
std::cout << i << '}';
}
if (!tree.parameters.empty()) {
std::cout << " with parameters {\n";
for (auto const& arg : tree.parameters) {
dump(arg, +i);
}
std::cout << i << '}';
}
std::cout << '\n';
}