From 7d67f1497cb7c4e36ccf0471a069daa1c14461f6 Mon Sep 17 00:00:00 2001 From: rvcas Date: Fri, 1 Mar 2024 11:32:36 -0500 Subject: [PATCH] feat(export): implement basic command functionality --- crates/aiken-project/src/error.rs | 136 +++++++++++++++------------- crates/aiken-project/src/lib.rs | 41 +++++++++ crates/aiken-project/src/options.rs | 9 ++ crates/aiken/src/cmd/export.rs | 30 +++++- 4 files changed, 150 insertions(+), 66 deletions(-) diff --git a/crates/aiken-project/src/error.rs b/crates/aiken-project/src/error.rs index a29b36c3..4235309b 100644 --- a/crates/aiken-project/src/error.rs +++ b/crates/aiken-project/src/error.rs @@ -120,6 +120,9 @@ pub enum Error { #[error("I found multiple suitable validators and I need you to tell me which one to pick.")] MoreThanOneValidatorFound { known_validators: Vec }, + + #[error("I couldn't find any exportable function named '{name}' in module '{module}'.")] + ExportNotFound { module: String, name: String }, } impl Error { @@ -177,27 +180,28 @@ impl From for Vec { impl ExtraData for Error { fn extra_data(&self) -> Option { match self { - Error::DuplicateModule { .. } => None, - Error::FileIo { .. } => None, - Error::Format { .. } => None, - Error::StandardIo { .. } => None, - Error::Blueprint { .. } => None, - Error::MissingManifest { .. } => None, - Error::TomlLoading { .. } => None, - Error::ImportCycle { .. } => None, - Error::Parse { .. } => None, + Error::DuplicateModule { .. } + | Error::FileIo { .. } + | Error::Format { .. } + | Error::StandardIo { .. } + | Error::Blueprint { .. } + | Error::MissingManifest { .. } + | Error::TomlLoading { .. } + | Error::ImportCycle { .. } + | Error::Parse { .. } + | Error::TestFailure { .. } + | Error::Http { .. } + | Error::ZipExtract { .. } + | Error::JoinError { .. } + | Error::UnknownPackageVersion { .. } + | Error::UnableToResolvePackage { .. } + | Error::Json { .. } + | Error::MalformedStakeAddress { .. } + | Error::NoValidatorNotFound { .. } + | Error::MoreThanOneValidatorFound { .. } + | Error::Module { .. } + | Error::ExportNotFound { .. } => None, Error::Type { error, .. } => error.extra_data(), - Error::TestFailure { .. } => None, - Error::Http { .. } => None, - Error::ZipExtract { .. } => None, - Error::JoinError { .. } => None, - Error::UnknownPackageVersion { .. } => None, - Error::UnableToResolvePackage { .. } => None, - Error::Json { .. } => None, - Error::MalformedStakeAddress { .. } => None, - Error::NoValidatorNotFound { .. } => None, - Error::MoreThanOneValidatorFound { .. } => None, - Error::Module { .. } => None, } } } @@ -210,53 +214,55 @@ pub trait GetSource { impl GetSource for Error { fn path(&self) -> Option { match self { - Error::DuplicateModule { second, .. } => Some(second.to_path_buf()), - Error::FileIo { .. } => None, - Error::Format { .. } => None, - Error::StandardIo(_) => None, - Error::Blueprint(_) => None, - Error::MissingManifest { path } => Some(path.to_path_buf()), - Error::TomlLoading { path, .. } => Some(path.to_path_buf()), - Error::ImportCycle { .. } => None, - Error::Parse { path, .. } => Some(path.to_path_buf()), - Error::Type { path, .. } => Some(path.to_path_buf()), - Error::TestFailure { path, .. } => Some(path.to_path_buf()), - Error::Http(_) => None, - Error::ZipExtract(_) => None, - Error::JoinError(_) => None, - Error::UnknownPackageVersion { .. } => None, - Error::UnableToResolvePackage { .. } => None, - Error::Json { .. } => None, - Error::MalformedStakeAddress { .. } => None, - Error::NoValidatorNotFound { .. } => None, - Error::MoreThanOneValidatorFound { .. } => None, - Error::Module { .. } => None, + Error::FileIo { .. } + | Error::Format { .. } + | Error::StandardIo(_) + | Error::Blueprint(_) + | Error::ImportCycle { .. } + | Error::Http(_) + | Error::ZipExtract(_) + | Error::JoinError(_) + | Error::UnknownPackageVersion { .. } + | Error::UnableToResolvePackage { .. } + | Error::Json { .. } + | Error::MalformedStakeAddress { .. } + | Error::NoValidatorNotFound { .. } + | Error::MoreThanOneValidatorFound { .. } + | Error::ExportNotFound { .. } + | Error::Module { .. } => None, + Error::DuplicateModule { second: path, .. } + | Error::MissingManifest { path } + | Error::TomlLoading { path, .. } + | Error::Parse { path, .. } + | Error::Type { path, .. } + | Error::TestFailure { path, .. } => Some(path.to_path_buf()), } } fn src(&self) -> Option { match self { - Error::DuplicateModule { .. } => None, - Error::FileIo { .. } => None, - Error::Format { .. } => None, - Error::StandardIo(_) => None, - Error::Blueprint(_) => None, - Error::MissingManifest { .. } => None, - Error::TomlLoading { src, .. } => Some(src.to_string()), - Error::ImportCycle { .. } => None, - Error::Parse { src, .. } => Some(src.to_string()), - Error::Type { src, .. } => Some(src.to_string()), - Error::TestFailure { .. } => None, - Error::Http(_) => None, - Error::ZipExtract(_) => None, - Error::JoinError(_) => None, - Error::UnknownPackageVersion { .. } => None, - Error::UnableToResolvePackage { .. } => None, - Error::Json { .. } => None, - Error::MalformedStakeAddress { .. } => None, - Error::NoValidatorNotFound { .. } => None, - Error::MoreThanOneValidatorFound { .. } => None, - Error::Module { .. } => None, + Error::DuplicateModule { .. } + | Error::FileIo { .. } + | Error::Format { .. } + | Error::StandardIo(_) + | Error::Blueprint(_) + | Error::MissingManifest { .. } + | Error::ImportCycle { .. } + | Error::TestFailure { .. } + | Error::Http(_) + | Error::ZipExtract(_) + | Error::JoinError(_) + | Error::UnknownPackageVersion { .. } + | Error::UnableToResolvePackage { .. } + | Error::Json { .. } + | Error::MalformedStakeAddress { .. } + | Error::NoValidatorNotFound { .. } + | Error::MoreThanOneValidatorFound { .. } + | Error::ExportNotFound { .. } + | Error::Module { .. } => None, + Error::TomlLoading { src, .. } | Error::Parse { src, .. } | Error::Type { src, .. } => { + Some(src.to_string()) + } } } } @@ -305,6 +311,7 @@ impl Diagnostic for Error { Error::MalformedStakeAddress { .. } => None, Error::NoValidatorNotFound { .. } => None, Error::MoreThanOneValidatorFound { .. } => None, + Error::ExportNotFound { .. } => None, Error::Module(e) => e.code().map(boxed), } } @@ -334,6 +341,7 @@ impl Diagnostic for Error { Error::Http(_) => None, Error::ZipExtract(_) => None, Error::JoinError(_) => None, + Error::ExportNotFound { .. } => None, Error::UnknownPackageVersion { .. } => Some(Box::new( "Perhaps, double-check the package repository and version?", )), @@ -379,6 +387,7 @@ impl Diagnostic for Error { Error::DuplicateModule { .. } => None, Error::FileIo { .. } => None, Error::ImportCycle { .. } => None, + Error::ExportNotFound { .. } => None, Error::Blueprint(e) => e.labels(), Error::Parse { error, .. } => error.labels(), Error::MissingManifest { .. } => None, @@ -413,6 +422,7 @@ impl Diagnostic for Error { Error::DuplicateModule { .. } => None, Error::FileIo { .. } => None, Error::ImportCycle { .. } => None, + Error::ExportNotFound { .. } => None, Error::Blueprint(e) => e.source_code(), Error::Parse { named, .. } => Some(named), Error::Type { named, .. } => Some(named), @@ -439,6 +449,7 @@ impl Diagnostic for Error { Error::DuplicateModule { .. } => None, Error::FileIo { .. } => None, Error::ImportCycle { .. } => None, + Error::ExportNotFound { .. } => None, Error::Blueprint(e) => e.url(), Error::Parse { .. } => None, Error::Type { error, .. } => error.url(), @@ -464,6 +475,7 @@ impl Diagnostic for Error { match self { Error::DuplicateModule { .. } => None, Error::FileIo { .. } => None, + Error::ExportNotFound { .. } => None, Error::Blueprint(e) => e.related(), Error::ImportCycle { .. } => None, Error::Parse { .. } => None, diff --git a/crates/aiken-project/src/lib.rs b/crates/aiken-project/src/lib.rs index e0b8f657..b988b7a9 100644 --- a/crates/aiken-project/src/lib.rs +++ b/crates/aiken-project/src/lib.rs @@ -464,6 +464,47 @@ where }) } + pub fn export(&self, module: &str, name: &str) -> Result { + let mut generator = self.checked_modules.new_generator( + &self.functions, + &self.data_types, + &self.module_types, + Tracing::silent(), + ); + + self.checked_modules + .get(module) + .and_then(|checked_module| { + checked_module.ast.definitions().find_map(|def| match def { + Definition::Fn(func) if func.name == name => { + let typed_anon = TypedExpr::Fn { + location: Span::empty(), + tipo: function( + func.arguments.iter().map(|arg| arg.tipo.clone()).collect(), + func.return_type.clone(), + ), + is_capture: false, + args: func.arguments.clone(), + body: func.body.clone().into(), + return_annotation: None, + }; + + Some(typed_anon) + } + _ => None, + }) + }) + .map(|body| { + let program = generator.generate_test(&body, &name.to_string()); + + program.to_pretty() + }) + .ok_or_else(|| Error::ExportNotFound { + module: module.to_string(), + name: name.to_string(), + }) + } + pub fn construct_parameter_incrementally( &self, title: Option<&String>, diff --git a/crates/aiken-project/src/options.rs b/crates/aiken-project/src/options.rs index 250da69d..aa0a8d33 100644 --- a/crates/aiken-project/src/options.rs +++ b/crates/aiken-project/src/options.rs @@ -5,6 +5,15 @@ pub struct Options { pub tracing: Tracing, } +impl Default for Options { + fn default() -> Self { + Self { + code_gen_mode: CodeGenMode::NoOp, + tracing: Tracing::silent(), + } + } +} + pub enum CodeGenMode { Test { match_tests: Option>, diff --git a/crates/aiken/src/cmd/export.rs b/crates/aiken/src/cmd/export.rs index 773acf7b..7eec0c38 100644 --- a/crates/aiken/src/cmd/export.rs +++ b/crates/aiken/src/cmd/export.rs @@ -1,14 +1,36 @@ +use std::path::PathBuf; + +use aiken_project::{options::Options, watch::with_project}; + #[derive(clap::Args)] pub struct Args { - /// Name of the validator's module within the project. Optional if there's only one validator + /// Path to project + directory: Option, + + /// Name of the function's module within the project #[clap(short, long)] module: String, - /// Name of the validator within the module. Optional if there's only one validator + /// Name of the function within the module #[clap(short, long)] name: String, } -pub fn exec(args: Args) -> miette::Result<()> { - Ok(()) +pub fn exec( + Args { + directory, + module, + name, + }: Args, +) -> miette::Result<()> { + with_project(directory.as_deref(), false, |p| { + p.compile(Options::default())?; + + let raw_uplc = p.export(&module, &name)?; + + println!("{}", raw_uplc); + + Ok(()) + }) + .map_err(|_| std::process::exit(1)) }