diff --git a/Cargo.lock b/Cargo.lock index 14ed619a..1c243db9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,6 +117,7 @@ dependencies = [ "futures", "hex", "ignore", + "indexmap", "itertools", "miette", "owo-colors", diff --git a/crates/aiken-lang/src/air.rs b/crates/aiken-lang/src/air.rs index 52791762..150c5266 100644 --- a/crates/aiken-lang/src/air.rs +++ b/crates/aiken-lang/src/air.rs @@ -1,5 +1,6 @@ -use std::{collections::HashSet, sync::Arc}; +use std::sync::Arc; +use indexmap::IndexSet; use uplc::builtins::DefaultFunction; use crate::{ @@ -127,8 +128,8 @@ pub enum Air { TupleClause { scope: Vec, tipo: Arc, - indices: HashSet<(usize, String)>, - predefined_indices: HashSet<(usize, String)>, + indices: IndexSet<(usize, String)>, + predefined_indices: IndexSet<(usize, String)>, subject_name: String, count: usize, complex_clause: bool, diff --git a/crates/aiken-lang/src/builder.rs b/crates/aiken-lang/src/builder.rs index 8ed0bd15..4c791610 100644 --- a/crates/aiken-lang/src/builder.rs +++ b/crates/aiken-lang/src/builder.rs @@ -1,10 +1,6 @@ -use std::{ - cell::RefCell, - collections::{HashMap, HashSet}, - sync::Arc, -}; +use std::{cell::RefCell, sync::Arc}; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; use uplc::{ ast::{ @@ -72,7 +68,7 @@ pub enum ClauseProperties { needs_constr_var: bool, is_complex_clause: bool, original_subject_name: String, - defined_tuple_indices: HashSet<(usize, String)>, + defined_tuple_indices: IndexSet<(usize, String)>, }, } @@ -92,7 +88,7 @@ impl ClauseProperties { needs_constr_var: false, is_complex_clause: false, original_subject_name: subject_name, - defined_tuple_indices: HashSet::new(), + defined_tuple_indices: IndexSet::new(), } } else { ClauseProperties::ConstrClause { @@ -542,6 +538,32 @@ pub fn list_access_to_uplc( .into(), } } else if names.is_empty() { + // Maybe check list is actually empty or should we leave that to when .. is only + // this would replace term.into() if we decide to + // body: choose_list( + // apply_wrap( + // Term::Builtin(DefaultFunction::TailList).force_wrap(), + // Term::Var(Name { + // text: format!( + // "tail_index_{}_{}", + // current_index, id_list[current_index] + // ), + // unique: 0.into(), + // }), + // ), + // term, + // apply_wrap( + // apply_wrap( + // Term::Builtin(DefaultFunction::Trace).force_wrap(), + // Term::Constant(UplcConstant::String( + // "List contains more items".to_string(), + // )), + // ), + // Term::Delay(Term::Error.into()), + // ) + // .force_wrap(), + // ) + // .into(), Term::Lambda { parameter_name: Name { text: format!("tail_index_{}_{}", current_index, id_list[current_index]), @@ -757,7 +779,7 @@ pub fn match_ir_for_recursion( } } -pub fn find_generics_to_replace(tipo: &mut Arc, generic_types: &HashMap>) { +pub fn find_generics_to_replace(tipo: &mut Arc, generic_types: &IndexMap>) { if let Some(id) = tipo.get_generic() { //If generic does not have a type we know of like a None in option then just use same type *tipo = generic_types.get(&id).unwrap_or(tipo).clone(); @@ -983,7 +1005,7 @@ pub fn wrap_validator_args(term: Term, arguments: Vec) -> Term, - generic_types: HashMap>, + generic_types: IndexMap>, full_type: &Arc, ) -> (String, Vec) { let mut new_air = ir.clone(); @@ -1390,14 +1412,14 @@ pub fn monomorphize( (new_name, new_air) } -pub fn handle_func_deps_ir( - dep_ir: &mut Vec, +pub fn handle_func_dependencies_ir( + dependencies_ir: &mut Vec, funt_comp: &FuncComponents, func_components: &IndexMap, - defined_functions: &mut HashMap, + defined_functions: &mut IndexMap, func_index_map: &IndexMap>, func_scope: &[u64], - to_be_defined: &mut HashMap, + to_be_defined: &mut IndexMap, ) { let mut funt_comp = funt_comp.clone(); @@ -1448,9 +1470,9 @@ pub fn handle_func_deps_ir( temp_ir.append(&mut recursion_ir); - temp_ir.append(dep_ir); + temp_ir.append(dependencies_ir); - *dep_ir = temp_ir; + *dependencies_ir = temp_ir; if get_common_ancestor(dep_scope, func_scope) == func_scope.to_vec() { defined_functions.insert(dependency, ()); } @@ -1501,7 +1523,7 @@ pub fn handle_recursion_ir( } pub fn lookup_data_type_by_tipo( - data_types: HashMap, + data_types: IndexMap, tipo: &Type, ) -> Option>> { match tipo { @@ -1536,7 +1558,7 @@ pub fn lookup_data_type_by_tipo( pub fn check_replaceable_opaque_type( t: &Arc, - data_types: &HashMap, + data_types: &IndexMap, ) -> bool { let data_type = lookup_data_type_by_tipo(data_types.clone(), t); @@ -1548,12 +1570,12 @@ pub fn check_replaceable_opaque_type( } } -pub fn replace_opaque_type(t: &mut Arc, data_types: HashMap) { +pub fn replace_opaque_type(t: &mut Arc, data_types: IndexMap) { if check_replaceable_opaque_type(t, &data_types) && matches!(&**t, Type::App { .. }) { let data_type = lookup_data_type_by_tipo(data_types.clone(), t).unwrap(); let new_type_fields = data_type.typed_parameters.clone(); - let mut generics_type_map: HashMap> = HashMap::new(); + let mut generics_type_map: IndexMap> = IndexMap::new(); for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) { let mut map = generics_type_map.into_iter().collect_vec(); diff --git a/crates/aiken-lang/src/uplc.rs b/crates/aiken-lang/src/uplc.rs index 0201d490..7a550f19 100644 --- a/crates/aiken-lang/src/uplc.rs +++ b/crates/aiken-lang/src/uplc.rs @@ -1,10 +1,6 @@ -use std::{ - collections::{HashMap, HashSet}, - sync::Arc, - vec, -}; +use std::{sync::Arc, vec}; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; use uplc::{ ast::{ @@ -28,9 +24,10 @@ use crate::{ builder::{ check_replaceable_opaque_type, check_when_pattern_needs, constants_ir, convert_constants_to_data, convert_data_to_type, convert_type_to_data, get_common_ancestor, - get_generics_and_type, handle_func_deps_ir, handle_recursion_ir, list_access_to_uplc, - lookup_data_type_by_tipo, monomorphize, rearrange_clauses, replace_opaque_type, - wrap_validator_args, ClauseProperties, DataTypeKey, FuncComponents, FunctionAccessKey, + get_generics_and_type, handle_func_dependencies_ir, handle_recursion_ir, + list_access_to_uplc, lookup_data_type_by_tipo, monomorphize, rearrange_clauses, + replace_opaque_type, wrap_validator_args, ClauseProperties, DataTypeKey, FuncComponents, + FunctionAccessKey, }, expr::TypedExpr, tipo::{ @@ -41,32 +38,32 @@ use crate::{ }; pub struct CodeGenerator<'a> { - defined_functions: HashMap, - functions: &'a HashMap, - // type_aliases: &'a HashMap<(String, String), &'a TypeAlias>>, - data_types: &'a HashMap, - module_types: &'a HashMap, + defined_functions: IndexMap, + functions: &'a IndexMap, + // type_aliases: &'a IndexMap<(String, String), &'a TypeAlias>>, + data_types: &'a IndexMap, + module_types: &'a IndexMap, id_gen: IdGenerator, needs_field_access: bool, - zero_arg_functions: HashMap>, + zero_arg_functions: IndexMap>, } impl<'a> CodeGenerator<'a> { pub fn new( - functions: &'a HashMap, - // type_aliases: &'a HashMap<(String, String), &'a TypeAlias>>, - data_types: &'a HashMap, - module_types: &'a HashMap, + functions: &'a IndexMap, + // type_aliases: &'a IndexMap<(String, String), &'a TypeAlias>>, + data_types: &'a IndexMap, + module_types: &'a IndexMap, ) -> Self { CodeGenerator { - defined_functions: HashMap::new(), + defined_functions: IndexMap::new(), functions, // type_aliases, data_types, module_types, id_gen: IdGenerator::new(), needs_field_access: false, - zero_arg_functions: HashMap::new(), + zero_arg_functions: IndexMap::new(), } } @@ -1040,7 +1037,7 @@ impl<'a> CodeGenerator<'a> { PatternConstructor::Record { field_map, .. } => field_map.clone().unwrap(), }; - let mut type_map: HashMap> = HashMap::new(); + let mut type_map: IndexMap> = IndexMap::new(); for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { let label = constructor_type.arguments[index].label.clone().unwrap(); @@ -1092,7 +1089,7 @@ impl<'a> CodeGenerator<'a> { }); } } else { - let mut type_map: HashMap> = HashMap::new(); + let mut type_map: IndexMap> = IndexMap::new(); for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { let field_type = arg.clone(); @@ -1380,7 +1377,7 @@ impl<'a> CodeGenerator<'a> { needs_constr_var: false, is_complex_clause: false, original_subject_name: item_name.clone(), - defined_tuple_indices: HashSet::new(), + defined_tuple_indices: IndexSet::new(), }; let mut inner_pattern_vec = vec![]; @@ -1406,7 +1403,7 @@ impl<'a> CodeGenerator<'a> { scope, tipo: pattern_type.clone(), indices: defined_indices, - predefined_indices: HashSet::new(), + predefined_indices: IndexSet::new(), subject_name: clause_properties.original_subject_name().to_string(), count: elems.len(), complex_clause: false, @@ -1625,7 +1622,7 @@ impl<'a> CodeGenerator<'a> { } }; - let mut type_map: HashMap> = HashMap::new(); + let mut type_map: IndexMap> = IndexMap::new(); for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { let label = constructor_type.arguments[index].label.clone().unwrap(); @@ -1694,7 +1691,7 @@ impl<'a> CodeGenerator<'a> { }); } } else { - let mut type_map: HashMap> = HashMap::new(); + let mut type_map: IndexMap> = IndexMap::new(); for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { let field_type = arg.clone(); @@ -1834,8 +1831,8 @@ impl<'a> CodeGenerator<'a> { ); let mut final_func_dep_ir = IndexMap::new(); - let mut zero_arg_defined_functions = HashMap::new(); - let mut to_be_defined = HashMap::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![]; @@ -1865,7 +1862,7 @@ impl<'a> CodeGenerator<'a> { if !funt_comp.args.is_empty() { // deal with function dependencies - handle_func_deps_ir( + handle_func_dependencies_ir( &mut dep_ir, funt_comp, &func_components, @@ -1877,16 +1874,17 @@ impl<'a> CodeGenerator<'a> { final_func_dep_ir.insert(func, dep_ir); } else { // since zero arg functions are run at compile time we need to pull all deps - let mut defined_functions = HashMap::new(); + // 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_deps_ir( + handle_func_dependencies_ir( &mut dep_ir, funt_comp, &func_components, &mut defined_functions, &func_index_map, func_scope, - &mut HashMap::new(), + &mut IndexMap::new(), ); let mut final_zero_arg_ir = dep_ir; @@ -1895,7 +1893,8 @@ impl<'a> CodeGenerator<'a> { self.convert_opaque_type_to_inner_ir(&mut final_zero_arg_ir); 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); } @@ -2095,7 +2094,7 @@ impl<'a> CodeGenerator<'a> { let param_types = constructor.tipo.arg_types().unwrap(); - let mut generics_type_map: HashMap> = HashMap::new(); + let mut generics_type_map: IndexMap> = IndexMap::new(); for (index, arg) in function.arguments.iter().enumerate() { if arg.tipo.is_generic() { @@ -2133,7 +2132,7 @@ impl<'a> CodeGenerator<'a> { to_be_defined_map.insert(function_key.clone(), scope.to_vec()); } else { to_be_defined_map.insert(function_key.clone(), scope.to_vec()); - let mut func_calls = HashMap::new(); + let mut func_calls = IndexMap::new(); for ir in func_ir.clone().into_iter() { if let Air::Var { @@ -2169,8 +2168,8 @@ impl<'a> CodeGenerator<'a> { } else if let (Some(function), Type::Fn { .. }) = (function, &*tipo) { - let mut generics_type_map: HashMap> = - HashMap::new(); + let mut generics_type_map: IndexMap> = + IndexMap::new(); let param_types = tipo.arg_types().unwrap(); @@ -4267,7 +4266,7 @@ impl<'a> CodeGenerator<'a> { let record = arg_stack.pop().unwrap(); - let mut args = HashMap::new(); + let mut args = IndexMap::new(); let mut unchanged_field_indices = vec![]; let mut prev_index = 0; for (index, tipo) in indices diff --git a/crates/aiken-project/Cargo.toml b/crates/aiken-project/Cargo.toml index e10ead1b..5bc164e9 100644 --- a/crates/aiken-project/Cargo.toml +++ b/crates/aiken-project/Cargo.toml @@ -16,6 +16,7 @@ fslock = "0.2.1" futures = "0.3.25" hex = "0.4.3" ignore = "0.4.18" +indexmap = "1.9.1" itertools = "0.10.1" miette = { version = "5.3.0", features = ["fancy"] } owo-colors = "3.5.0" diff --git a/crates/aiken-project/src/lib.rs b/crates/aiken-project/src/lib.rs index b6013b9f..86c3ca7c 100644 --- a/crates/aiken-project/src/lib.rs +++ b/crates/aiken-project/src/lib.rs @@ -20,6 +20,7 @@ use aiken_lang::{ IdGenerator, MINT, PUBLISH, SPEND, VALIDATOR_NAMES, WITHDRAW, }; use deps::UseManifest; +use indexmap::IndexMap; use miette::NamedSource; use options::{CodeGenMode, Options}; use package_name::PackageName; @@ -482,9 +483,9 @@ where validators: Vec<(PathBuf, String, TypedFunction)>, ) -> Result, Error> { let mut programs = Vec::new(); - let mut functions = HashMap::new(); - let mut type_aliases = HashMap::new(); - let mut data_types = HashMap::new(); + let mut functions = IndexMap::new(); + let mut type_aliases = IndexMap::new(); + let mut data_types = IndexMap::new(); let prelude_functions = builtins::prelude_functions(&self.id_gen); for (access_key, func) in prelude_functions.iter() { @@ -539,11 +540,15 @@ where .. } = func_def; + let mut modules_map = IndexMap::new(); + + modules_map.extend(self.module_types.clone()); + let mut generator = CodeGenerator::new( &functions, // &type_aliases, &data_types, - &self.module_types, + &modules_map, ); self.event_listener.handle_event(Event::GeneratingUPLC { @@ -573,9 +578,9 @@ where should_collect: fn(&TypedDefinition) -> bool, ) -> Result, Error> { let mut programs = Vec::new(); - let mut functions = HashMap::new(); - let mut type_aliases = HashMap::new(); - let mut data_types = HashMap::new(); + let mut functions = IndexMap::new(); + let mut type_aliases = IndexMap::new(); + let mut data_types = IndexMap::new(); let prelude_functions = builtins::prelude_functions(&self.id_gen); for (access_key, func) in prelude_functions.iter() { @@ -648,21 +653,25 @@ where }) } + let mut modules_map = IndexMap::new(); + + modules_map.extend(self.module_types.clone()); + let mut generator = CodeGenerator::new( &functions, // &type_aliases, &data_types, - &self.module_types, + &modules_map, ); let evaluation_hint = if let Some((bin_op, left_src, right_src)) = func_def.test_hint() { - let left = CodeGenerator::new(&functions, &data_types, &self.module_types) + let left = CodeGenerator::new(&functions, &data_types, &modules_map) .generate(*left_src, vec![], false) .try_into() .unwrap(); - let right = CodeGenerator::new(&functions, &data_types, &self.module_types) + let right = CodeGenerator::new(&functions, &data_types, &modules_map) .generate(*right_src, vec![], false) .try_into() .unwrap(); diff --git a/examples/acceptance_tests/036/assets/spend/spend/mainnet.addr b/examples/acceptance_tests/036/assets/spend/spend/mainnet.addr index ec36701e..1f30832e 100644 --- a/examples/acceptance_tests/036/assets/spend/spend/mainnet.addr +++ b/examples/acceptance_tests/036/assets/spend/spend/mainnet.addr @@ -1 +1 @@ -addr1w9zyujfu4a23cltkm7xe2usj7wedtvqnsk9ecg2zwt6a90s83wahe \ No newline at end of file +addr1w8ehrka3eyh8hqxt647qm56z0ju3x8fsyjv2f3cwp5kr5ssvegjnw \ No newline at end of file diff --git a/examples/acceptance_tests/036/assets/spend/spend/payment_script.json b/examples/acceptance_tests/036/assets/spend/spend/payment_script.json index 78c4254d..26f7ac73 100644 --- a/examples/acceptance_tests/036/assets/spend/spend/payment_script.json +++ b/examples/acceptance_tests/036/assets/spend/spend/payment_script.json @@ -1,5 +1,5 @@ { "type": "PlutusScriptV2", "description": "Generated by Aiken", - "cborHex": "59015159014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300c00130050013300500100237566601c601e00490011192999aab9f00114a2294000488c8c8cc0140052f5bded8c06600a002004004446464a666ae68cdc3800a40042006264640026eacd5d080098070011aab9d37540020044466006004002600200244464a666aae7c0044cdd2a400497ae01323232325333573466e3c0180044cdd2a400066ae80dd300125eb804ccc02002000c018dd71aab9d00337566aae78008d5d10011aba100100223335734002941289800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1" + "cborHex": "59015159014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300600130060013300600100237566601c601e00490011199ab9a0014a09448c94ccd55cf8008a5114a00024464646600a00297adef6c60330050010020022232325333573466e1c005200210031323200137566ae84004c034008d55ce9baa001002223300300200130010012223253335573e002266e9520024bd700991919192999ab9a3371e00c002266e9520003357406e980092f5c0266601001000600c6eb8d55ce8019bab35573c0046ae88008d5d08008011800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1" } \ No newline at end of file diff --git a/examples/acceptance_tests/036/assets/spend/spend/script.cbor b/examples/acceptance_tests/036/assets/spend/spend/script.cbor index 0d8bf202..8663ae49 100644 --- a/examples/acceptance_tests/036/assets/spend/spend/script.cbor +++ b/examples/acceptance_tests/036/assets/spend/spend/script.cbor @@ -1 +1 @@ -59014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300c00130050013300500100237566601c601e00490011192999aab9f00114a2294000488c8c8cc0140052f5bded8c06600a002004004446464a666ae68cdc3800a40042006264640026eacd5d080098070011aab9d37540020044466006004002600200244464a666aae7c0044cdd2a400497ae01323232325333573466e3c0180044cdd2a400066ae80dd300125eb804ccc02002000c018dd71aab9d00337566aae78008d5d10011aba100100223335734002941289800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1 \ No newline at end of file +59014e01000022253335734646464646466002006464646464646464646600201291010500000000000022323232300600130060013300600100237566601c601e00490011199ab9a0014a09448c94ccd55cf8008a5114a00024464646600a00297adef6c60330050010020022232325333573466e1c005200210031323200137566ae84004c034008d55ce9baa001002223300300200130010012223253335573e002266e9520024bd700991919192999ab9a3371e00c002266e9520003357406e980092f5c0266601001000600c6eb8d55ce8019bab35573c0046ae88008d5d08008011800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002357420020046eb0cc004c008cc004c00800d20004801088c8ccc00400520000032223333573466e1c0100095d0919980200219b8000348008d5d100080091aab9e37540022930b1 \ No newline at end of file diff --git a/examples/acceptance_tests/036/assets/spend/spend/testnet.addr b/examples/acceptance_tests/036/assets/spend/spend/testnet.addr index 4fcad1d6..54c31f14 100644 --- a/examples/acceptance_tests/036/assets/spend/spend/testnet.addr +++ b/examples/acceptance_tests/036/assets/spend/spend/testnet.addr @@ -1 +1 @@ -addr_test1wpzyujfu4a23cltkm7xe2usj7wedtvqnsk9ecg2zwt6a90sue6pcu \ No newline at end of file +addr_test1wrehrka3eyh8hqxt647qm56z0ju3x8fsyjv2f3cwp5kr5ssh3uwut \ No newline at end of file