use array::array; use enumset::{enum_set, EnumSet}; use pawarser::parser::ParserBuilder; use crate::{ syntax_error::SyntaxError, syntax_kind::{lex, SyntaxKind}, }; use self::object::object; mod array; mod object; pub(crate) type Parser<'src> = pawarser::Parser<'src, SyntaxKind, SyntaxError>; pub(crate) type CompletedMarker = pawarser::CompletedMarker; const BASIC_VALUE_TOKENS: EnumSet = 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 { object(p).or_else(|| array(p)).is_some() } } #[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); } }