From 0de5cbc74e5d222c15f2fe23d4f0484f4bc88faa Mon Sep 17 00:00:00 2001 From: rvcas Date: Thu, 18 Jul 2024 17:50:36 -0400 Subject: [PATCH] feat: implement new validator parsing --- crates/aiken-lang/src/ast.rs | 52 +++--- crates/aiken-lang/src/format.rs | 10 +- .../src/parser/definition/validator.rs | 160 +++++++++++++----- 3 files changed, 148 insertions(+), 74 deletions(-) diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index f3b0782d..cb84c368 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -541,10 +541,11 @@ pub type UntypedValidator = Validator<(), UntypedArg, UntypedExpr>; pub struct Validator { pub doc: Option, pub end_position: usize, - pub fun: Function, - pub other_fun: Option>, + pub handlers: Vec>, pub location: Span, + pub name: String, pub params: Vec, + pub fallback: Function, } 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!() } } diff --git a/crates/aiken-lang/src/format.rs b/crates/aiken-lang/src/format.rs index 0952e099..544f181e 100644 --- a/crates/aiken-lang/src/format.rs +++ b/crates/aiken-lang/src/format.rs @@ -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, + handlers: &'a [UntypedFunction], + fallback: &'a UntypedFunction, end_position: usize, ) -> Document<'a> { // validator(params) diff --git a/crates/aiken-lang/src/parser/definition/validator.rs b/crates/aiken-lang/src/parser/definition/validator.rs index cc54dbb4..dd5b46d9 100644 --- a/crates/aiken-lang/src/parser/definition/validator.rs +++ b/crates/aiken-lang/src/parser/definition/validator.rs @@ -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 { 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 { + 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 + } + } + "# + ); + } }