summaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c153
1 files changed, 115 insertions, 38 deletions
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, &current_token);
+
+ 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);
+ 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, &current_token);
+ }
+
+ if (current_token.kind != TOKEN_CCURLY) {
+ parser_error_push_unexpected_kind(parser, &current_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;