fixed: precedence of if-expressions
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 10 Dec 2023 02:03:36 +0000 (20:03 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 10 Dec 2023 02:03:36 +0000 (20:03 -0600)
compiler/src/parser.c
tests/nested-if-exprs [new file with mode: 0644]
tests/nested-if-exprs.onyx [new file with mode: 0644]

index 0898ba6c4e79a701698cdced76e58be47d14dce3..5199e973ad439096469e6b6ce129f6d7cd0390a3 100644 (file)
@@ -954,19 +954,6 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 break;
             }
 
-            case Token_Type_Keyword_If: {
-                AstIfExpression* if_expression = make_node(AstIfExpression, Ast_Kind_If_Expression);
-                if_expression->token = expect_token(parser, Token_Type_Keyword_If);
-
-                if_expression->true_expr  = retval;
-                if_expression->cond       = parse_expression(parser, 0);
-                expect_token(parser, Token_Type_Keyword_Else);
-                if_expression->false_expr = parse_expression(parser, 0);
-
-                retval = (AstTyped *) if_expression;
-                break;
-            }
-
             case '?': {
                 AstUnaryOp* unop = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
                 unop->token = expect_token(parser, '?');
@@ -1159,6 +1146,29 @@ static AstTyped* parse_expression(OnyxParser* parser, b32 assignment_allowed) {
     while (1) {
         if (parser->hit_unexpected_token) return root;
 
+        if (parser->curr->type == Token_Type_Keyword_If) {
+            AstIfExpression *ifexpr = make_node(AstIfExpression, Ast_Kind_If_Expression);
+            ifexpr->token = expect_token(parser, Token_Type_Keyword_If);
+
+            ifexpr->true_expr = root;
+            ifexpr->cond = parse_expression(parser, 0);
+            expect_token(parser, Token_Type_Keyword_Else);
+            ifexpr->false_expr = parse_expression(parser, 0);
+
+            // Check for the x = y if cond else z case.
+            // This would parse as (x = 1) if cond else z, but that is incorrect.
+            if (root->kind == Ast_Kind_Binary_Op && binop_is_assignment(((AstBinaryOp *) root)->operation)) {
+                AstBinaryOp *r = (AstBinaryOp *) root;
+                ifexpr->true_expr = r->right;
+                r->right = (AstTyped *) ifexpr;
+
+            } else {
+                root = (AstTyped *) ifexpr;
+            }
+
+            goto expression_done;
+        }
+
         bin_op_kind = binary_op_from_token_type(parser->curr->type);
         if (bin_op_kind == Binary_Op_Count) goto expression_done;
         if (binop_is_assignment(bin_op_kind) && !assignment_allowed) goto expression_done;
diff --git a/tests/nested-if-exprs b/tests/nested-if-exprs
new file mode 100644 (file)
index 0000000..cd5a535
--- /dev/null
@@ -0,0 +1,3 @@
+cmp(1, 2): -1
+cmp(2, 2): 0
+cmp(3, 2): 1
diff --git a/tests/nested-if-exprs.onyx b/tests/nested-if-exprs.onyx
new file mode 100644 (file)
index 0000000..c638857
--- /dev/null
@@ -0,0 +1,11 @@
+use core {printf}
+
+main :: () {
+    printf("cmp(1, 2): {}\n", cmp(1, 2));
+    printf("cmp(2, 2): {}\n", cmp(2, 2));
+    printf("cmp(3, 2): {}\n", cmp(3, 2));
+}
+
+cmp :: (a: i32, b: i32) -> i32 {
+    return 0 if a == b else -1 if a < b else 1;
+}
\ No newline at end of file