aboutsummaryrefslogtreecommitdiff
path: root/core/encoding/json/parser.odin
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-09-25 17:47:45 +0100
committergingerBill <bill@gingerbill.org>2021-09-25 17:47:45 +0100
commit6a271355a6f6e97db30bbe2ea4de44669d85606b (patch)
tree649023f20f05925be3ebdcfad6d49dcc5533eab9 /core/encoding/json/parser.odin
parent931fdd2dca7dcd4f647acb1b38d9cbe49ca9cb30 (diff)
Add `json.unmarshal`
Diffstat (limited to 'core/encoding/json/parser.odin')
-rw-r--r--core/encoding/json/parser.odin54
1 files changed, 35 insertions, 19 deletions
diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin
index b71d90b96..b74cd7402 100644
--- a/core/encoding/json/parser.odin
+++ b/core/encoding/json/parser.odin
@@ -10,11 +10,10 @@ Parser :: struct {
curr_token: Token,
spec: Specification,
allocator: mem.Allocator,
- unmarshal_data: any,
parse_integers: bool,
}
-make_parser :: proc(data: []byte, spec := Specification.JSON, parse_integers := false, allocator := context.allocator) -> Parser {
+make_parser :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> Parser {
p: Parser
p.tok = make_tokenizer(data, spec, parse_integers)
p.spec = spec
@@ -24,7 +23,7 @@ make_parser :: proc(data: []byte, spec := Specification.JSON, parse_integers :=
return p
}
-parse :: proc(data: []byte, spec := Specification.JSON, parse_integers := false, allocator := context.allocator) -> (Value, Error) {
+parse :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> (Value, Error) {
context.allocator = allocator
p := make_parser(data, spec, parse_integers, allocator)
@@ -94,7 +93,7 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
advance_token(p)
return
case .String:
- value = String(unquote_string(token, p.spec, p.allocator))
+ value = unquote_string(token, p.spec, p.allocator) or_return
advance_token(p)
return
@@ -161,24 +160,41 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
return
}
-clone_string :: proc(s: string, allocator: mem.Allocator) -> string {
+@(private)
+bytes_make :: proc(size, alignment: int, allocator: mem.Allocator) -> (bytes: []byte, err: Error) {
+ b, berr := mem.alloc_bytes(size, alignment, allocator)
+ if berr != nil {
+ if berr == .Out_Of_Memory {
+ err = .Out_Of_Memory
+ } else {
+ err = .Invalid_Allocator
+ }
+ }
+ bytes = b
+ return
+}
+
+clone_string :: proc(s: string, allocator: mem.Allocator) -> (str: string, err: Error) {
n := len(s)
- b := make([]byte, n+1, allocator)
+ b := bytes_make(n+1, 1, allocator) or_return
copy(b, s)
- b[n] = 0
- return string(b[:n])
+ if len(b) > n {
+ b[n] = 0
+ str = string(b[:n])
+ }
+ return
}
-parse_object_key :: proc(p: ^Parser) -> (key: string, err: Error) {
+parse_object_key :: proc(p: ^Parser, key_allocator: mem.Allocator) -> (key: string, err: Error) {
tok := p.curr_token
if p.spec == Specification.JSON5 {
if tok.kind == .String {
expect_token(p, .String)
- key = unquote_string(tok, p.spec, p.allocator)
+ key = unquote_string(tok, p.spec, key_allocator) or_return
return
} else if tok.kind == .Ident {
expect_token(p, .Ident)
- key = clone_string(tok.text, p.allocator)
+ key = clone_string(tok.text, key_allocator) or_return
return
}
}
@@ -186,7 +202,7 @@ parse_object_key :: proc(p: ^Parser) -> (key: string, err: Error) {
err = .Expected_String_For_Object_Key
return
}
- key = unquote_string(tok, p.spec, p.allocator)
+ key = unquote_string(tok, p.spec, key_allocator) or_return
return
}
@@ -205,7 +221,7 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
for p.curr_token.kind != .Close_Brace {
key: string
- key, err = parse_object_key(p)
+ key, err = parse_object_key(p, p.allocator)
if err != .None {
delete(key, p.allocator)
return
@@ -248,7 +264,7 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
// IMPORTANT NOTE(bill): unquote_string assumes a mostly valid string
-unquote_string :: proc(token: Token, spec: Specification, allocator := context.allocator) -> string {
+unquote_string :: proc(token: Token, spec: Specification, allocator := context.allocator) -> (value: string, err: Error) {
get_u2_rune :: proc(s: string) -> rune {
if len(s) < 4 || s[0] != '\\' || s[1] != 'x' {
return -1
@@ -287,16 +303,16 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
}
if token.kind != .String {
- return ""
+ return "", nil
}
s := token.text
if len(s) <= 2 {
- return ""
+ return "", nil
}
quote := s[0]
if s[0] != s[len(s)-1] {
// Invalid string
- return ""
+ return "", nil
}
s = s[1:len(s)-1]
@@ -320,7 +336,7 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
return clone_string(s, allocator)
}
- b := make([]byte, len(s) + 2*utf8.UTF_MAX, allocator)
+ b := bytes_make(len(s) + 2*utf8.UTF_MAX, 1, allocator) or_return
w := copy(b, s[0:i])
loop: for i < len(s) {
c := s[i]
@@ -423,5 +439,5 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
}
}
- return string(b[:w])
+ return string(b[:w]), nil
}