From c466e551692e90b876b35018d94237e3136a5fc0 Mon Sep 17 00:00:00 2001 From: PedroEdiaz Date: Tue, 17 Jun 2025 18:46:30 -0600 Subject: [PATCH 1/3] Add Integer and Enum Decode --- decode.odin | 59 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/decode.odin b/decode.odin index 22cbf90..576b9a4 100644 --- a/decode.odin +++ b/decode.odin @@ -2,6 +2,7 @@ package mustache import "base:runtime" import "core:reflect" +import "core:strconv" import "core:log" decode :: proc( v: any, key: string ) -> string { @@ -14,17 +15,67 @@ decode :: proc( v: any, key: string ) -> string { #partial switch info in ti.variant { case runtime.Type_Info_Struct: - return decode( reflect.struct_field_value_by_name(v, key), ".") + return decode( reflect.struct_field_value_by_name(v, key), "." ) case runtime.Type_Info_String: - switch s in a { + if key != "." do return "" + + switch t in a { case string: - return string(s) + return t case cstring: - return string(s) + return string(t) } + case runtime.Type_Info_Integer: + if key != "." do return "" + + buf: [40]byte + u := cast_any_int_to_u128(a) + + return strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) + case runtime.Type_Info_Enum: + return decode(any{v.data, info.base.id}, key) } return "" } + + +@(private) +cast_any_int_to_u128 :: proc(any_int_value: any) -> u128 { + u: u128 = 0 + + switch i in any_int_value { + case i8: u = u128(i) + case i16: u = u128(i) + case i32: u = u128(i) + case i64: u = u128(i) + case i128: u = u128(i) + case int: u = u128(i) + case u8: u = u128(i) + case u16: u = u128(i) + case u32: u = u128(i) + case u64: u = u128(i) + case u128: u = u128(i) + case uint: u = u128(i) + case uintptr: u = u128(i) + + case i16le: u = u128(i) + case i32le: u = u128(i) + case i64le: u = u128(i) + case u16le: u = u128(i) + case u32le: u = u128(i) + case u64le: u = u128(i) + case u128le: u = u128(i) + case i16be: u = u128(i) + case i32be: u = u128(i) + case i64be: u = u128(i) + case u16be: u = u128(i) + case u32be: u = u128(i) + case u64be: u = u128(i) + case u128be: u = u128(i) + } + + return u; +} From e4e797fe15ada583a56f7397451fde83a45ff737 Mon Sep 17 00:00:00 2001 From: PedroEdiaz Date: Tue, 17 Jun 2025 19:43:31 -0600 Subject: [PATCH 2/3] Add: Recursivity in decode --- decode.odin | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/decode.odin b/decode.odin index 576b9a4..960927d 100644 --- a/decode.odin +++ b/decode.odin @@ -3,10 +3,10 @@ package mustache import "base:runtime" import "core:reflect" import "core:strconv" +import "core:strings" import "core:log" decode :: proc( v: any, key: string ) -> string { - if v == nil do return "" ti := runtime.type_info_base(type_info_of(v.id)) @@ -15,7 +15,13 @@ decode :: proc( v: any, key: string ) -> string { #partial switch info in ti.variant { case runtime.Type_Info_Struct: - return decode( reflect.struct_field_value_by_name(v, key), "." ) + newkey, err := strings.split_after_n(key, ".", 2) + + if len(newkey) != 2 || err != nil { + return decode( reflect.struct_field_value_by_name(v, key), "." ) + } + + return decode( reflect.struct_field_value_by_name(v, newkey[0][:len(newkey[0])-1]), newkey[1] ) case runtime.Type_Info_String: if key != "." do return "" @@ -42,6 +48,7 @@ decode :: proc( v: any, key: string ) -> string { } +// Stealed from core:endoding/json @(private) cast_any_int_to_u128 :: proc(any_int_value: any) -> u128 { u: u128 = 0 From 31f2b1c5c9b78e369b8f9aa0d4280db9ba877cc5 Mon Sep 17 00:00:00 2001 From: PedroEdiaz Date: Wed, 18 Jun 2025 01:35:19 -0600 Subject: [PATCH 3/3] Add Sections as mustache for arrays --- decode.odin | 99 +++++++++++++++++------------------------ mustache.odin | 119 +++++++++++++++++++++++++++++++------------------- 2 files changed, 115 insertions(+), 103 deletions(-) diff --git a/decode.odin b/decode.odin index 960927d..c9d6bf3 100644 --- a/decode.odin +++ b/decode.odin @@ -1,20 +1,18 @@ package mustache -import "base:runtime" import "core:reflect" -import "core:strconv" import "core:strings" import "core:log" +import "core:fmt" -decode :: proc( v: any, key: string ) -> string { +decode :: proc( v: any, key: string ) -> any { if v == nil do return "" - ti := runtime.type_info_base(type_info_of(v.id)) - a := any{v.data, ti.id} + v := reflect.any_base(v) + ti := type_info_of(v.id) - #partial switch info in ti.variant { - - case runtime.Type_Info_Struct: + switch { + case reflect.is_struct(ti): newkey, err := strings.split_after_n(key, ".", 2) if len(newkey) != 2 || err != nil { @@ -22,67 +20,50 @@ decode :: proc( v: any, key: string ) -> string { } return decode( reflect.struct_field_value_by_name(v, newkey[0][:len(newkey[0])-1]), newkey[1] ) - - case runtime.Type_Info_String: + case reflect.is_string(ti): if key != "." do return "" - - switch t in a { - case string: - return t - case cstring: - return string(t) - } - - case runtime.Type_Info_Integer: + return v + case reflect.is_integer(ti): if key != "." do return "" - - buf: [40]byte - u := cast_any_int_to_u128(a) - - return strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) - case runtime.Type_Info_Enum: - return decode(any{v.data, info.base.id}, key) + return v + case reflect.is_enum(ti): + return decode(any{v.data, ti.id}, key) + case reflect.is_slice(ti): + if key != "." do return "" + return v + case: + log.warnf("%v", ti) } return "" } +decode_string :: proc( v: any, key: string ) -> string { + return fmt.tprintf("%v", decode(v, key)) +} -// Stealed from core:endoding/json -@(private) -cast_any_int_to_u128 :: proc(any_int_value: any) -> u128 { - u: u128 = 0 +preprocess :: proc( r: ^strings.Reader, v: any, key: string ) -> string { + if v == nil do return "" - switch i in any_int_value { - case i8: u = u128(i) - case i16: u = u128(i) - case i32: u = u128(i) - case i64: u = u128(i) - case i128: u = u128(i) - case int: u = u128(i) - case u8: u = u128(i) - case u16: u = u128(i) - case u32: u = u128(i) - case u64: u = u128(i) - case u128: u = u128(i) - case uint: u = u128(i) - case uintptr: u = u128(i) + save := r.i - case i16le: u = u128(i) - case i32le: u = u128(i) - case i64le: u = u128(i) - case u16le: u = u128(i) - case u32le: u = u128(i) - case u64le: u = u128(i) - case u128le: u = u128(i) - case i16be: u = u128(i) - case i32be: u = u128(i) - case i64be: u = u128(i) - case u16be: u = u128(i) - case u32be: u = u128(i) - case u64be: u = u128(i) - case u128be: u = u128(i) + t := reflect.any_base(decode(v, key)) + ti := type_info_of(t.id) + + ret : string + switch { + case reflect.is_slice(ti): + for i in 0.. string { +mustache_string :: proc(fmt: string, v: any ) -> string { + r : strings.Reader + strings.reader_init(&r, fmt) + return mustache(&r, v, "") +} + +mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string ) -> string { /* template works as a state machine, it manipulates `b` (returned string) and `key` (placeholder string), according to the states. No error @@ -33,49 +40,73 @@ mustache :: proc(fmt: string, v: any ) -> string { s:= state.writing - for c in fmt do switch c { - case '{': - switch s { - case .open_bracket: - s=.reading_key - case .close_bracket: - strings.write_string(&b, "}{" ) - s=.writing - case .writing: - s=.open_bracket - case .reading_key: - strings.write_rune(&key, '{' ) + for { + c, _, err := strings.reader_read_rune(r); + + if err != nil { + break } - case '}': - switch s { - case .open_bracket: - strings.write_string(&b, "{}" ) - s=.writing - case .close_bracket: - strings.write_string(&b, decode(v, strings.to_string(key) )) - strings.builder_reset(&key) - s=.writing - case .writing: - strings.write_rune(&b, '}' ) - s=.writing - case .reading_key: - s=.close_bracket - } - case: - switch s { - case .open_bracket: - strings.write_rune(&b, '{' ) - strings.write_rune(&b, c ) - s=.writing - case .close_bracket: - strings.write_rune(&key, '}' ) - strings.write_rune(&key, c ) - s=.reading_key - case .writing: - strings.write_rune(&b, c ) - s=.writing - case .reading_key: - strings.write_rune(&key, c ) + + switch c { + case '{': + switch s { + case .open_bracket: + s=.reading_key + case .close_bracket: + strings.write_string(&b, "}{" ) + s=.writing + case .writing: + s=.open_bracket + case .reading_key: + strings.write_rune(&key, '{' ) + } + case '}': + switch s { + case .open_bracket: + strings.write_string(&b, "{}" ) + s=.writing + case .close_bracket: + // Work with key + skey := strings.to_string(key) + strings.builder_reset(&key) + s=.writing + + if len(skey) == 0 { + break + } + + switch skey[0] { + case '/': + if skey[1:] == end_block { + return strings.to_string(b) + } + case '#': + strings.write_string(&b, preprocess(r, v, skey[1:]) ) + case: + strings.write_string(&b, decode_string(v, skey) ) + } + case .writing: + strings.write_rune(&b, '}' ) + s=.writing + case .reading_key: + s=.close_bracket + } + case: + switch s { + case .open_bracket: + strings.write_rune(&b, '{' ) + strings.write_rune(&b, c ) + s=.writing + case .close_bracket: + strings.write_rune(&key, '}' ) + strings.write_rune(&key, c ) + s=.reading_key + case .writing: + strings.write_rune(&b, c ) + s=.writing + case .reading_key: + strings.write_rune(&key, c ) + } } }