use crate::{
Pos,
lexical::{self, Error as _, Token},
};
use bitvec::prelude::*;
use std::{fmt, iter::Take, sync::Arc};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum StructKind {
Arr = 0,
Obj = 1,
}
impl From<StructKind> for bool {
fn from(value: StructKind) -> Self {
(value as u8) == 1
}
}
impl From<bool> for StructKind {
fn from(value: bool) -> Self {
match value {
false => StructKind::Arr,
true => StructKind::Obj,
}
}
}
impl From<BitRef<'_>> for StructKind {
fn from(value: BitRef<'_>) -> Self {
let value: bool = *value;
value.into()
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Expect {
ArrElementOrEnd,
ArrElementSepOrEnd,
Eof,
ObjName,
ObjNameOrEnd,
ObjNameSep,
ObjValueSepOrEnd,
#[default]
Value,
}
impl Expect {
pub const fn allowed_tokens(&self) -> &'static [Token] {
match self {
Expect::Value => &[
Token::ArrBegin,
Token::LitFalse,
Token::LitNull,
Token::LitTrue,
Token::Num,
Token::ObjBegin,
Token::Str,
],
Expect::ObjName => &[Token::Str],
Expect::ObjNameOrEnd => &[Token::Str, Token::ObjEnd],
Expect::ObjNameSep => &[Token::NameSep],
Expect::ObjValueSepOrEnd => &[Token::ObjEnd, Token::ValueSep],
Expect::ArrElementOrEnd => &[
Token::ArrBegin,
Token::ArrEnd,
Token::LitFalse,
Token::LitNull,
Token::LitTrue,
Token::Num,
Token::ObjBegin,
Token::Str,
],
Expect::ArrElementSepOrEnd => &[Token::ArrEnd, Token::ValueSep],
Expect::Eof => &[],
}
}
}
impl fmt::Display for Expect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::ArrElementOrEnd => "array element or ]",
Self::ArrElementSepOrEnd => ", or ]",
Self::Eof => "EOF",
Self::ObjName => "object member name",
Self::ObjNameOrEnd => "object member name or }",
Self::ObjNameSep => ":",
Self::ObjValueSepOrEnd => ", or }",
Self::Value => "value",
};
write!(f, "{s}")
}
}
const INLINE_LEN_BYTES: usize = 16;
const INLINE_LEN_USIZES: usize = INLINE_LEN_BYTES / std::mem::size_of::<usize>();
const NUM_INLINED_LEVELS: usize = INLINE_LEN_BYTES * 8;
#[derive(Clone, Debug)]
enum StructContext {
Inline(usize, BitArray<[usize; INLINE_LEN_USIZES]>),
Heap(BitVec),
}
impl StructContext {
fn push(&mut self, s: StructKind) {
match self {
StructContext::Inline(len, array) => {
if *len < array.len() {
array.set(*len, s.into());
*len += 1;
} else {
let mut v = BitVec::with_capacity(2 * array.len());
v.extend_from_bitslice(array);
v.push(s.into());
*self = StructContext::Heap(v);
}
}
StructContext::Heap(v) => v.push(s.into()),
}
}
fn pop(&mut self) -> Option<StructKind> {
match self {
StructContext::Inline(len, array) => {
*len -= 1;
if *len > 0 {
Some(array[*len - 1].into())
} else {
None
}
}
StructContext::Heap(v) => v.pop().map(Into::into),
}
}
fn peek(&self) -> Option<StructKind> {
match self {
StructContext::Inline(0, _) => None,
StructContext::Inline(len, array) => Some(array[*len - 1].into()),
StructContext::Heap(v) => v.last().map(Into::into),
}
}
fn level(&self) -> usize {
match self {
StructContext::Inline(len, _) => *len,
StructContext::Heap(v) => v.len(),
}
}
fn is_struct(&self) -> bool {
self.level() > 0
}
fn iter(&self) -> StructIter<bitvec::slice::Iter<'_, usize, Lsb0>> {
StructIter(match self {
StructContext::Inline(len, array) => array[0..*len].iter(),
StructContext::Heap(v) => v.iter(),
})
}
}
impl Default for StructContext {
fn default() -> Self {
Self::Inline(0, BitArray::new([0usize; INLINE_LEN_USIZES]))
}
}
impl IntoIterator for StructContext {
type Item = bool;
type IntoIter = StructContextIntoIter;
fn into_iter(self) -> Self::IntoIter {
match self {
Self::Inline(len, array) => StructContextIntoIter::Inline(array.into_iter().take(len)),
Self::Heap(v) => StructContextIntoIter::Heap(v.into_iter()),
}
}
}
impl PartialEq<StructContext> for StructContext {
fn eq(&self, other: &StructContext) -> bool {
match (self, other) {
(Self::Inline(m, a), Self::Inline(n, b)) => m == n && a[..*m] == b[..*m],
(Self::Inline(m, a), Self::Heap(w)) => *m == w.len() && &a[..*m] == w,
(Self::Heap(v), Self::Inline(n, b)) => v.len() == *n && &b[..*n] == v,
(Self::Heap(v), Self::Heap(w)) => v == w,
}
}
}
impl Eq for StructContext {}
#[doc(hidden)]
pub enum StructContextIntoIter {
Inline(Take<<BitArray<[usize; INLINE_LEN_USIZES]> as IntoIterator>::IntoIter>),
Heap(<BitVec as IntoIterator>::IntoIter),
}
impl Iterator for StructContextIntoIter {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
match self {
StructContextIntoIter::Inline(i) => i.next(),
StructContextIntoIter::Heap(i) => i.next(),
}
}
}
impl ExactSizeIterator for StructContextIntoIter {
fn len(&self) -> usize {
match self {
StructContextIntoIter::Inline(i) => i.len(),
StructContextIntoIter::Heap(i) => i.len(),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Context {
inner: StructContext,
expect: Expect,
}
impl Context {
pub fn expect(&self) -> Expect {
self.expect
}
pub fn level(&self) -> usize {
self.inner.level()
}
pub fn is_struct(&self) -> bool {
self.inner.is_struct()
}
pub fn struct_kind(&self) -> Option<StructKind> {
self.inner.peek()
}
pub fn iter(&self) -> StructIter<bitvec::slice::Iter<'_, usize, Lsb0>> {
self.inner.iter()
}
#[cfg(test)]
fn with_expect(expect: Expect) -> Self {
Self {
inner: StructContext::default(),
expect,
}
}
#[cfg(test)]
fn with_struct<I, T>(struct_kinds: I) -> Self
where
I: IntoIterator<Item = T>,
T: Into<StructKind>,
{
let mut this = Self::default();
struct_kinds
.into_iter()
.map(Into::into)
.for_each(|k| this.inner.push(k));
this
}
#[cfg(test)]
fn and_expect(mut self, expect: Expect) -> Self {
self.expect = expect;
self
}
}
impl IntoIterator for Context {
type Item = StructKind;
type IntoIter = StructIter<StructContextIntoIter>;
fn into_iter(self) -> Self::IntoIter {
StructIter(self.inner.into_iter())
}
}
pub struct StructIter<I>(I);
impl<I> Iterator for StructIter<I>
where
I: Iterator,
I::Item: Into<StructKind>,
{
type Item = StructKind;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(Into::<StructKind>::into)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<I> ExactSizeIterator for StructIter<I>
where
I: ExactSizeIterator,
I::Item: Into<StructKind>,
{
fn len(&self) -> usize {
self.0.len()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ErrorKind {
Level {
level: usize,
token: lexical::Token,
},
Lexical(lexical::ErrorKind),
Syntax {
context: Context,
token: lexical::Token,
},
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Level { level, token } => {
write!(
f,
"level error: level {level} would exceed parser's configured maximum on {token}"
)
}
Self::Lexical(lexical::ErrorKind::Read) => write!(f, "read error"),
Self::Lexical(inner) => {
write!(f, "lexical error: ")?;
inner.fmt(f)
}
Self::Syntax { context, token } => {
write!(
f,
"syntax error: expected {} but got {token}",
context.expect()
)
}
}
}
}
#[derive(Debug, Clone)]
pub struct Error {
kind: ErrorKind,
pos: Pos,
source: Option<Arc<dyn std::error::Error + Send + Sync + 'static>>,
}
impl Error {
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
pub fn pos(&self) -> &Pos {
&self.pos
}
pub fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source
.as_ref()
.map(|arc| &**arc as &(dyn std::error::Error + 'static))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} at {}", self.kind, self.pos)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Error::source(self)
}
}
#[repr(u8)]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
enum State {
#[default]
Ok = 0x00,
Err = 0xff,
}
pub struct Parser<L> {
lexer: L,
context: Context,
err: Option<Error>,
max_level: usize,
state: State,
}
impl<L> Parser<L>
where
L: lexical::Analyzer,
L::Error: 'static,
{
pub fn new(lexer: L) -> Self {
Self {
lexer,
context: Context::default(),
err: None,
max_level: NUM_INLINED_LEVELS,
state: State::default(),
}
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Token {
#[repr(u8)]
#[rustfmt::skip]
#[derive(Clone, Copy, Debug)]
enum Action {
ArrBegin, ArrElement, ArrElementSep, Ignore, Name, NameSep, ObjBegin, ObjValueSep,
StructEnd, Value, ErrLexical, ErrSyntax, ErrCached,
}
macro_rules! key {
($state:expr, $expect:expr, $token:expr) => {
($state as usize) | (($expect as usize) << 4) | ($token as usize)
};
}
static ACTION: [Action; 256] = {
let mut t = [Action::ErrSyntax; 256];
t[key!(State::Err, 0, 0)] = Action::ErrCached;
macro_rules! set_inner {
($expect:ident, [$($token:ident),+], $action:ident) => {
$(
t[key!(State::Ok, Expect::$expect, Token::$token)] = Action::$action;
)+
};
}
macro_rules! set {
([$($expect:ident),+], $tokens:tt, $action:ident) => {
$(
set_inner!($expect, $tokens, $action);
)+
};
}
set!([ArrElementOrEnd], [ArrEnd], StructEnd);
set!([ArrElementOrEnd, Value], [ObjBegin], ObjBegin);
set!([ArrElementOrEnd, Value], [ArrBegin], ArrBegin);
set!(
[ArrElementOrEnd],
[LitFalse, LitNull, LitTrue, Num, Str],
ArrElement
);
set!([ArrElementSepOrEnd], [ArrEnd], StructEnd);
set!([ArrElementSepOrEnd], [ValueSep], ArrElementSep);
set!([ObjName], [Str], Name);
set!([ObjNameOrEnd], [ObjEnd], StructEnd);
set!([ObjNameOrEnd], [Str], Name);
set!([ObjNameSep], [NameSep], NameSep);
set!([ObjValueSepOrEnd], [ValueSep], ObjValueSep);
set!([ObjValueSepOrEnd], [ObjEnd], StructEnd);
set!([Value], [LitFalse, LitNull, LitTrue, Num, Str], Value);
set!([Eof], [Eof], Ignore);
set!(
[
ArrElementOrEnd,
ArrElementSepOrEnd,
Eof,
ObjName,
ObjNameOrEnd,
ObjNameSep,
ObjValueSepOrEnd,
Value
],
[White],
Ignore
);
set!(
[
ArrElementOrEnd,
ArrElementSepOrEnd,
Eof,
ObjName,
ObjNameOrEnd,
ObjNameSep,
ObjValueSepOrEnd,
Value
],
[Err],
ErrLexical
);
t
};
let token = self.lexer.next();
let key = key!(self.state, self.context.expect, token);
match ACTION[key] {
Action::ArrBegin => {
let level = self.level();
if level < self.max_level {
self.context.inner.push(StructKind::Arr);
self.context.expect = Expect::ArrElementOrEnd;
return token;
} else {
self.err_level(token);
return Token::Err;
}
}
Action::ArrElement => self.context.expect = Expect::ArrElementSepOrEnd,
Action::ArrElementSep => self.context.expect = Expect::Value,
Action::Ignore => (),
Action::Name => self.context.expect = Expect::ObjNameSep,
Action::NameSep => self.context.expect = Expect::Value,
Action::ObjBegin => {
let level = self.level();
if level < self.max_level {
self.context.inner.push(StructKind::Obj);
self.context.expect = Expect::ObjNameOrEnd;
return token;
} else {
self.err_level(token);
return Token::Err;
}
}
Action::ObjValueSep => self.context.expect = Expect::ObjName,
Action::StructEnd => self.got_value(true),
Action::Value => self.got_value(false),
Action::ErrCached => return Token::Err,
Action::ErrLexical => {
self.err_lexical();
return Token::Err;
}
Action::ErrSyntax => {
self.err_syntax(token);
return Token::Err;
}
};
token
}
pub fn next_non_white(&mut self) -> Token {
let token = self.next();
if token != Token::White {
token
} else {
self.next()
}
}
pub fn next_meaningful(&mut self) -> Token {
let mut token = self.next();
loop {
match token {
Token::NameSep | Token::ValueSep | Token::White => token = self.next(),
_ => break token,
}
}
}
pub fn next_end(&mut self) -> Token {
let end_level = self.level();
loop {
let token = self.next();
match token {
Token::Eof | Token::Err => break token,
Token::ArrEnd | Token::ObjEnd if self.level() + 1 == end_level => break token,
_ => continue,
}
}
}
#[inline(always)]
pub fn content(&self) -> L::Content {
match self.state {
State::Ok => match self.lexer.try_content() {
Ok(c) => c,
Err(_) => unreachable!("lexer can't be in error state when parser isn't"),
},
State::Err => panic!("no content: parser is in error state (use `err()` instead)"),
}
}
#[inline]
pub fn err(&self) -> Error {
match self.try_content() {
Ok(_) => panic!(
"no error: last `next()` did not return `Token::Err` (use `content()` instead)"
),
Err(err) => err,
}
}
#[inline(always)]
pub fn pos(&self) -> &Pos {
self.lexer.pos()
}
pub fn try_content(&self) -> Result<L::Content, Error> {
match self.state {
State::Ok => Ok(self
.lexer
.try_content()
.expect("lexer must not be in an error state")),
State::Err => Err(self
.err
.clone()
.expect("error value must be available in error state")),
}
}
pub fn context(&self) -> &Context {
&self.context
}
#[inline(always)]
pub fn level(&self) -> usize {
self.context.level()
}
pub fn max_level(&self) -> usize {
self.max_level
}
pub fn set_max_level(&mut self, max_level: usize) {
if self.level() > max_level {
panic!(
"current level {} exceeds new max level {max_level}",
self.level()
);
}
self.max_level = max_level;
}
pub fn with_max_level(lexer: L, max_level: usize) -> Self {
let mut parser = Self::new(lexer);
parser.set_max_level(max_level);
parser
}
pub fn into_inner(self) -> L {
self.lexer
}
fn got_value(&mut self, pop: bool) {
let top = if pop {
self.context.inner.pop()
} else {
self.context.inner.peek()
};
match top {
Some(StructKind::Arr) => self.context.expect = Expect::ArrElementSepOrEnd,
Some(StructKind::Obj) => self.context.expect = Expect::ObjValueSepOrEnd,
None => self.context.expect = Expect::Eof,
}
}
fn err_level(&mut self, token: Token) {
self.state = State::Err;
self.err = Some(Error {
kind: ErrorKind::Level {
level: self.max_level + 1,
token,
},
pos: *self.pos(),
source: None,
});
}
fn err_lexical(&mut self) {
let err = self
.lexer
.try_content()
.expect_err("lexer should have error");
let kind = ErrorKind::Lexical(err.kind());
let source = Some(Arc::new(err) as Arc<dyn std::error::Error + Send + Sync + 'static>);
self.state = State::Err;
self.err = Some(Error {
kind,
pos: *self.lexer.pos(),
source,
})
}
fn err_syntax(&mut self, token: Token) {
self.state = State::Err;
self.err = Some(Error {
kind: ErrorKind::Syntax {
context: self.context.clone(),
token,
},
pos: *self.lexer.pos(),
source: None,
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::lexical::fixed::FixedAnalyzer;
use rstest::rstest;
#[rstest]
#[case(false, StructKind::Arr)]
#[case(true, StructKind::Obj)]
fn test_struct_kind_from_bool(#[case] t: bool, #[case] expect: StructKind) {
assert_eq!(expect, t.into());
assert_eq!(t, Into::<bool>::into(expect));
}
#[test]
fn test_struct_kind_from_bitref() {
let bits: BitArray<[u8; 1]> = bitarr![u8, Lsb0; 0, 1];
assert_eq!(StructKind::Arr, bits[0].into());
assert_eq!(StructKind::Obj, bits[1].into());
}
#[rstest]
#[case(Expect::ArrElementOrEnd, [Token::ArrBegin, Token::ArrEnd, Token::LitFalse, Token::LitNull, Token::LitTrue, Token::Num, Token::ObjBegin, Token::Str])]
#[case(Expect::ArrElementSepOrEnd, [Token::ArrEnd, Token::ValueSep])]
#[case(Expect::Eof, [])]
#[case(Expect::ObjName, [Token::Str])]
#[case(Expect::ObjNameOrEnd, [Token::Str, Token::ObjEnd])]
#[case(Expect::ObjNameSep, [Token::NameSep])]
#[case(Expect::ObjValueSepOrEnd, [Token::ObjEnd, Token::ValueSep])]
#[case(Expect::Value, [Token::ArrBegin, Token::LitFalse, Token::LitNull, Token::LitTrue, Token::Num, Token::ObjBegin, Token::Str])]
fn test_expect_allowed_tokens<const N: usize>(
#[case] input: Expect,
#[case] expect: [Token; N],
) {
let actual = input.allowed_tokens();
assert_eq!(expect, actual);
}
#[rstest]
#[case(Expect::ArrElementOrEnd, "array element or ]")]
#[case(Expect::ArrElementSepOrEnd, ", or ]")]
#[case(Expect::Eof, "EOF")]
#[case(Expect::ObjName, "object member name")]
#[case(Expect::ObjNameOrEnd, "object member name or }")]
#[case(Expect::ObjNameSep, ":")]
#[case(Expect::ObjValueSepOrEnd, ", or }")]
#[case(Expect::Value, "value")]
fn test_expect_display(#[case] variant: Expect, #[case] expect: &str) {
assert_eq!(expect, variant.to_string());
}
#[rstest]
#[case::empty(None::<StructKind>)]
#[case::array([StructKind::Arr])]
#[case::array_array([StructKind::Arr, StructKind::Arr])]
#[case::array_array_array([StructKind::Arr, StructKind::Arr, StructKind::Arr])]
#[case::array_array_object([StructKind::Arr, StructKind::Arr, StructKind::Obj])]
#[case::array_object([StructKind::Arr, StructKind::Obj])]
#[case::array_object_array([StructKind::Arr, StructKind::Obj, StructKind::Arr])]
#[case::array_object_object([StructKind::Arr, StructKind::Obj, StructKind::Obj])]
#[case::object([StructKind::Obj])]
#[case::object_array([StructKind::Obj, StructKind::Arr])]
#[case::object_array_array([StructKind::Obj, StructKind::Arr, StructKind::Arr])]
#[case::object_array_object([StructKind::Obj, StructKind::Arr, StructKind::Obj])]
#[case::object_object([StructKind::Obj, StructKind::Obj])]
#[case::object_object_array([StructKind::Obj, StructKind::Obj, StructKind::Arr])]
#[case::object_object_object([StructKind::Obj, StructKind::Obj, StructKind::Obj])]
#[case::heap(std::iter::repeat([false, true]).take(NUM_INLINED_LEVELS+3).flatten().map(Into::into))]
fn test_struct_context<I>(#[case] expect: I)
where
I: IntoIterator<Item = StructKind>,
{
let expect = expect.into_iter().collect::<Vec<_>>();
let mut ctx = StructContext::default();
assert_eq!(ctx, ctx);
assert_eq!(0, ctx.level());
assert_eq!(None, ctx.peek());
assert!(!ctx.is_struct());
assert_eq!(Vec::<StructKind>::new(), ctx.iter().collect::<Vec<_>>());
for (i, s) in expect.iter().enumerate() {
let prev_ctx = ctx.clone();
ctx.push(*s);
assert_eq!(ctx, ctx);
assert_ne!(prev_ctx, ctx);
assert_ne!(ctx, prev_ctx);
assert_eq!(i + 1, ctx.level());
assert_eq!(Some(*s), ctx.peek());
assert!(ctx.is_struct());
let progress = expect[0..=i].to_vec();
assert_eq!(progress, ctx.iter().collect::<Vec<_>>());
let iter = ctx.clone().into_iter();
assert_eq!(i + 1, iter.len());
assert_eq!(progress, iter.map(Into::into).collect::<Vec<_>>());
}
for (i, s) in expect.iter().enumerate().rev() {
assert_eq!(i + 1, ctx.level());
assert_eq!(Some(*s), ctx.peek());
assert!(ctx.is_struct());
let progress = expect[0..=i].to_vec();
assert_eq!(progress, ctx.iter().collect::<Vec<_>>());
let iter = ctx.clone().into_iter();
assert_eq!(i + 1, iter.len());
assert_eq!(progress, iter.map(Into::into).collect::<Vec<_>>());
let prev_ctx = ctx.clone();
ctx.pop();
assert_eq!(ctx, ctx);
assert_ne!(prev_ctx, ctx);
assert_ne!(ctx, prev_ctx);
}
assert_eq!(ctx, ctx);
assert_eq!(0, ctx.level());
assert_eq!(None, ctx.peek());
assert!(!ctx.is_struct());
assert_eq!(Vec::<StructKind>::new(), ctx.iter().collect::<Vec<_>>());
}
#[test]
fn test_struct_context_partial_eq() {
let empty_inline = StructContext::default();
let empty_heap = StructContext::Heap(BitVec::new());
assert_eq!(empty_inline, empty_inline);
assert_eq!(empty_inline, empty_heap);
assert_eq!(empty_heap, empty_inline);
assert_eq!(empty_heap, empty_heap);
let mut arr_inline = StructContext::default();
arr_inline.push(StructKind::Arr);
let mut arr_heap = BitVec::new();
arr_heap.push(StructKind::Arr.into());
let arr_heap = StructContext::Heap(arr_heap);
assert_eq!(arr_inline, arr_inline);
assert_eq!(arr_inline, arr_heap);
assert_eq!(arr_heap, arr_inline);
assert_eq!(arr_heap, arr_heap);
let mut obj_inline = StructContext::default();
obj_inline.push(StructKind::Obj);
let mut obj_heap = BitVec::new();
obj_heap.push(StructKind::Obj.into());
let obj_heap = StructContext::Heap(obj_heap);
assert_eq!(obj_inline, obj_inline);
assert_eq!(obj_inline, obj_heap);
assert_eq!(obj_heap, obj_inline);
assert_eq!(obj_heap, obj_heap);
macro_rules! assert_groups_ne {
(@one $a:expr, [$($b:expr),+]) => {
$( assert_ne!($a, $b); assert_ne!($b, $a); )+
};
(@group [$single:expr], $($rest:tt),+) => {
$( assert_groups_ne!(@one $single, $rest); )+
};
(@group [$head:expr, $($tail:expr),+], $($rest:tt),+) => {
$( assert_groups_ne!(@one $head, $rest); )+
assert_groups_ne!(@group [$($tail),+], $($rest),+);
};
($single:tt) => {};
($first:tt, $($rest:tt),+) => {
assert_groups_ne!(@group $first, $($rest),+);
assert_groups_ne!($($rest),+);
};
}
assert_groups_ne!(
[empty_inline, empty_heap],
[arr_inline, arr_heap],
[obj_inline, obj_heap]
);
}
#[test]
fn test_context() {
let context = Context::default();
assert_eq!(Expect::Value, context.expect());
assert!(!context.is_struct());
assert!(context.struct_kind().is_none());
assert!(context.iter().next().is_none());
assert!(context.clone().into_iter().next().is_none());
assert_eq!(0, context.into_iter().len());
}
#[rstest]
#[case(ErrorKind::Level { level: 1, token: Token::ArrBegin }, "level error: level 1 would exceed parser's configured maximum on [")]
#[case(ErrorKind::Level { level: 2, token: Token::ObjBegin }, "level error: level 2 would exceed parser's configured maximum on {")]
#[case(ErrorKind::Lexical(lexical::ErrorKind::Read), "read error")]
#[case(
ErrorKind::Lexical(lexical::ErrorKind::UnexpectedByte { token: Some(Token::LitTrue), expect: lexical::Expect::Char('r'), actual: b'!'}),
"lexical error: expected character 'r' but got character '!' (ASCII 0x21) in true token"
)]
#[case(
ErrorKind::Syntax { context: Context::default(), token: Token::Eof },
"syntax error: expected value but got EOF"
)]
fn test_error_kind_display(#[case] variant: ErrorKind, #[case] expect: &str) {
assert_eq!(expect, variant.to_string());
}
#[test]
fn test_error_no_source() {
let kind = ErrorKind::Syntax {
context: Context::default(),
token: Token::Eof,
};
let err = Error {
kind: kind.clone(),
pos: Pos::default(),
source: None,
};
assert_eq!(kind, *err.kind());
assert_eq!(Pos::default(), *err.pos());
assert!(err.source().is_none());
assert_eq!(
"syntax error: expected value but got EOF at line 1, column 1 (offset: 0)",
err.to_string()
);
}
#[test]
fn test_error_source() {
use crate::lexical::read::{self, ReadAnalyzer};
use std::{error::Error as StdErr, io};
struct ErrRead;
impl std::io::Read for ErrRead {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
Err(io::Error::new(io::ErrorKind::BrokenPipe, "boom"))
}
}
let mut parser = ReadAnalyzer::new(ErrRead).into_parser();
assert_eq!(Token::Err, parser.next());
let err = parser.err();
assert_eq!(ErrorKind::Lexical(lexical::ErrorKind::Read), *err.kind());
assert_eq!(
"read error at line 1, column 1 (offset: 0)",
err.to_string()
);
assert!(err.source().is_some());
assert!(StdErr::source(&err).is_some());
let source = err.source().unwrap();
let read_err = source.downcast_ref::<read::Error>().unwrap();
let source = read_err.source().unwrap();
let io_err = source.downcast_ref::<io::Error>().unwrap();
assert_eq!(io::ErrorKind::BrokenPipe, io_err.kind());
assert_eq!("boom", io_err.to_string());
}
#[test]
fn test_parser_content_new() {
let parser = FixedAnalyzer::new("{}".as_bytes()).into_parser();
assert_eq!("", parser.content().literal());
assert!(!parser.content().is_escaped());
assert_eq!("", parser.content().unescaped());
}
#[test]
#[should_panic(expected = "no content: parser is in error state (use `err()` instead)")]
fn test_parser_content_panic_on_err() {
let mut parser = FixedAnalyzer::new(",".as_bytes()).into_parser();
assert_eq!(Token::Err, parser.next());
let _ = parser.content();
}
#[test]
#[should_panic(
expected = "no error: last `next()` did not return `Token::Err` (use `content()` instead"
)]
fn test_parser_err_panic_on_content() {
let parser = FixedAnalyzer::new("".as_bytes()).into_parser();
let _ = parser.err();
}
#[test]
fn test_parser_set_max_level_inflight_level_less() {
let mut parser = FixedAnalyzer::new("{}".as_bytes()).into_parser();
assert_eq!(Token::ObjBegin, parser.next_meaningful());
assert_eq!(1, parser.level());
assert_eq!(
vec![StructKind::Obj],
parser.context().iter().collect::<Vec<_>>()
);
parser.set_max_level(2);
}
#[test]
fn test_parser_set_max_level_inflight_level_equal() {
let mut parser = FixedAnalyzer::new("[]".as_bytes()).into_parser();
assert_eq!(Token::ArrBegin, parser.next_meaningful());
assert_eq!(1, parser.level());
assert_eq!(
vec![StructKind::Arr],
parser.context().iter().collect::<Vec<_>>()
);
parser.set_max_level(1);
}
#[test]
#[should_panic(expected = "current level 2 exceeds new max level 1")]
fn test_parser_set_max_level_inflight_level_more() {
let mut parser = FixedAnalyzer::new("[{}]".as_bytes()).into_parser();
assert_eq!(Token::ArrBegin, parser.next());
assert_eq!(Token::ObjBegin, parser.next());
assert_eq!(2, parser.level());
assert_eq!(
vec![StructKind::Arr, StructKind::Obj],
parser.context().iter().collect::<Vec<_>>()
);
parser.set_max_level(1);
}
#[test]
fn test_parser_with_max_level() {
let mut parser = Parser::with_max_level(FixedAnalyzer::new("{".as_bytes()), 0);
assert_eq!(Token::Err, parser.next());
assert!(matches!(
parser.err().kind(),
ErrorKind::Level {
level: 1,
token: Token::ObjBegin
}
));
}
#[test]
fn test_parser_into_inner() {
let mut parser = FixedAnalyzer::new("[,".as_bytes()).into_parser();
assert_eq!(Token::ArrBegin, parser.next());
let mut lexer = parser.into_inner();
assert_eq!(Token::ValueSep, lexer.next());
assert_eq!(Token::Eof, lexer.next());
assert_eq!(Token::Eof, lexer.next());
}
#[rstest]
#[case::arr_empty("[]", [(Token::ArrBegin, "["), (Token::ArrEnd, "]")])]
#[case::arr_one("[1]", [(Token::ArrBegin, "["), (Token::Num, "1"), (Token::ArrEnd, "]")])]
#[case::arr_two(r#"["a",null]"#, [(Token::ArrBegin, "["), (Token::Str, r#""a""#), (Token::ValueSep, ","), (Token::LitNull, "null"), (Token::ArrEnd, "]")])]
#[case::arr_three(r#"[[],{},[123]]"#, [(Token::ArrBegin, "["), (Token::ArrBegin, "["), (Token::ArrEnd, "]"), (Token::ValueSep, ","), (Token::ObjBegin, "{"), (Token::ObjEnd, "}"), (Token::ValueSep, ","), (Token::ArrBegin, "["), (Token::Num, "123"), (Token::ArrEnd, "]"), (Token::ArrEnd, "]")])]
#[case::num("-123.4e+5", Some((Token::Num, "-123.4e+5")))]
#[case::lit_false("false", Some((Token::LitFalse, "false")))]
#[case::lit_null("null", Some((Token::LitNull, "null")))]
#[case::lit_true("true", Some((Token::LitTrue, "true")))]
#[case::obj_empty("{}", [(Token::ObjBegin, "{"), (Token::ObjEnd, "}")])]
#[case::obj_one_arr(r#"{"a":[]}"#, [(Token::ObjBegin, "{"), (Token::Str, r#""a""#), (Token::NameSep, ":"), (Token::ArrBegin, "["), (Token::ArrEnd, "]"), (Token::ObjEnd, "}")])]
#[case::obj_one_num(r#"{"a":1}"#, [(Token::ObjBegin, "{"), (Token::Str, r#""a""#), (Token::NameSep, ":"), (Token::Num, "1"), (Token::ObjEnd, "}")])]
#[case::obj_one_lit_false(r#"{"a":false}"#, [(Token::ObjBegin, "{"), (Token::Str, r#""a""#), (Token::NameSep, ":"), (Token::LitFalse, "false"), (Token::ObjEnd, "}")])]
#[case::obj_one_lit_null(r#"{"a":null}"#, [(Token::ObjBegin, "{"), (Token::Str, r#""a""#), (Token::NameSep, ":"), (Token::LitNull, "null"), (Token::ObjEnd, "}")])]
#[case::obj_one_lit_true(r#"{"a":true}"#, [(Token::ObjBegin, "{"), (Token::Str, r#""a""#), (Token::NameSep, ":"), (Token::LitTrue, "true"), (Token::ObjEnd, "}")])]
#[case::obj_one_str(r#"{"a":"b"}"#, [(Token::ObjBegin, "{"), (Token::Str, r#""a""#), (Token::NameSep, ":"), (Token::Str, r#""b""#), (Token::ObjEnd, "}")])]
#[case::obj_two(r#"{"a":null,"b":"c"}"#, [(Token::ObjBegin, "{"), (Token::Str, r#""a""#), (Token::NameSep, ":"), (Token::LitNull, "null"), (Token::ValueSep, ","), (Token::Str, r#""b""#), (Token::NameSep, ":"), (Token::Str, r#""c""#), (Token::ObjEnd, "}")])]
#[case::obj_three(r#"{"a":[],"b":{},"c":{"d":123}}"#, [(Token::ObjBegin, "{"), (Token::Str, r#""a""#), (Token::NameSep, ":"), (Token::ArrBegin, "["), (Token::ArrEnd, "]"), (Token::ValueSep, ","), (Token::Str, r#""b""#), (Token::NameSep, ":"), (Token::ObjBegin, "{"), (Token::ObjEnd, "}"), (Token::ValueSep, ","), (Token::Str, r#""c""#), (Token::NameSep, ":"), (Token::ObjBegin, "{"), (Token::Str, r#""d""#), (Token::NameSep, ":"), (Token::Num, "123"), (Token::ObjEnd, "}"), (Token::ObjEnd, "}")])]
#[case::str(r#""foo""#, Some((Token::Str, r#""foo""#)))]
#[case::white_arr(" [ false ] ", [(Token::White, " "), (Token::ArrBegin, "["), (Token::White, " "), (Token::LitFalse, "false"), (Token::White, " "), (Token::ArrEnd, "]"), (Token::White, " ")])]
#[case::white_lit_false(" false ", [(Token::White, " "), (Token::LitFalse, "false"), (Token::White, " ")])]
#[case::white_lit_null(" null ", [(Token::White, " "), (Token::LitNull, "null"), (Token::White, " ")])]
#[case::white_lit_true(" true ", [(Token::White, " "), (Token::LitTrue, "true"), (Token::White, " ")])]
#[case::white_num(" \n 42 ", [(Token::White, " \n "), (Token::Num, "42"), (Token::White, " ")])]
#[case::white_obj(r#" { "a" : null } "#, [(Token::White, " "), (Token::ObjBegin, "{"), (Token::White, " "), (Token::Str, r#""a""#), (Token::White, " "), (Token::NameSep, ":"), (Token::White, " "), (Token::LitNull, "null"), (Token::White, " "), (Token::ObjEnd, "}"), (Token::White, " ")])]
#[case::white_str(r#" "foo" "#, [(Token::White, " "), (Token::Str, r#""foo""#), (Token::White, " ")])]
fn test_parser_next<I>(#[case] input: &'static str, #[case] expect: I)
where
I: IntoIterator<Item = (Token, &'static str)> + Clone,
{
{
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
for (i, (expect_token, _)) in expect.clone().into_iter().enumerate() {
let actual_token = parser.next();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
}
assert_eq!(Token::Eof, parser.next());
assert_eq!(Token::Eof, parser.next());
assert_eq!(Expect::Eof, parser.context().expect());
assert_eq!(None, parser.context().struct_kind());
}
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
for (i, (expect_token, expect_literal)) in expect.clone().into_iter().enumerate() {
let actual_token = parser.next();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
let actual_content = parser.content();
let actual_literal = actual_content.literal();
assert_eq!(expect_literal, actual_literal);
}
assert_eq!(Token::Eof, parser.next());
assert_eq!(Token::Eof, parser.next());
assert_eq!(Expect::Eof, parser.context().expect());
assert_eq!(None, parser.context().struct_kind());
}
}
{
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
for (i, (expect_token, _)) in expect
.clone()
.into_iter()
.enumerate()
.filter(|(_, (t, _))| *t != Token::White)
{
let actual_token = parser.next_non_white();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
}
assert_eq!(Token::Eof, parser.next_non_white());
assert_eq!(Token::Eof, parser.next_non_white());
assert_eq!(Expect::Eof, parser.context().expect());
assert_eq!(None, parser.context().struct_kind());
}
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
for (i, (expect_token, expect_literal)) in expect
.clone()
.into_iter()
.enumerate()
.filter(|(_, (t, _))| *t != Token::White)
{
let actual_token = parser.next_non_white();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
let actual_content = parser.content();
let actual_literal = actual_content.literal();
assert_eq!(expect_literal, actual_literal);
}
assert_eq!(Token::Eof, parser.next_non_white());
assert_eq!(Token::Eof, parser.next_non_white());
assert_eq!(Expect::Eof, parser.context().expect());
assert_eq!(None, parser.context().struct_kind());
}
}
{
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
for (i, (expect_token, _)) in expect
.clone()
.into_iter()
.enumerate()
.filter(|(_, (t, _))| *t != Token::White && !t.is_punct())
{
let actual_token = parser.next_meaningful();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
}
assert_eq!(Token::Eof, parser.next_meaningful());
assert_eq!(Token::Eof, parser.next_meaningful());
}
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
for (i, (expect_token, expect_literal)) in expect
.clone()
.into_iter()
.enumerate()
.filter(|(_, (t, _))| *t != Token::White && !t.is_punct())
{
let actual_token = parser.next_meaningful();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
let actual_content = parser.content();
let actual_literal = actual_content.literal();
assert_eq!(expect_literal, actual_literal);
}
assert_eq!(Token::Eof, parser.next_meaningful());
assert_eq!(Token::Eof, parser.next_meaningful());
}
}
}
#[rstest]
#[case::arr_empty("[]")]
#[case::arr_single("[false]")]
#[case::arr_multiple("[1, -2, true]")]
#[case::arr_nested_empty("[[]]")]
#[case::arr_nested_single("[[1]]")]
#[case::lit("null")]
#[case::obj_empty("{}")]
#[case::obj_single(r#"{"a":1}"#)]
#[case::obj_multiple(r#"{"a":1, "bb":22}"#)]
#[case::obj_nested_empty(r#"{"a":{}}"#)]
#[case::obj_nested_single(r#"{"a":{"b":["c"]}}"#)]
#[case::num("1")]
#[case::str(r#""a""#)]
fn test_parser_next_end_root(#[case] input: &str) {
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
assert_eq!(Token::Eof, parser.next_end());
assert_eq!(0, parser.level());
assert_eq!(Token::Eof, parser.next());
assert_eq!(Expect::Eof, parser.context().expect());
assert_eq!(None, parser.context().struct_kind());
}
#[rstest]
#[case("[]", [Token::ArrBegin], Token::ArrEnd, 0, Token::Eof)]
#[case("[1]", [Token::ArrBegin], Token::ArrEnd, 0, Token::Eof)]
#[case("[1]", [Token::ArrBegin, Token::Num], Token::ArrEnd, 0, Token::Eof)]
#[case("[[]]", [Token::ArrBegin], Token::ArrEnd, 0, Token::Eof)]
#[case("[[]]", [Token::ArrBegin, Token::ArrBegin], Token::ArrEnd, 1, Token::ArrEnd)]
#[case("{}", [Token::ObjBegin], Token::ObjEnd, 0, Token::Eof)]
#[case(r#"{"a":1}"#, [Token::ObjBegin], Token::ObjEnd, 0, Token::Eof)]
#[case(r#"{"a":1}"#, [Token::ObjBegin, Token::Str], Token::ObjEnd, 0, Token::Eof)]
#[case(r#"{"a":1}"#, [Token::ObjBegin, Token::Str, Token::NameSep], Token::ObjEnd, 0, Token::Eof)]
#[case(r#"{"a":1}"#, [Token::ObjBegin, Token::Str, Token::NameSep, Token::Num], Token::ObjEnd, 0, Token::Eof)]
#[case(r#"{"a":{}}"#, [Token::ObjBegin, Token::Str, Token::NameSep], Token::ObjEnd, 0, Token::Eof)]
#[case(r#"{"a":{}}"#, [Token::ObjBegin, Token::Str, Token::NameSep, Token::ObjBegin], Token::ObjEnd, 1, Token::ObjEnd)]
fn test_parser_next_end_inside<I>(
#[case] input: &str,
#[case] leading_tokens: I,
#[case] expect_token: Token,
#[case] expect_level: usize,
#[case] expect_next: Token,
) where
I: IntoIterator<Item = Token>,
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
for (i, leading_token) in leading_tokens.into_iter().enumerate() {
let actual_token = parser.next();
assert_eq!(
leading_token, actual_token,
"expected leading token {i} to be {leading_token}, but it was {actual_token}"
);
}
assert_eq!(expect_token, parser.next_end());
assert_eq!(expect_level, parser.level());
assert_eq!(expect_next, parser.next());
}
#[rstest]
#[case::arr_max_level_0("[", 0, None::<Token>, Token::ArrBegin)]
#[case::arr_max_level_1("[[", 1, [Token::ArrBegin], Token::ArrBegin)]
#[case::arr_max_level_2("[[[", 2, [Token::ArrBegin, Token::ArrBegin], Token::ArrBegin)]
#[case::obj_max_level_0("{", 0, None::<Token>, Token::ObjBegin)]
#[case::obj_max_level_1(r#"{"a":{"#, 1, [Token::ObjBegin, Token::Str], Token::ObjBegin)]
#[case::obj_max_level_2(r#"{"a":{"b":{"#, 2, [Token::ObjBegin, Token::Str, Token::ObjBegin, Token::Str], Token::ObjBegin)]
#[case::mixed(r#"[null, {"a":1}, [true, {"b":[null]}]]"#, 3, [Token::ArrBegin, Token::LitNull, Token::ObjBegin, Token::Str, Token::Num, Token::ObjEnd, Token::ArrBegin, Token::LitTrue, Token::ObjBegin, Token::Str], Token::ArrBegin)]
fn test_parser_err_level<I>(
#[case] input: &str,
#[case] max_level: usize,
#[case] leading_tokens: I,
#[case] trigger_token: Token,
) where
I: IntoIterator<Item = Token>,
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
parser.set_max_level(max_level);
assert_eq!(max_level, parser.max_level());
for (i, expect_token) in leading_tokens.into_iter().enumerate() {
let actual_token = parser.next_meaningful();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
}
assert_eq!(Token::Err, parser.next_meaningful());
let err = parser.err();
let err_kind = err.kind();
assert!(
matches!(err_kind, ErrorKind::Level { level, token } if *level == max_level + 1 && *token == trigger_token),
"err_kind: {err_kind:?}"
);
assert_eq!(Token::Err, parser.next());
}
#[rstest]
#[case::expect_arr_element_or_end("[_", [Token::ArrBegin], lexical::ErrorKind::UnexpectedByte { token: None, expect: lexical::Expect::TokenStartChar, actual: b'_' })]
#[case::expect_arr_element_sep_or_end("[1 _", [Token::ArrBegin, Token::Num], lexical::ErrorKind::UnexpectedByte { token: None, expect: lexical::Expect::TokenStartChar, actual: b'_' })]
#[case::expect_eof("true \"", [Token::LitTrue], lexical::ErrorKind::UnexpectedEof(Token::Str))]
#[case::expect_obj_name(r#"{"a":"b",""#, [Token::ObjBegin, Token::Str, Token::Str], lexical::ErrorKind::UnexpectedEof(Token::Str))]
#[case::expect_obj_name_or_end("{1b", [Token::ObjBegin], lexical::ErrorKind::UnexpectedByte { token: Some(Token::Num), expect: lexical::Expect::DigitDotExpOrBoundary, actual: b'b' })]
#[case::expect_obj_name_sep(r#"{"a"n"#, [Token::ObjBegin, Token::Str], lexical::ErrorKind::UnexpectedEof(Token::LitNull))]
#[case::expect_value_root("1x", None::<Token>, lexical::ErrorKind::UnexpectedByte { token: Some(Token::Num), expect: lexical::Expect::DigitDotExpOrBoundary, actual: b'x' })]
#[case::expect_value_arr_element("[1,t", [Token::ArrBegin, Token::Num], lexical::ErrorKind::UnexpectedEof(Token::LitTrue))]
#[case::expect_value_obj_member(r#"{"a":n"#, [Token::ObjBegin, Token::Str], lexical::ErrorKind::UnexpectedEof(Token::LitNull))]
fn test_parser_err_lexical<I>(
#[case] input: &str,
#[case] leading_tokens: I,
#[case] expect_kind: lexical::ErrorKind,
) where
I: IntoIterator<Item = Token>,
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
for (i, expect_token) in leading_tokens.into_iter().enumerate() {
let actual_token = parser.next_meaningful();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
}
assert_eq!(Token::Err, parser.next_meaningful());
let err = parser.err();
let err_kind = err.kind();
assert!(
matches!(err_kind, ErrorKind::Lexical(actual_kind) if *actual_kind == expect_kind),
"err_kind: {err_kind:?}"
);
assert_eq!(Token::Err, parser.next());
}
#[rstest]
#[case::expect_arr_element_or_end_eof("[", [Token::ArrBegin], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementOrEnd), Token::Eof)]
#[case::expect_arr_element_or_end_name_sep("[:", [Token::ArrBegin], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementOrEnd), Token::NameSep)]
#[case::expect_arr_element_or_end_obj_end("[}", [Token::ArrBegin], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementOrEnd), Token::ObjEnd)]
#[case::expect_arr_element_or_end_value_sep("[,", [Token::ArrBegin], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementOrEnd), Token::ValueSep)]
#[case::expect_arr_element_sep_or_end_arr_begin(r#"[1,"a"["#, [Token::ArrBegin, Token::Num, Token::Str], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::ArrBegin)]
#[case::expect_arr_element_sep_or_end_eof("[1,2", [Token::ArrBegin, Token::Num, Token::Num], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::Eof)]
#[case::expect_arr_element_sep_or_end_lit_false("[1,[]false", [Token::ArrBegin, Token::Num, Token::ArrBegin, Token::ArrEnd], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::LitFalse)]
#[case::expect_arr_element_sep_or_end_lit_null("[1,{}null", [Token::ArrBegin, Token::Num, Token::ObjBegin, Token::ObjEnd], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::LitNull)]
#[case::expect_arr_element_sep_or_end_lit_true(r#"[1,"a"true"#, [Token::ArrBegin, Token::Num, Token::Str], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::LitTrue)]
#[case::expect_arr_element_sep_or_end_name_sep("[1,null:", [Token::ArrBegin, Token::Num, Token::LitNull], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::NameSep)]
#[case::expect_arr_element_sep_or_end_lit_true(r#"[1,"a"2"#, [Token::ArrBegin, Token::Num, Token::Str], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::Num)]
#[case::expect_arr_element_sep_or_end_obj_begin(r#"[1,true{"#, [Token::ArrBegin, Token::Num, Token::LitTrue], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::ObjBegin)]
#[case::expect_arr_element_sep_or_end_obj_end(r#"[[],1}"#, [Token::ArrBegin, Token::ArrBegin, Token::ArrEnd, Token::Num], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::ObjEnd)]
#[case::expect_arr_element_sep_or_end_str(r#"[1,false"a"}"#, [Token::ArrBegin, Token::Num, Token::LitFalse], Context::with_struct([StructKind::Arr]).and_expect(Expect::ArrElementSepOrEnd), Token::Str)]
#[case::expect_eof_arr_begin(r#"1["#, [Token::Num], Context::with_expect(Expect::Eof), Token::ArrBegin)]
#[case::expect_eof_arr_end(r#""foo"]"#, [Token::Str], Context::with_expect(Expect::Eof), Token::ArrEnd)]
#[case::expect_eof_lit_false("1 false", [Token::Num], Context::with_expect(Expect::Eof), Token::LitFalse)]
#[case::expect_eof_lit_null("[]null", [Token::ArrBegin, Token::ArrEnd], Context::with_expect(Expect::Eof), Token::LitNull)]
#[case::expect_eof_lit_true("{}true", [Token::ObjBegin, Token::ObjEnd], Context::with_expect(Expect::Eof), Token::LitTrue)]
#[case::expect_eof_name_sep("1:", [Token::Num], Context::with_expect(Expect::Eof), Token::NameSep)]
#[case::expect_eof_num("null -1", [Token::LitNull], Context::with_expect(Expect::Eof), Token::Num)]
#[case::expect_eof_obj_begin("[]{", [Token::ArrBegin, Token::ArrEnd], Context::with_expect(Expect::Eof), Token::ObjBegin)]
#[case::expect_eof_obj_end("{}}", [Token::ObjBegin, Token::ObjEnd], Context::with_expect(Expect::Eof), Token::ObjEnd)]
#[case::expect_eof_num(r#"0 "baz""#, [Token::Num], Context::with_expect(Expect::Eof), Token::Str)]
#[case::expect_eof_name_sep("[],", [Token::ArrBegin, Token::ArrEnd], Context::with_expect(Expect::Eof), Token::ValueSep)]
#[case::expect_obj_name_arr_begin(r#"{"a":"b",["#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::ArrBegin)]
#[case::expect_obj_name_arr_end(r#"{"a":"b",]"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::ArrEnd)]
#[case::expect_obj_name_eof(r#"{"a":"b","#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::Eof)]
#[case::expect_obj_name_lit_false(r#"{"a":"b",false"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::LitFalse)]
#[case::expect_obj_name_lit_null(r#"{"a":"b",null"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::LitNull)]
#[case::expect_obj_name_lit_true(r#"{"a":"b",true"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::LitTrue)]
#[case::expect_obj_name_name_sep(r#"{"a":"b",:"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::NameSep)]
#[case::expect_obj_name_num(r#"{"a":"b",1"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::Num)]
#[case::expect_obj_name_obj_begin(r#"{"a":"b",{"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::ObjBegin)]
#[case::expect_obj_name_obj_end(r#"{"a":"b",}"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::ObjEnd)]
#[case::expect_obj_name_value_sep(r#"{"a":"b",,"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjName), Token::ValueSep)]
#[case::expect_obj_name_or_end_arr_begin(r#"{["#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::ArrBegin)]
#[case::expect_obj_name_or_end_arr_end(r#"{]"#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::ArrEnd)]
#[case::expect_obj_name_or_end_eof(r#"{"#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::Eof)]
#[case::expect_obj_name_or_end_lit_false(r#"{false"#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::LitFalse)]
#[case::expect_obj_name_or_end_lit_null(r#"{null"#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::LitNull)]
#[case::expect_obj_name_or_end_lit_true(r#"{true"#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::LitTrue)]
#[case::expect_obj_name_or_end_name_sep(r#"{:"#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::NameSep)]
#[case::expect_obj_name_or_end_num(r#"{1"#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::Num)]
#[case::expect_obj_name_or_end_obj_begin(r#"{{"#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::ObjBegin)]
#[case::expect_obj_name_or_end_value_sep(r#"{,"#, [Token::ObjBegin], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameOrEnd), Token::ValueSep)]
#[case::expect_obj_name_sep_arr_begin(r#"{"a"["#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::ArrBegin)]
#[case::expect_obj_name_sep_arr_end(r#"{"a"]"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::ArrEnd)]
#[case::expect_obj_name_sep_eof(r#"{"a""#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::Eof)]
#[case::expect_obj_name_sep_lit_false(r#"{"a"false"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::LitFalse)]
#[case::expect_obj_name_sep_lit_null(r#"{"a"null"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::LitNull)]
#[case::expect_obj_name_sep_lit_true(r#"{"a"true"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::LitTrue)]
#[case::expect_obj_name_sep_num(r#"{"a"1"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::Num)]
#[case::expect_obj_name_sep_obj_begin(r#"{"a"{"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::ObjBegin)]
#[case::expect_obj_name_sep_obj_end(r#"{"a"}"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::ObjEnd)]
#[case::expect_obj_name_sep_str(r#"{"a""b""#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::Str)]
#[case::expect_obj_name_sep_value_sep(r#"{"a","#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjNameSep), Token::ValueSep)]
#[case::expect_obj_value_sep_or_end_arr_begin(r#"{"a":false["#, [Token::ObjBegin, Token::Str, Token::LitFalse], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::ArrBegin)]
#[case::expect_obj_value_sep_or_end_arr_end(r#"{"a":1]"#, [Token::ObjBegin, Token::Str, Token::Num], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::ArrEnd)]
#[case::expect_obj_value_sep_or_end_eof(r#"{"a":null"#, [Token::ObjBegin, Token::Str, Token::LitNull], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::Eof)]
#[case::expect_obj_value_sep_or_end_lit_false(r#"{"a":"b" false"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::LitFalse)]
#[case::expect_obj_value_sep_or_end_lit_null(r#"{"a":true null"#, [Token::ObjBegin, Token::Str, Token::LitTrue], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::LitNull)]
#[case::expect_obj_value_sep_or_end_lit_true(r#"{"a":{}true"#, [Token::ObjBegin, Token::Str, Token::ObjBegin, Token::ObjEnd], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::LitTrue)]
#[case::expect_obj_value_sep_or_end_name_sep(r#"{"a":"b":"#, [Token::ObjBegin, Token::Str, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::NameSep)]
#[case::expect_obj_value_sep_or_end_num(r#"{"a":[]1"#, [Token::ObjBegin, Token::Str, Token::ArrBegin, Token::ArrEnd], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::Num)]
#[case::expect_obj_value_sep_or_end_obj_begin(r#"{"a":false{"#, [Token::ObjBegin, Token::Str, Token::LitFalse], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::ObjBegin)]
#[case::expect_obj_value_sep_or_end_str(r#"{"a":1"b""#, [Token::ObjBegin, Token::Str, Token::Num], Context::with_struct([StructKind::Obj]).and_expect(Expect::ObjValueSepOrEnd), Token::Str)]
#[case::expect_value_arr_end("]", None::<Token>, Context::default(), Token::ArrEnd)]
#[case::expect_value_eof("", None::<Token>, Context::default(), Token::Eof)]
#[case::expect_value_name_sep(":", None::<Token>, Context::default(), Token::NameSep)]
#[case::expect_value_obj_end("}", None::<Token>, Context::default(), Token::ObjEnd)]
#[case::expect_value_value_sep(",", None::<Token>, Context::default(), Token::ValueSep)]
#[case::expect_value_in_arr_arr_end("[1,]", [Token::ArrBegin, Token::Num], Context::with_struct([StructKind::Arr]).and_expect(Expect::Value), Token::ArrEnd)]
#[case::expect_value_in_arr_eof("[1,", [Token::ArrBegin, Token::Num], Context::with_struct([StructKind::Arr]).and_expect(Expect::Value), Token::Eof)]
#[case::expect_value_in_arr_name_sep("[1,:", [Token::ArrBegin, Token::Num], Context::with_struct([StructKind::Arr]).and_expect(Expect::Value), Token::NameSep)]
#[case::expect_value_in_arr_obj_end("[1,}", [Token::ArrBegin, Token::Num], Context::with_struct([StructKind::Arr]).and_expect(Expect::Value), Token::ObjEnd)]
#[case::expect_value_in_arr_value_sep("[1,,", [Token::ArrBegin, Token::Num], Context::with_struct([StructKind::Arr]).and_expect(Expect::Value), Token::ValueSep)]
#[case::expect_value_in_obj_arr_end(r#"{"a":]"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::Value), Token::ArrEnd)]
#[case::expect_value_in_obj_name_sep(r#"{"a"::"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::Value), Token::NameSep)]
#[case::expect_value_in_obj_obj_end(r#"{"a":}"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::Value), Token::ObjEnd)]
#[case::expect_value_in_obj_value_sep(r#"{"a":,]"#, [Token::ObjBegin, Token::Str], Context::with_struct([StructKind::Obj]).and_expect(Expect::Value), Token::ValueSep)]
fn test_parser_err_syntax<I>(
#[case] input: &str,
#[case] leading_tokens: I,
#[case] expect_context: Context,
#[case] expect_token: Token,
) where
I: IntoIterator<Item = Token> + Clone,
{
{
let mut parser = FixedAnalyzer::new(input.as_bytes()).into_parser();
for (i, expect_token) in leading_tokens.clone().into_iter().enumerate() {
let actual_token = parser.next_meaningful();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
}
assert_eq!(Token::Err, parser.next_meaningful());
let err = parser.err();
let err_kind = err.kind();
assert!(
matches!(err_kind, ErrorKind::Syntax { context, token } if *context == expect_context && *token == expect_token),
"err_kind: {err_kind:?}"
);
assert_eq!(Token::Err, parser.next());
}
{
let mut lexer = FixedAnalyzer::new(input.as_bytes());
let mut buf = Vec::with_capacity(2 * input.len());
buf.push(b' ');
while !lexer.next().is_terminal() {
buf.extend_from_slice(lexer.content().literal().as_bytes());
buf.push(b' ');
}
let mut parser = FixedAnalyzer::new(buf).into_parser();
for (i, expect_token) in leading_tokens.into_iter().enumerate() {
let actual_token = parser.next_meaningful();
assert_eq!(
expect_token, actual_token,
"expected token {i} to be {expect_token} but it was {actual_token}"
);
}
assert_eq!(Token::Err, parser.next_meaningful());
let err = parser.err();
let err_kind = err.kind();
assert!(
matches!(err_kind, ErrorKind::Syntax { context, token } if *context == expect_context && *token == expect_token),
"err_kind: {err_kind:?}"
);
assert_eq!(Token::Err, parser.next());
}
}
#[test]
fn test_parser_smoke() {
const JSON_TEXT: &str = r#"{
"foo":[false,null,true,1,"bar",{},[[]]],
"baz":{"qux":5e-7,"abc\u0020123":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sed ipsum at arcu porta blandit."},
"π":[[null],[true],[1],["γγγ«γ‘γ―γδΈη"],[{},-3.00e+0]]
}"#;
const EXPECT: &[(Token, &str)] = &[
(Token::ObjBegin, "{"),
(Token::White, "\n "),
(Token::Str, r#""foo""#),
(Token::NameSep, ":"),
(Token::ArrBegin, "["),
(Token::LitFalse, "false"),
(Token::ValueSep, ","),
(Token::LitNull, "null"),
(Token::ValueSep, ","),
(Token::LitTrue, "true"),
(Token::ValueSep, ","),
(Token::Num, "1"),
(Token::ValueSep, ","),
(Token::Str, r#""bar""#),
(Token::ValueSep, ","),
(Token::ObjBegin, "{"),
(Token::ObjEnd, "}"),
(Token::ValueSep, ","),
(Token::ArrBegin, "["),
(Token::ArrBegin, "["),
(Token::ArrEnd, "]"),
(Token::ArrEnd, "]"),
(Token::ArrEnd, "]"),
(Token::ValueSep, ","),
(Token::White, "\n "),
(Token::Str, r#""baz""#),
(Token::NameSep, ":"),
(Token::ObjBegin, "{"),
(Token::Str, r#""qux""#),
(Token::NameSep, ":"),
(Token::Num, "5e-7"),
(Token::ValueSep, ","),
(Token::Str, r#""abc\u0020123""#),
(Token::NameSep, ":"),
(
Token::Str,
r#""Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sed ipsum at arcu porta blandit.""#,
),
(Token::ObjEnd, "}"),
(Token::ValueSep, ","),
(Token::White, "\n "),
(Token::Str, r#""π""#),
(Token::NameSep, ":"),
(Token::ArrBegin, "["),
(Token::ArrBegin, "["),
(Token::LitNull, "null"),
(Token::ArrEnd, "]"),
(Token::ValueSep, ","),
(Token::ArrBegin, "["),
(Token::LitTrue, "true"),
(Token::ArrEnd, "]"),
(Token::ValueSep, ","),
(Token::ArrBegin, "["),
(Token::Num, "1"),
(Token::ArrEnd, "]"),
(Token::ValueSep, ","),
(Token::ArrBegin, "["),
(Token::Str, r#""γγγ«γ‘γ―γδΈη""#),
(Token::ArrEnd, "]"),
(Token::ValueSep, ","),
(Token::ArrBegin, "["),
(Token::ObjBegin, "{"),
(Token::ObjEnd, "}"),
(Token::ValueSep, ","),
(Token::Num, "-3.00e+0"),
(Token::ArrEnd, "]"),
(Token::ArrEnd, "]"),
(Token::White, "\n"),
(Token::ObjEnd, "}"),
(Token::Eof, ""),
(Token::Eof, ""),
(Token::Eof, ""),
];
let mut parser = FixedAnalyzer::new(JSON_TEXT.as_bytes()).into_parser();
for (i, (expect_token, expect_literal)) in EXPECT.iter().enumerate() {
let actual_token = parser.next();
let content = parser.content();
assert_eq!(*expect_token, actual_token, "i = {i}, content = {content}");
assert_eq!(
*expect_literal,
content.literal(),
"i = {i}, token = {actual_token}"
);
}
}
}