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 ) + } } }