aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c232
1 files changed, 187 insertions, 45 deletions
diff --git a/src/parser.c b/src/parser.c
index e36790f..33e9146 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -24,6 +24,8 @@ static CHECK_RESULT Ast* parser_parse_rhs(Parser *self);
static CHECK_RESULT Ast* parser_parse_body(Parser *self);
static CHECK_RESULT Ast* parser_parse_struct_body(Parser *self);
static CHECK_RESULT Ast* parser_parse_rhs_binop(Parser *self);
+static void parser_parse_var_type(Parser *self, VariableType *result);
+static void parser_parse_var_type_def(Parser *self, VariableType *result);
static void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_scope);
int parser_thread_data_init(ParserThreadData *self) {
@@ -133,42 +135,119 @@ static void parser_parse_struct_body_loop(Parser *self, Scope *scope) {
}
/*
-TODO: Implement params and return types
-FUNC_SIGNATURE = 'fn' ('(' ')')?
+FUNC_PARAM = TOK_IDENTIFIER VAR_TYPE_DEF
+*/
+static CHECK_RESULT bool parser_parse_function_parameter(Parser *self, FunctionParameter *result) {
+ bool match;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IDENTIFIER, &match));
+ if(!match)
+ return bool_false;
+
+ result->name = self->tokenizer.value.identifier;
+ parser_parse_var_type_def(self, &result->type);
+ if(result->type.type == VARIABLE_TYPE_NONE) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "Expected ':' after parameter name");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
+
+ return bool_true;
+}
+
+/*
+FUNC_PARAMS = FUNC_PARAM (',' FUNC_PARAM)*
+*/
+static void parser_parse_function_parameters(Parser *self, FunctionSignature *func_sig) {
+ for(;;) {
+ FunctionParameter func_param;
+ bool match;
+ int result;
+
+ function_parameter_init(&func_param);
+ if(!parser_parse_function_parameter(self, &func_param)) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "Expected closure parameter");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
+
+ result = function_signature_add_parameter(func_sig, &func_param);
+ if(result == AST_ERR_DEF_DUP) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_code_reference_index(&self->tokenizer, func_param.name.data),
+ "Parameter with name %.*s was defined twice for the function", func_param.name.size, func_param.name.data);
+ self->error_context = ERROR_CONTEXT_NONE;
+ throw(result);
+ } else if(result != 0) {
+ throw(result);
+ }
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COMMA, &match));
+ if(!match)
+ return;
+ }
+}
+
+/*
+FUNC_RETURN_TYPES = VAR_TYPE (',' VAR_TYPE)*
+*/
+static void parser_parse_function_return_types(Parser *self, FunctionSignature *func_sig) {
+ for(;;) {
+ VariableType var_type;
+ bool match;
+
+ parser_parse_var_type(self, &var_type);
+ if(var_type.type == VARIABLE_TYPE_NONE) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "Expected closure return type");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
+ throw_if_error(function_signature_add_return_type(func_sig, &var_type));
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COMMA, &match));
+ if(!match)
+ return;
+ }
+}
+
+/*
+FUNC_SIGNATURE = 'fn' ('(' FUNC_PARAMS? ') FUNC_RETURN_TYPES? ')?
*/
static CHECK_RESULT FunctionSignature* parser_parse_function_signature(Parser *self) {
FunctionSignature *signature;
bool match;
+ throw_if_error(arena_allocator_alloc(self->allocator, sizeof(FunctionSignature), (void**)&signature));
+ throw_if_error(function_signature_init(signature, self->allocator));
+
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_FN, &match));
if(!match)
return NULL;
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_PAREN, &match));
if(match) {
- /* TODO: Parse parameters */
- throw_if_error(tokenizer_accept(&self->tokenizer, TOK_CLOSING_PAREN));
- /* TODO: Parse return types */
+ bool has_closing_paren;
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_CLOSING_PAREN, &has_closing_paren));
+ if(!has_closing_paren) {
+ parser_parse_function_parameters(self, signature);
+ throw_if_error(tokenizer_accept(&self->tokenizer, TOK_CLOSING_PAREN));
+ }
+ parser_parse_function_return_types(self, signature);
}
- throw_if_error(arena_allocator_alloc(self->allocator, sizeof(FunctionSignature), (void**)&signature));
- function_signature_init(signature);
return signature;
}
/*
-VAR_TYPE_DEF = ':' TOK_IDENTIFIER|FUNC_SIGNATURE
+VAR_TYPE = TOK_IDENTIFIER|FUNC_SIGNATURE
*/
-static void parser_parse_var_type_def(Parser *self, VariableType *result) {
+void parser_parse_var_type(Parser *self, VariableType *result) {
bool match;
result->type = VARIABLE_TYPE_NONE;
result->value.variable = NULL;
- throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COLON, &match));
- if(!match)
- return;
-
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IDENTIFIER, &match));
if(match) {
result->type = VARIABLE_TYPE_VARIABLE;
@@ -181,13 +260,29 @@ static void parser_parse_var_type_def(Parser *self, VariableType *result) {
result->value.signature = parser_parse_function_signature(self);
if(!result->value.signature) {
self->error = tokenizer_create_error(&self->tokenizer,
- tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data),
- "Expected type or closure signature");
+ tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data),
+ "Expected type or closure signature");
throw(PARSER_UNEXPECTED_TOKEN);
}
}
/*
+VAR_TYPE_DEF = ':' VAR_TYPE
+*/
+void parser_parse_var_type_def(Parser *self, VariableType *result) {
+ bool match;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COLON, &match));
+ if(!match) {
+ result->type = VARIABLE_TYPE_NONE;
+ result->value.variable = NULL;
+ return;
+ }
+
+ parser_parse_var_type(self, result);
+}
+
+/*
LHS_DECLARATION = 'extern'? 'pub'? 'const'|'var' TOK_IDENTIFIER VAR_TYPE_DEF?
*/
static CHECK_RESULT LhsExpr* parser_parse_declaration_lhs(Parser *self) {
@@ -263,6 +358,8 @@ static CHECK_RESULT FunctionDecl* parser_parse_closure(Parser *self) {
throw_if_error(arena_allocator_alloc(self->allocator, sizeof(FunctionDecl), (void**)&result));
throw_if_error(funcdecl_init(result, signature, self->current_scope, self->allocator));
+ signature->func_decl = result;
+ result->body.function_signature = signature;
self->current_scope = &result->body;
prev_has_func_parent = self->has_func_parent;
@@ -492,7 +589,7 @@ static CHECK_RESULT Ast* parser_parse_number(Parser *self) {
/*
RHS_S = STRING | NUMBER | FUNC_CALL_OR_VARIABLE
*/
-static Ast* parser_parse_rhs_single_expr(Parser *self) {
+static CHECK_RESULT Ast* parser_parse_rhs_single_expr(Parser *self) {
Ast *result;
bool match;
result = NULL;
@@ -634,21 +731,68 @@ static CHECK_RESULT Ast* parser_parse_conditional(Parser *self) {
}
/*
+LHS_RHS = CLOSURE|STRUCT|IMPORT
+*/
+static Ast* parser_parse_lhs_rhs(Parser *self, LhsExpr *lhs_expr) {
+ Ast *result;
+ FunctionDecl *func_decl;
+ StructDecl *struct_decl;
+ Import *import;
+
+ func_decl = parser_parse_closure(self);
+ if(func_decl) {
+ throw_if_error(ast_create(self->allocator, func_decl, AST_FUNCTION_DECL, &result));
+ func_decl->lhs_expr = lhs_expr;
+ return result;
+ }
+
+ struct_decl = parser_parse_struct_decl(self);
+ if(struct_decl) {
+ throw_if_error(ast_create(self->allocator, struct_decl, AST_STRUCT_DECL, &result));
+ return result;
+ }
+
+ import = parser_parse_import(self);
+ if(import) {
+ parser_queue_file(self, import->path, &import->file_scope);
+ throw_if_error(ast_create(self->allocator, import, AST_IMPORT, &result));
+ parser_parse_body_semicolon(self, result);
+ return result;
+ }
+
+ return NULL;
+}
+
+/*
+RETURN = 'return' RHS
+*/
+static ReturnExpr* parser_parse_return(Parser *self) {
+ bool match;
+ ReturnExpr *result;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_RETURN, &match));
+ if(!match)
+ return NULL;
+
+ throw_if_error(arena_allocator_alloc(self->allocator, sizeof(ReturnExpr), (void**)&result));
+ return_expr_init(result, parser_parse_rhs(self));
+ return result;
+}
+
+/*
BODY = (LHS_DECLARATION ';') |
- (LHS_DECLARATION '=' CLOSURE|STRUCT|IMPORT|(RHS BODY_SEMICOLON)) |
+ (LHS_DECLARATION '=' LHS_RHS|(RHS BODY_SEMICOLON)) |
CONDITIONAL |
(RHS ';'|('=' RHS BODY_SEMICOLON))
*/
Ast* parser_parse_body(Parser *self) {
Ast *result;
LhsExpr *lhs_expr;
+ ReturnExpr *return_expr;
Ast *rhs_expr;
lhs_expr = parser_parse_declaration_lhs(self);
if(lhs_expr) {
- FunctionDecl *func_decl;
- StructDecl *struct_decl;
- Import *import;
bool match;
throw_if_error(ast_create(self->allocator, lhs_expr, AST_LHS, &result));
@@ -675,25 +819,9 @@ Ast* parser_parse_body(Parser *self) {
throw_if_error(tokenizer_accept(&self->tokenizer, TOK_EQUALS));
- func_decl = parser_parse_closure(self);
- if(func_decl) {
- throw_if_error(ast_create(self->allocator, func_decl, AST_FUNCTION_DECL, &lhs_expr->rhs_expr));
- return result;
- }
-
- struct_decl = parser_parse_struct_decl(self);
- if(struct_decl) {
- throw_if_error(ast_create(self->allocator, struct_decl, AST_STRUCT_DECL, &lhs_expr->rhs_expr));
- return result;
- }
-
- import = parser_parse_import(self);
- if(import) {
- parser_queue_file(self, import->path, &import->file_scope);
- throw_if_error(ast_create(self->allocator, import, AST_IMPORT, &lhs_expr->rhs_expr));
- parser_parse_body_semicolon(self, lhs_expr->rhs_expr);
+ lhs_expr->rhs_expr = parser_parse_lhs_rhs(self, lhs_expr);
+ if(lhs_expr->rhs_expr)
return result;
- }
} else {
self->error_context = ERROR_CONTEXT_NO_LHS;
result = parser_parse_conditional(self);
@@ -701,6 +829,15 @@ Ast* parser_parse_body(Parser *self) {
return result;
}
+ if(self->has_func_parent) {
+ return_expr = parser_parse_return(self);
+ if(return_expr) {
+ throw_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON));
+ throw_if_error(ast_create(self->allocator, return_expr, AST_RETURN, &result));
+ return result;
+ }
+ }
+
self->error_context = ERROR_CONTEXT_RHS_STANDALONE;
rhs_expr = parser_parse_rhs(self);
self->error_context = ERROR_CONTEXT_NONE;
@@ -731,22 +868,26 @@ Ast* parser_parse_body(Parser *self) {
}
/*
-STRUCT_BODY = TOK_IDENTIFIER ':' TOK_IDENTIFIER ';'
+STRUCT_BODY = TOK_IDENTIFIER VAR_TYPE_DEF ';'
*/
Ast* parser_parse_struct_body(Parser *self) {
Ast *result;
BufferView var_name;
- BufferView type_name;
+ VariableType var_type;
StructField *struct_field;
throw_if_error(tokenizer_accept(&self->tokenizer, TOK_IDENTIFIER));
var_name = self->tokenizer.value.identifier;
- throw_if_error(tokenizer_accept(&self->tokenizer, TOK_COLON));
- throw_if_error(tokenizer_accept(&self->tokenizer, TOK_IDENTIFIER));
- type_name = self->tokenizer.value.identifier;
+ parser_parse_var_type_def(self, &var_type);
+ if(var_type.type == VARIABLE_TYPE_NONE) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "Expected ':' after struct field name");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
throw_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON));
throw_if_error(arena_allocator_alloc(self->allocator, sizeof(LhsExpr), (void**)&struct_field));
- structfield_init(struct_field, var_name, type_name);
+ structfield_init(struct_field, var_name, &var_type);
throw_if_error(ast_create(self->allocator, struct_field, AST_STRUCT_FIELD, &result));
return result;
}
@@ -767,7 +908,8 @@ int parser_parse_buffer(Parser *self, BufferView code_buffer, BufferView buffer_
tokenizer_print_error_object(&self->tokenizer, &self->error);
break;
case ERROR_CONTEXT_RHS_STANDALONE:
- tokenizer_print_error(&self->tokenizer, self->tokenizer.prev_index, "Expected string, variable, closure, struct, function call or import");
+ /* TODO: Only show "return" in error message if @self->has_func_parent */
+ tokenizer_print_error(&self->tokenizer, self->tokenizer.prev_index, "Expected string, variable, closure, struct, function call, import or return");
break;
case ERROR_CONTEXT_NO_LHS:
tokenizer_print_error(&self->tokenizer, self->tokenizer.prev_index, "Expected variable declaration, string, variable or function call");