1use text_scanner::{ext::JsonScannerExt, Scanner};
2
3use crate::{impl_lexer_from_scanner, ScanToken, ScannerExt, TokenSpan};
4
5#[derive(PartialEq, Eq, Clone, Copy, Debug)]
6pub enum JsonToken {
7 Space,
8 String,
9 Number,
10 Null,
11 True,
12 False,
13 Punct,
15 Delim,
17 Unknown,
23}
24
25impl ScanToken for JsonToken {
26 fn scan_token<'text>(scanner: &mut Scanner<'text>) -> Option<(Self, TokenSpan<'text>)> {
27 let (r, _s) = scanner.skip_whitespace();
28 if !r.is_empty() {
29 return Some((Self::Space, scanner.span(r)));
30 }
31
32 if let Ok((r, _c)) = scanner.accept_char_any(&['{', '}', '[', ']']) {
33 return Some((Self::Delim, scanner.span(r)));
34 } else if let Ok((r, _c)) = scanner.accept_char_any(&[':', ',']) {
35 return Some((Self::Punct, scanner.span(r)));
36 } else if let Ok((r, _c)) = scanner.scan_json_string() {
37 return Some((Self::String, scanner.span(r)));
38 } else if let Ok((r, _c)) = scanner.scan_json_number() {
39 return Some((Self::Number, scanner.span(r)));
40 }
41
42 let backtrack = scanner.cursor_pos();
43 let res = scanner.scan_with(|scanner| {
44 scanner.accept_if(|c| c.is_ascii_alphabetic())?;
45 scanner.skip_while(|c| c.is_ascii_alphabetic());
46
47 Ok(())
48 });
49 if let Ok((r, s)) = res {
50 match s {
51 "null" => return Some((Self::Null, scanner.span(r))),
52 "true" => return Some((Self::True, scanner.span(r))),
53 "false" => return Some((Self::False, scanner.span(r))),
54 _ => {
55 scanner.set_cursor_pos(backtrack);
56 }
57 }
58 }
59
60 let (r, _c) = scanner.next().ok()?;
61 Some((Self::Unknown, scanner.span(r)))
62 }
63}
64
65#[derive(Clone, Debug)]
71pub struct JsonLexer<'text> {
72 scanner: Scanner<'text>,
73}
74
75impl<'text> JsonLexer<'text> {
76 #[inline]
77 pub fn new(text: &'text str) -> Self {
78 Self {
79 scanner: Scanner::new(text),
80 }
81 }
82}
83
84impl_lexer_from_scanner!('text, JsonLexer<'text>, JsonToken, scanner);
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_json_lexer_spans() {
92 let input = include_str!("../../../text-scanner/src/ext/rust.rs");
95 let mut output = String::new();
96
97 let lexer = JsonLexer::new(input);
98 for (_tok, span) in lexer {
99 output.push_str(span.as_str());
100 }
101
102 assert_eq!(input, output);
103 }
104}