diff --git a/code/demo.odin b/code/demo.odin index 1106b1295..376ed30ac 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -11,8 +11,7 @@ import { win32 "sys/windows.odin"; } - -type Thing enum f64 { +const Thing = enum f64 { _, // Ignore first value A = 1<<(10*iota), B, @@ -20,21 +19,6 @@ type Thing enum f64 { D, }; -proc main() { - var ti = type_info(Thing); - match type info : type_info_base(ti) { - case Type_Info.Enum: - for var i = 0; i < info.names.count; i++ { - if i > 0 { - fmt.print(", "); - } - fmt.print(info.names[i]); - } - fmt.println(); - } - - var x Thing = Thing.A; - - fmt.println(x, Thing.B, Thing.C, Thing.D); - +const main = proc() { + fmt.println(Thing.A, Thing.B, Thing.C, Thing.D); } diff --git a/src/checker/checker.c b/src/checker/checker.c index 98107c9d0..4d4c8f30e 100644 --- a/src/checker/checker.c +++ b/src/checker/checker.c @@ -883,6 +883,9 @@ void add_type_info_type(Checker *c, Type *t) { case Type_Record: { switch (bt->Record.kind) { + case TypeRecord_Enum: + add_type_info_type(c, bt->Record.enum_base_type); + break; case TypeRecord_Union: add_type_info_type(c, t_int); /* fallthrough */ @@ -1072,13 +1075,13 @@ void init_preload(Checker *c) { c->done_preload = true; } -void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init); +bool check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init); #include "expr.c" #include "decl.c" #include "stmt.c" -void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init) { +bool check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init) { isize lhs = s->names.count; isize rhs = s->values.count; if (init != NULL) { @@ -1088,6 +1091,7 @@ void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init) if (init == NULL && rhs == 0) { if (s->type == NULL) { error_node(s->names.e[0], "Missing type or initial expression"); + return false; } } else if (lhs < rhs) { if (lhs < s->values.count) { @@ -1098,12 +1102,16 @@ void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init) } else { error_node(s->names.e[0], "Extra initial expression"); } + return false; } else if (lhs > rhs && (init != NULL || rhs != 1)) { AstNode *n = s->names.e[rhs]; gbString str = expr_to_string(n); error_node(n, "Missing expression for `%s`", str); gb_string_free(str); + return false; } + + return true; } @@ -1234,19 +1242,34 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As continue; } - ExactValue v = make_exact_value_integer(iota); - Entity *e = make_entity_constant(c->allocator, parent_scope, name->Ident, NULL, v); - e->identifier = name; AstNode *init = NULL; if (i < prev_spec->values.count) { init = prev_spec->values.e[i]; } - DeclInfo *di = make_declaration_info(c->allocator, e->scope); - di->type_expr = prev_spec->type; - di->init_expr = init; - add_entity_and_decl_info(c, name, e, di); + DeclInfo *d = make_declaration_info(c->allocator, parent_scope); + Entity *e = NULL; + + ExactValue v_iota = make_exact_value_integer(iota); + + AstNode *up_init = unparen_expr(init); + if (init != NULL && is_ast_node_type(up_init)) { + e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL); + d->type_expr = init; + d->init_expr = init; + } else if (init != NULL && up_init->kind == AstNode_ProcLit) { + e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags); + d->proc_decl = init; + } else { + e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, v_iota); + d->type_expr = prev_spec->type; + d->init_expr = init; + } + GB_ASSERT(e != NULL); + e->identifier = name; + + add_entity_and_decl_info(c, name, e, d); } check_arity_match(c, vs, prev_spec); @@ -1263,6 +1286,7 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL); e->identifier = ts->name; + DeclInfo *d = make_declaration_info(c->allocator, e->scope); d->type_expr = ts->type; d->init_expr = ts->type; diff --git a/src/checker/decl.c b/src/checker/decl.c index d73c79e35..818a31dd0 100644 --- a/src/checker/decl.c +++ b/src/checker/decl.c @@ -248,7 +248,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, } e->flags |= EntityFlag_Visited; - GB_ASSERT(c->context.iota.kind == ExactValue_Invalid); c->context.iota = e->Constant.value; e->Constant.value = (ExactValue){0}; @@ -267,7 +266,18 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, Operand operand = {0}; if (init != NULL) { - check_expr(c, &operand, init); + check_expr_or_type(c, &operand, init); + } + if (operand.mode == Addressing_Type) { + c->context.iota = (ExactValue){0}; + + e->Constant.value = (ExactValue){0}; + e->kind = Entity_TypeName; + + DeclInfo *d = c->context.decl; + d->type_expr = d->init_expr; + check_type_decl(c, e, d->type_expr, named_type); + return; } check_init_constant(c, e, &operand); @@ -319,113 +329,221 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin); e->type = proc_type; - ast_node(pd, ProcDecl, d->proc_decl); + if (d->proc_decl->kind == AstNode_ProcDecl) { + ast_node(pd, ProcDecl, d->proc_decl); - check_open_scope(c, pd->type); - check_procedure_type(c, proc_type, pd->type); + check_open_scope(c, pd->type); + check_procedure_type(c, proc_type, pd->type); - bool is_foreign = (pd->tags & ProcTag_foreign) != 0; - bool is_link_name = (pd->tags & ProcTag_link_name) != 0; - bool is_export = (pd->tags & ProcTag_export) != 0; - bool is_inline = (pd->tags & ProcTag_inline) != 0; - bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0; + bool is_foreign = (pd->tags & ProcTag_foreign) != 0; + bool is_link_name = (pd->tags & ProcTag_link_name) != 0; + bool is_export = (pd->tags & ProcTag_export) != 0; + bool is_inline = (pd->tags & ProcTag_inline) != 0; + bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0; - if ((d->scope->is_file || d->scope->is_global) && - str_eq(e->token.string, str_lit("main"))) { - if (proc_type != NULL) { - TypeProc *pt = &proc_type->Proc; - if (pt->param_count != 0 || - pt->result_count != 0) { - gbString str = type_to_string(proc_type); - error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str); - gb_string_free(str); + if ((d->scope->is_file || d->scope->is_global) && + str_eq(e->token.string, str_lit("main"))) { + if (proc_type != NULL) { + TypeProc *pt = &proc_type->Proc; + if (pt->param_count != 0 || + pt->result_count != 0) { + gbString str = type_to_string(proc_type); + error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str); + gb_string_free(str); + } } } - } - if (is_inline && is_no_inline) { - error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure"); - } + if (is_inline && is_no_inline) { + error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure"); + } - if (is_foreign && is_link_name) { - error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure"); - } else if (is_foreign && is_export) { - error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure"); - } + if (is_foreign && is_link_name) { + error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure"); + } else if (is_foreign && is_export) { + error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure"); + } - if (pd->body != NULL) { + if (pd->body != NULL) { + if (is_foreign) { + error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body"); + } + + if (proc_type->Proc.calling_convention != ProcCC_Odin) { + error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention"); + proc_type->Proc.calling_convention = ProcCC_Odin; + } + + d->scope = c->context.scope; + + GB_ASSERT(pd->body->kind == AstNode_BlockStmt); + check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags); + } + if (is_foreign) { - error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body"); - } - - if (proc_type->Proc.calling_convention != ProcCC_Odin) { - error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention"); - proc_type->Proc.calling_convention = ProcCC_Odin; - } - - d->scope = c->context.scope; - - GB_ASSERT(pd->body->kind == AstNode_BlockStmt); - check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags); - } - - if (is_foreign) { - MapEntity *fp = &c->info.foreign_procs; - AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl; - String name = proc_decl->name->Ident.string; - if (proc_decl->foreign_name.len > 0) { - name = proc_decl->foreign_name; - } - - e->Procedure.is_foreign = true; - e->Procedure.foreign_name = name; - - HashKey key = hash_string(name); - Entity **found = map_entity_get(fp, key); - if (found) { - Entity *f = *found; - TokenPos pos = f->token.pos; - Type *this_type = base_type(e->type); - Type *other_type = base_type(f->type); - if (!are_signatures_similar_enough(this_type, other_type)) { - error_node(d->proc_decl, - "Redeclaration of #foreign procedure `%.*s` with different type signatures\n" - "\tat %.*s(%td:%td)", - LIT(name), LIT(pos.file), pos.line, pos.column); - } - } else { - map_entity_set(fp, key, e); - } - } else { - String name = e->token.string; - if (is_link_name) { - AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl; - name = proc_decl->link_name; - } - - if (is_link_name || is_export) { MapEntity *fp = &c->info.foreign_procs; + AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl; + String name = proc_decl->name->Ident.string; + if (proc_decl->foreign_name.len > 0) { + name = proc_decl->foreign_name; + } - e->Procedure.link_name = name; + e->Procedure.is_foreign = true; + e->Procedure.foreign_name = name; HashKey key = hash_string(name); Entity **found = map_entity_get(fp, key); if (found) { Entity *f = *found; TokenPos pos = f->token.pos; - // TODO(bill): Better error message? - error_node(d->proc_decl, - "Non unique linking name for procedure `%.*s`\n" - "\tother at %.*s(%td:%td)", - LIT(name), LIT(pos.file), pos.line, pos.column); + Type *this_type = base_type(e->type); + Type *other_type = base_type(f->type); + if (!are_signatures_similar_enough(this_type, other_type)) { + error_node(d->proc_decl, + "Redeclaration of #foreign procedure `%.*s` with different type signatures\n" + "\tat %.*s(%td:%td)", + LIT(name), LIT(pos.file), pos.line, pos.column); + } } else { map_entity_set(fp, key, e); } - } - } + } else { + String name = e->token.string; + if (is_link_name) { + AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl; + name = proc_decl->link_name; + } - check_close_scope(c); + if (is_link_name || is_export) { + MapEntity *fp = &c->info.foreign_procs; + + e->Procedure.link_name = name; + + HashKey key = hash_string(name); + Entity **found = map_entity_get(fp, key); + if (found) { + Entity *f = *found; + TokenPos pos = f->token.pos; + // TODO(bill): Better error message? + error_node(d->proc_decl, + "Non unique linking name for procedure `%.*s`\n" + "\tother at %.*s(%td:%td)", + LIT(name), LIT(pos.file), pos.line, pos.column); + } else { + map_entity_set(fp, key, e); + } + } + } + + check_close_scope(c); + } else if (d->proc_decl->kind == AstNode_ProcLit) { + ast_node(pd, ProcLit, d->proc_decl); + + check_open_scope(c, pd->type); + check_procedure_type(c, proc_type, pd->type); + + bool is_foreign = (pd->tags & ProcTag_foreign) != 0; + bool is_link_name = (pd->tags & ProcTag_link_name) != 0; + bool is_export = (pd->tags & ProcTag_export) != 0; + bool is_inline = (pd->tags & ProcTag_inline) != 0; + bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0; + + if ((d->scope->is_file || d->scope->is_global) && + str_eq(e->token.string, str_lit("main"))) { + if (proc_type != NULL) { + TypeProc *pt = &proc_type->Proc; + if (pt->param_count != 0 || + pt->result_count != 0) { + gbString str = type_to_string(proc_type); + error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str); + gb_string_free(str); + } + } + } + + if (is_inline && is_no_inline) { + error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure"); + } + + if (is_foreign && is_link_name) { + error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure"); + } else if (is_foreign && is_export) { + error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure"); + } + + + if (pd->body != NULL) { + if (is_foreign) { + error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body"); + } + + if (proc_type->Proc.calling_convention != ProcCC_Odin) { + error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention"); + proc_type->Proc.calling_convention = ProcCC_Odin; + } + + d->scope = c->context.scope; + + GB_ASSERT(pd->body->kind == AstNode_BlockStmt); + check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags); + } + + if (is_foreign) { + MapEntity *fp = &c->info.foreign_procs; + String name = e->token.string; + if (pd->foreign_name.len > 0) { + name = pd->foreign_name; + } + + e->Procedure.is_foreign = true; + e->Procedure.foreign_name = name; + + HashKey key = hash_string(name); + Entity **found = map_entity_get(fp, key); + if (found) { + Entity *f = *found; + TokenPos pos = f->token.pos; + Type *this_type = base_type(e->type); + Type *other_type = base_type(f->type); + if (!are_signatures_similar_enough(this_type, other_type)) { + error_node(d->proc_decl, + "Redeclaration of #foreign procedure `%.*s` with different type signatures\n" + "\tat %.*s(%td:%td)", + LIT(name), LIT(pos.file), pos.line, pos.column); + } + } else { + map_entity_set(fp, key, e); + } + } else { + String name = e->token.string; + if (is_link_name) { + name = pd->link_name; + } + + if (is_link_name || is_export) { + MapEntity *fp = &c->info.foreign_procs; + + e->Procedure.link_name = name; + + HashKey key = hash_string(name); + Entity **found = map_entity_get(fp, key); + if (found) { + Entity *f = *found; + TokenPos pos = f->token.pos; + // TODO(bill): Better error message? + error_node(d->proc_decl, + "Non unique linking name for procedure `%.*s`\n" + "\tother at %.*s(%td:%td)", + LIT(name), LIT(pos.file), pos.line, pos.column); + } else { + map_entity_set(fp, key, e); + } + } + } + + check_close_scope(c); + } } void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) { diff --git a/src/checker/expr.c b/src/checker/expr.c index d0116e8b2..bf15d22dc 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -113,21 +113,35 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie continue; } - ExactValue v = make_exact_value_integer(iota); - Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v); - e->identifier = name; - AstNode *init = NULL; - if (i < last->values.count) { - init = last->values.e[i]; + if (i < vs->values.count) { + init = vs->values.e[i]; } - DeclInfo *di = make_declaration_info(c->allocator, e->scope); - di->type_expr = last->type; - di->init_expr = init; - add_entity_and_decl_info(c, name, e, di); + DeclInfo *d = make_declaration_info(c->allocator, c->context.scope); + Entity *e = NULL; - DelayedEntity delay = {name, e, di}; + ExactValue v_iota = make_exact_value_integer(iota); + + AstNode *up_init = unparen_expr(init); + if (init != NULL && is_ast_node_type(up_init)) { + e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL); + d->type_expr = init; + d->init_expr = init; + } else if (init != NULL && up_init->kind == AstNode_ProcLit) { + e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags); + d->proc_decl = init; + } else { + e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, v_iota); + d->type_expr = vs->type; + d->init_expr = init; + } + GB_ASSERT(e != NULL); + e->identifier = name; + + add_entity_and_decl_info(c, name, e, d); + + DelayedEntity delay = {name, e, d}; array_add(delayed_entities, delay); } diff --git a/src/parser.c b/src/parser.c index 2d61c9e92..12144462c 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1740,31 +1740,25 @@ AstNode *parse_operand(AstFile *f, bool lhs) { // Parse Procedure Type or Literal case Token_proc: { + Token token = f->curr_token; String foreign_name = {0}; String link_name = {0}; - AstNode *curr_proc = f->curr_proc; AstNode *type = parse_proc_type(f, &foreign_name, &link_name); - f->curr_proc = type; - - if (type->ProcType.tags & ProcTag_foreign) { - syntax_error(f->curr_token, "#foreign cannot be applied to procedure literals"); - } - if (type->ProcType.tags & ProcTag_export) { - syntax_error(f->curr_token, "#export cannot be applied to procedure literals"); - } if (f->curr_token.kind == Token_OpenBrace) { - AstNode *body; + u64 tags = type->ProcType.tags; - if ((type->ProcType.tags & ProcTag_foreign) != 0) { - syntax_error(f->curr_token, "A procedure tagged as `#foreign` cannot have a body"); + if ((tags & ProcTag_foreign) != 0) { + syntax_error(token, "A procedure tagged as `#foreign` cannot have a body"); } + AstNode *curr_proc = f->curr_proc; + f->curr_proc = type; + AstNode *body = parse_body(f); + f->curr_proc = curr_proc; - body = parse_body(f); - type = make_proc_lit(f, type, body, type->ProcType.tags, foreign_name, link_name); + return make_proc_lit(f, type, body, tags, foreign_name, link_name); } - f->curr_proc = curr_proc; return type; } @@ -1941,7 +1935,15 @@ AstNode *parse_type(AstFile *f); AstNode *parse_unary_expr(AstFile *f, bool lhs) { switch (f->curr_token.kind) { - case Token_Pointer: + case Token_Pointer: { + Token op = f->curr_token; + next_token(f); + AstNode *expr = parse_unary_expr(f, lhs); + if (is_ast_node_type(expr)) { + return make_pointer_type(f, op, expr); + } + return make_unary_expr(f, op, expr); + } break; case Token_Maybe: case Token_Add: case Token_Sub: diff --git a/src/ssa.c b/src/ssa.c index 10a54bf40..7eeb2131a 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -5038,25 +5038,48 @@ void ssa_gen_tree(ssaGen *s) { } break; case Entity_Procedure: { - AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl; - String original_name = name; - AstNode *body = pd->body; - if (e->Procedure.is_foreign) { - name = e->token.string; // NOTE(bill): Don't use the mangled name - } - if (pd->foreign_name.len > 0) { - name = pd->foreign_name; - } else if (pd->link_name.len > 0) { - name = pd->link_name; - } + if (decl->proc_decl->kind == AstNode_ProcDecl) { + AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl; + String original_name = name; + AstNode *body = pd->body; + if (e->Procedure.is_foreign) { + name = e->token.string; // NOTE(bill): Don't use the mangled name + } + if (pd->foreign_name.len > 0) { + name = pd->foreign_name; + } else if (pd->link_name.len > 0) { + name = pd->link_name; + } - ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name); - p->Proc.tags = pd->tags; + ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name); + p->Proc.tags = pd->tags; - ssa_module_add_value(m, e, p); - HashKey hash_name = hash_string(name); - if (map_ssa_value_get(&m->members, hash_name) == NULL) { - map_ssa_value_set(&m->members, hash_name, p); + ssa_module_add_value(m, e, p); + HashKey hash_name = hash_string(name); + if (map_ssa_value_get(&m->members, hash_name) == NULL) { + map_ssa_value_set(&m->members, hash_name, p); + } + } else if (decl->proc_decl->kind == AstNode_ProcLit) { + AstNodeProcLit *pd = &decl->proc_decl->ProcLit; + String original_name = name; + AstNode *body = pd->body; + if (e->Procedure.is_foreign) { + name = e->token.string; // NOTE(bill): Don't use the mangled name + } + if (pd->foreign_name.len > 0) { + name = pd->foreign_name; + } else if (pd->link_name.len > 0) { + name = pd->link_name; + } + + ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name); + p->Proc.tags = pd->tags; + + ssa_module_add_value(m, e, p); + HashKey hash_name = hash_string(name); + if (map_ssa_value_get(&m->members, hash_name) == NULL) { + map_ssa_value_set(&m->members, hash_name, p); + } } } break; }