diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-02-19 19:55:19 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-02-19 19:55:19 +0000 |
| commit | a94dfdf21d798bc72bbee0cc04b80149f0d4b8d2 (patch) | |
| tree | 3bf491ee4bd397de165a7732eba1bddb5ccb1bad /src/check_expr.c | |
| parent | c0d5237b75b1ce19ee0e003dcd2dcffa66c442fd (diff) | |
Begin changing `union` syntax
Diffstat (limited to 'src/check_expr.c')
| -rw-r--r-- | src/check_expr.c | 80 |
1 files changed, 67 insertions, 13 deletions
diff --git a/src/check_expr.c b/src/check_expr.c index 4c1deb265..d85c5100a 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -355,7 +355,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Token name_token = name->Ident; - if (str_eq(name_token.string, str_lit(""))) { + if (str_eq(name_token.string, str_lit("names"))) { error(name_token, "`names` is a reserved identifier for unions"); continue; } @@ -596,22 +596,76 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { GB_ASSERT(is_type_union(union_type)); ast_node(ut, UnionType, node); - isize field_count = 1; - for_array(field_index, ut->fields) { - AstNode *field = ut->fields.e[field_index]; - switch (field->kind) { - case_ast_node(f, Field, field); - field_count += f->names.count; - case_end; - } - } + isize field_count = ut->fields.count+1; + + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + + MapEntity entity_map = {0}; + map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count); Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count); - check_fields(c, node, ut->fields, fields, field_count, str_lit("union")); + isize field_index = 0; + fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL); + + for_array(i, ut->fields) { + AstNode *field = ut->fields.e[i]; + if (field->kind != AstNode_UnionField) { + continue; + } + ast_node(f, UnionField, ut->fields.e[i]); + Token name_token = f->name->Ident; + + if (str_eq(name_token.string, str_lit("names"))) { + error(name_token, "`names` is a reserved identifier for unions"); + continue; + } + + Type *base_type = make_type_struct(c->allocator); + { + ast_node(fl, FieldList, f->list); + isize field_count = 0; + for_array(j, fl->list) { + ast_node(f, Field, fl->list.e[j]); + field_count += f->names.count; + } + + Token token = name_token; + token.kind = Token_struct; + AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, fl->list, field_count, + false, true, NULL); + + check_open_scope(c, dummy_struct); + check_struct_type(c, base_type, dummy_struct); + check_close_scope(c); + base_type->Record.node = dummy_struct; + } + + Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL); + Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, type); + type->Named.type_name = e; + add_entity(c, c->context.scope, f->name, e); + + if (str_eq(name_token.string, str_lit("_"))) { + error(name_token, "`_` cannot be used a union subtype"); + continue; + } + + HashKey key = hash_string(name_token.string); + if (map_entity_get(&entity_map, key) != NULL) { + // TODO(bill): Scope checking already checks the declaration + error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string)); + } else { + map_entity_set(&entity_map, key, e); + fields[field_index++] = e; + } + add_entity_use(c, f->name, e); + } + + gb_temp_arena_memory_end(tmp); - union_type->Record.fields = fields; - union_type->Record.field_count = field_count; + union_type->Record.fields = fields; + union_type->Record.field_count = field_index; union_type->Record.names = make_names_field_for_record(c, c->context.scope); } |