diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index 7be53c11..324bcca7 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -19,7 +19,8 @@ use aiken_lang::{ uplc::CodeGenerator, IdGenerator, }; -use deps::UseManifest; +use config::PackageName; +use deps::{manifest::Package, UseManifest}; use miette::NamedSource; use options::{CodeGenMode, Options}; use pallas::{ @@ -61,6 +62,7 @@ where { config: Config, defined_modules: HashMap, + checked_modules: CheckedModules, id_gen: IdGenerator, module_types: HashMap, root: PathBuf, @@ -85,6 +87,7 @@ where Ok(Project { config, + checked_modules: CheckedModules::default(), defined_modules: HashMap::new(), id_gen, module_types, @@ -110,19 +113,29 @@ where name: self.config.name.to_string(), version: self.config.version.clone(), }); + self.read_source_files()?; let destination = destination.unwrap_or_else(|| self.root.join("doc")); - let mut parsed_modules = self.parse_sources()?; + + let mut parsed_modules = self.parse_sources(self.config.name.clone())?; + for (_, module) in parsed_modules.iter_mut() { module.attach_doc_and_module_comments(); } - let checked_modules = self.type_check(parsed_modules)?; + + self.type_check(parsed_modules)?; + self.event_listener.handle_event(Event::GeneratingDocFiles { output_path: destination.clone(), }); - let doc_files = - docs::generate_all(&self.root, &self.config, checked_modules.values().collect()); + + let doc_files = docs::generate_all( + &self.root, + &self.config, + self.checked_modules.values().collect(), + ); + for file in doc_files { let path = destination.join(file.path); fs::create_dir_all(path.parent().unwrap())?; @@ -153,14 +166,6 @@ where } pub fn compile(&mut self, options: Options) -> Result<(), Error> { - let manifest = deps::download( - &self.event_listener, - None, - UseManifest::Yes, - &self.root, - &self.config, - )?; - self.event_listener .handle_event(Event::StartingCompilation { root: self.root.clone(), @@ -168,31 +173,41 @@ where version: self.config.version.clone(), }); + self.compile_deps()?; + self.read_source_files()?; - let parsed_modules = self.parse_sources()?; - let mut checked_modules = self.type_check(parsed_modules)?; - let validators = self.validate_validators(&mut checked_modules)?; + + let parsed_modules = self.parse_sources(self.config.name.clone())?; + + self.type_check(parsed_modules)?; + + let validators = self.validate_validators()?; match options.code_gen_mode { CodeGenMode::Build(uplc_dump) => { self.event_listener.handle_event(Event::GeneratingUPLC { output_path: self.output_path(), }); - let programs = self.code_gen(validators, &checked_modules)?; + + let programs = self.code_gen(validators)?; + self.write_build_outputs(programs, uplc_dump)?; + Ok(()) } CodeGenMode::Test { match_tests, verbose, } => { - let tests = self.collect_scripts(&checked_modules, verbose, |def| { - matches!(def, Definition::Test(..)) - })?; + let tests = + self.collect_scripts(verbose, |def| matches!(def, Definition::Test(..)))?; + if !tests.is_empty() { self.event_listener.handle_event(Event::RunningTests); } + let results = self.eval_scripts(tests, match_tests); + let errors: Vec = results .iter() .filter_map(|e| { @@ -212,6 +227,7 @@ where self.event_listener .handle_event(Event::FinishedTests { tests: results }); + if !errors.is_empty() { Err(Error::List(errors)) } else { @@ -222,6 +238,26 @@ where } } + fn compile_deps(&mut self) -> Result<(), Error> { + let manifest = deps::download( + &self.event_listener, + None, + UseManifest::Yes, + &self.root, + &self.config, + )?; + + for package in manifest.packages { + self.read_package_source_files(&package)?; + + let parsed_modules = self.parse_sources(package.name)?; + + self.type_check(parsed_modules)?; + } + + Ok(()) + } + fn read_source_files(&mut self) -> Result<(), Error> { let lib = self.root.join("lib"); let validators = self.root.join("validators"); @@ -232,7 +268,18 @@ where Ok(()) } - fn parse_sources(&mut self) -> Result { + fn read_package_source_files(&mut self, package: &Package) -> Result<(), Error> { + let lib = self + .root + .join(paths::build_deps_package(&package.name)) + .join("lib"); + + self.aiken_files(&lib, ModuleKind::Lib)?; + + Ok(()) + } + + fn parse_sources(&mut self, package_name: PackageName) -> Result { self.event_listener.handle_event(Event::ParsingProjectFiles); let mut errors = Vec::new(); @@ -257,7 +304,7 @@ where name, path, extra, - package: self.config.name.to_string(), + package: package_name.to_string(), }; if let Some(first) = self @@ -293,10 +340,9 @@ where } } - fn type_check(&mut self, mut parsed_modules: ParsedModules) -> Result { + fn type_check(&mut self, mut parsed_modules: ParsedModules) -> Result<(), Error> { self.event_listener.handle_event(Event::TypeChecking); let processing_sequence = parsed_modules.sequence()?; - let mut modules = HashMap::with_capacity(parsed_modules.len() + 1); for name in processing_sequence { if let Some(ParsedModule { @@ -305,8 +351,7 @@ where code, kind, extra, - // TODO: come back and figure out where to use this - package: _package, + package, ast, }) = parsed_modules.remove(&name) { @@ -339,7 +384,7 @@ where self.module_types .insert(name.clone(), ast.type_info.clone()); - modules.insert( + self.checked_modules.insert( name.clone(), CheckedModule { kind, @@ -347,25 +392,22 @@ where name, code, ast, + package, input_path: path, }, ); } } - Ok(modules.into()) + Ok(()) } - fn validate_validators( - &self, - checked_modules: &mut CheckedModules, - ) -> Result, Error> { + fn validate_validators(&self) -> Result, Error> { let mut errors = Vec::new(); let mut validators = Vec::new(); - let mut indices_to_remove = Vec::new(); - for module in checked_modules.validators() { - for (index, def) in module.ast.definitions().enumerate() { + for module in self.checked_modules.validators() { + for def in module.ast.definitions() { if let Definition::Fn(func_def) = def { if VALIDATOR_NAMES.contains(&func_def.name.as_str()) { // validators must return a Bool @@ -418,14 +460,9 @@ where module.name.clone(), func_def.clone(), )); - indices_to_remove.push(index); } } } - - for index in indices_to_remove.drain(0..) { - module.ast.definitions.remove(index); - } } if errors.is_empty() { @@ -438,7 +475,6 @@ where fn code_gen( &mut self, validators: Vec<(PathBuf, String, TypedFunction)>, - checked_modules: &CheckedModules, ) -> Result, Error> { let mut programs = Vec::new(); let mut functions = HashMap::new(); @@ -457,7 +493,7 @@ where &option_data_type, ); - for module in checked_modules.values() { + for module in self.checked_modules.values() { for def in module.ast.definitions() { match def { Definition::Fn(func) => { @@ -529,7 +565,6 @@ where // TODO: revisit ownership and lifetimes of data in this function fn collect_scripts( &mut self, - checked_modules: &CheckedModules, verbose: bool, should_collect: fn(&TypedDefinition) -> bool, ) -> Result, Error> { @@ -550,10 +585,13 @@ where &option_data_type, ); - // let mut indices_to_remove = Vec::new(); let mut scripts = Vec::new(); - for module in checked_modules.values() { + for module in self + .checked_modules + .values() + .filter(|checked| checked.package == self.config.name.to_string()) + { for (_index, def) in module.ast.definitions().enumerate() { match def { Definition::Fn(func) => { @@ -595,10 +633,6 @@ where } } } - - // for index in indices_to_remove.drain(0..) { - // module.ast.definitions.remove(index); - // } } for (input_path, module_name, func_def) in scripts { diff --git a/crates/project/src/module.rs b/crates/project/src/module.rs index 2c722e6b..5d8658fc 100644 --- a/crates/project/src/module.rs +++ b/crates/project/src/module.rs @@ -219,11 +219,12 @@ pub struct CheckedModule { pub code: String, pub input_path: PathBuf, pub kind: ModuleKind, + pub package: String, pub ast: TypedModule, pub extra: ModuleExtra, } -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct CheckedModules(HashMap); impl From> for CheckedModules { @@ -239,10 +240,8 @@ impl From for HashMap { } impl CheckedModules { - pub fn validators(&mut self) -> impl Iterator { - self.0 - .values_mut() - .filter(|module| module.kind.is_validator()) + pub fn validators(&self) -> impl Iterator { + self.0.values().filter(|module| module.kind.is_validator()) } pub fn into_validators(self) -> impl Iterator { diff --git a/examples/sample/assets/swap/spend/mainnet.addr b/examples/sample/assets/swap/spend/mainnet.addr new file mode 100644 index 00000000..3d559d5a --- /dev/null +++ b/examples/sample/assets/swap/spend/mainnet.addr @@ -0,0 +1 @@ +addr1w9ke4flw57jhv5tjefm8xwkfdc56et559npkcycd6u9ascc07drtu \ No newline at end of file diff --git a/examples/sample/assets/swap/spend/mainnet.txt b/examples/sample/assets/swap/spend/mainnet.txt deleted file mode 100644 index a0c4433e..00000000 --- a/examples/sample/assets/swap/spend/mainnet.txt +++ /dev/null @@ -1 +0,0 @@ -addr1wyqlmv9mg7cc5gcrhkxsnund3640hrfmj7ynxpcpc5kux2c6u6ewl \ No newline at end of file diff --git a/examples/sample/assets/swap/spend/payment_script.json b/examples/sample/assets/swap/spend/payment_script.json index 400406f5..53ca12e9 100644 --- a/examples/sample/assets/swap/spend/payment_script.json +++ b/examples/sample/assets/swap/spend/payment_script.json @@ -1,5 +1,5 @@ { "type": "PlutusScriptV2", "description": "Generated by Aiken", - "cborHex": "5854585201000022253335734646466e3cdd7198009801002a40006eb8cc004c008011200022323330010014800000c888cccd5cd19b870040025742466600800866e0000d20023574400200246aae78dd50008a4c2d" + "cborHex": "58c058be0100002225333573464646464a666ae68008400452819191919800801919b8f001375c6600c600e01490001800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002375c6ae84004008dd619801180199801180180224000900819b97323001375c66004600600a900011b9900149010d48656c6c6f2c20576f726c64210022323330010014800000c888cccd5cd19b870040025742466600800866e0000d20023574400200246aae78dd50008a4c2d" } \ No newline at end of file diff --git a/examples/sample/assets/swap/spend/raw.uplc b/examples/sample/assets/swap/spend/raw.uplc deleted file mode 100644 index 0a092ce2..00000000 --- a/examples/sample/assets/swap/spend/raw.uplc +++ /dev/null @@ -1,141 +0,0 @@ -(program - 1.0.0 - (lam - datum - (lam - rdmr - (lam - _ - (force - [ - [ - [ - (force (builtin ifThenElse)) - [ - (lam - __constr_fields_exposer - [ - (lam - __constr_get_field - [ - (lam - x - [ - [ - (builtin equalsByteString) - [ - (builtin unBData) - [ - [ - __constr_get_field - [ __constr_fields_exposer datum ] - ] - (con integer 0) - ] - ] - ] - [ - (builtin unBData) - [ - [ - __constr_get_field - [ __constr_fields_exposer rdmr ] - ] - (con integer 0) - ] - ] - ] - ) - [ - [ - (builtin mkCons) - [ (builtin bData) (con bytestring #f4) ] - ] - [ - [ (builtin mkCons) rdmr ] - [ [ (builtin mkCons) datum ] (con listdata []) ] - ] - ] - ] - ) - (lam - __constr_list - (lam - __arg_number - [ - (lam - __recurse - [ - [ [ __recurse __recurse ] (con integer 0) ] - __constr_list - ] - ) - (lam - __self_recursor - (lam - __current_arg_number - (lam - __list_of_constr_args - [ - [ - [ - [ - (force (builtin ifThenElse)) - [ - [ - (builtin equalsInteger) - __arg_number - ] - __current_arg_number - ] - ] - (force (builtin headList)) - ] - (lam - __current_list_of_constr_args - [ - [ - [ __self_recursor __self_recursor ] - [ - [ - (builtin addInteger) - __current_arg_number - ] - (con integer 1) - ] - ] - [ - (force (builtin tailList)) - __current_list_of_constr_args - ] - ] - ) - ] - __list_of_constr_args - ] - ) - ) - ) - ] - ) - ) - ] - ) - (lam - __constr_var - [ - (force (force (builtin sndPair))) - [ (builtin unConstrData) __constr_var ] - ] - ) - ] - ] - (delay (con unit ())) - ] - (delay (error )) - ] - ) - ) - ) - ) -) \ No newline at end of file diff --git a/examples/sample/assets/swap/spend/script.cbor b/examples/sample/assets/swap/spend/script.cbor new file mode 100644 index 00000000..dd7ef103 --- /dev/null +++ b/examples/sample/assets/swap/spend/script.cbor @@ -0,0 +1 @@ +58be0100002225333573464646464a666ae68008400452819191919800801919b8f001375c6600c600e01490001800800911192999aab9f00114a026464a666ae68c01000852889998030030008021aba2002375c6ae84004008dd619801180199801180180224000900819b97323001375c66004600600a900011b9900149010d48656c6c6f2c20576f726c64210022323330010014800000c888cccd5cd19b870040025742466600800866e0000d20023574400200246aae78dd50008a4c2d \ No newline at end of file diff --git a/examples/sample/assets/swap/spend/script.txt b/examples/sample/assets/swap/spend/script.txt deleted file mode 100644 index b9e334ea..00000000 --- a/examples/sample/assets/swap/spend/script.txt +++ /dev/null @@ -1 +0,0 @@ -585201000022253335734646466e3cdd7198009801002a40006eb8cc004c008011200022323330010014800000c888cccd5cd19b870040025742466600800866e0000d20023574400200246aae78dd50008a4c2d \ No newline at end of file diff --git a/examples/sample/assets/swap/spend/testnet.addr b/examples/sample/assets/swap/spend/testnet.addr new file mode 100644 index 00000000..141a7c52 --- /dev/null +++ b/examples/sample/assets/swap/spend/testnet.addr @@ -0,0 +1 @@ +addr_test1wpke4flw57jhv5tjefm8xwkfdc56et559npkcycd6u9ascc5kelye \ No newline at end of file diff --git a/examples/sample/assets/swap/spend/testnet.txt b/examples/sample/assets/swap/spend/testnet.txt deleted file mode 100644 index 462b5d7b..00000000 --- a/examples/sample/assets/swap/spend/testnet.txt +++ /dev/null @@ -1 +0,0 @@ -addr_test1wqqlmv9mg7cc5gcrhkxsnund3640hrfmj7ynxpcpc5kux2cp5w9p6 \ No newline at end of file diff --git a/examples/sample/validators/swap.ak b/examples/sample/validators/swap.ak index 868965b3..4f5d66ea 100644 --- a/examples/sample/validators/swap.ak +++ b/examples/sample/validators/swap.ak @@ -1,18 +1,24 @@ -use sample - -// Stuff - -/// Spend validator -pub fn spend(datum: sample.Datum, rdmr: sample.Redeemer, _ctx: Nil) -> Bool { - let x = #(datum, rdmr, #[244]) - - let y = [#(#[222], #[222]), #(#[233], #[52])] - - let [z, f, ..g] = y - - let #(a, b, _) = x - - z == #(#[222], #[222]) +use aiken/list +use aiken/string +use aiken/hash.{Blake2b_224, Hash} +use aiken/transaction.{ScriptContext} +use aiken/transaction/credential.{VerificationKey} + +pub type Datum { + owner: Hash, +} + +pub type Redeemer { + msg: ByteArray, +} + +pub fn spend(datum: Datum, redeemer: Redeemer, context: ScriptContext) -> Bool { + let must_say_hello = string.from_bytearray(redeemer.msg) == "Hello, World!" + let must_be_signed = + context.transaction.extra_signatories + |> list.any(fn(vk) { vk == datum.owner }) + + must_say_hello && must_be_signed } test foo() {