2024-10-23 11:01:39 +00:00
|
|
|
use array::array;
|
2024-10-18 12:05:27 +00:00
|
|
|
use enumset::{enum_set, EnumSet};
|
2024-10-29 18:36:32 +00:00
|
|
|
use pawarser::parser::ParserBuilder;
|
2024-10-18 12:05:27 +00:00
|
|
|
|
2024-10-29 18:36:32 +00:00
|
|
|
use crate::{
|
|
|
|
syntax_error::SyntaxError,
|
|
|
|
syntax_kind::{lex, SyntaxKind},
|
|
|
|
};
|
2024-10-18 12:05:27 +00:00
|
|
|
|
|
|
|
use self::object::object;
|
|
|
|
|
2024-10-29 18:36:32 +00:00
|
|
|
mod array;
|
|
|
|
mod object;
|
|
|
|
|
2024-10-21 16:29:46 +00:00
|
|
|
pub(crate) type Parser<'src> = pawarser::Parser<'src, SyntaxKind, SyntaxError>;
|
|
|
|
pub(crate) type CompletedMarker = pawarser::CompletedMarker<SyntaxKind, SyntaxError>;
|
2024-10-18 12:05:27 +00:00
|
|
|
|
|
|
|
const BASIC_VALUE_TOKENS: EnumSet<SyntaxKind> =
|
|
|
|
enum_set!(SyntaxKind::BOOL | SyntaxKind::NULL | SyntaxKind::NUMBER | SyntaxKind::STRING);
|
|
|
|
|
|
|
|
pub fn value(p: &mut Parser) -> bool {
|
|
|
|
if BASIC_VALUE_TOKENS.contains(p.current()) {
|
|
|
|
p.do_bump();
|
|
|
|
return true;
|
|
|
|
} else {
|
2024-10-23 11:01:39 +00:00
|
|
|
object(p).or_else(|| array(p)).is_some()
|
2024-10-18 12:05:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-29 18:36:32 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::{
|
|
|
|
test_utils::{check_parser, gen_checks},
|
|
|
|
value,
|
|
|
|
};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn value_lit() {
|
|
|
|
gen_checks! {value;
|
|
|
|
r#""helo world""# => r#"ROOT { STRING "\"helo world\""; }"#,
|
|
|
|
"42" => r#"ROOT { NUMBER "42"; }"#,
|
|
|
|
"null" => r#"ROOT { NULL "null"; }"#,
|
|
|
|
"true" => r#"ROOT { BOOL "true"; }"#,
|
|
|
|
"false" => r#"ROOT { BOOL "false"; }"#
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test_utils {
|
|
|
|
use pawarser::parser::ParserBuilder;
|
|
|
|
|
|
|
|
use crate::syntax_kind::{lex, SyntaxKind};
|
|
|
|
|
|
|
|
use super::Parser;
|
|
|
|
|
|
|
|
macro_rules! gen_checks {
|
|
|
|
($fn_to_test:ident; $($in:literal => $out:literal),+) => {
|
|
|
|
$(crate::grammar::test_utils::check_parser($in, |p| { $fn_to_test(p); }, $out);)+
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) use gen_checks;
|
|
|
|
|
|
|
|
pub(super) fn check_parser(input: &str, parser_fn: fn(&mut Parser), expected_output: &str) {
|
|
|
|
let toks = lex(input);
|
|
|
|
let mut p: Parser = ParserBuilder::new(toks)
|
|
|
|
.add_meaningless(SyntaxKind::WHITESPACE)
|
|
|
|
.add_meaningless(SyntaxKind::NEWLINE)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
parser_fn(&mut p);
|
|
|
|
|
|
|
|
let out = p.finish();
|
|
|
|
|
|
|
|
assert_eq!(format!("{out:?}").trim_end(), expected_output);
|
|
|
|
}
|
|
|
|
}
|