Pass section

This commit is contained in:
PedroEdiaz
2025-06-19 21:57:18 -06:00
parent 774d1fd8eb
commit 0f76ad666a
2 changed files with 88 additions and 62 deletions

View File

@@ -4,21 +4,48 @@ import "base:runtime"
import "core:reflect" import "core:reflect"
import "core:strings" import "core:strings"
import "core:mem" import "core:mem"
import "core:fmt"
import "core:log" import "core:log"
decode :: proc( v: any, key: string ) -> any { @private
v := reflect.any_base(v) _clean_html :: proc(s: string) -> string {
ti := type_info_of(v.id) ret: strings.Builder
#partial switch i in runtime.type_info_base(ti).variant { for c in s do switch c {
case '<':
strings.write_string(&ret, "&lt;")
case '>':
strings.write_string(&ret, "&gt;")
case '&':
strings.write_string(&ret, "&amp;")
case '"':
strings.write_string(&ret, "&quot;")
case '\'':
strings.write_string(&ret, "&apos;")
case:
strings.write_rune(&ret, c)
}
return strings.to_string(ret)
}
decode :: proc( v: any, key: string ) -> any {
ti := type_info_of(v.id)
variant := runtime.type_info_base(ti).variant
#partial switch i in variant {
case runtime.Type_Info_Enumerated_Array: case runtime.Type_Info_Enumerated_Array:
return decode(any{v.data, ti.id}, key) return decode(any{v.data, ti.id}, key)
case runtime.Type_Info_Union: case runtime.Type_Info_Union:
return decode(any{v.data, reflect.union_variant_typeid(v) }, key) return decode(any{v.data, reflect.union_variant_typeid(v) }, key)
}
if key == "." {
return v
}
#partial switch i in variant {
case runtime.Type_Info_Struct: case runtime.Type_Info_Struct:
newkey, err := strings.split_after_n(key, ".", 2) newkey, err := strings.split_after_n(key, ".", 2)
@@ -74,36 +101,31 @@ decode :: proc( v: any, key: string ) -> any {
} }
} }
return "" return nil
} }
if key == "." { return nil
return v
}
return ""
}
decode_string :: proc( v: any, key: string ) -> string {
return fmt.tprintf("%v", decode(v, key))
} }
@private @private
mustache_section :: proc( r: ^strings.Reader, v: any, key: string, inv: bool = false ) -> string { mustache_section :: proc( r: ^strings.Reader, v, p: any, section_key: string, inv: bool = false ) -> string {
tmp := mustache(r, v, key) tmp := mustache(r, v, section_key)
defer delete(tmp)
tmp2 := mustache(tmp, p, section_key)
if inv { if inv {
return tmp return tmp2
} }
defer delete(tmp) delete(tmp2)
return "" return ""
} }
section :: proc( r: ^strings.Reader, v: any, key: string, inv: bool = false ) -> string { section :: proc( r: ^strings.Reader, v: any, section_key: string, inv: bool = false ) -> string {
save := r.i save := r.i
t := reflect.any_base(decode(v, key)) t := reflect.any_base(decode(v, section_key))
ti := type_info_of(t.id) ti := type_info_of(t.id)
#partial switch i in runtime.type_info_base(ti).variant { #partial switch i in runtime.type_info_base(ti).variant {
@@ -113,7 +135,7 @@ section :: proc( r: ^strings.Reader, v: any, key: string, inv: bool = false ) ->
elem :=reflect.index(t, i); elem :=reflect.index(t, i);
strings.reader_seek(r, save, .Start) strings.reader_seek(r, save, .Start)
tmp := mustache_section(r, elem, key, !inv) tmp := mustache_section(r, elem, v, section_key, !inv)
defer delete(tmp) defer delete(tmp)
ret = strings.concatenate({ret, tmp}) ret = strings.concatenate({ret, tmp})
@@ -122,13 +144,12 @@ section :: proc( r: ^strings.Reader, v: any, key: string, inv: bool = false ) ->
case runtime.Type_Info_Boolean: case runtime.Type_Info_Boolean:
b, _ := reflect.as_bool(t) b, _ := reflect.as_bool(t)
return mustache_section(r, t, key, b~inv) return mustache_section(r, t, v, section_key, b~inv)
} }
if t == nil { if t == nil {
return mustache_section(r, t, key, inv) return mustache_section(r, t, v, section_key, inv)
} }
return mustache_section(r, t, key, !inv) return mustache_section(r, t, v, section_key, !inv)
} }

View File

