From e7c1b28b529a5da7fe63dbb209e98c4c896b7abc Mon Sep 17 00:00:00 2001 From: rvcas Date: Wed, 12 Jul 2023 18:29:03 -0400 Subject: [PATCH] feat: add ability to reference validators in tests closes #632 --- CHANGELOG.md | 1 + crates/aiken-lang/src/gen_uplc.rs | 17 +++++ crates/aiken-lang/src/parser/token.rs | 2 +- crates/aiken-project/src/lib.rs | 98 ++++++++++++++++++--------- crates/aiken-project/src/module.rs | 2 +- 5 files changed, 86 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79cde379..719a0bfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - **aiken-lang**: Parsing of error / todo keywords in when cases - **aiken-lang**: Parsing of negative integer patterns and constants - **aiken-lang**: automatically infer unused validator args as `Data` +- **aiken-lang**: test crashing when referencing validators - **aiken**: mem and cpu values were not showing in white terminals, switched to cyan ### Changed diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index 6de17042..27678cb6 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -88,6 +88,23 @@ impl<'a> CodeGenerator<'a> { self.defined_functions = IndexMap::new(); } + pub fn insert_function( + &mut self, + module_name: String, + function_name: String, + variant_name: String, + value: &'a TypedFunction, + ) -> Option<&'a TypedFunction> { + self.functions.insert( + FunctionAccessKey { + module_name, + function_name, + variant_name, + }, + value, + ) + } + pub fn generate( &mut self, TypedValidator { diff --git a/crates/aiken-lang/src/parser/token.rs b/crates/aiken-lang/src/parser/token.rs index 43b25f81..412ed5c3 100644 --- a/crates/aiken-lang/src/parser/token.rs +++ b/crates/aiken-lang/src/parser/token.rs @@ -162,7 +162,7 @@ impl fmt::Display for Token { Token::Fn => "fn", Token::If => "if", Token::Else => "else", - Token::Use => "import", + Token::Use => "use", Token::Let => "let", Token::Opaque => "opaque", Token::Pub => "pub", diff --git a/crates/aiken-project/src/lib.rs b/crates/aiken-project/src/lib.rs index 3f157914..1d1cd62b 100644 --- a/crates/aiken-project/src/lib.rs +++ b/crates/aiken-project/src/lib.rs @@ -16,7 +16,7 @@ mod tests; use crate::blueprint::Blueprint; use aiken_lang::{ - ast::{Definition, Function, ModuleKind, Tracing, TypedDataType, TypedFunction}, + ast::{Definition, Function, ModuleKind, Tracing, TypedDataType, TypedFunction, Validator}, builtins, gen_uplc::builder::{DataTypeKey, FunctionAccessKey}, tipo::TypeInfo, @@ -638,6 +638,7 @@ where tracing: bool, ) -> Result, Error> { let mut scripts = Vec::new(); + let mut testable_validators = Vec::new(); let match_tests = match_tests.map(|mt| { mt.into_iter() @@ -669,46 +670,86 @@ where } for def in checked_module.ast.definitions() { - if let Definition::Test(func) = def { - if let Some(match_tests) = &match_tests { - let is_match = match_tests.iter().any(|(module, names)| { - let matched_module = - module.is_empty() || checked_module.name.contains(module); + match def { + Definition::Validator(Validator { + params, + fun, + other_fun, + .. + }) => { + let mut fun = fun.clone(); - let matched_name = match names { - None => true, - Some(names) => names.iter().any(|name| { - if exact_match { - name == &func.name - } else { - func.name.contains(name) - } - }), - }; + fun.arguments = params.clone().into_iter().chain(fun.arguments).collect(); - matched_module && matched_name - }); + testable_validators.push((&checked_module.name, fun)); - if is_match { + if let Some(other) = other_fun { + let mut other = other.clone(); + + other.arguments = + params.clone().into_iter().chain(other.arguments).collect(); + + testable_validators.push((&checked_module.name, other)); + } + } + Definition::Test(func) => { + if let Some(match_tests) = &match_tests { + let is_match = match_tests.iter().any(|(module, names)| { + let matched_module = + module.is_empty() || checked_module.name.contains(module); + + let matched_name = match names { + None => true, + Some(names) => names.iter().any(|name| { + if exact_match { + name == &func.name + } else { + func.name.contains(name) + } + }), + }; + + matched_module && matched_name + }); + + if is_match { + scripts.push(( + checked_module.input_path.clone(), + checked_module.name.clone(), + func, + )) + } + } else { scripts.push(( checked_module.input_path.clone(), checked_module.name.clone(), func, )) } - } else { - scripts.push(( - checked_module.input_path.clone(), - checked_module.name.clone(), - func, - )) } + _ => (), } } } let mut programs = Vec::new(); + let mut generator = self.checked_modules.new_generator( + &self.functions, + &self.data_types, + &self.module_types, + tracing, + ); + + for (module_name, testable_validator) in &testable_validators { + generator.insert_function( + module_name.to_string(), + testable_validator.name.clone(), + String::new(), + testable_validator, + ); + } + for (input_path, module_name, func_def) in scripts { let Function { name, @@ -724,13 +765,6 @@ where }) } - let mut generator = self.checked_modules.new_generator( - &self.functions, - &self.data_types, - &self.module_types, - tracing, - ); - let evaluation_hint = func_def.test_hint().map(|(bin_op, left_src, right_src)| { let left = generator .clone() diff --git a/crates/aiken-project/src/module.rs b/crates/aiken-project/src/module.rs index 1a39cf8f..a1e0915a 100644 --- a/crates/aiken-project/src/module.rs +++ b/crates/aiken-project/src/module.rs @@ -335,7 +335,7 @@ impl CheckedModules { Definition::TypeAlias(_) | Definition::ModuleConstant(_) | Definition::Test(_) - | Definition::Validator { .. } + | Definition::Validator(_) | Definition::Use(_) => {} } }