public inbox for ~johnnyrichard/olang-devel@lists.sr.ht
 help / color / mirror / code / Atom feed
* [PATCH olang v3 0/2] spec: parser: enable expression on function level
@ 2024-10-10 16:29 Carlos Maniero
  2024-10-10 16:29 ` [PATCH olang v3 1/2] " Carlos Maniero
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Carlos Maniero @ 2024-10-10 16:29 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Carlos Maniero

v3:
- transform the assignment expression into a binop
- fix unary precedence

Carlos Maniero (2):
  spec: parser: enable expression on function level
  parser: fix unary precedence

 docs/info/specification.texi      | 18 ++++++-------
 src/ast.c                         | 14 ----------
 src/ast.h                         |  2 +-
 src/checker.c                     |  8 ------
 src/codegen_linux_x86_64.c        | 35 ++++++++++++++-----------
 src/lexer.c                       |  1 +
 src/parser.c                      | 43 +++++--------------------------
 src/pretty_print_ast.c            | 40 ++++++++++++++++------------
 tests/olc/0029_var_assigment.ol   |  2 +-
 tests/olc/0030_while_statement.ol |  2 +-
 tests/olc/0034_pointers.ol        | 43 +++++++++++++++++++++++++++++++
 11 files changed, 107 insertions(+), 101 deletions(-)
 create mode 100644 tests/olc/0034_pointers.ol


base-commit: d45df92d81f00059ecd1f6478bac7e4511d9fd8d
-- 
2.46.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH olang v3 1/2] spec: parser: enable expression on function level
  2024-10-10 16:29 [PATCH olang v3 0/2] spec: parser: enable expression on function level Carlos Maniero
@ 2024-10-10 16:29 ` Carlos Maniero
  2024-10-10 16:29 ` [PATCH olang v3 2/2] parser: fix unary precedence Carlos Maniero
  2024-10-11  0:32 ` [PATCH olang v3 0/2] spec: parser: enable expression on function level Johnny Richard
  2 siblings, 0 replies; 5+ messages in thread
From: Carlos Maniero @ 2024-10-10 16:29 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Carlos Maniero

Previously, assignment statements were restricted to variable
assignments. This commit extends their functionality by:

    1. Enabling unary operators on the left-hand side (LHS) of
       assignments: This allows for expressions like { *a = 1 } to be
       valid.

    2. Permitting function calls within assignment statements: This
       enables calling functions without explicitly capturing their
       return values, as demonstrated in { my_fn() }.

Signed-off-by: Carlos Maniero <carlos@maniero.me>
---
 docs/info/specification.texi      | 18 +++++++-------
 src/ast.c                         | 14 -----------
 src/ast.h                         |  2 +-
 src/checker.c                     |  8 ------
 src/codegen_linux_x86_64.c        | 35 +++++++++++++++-----------
 src/lexer.c                       |  1 +
 src/parser.c                      | 41 +++++--------------------------
 src/pretty_print_ast.c            | 40 ++++++++++++++++++------------
 tests/olc/0029_var_assigment.ol   |  2 +-
 tests/olc/0030_while_statement.ol |  2 +-
 10 files changed, 63 insertions(+), 100 deletions(-)

diff --git a/docs/info/specification.texi b/docs/info/specification.texi
index a466331..e1c9d76 100644
--- a/docs/info/specification.texi
+++ b/docs/info/specification.texi
@@ -48,8 +48,7 @@ language.
 
 (* Statements *)
 <end-of-statement>    ::= ';' | <line-break>
-<common-statement>    ::= <variable-definition> | <constant-definition> | <assignment>
-<assignment>          ::= <variable-name> <ows> <assignment-operator> <ows> <expression>
+<common-statement>    ::= <variable-definition> | <constant-definition> | <expression>
 <assignment-operator> ::= '='
                         | '*='
                         | '/='
@@ -64,7 +63,8 @@ language.
 
 (* Expressions *)
 <expression> ::= <binary-expression>
-<binary-expression> ::= <logical-or-expression>
+<binary-expression> ::= <assignment-expression>
+<assignment-expression> ::= <logical-or-expression> (<ows> <assignment-operator> <ows> <logical-or-expression>)*
 <logical-or-expression> ::= <logical-and-expression> (<ows> '||' <ows> <logical-and-expression>)*
 <logical-and-expression> ::= <bitwise-or-expression> (<ows> '&&' <ows> <bitwise-or-expression>)*
 <bitwise-or-expression> ::= <bitwise-xor-expression> (<ows> '|' <ows> <bitwise-xor-expression>)*
