From 3148acf6a69868ddec0780daa293866fe079b7d4 Mon Sep 17 00:00:00 2001 From: dozn Date: Mon, 17 Mar 2025 01:51:01 -0700 Subject: [core:encoding/json] When Unmarshalling, Only Match Struct Tags If Present --- core/encoding/json/unmarshal.odin | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'core/encoding') diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index 57371e360..a5f3bd8c6 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -390,6 +390,9 @@ unmarshal_expect_token :: proc(p: ^Parser, kind: Token_Kind, loc := #caller_loca return prev } +// Struct tags can include not only the name of the JSON key, but also a tag such as `omitempty`. +// Example: `json:"key_name,omitempty"` +// This returns the first field as `json_name`, and the rest are returned as `extra`. @(private) json_name_from_tag_value :: proc(value: string) -> (json_name, extra: string) { json_name = value @@ -425,12 +428,6 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm defer delete(key, p.allocator) unmarshal_expect_token(p, .Colon) - - field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool { - prev_set := field_used[offset/8] & byte(offset&7) != 0 - field_used[offset/8] |= byte(offset&7) - return prev_set - } field_used_bytes := (reflect.size_of_typeid(ti.id)+7)/8 field_used := intrinsics.alloca(field_used_bytes + 1, 1) // + 1 to not overflow on size_of 0 types. @@ -449,7 +446,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm if use_field_idx < 0 { for field, field_idx in fields { - if key == field.name { + tag_value := reflect.struct_tag_get(field.tag, "json") + json_name, _ := json_name_from_tag_value(tag_value) + if json_name == "" && key == field.name { use_field_idx = field_idx break } @@ -470,7 +469,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm } } - if field.name == key || (field.tag != "" && reflect.struct_tag_get(field.tag, "json") == key) { + tag_value := reflect.struct_tag_get(field.tag, "json") + json_name, _ := json_name_from_tag_value(tag_value) + if (json_name == "" && field.name == key) || json_name == key { offset = field.offset type = field.type found = true @@ -492,6 +493,11 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm } if field_found { + field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool { + prev_set := field_used[offset/8] & byte(offset&7) != 0 + field_used[offset/8] |= byte(offset&7) + return prev_set + } if field_test(field_used, offset) { return .Multiple_Use_Field } -- cgit v1.2.3 From e4bc9677af62c74bb23f4c00d82d2a685ce64e50 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 22 Mar 2025 00:20:00 +0100 Subject: fix unmarshalling bit sets in json Fixes #4761 --- core/encoding/json/unmarshal.odin | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'core/encoding') diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index 57371e360..151bd69c3 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -117,9 +117,25 @@ assign_int :: proc(val: any, i: $T) -> bool { case uint: dst = uint (i) case uintptr: dst = uintptr(i) case: + is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool { + if ti == nil { + return false + } + t := runtime.type_info_base(ti) + #partial switch info in t.variant { + case runtime.Type_Info_Integer: + switch info.endianness { + case .Platform: return false + case .Little: return ODIN_ENDIAN != .Little + case .Big: return ODIN_ENDIAN != .Big + } + } + return false + } + ti := type_info_of(v.id) - if _, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok { - do_byte_swap := !reflect.bit_set_is_big_endian(v) + if info, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok { + do_byte_swap := is_bit_set_different_endian_to_platform(info.underlying) switch ti.size * 8 { case 0: // no-op. case 8: -- cgit v1.2.3 From f7c4c80ef3e50d72e2ec499ef395ed19c514d512 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 5 Apr 2025 16:36:26 +0200 Subject: Fix broken examples in documentation tester. No more: ``` We could not find the procedure "pkg_foo_example :: proc()" needed to test the example created for "pkg.foo" The following procedures were found: bar() ``` --- core/container/intrusive/list/intrusive_list.odin | 18 +-- core/encoding/uuid/generation.odin | 4 +- core/flags/util.odin | 2 +- core/math/rand/rand.odin | 2 +- core/simd/simd.odin | 168 +++++++++++++++------- core/strings/strings.odin | 2 +- 6 files changed, 127 insertions(+), 69 deletions(-) (limited to 'core/encoding') diff --git a/core/container/intrusive/list/intrusive_list.odin b/core/container/intrusive/list/intrusive_list.odin index 5b29efb22..1e116ef18 100644 --- a/core/container/intrusive/list/intrusive_list.odin +++ b/core/container/intrusive/list/intrusive_list.odin @@ -278,19 +278,19 @@ Example: iterate_next_example :: proc() { l: list.List - one := My_Struct{value=1} - two := My_Struct{value=2} + one := My_Next_Struct{value=1} + two := My_Next_Struct{value=2} list.push_back(&l, &one.node) list.push_back(&l, &two.node) - it := list.iterator_head(l, My_Struct, "node") + it := list.iterator_head(l, My_Next_Struct, "node") for num in list.iterate_next(&it) { fmt.println(num.value) } } - My_Struct :: struct { + My_Next_Struct :: struct { node : list.Node, value: int, } @@ -325,22 +325,22 @@ Example: import "core:fmt" import "core:container/intrusive/list" - iterate_next_example :: proc() { + iterate_prev_example :: proc() { l: list.List - one := My_Struct{value=1} - two := My_Struct{value=2} + one := My_Prev_Struct{value=1} + two := My_Prev_Struct{value=2} list.push_back(&l, &one.node) list.push_back(&l, &two.node) - it := list.iterator_tail(l, My_Struct, "node") + it := list.iterator_tail(l, My_Prev_Struct, "node") for num in list.iterate_prev(&it) { fmt.println(num.value) } } - My_Struct :: struct { + My_Prev_Struct :: struct { node : list.Node, value: int, } diff --git a/core/encoding/uuid/generation.odin b/core/encoding/uuid/generation.odin index 7c9d4b80c..b210f6a52 100644 --- a/core/encoding/uuid/generation.odin +++ b/core/encoding/uuid/generation.odin @@ -240,7 +240,7 @@ Example: import "core:encoding/uuid" import "core:fmt" - main :: proc() { + generate_v8_hash_bytes_example :: proc() { my_uuid := uuid.generate_v8_hash(uuid.Namespace_DNS, "www.odin-lang.org", .SHA256) my_uuid_string := uuid.to_string(my_uuid, context.temp_allocator) fmt.println(my_uuid_string) @@ -306,7 +306,7 @@ Example: import "core:encoding/uuid" import "core:fmt" - main :: proc() { + generate_v8_hash_string_example :: proc() { my_uuid := uuid.generate_v8_hash(uuid.Namespace_DNS, "www.odin-lang.org", .SHA256) my_uuid_string := uuid.to_string(my_uuid, context.temp_allocator) fmt.println(my_uuid_string) diff --git a/core/flags/util.odin b/core/flags/util.odin index c182289be..ce7e2e36c 100644 --- a/core/flags/util.odin +++ b/core/flags/util.odin @@ -95,7 +95,7 @@ Example: import "core:flags" import "core:fmt" - subtag_example :: proc() { + get_subtag_example :: proc() { args_tag := "precision=3,signed" precision, has_precision := flags.get_subtag(args_tag, "precision") diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 537256d32..c556702bd 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -33,7 +33,7 @@ Example: import "core:math/rand" import "core:fmt" - set_global_seed_example :: proc() { + reset_example :: proc() { rand.reset(1) fmt.println(rand.uint64()) } diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 0bce4e16a..37cc19ebd 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -1328,13 +1328,18 @@ Example: // to load valid positions of the `ptrs` array, and the array of defaults which // will have `127` in each position as the default value. - v1 := [4] f32 {1, 2, 3, 4}; - v2 := [4] f32 {9, 10,11,12}; - ptrs := #simd [4]rawptr { &v1[1], nil, &v2[1], nil } - mask := #simd [4]bool { true, false, true, false } - defaults := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } - res := simd.gather(ptrs, defaults, mask) - fmt.println(res) + import "core:fmt" + import "core:simd" + + simd_gather_example :: proc() { + v1 := [4] f32 {1, 2, 3, 4}; + v2 := [4] f32 {9, 10,11,12}; + ptrs := #simd [4]rawptr { &v1[1], nil, &v2[1], nil } + mask := #simd [4]bool { true, false, true, false } + defaults := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } + res := simd.gather(ptrs, defaults, mask) + fmt.println(res) + } Output: @@ -1396,14 +1401,19 @@ Example: // vectors. The addresses of store destinations are written to the first and the // third argument of the `ptr` vector, and the `mask` is set accordingly. - v1 := [4] f32 {1, 2, 3, 4}; - v2 := [4] f32 {5, 6, 7, 8}; - ptrs := #simd [4]rawptr { &v1[1], nil, &v2[1], nil } - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } - simd.scatter(ptrs, vals, mask) - fmt.println(v1) - fmt.println(v2) + import "core:fmt" + import "core:simd" + + simd_scatter_example :: proc() { + v1 := [4] f32 {1, 2, 3, 4}; + v2 := [4] f32 {5, 6, 7, 8}; + ptrs := #simd [4]rawptr { &v1[1], nil, &v2[1], nil } + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } + simd.scatter(ptrs, vals, mask) + fmt.println(v1) + fmt.println(v2) + } Output: @@ -1467,11 +1477,16 @@ Example: // third value (selected by the mask). The masked-off values are given the value // of 127 (`0x7f`). - src := [4] f32 {1, 2, 3, 4}; - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } - res := simd.masked_load(&src, vals, mask) - fmt.println(res) + import "core:fmt" + import "core:simd" + + simd_masked_load_example :: proc() { + src := [4] f32 {1, 2, 3, 4}; + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } + res := simd.masked_load(&src, vals, mask) + fmt.println(res) + } Output: @@ -1526,11 +1541,16 @@ Example: // Example below stores the value 127 into the first and the third slot of the // vector `v`. - v := [4] f32 {1, 2, 3, 4}; - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } - simd.masked_store(&v, vals, mask) - fmt.println(v) + import "core:fmt" + import "core:simd" + + simd_masked_store_example :: proc() { + v := [4] f32 {1, 2, 3, 4}; + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } + simd.masked_store(&v, vals, mask) + fmt.println(v) + } Output: @@ -1600,11 +1620,16 @@ Example: // the third lane of the result vector. All the other lanes of the result vector // will be initialized to the default value `127`. - v := [2] f64 {1, 2}; - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f64 { 0x7f, 0x7f, 0x7f, 0x7f } - res := simd.masked_expand_load(&v, vals, mask) - fmt.println(res) + import "core:fmt" + import "core:simd" + + simd_masked_expand_load_example :: proc() { + v := [2] f64 {1, 2}; + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f64 { 0x7f, 0x7f, 0x7f, 0x7f } + res := simd.masked_expand_load(&v, vals, mask) + fmt.println(res) + } Output: @@ -1661,11 +1686,16 @@ Example: // vector, the first and the third value. The items in the mask are set to `true` // in those lanes. - v := [2] f64 { }; - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f64 { 1, 2, 3, 4 } - simd.masked_compress_store(&v, vals, mask) - fmt.println(v) + import "core:fmt" + import "core:simd" + + simd_masked_compress_store_example :: proc() { + v := [2] f64 { }; + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f64 { 1, 2, 3, 4 } + simd.masked_compress_store(&v, vals, mask) + fmt.println(v) + } Output: @@ -1949,14 +1979,19 @@ Example: // The example below shows how the indices are used to determine which lanes of the // input vector get written into the result vector. - - x := #simd [4]f32 { 1.5, 2.5, 3.5, 4.5 } - res := simd.swizzle(x, 0, 3, 1, 1) - fmt.println("res") + + import "core:fmt" + import "core:simd" + + swizzle_example :: proc() { + x := #simd [4]f32 { 1.5, 2.5, 3.5, 4.5 } + res := simd.swizzle(x, 0, 3, 1, 1) + fmt.println(res) + } Output: - [ 1.5, 3.5, 2.5, 2.5 ] + <1.5, 4.5, 2.5, 2.5> The graphical representation of the operation is as follows. The `idx` vector in the picture represents the `indices` parameter: @@ -2013,8 +2048,14 @@ Example: // Since lanes 0, 1, 4, 7 contain negative numbers, the most significant // bits for them will be set. - v := #simd [8]i32 { -1, -2, +3, +4, -5, +6, +7, -8 } - fmt.println(simd.extract_msbs(v)) + + import "core:fmt" + import "core:simd" + + simd_extract_msbs_example :: proc() { + v := #simd [8]i32 { -1, -2, +3, +4, -5, +6, +7, -8 } + fmt.println(simd.extract_msbs(v)) + } Output: @@ -2052,8 +2093,14 @@ Example: // Since lanes 0, 2, 4, 6 contain odd integers, the least significant bits // for these lanes are set. - v := #simd [8]i32 { -1, -2, +3, +4, -5, +6, +7, -8 } - fmt.println(simd.extract_lsbs(v)) + + import "core:fmt" + import "core:simd" + + simd_extract_lsbs_example :: proc() { + v := #simd [8]i32 { -1, -2, +3, +4, -5, +6, +7, -8 } + fmt.println(simd.extract_lsbs(v)) + } Output: @@ -2097,15 +2144,20 @@ Example: // The example below shows how the indices are used to determine lanes of the // input vector that are shuffled into the result vector. - - a := #simd [4]f32 { 1, 2, 3, 4 } - b := #simd [4]f32 { 5, 6, 7, 8 } - res := simd.shuffle(a, b, 0, 4, 2, 5) - fmt.println("res") + + import "core:fmt" + import "core:simd" + + simd_shuffle_example :: proc() { + a := #simd [4]f32 { 1, 2, 3, 4 } + b := #simd [4]f32 { 5, 6, 7, 8 } + res := simd.shuffle(a, b, 0, 4, 2, 5) + fmt.println(res) + } Output: - [ 1, 5, 3, 6 ] + <1, 5, 3, 6> The graphical representation of the operation is as follows. The `idx` vector in the picture represents the `indices` parameter: @@ -2163,14 +2215,20 @@ Example: // The following example selects values from the two input vectors, `a` and `b` // into a single vector. - a := #simd [4] f64 { 1,2,3,4 } - b := #simd [4] f64 { 5,6,7,8 } - cond := #simd[4] int { 1, 0, 1, 0 } - fmt.println(simd.select(cond,a,b)) + + import "core:fmt" + import "core:simd" + + simd_select_example :: proc() { + a := #simd [4] f64 { 1,2,3,4 } + b := #simd [4] f64 { 5,6,7,8 } + cond := #simd[4] int { 1, 0, 1, 0 } + fmt.println(simd.select(cond,a,b)) + } Output: - [ 1, 6, 3, 8 ] + <1, 6, 3, 8> Graphically, the operation looks as follows. The `t` and `f` represent the `true` and `false` vectors respectively: diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 52230f572..247638cd6 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -787,7 +787,7 @@ Example: import "core:fmt" import "core:strings" - cut_example :: proc() { + cut_clone_example :: proc() { fmt.println(strings.cut_clone("some example text", 0, 4)) // -> "some" fmt.println(strings.cut_clone("some example text", 2, 2)) // -> "me" fmt.println(strings.cut_clone("some example text", 5, 7)) // -> "example" -- cgit v1.2.3 From 3287e1b0f0195401f6db8ffe9b94be67b352af57 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 7 Apr 2025 13:19:00 +0200 Subject: Fix HXA defer warning --- core/encoding/hxa/read.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'core/encoding') diff --git a/core/encoding/hxa/read.odin b/core/encoding/hxa/read.odin index a679946f8..6dde16848 100644 --- a/core/encoding/hxa/read.odin +++ b/core/encoding/hxa/read.odin @@ -79,7 +79,6 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato read_meta :: proc(r: ^Reader, capacity: u32le, allocator := context.allocator, loc := #caller_location) -> (meta_data: []Meta, err: Read_Error) { meta_data = make([]Meta, int(capacity), allocator=allocator) count := 0 - defer meta_data = meta_data[:count] for &m in meta_data { m.name = read_name(r) or_return @@ -105,6 +104,7 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato count += 1 } + meta_data = meta_data[:count] return } @@ -112,7 +112,6 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato stack_count := read_value(r, u32le) or_return layer_count := 0 layers = make(Layer_Stack, stack_count, allocator=allocator, loc=loc) - defer layers = layers[:layer_count] for &layer in layers { layer.name = read_name(r) or_return layer.components = read_value(r, u8) or_return @@ -136,6 +135,7 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato layer_count += 1 } + layers = layers[:layer_count] return } -- cgit v1.2.3 From 062a3c2fae3712c60af00798a0815509a732790b Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 19 Apr 2025 20:25:44 +0200 Subject: Fix parsing of CDATA tags (#5059) Fixes #5054 --- core/encoding/entity/entity.odin | 54 ++++++++-------- core/encoding/xml/tokenizer.odin | 38 ++++++------ core/encoding/xml/xml_reader.odin | 99 +++++++++++++++++------------- tests/core/assets/XML/entities.html | 5 ++ tests/core/encoding/xml/test_core_xml.odin | 12 ++-- 5 files changed, 110 insertions(+), 98 deletions(-) (limited to 'core/encoding') diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin index d2f1d46b2..cb8fa8611 100644 --- a/core/encoding/entity/entity.odin +++ b/core/encoding/entity/entity.odin @@ -108,7 +108,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := it couldn't have been part of an XML tag body to be decoded here. Keep in mind that we could already *be* inside a CDATA tag. - If so, write `>` as a literal and continue. + If so, write `<` as a literal and continue. */ if in_data { write_rune(&builder, '<') @@ -119,11 +119,9 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := case ']': // If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag. if in_data { - if t.read_offset + len(CDATA_END) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { - in_data = false - t.read_offset += len(CDATA_END) - 1 - } + if strings.has_prefix(t.src[t.offset:], CDATA_END) { + in_data = false + t.read_offset += len(CDATA_END) - 1 } continue } else { @@ -297,40 +295,40 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X assert(t != nil && t.r == '<') if t.read_offset + len(CDATA_START) >= len(t.src) { return false, .None } - if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { - t.read_offset += len(CDATA_START) - 1 - + s := string(t.src[t.offset:]) + if strings.has_prefix(s, CDATA_START) { if .Unbox_CDATA in options && .Decode_CDATA in options { // We're unboxing _and_ decoding CDATA + t.read_offset += len(CDATA_START) - 1 return true, .None } - // CDATA is passed through. - offset := t.offset - - // Scan until end of CDATA. + // CDATA is passed through. Scan until end of CDATA. + start_offset := t.offset + t.read_offset += len(CDATA_START) for { - advance(t) or_return - if t.r < 0 { return true, .CDATA_Not_Terminated } - - if t.read_offset + len(CDATA_END) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { - t.read_offset += len(CDATA_END) - 1 + advance(t) + if t.r < 0 { + // error(t, offset, "[scan_string] CDATA was not terminated\n") + return true, .CDATA_Not_Terminated + } - cdata := string(t.src[offset : t.read_offset]) - - if .Unbox_CDATA in options { - cdata = cdata[len(CDATA_START):] - cdata = cdata[:len(cdata) - len(CDATA_END)] - } + // Scan until the end of a CDATA tag. + if s = string(t.src[t.read_offset:]); strings.has_prefix(s, CDATA_END) { + t.read_offset += len(CDATA_END) + cdata := string(t.src[start_offset:t.read_offset]) - write_string(builder, cdata) - return false, .None + if .Unbox_CDATA in options { + cdata = cdata[len(CDATA_START):] + cdata = cdata[:len(cdata) - len(CDATA_END)] } + write_string(builder, cdata) + return false, .None } } - } else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START { + + } else if strings.has_prefix(s, COMMENT_START) { t.read_offset += len(COMMENT_START) // Comment is passed through by default. offset := t.offset diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index a2bbaf28e..3ef9a6388 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -16,6 +16,7 @@ package encoding_xml import "core:fmt" import "core:unicode" import "core:unicode/utf8" +import "core:strings" Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any) @@ -121,7 +122,7 @@ default_error_handler :: proc(pos: Pos, msg: string, args: ..any) { error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { pos := offset_to_pos(t, offset) if t.err != nil { - t.err(pos, msg, ..args) + t.err(pos=pos, fmt=msg, args=args) } t.error_count += 1 } @@ -268,32 +269,27 @@ scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) { // Skip CDATA skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) { - if t.read_offset + len(CDATA_START) >= len(t.src) { - // Can't be the start of a CDATA tag. + if s := string(t.src[t.offset:]); !strings.has_prefix(s, CDATA_START) { return .None } - if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { - t.read_offset += len(CDATA_START) - offset := t.offset + t.read_offset += len(CDATA_START) + offset := t.offset - cdata_scan: for { - advance_rune(t) - if t.ch < 0 { - error(t, offset, "[scan_string] CDATA was not terminated\n") - return .Premature_EOF - } + cdata_scan: for { + advance_rune(t) + if t.ch < 0 { + error(t, offset, "[scan_string] CDATA was not terminated\n") + return .Premature_EOF + } - // Scan until the end of a CDATA tag. - if t.read_offset + len(CDATA_END) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { - t.read_offset += len(CDATA_END) - break cdata_scan - } - } + // Scan until the end of a CDATA tag. + if s := string(t.src[t.read_offset:]); strings.has_prefix(s, CDATA_END) { + t.read_offset += len(CDATA_END) + break cdata_scan } } - return + return .None } @(optimization_mode="favor_size") @@ -393,6 +389,8 @@ scan :: proc(t: ^Tokenizer, multiline_string := false) -> Token { case '/': kind = .Slash case '-': kind = .Dash case ':': kind = .Colon + case '[': kind = .Open_Bracket + case ']': kind = .Close_Bracket case '"', '\'': kind = .Invalid diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index b8c8b13a4..60744357c 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -56,7 +56,7 @@ Option_Flag :: enum { Option_Flags :: bit_set[Option_Flag; u16] Document :: struct { - elements: [dynamic]Element, + elements: [dynamic]Element `fmt:"v,element_count"`, element_count: Element_ID, prologue: Attributes, @@ -70,15 +70,15 @@ Document :: struct { // If we encounter comments before the root node, and the option to intern comments is given, this is where they'll live. // Otherwise they'll be in the element tree. - comments: [dynamic]string, + comments: [dynamic]string `fmt:"-"`, // Internal - tokenizer: ^Tokenizer, - allocator: mem.Allocator, + tokenizer: ^Tokenizer `fmt:"-"`, + allocator: mem.Allocator `fmt:"-"`, // Input. Either the original buffer, or a copy if `.Input_May_Be_Modified` isn't specified. - input: []u8, - strings_to_free: [dynamic]string, + input: []u8 `fmt:"-"`, + strings_to_free: [dynamic]string `fmt:"-"`, } Element :: struct { @@ -195,7 +195,6 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha loop: for { skip_whitespace(t) - // NOTE(Jeroen): This is faster as a switch. switch t.ch { case '<': // Consume peeked `<` @@ -306,9 +305,13 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha } } + case .Open_Bracket: + // This could be a CDATA tag part of a tag's body. Unread the ` (attr: Attribute, offset: int, err: E t := doc.tokenizer key := expect(t, .Ident) or_return - offset = t.offset - len(key.text) - _ = expect(t, .Eq) or_return value := expect(t, .String, multiline_string=true) or_return @@ -591,6 +561,47 @@ parse_doctype :: proc(doc: ^Document) -> (err: Error) { return .None } +parse_body :: proc(doc: ^Document, element: Element_ID, opts: Options) -> (err: Error) { + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + body_text := scan_string(t, t.offset) or_return + needs_processing := .Unbox_CDATA in opts.flags + needs_processing |= .Decode_SGML_Entities in opts.flags + + if !needs_processing { + append(&doc.elements[element].value, body_text) + return + } + + decode_opts := entity.XML_Decode_Options{} + if .Keep_Tag_Body_Comments not_in opts.flags { + decode_opts += { .Comment_Strip } + } + + if .Decode_SGML_Entities not_in opts.flags { + decode_opts += { .No_Entity_Decode } + } + + if .Unbox_CDATA in opts.flags { + decode_opts += { .Unbox_CDATA } + if .Decode_SGML_Entities in opts.flags { + decode_opts += { .Decode_CDATA } + } + } + + decoded, decode_err := entity.decode_xml(body_text, decode_opts) + if decode_err == .None { + append(&doc.elements[element].value, decoded) + append(&doc.strings_to_free, decoded) + } else { + append(&doc.elements[element].value, body_text) + } + + return +} + Element_ID :: u32 new_element :: proc(doc: ^Document) -> (id: Element_ID) { @@ -609,4 +620,4 @@ new_element :: proc(doc: ^Document) -> (id: Element_ID) { cur := doc.element_count doc.element_count += 1 return cur -} +} \ No newline at end of file diff --git a/tests/core/assets/XML/entities.html b/tests/core/assets/XML/entities.html index 05a6b107e..a60f45070 100644 --- a/tests/core/assets/XML/entities.html +++ b/tests/core/assets/XML/entities.html @@ -25,5 +25,10 @@
| | | fj ` \ ® ϱ ∳ ⁏
+
HHellope!
+
HHellope!
+
HHellope!
+
HHellope!
+
HHellope!
\ No newline at end of file diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index c0e4329bd..409a8c9c0 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -114,7 +114,7 @@ xml_test_entities :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x05373317, + crc32 = 0x48f41216, }) } @@ -128,7 +128,7 @@ xml_test_entities_unbox :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x350ca83e, + crc32 = 0xd0567818, }) } @@ -142,7 +142,7 @@ xml_test_entities_unbox_decode :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x7f58db7d, + crc32 = 0x68d2571e, }) } @@ -191,7 +191,7 @@ xml_test_unicode :: proc(t: ^testing.T) { } @(private) -run_test :: proc(t: ^testing.T, test: TEST) { +run_test :: proc(t: ^testing.T, test: TEST, loc := #caller_location) { path := strings.concatenate({TEST_SUITE_PATH, test.filename}) defer delete(path) @@ -205,10 +205,10 @@ run_test :: proc(t: ^testing.T, test: TEST) { crc32 := hash.crc32(tree_bytes) failed := err != test.err - testing.expectf(t, err == test.err, "%v: Expected return value %v, got %v", test.filename, test.err, err) + testing.expectf(t, err == test.err, "%v: Expected return value %v, got %v", test.filename, test.err, err, loc=loc) failed |= crc32 != test.crc32 - testing.expectf(t, crc32 == test.crc32, "%v: Expected CRC 0x%08x, got 0x%08x, with options %v", test.filename, test.crc32, crc32, test.options) + testing.expectf(t, crc32 == test.crc32, "%v: Expected CRC 0x%08x, got 0x%08x, with options %v", test.filename, test.crc32, crc32, test.options, loc=loc) if failed { // Don't fully print big trees. -- cgit v1.2.3 From ab5ca087a7a64e2085edd955b403da0e8bc2c4f0 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 19 Apr 2025 23:44:02 +0200 Subject: Add comment --- core/encoding/xml/xml_reader.odin | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'core/encoding') diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 60744357c..d616be9dc 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -308,6 +308,10 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha case .Open_Bracket: // This could be a CDATA tag part of a tag's body. Unread the ` Date: Mon, 28 Apr 2025 22:03:20 +0300 Subject: Fix typo in private function --- core/encoding/json/tokenizer.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'core/encoding') diff --git a/core/encoding/json/tokenizer.odin b/core/encoding/json/tokenizer.odin index e46d879a7..ad928b7d9 100644 --- a/core/encoding/json/tokenizer.odin +++ b/core/encoding/json/tokenizer.odin @@ -101,7 +101,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { } } - scan_espace :: proc(t: ^Tokenizer) -> bool { + scan_escape :: proc(t: ^Tokenizer) -> bool { switch t.r { case '"', '\'', '\\', '/', 'b', 'n', 'r', 't', 'f': next_rune(t) @@ -310,7 +310,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { break } if r == '\\' { - scan_espace(t) + scan_escape(t) } } -- cgit v1.2.3 From 4f00224dd2908dc21c5412eba9167c63a217bf33 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 29 Apr 2025 01:10:15 +0200 Subject: Add cbor.unmarshal_from_bytes taking a []byte --- core/encoding/cbor/unmarshal.odin | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'core/encoding') diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin index c39255d9d..f752c5275 100644 --- a/core/encoding/cbor/unmarshal.odin +++ b/core/encoding/cbor/unmarshal.odin @@ -29,6 +29,7 @@ an input. unmarshal :: proc { unmarshal_from_reader, unmarshal_from_string, + unmarshal_from_bytes, } unmarshal_from_reader :: proc(r: io.Reader, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { @@ -51,6 +52,11 @@ unmarshal_from_string :: proc(s: string, ptr: ^$T, flags := Decoder_Flags{}, all return } +// Unmarshals from a slice of bytes, see docs on the proc group `Unmarshal` for more info. +unmarshal_from_bytes :: proc(bytes: []byte, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { + return unmarshal_from_string(string(bytes), ptr, flags, allocator, temp_allocator, loc) +} + unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { d := d -- cgit v1.2.3 From 3f5e09a0df18201e30a202a2074dc0c0a283c01b Mon Sep 17 00:00:00 2001 From: Barinzaya Date: Tue, 29 Apr 2025 08:19:43 -0400 Subject: Fixed an overflow when decoding a large CBOR slice. The initial allocation for the slice is limited to prevent untrusted data from forcing a huge allocation, but then the dynamic array was created with a capacity of the unlimited length, rather than the actual capacity of the allocation. This was causing a buffer overrun. --- core/encoding/cbor/unmarshal.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/encoding') diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin index f752c5275..24bbd8137 100644 --- a/core/encoding/cbor/unmarshal.odin +++ b/core/encoding/cbor/unmarshal.odin @@ -493,7 +493,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align, allocator=allocator, loc=loc) or_return defer if err != nil { mem.free_bytes(data, allocator=allocator, loc=loc) } - da := mem.Raw_Dynamic_Array{raw_data(data), 0, length, context.allocator } + da := mem.Raw_Dynamic_Array{raw_data(data), 0, scap, context.allocator } assign_array(d, &da, t.elem, length) or_return -- cgit v1.2.3 From a9df1b1cde1037d030f4e823ce576dfd9bcf9c97 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 20 May 2025 15:41:35 -0400 Subject: Rename `core:encoding/ansi` to `core:terminal/ansi` --- core/encoding/ansi/ansi.odin | 137 ---------------------------------- core/encoding/ansi/doc.odin | 20 ----- core/log/file_console_logger.odin | 2 +- core/terminal/ansi/ansi.odin | 137 ++++++++++++++++++++++++++++++++++ core/terminal/ansi/doc.odin | 20 +++++ core/testing/reporting.odin | 2 +- core/testing/runner.odin | 2 +- core/testing/signal_handler_libc.odin | 4 +- examples/all/all_main.odin | 4 +- 9 files changed, 164 insertions(+), 164 deletions(-) delete mode 100644 core/encoding/ansi/ansi.odin delete mode 100644 core/encoding/ansi/doc.odin create mode 100644 core/terminal/ansi/ansi.odin create mode 100644 core/terminal/ansi/doc.odin (limited to 'core/encoding') diff --git a/core/encoding/ansi/ansi.odin b/core/encoding/ansi/ansi.odin deleted file mode 100644 index 5550a1671..000000000 --- a/core/encoding/ansi/ansi.odin +++ /dev/null @@ -1,137 +0,0 @@ -package ansi - -BEL :: "\a" // Bell -BS :: "\b" // Backspace -ESC :: "\e" // Escape - -// Fe Escape sequences - -CSI :: ESC + "[" // Control Sequence Introducer -OSC :: ESC + "]" // Operating System Command -ST :: ESC + "\\" // String Terminator - -// CSI sequences - -CUU :: "A" // Cursor Up -CUD :: "B" // Cursor Down -CUF :: "C" // Cursor Forward -CUB :: "D" // Cursor Back -CNL :: "E" // Cursor Next Line -CPL :: "F" // Cursor Previous Line -CHA :: "G" // Cursor Horizontal Absolute -CUP :: "H" // Cursor Position -ED :: "J" // Erase in Display -EL :: "K" // Erase in Line -SU :: "S" // Scroll Up -SD :: "T" // Scroll Down -HVP :: "f" // Horizontal Vertical Position -SGR :: "m" // Select Graphic Rendition -AUX_ON :: "5i" // AUX Port On -AUX_OFF :: "4i" // AUX Port Off -DSR :: "6n" // Device Status Report - -// CSI: private sequences - -SCP :: "s" // Save Current Cursor Position -RCP :: "u" // Restore Saved Cursor Position -DECAWM_ON :: "?7h" // Auto Wrap Mode (Enabled) -DECAWM_OFF :: "?7l" // Auto Wrap Mode (Disabled) -DECTCEM_SHOW :: "?25h" // Text Cursor Enable Mode (Visible) -DECTCEM_HIDE :: "?25l" // Text Cursor Enable Mode (Invisible) - -// SGR sequences - -RESET :: "0" -BOLD :: "1" -FAINT :: "2" -ITALIC :: "3" // Not widely supported. -UNDERLINE :: "4" -BLINK_SLOW :: "5" -BLINK_RAPID :: "6" // Not widely supported. -INVERT :: "7" // Also known as reverse video. -HIDE :: "8" // Not widely supported. -STRIKE :: "9" -FONT_PRIMARY :: "10" -FONT_ALT1 :: "11" -FONT_ALT2 :: "12" -FONT_ALT3 :: "13" -FONT_ALT4 :: "14" -FONT_ALT5 :: "15" -FONT_ALT6 :: "16" -FONT_ALT7 :: "17" -FONT_ALT8 :: "18" -FONT_ALT9 :: "19" -FONT_FRAKTUR :: "20" // Rarely supported. -UNDERLINE_DOUBLE :: "21" // May be interpreted as "disable bold." -NO_BOLD_FAINT :: "22" -NO_ITALIC_BLACKLETTER :: "23" -NO_UNDERLINE :: "24" -NO_BLINK :: "25" -PROPORTIONAL_SPACING :: "26" -NO_REVERSE :: "27" -NO_HIDE :: "28" -NO_STRIKE :: "29" - -FG_BLACK :: "30" -FG_RED :: "31" -FG_GREEN :: "32" -FG_YELLOW :: "33" -FG_BLUE :: "34" -FG_MAGENTA :: "35" -FG_CYAN :: "36" -FG_WHITE :: "37" -FG_COLOR :: "38" -FG_COLOR_8_BIT :: "38;5" // Followed by ";n" where n is in 0..=255 -FG_COLOR_24_BIT :: "38;2" // Followed by ";r;g;b" where r,g,b are in 0..=255 -FG_DEFAULT :: "39" - -BG_BLACK :: "40" -BG_RED :: "41" -BG_GREEN :: "42" -BG_YELLOW :: "43" -BG_BLUE :: "44" -BG_MAGENTA :: "45" -BG_CYAN :: "46" -BG_WHITE :: "47" -BG_COLOR :: "48" -BG_COLOR_8_BIT :: "48;5" // Followed by ";n" where n is in 0..=255 -BG_COLOR_24_BIT :: "48;2" // Followed by ";r;g;b" where r,g,b are in 0..=255 -BG_DEFAULT :: "49" - -NO_PROPORTIONAL_SPACING :: "50" -FRAMED :: "51" -ENCIRCLED :: "52" -OVERLINED :: "53" -NO_FRAME_ENCIRCLE :: "54" -NO_OVERLINE :: "55" - -// SGR: non-standard bright colors - -FG_BRIGHT_BLACK :: "90" // Also known as grey. -FG_BRIGHT_RED :: "91" -FG_BRIGHT_GREEN :: "92" -FG_BRIGHT_YELLOW :: "93" -FG_BRIGHT_BLUE :: "94" -FG_BRIGHT_MAGENTA :: "95" -FG_BRIGHT_CYAN :: "96" -FG_BRIGHT_WHITE :: "97" - -BG_BRIGHT_BLACK :: "100" // Also known as grey. -BG_BRIGHT_RED :: "101" -BG_BRIGHT_GREEN :: "102" -BG_BRIGHT_YELLOW :: "103" -BG_BRIGHT_BLUE :: "104" -BG_BRIGHT_MAGENTA :: "105" -BG_BRIGHT_CYAN :: "106" -BG_BRIGHT_WHITE :: "107" - -// Fp Escape sequences - -DECSC :: ESC + "7" // DEC Save Cursor -DECRC :: ESC + "8" // DEC Restore Cursor - -// OSC sequences - -WINDOW_TITLE :: "2" // Followed by ";" ST. -HYPERLINK :: "8" // Followed by ";[params];" ST. Closed by OSC HYPERLINK ";;" ST. -CLIPBOARD :: "52" // Followed by ";c;" ST. diff --git a/core/encoding/ansi/doc.odin b/core/encoding/ansi/doc.odin deleted file mode 100644 index 966e6be00..000000000 --- a/core/encoding/ansi/doc.odin +++ /dev/null @@ -1,20 +0,0 @@ -/* -package ansi implements constant references to many widely-supported ANSI -escape codes, primarily used in terminal emulators for enhanced graphics, such -as colors, text styling, and animated displays. - -For example, you can print out a line of cyan text like this: - fmt.println(ansi.CSI + ansi.FG_CYAN + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR) - -Multiple SGR (Select Graphic Rendition) codes can be joined by semicolons: - fmt.println(ansi.CSI + ansi.BOLD + ";" + ansi.FG_BLUE + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR) - -If your terminal supports 24-bit true color mode, you can also do this: - fmt.println(ansi.CSI + ansi.FG_COLOR_24_BIT + ";0;255;255" + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR) - -For more information, see: -- [[ https://en.wikipedia.org/wiki/ANSI_escape_code ]] -- [[ https://www.vt100.net/docs/vt102-ug/chapter5.html ]] -- [[ https://invisible-island.net/xterm/ctlseqs/ctlseqs.html ]] -*/ -package ansi diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index f807f321f..0fe5c3477 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -3,11 +3,11 @@ package log import "base:runtime" -import "core:encoding/ansi" import "core:fmt" import "core:strings" import "core:os" import "core:terminal" +import "core:terminal/ansi" import "core:time" Level_Headers := [?]string{ diff --git a/core/terminal/ansi/ansi.odin b/core/terminal/ansi/ansi.odin new file mode 100644 index 000000000..5550a1671 --- /dev/null +++ b/core/terminal/ansi/ansi.odin @@ -0,0 +1,137 @@ +package ansi + +BEL :: "\a" // Bell +BS :: "\b" // Backspace +ESC :: "\e" // Escape + +// Fe Escape sequences + +CSI :: ESC + "[" // Control Sequence Introducer +OSC :: ESC + "]" // Operating System Command +ST :: ESC + "\\" // String Terminator + +// CSI sequences + +CUU :: "A" // Cursor Up +CUD :: "B" // Cursor Down +CUF :: "C" // Cursor Forward +CUB :: "D" // Cursor Back +CNL :: "E" // Cursor Next Line +CPL :: "F" // Cursor Previous Line +CHA :: "G" // Cursor Horizontal Absolute +CUP :: "H" // Cursor Position +ED :: "J" // Erase in Display +EL :: "K" // Erase in Line +SU :: "S" // Scroll Up +SD :: "T" // Scroll Down +HVP :: "f" // Horizontal Vertical Position +SGR :: "m" // Select Graphic Rendition +AUX_ON :: "5i" // AUX Port On +AUX_OFF :: "4i" // AUX Port Off +DSR :: "6n" // Device Status Report + +// CSI: private sequences + +SCP :: "s" // Save Current Cursor Position +RCP :: "u" // Restore Saved Cursor Position +DECAWM_ON :: "?7h" // Auto Wrap Mode (Enabled) +DECAWM_OFF :: "?7l" // Auto Wrap Mode (Disabled) +DECTCEM_SHOW :: "?25h" // Text Cursor Enable Mode (Visible) +DECTCEM_HIDE :: "?25l" // Text Cursor Enable Mode (Invisible) + +// SGR sequences + +RESET :: "0" +BOLD :: "1" +FAINT :: "2" +ITALIC :: "3" // Not widely supported. +UNDERLINE :: "4" +BLINK_SLOW :: "5" +BLINK_RAPID :: "6" // Not widely supported. +INVERT :: "7" // Also known as reverse video. +HIDE :: "8" // Not widely supported. +STRIKE :: "9" +FONT_PRIMARY :: "10" +FONT_ALT1 :: "11" +FONT_ALT2 :: "12" +FONT_ALT3 :: "13" +FONT_ALT4 :: "14" +FONT_ALT5 :: "15" +FONT_ALT6 :: "16" +FONT_ALT7 :: "17" +FONT_ALT8 :: "18" +FONT_ALT9 :: "19" +FONT_FRAKTUR :: "20" // Rarely supported. +UNDERLINE_DOUBLE :: "21" // May be interpreted as "disable bold." +NO_BOLD_FAINT :: "22" +NO_ITALIC_BLACKLETTER :: "23" +NO_UNDERLINE :: "24" +NO_BLINK :: "25" +PROPORTIONAL_SPACING :: "26" +NO_REVERSE :: "27" +NO_HIDE :: "28" +NO_STRIKE :: "29" + +FG_BLACK :: "30" +FG_RED :: "31" +FG_GREEN :: "32" +FG_YELLOW :: "33" +FG_BLUE :: "34" +FG_MAGENTA :: "35" +FG_CYAN :: "36" +FG_WHITE :: "37" +FG_COLOR :: "38" +FG_COLOR_8_BIT :: "38;5" // Followed by ";n" where n is in 0..=255 +FG_COLOR_24_BIT :: "38;2" // Followed by ";r;g;b" where r,g,b are in 0..=255 +FG_DEFAULT :: "39" + +BG_BLACK :: "40" +BG_RED :: "41" +BG_GREEN :: "42" +BG_YELLOW :: "43" +BG_BLUE :: "44" +BG_MAGENTA :: "45" +BG_CYAN :: "46" +BG_WHITE :: "47" +BG_COLOR :: "48" +BG_COLOR_8_BIT :: "48;5" // Followed by ";n" where n is in 0..=255 +BG_COLOR_24_BIT :: "48;2" // Followed by ";r;g;b" where r,g,b are in 0..=255 +BG_DEFAULT :: "49" + +NO_PROPORTIONAL_SPACING :: "50" +FRAMED :: "51" +ENCIRCLED :: "52" +OVERLINED :: "53" +NO_FRAME_ENCIRCLE :: "54" +NO_OVERLINE :: "55" + +// SGR: non-standard bright colors + +FG_BRIGHT_BLACK :: "90" // Also known as grey. +FG_BRIGHT_RED :: "91" +FG_BRIGHT_GREEN :: "92" +FG_BRIGHT_YELLOW :: "93" +FG_BRIGHT_BLUE :: "94" +FG_BRIGHT_MAGENTA :: "95" +FG_BRIGHT_CYAN :: "96" +FG_BRIGHT_WHITE :: "97" + +BG_BRIGHT_BLACK :: "100" // Also known as grey. +BG_BRIGHT_RED :: "101" +BG_BRIGHT_GREEN :: "102" +BG_BRIGHT_YELLOW :: "103" +BG_BRIGHT_BLUE :: "104" +BG_BRIGHT_MAGENTA :: "105" +BG_BRIGHT_CYAN :: "106" +BG_BRIGHT_WHITE :: "107" + +// Fp Escape sequences + +DECSC :: ESC + "7" // DEC Save Cursor +DECRC :: ESC + "8" // DEC Restore Cursor + +// OSC sequences + +WINDOW_TITLE :: "2" // Followed by ";" ST. +HYPERLINK :: "8" // Followed by ";[params];" ST. Closed by OSC HYPERLINK ";;" ST. +CLIPBOARD :: "52" // Followed by ";c;" ST. diff --git a/core/terminal/ansi/doc.odin b/core/terminal/ansi/doc.odin new file mode 100644 index 000000000..966e6be00 --- /dev/null +++ b/core/terminal/ansi/doc.odin @@ -0,0 +1,20 @@ +/* +package ansi implements constant references to many widely-supported ANSI +escape codes, primarily used in terminal emulators for enhanced graphics, such +as colors, text styling, and animated displays. + +For example, you can print out a line of cyan text like this: + fmt.println(ansi.CSI + ansi.FG_CYAN + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR) + +Multiple SGR (Select Graphic Rendition) codes can be joined by semicolons: + fmt.println(ansi.CSI + ansi.BOLD + ";" + ansi.FG_BLUE + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR) + +If your terminal supports 24-bit true color mode, you can also do this: + fmt.println(ansi.CSI + ansi.FG_COLOR_24_BIT + ";0;255;255" + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR) + +For more information, see: +- [[ https://en.wikipedia.org/wiki/ANSI_escape_code ]] +- [[ https://www.vt100.net/docs/vt102-ug/chapter5.html ]] +- [[ https://invisible-island.net/xterm/ctlseqs/ctlseqs.html ]] +*/ +package ansi diff --git a/core/testing/reporting.odin b/core/testing/reporting.odin index 6752cd79b..7c7eb7b2d 100644 --- a/core/testing/reporting.odin +++ b/core/testing/reporting.odin @@ -10,12 +10,12 @@ package testing */ import "base:runtime" -import "core:encoding/ansi" import "core:fmt" import "core:io" import "core:mem" import "core:path/filepath" import "core:strings" +import "core:terminal/ansi" // Definitions of colors for use in the test runner. SGR_RESET :: ansi.CSI + ansi.RESET + ansi.SGR diff --git a/core/testing/runner.odin b/core/testing/runner.odin index db0587370..c81d07109 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -13,7 +13,6 @@ package testing import "base:intrinsics" import "base:runtime" import "core:bytes" -import "core:encoding/ansi" @require import "core:encoding/base64" @require import "core:encoding/json" import "core:fmt" @@ -25,6 +24,7 @@ import "core:os" import "core:slice" @require import "core:strings" import "core:sync/chan" +import "core:terminal/ansi" import "core:thread" import "core:time" diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin index 281fbde40..d17a6d6dc 100644 --- a/core/testing/signal_handler_libc.odin +++ b/core/testing/signal_handler_libc.odin @@ -12,9 +12,9 @@ package testing import "base:intrinsics" import "core:c/libc" -import "core:encoding/ansi" -import "core:sync" import "core:os" +import "core:sync" +import "core:terminal/ansi" @(private="file") stop_runner_flag: libc.sig_atomic_t diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 97ecfee45..de037f6cd 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -58,7 +58,6 @@ import trace "core:debug/trace" import dynlib "core:dynlib" import net "core:net" -import ansi "core:encoding/ansi" import base32 "core:encoding/base32" import base64 "core:encoding/base64" import cbor "core:encoding/cbor" @@ -130,6 +129,7 @@ import sync "core:sync" import testing "core:testing" import terminal "core:terminal" +import ansi "core:terminal/ansi" import edit "core:text/edit" import i18n "core:text/i18n" @@ -203,7 +203,6 @@ _ :: pe _ :: trace _ :: dynlib _ :: net -_ :: ansi _ :: base32 _ :: base64 _ :: csv @@ -260,6 +259,7 @@ _ :: strings _ :: sync _ :: testing _ :: terminal +_ :: ansi _ :: scanner _ :: i18n _ :: match -- cgit v1.2.3 From cac18b4aba41df093aa4cc3ccdc53588fe879882 Mon Sep 17 00:00:00 2001 From: Wesley Kerfoot Date: Tue, 27 May 2025 14:27:22 -0400 Subject: Fix incorrect CSV reader settings for example, fix typo in docs --- core/encoding/csv/doc.odin | 2 -- core/encoding/csv/reader.odin | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'core/encoding') diff --git a/core/encoding/csv/doc.odin b/core/encoding/csv/doc.odin index bfeadafd6..7abe2be49 100644 --- a/core/encoding/csv/doc.odin +++ b/core/encoding/csv/doc.odin @@ -63,8 +63,6 @@ Example: read_csv_from_string :: proc(filename: string) { r: csv.Reader r.trim_leading_space = true - r.reuse_record = true // Without it you have to delete(record) - r.reuse_record_buffer = true // Without it you have to each of the fields within it defer csv.reader_destroy(&r) csv_data, ok := os.read_entire_file(filename) diff --git a/core/encoding/csv/reader.odin b/core/encoding/csv/reader.odin index 5348624d5..577ef219d 100644 --- a/core/encoding/csv/reader.odin +++ b/core/encoding/csv/reader.odin @@ -130,7 +130,7 @@ reader_destroy :: proc(r: ^Reader) { for record, row_idx in csv.iterator_next(&r) { ... } TIP: If you process the results within the loop and don't need to own the results, - you can set the Reader's `reuse_record` and `reuse_record_reuse_record_buffer` to true; + you can set the Reader's `reuse_record` and `reuse_record_buffer` to true; you won't need to delete the record or its fields. */ iterator_next :: proc(r: ^Reader) -> (record: []string, idx: int, err: Error, more: bool) { -- cgit v1.2.3 From 85224b21e69678923b5a514586d50730b8d823a3 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 4 Jun 2025 21:51:12 +0200 Subject: encoding/cbor: support the matrix type --- core/encoding/cbor/marshal.odin | 18 ++++++++++++++++++ core/encoding/cbor/unmarshal.odin | 13 +++++++++++++ tests/core/encoding/cbor/test_core_cbor.odin | 20 ++++++++++++++++++++ 3 files changed, 51 insertions(+) (limited to 'core/encoding') diff --git a/core/encoding/cbor/marshal.odin b/core/encoding/cbor/marshal.odin index aca71deb2..ec597c8a9 100644 --- a/core/encoding/cbor/marshal.odin +++ b/core/encoding/cbor/marshal.odin @@ -612,6 +612,24 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er case: panic("unknown bit_size size") } + case runtime.Type_Info_Matrix: + count := info.column_count * info.elem_stride + err_conv(_encode_u64(e, u64(count), .Array)) or_return + + if impl, ok := _tag_implementations_type[info.elem.id]; ok { + for i in 0..marshal(e, any{rawptr(data), info.elem.id}) or_return + } + return + } + + elem_ti := runtime.type_info_core(type_info_of(info.elem.id)) + for i in 0.. count { + return _unsupported(v, hdr) + } + + da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator } + + out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return + if out_of_space { return _unsupported(v, hdr) } + return + case: return _unsupported(v, hdr) } } diff --git a/tests/core/encoding/cbor/test_core_cbor.odin b/tests/core/encoding/cbor/test_core_cbor.odin index ee853ebac..a76d690be 100644 --- a/tests/core/encoding/cbor/test_core_cbor.odin +++ b/tests/core/encoding/cbor/test_core_cbor.odin @@ -43,6 +43,7 @@ Foo :: struct { biggest: big.Int, smallest: big.Int, ignore_this: ^Foo `cbor:"-"`, + mat: matrix[4, 4]f32, } FooBar :: enum { @@ -95,6 +96,7 @@ test_marshalling :: proc(t: ^testing.T) { onetwenty = i128(12345), small_onetwenty = -i128(max(u64)), ignore_this = &Foo{}, + mat = 1, } big.atoi(&f.biggest, "1234567891011121314151617181920") @@ -120,6 +122,24 @@ test_marshalling :: proc(t: ^testing.T) { defer delete(diagnosis) testing.expect_value(t, diagnosis, `{ "no": null, + "mat": [ + 1.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 1.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 1.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 1.0000 + ], "neg": -69, "nos": undefined, "now": 1(1701117968), -- cgit v1.2.3 From 9eefa2006eccdf942c01fc1421784edea78c5591 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 4 Jun 2025 22:00:02 +0200 Subject: encoding/cbor: support simd vectors --- core/encoding/cbor/marshal.odin | 18 ++++++++++++++++++ core/encoding/cbor/unmarshal.odin | 12 ++++++++++++ tests/core/encoding/cbor/test_core_cbor.odin | 8 ++++++++ 3 files changed, 38 insertions(+) (limited to 'core/encoding') diff --git a/core/encoding/cbor/marshal.odin b/core/encoding/cbor/marshal.odin index ec597c8a9..b23087c90 100644 --- a/core/encoding/cbor/marshal.odin +++ b/core/encoding/cbor/marshal.odin @@ -630,6 +630,24 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er _marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return } return + + case runtime.Type_Info_Simd_Vector: + err_conv(_encode_u64(e, u64(info.count), .Array)) or_return + + if impl, ok := _tag_implementations_type[info.elem.id]; ok { + for i in 0..marshal(e, any{rawptr(data), info.elem.id}) or_return + } + return + } + + elem_ti := runtime.type_info_core(type_info_of(info.elem.id)) + for i in 0.. t.count { + return _unsupported(v, hdr) + } + + da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator } + + out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return + if out_of_space { return _unsupported(v, hdr) } + return + case: return _unsupported(v, hdr) } } diff --git a/tests/core/encoding/cbor/test_core_cbor.odin b/tests/core/encoding/cbor/test_core_cbor.odin index a76d690be..7bea69d2e 100644 --- a/tests/core/encoding/cbor/test_core_cbor.odin +++ b/tests/core/encoding/cbor/test_core_cbor.odin @@ -44,6 +44,7 @@ Foo :: struct { smallest: big.Int, ignore_this: ^Foo `cbor:"-"`, mat: matrix[4, 4]f32, + vec: #simd [4]f64, } FooBar :: enum { @@ -97,6 +98,7 @@ test_marshalling :: proc(t: ^testing.T) { small_onetwenty = -i128(max(u64)), ignore_this = &Foo{}, mat = 1, + vec = 2, } big.atoi(&f.biggest, "1234567891011121314151617181920") @@ -145,6 +147,12 @@ test_marshalling :: proc(t: ^testing.T) { "now": 1(1701117968), "pos": 1212, "str": "Hellope", + "vec": [ + 2.0000, + 2.0000, + 2.0000, + 2.0000 + ], "yes": true, "comp": [ 32.0000, -- cgit v1.2.3 From b7de15caa342fd81fb203015e2fd22a82e523342 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 5 Jun 2025 16:29:41 -0400 Subject: Clarify `strconv.append_*` to `strconv.write_*` --- core/encoding/cbor/cbor.odin | 6 +-- core/encoding/json/marshal.odin | 8 ++-- core/fmt/fmt.odin | 8 ++-- core/io/util.odin | 16 +++---- core/math/fixed/fixed.odin | 6 +-- core/net/url.odin | 2 +- core/os/os.odin | 2 +- core/os/os2/file_util.odin | 2 +- core/strconv/integers.odin | 14 +++---- core/strconv/strconv.odin | 84 ++++++++++++++++++------------------- core/strings/builder.odin | 12 +++--- tests/core/math/test_core_math.odin | 2 +- 12 files changed, 81 insertions(+), 81 deletions(-) (limited to 'core/encoding') diff --git a/core/encoding/cbor/cbor.odin b/core/encoding/cbor/cbor.odin index 8eb829ed3..1fb7c34ab 100644 --- a/core/encoding/cbor/cbor.odin +++ b/core/encoding/cbor/cbor.odin @@ -385,17 +385,17 @@ to_diagnostic_format_writer :: proc(w: io.Writer, val: Value, padding := 0) -> i // which we want for the diagnostic format. case f16: buf: [64]byte - str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f16), 8*size_of(f16)) + str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f16), 8*size_of(f16)) if str[0] == '+' && str != "+Inf" { str = str[1:] } io.write_string(w, str) or_return case f32: buf: [128]byte - str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f32), 8*size_of(f32)) + str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f32), 8*size_of(f32)) if str[0] == '+' && str != "+Inf" { str = str[1:] } io.write_string(w, str) or_return case f64: buf: [256]byte - str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f64), 8*size_of(f64)) + str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f64), 8*size_of(f64)) if str[0] == '+' && str != "+Inf" { str = str[1:] } io.write_string(w, str) or_return diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 020facd14..ebb9a639c 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -108,13 +108,13 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) { switch i in a { case u8, u16, u32, u64, u128: - s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix }) + s = strconv.write_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix }) case: - s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) + s = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) } } else { - s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) + s = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) } io.write_string(w, s) or_return @@ -286,7 +286,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Integer: buf: [40]byte u := cast_any_int_to_u128(ka) - name = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*kti.size, "0123456789", nil) + name = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*kti.size, "0123456789", nil) opt_write_key(w, opt, name) or_return case: return .Unsupported_Type diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 9c07847dd..0f6470cca 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1122,7 +1122,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d flags: strconv.Int_Flags if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} } if fi.plus { flags += {.Plus} } - s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags) + s := strconv.write_bits(buf[start:], u, base, is_signed, bit_size, digits, flags) prev_zero := fi.zero defer fi.zero = prev_zero fi.zero = false @@ -1207,7 +1207,7 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i flags: strconv.Int_Flags if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} } if fi.plus { flags += {.Plus} } - s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags) + s := strconv.write_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags) if fi.hash && fi.zero && fi.indent == 0 { c: byte = 0 @@ -1272,7 +1272,7 @@ _fmt_memory :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, units: st } buf: [256]byte - str := strconv.append_float(buf[:], amt, 'f', prec, 64) + str := strconv.write_float(buf[:], amt, 'f', prec, 64) // Add the unit at the end. copy(buf[len(str):], units[off:off+unit_len]) @@ -1424,7 +1424,7 @@ _fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: b buf: [386]byte // Can return "NaN", "+Inf", "-Inf", "+", "-". - str := strconv.append_float(buf[:], v, float_fmt, prec, bit_size) + str := strconv.write_float(buf[:], v, float_fmt, prec, bit_size) if !fi.plus { // Strip sign from "+" but not "+Inf". diff --git a/core/io/util.odin b/core/io/util.odin index fdbbd5b9f..fa98e007b 100644 --- a/core/io/util.odin +++ b/core/io/util.odin @@ -22,12 +22,12 @@ write_ptr_at :: proc(w: Writer_At, p: rawptr, byte_size: int, offset: i64, n_wri write_u64 :: proc(w: Writer, i: u64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { buf: [32]byte - s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], i, base, false, 64, strconv.digits, nil) return write_string(w, s, n_written) } write_i64 :: proc(w: Writer, i: i64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { buf: [32]byte - s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) return write_string(w, s, n_written) } @@ -40,18 +40,18 @@ write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> ( write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { buf: [39]byte - s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil) + s := strconv.write_bits_128(buf[:], i, base, false, 128, strconv.digits, nil) return write_string(w, s, n_written) } write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { buf: [40]byte - s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil) + s := strconv.write_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil) return write_string(w, s, n_written) } write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: Error) { buf: [386]byte - str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) + str := strconv.write_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) s := buf[:len(str)+1] if s[1] == '+' || s[1] == '-' { s = s[1:] @@ -67,7 +67,7 @@ write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: E write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: Error) { buf: [386]byte - str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) + str := strconv.write_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) s := buf[:len(str)+1] if s[1] == '+' || s[1] == '-' { s = s[1:] @@ -83,7 +83,7 @@ write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: E write_f64 :: proc(w: Writer, val: f64, n_written: ^int = nil) -> (n: int, err: Error) { buf: [386]byte - str := strconv.append_float(buf[1:], val, 'f', 2*size_of(val), 8*size_of(val)) + str := strconv.write_float(buf[1:], val, 'f', 2*size_of(val), 8*size_of(val)) s := buf[:len(str)+1] if s[1] == '+' || s[1] == '-' { s = s[1:] @@ -130,7 +130,7 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^ write_string(w, `\x`, &n) or_return buf: [2]byte - s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil) switch len(s) { case 0: write_string(w, "00", &n) or_return diff --git a/core/math/fixed/fixed.odin b/core/math/fixed/fixed.odin index b23090307..119e727a7 100644 --- a/core/math/fixed/fixed.odin +++ b/core/math/fixed/fixed.odin @@ -124,16 +124,16 @@ append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string { when size_of(Backing) < 16 { T :: u64 - append_uint :: strconv.append_uint + write_uint :: strconv.write_uint } else { T :: u128 - append_uint :: strconv.append_u128 + write_uint :: strconv.write_u128 } integer := T(x.i) >> Fraction_Width fraction := T(x.i) & (1< string { bytes, n := utf8.encode_rune(ch) for byte in bytes[:n] { buf: [2]u8 = --- - t := strconv.append_int(buf[:], i64(byte), 16) + t := strconv.write_int(buf[:], i64(byte), 16) strings.write_rune(&b, '%') strings.write_string(&b, t) } diff --git a/core/os/os.odin b/core/os/os.odin index 30b86d4cd..fde48fbf4 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -57,7 +57,7 @@ write_encoded_rune :: proc(f: Handle, r: rune) -> (n: int, err: Error) { if r < 32 { if wrap(write_string(f, "\\x"), &n, &err) { return } b: [2]byte - s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) + s := strconv.write_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) switch len(s) { case 0: if wrap(write_string(f, "00"), &n, &err) { return } case 1: if wrap(write_rune(f, '0'), &n, &err) { return } diff --git a/core/os/os2/file_util.odin b/core/os/os2/file_util.odin index 8af46fab3..407c38f88 100644 --- a/core/os/os2/file_util.odin +++ b/core/os/os2/file_util.odin @@ -59,7 +59,7 @@ write_encoded_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) { if r < 32 { if wrap(write_string(f, "\\x"), &n, &err) { return } b: [2]byte - s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) + s := strconv.write_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) switch len(s) { case 0: if wrap(write_string(f, "00"), &n, &err) { return } case 1: if wrap(write_rune(f, '0'), &n, &err) { return } diff --git a/core/strconv/integers.odin b/core/strconv/integers.odin index 98a432ac5..0db110d10 100644 --- a/core/strconv/integers.odin +++ b/core/strconv/integers.odin @@ -48,7 +48,7 @@ is_integer_negative :: proc(x: u64, is_signed: bool, bit_size: int) -> (u: u64, return } /* -Appends the string representation of an integer to a buffer with specified base, flags, and digit set. +Writes the string representation of an integer to a buffer with specified base, flags, and digit set. **Inputs** - buf: The buffer to append the integer representation to @@ -62,9 +62,9 @@ Appends the string representation of an integer to a buffer with specified base, **Returns** - The string containing the integer representation appended to the buffer */ -append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { +write_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { if base < 2 || base > MAX_BASE { - panic("strconv: illegal base passed to append_bits") + panic("strconv: illegal base passed to write_bits") } a: [129]byte @@ -146,7 +146,7 @@ is_integer_negative_128 :: proc(x: u128, is_signed: bool, bit_size: int) -> (u: return } /* -Appends the string representation of a 128-bit integer to a buffer with specified base, flags, and digit set. +Writes the string representation of a 128-bit integer to a buffer with specified base, flags, and digit set. **Inputs** - buf: The buffer to append the integer representation to @@ -158,11 +158,11 @@ Appends the string representation of a 128-bit integer to a buffer with specifie - flags: The Int_Flags bit set to control integer formatting **Returns** -- The string containing the integer representation appended to the buffer +- The string containing the integer representation written to the buffer */ -append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { +write_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { if base < 2 || base > MAX_BASE { - panic("strconv: illegal base passed to append_bits") + panic("strconv: illegal base passed to write_bits") } a: [140]byte diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index 4cecd1911..99a290d83 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -1451,19 +1451,19 @@ parse_quaternion64 :: proc(str: string, n: ^int = nil) -> (value: quaternion64, return cast(quaternion64)v, ok } /* -Appends a boolean value as a string to the given buffer +Writes a boolean value as a string to the given buffer **Inputs** -- buf: The buffer to append the boolean value to -- b: The boolean value to be appended +- buf: The buffer to write the boolean value to +- b: The boolean value to be written Example: import "core:fmt" import "core:strconv" - append_bool_example :: proc() { + write_bool_example :: proc() { buf: [6]byte - result := strconv.append_bool(buf[:], true) + result := strconv.write_bool(buf[:], true) fmt.println(result, buf) } @@ -1472,9 +1472,9 @@ Output: true [116, 114, 117, 101, 0, 0] **Returns** -- The resulting string after appending the boolean value +- The resulting string after writing the boolean value */ -append_bool :: proc(buf: []byte, b: bool) -> string { +write_bool :: proc(buf: []byte, b: bool) -> string { n := 0 if b { n = copy(buf, "true") @@ -1484,20 +1484,20 @@ append_bool :: proc(buf: []byte, b: bool) -> string { return string(buf[:n]) } /* -Appends an unsigned integer value as a string to the given buffer with the specified base +Writes an unsigned integer value as a string to the given buffer with the specified base **Inputs** -- buf: The buffer to append the unsigned integer value to -- u: The unsigned integer value to be appended +- buf: The buffer to write the unsigned integer value to +- u: The unsigned integer value to be written - base: The base to use for converting the integer value Example: import "core:fmt" import "core:strconv" - append_uint_example :: proc() { + write_uint_example :: proc() { buf: [4]byte - result := strconv.append_uint(buf[:], 42, 16) + result := strconv.write_uint(buf[:], 42, 16) fmt.println(result, buf) } @@ -1506,26 +1506,26 @@ Output: 2a [50, 97, 0, 0] **Returns** -- The resulting string after appending the unsigned integer value +- The resulting string after writing the unsigned integer value */ -append_uint :: proc(buf: []byte, u: u64, base: int) -> string { - return append_bits(buf, u, base, false, 8*size_of(uint), digits, nil) +write_uint :: proc(buf: []byte, u: u64, base: int) -> string { + return write_bits(buf, u, base, false, 8*size_of(uint), digits, nil) } /* -Appends a signed integer value as a string to the given buffer with the specified base +Writes a signed integer value as a string to the given buffer with the specified base **Inputs** -- buf: The buffer to append the signed integer value to -- i: The signed integer value to be appended +- buf: The buffer to write the signed integer value to +- i: The signed integer value to be written - base: The base to use for converting the integer value Example: import "core:fmt" import "core:strconv" - append_int_example :: proc() { + write_int_example :: proc() { buf: [4]byte - result := strconv.append_int(buf[:], -42, 10) + result := strconv.write_int(buf[:], -42, 10) fmt.println(result, buf) } @@ -1534,16 +1534,16 @@ Output: -42 [45, 52, 50, 0] **Returns** -- The resulting string after appending the signed integer value +- The resulting string after writing the signed integer value */ -append_int :: proc(buf: []byte, i: i64, base: int) -> string { - return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil) +write_int :: proc(buf: []byte, i: i64, base: int) -> string { + return write_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil) } -append_u128 :: proc(buf: []byte, u: u128, base: int) -> string { - return append_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil) +write_u128 :: proc(buf: []byte, u: u128, base: int) -> string { + return write_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil) } /* @@ -1571,7 +1571,7 @@ Output: - The resulting string after converting the integer value */ itoa :: proc(buf: []byte, i: int) -> string { - return append_int(buf, i64(i), 10) + return write_int(buf, i64(i), 10) } /* Converts a string to an integer value @@ -1623,14 +1623,14 @@ atof :: proc(s: string) -> f64 { v, _ := parse_f64(s) return v } -// Alias to `append_float` -ftoa :: append_float +// Alias to `write_float` +ftoa :: write_float /* -Appends a float64 value as a string to the given buffer with the specified format and precision +Writes a float64 value as a string to the given buffer with the specified format and precision **Inputs** -- buf: The buffer to append the float64 value to -- f: The float64 value to be appended +- buf: The buffer to write the float64 value to +- f: The float64 value to be written - fmt: The byte specifying the format to use for the conversion - prec: The precision to use for the conversion - bit_size: The size of the float in bits (32 or 64) @@ -1639,9 +1639,9 @@ Example: import "core:fmt" import "core:strconv" - append_float_example :: proc() { + write_float_example :: proc() { buf: [8]byte - result := strconv.append_float(buf[:], 3.14159, 'f', 2, 64) + result := strconv.write_float(buf[:], 3.14159, 'f', 2, 64) fmt.println(result, buf) } @@ -1650,16 +1650,16 @@ Output: +3.14 [43, 51, 46, 49, 52, 0, 0, 0] **Returns** -- The resulting string after appending the float +- The resulting string after writing the float */ -append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { +write_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { return string(generic_ftoa(buf, f, fmt, prec, bit_size)) } /* -Appends a quoted string representation of the input string to a given byte slice and returns the result as a string +Writes a quoted string representation of the input string to a given byte slice and returns the result as a string **Inputs** -- buf: The byte slice to which the quoted string will be appended +- buf: The byte slice to which the quoted string will be written - str: The input string to be quoted !! ISSUE !! NOT EXPECTED -- "\"hello\"" was expected @@ -1679,7 +1679,7 @@ Output: "'h''e''l''l''o'" [34, 39, 104, 39, 39, 101, 39, 39, 108, 39, 39, 108, 39, 39, 111, 39, 34, 0, 0, 0] **Returns** -- The resulting string after appending the quoted string representation +- The resulting string after writing the quoted string representation */ quote :: proc(buf: []byte, str: string) -> string { write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) { @@ -1719,10 +1719,10 @@ quote :: proc(buf: []byte, str: string) -> string { return string(buf[:i]) } /* -Appends a quoted rune representation of the input rune to a given byte slice and returns the result as a string +Writes a quoted rune representation of the input rune to a given byte slice and returns the result as a string **Inputs** -- buf: The byte slice to which the quoted rune will be appended +- buf: The byte slice to which the quoted rune will be written - r: The input rune to be quoted Example: @@ -1740,7 +1740,7 @@ Output: 'A' [39, 65, 39, 0] **Returns** -- The resulting string after appending the quoted rune representation +- The resulting string after writing the quoted rune representation */ quote_rune :: proc(buf: []byte, r: rune) -> string { write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) { @@ -1783,7 +1783,7 @@ quote_rune :: proc(buf: []byte, r: rune) -> string { if r < 32 { write_string(buf, &i, "\\x") b: [2]byte - s := append_bits(b[:], u64(r), 16, true, 64, digits, nil) + s := write_bits(b[:], u64(r), 16, true, 64, digits, nil) switch len(s) { case 0: write_string(buf, &i, "00") case 1: write_rune(buf, &i, '0') diff --git a/core/strings/builder.odin b/core/strings/builder.odin index 05382f04e..b1180d5e9 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -675,7 +675,7 @@ Returns: */ write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) { buf: [384]byte - s := strconv.append_float(buf[:], f, fmt, prec, bit_size) + s := strconv.write_float(buf[:], f, fmt, prec, bit_size) // If the result starts with a `+` then unless we always want signed results, // we skip it unless it's followed by an `I` (because of +Inf). if !always_signed && (buf[0] == '+' && buf[1] != 'I') { @@ -699,7 +699,7 @@ Returns: */ write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) { buf: [384]byte - s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) + s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) if !always_signed && (buf[0] == '+' && buf[1] != 'I') { s = s[1:] } @@ -739,7 +739,7 @@ Output: */ write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n: int) { buf: [384]byte - s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) + s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) if !always_signed && (buf[0] == '+' && buf[1] != 'I') { s = s[1:] } @@ -761,7 +761,7 @@ Returns: */ write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) { buf: [384]byte - s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) + s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) if !always_signed && (buf[0] == '+' && buf[1] != 'I') { s = s[1:] } @@ -782,7 +782,7 @@ Returns: */ write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) { buf: [32]byte - s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], i, base, false, 64, strconv.digits, nil) return write_string(b, s) } /* @@ -800,7 +800,7 @@ Returns: */ write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) { buf: [32]byte - s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) return write_string(b, s) } /* diff --git a/tests/core/math/test_core_math.odin b/tests/core/math/test_core_math.odin index 5797cb4ea..009e3fedd 100644 --- a/tests/core/math/test_core_math.odin +++ b/tests/core/math/test_core_math.odin @@ -1238,7 +1238,7 @@ test_count_digits :: proc(t: ^testing.T) { buf: [64]u8 for n in 0.. Date: Mon, 9 Jun 2025 15:09:04 +0200 Subject: Fix #4705 Allocate `doc.tokenizer`, and free it in `destroy`. --- core/encoding/xml/xml_reader.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'core/encoding') diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index d616be9dc..707d2b3f3 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -175,7 +175,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha data = bytes.clone(data) } - t := &Tokenizer{} + t := new(Tokenizer) init(t, string(data), path, error_handler) doc = new(Document) @@ -403,6 +403,7 @@ destroy :: proc(doc: ^Document) { } delete(doc.strings_to_free) + free(doc.tokenizer) free(doc) } -- cgit v1.2.3 From ae02d3d02d2eb5132fa7c6573ed7db20d7e18f3e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 2 Aug 2025 11:55:16 +0100 Subject: Begin supporting `string16` across the core library --- base/intrinsics/intrinsics.odin | 1 + base/runtime/print.odin | 6 +++ core/encoding/cbor/tags.odin | 2 +- core/encoding/cbor/unmarshal.odin | 2 + core/encoding/json/marshal.odin | 8 ++-- core/encoding/json/unmarshal.odin | 4 +- core/flags/internal_rtti.odin | 2 + core/fmt/fmt.odin | 16 ++++---- core/io/io.odin | 4 +- core/reflect/types.odin | 8 ++-- src/check_builtin.cpp | 2 + src/check_expr.cpp | 42 +++++++++++++++++---- src/checker_builtin_procs.hpp | 2 + src/llvm_backend.cpp | 6 +++ src/llvm_backend_const.cpp | 77 +++++++++++++++++++++++++++++++++++++-- src/llvm_backend_debug.cpp | 14 +++++++ src/llvm_backend_expr.cpp | 3 +- src/llvm_backend_general.cpp | 37 +++++++++++++++++++ src/llvm_backend_utility.cpp | 19 +++++++++- src/string.cpp | 7 ++++ 20 files changed, 230 insertions(+), 32 deletions(-) (limited to 'core/encoding') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index be75739fe..d45d24f48 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -141,6 +141,7 @@ type_is_quaternion :: proc($T: typeid) -> bool --- type_is_string :: proc($T: typeid) -> bool --- type_is_typeid :: proc($T: typeid) -> bool --- type_is_any :: proc($T: typeid) -> bool --- +type_is_string16 :: proc($T: typeid) -> bool --- type_is_endian_platform :: proc($T: typeid) -> bool --- type_is_endian_little :: proc($T: typeid) -> bool --- diff --git a/base/runtime/print.odin b/base/runtime/print.odin index 145f002d1..85ed49445 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -293,7 +293,13 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_string("quaternion") print_u64(u64(8*ti.size)) case Type_Info_String: + if info.is_cstring { + print_byte('c') + } print_string("string") + if info.is_utf16 { + print_string("16") + } case Type_Info_Boolean: switch ti.id { case bool: print_string("bool") diff --git a/core/encoding/cbor/tags.odin b/core/encoding/cbor/tags.odin index 17420af46..e0e69cbf5 100644 --- a/core/encoding/cbor/tags.odin +++ b/core/encoding/cbor/tags.odin @@ -298,7 +298,7 @@ tag_base64_unmarshal :: proc(_: ^Tag_Implementation, d: Decoder, _: Tag_Number, #partial switch t in ti.variant { case reflect.Type_Info_String: - + assert(!t.is_utf16) if t.is_cstring { length := base64.decoded_len(bytes) builder := strings.builder_make(0, length+1) diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin index 365ac5d6f..2840429f5 100644 --- a/core/encoding/cbor/unmarshal.odin +++ b/core/encoding/cbor/unmarshal.odin @@ -335,6 +335,8 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.a _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) { #partial switch t in ti.variant { case reflect.Type_Info_String: + assert(!t.is_utf16) + bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return if t.is_cstring { diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index ebb9a639c..cdb00a354 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -353,10 +353,10 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: #partial switch info in ti.variant { case runtime.Type_Info_String: switch x in v { - case string: - return x == "" - case cstring: - return x == nil || x == "" + case string: return x == "" + case cstring: return x == nil || x == "" + case string16: return x == "" + case cstring16: return x == nil || x == "" } case runtime.Type_Info_Any: return v.(any) == nil diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index b9ed1476f..51e7e3b81 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -570,7 +570,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm key_ptr: rawptr #partial switch tk in t.key.variant { - case runtime.Type_Info_String: + case runtime.Type_Info_String: + assert(!tk.is_utf16) + key_ptr = rawptr(&key) key_cstr: cstring if reflect.is_cstring(t.key) { diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin index 1c559ca55..58224cc87 100644 --- a/core/flags/internal_rtti.odin +++ b/core/flags/internal_rtti.odin @@ -127,6 +127,8 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info: } case runtime.Type_Info_String: + assert(!specific_type_info.is_utf16) + if specific_type_info.is_cstring { cstr_ptr := (^cstring)(ptr) if cstr_ptr != nil { diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 7fe6287d4..9c245de94 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -2346,14 +2346,14 @@ fmt_array :: proc(fi: ^Info, data: rawptr, n: int, elem_size: int, elem: ^reflec } switch reflect.type_info_base(elem).id { - case byte: fmt_string(fi, string(([^]byte)(data)[:n]), verb); return - case u16: print_utf16(fi, ([^]u16)(data)[:n]); return - case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return - case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return - case u32: print_utf32(fi, ([^]u32)(data)[:n]); return - case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return - case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return - case rune: print_utf32(fi, ([^]rune)(data)[:n]); return + case byte: fmt_string(fi, string (([^]byte)(data)[:n]), verb); return + case u16: fmt_string16(fi, string16(([^]u16) (data)[:n]), verb); return + case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return + case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return + case u32: print_utf32(fi, ([^]u32)(data)[:n]); return + case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return + case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return + case rune: print_utf32(fi, ([^]rune)(data)[:n]); return } } if verb == 'p' { diff --git a/core/io/io.odin b/core/io/io.odin index 5431519bf..c4eb6a073 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -319,7 +319,6 @@ write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int, write_string16 :: proc(s: Writer, str: string16, n_written: ^int = nil) -> (n: int, err: Error) { for i := 0; i < len(str); i += 1 { r := rune(utf16.REPLACEMENT_CHAR) - switch c := str[i]; { case c < utf16._surr1, utf16._surr3 <= c: r = rune(c) @@ -329,7 +328,8 @@ write_string16 :: proc(s: Writer, str: string16, n_written: ^int = nil) -> (n: i i += 1 } - w, err := write_rune(s, r, n_written) + w: int + w, err = write_rune(s, r, n_written) n += w if err != nil { return diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 511c5c9bd..2351408cc 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -511,9 +511,11 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt io.write_i64(w, i64(8*ti.size), 10, &n) or_return case Type_Info_String: if info.is_cstring { - io.write_string(w, "cstring", &n) or_return - } else { - io.write_string(w, "string", &n) or_return + io.write_byte(w, 'c', &n) or_return + } + io.write_string(w, "string", &n) or_return + if info.is_utf16 { + io.write_string(w, "16", &n) or_return } case Type_Info_Boolean: switch ti.id { diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d36cf4520..4abace637 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -19,6 +19,7 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool is_type_complex, is_type_quaternion, is_type_string, + is_type_string16, is_type_typeid, is_type_any, is_type_endian_platform, @@ -6139,6 +6140,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_type_is_complex: case BuiltinProc_type_is_quaternion: case BuiltinProc_type_is_string: + case BuiltinProc_type_is_string16: case BuiltinProc_type_is_typeid: case BuiltinProc_type_is_any: case BuiltinProc_type_is_endian_platform: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 57073e22f..8d2e4d637 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2106,6 +2106,9 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i } else if (is_type_boolean(type)) { return in_value.kind == ExactValue_Bool; } else if (is_type_string(type)) { + if (in_value.kind == ExactValue_String16) { + return is_type_string16(type) || is_type_cstring16(type); + } return in_value.kind == ExactValue_String; } else if (is_type_integer(type) || is_type_rune(type)) { if (in_value.kind == ExactValue_Bool) { @@ -2320,6 +2323,9 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i if (in_value.kind == ExactValue_String) { return false; } + if (in_value.kind == ExactValue_String16) { + return false; + } if (out_value) *out_value = in_value; } else if (is_type_bit_set(type)) { if (in_value.kind == ExactValue_Integer) { @@ -4654,6 +4660,13 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar break; } } + } else if (operand->value.kind == ExactValue_String16) { + String16 s = operand->value.value_string16; + if (is_type_u16_array(t)) { + if (s.len == t->Array.count) { + break; + } + } } operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); @@ -4983,6 +4996,12 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v if (success_) *success_ = true; if (finish_) *finish_ = true; return exact_value_u64(val); + } else if (value.kind == ExactValue_String16) { + GB_ASSERT(0 <= index && index < value.value_string.len); + u16 val = value.value_string16[index]; + if (success_) *success_ = true; + if (finish_) *finish_ = true; + return exact_value_u64(val); } if (value.kind != ExactValue_Compound) { if (success_) *success_ = true; @@ -11124,15 +11143,21 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, o->expr = node; return kind; } - - String s = {}; - if (o->value.kind == ExactValue_String) { - s = o->value.value_string; - } - o->mode = Addressing_Constant; o->type = t; - o->value = exact_value_string(substring(s, cast(isize)indices[0], cast(isize)indices[1])); + + if (o->value.kind == ExactValue_String16) { + String16 s = o->value.value_string16; + + o->value = exact_value_string16(substring(s, cast(isize)indices[0], cast(isize)indices[1])); + } else { + String s = {}; + if (o->value.kind == ExactValue_String) { + s = o->value.value_string; + } + + o->value = exact_value_string(substring(s, cast(isize)indices[0], cast(isize)indices[1])); + } } return kind; } @@ -11221,6 +11246,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast Type *t = t_invalid; switch (node->tav.value.kind) { case ExactValue_String: t = t_untyped_string; break; + case ExactValue_String16: t = t_string16; break; // TODO(bill): determine this correctly case ExactValue_Float: t = t_untyped_float; break; case ExactValue_Complex: t = t_untyped_complex; break; case ExactValue_Quaternion: t = t_untyped_quaternion; break; @@ -11657,6 +11683,8 @@ gb_internal bool is_exact_value_zero(ExactValue const &v) { return !v.value_bool; case ExactValue_String: return v.value_string.len == 0; + case ExactValue_String16: + return v.value_string16.len == 0; case ExactValue_Integer: return big_int_is_zero(&v.value_integer); case ExactValue_Float: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 8e135ab10..bff887d9e 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -250,6 +250,7 @@ BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_complex, BuiltinProc_type_is_quaternion, BuiltinProc_type_is_string, + BuiltinProc_type_is_string16, BuiltinProc_type_is_typeid, BuiltinProc_type_is_any, @@ -607,6 +608,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_complex"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_quaternion"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_string"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_string16"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_typeid"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 13a1d8cf3..f37415cc1 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1264,7 +1264,13 @@ String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) { case Basic_string: return build_context.metrics.int_size == 4 ? str_lit("{string=*i}") : str_lit("{string=*q}"); + case Basic_string16: + return build_context.metrics.int_size == 4 ? str_lit("{string16=*i}") : str_lit("{string16=*q}"); + case Basic_cstring: return str_lit("*"); + case Basic_cstring16: return str_lit("*"); + + case Basic_any: return str_lit("{any=^v^v}"); // rawptr + ^Type_Info case Basic_typeid: diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index c3112934e..8c05ed4a2 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -122,6 +122,25 @@ gb_internal lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) { gb_internal LLVMValueRef llvm_const_string_internal(lbModule *m, Type *t, LLVMValueRef data, LLVMValueRef len) { + GB_ASSERT(!is_type_string16(t)); + if (build_context.metrics.ptr_size < build_context.metrics.int_size) { + LLVMValueRef values[3] = { + data, + LLVMConstNull(lb_type(m, t_i32)), + len, + }; + return llvm_const_named_struct_internal(lb_type(m, t), values, 3); + } else { + LLVMValueRef values[2] = { + data, + len, + }; + return llvm_const_named_struct_internal(lb_type(m, t), values, 2); + } +} + +gb_internal LLVMValueRef llvm_const_string16_internal(lbModule *m, Type *t, LLVMValueRef data, LLVMValueRef len) { + GB_ASSERT(is_type_string16(t)); if (build_context.metrics.ptr_size < build_context.metrics.int_size) { LLVMValueRef values[3] = { data, @@ -238,6 +257,10 @@ gb_internal lbValue lb_const_string(lbModule *m, String const &value) { return lb_const_value(m, t_string, exact_value_string(value)); } +gb_internal lbValue lb_const_string(lbModule *m, String16 const &value) { + return lb_const_value(m, t_string16, exact_value_string16(value)); +} + gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value) { lbValue res = {}; @@ -569,7 +592,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb GB_ASSERT(is_type_slice(type)); res.value = lb_find_or_add_entity_string_byte_slice_with_type(m, value.value_string, original_type).value; return res; - } else { + } else if (value.kind == ExactValue_String16) { + GB_ASSERT(is_type_slice(type)); + GB_PANIC("TODO(bill): UTF-16 String"); + return res; + }else { ast_node(cl, CompoundLit, value.value_compound); isize count = cl->elems.count; @@ -751,15 +778,23 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb { bool custom_link_section = cc.link_section.len > 0; - LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, value.value_string, custom_link_section); + LLVMValueRef ptr = nullptr; lbValue res = {}; res.type = default_type(original_type); + if (is_type_string16(res.type) || is_type_cstring16(res.type)) { + TEMPORARY_ALLOCATOR_GUARD(); + String16 s16 = string_to_string16(temporary_allocator(), value.value_string); + ptr = lb_find_or_add_entity_string16_ptr(m, s16, custom_link_section); + } else { + ptr = lb_find_or_add_entity_string_ptr(m, value.value_string, custom_link_section); + } + if (custom_link_section) { LLVMSetSection(ptr, alloc_cstring(permanent_allocator(), cc.link_section)); } - if (is_type_cstring(res.type)) { + if (is_type_cstring(res.type) || is_type_cstring16(res.type)) { res.value = ptr; } else { if (value.value_string.len == 0) { @@ -768,12 +803,46 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), value.value_string.len, true); GB_ASSERT(is_type_string(original_type)); - res.value = llvm_const_string_internal(m, original_type, ptr, str_len); + if (is_type_string16(res.type)) { + res.value = llvm_const_string16_internal(m, original_type, ptr, str_len); + } else { + res.value = llvm_const_string_internal(m, original_type, ptr, str_len); + } + } + + return res; + } + + case ExactValue_String16: + { + GB_ASSERT(is_type_string16(res.type) || is_type_cstring16(res.type)); + + bool custom_link_section = cc.link_section.len > 0; + + LLVMValueRef ptr = lb_find_or_add_entity_string16_ptr(m, value.value_string16, custom_link_section); + lbValue res = {}; + res.type = default_type(original_type); + + if (custom_link_section) { + LLVMSetSection(ptr, alloc_cstring(permanent_allocator(), cc.link_section)); + } + + if (is_type_cstring16(res.type)) { + res.value = ptr; + } else { + if (value.value_string16.len == 0) { + ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); + } + LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), value.value_string16.len, true); + GB_ASSERT(is_type_string(original_type)); + + res.value = llvm_const_string16_internal(m, original_type, ptr, str_len); } return res; } + case ExactValue_Integer: if (is_type_pointer(type) || is_type_multi_pointer(type) || is_type_proc(type)) { LLVMTypeRef t = lb_type(m, original_type); diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 024c5564e..182920fc7 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -802,6 +802,20 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { LLVMMetadataRef char_type = lb_debug_type_basic_type(m, str_lit("char"), 8, LLVMDWARFTypeEncoding_Unsigned); return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, ptr_bits, ptr_bits, 0, "cstring", 7); } + + case Basic_string16: + { + LLVMMetadataRef elements[2] = {}; + elements[0] = lb_debug_struct_field(m, str_lit("data"), t_u16_ptr, 0); + elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, int_bits); + return lb_debug_basic_struct(m, str_lit("string16"), 2*int_bits, int_bits, elements, gb_count_of(elements)); + } + case Basic_cstring16: + { + LLVMMetadataRef char_type = lb_debug_type_basic_type(m, str_lit("wchar_t"), 16, LLVMDWARFTypeEncoding_Unsigned); + return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, ptr_bits, ptr_bits, 0, "cstring16", 7); + } + case Basic_any: { LLVMMetadataRef elements[2] = {}; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index fbf0dea11..3463b6083 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4354,12 +4354,13 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { } - case Type_Basic: { // Basic_string + case Type_Basic: { // Basic_string/Basic_string16 lbValue str; lbValue elem; lbValue len; lbValue index; + str = lb_build_expr(p, ie->expr); if (deref) { str = lb_emit_load(p, str); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index d9771a75b..9ef1c23c0 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2715,6 +2715,43 @@ gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String co } } +gb_internal LLVMValueRef lb_find_or_add_entity_string16_ptr(lbModule *m, String16 const &str, bool custom_link_section) { + // TODO(bill): caching for UTF-16 strings + + LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; + + LLVMValueRef data = nullptr; + { + LLVMTypeRef llvm_u16 = LLVMInt16TypeInContext(m->ctx); + + TEMPORARY_ALLOCATOR_GUARD(); + + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, str.len+1); + + for (isize i = 0; i < str.len; i++) { + values[i] = LLVMConstInt(llvm_u16, str.text[i], false); + } + values[str.len] = LLVMConstInt(llvm_u16, 0, false); + + data = LLVMConstArray(llvm_u16, values, cast(unsigned)(str.len+1)); + } + + + u32 id = m->global_array_index.fetch_add(1); + gbString name = gb_string_make(temporary_allocator(), "csbs$"); + name = gb_string_appendc(name, m->module_name); + name = gb_string_append_fmt(name, "$%x", id); + + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); + LLVMSetInitializer(global_data, data); + lb_make_global_private_const(global_data); + LLVMSetAlignment(global_data, 1); + + LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); + return ptr; +} + gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str, bool custom_link_section) { LLVMValueRef ptr = nullptr; if (str.len != 0) { diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index d4117b7ff..ea1bae4e9 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -6,6 +6,7 @@ gb_internal bool lb_is_type_aggregate(Type *t) { case Type_Basic: switch (t->Basic.kind) { case Basic_string: + case Basic_string16: case Basic_any: return true; @@ -981,7 +982,8 @@ gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) { } else if (build_context.ptr_size != build_context.int_size) { switch (t->kind) { case Type_Basic: - if (t->Basic.kind != Basic_string) { + if (t->Basic.kind != Basic_string && + t->Basic.kind != Basic_string16) { break; } /*fallthrough*/ @@ -1160,6 +1162,11 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { case 0: result_type = alloc_type_pointer(t->Slice.elem); break; case 1: result_type = t_int; break; } + } else if (is_type_string16(t)) { + switch (index) { + case 0: result_type = t_u16_ptr; break; + case 1: result_type = t_int; break; + } } else if (is_type_string(t)) { switch (index) { case 0: result_type = t_u8_ptr; break; @@ -1273,6 +1280,12 @@ gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { switch (t->kind) { case Type_Basic: switch (t->Basic.kind) { + case Basic_string16: + switch (index) { + case 0: result_type = t_u16_ptr; break; + case 1: result_type = t_int; break; + } + break; case Basic_string: switch (index) { case 0: result_type = t_u8_ptr; break; @@ -1440,6 +1453,10 @@ gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection e = lb_emit_struct_ep(p, e, index); break; + case Basic_string16: + e = lb_emit_struct_ep(p, e, index); + break; + default: GB_PANIC("un-gep-able type %s", type_to_string(type)); break; diff --git a/src/string.cpp b/src/string.cpp index 8405938f4..8cc0e93f3 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -79,6 +79,13 @@ gb_internal String substring(String const &s, isize lo, isize hi) { return make_string(s.text+lo, hi-lo); } +gb_internal String16 substring(String16 const &s, isize lo, isize hi) { + isize max = s.len; + GB_ASSERT_MSG(lo <= hi && hi <= max, "%td..%td..%td", lo, hi, max); + + return make_string16(s.text+lo, hi-lo); +} + gb_internal char *alloc_cstring(gbAllocator a, String s) { char *c_str = gb_alloc_array(a, char, s.len+1); -- cgit v1.2.3 From af3184adc96cef59fff986ea6400caa6dbdb56ae Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 5 Aug 2025 15:12:54 +0100 Subject: Change `is_utf16` field to `encoding` and use an enum --- base/runtime/core.odin | 7 ++++++- base/runtime/print.odin | 5 +++-- core/encoding/cbor/tags.odin | 2 +- core/encoding/cbor/unmarshal.odin | 2 +- core/encoding/json/unmarshal.odin | 2 +- core/flags/internal_rtti.odin | 2 +- core/reflect/types.odin | 5 +++-- src/checker.cpp | 3 +++ src/llvm_backend_type.cpp | 16 ++++++++++++---- src/types.cpp | 2 ++ 10 files changed, 33 insertions(+), 13 deletions(-) (limited to 'core/encoding') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index fe40427ff..478a3d307 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -61,6 +61,11 @@ Type_Info_Struct_Soa_Kind :: enum u8 { Dynamic = 3, } +Type_Info_String_Encoding_Kind :: enum u8 { + UTF_8 = 0, + UTF_16 = 1, +} + // Variant Types Type_Info_Named :: struct { name: string, @@ -73,7 +78,7 @@ Type_Info_Rune :: struct {} Type_Info_Float :: struct {endianness: Platform_Endianness} Type_Info_Complex :: struct {} Type_Info_Quaternion :: struct {} -Type_Info_String :: struct {is_cstring: bool, is_utf16: bool} +Type_Info_String :: struct {is_cstring: bool, encoding: Type_Info_String_Encoding_Kind} Type_Info_Boolean :: struct {} Type_Info_Any :: struct {} Type_Info_Type_Id :: struct {} diff --git a/base/runtime/print.odin b/base/runtime/print.odin index 85ed49445..2cfb6661b 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -297,8 +297,9 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_byte('c') } print_string("string") - if info.is_utf16 { - print_string("16") + switch info.encoding { + case .UTF_8: /**/ + case .UTF_16: print_string("16") } case Type_Info_Boolean: switch ti.id { diff --git a/core/encoding/cbor/tags.odin b/core/encoding/cbor/tags.odin index e0e69cbf5..ae1664dfc 100644 --- a/core/encoding/cbor/tags.odin +++ b/core/encoding/cbor/tags.odin @@ -298,7 +298,7 @@ tag_base64_unmarshal :: proc(_: ^Tag_Implementation, d: Decoder, _: Tag_Number, #partial switch t in ti.variant { case reflect.Type_Info_String: - assert(!t.is_utf16) + assert(t.encoding == .UTF_8) if t.is_cstring { length := base64.decoded_len(bytes) builder := strings.builder_make(0, length+1) diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin index 2840429f5..043b2ec60 100644 --- a/core/encoding/cbor/unmarshal.odin +++ b/core/encoding/cbor/unmarshal.odin @@ -335,7 +335,7 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.a _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) { #partial switch t in ti.variant { case reflect.Type_Info_String: - assert(!t.is_utf16) + assert(t.encoding == .UTF_8) bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index 51e7e3b81..0b65adaac 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -571,7 +571,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm #partial switch tk in t.key.variant { case runtime.Type_Info_String: - assert(!tk.is_utf16) + assert(tk.encoding == .UTF_8) key_ptr = rawptr(&key) key_cstr: cstring diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin index 58224cc87..a1b050597 100644 --- a/core/flags/internal_rtti.odin +++ b/core/flags/internal_rtti.odin @@ -127,7 +127,7 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info: } case runtime.Type_Info_String: - assert(!specific_type_info.is_utf16) + assert(specific_type_info.encoding == .UTF_8) if specific_type_info.is_cstring { cstr_ptr := (^cstring)(ptr) diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 2351408cc..98b7b368f 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -514,8 +514,9 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt io.write_byte(w, 'c', &n) or_return } io.write_string(w, "string", &n) or_return - if info.is_utf16 { - io.write_string(w, "16", &n) or_return + switch info.encoding { + case .UTF_8: /**/ + case .UTF_16: io.write_string(w, "16", &n) or_return } case Type_Info_Boolean: switch ti.id { diff --git a/src/checker.cpp b/src/checker.cpp index e9fa792f3..e72061f56 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3101,6 +3101,9 @@ gb_internal void init_core_type_info(Checker *c) { GB_ASSERT(tis->fields.count == 5); + Entity *type_info_string_encoding_kind = find_core_entity(c, str_lit("Type_Info_String_Encoding_Kind")); + t_type_info_string_encoding_kind = type_info_string_encoding_kind->type; + Entity *type_info_variant = tis->fields[4]; Type *tiv_type = type_info_variant->type; GB_ASSERT(is_type_union(tiv_type)); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index a91d77fe5..d1e7c0559 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -525,7 +525,15 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ break; case Basic_string: - tag_type = t_type_info_string; + { + tag_type = t_type_info_string; + LLVMValueRef vals[2] = { + lb_const_bool(m, t_bool, false).value, + lb_const_int(m, t_type_info_string_encoding_kind, 0).value, + }; + + variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); + } break; case Basic_cstring: @@ -533,7 +541,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ tag_type = t_type_info_string; LLVMValueRef vals[2] = { lb_const_bool(m, t_bool, true).value, - lb_const_bool(m, t_bool, false).value, + lb_const_int(m, t_type_info_string_encoding_kind, 0).value, }; variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); @@ -545,7 +553,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ tag_type = t_type_info_string; LLVMValueRef vals[2] = { lb_const_bool(m, t_bool, false).value, - lb_const_bool(m, t_bool, true).value, + lb_const_int(m, t_type_info_string_encoding_kind, 1).value, }; variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); @@ -558,7 +566,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ tag_type = t_type_info_string; LLVMValueRef vals[2] = { lb_const_bool(m, t_bool, true).value, - lb_const_bool(m, t_bool, true).value, + lb_const_int(m, t_type_info_string_encoding_kind, 1).value, }; variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); diff --git a/src/types.cpp b/src/types.cpp index 51d170f2b..c465714db 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -661,6 +661,8 @@ gb_global Type *t_type_info_enum_value = nullptr; gb_global Type *t_type_info_ptr = nullptr; gb_global Type *t_type_info_enum_value_ptr = nullptr; +gb_global Type *t_type_info_string_encoding_kind = nullptr; + gb_global Type *t_type_info_named = nullptr; gb_global Type *t_type_info_integer = nullptr; gb_global Type *t_type_info_rune = nullptr; -- cgit v1.2.3 From 7642e0a0e0bb0ff79da6ac7a2ba3b787afa32b78 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 8 Aug 2025 12:10:01 +0100 Subject: Require `@(init)` and `@(fini)` to be `proc "contextless" ()` --- base/runtime/default_allocators_nil.odin | 2 +- base/runtime/default_temp_allocator_arena.odin | 7 +++++-- base/runtime/default_temporary_allocator.odin | 6 +++--- base/runtime/thread_management.odin | 11 +++++++++-- core/encoding/cbor/tags.odin | 10 ++++++---- core/image/bmp/bmp.odin | 2 +- core/image/general.odin | 10 +++++----- core/image/netpbm/netpbm.odin | 2 +- core/image/png/png.odin | 2 +- core/image/qoi/qoi.odin | 2 +- core/image/tga/tga.odin | 2 +- core/log/file_console_logger.odin | 4 +++- core/math/big/helpers.odin | 18 ++++++++++-------- core/math/big/internal.odin | 9 +++++---- core/mem/virtual/virtual.odin | 2 +- core/mem/virtual/virtual_linux.odin | 4 ++-- core/mem/virtual/virtual_other.odin | 2 +- core/mem/virtual/virtual_posix.odin | 4 ++-- core/mem/virtual/virtual_windows.odin | 4 ++-- core/net/socket_windows.odin | 2 +- core/os/os2/allocators.odin | 4 ++-- core/os/os2/file_posix.odin | 4 ++-- core/os/os2/file_wasi.odin | 4 ++-- core/os/os2/file_windows.odin | 8 ++++---- core/os/os2/path_windows.odin | 2 +- core/os/os_darwin.odin | 6 ++++-- core/os/os_freebsd.odin | 6 ++++-- core/os/os_haiku.odin | 6 ++++-- core/os/os_linux.odin | 6 ++++-- core/os/os_netbsd.odin | 6 ++++-- core/os/os_openbsd.odin | 6 ++++-- core/os/os_wasi.odin | 10 ++++++---- core/os/os_windows.odin | 6 ++++-- core/sys/info/cpu_intel.odin | 4 ++-- core/sys/info/cpu_linux_arm.odin | 4 +++- core/sys/info/cpu_linux_intel.odin | 5 ++++- core/sys/info/cpu_windows.odin | 5 ++++- core/sys/info/platform_darwin.odin | 5 ++++- core/sys/info/platform_linux.odin | 9 ++++++--- core/sys/info/platform_windows.odin | 12 ++++++++---- core/sys/windows/util.odin | 4 ++-- core/terminal/internal.odin | 7 +++++-- core/terminal/terminal_js.odin | 6 +++--- core/terminal/terminal_posix.odin | 8 +++++--- core/terminal/terminal_windows.odin | 9 ++++++--- src/checker.cpp | 9 +++++++++ vendor/miniaudio/common.odin | 4 ++-- 47 files changed, 169 insertions(+), 101 deletions(-) (limited to 'core/encoding') diff --git a/base/runtime/default_allocators_nil.odin b/base/runtime/default_allocators_nil.odin index e7a1b1a74..14edd11dd 100644 --- a/base/runtime/default_allocators_nil.odin +++ b/base/runtime/default_allocators_nil.odin @@ -23,7 +23,7 @@ nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return nil, .None } -nil_allocator :: proc() -> Allocator { +nil_allocator :: proc "contextless" () -> Allocator { return Allocator{ procedure = nil_allocator_proc, data = nil, diff --git a/base/runtime/default_temp_allocator_arena.odin b/base/runtime/default_temp_allocator_arena.odin index ca144b66f..525f81825 100644 --- a/base/runtime/default_temp_allocator_arena.odin +++ b/base/runtime/default_temp_allocator_arena.odin @@ -52,10 +52,13 @@ memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint return } -memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) { +memory_block_dealloc :: proc "contextless" (block_to_free: ^Memory_Block, loc := #caller_location) { if block_to_free != nil { + allocator := block_to_free.allocator // sanitizer.address_unpoison(block_to_free.base, block_to_free.capacity) + context = default_context() + context.allocator = allocator mem_free(block_to_free, allocator, loc) } } @@ -172,7 +175,7 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { arena.total_used = 0 } -arena_destroy :: proc(arena: ^Arena, loc := #caller_location) { +arena_destroy :: proc "contextless" (arena: ^Arena, loc := #caller_location) { for arena.curr_block != nil { free_block := arena.curr_block arena.curr_block = free_block.prev diff --git a/base/runtime/default_temporary_allocator.odin b/base/runtime/default_temporary_allocator.odin index b355ded70..671728be8 100644 --- a/base/runtime/default_temporary_allocator.odin +++ b/base/runtime/default_temporary_allocator.odin @@ -8,7 +8,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR { default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {} - default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {} + default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {} default_temp_allocator_proc :: nil_allocator_proc @@ -28,7 +28,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR { _ = arena_init(&s.arena, uint(size), backing_allocator) } - default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) { + default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) { if s != nil { arena_destroy(&s.arena) s^ = {} @@ -56,7 +56,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR { } @(fini, private) - _destroy_temp_allocator_fini :: proc() { + _destroy_temp_allocator_fini :: proc "contextless" () { default_temp_allocator_destroy(&global_default_temp_allocator_data) } } diff --git a/base/runtime/thread_management.odin b/base/runtime/thread_management.odin index cabd4691c..97dcbc8f5 100644 --- a/base/runtime/thread_management.odin +++ b/base/runtime/thread_management.odin @@ -1,10 +1,14 @@ package runtime -Thread_Local_Cleaner :: #type proc "odin" () +Thread_Local_Cleaner_Odin :: #type proc "odin" () +Thread_Local_Cleaner_Contextless :: #type proc "contextless" () + +Thread_Local_Cleaner :: union #shared_nil {Thread_Local_Cleaner_Odin, Thread_Local_Cleaner_Contextless} @(private="file") thread_local_cleaners: [8]Thread_Local_Cleaner + // Add a procedure that will be run at the end of a thread for the purpose of // deallocating state marked as `thread_local`. // @@ -29,6 +33,9 @@ run_thread_local_cleaners :: proc "odin" () { if p == nil { break } - p() + switch v in p { + case Thread_Local_Cleaner_Odin: v() + case Thread_Local_Cleaner_Contextless: v() + } } } diff --git a/core/encoding/cbor/tags.odin b/core/encoding/cbor/tags.odin index ae1664dfc..be07b926a 100644 --- a/core/encoding/cbor/tags.odin +++ b/core/encoding/cbor/tags.odin @@ -82,14 +82,16 @@ _tag_implementations_id: map[string]Tag_Implementation _tag_implementations_type: map[typeid]Tag_Implementation // Register a custom tag implementation to be used when marshalling that type and unmarshalling that tag number. -tag_register_type :: proc(impl: Tag_Implementation, nr: Tag_Number, type: typeid) { +tag_register_type :: proc "contextless" (impl: Tag_Implementation, nr: Tag_Number, type: typeid) { + context = runtime.default_context() _tag_implementations_nr[nr] = impl _tag_implementations_type[type] = impl } // Register a custom tag implementation to be used when marshalling that tag number or marshalling // a field with the struct tag `cbor_tag:"nr"`. -tag_register_number :: proc(impl: Tag_Implementation, nr: Tag_Number, id: string) { +tag_register_number :: proc "contextless" (impl: Tag_Implementation, nr: Tag_Number, id: string) { + context = runtime.default_context() _tag_implementations_nr[nr] = impl _tag_implementations_id[id] = impl } @@ -98,13 +100,13 @@ tag_register_number :: proc(impl: Tag_Implementation, nr: Tag_Number, id: string INITIALIZE_DEFAULT_TAGS :: #config(CBOR_INITIALIZE_DEFAULT_TAGS, !ODIN_DEFAULT_TO_PANIC_ALLOCATOR && !ODIN_DEFAULT_TO_NIL_ALLOCATOR) @(private, init, disabled=!INITIALIZE_DEFAULT_TAGS) -tags_initialize_defaults :: proc() { +tags_initialize_defaults :: proc "contextless" () { tags_register_defaults() } // Registers tags that have implementations provided by this package. // This is done by default and can be controlled with the `CBOR_INITIALIZE_DEFAULT_TAGS` define. -tags_register_defaults :: proc() { +tags_register_defaults :: proc "contextless" () { tag_register_number({nil, tag_time_unmarshal, tag_time_marshal}, TAG_EPOCH_TIME_NR, TAG_EPOCH_TIME_ID) tag_register_number({nil, tag_base64_unmarshal, tag_base64_marshal}, TAG_BASE64_NR, TAG_BASE64_ID) tag_register_number({nil, tag_cbor_unmarshal, tag_cbor_marshal}, TAG_CBOR_NR, TAG_CBOR_ID) diff --git a/core/image/bmp/bmp.odin b/core/image/bmp/bmp.odin index 057c2ffa0..d5a094e83 100644 --- a/core/image/bmp/bmp.odin +++ b/core/image/bmp/bmp.odin @@ -741,6 +741,6 @@ destroy :: proc(img: ^Image) { } @(init, private) -_register :: proc() { +_register :: proc "contextless" () { image.register(.BMP, load_from_bytes, destroy) } diff --git a/core/image/general.odin b/core/image/general.odin index e92b54f18..336b41d25 100644 --- a/core/image/general.odin +++ b/core/image/general.odin @@ -10,13 +10,13 @@ Destroy_Proc :: #type proc(img: ^Image) _internal_loaders: [Which_File_Type]Loader_Proc _internal_destroyers: [Which_File_Type]Destroy_Proc -register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) { - assert(loader != nil) - assert(destroyer != nil) - assert(_internal_loaders[kind] == nil) +register :: proc "contextless" (kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) { + assert_contextless(loader != nil) + assert_contextless(destroyer != nil) + assert_contextless(_internal_loaders[kind] == nil) _internal_loaders[kind] = loader - assert(_internal_destroyers[kind] == nil) + assert_contextless(_internal_destroyers[kind] == nil) _internal_destroyers[kind] = destroyer } diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index a9dc6599a..25e0228b5 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -720,7 +720,7 @@ autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, for } @(init, private) -_register :: proc() { +_register :: proc "contextless" () { loader :: proc(data: []byte, options: image.Options, allocator: mem.Allocator) -> (img: ^Image, err: Error) { return load_from_bytes(data, allocator) } diff --git a/core/image/png/png.odin b/core/image/png/png.odin index 3eb56c245..87efcf9b5 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -1611,6 +1611,6 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH } @(init, private) -_register :: proc() { +_register :: proc "contextless" () { image.register(.PNG, load_from_bytes, destroy) } diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin index 6b6149e60..ded8d7971 100644 --- a/core/image/qoi/qoi.odin +++ b/core/image/qoi/qoi.odin @@ -371,6 +371,6 @@ qoi_hash :: #force_inline proc(pixel: RGBA_Pixel) -> (index: u8) { } @(init, private) -_register :: proc() { +_register :: proc "contextless" () { image.register(.QOI, load_from_bytes, destroy) } diff --git a/core/image/tga/tga.odin b/core/image/tga/tga.odin index 46e37a0cf..5fda803c5 100644 --- a/core/image/tga/tga.odin +++ b/core/image/tga/tga.odin @@ -406,6 +406,6 @@ IMAGE_DESCRIPTOR_RIGHT_MASK :: 1<<4 IMAGE_DESCRIPTOR_TOP_MASK :: 1<<5 @(init, private) -_register :: proc() { +_register :: proc "contextless" () { image.register(.TGA, load_from_bytes, destroy) } \ No newline at end of file diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index 0fe5c3477..f0acc8a22 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -43,12 +43,14 @@ File_Console_Logger_Data :: struct { @(private) global_subtract_stderr_options: Options @(init, private) -init_standard_stream_status :: proc() { +init_standard_stream_status :: proc "contextless" () { // NOTE(Feoramund): While it is technically possible for these streams to // be redirected during the runtime of the program, the cost of checking on // every single log message is not worth it to support such an // uncommonly-used feature. if terminal.color_enabled { + context = runtime.default_context() + // This is done this way because it's possible that only one of these // streams could be redirected to a file. if !terminal.is_terminal(os.stdout) { diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index ee09bb2c7..569f0b810 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -7,6 +7,7 @@ package math_big import "base:intrinsics" +import "base:runtime" import rnd "core:math/rand" /* @@ -778,22 +779,23 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{} @(init, private) -_init_constants :: proc() { +_init_constants :: proc "contextless" () { initialize_constants() } -initialize_constants :: proc() -> (res: int) { - internal_set( INT_ZERO, 0); INT_ZERO.flags = {.Immutable} - internal_set( INT_ONE, 1); INT_ONE.flags = {.Immutable} - internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable} +initialize_constants :: proc "contextless" () -> (res: int) { + context = runtime.default_context() + internal_int_set_from_integer( INT_ZERO, 0); INT_ZERO.flags = {.Immutable} + internal_int_set_from_integer( INT_ONE, 1); INT_ONE.flags = {.Immutable} + internal_int_set_from_integer(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable} /* We set these special values to -1 or 1 so they don't get mistake for zero accidentally. This allows for shortcut tests of is_zero as .used == 0. */ - internal_set( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN} - internal_set( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf} - internal_set(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf} + internal_int_set_from_integer( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN} + internal_int_set_from_integer( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf} + internal_int_set_from_integer(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf} return _DEFAULT_MUL_KARATSUBA_CUTOFF } diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 4707177c4..8b176e7c0 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -27,10 +27,11 @@ package math_big -import "core:mem" +import "base:builtin" import "base:intrinsics" +import "base:runtime" +import "core:mem" import rnd "core:math/rand" -import "base:builtin" /* Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7. @@ -2885,12 +2886,12 @@ internal_clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context } internal_clear_if_uninitialized :: proc {internal_clear_if_uninitialized_single, internal_clear_if_uninitialized_multi, } -internal_error_if_immutable_single :: proc(arg: ^Int) -> (err: Error) { +internal_error_if_immutable_single :: proc "contextless" (arg: ^Int) -> (err: Error) { if arg != nil && .Immutable in arg.flags { return .Assignment_To_Immutable } return nil } -internal_error_if_immutable_multi :: proc(args: ..^Int) -> (err: Error) { +internal_error_if_immutable_multi :: proc "contextless" (args: ..^Int) -> (err: Error) { for i in args { if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable } } diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index 3027e5848..3f388acf3 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -9,7 +9,7 @@ _ :: runtime DEFAULT_PAGE_SIZE := uint(4096) @(init, private) -platform_memory_init :: proc() { +platform_memory_init :: proc "contextless" () { _platform_memory_init() } diff --git a/core/mem/virtual/virtual_linux.odin b/core/mem/virtual/virtual_linux.odin index 3e0d7668b..f819fbf86 100644 --- a/core/mem/virtual/virtual_linux.odin +++ b/core/mem/virtual/virtual_linux.odin @@ -43,10 +43,10 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) return errno == .NONE } -_platform_memory_init :: proc() { +_platform_memory_init :: proc "contextless" () { DEFAULT_PAGE_SIZE = 4096 // is power of two - assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) + assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) } diff --git a/core/mem/virtual/virtual_other.odin b/core/mem/virtual/virtual_other.odin index a57856975..c6386e842 100644 --- a/core/mem/virtual/virtual_other.odin +++ b/core/mem/virtual/virtual_other.odin @@ -25,7 +25,7 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) return false } -_platform_memory_init :: proc() { +_platform_memory_init :: proc "contextless" () { } _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { diff --git a/core/mem/virtual/virtual_posix.odin b/core/mem/virtual/virtual_posix.odin index 0b304a5e7..4bb161770 100644 --- a/core/mem/virtual/virtual_posix.odin +++ b/core/mem/virtual/virtual_posix.odin @@ -28,13 +28,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) return posix.mprotect(data, size, transmute(posix.Prot_Flags)flags) == .OK } -_platform_memory_init :: proc() { +_platform_memory_init :: proc "contextless" () { // NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`. size := posix.sysconf(._PAGESIZE) DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE)) // is power of two - assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) + assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) } _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { diff --git a/core/mem/virtual/virtual_windows.odin b/core/mem/virtual/virtual_windows.odin index 3fd4eeb68..1d777af17 100644 --- a/core/mem/virtual/virtual_windows.odin +++ b/core/mem/virtual/virtual_windows.odin @@ -146,13 +146,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) @(no_sanitize_address) -_platform_memory_init :: proc() { +_platform_memory_init :: proc "contextless" () { sys_info: SYSTEM_INFO GetSystemInfo(&sys_info) DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize)) // is power of two - assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) + assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) } diff --git a/core/net/socket_windows.odin b/core/net/socket_windows.odin index cab820ed5..9127874de 100644 --- a/core/net/socket_windows.odin +++ b/core/net/socket_windows.odin @@ -79,7 +79,7 @@ Shutdown_Manner :: enum c.int { } @(init, private) -ensure_winsock_initialized :: proc() { +ensure_winsock_initialized :: proc "contextless" () { win.ensure_winsock_initialized() } diff --git a/core/os/os2/allocators.odin b/core/os/os2/allocators.odin index cedfbdee1..36a7d72be 100644 --- a/core/os/os2/allocators.odin +++ b/core/os/os2/allocators.odin @@ -16,7 +16,7 @@ MAX_TEMP_ARENA_COLLISIONS :: MAX_TEMP_ARENA_COUNT - 1 global_default_temp_allocator_arenas: [MAX_TEMP_ARENA_COUNT]runtime.Arena @(fini, private) -temp_allocator_fini :: proc() { +temp_allocator_fini :: proc "contextless" () { for &arena in global_default_temp_allocator_arenas { runtime.arena_destroy(&arena) } @@ -69,6 +69,6 @@ _temp_allocator_end :: proc(tmp: runtime.Arena_Temp) { } @(init, private) -init_thread_local_cleaner :: proc() { +init_thread_local_cleaner :: proc "contextless" () { runtime.add_thread_local_cleaner(temp_allocator_fini) } diff --git a/core/os/os2/file_posix.odin b/core/os/os2/file_posix.odin index 2d74618ee..fed8d766c 100644 --- a/core/os/os2/file_posix.odin +++ b/core/os/os2/file_posix.odin @@ -25,8 +25,8 @@ File_Impl :: struct { } @(init) -init_std_files :: proc() { - new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File { +init_std_files :: proc "contextless" () { + new_std :: proc "contextless" (impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File { impl.file.impl = impl impl.fd = fd impl.allocator = runtime.nil_allocator() diff --git a/core/os/os2/file_wasi.odin b/core/os/os2/file_wasi.odin index 0245841e3..1d417ffb1 100644 --- a/core/os/os2/file_wasi.odin +++ b/core/os/os2/file_wasi.odin @@ -30,8 +30,8 @@ Preopen :: struct { preopens: []Preopen @(init) -init_std_files :: proc() { - new_std :: proc(impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File { +init_std_files :: proc "contextless" () { + new_std :: proc "contextless" (impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File { impl.file.impl = impl impl.allocator = runtime.nil_allocator() impl.fd = fd diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index 25e9cb4b0..b39e65fe2 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -43,8 +43,8 @@ File_Impl :: struct { } @(init) -init_std_files :: proc() { - new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File { +init_std_files :: proc "contextless" () { + new_std :: proc "contextless" (impl: ^File_Impl, code: u32, name: string) -> ^File { impl.file.impl = impl impl.allocator = runtime.nil_allocator() @@ -77,7 +77,7 @@ init_std_files :: proc() { stderr = new_std(&files[2], win32.STD_ERROR_HANDLE, "") } -_handle :: proc(f: ^File) -> win32.HANDLE { +_handle :: proc "contextless" (f: ^File) -> win32.HANDLE { return win32.HANDLE(_fd(f)) } @@ -234,7 +234,7 @@ _clone :: proc(f: ^File) -> (clone: ^File, err: Error) { return _new_file(uintptr(clonefd), name(f), file_allocator()) } -_fd :: proc(f: ^File) -> uintptr { +_fd :: proc "contextless" (f: ^File) -> uintptr { if f == nil || f.impl == nil { return INVALID_HANDLE } diff --git a/core/os/os2/path_windows.odin b/core/os/os2/path_windows.odin index e0a00b07a..e5a1545ec 100644 --- a/core/os/os2/path_windows.odin +++ b/core/os/os2/path_windows.odin @@ -160,7 +160,7 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err can_use_long_paths: bool @(init) -init_long_path_support :: proc() { +init_long_path_support :: proc "contextless" () { can_use_long_paths = false key: win32.HKEY diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 1010d27a8..77b5825dd 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -1226,7 +1226,8 @@ _processor_core_count :: proc() -> int { } @(private, require_results) -_alloc_command_line_arguments :: proc() -> []string { +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) for _, i in res { res[i] = string(runtime.args__[i]) @@ -1235,7 +1236,8 @@ _alloc_command_line_arguments :: proc() -> []string { } @(private, fini) -_delete_command_line_arguments :: proc() { +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() delete(args) } diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index aeffdcb87..0542e10dc 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -965,7 +965,8 @@ _processor_core_count :: proc() -> int { @(private, require_results) -_alloc_command_line_arguments :: proc() -> []string { +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) for _, i in res { res[i] = string(runtime.args__[i]) @@ -974,6 +975,7 @@ _alloc_command_line_arguments :: proc() -> []string { } @(private, fini) -_delete_command_line_arguments :: proc() { +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() delete(args) } diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index b56d516a4..e7c71338b 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -317,7 +317,8 @@ file_size :: proc(fd: Handle) -> (i64, Error) { args := _alloc_command_line_arguments() @(private, require_results) -_alloc_command_line_arguments :: proc() -> []string { +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { res[i] = string(arg) @@ -326,7 +327,8 @@ _alloc_command_line_arguments :: proc() -> []string { } @(private, fini) -_delete_command_line_arguments :: proc() { +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() delete(args) } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 66c30711d..15d230820 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -1098,7 +1098,8 @@ _processor_core_count :: proc() -> int { } @(private, require_results) -_alloc_command_line_arguments :: proc() -> []string { +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) for _, i in res { res[i] = string(runtime.args__[i]) @@ -1107,7 +1108,8 @@ _alloc_command_line_arguments :: proc() -> []string { } @(private, fini) -_delete_command_line_arguments :: proc() { +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() delete(args) } diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index accc5abcd..30511012f 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -1015,7 +1015,8 @@ _processor_core_count :: proc() -> int { } @(private, require_results) -_alloc_command_line_arguments :: proc() -> []string { +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) for _, i in res { res[i] = string(runtime.args__[i]) @@ -1024,6 +1025,7 @@ _alloc_command_line_arguments :: proc() -> []string { } @(private, fini) -_delete_command_line_arguments :: proc() { +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() delete(args) } diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index ec9181ba6..50ee37dff 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -915,7 +915,8 @@ _processor_core_count :: proc() -> int { } @(private, require_results) -_alloc_command_line_arguments :: proc() -> []string { +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) for _, i in res { res[i] = string(runtime.args__[i]) @@ -924,6 +925,7 @@ _alloc_command_line_arguments :: proc() -> []string { } @(private, fini) -_delete_command_line_arguments :: proc() { +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() delete(args) } diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index f135e4d42..53c242a01 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -28,16 +28,18 @@ stderr: Handle = 2 args := _alloc_command_line_arguments() @(private, require_results) -_alloc_command_line_arguments :: proc() -> (args: []string) { - args = make([]string, len(runtime.args__)) +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() + args := make([]string, len(runtime.args__)) for &arg, i in args { arg = string(runtime.args__[i]) } - return + return args } @(private, fini) -_delete_command_line_arguments :: proc() { +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() delete(args) } diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 3c1725cc5..03c194596 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -194,7 +194,8 @@ current_thread_id :: proc "contextless" () -> int { @(private, require_results) -_alloc_command_line_arguments :: proc() -> []string { +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() arg_count: i32 arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count) arg_list := make([]string, int(arg_count)) @@ -216,7 +217,8 @@ _alloc_command_line_arguments :: proc() -> []string { } @(private, fini) -_delete_command_line_arguments :: proc() { +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() for s in args { delete(s) } diff --git a/core/sys/info/cpu_intel.odin b/core/sys/info/cpu_intel.odin index 7c5b38ca4..e8f07c732 100644 --- a/core/sys/info/cpu_intel.odin +++ b/core/sys/info/cpu_intel.odin @@ -52,7 +52,7 @@ CPU :: struct { cpu: CPU @(init, private) -init_cpu_features :: proc "c" () { +init_cpu_features :: proc "contextless" () { is_set :: #force_inline proc "c" (bit: u32, value: u32) -> bool { return (value>>bit) & 0x1 != 0 } @@ -156,7 +156,7 @@ init_cpu_features :: proc "c" () { _cpu_name_buf: [72]u8 @(init, private) -init_cpu_name :: proc "c" () { +init_cpu_name :: proc "contextless" () { number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0) if number_of_extended_ids < 0x8000_0004 { return diff --git a/core/sys/info/cpu_linux_arm.odin b/core/sys/info/cpu_linux_arm.odin index cde76a83d..6e8b1a634 100644 --- a/core/sys/info/cpu_linux_arm.odin +++ b/core/sys/info/cpu_linux_arm.odin @@ -2,11 +2,13 @@ #+build linux package sysinfo +import "base:runtime" import "core:sys/linux" import "core:strings" @(init, private) -init_cpu_features :: proc() { +init_cpu_features :: proc "contextless" () { + context = runtime.default_context() fd, err := linux.open("/proc/cpuinfo", {}) if err != .NONE { return } defer linux.close(fd) diff --git a/core/sys/info/cpu_linux_intel.odin b/core/sys/info/cpu_linux_intel.odin index e43737475..af76a75e4 100644 --- a/core/sys/info/cpu_linux_intel.odin +++ b/core/sys/info/cpu_linux_intel.odin @@ -2,12 +2,15 @@ #+build linux package sysinfo +import "base:runtime" import "core:sys/linux" import "core:strings" import "core:strconv" @(init, private) -init_cpu_core_count :: proc() { +init_cpu_core_count :: proc "contextless" () { + context = runtime.default_context() + fd, err := linux.open("/proc/cpuinfo", {}) if err != .NONE { return } defer linux.close(fd) diff --git a/core/sys/info/cpu_windows.odin b/core/sys/info/cpu_windows.odin index 7dd2d2a8c..72d79f9a7 100644 --- a/core/sys/info/cpu_windows.odin +++ b/core/sys/info/cpu_windows.odin @@ -2,9 +2,12 @@ package sysinfo import sys "core:sys/windows" import "base:intrinsics" +import "base:runtime" @(init, private) -init_cpu_core_count :: proc() { +init_cpu_core_count :: proc "contextless" () { + context = runtime.default_context() + infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION defer delete(infos) diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin index 3fc8064ec..07c26ec28 100644 --- a/core/sys/info/platform_darwin.odin +++ b/core/sys/info/platform_darwin.odin @@ -1,5 +1,7 @@ package sysinfo +import "base:runtime" + import "core:strconv" import "core:strings" import "core:sys/unix" @@ -9,7 +11,8 @@ import NS "core:sys/darwin/Foundation" version_string_buf: [1024]u8 @(init, private) -init_platform :: proc() { +init_platform :: proc "contextless" () { + context = runtime.default_context() ws :: strings.write_string wi :: strings.write_int diff --git a/core/sys/info/platform_linux.odin b/core/sys/info/platform_linux.odin index 9c342e567..43cd580c1 100644 --- a/core/sys/info/platform_linux.odin +++ b/core/sys/info/platform_linux.odin @@ -1,6 +1,7 @@ package sysinfo import "base:intrinsics" +import "base:runtime" import "core:strconv" import "core:strings" @@ -10,7 +11,9 @@ import "core:sys/linux" version_string_buf: [1024]u8 @(init, private) -init_os_version :: proc () { +init_os_version :: proc "contextless" () { + context = runtime.default_context() + os_version.platform = .Linux b := strings.builder_from_bytes(version_string_buf[:]) @@ -91,11 +94,11 @@ init_os_version :: proc () { } @(init, private) -init_ram :: proc() { +init_ram :: proc "contextless" () { // Retrieve RAM info using `sysinfo` sys_info: linux.Sys_Info errno := linux.sysinfo(&sys_info) - assert(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!") + assert_contextless(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!") ram = RAM{ total_ram = int(sys_info.totalram) * int(sys_info.mem_unit), free_ram = int(sys_info.freeram) * int(sys_info.mem_unit), diff --git a/core/sys/info/platform_windows.odin b/core/sys/info/platform_windows.odin index dd1441d30..ff8ebe2ee 100644 --- a/core/sys/info/platform_windows.odin +++ b/core/sys/info/platform_windows.odin @@ -12,7 +12,9 @@ import "base:runtime" version_string_buf: [1024]u8 @(init, private) -init_os_version :: proc () { +init_os_version :: proc "contextless" () { + context = runtime.default_context() + /* NOTE(Jeroen): `GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10. @@ -43,6 +45,7 @@ init_os_version :: proc () { os_version.minor = int(osvi.dwMinorVersion) os_version.build[0] = int(osvi.dwBuildNumber) + b := strings.builder_from_bytes(version_string_buf[:]) strings.write_string(&b, "Windows ") @@ -259,7 +262,7 @@ init_os_version :: proc () { } @(init, private) -init_ram :: proc() { +init_ram :: proc "contextless" () { state: sys.MEMORYSTATUSEX state.dwLength = size_of(state) @@ -276,10 +279,11 @@ init_ram :: proc() { } @(init, private) -init_gpu_info :: proc() { - +init_gpu_info :: proc "contextless" () { GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\" + context = runtime.default_context() + gpu_list: [dynamic]GPU gpu_index: int diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin index 10dc907e7..125038ac4 100644 --- a/core/sys/windows/util.odin +++ b/core/sys/windows/util.odin @@ -628,7 +628,7 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P } } -ensure_winsock_initialized :: proc() { +ensure_winsock_initialized :: proc "contextless" () { @static gate := false @static initted := false @@ -644,7 +644,7 @@ ensure_winsock_initialized :: proc() { unused_info: WSADATA version_requested := WORD(2) << 8 | 2 res := WSAStartup(version_requested, &unused_info) - assert(res == 0, "unable to initialized Winsock2") + assert_contextless(res == 0, "unable to initialized Winsock2") initted = true } diff --git a/core/terminal/internal.odin b/core/terminal/internal.odin index 44007e14f..9404ff833 100644 --- a/core/terminal/internal.odin +++ b/core/terminal/internal.odin @@ -1,6 +1,7 @@ #+private package terminal +import "base:runtime" import "core:os" import "core:strings" @@ -68,9 +69,11 @@ get_environment_color :: proc() -> Color_Depth { } @(init) -init_terminal :: proc() { +init_terminal :: proc "contextless" () { _init_terminal() + context = runtime.default_context() + // We respect `NO_COLOR` specifically as a color-disabler but not as a // blanket ban on any terminal manipulation codes, hence why this comes // after `_init_terminal` which will allow Windows to enable Virtual @@ -81,6 +84,6 @@ init_terminal :: proc() { } @(fini) -fini_terminal :: proc() { +fini_terminal :: proc "contextless" () { _fini_terminal() } diff --git a/core/terminal/terminal_js.odin b/core/terminal/terminal_js.odin index 2d880420b..4dcd4465e 100644 --- a/core/terminal/terminal_js.odin +++ b/core/terminal/terminal_js.odin @@ -4,12 +4,12 @@ package terminal import "core:os" -_is_terminal :: proc(handle: os.Handle) -> bool { +_is_terminal :: proc "contextless" (handle: os.Handle) -> bool { return true } -_init_terminal :: proc() { +_init_terminal :: proc "contextless" () { color_depth = .None } -_fini_terminal :: proc() { } \ No newline at end of file +_fini_terminal :: proc "contextless" () { } \ No newline at end of file diff --git a/core/terminal/terminal_posix.odin b/core/terminal/terminal_posix.odin index f578e12c6..8d96dd256 100644 --- a/core/terminal/terminal_posix.odin +++ b/core/terminal/terminal_posix.odin @@ -2,15 +2,17 @@ #+build linux, darwin, netbsd, openbsd, freebsd, haiku package terminal +import "base:runtime" import "core:os" import "core:sys/posix" -_is_terminal :: proc(handle: os.Handle) -> bool { +_is_terminal :: proc "contextless" (handle: os.Handle) -> bool { return bool(posix.isatty(posix.FD(handle))) } -_init_terminal :: proc() { +_init_terminal :: proc "contextless" () { + context = runtime.default_context() color_depth = get_environment_color() } -_fini_terminal :: proc() { } +_fini_terminal :: proc "contextless" () { } diff --git a/core/terminal/terminal_windows.odin b/core/terminal/terminal_windows.odin index 18ec98332..6d5f98a1f 100644 --- a/core/terminal/terminal_windows.odin +++ b/core/terminal/terminal_windows.odin @@ -1,10 +1,11 @@ #+private package terminal +import "base:runtime" import "core:os" import "core:sys/windows" -_is_terminal :: proc(handle: os.Handle) -> bool { +_is_terminal :: proc "contextless" (handle: os.Handle) -> bool { is_tty := windows.GetFileType(windows.HANDLE(handle)) == windows.FILE_TYPE_CHAR return is_tty } @@ -18,7 +19,7 @@ old_modes: [2]struct{ } @(init) -_init_terminal :: proc() { +_init_terminal :: proc "contextless" () { vtp_enabled: bool for &v in old_modes { @@ -42,13 +43,15 @@ _init_terminal :: proc() { // This color depth is available on Windows 10 since build 10586. color_depth = .Four_Bit } else { + context = runtime.default_context() + // The user may be on a non-default terminal emulator. color_depth = get_environment_color() } } @(fini) -_fini_terminal :: proc() { +_fini_terminal :: proc "contextless" () { for v in old_modes { handle := windows.GetStdHandle(v.handle) if handle == windows.INVALID_HANDLE || handle == nil { diff --git a/src/checker.cpp b/src/checker.cpp index a13290750..f631a1412 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2675,6 +2675,10 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st is_init = false; } + if (t->Proc.calling_convention != ProcCC_Contextless) { + error(e->token, "@(init) procedures must be declared as \"contextless\""); + } + if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { error(e->token, "@(init) procedures must be declared at the file scope"); is_init = false; @@ -2689,6 +2693,7 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st error(e->token, "An @(init) procedure must not use a blank identifier as its name"); } + if (is_init) { add_dependency_to_set(c, e); array_add(&c->info.init_procedures, e); @@ -2706,6 +2711,10 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st is_fini = false; } + if (t->Proc.calling_convention != ProcCC_Contextless) { + error(e->token, "@(fini) procedures must be declared as \"contextless\""); + } + if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { error(e->token, "@(fini) procedures must be declared at the file scope"); is_fini = false; diff --git a/vendor/miniaudio/common.odin b/vendor/miniaudio/common.odin index 0263278bc..e675cb7f6 100644 --- a/vendor/miniaudio/common.odin +++ b/vendor/miniaudio/common.odin @@ -25,7 +25,7 @@ BINDINGS_VERSION :: [3]u32{BINDINGS_VERSION_MAJOR, BINDINGS_VERSION_MIN BINDINGS_VERSION_STRING :: "0.11.22" @(init) -version_check :: proc() { +version_check :: proc "contextless" () { v: [3]u32 version(&v.x, &v.y, &v.z) if v != BINDINGS_VERSION { @@ -43,7 +43,7 @@ version_check :: proc() { n += copy(buf[n:], "and executing `make`") } - panic(string(buf[:n])) + panic_contextless(string(buf[:n])) } } -- cgit v1.2.3 From d3b877031838c5a13c4adbfdd1d8fb77c35c9801 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 28 Sep 2025 20:48:13 +0100 Subject: Add `#+test` to base32_test.odin --- core/encoding/base32/base32_test.odin | 1 + 1 file changed, 1 insertion(+) (limited to 'core/encoding') diff --git a/core/encoding/base32/base32_test.odin b/core/encoding/base32/base32_test.odin index ea41ae36f..07d5c8080 100644 --- a/core/encoding/base32/base32_test.odin +++ b/core/encoding/base32/base32_test.odin @@ -1,3 +1,4 @@ +#+test package encoding_base32 import "core:testing" -- cgit v1.2.3