From 53a331bc8b2fc33bd2b7e25a23b4128f89ee0b52 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 7 Jun 2019 10:47:47 +0200 Subject: Add assignment, while, extern, function signature type, start on bytecode --- src/parser.c | 392 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 277 insertions(+), 115 deletions(-) (limited to 'src/parser.c') diff --git a/src/parser.c b/src/parser.c index f05b31d..c0d2c6d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -20,9 +20,10 @@ do { \ throw(return_if_result); \ } while(0) -static CHECK_RESULT Ast* parser_parse_rhs_start(Parser *self, bool is_standalone); +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_queue_file(Parser *self, BufferView path, FileScopeReference **file_scope); int parser_thread_data_init(ParserThreadData *self) { @@ -61,7 +62,7 @@ int parser_init(Parser *self, amal_compiler *compiler, ScopedAllocator *allocato self->error_context = ERROR_CONTEXT_NONE; return_if_error(structdecl_init(&self->struct_decl, &compiler->root_scope, allocator)); self->struct_decl.body.parser = self; - return_if_error(lhsexpr_init(&self->file_decl, bool_true, bool_true, create_buffer_view_null(), self->allocator)); + return_if_error(lhsexpr_init(&self->file_decl, bool_true, bool_true, bool_true, create_buffer_view_null(), self->allocator)); return_if_error(ast_create(self->allocator, &self->struct_decl, AST_STRUCT_DECL, &self->file_decl.rhs_expr)); self->current_scope = &self->struct_decl.body; self->has_func_parent = bool_false; @@ -132,30 +133,78 @@ static void parser_parse_struct_body_loop(Parser *self, Scope *scope) { } /* -VAR_TYPE_DEF = ':' TOK_IDENTIFIER +TODO: Implement params and return types +FUNC_SIGNATURE = 'fn' ('(' ')')? */ -static void parser_parse_var_type_def(Parser *self, BufferView *type_name) { +static CHECK_RESULT FunctionSignature* parser_parse_function_signature(Parser *self) { + FunctionSignature *signature; bool match; + + 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 */ + } + + throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(FunctionSignature), (void**)&signature)); + signature->params = 0; + return signature; +} + +/* +VAR_TYPE_DEF = ':' TOK_IDENTIFIER|FUNC_SIGNATURE +*/ +static CHECK_RESULT int parser_parse_var_type_def(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 -1; + + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IDENTIFIER, &match)); if(match) { - throw_if_error(tokenizer_accept(&self->tokenizer, TOK_IDENTIFIER)); - *type_name = self->tokenizer.value.identifier; + result->type = VARIABLE_TYPE_VARIABLE; + throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(Variable), (void**)&result->value.variable)); + variable_init(result->value.variable, self->tokenizer.value.identifier); + return 0; + } + + result->type = VARIABLE_TYPE_SIGNATURE; + 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"); + throw(PARSER_UNEXPECTED_TOKEN); } + return 0; } /* -LHS = ('pub'? 'const' TOK_IDENTIFIER VAR_TYPE_DEF? '=') | - ('pub'? 'var' TOK_IDENTIFIER VAR_TYPE_DEF? '='|';') +LHS_DECLARATION = 'extern'? 'pub'? 'const'|'var' TOK_IDENTIFIER VAR_TYPE_DEF? */ -static CHECK_RESULT LhsExpr* parser_parse_lhs(Parser *self, bool *assignment_or_rhs) { +static CHECK_RESULT LhsExpr* parser_parse_declaration_lhs(Parser *self) { LhsExpr *result; + bool is_extern; bool is_pub; bool is_const; - bool match; BufferView var_name; - result = NULL; - *assignment_or_rhs = bool_true; + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_EXTERN, &is_extern)); + if(is_extern && self->has_func_parent) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data), + "Only declarations in structs can be extern"); + throw(PARSER_UNEXPECTED_TOKEN); + } throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_PUB, &is_pub)); if(is_pub && self->has_func_parent) { @@ -168,77 +217,48 @@ static CHECK_RESULT LhsExpr* parser_parse_lhs(Parser *self, bool *assignment_or_ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_CONST, &is_const)); if(!is_const) { bool isVar; + + if(is_extern) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_code_reference_index(&self->tokenizer, self->tokenizer.value.identifier.data), + "Extern variable have to be declared with \"const\""); + throw(PARSER_UNEXPECTED_TOKEN); + } + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_VAR, &isVar)); if(!isVar) - return result; + return NULL; } throw_if_error(tokenizer_accept(&self->tokenizer, TOK_IDENTIFIER)); var_name = self->tokenizer.value.identifier; throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(LhsExpr), (void**)&result)); - throw_if_error(lhsexpr_init(result, is_pub, is_const, var_name, self->allocator)); - - parser_parse_var_type_def(self, &result->type.name); - - throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_EQUALS, &match)); - if(match) { - *assignment_or_rhs = bool_true; - return result; - } + throw_if_error(lhsexpr_init(result, is_extern, is_pub, is_const, var_name, self->allocator)); - if(!result->type.name.data) { - self->error = tokenizer_create_error(&self->tokenizer, - tokenizer_get_error_index(&self->tokenizer), - "Variable declaration requires type or right-hand side expression (Expected ':' or '=')"); - throw(PARSER_UNEXPECTED_TOKEN); - } - - *assignment_or_rhs = bool_false; - throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_SEMICOLON, &match)); - if(match && is_const) { - self->error = tokenizer_create_error(&self->tokenizer, - tokenizer_get_error_index(&self->tokenizer), - "Const variable declaration requires assignment (expected '=', got ';')"); - throw(PARSER_UNEXPECTED_TOKEN); - } - if(!match) { - self->error = tokenizer_create_error(&self->tokenizer, - tokenizer_get_error_index(&self->tokenizer), - "Expected ';'"); - throw(PARSER_UNEXPECTED_TOKEN); - } + ignore_result_int(parser_parse_var_type_def(self, &result->type)); return result; } /* -TODO: Implement params and return types -CLOSURE = 'fn' ('(' PARAM? (',' PARAM)* ')')? '{' BODY_LOOP '}' + +CLOSURE = FUNC_SIGNATURE '{' BODY_LOOP '}' */ static CHECK_RESULT FunctionDecl* parser_parse_closure(Parser *self) { + FunctionSignature *signature; FunctionDecl *result; - bool match; bool prev_has_func_parent; - result = NULL; - throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_FN, &match)); - if(!match) - return result; - - throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_BRACE, &match)); - if(!match) { - throw_if_error(tokenizer_accept(&self->tokenizer, TOK_OPEN_PAREN)); - /* TODO: Parse parameters */ - throw_if_error(tokenizer_accept(&self->tokenizer, TOK_CLOSING_PAREN)); - /* TODO: Parse return types */ - throw_if_error(tokenizer_accept(&self->tokenizer, TOK_OPEN_BRACE)); - } + signature = parser_parse_function_signature(self); + if(!signature) + return NULL; throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(FunctionDecl), (void**)&result)); - throw_if_error(funcdecl_init(result, self->current_scope, self->allocator)); + throw_if_error(funcdecl_init(result, signature, self->current_scope, self->allocator)); self->current_scope = &result->body; prev_has_func_parent = self->has_func_parent; self->has_func_parent = bool_true; + throw_if_error(tokenizer_accept(&self->tokenizer, TOK_OPEN_BRACE)); parser_parse_body_loop(self, self->current_scope, TOK_CLOSING_BRACE); self->current_scope = result->body.parent; self->has_func_parent = prev_has_func_parent; @@ -286,14 +306,14 @@ static void parser_parse_function_args(Parser *self, FunctionCall *func_call) { throw_if_error(tokenizer_accept(&self->tokenizer, TOK_COMMA)); first_arg = bool_false; - arg_expr = parser_parse_rhs_start(self, bool_false); + arg_expr = parser_parse_rhs(self); throw_if_error(buffer_append(&func_call->args, &arg_expr, sizeof(arg_expr))); } } /* VARIABLE = TOK_IDENTIFIER -FUNC_CALL_OR_VARIABLE = VARIABLE '(' FUNC_ARGS ')' +FUNC_CALL_OR_VARIABLE = VARIABLE ('(' FUNC_ARGS ')')? */ static CHECK_RESULT Ast* parser_parse_function_call_or_variable(Parser *self) { Ast *result; @@ -319,6 +339,7 @@ static CHECK_RESULT Ast* parser_parse_function_call_or_variable(Parser *self) { throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(FunctionCall), (void**)&func_call)); throw_if_error(funccall_init(func_call, self->tokenizer.value.identifier, self->allocator)); throw_if_error(ast_create(self->allocator, func_call, AST_FUNCTION_CALL, &result)); + /* Ends after TOK_CLOSING_PAREN */ parser_parse_function_args(self, func_call); return result; } @@ -340,6 +361,109 @@ static CHECK_RESULT Import* parser_parse_import(Parser *self) { return result; } +/* +ELSE_IF_STATEMENT = 'else' ('if' RHS_BINOP)? ('{' BODY_LOOP '}')|BODY +*/ +static CHECK_RESULT ElseIfStatement* parser_parse_else_if_statement(Parser *self) { + ElseIfStatement *result; + bool match; + + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_ELSE, &match)); + if(!match) + return NULL; + + throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(ElseIfStatement), (void**)&result)); + throw_if_error(else_if_statement_init(result, self->current_scope, self->allocator)); + + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IF, &match)); + if(match) + result->condition = parser_parse_rhs_binop(self); + + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_BRACE, &match)); + if(match) { + parser_parse_body_loop(self, &result->body, TOK_CLOSING_BRACE); + } else { + Ast *body_obj; + body_obj = parser_parse_body(self); + throw_if_error(scope_add_child(&result->body, body_obj)); + } + + return result; +} + +static void parser_parse_else_if_statement_loop(Parser *self, IfStatement *if_stmt) { + ElseIfStatement *else_if_stmt; + else_if_stmt = if_stmt->else_if_stmt; + for(;;) { + ElseIfStatement *next_else_if; + next_else_if = parser_parse_else_if_statement(self); + if(!next_else_if) + break; + else_if_stmt->next_else_if_stmt = next_else_if; + /* else statement, which because they have no conditions; can't be followed by another else statement */ + if(!else_if_stmt->condition) + break; + else_if_stmt = next_else_if; + } +} + +/* +IF_STATEMENT = 'if' RHS_BINOP ('{' BODY_LOOP '}')|BODY ELSE_IF_STATEMENT* +*/ +static CHECK_RESULT IfStatement* parser_parse_if_statement(Parser *self) { + IfStatement *result; + bool match; + + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IF, &match)); + if(!match) + return NULL; + + throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(IfStatement), (void**)&result)); + throw_if_error(if_statement_init(result, self->current_scope, self->allocator)); + + result->condition = parser_parse_rhs_binop(self); + + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_BRACE, &match)); + if(match) { + parser_parse_body_loop(self, &result->body, TOK_CLOSING_BRACE); + } else { + Ast *body_obj; + body_obj = parser_parse_body(self); + throw_if_error(scope_add_child(&result->body, body_obj)); + } + + parser_parse_else_if_statement_loop(self, result); + return result; +} + +/* +WHILE_STATEMENT = 'while' RHS_BINOP ('{' BODY_LOOP '}')|BODY +*/ +static CHECK_RESULT WhileStatement* parser_parse_while_statement(Parser *self) { + WhileStatement *result; + bool match; + + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_WHILE, &match)); + if(!match) + return NULL; + + throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(WhileStatement), (void**)&result)); + throw_if_error(while_statement_init(result, self->current_scope, self->allocator)); + + result->condition = parser_parse_rhs_binop(self); + + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_BRACE, &match)); + if(match) { + parser_parse_body_loop(self, &result->body, TOK_CLOSING_BRACE); + } else { + Ast *body_obj; + body_obj = parser_parse_body(self); + throw_if_error(scope_add_child(&result->body, body_obj)); + } + + return result; +} + static CHECK_RESULT Ast* parser_parse_number(Parser *self) { Ast *result; bool match; @@ -388,8 +512,6 @@ static Ast* parser_parse_rhs_single_expr(Parser *self) { throw(PARSER_UNEXPECTED_TOKEN); } -static CHECK_RESULT Ast* parser_parse_rhs_binop(Parser *self); - /* RHS_BINOP_OPT_PAREN = RHS_S | '(' RHS_BINOP ')' */ @@ -442,7 +564,7 @@ RHS = RHS_BINOP ';' Note: Parantheses count has to match for the beginning paranthesis and the ending parenthesis. */ -static CHECK_RESULT Ast* parser_parse_rhs(Parser *self) { +Ast* parser_parse_rhs(Parser *self) { /* TODO: If binop only contains one expression, then use that directly for @rhs_expr */ Ast *result; result = parser_parse_rhs_binop(self); @@ -452,41 +574,9 @@ static CHECK_RESULT Ast* parser_parse_rhs(Parser *self) { return result; } -/* -RHS_START = CLOSURE | IMPORT | RHS -*/ -Ast* parser_parse_rhs_start(Parser *self, bool is_standalone) { - Ast *result; - - if(!is_standalone) { - 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)); - 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)); - return result; - } - self->error_context = ERROR_CONTEXT_RHS_STANDALONE; - } - - result = parser_parse_rhs(self); - self->error_context = ERROR_CONTEXT_NONE; - return result; +static bool type_requires_semicolon_at_end(AstType type) { + /* TODO: Check for tables */ + return type != AST_FUNCTION_DECL && type != AST_STRUCT_DECL && type != AST_IF_STATEMENT; } /* @@ -508,37 +598,109 @@ static void parser_parse_body_semicolon(Parser *self, Ast *expr) { return; } - /* TODO: Check for tables */ - if(expr->type != AST_FUNCTION_DECL && expr->type != AST_STRUCT_DECL) + if(type_requires_semicolon_at_end(expr->type)) throw_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON)); } +/* CONDITIONAL = (IF_STATEMENT|WHILE_STATEMENT)? */ +static CHECK_RESULT Ast* parser_parse_conditional(Parser *self) { + Ast *result; + IfStatement *if_stmt; + WhileStatement *while_stmt; + + if_stmt = parser_parse_if_statement(self); + if(if_stmt) { + throw_if_error(ast_create(self->allocator, if_stmt, AST_IF_STATEMENT, &result)); + self->error_context = ERROR_CONTEXT_NONE; + return result; + } + + while_stmt = parser_parse_while_statement(self); + if(while_stmt) { + throw_if_error(ast_create(self->allocator, while_stmt, AST_WHILE_STATEMENT, &result)); + self->error_context = ERROR_CONTEXT_NONE; + return result; + } + + return NULL; +} + /* -BODY = LHS ';' | - (LHS '=' RHS_START BODY_SEMICOLON) | - (RHS_START BODY_SEMICOLON) +BODY = (LHS_DECLARATION ';') | + (LHS_DECLARATION '=' CLOSURE|STRUCT|IMPORT|(RHS BODY_SEMICOLON)) | + CONDITIONAL | + (RHS ';'|('=' RHS BODY_SEMICOLON)) */ Ast* parser_parse_body(Parser *self) { - bool assignment_or_rhs; Ast *result; LhsExpr *lhs_expr; Ast *rhs_expr; - lhs_expr = parser_parse_lhs(self, &assignment_or_rhs); - if(!assignment_or_rhs) { + lhs_expr = parser_parse_declaration_lhs(self); + if(lhs_expr) { + bool match; throw_if_error(ast_create(self->allocator, lhs_expr, AST_LHS, &result)); - return result; - } - - if(!lhs_expr) + if(lhs_expr->is_extern) { + throw_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON)); + return result; + } else { + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_SEMICOLON, &match)); + if(match) + return result; + } + + throw_if_error(tokenizer_accept(&self->tokenizer, TOK_EQUALS)); + + 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, &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); + return result; + } + } else { self->error_context = ERROR_CONTEXT_NO_LHS; + result = parser_parse_conditional(self); + if(result) + return result; + } - rhs_expr = parser_parse_rhs_start(self, !lhs_expr); + self->error_context = ERROR_CONTEXT_RHS_STANDALONE; + rhs_expr = parser_parse_rhs(self); + self->error_context = ERROR_CONTEXT_NONE; if(lhs_expr) { lhs_expr->rhs_expr = rhs_expr; - throw_if_error(ast_create(self->allocator, lhs_expr, AST_LHS, &result)); } else { - result = rhs_expr; + bool match; + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_EQUALS, &match)); + if(match) { + AssignmentExpr *assign_expr; + throw_if_error(scoped_allocator_alloc(self->allocator, sizeof(AssignmentExpr), (void**)&assign_expr)); + throw_if_error(ast_create(self->allocator, assign_expr, AST_ASSIGN, &result)); + assign_expr->lhs_expr = rhs_expr; + + self->error_context = ERROR_CONTEXT_RHS_STANDALONE; + assign_expr->rhs_expr = parser_parse_rhs(self); + self->error_context = ERROR_CONTEXT_NONE; + } else { + result = rhs_expr; + } } parser_parse_body_semicolon(self, rhs_expr); -- cgit v1.2.3