use chumsky::prelude::*; use crate::{ ast, parser::{error::ParseError, token::Token}, }; use super::function; pub fn parser() -> impl Parser { just(Token::Validator) .ignore_then( function::param(true) .separated_by(just(Token::Comma)) .allow_trailing() .delimited_by(just(Token::LeftParen), just(Token::RightParen)) .map_with_span(|arguments, span| (arguments, span)) .or_not(), ) .then( function() .repeated() .at_least(1) .at_most(2) .delimited_by(just(Token::LeftBrace), just(Token::RightBrace)) .map(|defs| { defs.into_iter().map(|def| { let ast::UntypedDefinition::Fn(fun) = def else { unreachable!("It should be a fn definition"); }; fun }) }), ) .map_with_span(|(opt_extra_params, mut functions), span| { let (params, params_span) = opt_extra_params.unwrap_or(( vec![], ast::Span { start: 0, end: span.start + "validator".len(), }, )); ast::UntypedDefinition::Validator(ast::Validator { doc: None, fun: functions .next() .expect("unwrapping safe because there's 'at_least(1)' function"), other_fun: functions.next(), location: ast::Span { start: span.start, // capture the span from the optional params end: params_span.end, }, params, end_position: span.end - 1, }) }) } #[cfg(test)] mod tests { use crate::assert_definition; #[test] fn validator() { assert_definition!( r#" validator { fn foo(datum, rdmr, ctx) { True } } "# ); } #[test] fn double_validator() { assert_definition!( r#" validator { fn foo(datum, rdmr, ctx) { True } fn bar(rdmr, ctx) { True } } "# ); } }