aiken/crates/aiken-lang/src/parser/definition/validator.rs

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
}
}
"#
);
}
}