summaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
authorJohnny Richard <johnny@johnnyrichard.com>2023-05-01 01:57:22 +0200
committerCarlos Maniero <carlos@maniero.me>2023-05-01 18:24:42 -0300
commite3d8e031c6f20c68f2227028ee8b3e73cd9b8161 (patch)
tree52068df5df3fea73eea9e5af311b03771a0f614a /src/parser.c
parent8c56ddf0b640b8880eb5b97e5ca1b787585c29c0 (diff)
parser: Implement variable assignment
This commit introduces variable assignment making it possible to change a variable value. Example: myvar: i32 = 1; myvar = 2; Signed-off-by: Johnny Richard <johnny@johnnyrichard.com> Co-authored-by: Carlos Maniero <carlos@maniero.me>
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c94
1 files changed, 81 insertions, 13 deletions
diff --git a/src/parser.c b/src/parser.c
index af372fb..ad0fdc9 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -236,6 +236,40 @@ parser_parse_return_stmt(parser_t *parser, ast_node_t *node)
}
static bool
+parser_parse_variable_assignment(parser_t *parser, token_t variable_token, ast_node_t *node)
+{
+ if (!drop_expected_token(parser, TOKEN_EQUAL))
+ return false;
+
+ ast_node_t *expression = ast_node_new();
+
+ if (!parser_parse_expression(parser, expression) || !drop_expected_token(parser, TOKEN_SEMICOLON)) {
+ ast_node_destroy(expression);
+ return false;
+ }
+
+ ast_node_t *variable_declaration_node = scope_get(parser->scope, variable_token.value);
+
+ if (variable_declaration_node == NULL) {
+ parser_error_t error;
+ error.token = variable_token;
+
+ sprintf(error.message, "trying to assign '" SVFMT "' before defining it.", SVARG(&variable_token.value));
+
+ parser->errors[parser->errors_len++] = error;
+ return false;
+ }
+
+ assert(variable_declaration_node->kind == AST_VARIABLE_DECLARATION);
+
+ node->kind = AST_VARIABLE_ASSIGNMENT;
+ node->data = (ast_node_data_t){ .variable_assignment = {
+ .identifier = &variable_declaration_node->data.variable_declaration.identifier,
+ .expression = expression } };
+ return true;
+}
+
+static bool
parser_parse_variable_definition(parser_t *parser, string_view_t variable_name, ast_node_t *node)
{
if (!drop_expected_token(parser, TOKEN_COLON))
@@ -268,9 +302,12 @@ parser_parse_block_declarations(parser_t *parser, vector_t *body)
token_t current_token;
lexer_next_token(parser->lexer, &current_token);
+ scope_enter(parser->scope);
+
while (current_token.kind != TOKEN_CCURLY && current_token.kind != TOKEN_EOF) {
if (current_token.kind != TOKEN_NAME) {
parser_error_push_unexpected_kind(parser, &current_token, TOKEN_NAME);
+ scope_leave(parser->scope);
return false;
}
@@ -280,20 +317,53 @@ parser_parse_block_declarations(parser_t *parser, vector_t *body)
if (!parsed_return) {
ast_node_destroy(return_node);
+ scope_leave(parser->scope);
return false;
}
vector_push_back(body, return_node);
} else {
- ast_node_t *variable_node = ast_node_new();
- bool parsed_variable = parser_parse_variable_definition(parser, current_token.value, variable_node);
-
- if (!parsed_variable) {
- ast_node_destroy(variable_node);
- return false;
+ token_t token;
+ lexer_peek_next_token(parser->lexer, &token);
+
+ switch (token.kind) {
+ case TOKEN_COLON: {
+ ast_node_t *variable_node = ast_node_new();
+
+ if (!parser_parse_variable_definition(parser, current_token.value, variable_node)) {
+ ast_node_destroy(variable_node);
+ return false;
+ }
+
+ vector_push_back(body, variable_node);
+ break;
+ }
+ case TOKEN_EQUAL: {
+ ast_node_t *variable_assignment = ast_node_new();
+
+ if (!parser_parse_variable_assignment(parser, current_token, variable_assignment)) {
+ ast_node_destroy(variable_assignment);
+ return false;
+ }
+
+ vector_push_back(body, variable_assignment);
+ break;
+ }
+ case TOKEN_NAME:
+ case TOKEN_OPAREN:
+ case TOKEN_CPAREN:
+ case TOKEN_SEMICOLON:
+ case TOKEN_OCURLY:
+ case TOKEN_CCURLY:
+ case TOKEN_NUMBER:
+ case TOKEN_PLUS:
+ case TOKEN_MINUS:
+ case TOKEN_STAR:
+ case TOKEN_SLASH:
+ case TOKEN_EOF:
+ case TOKEN_UNKNOWN:
+ break;
}
-
- vector_push_back(body, variable_node);
}
lexer_next_token(parser->lexer, &current_token);
@@ -301,6 +371,7 @@ parser_parse_block_declarations(parser_t *parser, vector_t *body)
if (current_token.kind != TOKEN_CCURLY) {
parser_error_push_unexpected_kind(parser, &current_token, TOKEN_CCURLY);
+ scope_leave(parser->scope);
return false;
}
@@ -313,8 +384,10 @@ parser_parse_block_declarations(parser_t *parser, vector_t *body)
sprintf(error.message, "expected 'return' keyword.");
parser->errors[parser->errors_len++] = error;
+ scope_leave(parser->scope);
return false;
}
+ scope_leave(parser->scope);
return true;
}
@@ -347,14 +420,9 @@ parser_parse_function_declaration(parser_t *parser, ast_node_t *node)
ast_node_init_function_declaration(node, func_name_token.value, return_type, body);
scope_push(parser->scope, &node->data.function.identifier, node);
- scope_enter(parser->scope);
-
if (!parser_parse_block_declarations(parser, body)) {
- scope_leave(parser->scope);
return false;
}
- scope_leave(parser->scope);
-
return true;
}