diff --git a/src/musique.hh b/src/musique.hh index 7f148f9..59914b7 100644 --- a/src/musique.hh +++ b/src/musique.hh @@ -575,6 +575,9 @@ struct Parser /// Parse infix expression Result parse_infix_expression(); + /// Parse right hand size of infix expression + Result parse_rhs_of_infix_expression(Ast lhs); + /// Parse either index expression or atomic expression Result parse_index_expression(); diff --git a/src/parser.cc b/src/parser.cc index a21611d..3952929 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -3,6 +3,8 @@ static Ast wrap_if_several(std::vector &&ast, Ast(*wrapper)(std::vector)); +static usize precedense(std::string_view op); + static inline bool is_identifier_looking(Token::Type type) { switch (type) { @@ -122,17 +124,61 @@ Result Parser::parse_infix_expression() auto atomics = Try(parse_many(*this, &Parser::parse_index_expression, std::nullopt, At_Least::One)); auto lhs = wrap_if_several(std::move(atomics), Ast::call); - if (expect(Token::Type::Operator) || expect(Token::Type::Keyword, "and") || expect(Token::Type::Keyword, "or")) { + bool const next_is_operator = expect(Token::Type::Operator) + || expect(Token::Type::Keyword, "and") + || expect(Token::Type::Keyword, "or"); + + if (next_is_operator) { assert(not expect(Token::Type::Operator, "."), "This should be handled by parse_index_expression"); auto op = consume(); - return parse_expression().map([&](Ast rhs) { - return Ast::binary(std::move(op), std::move(lhs), std::move(rhs)); - }); + + Ast ast; + ast.location = op.location; + ast.type = Ast::Type::Binary; + ast.token = std::move(op); + ast.arguments.emplace_back(std::move(lhs)); + return parse_rhs_of_infix_expression(std::move(ast)); } return lhs; } +Result Parser::parse_rhs_of_infix_expression(Ast lhs) +{ + auto atomics = Try(parse_many(*this, &Parser::parse_index_expression, std::nullopt, At_Least::One)); + auto rhs = wrap_if_several(std::move(atomics), Ast::call); + + bool const next_is_operator = expect(Token::Type::Operator) + || expect(Token::Type::Keyword, "and") + || expect(Token::Type::Keyword, "or"); + + if (!next_is_operator) { + lhs.arguments.emplace_back(std::move(rhs)); + return lhs; + } + + assert(not expect(Token::Type::Operator, "."), "This should be handled by parse_index_expression"); + auto op = consume(); + + if (precedense(lhs.token.source) > precedense(op.source)) { + lhs.arguments.emplace_back(std::move(rhs)); + Ast ast; + ast.location = op.location; + ast.type = Ast::Type::Binary; + ast.token = std::move(op); + ast.arguments.emplace_back(std::move(lhs)); + return parse_rhs_of_infix_expression(std::move(ast)); + } + + Ast ast; + ast.location = op.location; + ast.type = Ast::Type::Binary; + ast.token = std::move(op); + ast.arguments.emplace_back(std::move(rhs)); + lhs.arguments.emplace_back(Try(parse_rhs_of_infix_expression(std::move(ast)))); + return lhs; +} + Result Parser::parse_index_expression() { auto result = Try(parse_atomic_expression()); @@ -433,6 +479,22 @@ Ast wrap_if_several(std::vector &&ast, Ast(*wrapper)(std::vector)) return wrapper(std::move(ast)); } +constexpr bool one_of(std::string_view id, auto const& ...args) +{ + return ((id == args) || ...); +} + +static usize precedense(std::string_view op) +{ + if (one_of(op, "or")) return 100; + if (one_of(op, "and")) return 150; + if (one_of(op, "<", ">", "<=", ">=", "==", "!=")) return 200; + if (one_of(op, "+", "-")) return 300; + if (one_of(op, "*", "/")) return 400; + + unreachable(); +} + bool operator==(Ast const& lhs, Ast const& rhs) { if (lhs.type != rhs.type) {