feat: implement new validator parsing

This commit is contained in:
rvcas 2024-07-18 17:50:36 -04:00 committed by KtorZ
parent c98e32d3e9
commit 0de5cbc74e
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
3 changed files with 148 additions and 74 deletions

View File

@ -541,10 +541,11 @@ pub type UntypedValidator = Validator<(), UntypedArg, UntypedExpr>;
pub struct Validator<T, Arg, Expr> {
pub doc: Option<String>,
pub end_position: usize,
pub fun: Function<T, Expr, Arg>,
pub other_fun: Option<Function<T, Expr, Arg>>,
pub handlers: Vec<Function<T, Expr, Arg>>,
pub location: Span,
pub name: String,
pub params: Vec<Arg>,
pub fallback: Function<T, Expr, Arg>,
}
impl TypedValidator {
@ -552,12 +553,12 @@ impl TypedValidator {
self.params
.iter()
.find_map(|arg| arg.find_node(byte_index))
.or_else(|| self.fun.find_node(byte_index))
.or_else(|| {
self.other_fun
.as_ref()
.and_then(|f| f.find_node(byte_index))
self.handlers
.iter()
.find_map(|func| func.find_node(byte_index))
})
.or_else(|| self.fallback.find_node(byte_index))
}
pub fn into_function_definition<'a, F>(
@ -568,27 +569,28 @@ impl TypedValidator {
where
F: Fn(&'a TypedFunction, Option<&'a TypedFunction>) -> Option<&'a TypedFunction> + 'a,
{
match select(&self.fun, self.other_fun.as_ref()) {
None => None,
Some(fun) => {
let mut fun = fun.clone();
// match select(&self.fun, self.other_fun.as_ref()) {
// None => None,
// Some(fun) => {
// let mut fun = fun.clone();
fun.arguments = self
.params
.clone()
.into_iter()
.chain(fun.arguments)
.collect();
// fun.arguments = self
// .params
// .clone()
// .into_iter()
// .chain(fun.arguments)
// .collect();
Some((
FunctionAccessKey {
module_name: module_name.to_string(),
function_name: fun.name.clone(),
},
fun,
))
}
}
// Some((
// FunctionAccessKey {
// module_name: module_name.to_string(),
// function_name: fun.name.clone(),
// },
// fun,
// ))
// }
// }
todo!()
}
}

View File

@ -236,11 +236,11 @@ impl<'comments> Formatter<'comments> {
Definition::Validator(Validator {
end_position,
fun,
other_fun,
handlers,
fallback,
params,
..
}) => self.definition_validator(params, fun, other_fun, *end_position),
}) => self.definition_validator(params, handlers, fallback, *end_position),
Definition::Test(Function {
name,
@ -582,8 +582,8 @@ impl<'comments> Formatter<'comments> {
fn definition_validator<'a>(
&mut self,
params: &'a [UntypedArg],
fun: &'a UntypedFunction,
other_fun: &'a Option<UntypedFunction>,
handlers: &'a [UntypedFunction],
fallback: &'a UntypedFunction,
end_position: usize,
) -> Document<'a> {
// validator(params)

View File

@ -1,66 +1,117 @@
use chumsky::prelude::*;
use crate::{
ast,
parser::{error::ParseError, token::Token},
ast::{self, ArgBy, ArgName},
expr::UntypedExpr,
parser::{annotation, error::ParseError, expr, token::Token},
};
use super::function;
use super::function::param;
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
just(Token::Validator)
.ignore_then(
function::param(true)
.ignore_then(select! {Token::Name {name} => name})
.then(
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(),
)
// so far: validator my_validator(arg1: Whatever)
.then(
function()
select! {Token::Name {name} => name}
.then(args_and_body())
.map(|(name, mut function)| {
function.name = name;
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
})
}),
.then(just(Token::Else).ignore_then(args_and_body()).or_not())
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
)
.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(),
},
));
.map_with_span(
|((name, opt_extra_params), (handlers, opt_catch_all)), span| {
let (params, params_span) = opt_extra_params.unwrap_or((
vec![],
ast::Span {
start: 0,
end: span.start + "validator".len(),
},
));
let fun = functions
.next()
.expect("unwrapping safe because there's 'at_least(1)' function");
ast::UntypedDefinition::Validator(ast::Validator {
doc: None,
name,
handlers,
location: ast::Span {
start: span.start,
// capture the span from the optional params
end: params_span.end,
},
params,
end_position: span.end - 1,
fallback: opt_catch_all.unwrap_or(ast::Function {
arguments: vec![ast::UntypedArg {
by: ArgBy::ByName(ArgName::Discarded {
name: "_ctx".to_string(),
label: "_ctx".to_string(),
location: ast::Span::empty(),
}),
location: ast::Span::empty(),
annotation: None,
doc: None,
is_validator_param: false,
}],
body: UntypedExpr::fail(None, ast::Span::empty()),
doc: None,
location: ast::Span::empty(),
end_position: span.end - 1,
name: "fallback".to_string(),
public: true,
return_annotation: None,
return_type: (),
on_test_failure: ast::OnTestFailure::FailImmediately,
}),
})
},
)
}
let other_fun = functions.next();
ast::UntypedDefinition::Validator(ast::Validator {
pub fn args_and_body() -> impl Parser<Token, ast::UntypedFunction, Error = ParseError> {
param(false)
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
.map_with_span(|arguments, span| (arguments, span))
.then(just(Token::RArrow).ignore_then(annotation()).or_not())
.then(
expr::sequence()
.or_not()
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
)
.map_with_span(
|(((arguments, args_span), return_annotation), body), span| ast::Function {
arguments,
body: body.unwrap_or_else(|| UntypedExpr::todo(None, span)),
doc: None,
fun,
other_fun,
location: ast::Span {
start: span.start,
// capture the span from the optional params
end: params_span.end,
end: return_annotation
.as_ref()
.map(|l| l.location().end)
.unwrap_or_else(|| args_span.end),
},
params,
end_position: span.end - 1,
})
})
name: "temp".to_string(),
public: true,
return_annotation,
return_type: (),
on_test_failure: ast::OnTestFailure::FailImmediately,
},
)
}
#[cfg(test)]
@ -71,8 +122,8 @@ mod tests {
fn validator() {
assert_definition!(
r#"
validator {
fn foo(datum, rdmr, ctx) {
validator hello {
spend (datum, rdmr, ctx) {
True
}
}
@ -84,16 +135,37 @@ mod tests {
fn double_validator() {
assert_definition!(
r#"
validator {
fn foo(datum, rdmr, ctx) {
validator thing {
spend (datum, rdmr, ctx) {
True
}
fn bar(rdmr, ctx) {
mint (rdmr, ctx) {
True
}
}
"#
);
}
#[test]
fn fallback() {
assert_definition!(
r#"
validator thing {
spend (datum, rdmr, ctx) {
True
}
mint (rdmr, ctx) {
True
}
else (_) {
fail
}
}
"#
);
}
}