1use std::{
2 collections::VecDeque,
3 mem::take,
4 ops::{Deref, RangeInclusive},
5};
6
7use crate::{
8 big_numbers::big_float::BigFloat,
9 common::{cast::Cast, default::default},
10 js::js_bigint::{add, equals, from_u64, mul, negative, JsBigintMutRef, Sign},
11 mem::manager::{Dealloc, Manager},
12 range_map::{from_one, from_range, merge, merge_list, RangeMap, State},
13};
14
15#[derive(Debug)]
16pub enum JsonToken<D: Dealloc> {
17 String(String),
18 Number(f64),
19 ObjectBegin,
20 ObjectEnd,
21 ArrayBegin,
22 ArrayEnd,
23 Colon,
24 Comma,
25 Equals,
26 Dot,
27 ErrorToken(ErrorType),
28 BigInt(JsBigintMutRef<D>),
29 Id(String),
30 NewLine,
31 Semicolon,
32 OpeningParenthesis,
33 ClosingParenthesis,
34}
35
36impl<D: Dealloc> PartialEq for JsonToken<D> {
37 fn eq(&self, other: &Self) -> bool {
38 match (self, other) {
39 (Self::String(l0), Self::String(r0)) => l0 == r0,
40 (Self::Number(l0), Self::Number(r0)) => l0 == r0,
41 (Self::ErrorToken(l0), Self::ErrorToken(r0)) => l0 == r0,
42 (Self::BigInt(l0), Self::BigInt(r0)) => equals(l0, r0),
43 (Self::Id(l0), Self::Id(r0)) => l0 == r0,
44 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
45 }
46 }
47}
48
49#[derive(Debug, PartialEq)]
50pub enum ErrorType {
51 UnexpectedCharacter,
52 InvalidToken,
53 InvalidNumber,
54 InvalidHex,
55 MissingQuotes,
56 CommentClosingExpected,
57}
58
59#[derive(Default)]
60pub enum TokenizerState<D: Dealloc> {
61 #[default]
62 Initial,
63 ParseId(String),
64 ParseString(String),
65 ParseEscapeChar(String),
66 ParseUnicodeChar(ParseUnicodeCharState),
67 ParseMinus,
68 ParseZero(Sign),
69 ParseInt(IntState<D>),
70 ParseFracBegin(IntState<D>),
71 ParseFrac(FloatState<D>),
72 ParseExpBegin(ExpState<D>),
73 ParseExpSign(ExpState<D>),
74 ParseExp(ExpState<D>),
75 ParseBigInt(JsBigintMutRef<D>),
76 ParseNewLine,
77 ParseCommentStart,
78 ParseSinglelineComment,
79 ParseMultilineComment,
80 ParseMultilineCommentAsterix,
81 ParseOperator(String),
82}
83
84impl<D: Dealloc + 'static> TokenizerState<D> {
85 fn push<M: Manager<Dealloc = D> + 'static>(
86 self,
87 manager: M,
88 c: char,
89 maps: &TransitionMaps<M>,
90 ) -> (Vec<JsonToken<D>>, TokenizerState<D>) {
91 match self {
92 TokenizerState::Initial => get_next_state(manager, (), c, &maps.initial, maps),
93 TokenizerState::ParseId(s) => get_next_state(manager, s, c, &maps.id, maps),
94 TokenizerState::ParseString(s) => get_next_state(manager, s, c, &maps.string, maps),
95 TokenizerState::ParseEscapeChar(s) => {
96 get_next_state(manager, s, c, &maps.escape_char, maps)
97 }
98 TokenizerState::ParseUnicodeChar(s) => {
99 get_next_state(manager, s, c, &maps.unicode_char, maps)
100 }
101 TokenizerState::ParseZero(s) => get_next_state(manager, s, c, &maps.zero, maps),
102 TokenizerState::ParseInt(s) => get_next_state(manager, s, c, &maps.int, maps),
103 TokenizerState::ParseMinus => get_next_state(manager, (), c, &maps.minus, maps),
104 TokenizerState::ParseFracBegin(s) => {
105 get_next_state(manager, s, c, &maps.frac_begin, maps)
106 }
107 TokenizerState::ParseFrac(s) => get_next_state(manager, s, c, &maps.frac, maps),
108 TokenizerState::ParseExpBegin(s) => {
109 get_next_state(manager, s, c, &maps.exp_begin, maps)
110 }
111 TokenizerState::ParseExpSign(s) | TokenizerState::ParseExp(s) => {
112 get_next_state(manager, s, c, &maps.exp, maps)
113 }
114 TokenizerState::ParseBigInt(s) => get_next_state(manager, s, c, &maps.big_int, maps),
115 TokenizerState::ParseNewLine => get_next_state(manager, (), c, &maps.new_line, maps),
116 TokenizerState::ParseCommentStart => {
117 get_next_state(manager, (), c, &maps.comment_start, maps)
118 }
119 TokenizerState::ParseSinglelineComment => {
120 get_next_state(manager, (), c, &maps.singleline_comment, maps)
121 }
122 TokenizerState::ParseMultilineComment => {
123 get_next_state(manager, (), c, &maps.multiline_comment, maps)
124 }
125 TokenizerState::ParseMultilineCommentAsterix => {
126 get_next_state(manager, (), c, &maps.multiline_comment_asterix, maps)
127 }
128 TokenizerState::ParseOperator(s) => get_next_state(manager, s, c, &maps.operator, maps),
129 }
130 }
131
132 pub fn push_mut<M: Manager<Dealloc = D> + 'static>(
133 &mut self,
134 manager: M,
135 c: char,
136 tm: &TransitionMaps<M>,
137 ) -> Vec<JsonToken<M::Dealloc>> {
138 let tokens;
139 (tokens, *self) = take(self).push(manager, c, tm);
140 tokens
141 }
142
143 fn end<M: Manager<Dealloc = D>>(self, manager: M) -> Vec<JsonToken<D>> {
144 match self {
145 TokenizerState::Initial
146 | TokenizerState::ParseNewLine
147 | TokenizerState::ParseSinglelineComment => default(),
148 TokenizerState::ParseId(s) => [JsonToken::Id(s)].cast(),
149 TokenizerState::ParseString(_)
150 | TokenizerState::ParseEscapeChar(_)
151 | TokenizerState::ParseUnicodeChar(_) => {
152 [JsonToken::ErrorToken(ErrorType::MissingQuotes)].cast()
153 }
154 TokenizerState::ParseCommentStart => {
155 [JsonToken::ErrorToken(ErrorType::UnexpectedCharacter)].cast()
156 }
157 TokenizerState::ParseMultilineComment
158 | TokenizerState::ParseMultilineCommentAsterix => {
159 [JsonToken::ErrorToken(ErrorType::CommentClosingExpected)].cast()
160 }
161 TokenizerState::ParseZero(_) => [JsonToken::Number(default())].cast(),
162 TokenizerState::ParseInt(s) => [int_state_into_number_token(manager, s)].cast(),
163 TokenizerState::ParseFrac(s) => [float_state_into_token(manager, s)].cast(),
164 TokenizerState::ParseExp(s) => [exp_state_into_token(manager, s)].cast(),
165 TokenizerState::ParseBigInt(s) => [JsonToken::BigInt(s)].cast(),
166 TokenizerState::ParseMinus
167 | TokenizerState::ParseFracBegin(_)
168 | TokenizerState::ParseExpBegin(_)
169 | TokenizerState::ParseExpSign(_) => {
170 [JsonToken::ErrorToken(ErrorType::InvalidNumber)].cast()
171 }
172 TokenizerState::ParseOperator(s) => [operator_to_token(s).unwrap()].cast(),
173 }
174 }
175}
176
177pub struct ParseUnicodeCharState {
178 s: String,
179 unicode: u32,
180 index: u8,
181}
182
183impl ParseUnicodeCharState {
184 fn push<M: Manager>(
185 mut self,
186 i: u32,
187 ) -> (Vec<JsonToken<M::Dealloc>>, TokenizerState<M::Dealloc>) {
188 let new_unicode = self.unicode | (i << ((3 - self.index) * 4));
189 match self.index {
190 3 => {
191 let c = char::from_u32(new_unicode);
192 match c {
193 Some(c) => continue_string_state::<M>(self.s, c),
194 None => (
195 [JsonToken::ErrorToken(ErrorType::InvalidHex)].cast(),
196 TokenizerState::Initial,
197 ),
198 }
199 }
200 0..=2 => {
201 self.unicode = new_unicode;
202 self.index += 1;
203 (default(), TokenizerState::ParseUnicodeChar(self))
204 }
205 _ => unreachable!(),
206 }
207 }
208}
209
210pub fn bigfloat_to_f64<M: Manager>(bf_10: BigFloat<10, M>) -> f64 {
211 let bf_2 = bf_10.to_bin(54);
212 bf_2.to_f64()
213}
214
215pub struct IntState<D: Dealloc> {
216 b: JsBigintMutRef<D>,
217 s: Sign,
218}
219
220impl<D: Dealloc> JsBigintMutRef<D> {
221 fn from_digit<M: Manager<Dealloc = D>>(m: M, c: char) -> JsBigintMutRef<M::Dealloc> {
222 from_u64(m, Sign::Positive, digit_to_number(c))
223 }
224
225 fn add_digit<M: Manager<Dealloc = D>>(self, m: M, c: char) -> JsBigintMutRef<M::Dealloc> {
226 add(
227 m,
228 mul(m, self.deref(), from_u64(m, Sign::Positive, 10).deref()).deref(),
229 Self::from_digit(m, c).deref(),
230 )
231 }
232}
233
234impl<D: Dealloc> IntState<D> {
235 fn into_float_state(self) -> FloatState<D> {
236 FloatState {
237 b: self.b,
238 s: self.s,
239 fe: 0,
240 }
241 }
242
243 fn into_exp_state(self) -> ExpState<D> {
244 ExpState {
245 b: self.b,
246 s: self.s,
247 fe: 0,
248 es: Sign::Positive,
249 e: 0,
250 }
251 }
252
253 fn into_bigint_state<M: Manager<Dealloc = D>>(self, m: M) -> JsBigintMutRef<D> {
254 match self.s {
255 Sign::Positive => self.b,
256 Sign::Negative => negative(m, self.b.deref()),
257 }
258 }
259}
260
261fn int_state_into_number_token<M: Manager>(
262 manager: M,
263 state: IntState<M::Dealloc>,
264) -> JsonToken<M::Dealloc> {
265 JsonToken::Number(bigfloat_to_f64(BigFloat {
266 manager,
267 significand: state.b,
268 sign: state.s,
269 exp: 0,
270 non_zero_reminder: false,
271 }))
272}
273
274pub struct FloatState<D: Dealloc> {
275 b: JsBigintMutRef<D>,
276 s: Sign,
277 fe: i64,
278}
279
280impl<D: Dealloc> FloatState<D> {
281 fn add_digit<M: Manager<Dealloc = D>>(mut self, m: M, c: char) -> FloatState<M::Dealloc> {
282 self.b = self.b.add_digit(m, c);
283 self.fe -= 1;
284 self
285 }
286
287 fn into_exp_state(self) -> ExpState<D> {
288 ExpState {
289 b: self.b,
290 s: self.s,
291 fe: self.fe,
292 es: Sign::Positive,
293 e: 0,
294 }
295 }
296}
297
298fn float_state_into_token<M: Manager>(
299 manager: M,
300 state: FloatState<M::Dealloc>,
301) -> JsonToken<M::Dealloc> {
302 JsonToken::Number(bigfloat_to_f64(BigFloat {
303 manager,
304 significand: state.b,
305 sign: state.s,
306 exp: state.fe,
307 non_zero_reminder: false,
308 }))
309}
310
311pub struct ExpState<D: Dealloc> {
312 b: JsBigintMutRef<D>,
313 s: Sign,
314 fe: i64,
315 es: Sign,
316 e: i64,
317}
318
319impl<D: Dealloc> ExpState<D> {
320 const fn add_digit(mut self, c: char) -> ExpState<D> {
321 self.e = self.e * 10 + digit_to_number(c) as i64;
322 self
323 }
324}
325
326fn exp_state_into_token<M: Manager>(
327 manager: M,
328 state: ExpState<M::Dealloc>,
329) -> JsonToken<M::Dealloc> {
330 let exp = state.fe
331 + match state.es {
332 Sign::Positive => state.e,
333 Sign::Negative => -state.e,
334 };
335 JsonToken::Number(bigfloat_to_f64(BigFloat {
336 manager,
337 significand: state.b,
338 sign: state.s,
339 exp,
340 non_zero_reminder: false,
341 }))
342}
343
344const CP_0: u32 = 0x30;
345
346fn operator_to_token<D: Dealloc>(s: String) -> Option<JsonToken<D>> {
347 match s.as_str() {
348 "{" => Some(JsonToken::ObjectBegin),
349 "}" => Some(JsonToken::ObjectEnd),
350 "[" => Some(JsonToken::ArrayBegin),
351 "]" => Some(JsonToken::ArrayEnd),
352 ":" => Some(JsonToken::Colon),
353 "," => Some(JsonToken::Comma),
354 "=" => Some(JsonToken::Equals),
355 "." => Some(JsonToken::Dot),
356 ";" => Some(JsonToken::Semicolon),
357 "(" => Some(JsonToken::OpeningParenthesis),
358 ")" => Some(JsonToken::ClosingParenthesis),
359 _ => None,
360 }
361}
362
363const WHITE_SPACE_CHARS: [char; 4] = [' ', '\n', '\t', '\r'];
364const NEW_LINE_CHARS: [char; 2] = ['\n', '\r'];
365const OPERATOR_CHARS: [char; 10] = ['{', '}', '[', ']', ':', ',', '=', ';', '(', ')'];
366
367fn id_start() -> Vec<RangeInclusive<char>> {
368 ['a'..='z', 'A'..='Z', one('_'), one('$')].cast()
369}
370
371fn id_char() -> Vec<RangeInclusive<char>> {
372 ['a'..='z', 'A'..='Z', one('_'), one('$'), '0'..='9'].cast()
373}
374
375fn operator_chars_with_dot() -> Vec<RangeInclusive<char>> {
376 let c = OPERATOR_CHARS.into_iter().chain(['.']);
377 set(c)
378}
379
380fn terminal_for_number() -> Vec<RangeInclusive<char>> {
381 let c = WHITE_SPACE_CHARS
382 .into_iter()
383 .chain(OPERATOR_CHARS)
384 .chain(['"', '/']);
385 set(c)
386}
387
388const fn digit_to_number(c: char) -> u64 {
389 c as u64 - CP_0 as u64
390}
391
392fn start_number<M: Manager>(manager: M, s: Sign, c: char) -> IntState<M::Dealloc> {
393 IntState {
394 b: JsBigintMutRef::from_digit(manager, c),
395 s,
396 }
397}
398
399fn create_range_map<T, M: Manager>(
400 list: Vec<RangeInclusive<char>>,
401 t: Transition<T, M>,
402) -> RangeMap<char, State<Transition<T, M>>> {
403 let mut result = RangeMap { list: default() };
404 for range in list {
405 result = merge(from_range(range, t), result);
406 }
407 result
408}
409
410fn one(c: char) -> RangeInclusive<char> {
411 RangeInclusive::new(c, c)
412}
413
414fn set(arr: impl IntoIterator<Item = char>) -> Vec<RangeInclusive<char>> {
415 let mut result = Vec::new();
416 for c in arr {
417 result.push(one(c));
418 }
419 result
420}
421
422type Transition<T, M> = TransitionFunc<M, T>;
423
424struct TransitionMap<T, M: Manager> {
425 def: Transition<T, M>,
426 rm: RangeMap<char, State<Transition<T, M>>>,
427}
428
429pub struct TransitionMaps<M: Manager> {
430 initial: TransitionMap<(), M>,
431 id: TransitionMap<String, M>,
432 string: TransitionMap<String, M>,
433 escape_char: TransitionMap<String, M>,
434 unicode_char: TransitionMap<ParseUnicodeCharState, M>,
435 zero: TransitionMap<Sign, M>,
436 int: TransitionMap<IntState<M::Dealloc>, M>,
437 minus: TransitionMap<(), M>,
438 frac_begin: TransitionMap<IntState<M::Dealloc>, M>,
439 frac: TransitionMap<FloatState<M::Dealloc>, M>,
440 exp_begin: TransitionMap<ExpState<M::Dealloc>, M>,
441 exp: TransitionMap<ExpState<M::Dealloc>, M>,
442 big_int: TransitionMap<JsBigintMutRef<M::Dealloc>, M>,
443 new_line: TransitionMap<(), M>,
444 comment_start: TransitionMap<(), M>,
445 singleline_comment: TransitionMap<(), M>,
446 multiline_comment: TransitionMap<(), M>,
447 multiline_comment_asterix: TransitionMap<(), M>,
448 operator: TransitionMap<String, M>,
449}
450
451pub fn create_transition_maps<M: Manager + 'static>() -> TransitionMaps<M> {
452 TransitionMaps {
453 initial: create_initial_transitions(),
454 id: create_id_transitions(),
455 string: create_string_transactions(),
456 escape_char: create_escape_char_transactions(),
457 unicode_char: create_unicode_char_transactions(),
458 zero: create_zero_transactions(),
459 int: create_int_transactions(),
460 minus: create_minus_transactions(),
461 frac_begin: create_frac_begin_transactions(),
462 frac: create_frac_transactions(),
463 exp_begin: create_exp_begin_transactions(),
464 exp: create_exp_transactions(),
465 big_int: create_big_int_transactions(),
466 new_line: create_new_line_transactions(),
467 comment_start: create_comment_start_transactions(),
468 singleline_comment: create_singleline_comment_transactions(),
469 multiline_comment: create_multiline_comment_transactions(),
470 multiline_comment_asterix: create_multiline_comment_asterix_transactions(),
471 operator: create_operator_transactions(),
472 }
473}
474
475fn get_next_state<T: 'static, M: Manager + 'static>(
476 manager: M,
477 state: T,
478 c: char,
479 tm: &TransitionMap<T, M>,
480 maps: &TransitionMaps<M>,
481) -> (Vec<JsonToken<M::Dealloc>>, TokenizerState<M::Dealloc>) {
482 let entry = tm.rm.get(c);
483 match &entry.value {
484 Some(f) => f(manager, state, c, maps),
485 None => (tm.def)(manager, state, c, maps),
486 }
487}
488
489fn create_initial_transitions<M: Manager>() -> TransitionMap<(), M> {
490 type Func<M> = TransitionFunc<M, ()>;
491 TransitionMap {
492 def: (|_, _, _, _| {
493 (
494 [JsonToken::ErrorToken(ErrorType::UnexpectedCharacter)].cast(),
495 TokenizerState::Initial,
496 )
497 }) as Func<M>,
498 rm: merge_list(
499 [
500 create_range_map(operator_chars_with_dot(), |_, _, c, _| {
501 (default(), TokenizerState::ParseOperator(c.to_string()))
502 }),
503 from_range('1'..='9', |manager: M, _, c, _| {
504 (
505 default(),
506 TokenizerState::ParseInt(start_number(manager, Sign::Positive, c)),
507 )
508 }),
509 from_one('"', |_, _, _, _| {
510 (default(), TokenizerState::ParseString(String::default()))
511 }),
512 from_one('0', |_, _, _, _| {
513 (default(), TokenizerState::ParseZero(Sign::Positive))
514 }),
515 from_one('-', |_, _, _, _| (default(), TokenizerState::ParseMinus)),
516 create_range_map(id_start(), |_, _, c, _| {
517 (default(), TokenizerState::ParseId(c.to_string()))
518 }),
519 from_one('\n', |_, _, _, _| (default(), TokenizerState::ParseNewLine)),
520 create_range_map(set([' ', '\t', '\r']), |_, _, _, _| {
521 (default(), TokenizerState::Initial)
522 }),
523 from_one('/', |_, _, _, _| {
524 (default(), TokenizerState::ParseCommentStart)
525 }),
526 ]
527 .cast(),
528 ),
529 }
530}
531
532fn create_id_transitions<M: Manager + 'static>() -> TransitionMap<String, M> {
533 TransitionMap {
534 def: |manager, s, c, maps| {
535 transfer_state(
536 manager,
537 [JsonToken::Id(s)].cast(),
538 TokenizerState::Initial,
539 c,
540 maps,
541 )
542 },
543 rm: create_range_map(id_char(), |_, mut s, c, _| {
544 s.push(c);
545 (default(), TokenizerState::ParseId(s))
546 }),
547 }
548}
549
550fn create_string_transactions<M: Manager>() -> TransitionMap<String, M> {
551 TransitionMap {
552 def: |_, mut s, c, _| {
553 s.push(c);
554 (default(), TokenizerState::ParseString(s))
555 },
556 rm: merge(
557 from_one('"', |_, s, _, _| {
558 ([JsonToken::String(s)].cast(), TokenizerState::Initial)
559 }),
560 from_one('\\', |_, s, _, _| {
561 (default(), TokenizerState::ParseEscapeChar(s))
562 }),
563 ),
564 }
565}
566
567fn continue_string_state<M: Manager>(
568 mut s: String,
569 c: char,
570) -> (Vec<JsonToken<M::Dealloc>>, TokenizerState<M::Dealloc>) {
571 s.push(c);
572 (default(), TokenizerState::ParseString(s))
573}
574
575fn transfer_state<M: Manager + 'static>(
576 manager: M,
577 mut vec: Vec<JsonToken<M::Dealloc>>,
578 mut state: TokenizerState<M::Dealloc>,
579 c: char,
580 maps: &TransitionMaps<M>,
581) -> (Vec<JsonToken<M::Dealloc>>, TokenizerState<M::Dealloc>) {
582 let next_tokens;
583 (next_tokens, state) = state.push(manager, c, maps);
584 vec.extend(next_tokens);
585 (vec, state)
586}
587
588fn create_escape_char_transactions<M: Manager + 'static>() -> TransitionMap<String, M> {
589 TransitionMap {
590 def: |manager, s, c, maps| {
591 transfer_state(
592 manager,
593 [JsonToken::ErrorToken(ErrorType::UnexpectedCharacter)].cast(),
594 TokenizerState::ParseString(s),
595 c,
596 maps,
597 )
598 },
599 rm: merge_list(
600 [
601 create_range_map(set(['\"', '\\', '/']), |_, s, c, _| {
602 continue_string_state::<M>(s, c)
603 }),
604 from_one('b', |_, s, _, _| continue_string_state::<M>(s, '\u{8}')),
605 from_one('f', |_, s, _, _| continue_string_state::<M>(s, '\u{c}')),
606 from_one('n', |_, s, _, _| continue_string_state::<M>(s, '\n')),
607 from_one('r', |_, s, _, _| continue_string_state::<M>(s, '\r')),
608 from_one('t', |_, s, _, _| continue_string_state::<M>(s, '\t')),
609 from_one('u', |_, s, _, _| {
610 (
611 default(),
612 TokenizerState::ParseUnicodeChar(ParseUnicodeCharState {
613 s,
614 unicode: 0,
615 index: 0,
616 }),
617 )
618 }),
619 ]
620 .cast(),
621 ),
622 }
623}
624
625fn create_unicode_char_transactions<M: Manager + 'static>(
626) -> TransitionMap<ParseUnicodeCharState, M> {
627 type Func<M> = TransitionFunc<M, ParseUnicodeCharState>;
628 TransitionMap {
629 def: |manager, state, c, maps| {
630 transfer_state(
631 manager,
632 [JsonToken::ErrorToken(ErrorType::InvalidHex)].cast(),
633 TokenizerState::ParseString(state.s),
634 c,
635 maps,
636 )
637 },
638 rm: merge_list(
639 [
640 from_range(
641 '0'..='9',
642 (|_, state, c, _| state.push::<M>(c as u32 - '0' as u32)) as Func<M>,
643 ),
644 from_range(
645 'a'..='f',
646 (|_, state, c, _| state.push::<M>(c as u32 - ('a' as u32 - 10))) as Func<M>,
647 ),
648 from_range(
649 'A'..='F',
650 (|_, state, c, _| state.push::<M>(c as u32 - ('A' as u32 - 10))) as Func<M>,
651 ),
652 ]
653 .cast(),
654 ),
655 }
656}
657
658fn create_zero_transactions<M: Manager + 'static>() -> TransitionMap<Sign, M> {
659 type Func<M> = TransitionFunc<M, Sign>;
660 TransitionMap {
661 def: (|manager, _, c, maps| tokenize_invalid_number(manager, c, maps)) as Func<M>,
662 rm: merge_list(
663 [
664 from_one(
665 '.',
666 (|manager, s, _, _| {
667 (
668 default(),
669 TokenizerState::ParseFracBegin(IntState {
670 b: from_u64(manager, Sign::Positive, 0),
671 s,
672 }),
673 )
674 }) as Func<M>,
675 ),
676 create_range_map(set(['e', 'E']), |manager, s, _, _| {
677 (
678 default(),
679 TokenizerState::ParseExpBegin(ExpState {
680 b: from_u64(manager, s, 0),
681 s,
682 fe: 0,
683 es: Sign::Positive,
684 e: 0,
685 }),
686 )
687 }),
688 from_one(
689 'n',
690 (|manager, s, _, _| {
691 (
692 default(),
693 TokenizerState::ParseBigInt(from_u64(manager, s, 0)),
694 )
695 }) as Func<M>,
696 ),
697 create_range_map(terminal_for_number(), |manager, _, c, maps| {
698 transfer_state(
699 manager,
700 [JsonToken::Number(default())].cast(),
701 TokenizerState::Initial,
702 c,
703 maps,
704 )
705 }),
706 ]
707 .cast(),
708 ),
709 }
710}
711
712fn create_int_transactions<M: Manager + 'static>() -> TransitionMap<IntState<M::Dealloc>, M> {
713 type Func<M> = TransitionFunc<M, IntState<<M as Manager>::Dealloc>>;
714 TransitionMap {
715 def: (|manager, _, c, maps| tokenize_invalid_number(manager, c, maps)) as Func<M>,
716 rm: merge_list(
717 [
718 from_range(
719 '0'..='9',
720 (|manager, s, c, _| {
721 (
722 default(),
723 TokenizerState::ParseInt(IntState {
724 b: s.b.add_digit(manager, c),
725 s: s.s,
726 }),
727 )
728 }) as Func<M>,
729 ),
730 from_one('.', |_, s, _, _| {
731 (default(), TokenizerState::ParseFracBegin(s))
732 }),
733 create_range_map(set(['e', 'E']), |_, s, _, _| {
734 (default(), TokenizerState::ParseExpBegin(s.into_exp_state()))
735 }),
736 from_one('n', |m, s, _, _| {
737 (
738 default(),
739 TokenizerState::ParseBigInt(s.into_bigint_state(m)),
740 )
741 }),
742 create_range_map(terminal_for_number(), |manager, s, c, maps| {
743 transfer_state(
744 manager,
745 [int_state_into_number_token(manager, s)].cast(),
746 TokenizerState::Initial,
747 c,
748 maps,
749 )
750 }),
751 ]
752 .cast(),
753 ),
754 }
755}
756
757fn create_frac_begin_transactions<M: Manager + 'static>() -> TransitionMap<IntState<M::Dealloc>, M>
758{
759 type Func<M> = TransitionFunc<M, IntState<<M as Manager>::Dealloc>>;
760 TransitionMap {
761 def: (|manager, _, c, maps| tokenize_invalid_number(manager, c, maps)) as Func<M>,
762 rm: from_range(
763 '0'..='9',
764 (|manager, s, c, _| {
765 (
766 default(),
767 TokenizerState::ParseFrac(s.into_float_state().add_digit(manager, c)),
768 )
769 }) as Func<M>,
770 ),
771 }
772}
773
774fn create_frac_transactions<M: Manager + 'static>() -> TransitionMap<FloatState<M::Dealloc>, M> {
775 type Func<M> = TransitionFunc<M, FloatState<<M as Manager>::Dealloc>>;
776 TransitionMap {
777 def: (|manager, _, c, maps| tokenize_invalid_number(manager, c, maps)) as Func<M>,
778 rm: merge_list(
779 [
780 from_range(
781 '0'..='9',
782 (|manager, s, c, _| {
783 (
784 default(),
785 TokenizerState::ParseFrac(s.add_digit(manager, c)),
786 )
787 }) as Func<M>,
788 ),
789 create_range_map(set(['e', 'E']), |_, s, _, _| {
790 (default(), TokenizerState::ParseExpBegin(s.into_exp_state()))
791 }),
792 create_range_map(terminal_for_number(), |manager, s, c, maps| {
793 transfer_state(
794 manager,
795 [float_state_into_token(manager, s)].cast(),
796 TokenizerState::Initial,
797 c,
798 maps,
799 )
800 }),
801 ]
802 .cast(),
803 ),
804 }
805}
806
807fn create_minus_transactions<M: Manager + 'static>() -> TransitionMap<(), M> {
808 type Func<M> = TransitionFunc<M, ()>;
809 TransitionMap {
810 def: (|manager, _, c, maps| tokenize_invalid_number(manager, c, maps)) as Func<M>,
811 rm: merge(
812 from_one(
813 '0',
814 (|_, _, _, _| (default(), TokenizerState::ParseZero(Sign::Negative))) as Func<M>,
815 ),
816 from_range('1'..='9', |manager, _, c, _| {
817 (
818 default(),
819 TokenizerState::ParseInt(start_number(manager, Sign::Negative, c)),
820 )
821 }),
822 ),
823 }
824}
825
826fn create_exp_begin_transactions<M: Manager + 'static>() -> TransitionMap<ExpState<M::Dealloc>, M> {
827 type Func<M> = TransitionFunc<M, ExpState<<M as Manager>::Dealloc>>;
828 TransitionMap {
829 def: (|manager, _, c, maps| tokenize_invalid_number(manager, c, maps)) as Func<M>,
830 rm: merge_list(
831 [
832 from_range(
833 '0'..='9',
834 (|_, s, c, _| (default(), TokenizerState::ParseExp(s.add_digit(c)))) as Func<M>,
835 ),
836 from_one('+', |_, s, _, _| {
837 (default(), TokenizerState::ParseExpSign(s))
838 }),
839 from_one('-', |_, mut s, _, _| {
840 (default(), {
841 s.es = Sign::Negative;
842 TokenizerState::ParseExpSign(s)
843 })
844 }),
845 create_range_map(terminal_for_number(), |manager, s, c, maps| {
846 transfer_state(
847 manager,
848 [exp_state_into_token(manager, s)].cast(),
849 TokenizerState::Initial,
850 c,
851 maps,
852 )
853 }),
854 ]
855 .cast(),
856 ),
857 }
858}
859
860fn create_exp_transactions<M: Manager + 'static>() -> TransitionMap<ExpState<M::Dealloc>, M> {
861 type Func<M> = TransitionFunc<M, ExpState<<M as Manager>::Dealloc>>;
862 TransitionMap {
863 def: (|manager, _, c, maps| tokenize_invalid_number(manager, c, maps)) as Func<M>,
864 rm: merge(
865 from_range(
866 '0'..='9',
867 (|_, s, c, _| (default(), TokenizerState::ParseExp(s.add_digit(c)))) as Func<M>,
868 ),
869 create_range_map(terminal_for_number(), |manager, s, c, maps| {
870 transfer_state(
871 manager,
872 [exp_state_into_token(manager, s)].cast(),
873 TokenizerState::Initial,
874 c,
875 maps,
876 )
877 }),
878 ),
879 }
880}
881
882fn create_big_int_transactions<M: Manager + 'static>(
883) -> TransitionMap<JsBigintMutRef<M::Dealloc>, M> {
884 type Func<M> = TransitionFunc<M, JsBigintMutRef<<M as Manager>::Dealloc>>;
885 TransitionMap {
886 def: (|manager, _, c, maps| tokenize_invalid_number(manager, c, maps)) as Func<M>,
887 rm: create_range_map(terminal_for_number(), |manager, s, c, maps| {
888 transfer_state(
889 manager,
890 [JsonToken::BigInt(s)].cast(),
891 TokenizerState::Initial,
892 c,
893 maps,
894 )
895 }),
896 }
897}
898
899fn tokenize_invalid_number<M: Manager + 'static>(
900 manager: M,
901 c: char,
902 maps: &TransitionMaps<M>,
903) -> (Vec<JsonToken<M::Dealloc>>, TokenizerState<M::Dealloc>) {
904 transfer_state(
905 manager,
906 [JsonToken::ErrorToken(ErrorType::InvalidNumber)].cast(),
907 TokenizerState::Initial,
908 c,
909 maps,
910 )
911}
912
913fn create_new_line_transactions<M: Manager + 'static>() -> TransitionMap<(), M> {
914 type Func<M> = TransitionFunc<M, ()>;
915 TransitionMap {
916 def: (|manager, _, c, maps| {
917 transfer_state(
918 manager,
919 [JsonToken::NewLine].cast(),
920 TokenizerState::Initial,
921 c,
922 maps,
923 )
924 }) as Func<M>,
925 rm: create_range_map(set(WHITE_SPACE_CHARS), |_, _, _, _| {
926 (default(), TokenizerState::ParseNewLine)
927 }),
928 }
929}
930
931fn create_comment_start_transactions<M: Manager>() -> TransitionMap<(), M> {
932 type Func<M> = TransitionFunc<M, ()>;
933 TransitionMap {
934 def: (|_, _, _, _| {
935 (
936 [JsonToken::ErrorToken(ErrorType::UnexpectedCharacter)].cast(),
937 TokenizerState::Initial,
938 )
939 }) as Func<M>,
940 rm: merge(
941 from_one('/', |_, _, _, _| {
942 (default(), TokenizerState::ParseSinglelineComment)
943 }),
944 from_one('*', |_, _, _, _| {
945 (default(), TokenizerState::ParseMultilineComment)
946 }),
947 ),
948 }
949}
950
951type TransitionFunc<M, S> = fn(
952 m: M,
953 s: S,
954 c: char,
955 maps: &TransitionMaps<M>,
956) -> (
957 Vec<JsonToken<<M as Manager>::Dealloc>>,
958 TokenizerState<<M as Manager>::Dealloc>,
959);
960
961fn create_singleline_comment_transactions<M: Manager>() -> TransitionMap<(), M> {
962 type Func<M> = TransitionFunc<M, ()>;
963 TransitionMap {
964 def: (|_, _, _, _| (default(), TokenizerState::ParseSinglelineComment)) as Func<M>,
965 rm: create_range_map(set(NEW_LINE_CHARS), |_, _, _, _| {
966 (default(), TokenizerState::ParseNewLine)
967 }),
968 }
969}
970
971fn create_multiline_comment_transactions<M: Manager>() -> TransitionMap<(), M> {
972 type Func<M> = fn(
973 m: M,
974 s: (),
975 c: char,
976 maps: &TransitionMaps<M>,
977 ) -> (
978 Vec<JsonToken<<M as Manager>::Dealloc>>,
979 TokenizerState<<M as Manager>::Dealloc>,
980 );
981 TransitionMap {
982 def: (|_, _, _, _| (default(), TokenizerState::ParseMultilineComment)) as Func<M>,
983 rm: from_one('*', |_, _, _, _| {
984 (default(), TokenizerState::ParseMultilineCommentAsterix)
985 }),
986 }
987}
988
989fn create_multiline_comment_asterix_transactions<M: Manager>() -> TransitionMap<(), M> {
990 type Func<M> = fn(
991 m: M,
992 s: (),
993 c: char,
994 maps: &TransitionMaps<M>,
995 ) -> (
996 Vec<JsonToken<<M as Manager>::Dealloc>>,
997 TokenizerState<<M as Manager>::Dealloc>,
998 );
999 TransitionMap {
1000 def: (|_, _, _, _| (default(), TokenizerState::ParseMultilineComment)) as Func<M>,
1001 rm: merge(
1002 from_one('/', |_, _, _, _| (default(), TokenizerState::Initial)),
1003 from_one('*', |_, _, _, _| {
1004 (default(), TokenizerState::ParseMultilineCommentAsterix)
1005 }),
1006 ),
1007 }
1008}
1009
1010fn create_operator_transactions<M: Manager + 'static>() -> TransitionMap<String, M> {
1011 TransitionMap {
1012 def: |manager, s, c, maps| {
1013 let token = operator_to_token(s).unwrap();
1014 transfer_state(manager, [token].cast(), TokenizerState::Initial, c, maps)
1015 },
1016 rm: create_range_map(operator_chars_with_dot(), |manager, s, c, maps| {
1017 let mut next_string = s.clone();
1018 next_string.push(c);
1019 match operator_to_token::<M::Dealloc>(next_string) {
1020 Some(_) => {
1021 let mut next_string = s.clone();
1022 next_string.push(c);
1023 (default(), TokenizerState::ParseOperator(next_string))
1024 }
1025 _ => {
1026 let token = operator_to_token(s).unwrap();
1027 transfer_state(manager, [token].cast(), TokenizerState::Initial, c, maps)
1028 }
1029 }
1030 }),
1031 }
1032}
1033
1034pub fn tokenize<M: Manager + 'static>(manager: M, input: String) -> Vec<JsonToken<M::Dealloc>> {
1035 TokenizerStateIterator::new(manager, input.chars()).collect()
1036}
1037
1038pub struct TokenizerStateIterator<T: Iterator<Item = char>, M: Manager> {
1039 manager: M,
1040 chars: T,
1041 cache: VecDeque<JsonToken<M::Dealloc>>,
1042 state: TokenizerState<M::Dealloc>,
1043 maps: TransitionMaps<M>,
1044 end: bool,
1045}
1046
1047impl<T: Iterator<Item = char>, M: Manager + 'static> TokenizerStateIterator<T, M> {
1048 pub fn new(manager: M, chars: T) -> Self {
1049 Self {
1050 manager,
1051 chars,
1052 cache: default(),
1053 state: default(),
1054 maps: create_transition_maps(),
1055 end: false,
1056 }
1057 }
1058}
1059
1060impl<T: Iterator<Item = char>, M: Manager + 'static> Iterator for TokenizerStateIterator<T, M> {
1061 type Item = JsonToken<M::Dealloc>;
1062
1063 fn next(&mut self) -> Option<Self::Item> {
1064 loop {
1065 if let Some(result) = self.cache.pop_front() {
1066 return Some(result);
1067 }
1068 if self.end {
1069 return None;
1070 }
1071 match self.chars.next() {
1072 Some(c) => self
1073 .cache
1074 .extend(self.state.push_mut(self.manager, c, &self.maps)),
1075 None => {
1076 self.end = true;
1077 self.cache.extend(take(&mut self.state).end(self.manager))
1078 }
1079 }
1080 }
1081 }
1082}
1083
1084#[cfg(test)]
1085mod test {
1086 use wasm_bindgen_test::wasm_bindgen_test;
1087
1088 use crate::{
1089 big_numbers::big_float::BigFloat,
1090 js::js_bigint::{from_u64, new_bigint, zero, Sign},
1091 mem::global::{Global, GLOBAL},
1092 tokenizer::bigfloat_to_f64,
1093 };
1094
1095 use super::{tokenize, ErrorType, JsonToken};
1096
1097 #[test]
1098 #[wasm_bindgen_test]
1099 fn test_empty() {
1100 let result = tokenize(GLOBAL, String::from(""));
1101 assert_eq!(result.len(), 0);
1102 }
1103
1104 #[test]
1105 #[wasm_bindgen_test]
1106 fn test_ops() {
1107 let result = tokenize(GLOBAL, String::from("{"));
1108 assert_eq!(result[0], JsonToken::<Global>::ObjectBegin);
1109
1110 let result = tokenize(GLOBAL, String::from("}"));
1111 assert_eq!(&result, &[JsonToken::ObjectEnd]);
1112
1113 let result = tokenize(GLOBAL, String::from("["));
1114 assert_eq!(&result, &[JsonToken::ArrayBegin]);
1115
1116 let result = tokenize(GLOBAL, String::from("]"));
1117 assert_eq!(&result, &[JsonToken::ArrayEnd]);
1118
1119 let result = tokenize(GLOBAL, String::from(":"));
1120 assert_eq!(&result, &[JsonToken::Colon]);
1121
1122 let result = tokenize(GLOBAL, String::from(","));
1123 assert_eq!(&result, &[JsonToken::Comma]);
1124
1125 let result = tokenize(GLOBAL, String::from("="));
1126 assert_eq!(&result, &[JsonToken::Equals]);
1127
1128 let result = tokenize(GLOBAL, String::from("."));
1129 assert_eq!(&result, &[JsonToken::Dot]);
1130
1131 let result = tokenize(GLOBAL, String::from(";"));
1132 assert_eq!(&result, &[JsonToken::Semicolon]);
1133
1134 let result = tokenize(GLOBAL, String::from("()"));
1135 assert_eq!(
1136 &result,
1137 &[JsonToken::OpeningParenthesis, JsonToken::ClosingParenthesis]
1138 );
1139
1140 let result = tokenize(GLOBAL, String::from("[{ :, }]"));
1141 assert_eq!(
1142 &result,
1143 &[
1144 JsonToken::ArrayBegin,
1145 JsonToken::ObjectBegin,
1146 JsonToken::Colon,
1147 JsonToken::Comma,
1148 JsonToken::ObjectEnd,
1149 JsonToken::ArrayEnd
1150 ]
1151 );
1152 }
1153
1154 #[test]
1155 #[wasm_bindgen_test]
1156 fn test_id() {
1157 let result = tokenize(GLOBAL, String::from("true"));
1158 assert_eq!(&result, &[JsonToken::Id(String::from("true"))]);
1159
1160 let result = tokenize(GLOBAL, String::from("false"));
1161 assert_eq!(&result, &[JsonToken::Id(String::from("false"))]);
1162
1163 let result = tokenize(GLOBAL, String::from("null"));
1164 assert_eq!(&result, &[JsonToken::Id(String::from("null"))]);
1165
1166 let result = tokenize(GLOBAL, String::from("tru tru"));
1167 assert_eq!(
1168 &result,
1169 &[
1170 JsonToken::Id(String::from("tru")),
1171 JsonToken::Id(String::from("tru")),
1172 ]
1173 );
1174
1175 let result = tokenize(GLOBAL, String::from("ABCxyz_0123456789$"));
1176 assert_eq!(
1177 &result,
1178 &[JsonToken::Id(String::from("ABCxyz_0123456789$")),]
1179 );
1180
1181 let result = tokenize(GLOBAL, String::from("_"));
1182 assert_eq!(&result, &[JsonToken::Id(String::from("_")),]);
1183
1184 let result = tokenize(GLOBAL, String::from("$"));
1185 assert_eq!(&result, &[JsonToken::Id(String::from("$")),]);
1186 }
1187
1188 #[test]
1189 #[wasm_bindgen_test]
1190 fn test_whitespace() {
1191 let result = tokenize(GLOBAL, String::from(" \t\n\r"));
1192 assert_eq!(&result, &[]);
1193 }
1194
1195 #[test]
1196 #[wasm_bindgen_test]
1197 fn test_string() {
1198 let result = tokenize(GLOBAL, String::from("\"\""));
1199 assert_eq!(&result, &[JsonToken::String("".to_string())]);
1200
1201 let result = tokenize(GLOBAL, String::from("\"value\""));
1202 assert_eq!(&result, &[JsonToken::String("value".to_string())]);
1203
1204 let result = tokenize(GLOBAL, String::from("\"value1\" \"value2\""));
1205 assert_eq!(
1206 &result,
1207 &[
1208 JsonToken::String("value1".to_string()),
1209 JsonToken::String("value2".to_string())
1210 ]
1211 );
1212
1213 let result = tokenize(GLOBAL, String::from("\"value"));
1214 assert_eq!(&result, &[JsonToken::ErrorToken(ErrorType::MissingQuotes)]);
1215 }
1216
1217 #[test]
1218 #[wasm_bindgen_test]
1219 fn test_escaped_characters() {
1220 let result = tokenize(GLOBAL, String::from("\"\\b\\f\\n\\r\\t\""));
1221 assert_eq!(
1222 &result,
1223 &[JsonToken::String("\u{8}\u{c}\n\r\t".to_string())]
1224 );
1225
1226 let result = tokenize(GLOBAL, String::from("\"\\x\""));
1227 assert_eq!(
1228 &result,
1229 &[
1230 JsonToken::ErrorToken(ErrorType::UnexpectedCharacter),
1231 JsonToken::String("x".to_string())
1232 ]
1233 );
1234
1235 let result = tokenize(GLOBAL, String::from("\"\\"));
1236 assert_eq!(&result, &[JsonToken::ErrorToken(ErrorType::MissingQuotes)]);
1237 }
1238
1239 #[test]
1240 #[wasm_bindgen_test]
1241 fn test_unicode() {
1242 let result = tokenize(GLOBAL, String::from("\"\\u1234\""));
1243 assert_eq!(&result, &[JsonToken::String("ሴ".to_string())]);
1244
1245 let result = tokenize(GLOBAL, String::from("\"\\uaBcDEeFf\""));
1246 assert_eq!(&result, &[JsonToken::String("ꯍEeFf".to_string())]);
1247
1248 let result = tokenize(GLOBAL, String::from("\"\\uEeFg\""));
1249 assert_eq!(
1250 &result,
1251 &[
1252 JsonToken::ErrorToken(ErrorType::InvalidHex),
1253 JsonToken::String("g".to_string())
1254 ]
1255 );
1256
1257 let result = tokenize(GLOBAL, String::from("\"\\uEeF"));
1258 assert_eq!(&result, &[JsonToken::ErrorToken(ErrorType::MissingQuotes)]);
1259 }
1260
1261 #[test]
1262 #[wasm_bindgen_test]
1263 fn test_integer() {
1264 let result = tokenize(GLOBAL, String::from("0"));
1265 assert_eq!(&result, &[JsonToken::Number(0.0)]);
1266
1267 let result = tokenize(GLOBAL, String::from("-0"));
1268 assert_eq!(&result, &[JsonToken::Number(0.0)]);
1269
1270 let result = tokenize(GLOBAL, String::from("0abc"));
1271 assert_eq!(
1272 &result,
1273 &[
1274 JsonToken::ErrorToken(ErrorType::InvalidNumber),
1275 JsonToken::Id(String::from("abc"))
1276 ]
1277 );
1278
1279 let result = tokenize(GLOBAL, String::from("0. 2"));
1280 assert_eq!(
1281 &result,
1282 &[
1283 JsonToken::ErrorToken(ErrorType::InvalidNumber),
1284 JsonToken::Number(2.0)
1285 ]
1286 );
1287
1288 let result = tokenize(GLOBAL, String::from("1234567890"));
1289 assert_eq!(&result, &[JsonToken::Number(1234567890.0)]);
1290
1291 let result = tokenize(GLOBAL, String::from("-1234567890"));
1292 assert_eq!(&result, &[JsonToken::Number(-1234567890.0)]);
1293
1294 let result = tokenize(GLOBAL, String::from("[0,1]"));
1295 assert_eq!(
1296 &result,
1297 &[
1298 JsonToken::ArrayBegin,
1299 JsonToken::Number(0.0),
1300 JsonToken::Comma,
1301 JsonToken::Number(1.0),
1302 JsonToken::ArrayEnd
1303 ]
1304 );
1305
1306 let result = tokenize(GLOBAL, String::from("001"));
1307 assert_eq!(
1308 &result,
1309 &[
1310 JsonToken::ErrorToken(ErrorType::InvalidNumber),
1311 JsonToken::ErrorToken(ErrorType::InvalidNumber),
1312 JsonToken::Number(1.0),
1313 ]
1314 );
1315
1316 let result = tokenize(GLOBAL, String::from("-"));
1317 assert_eq!(&result, &[JsonToken::ErrorToken(ErrorType::InvalidNumber)]);
1318
1319 let result = tokenize(GLOBAL, String::from("-{}"));
1320 assert_eq!(
1321 &result,
1322 &[
1323 JsonToken::ErrorToken(ErrorType::InvalidNumber),
1324 JsonToken::ObjectBegin,
1325 JsonToken::ObjectEnd
1326 ]
1327 );
1328
1329 let result = tokenize(GLOBAL, String::from("9007199254740991"));
1330 assert_eq!(&result, &[JsonToken::Number(9007199254740991.0)]);
1331
1332 let result = tokenize(GLOBAL, String::from("9007199254740992"));
1333 assert_eq!(&result, &[JsonToken::Number(9007199254740992.0)]);
1334
1335 let result = tokenize(GLOBAL, String::from("9007199254740993"));
1336 assert_eq!(&result, &[JsonToken::Number(9007199254740993.0)]);
1337 }
1338
1339 #[test]
1340 #[wasm_bindgen_test]
1341 fn test_big_float() {
1342 let result = tokenize(
1343 GLOBAL,
1344 String::from("340282366920938463463374607431768211456"),
1345 );
1346 assert_eq!(
1347 &result,
1348 &[JsonToken::Number(bigfloat_to_f64(BigFloat {
1349 manager: GLOBAL,
1350 significand: new_bigint(GLOBAL, Sign::Positive, [0, 0, 1]),
1351 sign: Sign::Positive,
1352 exp: 0,
1353 non_zero_reminder: false
1354 }))]
1355 );
1356 }
1357
1358 #[test]
1359 #[wasm_bindgen_test]
1360 fn test_float() {
1361 let result = tokenize(GLOBAL, String::from("0.01"));
1362 assert_eq!(&result, &[JsonToken::Number(0.01)]);
1363
1364 let result = tokenize(GLOBAL, String::from("[-12.34]"));
1365 assert_eq!(
1366 &result,
1367 &[
1368 JsonToken::ArrayBegin,
1369 JsonToken::Number(-12.34),
1370 JsonToken::ArrayEnd
1371 ]
1372 );
1373 }
1374
1375 #[test]
1376 #[wasm_bindgen_test]
1377 fn test_infinity() {
1378 let result = tokenize(GLOBAL, String::from("1e1000"));
1379 assert_eq!(&result, &[JsonToken::Number(f64::INFINITY)]);
1380
1381 let result = tokenize(GLOBAL, String::from("-1e+1000"));
1382 assert_eq!(&result, &[JsonToken::Number(f64::NEG_INFINITY)]);
1383 }
1384
1385 #[test]
1386 #[wasm_bindgen_test]
1387 fn test_exp() {
1388 let result = tokenize(GLOBAL, String::from("1e2"));
1389 assert_eq!(&result, &[JsonToken::Number(1e2)]);
1390
1391 let result = tokenize(GLOBAL, String::from("1E+2"));
1392 assert_eq!(&result, &[JsonToken::Number(1e2)]);
1393
1394 let result = tokenize(GLOBAL, String::from("0e-2"));
1395 assert_eq!(&result, &[JsonToken::Number(0.0)]);
1396
1397 let result = tokenize(GLOBAL, String::from("1e-2"));
1398 assert_eq!(&result, &[JsonToken::Number(1e-2)]);
1399
1400 let result = tokenize(GLOBAL, String::from("1.2e+2"));
1401 assert_eq!(&result, &[JsonToken::Number(1.2e+2)]);
1402
1403 let result = tokenize(GLOBAL, String::from("12e0000"));
1404 assert_eq!(&result, &[JsonToken::Number(12.0)]);
1405
1406 let result = tokenize(GLOBAL, String::from("1e"));
1407 assert_eq!(&result, &[JsonToken::ErrorToken(ErrorType::InvalidNumber)]);
1408
1409 let result = tokenize(GLOBAL, String::from("1e+"));
1410 assert_eq!(&result, &[JsonToken::ErrorToken(ErrorType::InvalidNumber)]);
1411
1412 let result = tokenize(GLOBAL, String::from("1e-"));
1413 assert_eq!(&result, &[JsonToken::ErrorToken(ErrorType::InvalidNumber)]);
1414 }
1415
1416 #[test]
1417 #[wasm_bindgen_test]
1418 fn test_big_int() {
1419 let result = tokenize(GLOBAL, String::from("0n"));
1420 assert_eq!(&result, &[JsonToken::BigInt(zero(GLOBAL))]);
1421
1422 let result = tokenize(GLOBAL, String::from("-0n"));
1423 assert_eq!(
1424 &result,
1425 &[JsonToken::BigInt(from_u64(GLOBAL, Sign::Negative, 0))]
1426 );
1427
1428 let result = tokenize(GLOBAL, String::from("1234567890n"));
1429 assert_eq!(
1430 &result,
1431 &[JsonToken::BigInt(from_u64(
1432 GLOBAL,
1433 Sign::Positive,
1434 1234567890
1435 ))]
1436 );
1437
1438 let result = tokenize(GLOBAL, String::from("-1234567890n"));
1439 assert_eq!(
1440 &result,
1441 &[JsonToken::BigInt(from_u64(
1442 GLOBAL,
1443 Sign::Negative,
1444 1234567890
1445 ))]
1446 );
1447
1448 let result = tokenize(GLOBAL, String::from("123.456n"));
1449 assert_eq!(
1450 &result,
1451 &[
1452 JsonToken::ErrorToken(ErrorType::InvalidNumber),
1453 JsonToken::Id(String::from("n"))
1454 ]
1455 );
1456
1457 let result = tokenize(GLOBAL, String::from("123e456n"));
1458 assert_eq!(
1459 &result,
1460 &[
1461 JsonToken::ErrorToken(ErrorType::InvalidNumber),
1462 JsonToken::Id(String::from("n"))
1463 ]
1464 );
1465
1466 let result = tokenize(GLOBAL, String::from("1234567890na"));
1467 assert_eq!(
1468 &result,
1469 &[
1470 JsonToken::ErrorToken(ErrorType::InvalidNumber),
1471 JsonToken::Id(String::from("a"))
1472 ]
1473 );
1474
1475 let result = tokenize(GLOBAL, String::from("1234567890nn"));
1476 assert_eq!(
1477 &result,
1478 &[
1479 JsonToken::ErrorToken(ErrorType::InvalidNumber),
1480 JsonToken::Id(String::from("n"))
1481 ]
1482 );
1483 }
1484
1485 #[test]
1486 #[wasm_bindgen_test]
1487 fn test_errors() {
1488 let result = tokenize(GLOBAL, String::from("ᄑ"));
1489 assert_eq!(
1490 &result,
1491 &[JsonToken::ErrorToken(ErrorType::UnexpectedCharacter)]
1492 );
1493 }
1494
1495 #[test]
1496 #[wasm_bindgen_test]
1497 fn test_djs() {
1498 let result = tokenize(GLOBAL, String::from("module.exports = "));
1499 assert_eq!(
1500 &result,
1501 &[
1502 JsonToken::Id(String::from("module")),
1503 JsonToken::Dot,
1504 JsonToken::Id(String::from("exports")),
1505 JsonToken::Equals,
1506 ]
1507 );
1508 }
1509
1510 #[test]
1511 #[wasm_bindgen_test]
1512 fn test_singleline_comments() {
1513 let result = tokenize(GLOBAL, String::from("{//abc\n2\n}"));
1514 assert_eq!(
1515 &result,
1516 &[
1517 JsonToken::ObjectBegin,
1518 JsonToken::NewLine,
1519 JsonToken::Number(2.0),
1520 JsonToken::NewLine,
1521 JsonToken::ObjectEnd,
1522 ]
1523 );
1524
1525 let result = tokenize(GLOBAL, String::from("0//abc/*"));
1526 assert_eq!(&result, &[JsonToken::Number(0.0),]);
1527
1528 let result = tokenize(GLOBAL, String::from("0//abc 1"));
1529 assert_eq!(&result, &[JsonToken::Number(0.0)]);
1530
1531 let result = tokenize(GLOBAL, String::from("0//abc\n1"));
1532 assert_eq!(
1533 &result,
1534 &[
1535 JsonToken::Number(0.0),
1536 JsonToken::NewLine,
1537 JsonToken::Number(1.0)
1538 ]
1539 );
1540
1541 let result = tokenize(GLOBAL, String::from("0//"));
1542 assert_eq!(&result, &[JsonToken::Number(0.0),]);
1543
1544 let result = tokenize(GLOBAL, String::from("0/"));
1545 assert_eq!(
1546 &result,
1547 &[
1548 JsonToken::Number(0.0),
1549 JsonToken::ErrorToken(ErrorType::UnexpectedCharacter),
1550 ]
1551 );
1552
1553 let result = tokenize(GLOBAL, String::from("0/a"));
1554 assert_eq!(
1555 &result,
1556 &[
1557 JsonToken::Number(0.0),
1558 JsonToken::ErrorToken(ErrorType::UnexpectedCharacter),
1559 ]
1560 );
1561 }
1562
1563 #[test]
1564 #[wasm_bindgen_test]
1565 fn test_multiline_comments() {
1566 let result = tokenize(GLOBAL, String::from("{/*abc\ndef*/2}"));
1567 assert_eq!(
1568 &result,
1569 &[
1570 JsonToken::ObjectBegin,
1571 JsonToken::Number(2.0),
1572 JsonToken::ObjectEnd,
1573 ]
1574 );
1575
1576 let result = tokenize(GLOBAL, String::from("{/*/* /**/2}"));
1577 assert_eq!(
1578 &result,
1579 &[
1580 JsonToken::ObjectBegin,
1581 JsonToken::Number(2.0),
1582 JsonToken::ObjectEnd,
1583 ]
1584 );
1585
1586 let result = tokenize(GLOBAL, String::from("{/*"));
1587 assert_eq!(
1588 &result,
1589 &[
1590 JsonToken::ObjectBegin,
1591 JsonToken::ErrorToken(ErrorType::CommentClosingExpected),
1592 ]
1593 );
1594
1595 let result = tokenize(GLOBAL, String::from("{/**"));
1596 assert_eq!(
1597 &result,
1598 &[
1599 JsonToken::ObjectBegin,
1600 JsonToken::ErrorToken(ErrorType::CommentClosingExpected),
1601 ]
1602 );
1603 }
1604}