diff --git a/code/demo.odin b/code/demo.odin index 2577f8d3c..401853f1d 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,4 +1,4 @@ -#import "fmt.odin"; +#import . "fmt.odin"; #import "atomic.odin"; #import "hash.odin"; #import "math.odin"; @@ -6,18 +6,18 @@ #import "opengl.odin"; #import "os.odin"; #import "sync.odin"; +#import "types.odin"; #import "utf8.odin"; -#import ht "http_test.odin"; main :: proc() { + { Fruit :: enum { APPLE, BANANA, COCONUT, } - - fmt.println(Fruit.names); + println(x, Fruit.names); } when false { @@ -33,16 +33,16 @@ when false { c := m[3.0]; assert(ok && c == 564); - fmt.print("map["); + print("map["); i := 0; for val, key in m { if i > 0 { - fmt.print(", "); + print(", "); } - fmt.printf("%v=%v", key, val); + printf("%v=%v", key, val); i += 1; } - fmt.println("]"); + println("]"); } { m := map[string]u32{ @@ -56,11 +56,11 @@ when false { _, ok := m["c"]; assert(ok && c == 7654); - fmt.println(m); + println(m); } { - fmt.println("Hellope!"); + println("Hellope!"); x: [dynamic]f64; reserve(x, 16); @@ -68,24 +68,24 @@ when false { append(x, 2_000_000.500_000, 3, 5, 7); for p, i in x { - if i > 0 { fmt.print(", "); } - fmt.print(p); + if i > 0 { print(", "); } + print(p); } - fmt.println(); + println(); { Vec3 :: [vector 3]f32; x := Vec3{1, 2, 3}; y := Vec3{4, 5, 6}; - fmt.println(x < y); - fmt.println(x + y); - fmt.println(x - y); - fmt.println(x * y); - fmt.println(x / y); + println(x < y); + println(x + y); + println(x - y); + println(x * y); + println(x / y); for i in x { - fmt.println(i); + println(i); } } } diff --git a/core/_preload.odin b/core/_preload.odin index 802fc3801..8924bf87c 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -17,7 +17,7 @@ Type_Info_Member :: struct #ordered { name: string, // can be empty if tuple type_info: ^Type_Info, - offset: int, // offsets are not used in tuples + offset: int, // offsets may not be used in tuples } Type_Info_Record :: struct #ordered { fields: []Type_Info_Member, @@ -83,7 +83,7 @@ Type_Info :: union { count: int, align: int, }, - Tuple: Type_Info_Record, + Tuple: Type_Info_Record, // Only really used for procedures Struct: Type_Info_Record, Union: Type_Info_Record, Raw_Union: Type_Info_Record, @@ -373,7 +373,7 @@ Raw_Dynamic_Array :: struct #ordered { }; Raw_Dynamic_Map :: struct #ordered { - hashes: [dynamic]int, + hashes: [...]int, entries: Raw_Dynamic_Array, }; diff --git a/core/atomic.odin b/core/atomic.odin index 3be3c1d40..3db437a4b 100644 --- a/core/atomic.odin +++ b/core/atomic.odin @@ -5,7 +5,7 @@ _ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version -yield_thread :: proc() { win32._mm_pause(); } +yield_thread :: proc() { win32.mm_pause(); } mfence :: proc() { win32.ReadWriteBarrier(); } sfence :: proc() { win32.WriteBarrier(); } lfence :: proc() { win32.ReadBarrier(); } diff --git a/core/fmt.odin b/core/fmt.odin index caa17f77d..d990fcada 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -3,7 +3,8 @@ #import "utf8.odin"; #import "types.odin"; -DEFAULT_BUFFER_SIZE :: 1<<12; + +_BUFFER_SIZE :: 1<<12; Buffer :: struct { data: []byte, @@ -60,7 +61,7 @@ Fmt_Info :: struct { fprint :: proc(fd: os.Handle, args: ...any) -> int { - data: [DEFAULT_BUFFER_SIZE]byte; + data: [_BUFFER_SIZE]byte; buf := Buffer{data[:], 0}; bprint(^buf, ...args); os.write(fd, buf.data[:buf.length]); @@ -68,14 +69,14 @@ fprint :: proc(fd: os.Handle, args: ...any) -> int { } fprintln :: proc(fd: os.Handle, args: ...any) -> int { - data: [DEFAULT_BUFFER_SIZE]byte; + data: [_BUFFER_SIZE]byte; buf := Buffer{data[:], 0}; bprintln(^buf, ...args); os.write(fd, buf.data[:buf.length]); return buf.length; } fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int { - data: [DEFAULT_BUFFER_SIZE]byte; + data: [_BUFFER_SIZE]byte; buf := Buffer{data[:], 0}; bprintf(^buf, fmt, ...args); os.write(fd, buf.data[:buf.length]); @@ -95,7 +96,7 @@ printf :: proc(fmt: string, args: ...any) -> int { fprint_type :: proc(fd: os.Handle, info: ^Type_Info) { - data: [DEFAULT_BUFFER_SIZE]byte; + data: [_BUFFER_SIZE]byte; buf := Buffer{data[:], 0}; buffer_write_type(^buf, info); os.write(fd, buf.data[:buf.length]); @@ -174,8 +175,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { buffer_write_string(buf, "]"); buffer_write_type(buf, info.elem); case Dynamic_Array: - buffer_write_string(buf, "[dynamic"); - buffer_write_string(buf, "]"); + buffer_write_string(buf, "[...]"); buffer_write_type(buf, info.elem); case Slice: buffer_write_string(buf, "["); @@ -316,7 +316,7 @@ parse_int :: proc(s: string, offset: int) -> (int, int, bool) { return result, offset+i, i != 0; } -arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset: int, arg_count: int) -> (int, int, bool) { +_arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset: int, arg_count: int) -> (int, int, bool) { parse_arg_number :: proc(format: string) -> (int, int, bool) { if format.count < 3 { return 0, 1, false; @@ -961,7 +961,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int { } } - arg_index, i, was_prev_index = arg_number(^fi, arg_index, fmt, i, args.count); + arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count); // Width if i < end && fmt[i] == '*' { @@ -991,7 +991,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int { fi.good_arg_index = false; } if i < end && fmt[i] == '*' { - arg_index, i, was_prev_index = arg_number(^fi, arg_index, fmt, i, args.count); + arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count); i += 1; fi.prec, arg_index, fi.prec_set = int_from_arg(args, arg_index); if fi.prec < 0 { @@ -1012,7 +1012,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int { } if !was_prev_index { - arg_index, i, was_prev_index = arg_number(^fi, arg_index, fmt, i, args.count); + arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count); } if i >= end { diff --git a/core/sys/windows.odin b/core/sys/windows.odin index 2aca8fe1d..4c32cbd3e 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -1,9 +1,8 @@ -_ := compile_assert(ODIN_OS == "windows"); -#foreign_system_library "kernel32.lib"; -#foreign_system_library "user32.lib"; -#foreign_system_library "gdi32.lib"; -#foreign_system_library "winmm.lib"; -#foreign_system_library "opengl32.lib"; +#foreign_system_library "kernel32.lib" when ODIN_OS == "windows"; +#foreign_system_library "user32.lib" when ODIN_OS == "windows"; +#foreign_system_library "gdi32.lib" when ODIN_OS == "windows"; +#foreign_system_library "winmm.lib" when ODIN_OS == "windows"; +#foreign_system_library "opengl32.lib" when ODIN_OS == "windows"; HANDLE :: rawptr; HWND :: HANDLE; @@ -23,7 +22,7 @@ BOOL :: i32; WNDPROC :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c; -INVALID_HANDLE_VALUE :: cast(HANDLE)(~cast(int)0); +INVALID_HANDLE_VALUE :: cast(HANDLE)~cast(int)0; FALSE: BOOL : 0; TRUE: BOOL : 1; @@ -289,7 +288,7 @@ InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign ke InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32; InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32; -_mm_pause :: proc() #foreign kernel32; +mm_pause :: proc() #foreign kernel32 "_mm_pause"; ReadWriteBarrier :: proc() #foreign kernel32; WriteBarrier :: proc() #foreign kernel32; ReadBarrier :: proc() #foreign kernel32; diff --git a/src/check_expr.c b/src/check_expr.c index d3bc5895c..a6a07b140 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -360,6 +360,11 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Token name_token = name->Ident; + if (str_eq(name_token.string, str_lit(""))) { + error(name_token, "`names` is a reserved identifier for unions"); + continue; + } + 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; @@ -521,6 +526,11 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { struct_type->Record.fields_in_src_order = fields; struct_type->Record.field_count = field_count; + // struct_type->Record.names = make_entity_field(c->allocator, c->context.scope, + // make_token_ident(str_lit("names")), t_string_slice, false, 0); + // struct_type->Record.names->Variable.is_immutable = true; + // struct_type->Record.names->flags |= EntityFlag_TypeField; + if (!st->is_packed && !st->is_ordered) { // NOTE(bill): Reorder fields for reduced size/performance @@ -605,6 +615,11 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { union_type->Record.fields = fields; union_type->Record.field_count = field_count; + + // union_type->Record.names = make_entity_field(c->allocator, c->context.scope, + // make_token_ident(str_lit("names")), t_string_slice, false, 0); + // union_type->Record.names->Variable.is_immutable = true; + // union_type->Record.names->flags |= EntityFlag_TypeField; } void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { @@ -628,6 +643,11 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { union_type->Record.fields = fields; union_type->Record.field_count = field_count; + +// union_type->Record.names = make_entity_field(c->allocator, c->context.scope, +// make_token_ident(str_lit("names")), t_string_slice, false, 0); +// union_type->Record.names->Variable.is_immutable = true; +// union_type->Record.names->flags |= EntityFlag_TypeField; } // GB_COMPARE_PROC(cmp_enum_order) { @@ -664,6 +684,10 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod error_node(node, "Base type for enumeration must be numeric"); return; } + if (is_type_enum(base_type)) { + error_node(node, "Base type for enumeration cannot be another enumeration"); + return; + } // NOTE(bill): Must be up here for the `check_init_constant` system enum_type->Record.enum_base_type = base_type; @@ -764,8 +788,9 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod add_entity_use(c, field, e); } } - GB_ASSERT(field_count <= et->fields.count); + gb_temp_arena_memory_end(tmp); + enum_type->Record.fields = fields; enum_type->Record.field_count = field_count; @@ -777,12 +802,10 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope, make_token_ident(str_lit("max_value")), constant_type, max_value); - enum_type->Record.enum_names = make_entity_field(c->allocator, c->context.scope, + enum_type->Record.names = make_entity_field(c->allocator, c->context.scope, make_token_ident(str_lit("names")), t_string_slice, false, 0); - enum_type->Record.enum_names->Variable.is_immutable = true; - enum_type->Record.enum_names->flags |= EntityFlag_EnumField; - - gb_temp_arena_memory_end(tmp); + enum_type->Record.names->Variable.is_immutable = true; + enum_type->Record.names->flags |= EntityFlag_TypeField; } @@ -1058,6 +1081,11 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) { return 0; } Operand o = {0}; + if (e->kind == AstNode_UnaryExpr && + e->UnaryExpr.op.kind == Token_Question) { + return -1; + } + check_expr(c, &o, e); if (o.mode != Addressing_Constant) { if (o.mode != Addressing_Invalid) { @@ -1291,7 +1319,12 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) { case_ast_node(at, ArrayType, e); if (at->count != NULL) { Type *elem = check_type_extra(c, at->elem, NULL); - type = make_type_array(c->allocator, elem, check_array_or_map_count(c, at->count, false)); + i64 count = check_array_or_map_count(c, at->count, false); + if (count < 0) { + error_node(at->count, "? can only be used in conjuction with compound literals"); + count = 0; + } + type = make_type_array(c->allocator, elem, count); } else { Type *elem = check_type(c, at->elem); type = make_type_slice(c->allocator, elem); @@ -2506,18 +2539,22 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h add_entity_use(c, op_expr, e); expr_entity = e; - if (e != NULL && e->kind == Entity_ImportName && - selector->kind == AstNode_Ident) { + if (e != NULL && e->kind == Entity_ImportName && selector->kind == AstNode_Ident) { + // IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile + // It pretty much needs to be in this order and this way + // If you can clean this up, please do but be really careful + String sel_name = selector->Ident.string; check_op_expr = false; entity = scope_lookup_entity(e->ImportName.scope, sel_name); bool is_declared = entity != NULL; - if (entity->kind == Entity_Builtin) { - is_declared = false; - } - if (entity->scope->is_global && !e->ImportName.scope->is_global) { - is_declared = false; + if (is_declared) { + if (entity->kind == Entity_Builtin) { + is_declared = false; + } else if (entity->scope->is_global && !e->ImportName.scope->is_global) { + is_declared = false; + } } if (!is_declared) { error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name)); @@ -2539,6 +2576,17 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h } } + + is_not_exported = !is_entity_name_exported(entity); + + if (is_not_exported) { + gbString sel_str = expr_to_string(selector); + error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(name)); + gb_string_free(sel_str); + // NOTE(bill): We will have to cause an error his even though it exists + goto error; + } + if (is_overloaded) { Scope *s = entity->scope; bool skip = false; @@ -2583,7 +2631,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h } bool *found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity)); - if (!found) { is_not_exported = false; } else { @@ -2613,8 +2660,8 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type); entity = sel.entity; - // NOTE(bill): Add enum type info needed for fields like `names` - if (entity != NULL && (entity->flags&EntityFlag_EnumField)) { + // NOTE(bill): Add type info needed for fields like `names` + if (entity != NULL && (entity->flags&EntityFlag_TypeField)) { add_type_info_type(c, operand->type); } } @@ -4454,16 +4501,18 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_ast_node(cl, CompoundLit, node); Type *type = type_hint; - bool ellipsis_array = false; + bool is_to_be_determined_array_count = false; bool is_constant = true; if (cl->type != NULL) { type = NULL; // [..]Type if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) { - if (cl->type->ArrayType.count->kind == AstNode_Ellipsis) { + AstNode *count = cl->type->ArrayType.count; + if (count->kind == AstNode_UnaryExpr && + count->UnaryExpr.op.kind == Token_Question) { type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1); - ellipsis_array = true; + is_to_be_determined_array_count = true; } } @@ -4575,18 +4624,28 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case Type_Slice: case Type_Array: case Type_Vector: + case Type_DynamicArray: { Type *elem_type = NULL; String context_name = {0}; + i64 max_type_count = -1; if (t->kind == Type_Slice) { elem_type = t->Slice.elem; context_name = str_lit("slice literal"); } else if (t->kind == Type_Vector) { elem_type = t->Vector.elem; context_name = str_lit("vector literal"); - } else { + max_type_count = t->Vector.count; + } else if (t->kind == Type_Array) { elem_type = t->Array.elem; context_name = str_lit("array literal"); + max_type_count = t->Array.count; + } else if (t->kind == Type_DynamicArray) { + elem_type = t->DynamicArray.elem; + context_name = str_lit("dynamic array literal"); + is_constant = false; + } else { + GB_PANIC("unreachable"); } @@ -4606,15 +4665,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint continue; } - if (t->kind == Type_Array && - t->Array.count >= 0 && - index >= t->Array.count) { - error_node(e, "Index %lld is out of bounds (>= %lld) for array literal", index, t->Array.count); - } - if (t->kind == Type_Vector && - t->Vector.count >= 0 && - index >= t->Vector.count) { - error_node(e, "Index %lld is out of bounds (>= %lld) for vector literal", index, t->Vector.count); + if (0 <= max_type_count && max_type_count <= index) { + error_node(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); } Operand operand = {0}; @@ -4635,7 +4687,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } } - if (t->kind == Type_Array && ellipsis_array) { + if (t->kind == Type_Array && is_to_be_determined_array_count) { t->Array.count = max; } } break; @@ -5153,14 +5205,17 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } case_end; + case AstNode_HelperType: case AstNode_ProcType: case AstNode_PointerType: case AstNode_ArrayType: + case AstNode_DynamicArrayType: case AstNode_VectorType: case AstNode_StructType: case AstNode_UnionType: case AstNode_RawUnionType: case AstNode_EnumType: + case AstNode_MapType: o->mode = Addressing_Type; o->type = check_type(c, node); break; @@ -5388,7 +5443,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_end; case_ast_node(e, Ellipsis, node); - str = gb_string_appendc(str, ".."); + str = gb_string_appendc(str, "..."); case_end; case_ast_node(fv, FieldValue, node); @@ -5404,13 +5459,18 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_ast_node(at, ArrayType, node); str = gb_string_appendc(str, "["); - str = write_expr_to_string(str, at->count); + if (at->count->kind == AstNode_UnaryExpr && + at->count->UnaryExpr.op.kind == Token_Hash) { + str = gb_string_appendc(str, "#"); + } else { + str = write_expr_to_string(str, at->count); + } str = gb_string_appendc(str, "]"); str = write_expr_to_string(str, at->elem); case_end; case_ast_node(at, DynamicArrayType, node); - str = gb_string_appendc(str, "[dynamic]"); + str = gb_string_appendc(str, "[...]"); str = write_expr_to_string(str, at->elem); case_end; diff --git a/src/check_stmt.c b/src/check_stmt.c index 9067d1037..bbe254615 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -999,7 +999,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } - if (unparen_expr(lhs)->kind != AstNode_Ident) { + if (lhs->kind != AstNode_Ident) { error_node(rhs, "Expected an identifier, got `%.*s`", LIT(ast_node_strings[rhs->kind])); break; } @@ -1067,9 +1067,17 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } check_open_scope(c, stmt); - if (case_type != NULL) { - add_type_info_type(c, case_type); + if (case_type == NULL) { + if (is_union_ptr) { + case_type = type_deref(x.type); + } else { + case_type = x.type; + } + } + add_type_info_type(c, case_type); + + { // NOTE(bill): Dummy type Type *tt = case_type; if (is_union_ptr) { diff --git a/src/checker.c b/src/checker.c index d991561ce..b20f17200 100644 --- a/src/checker.c +++ b/src/checker.c @@ -208,6 +208,7 @@ typedef struct Scope { bool is_global; bool is_file; bool is_init; + bool has_been_imported; // This is only applicable to file scopes AstFile * file; } Scope; gb_global Scope *universal_scope = NULL; @@ -1542,6 +1543,12 @@ void check_all_global_entities(Checker *c) { } add_curr_ast_file(c, d->scope->file); + if (!d->scope->has_been_imported) { + // NOTE(bill): All of these unchecked entities could mean a lot of unused allocations + // TODO(bill): Should this be worried about? + continue; + } + if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) { if (e->scope->is_init) { error(e->token, "`main` is reserved as the entry point procedure in the initial scope"); @@ -1575,6 +1582,30 @@ void check_all_global_entities(Checker *c) { } +bool is_string_an_identifier(String s) { + isize offset = 0; + if (s.len < 1) { + return false; + } + while (offset < s.len) { + bool ok = false; + Rune r = -1; + isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r); + if (offset == 0) { + ok = rune_is_letter(r); + } else { + ok = rune_is_letter(r) || rune_is_digit(r); + } + + if (!ok) { + return false; + } + offset += size; + } + + return offset == s.len; +} + String path_to_entity_name(String name, String fullpath) { if (name.len != 0) { return name; @@ -1619,6 +1650,12 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { ast_node(id, ImportDecl, decl); Token token = id->relpath; + GB_ASSERT(parent_scope->is_file); + + if (!parent_scope->has_been_imported) { + continue; + } + HashKey key = hash_string(id->fullpath); Scope **found = map_scope_get(file_scopes, key); if (found == NULL) { @@ -1665,6 +1702,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { warning(token, "Multiple #import of the same file within this scope"); } + scope->has_been_imported = true; + if (str_eq(id->import_name.string, str_lit("."))) { // NOTE(bill): Add imported entities to this file's scope for_array(elem_index, scope->elements.entries) { @@ -1677,9 +1716,17 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { case Entity_LibraryName: break; default: { - bool ok = add_entity(c, parent_scope, NULL, e); - if (ok && id->is_import) { // `#import`ed entities don't get exported - map_bool_set(&parent_scope->implicit, hash_pointer(e), true); + + if (id->is_import) { + if (is_entity_name_exported(e)) { + // TODO(bill): Should these entities be imported but cause an error when used? + bool ok = add_entity(c, parent_scope, NULL, e); + if (ok) { + map_bool_set(&parent_scope->implicit, hash_pointer(e), true); + } + } + } else { + /* bool ok = */add_entity(c, parent_scope, NULL, e); } } break; } @@ -1734,6 +1781,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { } } + String library_name = path_to_entity_name(fl->library_name.string, file_str); if (str_eq(library_name, str_lit("_"))) { error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string)); @@ -1768,6 +1816,10 @@ void check_parsed_files(Checker *c) { array_add(&c->global_scope->shared, scope); } + if (scope->is_init || scope->is_global) { + scope->has_been_imported = true; + } + f->scope = scope; f->decl_info = make_declaration_info(c->allocator, f->scope); HashKey key = hash_string(f->tokenizer.fullpath); diff --git a/src/common.c b/src/common.c index e2a70f576..f09282b5a 100644 --- a/src/common.c +++ b/src/common.c @@ -6,6 +6,7 @@ gbAllocator heap_allocator(void) { return gb_heap_allocator(); } +#include "unicode.c" #include "string.c" #include "array.c" diff --git a/src/entity.c b/src/entity.c index 37c79b488..b571f98e6 100644 --- a/src/entity.c +++ b/src/entity.c @@ -37,7 +37,7 @@ typedef enum EntityFlag { EntityFlag_VectorElem = 1<<5, EntityFlag_Ellipsis = 1<<6, EntityFlag_NoAlias = 1<<7, - EntityFlag_EnumField = 1<<8, + EntityFlag_TypeField = 1<<8, } EntityFlag; typedef enum OverloadKind { @@ -98,6 +98,15 @@ struct Entity { gb_global Entity *e_context = NULL; +bool is_entity_name_exported(Entity *e) { + GB_ASSERT(e != NULL); + String name = e->token.string; + if (name.len == 0) { + return false; + } + return name.text[0] != '_'; +} + Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) { Entity *entity = gb_alloc_item(a, Entity); diff --git a/src/ir.c b/src/ir.c index 05a21d0d8..550c9b1b4 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1008,6 +1008,22 @@ irValue *ir_make_value_procedure(gbAllocator a, irModule *m, Entity *entity, Typ return v; } + +irValue *ir_generate_array(irModule *m, Type *elem_type, i64 count, String prefix, i64 id) { + gbAllocator a = m->allocator; + Token token = {Token_Ident}; + isize name_len = prefix.len + 10; + token.string.text = gb_alloc_array(a, u8, name_len); + token.string.len = gb_snprintf(cast(char *)token.string.text, name_len, + "%.*s-%llx", LIT(prefix), id)-1; + Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, elem_type, count), false); + irValue *value = ir_make_value_global(a, e, NULL); + value->Global.is_private = true; + ir_module_add_value(m, e, value); + map_ir_value_set(&m->members, hash_string(token.string), value); + return value; +} + irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) { Scope *scope = NULL; if (node != NULL) { @@ -3709,50 +3725,55 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { AstNode *sel = unparen_expr(se->selector); if (sel->kind == AstNode_Ident) { String selector = sel->Ident.string; - Type *type = type_of_expr(proc->module->info, se->expr); + TypeAndValue *tav = type_and_value_of_expression(proc->module->info, se->expr); - if (is_type_enum(type)) { - Selection sel = lookup_field(proc->module->allocator, type, selector, true); - Entity *e = sel.entity; - GB_ASSERT(e->kind == Entity_Variable); - i32 index = e->Variable.field_index; - switch (index) { - case 0: { - irValue *ti_ptr = ir_type_info(proc, type); - { - irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1); - args[0] = ti_ptr; - ti_ptr = ir_emit_global_call(proc, "type_info_base", args, 1); - } - - - irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr); - irValue *names_ptr = ir_emit_struct_ep(proc, enum_info, 1); - return ir_make_addr(names_ptr); - } break; - default: - GB_PANIC("Unhandled enum index %d %.*s", index, LIT(selector)); - break; - } - } - - type = base_type(type); - - if (type == t_invalid) { + if (tav == NULL) { // NOTE(bill): Imports Entity *imp = entity_of_ident(proc->module->info, se->expr); if (imp != NULL) { GB_ASSERT(imp->kind == Entity_ImportName); } return ir_build_addr(proc, unparen_expr(se->selector)); - } else { - Selection sel = lookup_field(proc->module->allocator, type, selector, false); - GB_ASSERT(sel.entity != NULL); - - irValue *a = ir_build_addr(proc, se->expr).addr; - a = ir_emit_deep_field_gep(proc, type, a, sel); - return ir_make_addr(a); } + + + Type *type = base_type(tav->type); + if (tav->mode == Addressing_Type) { // Addressing_Type + Selection sel = lookup_field(proc->module->allocator, type, selector, true); + Entity *e = sel.entity; + GB_ASSERT(e->kind == Entity_Variable); + GB_ASSERT(e->flags & EntityFlag_TypeField); + String name = e->token.string; + if (str_eq(name, str_lit("names"))) { + irValue *ti_ptr = ir_type_info(proc, type); + // { + // irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1); + // args[0] = ti_ptr; + // ti_ptr = ir_emit_global_call(proc, "type_info_base", args, 1); + // } + irValue *names_ptr = NULL; + + if (is_type_enum(type)) { + irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr); + names_ptr = ir_emit_struct_ep(proc, enum_info, 1); + } else { + GB_PANIC("TODO(bill): `names` for records"); + // irValue *record_info = ir_emit_conv(proc, ti_ptr, t_type_info_record_ptr); + // names_ptr = ir_emit_struct_ep(proc, record_info, 1); + } + return ir_make_addr(names_ptr); + } else { + GB_PANIC("Unhandled TypeField %.*s", LIT(name)); + } + GB_PANIC("Unreachable"); + } + + Selection sel = lookup_field(proc->module->allocator, type, selector, false); + GB_ASSERT(sel.entity != NULL); + + irValue *a = ir_build_addr(proc, se->expr).addr; + a = ir_emit_deep_field_gep(proc, type, a, sel); + return ir_make_addr(a); } else { Type *type = base_type(type_of_expr(proc->module->info, se->expr)); GB_ASSERT(is_type_integer(type)); @@ -4117,33 +4138,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { ir_emit_store(proc, gep, ev); } } - - - // irValue *result = ir_add_module_constant(proc->module, type, make_exact_value_compound(expr)); - // for_array(index, cl->elems) { - // AstNode *elem = cl->elems.e[index]; - // if (ir_is_elem_const(proc->module, elem, et)) { - // continue; - // } - // irValue *field_elem = ir_build_expr(proc, elem); - // Type *t = ir_type(field_elem); - // GB_ASSERT(t->kind != Type_Tuple); - // irValue *ev = ir_emit_conv(proc, field_elem, et); - // irValue *i = ir_make_const_int(proc->module->allocator, index); - // result = ir_emit(proc, ir_make_instr_insert_element(proc, result, ev, i)); - // } - - // if (cl->elems.count == 1 && bt->Vector.count > 1) { - // isize index_count = bt->Vector.count; - // i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count); - // for (isize i = 0; i < index_count; i++) { - // indices[i] = 0; - // } - // irValue *sv = ir_emit(proc, ir_make_instr_vector_shuffle(proc, result, indices, index_count)); - // ir_emit_store(proc, v, sv); - // return ir_make_addr(v); - // } - // ir_emit_store(proc, v, result); } break; case Type_Record: { @@ -4186,13 +4180,51 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { } } break; + case Type_DynamicArray: { + if (cl->elems.count == 0) { + break; + } + Type *elem = bt->DynamicArray.elem; + gbAllocator a = proc->module->allocator; + irValue *size = ir_make_const_int(a, type_size_of(proc->module->sizes, a, elem)); + irValue *align = ir_make_const_int(a, type_align_of(proc->module->sizes, a, elem)); + { + irValue **args = gb_alloc_array(a, irValue *, 4); + args[0] = ir_emit_conv(proc, v, t_rawptr); + args[1] = size; + args[2] = align; + args[3] = ir_make_const_int(a, 2*cl->elems.count); + ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4); + } + + i64 item_count = cl->elems.count; + irValue *items = ir_generate_array(proc->module, elem, item_count, str_lit("__dacl$"), cast(i64)cast(intptr)expr); + + for_array(field_index, cl->elems) { + AstNode *f = cl->elems.e[field_index]; + irValue *value = ir_emit_conv(proc, ir_build_expr(proc, f), elem); + irValue *ep = ir_emit_array_epi(proc, items, field_index); + ir_emit_store(proc, ep, value); + } + + { + irValue **args = gb_alloc_array(a, irValue *, 5); + args[0] = ir_emit_conv(proc, v, t_rawptr); + args[1] = size; + args[2] = align; + args[3] = ir_emit_conv(proc, items, t_rawptr); + args[4] = ir_make_const_int(a, item_count); + ir_emit_global_call(proc, "__dynamic_array_append", args, 5); + } + } break; + case Type_Map: { if (cl->elems.count == 0) { break; } gbAllocator a = proc->module->allocator; { - irValue **args = gb_alloc_array(a, irValue *, 4); + irValue **args = gb_alloc_array(a, irValue *, 2); args[0] = ir_gen_map_header(proc, v, type); args[1] = ir_make_const_int(a, 2*cl->elems.count); ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); @@ -5294,17 +5326,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { AstNode *clause = body->stmts.e[i]; ast_node(cc, CaseClause, clause); - if (cc->list.count == 0) { - // default case - default_stmts = cc->stmts; - default_block = ir_new_block(proc, clause, "type-match.dflt.body"); - continue; - } - GB_ASSERT(cc->list.count == 1); - - - irBlock *body = ir_new_block(proc, clause, "type-match.case.body"); - Entity *tag_var_entity = NULL; Type *tag_var_type = NULL; if (str_eq(tag_var_name, str_lit("_"))) { @@ -5324,6 +5345,26 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irBlock *next_cond = NULL; irValue *cond = NULL; + if (cc->list.count == 0) { + // default case + default_stmts = cc->stmts; + default_block = ir_new_block(proc, clause, "type-match.dflt.body"); + + + irValue *tag_var = NULL; + if (tag_var_entity != NULL) { + tag_var = ir_add_local(proc, tag_var_entity); + } else { + tag_var = ir_add_local_generated(proc, tag_var_type); + } + ir_emit_store(proc, tag_var, parent); + continue; + } + GB_ASSERT(cc->list.count == 1); + + irBlock *body = ir_new_block(proc, clause, "type-match.case.body"); + + if (is_union_ptr) { Type *bt = type_deref(tag_var_type); irValue *index = NULL; @@ -6409,38 +6450,10 @@ void ir_gen_tree(irGen *s) { if (t->Record.field_count > 0) { Entity **fields = t->Record.fields; isize count = t->Record.field_count; - irValue *name_array = NULL; - irValue *value_array = NULL; - - { - Token token = {Token_Ident}; - i32 id = cast(i32)entry_index; - char name_base[] = "__$enum_names"; - isize name_len = gb_size_of(name_base) + 10; - token.string.text = gb_alloc_array(a, u8, name_len); - token.string.len = gb_snprintf(cast(char *)token.string.text, name_len, - "%s-%d", name_base, id)-1; - Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_string, count), false); - name_array = ir_make_value_global(a, e, NULL); - name_array->Global.is_private = true; - ir_module_add_value(m, e, name_array); - map_ir_value_set(&m->members, hash_string(token.string), name_array); - } - - { - Token token = {Token_Ident}; - i32 id = cast(i32)entry_index; - char name_base[] = "__$enum_values"; - isize name_len = gb_size_of(name_base) + 10; - token.string.text = gb_alloc_array(a, u8, name_len); - token.string.len = gb_snprintf(cast(char *)token.string.text, name_len, - "%s-%d", name_base, id)-1; - Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_type_info_enum_value, count), false); - value_array = ir_make_value_global(a, e, NULL); - value_array->Global.is_private = true; - ir_module_add_value(m, e, value_array); - map_ir_value_set(&m->members, hash_string(token.string), value_array); - } + irValue *name_array = ir_generate_array(m, t_string, count, + str_lit("__$enum_names"), cast(i64)entry_index); + irValue *value_array = ir_generate_array(m, t_type_info_enum_value, count, + str_lit("__$enum_values"), cast(i64)entry_index); bool is_value_int = is_type_integer(t->Record.enum_base_type); diff --git a/src/main.c b/src/main.c index ba05144f7..235d68c58 100644 --- a/src/main.c +++ b/src/main.c @@ -4,7 +4,6 @@ extern "C" { #include "common.c" #include "timings.c" -#include "unicode.c" #include "build.c" #include "tokenizer.c" #include "parser.c" diff --git a/src/parser.c b/src/parser.c index 3179509e7..b4902982c 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1832,6 +1832,7 @@ bool is_literal_type(AstNode *node) { case AstNode_ArrayType: case AstNode_VectorType: case AstNode_StructType: + case AstNode_DynamicArrayType: case AstNode_MapType: return true; } @@ -2337,26 +2338,6 @@ bool parse_expect_separator(AstFile *f, TokenKind separator, AstNode *param) { return false; } -AstNodeArray convert_to_ident_list(AstFile *f, AstNodeArray list) { - AstNodeArray idents = {0}; - array_init_reserve(&idents, heap_allocator(), list.count); - // Convert to ident list - for_array(i, list) { - AstNode *ident = list.e[i]; - switch (ident->kind) { - case AstNode_Ident: - case AstNode_BadExpr: - break; - default: - error_node(ident, "Expected an identifier"); - ident = ast_ident(f, blank_token); - break; - } - array_add(&idents, ident); - } - return idents; -} - AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) { if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) { Token tok = f->curr_token; @@ -2377,16 +2358,24 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) { return type; } +bool is_token_field_prefix(TokenKind kind) { + switch (kind) { + case Token_using: + case Token_no_alias: + // case Token_immutable: + return true; + } + return false; +} + u32 parse_field_prefixes(AstFile *f) { i32 using_count = 0; i32 no_alias_count = 0; i32 immutable_count = 0; - bool loop = true; - while (loop) { + while (is_token_field_prefix(f->curr_token.kind)) { switch (f->curr_token.kind) { - default: loop = false; break; case Token_using: using_count += 1; next_token(f); break; case Token_no_alias: no_alias_count += 1; next_token(f); break; // case Token_immutable: immutable_count += 1; next_token(f); break; @@ -2404,8 +2393,8 @@ u32 parse_field_prefixes(AstFile *f) { return field_flags; } -u32 check_field_prefixes(AstFile *f, AstNodeArray names, u32 allowed_flags, u32 set_flags) { - if (names.count > 1 && (set_flags&FieldFlag_using)) { +u32 check_field_prefixes(AstFile *f, isize name_count, u32 allowed_flags, u32 set_flags) { + if (name_count > 1 && (set_flags&FieldFlag_using)) { syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type"); set_flags &= ~FieldFlag_using; } @@ -2425,19 +2414,54 @@ u32 check_field_prefixes(AstFile *f, AstNodeArray names, u32 allowed_flags, u32 return set_flags; } +typedef struct AstNodeAndFlags { + AstNode *node; + u32 flags; +} AstNodeAndFlags; + +typedef Array(AstNodeAndFlags) AstNodeAndFlagsArray; + +AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool ignore_flags) { + AstNodeArray idents = {0}; + array_init_reserve(&idents, heap_allocator(), list.count); + // Convert to ident list + for_array(i, list) { + AstNode *ident = list.e[i].node; + + if (!ignore_flags) { + if (i != 0) { + error_node(ident, "Illegal use of prefixes in parameter list"); + } + } + + switch (ident->kind) { + case AstNode_Ident: + case AstNode_BadExpr: + break; + default: + error_node(ident, "Expected an identifier"); + ident = ast_ident(f, blank_token); + break; + } + array_add(&idents, ident); + } + return idents; +} + AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) { AstNodeArray params = make_ast_node_array(f); - AstNodeArray list = make_ast_node_array(f); - isize name_count = 0; + AstNodeAndFlagsArray list = {0}; array_init(&list, heap_allocator()); // LEAK(bill): + isize total_name_count = 0; bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis; - u32 set_flags = parse_field_prefixes(f); while (f->curr_token.kind != follow && f->curr_token.kind != Token_Colon && f->curr_token.kind != Token_EOF) { + u32 flags = parse_field_prefixes(f); AstNode *param = parse_var_type(f, allow_ellipsis); - array_add(&list, param); + AstNodeAndFlags naf = {param, flags}; + array_add(&list, naf); if (f->curr_token.kind != Token_Comma) { break; } @@ -2445,12 +2469,16 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, } if (f->curr_token.kind == Token_Colon) { - AstNodeArray names = convert_to_ident_list(f, list); // Copy for semantic reasons + AstNodeArray names = convert_to_ident_list(f, list, true); // Copy for semantic reasons if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); } - set_flags = check_field_prefixes(f, names, allowed_flags, set_flags); - name_count += names.count; + u32 set_flags = 0; + if (list.count > 0) { + set_flags = list.e[0].flags; + } + set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags); + total_name_count += names.count; expect_token_after(f, Token_Colon, "field list"); AstNode *type = parse_var_type(f, allow_ellipsis); @@ -2467,8 +2495,8 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, syntax_error(f->curr_token, "Empty field declaration"); break; } - set_flags = check_field_prefixes(f, names, allowed_flags, set_flags); - name_count += names.count; + set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags); + total_name_count += names.count; expect_token_after(f, Token_Colon, "field list"); AstNode *type = parse_var_type(f, allow_ellipsis); @@ -2480,25 +2508,25 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, } } - if (name_count_) *name_count_ = name_count; + if (name_count_) *name_count_ = total_name_count; return params; } - set_flags = check_field_prefixes(f, list, allowed_flags, set_flags); for_array(i, list) { AstNodeArray names = {0}; - AstNode *type = list.e[i]; + AstNode *type = list.e[i].node; Token token = blank_token; array_init_count(&names, heap_allocator(), 1); token.pos = ast_node_token(type).pos; names.e[0] = ast_ident(f, token); + u32 flags = check_field_prefixes(f, list.count, allowed_flags, list.e[i].flags); - AstNode *param = ast_field(f, names, list.e[i], set_flags); + AstNode *param = ast_field(f, names, list.e[i].node, flags); array_add(¶ms, param); } - if (name_count_) *name_count_ = name_count; + if (name_count_) *name_count_ = total_name_count; return params; } @@ -2548,8 +2576,8 @@ AstNode *parse_type_or_ident(AstFile *f) { AstNode *count_expr = NULL; bool is_vector = false; - if (f->curr_token.kind == Token_Ellipsis) { - count_expr = ast_ellipsis(f, expect_token(f, Token_Ellipsis), NULL); + if (f->curr_token.kind == Token_Question) { + count_expr = ast_unary_expr(f, expect_token(f, Token_Question), NULL); } else if (f->curr_token.kind == Token_vector) { next_token(f); if (f->curr_token.kind != Token_CloseBracket) { @@ -2560,7 +2588,7 @@ AstNode *parse_type_or_ident(AstFile *f) { syntax_error(f->curr_token, "Vector type missing count"); } is_vector = true; - } else if (f->curr_token.kind == Token_dynamic) { + } else if (f->curr_token.kind == Token_Ellipsis) { next_token(f); expect_token(f, Token_CloseBracket); return ast_dynamic_array_type(f, token, parse_type(f)); @@ -2627,12 +2655,10 @@ AstNode *parse_type_or_ident(AstFile *f) { f->expr_level = prev_level; - if (is_packed && is_ordered) { syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering"); } - Token open = expect_token_after(f, Token_OpenBrace, "struct"); isize decl_count = 0; AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct")); @@ -2685,12 +2711,10 @@ AstNode *parse_type_or_ident(AstFile *f) { } case Token_OpenParen: { - // NOTE(bill): Skip the paren expression Token open = expect_token(f, Token_OpenParen); AstNode *type = parse_type(f); Token close = expect_token(f, Token_CloseParen); - return type; - // return ast_paren_expr(f, type, open, close); + return ast_paren_expr(f, type, open, close); } break; } @@ -3504,6 +3528,7 @@ AstNodeArray parse_stmt_list(AstFile *f) { ParseFileError init_ast_file(AstFile *f, String fullpath) { + fullpath = string_trim_whitespace(fullpath); // Just in case if (!string_has_extension(fullpath, str_lit("odin"))) { return ParseFile_WrongExtension; } @@ -3583,6 +3608,9 @@ void destroy_parser(Parser *p) { bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) { gb_mutex_lock(&p->mutex); + path = string_trim_whitespace(path); + rel_path = string_trim_whitespace(rel_path); + for_array(i, p->imports) { String import = p->imports.e[i].path; if (str_eq(import, path)) { @@ -3763,7 +3791,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) { gb_printf_err("Invalid file extension: File must have the extension `.odin`"); break; case ParseFile_InvalidFile: - gb_printf_err("Invalid file"); + gb_printf_err("Invalid file or cannot be found"); break; case ParseFile_Permission: gb_printf_err("File permissions problem"); diff --git a/src/string.c b/src/string.c index 8558616bf..38874a7d5 100644 --- a/src/string.c +++ b/src/string.c @@ -145,16 +145,37 @@ gb_inline isize string_extension_position(String str) { return dot_pos; } +String string_trim_whitespace(String str) { + while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) { + str.len--; + } + + while (str.len > 0 && rune_is_whitespace(str.text[0])) { + str.text++; + str.len--; + } + + return str; +} + gb_inline bool string_has_extension(String str, String ext) { - if (str.len > ext.len+1) { - u8 *s = str.text+str.len - ext.len-1; - if (s[0] == '.') { - s++; - return gb_memcompare(s, ext.text, ext.len) == 0; - } + str = string_trim_whitespace(str); + if (str.len <= ext.len+1) { return false; } - return false; + isize len = str.len; + for (isize i = len-1; i >= 0; i--) { + if (str.text[i] == '.') { + break; + } + len--; + } + if (len == 0) { + return false; + } + + u8 *s = str.text + len; + return gb_memcompare(s, ext.text, ext.len) == 0; } bool string_contains_char(String s, u8 c) { diff --git a/src/tokenizer.c b/src/tokenizer.c index 92256f021..766e8b912 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -107,12 +107,12 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token_vector, "vector"), \ TOKEN_KIND(Token_map, "map"), \ - TOKEN_KIND(Token_static, "static"), \ - TOKEN_KIND(Token_dynamic, "dynamic"), \ + /* TOKEN_KIND(Token_static, "static"), */ \ + /* TOKEN_KIND(Token_dynamic, "dynamic"), */ \ TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_no_alias, "no_alias"), \ - /* TOKEN_KIND(Token_mutable, "mutable"), */ \ - /* TOKEN_KIND(Token_immutable, "immutable"), */\ + /* TOKEN_KIND(Token_mutable, "mutable"), */ \ + /* TOKEN_KIND(Token_immutable, "immutable"), */ \ TOKEN_KIND(Token_thread_local, "thread_local"), \ TOKEN_KIND(Token_cast, "cast"), \ TOKEN_KIND(Token_transmute, "transmute"), \ diff --git a/src/types.c b/src/types.c index 71888a372..af8d4dd37 100644 --- a/src/types.c +++ b/src/types.c @@ -102,12 +102,12 @@ typedef struct TypeRecord { Entity **fields_in_src_order; // Entity_Variable i64 custom_align; // NOTE(bill): Only used in structs at the moment + Entity * names; Type * enum_base_type; Entity * enum_count; Entity * enum_min_value; Entity * enum_max_value; - Entity * enum_names; } TypeRecord; #define TYPE_KINDS \ @@ -1318,6 +1318,14 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n return sel; } if (is_type) { + if (type->kind == Type_Record) { + if (type->Record.names != NULL && + str_eq(field_name, str_lit("names"))) { + sel.entity = type->Record.names; + return sel; + } + } + 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 @@ -1347,10 +1355,6 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = type->Record.enum_max_value; return sel; } - if (str_eq(field_name, str_lit("names"))) { - sel.entity = type->Record.enum_names; - return sel; - } } for (isize i = 0; i < type->Record.field_count; i++) { diff --git a/src/unicode.c b/src/unicode.c index e4bf28be8..d65f2f2ae 100644 --- a/src/unicode.c +++ b/src/unicode.c @@ -39,28 +39,3 @@ bool rune_is_whitespace(Rune r) { } return false; } - - -bool is_string_an_identifier(String s) { - isize offset = 0; - if (s.len < 1) { - return false; - } - while (offset < s.len) { - bool ok = false; - Rune r = -1; - isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r); - if (offset == 0) { - ok = rune_is_letter(r); - } else { - ok = rune_is_letter(r) || rune_is_digit(r); - } - - if (!ok) { - return false; - } - offset += size; - } - - return offset == s.len; -}