diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/checker/checker.c | 93 | ||||
| -rw-r--r-- | src/checker/expr.c | 83 | ||||
| -rw-r--r-- | src/checker/stmt.c | 84 | ||||
| -rw-r--r-- | src/parser.c | 479 | ||||
| -rw-r--r-- | src/ssa.c | 72 |
5 files changed, 565 insertions, 246 deletions
diff --git a/src/checker/checker.c b/src/checker/checker.c index 3e0606d6a..3af0c2f8b 100644 --- a/src/checker/checker.c +++ b/src/checker/checker.c @@ -1106,6 +1106,94 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As switch (decl->kind) { case_ast_node(bd, BadDecl, decl); case_end; + case_ast_node(gd, GenericDecl, decl); + if (!parent_scope->is_file) { + // NOTE(bill): Within a procedure, variables must be in order + continue; + } + + for_array(spec_index, gd->specs) { + AstNode *spec = gd->specs.e[spec_index]; + switch (spec->kind) { + case_ast_node(vs, ValueSpec, spec); + switch (vs->keyword) { + case Token_var: { + // NOTE(bill): You need to store the entity information here unline a constant declaration + isize entity_count = vs->names.count; + isize entity_index = 0; + Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); + DeclInfo *di = NULL; + if (vs->values.count > 0) { + di = make_declaration_info(heap_allocator(), parent_scope); + di->entities = entities; + di->entity_count = entity_count; + di->type_expr = vs->type; + di->init_expr = vs->values.e[0]; + } + + for_array(i, vs->names) { + AstNode *name = vs->names.e[i]; + AstNode *value = NULL; + if (i < vs->values.count) { + value = vs->values.e[i]; + } + if (name->kind != AstNode_Ident) { + error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); + continue; + } + Entity *e = make_entity_variable(c->allocator, parent_scope, name->Ident, NULL); + e->identifier = name; + entities[entity_index++] = e; + + DeclInfo *d = di; + if (d == NULL) { + AstNode *init_expr = value; + d = make_declaration_info(heap_allocator(), e->scope); + d->type_expr = vs->type; + d->init_expr = init_expr; + d->var_decl_tags = gd->tags; + } + + add_entity_and_decl_info(c, name, e, d); + } + } break; + + case Token_const: { + for_array(i, vs->values) { + AstNode *name = vs->names.e[i]; + AstNode *value = unparen_expr(vs->values.e[i]); + if (name->kind != AstNode_Ident) { + error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); + continue; + } + + ExactValue v = {ExactValue_Invalid}; + Entity *e = make_entity_constant(c->allocator, parent_scope, name->Ident, NULL, v); + e->identifier = name; + DeclInfo *di = make_declaration_info(c->allocator, e->scope); + di->type_expr = vs->type; + di->init_expr = value; + add_entity_and_decl_info(c, name, e, di); + } + + isize lhs_count = vs->names.count; + isize rhs_count = vs->values.count; + + if (rhs_count == 0 && vs->type == NULL) { + error_node(decl, "Missing type or initial expression"); + } else if (lhs_count < rhs_count) { + error_node(decl, "Extra initial expression"); + } + } break; + } + case_end; + + default: + error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind])); + break; + } + } + case_end; case_ast_node(id, ImportDecl, decl); if (!parent_scope->is_file) { // NOTE(bill): _Should_ be caught by the parser @@ -1428,7 +1516,10 @@ void check_parsed_files(Checker *c) { ImplicitValueInfo *ivi = &implicit_value_infos[i]; Entity *backing = scope_lookup_entity(e->scope, ivi->backing_name); - GB_ASSERT(backing != NULL); + // GB_ASSERT(backing != NULL); + if (backing == NULL) { + gb_exit(1); + } e->ImplicitValue.backing = backing; } diff --git a/src/checker/expr.c b/src/checker/expr.c index 8900cb4a7..3f8215f55 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -80,6 +80,89 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie case_ast_node(ws, WhenStmt, node); // Will be handled later case_end; + case_ast_node(gd, GenericDecl, node); + for_array(spec_index, gd->specs) { + AstNode *spec = gd->specs.e[spec_index]; + switch (spec->kind) { + case_ast_node(vs, ValueSpec, spec); + switch (vs->keyword) { + case Token_var: + break; + + case Token_const: { + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + + isize entity_count = vs->names.count; + isize entity_index = 0; + Entity **entities = gb_alloc_array(c->tmp_allocator, Entity *, entity_count); + + for_array(i, vs->values) { + AstNode *name = vs->names.e[i]; + AstNode *value = unparen_expr(vs->values.e[i]); + if (name->kind != AstNode_Ident) { + error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); + entities[entity_index++] = NULL; + continue; + } + + ExactValue v = {ExactValue_Invalid}; + Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v); + e->identifier = name; + entities[entity_index++] = e; + DeclInfo *d = make_declaration_info(c->allocator, e->scope); + d->type_expr = vs->type; + d->init_expr = value; + add_entity_and_decl_info(c, name, e, d); + + DelayedEntity delay = {name, e, d}; + array_add(delayed_entities, delay); + } + + isize lhs_count = vs->names.count; + isize rhs_count = vs->values.count; + + // TODO(bill): Better error messages or is this good enough? + if (rhs_count == 0 && vs->type == NULL) { + error_node(node, "Missing type or initial expression"); + } else if (lhs_count < rhs_count) { + error_node(node, "Extra initial expression"); + } + + if (dof != NULL) { + // NOTE(bill): Within a record + for_array(i, vs->names) { + Entity *e = entities[i]; + if (e == NULL) { + continue; + } + AstNode *name = vs->names.e[i]; + if (name->kind != AstNode_Ident) { + continue; + } + Token name_token = name->Ident; + if (str_eq(name_token.string, str_lit("_"))) { + dof->other_fields[dof->other_field_index++] = e; + } else { + HashKey key = hash_string(name_token.string); + if (map_entity_get(dof->entity_map, key) != NULL) { + // TODO(bill): Scope checking already checks the declaration + error(name_token, "`%.*s` is already declared in this record", LIT(name_token.string)); + } else { + map_entity_set(dof->entity_map, key, e); + dof->other_fields[dof->other_field_index++] = e; + } + add_entity(c, c->context.scope, name, e); + } + } + } + + gb_temp_arena_memory_end(tmp); + } break; + } + case_end; + } + } + case_end; case_ast_node(cd, ConstDecl, node); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); diff --git a/src/checker/stmt.c b/src/checker/stmt.c index f1074e2e6..7e1578987 100644 --- a/src/checker/stmt.c +++ b/src/checker/stmt.c @@ -1074,6 +1074,90 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_var_decl_node(c, node); case_end; + case_ast_node(gd, GenericDecl, node); + for_array(spec_index, gd->specs) { + AstNode *spec = gd->specs.e[spec_index]; + switch (spec->kind) { + case_ast_node(vs, ValueSpec, spec); + switch (vs->keyword) { + case Token_var: { + isize entity_count = vs->names.count; + isize entity_index = 0; + Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); + + for_array(i, vs->names) { + AstNode *name = vs->names.e[i]; + Entity *entity = NULL; + if (name->kind == AstNode_Ident) { + Token token = name->Ident; + String str = token.string; + Entity *found = NULL; + // NOTE(bill): Ignore assignments to `_` + if (str_ne(str, str_lit("_"))) { + found = current_scope_lookup_entity(c->context.scope, str); + } + if (found == NULL) { + entity = make_entity_variable(c->allocator, c->context.scope, token, NULL); + add_entity_definition(&c->info, name, entity); + } else { + TokenPos pos = found->token.pos; + error(token, + "Redeclaration of `%.*s` in this scope\n" + "\tat %.*s(%td:%td)", + LIT(str), LIT(pos.file), pos.line, pos.column); + entity = found; + } + } else { + error_node(name, "A variable declaration must be an identifier"); + } + if (entity == NULL) { + entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name)); + } + entities[entity_index++] = entity; + } + + Type *init_type = NULL; + if (vs->type) { + init_type = check_type_extra(c, vs->type, NULL); + if (init_type == NULL) { + init_type = t_invalid; + } + } + + for (isize i = 0; i < entity_count; i++) { + Entity *e = entities[i]; + GB_ASSERT(e != NULL); + if (e->flags & EntityFlag_Visited) { + e->type = t_invalid; + continue; + } + e->flags |= EntityFlag_Visited; + + if (e->type == NULL) + e->type = init_type; + } + + check_init_variables(c, entities, entity_count, vs->values, str_lit("variable declaration")); + + for_array(i, vs->names) { + if (entities[i] != NULL) { + add_entity(c, c->context.scope, vs->names.e[i], entities[i]); + } + } + } break; + + case Token_const: + break; + } + case_end; + + default: + error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind])); + break; + } + } + case_end; + case_ast_node(cd, ConstDecl, node); // NOTE(bill): Handled elsewhere case_end; diff --git a/src/parser.c b/src/parser.c index c8329aabe..f8460e824 100644 --- a/src/parser.c +++ b/src/parser.c @@ -224,37 +224,53 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ \ AST_NODE_KIND(_ComplexStmtEnd, "", i32) \ AST_NODE_KIND(_StmtEnd, "", i32) \ +AST_NODE_KIND(_SpecBegin, "", i32) \ + AST_NODE_KIND(ValueSpec, "value specification", struct { \ + TokenKind keyword; \ + AstNodeArray names; \ + AstNode * type; \ + AstNodeArray values; \ + }) \ +AST_NODE_KIND(_SpecEnd, "", i32) \ AST_NODE_KIND(_DeclBegin, "", i32) \ - AST_NODE_KIND(BadDecl, "bad declaration", struct { Token begin, end; }) \ + AST_NODE_KIND(BadDecl, "bad declaration", struct { Token begin, end; }) \ + AST_NODE_KIND(GenericDecl, "generic declaration", struct { \ + Token token; \ + Token open, close; \ + AstNodeArray specs; \ + u64 tags; \ + bool is_using; \ + }) \ AST_NODE_KIND(VarDecl, "variable declaration", struct { \ - u64 tags; \ - bool is_using; \ - AstNodeArray names; \ - AstNode * type; \ - AstNodeArray values; \ - AstNode * note; \ + u64 tags; \ + bool is_using; \ + AstNodeArray names; \ + AstNode * type; \ + AstNodeArray values; \ + AstNode * note; \ }) \ AST_NODE_KIND(ConstDecl, "constant declaration", struct { \ - u64 tags; \ - AstNodeArray names; \ - AstNode * type; \ - AstNodeArray values; \ - AstNode * note; \ - }) \ - AST_NODE_KIND(ProcDecl, "procedure declaration", struct { \ - AstNode *name; \ - AstNode *type; \ - AstNode *body; \ - u64 tags; \ - String foreign_name; \ - String link_name; \ - AstNode *note; \ + u64 tags; \ + AstNodeArray names; \ + AstNode * type; \ + AstNodeArray values; \ + AstNode * note; \ }) \ AST_NODE_KIND(TypeDecl, "type declaration", struct { \ - Token token; \ - AstNode *name, *type; \ + Token token; \ + AstNode *name; \ + AstNode *type; \ AstNode *note; \ }) \ + AST_NODE_KIND(ProcDecl, "procedure declaration", struct { \ + AstNode *name; \ + AstNode *type; \ + AstNode *body; \ + u64 tags; \ + String foreign_name; \ + String link_name; \ + AstNode *note; \ + }) \ AST_NODE_KIND(ImportDecl, "import declaration", struct { \ Token token, relpath; \ String fullpath; \ @@ -459,20 +475,27 @@ Token ast_node_token(AstNode *node) { return node->PushAllocator.token; case AstNode_PushContext: return node->PushContext.token; + case AstNode_BadDecl: return node->BadDecl.begin; + case AstNode_GenericDecl: + return node->GenericDecl.token; case AstNode_VarDecl: return ast_node_token(node->VarDecl.names.e[0]); case AstNode_ConstDecl: return ast_node_token(node->ConstDecl.names.e[0]); case AstNode_ProcDecl: - return node->ProcDecl.name->Ident; + return ast_node_token(node->ProcDecl.name); case AstNode_TypeDecl: - return node->TypeDecl.token; + return ast_node_token(node->TypeDecl.name); case AstNode_ImportDecl: return node->ImportDecl.token; case AstNode_ForeignLibrary: return node->ForeignLibrary.token; + + case AstNode_ValueSpec: + return ast_node_token(node->ValueSpec.names.e[0]); + case AstNode_Parameter: { if (node->Parameter.names.count > 0) { return ast_node_token(node->Parameter.names.e[0]); @@ -1033,6 +1056,29 @@ AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, AstNode * return result; } + +AstNode *make_generic_decl(AstFile *f, Token token, Token open, Token close, AstNodeArray specs, u64 tags, bool is_using) { + AstNode *result = make_node(f, AstNode_GenericDecl); + result->GenericDecl.token = token; + result->GenericDecl.open = open; + result->GenericDecl.close = close; + result->GenericDecl.specs = specs; + result->GenericDecl.tags = tags; + result->GenericDecl.is_using = is_using; + return result; +} + +AstNode *make_value_spec(AstFile *f, TokenKind keyword, AstNodeArray names, AstNode *type, AstNodeArray values) { + AstNode *result = make_node(f, AstNode_ValueSpec); + result->ValueSpec.keyword = keyword; + result->ValueSpec.names = names; + result->ValueSpec.type = type; + result->ValueSpec.values = values; + return result; +} + + + bool next_token(AstFile *f) { if (f->curr_token_index+1 < f->tokens.count) { if (f->curr_token.kind != Token_Comment) { @@ -1054,16 +1100,9 @@ Token expect_token(AstFile *f, TokenKind kind) { Token prev = f->curr_token; if (prev.kind != kind) { String p = token_strings[prev.kind]; - if (prev.kind == Token_Semicolon && - str_eq(prev.string, str_lit("\n"))) { - syntax_error(f->curr_token, "Expected `%.*s`, got newline", - LIT(token_strings[kind]), - LIT(p)); - } else { - syntax_error(f->curr_token, "Expected `%.*s`, got `%.*s`", - LIT(token_strings[kind]), - LIT(token_strings[prev.kind])); - } + syntax_error(f->curr_token, "Expected `%.*s`, got `%.*s`", + LIT(token_strings[kind]), + LIT(token_strings[prev.kind])); } next_token(f); return prev; @@ -1073,10 +1112,6 @@ Token expect_token_after(AstFile *f, TokenKind kind, char *msg) { Token prev = f->curr_token; if (prev.kind != kind) { String p = token_strings[prev.kind]; - if (prev.kind == Token_Semicolon && - str_eq(prev.string, str_lit("\n"))) { - p = str_lit("newline"); - } syntax_error(f->curr_token, "Expected `%.*s` after %s, got `%.*s`", LIT(token_strings[kind]), msg, @@ -1136,6 +1171,11 @@ void fix_advance_to_next_stmt(AstFile *f) { case Token_Semicolon: return; + case Token_var: + case Token_const: + case Token_type: + case Token_proc: + case Token_if: case Token_when: case Token_return: @@ -1204,8 +1244,9 @@ void expect_semicolon(AstFile *f, AstNode *s) { break; } - syntax_error(prev_token, "Expected `;` after %.*s, got %.*s", - LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind])); + syntax_error(prev_token, "Expected `;` after %.*s, got %.*s %d %d", + LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind]), + Token_Semicolon, prev_token.kind); } else { syntax_error(prev_token, "Expected `;`"); } @@ -1831,6 +1872,21 @@ AstNodeArray parse_rhs_expr_list(AstFile *f) { return parse_expr_list(f, false); } +AstNodeArray parse_identfier_list(AstFile *f) { + AstNodeArray list = make_ast_node_array(f); + + do { + array_add(&list, parse_identifier(f)); + if (f->curr_token.kind != Token_Comma || + f->curr_token.kind == Token_EOF) { + break; + } + next_token(f); + } while (true); + + return list; +} + void parse_check_name_list_for_reserves(AstFile *f, AstNodeArray names) { for_array(i, names) { AstNode *name = names.e[i]; @@ -1845,13 +1901,126 @@ void parse_check_name_list_for_reserves(AstFile *f, AstNodeArray names) { } } -AstNode *parse_value_decl(AstFile *f); +AstNode *parse_type_attempt(AstFile *f) { + AstNode *type = parse_identifier_or_type(f); + if (type != NULL) { + // TODO(bill): Handle? + } + return type; +} + +AstNode *parse_type(AstFile *f) { + AstNode *type = parse_type_attempt(f); + if (type == NULL) { + Token token = f->curr_token; + syntax_error(token, "Expected a type"); + next_token(f); + return make_bad_expr(f, token, f->curr_token); + } + return type; +} + + +#define PARSE_SPEC_PROC(name) AstNode *(name)(AstFile *f, TokenKind keyword) +typedef PARSE_SPEC_PROC(*ParserSpecProc); + + +AstNode *parse_generic_decl(AstFile *f, TokenKind keyword, ParserSpecProc spec_proc) { + Token token = expect_token(f, keyword); + Token open = {0}, close = {0}; + AstNodeArray specs = {0}; + if (f->curr_token.kind == Token_OpenParen) { + open = expect_token(f, Token_OpenParen); + array_init(&specs, heap_allocator()); + + while (f->curr_token.kind != Token_CloseParen && + f->curr_token.kind != Token_EOF) { + AstNode *spec = spec_proc(f, keyword); + array_add(&specs, spec); + expect_semicolon(f, spec); + } + + close = expect_token(f, Token_CloseParen); + } else { + array_init_reserve(&specs, heap_allocator(), 1); + array_add(&specs, spec_proc(f, keyword)); + } + + return make_generic_decl(f, token, open, close, specs, 0, false); +} + +PARSE_SPEC_PROC(parse_value_spec) { + AstNodeArray names = parse_identfier_list(f); + parse_check_name_list_for_reserves(f, names); + AstNode *type = parse_type_attempt(f); + AstNodeArray values = {0}; + + if (allow_token(f, Token_Eq)) { + values = parse_rhs_expr_list(f); + } + + if (values.count > names.count) { + syntax_error(f->curr_token, "Too many values on the right hand side of the declaration"); + } + + if (keyword == Token_const) { + if (values.count < names.count) { + syntax_error(f->curr_token, "All constant declarations must be defined"); + } else if (values.count == 0) { + syntax_error(f->curr_token, "Expected an expression for this declaration"); + } + } + + if (type == NULL && values.count == 0 && names.count > 0) { + syntax_error(f->curr_token, "Missing type or initialization"); + return make_bad_decl(f, f->curr_token, f->curr_token); + } + + // TODO(bill): Fix this so it does not require it + if (values.e == NULL) { + values = make_ast_node_array(f); + } + + return make_value_spec(f, keyword, names, type, values); +} + + +AstNode *parse_type_decl(AstFile *f) { + Token token = expect_token(f, Token_type); + AstNode *name = parse_identifier(f); + AstNode *type = parse_type(f); + return make_type_decl(f, token, name, type); +} + +AstNode *parse_proc_decl(AstFile *f); + +AstNode *parse_decl(AstFile *f) { + switch (f->curr_token.kind) { + case Token_var: + case Token_const: + return parse_generic_decl(f, f->curr_token.kind, parse_value_spec); + + case Token_type: + return parse_type_decl(f); + + case Token_proc: + return parse_proc_decl(f); + + default: { + Token token = f->curr_token; + syntax_error(token, "Expected a declaration"); + fix_advance_to_next_stmt(f); + return make_bad_decl(f, token, f->curr_token); + } + } +} + AstNode *parse_simple_stmt(AstFile *f) { switch (f->curr_token.kind) { case Token_var: case Token_const: - return parse_value_decl(f); + return parse_decl(f); } isize lhs_count = 0, rhs_count = 0; @@ -1888,85 +2057,6 @@ AstNode *parse_simple_stmt(AstFile *f) { } return make_assign_stmt(f, token, lhs, rhs); } break; - - // case Token_Colon: { // Declare - // AstNodeArray names = lhs; - // parse_check_name_list_for_reserves(f, names); - - // Token colon = expect_token(f, Token_Colon); - // AstNode *type = parse_identifier_or_type(f); - // AstNodeArray values = {0}; - - // if (allow_token(f, Token_Eq)) { - // values = parse_rhs_expr_list(f); - // if (values.count > names.count) { - // syntax_error(f->curr_token, "Too many values on the right hand side of the declaration"); - // } else if (values.count == 0) { - // syntax_error(f->curr_token, "Expected an expression for this declaration"); - // } - // if (type == NULL && values.count == 0) { - // syntax_error(f->curr_token, "Missing variable type or initialization"); - // return make_bad_decl(f, f->curr_token, f->curr_token); - // } - // } - - // if (values.e == NULL) { - // values = make_ast_node_array(f); - // } - - // return make_var_decl(f, names, type, values); - // } break; - - // case Token_ColonColon: { - // AstNodeArray names = lhs; - // parse_check_name_list_for_reserves(f, names); - - // Token colon_colon = expect_token(f, Token_ColonColon); - - // // if (f->curr_token.kind == Token_type || - // // f->curr_token.kind == Token_struct || - // // f->curr_token.kind == Token_enum || - // // f->curr_token.kind == Token_union || - // // f->curr_token.kind == Token_raw_union) { - // // // if (f->curr_token.kind == Token_type) { - // // Token token = f->curr_token; - // // if (token.kind == Token_type) { - // // next_token(f); - // // } - // // if (names.count != 1) { - // // syntax_error_node(names.e[0], "You can only declare one type at a time"); - // // return make_bad_decl(f, names.e[0]->Ident, token); - // // } - - // // return make_type_decl(f, token, names.e[0], parse_type(f)); - // // } else if (f->curr_token.kind == Token_proc) { - // // // NOTE(bill): Procedure declarations - // // Token proc_token = f->curr_token; - // // AstNode *name = names.e[0]; - // // if (names.count != 1) { - // // syntax_error(proc_token, "You can only declare one procedure at a time"); - // // return make_bad_decl(f, name->Ident, proc_token); - // // } - - // // return parse_proc_decl(f, proc_token, name); - // // } - - // AstNodeArray values = parse_rhs_expr_list(f); - // if (values.count > names.count) { - // syntax_error(f->curr_token, "Too many values on the right hand side of the declaration"); - // } else if (values.count < names.count) { - // syntax_error(f->curr_token, "All constant declarations must be defined"); - // } else if (values.count == 0) { - // syntax_error(f->curr_token, "Expected an expression for this declaration"); - // } - - // if (values.count == 0 && names.count > 0) { - // syntax_error(f->curr_token, "Missing constant value"); - // return make_bad_decl(f, f->curr_token, f->curr_token); - // } - - // return make_const_decl(f, names, NULL, values); - // } break; } if (lhs_count > 1) { @@ -2013,41 +2103,6 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) { return make_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]); } -AstNodeArray parse_identfier_list(AstFile *f) { - AstNodeArray list = make_ast_node_array(f); - - do { - array_add(&list, parse_identifier(f)); - if (f->curr_token.kind != Token_Comma || - f->curr_token.kind == Token_EOF) { - break; - } - next_token(f); - } while (true); - - return list; -} - - - -AstNode *parse_type_attempt(AstFile *f) { - AstNode *type = parse_identifier_or_type(f); - if (type != NULL) { - // TODO(bill): Handle? - } - return type; -} - -AstNode *parse_type(AstFile *f) { - AstNode *type = parse_type_attempt(f); - if (type == NULL) { - Token token = f->curr_token; - syntax_error(token, "Expected a type"); - next_token(f); - return make_bad_expr(f, token, f->curr_token); - } - return type; -} void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results); @@ -2691,75 +2746,15 @@ AstNode *parse_asm_stmt(AstFile *f) { } -AstNode *parse_type_decl(AstFile *f) { - Token token = expect_token(f, Token_type); - AstNode *name = parse_identifier(f); - AstNode *type = parse_type(f); - return make_type_decl(f, token, name, type); -} - -AstNode *parse_value_decl(AstFile *f) { - Token token = f->curr_token; - switch (token.kind) { - case Token_var: - case Token_const: - next_token(f); - break; - default: - next_token(f); - syntax_error(token, "Expected a variable or constant declaration"); - fix_advance_to_next_stmt(f); - return make_bad_decl(f, token, f->curr_token); - } - - AstNodeArray names = parse_identfier_list(f); - parse_check_name_list_for_reserves(f, names); - AstNode *type = parse_type_attempt(f); - AstNodeArray values = {0}; - - if (allow_token(f, Token_Eq)) { - values = parse_rhs_expr_list(f); - } - - if (values.count > names.count) { - syntax_error(f->curr_token, "Too many values on the right hand side of the declaration"); - } else if (token.kind == Token_const) { - if (values.count < names.count) { - syntax_error(f->curr_token, "All constant declarations must be defined"); - } else if (values.count == 0) { - syntax_error(f->curr_token, "Expected an expression for this declaration"); - } - } - - if (type == NULL && values.count == 0 && names.count > 0) { - syntax_error(f->curr_token, "Missing type or initialization"); - return make_bad_decl(f, f->curr_token, f->curr_token); - } - - // TODO(bill): Fix this so it does not require it - if (values.e == NULL) { - values = make_ast_node_array(f); - } - - - AstNode *decl = NULL; - - switch (token.kind) { - case Token_var: - decl = make_var_decl(f, names, type, values); - break; - case Token_const: - decl = make_const_decl(f, names, type, values); - break; - } - return decl; -} AstNode *parse_stmt(AstFile *f) { AstNode *s = NULL; Token token = f->curr_token; switch (token.kind) { // Operands + case Token_var: + case Token_const: + case Token_Ident: case Token_Integer: case Token_Float: @@ -2775,6 +2770,13 @@ AstNode *parse_stmt(AstFile *f) { expect_semicolon(f, s); return s; + case Token_proc: + return parse_proc_decl(f); + case Token_type: + s = parse_type_decl(f); + expect_semicolon(f, s); + return s; + // TODO(bill): other keywords case Token_if: return parse_if_stmt(f); case Token_when: return parse_when_stmt(f); @@ -2792,25 +2794,9 @@ AstNode *parse_stmt(AstFile *f) { expect_semicolon(f, s); return s; - case Token_proc: - return parse_proc_decl(f); - case Token_type: - s = parse_type_decl(f); - expect_semicolon(f, s); - return s; - case Token_var: - case Token_const: - s = parse_value_decl(f); - expect_semicolon(f, s); - return s; - - case Token_using: { - AstNode *node = NULL; - next_token(f); - node = parse_stmt(f); - + AstNode *node = parse_stmt(f); bool valid = false; switch (node->kind) { @@ -2833,7 +2819,6 @@ AstNode *parse_stmt(AstFile *f) { return make_bad_stmt(f, token, f->curr_token); } - return make_using_stmt(f, token, node); } break; @@ -2961,17 +2946,23 @@ AstNode *parse_stmt(AstFile *f) { expect_semicolon(f, s); return s; } else if (str_eq(tag, str_lit("thread_local"))) { - AstNode *var_decl = parse_simple_stmt(f); - if (var_decl->kind != AstNode_VarDecl) { + AstNode *decl = parse_simple_stmt(f); + if (decl->kind != AstNode_VarDecl && + (decl->kind == AstNode_GenericDecl && + decl->GenericDecl.token.kind != Token_var)) { syntax_error(token, "#thread_local may only be applied to variable declarations"); - return make_bad_decl(f, token, ast_node_token(var_decl)); + return make_bad_decl(f, token, ast_node_token(decl)); } if (f->curr_proc != NULL) { syntax_error(token, "#thread_local is only allowed at the file scope"); - return make_bad_decl(f, token, ast_node_token(var_decl)); + return make_bad_decl(f, token, ast_node_token(decl)); + } + if (decl->kind == AstNode_VarDecl) { + decl->VarDecl.tags |= VarDeclTag_thread_local; + } else if (decl->kind == AstNode_GenericDecl) { + decl->GenericDecl.tags |= VarDeclTag_thread_local; } - var_decl->VarDecl.tags |= VarDeclTag_thread_local; - return var_decl; + return decl; } else if (str_eq(tag, str_lit("bounds_check"))) { s = parse_stmt(f); s->stmt_state_flags |= StmtStateFlag_bounds_check; @@ -3849,7 +3849,8 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) { case_ast_node(us, UsingStmt, node); AstNode *decl = unparen_expr(us->node); - if (decl->kind == AstNode_VarDecl) { + if (decl->kind == AstNode_VarDecl && + decl->kind == AstNode_GenericDecl) { ssa_build_stmt(proc, decl); } case_end; @@ -3858,6 +3859,75 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) { ssa_build_when_stmt(proc, ws); case_end; + + case_ast_node(gd, GenericDecl, node); + for_array(spec_index, gd->specs) { + AstNode *spec = gd->specs.e[spec_index]; + switch (spec->kind) { + case_ast_node(vs, ValueSpec, spec); + switch (vs->keyword) { + case Token_const: + break; + case Token_var: { + ssaModule *m = proc->module; + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); + + if (vs->values.count == 0) { // declared and zero-initialized + for_array(i, vs->names) { + AstNode *name = vs->names.e[i]; + if (!ssa_is_blank_ident(name)) { + ssa_add_local_for_identifier(proc, name, true); + } + } + } else { // Tuple(s) + Array(ssaAddr) lvals; + ssaValueArray inits; + array_init_reserve(&lvals, m->tmp_allocator, vs->names.count); + array_init_reserve(&inits, m->tmp_allocator, vs->names.count); + + for_array(i, vs->names) { + AstNode *name = vs->names.e[i]; + ssaAddr lval = ssa_make_addr(NULL, NULL); + if (!ssa_is_blank_ident(name)) { + ssa_add_local_for_identifier(proc, name, false); + lval = ssa_build_addr(proc, name); + } + + array_add(&lvals, lval); + } + + for_array(i, vs->values) { + ssaValue *init = ssa_build_expr(proc, vs->values.e[i]); + Type *t = ssa_type(init); + if (t->kind == Type_Tuple) { + for (isize i = 0; i < t->Tuple.variable_count; i++) { + Entity *e = t->Tuple.variables[i]; + ssaValue *v = ssa_emit_struct_ev(proc, init, i); + array_add(&inits, v); + } + } else { + array_add(&inits, init); + } + } + + + for_array(i, inits) { + if (lvals.e[i].addr == NULL) { + continue; + } + ssaValue *v = ssa_emit_conv(proc, inits.e[i], ssa_addr_type(lvals.e[i])); + ssa_addr_store(proc, lvals.e[i], v); + } + } + + gb_temp_arena_memory_end(tmp); + } break; + } + case_end; + } + } + case_end; + case_ast_node(vd, VarDecl, node); ssaModule *m = proc->module; gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); |