aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-06-07 10:47:47 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commit53a331bc8b2fc33bd2b7e25a23b4128f89ee0b52 (patch)
tree2e5c0f4cda85b2afdb6142145fa7ded61d100f02 /src/parser.c
parent1b68fdcf5aebf2bc53bbd9234c77aea243c0decd (diff)
Add assignment, while, extern, function signature type, start on bytecode
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c392
1 files changed, 277 insertions, 115 deletions
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);