From e3d8e031c6f20c68f2227028ee8b3e73cd9b8161 Mon Sep 17 00:00:00 2001 From: Johnny Richard Date: Mon, 1 May 2023 01:57:22 +0200 Subject: 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 Co-authored-by: Carlos Maniero --- src/parser.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 13 deletions(-) (limited to 'src/parser.c') diff --git a/src/parser.c b/src/parser.c index af372fb..ad0fdc9 100644 --- a/src/parser.c +++ b/src/parser.c @@ -235,6 +235,40 @@ parser_parse_return_stmt(parser_t *parser, ast_node_t *node) return true; } +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) { @@ -268,9 +302,12 @@ parser_parse_block_declarations(parser_t *parser, vector_t *body) token_t current_token; lexer_next_token(parser->lexer, ¤t_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, ¤t_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, ¤t_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, ¤t_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; } -- cgit v1.2.3