From d452758afc2a503bc5bc04da04cfdd4af90da1ac Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 28 Sep 2021 15:01:11 +0100 Subject: [PATCH] Improve MJSON handling --- core/encoding/json/parser.odin | 38 +++++------ core/encoding/json/unmarshal.odin | 110 +++++++++++++++++------------- core/encoding/json/validator.odin | 7 ++ 3 files changed, 86 insertions(+), 69 deletions(-) diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index 0bb4c03a5..af32e7266 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -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 } } diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index e05c140da..46c248e01 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -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 diff --git a/core/encoding/json/validator.odin b/core/encoding/json/validator.odin index 085dd384a..961c2dc23 100644 --- a/core/encoding/json/validator.odin +++ b/core/encoding/json/validator.odin @@ -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 {