@@ -82,12 +82,12 @@ language.
                        | '(' <ows>  <expression> <ows> ')'
 
 <unary-expression> ::= <unary-operator> <ows> <primary-expression>
-<unary-operator> ::= &
-                   | *
-                   | +
-                   | -
-                   | ~
-                   | !
+<unary-operator> ::= '&'
+                   | '*'
+                   | '+'
+                   | '-'
+                   | '~'
+                   | '!'
 
 (* Identifiers *)
 <type>                ::= 'u32'
diff --git a/src/ast.c b/src/ast.c
index 5a36ccb..c64e660 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -158,20 +158,6 @@ ast_new_node_ref(arena_t *arena, token_loc_t loc, string_view_t id)
     return node_ref;
 }
 
-ast_node_t *
-ast_new_node_var_assign_stmt(arena_t *arena, token_loc_t loc, ast_node_t *ref, ast_node_t *expr)
-{
-    ast_node_t *node_var_assign_stmt = (ast_node_t *)arena_alloc(arena, sizeof(ast_node_t));
-    assert(node_var_assign_stmt);
-
-    node_var_assign_stmt->kind = AST_NODE_VAR_ASSIGN_STMT;
-    node_var_assign_stmt->loc = loc;
-    node_var_assign_stmt->as_var_assign_stmt.ref = ref;
-    node_var_assign_stmt->as_var_assign_stmt.expr = expr;
-
-    return node_var_assign_stmt;
-}
-
 ast_node_t *
 ast_new_node_return_stmt(arena_t *arena, token_loc_t loc, ast_node_t *expr)
 {
diff --git a/src/ast.h b/src/ast.h
index ee94f57..6da11cf 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -37,7 +37,6 @@ typedef enum
     AST_NODE_VAR_DEF,
     AST_NODE_BINARY_OP,
     AST_NODE_UNARY_OP,
-    AST_NODE_VAR_ASSIGN_STMT,
     AST_NODE_RETURN_STMT,
     AST_NODE_IF_STMT,
     AST_NODE_WHILE_STMT,
@@ -139,6 +138,7 @@ typedef enum ast_binary_op_kind
     AST_BINOP_CMP_NEQ,
     AST_BINOP_LOGICAL_AND,
     AST_BINOP_LOGICAL_OR,
+    AST_BINOP_ASSIGN,
 } ast_binary_op_kind_t;
 
 typedef struct ast_binary_op
diff --git a/src/checker.c b/src/checker.c
index 62d612f..e06cfe9 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -184,14 +184,6 @@ populate_scope(checker_t *checker, scope_t *scope, ast_node_t *ast)
             return;
         }
 
