tokenizer.odin 8.1 KB

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