diff --git a/code/demo.odin b/code/demo.odin index 30a2b639e..e98e0d5a1 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,22 +1,8 @@ -#import "fmt.odin" as fmt +// #import "fmt.odin" as fmt +// #import "os.odin" as os main :: proc() { - Fruit :: enum { - APPLE = -2, - BANANA, - GRAPE, - MELON = 123, - TOMATO, - } - s1 := enum_to_string(Fruit.BANANA) - e := Fruit.MELON - s2 := enum_to_string(e) - - fmt.println(Fruit.APPLE) - fmt.println(Fruit.count) - fmt.println(Fruit.min_value) - fmt.println(Fruit.max_value) } @@ -24,6 +10,51 @@ main :: proc() { // #foreign_system_library "Ws2_32" + +// SOCKET :: type uint +// INVALID_SOCKET :: ~(0 as SOCKET) + +// AF :: enum i32 { +// UNSPEC = 0, // unspecified +// UNIX = 1, // local to host (pipes, portals) +// INET = 2, // internetwork: UDP, TCP, etc. +// IMPLINK = 3, // arpanet imp addresses +// PUP = 4, // pup protocols: e.g. BSP +// CHAOS = 5, // mit CHAOS protocols +// NS = 6, // XEROX NS protocols +// ISO = 7, // ISO protocols +// OSI = ISO, // OSI is ISO +// ECMA = 8, // european computer manufacturers +// DATAKIT = 9, // datakit protocols +// CCITT = 10, // CCITT protocols, X.25 etc +// SNA = 11, // IBM SNA +// DECnet = 12, // DECnet +// DLI = 13, // Direct data link interface +// LAT = 14, // LAT +// HYLINK = 15, // NSC Hyperchannel +// APPLETALK = 16, // AppleTalk +// ROUTE = 17, // Internal Routing Protocol +// LINK = 18, // Link layer interface +// XTP = 19, // eXpress Transfer Protocol (no AF) +// COIP = 20, // connection-oriented IP, aka ST II +// CNT = 21, // Computer Network Technology +// RTIP = 22, // Help Identify RTIP packets +// IPX = 23, // Novell Internet Protocol +// SIP = 24, // Simple Internet Protocol +// PIP = 25, // Help Identify PIP packets +// MAX = 26, +// } + +// SOCK_STREAM :: 1 +// SOCKET_ERROR :: -1 +// IPPROTO_TCP :: 6 +// AI_PASSIVE :: 0x0020 +// SOMAXCONN :: 128 + +// SD_RECEIVE :: 0 +// SD_SEND :: 1 +// SD_BOTH :: 2 + // WSADESCRIPTION_LEN :: 256 // WSASYS_STATUS_LEN :: 128 // WSADATA :: struct #ordered { @@ -31,6 +62,7 @@ main :: proc() { // high_version: i16 +// // NOTE(bill): This is x64 ordering // max_sockets: u16 // max_udp_dg: u16 // vendor_info: ^byte @@ -55,48 +87,6 @@ main :: proc() { // } -// SOCKET :: type uint -// INVALID_SOCKET :: ~(0 as SOCKET) - -// AF_UNSPEC :: 0 // unspecified -// AF_UNIX :: 1 // local to host (pipes, portals) -// AF_INET :: 2 // internetwork: UDP, TCP, etc. -// AF_IMPLINK :: 3 // arpanet imp addresses -// AF_PUP :: 4 // pup protocols: e.g. BSP -// AF_CHAOS :: 5 // mit CHAOS protocols -// AF_NS :: 6 // XEROX NS protocols -// AF_ISO :: 7 // ISO protocols -// AF_OSI :: AF_ISO // OSI is ISO -// AF_ECMA :: 8 // european computer manufacturers -// AF_DATAKIT :: 9 // datakit protocols -// AF_CCITT :: 10 // CCITT protocols, X.25 etc -// AF_SNA :: 11 // IBM SNA -// AF_DECnet :: 12 // DECnet -// AF_DLI :: 13 // Direct data link interface -// AF_LAT :: 14 // LAT -// AF_HYLINK :: 15 // NSC Hyperchannel -// AF_APPLETALK :: 16 // AppleTalk -// AF_ROUTE :: 17 // Internal Routing Protocol -// AF_LINK :: 18 // Link layer interface -// pseudo_AF_XTP :: 19 // eXpress Transfer Protocol (no AF) -// AF_COIP :: 20 // connection-oriented IP, aka ST II -// AF_CNT :: 21 // Computer Network Technology -// pseudo_AF_RTIP :: 22 // Help Identify RTIP packets -// AF_IPX :: 23 // Novell Internet Protocol -// AF_SIP :: 24 // Simple Internet Protocol -// pseudo_AF_PIP :: 25 // Help Identify PIP packets -// AF_MAX :: 26 - -// SOCK_STREAM :: 1 -// SOCKET_ERROR :: -1 -// IPPROTO_TCP :: 6 -// AI_PASSIVE :: 0x0020 -// SOMAXCONN :: 128 - -// SD_RECEIVE :: 0 -// SD_SEND :: 1 -// SD_BOTH :: 2 - // WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import // WSACleanup :: proc() -> i32 #foreign #dll_import // getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import @@ -131,7 +121,7 @@ main :: proc() { // } // defer WSACleanup() -// hints.family = AF_INET +// hints.family = AF.INET as i32 // hints.socktype = SOCK_STREAM // hints.protocol = IPPROTO_TCP // hints.flags = AI_PASSIVE diff --git a/code/old_demos/demo002.odin b/code/old_demos/demo002.odin index b9923f37a..ddb38c1e6 100644 --- a/code/old_demos/demo002.odin +++ b/code/old_demos/demo002.odin @@ -120,7 +120,7 @@ variadic_procedures :: proc() { print_prefix_f32s("a"); nl() print_prefix_f32s("b", 1); nl() - print_prefix_f32s("c", 1, 2, 3); nl() +7 print_prefix_f32s("c", 1, 2, 3); nl() // Internally, the variadic procedures get allocated to an array on the stack, // and this array is passed a slice diff --git a/core/fmt.odin b/core/fmt.odin index cd8c45434..1864b0e5c 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -2,42 +2,47 @@ PRINT_BUF_SIZE :: 1<<12 -fprint :: proc(f: ^os.File, args: ..any) { - data: [PRINT_BUF_SIZE]byte - buf := data[:0] +bprint :: proc(buf: ^[]byte, args: ..any) { prev_string := false for i := 0; i < args.count; i++ { arg := args[i] is_string := arg.data != null && type_info_is_string(arg.type_info) - if i > 0 && is_string && !prev_string { - print_space_to_buffer(^buf) + if i > 0 && !is_string && !prev_string { + print_space_to_buffer(buf) } - print_any_to_buffer(^buf, arg) + print_any_to_buffer(buf, arg) prev_string = is_string; } +} +bprintln :: proc(buf: ^[]byte, args: ..any) { + for i := 0; i < args.count; i++ { + if i > 0 { + append(buf, #rune " ") + } + print_any_to_buffer(buf, args[i]) + } + print_nl_to_buffer(buf) +} + +fprint :: proc(f: ^os.File, args: ..any) { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + bprint(^buf, ..args) os.write(f, buf) } fprintln :: proc(f: ^os.File, args: ..any) { data: [PRINT_BUF_SIZE]byte buf := data[:0] - - for i := 0; i < args.count; i++ { - if i > 0 { - append(^buf, #rune " ") - } - print_any_to_buffer(^buf, args[i]) - } - - print_nl_to_buffer(^buf) + bprintln(^buf, ..args) os.write(f, buf) } fprintf :: proc(f: ^os.File, fmt: string, args: ..any) { data: [PRINT_BUF_SIZE]byte buf := data[:0] - printf_to_buffer(^buf, fmt, ..args) + bprintf(^buf, fmt, ..args) os.write(f, buf) } @@ -52,6 +57,39 @@ printf :: proc(fmt: string, args: ..any) { fprintf(os.stdout, fmt, ..args) } +sprint :: proc(args: ..any) -> string { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + bprint(^buf, ..args) + s := new_slice(byte, buf.count) + copy(s, buf) + return s as string +} +sprintln :: proc(args: ..any) -> string { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + bprintln(^buf, ..args) + s := new_slice(byte, buf.count) + copy(s, buf) + return s as string +} +sprintf :: proc(fmt: string, args: ..any) -> string { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + bprintf(^buf, fmt, ..args) + s := new_slice(byte, buf.count) + copy(s, buf) + return s as string +} + + + +fprint_type :: proc(f: ^os.File, info: ^Type_Info) { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + print_type_to_buffer(^buf, info) + os.write(f, buf) +} @@ -561,7 +599,7 @@ type_info_is_string :: proc(info: ^Type_Info) -> bool { } -printf_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) { +bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) { is_digit :: proc(r: rune) -> bool #inline { return r >= #rune "0" && r <= #rune "9" } diff --git a/core/runtime.odin b/core/runtime.odin index 8fa840597..52c3f68a0 100644 --- a/core/runtime.odin +++ b/core/runtime.odin @@ -63,6 +63,18 @@ Type_Info :: union { } } +type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { + for { + match type i : info { + case Type_Info.Named: + info = i.base + continue + } + + return info + } +} + assume :: proc(cond: bool) #foreign "llvm.assume" diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index c891b3024..abb911709 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -416,7 +416,7 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) { void check_scope_usage(Checker *c, Scope *scope) { // TODO(bill): Use this? -#if 1 +#if 0 gb_for_array(i, scope->elements.entries) { auto *entry = scope->elements.entries + i; Entity *e = entry->value; @@ -457,9 +457,7 @@ void add_global_entity(Entity *entity) { } void add_global_constant(gbAllocator a, String name, Type *type, ExactValue value) { - Token token = {Token_Identifier}; - token.string = name; - Entity *entity = alloc_entity(a, Entity_Constant, NULL, token, type); + Entity *entity = alloc_entity(a, Entity_Constant, NULL, make_token_ident(name), type); entity->Constant.value = value; add_global_entity(entity); } @@ -475,14 +473,10 @@ void init_universal_scope(void) { // Types for (isize i = 0; i < gb_count_of(basic_types); i++) { - Token token = {Token_Identifier}; - token.string = basic_types[i].Basic.name; - add_global_entity(make_entity_type_name(a, NULL, token, &basic_types[i])); + add_global_entity(make_entity_type_name(a, NULL, make_token_ident(basic_types[i].Basic.name), &basic_types[i])); } for (isize i = 0; i < gb_count_of(basic_type_aliases); i++) { - Token token = {Token_Identifier}; - token.string = basic_type_aliases[i].Basic.name; - add_global_entity(make_entity_type_name(a, NULL, token, &basic_type_aliases[i])); + add_global_entity(make_entity_type_name(a, NULL, make_token_ident(basic_type_aliases[i].Basic.name), &basic_type_aliases[i])); } // Constants @@ -493,9 +487,7 @@ void init_universal_scope(void) { // Builtin Procedures for (isize i = 0; i < gb_count_of(builtin_procs); i++) { BuiltinProcId id = cast(BuiltinProcId)i; - Token token = {Token_Identifier}; - token.string = builtin_procs[i].name; - Entity *entity = alloc_entity(a, Entity_Builtin, NULL, token, t_invalid); + Entity *entity = alloc_entity(a, Entity_Builtin, NULL, make_token_ident(builtin_procs[i].name), t_invalid); entity->Builtin.id = id; add_global_entity(entity); } @@ -968,7 +960,7 @@ void check_parsed_files(Checker *c) { di->entities = entities; di->entity_count = entity_count; di->type_expr = vd->type; - di->init_expr = vd->values[0]; // TODO(bill): Is this correct? + di->init_expr = vd->values[0]; } gb_for_array(i, vd->names) { diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 231e467bf..bea09e678 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -133,8 +133,7 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu } -// NOTE(bill): `content_name` is for debugging -// TODO(bill): Maybe allow assignment to tuples? +// NOTE(bill): `content_name` is for debugging and error messages void check_assignment(Checker *c, Operand *operand, Type *type, String context_name, b32 is_argument = false) { check_not_tuple(c, operand); if (operand->mode == Addressing_Invalid) @@ -153,8 +152,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n } } - - if (type != NULL) { if (!check_is_assignable_to(c, operand, type, is_argument)) { gbString type_string = type_to_string(type); @@ -579,8 +576,6 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod if (named_type != NULL) { constant_type = named_type; } - Token blank_token = {Token_Identifier}; - blank_token.string = make_string(""); Entity *blank_entity = make_entity_constant(c->allocator, c->context.scope, blank_token, constant_type, make_exact_value_integer(0));; gb_for_array(i, et->fields) { @@ -590,15 +585,15 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod Token name_token = f->field->Ident; if (name_token.string == make_string("count")) { - error(name_token, "`count` is a reserved identifier for enums"); + error(name_token, "`count` is a reserved identifier for enumerations"); fields[field_index++] = blank_entity; continue; } else if (name_token.string == make_string("min_value")) { - error(name_token, "`min_value` is a reserved identifier for enums"); + error(name_token, "`min_value` is a reserved identifier for enumerations"); fields[field_index++] = blank_entity; continue; } else if (name_token.string == make_string("max_value")) { - error(name_token, "`max_value` is a reserved identifier for enums"); + error(name_token, "`max_value` is a reserved identifier for enumerations"); fields[field_index++] = blank_entity; continue; } @@ -611,7 +606,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod o.mode = Addressing_Invalid; } if (o.mode != Addressing_Invalid) { - check_assignment(c, &o, base_type, make_string("enumeration")); + check_assignment(c, &o, constant_type, make_string("enumeration")); } if (o.mode != Addressing_Invalid) { iota = o.value; @@ -639,14 +634,21 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod error(name_token, "`%.*s` is already declared in this enumeration", LIT(name_token.string)); } else { map_set(&entity_map, key, e); + add_entity(c, c->context.scope, NULL, e); fields[field_index++] = e; } add_entity_use(&c->info, f->field, e); } - enum_type->Record.min_value = min_value; - enum_type->Record.max_value = max_value; + enum_type->Record.other_fields = fields; enum_type->Record.other_field_count = gb_array_count(et->fields); + + enum_type->Record.enum_count = make_entity_constant(c->allocator, NULL, + make_token_ident(make_string("count")), t_int, make_exact_value_integer(enum_type->Record.other_field_count)); + enum_type->Record.min_value = make_entity_constant(c->allocator, NULL, + make_token_ident(make_string("min_value")), constant_type, make_exact_value_integer(min_value)); + enum_type->Record.max_value = make_entity_constant(c->allocator, NULL, + make_token_ident(make_string("max_value")), constant_type, make_exact_value_integer(max_value)); } Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_variadic_) { @@ -1019,7 +1021,9 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c case_ast_node(et, EnumType, e); type = make_type_enum(c->allocator); set_base_type(named_type, type); + check_open_scope(c, e); check_enum_type(c, type, named_type, e); + check_close_scope(c); type->Record.node = e; goto end; case_end; @@ -2070,7 +2074,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { } if (entity == NULL) { - entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity; + entity = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity; } if (entity == NULL) { gbString op_str = expr_to_string(op_expr); @@ -2217,7 +2221,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Operand op = {}; check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; - if (!type) { + if (type == NULL || op.mode == Addressing_Builtin) { error(ast_node_token(ce->args[0]), "Expected a type for `size_of`"); return false; } @@ -2231,8 +2235,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_size_of_val: // size_of_val :: proc(val: Type) -> int check_assignment(c, operand, NULL, make_string("argument of `size_of_val`")); - if (operand->mode == Addressing_Invalid) + if (operand->mode == Addressing_Invalid) { return false; + } operand->mode = Addressing_Constant; operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, operand->type)); @@ -2244,7 +2249,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Operand op = {}; check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; - if (!type) { + if (type == NULL || op.mode == Addressing_Builtin) { error(ast_node_token(ce->args[0]), "Expected a type for `align_of`"); return false; } @@ -2256,8 +2261,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_align_of_val: // align_of_val :: proc(val: Type) -> int check_assignment(c, operand, NULL, make_string("argument of `align_of_val`")); - if (operand->mode == Addressing_Invalid) + if (operand->mode == Addressing_Invalid) { return false; + } operand->mode = Addressing_Constant; operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, operand->type)); @@ -2270,7 +2276,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) check_expr_or_type(c, &op, ce->args[0]); Type *type = get_base_type(op.type); AstNode *field_arg = unparen_expr(ce->args[1]); - if (type != NULL) { + if (type != NULL || op.mode == Addressing_Builtin) { error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`"); return false; } @@ -2286,7 +2292,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) ast_node(arg, Ident, field_arg); - Selection sel = lookup_field(type, arg->string, operand->mode == Addressing_Type); + Selection sel = lookup_field(c->allocator, type, arg->string, operand->mode == Addressing_Type); if (sel.entity == NULL) { gbString type_str = type_to_string(type); error(ast_node_token(ce->args[0]), @@ -2324,7 +2330,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) ast_node(i, Ident, s->selector); - Selection sel = lookup_field(type, i->string, operand->mode == Addressing_Type); + Selection sel = lookup_field(c->allocator, type, i->string, operand->mode == Addressing_Type); if (sel.entity == NULL) { gbString type_str = type_to_string(type); error(ast_node_token(arg), @@ -2341,7 +2347,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_type_of_val: // type_of_val :: proc(val: Type) -> type(Type) check_assignment(c, operand, NULL, make_string("argument of `type_of_val`")); - if (operand->mode == Addressing_Invalid) + if (operand->mode == Addressing_Invalid || operand->mode == Addressing_Builtin) return false; operand->mode = Addressing_Type; break; @@ -2349,11 +2355,16 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_type_info: { // type_info :: proc(val_or_type) -> ^Type_Info - Operand op = {}; - check_expr_or_type(c, &op, ce->args[0]); - add_type_info_type(c, op.type); operand->mode = Addressing_Value; operand->type = t_type_info_ptr; + + Operand op = {}; + check_expr_or_type(c, &op, ce->args[0]); + if (op.type == NULL || op.type == t_invalid || operand->mode == Addressing_Builtin) { + error(ast_node_token(op.expr), "Invalid argument to `type_info`"); + return false; + } + add_type_info_type(c, op.type); } break; case BuiltinProc_compile_assert: @@ -3193,7 +3204,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } String name = kv->field->Ident.string; - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type); if (sel.entity == NULL) { error(ast_node_token(elem), "Unknown field `%.*s` in structure literal", LIT(name)); diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 215df1612..c8fe672f7 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -120,8 +120,9 @@ struct Type { // enum only Type * enum_base; // Default is `int` - i64 min_value; - i64 max_value; + Entity * enum_count; + Entity * min_value; + Entity * max_value; // struct only i64 * struct_offsets; @@ -703,25 +704,28 @@ Selection make_selection(Entity *entity, gbArray(isize) index, b32 indirect) { } void selection_add_index(Selection *s, isize index) { + // IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form + // of heap allocation if (s->index == NULL) { gb_array_init(s->index, gb_heap_allocator()); } gb_array_append(s->index, index); } -gb_global Entity *entity__any_type_info = NULL; -gb_global Entity *entity__any_data = NULL; -gb_global Entity *entity__string_data = NULL; -gb_global Entity *entity__string_count = NULL; +gb_global Entity *entity__any_type_info = NULL; +gb_global Entity *entity__any_data = NULL; +gb_global Entity *entity__string_data = NULL; +gb_global Entity *entity__string_count = NULL; +gb_global Entity *entity__slice_count = NULL; +gb_global Entity *entity__slice_capacity = NULL; -Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) { +Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) { GB_ASSERT(type_ != NULL); if (field_name == make_string("_")) { return empty_selection; } - gbAllocator a = gb_heap_allocator(); Type *type = type_deref(type_); b32 is_ptr = type != type_; type = get_base_type(type); @@ -732,14 +736,10 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se String type_info_str = make_string("type_info"); String data_str = make_string("data"); if (entity__any_type_info == NULL) { - Token token = {Token_Identifier}; - token.string = type_info_str; - entity__any_type_info = make_entity_field(a, NULL, token, t_type_info_ptr, false, 0); + entity__any_type_info = make_entity_field(a, NULL, make_token_ident(type_info_str), t_type_info_ptr, false, 0); } if (entity__any_data == NULL) { - Token token = {Token_Identifier}; - token.string = data_str; - entity__any_data = make_entity_field(a, NULL, token, t_rawptr, false, 1); + entity__any_data = make_entity_field(a, NULL, make_token_ident(data_str), t_rawptr, false, 1); } if (field_name == type_info_str) { @@ -756,15 +756,11 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se String data_str = make_string("data"); String count_str = make_string("count"); if (entity__string_data == NULL) { - Token token = {Token_Identifier}; - token.string = data_str; - entity__string_data = make_entity_field(a, NULL, token, make_type_pointer(a, t_u8), false, 0); + entity__string_data = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, t_u8), false, 0); } if (entity__string_count == NULL) { - Token token = {Token_Identifier}; - token.string = count_str; - entity__string_count = make_entity_field(a, NULL, token, t_int, false, 1); + entity__string_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1); } if (field_name == data_str) { @@ -784,20 +780,16 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se String count_str = make_string("count"); // NOTE(bill): Underlying memory address cannot be changed if (field_name == count_str) { - Token token = {Token_Identifier}; - token.string = count_str; // HACK(bill): Memory leak - sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Array.count)); + sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Array.count)); return sel; } } else if (type->kind == Type_Vector) { String count_str = make_string("count"); // NOTE(bill): Vectors are not addressable if (field_name == count_str) { - Token token = {Token_Identifier}; - token.string = count_str; // HACK(bill): Memory leak - sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Vector.count)); + sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Vector.count)); return sel; } } else if (type->kind == Type_Slice) { @@ -807,24 +799,24 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se if (field_name == data_str) { selection_add_index(&sel, 0); - Token token = {Token_Identifier}; - token.string = data_str; // HACK(bill): Memory leak - sel.entity = make_entity_field(a, NULL, token, make_type_pointer(a, type->Slice.elem), false, 0); + sel.entity = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, type->Slice.elem), false, 0); return sel; } else if (field_name == count_str) { selection_add_index(&sel, 1); - Token token = {Token_Identifier}; - token.string = count_str; - // HACK(bill): Memory leak - sel.entity = make_entity_field(a, NULL, token, t_int, false, 1); + if (entity__slice_count == NULL) { + entity__slice_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1); + } + + sel.entity = entity__slice_count; return sel; } else if (field_name == capacity_str) { selection_add_index(&sel, 2); - Token token = {Token_Identifier}; - token.string = capacity_str; - // HACK(bill): Memory leak - sel.entity = make_entity_field(a, NULL, token, t_int, false, 2); + if (entity__slice_capacity == NULL) { + entity__slice_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2); + } + + sel.entity = entity__slice_capacity; return sel; } } @@ -834,6 +826,8 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se } if (is_type) { if (is_type_union(type)) { + // NOTE(bill): The subtype for a union are stored in the fields + // as they are "kind of" like variables but not for (isize i = 0; i < type->Record.field_count; i++) { Entity *f = type->Record.fields[i]; GB_ASSERT(f->kind == Entity_TypeName); @@ -856,27 +850,14 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se } if (is_type_enum(type)) { - String count_str = make_string("count"); - String min_value_str = make_string("min_value"); - String max_value_str = make_string("max_value"); - - if (field_name == count_str) { - Token token = {Token_Identifier}; - token.string = count_str; - // HACK(bill): Memory leak - sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Record.other_field_count)); + if (field_name == make_string("count")) { + sel.entity = type->Record.enum_count; return sel; - } else if (field_name == min_value_str) { - Token token = {Token_Identifier}; - token.string = min_value_str; - // HACK(bill): Memory leak - sel.entity = make_entity_constant(a, NULL, token, type->Record.enum_base, make_exact_value_integer(type->Record.min_value)); + } else if (field_name == make_string("min_value")) { + sel.entity = type->Record.min_value; return sel; - } else if (field_name == max_value_str) { - Token token = {Token_Identifier}; - token.string = max_value_str; - // HACK(bill): Memory leak - sel.entity = make_entity_constant(a, NULL, token, type->Record.enum_base, make_exact_value_integer(type->Record.max_value)); + } else if (field_name == make_string("max_value")) { + sel.entity = type->Record.max_value; return sel; } } @@ -887,7 +868,7 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field); String str = f->token.string; if (field_name == str) { - selection_add_index(&sel, i); + selection_add_index(&sel, i); // HACK(bill): Leaky memory sel.entity = f; return sel; } @@ -899,7 +880,7 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se } selection_add_index(&sel, i); // HACK(bill): Leaky memory - sel = lookup_field(f->type, field_name, is_type, sel); + sel = lookup_field(a, f->type, field_name, is_type, sel); if (sel.entity != NULL) { if (is_type_pointer(f->type)) diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index 301bfd924..313299552 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -396,18 +396,11 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { ssa_fprintf(f, "%%%d = alloca ", value->id); ssa_print_type(f, m, type); ssa_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type)); - // if (instr->Local.zero_initialized) { - // ssa_fprintf(f, "\tstore "); - // ssa_print_type(f, m, type); - // ssa_fprintf(f, " zeroinitializer, "); - // ssa_print_type(f, m, type); - // ssa_fprintf(f, "* %%%d\n", value->id); - // } } break; case ssaInstr_ZeroInit: { Type *type = type_deref(ssa_type(instr->ZeroInit.address)); - ssa_fprintf(f, "\tstore "); + ssa_fprintf(f, "store "); ssa_print_type(f, m, type); ssa_fprintf(f, " zeroinitializer, "); ssa_print_type(f, m, type); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index d04938f26..9342e5931 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -385,12 +385,8 @@ void ssa_init_module(ssaModule *m, Checker *c) { // Add type info data { String name = make_string(SSA_TYPE_INFO_DATA_NAME); - Token token = {Token_Identifier}; - token.string = name; - - isize count = gb_array_count(c->info.type_info_map.entries); - Entity *e = make_entity_variable(m->allocator, NULL, token, make_type_array(m->allocator, t_type_info, count)); + Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), make_type_array(m->allocator, t_type_info, count)); ssaValue *g = ssa_make_value_global(m->allocator, e, NULL); g->Global.is_private = true; ssa_module_add_value(m, e, g); @@ -421,10 +417,7 @@ void ssa_init_module(ssaModule *m, Checker *c) { } String name = make_string(SSA_TYPE_INFO_DATA_MEMBER_NAME); - Token token = {Token_Identifier}; - token.string = name; - - Entity *e = make_entity_variable(m->allocator, NULL, token, + Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), make_type_array(m->allocator, t_type_info_member, count)); ssaValue *g = ssa_make_value_global(m->allocator, e, NULL); ssa_module_add_value(m, e, g); @@ -1095,6 +1088,10 @@ void ssa_end_procedure_body(ssaProcedure *proc) { ssa_emit_ret(proc, NULL); } + if (gb_array_count(proc->curr_block->instrs) == 0) { + ssa_emit_unreachable(proc); + } + proc->curr_block = proc->decl_block; ssa_emit_jump(proc, proc->entry_block); @@ -1560,14 +1557,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg Type *src = get_enum_base_type(get_base_type(src_type)); Type *dst = get_enum_base_type(get_base_type(t)); - if (are_types_identical(src, dst)) { - return value; - } if (value->kind == ssaValue_Constant) { if (is_type_any(dst)) { - Type *dt = default_type(get_base_type(src_type)); - ssaValue *default_value = ssa_add_local_generated(proc, dt); + ssaValue *default_value = ssa_add_local_generated(proc, default_type(src_type)); ssa_emit_store(proc, default_value, value); return ssa_emit_conv(proc, ssa_emit_load(proc, default_value), t_any, is_argument); } else if (dst->kind == Type_Basic) { @@ -1587,6 +1580,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg } } + if (are_types_identical(src, dst)) { + return value; + } + // integer -> integer if (is_type_integer(src) && is_type_integer(dst)) { GB_ASSERT(src->kind == Type_Basic && @@ -1684,7 +1681,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg // gb_printf("field_name: %.*s\n", LIT(field_name)); if (field_name.len > 0) { // NOTE(bill): It can be casted - Selection sel = lookup_field(sb, field_name, false); + Selection sel = lookup_field(proc->module->allocator, sb, field_name, false); if (sel.entity != NULL) { ssa_emit_comment(proc, make_string("cast - polymorphism")); if (src_is_ptr) { @@ -1821,7 +1818,7 @@ ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) { String field_name = check_down_cast_name(t, type_deref(ssa_type(value))); GB_ASSERT(field_name.len > 0); - Selection sel = lookup_field(t, field_name, false); + Selection sel = lookup_field(proc->module->allocator, t, field_name, false); Type *t_u8_ptr = make_type_pointer(allocator, t_u8); ssaValue *bytes = ssa_emit_conv(proc, value, t_u8_ptr); @@ -2088,11 +2085,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue if (elem->kind == AstNode_FieldValue) { ast_node(kv, FieldValue, elem); - Selection sel = lookup_field(base_type, kv->field->Ident.string, false); + Selection sel = lookup_field(proc->module->allocator, base_type, kv->field->Ident.string, false); index = sel.index[0]; field_expr = ssa_build_expr(proc, kv->value); } else { - Selection sel = lookup_field(base_type, st->fields_in_src_order[field_index]->token.string, false); + Selection sel = lookup_field(proc->module->allocator, base_type, st->fields_in_src_order[field_index]->token.string, false); index = sel.index[0]; field_expr = ssa_build_expr(proc, elem); } @@ -2158,7 +2155,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue Entity *e = *found; switch (e->Builtin.id) { case BuiltinProc_type_info: { - ssaValue *x = ssa_build_expr(proc, ce->args[0]); Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); return ssa_type_info(proc, t); } break; @@ -2629,7 +2625,7 @@ ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) { p = ssa_add_using_variable(proc, parent); } - Selection sel = lookup_field(parent->type, name, false); + Selection sel = lookup_field(proc->module->allocator, parent->type, name, false); GB_ASSERT(sel.entity != NULL); ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent)); ssaValue *v = NULL; @@ -2694,25 +2690,14 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { Type *type = get_base_type(type_of_expr(proc->module->info, se->expr)); if (type == t_invalid) { - // Imports + // NOTE(bill): Imports Entity *imp = entity_of_ident(proc->module->info, se->expr); if (imp != NULL) { GB_ASSERT(imp->kind == Entity_ImportName); } return ssa_build_addr(proc, unparen_expr(se->selector)); - } /* else if (type == t_string) { - Selection sel = lookup_field(type, selector, false); - GB_ASSERT(sel.entity != NULL); - - // NOTE(bill): This could a constant and the only non constant - // selector is the `.data`, so build the expression instead - ssaValue *e = ssa_build_expr(proc, se->expr); - ssaValue *a = ssa_build_addr(proc, se->expr).addr; - - a = ssa_emit_deep_field_gep(proc, type, a, sel); - return ssa_make_addr(a, expr); - } */else { - Selection sel = lookup_field(type, selector, false); + } else { + Selection sel = lookup_field(proc->module->allocator, type, selector, false); GB_ASSERT(sel.entity != NULL); ssaValue *a = ssa_build_addr(proc, se->expr).addr; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index f0aa0dc66..88fec813f 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -150,6 +150,13 @@ struct Token { }; Token empty_token = {Token_Invalid}; +Token blank_token = {Token_Identifier, {cast(u8 *)"_", 1}}; + +Token make_token_ident(String s) { + Token t = {Token_Identifier}; + t.string = s; + return t; +} struct ErrorCollector {