Skip to main content

json_syntax/parse/
mod.rs

1use decoded_char::DecodedChar;
2use locspan::Span;
3use std::fmt;
4use utf8_decode::Utf8Error;
5
6mod array;
7mod boolean;
8mod null;
9mod number;
10mod object;
11mod string;
12mod value;
13
14use crate::JsonCodeMap;
15
16/// Parser options.
17#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
18pub struct Options {
19	/// Whether or not to accept a high surrogate without its low counterpart
20	/// in strings.
21	///
22	/// In such instance, the high surrogate will be replaced with the Unicode
23	/// REPLACEMENT CHARACTER, U+FFFD.
24	pub accept_truncated_surrogate_pair: bool,
25
26	/// Whether or not to accept invalid Unicode codepoints in strings.
27	///
28	/// Invalid codepoints will be replaced with the Unicode
29	/// REPLACEMENT CHARACTER, U+FFFD.
30	pub accept_invalid_codepoints: bool,
31}
32
33impl Options {
34	/// Strict mode.
35	///
36	/// All options are set to `false`.
37	pub fn strict() -> Self {
38		Self {
39			accept_truncated_surrogate_pair: false,
40			accept_invalid_codepoints: false,
41		}
42	}
43
44	/// Flexible mode.
45	///
46	/// All options are set to `true`.
47	pub fn flexible() -> Self {
48		Self {
49			accept_truncated_surrogate_pair: true,
50			accept_invalid_codepoints: true,
51		}
52	}
53}
54
55impl Default for Options {
56	fn default() -> Self {
57		Self::strict()
58	}
59}
60
61pub trait JsonParse: Sized {
62	fn parse_slice(content: &[u8]) -> Result<(Self, JsonCodeMap), JsonParseError> {
63		Self::parse_utf8(utf8_decode::Decoder::new(content.iter().copied()))
64			.map_err(JsonParseError::erase_utf8_error)
65	}
66
67	fn parse_slice_with(
68		content: &[u8],
69		options: Options,
70	) -> Result<(Self, JsonCodeMap), JsonParseError> {
71		Self::parse_utf8_with(utf8_decode::Decoder::new(content.iter().copied()), options)
72			.map_err(JsonParseError::erase_utf8_error)
73	}
74
75	fn parse_str(content: &str) -> Result<(Self, JsonCodeMap), JsonParseError> {
76		Self::parse_utf8(content.chars().map(Ok))
77	}
78
79	fn parse_str_with(
80		content: &str,
81		options: Options,
82	) -> Result<(Self, JsonCodeMap), JsonParseError> {
83		Self::parse_utf8_with(content.chars().map(Ok), options)
84	}
85
86	fn parse_infallible_utf8<C>(chars: C) -> Result<(Self, JsonCodeMap), JsonParseError>
87	where
88		C: Iterator<Item = char>,
89	{
90		Self::parse_infallible(chars.map(DecodedChar::from_utf8))
91	}
92
93	fn parse_utf8_infallible_with<C>(
94		chars: C,
95		options: Options,
96	) -> Result<(Self, JsonCodeMap), JsonParseError>
97	where
98		C: Iterator<Item = char>,
99	{
100		Self::parse_infallible_with(chars.map(DecodedChar::from_utf8), options)
101	}
102
103	fn parse_utf8<C, E>(chars: C) -> Result<(Self, JsonCodeMap), JsonParseError<E>>
104	where
105		C: Iterator<Item = Result<char, E>>,
106	{
107		Self::parse(chars.map(|c| c.map(DecodedChar::from_utf8)))
108	}
109
110	fn parse_utf8_with<C, E>(
111		chars: C,
112		options: Options,
113	) -> Result<(Self, JsonCodeMap), JsonParseError<E>>
114	where
115		C: Iterator<Item = Result<char, E>>,
116	{
117		Self::parse_with(chars.map(|c| c.map(DecodedChar::from_utf8)), options)
118	}
119
120	fn parse_infallible<C>(chars: C) -> Result<(Self, JsonCodeMap), JsonParseError>
121	where
122		C: Iterator<Item = DecodedChar>,
123	{
124		let mut parser = Parser::new(chars.map(Ok));
125		let value = Self::parse_in(&mut parser, JsonParsingContext::None)?.0;
126		Ok((value, parser.code_map))
127	}
128
129	fn parse_infallible_with<C>(
130		chars: C,
131		options: Options,
132	) -> Result<(Self, JsonCodeMap), JsonParseError>
133	where
134		C: Iterator<Item = DecodedChar>,
135	{
136		let mut parser = Parser::new_with(chars.map(Ok), options);
137		let value = Self::parse_in(&mut parser, JsonParsingContext::None)?.0;
138		Ok((value, parser.code_map))
139	}
140
141	fn parse<C, E>(chars: C) -> Result<(Self, JsonCodeMap), JsonParseError<E>>
142	where
143		C: Iterator<Item = Result<DecodedChar, E>>,
144	{
145		let mut parser = Parser::new(chars);
146		let value = Self::parse_in(&mut parser, JsonParsingContext::None)?.0;
147		Ok((value, parser.code_map))
148	}
149
150	fn parse_with<C, E>(
151		chars: C,
152		options: Options,
153	) -> Result<(Self, JsonCodeMap), JsonParseError<E>>
154	where
155		C: Iterator<Item = Result<DecodedChar, E>>,
156	{
157		let mut parser = Parser::new_with(chars, options);
158		let value = Self::parse_in(&mut parser, JsonParsingContext::None)?.0;
159		Ok((value, parser.code_map))
160	}
161
162	fn parse_in<C, E>(
163		parser: &mut Parser<C, E>,
164		context: JsonParsingContext,
165	) -> Result<(Self, usize), JsonParseError<E>>
166	where
167		C: Iterator<Item = Result<DecodedChar, E>>;
168}
169
170/// JSON parser.
171pub struct Parser<C: Iterator<Item = Result<DecodedChar, E>>, E> {
172	/// Character stream.
173	chars: C,
174
175	/// Pending next char.
176	pending: Option<DecodedChar>,
177
178	/// Position in the stream.
179	position: usize,
180
181	/// Parser options.
182	options: Options,
183
184	/// Code-map.
185	code_map: JsonCodeMap,
186}
187
188/// Checks if the given char `c` is a JSON whitespace.
189#[inline(always)]
190pub fn is_whitespace(c: char) -> bool {
191	matches!(c, ' ' | '\t' | '\r' | '\n')
192}
193
194impl<C: Iterator<Item = Result<DecodedChar, E>>, E> Parser<C, E> {
195	pub fn new(chars: C) -> Self {
196		Self {
197			chars,
198			pending: None,
199			position: 0,
200			options: Options::default(),
201			code_map: JsonCodeMap::default(),
202		}
203	}
204
205	pub fn new_with(chars: C, options: Options) -> Self {
206		Self {
207			chars,
208			pending: None,
209			position: 0,
210			options,
211			code_map: JsonCodeMap::default(),
212		}
213	}
214
215	fn begin_fragment(&mut self) -> usize {
216		self.code_map.reserve(self.position)
217	}
218
219	fn end_fragment(&mut self, i: usize) {
220		let entry_count = self.code_map.len();
221		let entry = self.code_map.get_mut(i).unwrap();
222		entry.span.end = self.position;
223		entry.volume = entry_count - i;
224	}
225
226	fn peek_char(&mut self) -> Result<Option<char>, JsonParseError<E>> {
227		match self.pending {
228			Some(c) => Ok(Some(c.chr())),
229			None => match self.chars.next() {
230				Some(Ok(c)) => {
231					self.pending = Some(c);
232					Ok(Some(c.chr()))
233				}
234				Some(Err(e)) => Err(JsonParseError::Stream(self.position, e)),
235				None => Ok(None),
236			},
237		}
238	}
239
240	fn next_char(&mut self) -> Result<(usize, Option<char>), JsonParseError<E>> {
241		let c = match self.pending.take() {
242			Some(c) => Some(c),
243			None => self
244				.chars
245				.next()
246				.transpose()
247				.map_err(|e| JsonParseError::Stream(self.position, e))?,
248		};
249
250		let p = self.position;
251		let c = c.map(|c| {
252			self.position += c.len();
253			c.chr()
254		});
255
256		Ok((p, c))
257	}
258
259	fn skip_whitespaces(&mut self) -> Result<(), JsonParseError<E>> {
260		while let Some(c) = self.peek_char()? {
261			if is_whitespace(c) {
262				self.next_char()?;
263			} else {
264				break;
265			}
266		}
267
268		Ok(())
269	}
270}
271
272/// Parse error.
273#[derive(Debug)]
274pub enum JsonParseError<E = core::convert::Infallible> {
275	/// Stream error.
276	///
277	/// The first parameter is the byte index at which the error occurred.
278	Stream(usize, E),
279
280	/// Unexpected character or end of stream.
281	///
282	/// The first parameter is the byte index at which the error occurred.
283	Unexpected(usize, Option<char>),
284
285	/// Invalid unicode codepoint.
286	///
287	/// The first parameter is the span at which the error occurred.
288	InvalidUnicodeCodePoint(Span, u32),
289
290	/// Missing low surrogate in a string.
291	///
292	/// The first parameter is the byte index at which the error occurred.
293	MissingLowSurrogate(Span, u16),
294
295	/// Invalid low surrogate in a string.
296	///
297	/// The first parameter is the span at which the error occurred.
298	InvalidLowSurrogate(Span, u16, u32),
299
300	/// UTF-8 encoding error.
301	InvalidUtf8(usize),
302}
303
304impl<E> JsonParseError<E> {
305	/// Creates an `Unexpected` error.
306	#[inline(always)]
307	fn unexpected(position: usize, c: Option<char>) -> Self {
308		// panic!("unexpected {:?}", c);
309		Self::Unexpected(position, c)
310	}
311
312	pub fn position(&self) -> usize {
313		match self {
314			Self::Stream(p, _) => *p,
315			Self::Unexpected(p, _) => *p,
316			Self::InvalidUnicodeCodePoint(span, _) => span.start,
317			Self::MissingLowSurrogate(span, _) => span.start,
318			Self::InvalidLowSurrogate(span, _, _) => span.start,
319			Self::InvalidUtf8(p) => *p,
320		}
321	}
322
323	pub fn span(&self) -> Span {
324		match self {
325			Self::Stream(p, _) => Span::new(*p, *p),
326			Self::Unexpected(p, _) => Span::new(*p, *p),
327			Self::InvalidUnicodeCodePoint(span, _) => *span,
328			Self::MissingLowSurrogate(span, _) => *span,
329			Self::InvalidLowSurrogate(span, _, _) => *span,
330			Self::InvalidUtf8(p) => Span::new(*p, *p),
331		}
332	}
333}
334
335impl JsonParseError<Utf8Error> {
336	fn erase_utf8_error(self) -> JsonParseError {
337		match self {
338			Self::Stream(p, _) => JsonParseError::InvalidUtf8(p),
339			Self::Unexpected(p, e) => JsonParseError::Unexpected(p, e),
340			Self::InvalidUnicodeCodePoint(s, e) => JsonParseError::InvalidUnicodeCodePoint(s, e),
341			Self::MissingLowSurrogate(s, e) => JsonParseError::MissingLowSurrogate(s, e),
342			Self::InvalidLowSurrogate(s, a, b) => JsonParseError::InvalidLowSurrogate(s, a, b),
343			Self::InvalidUtf8(p) => JsonParseError::InvalidUtf8(p),
344		}
345	}
346}
347
348impl<E: fmt::Display> fmt::Display for JsonParseError<E> {
349	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350		match self {
351			Self::Stream(_, e) => e.fmt(f),
352			Self::Unexpected(_, Some(c)) => write!(f, "unexpected character `{}`", c),
353			Self::Unexpected(_, None) => write!(f, "unexpected end of file"),
354			Self::InvalidUnicodeCodePoint(_, c) => write!(f, "invalid Unicode code point {:x}", *c),
355			Self::MissingLowSurrogate(_, _) => write!(f, "missing low surrogate"),
356			Self::InvalidLowSurrogate(_, _, _) => write!(f, "invalid low surrogate"),
357			Self::InvalidUtf8(_) => write!(f, "invalid UTF-8"),
358		}
359	}
360}
361
362impl<E: 'static + std::error::Error> std::error::Error for JsonParseError<E> {
363	fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
364		match self {
365			Self::Stream(_, e) => Some(e),
366			_ => None,
367		}
368	}
369}
370
371/// Parsing context.
372///
373/// Defines what characters are allowed after a value.
374#[derive(Clone, Copy, PartialEq, Eq, Debug)]
375pub enum JsonParsingContext {
376	None,
377	Array,
378	ObjectKey,
379	ObjectValue,
380}
381
382impl JsonParsingContext {
383	/// Checks if the given character `c` can follow a value in this context.
384	pub fn follows(&self, c: char) -> bool {
385		match self {
386			Self::None => is_whitespace(c),
387			Self::Array => is_whitespace(c) || matches!(c, ',' | ']'),
388			Self::ObjectKey => is_whitespace(c) || matches!(c, ':'),
389			Self::ObjectValue => is_whitespace(c) || matches!(c, ',' | '}'),
390		}
391	}
392}