validator.odin 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package json
  2. import "core:mem"
  3. // NOTE(bill): is_valid will not check for duplicate keys
  4. is_valid :: proc(data: []byte, spec := Specification.JSON) -> bool {
  5. p := make_parser(data, spec, mem.nil_allocator());
  6. if p.spec == Specification.JSON5 {
  7. return validate_value(&p);
  8. }
  9. return validate_object(&p);
  10. }
  11. validate_object_key :: proc(p: ^Parser) -> bool {
  12. tok := p.curr_token;
  13. if p.spec == Specification.JSON5 {
  14. if tok.kind == .String {
  15. expect_token(p, .String);
  16. return true;
  17. } else if tok.kind == .Ident {
  18. expect_token(p, .Ident);
  19. return true;
  20. }
  21. }
  22. err := expect_token(p, .String);
  23. return err == Error.None;
  24. }
  25. validate_object :: proc(p: ^Parser) -> bool {
  26. if err := expect_token(p, .Open_Brace); err != Error.None {
  27. return false;
  28. }
  29. for p.curr_token.kind != .Close_Brace {
  30. if !validate_object_key(p) {
  31. return false;
  32. }
  33. if colon_err := expect_token(p, .Colon); colon_err != Error.None {
  34. return false;
  35. }
  36. if !validate_value(p) {
  37. return false;
  38. }
  39. if p.spec == Specification.JSON5 {
  40. // Allow trailing commas
  41. if allow_token(p, .Comma) {
  42. continue;
  43. }
  44. } else {
  45. // Disallow trailing commas
  46. if allow_token(p, .Comma) {
  47. continue;
  48. } else {
  49. break;
  50. }
  51. }
  52. }
  53. if err := expect_token(p, .Close_Brace); err != Error.None {
  54. return false;
  55. }
  56. return true;
  57. }
  58. validate_array :: proc(p: ^Parser) -> bool {
  59. if err := expect_token(p, .Open_Bracket); err != Error.None {
  60. return false;
  61. }
  62. for p.curr_token.kind != .Close_Bracket {
  63. if !validate_value(p) {
  64. return false;
  65. }
  66. // Disallow trailing commas for the time being
  67. if allow_token(p, .Comma) {
  68. continue;
  69. } else {
  70. break;
  71. }
  72. }
  73. if err := expect_token(p, .Close_Bracket); err != Error.None {
  74. return false;
  75. }
  76. return true;
  77. }
  78. validate_value :: proc(p: ^Parser) -> bool {
  79. token := p.curr_token;
  80. #partial switch token.kind {
  81. case .Null, .False, .True:
  82. advance_token(p);
  83. return true;
  84. case .Integer, .Float:
  85. advance_token(p);
  86. return true;
  87. case .String:
  88. advance_token(p);
  89. return is_valid_string_literal(token.text, p.spec);
  90. case .Open_Brace:
  91. return validate_object(p);
  92. case .Open_Bracket:
  93. return validate_array(p);
  94. case:
  95. if p.spec == Specification.JSON5 {
  96. #partial switch token.kind {
  97. case .Infinity, .NaN:
  98. advance_token(p);
  99. return true;
  100. }
  101. }
  102. }
  103. return false;
  104. }