From: Carlos Maniero <carlos@maniero.me>
To: ~johnnyrichard/olang-devel@lists.sr.ht
Cc: Carlos Maniero <carlos@maniero.me>
Subject: [PATCH olang v3 1/2] spec: parser: enable expression on function level
Date: Thu, 10 Oct 2024 16:29:31 +0000 (UTC) [thread overview]
Message-ID: <20241010162918.338338-2-carlos@maniero.me> (raw)
In-Reply-To: <20241010162918.338338-1-carlos@maniero.me>
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
next prev parent reply other threads:[~2024-10-10 16:43 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-10 16:29 [PATCH olang v3 0/2] " Carlos Maniero
2024-10-10 16:29 ` Carlos Maniero [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241010162918.338338-2-carlos@maniero.me \
--to=carlos@maniero.me \
--cc=~johnnyrichard/olang-devel@lists.sr.ht \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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