From c1a1bd2320b4c1508c4ab20d23b7c193a94d8026 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Tue, 25 Apr 2023 03:52:59 -0300 Subject: parser: Add support for variables and identifiers in function body This commit adds support for variables and identifiers in the function body of the parser, stored as a vector. However, at this point, identifier resolution is not fully implemented, and we currently accept identifiers without checking if they can be resolved. This is a known limitation that will be addressed in a future commit once hash-tables are added to the parser. Signed-off-by: Carlos Maniero Reviewed-by: Johnny Richard --- src/parser.c | 153 ++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 115 insertions(+), 38 deletions(-) (limited to 'src/parser.c') diff --git a/src/parser.c b/src/parser.c index a123648..5399cfd 100644 --- a/src/parser.c +++ b/src/parser.c @@ -24,6 +24,7 @@ #include "ast.h" #include "lexer.h" #include "parser.h" +#include "vector.h" void parser_init(parser_t *parser, lexer_t *lexer) @@ -34,32 +35,27 @@ parser_init(parser_t *parser, lexer_t *lexer) parser->errors_len = 0; } -static bool -expected_token(token_t *token, parser_t *parser, token_kind_t kind) +static void +parser_error_push_unexpected_kind(parser_t *parser, token_t *token, token_kind_t expected) { - lexer_next_token(parser->lexer, token); - parser_error_t error; + parser_error_t* error = &parser->errors[parser->errors_len++]; + error->token = *token; if (token->kind == TOKEN_EOF) { - error.token = *token; - sprintf( - error.message, - "expected '%s' but got end of file", - token_kind_to_str(kind) - ); - - parser->errors[parser->errors_len++] = error; - return false; + sprintf(error->message, "expected '%s' but got end of file", token_kind_to_str(expected)); + return; } + sprintf(error->message, "expected '%s' but got '%s'", token_kind_to_str(expected), token_kind_to_str(token->kind)); +} + +static bool +expected_token(token_t *token, parser_t *parser, token_kind_t kind) +{ + lexer_next_token(parser->lexer, token); + if (token->kind != kind) { - error.token = *token; - sprintf( - error.message, - "expected '%s' but got '%s'", - token_kind_to_str(kind), token_kind_to_str(token->kind) - ); - parser->errors[parser->errors_len++] = error; + parser_error_push_unexpected_kind(parser, token, kind); return false; } @@ -120,6 +116,10 @@ parser_parse_factor(parser_t *parser, ast_node_t *node) parser_parse_expression(parser, node); if (!drop_expected_token(parser, TOKEN_CPAREN)) return false; return true; + } else if (token.kind == TOKEN_NAME) { + /// FIXME: Check if the identifier is defined + ast_node_init_identifier(node, token.value); + return true; } // FIXME: Extract this erros logic to a function @@ -196,33 +196,112 @@ parser_parse_expression(parser_t *parser, ast_node_t *node) bool parser_parse_return_stmt(parser_t *parser, ast_node_t *node) { - token_t return_keyword_token; + ast_node_t *argument_token = ast_node_new(); + if (!parser_parse_expression(parser, argument_token)) return false; - if (!drop_expected_token(parser, TOKEN_OCURLY)) return false; + if (!drop_expected_token(parser, TOKEN_SEMICOLON)) return false; + + ast_node_init_return_stmt(node, argument_token); + return true; +} + +bool +parser_parse_variable_definition(parser_t *parser, string_view_t variable_name, ast_node_t *node) +{ + if (!drop_expected_token(parser, TOKEN_COLON)) return false; + + type_t type; + + // FIXME: change the parameters order + if (!parser_parse_type(&type, parser)) return false; - if(!expected_token(&return_keyword_token, parser, TOKEN_NAME)) return false; + token_t equal_token; - if (!string_view_eq(return_keyword_token.value, string_view_from_str("return"))) { + if (!expected_token(&equal_token, parser, TOKEN_OP)) return false; + + if (!string_view_eq(equal_token.value, string_view_from_str("="))) { parser_error_t error; - error.token = return_keyword_token; + error.token = equal_token; sprintf( error.message, - "expected 'return' keyword but got '"SVFMT"'", - SVARG(&return_keyword_token.value) + "expected '=' but got "SVFMT, + SVARG(&equal_token.value) ); parser->errors[parser->errors_len++] = error; return false; } - ast_node_t *argument_token = ast_node_new(); - if (!parser_parse_expression(parser, argument_token)) return false; + ast_node_t *expression = ast_node_new(); - if (!drop_expected_token(parser, TOKEN_SEMICOLON)) return false; - if (!drop_expected_token(parser, TOKEN_CCURLY)) return false; + if (!parser_parse_expression(parser, expression) || !drop_expected_token(parser, TOKEN_SEMICOLON)) { + ast_node_destroy(expression); + return false; + } + + ast_node_init_variable_declaration(node, variable_name, type, expression); - ast_node_init_return_stmt(node, argument_token); + return true; +} + +bool +parser_parse_block_declarations(parser_t *parser, vector_t *body) +{ + token_t current_token; + lexer_next_token(parser->lexer, ¤t_token); + + 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); + return false; + } + + if (string_view_eq(current_token.value, string_view_from_str("return"))) { + ast_node_t *return_node = ast_node_new(); + bool parsed_return = parser_parse_return_stmt(parser, return_node); + + if (!parsed_return) { + ast_node_destroy(return_node); + 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; + } + + vector_push_back(body, variable_node); + } + + lexer_next_token(parser->lexer, ¤t_token); + } + + if (current_token.kind != TOKEN_CCURLY) { + parser_error_push_unexpected_kind(parser, ¤t_token, TOKEN_CCURLY); + return false; + } + + ast_node_t *latest_node = vector_at(body, body->size - 1); + + if (latest_node->kind != AST_RETURN_STMT) { + parser_error_t error; + error.token = current_token; + + sprintf( + error.message, + "expected 'return' keyword." + ); + + parser->errors[parser->errors_len++] = error; + return false; + } return true; } @@ -245,19 +324,17 @@ parser_parse_function_declaration(parser_t *parser, ast_node_t *node) return false; } - ast_node_t *return_node = ast_node_new(); + if (!drop_expected_token(parser, TOKEN_OCURLY)) return false; - bool parsed_return = parser_parse_return_stmt(parser, return_node); + vector_t* body = vector_new(); - if (!parsed_return) { - return false; - } + if (!parser_parse_block_declarations(parser, body)) return false; ast_node_init_function_declaration( node, func_name_token.value, return_type, - return_node + body ); return true; -- cgit v1.2.3