nanvm_lib/tokenizer/
mod.rs

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}