From 32b02009662313ebab908ac89dac849581071339 Mon Sep 17 00:00:00 2001 From: Kasey White Date: Tue, 14 Feb 2023 20:49:40 -0500 Subject: [PATCH] fixes: tuple clauses, zero args funcs, list clause named pattern List Clauses patterns handle var cases Fixed Tuple Clauses issue with last clause not being a tuple Redid how zero arg functions and dependencies are handled. Tough one lol --- crates/aiken-lang/src/builder.rs | 40 ++++---- crates/aiken-lang/src/uplc.rs | 113 ++++++++++++++++----- examples/acceptance_tests/055/aiken.lock | 4 +- examples/acceptance_tests/055/aiken.toml | 2 +- examples/acceptance_tests/055/lib/tests.ak | 109 +++++--------------- 5 files changed, 131 insertions(+), 137 deletions(-) diff --git a/crates/aiken-lang/src/builder.rs b/crates/aiken-lang/src/builder.rs index 8dc19a44..cf9ec97a 100644 --- a/crates/aiken-lang/src/builder.rs +++ b/crates/aiken-lang/src/builder.rs @@ -31,6 +31,7 @@ pub struct FuncComponents { pub dependencies: Vec, pub args: Vec, pub recursive: bool, + pub defined_by_zero_arg: bool, } #[derive(Clone, Eq, Debug, PartialEq, Hash)] @@ -1862,8 +1863,7 @@ pub fn handle_func_dependencies_ir( dependency_vec.reverse(); while let Some(dependency) = dependency_vec.pop() { - if (defined_functions.contains_key(&dependency) && !funt_comp.args.is_empty()) - || func_components.get(&dependency).is_none() + if defined_functions.contains_key(&dependency) || func_components.get(&dependency).is_none() { continue; } @@ -1874,31 +1874,27 @@ pub fn handle_func_dependencies_ir( if get_common_ancestor(dep_scope, func_scope) == func_scope.to_vec() || funt_comp.args.is_empty() { - // we handle zero arg functions and their dependencies in a unique way - if !depend_comp.args.is_empty() { - let mut recursion_ir = vec![]; - handle_recursion_ir(&dependency, depend_comp, &mut recursion_ir); + let mut recursion_ir = vec![]; + handle_recursion_ir(&dependency, depend_comp, &mut recursion_ir); - let mut temp_ir = vec![Air::DefineFunc { - scope: func_scope.to_vec(), - func_name: dependency.function_name.clone(), - module_name: dependency.module_name.clone(), - params: depend_comp.args.clone(), - recursive: depend_comp.recursive, - variant_name: dependency.variant_name.clone(), - }]; + let mut temp_ir = vec![Air::DefineFunc { + scope: func_scope.to_vec(), + func_name: dependency.function_name.clone(), + module_name: dependency.module_name.clone(), + params: depend_comp.args.clone(), + recursive: depend_comp.recursive, + variant_name: dependency.variant_name.clone(), + }]; - temp_ir.append(&mut recursion_ir); + temp_ir.append(&mut recursion_ir); - temp_ir.append(dependencies_ir); + temp_ir.append(dependencies_ir); - *dependencies_ir = temp_ir; - if get_common_ancestor(dep_scope, func_scope) == func_scope.to_vec() { - defined_functions.insert(dependency, ()); - } + *dependencies_ir = temp_ir; + if get_common_ancestor(dep_scope, func_scope) == func_scope.to_vec() { + defined_functions.insert(dependency, ()); } - } else { - // Dependency will need to be defined somewhere in the main body + } else if depend_comp.args.is_empty() { to_be_defined.insert(dependency, ()); } } diff --git a/crates/aiken-lang/src/uplc.rs b/crates/aiken-lang/src/uplc.rs index 61a1faf2..e326c487 100644 --- a/crates/aiken-lang/src/uplc.rs +++ b/crates/aiken-lang/src/uplc.rs @@ -411,7 +411,7 @@ impl<'a> CodeGenerator<'a> { final_scope.push(self.id_gen.next()); - if !matches!(clause_properties, ClauseProperties::TupleClause { .. }) { + if !matches!(last_pattern, Pattern::Tuple { .. }) { pattern_vec.push(Air::Finally { scope: final_scope.clone(), }); @@ -773,8 +773,14 @@ impl<'a> CodeGenerator<'a> { let current_clause_index = if let Pattern::List { elements, .. } = &clause.pattern[0] { elements.len() + } else if let Pattern::Assign { pattern, .. } = &clause.pattern[0] { + if let Pattern::List { elements, .. } = pattern.as_ref() { + elements.len() + } else { + unreachable!("{:#?}", pattern) + } } else { - unreachable!() + unreachable!("{:#?}", &clause.pattern[0]) }; let prev_index = *current_index; @@ -801,6 +807,14 @@ impl<'a> CodeGenerator<'a> { &clauses[index + 1].pattern[0] { elements.len() + } else if let Pattern::Assign { pattern, .. } = + &clauses[index + 1].pattern[0] + { + if let Pattern::List { elements, .. } = pattern.as_ref() { + elements.len() + } else { + unreachable!("{:#?}", pattern) + } } else { unreachable!() }; @@ -2755,33 +2769,55 @@ impl<'a> CodeGenerator<'a> { let recursion_func_map = IndexMap::new(); - self.define_recurse_ir( + self.define_ir_recurse( ir_stack, &mut func_components, &mut func_index_map, recursion_func_map, + false, ); let mut final_func_dep_ir = IndexMap::new(); - let mut zero_arg_defined_functions = IndexMap::new(); let mut to_be_defined = IndexMap::new(); let mut dependency_map = IndexMap::new(); let mut dependency_vec = vec![]; - let mut func_keys = func_components.keys().cloned().collect_vec(); + let mut func_keys = func_components + .clone() + .into_iter() + .filter(|(_, val)| !val.defined_by_zero_arg) + .map(|(key, val)| (key, val.defined_by_zero_arg)) + .collect_vec(); // deal with function dependencies by sorting order in which we iter over them. while let Some(function) = func_keys.pop() { - let funct_comp = func_components.get(&function).unwrap(); - if dependency_map.contains_key(&function) { - dependency_map.shift_remove(&function); + let funct_comp = func_components.get(&function.0).unwrap(); + if dependency_map.contains_key(&function.0) { + dependency_map.shift_remove(&function.0); } - dependency_map.insert(function, ()); - func_keys.extend(funct_comp.dependencies.clone().into_iter()); + dependency_map.insert(function.0, function.1); + func_keys.extend( + funct_comp + .dependencies + .iter() + .map(|key| { + ( + key.clone(), + func_components.get(key).unwrap().defined_by_zero_arg, + ) + }) + .collect_vec(), + ); } - dependency_vec.extend(dependency_map.keys().cloned()); + dependency_vec.extend( + dependency_map + .iter() + .filter(|(_, defined_in_zero_arg)| !**defined_in_zero_arg) + .map(|(key, _)| key.clone()) + .collect_vec(), + ); for func in dependency_vec { if self.defined_functions.contains_key(&func) { @@ -2808,6 +2844,7 @@ impl<'a> CodeGenerator<'a> { // since zero arg functions are run at compile time we need to pull all deps // note anon functions are not included in the above. They exist in a function anyway let mut defined_functions = IndexMap::new(); + // deal with function dependencies in zero arg functions handle_func_dependencies_ir( &mut dep_ir, @@ -2816,7 +2853,7 @@ impl<'a> CodeGenerator<'a> { &mut defined_functions, &func_index_map, func_scope, - &mut IndexMap::new(), + &mut to_be_defined, ); let mut final_zero_arg_ir = dep_ir; @@ -2827,18 +2864,33 @@ impl<'a> CodeGenerator<'a> { self.zero_arg_functions.insert(func, final_zero_arg_ir); // zero arg functions don't contain the dependencies since they are pre-evaluated // As such we add functions to defined only after dependencies for all other functions are calculated - for (key, val) in defined_functions.into_iter() { - zero_arg_defined_functions.insert(key, val); - } } } - // handle functions that are used in zero arg funcs but also used by the validator - // or a func used by the validator - for (key, val) in zero_arg_defined_functions.into_iter() { - if !to_be_defined.contains_key(&key) { - self.defined_functions.insert(key, val); - } + while let Some(func) = to_be_defined.pop() { + let mut dep_ir = vec![]; + let mut defined_functions = IndexMap::new(); + // deal with function dependencies in zero arg functions + + let funt_comp = func_components.get(&func.0).unwrap(); + let func_scope = func_index_map.get(&func.0).unwrap(); + + handle_func_dependencies_ir( + &mut dep_ir, + funt_comp, + &func_components, + &mut defined_functions, + &func_index_map, + func_scope, + &mut to_be_defined, + ); + + let mut final_zero_arg_ir = dep_ir; + final_zero_arg_ir.extend(funt_comp.ir.clone()); + + self.convert_opaque_type_to_inner_ir(&mut final_zero_arg_ir); + + self.zero_arg_functions.insert(func.0, final_zero_arg_ir); } for (index, ir) in ir_stack.clone().into_iter().enumerate().rev() { @@ -2850,6 +2902,7 @@ impl<'a> CodeGenerator<'a> { get_common_ancestor(&func.1, &ir.scope()) == ir.scope() && !self.defined_functions.contains_key(&func.0) && !self.zero_arg_functions.contains_key(&func.0) + && !(*dependency_map.get(&func.0).unwrap()) }) .collect_vec(); @@ -2894,14 +2947,15 @@ impl<'a> CodeGenerator<'a> { } } - fn define_recurse_ir( + fn define_ir_recurse( &mut self, ir_stack: &mut [Air], func_components: &mut IndexMap, func_index_map: &mut IndexMap>, mut recursion_func_map: IndexMap, + in_zero_arg_func: bool, ) { - self.process_define_ir(ir_stack, func_components, func_index_map); + self.define_ir_processor(ir_stack, func_components, func_index_map, in_zero_arg_func); let mut recursion_func_map_to_add = recursion_func_map.clone(); @@ -2910,6 +2964,7 @@ impl<'a> CodeGenerator<'a> { let function_components = func_components.get_mut(func).unwrap(); let mut function_ir = function_components.ir.clone(); + let in_zero_arg = function_components.args.is_empty() || in_zero_arg_func; let mut skip = false; for ir in function_ir.clone() { @@ -2965,18 +3020,22 @@ impl<'a> CodeGenerator<'a> { let mut inner_func_index_map = IndexMap::new(); - self.define_recurse_ir( + self.define_ir_recurse( &mut function_ir, &mut inner_func_components, &mut inner_func_index_map, recursion_func_map.clone(), + in_zero_arg, ); function_components.ir = function_ir; //now unify for item in inner_func_components { - if !func_components.contains_key(&item.0) { + if let Some(entry) = func_components.get_mut(&item.0) { + entry.defined_by_zero_arg = + entry.defined_by_zero_arg && item.1.defined_by_zero_arg + } else { func_components.insert(item.0, item.1); } } @@ -2992,11 +3051,12 @@ impl<'a> CodeGenerator<'a> { } } - fn process_define_ir( + fn define_ir_processor( &mut self, ir_stack: &mut [Air], func_components: &mut IndexMap, func_index_map: &mut IndexMap>, + in_zero_arg_func: bool, ) { let mut to_be_defined_map: IndexMap> = IndexMap::new(); for (index, ir) in ir_stack.to_vec().iter().enumerate().rev() { @@ -3172,6 +3232,7 @@ impl<'a> CodeGenerator<'a> { dependencies: func_calls.keys().cloned().collect_vec(), recursive, args, + defined_by_zero_arg: in_zero_arg_func, }, ); } diff --git a/examples/acceptance_tests/055/aiken.lock b/examples/acceptance_tests/055/aiken.lock index 00bfb887..550023f7 100644 --- a/examples/acceptance_tests/055/aiken.lock +++ b/examples/acceptance_tests/055/aiken.lock @@ -3,11 +3,11 @@ [[requirements]] name = "aiken-lang/stdlib" -version = "cf89161cbcd5e2c9519e7ea5d61986473b708179" +version = "3b47c89006e7580c2213370d7426ed2a38d2836e" source = "github" [[packages]] name = "aiken-lang/stdlib" -version = "cf89161cbcd5e2c9519e7ea5d61986473b708179" +version = "3b47c89006e7580c2213370d7426ed2a38d2836e" requirements = [] source = "github" diff --git a/examples/acceptance_tests/055/aiken.toml b/examples/acceptance_tests/055/aiken.toml index b642d219..1a35f90d 100644 --- a/examples/acceptance_tests/055/aiken.toml +++ b/examples/acceptance_tests/055/aiken.toml @@ -2,5 +2,5 @@ name = "aiken-lang/acceptance_test_055" version = "0.0.0" dependencies = [ - { name = "aiken-lang/stdlib", version="cf89161cbcd5e2c9519e7ea5d61986473b708179", source = "github" }, + { name = "aiken-lang/stdlib", version="3b47c89006e7580c2213370d7426ed2a38d2836e", source = "github" }, ] diff --git a/examples/acceptance_tests/055/lib/tests.ak b/examples/acceptance_tests/055/lib/tests.ak index b2bc6811..81e30020 100644 --- a/examples/acceptance_tests/055/lib/tests.ak +++ b/examples/acceptance_tests/055/lib/tests.ak @@ -1,16 +1,9 @@ use aiken/bytearray use aiken/dict use aiken/hash.{Hash, Sha2_256, sha2_256} -use aiken/interval.{Interval, IntervalBound, PositiveInfinity} +use aiken/interval.{between, intersection, is_empty, strictly_between} use aiken/list -use aiken/string -use aiken/transaction.{ - InlineDatum, Input, Output, OutputReference, Transaction, TransactionId, -} -use aiken/transaction/credential.{ - Address, PublicKeyCredential, ScriptCredential, StakeCredential, -} -use aiken/transaction/value +use aiken/transaction.{InlineDatum} // MerkleTree in Aiken (ported from: https://github.com/input-output-hk/hydra/blob/master/plutus-merkle-tree/src/Plutus/MerkleTree.hs) @@ -74,83 +67,27 @@ test foo() { size(mt) == 3 } -// const keyhash = #"010203040506" - -// const scripthash = #"060504030201" - -// pub fn keyhash_address(with_stake_credential: Option) { -// Address { -// payment_credential: PublicKeyCredential(keyhash), -// stake_credential: with_stake_credential, -// } -// } - -// pub fn scripthash_address(with_stake_credential: Option) { -// Address { -// payment_credential: ScriptCredential(scripthash), -// stake_credential: with_stake_credential, -// } -// } - -// type SampleData { -// a: Int, -// b: ByteArray, -// } - -// pub fn tx_1() -> Transaction { -// let sample_datum = SampleData { a: 1, b: #"01" } -// // let sample_data: Data = sample_datum -// let tx = -// Transaction { -// inputs: [ -// Input { -// output_reference: OutputReference { -// transaction_id: TransactionId { hash: #"" }, -// output_index: 0, -// }, -// output: Output { -// address: scripthash_address(None), -// value: value.zero(), -// datum: InlineDatum(sample_datum), -// reference_script: None, -// }, -// }, -// ], -// reference_inputs: [], -// outputs: [ -// Output { -// address: keyhash_address(None), -// value: value.from_lovelace(10000), -// datum: InlineDatum(sample_datum), -// reference_script: None, -// }, -// ], -// fee: value.zero(), -// mint: value.from_asset(#"000000", #"00", -1), -// certificates: [], -// withdrawals: dict.new(), -// validity_range: Interval { -// lower_bound: IntervalBound { -// bound_type: PositiveInfinity, -// is_inclusive: True, -// }, -// upper_bound: IntervalBound { -// bound_type: PositiveInfinity, -// is_inclusive: True, -// }, -// }, -// extra_signatories: [keyhash], -// redeemers: dict.new(), -// datums: dict.new(), -// id: TransactionId { hash: #"" }, -// } -// tx -// } - -// test some_test2() { -// tx_1() == tx_1() -// } - test some_test1() { InlineDatum(Void) == InlineDatum(Void) } + +test intersection_3() { + let iv1 = between(0, 1) + let iv2 = strictly_between(1, 2) + intersection(iv1, iv2) + |> is_empty +} + +const fooz = #"666f6f" + +const bar = #"626172" + +fn fixture_1() { + dict.new() + |> dict.insert(fooz, 42, bytearray.compare) + |> dict.insert(bar, 14, bytearray.compare) +} + +test union_1() { + dict.union(fixture_1(), dict.new(), bytearray.compare) == fixture_1() +}