tokenizer.odin 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. package json
  2. import "core:unicode/utf8"
  3. Token :: struct {
  4. using pos: Pos,
  5. kind: Token_Kind,
  6. text: string,
  7. }
  8. Token_Kind :: enum {
  9. Invalid,
  10. EOF,
  11. Null,
  12. False,
  13. True,
  14. Infinity,
  15. NaN,
  16. Ident,
  17. Integer,
  18. Float,
  19. String,
  20. Colon,
  21. Comma,
  22. Open_Brace,
  23. Close_Brace,
  24. Open_Bracket,
  25. Close_Bracket,
  26. }
  27. Tokenizer :: struct {
  28. using pos: Pos,
  29. data: []byte,
  30. r: rune, // current rune
  31. w: int, // current rune width in bytes
  32. curr_line_offset: int,
  33. spec: Specification,
  34. parse_integers: bool,
  35. }
  36. make_tokenizer :: proc(data: []byte, spec := Specification.JSON, parse_integers := false) -> Tokenizer {
  37. t := Tokenizer{pos = {line=1}, data = data, spec = spec, parse_integers = parse_integers};
  38. next_rune(&t);
  39. if t.r == utf8.RUNE_BOM {
  40. next_rune(&t);
  41. }
  42. return t;
  43. }
  44. next_rune :: proc(t: ^Tokenizer) -> rune #no_bounds_check {
  45. if t.offset >= len(t.data) {
  46. return utf8.RUNE_EOF;
  47. }
  48. t.offset += t.w;
  49. t.r, t.w = utf8.decode_rune(t.data[t.offset:]);
  50. t.pos.column = t.offset - t.curr_line_offset;
  51. return t.r;
  52. }
  53. get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
  54. skip_digits :: proc(t: ^Tokenizer) {
  55. for t.offset < len(t.data) {
  56. if '0' <= t.r && t.r <= '9' {
  57. // Okay
  58. } else {
  59. return;
  60. }
  61. next_rune(t);
  62. }
  63. }
  64. skip_hex_digits :: proc(t: ^Tokenizer) {
  65. for t.offset < len(t.data) {
  66. next_rune(t);
  67. switch t.r {
  68. case '0'..'9', 'a'..'f', 'A'..'F':
  69. // Okay
  70. case:
  71. return;
  72. }
  73. }
  74. }
  75. scan_espace :: proc(t: ^Tokenizer) -> bool {
  76. switch t.r {
  77. case '"', '\'', '\\', '/', 'b', 'n', 'r', 't', 'f':
  78. next_rune(t);
  79. return true;
  80. case 'u':
  81. // Expect 4 hexadecimal digits
  82. for i := 0; i < 4; i += 1 {
  83. r := next_rune(t);
  84. switch r {
  85. case '0'..'9', 'a'..'f', 'A'..'F':
  86. // Okay
  87. case:
  88. return false;
  89. }
  90. }
  91. case:
  92. // Ignore the next rune regardless
  93. next_rune(t);
  94. }
  95. return false;
  96. }
  97. skip_whitespace :: proc(t: ^Tokenizer) -> rune {
  98. loop: for t.offset < len(t.data) {
  99. switch t.r {
  100. case ' ', '\t', '\v', '\f', '\r':
  101. next_rune(t);
  102. case '\n':
  103. t.line += 1;
  104. t.curr_line_offset = t.offset;
  105. t.pos.column = 1;
  106. next_rune(t);
  107. case:
  108. if t.spec == .JSON5 {
  109. switch t.r {
  110. case 0x2028, 0x2029, 0xFEFF:
  111. next_rune(t);
  112. continue loop;
  113. }
  114. }
  115. break loop;
  116. }
  117. }
  118. return t.r;
  119. }
  120. skip_to_next_line :: proc(t: ^Tokenizer) {
  121. for t.offset < len(t.data) {
  122. r := next_rune(t);
  123. if r == '\n' {
  124. return;
  125. }
  126. }
  127. }
  128. skip_alphanum :: proc(t: ^Tokenizer) {
  129. for t.offset < len(t.data) {
  130. switch next_rune(t) {
  131. case 'A'..'Z', 'a'..'z', '0'..'9', '_':
  132. continue;
  133. }
  134. return;
  135. }
  136. }
  137. skip_whitespace(t);
  138. token.pos = t.pos;
  139. token.kind = .Invalid;
  140. curr_rune := t.r;
  141. next_rune(t);
  142. block: switch curr_rune {
  143. case utf8.RUNE_ERROR:
  144. err = .Illegal_Character;
  145. case utf8.RUNE_EOF, '\x00':
  146. token.kind = .EOF;
  147. err = .EOF;
  148. case 'A'..'Z', 'a'..'z', '_':
  149. token.kind = .Ident;
  150. skip_alphanum(t);
  151. switch str := string(t.data[token.offset:t.offset]); str {
  152. case "null": token.kind = .Null;
  153. case "false": token.kind = .False;
  154. case "true": token.kind = .True;
  155. case:
  156. if t.spec == .JSON5 {
  157. switch str {
  158. case "Infinity": token.kind = .Infinity;
  159. case "NaN": token.kind = .NaN;
  160. }
  161. }
  162. }
  163. case '+':
  164. err = .Illegal_Character;
  165. if t.spec != .JSON5 {
  166. break;
  167. }
  168. fallthrough;
  169. case '-':
  170. switch t.r {
  171. case '0'..'9':
  172. // Okay
  173. case:
  174. // Illegal use of +/-
  175. err = .Illegal_Character;
  176. if t.spec == .JSON5 {
  177. if t.r == 'I' || t.r == 'N' {
  178. skip_alphanum(t);
  179. }
  180. switch string(t.data[token.offset:t.offset]) {
  181. case "-Infinity": token.kind = .Infinity;
  182. case "-NaN": token.kind = .NaN;
  183. }
  184. }
  185. break block;
  186. }
  187. fallthrough;
  188. case '0'..'9':
  189. token.kind = t.parse_integers ? .Integer : .Float;
  190. if t.spec == .JSON5 { // Hexadecimal Numbers
  191. if curr_rune == '0' && (t.r == 'x' || t.r == 'X') {
  192. next_rune(t);
  193. skip_hex_digits(t);
  194. break;
  195. }
  196. }
  197. skip_digits(t);
  198. if t.r == '.' {
  199. token.kind = .Float;
  200. next_rune(t);
  201. skip_digits(t);
  202. }
  203. if t.r == 'e' || t.r == 'E' {
  204. switch r := next_rune(t); r {
  205. case '+', '-':
  206. next_rune(t);
  207. }
  208. skip_digits(t);
  209. }
  210. str := string(t.data[token.offset:t.offset]);
  211. if !is_valid_number(str, t.spec) {
  212. err = .Invalid_Number;
  213. }
  214. case '.':
  215. err = .Illegal_Character;
  216. if t.spec == .JSON5 { // Allow leading decimal point
  217. skip_digits(t);
  218. if t.r == 'e' || t.r == 'E' {
  219. switch r := next_rune(t); r {
  220. case '+', '-':
  221. next_rune(t);
  222. }
  223. skip_digits(t);
  224. }
  225. str := string(t.data[token.offset:t.offset]);
  226. if !is_valid_number(str, t.spec) {
  227. err = .Invalid_Number;
  228. }
  229. }
  230. case '\'':
  231. err = .Illegal_Character;
  232. if t.spec != .JSON5 {
  233. break;
  234. }
  235. fallthrough;
  236. case '"':
  237. token.kind = .String;
  238. quote := curr_rune;
  239. for t.offset < len(t.data) {
  240. r := t.r;
  241. if r == '\n' || r < 0 {
  242. err = .String_Not_Terminated;
  243. break;
  244. }
  245. next_rune(t);
  246. if r == quote {
  247. break;
  248. }
  249. if r == '\\' {
  250. scan_espace(t);
  251. }
  252. }
  253. str := string(t.data[token.offset : t.offset]);
  254. if !is_valid_string_literal(str, t.spec) {
  255. err = .Invalid_String;
  256. }
  257. case ',': token.kind = .Comma;
  258. case ':': token.kind = .Colon;
  259. case '{': token.kind = .Open_Brace;
  260. case '}': token.kind = .Close_Brace;
  261. case '[': token.kind = .Open_Bracket;
  262. case ']': token.kind = .Close_Bracket;
  263. case '/':
  264. err = .Illegal_Character;
  265. if t.spec == .JSON5 {
  266. switch t.r {
  267. case '/':
  268. // Single-line comments
  269. skip_to_next_line(t);
  270. return get_token(t);
  271. case '*':
  272. // None-nested multi-line comments
  273. for t.offset < len(t.data) {
  274. next_rune(t);
  275. if t.r == '*' {
  276. next_rune(t);
  277. if t.r == '/' {
  278. next_rune(t);
  279. return get_token(t);
  280. }
  281. }
  282. }
  283. err = .EOF;
  284. }
  285. }
  286. case: err = .Illegal_Character;
  287. }
  288. token.text = string(t.data[token.offset : t.offset]);
  289. return;
  290. }
  291. is_valid_number :: proc(str: string, spec: Specification) -> bool {
  292. s := str;
  293. if s == "" {
  294. return false;
  295. }
  296. if s[0] == '-' {
  297. s = s[1:];
  298. if s == "" {
  299. return false;
  300. }
  301. } else if spec == .JSON5 {
  302. if s[0] == '+' { // Allow positive sign
  303. s = s[1:];
  304. if s == "" {
  305. return false;
  306. }
  307. }
  308. }
  309. switch s[0] {
  310. case '0':
  311. s = s[1:];
  312. case '1'..'9':
  313. s = s[1:];
  314. for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
  315. s = s[1:];
  316. }
  317. case '.':
  318. if spec == .JSON5 { // Allow leading decimal point
  319. s = s[1:];
  320. } else {
  321. return false;
  322. }
  323. case:
  324. return false;
  325. }
  326. if spec == .JSON5 {
  327. if len(s) == 1 && s[0] == '.' { // Allow trailing decimal point
  328. return true;
  329. }
  330. }
  331. if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
  332. s = s[2:];
  333. for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
  334. s = s[1:];
  335. }
  336. }
  337. if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
  338. s = s[1:];
  339. switch s[0] {
  340. case '+', '-':
  341. s = s[1:];
  342. if s == "" {
  343. return false;
  344. }
  345. }
  346. for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
  347. s = s[1:];
  348. }
  349. }
  350. // The string should be empty now to be valid
  351. return s == "";
  352. }
  353. is_valid_string_literal :: proc(str: string, spec: Specification) -> bool {
  354. s := str;
  355. if len(s) < 2 {
  356. return false;
  357. }
  358. quote := s[0];
  359. if s[0] != s[len(s)-1] {
  360. return false;
  361. }
  362. if s[0] != '"' || s[len(s)-1] != '"' {
  363. if spec == .JSON5 {
  364. if s[0] != '\'' || s[len(s)-1] != '\'' {
  365. return false;
  366. }
  367. } else {
  368. return false;
  369. }
  370. }
  371. s = s[1 : len(s)-1];
  372. i := 0;
  373. for i < len(s) {
  374. c := s[i];
  375. switch {
  376. case c == '\\':
  377. i += 1;
  378. if i >= len(s) {
  379. return false;
  380. }
  381. switch s[i] {
  382. case '"', '\'', '\\', '/', 'b', 'n', 'r', 't', 'f':
  383. i += 1;
  384. case 'u':
  385. if i >= len(s) {
  386. return false;
  387. }
  388. hex := s[i+1:];
  389. if len(hex) < 4 {
  390. return false;
  391. }
  392. hex = hex[:4];
  393. i += 5;
  394. for j := 0; j < 4; j += 1 {
  395. c2 := hex[j];
  396. switch c2 {
  397. case '0'..'9', 'a'..'z', 'A'..'Z':
  398. // Okay
  399. case:
  400. return false;
  401. }
  402. }
  403. case: return false;
  404. }
  405. case c == quote, c < ' ':
  406. return false;
  407. case c < utf8.RUNE_SELF:
  408. i += 1;
  409. case:
  410. r, width := utf8.decode_rune_in_string(s[i:]);
  411. if r == utf8.RUNE_ERROR && width == 1 {
  412. return false;
  413. }
  414. i += width;
  415. }
  416. }
  417. if i == len(s) {
  418. return true;
  419. }
  420. return true;
  421. }