mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-11 02:19:30 +00:00
Update core:encoding/json to use proc groups and @(require_results)
This commit is contained in:
@@ -134,6 +134,7 @@ register_user_marshaler :: proc(id: typeid, marshaler: User_Marshaler) -> Regist
|
||||
return .None
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Marshal_Error) {
|
||||
b := strings.builder_make(allocator, loc)
|
||||
defer if err != nil {
|
||||
|
||||
@@ -14,9 +14,16 @@ Parser :: struct {
|
||||
parse_integers: bool,
|
||||
}
|
||||
|
||||
make_parser :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> Parser {
|
||||
make_parser :: proc{
|
||||
make_parser_from_bytes,
|
||||
make_parser_from_string,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
make_parser_from_bytes :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> Parser {
|
||||
return make_parser_from_string(string(data), spec, parse_integers, allocator)
|
||||
}
|
||||
@(require_results)
|
||||
make_parser_from_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> Parser {
|
||||
p: Parser
|
||||
p.tok = make_tokenizer(data, spec, parse_integers)
|
||||
@@ -27,11 +34,18 @@ make_parser_from_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, par
|
||||
return p
|
||||
}
|
||||
|
||||
parse :: proc{
|
||||
parse_bytes,
|
||||
parse_string,
|
||||
}
|
||||
|
||||
parse :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) {
|
||||
|
||||
@(require_results)
|
||||
parse_bytes :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) {
|
||||
return parse_string(string(data), spec, parse_integers, allocator, loc)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) {
|
||||
context.allocator = allocator
|
||||
p := make_parser_from_string(data, spec, parse_integers, allocator)
|
||||
@@ -51,6 +65,7 @@ parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers
|
||||
return parse_object(&p, loc)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
token_end_pos :: proc(tok: Token) -> Pos {
|
||||
end := tok.pos
|
||||
end.offset += len(tok.text)
|
||||
@@ -65,6 +80,7 @@ advance_token :: proc(p: ^Parser) -> (Token, Error) {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
allow_token :: proc(p: ^Parser, kind: Token_Kind) -> bool {
|
||||
if p.curr_token.kind == kind {
|
||||
advance_token(p)
|
||||
@@ -73,6 +89,7 @@ allow_token :: proc(p: ^Parser, kind: Token_Kind) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
expect_token :: proc(p: ^Parser, kind: Token_Kind) -> Error {
|
||||
prev := p.curr_token
|
||||
advance_token(p)
|
||||
@@ -83,6 +100,7 @@ expect_token :: proc(p: ^Parser, kind: Token_Kind) -> Error {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
parse_colon :: proc(p: ^Parser) -> (err: Error) {
|
||||
colon_err := expect_token(p, .Colon)
|
||||
if colon_err == nil {
|
||||
@@ -91,6 +109,7 @@ parse_colon :: proc(p: ^Parser) -> (err: Error) {
|
||||
return .Expected_Colon_After_Key
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_comma :: proc(p: ^Parser) -> (do_break: bool) {
|
||||
switch p.spec {
|
||||
case .JSON5, .MJSON:
|
||||
@@ -106,6 +125,7 @@ parse_comma :: proc(p: ^Parser) -> (do_break: bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_value :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) {
|
||||
err = .None
|
||||
token := p.curr_token
|
||||
@@ -176,6 +196,7 @@ parse_value :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err:
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_array :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) {
|
||||
err = .None
|
||||
expect_token(p, .Open_Bracket) or_return
|
||||
@@ -203,7 +224,7 @@ parse_array :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err:
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private, require_results)
|
||||
bytes_make :: proc(size, alignment: int, allocator: mem.Allocator, loc := #caller_location) -> (bytes: []byte, err: Error) {
|
||||
b, berr := mem.alloc_bytes(size, alignment, allocator, loc)
|
||||
if berr != nil {
|
||||
@@ -217,6 +238,7 @@ bytes_make :: proc(size, alignment: int, allocator: mem.Allocator, loc := #calle
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
clone_string :: proc(s: string, allocator: mem.Allocator, loc := #caller_location) -> (str: string, err: Error) {
|
||||
n := len(s)
|
||||
b := bytes_make(n+1, 1, allocator, loc) or_return
|
||||
@@ -228,6 +250,7 @@ clone_string :: proc(s: string, allocator: mem.Allocator, loc := #caller_locatio
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_object_key :: proc(p: ^Parser, key_allocator: mem.Allocator, loc := #caller_location) -> (key: string, err: Error) {
|
||||
tok := p.curr_token
|
||||
if p.spec != .JSON {
|
||||
@@ -242,6 +265,7 @@ parse_object_key :: proc(p: ^Parser, key_allocator: mem.Allocator, loc := #calle
|
||||
return unquote_string(tok, p.spec, key_allocator, loc)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_object_body :: proc(p: ^Parser, end_token: Token_Kind, loc := #caller_location) -> (obj: Object, err: Error) {
|
||||
obj = make(Object, allocator=p.allocator, loc=loc)
|
||||
|
||||
@@ -282,6 +306,7 @@ parse_object_body :: proc(p: ^Parser, end_token: Token_Kind, loc := #caller_loca
|
||||
return obj, .None
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
parse_object :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) {
|
||||
expect_token(p, .Open_Brace) or_return
|
||||
obj := parse_object_body(p, .Close_Brace, loc) or_return
|
||||
@@ -291,6 +316,7 @@ parse_object :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err:
|
||||
|
||||
|
||||
// IMPORTANT NOTE(bill): unquote_string assumes a mostly valid string
|
||||
@(require_results)
|
||||
unquote_string :: proc(token: Token, spec: Specification, allocator := context.allocator, loc := #caller_location) -> (value: string, err: Error) {
|
||||
get_u2_rune :: proc(s: string) -> rune {
|
||||
if len(s) < 4 || s[0] != '\\' || s[1] != 'x' {
|
||||
|
||||
@@ -49,11 +49,12 @@ Tokenizer :: struct {
|
||||
curr_line_offset: int,
|
||||
spec: Specification,
|
||||
parse_integers: bool,
|
||||
insert_comma: bool,
|
||||
insert_comma: bool,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
make_tokenizer :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false) -> Tokenizer {
|
||||
t := Tokenizer{pos = {line=1}, data = data, spec = spec, parse_integers = parse_integers}
|
||||
next_rune(&t)
|
||||
@@ -78,6 +79,7 @@ next_rune :: proc(t: ^Tokenizer) -> rune #no_bounds_check {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
skip_digits :: proc(t: ^Tokenizer) {
|
||||
for t.offset < len(t.data) {
|
||||
@@ -101,6 +103,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
scan_escape :: proc(t: ^Tokenizer) -> bool {
|
||||
switch t.r {
|
||||
case '"', '\'', '\\', '/', 'b', 'n', 'r', 't', 'f':
|
||||
@@ -125,7 +128,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
return false
|
||||
}
|
||||
|
||||
skip_whitespace :: proc(t: ^Tokenizer, on_newline: bool) -> rune {
|
||||
skip_whitespace :: proc(t: ^Tokenizer, on_newline: bool) {
|
||||
loop: for t.offset < len(t.data) {
|
||||
switch t.r {
|
||||
case ' ', '\t', '\v', '\f', '\r':
|
||||
@@ -149,7 +152,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
return t.r
|
||||
return
|
||||
}
|
||||
|
||||
skip_to_next_line :: proc(t: ^Tokenizer) {
|
||||
@@ -310,7 +313,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
break
|
||||
}
|
||||
if r == '\\' {
|
||||
scan_escape(t)
|
||||
_ = scan_escape(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,10 +350,8 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
case '*':
|
||||
// None-nested multi-line comments
|
||||
for t.offset < len(t.data) {
|
||||
next_rune(t)
|
||||
if t.r == '*' {
|
||||
next_rune(t)
|
||||
if t.r == '/' {
|
||||
if next_rune(t) == '*' {
|
||||
if next_rune(t) == '/' {
|
||||
next_rune(t)
|
||||
return get_token(t)
|
||||
}
|
||||
@@ -385,6 +386,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
is_valid_number :: proc(str: string, spec: Specification) -> bool {
|
||||
s := str
|
||||
if s == "" {
|
||||
@@ -473,6 +475,7 @@ is_valid_number :: proc(str: string, spec: Specification) -> bool {
|
||||
return s == ""
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_valid_string_literal :: proc(str: string, spec: Specification) -> bool {
|
||||
s := str
|
||||
if len(s) < 2 {
|
||||
|
||||
@@ -112,6 +112,7 @@ destroy_value :: proc(value: Value, allocator := context.allocator, loc := #call
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
clone_value :: proc(value: Value, allocator := context.allocator) -> Value {
|
||||
value := value
|
||||
context.allocator = allocator
|
||||
|
||||
@@ -635,7 +635,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
defer p.allocator = allocator
|
||||
p.allocator = mem.nil_allocator()
|
||||
|
||||
parse_value(p) or_return
|
||||
_ = parse_value(p) or_return
|
||||
if parse_comma(p) {
|
||||
break struct_loop
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package encoding_json
|
||||
import "core:mem"
|
||||
|
||||
// NOTE(bill): is_valid will not check for duplicate keys
|
||||
@(require_results)
|
||||
is_valid :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false) -> bool {
|
||||
p := make_parser(data, spec, parse_integers, mem.nil_allocator())
|
||||
|
||||
@@ -21,6 +22,7 @@ is_valid :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers :=
|
||||
return validate_object(&p)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_object_key :: proc(p: ^Parser) -> bool {
|
||||
if p.spec != .JSON {
|
||||
if allow_token(p, .Ident) {
|
||||
@@ -31,6 +33,7 @@ validate_object_key :: proc(p: ^Parser) -> bool {
|
||||
return err == .None
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> bool {
|
||||
for p.curr_token.kind != end_token {
|
||||
if !validate_object_key(p) {
|
||||
@@ -48,6 +51,7 @@ validate_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_object :: proc(p: ^Parser) -> bool {
|
||||
if err := expect_token(p, .Open_Brace); err != .None {
|
||||
return false
|
||||
@@ -61,6 +65,7 @@ validate_object :: proc(p: ^Parser) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_array :: proc(p: ^Parser) -> bool {
|
||||
if err := expect_token(p, .Open_Bracket); err != .None {
|
||||
return false
|
||||
@@ -83,6 +88,7 @@ validate_array :: proc(p: ^Parser) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
validate_value :: proc(p: ^Parser) -> bool {
|
||||
token := p.curr_token
|
||||
|
||||
|
||||
Reference in New Issue
Block a user