diff options
Diffstat (limited to 'src/parser.cpp')
| -rw-r--r-- | src/parser.cpp | 374 |
1 files changed, 176 insertions, 198 deletions
diff --git a/src/parser.cpp b/src/parser.cpp index 2deac0b2d..4a5a8d63e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,6 +1,4 @@ struct AstNode; -struct Type; -struct AstScope; enum ParseFileError { ParseFile_None, @@ -30,8 +28,6 @@ struct AstFile { AstNode *decls; isize decl_count; - AstScope *file_scope; - AstScope *curr_scope; AstNode *curr_proc; isize scope_level; @@ -43,19 +39,6 @@ struct AstFile { TokenPos fix_prev_pos; }; -// NOTE(bill): Just used to quickly check if there is double declaration in the same scope -// No type checking actually happens -// TODO(bill): Should this be completely handled in the semantic checker or is it better here? -struct AstEntity { - Token token; - AstScope *parent; - AstNode * decl; -}; - -struct AstScope { - AstScope *parent; - Map<AstEntity> entities; // Key: Token.string -}; struct Parser { String init_fullpath; @@ -91,12 +74,9 @@ enum CallExprKind { }; #define AST_NODE_KINDS \ - AST_NODE_KIND(Invalid, "invalid node", struct{}) \ + AST_NODE_KIND(Invalid, "invalid node", struct{}) \ AST_NODE_KIND(BasicLit, "basic literal", Token) \ - AST_NODE_KIND(Ident, "identifier", struct { \ - Token token; \ - AstEntity *entity; \ - }) \ + AST_NODE_KIND(Ident, "identifier", Token) \ AST_NODE_KIND(ProcLit, "procedure literal", struct { \ AstNode *type; \ AstNode *body; \ @@ -170,6 +150,17 @@ AST_NODE_KIND(_ComplexStmtBegin, "", struct{}) \ AstNode *init, *cond, *post; \ AstNode *body; \ }) \ + AST_NODE_KIND(CaseClause, "case clause", struct { \ + Token token; \ + AstNode *list; \ + AstNode *stmts; \ + isize list_count, stmt_count; \ + }) \ + AST_NODE_KIND(MatchStmt, "match statement", struct { \ + Token token; \ + AstNode *init, *tag; \ + AstNode *body; \ + }) \ AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \ AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; }) \ AST_NODE_KIND(UsingStmt, "using statement", struct { Token token; AstNode *node; }) \ @@ -232,7 +223,7 @@ AST_NODE_KIND(_TypeBegin, "", struct{}) \ isize decl_count; \ b32 is_packed; \ }) \ - AST_NODE_KIND(UnionType, "union type", struct { \ + AST_NODE_KIND(RawUnionType, "raw union type", struct { \ Token token; \ AstNode *decl_list; \ isize decl_count; \ @@ -276,15 +267,6 @@ struct AstNode { - -gb_inline AstScope *make_ast_scope(AstFile *f, AstScope *parent) { - AstScope *scope = gb_alloc_item(gb_arena_allocator(&f->arena), AstScope); - map_init(&scope->entities, gb_heap_allocator()); - scope->parent = parent; - return scope; -} - - gb_inline b32 is_ast_node_expr(AstNode *node) { return gb_is_between(node->kind, AstNode__ExprBegin+1, AstNode__ExprEnd-1); } @@ -307,7 +289,7 @@ Token ast_node_token(AstNode *node) { case AstNode_BasicLit: return node->BasicLit; case AstNode_Ident: - return node->Ident.token; + return node->Ident; case AstNode_ProcLit: return ast_node_token(node->ProcLit.type); case AstNode_CompoundLit: @@ -356,6 +338,10 @@ Token ast_node_token(AstNode *node) { return node->ReturnStmt.token; case AstNode_ForStmt: return node->ForStmt.token; + case AstNode_MatchStmt: + return node->MatchStmt.token; + case AstNode_CaseClause: + return node->CaseClause.token; case AstNode_DeferStmt: return node->DeferStmt.token; case AstNode_BranchStmt: @@ -367,7 +353,7 @@ Token ast_node_token(AstNode *node) { case AstNode_VarDecl: return ast_node_token(node->VarDecl.name_list); case AstNode_ProcDecl: - return node->ProcDecl.name->Ident.token; + return node->ProcDecl.name->Ident; case AstNode_TypeDecl: return node->TypeDecl.token; case AstNode_LoadDecl: @@ -390,66 +376,19 @@ Token ast_node_token(AstNode *node) { return node->VectorType.token; case AstNode_StructType: return node->StructType.token; - case AstNode_UnionType: - return node->UnionType.token; + case AstNode_RawUnionType: + return node->RawUnionType.token; case AstNode_EnumType: return node->EnumType.token; } return empty_token; -;} - -gb_inline void destroy_ast_scope(AstScope *scope) { - // NOTE(bill): No need to free the actual pointer to the AstScope - // as there should be enough room in the arena - map_destroy(&scope->entities); -} - -gb_inline AstScope *open_ast_scope(AstFile *f) { - AstScope *scope = make_ast_scope(f, f->curr_scope); - f->curr_scope = scope; - f->scope_level++; - return f->curr_scope; -} - -gb_inline void close_ast_scope(AstFile *f) { - GB_ASSERT_NOT_NULL(f->curr_scope); - GB_ASSERT(f->scope_level > 0); - { - AstScope *parent = f->curr_scope->parent; - if (f->curr_scope) { - destroy_ast_scope(f->curr_scope); - } - f->curr_scope = parent; - f->scope_level--; - } -} - -AstEntity *make_ast_entity(AstFile *f, Token token, AstNode *decl, AstScope *parent) { - AstEntity *entity = gb_alloc_item(gb_arena_allocator(&f->arena), AstEntity); - entity->token = token; - entity->decl = decl; - entity->parent = parent; - return entity; } HashKey hash_token(Token t) { return hash_string(t.string); } -AstEntity *ast_scope_lookup(AstScope *scope, Token token) { - return map_get(&scope->entities, hash_token(token)); -} - -AstEntity *ast_scope_insert(AstScope *scope, AstEntity entity) { - AstEntity *prev = ast_scope_lookup(scope, entity.token); - if (prev == NULL) { - map_set(&scope->entities, hash_token(entity.token), entity); - } - return prev; -} - - #define ast_file_err(f, token, fmt, ...) ast_file_err_(f, __FUNCTION__, token, fmt, ##__VA_ARGS__) void ast_file_err_(AstFile *file, char *function, Token token, char *fmt, ...) { // NOTE(bill): Duplicate error, skip it @@ -598,10 +537,9 @@ gb_inline AstNode *make_basic_lit(AstFile *f, Token basic_lit) { return result; } -gb_inline AstNode *make_ident(AstFile *f, Token token, AstEntity *entity = NULL) { +gb_inline AstNode *make_ident(AstFile *f, Token token) { AstNode *result = make_node(f, AstNode_Ident); - result->Ident.token = token; - result->Ident.entity = entity; + result->Ident = token; return result; } @@ -698,12 +636,34 @@ gb_inline AstNode *make_return_stmt(AstFile *f, Token token, AstNode *result_lis gb_inline AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) { AstNode *result = make_node(f, AstNode_ForStmt); result->ForStmt.token = token; - result->ForStmt.init = init; - result->ForStmt.cond = cond; - result->ForStmt.post = post; - result->ForStmt.body = body; + result->ForStmt.init = init; + result->ForStmt.cond = cond; + result->ForStmt.post = post; + result->ForStmt.body = body; return result; } + + +gb_inline AstNode *make_match_stmt(AstFile *f, Token token, AstNode *init, AstNode *tag, AstNode *body) { + AstNode *result = make_node(f, AstNode_MatchStmt); + result->MatchStmt.token = token; + result->MatchStmt.init = init; + result->MatchStmt.tag = tag; + result->MatchStmt.body = body; + return result; +} + +gb_inline AstNode *make_case_clause(AstFile *f, Token token, AstNode *list, isize list_count, AstNode *stmts, isize stmt_count) { + AstNode *result = make_node(f, AstNode_CaseClause); + result->CaseClause.token = token; + result->CaseClause.list = list; + result->CaseClause.list_count = list_count; + result->CaseClause.stmts = stmts; + result->CaseClause.stmt_count = stmt_count; + return result; +} + + gb_inline AstNode *make_defer_stmt(AstFile *f, Token token, AstNode *stmt) { AstNode *result = make_node(f, AstNode_DeferStmt); result->DeferStmt.token = token; @@ -804,11 +764,11 @@ gb_inline AstNode *make_struct_type(AstFile *f, Token token, AstNode *decl_list, return result; } -gb_inline AstNode *make_union_type(AstFile *f, Token token, AstNode *decl_list, isize decl_count) { - AstNode *result = make_node(f, AstNode_UnionType); - result->UnionType.token = token; - result->UnionType.decl_list = decl_list; - result->UnionType.decl_count = decl_count; +gb_inline AstNode *make_raw_union_type(AstFile *f, Token token, AstNode *decl_list, isize decl_count) { + AstNode *result = make_node(f, AstNode_RawUnionType); + result->RawUnionType.token = token; + result->RawUnionType.decl_list = decl_list; + result->RawUnionType.decl_count = decl_count; return result; } @@ -902,30 +862,6 @@ b32 is_blank_ident(String str) { return false; } -gb_internal void add_ast_entity(AstFile *f, AstScope *scope, AstNode *declaration, AstNode *name_list) { - for (AstNode *n = name_list; n != NULL; n = n->next) { - if (n->kind != AstNode_Ident) { - ast_file_err(f, ast_node_token(declaration), "Identifier is already declared or resolved"); - continue; - } - - AstEntity *entity = make_ast_entity(f, n->Ident.token, declaration, scope); - n->Ident.entity = entity; - - AstEntity *insert_entity = ast_scope_insert(scope, *entity); - if (insert_entity != NULL && !is_blank_ident(insert_entity->token.string)) { - ast_file_err(f, entity->token, - "There is already a previous declaration of `%.*s` in the current scope\n" - "at \t%.*s(%td:%td)", - LIT(insert_entity->token.string), - LIT(insert_entity->token.pos.file), - insert_entity->token.pos.line, - insert_entity->token.pos.column); - } - } -} - - void fix_advance_to_next_stmt(AstFile *f) { // TODO(bill): fix_advance_to_next_stmt @@ -994,10 +930,10 @@ b32 expect_semicolon_after_stmt(AstFile *f, AstNode *s) { AstNode *parse_expr(AstFile *f, b32 lhs); -AstNode *parse_proc_type(AstFile *f, AstScope **scope_); +AstNode *parse_proc_type(AstFile *f); AstNode *parse_stmt_list(AstFile *f, isize *list_count_); AstNode *parse_stmt(AstFile *f); -AstNode *parse_body(AstFile *f, AstScope *scope); +AstNode *parse_body(AstFile *f); AstNode *parse_identifier(AstFile *f) { Token token = f->cursor[0]; @@ -1218,9 +1154,8 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { // Parse Procedure Type or Literal case Token_proc: { - AstScope *scope = NULL; AstNode *curr_proc = f->curr_proc; - AstNode *type = parse_proc_type(f, &scope); + AstNode *type = parse_proc_type(f); f->curr_proc = type; defer (f->curr_proc = curr_proc); @@ -1235,13 +1170,10 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { return type; } else { AstNode *body; - AstScope *curr_scope = f->curr_scope; - f->curr_scope = scope; f->expr_level++; - body = parse_body(f, scope); + body = parse_body(f); f->expr_level--; - f->curr_scope = curr_scope; return make_proc_lit(f, type, body, tags); } @@ -1538,7 +1470,7 @@ AstNode *parse_simple_stmt(AstFile *f) { case Token_CmpAndEq: case Token_CmpOrEq: { - if (f->curr_scope == f->file_scope) { + if (f->curr_proc == NULL) { ast_file_err(f, f->cursor[0], "You cannot use a simple statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -1566,7 +1498,7 @@ AstNode *parse_simple_stmt(AstFile *f) { switch (token.kind) { case Token_Increment: case Token_Decrement: - if (f->curr_scope == f->file_scope) { + if (f->curr_proc == NULL) { ast_file_err(f, f->cursor[0], "You cannot use a simple statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -1581,15 +1513,11 @@ AstNode *parse_simple_stmt(AstFile *f) { AstNode *parse_block_stmt(AstFile *f) { - if (f->curr_scope == f->file_scope) { + if (f->curr_proc == NULL) { ast_file_err(f, f->cursor[0], "You cannot use a block statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } - AstNode *block_stmt; - - open_ast_scope(f); - block_stmt = parse_body(f, f->curr_scope); - close_ast_scope(f); + AstNode *block_stmt = parse_body(f); return block_stmt; } @@ -1644,7 +1572,7 @@ AstNode *parse_type(AstFile *f) { return type; } -AstNode *parse_field_decl(AstFile *f, AstScope *scope, b32 allow_using) { +AstNode *parse_field_decl(AstFile *f, b32 allow_using) { b32 is_using = false; AstNode *name_list = NULL; isize name_count = 0; @@ -1670,29 +1598,26 @@ AstNode *parse_field_decl(AstFile *f, AstScope *scope, b32 allow_using) { ast_file_err(f, f->cursor[0], "Expected a type for this field declaration"); AstNode *field = make_field(f, name_list, name_count, type, is_using); - add_ast_entity(f, scope, field, name_list); return field; } -Token parse_procedure_signature(AstFile *f, AstScope *scope, +Token parse_procedure_signature(AstFile *f, AstNode **param_list, isize *param_count, AstNode **result_list, isize *result_count); -AstNode *parse_proc_type(AstFile *f, AstScope **scope_) { - AstScope *scope = make_ast_scope(f, f->file_scope); // Procedure's scope +AstNode *parse_proc_type(AstFile *f) { AstNode *params = NULL; AstNode *results = NULL; isize param_count = 0; isize result_count = 0; - Token proc_token = parse_procedure_signature(f, scope, ¶ms, ¶m_count, &results, &result_count); + Token proc_token = parse_procedure_signature(f, ¶ms, ¶m_count, &results, &result_count); - if (scope_) *scope_ = scope; return make_proc_type(f, proc_token, params, param_count, results, result_count); } -AstNode *parse_parameter_list(AstFile *f, AstScope *scope, isize *param_count_, TokenKind separator, b32 allow_using) { +AstNode *parse_parameter_list(AstFile *f, isize *param_count_, TokenKind separator, b32 allow_using) { AstNode *param_list = NULL; AstNode *param_list_curr = NULL; isize param_count = 0; @@ -1701,7 +1626,7 @@ AstNode *parse_parameter_list(AstFile *f, AstScope *scope, isize *param_count_, if (!allow_using && allow_token(f, Token_using)) { ast_file_err(f, f->cursor[-1], "`using` is only allowed within structures (at the moment)"); } - AstNode *field = parse_field_decl(f, scope, allow_using); + AstNode *field = parse_field_decl(f, allow_using); DLIST_APPEND(param_list, param_list_curr, field); param_count += field->Field.name_count; if (f->cursor[0].kind != separator) @@ -1826,12 +1751,6 @@ AstNode *parse_identifier_or_type(AstFile *f) { } } - AstScope *scope = make_ast_scope(f, NULL); // NOTE(bill): The struct needs its own scope with NO parent - AstScope *curr_scope = f->curr_scope; - f->curr_scope = scope; - defer (f->curr_scope = curr_scope); - - Token open = expect_token(f, Token_OpenBrace); isize decl_count = 0; AstNode *decls = parse_struct_params(f, &decl_count); @@ -1840,20 +1759,14 @@ AstNode *parse_identifier_or_type(AstFile *f) { return make_struct_type(f, token, decls, decl_count, is_packed); } break; - case Token_union: { - Token token = expect_token(f, Token_union); - AstScope *scope = make_ast_scope(f, NULL); // NOTE(bill): The struct needs its own scope with NO parent - AstScope *curr_scope = f->curr_scope; - f->curr_scope = scope; - defer (f->curr_scope = curr_scope); - - + case Token_raw_union: { + Token token = expect_token(f, Token_raw_union); Token open = expect_token(f, Token_OpenBrace); isize decl_count = 0; AstNode *decls = parse_struct_params(f, &decl_count); Token close = expect_token(f, Token_CloseBrace); - return make_union_type(f, token, decls, decl_count); + return make_raw_union_type(f, token, decls, decl_count); } case Token_enum: { @@ -1895,7 +1808,7 @@ AstNode *parse_identifier_or_type(AstFile *f) { case Token_proc: { AstNode *curr_proc = f->curr_proc; - AstNode *type = parse_proc_type(f, NULL); + AstNode *type = parse_proc_type(f); f->curr_proc = type; f->curr_proc = curr_proc; return type; @@ -1930,7 +1843,7 @@ AstNode *parse_identifier_or_type(AstFile *f) { } -AstNode *parse_results(AstFile *f, AstScope *scope, isize *result_count) { +AstNode *parse_results(AstFile *f, isize *result_count) { if (allow_token(f, Token_ArrowRight)) { if (f->cursor[0].kind == Token_OpenParen) { expect_token(f, Token_OpenParen); @@ -1959,18 +1872,18 @@ AstNode *parse_results(AstFile *f, AstScope *scope, isize *result_count) { return NULL; } -Token parse_procedure_signature(AstFile *f, AstScope *scope, +Token parse_procedure_signature(AstFile *f, AstNode **param_list, isize *param_count, AstNode **result_list, isize *result_count) { Token proc_token = expect_token(f, Token_proc); expect_token(f, Token_OpenParen); - *param_list = parse_parameter_list(f, scope, param_count, Token_Comma, true); + *param_list = parse_parameter_list(f, param_count, Token_Comma, true); expect_token(f, Token_CloseParen); - *result_list = parse_results(f, scope, result_count); + *result_list = parse_results(f, result_count); return proc_token; } -AstNode *parse_body(AstFile *f, AstScope *scope) { +AstNode *parse_body(AstFile *f) { AstNode *statement_list = NULL; isize statement_list_count = 0; Token open, close; @@ -1989,9 +1902,8 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) { isize param_count = 0; isize result_count = 0; - AstScope *scope = open_ast_scope(f); - - parse_procedure_signature(f, scope, ¶m_list, ¶m_count, &result_list, &result_count); + parse_procedure_signature(f, ¶m_list, ¶m_count, &result_list, &result_count); + AstNode *proc_type = make_proc_type(f, proc_token, param_list, param_count, result_list, result_count); AstNode *body = NULL; u64 tags = 0; @@ -1999,16 +1911,17 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) { parse_proc_tags(f, &tags, &foreign_name); + AstNode *curr_proc = f->curr_proc; + f->curr_proc = proc_type; + defer (f->curr_proc = curr_proc); + if (f->cursor[0].kind == Token_OpenBrace) { if ((tags & ProcTag_foreign) != 0) { ast_file_err(f, f->cursor[0], "A procedure tagged as `#foreign` cannot have a body"); } - body = parse_body(f, scope); + body = parse_body(f); } - close_ast_scope(f); - - AstNode *proc_type = make_proc_type(f, proc_token, param_list, param_count, result_list, result_count); return make_proc_decl(f, name, proc_type, body, tags, foreign_name); } @@ -2036,7 +1949,7 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) { Token token = expect_token(f, Token_type); if (name_count != 1) { ast_file_err(f, ast_node_token(name_list), "You can only declare one type at a time"); - return make_bad_decl(f, name_list->Ident.token, token); + return make_bad_decl(f, name_list->Ident, token); } if (type != NULL) { @@ -2053,11 +1966,10 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) { AstNode *name = name_list; if (name_count != 1) { ast_file_err(f, proc_token, "You can only declare one procedure at a time"); - return make_bad_decl(f, name->Ident.token, proc_token); + return make_bad_decl(f, name->Ident, proc_token); } AstNode *proc_decl = parse_proc_decl(f, proc_token, name); - add_ast_entity(f, f->curr_scope, proc_decl, name_list); return proc_decl; } else { @@ -2091,13 +2003,12 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) { } AstNode *var_decl = make_var_decl(f, declaration_kind, name_list, name_count, type, value_list, value_count); - add_ast_entity(f, f->curr_scope, var_decl, name_list); return var_decl; } AstNode *parse_if_stmt(AstFile *f) { - if (f->curr_scope == f->file_scope) { + if (f->curr_proc == NULL) { ast_file_err(f, f->cursor[0], "You cannot use an if statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -2108,9 +2019,6 @@ AstNode *parse_if_stmt(AstFile *f) { AstNode *body = NULL; AstNode *else_stmt = NULL; - open_ast_scope(f); - defer (close_ast_scope(f)); - isize prev_level = f->expr_level; f->expr_level = -1; @@ -2154,7 +2062,7 @@ AstNode *parse_if_stmt(AstFile *f) { } AstNode *parse_return_stmt(AstFile *f) { - if (f->curr_scope == f->file_scope) { + if (f->curr_proc == NULL) { ast_file_err(f, f->cursor[0], "You cannot use a return statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -2175,14 +2083,12 @@ AstNode *parse_return_stmt(AstFile *f) { } AstNode *parse_for_stmt(AstFile *f) { - if (f->curr_scope == f->file_scope) { + if (f->curr_proc == NULL) { ast_file_err(f, f->cursor[0], "You cannot use a for statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } Token token = expect_token(f, Token_for); - open_ast_scope(f); - defer (close_ast_scope(f)); AstNode *init = NULL; AstNode *cond = NULL; @@ -2220,8 +2126,78 @@ AstNode *parse_for_stmt(AstFile *f) { return make_for_stmt(f, token, init, cond, end, body); } +AstNode *parse_case_clause(AstFile *f) { + Token token = f->cursor[0]; + AstNode *list = NULL; + isize list_count = 0; + if (allow_token(f, Token_case)) { + list = parse_rhs_expr_list(f, &list_count); + } else { + expect_token(f, Token_default); + } + expect_token(f, Token_Colon); // TODO(bill): Is this the best syntax? + isize stmt_count = 0; + AstNode *stmts = parse_stmt_list(f, &stmt_count); + + return make_case_clause(f, token, list, list_count, stmts, stmt_count); +} + +AstNode *parse_match_stmt(AstFile *f) { + if (f->curr_proc == NULL) { + ast_file_err(f, f->cursor[0], "You cannot use a match statement in the file scope"); + return make_bad_stmt(f, f->cursor[0], f->cursor[0]); + } + + Token token = expect_token(f, Token_match); + + AstNode *init = NULL; + AstNode *tag = NULL; + if (f->cursor[0].kind != Token_OpenBrace) { + isize prev_level = f->expr_level; + f->expr_level = -1; + if (f->cursor[0].kind != Token_Semicolon) { + tag = parse_simple_stmt(f); + } + if (allow_token(f, Token_Semicolon)) { + init = tag; + tag = NULL; + if (f->cursor[0].kind != Token_OpenBrace) { + tag = parse_simple_stmt(f); + } + } + + f->expr_level = prev_level; + } + + Token open = expect_token(f, Token_OpenBrace); + AstNode *list = NULL; + AstNode *list_curr = NULL; + isize list_count = 0; +#if 1 + while (f->cursor[0].kind == Token_case || + f->cursor[0].kind == Token_default) { + DLIST_APPEND(list, list_curr, parse_case_clause(f)); + list_count++; + } +#else + + while (f->cursor[0].kind == Token_ArrowRight) { + DLIST_APPEND(list, list_curr, parse_case_clause(f)); + list_count++; + } + +#endif + Token close = expect_token(f, Token_CloseBrace); + + AstNode *body = make_block_stmt(f, list, list_count, open, close); + + tag = convert_stmt_to_expr(f, tag, make_string("match expression")); + return make_match_stmt(f, token, init, tag, body); +} + + AstNode *parse_defer_stmt(AstFile *f) { - if (f->curr_scope == f->file_scope) { + if (f->curr_proc == NULL) { ast_file_err(f, f->cursor[0], "You cannot use a defer statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -2268,16 +2244,16 @@ AstNode *parse_stmt(AstFile *f) { case Token_if: return parse_if_stmt(f); case Token_return: return parse_return_stmt(f); case Token_for: return parse_for_stmt(f); + case Token_match: return parse_match_stmt(f); case Token_defer: return parse_defer_stmt(f); - // case Token_match: return NULL; // TODO(bill): Token_match - // case Token_case: return NULL; // TODO(bill): Token_case case Token_break: case Token_continue: case Token_fallthrough: next_token(f); - expect_token(f, Token_Semicolon); - return make_branch_stmt(f, token); + s = make_branch_stmt(f, token); + expect_semicolon_after_stmt(f, s); + return s; case Token_using: { AstNode *node = NULL; @@ -2318,14 +2294,14 @@ AstNode *parse_stmt(AstFile *f) { if (are_strings_equal(s->TagStmt.name.string, make_string("load"))) { Token file_path = expect_token(f, Token_String); - if (f->curr_scope == f->file_scope) { + if (f->curr_proc == NULL) { return make_load_decl(f, s->TagStmt.token, file_path); } ast_file_err(f, token, "You cannot `load` within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); } else if (are_strings_equal(s->TagStmt.name.string, make_string("foreign_system_library"))) { Token file_path = expect_token(f, Token_String); - if (f->curr_scope == f->file_scope) { + if (f->curr_proc == NULL) { return make_foreign_system_library(f, s->TagStmt.token, file_path); } ast_file_err(f, token, "You cannot using `foreign_system_library` within a procedure. This must be done at the file scope."); @@ -2337,7 +2313,7 @@ AstNode *parse_stmt(AstFile *f) { ast_file_err(f, token, "#thread_local may only be applied to variable declarations"); return make_bad_decl(f, token, ast_node_token(var_decl)); } - if (f->curr_scope != f->file_scope) { + if (f->curr_proc != NULL) { ast_file_err(f, token, "#thread_local is only allowed at the file scope."); return make_bad_decl(f, token, ast_node_token(var_decl)); } @@ -2371,10 +2347,14 @@ AstNode *parse_stmt_list(AstFile *f, isize *list_count_) { isize list_count = 0; while (f->cursor[0].kind != Token_case && + f->cursor[0].kind != Token_default && f->cursor[0].kind != Token_CloseBrace && f->cursor[0].kind != Token_EOF) { - DLIST_APPEND(list_root, list_curr, parse_stmt(f)); - list_count++; + AstNode *stmt = parse_stmt(f); + if (stmt && stmt->kind != AstNode_EmptyStmt) { + DLIST_APPEND(list_root, list_curr, stmt); + list_count++; + } } if (list_count_) *list_count_ = list_count; @@ -2405,12 +2385,11 @@ ParseFileError init_ast_file(AstFile *f, String fullpath) { f->cursor = &f->tokens[0]; // NOTE(bill): Is this big enough or too small? - isize arena_size = gb_max(gb_size_of(AstNode), gb_size_of(AstScope)); + isize arena_size = gb_size_of(AstNode); arena_size *= 2*gb_array_count(f->tokens); gb_arena_init_from_allocator(&f->arena, gb_heap_allocator(), arena_size); - open_ast_scope(f); - f->file_scope = f->curr_scope; + f->curr_proc = NULL; return ParseFile_None; } @@ -2428,7 +2407,6 @@ ParseFileError init_ast_file(AstFile *f, String fullpath) { } void destroy_ast_file(AstFile *f) { - close_ast_scope(f); gb_arena_free(&f->arena); gb_array_free(f->tokens); gb_free(gb_heap_allocator(), f->tokenizer.fullpath.text); |