-        case AST_NODE_VAR_ASSIGN_STMT: {
-            ast_var_assign_stmt_t var_assign_stmt = ast->as_var_assign_stmt;
-
-            populate_scope(checker, scope, var_assign_stmt.ref);
-            populate_scope(checker, scope, var_assign_stmt.expr);
-            return;
-        }
-
         case AST_NODE_RETURN_STMT: {
             ast_return_stmt_t return_stmt = ast->as_return_stmt;
 
diff --git a/src/codegen_linux_x86_64.c b/src/codegen_linux_x86_64.c
index ae28aa5..8a73263 100644
--- a/src/codegen_linux_x86_64.c
+++ b/src/codegen_linux_x86_64.c
@@ -524,6 +524,24 @@ codegen_linux_x86_64_emit_expression(codegen_x86_64_t *codegen, ast_node_t *expr
 
                     return 1;
                 }
+                case AST_BINOP_ASSIGN: {
+                    // FIXME: It may not be a ref
+                    ast_ref_t ref = bin_op.lhs->as_ref;
+                    scope_t *scope = ref.scope;
+
+                    symbol_t *symbol = scope_lookup(scope, ref.id);
+                    assert(symbol);
+
+                    size_t offset = codegen_linux_x86_64_get_stack_offset(codegen, symbol);
+
+                    codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+
+                    size_t type_size = type_to_bytes(symbol->type);
+                    fprintf(codegen->out, "    mov %s, -%ld(%%rbp)\n", get_reg_for(REG_ACCUMULATOR, type_size), offset);
+
+                    // FIXME: we don't support a = b = c
+                    return 0;
+                }
                 default: {
                     assert(0 && "unsupported binary operation");
                     return 0;
@@ -599,21 +617,8 @@ codegen_linux_x86_64_emit_block(codegen_x86_64_t *codegen, ast_block_t *block)
                 break;
             }
 
-            case AST_NODE_VAR_ASSIGN_STMT: {
-                ast_var_assign_stmt_t var_assign = node->as_var_assign_stmt;
-                ast_ref_t ref = var_assign.ref->as_ref;
-                scope_t *scope = ref.scope;
-
-                symbol_t *symbol = scope_lookup(scope, ref.id);
-                assert(symbol);
-
-                size_t offset = codegen_linux_x86_64_get_stack_offset(codegen, symbol);
-
-                codegen_linux_x86_64_emit_expression(codegen, var_assign.expr);
-
-                size_t type_size = type_to_bytes(symbol->type);
-                fprintf(codegen->out, "    mov %s, -%ld(%%rbp)\n", get_reg_for(REG_ACCUMULATOR, type_size), offset);
-
+            case AST_NODE_BINARY_OP: {
+                codegen_linux_x86_64_emit_expression(codegen, node);
                 break;
             }
 
diff --git a/src/lexer.c b/src/lexer.c
index 9e012bd..c4f645c 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -339,6 +339,7 @@ bool
 token_kind_is_binary_op(token_kind_t kind)
 {
     switch (kind) {
+        case TOKEN_EQ:
         case TOKEN_PLUS:
         case TOKEN_DASH:
         case TOKEN_SLASH:
diff --git a/src/parser.c b/src/parser.c
index f712bfc..44a4900 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -52,9 +52,6 @@ parser_parse_while_stmt(parser_t *parser);
 static ast_node_t *
 parser_parse_var_def(parser_t *parser);
 
-static ast_node_t *
-parser_parse_var_assign_stmt(parser_t *parser);
-
 static ast_node_t *
 parser_parse_fn_definition(parser_t *parser);
 
@@ -150,6 +147,8 @@ token_kind_to_binary_op_kind(token_kind_t kind)
             return AST_BINOP_LOGICAL_AND;
         case TOKEN_LOGICAL_OR:
             return AST_BINOP_LOGICAL_OR;
+        case TOKEN_EQ:
+            return AST_BINOP_ASSIGN;
         default: {
             fprintf(stderr, "error: token kind (%s) not compatible with binary op kind\n", token_kind_to_cstr(kind));
             assert(false);
@@ -160,6 +159,7 @@ token_kind_to_binary_op_kind(token_kind_t kind)
 typedef enum
 {
     BINOP_MIN_PREC,
+    BINOP_ASSIGN_PREC,
     BINOP_LOGICAL_OR_PREC,
     BINOP_LOGICAL_AND_PREC,
     BINOP_BITWISE_OR_PREC,
@@ -204,6 +204,8 @@ get_binary_op_precedence(token_kind_t kind)
             return BINOP_LOGICAL_AND_PREC;
         case TOKEN_LOGICAL_OR:
             return BINOP_LOGICAL_OR_PREC;
+        case TOKEN_EQ:
+            return BINOP_ASSIGN_PREC;
         default:
             assert(false);
     }
@@ -293,7 +295,6 @@ parser_parse_factor(parser_t *parser)
                 list_t *args = parser_parse_fn_args(parser);
                 return ast_new_node_fn_call(parser->arena, token_id.loc, token_id.value, args);
             }
-
             return ast_new_node_ref(parser->arena, token_id.loc, token_id.value);
         }
         case TOKEN_AND:
@@ -536,20 +537,11 @@ StartLoop:
             node = parser_parse_var_def(parser);
             break;
         }
-        case TOKEN_ID: {
-            lexer_lookahead(parser->lexer, &next_token, 2);
-            if (!expected_token(&next_token, TOKEN_EQ)) {
-                return NULL;
-            }
-            node = parser_parse_var_assign_stmt(parser);
-            break;
-        }
         case TOKEN_CCURLY: {
             goto EndLoop;
         }
         default: {
-            // FIXME: write a better error message
-            goto EndLoop;
+            node = parser_parse_expr(parser);
         }
     }
 
@@ -711,27 +703,6 @@ parser_parse_var_def(parser_t *parser)
     return var_node;
 }
 
-static ast_node_t *
-parser_parse_var_assign_stmt(parser_t *parser)
-{
-    token_t token_id;
-
-    if (!expected_next_token(parser, &token_id, TOKEN_ID)) {
-        return NULL;
-    }
-
-    token_t token_eq;
-
-    if (!expected_next_token(parser, &token_eq, TOKEN_EQ)) {
-        return NULL;
-    }
-
-    ast_node_t *ref = ast_new_node_ref(parser->arena, token_id.loc, token_id.value);
-    ast_node_t *expr = parser_parse_expr(parser);
-
-    return ast_new_node_var_assign_stmt(parser->arena, token_eq.loc, ref, expr);
-}
-
 static bool
 skip_expected_token(parser_t *parser, token_kind_t expected_kind)
 {
diff --git a/src/pretty_print_ast.c b/src/pretty_print_ast.c
index 3a42412..387cde4 100644
--- a/src/pretty_print_ast.c
+++ b/src/pretty_print_ast.c
@@ -193,20 +193,6 @@ ast_node_to_pretty_print_node(ast_node_t *ast, arena_t *arena)
             }
             return node;
         }
-        case AST_NODE_VAR_ASSIGN_STMT: {
-            pretty_print_node_t *node = pretty_print_node_new(arena);
-            ast_var_assign_stmt_t var_assign_stmt = ast->as_var_assign_stmt;
-
-            node->name = "Var_Assigment";
-
-            pretty_print_node_t *ref = ast_node_to_pretty_print_node(var_assign_stmt.ref, arena);
-            pretty_print_node_t *expr = ast_node_to_pretty_print_node(var_assign_stmt.expr, arena);
-
-            list_append(node->children, ref);
-            list_append(node->children, expr);
-
-            return node;
-        }
         case AST_NODE_RETURN_STMT: {
             pretty_print_node_t *node = pretty_print_node_new(arena);
             ast_return_stmt_t return_stmt = ast->as_return_stmt;
@@ -371,6 +357,10 @@ ast_node_to_pretty_print_node(ast_node_t *ast, arena_t *arena)
                     node->name = "Binary_Operation (|)";
                     break;
                 }
+                case AST_BINOP_ASSIGN: {
+                    node->name = "Binary_Operation (=)";
+                    break;
+                }
                 default:
                     assert(false && "binop not implemented");
             }
@@ -393,8 +383,26 @@ ast_node_to_pretty_print_node(ast_node_t *ast, arena_t *arena)
                     node->name = "Unary_Operation (~)";
                     break;
                 }
-                default:
-                    assert(false && "unary operation kind not implemented");
+                case AST_UNARY_DEREFERENCE: {
+                    node->name = "Unary_Operation (*)";
+                    break;
+                }
+                case AST_UNARY_NEGATIVE: {
+                    node->name = "Unary_Operation (-)";
+                    break;
+                }
+                case AST_UNARY_LOGICAL_NOT: {
+                    node->name = "Unary_Operation (!)";
+                    break;
+                }
+                case AST_UNARY_POSITIVE: {
+                    node->name = "Unary_Operation (+)";
+                    break;
+                }
+                case AST_UNARY_ADDRESSOF: {
+                    node->name = "Unary_Operation (&)";
+                    break;
+                }
             }
 
             pretty_print_node_t *expr = ast_node_to_pretty_print_node(unary_op.expr, arena);
