* [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