123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- package json
- import "core:mem"
- // NOTE(bill): is_valid will not check for duplicate keys
- is_valid :: proc(data: []byte, spec := Specification.JSON, parse_integers := false) -> bool {
- p := make_parser(data, spec, parse_integers, mem.nil_allocator());
- if p.spec == Specification.JSON5 {
- return validate_value(&p);
- }
- return validate_object(&p);
- }
- validate_object_key :: proc(p: ^Parser) -> bool {
- tok := p.curr_token;
- if p.spec == Specification.JSON5 {
- if tok.kind == .String {
- expect_token(p, .String);
- return true;
- } else if tok.kind == .Ident {
- expect_token(p, .Ident);
- return true;
- }
- }
- err := expect_token(p, .String);
- return err == Error.None;
- }
- validate_object :: proc(p: ^Parser) -> bool {
- if err := expect_token(p, .Open_Brace); err != Error.None {
- return false;
- }
- for p.curr_token.kind != .Close_Brace {
- if !validate_object_key(p) {
- return false;
- }
- if colon_err := expect_token(p, .Colon); colon_err != Error.None {
- return false;
- }
- if !validate_value(p) {
- return false;
- }
- if p.spec == Specification.JSON5 {
- // Allow trailing commas
- if allow_token(p, .Comma) {
- continue;
- }
- } else {
- // Disallow trailing commas
- if allow_token(p, .Comma) {
- continue;
- } else {
- break;
- }
- }
- }
- if err := expect_token(p, .Close_Brace); err != Error.None {
- return false;
- }
- return true;
- }
- validate_array :: proc(p: ^Parser) -> bool {
- if err := expect_token(p, .Open_Bracket); err != Error.None {
- return false;
- }
- for p.curr_token.kind != .Close_Bracket {
- if !validate_value(p) {
- return false;
- }
- // Disallow trailing commas for the time being
- if allow_token(p, .Comma) {
- continue;
- } else {
- break;
- }
- }
- if err := expect_token(p, .Close_Bracket); err != Error.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:
- if p.spec == Specification.JSON5 {
- #partial switch token.kind {
- case .Infinity, .NaN:
- advance_token(p);
- return true;
- }
- }
- }
- return false;
- }
|