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**: 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
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@ pub const BACKPASS_VARIABLE: &str = "_backpass";
|
|||
pub const CAPTURE_VARIABLE: &str = "_capture";
|
||||
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 UntypedModule = Module<(), UntypedDefinition>;
|
||||
|
||||
|
@ -28,6 +32,8 @@ pub type UntypedModule = Module<(), UntypedDefinition>;
|
|||
pub enum ModuleKind {
|
||||
Lib,
|
||||
Validator,
|
||||
Env,
|
||||
Config,
|
||||
}
|
||||
|
||||
impl ModuleKind {
|
||||
|
@ -38,6 +44,14 @@ impl ModuleKind {
|
|||
pub fn is_lib(&self) -> bool {
|
||||
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)]
|
||||
|
@ -61,16 +75,18 @@ impl<Info, Definitions> Module<Info, Definitions> {
|
|||
}
|
||||
|
||||
impl UntypedModule {
|
||||
pub fn dependencies(&self) -> Vec<(String, Span)> {
|
||||
pub fn dependencies(&self, env_modules: &[String]) -> Vec<String> {
|
||||
self.definitions()
|
||||
.flat_map(|def| {
|
||||
if let Definition::Use(Use {
|
||||
location, module, ..
|
||||
}) = def
|
||||
{
|
||||
Some((module.join("/"), *location))
|
||||
if let Definition::Use(Use { module, .. }) = def {
|
||||
let name = module.join("/");
|
||||
if name == ENV_MODULE {
|
||||
env_modules.to_vec()
|
||||
} else {
|
||||
vec![name]
|
||||
}
|
||||
} else {
|
||||
None
|
||||
Vec::new()
|
||||
}
|
||||
})
|
||||
.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 {
|
||||
Annotation::Constructor {
|
||||
name: "Data".to_string(),
|
||||
|
|
|
@ -25,8 +25,8 @@ use ordinal::Ordinal;
|
|||
use std::rc::Rc;
|
||||
use vec1::Vec1;
|
||||
|
||||
const INDENT: isize = 2;
|
||||
const DOCS_MAX_COLUMNS: isize = 80;
|
||||
pub const INDENT: isize = 2;
|
||||
pub const DOCS_MAX_COLUMNS: isize = 80;
|
||||
|
||||
pub fn pretty(writer: &mut String, module: UntypedModule, extra: ModuleExtra, src: &str) {
|
||||
let intermediate = Intermediate {
|
||||
|
@ -130,7 +130,7 @@ impl<'comments> Formatter<'comments> {
|
|||
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_declarations = false;
|
||||
let mut imports = Vec::new();
|
||||
|
|
|
@ -49,6 +49,7 @@ macro_rules! aiken_fn {
|
|||
$module_types,
|
||||
$crate::ast::Tracing::silent(),
|
||||
&mut warnings,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ fn check_module(
|
|||
&module_types,
|
||||
Tracing::All(TraceLevel::Verbose),
|
||||
&mut warnings,
|
||||
None,
|
||||
)
|
||||
.expect("extra dependency did not compile");
|
||||
module_types.insert(package.clone(), typed_module.type_info.clone());
|
||||
|
@ -50,6 +51,7 @@ fn check_module(
|
|||
&module_types,
|
||||
tracing,
|
||||
&mut warnings,
|
||||
None,
|
||||
);
|
||||
|
||||
result
|
||||
|
|
|
@ -7,7 +7,7 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
ast::{
|
||||
Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind,
|
||||
self, Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind,
|
||||
RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition, TypedFunction,
|
||||
TypedPattern, UnqualifiedImport, UntypedArg, UntypedDefinition, UntypedFunction, Use,
|
||||
Validator, PIPE_VARIABLE,
|
||||
|
@ -80,11 +80,49 @@ pub struct Environment<'a> {
|
|||
/// A mapping from known annotations to their resolved 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
|
||||
pub warnings: &'a mut Vec<Warning>,
|
||||
}
|
||||
|
||||
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) {
|
||||
let unused = self
|
||||
.entity_usages
|
||||
|
@ -351,7 +389,7 @@ impl<'a> Environment<'a> {
|
|||
.ok_or_else(|| Error::UnknownModule {
|
||||
location,
|
||||
name: name.to_string(),
|
||||
imported_modules: self
|
||||
known_modules: self
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
|
@ -397,7 +435,7 @@ impl<'a> Environment<'a> {
|
|||
.get(m)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
name: m.to_string(),
|
||||
imported_modules: self
|
||||
known_modules: self
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
|
@ -705,6 +743,7 @@ impl<'a> Environment<'a> {
|
|||
current_kind: &'a ModuleKind,
|
||||
importable_modules: &'a HashMap<String, TypeInfo>,
|
||||
warnings: &'a mut Vec<Warning>,
|
||||
target_env: Option<&'a str>,
|
||||
) -> Self {
|
||||
let prelude = importable_modules
|
||||
.get("aiken")
|
||||
|
@ -731,6 +770,7 @@ impl<'a> Environment<'a> {
|
|||
annotations: HashMap::new(),
|
||||
warnings,
|
||||
entity_usages: vec![HashMap::new()],
|
||||
target_env,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,24 +812,16 @@ impl<'a> Environment<'a> {
|
|||
location,
|
||||
package: _,
|
||||
}) => {
|
||||
let name = module.join("/");
|
||||
|
||||
// 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(),
|
||||
})?;
|
||||
let module_info = self.find_module(module, *location)?;
|
||||
|
||||
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 {
|
||||
location: *location,
|
||||
name,
|
||||
name: module.join("/"),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1710,7 +1742,7 @@ impl<'a> Environment<'a> {
|
|||
.ok_or_else(|| Error::UnknownModule {
|
||||
location,
|
||||
name: name.to_string(),
|
||||
imported_modules: self
|
||||
known_modules: self
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
|
|
|
@ -751,13 +751,39 @@ Perhaps, try the following:
|
|||
#[diagnostic(code("unknown::module"))]
|
||||
#[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 {
|
||||
#[label]
|
||||
location: Span,
|
||||
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(
|
||||
|
@ -1066,6 +1092,7 @@ impl ExtraData for Error {
|
|||
| Error::UnknownModuleType { .. }
|
||||
| Error::UnknownModuleValue { .. }
|
||||
| Error::UnknownRecordField { .. }
|
||||
| Error::UnknownEnvironment { .. }
|
||||
| Error::UnnecessarySpreadOperator { .. }
|
||||
| Error::UpdateMultiConstructorType { .. }
|
||||
| Error::ValidatorImported { .. }
|
||||
|
|
|
@ -956,9 +956,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
.ok_or_else(|| Error::UnknownModule {
|
||||
name: module_alias.to_string(),
|
||||
location: *module_location,
|
||||
imported_modules: self
|
||||
known_modules: self
|
||||
.environment
|
||||
.imported_modules
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
|
@ -2327,9 +2327,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
.ok_or_else(|| Error::UnknownModule {
|
||||
location: *location,
|
||||
name: module_name.to_string(),
|
||||
imported_modules: self
|
||||
known_modules: self
|
||||
.environment
|
||||
.imported_modules
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::{
|
|||
use std::{borrow::Borrow, collections::HashMap, ops::Deref, rc::Rc};
|
||||
|
||||
impl UntypedModule {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn infer(
|
||||
mut self,
|
||||
id_gen: &IdGenerator,
|
||||
|
@ -27,11 +28,12 @@ impl UntypedModule {
|
|||
modules: &HashMap<String, TypeInfo>,
|
||||
tracing: Tracing,
|
||||
warnings: &mut Vec<Warning>,
|
||||
env: Option<&str>,
|
||||
) -> Result<TypedModule, Error> {
|
||||
let module_name = self.name.clone();
|
||||
let docs = std::mem::take(&mut self.docs);
|
||||
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 value_names = HashMap::with_capacity(self.definitions.len());
|
||||
|
@ -574,18 +576,7 @@ fn infer_definition(
|
|||
unqualified,
|
||||
package: _,
|
||||
}) => {
|
||||
let name = module.join("/");
|
||||
|
||||
// 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(),
|
||||
})?;
|
||||
let module_info = environment.find_module(&module, location)?;
|
||||
|
||||
Ok(Definition::Use(Use {
|
||||
location,
|
||||
|
|
|
@ -40,6 +40,7 @@ impl LspProject {
|
|||
u32::default(),
|
||||
PropertyTest::DEFAULT_MAX_SUCCESS,
|
||||
Tracing::silent(),
|
||||
None,
|
||||
);
|
||||
|
||||
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 aiken_lang::ast::Span;
|
||||
use semver::Version;
|
||||
|
||||
use miette::NamedSource;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
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)]
|
||||
pub struct Config {
|
||||
|
@ -27,6 +34,195 @@ pub struct Config {
|
|||
pub repository: Option<Repository>,
|
||||
#[serde(default)]
|
||||
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>
|
||||
|
@ -108,6 +304,7 @@ impl Config {
|
|||
},
|
||||
source: Platform::Github,
|
||||
}],
|
||||
config: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,3 +378,53 @@ Version: {}"#,
|
|||
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}'.")]
|
||||
ExportNotFound { module: String, name: String },
|
||||
|
||||
#[error("I located conditional modules under 'env', but no default one!")]
|
||||
NoDefaultEnvironment,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
|
@ -195,6 +198,7 @@ impl ExtraData for Error {
|
|||
| Error::NoValidatorNotFound { .. }
|
||||
| Error::MoreThanOneValidatorFound { .. }
|
||||
| Error::Module { .. }
|
||||
| Error::NoDefaultEnvironment { .. }
|
||||
| Error::ExportNotFound { .. } => None,
|
||||
Error::Type { error, .. } => error.extra_data(),
|
||||
}
|
||||
|
@ -224,6 +228,7 @@ impl GetSource for Error {
|
|||
| Error::NoValidatorNotFound { .. }
|
||||
| Error::MoreThanOneValidatorFound { .. }
|
||||
| Error::ExportNotFound { .. }
|
||||
| Error::NoDefaultEnvironment { .. }
|
||||
| Error::Module { .. } => None,
|
||||
Error::DuplicateModule { second: path, .. }
|
||||
| Error::MissingManifest { path }
|
||||
|
@ -252,6 +257,7 @@ impl GetSource for Error {
|
|||
| Error::Json { .. }
|
||||
| Error::MalformedStakeAddress { .. }
|
||||
| Error::NoValidatorNotFound { .. }
|
||||
| Error::NoDefaultEnvironment { .. }
|
||||
| Error::MoreThanOneValidatorFound { .. }
|
||||
| Error::ExportNotFound { .. }
|
||||
| Error::Module { .. } => None,
|
||||
|
@ -307,6 +313,7 @@ impl Diagnostic for Error {
|
|||
Error::NoValidatorNotFound { .. } => None,
|
||||
Error::MoreThanOneValidatorFound { .. } => None,
|
||||
Error::ExportNotFound { .. } => None,
|
||||
Error::NoDefaultEnvironment { .. } => None,
|
||||
Error::Module(e) => e.code().map(boxed),
|
||||
}
|
||||
}
|
||||
|
@ -330,6 +337,9 @@ impl Diagnostic for Error {
|
|||
Error::MissingManifest { .. } => Some(Box::new(
|
||||
"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::Format { .. } => None,
|
||||
Error::TestFailure { .. } => None,
|
||||
|
@ -408,6 +418,7 @@ impl Diagnostic for Error {
|
|||
Error::MalformedStakeAddress { .. } => None,
|
||||
Error::NoValidatorNotFound { .. } => None,
|
||||
Error::MoreThanOneValidatorFound { .. } => None,
|
||||
Error::NoDefaultEnvironment { .. } => None,
|
||||
Error::Module(e) => e.labels(),
|
||||
}
|
||||
}
|
||||
|
@ -419,6 +430,7 @@ impl Diagnostic for Error {
|
|||
Error::ImportCycle { .. } => None,
|
||||
Error::ExportNotFound { .. } => None,
|
||||
Error::Blueprint(e) => e.source_code(),
|
||||
Error::NoDefaultEnvironment { .. } => None,
|
||||
Error::Parse { named, .. } => Some(named),
|
||||
Error::Type { named, .. } => Some(named),
|
||||
Error::StandardIo(_) => None,
|
||||
|
@ -462,6 +474,7 @@ impl Diagnostic for Error {
|
|||
Error::MalformedStakeAddress { .. } => None,
|
||||
Error::NoValidatorNotFound { .. } => None,
|
||||
Error::MoreThanOneValidatorFound { .. } => None,
|
||||
Error::NoDefaultEnvironment { .. } => None,
|
||||
Error::Module(e) => e.url(),
|
||||
}
|
||||
}
|
||||
|
@ -476,6 +489,7 @@ impl Diagnostic for Error {
|
|||
Error::Parse { .. } => None,
|
||||
Error::Type { error, .. } => error.related(),
|
||||
Error::StandardIo(_) => None,
|
||||
Error::NoDefaultEnvironment { .. } => None,
|
||||
Error::MissingManifest { .. } => None,
|
||||
Error::TomlLoading { .. } => None,
|
||||
Error::Format { .. } => None,
|
||||
|
@ -512,6 +526,8 @@ pub enum Warning {
|
|||
InvalidModuleName { path: PathBuf },
|
||||
#[error("aiken.toml demands compiler version {demanded}, but you are using {current}.")]
|
||||
CompilerVersionMismatch { demanded: String, current: String },
|
||||
#[error("No configuration found for environment {env}.")]
|
||||
NoConfigurationForEnv { env: String },
|
||||
}
|
||||
|
||||
impl ExtraData for Warning {
|
||||
|
@ -520,7 +536,8 @@ impl ExtraData for Warning {
|
|||
Warning::NoValidators { .. }
|
||||
| Warning::DependencyAlreadyExists { .. }
|
||||
| Warning::InvalidModuleName { .. }
|
||||
| Warning::CompilerVersionMismatch { .. } => None,
|
||||
| Warning::CompilerVersionMismatch { .. }
|
||||
| Warning::NoConfigurationForEnv { .. } => None,
|
||||
Warning::Type { warning, .. } => warning.extra_data(),
|
||||
}
|
||||
}
|
||||
|
@ -532,6 +549,7 @@ impl GetSource for Warning {
|
|||
Warning::InvalidModuleName { path } | Warning::Type { path, .. } => Some(path.clone()),
|
||||
Warning::NoValidators
|
||||
| Warning::DependencyAlreadyExists { .. }
|
||||
| Warning::NoConfigurationForEnv { .. }
|
||||
| Warning::CompilerVersionMismatch { .. } => None,
|
||||
}
|
||||
}
|
||||
|
@ -542,6 +560,7 @@ impl GetSource for Warning {
|
|||
Warning::NoValidators
|
||||
| Warning::InvalidModuleName { .. }
|
||||
| Warning::DependencyAlreadyExists { .. }
|
||||
| Warning::NoConfigurationForEnv { .. }
|
||||
| Warning::CompilerVersionMismatch { .. } => None,
|
||||
}
|
||||
}
|
||||
|
@ -557,6 +576,7 @@ impl Diagnostic for Warning {
|
|||
Warning::Type { named, .. } => Some(named),
|
||||
Warning::NoValidators
|
||||
| Warning::InvalidModuleName { .. }
|
||||
| Warning::NoConfigurationForEnv { .. }
|
||||
| Warning::DependencyAlreadyExists { .. }
|
||||
| Warning::CompilerVersionMismatch { .. } => None,
|
||||
}
|
||||
|
@ -568,6 +588,7 @@ impl Diagnostic for Warning {
|
|||
Warning::InvalidModuleName { .. }
|
||||
| Warning::NoValidators
|
||||
| Warning::DependencyAlreadyExists { .. }
|
||||
| Warning::NoConfigurationForEnv { .. }
|
||||
| Warning::CompilerVersionMismatch { .. } => None,
|
||||
}
|
||||
}
|
||||
|
@ -586,6 +607,9 @@ impl Diagnostic for Warning {
|
|||
Warning::DependencyAlreadyExists { .. } => {
|
||||
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(
|
||||
"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::{
|
||||
ast::{
|
||||
DataTypeKey, Definition, FunctionAccessKey, ModuleKind, Tracing, TypedDataType,
|
||||
TypedFunction,
|
||||
self, DataTypeKey, Definition, FunctionAccessKey, ModuleKind, Tracing, TypedDataType,
|
||||
TypedFunction, UntypedDefinition,
|
||||
},
|
||||
builtins,
|
||||
expr::UntypedExpr,
|
||||
format::{Formatter, DOCS_MAX_COLUMNS},
|
||||
gen_uplc::CodeGenerator,
|
||||
line_numbers::LineNumbers,
|
||||
plutus_version::PlutusVersion,
|
||||
|
@ -78,6 +79,12 @@ pub struct Checkpoint {
|
|||
defined_modules: HashMap<String, PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum AddModuleBy {
|
||||
Source { name: String, code: String },
|
||||
Path(PathBuf),
|
||||
}
|
||||
|
||||
pub struct Project<T>
|
||||
where
|
||||
T: EventListener,
|
||||
|
@ -184,10 +191,16 @@ where
|
|||
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 {
|
||||
code_gen_mode: CodeGenMode::Build(uplc),
|
||||
tracing,
|
||||
env,
|
||||
};
|
||||
|
||||
self.compile(options)
|
||||
|
@ -205,11 +218,13 @@ where
|
|||
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())?;
|
||||
|
||||
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"));
|
||||
|
||||
|
@ -250,9 +265,11 @@ where
|
|||
seed: u32,
|
||||
property_max_success: usize,
|
||||
tracing: Tracing,
|
||||
env: Option<String>,
|
||||
) -> Result<(), Vec<Error>> {
|
||||
let options = Options {
|
||||
tracing,
|
||||
env,
|
||||
code_gen_mode: if skip_tests {
|
||||
CodeGenMode::NoOp
|
||||
} else {
|
||||
|
@ -293,6 +310,32 @@ where
|
|||
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>> {
|
||||
self.event_listener
|
||||
.handle_event(Event::StartingCompilation {
|
||||
|
@ -301,11 +344,15 @@ where
|
|||
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())?;
|
||||
|
||||
self.type_check(&mut modules, options.tracing, true)?;
|
||||
self.type_check(&mut modules, options.tracing, env, true)?;
|
||||
|
||||
match options.code_gen_mode {
|
||||
CodeGenMode::Build(uplc_dump) => {
|
||||
|
@ -610,12 +657,28 @@ where
|
|||
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 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(&lib, ModuleKind::Lib)?;
|
||||
self.aiken_files(&env, ModuleKind::Env)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -721,6 +784,7 @@ where
|
|||
&mut self,
|
||||
modules: &mut ParsedModules,
|
||||
tracing: Tracing,
|
||||
env: Option<&str>,
|
||||
validate_module_name: bool,
|
||||
) -> Result<(), Vec<Error>> {
|
||||
let our_modules: BTreeSet<String> = modules.keys().cloned().collect();
|
||||
|
@ -733,6 +797,7 @@ where
|
|||
&self.id_gen,
|
||||
&self.config.name.to_string(),
|
||||
tracing,
|
||||
env,
|
||||
validate_module_name,
|
||||
&mut self.module_sources,
|
||||
&mut self.module_types,
|
||||
|
@ -879,12 +944,18 @@ where
|
|||
}
|
||||
|
||||
fn aiken_files(&mut self, dir: &Path, kind: ModuleKind) -> Result<(), Error> {
|
||||
let mut has_default = None;
|
||||
|
||||
walkdir::WalkDir::new(dir)
|
||||
.follow_links(true)
|
||||
.into_iter()
|
||||
.filter_map(Result::ok)
|
||||
.filter(|e| e.file_type().is_file())
|
||||
.try_for_each(|d| {
|
||||
if has_default.is_none() {
|
||||
has_default = Some(false);
|
||||
}
|
||||
|
||||
let path = d.into_path();
|
||||
let keep = is_aiken_path(&path, dir);
|
||||
let ext = path.extension();
|
||||
|
@ -895,19 +966,39 @@ where
|
|||
}
|
||||
|
||||
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 {
|
||||
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> {
|
||||
let name = self.module_name(dir, &path);
|
||||
let code = fs::read_to_string(&path).map_err(|error| Error::FileIo {
|
||||
path: path.clone(),
|
||||
error,
|
||||
})?;
|
||||
fn add_module(
|
||||
&mut self,
|
||||
add_by: AddModuleBy,
|
||||
dir: &Path,
|
||||
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 {
|
||||
name,
|
||||
|
|
|
@ -32,16 +32,9 @@ pub struct 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 deps: Vec<_> = self
|
||||
.ast
|
||||
.dependencies()
|
||||
.into_iter()
|
||||
.map(|(dep, _span)| dep)
|
||||
.collect();
|
||||
|
||||
let deps: Vec<_> = self.ast.dependencies(env_modules);
|
||||
(name, deps)
|
||||
}
|
||||
|
||||
|
@ -51,6 +44,7 @@ impl ParsedModule {
|
|||
id_gen: &IdGenerator,
|
||||
package: &str,
|
||||
tracing: Tracing,
|
||||
env: Option<&str>,
|
||||
validate_module_name: bool,
|
||||
module_sources: &mut HashMap<String, (String, LineNumbers)>,
|
||||
module_types: &mut HashMap<String, TypeInfo>,
|
||||
|
@ -68,6 +62,7 @@ impl ParsedModule {
|
|||
module_types,
|
||||
tracing,
|
||||
&mut warnings,
|
||||
env,
|
||||
)
|
||||
.map_err(|error| Error::Type {
|
||||
path: self.path.clone(),
|
||||
|
@ -122,10 +117,19 @@ impl ParsedModules {
|
|||
}
|
||||
|
||||
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
|
||||
.0
|
||||
.values()
|
||||
.map(|m| m.deps_for_graph())
|
||||
.map(|m| m.deps_for_graph(&env_modules))
|
||||
.collect::<Vec<(String, Vec<String>)>>();
|
||||
|
||||
let capacity = inputs.len();
|
||||
|
|
|
@ -3,6 +3,7 @@ use aiken_lang::ast::Tracing;
|
|||
pub struct Options {
|
||||
pub code_gen_mode: CodeGenMode,
|
||||
pub tracing: Tracing,
|
||||
pub env: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for Options {
|
||||
|
@ -10,6 +11,7 @@ impl Default for Options {
|
|||
Self {
|
||||
code_gen_mode: CodeGenMode::NoOp,
|
||||
tracing: Tracing::silent(),
|
||||
env: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1314,6 +1314,7 @@ mod test {
|
|||
&module_types,
|
||||
Tracing::All(TraceLevel::Verbose),
|
||||
&mut warnings,
|
||||
None,
|
||||
)
|
||||
.expect("Failed to type-check module.");
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ impl TestProject {
|
|||
&self.module_types,
|
||||
Tracing::All(TraceLevel::Verbose),
|
||||
&mut warnings,
|
||||
None,
|
||||
)
|
||||
.expect("Failed to type-check module");
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use aiken_lang::ast::Tracing;
|
||||
use aiken_project::watch::with_project;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -20,10 +19,6 @@ pub struct Args {
|
|||
#[clap(long)]
|
||||
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)
|
||||
#[clap(long)]
|
||||
mainnet: bool,
|
||||
|
@ -35,15 +30,10 @@ pub fn exec(
|
|||
module,
|
||||
validator,
|
||||
delegated_to,
|
||||
rebuild,
|
||||
mainnet,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(directory.as_deref(), false, |p| {
|
||||
if rebuild {
|
||||
p.build(false, Tracing::silent())?;
|
||||
}
|
||||
|
||||
let title = module.as_ref().map(|m| {
|
||||
format!(
|
||||
"{m}{}",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use aiken_lang::ast::Tracing;
|
||||
use aiken_project::watch::with_project;
|
||||
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
|
||||
#[clap(short, long)]
|
||||
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(
|
||||
|
@ -26,14 +21,9 @@ pub fn exec(
|
|||
directory,
|
||||
module,
|
||||
validator,
|
||||
rebuild,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(directory.as_deref(), false, |p| {
|
||||
if rebuild {
|
||||
p.build(false, Tracing::silent())?;
|
||||
}
|
||||
|
||||
let title = module.as_ref().map(|m| {
|
||||
format!(
|
||||
"{m}{}",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use aiken_lang::ast::Tracing;
|
||||
use aiken_project::watch::with_project;
|
||||
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
|
||||
#[clap(short, long)]
|
||||
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(
|
||||
|
@ -26,14 +21,9 @@ pub fn exec(
|
|||
directory,
|
||||
module,
|
||||
validator,
|
||||
rebuild,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(directory.as_deref(), false, |p| {
|
||||
if rebuild {
|
||||
p.build(false, Tracing::silent())?;
|
||||
}
|
||||
|
||||
let title = module.as_ref().map(|m| {
|
||||
format!(
|
||||
"{m}{}",
|
||||
|
|
|
@ -21,6 +21,10 @@ pub struct Args {
|
|||
#[clap(short, long)]
|
||||
uplc: bool,
|
||||
|
||||
/// Environment to build against.
|
||||
#[clap(long)]
|
||||
env: Option<String>,
|
||||
|
||||
/// Filter traces to be included in the generated program(s).
|
||||
///
|
||||
/// - user-defined:
|
||||
|
@ -63,6 +67,7 @@ pub fn exec(
|
|||
uplc,
|
||||
filter_traces,
|
||||
trace_level,
|
||||
env,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
let result = if watch {
|
||||
|
@ -73,6 +78,7 @@ pub fn exec(
|
|||
Some(filter_traces) => filter_traces(trace_level),
|
||||
None => Tracing::All(trace_level),
|
||||
},
|
||||
env.clone(),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
|
@ -83,6 +89,7 @@ pub fn exec(
|
|||
Some(filter_traces) => filter_traces(trace_level),
|
||||
None => Tracing::All(trace_level),
|
||||
},
|
||||
env.clone(),
|
||||
)
|
||||
})
|
||||
};
|
||||
|
|
|
@ -48,6 +48,10 @@ pub struct Args {
|
|||
#[clap(short, long)]
|
||||
exact_match: bool,
|
||||
|
||||
/// Environment to build against.
|
||||
#[clap(long)]
|
||||
env: Option<String>,
|
||||
|
||||
/// Filter traces to be included in the generated program(s).
|
||||
///
|
||||
/// - user-defined:
|
||||
|
@ -95,6 +99,7 @@ pub fn exec(
|
|||
trace_level,
|
||||
seed,
|
||||
max_success,
|
||||
env,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
@ -114,6 +119,7 @@ pub fn exec(
|
|||
Some(filter_traces) => filter_traces(trace_level),
|
||||
None => Tracing::All(trace_level),
|
||||
},
|
||||
env.clone(),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
|
@ -129,6 +135,7 @@ pub fn exec(
|
|||
Some(filter_traces) => filter_traces(trace_level),
|
||||
None => Tracing::All(trace_level),
|
||||
},
|
||||
env.clone(),
|
||||
)
|
||||
})
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue