summaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
authorCarlos Maniero <carlos@maniero.me>2023-05-08 23:53:42 -0300
committerJohnny Richard <johnny@johnnyrichard.com>2023-05-09 21:46:51 +0200
commit35425aa5837543e4cc3fc82266dc2ae429cb2779 (patch)
tree1d7dec87dc17785162c20206371818f5e28fd99b /src/parser.c
parent3842de0e22d72075f06bd8cc44b8744e86c21725 (diff)
parser: Ensure the expression types
When assign a variable or returning a value it now ensures that the expression matches the expected type. To make this possible a %result_type% field was added to ast_node_t and this field is used whenever to make the comparison. Signed-off-by: Carlos Maniero <carlos@maniero.me> Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c61
1 files changed, 49 insertions, 12 deletions
diff --git a/src/parser.c b/src/parser.c
index 22313a6..7a22f16 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -27,6 +27,9 @@
#include "scope.h"
#include "vector.h"
+static bool
+parser_expression_matches_the_expected_type(parser_t *parser, ast_node_t *expression, type_t type, token_t token);
+
void
parser_init(parser_t *parser, lexer_t *lexer, scope_t *scope)
{
@@ -169,7 +172,8 @@ parser_parse_factor(parser_t *parser)
return NULL;
}
- return ast_node_new_variable(&var_node->data.variable_declaration.identifier);
+ return ast_node_new_variable(&var_node->data.variable_declaration.identifier,
+ var_node->data.variable_declaration.type);
}
default: {
parser_error_t error;
@@ -204,7 +208,7 @@ parser_parse_term(parser_t *parser)
return NULL;
}
- node = ast_node_new_binary_operation(token_to_binary_operation_kind(&token), left, right);
+ node = ast_node_new_binary_operation(token_to_binary_operation_kind(&token), left, right, TYPE_I32);
lexer_peek_next_token(parser->lexer, &token);
}
@@ -242,7 +246,7 @@ parser_parse_expression(parser_t *parser)
return NULL;
}
- node = ast_node_new_binary_operation(token_to_binary_operation_kind(&token), left, right);
+ node = ast_node_new_binary_operation(token_to_binary_operation_kind(&token), left, right, TYPE_I32);
lexer_peek_next_token(parser->lexer, &token);
}
@@ -251,23 +255,29 @@ parser_parse_expression(parser_t *parser)
}
static ast_node_t *
-parser_parse_return_stmt(parser_t *parser)
+parser_parse_return_stmt(parser_t *parser, type_t result_type)
{
- if (!drop_expected_token(parser, TOKEN_KEYWORD_RETURN)) {
+ token_t token;
+ if (!expected_token(&token, parser, TOKEN_KEYWORD_RETURN)) {
return NULL;
}
- ast_node_t *argument_token = parser_parse_expression(parser);
- if (argument_token == NULL) {
+ ast_node_t *expression = parser_parse_expression(parser);
+ if (expression == NULL) {
return NULL;
}
if (!drop_expected_token(parser, TOKEN_SEMICOLON)) {
- ast_node_destroy(argument_token);
+ ast_node_destroy(expression);
+ return NULL;
+ }
+
+ if (!parser_expression_matches_the_expected_type(parser, expression, result_type, token)) {
+ ast_node_destroy(expression);
return NULL;
}
- return ast_node_new_return_stmt(argument_token);
+ return ast_node_new_return_stmt(expression);
}
static ast_node_t *
@@ -307,9 +317,31 @@ parser_parse_variable_assignment(parser_t *parser)
assert(variable_declaration_node->kind == AST_VARIABLE_DECLARATION);
+ if (!parser_expression_matches_the_expected_type(
+ parser, expression, variable_declaration_node->data.variable_declaration.type, variable_token)) {
+ ast_node_destroy(expression);
+ return false;
+ }
+
return ast_node_new_variable_assignment(&variable_declaration_node->data.variable_declaration.identifier, expression);
}
+static bool
+parser_expression_matches_the_expected_type(parser_t *parser, ast_node_t *expression, type_t type, token_t token)
+{
+ if (expression->result_type != type) {
+ parser_error_t error;
+ error.token = token;
+ sprintf(error.message,
+ "incompatible types: expected '%s', actual '%s'.",
+ ast_type_to_str(type),
+ ast_type_to_str(expression->result_type));
+ parser->errors[parser->errors_len++] = error;
+ return false;
+ }
+ return true;
+}
+
static ast_node_t *
parser_parse_variable_declaration(parser_t *parser)
{
@@ -348,6 +380,11 @@ parser_parse_variable_declaration(parser_t *parser)
return NULL;
}
+ if (!parser_expression_matches_the_expected_type(parser, expression, type, variable_name)) {
+ ast_node_destroy(expression);
+ return NULL;
+ }
+
ast_node_t *node = ast_node_new_variable_declaration(variable_name.value, type, expression);
scope_push(parser->scope, &node->data.variable_declaration.identifier, node);
@@ -426,7 +463,7 @@ parser_ensure_function_return_statement(parser_t *parser, vector_t *body, token_
}
static vector_t *
-parser_parse_block_declarations(parser_t *parser)
+parser_parse_block_declarations(parser_t *parser, type_t result_type)
{
if (!drop_expected_token(parser, TOKEN_OCURLY)) {
return NULL;
@@ -441,7 +478,7 @@ parser_parse_block_declarations(parser_t *parser)
while (!is_block_end(parser)) {
if (is_next_statement_return(parser)) {
- ast_node_t *return_node = parser_parse_return_stmt(parser);
+ ast_node_t *return_node = parser_parse_return_stmt(parser, result_type);
if (return_node == NULL) {
scope_leave(parser->scope);
@@ -529,7 +566,7 @@ parser_parse_function_declaration(parser_t *parser)
return NULL;
}
- vector_t *body = parser_parse_block_declarations(parser);
+ vector_t *body = parser_parse_block_declarations(parser, return_type);
if (body == NULL) {
return NULL;