Improve MJSON handling

This commit is contained in:
gingerBill
2021-09-28 15:01:11 +01:00
parent c933054872
commit d452758afc
3 changed files with 86 additions and 69 deletions

View File

@@ -109,63 +109,61 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
token := p.curr_token
#partial switch token.kind {
case .Null:
value = Null{}
advance_token(p)
value = Null{}
return
case .False:
value = Boolean(false)
advance_token(p)
value = Boolean(false)
return
case .True:
value = Boolean(true)
advance_token(p)
value = Boolean(true)
return
case .Integer:
advance_token(p)
i, _ := strconv.parse_i64(token.text)
value = Integer(i)
advance_token(p)
return
case .Float:
advance_token(p)
f, _ := strconv.parse_f64(token.text)
value = Float(f)
advance_token(p)
return
case .String:
value = unquote_string(token, p.spec, p.allocator) or_return
advance_token(p)
return
case .Open_Brace:
return parse_object(p)
case .Open_Bracket:
return parse_array(p)
case .Ident:
if p.spec == .MJSON {
advance_token(p)
return string(token.text), nil
}
case .String:
advance_token(p)
return unquote_string(token, p.spec, p.allocator)
case .Open_Brace:
return parse_object(p)
case .Open_Bracket:
return parse_array(p)
case:
if p.spec != .JSON {
#partial switch token.kind {
case .Infinity:
switch {
case allow_token(p, .Infinity):
inf: u64 = 0x7ff0000000000000
if token.text[0] == '-' {
inf = 0xfff0000000000000
}
value = transmute(f64)inf
advance_token(p)
return
case .NaN:
case allow_token(p, .NaN):
nan: u64 = 0x7ff7ffffffffffff
if token.text[0] == '-' {
nan = 0xfff7ffffffffffff
}
value = transmute(f64)nan
advance_token(p)
return
}
}

View File

@@ -139,6 +139,56 @@ assign_float :: proc(val: any, i: $T) -> bool {
}
@(private)
unmarsal_string :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.Type_Info) -> bool {
val := val
switch dst in &val {
case string:
dst = str
return true
case cstring:
if str == "" {
dst = strings.clone_to_cstring("", p.allocator)
} else {
// NOTE: This is valid because 'clone_string' appends a NUL terminator
dst = cstring(raw_data(str))
}
return true
}
defer delete(str, p.allocator)
#partial switch variant in ti.variant {
case reflect.Type_Info_Enum:
for name, i in variant.names {
if name == str {
assign_int(val, variant.values[i])
return true
}
}
// TODO(bill): should this be an error or not?
return true
case reflect.Type_Info_Integer:
i := strconv.parse_i128(str) or_return
if assign_int(val, i) {
return true
}
if assign_float(val, i) {
return true
}
case reflect.Type_Info_Float:
f := strconv.parse_f64(str) or_return
if assign_int(val, f) {
return true
}
if assign_float(val, f) {
return true
}
}
return false
}
@(private)
unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
@@ -195,60 +245,22 @@ unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
}
}
return UNSUPPORTED_TYPE
case .Ident:
advance_token(p)
if p.spec == .MJSON {
if unmarsal_string(p, any{v.data, ti.id}, token.text, ti) {
return nil
}
}
return UNSUPPORTED_TYPE
case .String:
advance_token(p)
str := unquote_string(token, p.spec, p.allocator) or_return
val := any{v.data, ti.id}
switch dst in &val {
case string:
dst = str
return
case cstring:
if str == "" {
dst = strings.clone_to_cstring("", p.allocator)
} else {
// NOTE: This is valid because 'clone_string' appends a NUL terminator
dst = cstring(raw_data(str))
}
return
}
defer delete(str, p.allocator)
#partial switch variant in ti.variant {
case reflect.Type_Info_Enum:
for name, i in variant.names {
if name == str {
assign_int(val, variant.values[i])
return nil
}
}
// TODO(bill): should this be an error or not?
if unmarsal_string(p, any{v.data, ti.id}, str, ti) {
return nil
case reflect.Type_Info_Integer:
i, ok := strconv.parse_i128(token.text)
if !ok {
return UNSUPPORTED_TYPE
}
if assign_int(val, i) {
return
}
if assign_float(val, i) {
return
}
case reflect.Type_Info_Float:
f, ok := strconv.parse_f64(token.text)
if !ok {
return UNSUPPORTED_TYPE
}
if assign_int(val, f) {
return
}
if assign_float(val, f) {
return
}
}
return UNSUPPORTED_TYPE

View File

@@ -102,6 +102,13 @@ validate_value :: proc(p: ^Parser) -> bool {
case .Open_Bracket:
return validate_array(p)
case .Ident:
if p.spec == .MJSON {
advance_token(p)
return true
}
return false
case:
if p.spec != .JSON {