Merge pull request #994 from aiken-lang/conditional-modules
Conditional configuration & environment
This commit is contained in:
commit
e6bb13def6
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
- **aiken-lang**: add support for `mk_cons` and `mk_pair_data` builtins. See [#964](https://github.com/aiken-lang/aiken/issues/964). @KtorZ
|
- **aiken-lang**: add support for `mk_cons` and `mk_pair_data` builtins. See [#964](https://github.com/aiken-lang/aiken/issues/964). @KtorZ
|
||||||
- **aiken-lang**: pattern-matching on bytearrays is now available. See [#989](https://github.com/aiken-lang/aiken/issues/989). @KtorZ
|
- **aiken-lang**: pattern-matching on bytearrays is now available. See [#989](https://github.com/aiken-lang/aiken/issues/989). @KtorZ
|
||||||
|
- **aiken-project**: conditional configuration and environment. See [#937](https://github.com/aiken-lang/aiken/issues/937). @KtorZ
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,10 @@ pub const BACKPASS_VARIABLE: &str = "_backpass";
|
||||||
pub const CAPTURE_VARIABLE: &str = "_capture";
|
pub const CAPTURE_VARIABLE: &str = "_capture";
|
||||||
pub const PIPE_VARIABLE: &str = "_pipe";
|
pub const PIPE_VARIABLE: &str = "_pipe";
|
||||||
|
|
||||||
|
pub const ENV_MODULE: &str = "env";
|
||||||
|
pub const CONFIG_MODULE: &str = "config";
|
||||||
|
pub const DEFAULT_ENV_MODULE: &str = "default";
|
||||||
|
|
||||||
pub type TypedModule = Module<TypeInfo, TypedDefinition>;
|
pub type TypedModule = Module<TypeInfo, TypedDefinition>;
|
||||||
pub type UntypedModule = Module<(), UntypedDefinition>;
|
pub type UntypedModule = Module<(), UntypedDefinition>;
|
||||||
|
|
||||||
|
@ -28,6 +32,8 @@ pub type UntypedModule = Module<(), UntypedDefinition>;
|
||||||
pub enum ModuleKind {
|
pub enum ModuleKind {
|
||||||
Lib,
|
Lib,
|
||||||
Validator,
|
Validator,
|
||||||
|
Env,
|
||||||
|
Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleKind {
|
impl ModuleKind {
|
||||||
|
@ -38,6 +44,14 @@ impl ModuleKind {
|
||||||
pub fn is_lib(&self) -> bool {
|
pub fn is_lib(&self) -> bool {
|
||||||
matches!(self, ModuleKind::Lib)
|
matches!(self, ModuleKind::Lib)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_env(&self) -> bool {
|
||||||
|
matches!(self, ModuleKind::Env)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_config(&self) -> bool {
|
||||||
|
matches!(self, ModuleKind::Config)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
@ -61,16 +75,18 @@ impl<Info, Definitions> Module<Info, Definitions> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UntypedModule {
|
impl UntypedModule {
|
||||||
pub fn dependencies(&self) -> Vec<(String, Span)> {
|
pub fn dependencies(&self, env_modules: &[String]) -> Vec<String> {
|
||||||
self.definitions()
|
self.definitions()
|
||||||
.flat_map(|def| {
|
.flat_map(|def| {
|
||||||
if let Definition::Use(Use {
|
if let Definition::Use(Use { module, .. }) = def {
|
||||||
location, module, ..
|
let name = module.join("/");
|
||||||
}) = def
|
if name == ENV_MODULE {
|
||||||
{
|
env_modules.to_vec()
|
||||||
Some((module.join("/"), *location))
|
} else {
|
||||||
|
vec![name]
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
Vec::new()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -1069,6 +1085,15 @@ impl Annotation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bytearray(location: Span) -> Self {
|
||||||
|
Annotation::Constructor {
|
||||||
|
name: "ByteArray".to_string(),
|
||||||
|
module: None,
|
||||||
|
arguments: vec![],
|
||||||
|
location,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data(location: Span) -> Self {
|
pub fn data(location: Span) -> Self {
|
||||||
Annotation::Constructor {
|
Annotation::Constructor {
|
||||||
name: "Data".to_string(),
|
name: "Data".to_string(),
|
||||||
|
|
|
@ -25,8 +25,8 @@ use ordinal::Ordinal;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use vec1::Vec1;
|
use vec1::Vec1;
|
||||||
|
|
||||||
const INDENT: isize = 2;
|
pub const INDENT: isize = 2;
|
||||||
const DOCS_MAX_COLUMNS: isize = 80;
|
pub const DOCS_MAX_COLUMNS: isize = 80;
|
||||||
|
|
||||||
pub fn pretty(writer: &mut String, module: UntypedModule, extra: ModuleExtra, src: &str) {
|
pub fn pretty(writer: &mut String, module: UntypedModule, extra: ModuleExtra, src: &str) {
|
||||||
let intermediate = Intermediate {
|
let intermediate = Intermediate {
|
||||||
|
@ -130,7 +130,7 @@ impl<'comments> Formatter<'comments> {
|
||||||
end != 0
|
end != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn definitions<'a>(&mut self, definitions: &'a [UntypedDefinition]) -> Document<'a> {
|
pub fn definitions<'a>(&mut self, definitions: &'a [UntypedDefinition]) -> Document<'a> {
|
||||||
let mut has_imports = false;
|
let mut has_imports = false;
|
||||||
let mut has_declarations = false;
|
let mut has_declarations = false;
|
||||||
let mut imports = Vec::new();
|
let mut imports = Vec::new();
|
||||||
|
|
|
@ -49,6 +49,7 @@ macro_rules! aiken_fn {
|
||||||
$module_types,
|
$module_types,
|
||||||
$crate::ast::Tracing::silent(),
|
$crate::ast::Tracing::silent(),
|
||||||
&mut warnings,
|
&mut warnings,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ fn check_module(
|
||||||
&module_types,
|
&module_types,
|
||||||
Tracing::All(TraceLevel::Verbose),
|
Tracing::All(TraceLevel::Verbose),
|
||||||
&mut warnings,
|
&mut warnings,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.expect("extra dependency did not compile");
|
.expect("extra dependency did not compile");
|
||||||
module_types.insert(package.clone(), typed_module.type_info.clone());
|
module_types.insert(package.clone(), typed_module.type_info.clone());
|
||||||
|
@ -50,6 +51,7 @@ fn check_module(
|
||||||
&module_types,
|
&module_types,
|
||||||
tracing,
|
tracing,
|
||||||
&mut warnings,
|
&mut warnings,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
result
|
result
|
||||||
|
|
|
@ -7,7 +7,7 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind,
|
self, Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind,
|
||||||
RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition, TypedFunction,
|
RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition, TypedFunction,
|
||||||
TypedPattern, UnqualifiedImport, UntypedArg, UntypedDefinition, UntypedFunction, Use,
|
TypedPattern, UnqualifiedImport, UntypedArg, UntypedDefinition, UntypedFunction, Use,
|
||||||
Validator, PIPE_VARIABLE,
|
Validator, PIPE_VARIABLE,
|
||||||
|
@ -80,11 +80,49 @@ pub struct Environment<'a> {
|
||||||
/// A mapping from known annotations to their resolved type.
|
/// A mapping from known annotations to their resolved type.
|
||||||
pub annotations: HashMap<Annotation, Rc<Type>>,
|
pub annotations: HashMap<Annotation, Rc<Type>>,
|
||||||
|
|
||||||
|
/// The user-defined target environment referred to as the module 'env'.
|
||||||
|
pub target_env: Option<&'a str>,
|
||||||
|
|
||||||
/// Warnings
|
/// Warnings
|
||||||
pub warnings: &'a mut Vec<Warning>,
|
pub warnings: &'a mut Vec<Warning>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Environment<'a> {
|
impl<'a> Environment<'a> {
|
||||||
|
pub fn find_module(&self, fragments: &[String], location: Span) -> Result<&'a TypeInfo, Error> {
|
||||||
|
let mut name = fragments.join("/");
|
||||||
|
|
||||||
|
let is_env = name == ast::ENV_MODULE;
|
||||||
|
|
||||||
|
if is_env {
|
||||||
|
name = self
|
||||||
|
.target_env
|
||||||
|
.unwrap_or(ast::DEFAULT_ENV_MODULE)
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.importable_modules.get(&name).ok_or_else(|| {
|
||||||
|
if is_env {
|
||||||
|
Error::UnknownEnvironment {
|
||||||
|
name,
|
||||||
|
known_environments: self
|
||||||
|
.importable_modules
|
||||||
|
.values()
|
||||||
|
.filter_map(|m| match m.kind {
|
||||||
|
ModuleKind::Env => Some(m.name.clone()),
|
||||||
|
ModuleKind::Lib | ModuleKind::Validator | ModuleKind::Config => None,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error::UnknownModule {
|
||||||
|
location,
|
||||||
|
name,
|
||||||
|
known_modules: self.importable_modules.keys().cloned().collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn close_scope(&mut self, data: ScopeResetData) {
|
pub fn close_scope(&mut self, data: ScopeResetData) {
|
||||||
let unused = self
|
let unused = self
|
||||||
.entity_usages
|
.entity_usages
|
||||||
|
@ -351,7 +389,7 @@ impl<'a> Environment<'a> {
|
||||||
.ok_or_else(|| Error::UnknownModule {
|
.ok_or_else(|| Error::UnknownModule {
|
||||||
location,
|
location,
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
imported_modules: self
|
known_modules: self
|
||||||
.importable_modules
|
.importable_modules
|
||||||
.keys()
|
.keys()
|
||||||
.map(|t| t.to_string())
|
.map(|t| t.to_string())
|
||||||
|
@ -397,7 +435,7 @@ impl<'a> Environment<'a> {
|
||||||
.get(m)
|
.get(m)
|
||||||
.ok_or_else(|| Error::UnknownModule {
|
.ok_or_else(|| Error::UnknownModule {
|
||||||
name: m.to_string(),
|
name: m.to_string(),
|
||||||
imported_modules: self
|
known_modules: self
|
||||||
.importable_modules
|
.importable_modules
|
||||||
.keys()
|
.keys()
|
||||||
.map(|t| t.to_string())
|
.map(|t| t.to_string())
|
||||||
|
@ -705,6 +743,7 @@ impl<'a> Environment<'a> {
|
||||||
current_kind: &'a ModuleKind,
|
current_kind: &'a ModuleKind,
|
||||||
importable_modules: &'a HashMap<String, TypeInfo>,
|
importable_modules: &'a HashMap<String, TypeInfo>,
|
||||||
warnings: &'a mut Vec<Warning>,
|
warnings: &'a mut Vec<Warning>,
|
||||||
|
target_env: Option<&'a str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let prelude = importable_modules
|
let prelude = importable_modules
|
||||||
.get("aiken")
|
.get("aiken")
|
||||||
|
@ -731,6 +770,7 @@ impl<'a> Environment<'a> {
|
||||||
annotations: HashMap::new(),
|
annotations: HashMap::new(),
|
||||||
warnings,
|
warnings,
|
||||||
entity_usages: vec![HashMap::new()],
|
entity_usages: vec![HashMap::new()],
|
||||||
|
target_env,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,24 +812,16 @@ impl<'a> Environment<'a> {
|
||||||
location,
|
location,
|
||||||
package: _,
|
package: _,
|
||||||
}) => {
|
}) => {
|
||||||
let name = module.join("/");
|
let module_info = self.find_module(module, *location)?;
|
||||||
|
|
||||||
// Find imported module
|
|
||||||
let module_info =
|
|
||||||
self.importable_modules
|
|
||||||
.get(&name)
|
|
||||||
.ok_or_else(|| Error::UnknownModule {
|
|
||||||
location: *location,
|
|
||||||
name: name.clone(),
|
|
||||||
imported_modules: self.imported_modules.keys().cloned().collect(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if module_info.kind.is_validator()
|
if module_info.kind.is_validator()
|
||||||
&& (self.current_kind.is_lib() || !self.current_module.starts_with("tests"))
|
&& (self.current_kind.is_lib()
|
||||||
|
|| self.current_kind.is_env()
|
||||||
|
|| !self.current_module.starts_with("tests"))
|
||||||
{
|
{
|
||||||
return Err(Error::ValidatorImported {
|
return Err(Error::ValidatorImported {
|
||||||
location: *location,
|
location: *location,
|
||||||
name,
|
name: module.join("/"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1710,7 +1742,7 @@ impl<'a> Environment<'a> {
|
||||||
.ok_or_else(|| Error::UnknownModule {
|
.ok_or_else(|| Error::UnknownModule {
|
||||||
location,
|
location,
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
imported_modules: self
|
known_modules: self
|
||||||
.importable_modules
|
.importable_modules
|
||||||
.keys()
|
.keys()
|
||||||
.map(|t| t.to_string())
|
.map(|t| t.to_string())
|
||||||
|
|
|
@ -751,13 +751,39 @@ Perhaps, try the following:
|
||||||
#[diagnostic(code("unknown::module"))]
|
#[diagnostic(code("unknown::module"))]
|
||||||
#[diagnostic(help(
|
#[diagnostic(help(
|
||||||
"{}",
|
"{}",
|
||||||
suggest_neighbor(name, imported_modules.iter(), "Did you forget to add a package as dependency?")
|
suggest_neighbor(name, known_modules.iter(), "Did you forget to add a package as dependency?")
|
||||||
))]
|
))]
|
||||||
UnknownModule {
|
UnknownModule {
|
||||||
#[label]
|
#[label]
|
||||||
location: Span,
|
location: Span,
|
||||||
name: String,
|
name: String,
|
||||||
imported_modules: Vec<String>,
|
known_modules: Vec<String>,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[error(
|
||||||
|
"I couldn't find any module for the environment: '{}'\n",
|
||||||
|
name.if_supports_color(Stdout, |s| s.purple())
|
||||||
|
)]
|
||||||
|
#[diagnostic(code("unknown::environment"))]
|
||||||
|
#[diagnostic(help(
|
||||||
|
"{}{}",
|
||||||
|
if known_environments.is_empty() {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"I know about the following environments:\n{}\n\n",
|
||||||
|
known_environments
|
||||||
|
.iter()
|
||||||
|
.map(|s| format!("─▶ {}", s.if_supports_color(Stdout, |s| s.purple())))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
)
|
||||||
|
},
|
||||||
|
suggest_neighbor(name, known_environments.iter(), "Did you forget to define this environment?")
|
||||||
|
))]
|
||||||
|
UnknownEnvironment {
|
||||||
|
name: String,
|
||||||
|
known_environments: Vec<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
|
@ -1066,6 +1092,7 @@ impl ExtraData for Error {
|
||||||
| Error::UnknownModuleType { .. }
|
| Error::UnknownModuleType { .. }
|
||||||
| Error::UnknownModuleValue { .. }
|
| Error::UnknownModuleValue { .. }
|
||||||
| Error::UnknownRecordField { .. }
|
| Error::UnknownRecordField { .. }
|
||||||
|
| Error::UnknownEnvironment { .. }
|
||||||
| Error::UnnecessarySpreadOperator { .. }
|
| Error::UnnecessarySpreadOperator { .. }
|
||||||
| Error::UpdateMultiConstructorType { .. }
|
| Error::UpdateMultiConstructorType { .. }
|
||||||
| Error::ValidatorImported { .. }
|
| Error::ValidatorImported { .. }
|
||||||
|
|
|
@ -956,9 +956,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
.ok_or_else(|| Error::UnknownModule {
|
.ok_or_else(|| Error::UnknownModule {
|
||||||
name: module_alias.to_string(),
|
name: module_alias.to_string(),
|
||||||
location: *module_location,
|
location: *module_location,
|
||||||
imported_modules: self
|
known_modules: self
|
||||||
.environment
|
.environment
|
||||||
.imported_modules
|
.importable_modules
|
||||||
.keys()
|
.keys()
|
||||||
.map(|t| t.to_string())
|
.map(|t| t.to_string())
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -2327,9 +2327,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
.ok_or_else(|| Error::UnknownModule {
|
.ok_or_else(|| Error::UnknownModule {
|
||||||
location: *location,
|
location: *location,
|
||||||
name: module_name.to_string(),
|
name: module_name.to_string(),
|
||||||
imported_modules: self
|
known_modules: self
|
||||||
.environment
|
.environment
|
||||||
.imported_modules
|
.importable_modules
|
||||||
.keys()
|
.keys()
|
||||||
.map(|t| t.to_string())
|
.map(|t| t.to_string())
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
|
@ -19,6 +19,7 @@ use crate::{
|
||||||
use std::{borrow::Borrow, collections::HashMap, ops::Deref, rc::Rc};
|
use std::{borrow::Borrow, collections::HashMap, ops::Deref, rc::Rc};
|
||||||
|
|
||||||
impl UntypedModule {
|
impl UntypedModule {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn infer(
|
pub fn infer(
|
||||||
mut self,
|
mut self,
|
||||||
id_gen: &IdGenerator,
|
id_gen: &IdGenerator,
|
||||||
|
@ -27,11 +28,12 @@ impl UntypedModule {
|
||||||
modules: &HashMap<String, TypeInfo>,
|
modules: &HashMap<String, TypeInfo>,
|
||||||
tracing: Tracing,
|
tracing: Tracing,
|
||||||
warnings: &mut Vec<Warning>,
|
warnings: &mut Vec<Warning>,
|
||||||
|
env: Option<&str>,
|
||||||
) -> Result<TypedModule, Error> {
|
) -> Result<TypedModule, Error> {
|
||||||
let module_name = self.name.clone();
|
let module_name = self.name.clone();
|
||||||
let docs = std::mem::take(&mut self.docs);
|
let docs = std::mem::take(&mut self.docs);
|
||||||
let mut environment =
|
let mut environment =
|
||||||
Environment::new(id_gen.clone(), &module_name, &kind, modules, warnings);
|
Environment::new(id_gen.clone(), &module_name, &kind, modules, warnings, env);
|
||||||
|
|
||||||
let mut type_names = HashMap::with_capacity(self.definitions.len());
|
let mut type_names = HashMap::with_capacity(self.definitions.len());
|
||||||
let mut value_names = HashMap::with_capacity(self.definitions.len());
|
let mut value_names = HashMap::with_capacity(self.definitions.len());
|
||||||
|
@ -574,18 +576,7 @@ fn infer_definition(
|
||||||
unqualified,
|
unqualified,
|
||||||
package: _,
|
package: _,
|
||||||
}) => {
|
}) => {
|
||||||
let name = module.join("/");
|
let module_info = environment.find_module(&module, location)?;
|
||||||
|
|
||||||
// Find imported module
|
|
||||||
let module_info =
|
|
||||||
environment
|
|
||||||
.importable_modules
|
|
||||||
.get(&name)
|
|
||||||
.ok_or_else(|| Error::UnknownModule {
|
|
||||||
location,
|
|
||||||
name,
|
|
||||||
imported_modules: environment.imported_modules.keys().cloned().collect(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Definition::Use(Use {
|
Ok(Definition::Use(Use {
|
||||||
location,
|
location,
|
||||||
|
|
|
@ -40,6 +40,7 @@ impl LspProject {
|
||||||
u32::default(),
|
u32::default(),
|
||||||
PropertyTest::DEFAULT_MAX_SUCCESS,
|
PropertyTest::DEFAULT_MAX_SUCCESS,
|
||||||
Tracing::silent(),
|
Tracing::silent(),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.project.restore(checkpoint);
|
self.project.restore(checkpoint);
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
use std::{fmt::Display, fs, io, path::Path};
|
|
||||||
|
|
||||||
use crate::{github::repo::LatestRelease, package_name::PackageName, paths, Error};
|
use crate::{github::repo::LatestRelease, package_name::PackageName, paths, Error};
|
||||||
use aiken_lang::ast::Span;
|
|
||||||
use semver::Version;
|
|
||||||
|
|
||||||
use miette::NamedSource;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub use aiken_lang::plutus_version::PlutusVersion;
|
pub use aiken_lang::plutus_version::PlutusVersion;
|
||||||
|
use aiken_lang::{
|
||||||
|
ast::{
|
||||||
|
Annotation, ByteArrayFormatPreference, Constant, ModuleConstant, Span, UntypedDefinition,
|
||||||
|
},
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::token::Base,
|
||||||
|
};
|
||||||
|
use miette::NamedSource;
|
||||||
|
use semver::Version;
|
||||||
|
use serde::{
|
||||||
|
de,
|
||||||
|
ser::{self, SerializeSeq, SerializeStruct},
|
||||||
|
Deserialize, Serialize,
|
||||||
|
};
|
||||||
|
use std::{collections::BTreeMap, fmt::Display, fs, io, path::Path};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone)]
|
#[derive(Deserialize, Serialize, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
@ -27,6 +34,195 @@ pub struct Config {
|
||||||
pub repository: Option<Repository>,
|
pub repository: Option<Repository>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub dependencies: Vec<Dependency>,
|
pub dependencies: Vec<Dependency>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub config: BTreeMap<String, BTreeMap<String, SimpleExpr>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum SimpleExpr {
|
||||||
|
Int(i64),
|
||||||
|
Bool(bool),
|
||||||
|
ByteArray(Vec<u8>, ByteArrayFormatPreference),
|
||||||
|
List(Vec<SimpleExpr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleExpr {
|
||||||
|
pub fn as_untyped_expr(&self) -> UntypedExpr {
|
||||||
|
match self {
|
||||||
|
SimpleExpr::Bool(b) => UntypedExpr::Var {
|
||||||
|
location: Span::empty(),
|
||||||
|
name: if *b { "True" } else { "False" }.to_string(),
|
||||||
|
},
|
||||||
|
SimpleExpr::Int(i) => UntypedExpr::UInt {
|
||||||
|
location: Span::empty(),
|
||||||
|
value: format!("{i}"),
|
||||||
|
base: Base::Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SimpleExpr::ByteArray(bs, preferred_format) => UntypedExpr::ByteArray {
|
||||||
|
location: Span::empty(),
|
||||||
|
bytes: bs.to_vec(),
|
||||||
|
preferred_format: *preferred_format,
|
||||||
|
},
|
||||||
|
SimpleExpr::List(es) => UntypedExpr::List {
|
||||||
|
location: Span::empty(),
|
||||||
|
elements: es.iter().map(|e| e.as_untyped_expr()).collect(),
|
||||||
|
tail: None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_definition(&self, identifier: &str) -> UntypedDefinition {
|
||||||
|
let location = Span::empty();
|
||||||
|
|
||||||
|
let (value, annotation) = match self {
|
||||||
|
SimpleExpr::Bool(..) => todo!("requires https://github.com/aiken-lang/aiken/pull/992"),
|
||||||
|
SimpleExpr::Int(i) => (
|
||||||
|
// TODO: Replace with 'self.as_untyped_expr()' after https://github.com/aiken-lang/aiken/pull/992
|
||||||
|
Constant::Int {
|
||||||
|
location,
|
||||||
|
value: format!("{i}"),
|
||||||
|
base: Base::Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Some(Annotation::int(location)),
|
||||||
|
),
|
||||||
|
SimpleExpr::ByteArray(bs, preferred_format) => (
|
||||||
|
// TODO: Replace with 'self.as_untyped_expr()' after https://github.com/aiken-lang/aiken/pull/992
|
||||||
|
Constant::ByteArray {
|
||||||
|
location,
|
||||||
|
bytes: bs.to_vec(),
|
||||||
|
preferred_format: *preferred_format,
|
||||||
|
},
|
||||||
|
Some(Annotation::bytearray(location)),
|
||||||
|
),
|
||||||
|
SimpleExpr::List(..) => todo!("requires https://github.com/aiken-lang/aiken/pull/992"),
|
||||||
|
};
|
||||||
|
|
||||||
|
UntypedDefinition::ModuleConstant(ModuleConstant {
|
||||||
|
location: Span::empty(),
|
||||||
|
doc: None,
|
||||||
|
public: true,
|
||||||
|
name: identifier.to_string(),
|
||||||
|
annotation,
|
||||||
|
value: Box::new(value),
|
||||||
|
tipo: (),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for SimpleExpr {
|
||||||
|
fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
match self {
|
||||||
|
SimpleExpr::Bool(b) => serializer.serialize_bool(*b),
|
||||||
|
SimpleExpr::Int(i) => serializer.serialize_i64(*i),
|
||||||
|
SimpleExpr::ByteArray(bs, preferred_format) => match preferred_format {
|
||||||
|
ByteArrayFormatPreference::Utf8String => {
|
||||||
|
serializer.serialize_str(String::from_utf8(bs.to_vec()).unwrap().as_str())
|
||||||
|
}
|
||||||
|
ByteArrayFormatPreference::ArrayOfBytes(..)
|
||||||
|
| ByteArrayFormatPreference::HexadecimalString => {
|
||||||
|
let mut s = serializer.serialize_struct("ByteArray", 2)?;
|
||||||
|
s.serialize_field("bytes", &hex::encode(bs))?;
|
||||||
|
s.serialize_field("encoding", "base16")?;
|
||||||
|
s.end()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SimpleExpr::List(es) => {
|
||||||
|
let mut seq = serializer.serialize_seq(Some(es.len()))?;
|
||||||
|
for e in es {
|
||||||
|
seq.serialize_element(e)?;
|
||||||
|
}
|
||||||
|
seq.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deserialize<'a> for SimpleExpr {
|
||||||
|
fn deserialize<D: de::Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
|
struct SimpleExprVisitor;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
enum Encoding {
|
||||||
|
#[serde(rename(deserialize = "utf8"))]
|
||||||
|
Utf8,
|
||||||
|
#[serde(rename(deserialize = "utf-8"))]
|
||||||
|
Utf8Bis,
|
||||||
|
#[serde(rename(deserialize = "hex"))]
|
||||||
|
Hex,
|
||||||
|
#[serde(rename(deserialize = "base16"))]
|
||||||
|
Base16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Bytes {
|
||||||
|
bytes: String,
|
||||||
|
encoding: Encoding,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> de::Visitor<'a> for SimpleExprVisitor {
|
||||||
|
type Value = SimpleExpr;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("Int | Bool | ByteArray | List<any_of_those>")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bool<E>(self, b: bool) -> Result<Self::Value, E> {
|
||||||
|
Ok(SimpleExpr::Bool(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_i64<E>(self, i: i64) -> Result<Self::Value, E> {
|
||||||
|
Ok(SimpleExpr::Int(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> {
|
||||||
|
Ok(SimpleExpr::ByteArray(
|
||||||
|
s.as_bytes().to_vec(),
|
||||||
|
ByteArrayFormatPreference::Utf8String,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
|
||||||
|
where
|
||||||
|
V: de::MapAccess<'a>,
|
||||||
|
{
|
||||||
|
let Bytes { bytes, encoding } =
|
||||||
|
Bytes::deserialize(de::value::MapAccessDeserializer::new(map))?;
|
||||||
|
|
||||||
|
match encoding {
|
||||||
|
Encoding::Hex | Encoding::Base16 => match hex::decode(&bytes) {
|
||||||
|
Err(e) => Err(de::Error::custom(format!("invalid base16 string: {e:?}"))),
|
||||||
|
Ok(bytes) => Ok(SimpleExpr::ByteArray(
|
||||||
|
bytes,
|
||||||
|
ByteArrayFormatPreference::HexadecimalString,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
Encoding::Utf8 | Encoding::Utf8Bis => Ok(SimpleExpr::ByteArray(
|
||||||
|
bytes.as_bytes().to_vec(),
|
||||||
|
ByteArrayFormatPreference::Utf8String,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: de::SeqAccess<'a>,
|
||||||
|
{
|
||||||
|
let mut es = Vec::new();
|
||||||
|
|
||||||
|
while let Some(e) = seq.next_element()? {
|
||||||
|
es.push(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SimpleExpr::List(es))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(SimpleExprVisitor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_version<'de, D>(deserializer: D) -> Result<Version, D::Error>
|
fn deserialize_version<'de, D>(deserializer: D) -> Result<Version, D::Error>
|
||||||
|
@ -108,6 +304,7 @@ impl Config {
|
||||||
},
|
},
|
||||||
source: Platform::Github,
|
source: Platform::Github,
|
||||||
}],
|
}],
|
||||||
|
config: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,3 +378,53 @@ Version: {}"#,
|
||||||
compiler_version(true),
|
compiler_version(true),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use proptest::prelude::*;
|
||||||
|
|
||||||
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
|
fn arbitrary_simple_expr() -> impl Strategy<Value = SimpleExpr> {
|
||||||
|
let leaf = prop_oneof![
|
||||||
|
(any::<i64>)().prop_map(SimpleExpr::Int),
|
||||||
|
(any::<bool>)().prop_map(SimpleExpr::Bool),
|
||||||
|
"[a-z0-9]*".prop_map(|bytes| SimpleExpr::ByteArray(
|
||||||
|
bytes.as_bytes().to_vec(),
|
||||||
|
ByteArrayFormatPreference::Utf8String
|
||||||
|
)),
|
||||||
|
"([0-9a-f][0-9a-f])*".prop_map(|bytes| SimpleExpr::ByteArray(
|
||||||
|
bytes.as_bytes().to_vec(),
|
||||||
|
ByteArrayFormatPreference::HexadecimalString
|
||||||
|
))
|
||||||
|
];
|
||||||
|
|
||||||
|
leaf.prop_recursive(3, 8, 3, |inner| {
|
||||||
|
prop_oneof![
|
||||||
|
inner.clone(),
|
||||||
|
prop::collection::vec(inner.clone(), 0..3).prop_map(SimpleExpr::List)
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct TestConfig {
|
||||||
|
expr: SimpleExpr,
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn round_trip_simple_expr(expr in arbitrary_simple_expr()) {
|
||||||
|
let pretty = toml::to_string_pretty(&TestConfig { expr });
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
pretty.as_ref().map(|s| toml::from_str::<TestConfig>(s.as_str())),
|
||||||
|
Ok(Ok(..)),
|
||||||
|
),
|
||||||
|
"\ncounterexample: {}\n",
|
||||||
|
pretty.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -127,6 +127,9 @@ pub enum Error {
|
||||||
|
|
||||||
#[error("I couldn't find any exportable function named '{name}' in module '{module}'.")]
|
#[error("I couldn't find any exportable function named '{name}' in module '{module}'.")]
|
||||||
ExportNotFound { module: String, name: String },
|
ExportNotFound { module: String, name: String },
|
||||||
|
|
||||||
|
#[error("I located conditional modules under 'env', but no default one!")]
|
||||||
|
NoDefaultEnvironment,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
|
@ -195,6 +198,7 @@ impl ExtraData for Error {
|
||||||
| Error::NoValidatorNotFound { .. }
|
| Error::NoValidatorNotFound { .. }
|
||||||
| Error::MoreThanOneValidatorFound { .. }
|
| Error::MoreThanOneValidatorFound { .. }
|
||||||
| Error::Module { .. }
|
| Error::Module { .. }
|
||||||
|
| Error::NoDefaultEnvironment { .. }
|
||||||
| Error::ExportNotFound { .. } => None,
|
| Error::ExportNotFound { .. } => None,
|
||||||
Error::Type { error, .. } => error.extra_data(),
|
Error::Type { error, .. } => error.extra_data(),
|
||||||
}
|
}
|
||||||
|
@ -224,6 +228,7 @@ impl GetSource for Error {
|
||||||
| Error::NoValidatorNotFound { .. }
|
| Error::NoValidatorNotFound { .. }
|
||||||
| Error::MoreThanOneValidatorFound { .. }
|
| Error::MoreThanOneValidatorFound { .. }
|
||||||
| Error::ExportNotFound { .. }
|
| Error::ExportNotFound { .. }
|
||||||
|
| Error::NoDefaultEnvironment { .. }
|
||||||
| Error::Module { .. } => None,
|
| Error::Module { .. } => None,
|
||||||
Error::DuplicateModule { second: path, .. }
|
Error::DuplicateModule { second: path, .. }
|
||||||
| Error::MissingManifest { path }
|
| Error::MissingManifest { path }
|
||||||
|
@ -252,6 +257,7 @@ impl GetSource for Error {
|
||||||
| Error::Json { .. }
|
| Error::Json { .. }
|
||||||
| Error::MalformedStakeAddress { .. }
|
| Error::MalformedStakeAddress { .. }
|
||||||
| Error::NoValidatorNotFound { .. }
|
| Error::NoValidatorNotFound { .. }
|
||||||
|
| Error::NoDefaultEnvironment { .. }
|
||||||
| Error::MoreThanOneValidatorFound { .. }
|
| Error::MoreThanOneValidatorFound { .. }
|
||||||
| Error::ExportNotFound { .. }
|
| Error::ExportNotFound { .. }
|
||||||
| Error::Module { .. } => None,
|
| Error::Module { .. } => None,
|
||||||
|
@ -307,6 +313,7 @@ impl Diagnostic for Error {
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
Error::ExportNotFound { .. } => None,
|
Error::ExportNotFound { .. } => None,
|
||||||
|
Error::NoDefaultEnvironment { .. } => None,
|
||||||
Error::Module(e) => e.code().map(boxed),
|
Error::Module(e) => e.code().map(boxed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,6 +337,9 @@ impl Diagnostic for Error {
|
||||||
Error::MissingManifest { .. } => Some(Box::new(
|
Error::MissingManifest { .. } => Some(Box::new(
|
||||||
"Try running `aiken new <REPOSITORY/PROJECT>` to initialise a project with an example manifest.",
|
"Try running `aiken new <REPOSITORY/PROJECT>` to initialise a project with an example manifest.",
|
||||||
)),
|
)),
|
||||||
|
Error::NoDefaultEnvironment { .. } => Some(Box::new(
|
||||||
|
"Environment module names are free, but there must be at least one named 'default.ak'.",
|
||||||
|
)),
|
||||||
Error::TomlLoading { .. } => None,
|
Error::TomlLoading { .. } => None,
|
||||||
Error::Format { .. } => None,
|
Error::Format { .. } => None,
|
||||||
Error::TestFailure { .. } => None,
|
Error::TestFailure { .. } => None,
|
||||||
|
@ -408,6 +418,7 @@ impl Diagnostic for Error {
|
||||||
Error::MalformedStakeAddress { .. } => None,
|
Error::MalformedStakeAddress { .. } => None,
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
|
Error::NoDefaultEnvironment { .. } => None,
|
||||||
Error::Module(e) => e.labels(),
|
Error::Module(e) => e.labels(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,6 +430,7 @@ impl Diagnostic for Error {
|
||||||
Error::ImportCycle { .. } => None,
|
Error::ImportCycle { .. } => None,
|
||||||
Error::ExportNotFound { .. } => None,
|
Error::ExportNotFound { .. } => None,
|
||||||
Error::Blueprint(e) => e.source_code(),
|
Error::Blueprint(e) => e.source_code(),
|
||||||
|
Error::NoDefaultEnvironment { .. } => None,
|
||||||
Error::Parse { named, .. } => Some(named),
|
Error::Parse { named, .. } => Some(named),
|
||||||
Error::Type { named, .. } => Some(named),
|
Error::Type { named, .. } => Some(named),
|
||||||
Error::StandardIo(_) => None,
|
Error::StandardIo(_) => None,
|
||||||
|
@ -462,6 +474,7 @@ impl Diagnostic for Error {
|
||||||
Error::MalformedStakeAddress { .. } => None,
|
Error::MalformedStakeAddress { .. } => None,
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
|
Error::NoDefaultEnvironment { .. } => None,
|
||||||
Error::Module(e) => e.url(),
|
Error::Module(e) => e.url(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,6 +489,7 @@ impl Diagnostic for Error {
|
||||||
Error::Parse { .. } => None,
|
Error::Parse { .. } => None,
|
||||||
Error::Type { error, .. } => error.related(),
|
Error::Type { error, .. } => error.related(),
|
||||||
Error::StandardIo(_) => None,
|
Error::StandardIo(_) => None,
|
||||||
|
Error::NoDefaultEnvironment { .. } => None,
|
||||||
Error::MissingManifest { .. } => None,
|
Error::MissingManifest { .. } => None,
|
||||||
Error::TomlLoading { .. } => None,
|
Error::TomlLoading { .. } => None,
|
||||||
Error::Format { .. } => None,
|
Error::Format { .. } => None,
|
||||||
|
@ -512,6 +526,8 @@ pub enum Warning {
|
||||||
InvalidModuleName { path: PathBuf },
|
InvalidModuleName { path: PathBuf },
|
||||||
#[error("aiken.toml demands compiler version {demanded}, but you are using {current}.")]
|
#[error("aiken.toml demands compiler version {demanded}, but you are using {current}.")]
|
||||||
CompilerVersionMismatch { demanded: String, current: String },
|
CompilerVersionMismatch { demanded: String, current: String },
|
||||||
|
#[error("No configuration found for environment {env}.")]
|
||||||
|
NoConfigurationForEnv { env: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtraData for Warning {
|
impl ExtraData for Warning {
|
||||||
|
@ -520,7 +536,8 @@ impl ExtraData for Warning {
|
||||||
Warning::NoValidators { .. }
|
Warning::NoValidators { .. }
|
||||||
| Warning::DependencyAlreadyExists { .. }
|
| Warning::DependencyAlreadyExists { .. }
|
||||||
| Warning::InvalidModuleName { .. }
|
| Warning::InvalidModuleName { .. }
|
||||||
| Warning::CompilerVersionMismatch { .. } => None,
|
| Warning::CompilerVersionMismatch { .. }
|
||||||
|
| Warning::NoConfigurationForEnv { .. } => None,
|
||||||
Warning::Type { warning, .. } => warning.extra_data(),
|
Warning::Type { warning, .. } => warning.extra_data(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -532,6 +549,7 @@ impl GetSource for Warning {
|
||||||
Warning::InvalidModuleName { path } | Warning::Type { path, .. } => Some(path.clone()),
|
Warning::InvalidModuleName { path } | Warning::Type { path, .. } => Some(path.clone()),
|
||||||
Warning::NoValidators
|
Warning::NoValidators
|
||||||
| Warning::DependencyAlreadyExists { .. }
|
| Warning::DependencyAlreadyExists { .. }
|
||||||
|
| Warning::NoConfigurationForEnv { .. }
|
||||||
| Warning::CompilerVersionMismatch { .. } => None,
|
| Warning::CompilerVersionMismatch { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -542,6 +560,7 @@ impl GetSource for Warning {
|
||||||
Warning::NoValidators
|
Warning::NoValidators
|
||||||
| Warning::InvalidModuleName { .. }
|
| Warning::InvalidModuleName { .. }
|
||||||
| Warning::DependencyAlreadyExists { .. }
|
| Warning::DependencyAlreadyExists { .. }
|
||||||
|
| Warning::NoConfigurationForEnv { .. }
|
||||||
| Warning::CompilerVersionMismatch { .. } => None,
|
| Warning::CompilerVersionMismatch { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,6 +576,7 @@ impl Diagnostic for Warning {
|
||||||
Warning::Type { named, .. } => Some(named),
|
Warning::Type { named, .. } => Some(named),
|
||||||
Warning::NoValidators
|
Warning::NoValidators
|
||||||
| Warning::InvalidModuleName { .. }
|
| Warning::InvalidModuleName { .. }
|
||||||
|
| Warning::NoConfigurationForEnv { .. }
|
||||||
| Warning::DependencyAlreadyExists { .. }
|
| Warning::DependencyAlreadyExists { .. }
|
||||||
| Warning::CompilerVersionMismatch { .. } => None,
|
| Warning::CompilerVersionMismatch { .. } => None,
|
||||||
}
|
}
|
||||||
|
@ -568,6 +588,7 @@ impl Diagnostic for Warning {
|
||||||
Warning::InvalidModuleName { .. }
|
Warning::InvalidModuleName { .. }
|
||||||
| Warning::NoValidators
|
| Warning::NoValidators
|
||||||
| Warning::DependencyAlreadyExists { .. }
|
| Warning::DependencyAlreadyExists { .. }
|
||||||
|
| Warning::NoConfigurationForEnv { .. }
|
||||||
| Warning::CompilerVersionMismatch { .. } => None,
|
| Warning::CompilerVersionMismatch { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -586,6 +607,9 @@ impl Diagnostic for Warning {
|
||||||
Warning::DependencyAlreadyExists { .. } => {
|
Warning::DependencyAlreadyExists { .. } => {
|
||||||
Some(Box::new("aiken::packages::already_exists"))
|
Some(Box::new("aiken::packages::already_exists"))
|
||||||
}
|
}
|
||||||
|
Warning::NoConfigurationForEnv { .. } => {
|
||||||
|
Some(Box::new("aiken::project::config::missing::env"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,6 +627,9 @@ impl Diagnostic for Warning {
|
||||||
Warning::DependencyAlreadyExists { .. } => Some(Box::new(
|
Warning::DependencyAlreadyExists { .. } => Some(Box::new(
|
||||||
"If you need to change the version, try 'aiken packages upgrade' instead.",
|
"If you need to change the version, try 'aiken packages upgrade' instead.",
|
||||||
)),
|
)),
|
||||||
|
Warning::NoConfigurationForEnv { .. } => Some(Box::new(
|
||||||
|
"When configuration keys are missing for a target environment, no 'config' module will be created. This may lead to issues down the line.",
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,11 +32,12 @@ use crate::{
|
||||||
};
|
};
|
||||||
use aiken_lang::{
|
use aiken_lang::{
|
||||||
ast::{
|
ast::{
|
||||||
DataTypeKey, Definition, FunctionAccessKey, ModuleKind, Tracing, TypedDataType,
|
self, DataTypeKey, Definition, FunctionAccessKey, ModuleKind, Tracing, TypedDataType,
|
||||||
TypedFunction,
|
TypedFunction, UntypedDefinition,
|
||||||
},
|
},
|
||||||
builtins,
|
builtins,
|
||||||
expr::UntypedExpr,
|
expr::UntypedExpr,
|
||||||
|
format::{Formatter, DOCS_MAX_COLUMNS},
|
||||||
gen_uplc::CodeGenerator,
|
gen_uplc::CodeGenerator,
|
||||||
line_numbers::LineNumbers,
|
line_numbers::LineNumbers,
|
||||||
plutus_version::PlutusVersion,
|
plutus_version::PlutusVersion,
|
||||||
|
@ -78,6 +79,12 @@ pub struct Checkpoint {
|
||||||
defined_modules: HashMap<String, PathBuf>,
|
defined_modules: HashMap<String, PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum AddModuleBy {
|
||||||
|
Source { name: String, code: String },
|
||||||
|
Path(PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Project<T>
|
pub struct Project<T>
|
||||||
where
|
where
|
||||||
T: EventListener,
|
T: EventListener,
|
||||||
|
@ -184,10 +191,16 @@ where
|
||||||
self.defined_modules = checkpoint.defined_modules;
|
self.defined_modules = checkpoint.defined_modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(&mut self, uplc: bool, tracing: Tracing) -> Result<(), Vec<Error>> {
|
pub fn build(
|
||||||
|
&mut self,
|
||||||
|
uplc: bool,
|
||||||
|
tracing: Tracing,
|
||||||
|
env: Option<String>,
|
||||||
|
) -> Result<(), Vec<Error>> {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
code_gen_mode: CodeGenMode::Build(uplc),
|
code_gen_mode: CodeGenMode::Build(uplc),
|
||||||
tracing,
|
tracing,
|
||||||
|
env,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.compile(options)
|
self.compile(options)
|
||||||
|
@ -205,11 +218,13 @@ where
|
||||||
version: self.config.version.clone(),
|
version: self.config.version.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.read_source_files()?;
|
let config = self.config_definitions(None);
|
||||||
|
|
||||||
|
self.read_source_files(config)?;
|
||||||
|
|
||||||
let mut modules = self.parse_sources(self.config.name.clone())?;
|
let mut modules = self.parse_sources(self.config.name.clone())?;
|
||||||
|
|
||||||
self.type_check(&mut modules, Tracing::silent(), false)?;
|
self.type_check(&mut modules, Tracing::silent(), None, false)?;
|
||||||
|
|
||||||
let destination = destination.unwrap_or_else(|| self.root.join("docs"));
|
let destination = destination.unwrap_or_else(|| self.root.join("docs"));
|
||||||
|
|
||||||
|
@ -250,9 +265,11 @@ where
|
||||||
seed: u32,
|
seed: u32,
|
||||||
property_max_success: usize,
|
property_max_success: usize,
|
||||||
tracing: Tracing,
|
tracing: Tracing,
|
||||||
|
env: Option<String>,
|
||||||
) -> Result<(), Vec<Error>> {
|
) -> Result<(), Vec<Error>> {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
tracing,
|
tracing,
|
||||||
|
env,
|
||||||
code_gen_mode: if skip_tests {
|
code_gen_mode: if skip_tests {
|
||||||
CodeGenMode::NoOp
|
CodeGenMode::NoOp
|
||||||
} else {
|
} else {
|
||||||
|
@ -293,6 +310,32 @@ where
|
||||||
self.root.join("plutus.json")
|
self.root.join("plutus.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn config_definitions(&mut self, env: Option<&str>) -> Option<Vec<UntypedDefinition>> {
|
||||||
|
if !self.config.config.is_empty() {
|
||||||
|
let env = env.unwrap_or(ast::DEFAULT_ENV_MODULE);
|
||||||
|
|
||||||
|
match self.config.config.get(env) {
|
||||||
|
None => {
|
||||||
|
self.warnings.push(Warning::NoConfigurationForEnv {
|
||||||
|
env: env.to_string(),
|
||||||
|
});
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Some(config) => {
|
||||||
|
let mut conf_definitions = Vec::new();
|
||||||
|
|
||||||
|
for (identifier, value) in config.iter() {
|
||||||
|
conf_definitions.push(value.as_definition(identifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(conf_definitions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compile(&mut self, options: Options) -> Result<(), Vec<Error>> {
|
pub fn compile(&mut self, options: Options) -> Result<(), Vec<Error>> {
|
||||||
self.event_listener
|
self.event_listener
|
||||||
.handle_event(Event::StartingCompilation {
|
.handle_event(Event::StartingCompilation {
|
||||||
|
@ -301,11 +344,15 @@ where
|
||||||
version: self.config.version.clone(),
|
version: self.config.version.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.read_source_files()?;
|
let env = options.env.as_deref();
|
||||||
|
|
||||||
|
let config = self.config_definitions(env);
|
||||||
|
|
||||||
|
self.read_source_files(config)?;
|
||||||
|
|
||||||
let mut modules = self.parse_sources(self.config.name.clone())?;
|
let mut modules = self.parse_sources(self.config.name.clone())?;
|
||||||
|
|
||||||
self.type_check(&mut modules, options.tracing, true)?;
|
self.type_check(&mut modules, options.tracing, env, true)?;
|
||||||
|
|
||||||
match options.code_gen_mode {
|
match options.code_gen_mode {
|
||||||
CodeGenMode::Build(uplc_dump) => {
|
CodeGenMode::Build(uplc_dump) => {
|
||||||
|
@ -610,12 +657,28 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_source_files(&mut self) -> Result<(), Error> {
|
fn read_source_files(&mut self, config: Option<Vec<UntypedDefinition>>) -> Result<(), Error> {
|
||||||
|
let env = self.root.join("env");
|
||||||
let lib = self.root.join("lib");
|
let lib = self.root.join("lib");
|
||||||
let validators = self.root.join("validators");
|
let validators = self.root.join("validators");
|
||||||
|
let root = self.root.clone();
|
||||||
|
|
||||||
|
if let Some(defs) = config {
|
||||||
|
self.add_module(
|
||||||
|
AddModuleBy::Source {
|
||||||
|
name: ast::CONFIG_MODULE.to_string(),
|
||||||
|
code: Formatter::new()
|
||||||
|
.definitions(&defs[..])
|
||||||
|
.to_pretty_string(DOCS_MAX_COLUMNS),
|
||||||
|
},
|
||||||
|
&root,
|
||||||
|
ModuleKind::Config,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
self.aiken_files(&validators, ModuleKind::Validator)?;
|
self.aiken_files(&validators, ModuleKind::Validator)?;
|
||||||
self.aiken_files(&lib, ModuleKind::Lib)?;
|
self.aiken_files(&lib, ModuleKind::Lib)?;
|
||||||
|
self.aiken_files(&env, ModuleKind::Env)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -721,6 +784,7 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
modules: &mut ParsedModules,
|
modules: &mut ParsedModules,
|
||||||
tracing: Tracing,
|
tracing: Tracing,
|
||||||
|
env: Option<&str>,
|
||||||
validate_module_name: bool,
|
validate_module_name: bool,
|
||||||
) -> Result<(), Vec<Error>> {
|
) -> Result<(), Vec<Error>> {
|
||||||
let our_modules: BTreeSet<String> = modules.keys().cloned().collect();
|
let our_modules: BTreeSet<String> = modules.keys().cloned().collect();
|
||||||
|
@ -733,6 +797,7 @@ where
|
||||||
&self.id_gen,
|
&self.id_gen,
|
||||||
&self.config.name.to_string(),
|
&self.config.name.to_string(),
|
||||||
tracing,
|
tracing,
|
||||||
|
env,
|
||||||
validate_module_name,
|
validate_module_name,
|
||||||
&mut self.module_sources,
|
&mut self.module_sources,
|
||||||
&mut self.module_types,
|
&mut self.module_types,
|
||||||
|
@ -879,12 +944,18 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aiken_files(&mut self, dir: &Path, kind: ModuleKind) -> Result<(), Error> {
|
fn aiken_files(&mut self, dir: &Path, kind: ModuleKind) -> Result<(), Error> {
|
||||||
|
let mut has_default = None;
|
||||||
|
|
||||||
walkdir::WalkDir::new(dir)
|
walkdir::WalkDir::new(dir)
|
||||||
.follow_links(true)
|
.follow_links(true)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(Result::ok)
|
.filter_map(Result::ok)
|
||||||
.filter(|e| e.file_type().is_file())
|
.filter(|e| e.file_type().is_file())
|
||||||
.try_for_each(|d| {
|
.try_for_each(|d| {
|
||||||
|
if has_default.is_none() {
|
||||||
|
has_default = Some(false);
|
||||||
|
}
|
||||||
|
|
||||||
let path = d.into_path();
|
let path = d.into_path();
|
||||||
let keep = is_aiken_path(&path, dir);
|
let keep = is_aiken_path(&path, dir);
|
||||||
let ext = path.extension();
|
let ext = path.extension();
|
||||||
|
@ -895,19 +966,39 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
if keep {
|
if keep {
|
||||||
self.add_module(path, dir, kind)
|
if self.module_name(dir, &path).as_str() == ast::DEFAULT_ENV_MODULE {
|
||||||
|
has_default = Some(true);
|
||||||
|
}
|
||||||
|
self.add_module(AddModuleBy::Path(path), dir, kind)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
})
|
})?;
|
||||||
|
|
||||||
|
if kind == ModuleKind::Env && has_default == Some(false) {
|
||||||
|
return Err(Error::NoDefaultEnvironment);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_module(&mut self, path: PathBuf, dir: &Path, kind: ModuleKind) -> Result<(), Error> {
|
fn add_module(
|
||||||
let name = self.module_name(dir, &path);
|
&mut self,
|
||||||
let code = fs::read_to_string(&path).map_err(|error| Error::FileIo {
|
add_by: AddModuleBy,
|
||||||
path: path.clone(),
|
dir: &Path,
|
||||||
error,
|
kind: ModuleKind,
|
||||||
})?;
|
) -> Result<(), Error> {
|
||||||
|
let (name, code, path) = match add_by {
|
||||||
|
AddModuleBy::Path(path) => {
|
||||||
|
let name = self.module_name(dir, &path);
|
||||||
|
let code = fs::read_to_string(&path).map_err(|error| Error::FileIo {
|
||||||
|
path: path.clone(),
|
||||||
|
error,
|
||||||
|
})?;
|
||||||
|
(name, code, path)
|
||||||
|
}
|
||||||
|
AddModuleBy::Source { name, code } => (name, code, dir.to_path_buf()),
|
||||||
|
};
|
||||||
|
|
||||||
self.sources.push(Source {
|
self.sources.push(Source {
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -32,16 +32,9 @@ pub struct ParsedModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParsedModule {
|
impl ParsedModule {
|
||||||
pub fn deps_for_graph(&self) -> (String, Vec<String>) {
|
pub fn deps_for_graph(&self, env_modules: &[String]) -> (String, Vec<String>) {
|
||||||
let name = self.name.clone();
|
let name = self.name.clone();
|
||||||
|
let deps: Vec<_> = self.ast.dependencies(env_modules);
|
||||||
let deps: Vec<_> = self
|
|
||||||
.ast
|
|
||||||
.dependencies()
|
|
||||||
.into_iter()
|
|
||||||
.map(|(dep, _span)| dep)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
(name, deps)
|
(name, deps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +44,7 @@ impl ParsedModule {
|
||||||
id_gen: &IdGenerator,
|
id_gen: &IdGenerator,
|
||||||
package: &str,
|
package: &str,
|
||||||
tracing: Tracing,
|
tracing: Tracing,
|
||||||
|
env: Option<&str>,
|
||||||
validate_module_name: bool,
|
validate_module_name: bool,
|
||||||
module_sources: &mut HashMap<String, (String, LineNumbers)>,
|
module_sources: &mut HashMap<String, (String, LineNumbers)>,
|
||||||
module_types: &mut HashMap<String, TypeInfo>,
|
module_types: &mut HashMap<String, TypeInfo>,
|
||||||
|
@ -68,6 +62,7 @@ impl ParsedModule {
|
||||||
module_types,
|
module_types,
|
||||||
tracing,
|
tracing,
|
||||||
&mut warnings,
|
&mut warnings,
|
||||||
|
env,
|
||||||
)
|
)
|
||||||
.map_err(|error| Error::Type {
|
.map_err(|error| Error::Type {
|
||||||
path: self.path.clone(),
|
path: self.path.clone(),
|
||||||
|
@ -122,10 +117,19 @@ impl ParsedModules {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sequence(&self, our_modules: &BTreeSet<String>) -> Result<Vec<String>, Error> {
|
pub fn sequence(&self, our_modules: &BTreeSet<String>) -> Result<Vec<String>, Error> {
|
||||||
|
let env_modules = self
|
||||||
|
.0
|
||||||
|
.values()
|
||||||
|
.filter_map(|m| match m.kind {
|
||||||
|
ModuleKind::Env => Some(m.name.clone()),
|
||||||
|
ModuleKind::Lib | ModuleKind::Validator | ModuleKind::Config => None,
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let inputs = self
|
let inputs = self
|
||||||
.0
|
.0
|
||||||
.values()
|
.values()
|
||||||
.map(|m| m.deps_for_graph())
|
.map(|m| m.deps_for_graph(&env_modules))
|
||||||
.collect::<Vec<(String, Vec<String>)>>();
|
.collect::<Vec<(String, Vec<String>)>>();
|
||||||
|
|
||||||
let capacity = inputs.len();
|
let capacity = inputs.len();
|
||||||
|
|
|
@ -3,6 +3,7 @@ use aiken_lang::ast::Tracing;
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
pub code_gen_mode: CodeGenMode,
|
pub code_gen_mode: CodeGenMode,
|
||||||
pub tracing: Tracing,
|
pub tracing: Tracing,
|
||||||
|
pub env: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Options {
|
impl Default for Options {
|
||||||
|
@ -10,6 +11,7 @@ impl Default for Options {
|
||||||
Self {
|
Self {
|
||||||
code_gen_mode: CodeGenMode::NoOp,
|
code_gen_mode: CodeGenMode::NoOp,
|
||||||
tracing: Tracing::silent(),
|
tracing: Tracing::silent(),
|
||||||
|
env: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1314,6 +1314,7 @@ mod test {
|
||||||
&module_types,
|
&module_types,
|
||||||
Tracing::All(TraceLevel::Verbose),
|
Tracing::All(TraceLevel::Verbose),
|
||||||
&mut warnings,
|
&mut warnings,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.expect("Failed to type-check module.");
|
.expect("Failed to type-check module.");
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,7 @@ impl TestProject {
|
||||||
&self.module_types,
|
&self.module_types,
|
||||||
Tracing::All(TraceLevel::Verbose),
|
Tracing::All(TraceLevel::Verbose),
|
||||||
&mut warnings,
|
&mut warnings,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.expect("Failed to type-check module");
|
.expect("Failed to type-check module");
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use aiken_lang::ast::Tracing;
|
|
||||||
use aiken_project::watch::with_project;
|
use aiken_project::watch::with_project;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -20,10 +19,6 @@ pub struct Args {
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
delegated_to: Option<String>,
|
delegated_to: Option<String>,
|
||||||
|
|
||||||
/// Force the project to be rebuilt, otherwise relies on existing artifacts (i.e. plutus.json)
|
|
||||||
#[clap(long)]
|
|
||||||
rebuild: bool,
|
|
||||||
|
|
||||||
/// Output the address for mainnet (this command defaults to testnet)
|
/// Output the address for mainnet (this command defaults to testnet)
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
mainnet: bool,
|
mainnet: bool,
|
||||||
|
@ -35,15 +30,10 @@ pub fn exec(
|
||||||
module,
|
module,
|
||||||
validator,
|
validator,
|
||||||
delegated_to,
|
delegated_to,
|
||||||
rebuild,
|
|
||||||
mainnet,
|
mainnet,
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
with_project(directory.as_deref(), false, |p| {
|
with_project(directory.as_deref(), false, |p| {
|
||||||
if rebuild {
|
|
||||||
p.build(false, Tracing::silent())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let title = module.as_ref().map(|m| {
|
let title = module.as_ref().map(|m| {
|
||||||
format!(
|
format!(
|
||||||
"{m}{}",
|
"{m}{}",
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use aiken_lang::ast::Tracing;
|
|
||||||
use aiken_project::watch::with_project;
|
use aiken_project::watch::with_project;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -15,10 +14,6 @@ pub struct Args {
|
||||||
/// Name of the validator within the module. Optional if there's only one validator
|
/// Name of the validator within the module. Optional if there's only one validator
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
validator: Option<String>,
|
validator: Option<String>,
|
||||||
|
|
||||||
/// Force the project to be rebuilt, otherwise relies on existing artifacts (i.e. plutus.json)
|
|
||||||
#[clap(long)]
|
|
||||||
rebuild: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec(
|
pub fn exec(
|
||||||
|
@ -26,14 +21,9 @@ pub fn exec(
|
||||||
directory,
|
directory,
|
||||||
module,
|
module,
|
||||||
validator,
|
validator,
|
||||||
rebuild,
|
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
with_project(directory.as_deref(), false, |p| {
|
with_project(directory.as_deref(), false, |p| {
|
||||||
if rebuild {
|
|
||||||
p.build(false, Tracing::silent())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let title = module.as_ref().map(|m| {
|
let title = module.as_ref().map(|m| {
|
||||||
format!(
|
format!(
|
||||||
"{m}{}",
|
"{m}{}",
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use aiken_lang::ast::Tracing;
|
|
||||||
use aiken_project::watch::with_project;
|
use aiken_project::watch::with_project;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -15,10 +14,6 @@ pub struct Args {
|
||||||
/// Name of the validator within the module. Optional if there's only one validator
|
/// Name of the validator within the module. Optional if there's only one validator
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
validator: Option<String>,
|
validator: Option<String>,
|
||||||
|
|
||||||
/// Force the project to be rebuilt, otherwise relies on existing artifacts (i.e. plutus.json)
|
|
||||||
#[clap(long)]
|
|
||||||
rebuild: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec(
|
pub fn exec(
|
||||||
|
@ -26,14 +21,9 @@ pub fn exec(
|
||||||
directory,
|
directory,
|
||||||
module,
|
module,
|
||||||
validator,
|
validator,
|
||||||
rebuild,
|
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
with_project(directory.as_deref(), false, |p| {
|
with_project(directory.as_deref(), false, |p| {
|
||||||
if rebuild {
|
|
||||||
p.build(false, Tracing::silent())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let title = module.as_ref().map(|m| {
|
let title = module.as_ref().map(|m| {
|
||||||
format!(
|
format!(
|
||||||
"{m}{}",
|
"{m}{}",
|
||||||
|
|
|
@ -21,6 +21,10 @@ pub struct Args {
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
uplc: bool,
|
uplc: bool,
|
||||||
|
|
||||||
|
/// Environment to build against.
|
||||||
|
#[clap(long)]
|
||||||
|
env: Option<String>,
|
||||||
|
|
||||||
/// Filter traces to be included in the generated program(s).
|
/// Filter traces to be included in the generated program(s).
|
||||||
///
|
///
|
||||||
/// - user-defined:
|
/// - user-defined:
|
||||||
|
@ -63,6 +67,7 @@ pub fn exec(
|
||||||
uplc,
|
uplc,
|
||||||
filter_traces,
|
filter_traces,
|
||||||
trace_level,
|
trace_level,
|
||||||
|
env,
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
let result = if watch {
|
let result = if watch {
|
||||||
|
@ -73,6 +78,7 @@ pub fn exec(
|
||||||
Some(filter_traces) => filter_traces(trace_level),
|
Some(filter_traces) => filter_traces(trace_level),
|
||||||
None => Tracing::All(trace_level),
|
None => Tracing::All(trace_level),
|
||||||
},
|
},
|
||||||
|
env.clone(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -83,6 +89,7 @@ pub fn exec(
|
||||||
Some(filter_traces) => filter_traces(trace_level),
|
Some(filter_traces) => filter_traces(trace_level),
|
||||||
None => Tracing::All(trace_level),
|
None => Tracing::All(trace_level),
|
||||||
},
|
},
|
||||||
|
env.clone(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,6 +48,10 @@ pub struct Args {
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
exact_match: bool,
|
exact_match: bool,
|
||||||
|
|
||||||
|
/// Environment to build against.
|
||||||
|
#[clap(long)]
|
||||||
|
env: Option<String>,
|
||||||
|
|
||||||
/// Filter traces to be included in the generated program(s).
|
/// Filter traces to be included in the generated program(s).
|
||||||
///
|
///
|
||||||
/// - user-defined:
|
/// - user-defined:
|
||||||
|
@ -95,6 +99,7 @@ pub fn exec(
|
||||||
trace_level,
|
trace_level,
|
||||||
seed,
|
seed,
|
||||||
max_success,
|
max_success,
|
||||||
|
env,
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
@ -114,6 +119,7 @@ pub fn exec(
|
||||||
Some(filter_traces) => filter_traces(trace_level),
|
Some(filter_traces) => filter_traces(trace_level),
|
||||||
None => Tracing::All(trace_level),
|
None => Tracing::All(trace_level),
|
||||||
},
|
},
|
||||||
|
env.clone(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -129,6 +135,7 @@ pub fn exec(
|
||||||
Some(filter_traces) => filter_traces(trace_level),
|
Some(filter_traces) => filter_traces(trace_level),
|
||||||
None => Tracing::All(trace_level),
|
None => Tracing::All(trace_level),
|
||||||
},
|
},
|
||||||
|
env.clone(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue