toml: support arrays in value key query syntax (#12527)

pull/12533/head
Larpon 2021-11-20 18:45:17 +01:00 committed by GitHub
parent 82010e729d
commit 4b9e8e243c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 15 deletions

View File

@ -0,0 +1,32 @@
import toml
const toml_text = '
modules = [ "ui", "toml" ]
errors = []
[[themes]]
name = "Dracula"
colors = [ "red", "black", "white" ]
[[themes]]
name = "Lemon"
colors = [
"green",
"yellow",
[ "transparent" ]
]
'
fn test_value_query_in_array() {
toml_doc := toml.parse(toml_text) or { panic(err) }
mut value := toml_doc.value('themes[0].colors[1]').string()
assert value == 'black'
value = toml_doc.value('themes[1].colors[0]').string()
assert value == 'green'
value = toml_doc.value('themes[1].colors[2].[0]').string()
assert value == 'transparent'
value = toml_doc.value('modules[1]').string()
assert value == 'toml'
value = toml_doc.value('errors[11]').default_to('<none>').string()
assert value == '<none>'
}

View File

@ -156,28 +156,48 @@ pub fn (d Doc) to_any() Any {
}
// value queries a value from the TOML document.
// `key` should be in "dotted" form (`a.b.c`).
// `key` supports quoted keys like `a."b.c"`.
// `key` supports a small query syntax scheme:
// Maps can be queried in "dotted" form e.g. `a.b.c`.
// quoted keys are supported as `a."b.c"` or `a.'b.c'`.
// Arrays can be queried with `a[0].b[1].[2]`.
pub fn (d Doc) value(key string) Any {
values := d.ast.table as map[string]ast.Value
key_split := parse_dotted_key(key) or { return Any(Null{}) }
return d.value_(values, key_split)
return d.value_(d.ast.table, key_split)
}
// value_ returns the value found at `key` in the map `values` as `Any` type.
fn (d Doc) value_(values map[string]ast.Value, key []string) Any {
value := values[key[0]] or {
return Any(Null{})
// TODO decide this
// panic(@MOD + '.' + @STRUCT + '.' + @FN + ' key "$key[0]" does not exist')
fn (d Doc) value_(value ast.Value, key []string) Any {
assert key.len > 0
mut ast_value := ast.Value(ast.Null{})
mut index := -1
mut k := key[0]
if k.contains('[') {
index = k.all_after('[').all_before(']').int()
if k.starts_with('[') {
k = '' // k.all_after(']')
} else {
k = k.all_before('[')
}
}
if k == '' {
a := value as []ast.Value
ast_value = a[index] or { return Any(Null{}) }
}
if value is map[string]ast.Value {
ast_value = value[k] or { return Any(Null{}) }
if index > -1 {
a := ast_value as []ast.Value
ast_value = a[index] or { return Any(Null{}) }
}
}
if key.len <= 1 {
return d.ast_to_any(ast_value)
}
// `match` isn't currently very suitable for these types of sum type constructs...
if value is map[string]ast.Value {
if key.len <= 1 {
return d.ast_to_any(value)
}
m := (value as map[string]ast.Value)
return d.value_(m, key[1..])
if ast_value is map[string]ast.Value || ast_value is []ast.Value {
return d.value_(ast_value, key[1..])
}
return d.ast_to_any(value)
}