diff --git a/tests/olc/0029_var_assigment.ol b/tests/olc/0029_var_assigment.ol
index 0e04fcc..402d73a 100644
--- a/tests/olc/0029_var_assigment.ol
+++ b/tests/olc/0029_var_assigment.ol
@@ -29,7 +29,7 @@ fn main(): u32 {
 #   `-Block
 #     |-Var_Definition <name:code> <kind:u32>
 #     | `-Literal <kind:u32> <value:1>
-#     |-Var_Assigment
+#     |-Binary_Operation (=)
 #     | |-Reference <name:code>
 #     | `-Literal <kind:u32> <value:0>
 #     `-Return_Statement
diff --git a/tests/olc/0030_while_statement.ol b/tests/olc/0030_while_statement.ol
index 0eca528..0ce0185 100644
--- a/tests/olc/0030_while_statement.ol
+++ b/tests/olc/0030_while_statement.ol
@@ -38,7 +38,7 @@ fn main(): u32 {
 #     | | |-Reference <name:i>
 #     | | `-Literal <kind:u32> <value:10>
 #     | `-Block
-#     |   `-Var_Assigment
+#     |   `-Binary_Operation (=)
 #     |     |-Reference <name:i>
 #     |     `-Binary_Operation (+)
 #     |       |-Reference <name:i>
-- 
2.46.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH olang v3 2/2] parser: fix unary precedence
  2024-10-10 16:29 [PATCH olang v3 0/2] spec: parser: enable expression on function level Carlos Maniero
  2024-10-10 16:29 ` [PATCH olang v3 1/2] " Carlos Maniero
@ 2024-10-10 16:29 ` Carlos Maniero
  2024-10-10 16:30   ` [olang/patches/.build.yml] build success builds.sr.ht
  2024-10-11  0:32 ` [PATCH olang v3 0/2] spec: parser: enable expression on function level Johnny Richard
  2 siblings, 1 reply; 5+ messages in thread
From: Carlos Maniero @ 2024-10-10 16:29 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Carlos Maniero

Unary is only supposed to contain primary expressions. Before this
commit, the code { *a = 1 } was interpreted as { *(a = 1) }.

Signed-off-by: Carlos Maniero <carlos@maniero.me>
---
 src/parser.c               |  2 +-
 tests/olc/0034_pointers.ol | 43 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 1 deletion(-)
 create mode 100644 tests/olc/0034_pointers.ol

diff --git a/src/parser.c b/src/parser.c
index 44a4900..177195d 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -303,7 +303,7 @@ parser_parse_factor(parser_t *parser)
         case TOKEN_DASH:
         case TOKEN_TILDE:
         case TOKEN_BANG: {
-            ast_node_t *expr = parser_parse_expr(parser);
+            ast_node_t *expr = parser_parse_factor(parser);
             if (expr == NULL) {
                 return NULL;
             }
diff --git a/tests/olc/0034_pointers.ol b/tests/olc/0034_pointers.ol
new file mode 100644
index 0000000..3f3e80b
--- /dev/null
+++ b/tests/olc/0034_pointers.ol
@@ -0,0 +1,43 @@
+# Copyright (C) 2024 olang mantainers
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+# A minimal olang program
+fn main(): u32 {
+  var a: u32 = 1
+  var b: u32* = &a
+  *b = 0
+  return a
+}
+
+# xTEST test_compile(exit_code=0)
+#
+# xTEST test_run_binary(exit_code=0)
+#
+# TEST test_ast WITH
+# Translation_Unit
+# `-Function_Definition <name:main> <return:u32>
+#   `-Block
+#     |-Var_Definition <name:a> <kind:u32>
+#     | `-Literal <kind:u32> <value:1>
+#     |-Var_Definition <name:b> <kind:u32*>
+#     | `-Unary_Operation (&)
+#     |   `-Reference <name:a>
+#     |-Binary_Operation (=)
+#     | |-Unary_Operation (*)
+#     | | `-Reference <name:b>
+#     | `-Literal <kind:u32> <value:0>
+#     `-Return_Statement
+#       `-Reference <name:a>
+# END
-- 
2.46.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [olang/patches/.build.yml] build success
  2024-10-10 16:29 ` [PATCH olang v3 2/2] parser: fix unary precedence Carlos Maniero
@ 2024-10-10 16:30   ` builds.sr.ht
  0 siblings, 0 replies; 5+ messages in thread
From: builds.sr.ht @ 2024-10-10 16:30 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 21s

[spec: parser: enable expression on function level][0] v3 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55420
[1]: mailto:carlos@maniero.me

✓ #1348367 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1348367

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH olang v3 0/2] spec: parser: enable expression on function level
  2024-10-10 16:29 [PATCH olang v3 0/2] spec: parser: enable expression on function level Carlos Maniero
  2024-10-10 16:29 ` [PATCH olang v3 1/2] " Carlos Maniero
  2024-10-10 16:29 ` [PATCH olang v3 2/2] parser: fix unary precedence Carlos Maniero
@ 2024-10-11  0:32 ` Johnny Richard
  2 siblings, 0 replies; 5+ messages in thread
From: Johnny Richard @ 2024-10-11  0:32 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

Thanks, applied!

To git.sr.ht:~johnnyrichard/olang
   d45df92..3c15dde  main -> main


---->8----
Subject: [PATCH olang] fixup! parser: fix unary precedence


diff --git a/tests/olc/0034_pointers.ol b/tests/olc/0034_pointers.ol
index 3f3e80b..0e95af4 100644
--- a/tests/olc/0034_pointers.ol
+++ b/tests/olc/0034_pointers.ol
@@ -13,7 +13,6 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-# A minimal olang program
 fn main(): u32 {
   var a: u32 = 1
   var b: u32* = &a


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-10-10 22:33 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-10 16:29 [PATCH olang v3 0/2] spec: parser: enable expression on function level Carlos Maniero
2024-10-10 16:29 ` [PATCH olang v3 1/2] " Carlos Maniero
2024-10-10 16:29 ` [PATCH olang v3 2/2] parser: fix unary precedence Carlos Maniero
2024-10-10 16:30   ` [olang/patches/.build.yml] build success builds.sr.ht
2024-10-11  0:32 ` [PATCH olang v3 0/2] spec: parser: enable expression on function level Johnny Richard

Code repositories for project(s) associated with this public inbox

	https://git.johnnyrichard.com/olang.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox