From 76b94e1da394a2c193613ede94520c9f70832dae Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 6 Mar 2023 19:40:45 -0600 Subject: [PATCH] fixed: parsing of method call with wrong precedence --- compiler/src/lex.c | 1 + compiler/src/parser.c | 70 +++++++++++++++-------- tests/bugs/method_call_source_double.onyx | 2 +- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/compiler/src/lex.c b/compiler/src/lex.c index e85304ca..46c466b9 100644 --- a/compiler/src/lex.c +++ b/compiler/src/lex.c @@ -67,6 +67,7 @@ static const char* token_type_names[] = { ">>>=", "..", "~~", + "??", "TOKEN_TYPE_SYMBOL", "TOKEN_TYPE_LITERAL_STRING", diff --git a/compiler/src/parser.c b/compiler/src/parser.c index acc460c1..465ae793 100644 --- a/compiler/src/parser.c +++ b/compiler/src/parser.c @@ -354,6 +354,29 @@ static void parse_arguments(OnyxParser* parser, TokenType end_token, Arguments* } } +static AstCall* parse_function_call(OnyxParser *parser, AstTyped *callee) { + AstCall* call_node = make_node(AstCall, Ast_Kind_Call); + call_node->token = expect_token(parser, '('); + call_node->callee = callee; + + arguments_initialize(&call_node->args); + + parse_arguments(parser, ')', &call_node->args); + + // Wrap expressions in AstArgument + bh_arr_each(AstTyped *, arg, call_node->args.values) { + if ((*arg) == NULL) continue; + *arg = (AstTyped *) make_argument(parser->allocator, *arg); + } + + bh_arr_each(AstNamedValue *, named_value, call_node->args.named_values) { + if ((*named_value)->value == NULL) continue; + (*named_value)->value = (AstTyped *) make_argument(parser->allocator, (AstTyped *) (*named_value)->value); + } + + return call_node; +} + static AstTyped* parse_factor(OnyxParser* parser) { AstTyped* retval = NULL; @@ -852,27 +875,7 @@ static AstTyped* parse_factor(OnyxParser* parser) { case '(': { if (!parser->parse_calls) goto factor_parsed; - - AstCall* call_node = make_node(AstCall, Ast_Kind_Call); - call_node->token = expect_token(parser, '('); - call_node->callee = retval; - - arguments_initialize(&call_node->args); - - parse_arguments(parser, ')', &call_node->args); - - // Wrap expressions in AstArgument - bh_arr_each(AstTyped *, arg, call_node->args.values) { - if ((*arg) == NULL) continue; - *arg = (AstTyped *) make_argument(parser->allocator, *arg); - } - - bh_arr_each(AstNamedValue *, named_value, call_node->args.named_values) { - if ((*named_value)->value == NULL) continue; - (*named_value)->value = (AstTyped *) make_argument(parser->allocator, (AstTyped *) (*named_value)->value); - } - - retval = (AstTyped *) call_node; + retval = (AstTyped *) parse_function_call(parser, retval); break; } @@ -900,6 +903,27 @@ static AstTyped* parse_factor(OnyxParser* parser) { break; } + case Token_Type_Right_Arrow: { + AstBinaryOp* method_call = make_node(AstBinaryOp, Ast_Kind_Method_Call); + method_call->token = expect_token(parser, Token_Type_Right_Arrow); + + method_call->left = retval; + + OnyxToken *method_name = expect_token(parser, Token_Type_Symbol); + AstNode *method = make_symbol(context.ast_alloc, method_name); + + if (parser->curr->type != '(') { + // CLEANUP: This error message is horrendous. + onyx_report_error(parser->curr->pos, Error_Critical, "Bad method call. Expected object->method(arguments), got something else."); + break; + } + + method_call->right = (AstTyped *) parse_function_call(parser, (AstTyped *) method); + + retval = (AstTyped *) method_call; + break; + } + default: goto factor_parsed; } } @@ -953,8 +977,6 @@ static inline i32 get_precedence(BinaryOp kind) { case Binary_Op_Modulus: return 9; - case Binary_Op_Method_Call: return 10; - case Binary_Op_Coalesce: return 11; default: return -1; @@ -1002,7 +1024,6 @@ static BinaryOp binary_op_from_token_type(TokenType t) { case Token_Type_Pipe: return Binary_Op_Pipe; case Token_Type_Dot_Dot: return Binary_Op_Range; case '[': return Binary_Op_Subscript; - case Token_Type_Right_Arrow: return Binary_Op_Method_Call; case Token_Type_Question_Question: return Binary_Op_Coalesce; default: return Binary_Op_Count; } @@ -1073,7 +1094,6 @@ static AstTyped* parse_expression(OnyxParser* parser, b32 assignment_allowed) { AstBinaryOp* bin_op; if (bin_op_kind == Binary_Op_Pipe) bin_op = make_node(AstBinaryOp, Ast_Kind_Pipe); - else if (bin_op_kind == Binary_Op_Method_Call) bin_op = make_node(AstBinaryOp, Ast_Kind_Method_Call); else if (bin_op_kind == Binary_Op_Range) bin_op = (AstBinaryOp *) make_node(AstRangeLiteral, Ast_Kind_Range_Literal); else bin_op = make_node(AstBinaryOp, Ast_Kind_Binary_Op); diff --git a/tests/bugs/method_call_source_double.onyx b/tests/bugs/method_call_source_double.onyx index 63866adb..884f559c 100644 --- a/tests/bugs/method_call_source_double.onyx +++ b/tests/bugs/method_call_source_double.onyx @@ -30,6 +30,6 @@ make_foo :: () -> &Foo { main :: () { make_foo()->f(); - Foo.{&good_foo, 5678}->f(); + (Foo.{&good_foo, 5678})->f(); } -- 2.25.1