123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- package json
- import "core:mem"
- // NOTE(bill): is_valid will not check for duplicate keys
- is_valid :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false) -> bool {
- p := make_parser(data, spec, parse_integers, mem.nil_allocator())
-
- switch p.spec {
- case .JSON:
- return validate_object(&p)
- case .JSON5:
- return validate_value(&p)
- case .MJSON:
- #partial switch p.curr_token.kind {
- case .Ident, .String:
- return validate_object_body(&p, .EOF)
- }
- return validate_value(&p)
- }
- return validate_object(&p)
- }
- validate_object_key :: proc(p: ^Parser) -> bool {
- if p.spec != .JSON {
- if allow_token(p, .Ident) {
- return true
- }
- }
- err := expect_token(p, .String)
- return err == .None
- }
- validate_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> bool {
- for p.curr_token.kind != end_token {
- if !validate_object_key(p) {
- return false
- }
- if parse_colon(p) != nil {
- return false
- }
- validate_value(p) or_return
- if parse_comma(p) {
- break
- }
- }
- return true
- }
- validate_object :: proc(p: ^Parser) -> bool {
- if err := expect_token(p, .Open_Brace); err != .None {
- return false
- }
-
- validate_object_body(p, .Close_Brace) or_return
- if err := expect_token(p, .Close_Brace); err != .None {
- return false
- }
- return true
- }
- validate_array :: proc(p: ^Parser) -> bool {
- if err := expect_token(p, .Open_Bracket); err != .None {
- return false
- }
- for p.curr_token.kind != .Close_Bracket {
- if !validate_value(p) {
- return false
- }
- if parse_comma(p) {
- break
- }
- }
- if err := expect_token(p, .Close_Bracket); err != .None {
- return false
- }
- return true
- }
- validate_value :: proc(p: ^Parser) -> bool {
- token := p.curr_token
- #partial switch token.kind {
- case .Null, .False, .True:
- advance_token(p)
- return true
- case .Integer, .Float:
- advance_token(p)
- return true
- case .String:
- advance_token(p)
- return is_valid_string_literal(token.text, p.spec)
- case .Open_Brace:
- return validate_object(p)
- 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 {
- #partial switch token.kind {
- case .Infinity, .NaN:
- advance_token(p)
- return true
- }
- }
- }
- return false
- }
|