Precedense aware parser
This commit is contained in:
parent
854b72cf35
commit
ea1dddaf26
@ -575,6 +575,9 @@ struct Parser
|
|||||||
/// Parse infix expression
|
/// Parse infix expression
|
||||||
Result<Ast> parse_infix_expression();
|
Result<Ast> parse_infix_expression();
|
||||||
|
|
||||||
|
/// Parse right hand size of infix expression
|
||||||
|
Result<Ast> parse_rhs_of_infix_expression(Ast lhs);
|
||||||
|
|
||||||
/// Parse either index expression or atomic expression
|
/// Parse either index expression or atomic expression
|
||||||
Result<Ast> parse_index_expression();
|
Result<Ast> parse_index_expression();
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
static Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>));
|
static Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>));
|
||||||
|
|
||||||
|
static usize precedense(std::string_view op);
|
||||||
|
|
||||||
static inline bool is_identifier_looking(Token::Type type)
|
static inline bool is_identifier_looking(Token::Type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -122,17 +124,61 @@ Result<Ast> Parser::parse_infix_expression()
|
|||||||
auto atomics = Try(parse_many(*this, &Parser::parse_index_expression, std::nullopt, At_Least::One));
|
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);
|
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");
|
assert(not expect(Token::Type::Operator, "."), "This should be handled by parse_index_expression");
|
||||||
auto op = consume();
|
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;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Ast> 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<Ast> Parser::parse_index_expression()
|
Result<Ast> Parser::parse_index_expression()
|
||||||
{
|
{
|
||||||
auto result = Try(parse_atomic_expression());
|
auto result = Try(parse_atomic_expression());
|
||||||
@ -433,6 +479,22 @@ Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>))
|
|||||||
return wrapper(std::move(ast));
|
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)
|
bool operator==(Ast const& lhs, Ast const& rhs)
|
||||||
{
|
{
|
||||||
if (lhs.type != rhs.type) {
|
if (lhs.type != rhs.type) {
|
||||||
|
Loading…
Reference in New Issue
Block a user