@@ -1,6 +1,6 @@
package mustache package mustache
import "core:log" import "core:fmt"
import "core:strings" import "core:strings"
state :: enum { state :: enum {
@@ -11,31 +11,21 @@ state :: enum {
} }
mustache :: proc{mustache_reader, mustache_string} mustache :: proc{mustache_reader, mustache_string}
/*
Input:
- fmt: A string with placeholders in the form `{{key}}`.
- dict: A map from string to string, where each key corresponds to a placeholder in the format string.
Returns: mustache_string :: proc(fmt: string, data: any , section_key: string = "") -> string {
A new string with all placeholders replaced by their corresponding values from
the dictionary. If a key is missing in the dictionary, the placeholder is
replaces with an empty string.
*/
mustache_string :: proc(fmt: string, v: any , end_block: string = "") -> string {
r : strings.Reader r : strings.Reader
strings.reader_init(&r, fmt) strings.reader_init(&r, fmt)
return mustache(&r, v, end_block) return mustache(&r, data, section_key)
} }
mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) -> string { mustache_reader :: proc(r: ^strings.Reader, data: any, section_key: string = "" ) -> string {
/* /*
template works as a state machine, it manipulates `b` (returned string) This is the main parser for mustache templates, it's a recursive decent parser, that works as a state machine,
and `key` (placeholder string), according to the states. No error it manipulates the processed template with data, `ret`, and the key to element on data `key`, according to the states.
returns are needed because if `key` is not close it writes it as This approach let us process the data as fast as posible.
it's not a placeholder
*/ */
b, key: strings.Builder ret, key: strings.Builder
defer strings.builder_destroy(&key) defer strings.builder_destroy(&key)
s:= state.writing s:= state.writing
@@ -53,7 +43,7 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
case .open_bracket: case .open_bracket:
s=.reading_key s=.reading_key
case .close_bracket: case .close_bracket:
strings.write_string(&b, "}{" ) strings.write_string(&ret, "}{" )
s=.writing s=.writing
case .writing: case .writing:
s=.open_bracket s=.open_bracket
@@ -63,7 +53,7 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
case '}': case '}':
switch s { switch s {
case .open_bracket: case .open_bracket:
strings.write_string(&b, "{}" ) strings.write_string(&ret, "{}" )
s=.writing s=.writing
case .close_bracket: case .close_bracket:
// Work with key // Work with key
@@ -77,18 +67,33 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
switch skey[0] { switch skey[0] {
case '/': case '/':
if skey[1:] == end_block { if skey[1:] == section_key {
return strings.to_string(b) return strings.to_string(ret)
} }
case '#': case '#':
strings.write_string(&b, section(r, v, skey[1:]) ) strings.write_string(&ret, section(r, data, skey[1:]) )
case '^': case '^':
strings.write_string(&b, section(r, v, skey[1:], true) ) strings.write_string(&ret, section(r, data, skey[1:], true) )
case '&':
strings.write_string(&ret, fmt.tprintf("%v",decode(data, skey[1:])) )
case: case:
strings.write_string(&b, decode_string(v, skey) ) dec := decode(data, skey)
if dec == nil {
// If not decoded write as key
strings.write_string(&ret, "{{" )
strings.write_string(&ret, skey )
strings.write_string(&ret, "}}" )
break
}
clean := _clean_html(fmt.tprintf("%v", dec))
defer delete(clean)
strings.write_string(&ret, clean)
} }
case .writing: case .writing:
strings.write_rune(&b, '}' ) strings.write_rune(&ret, '}' )
s=.writing s=.writing
case .reading_key: case .reading_key:
s=.close_bracket s=.close_bracket
@@ -96,15 +101,15 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
case: case:
switch s { switch s {
case .open_bracket: case .open_bracket:
strings.write_rune(&b, '{' ) strings.write_rune(&ret, '{' )
strings.write_rune(&b, c ) strings.write_rune(&ret, c )
s=.writing s=.writing
case .close_bracket: case .close_bracket:
strings.write_rune(&key, '}' ) strings.write_rune(&key, '}' )
strings.write_rune(&key, c ) strings.write_rune(&key, c )
s=.reading_key s=.reading_key
case .writing: case .writing:
strings.write_rune(&b, c ) strings.write_rune(&ret, c )
s=.writing s=.writing
case .reading_key: case .reading_key:
strings.write_rune(&key, c ) strings.write_rune(&key, c )
@@ -114,18 +119,18 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
switch s { switch s {
case .open_bracket: case .open_bracket:
strings.write_rune(&b, '{' ) strings.write_rune(&ret, '{' )
case .reading_key: case .reading_key:
strings.write_string(&b,"{{") strings.write_string(&ret,"{{")
strings.write_string(&b,strings.to_string(key)) strings.write_string(&ret,strings.to_string(key))
case .close_bracket: case .close_bracket:
strings.write_string(&b,"{{") strings.write_string(&ret,"{{")
strings.write_string(&b,strings.to_string(key)) strings.write_string(&ret,strings.to_string(key))
strings.write_rune(&b, '}' ) strings.write_rune(&ret, '}' )
case .writing: case .writing:
} }
return strings.to_string(b) return strings.to_string(ret)
} }
/* /*