diff options
author | Carlos Maniero <carlosmaniero@gmail.com> | 2023-04-20 13:32:36 -0300 |
---|---|---|
committer | Johnny Richard <johnny@johnnyrichard.com> | 2023-04-20 18:31:55 +0200 |
commit | 3ceb85bd93fa87a5be3682ab8995abea82a63ea3 (patch) | |
tree | 9512c4255bd87967dfd42a8ca68abd18e34e7407 /src/parser.c | |
parent | a47e5ceb6eefdac9c5f5473e1fee0d33a5f4646e (diff) |
parser: Stop exiting on parser error
Previously, when an error occurred during parsing, the application
would exit, making it difficult to test the parser and limiting the
compiler's extensibility. This commit improves the parser's error
handling by allowing for continued execution after an error, enabling
easier testing and increased flexibility.
The parser is prepared to handle multiples errors, although the
current implementation always returns a single error, it may be
useful given multiples functions where we can show errors by context.
Signed-off-by: Carlos Maniero <carlosmaniero@gmail.com>
Reviwed-by: Johnny Richard <johnny@johnnyrichard.com>
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 138 |
1 files changed, 97 insertions, 41 deletions
diff --git a/src/parser.c b/src/parser.c index b1e6a1f..4646de0 100644 --- a/src/parser.c +++ b/src/parser.c @@ -16,6 +16,7 @@ */ #include <assert.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -30,83 +31,136 @@ parser_init(parser_t *parser, lexer_t *lexer) assert(parser && "parser must be defined"); assert(lexer && "lexer must be defined"); parser->lexer = lexer; + parser->errors_len = 0; } -static token_t -expected_token(parser_t *parser, token_kind_t kind) +static bool +expected_token(token_t *token, parser_t *parser, token_kind_t kind) { - token_t token; - lexer_next_token(parser->lexer, &token); - - if (token.kind == TOKEN_EOF) { - fprintf( - stderr, - "%s:%d:%d: [ERROR]: expected '%s' but got end of file\n", - token.filepath, token.row + 1, token.col + 1, + lexer_next_token(parser->lexer, token); + parser_error_t error; + + if (token->kind == TOKEN_EOF) { + error.token = *token; + sprintf( + error.message, + "expected '%s' but got end of file", token_kind_to_str(kind) ); - exit(EXIT_FAILURE); + + parser->errors[parser->errors_len++] = error; + return false; } - if (token.kind != kind) { - fprintf( - stderr, - "%s:%d:%d: [ERROR]: expected '%s' but got '%s'\n", - token.filepath, token.row + 1, token.col + 1, - token_kind_to_str(kind), token_kind_to_str(token.kind) + 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) ); - exit(EXIT_FAILURE); + parser->errors[parser->errors_len++] = error; + return false; } - return token; + return true; +} + +static bool +drop_expected_token(parser_t *parser, token_kind_t kind) +{ + token_t ignored_token; + return expected_token(&ignored_token, parser, kind); } -static type_t -parser_parse_type(parser_t *parser) +static bool +parser_parse_type(type_t *type, parser_t *parser) { - token_t token = expected_token(parser, TOKEN_NAME); + token_t token; + + if(!expected_token(&token, parser, TOKEN_NAME)) return false; if (string_view_eq(token.value, string_view_from_str("i32"))) { - return TYPE_I32; + *type = TYPE_I32; + return true; } - fprintf(stderr, "[ERROR]: expected type 'i32' but got '"SVFMT"'\n", SVARG(&token.value)); - exit(EXIT_FAILURE); + parser_error_t error; + error.token = token; + + sprintf( + error.message, + "type '"SVFMT"' is not defined", + SVARG(&token.value) + ); + + parser->errors[parser->errors_len++] = error; + return false; } -void +bool parser_parse_return_stmt(parser_t *parser, ast_node_t *node) { - expected_token(parser, TOKEN_OCURLY); - token_t return_keyword_token = expected_token(parser, TOKEN_NAME); + token_t return_keyword_token; + + if (!drop_expected_token(parser, TOKEN_OCURLY)) return false; + + if(!expected_token(&return_keyword_token, parser, TOKEN_NAME)) return false; if (!string_view_eq(return_keyword_token.value, string_view_from_str("return"))) { - // TODO: Add filename:row:col prefix to expected token exceptions - fprintf(stderr, "[ERROR]: expected 'return' keyword but got '"SVFMT"'\n", SVARG(&return_keyword_token.value)); - exit(EXIT_FAILURE); + parser_error_t error; + error.token = return_keyword_token; + + sprintf( + error.message, + "expected 'return' keyword but got '"SVFMT"'", + SVARG(&return_keyword_token.value) + ); + + parser->errors[parser->errors_len++] = error; + return false; } - token_t number_token = expected_token(parser, TOKEN_NUMBER); - expected_token(parser, TOKEN_SEMICOLON); - expected_token(parser, TOKEN_CCURLY); + token_t number_token; + + if (!expected_token(&number_token, parser, TOKEN_NUMBER)) return false; + + if (!drop_expected_token(parser, TOKEN_SEMICOLON)) return false; + if (!drop_expected_token(parser, TOKEN_CCURLY)) return false; char number_as_str[number_token.value.size]; string_view_to_str(&number_token.value, number_as_str); ast_node_init_return_stmt(node, atoi(number_as_str)); + return true; } -void +bool parser_parse_function_declaration(parser_t *parser, ast_node_t *node) { - token_t func_name_token = expected_token(parser, TOKEN_NAME); - expected_token(parser, TOKEN_OPAREN); - expected_token(parser, TOKEN_CPAREN); - expected_token(parser, TOKEN_COLON); - type_t return_type = parser_parse_type(parser); + token_t func_name_token; + + if (!expected_token(&func_name_token, parser, TOKEN_NAME)) { + return false; + } + + if (!drop_expected_token(parser, TOKEN_OPAREN)) return false; + if (!drop_expected_token(parser, TOKEN_CPAREN)) return false; + if (!drop_expected_token(parser, TOKEN_COLON)) return false; + + type_t return_type; + + if(!parser_parse_type(&return_type, parser)) { + return false; + } ast_node_t *return_node = ast_node_new(); - parser_parse_return_stmt(parser, return_node); + + bool parsed_return = parser_parse_return_stmt(parser, return_node); + + if (!parsed_return) { + return false; + } ast_node_init_function_declaration( node, @@ -114,4 +168,6 @@ parser_parse_function_declaration(parser_t *parser, ast_node_t *node) return_type, return_node ); + + return true; } |