Block expressions
This commit is contained in:
parent
c5260df41c
commit
5bfec0e77a
@ -29,8 +29,9 @@ void usage()
|
||||
|
||||
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";
|
||||
dump(ast);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -291,6 +291,7 @@ struct Ast
|
||||
static Ast binary(Token, Ast lhs, Ast rhs);
|
||||
static Ast call(std::vector<Ast> call);
|
||||
static Ast sequence(std::vector<Ast> call);
|
||||
static Ast block(Ast seq, std::vector<Ast> parameters = {});
|
||||
|
||||
enum class Type
|
||||
{
|
||||
@ -298,15 +299,19 @@ struct Ast
|
||||
Binary, // Binary operator application like `1` + `2`
|
||||
Call, // Function call application like `print 42`
|
||||
Sequence, // Several expressions sequences like `42`, `42; 32`
|
||||
Block, // Block expressions like `[42; hello]`
|
||||
};
|
||||
|
||||
Type type;
|
||||
Token token;
|
||||
std::vector<Ast> arguments;
|
||||
std::vector<Ast> arguments{};
|
||||
std::vector<Ast> parameters{};
|
||||
};
|
||||
|
||||
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);
|
||||
void dump(Ast const& ast, unsigned indent = 0);
|
||||
|
||||
struct Parser
|
||||
{
|
||||
@ -321,6 +326,7 @@ struct Parser
|
||||
Result<Ast> parse_expression();
|
||||
Result<Ast> parse_infix_expression();
|
||||
Result<Ast> parse_atomic_expression();
|
||||
Result<Ast> parse_identifier();
|
||||
|
||||
Result<Token> peek() const;
|
||||
Result<Token::Type> peek_type() const;
|
||||
|
@ -60,6 +60,26 @@ Result<Ast> Parser::parse_atomic_expression()
|
||||
case Token::Type::Numeric:
|
||||
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:
|
||||
consume();
|
||||
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)
|
||||
{
|
||||
std::vector<Ast> trees;
|
||||
@ -161,6 +187,18 @@ Ast Ast::sequence(std::vector<Ast> expressions)
|
||||
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>))
|
||||
{
|
||||
if (ast.size() == 1)
|
||||
@ -184,6 +222,7 @@ bool operator==(Ast const& lhs, Ast const& rhs)
|
||||
&& lhs.arguments.size() == rhs.arguments.size()
|
||||
&& std::equal(lhs.arguments.begin(), lhs.arguments.end(), rhs.arguments.begin());
|
||||
|
||||
case Ast::Type::Block:
|
||||
case Ast::Type::Call:
|
||||
case Ast::Type::Sequence:
|
||||
return lhs.arguments.size() == rhs.arguments.size()
|
||||
@ -193,9 +232,21 @@ bool operator==(Ast const& lhs, Ast const& rhs)
|
||||
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)
|
||||
{
|
||||
os << "Ast(" << tree.token.source << ")";
|
||||
os << "Ast::" << tree.type << "(" << tree.token.source << ")";
|
||||
if (!tree.arguments.empty()) {
|
||||
os << " { ";
|
||||
for (auto const& arg : tree.arguments) {
|
||||
@ -203,5 +254,50 @@ std::ostream& operator<<(std::ostream& os, Ast const& tree)
|
||||
}
|
||||
os << '}';
|
||||
}
|
||||
|
||||
if (!tree.parameters.empty()) {
|
||||
os << " with parameters { ";
|
||||
for (auto const& arg : tree.parameters) {
|
||||
os << arg << ' ';
|
||||
}
|
||||
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';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user