From 8c121f6d97da3ef466ac2e74374691a21f38ae8b Mon Sep 17 00:00:00 2001 From: KtorZ Date: Tue, 6 Aug 2024 11:09:05 +0200 Subject: [PATCH] Document 'export' and provide better errors on module not found. --- crates/aiken-lang/src/tipo/error.rs | 2 +- crates/aiken-project/src/error.rs | 22 ++++++++++++++++++++++ crates/aiken-project/src/lib.rs | 21 ++++++++++++++------- crates/aiken/src/cmd/export.rs | 2 ++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index 81ed0519..a07f035d 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -1820,7 +1820,7 @@ pub enum UnknownRecordFieldSituation { FunctionCall, } -fn format_suggestion(sample: &UntypedExpr) -> String { +pub fn format_suggestion(sample: &UntypedExpr) -> String { Formatter::new() .expr(sample, false) .to_pretty_string(70) diff --git a/crates/aiken-project/src/error.rs b/crates/aiken-project/src/error.rs index c0bdee4f..5f0ebe33 100644 --- a/crates/aiken-project/src/error.rs +++ b/crates/aiken-project/src/error.rs @@ -128,6 +128,12 @@ pub enum Error { #[error("I couldn't find any exportable function named '{name}' in module '{module}'.")] ExportNotFound { module: String, name: String }, + #[error("No such module '{module}' found in the project.")] + ModuleNotFound { + module: String, + known_modules: Vec, + }, + #[error("I located conditional modules under 'env', but no default one!")] NoDefaultEnvironment, } @@ -199,6 +205,7 @@ impl ExtraData for Error { | Error::MoreThanOneValidatorFound { .. } | Error::Module { .. } | Error::NoDefaultEnvironment { .. } + | Error::ModuleNotFound { .. } | Error::ExportNotFound { .. } => None, Error::Type { error, .. } => error.extra_data(), } @@ -227,6 +234,7 @@ impl GetSource for Error { | Error::MalformedStakeAddress { .. } | Error::NoValidatorNotFound { .. } | Error::MoreThanOneValidatorFound { .. } + | Error::ModuleNotFound { .. } | Error::ExportNotFound { .. } | Error::NoDefaultEnvironment { .. } | Error::Module { .. } => None, @@ -259,6 +267,7 @@ impl GetSource for Error { | Error::NoValidatorNotFound { .. } | Error::NoDefaultEnvironment { .. } | Error::MoreThanOneValidatorFound { .. } + | Error::ModuleNotFound { .. } | Error::ExportNotFound { .. } | Error::Module { .. } => None, Error::TomlLoading { src, .. } | Error::Parse { src, .. } | Error::Type { src, .. } => { @@ -313,6 +322,7 @@ impl Diagnostic for Error { Error::NoValidatorNotFound { .. } => None, Error::MoreThanOneValidatorFound { .. } => None, Error::ExportNotFound { .. } => None, + Error::ModuleNotFound { .. } => None, Error::NoDefaultEnvironment { .. } => None, Error::Module(e) => e.code().map(boxed), } @@ -347,6 +357,14 @@ impl Diagnostic for Error { Error::ZipExtract(_) => None, Error::JoinError(_) => None, Error::ExportNotFound { .. } => None, + Error::ModuleNotFound { known_modules, .. } => Some(Box::new(format!( + "I know about the following modules:\n{}", + known_modules + .iter() + .map(|s| format!("─▶ {}", s.if_supports_color(Stdout, |s| s.purple()))) + .collect::>() + .join("\n") + ))), Error::UnknownPackageVersion { .. } => Some(Box::new( "Perhaps, double-check the package repository and version?", )), @@ -419,6 +437,7 @@ impl Diagnostic for Error { Error::NoValidatorNotFound { .. } => None, Error::MoreThanOneValidatorFound { .. } => None, Error::NoDefaultEnvironment { .. } => None, + Error::ModuleNotFound { .. } => None, Error::Module(e) => e.labels(), } } @@ -428,6 +447,7 @@ impl Diagnostic for Error { Error::DuplicateModule { .. } => None, Error::FileIo { .. } => None, Error::ImportCycle { .. } => None, + Error::ModuleNotFound { .. } => None, Error::ExportNotFound { .. } => None, Error::Blueprint(e) => e.source_code(), Error::NoDefaultEnvironment { .. } => None, @@ -456,6 +476,7 @@ impl Diagnostic for Error { Error::DuplicateModule { .. } => None, Error::FileIo { .. } => None, Error::ImportCycle { .. } => None, + Error::ModuleNotFound { .. } => None, Error::ExportNotFound { .. } => None, Error::Blueprint(e) => e.url(), Error::Parse { .. } => None, @@ -483,6 +504,7 @@ impl Diagnostic for Error { match self { Error::DuplicateModule { .. } => None, Error::FileIo { .. } => None, + Error::ModuleNotFound { .. } => None, Error::ExportNotFound { .. } => None, Error::Blueprint(e) => e.related(), Error::ImportCycle { .. } => None, diff --git a/crates/aiken-project/src/lib.rs b/crates/aiken-project/src/lib.rs index 1ad009f3..1ffc6160 100644 --- a/crates/aiken-project/src/lib.rs +++ b/crates/aiken-project/src/lib.rs @@ -534,13 +534,20 @@ where } pub fn export(&self, module: &str, name: &str, tracing: Tracing) -> Result { - 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 => Some((checked_module, func)), - _ => None, - }) + let checked_module = + self.checked_modules + .get(module) + .ok_or_else(|| Error::ModuleNotFound { + module: module.to_string(), + known_modules: self.checked_modules.keys().cloned().collect(), + })?; + + checked_module + .ast + .definitions() + .find_map(|def| match def { + Definition::Fn(func) if func.name == name => Some((checked_module, func)), + _ => None, }) .map(|(checked_module, func)| { let mut generator = self.new_generator(tracing); diff --git a/crates/aiken/src/cmd/export.rs b/crates/aiken/src/cmd/export.rs index a1c36932..6debdcd2 100644 --- a/crates/aiken/src/cmd/export.rs +++ b/crates/aiken/src/cmd/export.rs @@ -4,6 +4,8 @@ use aiken_project::{options::Options, watch::with_project}; use std::path::PathBuf; #[derive(clap::Args)] +/// Export a function as a standalone UPLC program. Arguments to the function can be applied using +/// `aiken apply`. pub struct Args { /// Path to project directory: Option,