96 lines
2.5 KiB
Rust
96 lines
2.5 KiB
Rust
use chumsky::prelude::*;
|
|
|
|
use crate::{
|
|
ast,
|
|
parser::{error::ParseError, token::Token},
|
|
};
|
|
|
|
use super::function;
|
|
|
|
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
|
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
|
|
}
|
|
}
|
|
"#
|
|
);
|
|
}
|
|
}
|