diff --git a/src/main.cc b/src/main.cc index 1d9efdf..989a0b9 100644 --- a/src/main.cc +++ b/src/main.cc @@ -29,8 +29,9 @@ void usage() static Result 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 {}; } diff --git a/src/musique.hh b/src/musique.hh index 38b426e..82e3c39 100644 --- a/src/musique.hh +++ b/src/musique.hh @@ -291,6 +291,7 @@ struct Ast static Ast binary(Token, Ast lhs, Ast rhs); static Ast call(std::vector call); static Ast sequence(std::vector call); + static Ast block(Ast seq, std::vector 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 arguments; + std::vector arguments{}; + std::vector 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 parse_expression(); Result parse_infix_expression(); Result parse_atomic_expression(); + Result parse_identifier(); Result peek() const; Result peek_type() const; diff --git a/src/parser.cc b/src/parser.cc index 25a8a04..2803fe9 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -60,6 +60,26 @@ Result Parser::parse_atomic_expression() case Token::Type::Numeric: return Ast::literal(consume()); + case Token::Type::Open_Block: + { + consume(); + auto start = token_id; + std::vector 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 { + 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 { @@ -75,6 +95,12 @@ Result Parser::parse_atomic_expression() } } +Result Parser::parse_identifier() +{ + Try(ensure(Token::Type::Symbol)); + return Ast::literal(consume()); +} + Result> parse_one_or_more(Parser &p, Result (Parser::*parser)(), std::optional separator) { std::vector trees; @@ -161,6 +187,18 @@ Ast Ast::sequence(std::vector expressions) return ast; } +Ast Ast::block(Ast seq, std::vector 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(*wrapper)(std::vector)) { 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'; +}