diff options
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 232 |
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"); |