Skip to main content

jstrict/parse/
mod.rs

1//! JSON parsing.
2//!
3//! [`Parse`] is the entry point: `Value::parse_str`, `Value::parse_slice` and
4//! friends return the parsed value together with a
5//! [`CodeMap`]. When the code map is not needed, the
6//! [`parse_str_value`] / [`parse_slice_value`] functions take a faster path
7//! that skips span tracking.
8//!
9//! Parsing is strict by default; [`Options`] relaxes surrogate and codepoint
10//! handling.
11use core::convert::Infallible;
12use decoded_char::DecodedChar;
13use locspan::Span;
14use std::error::Error as StdError;
15use std::fmt;
16
17mod array;
18mod boolean;
19mod null;
20mod number;
21mod object;
22pub(crate) mod slice;
23mod string;
24mod value;
25
26use crate::{CodeMap, Value};
27
28/// Parser options.
29#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
30pub struct Options {
31	/// Whether or not to accept a high surrogate without its low counterpart
32	/// in strings.
33	///
34	/// In such instance, the high surrogate will be replaced with the Unicode
35	/// REPLACEMENT CHARACTER, U+FFFD.
36	pub accept_truncated_surrogate_pair: bool,
37
38	/// Whether or not to accept invalid Unicode codepoints in strings.
39	///
40	/// Invalid codepoints will be replaced with the Unicode
41	/// REPLACEMENT CHARACTER, U+FFFD.
42	pub accept_invalid_codepoints: bool,
43}
44
45impl Options {
46	/// Strict mode.
47	///
48	/// All options are set to `false`.
49	#[must_use]
50	pub const fn strict() -> Self {
51		Self {
52			accept_truncated_surrogate_pair: false,
53			accept_invalid_codepoints: false,
54		}
55	}
56
57	/// Flexible mode.
58	///
59	/// All options are set to `true`.
60	#[must_use]
61	pub const fn flexible() -> Self {
62		Self {
63			accept_truncated_surrogate_pair: true,
64			accept_invalid_codepoints: true,
65		}
66	}
67}
68
69impl Default for Options {
70	fn default() -> Self {
71		Self::strict()
72	}
73}
74
75/// Parses a [`Value`] from a `&str` without building a [`CodeMap`].
76///
77/// This is the fastest path: the slice parser is monomorphised against
78/// a no-op fragment recorder, so each value is built with zero
79/// `Vec::push` for span tracking.
80///
81/// # Errors
82///
83/// Returns an [`Error`] if the input is not well-formed JSON.
84pub fn parse_str_value(content: &str) -> Result<Value, Error> {
85	parse_str_value_with(content, Options::default())
86}
87
88/// Like [`parse_str_value`] but with a custom [`Options`].
89///
90/// # Errors
91///
92/// Returns an [`Error`] if the input is not well-formed JSON.
93pub fn parse_str_value_with(content: &str, options: Options) -> Result<Value, Error> {
94	let (value, _) = slice::parse_value_str_with(content, options, slice::NoOp)?;
95	Ok(value)
96}
97
98/// Parses a [`Value`] from `&[u8]` without building a [`CodeMap`].
99///
100/// See [`parse_str_value`].
101///
102/// # Errors
103///
104/// Returns an [`Error`] if the input is not well-formed JSON.
105pub fn parse_slice_value(content: &[u8]) -> Result<Value, Error> {
106	parse_slice_value_with(content, Options::default())
107}
108
109/// Like [`parse_slice_value`] but with a custom [`Options`].
110///
111/// # Errors
112///
113/// Returns an [`Error`] if the input is not well-formed JSON.
114pub fn parse_slice_value_with(content: &[u8], options: Options) -> Result<Value, Error> {
115	let (value, _) = slice::parse_value_slice_with(content, options, slice::NoOp)?;
116	Ok(value)
117}
118
119/// JSON parsing methods.
120///
121/// Every method returns the parsed value together with the [`CodeMap`]
122/// describing where each of its fragments came from.
123///
124/// # Example
125///
126/// ```
127/// use jstrict::{Parse, Value};
128///
129/// let (value, code_map) = Value::parse_str("[1, 2]")?;
130/// assert_eq!(code_map.len(), 3); // the array and its two items.
131/// # Ok::<_, jstrict::parse::Error>(())
132/// ```
133pub trait Parse: Sized {
134	/// Parses a value from a UTF-8 byte slice.
135	///
136	/// # Errors
137	///
138	/// Returns an [`Error`] if the input is not well-formed JSON.
139	fn parse_slice(content: &[u8]) -> Result<(Self, CodeMap), Error> {
140		Self::parse_utf8(utf8_decode::Decoder::new(content.iter().copied()))
141			.map_err(Error::io_into_utf8)
142	}
143
144	/// Parses a value from a UTF-8 byte slice, with the given `options`.
145	///
146	/// # Errors
147	///
148	/// Returns an [`Error`] if the input is not well-formed JSON.
149	fn parse_slice_with(content: &[u8], options: Options) -> Result<(Self, CodeMap), Error> {
150		Self::parse_utf8_with(utf8_decode::Decoder::new(content.iter().copied()), options)
151			.map_err(Error::io_into_utf8)
152	}
153
154	/// Parses a value from a string.
155	///
156	/// # Errors
157	///
158	/// Returns an [`Error`] if the input is not well-formed JSON.
159	fn parse_str(content: &str) -> Result<(Self, CodeMap), Error> {
160		Self::parse_utf8(content.chars().map(Ok))
161	}
162
163	/// Parses a value from a string, with the given `options`.
164	///
165	/// # Errors
166	///
167	/// Returns an [`Error`] if the input is not well-formed JSON.
168	fn parse_str_with(content: &str, options: Options) -> Result<(Self, CodeMap), Error> {
169		Self::parse_utf8_with(content.chars().map(Ok), options)
170	}
171
172	/// Parses a value from an infallible iterator of UTF-8 characters.
173	///
174	/// # Errors
175	///
176	/// Returns an [`Error`] if the input is not well-formed JSON.
177	fn parse_infallible_utf8<C>(chars: C) -> Result<(Self, CodeMap), Error>
178	where
179		C: Iterator<Item = char>,
180	{
181		Self::parse_infallible(chars.map(DecodedChar::from_utf8))
182	}
183
184	/// Parses a value from an infallible iterator of UTF-8 characters, with
185	/// the given `options`.
186	///
187	/// # Errors
188	///
189	/// Returns an [`Error`] if the input is not well-formed JSON.
190	fn parse_utf8_infallible_with<C>(chars: C, options: Options) -> Result<(Self, CodeMap), Error>
191	where
192		C: Iterator<Item = char>,
193	{
194		Self::parse_infallible_with(chars.map(DecodedChar::from_utf8), options)
195	}
196
197	/// Parses a value from a fallible iterator of UTF-8 characters.
198	///
199	/// Stream errors of type `E` are wrapped in [`Error::Stream`].
200	///
201	/// # Errors
202	///
203	/// Returns [`Error::Stream`] if the character stream yields an error, or
204	/// another [`Error`] variant if the input is not well-formed JSON.
205	fn parse_utf8<C, E>(chars: C) -> Result<(Self, CodeMap), Error<E>>
206	where
207		C: Iterator<Item = Result<char, E>>,
208	{
209		Self::parse(chars.map(|c| c.map(DecodedChar::from_utf8)))
210	}
211
212	/// Parses a value from a fallible iterator of UTF-8 characters, with the
213	/// given `options`.
214	///
215	/// # Errors
216	///
217	/// Returns [`Error::Stream`] if the character stream yields an error, or
218	/// another [`Error`] variant if the input is not well-formed JSON.
219	fn parse_utf8_with<C, E>(chars: C, options: Options) -> Result<(Self, CodeMap), Error<E>>
220	where
221		C: Iterator<Item = Result<char, E>>,
222	{
223		Self::parse_with(chars.map(|c| c.map(DecodedChar::from_utf8)), options)
224	}
225
226	/// Parses a value from an infallible iterator of decoded characters.
227	///
228	/// Unlike the `utf8` variants, [`DecodedChar`] carries the byte length of
229	/// each character in the *source* encoding, so spans stay accurate when
230	/// the input is not UTF-8.
231	///
232	/// # Errors
233	///
234	/// Returns an [`Error`] if the input is not well-formed JSON.
235	fn parse_infallible<C>(chars: C) -> Result<(Self, CodeMap), Error>
236	where
237		C: Iterator<Item = DecodedChar>,
238	{
239		let mut parser = Parser::new(chars.map(Ok));
240		let value = Self::parse_in(&mut parser, Context::None)?.0;
241		Ok((value, parser.code_map))
242	}
243
244	/// Parses a value from an infallible iterator of decoded characters, with
245	/// the given `options`.
246	///
247	/// # Errors
248	///
249	/// Returns an [`Error`] if the input is not well-formed JSON.
250	fn parse_infallible_with<C>(chars: C, options: Options) -> Result<(Self, CodeMap), Error>
251	where
252		C: Iterator<Item = DecodedChar>,
253	{
254		let mut parser = Parser::new_with(chars.map(Ok), options);
255		let value = Self::parse_in(&mut parser, Context::None)?.0;
256		Ok((value, parser.code_map))
257	}
258
259	/// Parses a value from a fallible iterator of decoded characters.
260	///
261	/// # Errors
262	///
263	/// Returns [`Error::Stream`] if the character stream yields an error, or
264	/// another [`Error`] variant if the input is not well-formed JSON.
265	fn parse<C, E>(chars: C) -> Result<(Self, CodeMap), Error<E>>
266	where
267		C: Iterator<Item = Result<DecodedChar, E>>,
268	{
269		let mut parser = Parser::new(chars);
270		let value = Self::parse_in(&mut parser, Context::None)?.0;
271		Ok((value, parser.code_map))
272	}
273
274	/// Parses a value from a fallible iterator of decoded characters, with the
275	/// given `options`.
276	///
277	/// # Errors
278	///
279	/// Returns [`Error::Stream`] if the character stream yields an error, or
280	/// another [`Error`] variant if the input is not well-formed JSON.
281	fn parse_with<C, E>(chars: C, options: Options) -> Result<(Self, CodeMap), Error<E>>
282	where
283		C: Iterator<Item = Result<DecodedChar, E>>,
284	{
285		let mut parser = Parser::new_with(chars, options);
286		let value = Self::parse_in(&mut parser, Context::None)?.0;
287		Ok((value, parser.code_map))
288	}
289
290	/// Parses a value in the middle of an ongoing parse, using `parser` and
291	/// the surrounding [`Context`].
292	///
293	/// Returns the value along with the index of its code map fragment. This
294	/// is the single method implementors must provide; everything else is a
295	/// wrapper around it.
296	///
297	/// # Errors
298	///
299	/// Returns [`Error::Stream`] if the character stream yields an error, or
300	/// another [`Error`] variant if the input is not well-formed JSON.
301	fn parse_in<C, E>(
302		parser: &mut Parser<C, E>,
303		context: Context,
304	) -> Result<(Self, usize), Error<E>>
305	where
306		C: Iterator<Item = Result<DecodedChar, E>>;
307}
308
309/// JSON parser.
310pub struct Parser<C: Iterator<Item = Result<DecodedChar, E>>, E> {
311	/// Character stream.
312	chars: C,
313
314	/// Pending next char.
315	pending: Option<DecodedChar>,
316
317	/// Position in the stream.
318	position: usize,
319
320	/// Parser options.
321	options: Options,
322
323	/// Code-map.
324	code_map: CodeMap,
325}
326
327/// Checks if the given char `c` is a JSON whitespace.
328#[inline(always)]
329#[must_use]
330pub const fn is_whitespace(c: char) -> bool {
331	matches!(c, ' ' | '\t' | '\r' | '\n')
332}
333
334impl<C: Iterator<Item = Result<DecodedChar, E>>, E> Parser<C, E> {
335	/// Creates a new parser over `chars`, in strict mode.
336	pub fn new(chars: C) -> Self {
337		Self {
338			chars,
339			pending: None,
340			position: 0,
341			options: Options::default(),
342			code_map: CodeMap::default(),
343		}
344	}
345
346	/// Creates a new parser over `chars`, with the given `options`.
347	pub fn new_with(chars: C, options: Options) -> Self {
348		Self {
349			chars,
350			pending: None,
351			position: 0,
352			options,
353			code_map: CodeMap::default(),
354		}
355	}
356
357	fn begin_fragment(&mut self) -> usize {
358		self.code_map.reserve(self.position)
359	}
360
361	fn end_fragment(&mut self, i: usize) {
362		let entry_count = self.code_map.len();
363		let Some(entry) = self.code_map.get_mut(i) else {
364			return;
365		};
366		entry.span.end = self.position;
367		entry.volume = entry_count - i;
368	}
369
370	fn peek_char(&mut self) -> Result<Option<char>, Error<E>> {
371		match self.pending {
372			Some(c) => Ok(Some(c.chr())),
373			None => match self.chars.next() {
374				Some(Ok(c)) => {
375					self.pending = Some(c);
376					Ok(Some(c.chr()))
377				}
378				Some(Err(e)) => Err(Error::Stream(self.position, e)),
379				None => Ok(None),
380			},
381		}
382	}
383
384	fn next_char(&mut self) -> Result<(usize, Option<char>), Error<E>> {
385		let c = match self.pending.take() {
386			Some(c) => Some(c),
387			None => self
388				.chars
389				.next()
390				.transpose()
391				.map_err(|e| Error::Stream(self.position, e))?,
392		};
393
394		let p = self.position;
395		let c = c.map(|c| {
396			self.position += c.len();
397			c.chr()
398		});
399
400		Ok((p, c))
401	}
402
403	fn skip_whitespaces(&mut self) -> Result<(), Error<E>> {
404		while let Some(c) = self.peek_char()? {
405			if is_whitespace(c) {
406				self.next_char()?;
407			} else {
408				break;
409			}
410		}
411
412		Ok(())
413	}
414}
415
416/// Parse error.
417#[derive(Debug)]
418pub enum Error<E = Infallible> {
419	/// Stream error.
420	///
421	/// The first parameter is the byte index at which the error occurred.
422	Stream(usize, E),
423
424	/// Unexpected character or end of stream.
425	///
426	/// The first parameter is the byte index at which the error occurred.
427	Unexpected(usize, Option<char>),
428
429	/// Invalid unicode codepoint.
430	///
431	/// The first parameter is the span at which the error occurred.
432	InvalidUnicodeCodePoint(Span, u32),
433
434	/// Missing low surrogate in a string.
435	///
436	/// The first parameter is the byte index at which the error occurred.
437	MissingLowSurrogate(Span, u32),
438
439	/// Invalid low surrogate in a string.
440	///
441	/// The first parameter is the span at which the error occurred.
442	InvalidLowSurrogate(Span, u32, u32),
443
444	/// UTF-8 encoding error.
445	InvalidUtf8(usize),
446}
447
448impl<E> Error<E> {
449	/// Creates an `Unexpected` error.
450	#[inline(always)]
451	const fn unexpected(position: usize, c: Option<char>) -> Self {
452		// panic!("unexpected {:?}", c);
453		Self::Unexpected(position, c)
454	}
455
456	/// Returns the byte position at which the error occurred.
457	pub const fn position(&self) -> usize {
458		match self {
459			Self::Stream(p, _) | Self::Unexpected(p, _) | Self::InvalidUtf8(p) => *p,
460			Self::InvalidUnicodeCodePoint(span, _)
461			| Self::MissingLowSurrogate(span, _)
462			| Self::InvalidLowSurrogate(span, _, _) => span.start,
463		}
464	}
465
466	/// Returns the byte span the error covers.
467	///
468	/// Errors that point at a single position return an empty span there.
469	pub fn span(&self) -> Span {
470		match self {
471			Self::Stream(p, _) | Self::Unexpected(p, _) | Self::InvalidUtf8(p) => Span::new(*p, *p),
472			Self::InvalidUnicodeCodePoint(span, _)
473			| Self::MissingLowSurrogate(span, _)
474			| Self::InvalidLowSurrogate(span, _, _) => *span,
475		}
476	}
477}
478
479impl Error<utf8_decode::Utf8Error> {
480	const fn io_into_utf8(self) -> Error {
481		match self {
482			Self::Stream(p, _) | Self::InvalidUtf8(p) => Error::InvalidUtf8(p),
483			Self::Unexpected(p, e) => Error::Unexpected(p, e),
484			Self::InvalidUnicodeCodePoint(s, e) => Error::InvalidUnicodeCodePoint(s, e),
485			Self::MissingLowSurrogate(s, e) => Error::MissingLowSurrogate(s, e),
486			Self::InvalidLowSurrogate(s, a, b) => Error::InvalidLowSurrogate(s, a, b),
487		}
488	}
489}
490
491impl<E: fmt::Display> fmt::Display for Error<E> {
492	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493		match self {
494			Self::Stream(_, e) => e.fmt(f),
495			Self::Unexpected(_, Some(c)) => write!(f, "unexpected character `{c}`"),
496			Self::Unexpected(_, None) => write!(f, "unexpected end of file"),
497			Self::InvalidUnicodeCodePoint(_, c) => write!(f, "invalid Unicode code point {:x}", *c),
498			Self::MissingLowSurrogate(_, _) => write!(f, "missing low surrogate"),
499			Self::InvalidLowSurrogate(_, _, _) => write!(f, "invalid low surrogate"),
500			Self::InvalidUtf8(_) => write!(f, "invalid UTF-8"),
501		}
502	}
503}
504
505impl<E: 'static + StdError> StdError for Error<E> {
506	fn source(&self) -> Option<&(dyn StdError + 'static)> {
507		match self {
508			Self::Stream(_, e) => Some(e),
509			Self::Unexpected(..)
510			| Self::InvalidUnicodeCodePoint(..)
511			| Self::MissingLowSurrogate(..)
512			| Self::InvalidLowSurrogate(..)
513			| Self::InvalidUtf8(..) => None,
514		}
515	}
516}
517
518/// Parsing context.
519///
520/// Defines what characters are allowed after a value.
521#[derive(Clone, Copy, PartialEq, Eq, Debug)]
522pub enum Context {
523	/// Top level: only whitespace may follow the value.
524	None,
525
526	/// Inside an array: `,` or `]` may follow the value.
527	Array,
528
529	/// An object key: `:` may follow the value.
530	ObjectKey,
531
532	/// An object entry value: `,` or `}` may follow the value.
533	ObjectValue,
534}
535
536impl Context {
537	/// Checks if the given character `c` can follow a value in this context.
538	#[must_use]
539	pub const fn follows(&self, c: char) -> bool {
540		match self {
541			Self::None => is_whitespace(c),
542			Self::Array => is_whitespace(c) || matches!(c, ',' | ']'),
543			Self::ObjectKey => is_whitespace(c) || matches!(c, ':'),
544			Self::ObjectValue => is_whitespace(c) || matches!(c, ',' | '}'),
545		}
546	}
547}