Skip to main content

ephemeris_documents/json/
parser.rs

1//! Builds the syntax tree from tokens.
2
3use super::Dialect;
4use super::cst::{
5    Array, Comma, Document, Item, Key, Kind, Member, Object, Scalar, Tail, Trivia, Value,
6};
7use super::lexer::{Lexer, Token, TokenKind};
8use crate::error::{JsonError, JsonErrorKind};
9
10const MAX_DEPTH: usize = 128;
11
12/// How an element ended and what starts the next one.
13struct Next {
14    /// Without a comma, the container must close.
15    comma: Comma,
16    /// Trivia from the first line break after the element on. It belongs to
17    /// what comes next.
18    leading: String,
19}
20
21pub(super) struct Parser<'a> {
22    tokens: Vec<Token<'a>>,
23    index: usize,
24    end: usize,
25}
26
27impl<'a> Parser<'a> {
28    /// Parse `source` as one JSON5 document.
29    pub(super) fn parse(source: &'a str, dialect: Dialect) -> Result<Document, JsonError> {
30        let mut parser = Self {
31            tokens: Lexer::tokenize(source)?,
32            index: 0,
33            end: source.len(),
34        };
35        let leading = Trivia::new(parser.trivia());
36        if parser.peek().is_none() {
37            let value = Value::new(leading, Kind::Object(Object::new()));
38            return Ok(Document::parsed(
39                dialect,
40                value,
41                Trivia::new("\n".to_owned()),
42            ));
43        }
44        let value = parser.value(0, leading)?;
45        let trailing = Trivia::new(parser.trivia());
46        if let Some(token) = parser.peek() {
47            return Err(JsonError {
48                offset: token.start,
49                kind: JsonErrorKind::TrailingContent,
50            });
51        }
52        Ok(Document::parsed(dialect, value, trailing))
53    }
54
55    fn peek(&self) -> Option<&Token<'a>> {
56        self.tokens.get(self.index)
57    }
58
59    const fn advance(&mut self) {
60        self.index = self.index.saturating_add(1);
61    }
62
63    fn at(&self, kind: &TokenKind) -> bool {
64        self.peek().is_some_and(|token| token.kind == *kind)
65    }
66
67    fn eat(&mut self, kind: &TokenKind) -> bool {
68        let found = self.at(kind);
69        if found {
70            self.advance();
71        }
72        found
73    }
74
75    /// The error for the current token, or for the end of input.
76    fn unexpected(&self) -> JsonError {
77        self.peek().map_or(
78            JsonError {
79                offset: self.end,
80                kind: JsonErrorKind::UnexpectedEnd,
81            },
82            |token| JsonError {
83                offset: token.start,
84                kind: JsonErrorKind::UnexpectedCharacter {
85                    found: token.text.chars().next().unwrap_or_default(),
86                },
87            },
88        )
89    }
90
91    fn expect(&mut self, kind: &TokenKind) -> Result<(), JsonError> {
92        if self.eat(kind) {
93            Ok(())
94        } else {
95            Err(self.unexpected())
96        }
97    }
98
99    /// Consume a run of trivia tokens.
100    fn trivia(&mut self) -> String {
101        let mut text = String::new();
102        while let Some(token) = self.peek()
103            && token.kind.is_trivia()
104        {
105            text.push_str(token.text);
106            self.advance();
107        }
108        text
109    }
110
111    /// Consume a run of trivia tokens and split it before its first line
112    /// terminator that is not inside a comment.
113    fn split_line(&mut self) -> (String, String) {
114        let mut head = String::new();
115        while let Some(token) = self.peek()
116            && token.kind.is_trivia()
117        {
118            let text = token.text;
119            let cut = if token.kind == TokenKind::Whitespace {
120                text.find(Lexer::is_line_terminator)
121            } else {
122                None
123            };
124            self.advance();
125            let Some((before, after)) = cut.and_then(|at| text.split_at_checked(at)) else {
126                head.push_str(text);
127                continue;
128            };
129            head.push_str(before);
130            let mut rest = after.to_owned();
131            rest.push_str(&self.trivia());
132            return (head, rest);
133        }
134        (head, String::new())
135    }
136
137    /// Read what follows a value: an optional comma and the rest of the line.
138    fn tail(&mut self) -> (Tail, Next) {
139        let saved = self.index;
140        let between = self.trivia();
141        if self.eat(&TokenKind::Comma) {
142            let (trailing, rest) = self.split_line();
143            let tail = Tail::new(Trivia::new(between), Comma::Present, Trivia::new(trailing));
144            return (
145                tail,
146                Next {
147                    comma: Comma::Present,
148                    leading: rest,
149                },
150            );
151        }
152        self.index = saved;
153        let (trailing, rest) = self.split_line();
154        let tail = Tail::new(Trivia::default(), Comma::Absent, Trivia::new(trailing));
155        (
156            tail,
157            Next {
158                comma: Comma::Absent,
159                leading: rest,
160            },
161        )
162    }
163
164    fn value(&mut self, depth: usize, leading: Trivia) -> Result<Value, JsonError> {
165        self.kind(depth).map(|kind| Value::new(leading, kind))
166    }
167
168    fn kind(&mut self, depth: usize) -> Result<Kind, JsonError> {
169        let Some(token) = self.peek() else {
170            return Err(self.unexpected());
171        };
172        let (start, text) = (token.start, token.text);
173        match &token.kind {
174            TokenKind::OpenBrace | TokenKind::OpenBracket if depth >= MAX_DEPTH => Err(JsonError {
175                offset: start,
176                kind: JsonErrorKind::DepthExceeded,
177            }),
178            TokenKind::OpenBrace => {
179                self.advance();
180                self.object(depth).map(Kind::Object)
181            }
182            TokenKind::OpenBracket => {
183                self.advance();
184                self.array(depth).map(Kind::Array)
185            }
186            TokenKind::String(_) | TokenKind::Number => Ok(self.scalar(text, start)),
187            TokenKind::Identifier(_)
188                if matches!(text, "true" | "false" | "null" | "Infinity" | "NaN") =>
189            {
190                Ok(self.scalar(text, start))
191            }
192            TokenKind::CloseBrace
193            | TokenKind::CloseBracket
194            | TokenKind::Colon
195            | TokenKind::Comma
196            | TokenKind::Identifier(_)
197            | TokenKind::Whitespace
198            | TokenKind::LineComment
199            | TokenKind::BlockComment => Err(self.unexpected()),
200        }
201    }
202
203    fn scalar(&mut self, text: &str, offset: usize) -> Kind {
204        self.advance();
205        Kind::Scalar(Scalar::from_source(text.to_owned(), offset))
206    }
207
208    fn key(&mut self) -> Result<Key, JsonError> {
209        let Some(token) = self.peek() else {
210            return Err(self.unexpected());
211        };
212        let name = match &token.kind {
213            TokenKind::String(Some(name)) | TokenKind::Identifier(name) => name.clone(),
214            TokenKind::String(None) => {
215                return Err(JsonError {
216                    offset: token.start,
217                    kind: JsonErrorKind::InvalidEscape,
218                });
219            }
220            TokenKind::OpenBrace
221            | TokenKind::CloseBrace
222            | TokenKind::OpenBracket
223            | TokenKind::CloseBracket
224            | TokenKind::Colon
225            | TokenKind::Comma
226            | TokenKind::Number
227            | TokenKind::Whitespace
228            | TokenKind::LineComment
229            | TokenKind::BlockComment => return Err(self.unexpected()),
230        };
231        let key = Key::from_source(token.text.to_owned(), name);
232        self.advance();
233        Ok(key)
234    }
235
236    /// Parse elements through the `close` token and return the trivia before
237    /// it. `element` reads one element, given the trivia before it.
238    fn elements(
239        &mut self,
240        close: &TokenKind,
241        mut element: impl FnMut(&mut Self, Trivia) -> Result<Next, JsonError>,
242    ) -> Result<Trivia, JsonError> {
243        let mut next = Next {
244            comma: Comma::Present,
245            leading: String::new(),
246        };
247        loop {
248            let mut leading = next.leading;
249            leading.push_str(&self.trivia());
250            if self.eat(close) {
251                return Ok(Trivia::new(leading));
252            }
253            if next.comma == Comma::Absent {
254                return Err(self.unexpected());
255            }
256            next = element(self, Trivia::new(leading))?;
257        }
258    }
259
260    /// Parse after the opening brace, through the closing brace.
261    fn object(&mut self, depth: usize) -> Result<Object, JsonError> {
262        let mut object = Object::new();
263        let inner = self.elements(&TokenKind::CloseBrace, |parser, leading| {
264            let key_start = parser.peek().map_or(parser.end, |token| token.start);
265            let key = parser.key()?;
266            let after_key = Trivia::new(parser.trivia());
267            parser.expect(&TokenKind::Colon)?;
268            let after_colon = Trivia::new(parser.trivia());
269            let value = parser.value(depth.saturating_add(1), leading)?;
270            let (tail, next) = parser.tail();
271            object
272                .push(Member::parsed(key, after_key, after_colon, value, tail))
273                .map_err(|duplicate| JsonError {
274                    offset: key_start,
275                    kind: JsonErrorKind::DuplicateKey {
276                        name: duplicate.name,
277                    },
278                })?;
279            Ok(next)
280        })?;
281        Ok(object.closed_by(inner))
282    }
283
284    /// Parse after the opening bracket, through the closing bracket.
285    fn array(&mut self, depth: usize) -> Result<Array, JsonError> {
286        let mut items = Vec::new();
287        let inner = self.elements(&TokenKind::CloseBracket, |parser, leading| {
288            let value = parser.value(depth.saturating_add(1), leading)?;
289            let (tail, next) = parser.tail();
290            items.push(Item::parsed(value, tail));
291            Ok(next)
292        })?;
293        Ok(Array::parsed(items, inner))
294    }
295}