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:strings"
import "core:mem"
import "core:fmt"
import "core:log"
decode :: proc( v: any, key: string ) -> any {
v := reflect.any_base(v)
ti := type_info_of(v.id)
@private
_clean_html :: proc(s: string) -> string {
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:
return decode(any{v.data, ti.id}, key)
case runtime.Type_Info_Union:
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:
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 v
}
return ""
}
decode_string :: proc( v: any, key: string ) -> string {
return fmt.tprintf("%v", decode(v, key))
return nil
}
@private
mustache_section :: proc( r: ^strings.Reader, v: any, key: string, inv: bool = false ) -> string {
tmp := mustache(r, v, key)
mustache_section :: proc( r: ^strings.Reader, v, p: any, section_key: string, inv: bool = false ) -> string {
tmp := mustache(r, v, section_key)
defer delete(tmp)
tmp2 := mustache(tmp, p, section_key)
if inv {
return tmp
return tmp2
}
defer delete(tmp)
delete(tmp2)
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
t := reflect.any_base(decode(v, key))
t := reflect.any_base(decode(v, section_key))
ti := type_info_of(t.id)
#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);
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)
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:
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 {
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
import "core:log"
import "core:fmt"
import "core:strings"
state :: enum {
@@ -11,31 +11,21 @@ state :: enum {
}
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:
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 {
mustache_string :: proc(fmt: string, data: any , section_key: string = "") -> string {
r : strings.Reader
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)
and `key` (placeholder string), according to the states. No error
returns are needed because if `key` is not close it writes it as
it's not a placeholder
This is the main parser for mustache templates, it's a recursive decent parser, that works as a state machine,
it manipulates the processed template with data, `ret`, and the key to element on data `key`, according to the states.
This approach let us process the data as fast as posible.
*/
b, key: strings.Builder
ret, key: strings.Builder
defer strings.builder_destroy(&key)
s:= state.writing
@@ -53,7 +43,7 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
case .open_bracket:
s=.reading_key
case .close_bracket:
strings.write_string(&b, "}{" )
strings.write_string(&ret, "}{" )
s=.writing
case .writing:
s=.open_bracket
@@ -63,7 +53,7 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
case '}':
switch s {
case .open_bracket:
strings.write_string(&b, "{}" )
strings.write_string(&ret, "{}" )
s=.writing
case .close_bracket:
// Work with key
@@ -77,18 +67,33 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
switch skey[0] {
case '/':
if skey[1:] == end_block {
return strings.to_string(b)
if skey[1:] == section_key {
return strings.to_string(ret)
}
case '#':
strings.write_string(&b, section(r, v, skey[1:]) )
strings.write_string(&ret, section(r, data, skey[1:]) )
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:
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:
strings.write_rune(&b, '}' )
strings.write_rune(&ret, '}' )
s=.writing
case .reading_key:
s=.close_bracket
@@ -96,15 +101,15 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
case:
switch s {
case .open_bracket:
strings.write_rune(&b, '{' )
strings.write_rune(&b, c )
strings.write_rune(&ret, '{' )
strings.write_rune(&ret, 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 )
strings.write_rune(&ret, c )
s=.writing
case .reading_key:
strings.write_rune(&key, c )
@@ -114,18 +119,18 @@ mustache_reader :: proc(r: ^strings.Reader, v: any, end_block: string = "" ) ->
switch s {
case .open_bracket:
strings.write_rune(&b, '{' )
strings.write_rune(&ret, '{' )
case .reading_key:
strings.write_string(&b,"{{")
strings.write_string(&b,strings.to_string(key))
strings.write_string(&ret,"{{")
strings.write_string(&ret,strings.to_string(key))
case .close_bracket:
strings.write_string(&b,"{{")
strings.write_string(&b,strings.to_string(key))
strings.write_rune(&b, '}' )
strings.write_string(&ret,"{{")
strings.write_string(&ret,strings.to_string(key))
strings.write_rune(&ret, '}' )
case .writing:
}
return strings.to_string(b)
return strings.to_string(ret)
}
/*