Merge pull request #977 from aiken-lang/rvcas/validators_v3
Implement PlutusV3 Validators
This commit is contained in:
commit
9943c2cc7a
|
@ -1948,8 +1948,9 @@ checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f"
|
|||
|
||||
[[package]]
|
||||
name = "pallas-addresses"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=454b3bcf32cdc238aba65e4c3e4656a352480ec1#454b3bcf32cdc238aba65e4c3e4656a352480ec1"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c38fac39e0da3b0fc4c859635c72e97584f01f3a0f4f1508b0851c02d6d52f15"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"bech32",
|
||||
|
@ -1963,8 +1964,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pallas-codec"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=454b3bcf32cdc238aba65e4c3e4656a352480ec1#454b3bcf32cdc238aba65e4c3e4656a352480ec1"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea8a4b87dbc8bcb8aeb865f7cca5e1eb29744330e23b307169fc30537648b264"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"minicbor",
|
||||
|
@ -1975,8 +1977,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pallas-crypto"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=454b3bcf32cdc238aba65e4c3e4656a352480ec1#454b3bcf32cdc238aba65e4c3e4656a352480ec1"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b98c3f204299d47d9b581ab425043789caff1f491c078ee3d3f109d6556f725"
|
||||
dependencies = [
|
||||
"cryptoxide",
|
||||
"hex",
|
||||
|
@ -1988,8 +1991,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pallas-primitives"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=454b3bcf32cdc238aba65e4c3e4656a352480ec1#454b3bcf32cdc238aba65e4c3e4656a352480ec1"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f64835dd9cbdd75a38961a190b983f02746c872340daf1a921eada8c525a4b6"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"bech32",
|
||||
|
@ -2003,8 +2007,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pallas-traverse"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/KtorZ/pallas.git?rev=454b3bcf32cdc238aba65e4c3e4656a352480ec1#454b3bcf32cdc238aba65e4c3e4656a352480ec1"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad516b05ba7d838ee84f9998d7b2b4ff7acc178cb052bcfd5fea9edc2ef6023f"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"itertools 0.13.0",
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -49,11 +49,11 @@ x86_64-unknown-linux-gnu = "ubuntu-22.04"
|
|||
walkdir = "2.3.2"
|
||||
insta = { version = "1.30.0", features = ["yaml", "json", "redactions"] }
|
||||
miette = { version = "7.2.0", features = ["fancy"] }
|
||||
pallas-addresses = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
|
||||
pallas-codec = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1", features = ["num-bigint"] }
|
||||
pallas-crypto = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
|
||||
pallas-primitives = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
|
||||
pallas-traverse = { git = "https://github.com/KtorZ/pallas.git", rev = "454b3bcf32cdc238aba65e4c3e4656a352480ec1" }
|
||||
pallas-addresses = "0.30.1"
|
||||
pallas-codec = { version = "0.30.1", features = ["num-bigint"] }
|
||||
pallas-crypto = "0.30.1"
|
||||
pallas-primitives = "0.30.1"
|
||||
pallas-traverse = "0.30.1"
|
||||
|
||||
[profile.dev.package.insta]
|
||||
opt-level = 3
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
pub mod well_known;
|
||||
|
||||
use crate::{
|
||||
builtins::{self, g1_element, g2_element},
|
||||
ast::well_known::VALIDATOR_ELSE,
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
line_numbers::LineNumbers,
|
||||
parser::token::{Base, Token},
|
||||
|
@ -25,6 +27,13 @@ pub const ENV_MODULE: &str = "env";
|
|||
pub const CONFIG_MODULE: &str = "config";
|
||||
pub const DEFAULT_ENV_MODULE: &str = "default";
|
||||
|
||||
pub const HANDLER_SPEND: &str = "spend";
|
||||
pub const HANDLER_MINT: &str = "mint";
|
||||
pub const HANDLER_WITHDRAW: &str = "withdraw";
|
||||
pub const HANDLER_PUBLISH: &str = "publish";
|
||||
pub const HANDLER_VOTE: &str = "vote";
|
||||
pub const HANDLER_PROPOSE: &str = "propose";
|
||||
|
||||
pub type TypedModule = Module<TypeInfo, TypedDefinition>;
|
||||
pub type UntypedModule = Module<(), UntypedDefinition>;
|
||||
|
||||
|
@ -189,11 +198,7 @@ impl TypedModule {
|
|||
Definition::Validator(v) => {
|
||||
let module_name = self.name.as_str();
|
||||
|
||||
if let Some((k, v)) = v.into_function_definition(module_name, |f, _| Some(f)) {
|
||||
functions.insert(k, v);
|
||||
}
|
||||
|
||||
if let Some((k, v)) = v.into_function_definition(module_name, |_, f| f) {
|
||||
for (k, v) in v.into_function_definitions(module_name) {
|
||||
functions.insert(k, v);
|
||||
}
|
||||
}
|
||||
|
@ -237,6 +242,19 @@ fn str_to_keyword(word: &str) -> Option<Token> {
|
|||
pub type TypedFunction = Function<Rc<Type>, TypedExpr, TypedArg>;
|
||||
pub type UntypedFunction = Function<(), UntypedExpr, UntypedArg>;
|
||||
|
||||
impl UntypedFunction {
|
||||
pub fn is_default_fallback(&self) -> bool {
|
||||
matches!(
|
||||
&self.arguments[..],
|
||||
[UntypedArg {
|
||||
by: ArgBy::ByName(ArgName::Discarded { .. }),
|
||||
..
|
||||
}]
|
||||
) && matches!(&self.body, UntypedExpr::ErrorTerm { .. })
|
||||
&& self.name.as_str() == well_known::VALIDATOR_ELSE
|
||||
}
|
||||
}
|
||||
|
||||
pub type TypedTest = Function<Rc<Type>, TypedExpr, TypedArgVia>;
|
||||
pub type UntypedTest = Function<(), UntypedExpr, UntypedArgVia>;
|
||||
|
||||
|
@ -261,6 +279,16 @@ pub struct Function<T, Expr, Arg> {
|
|||
pub on_test_failure: OnTestFailure,
|
||||
}
|
||||
|
||||
impl<T, Expr, Arg> Function<T, Expr, Arg> {
|
||||
pub fn is_spend(&self) -> bool {
|
||||
self.name == HANDLER_SPEND
|
||||
}
|
||||
|
||||
pub fn is_mint(&self) -> bool {
|
||||
self.name == HANDLER_MINT
|
||||
}
|
||||
}
|
||||
|
||||
impl TypedFunction {
|
||||
pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
|
||||
self.arguments
|
||||
|
@ -273,6 +301,33 @@ impl TypedFunction {
|
|||
.and_then(|a| a.find_node(byte_index))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn has_valid_purpose_name(&self) -> bool {
|
||||
self.name == HANDLER_SPEND
|
||||
|| self.name == HANDLER_PUBLISH
|
||||
|| self.name == HANDLER_PROPOSE
|
||||
|| self.name == HANDLER_MINT
|
||||
|| self.name == HANDLER_WITHDRAW
|
||||
|| self.name == HANDLER_VOTE
|
||||
}
|
||||
|
||||
pub fn validator_arity(&self) -> usize {
|
||||
if self.name == HANDLER_SPEND {
|
||||
4
|
||||
} else if self.name == HANDLER_MINT
|
||||
|| self.name == HANDLER_WITHDRAW
|
||||
|| self.name == HANDLER_VOTE
|
||||
|| self.name == HANDLER_PUBLISH
|
||||
|| self.name == HANDLER_PROPOSE
|
||||
{
|
||||
3
|
||||
} else {
|
||||
panic!(
|
||||
"tried to get validator arity of a non-validator function {}",
|
||||
&self.name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypedTest {
|
||||
|
@ -349,153 +404,37 @@ pub struct FunctionAccessKey {
|
|||
pub function_name: String,
|
||||
}
|
||||
|
||||
pub type UntypedDataType = DataType<()>;
|
||||
pub type TypedDataType = DataType<Rc<Type>>;
|
||||
|
||||
impl TypedDataType {
|
||||
pub fn data() -> Self {
|
||||
DataType {
|
||||
constructors: vec![],
|
||||
doc: None,
|
||||
pub fn known_enum(name: &str, constructors: &[&str]) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
constructors: RecordConstructor::known_enum(constructors),
|
||||
location: Span::empty(),
|
||||
name: "Data".to_string(),
|
||||
opaque: false,
|
||||
parameters: vec![],
|
||||
public: true,
|
||||
parameters: vec![],
|
||||
typed_parameters: vec![],
|
||||
doc: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bool() -> Self {
|
||||
DataType {
|
||||
constructors: vec![
|
||||
RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: "False".to_string(),
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
},
|
||||
RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: "True".to_string(),
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
},
|
||||
],
|
||||
doc: None,
|
||||
location: Span::empty(),
|
||||
name: "Bool".to_string(),
|
||||
opaque: false,
|
||||
parameters: vec![],
|
||||
public: true,
|
||||
typed_parameters: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prng() -> Self {
|
||||
DataType {
|
||||
constructors: vec![
|
||||
RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: "Seeded".to_string(),
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
},
|
||||
RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: "Replayed".to_string(),
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
},
|
||||
],
|
||||
doc: None,
|
||||
location: Span::empty(),
|
||||
name: "PRNG".to_string(),
|
||||
opaque: false,
|
||||
parameters: vec![],
|
||||
public: true,
|
||||
typed_parameters: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ordering() -> Self {
|
||||
DataType {
|
||||
constructors: vec![
|
||||
RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: "Less".to_string(),
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
},
|
||||
RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: "Equal".to_string(),
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
},
|
||||
RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: "Greater".to_string(),
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
},
|
||||
],
|
||||
doc: None,
|
||||
location: Span::empty(),
|
||||
name: "Ordering".to_string(),
|
||||
opaque: false,
|
||||
parameters: vec![],
|
||||
public: true,
|
||||
typed_parameters: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn option(tipo: Rc<Type>) -> Self {
|
||||
DataType {
|
||||
constructors: vec![
|
||||
RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: "Some".to_string(),
|
||||
arguments: vec![RecordConstructorArg {
|
||||
label: None,
|
||||
annotation: Annotation::Var {
|
||||
location: Span::empty(),
|
||||
name: "a".to_string(),
|
||||
},
|
||||
location: Span::empty(),
|
||||
tipo: tipo.clone(),
|
||||
doc: None,
|
||||
}],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
},
|
||||
RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: "None".to_string(),
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
},
|
||||
],
|
||||
doc: None,
|
||||
location: Span::empty(),
|
||||
name: "Option".to_string(),
|
||||
opaque: false,
|
||||
parameters: vec!["a".to_string()],
|
||||
public: true,
|
||||
typed_parameters: vec![tipo],
|
||||
}
|
||||
pub fn is_never(&self) -> bool {
|
||||
self.name == well_known::NEVER
|
||||
&& self.constructors.len() == well_known::NEVER_CONSTRUCTORS.len()
|
||||
&& self.location == Span::empty()
|
||||
&& self
|
||||
.constructors
|
||||
.iter()
|
||||
.zip(well_known::NEVER_CONSTRUCTORS)
|
||||
.all(|(constructor, name)| {
|
||||
name == &constructor.name && constructor.arguments.is_empty()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub type UntypedDataType = DataType<()>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct DataType<T> {
|
||||
pub constructors: Vec<RecordConstructor<T>>,
|
||||
|
@ -537,58 +476,260 @@ pub struct ModuleConstant<T> {
|
|||
pub type TypedValidator = Validator<Rc<Type>, TypedArg, TypedExpr>;
|
||||
pub type UntypedValidator = Validator<(), UntypedArg, UntypedExpr>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Purpose {
|
||||
Spend,
|
||||
Mint,
|
||||
Withdraw,
|
||||
Publish,
|
||||
Propose,
|
||||
Vote,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Validator<T, Arg, Expr> {
|
||||
pub doc: Option<String>,
|
||||
pub end_position: usize,
|
||||
pub fun: Function<T, Expr, Arg>,
|
||||
pub other_fun: Option<Function<T, Expr, Arg>>,
|
||||
pub handlers: Vec<Function<T, Expr, Arg>>,
|
||||
pub location: Span,
|
||||
pub name: String,
|
||||
pub params: Vec<Arg>,
|
||||
pub fallback: Function<T, Expr, Arg>,
|
||||
}
|
||||
|
||||
impl<T, Arg, Expr> Validator<T, Arg, Expr> {
|
||||
pub fn handler_name(validator: &str, handler: &str) -> String {
|
||||
format!("{}.{}", validator, handler)
|
||||
}
|
||||
}
|
||||
|
||||
impl UntypedValidator {
|
||||
pub fn default_fallback(location: Span) -> UntypedFunction {
|
||||
Function {
|
||||
arguments: vec![UntypedArg {
|
||||
by: ArgBy::ByName(ArgName::Discarded {
|
||||
name: "_".to_string(),
|
||||
label: "_".to_string(),
|
||||
location,
|
||||
}),
|
||||
location,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
}],
|
||||
body: UntypedExpr::fail(None, location),
|
||||
doc: None,
|
||||
location,
|
||||
end_position: location.end - 1,
|
||||
name: well_known::VALIDATOR_ELSE.to_string(),
|
||||
public: true,
|
||||
return_annotation: Some(Annotation::boolean(location)),
|
||||
return_type: (),
|
||||
on_test_failure: OnTestFailure::FailImmediately,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypedValidator {
|
||||
pub fn available_handler_names() -> Vec<String> {
|
||||
vec![
|
||||
HANDLER_SPEND.to_string(),
|
||||
HANDLER_MINT.to_string(),
|
||||
HANDLER_WITHDRAW.to_string(),
|
||||
HANDLER_PUBLISH.to_string(),
|
||||
HANDLER_VOTE.to_string(),
|
||||
HANDLER_PROPOSE.to_string(),
|
||||
VALIDATOR_ELSE.to_string(),
|
||||
]
|
||||
}
|
||||
|
||||
// Define a validator wrapper extracting and matching on script purpose for
|
||||
// users.
|
||||
pub fn into_script_context_handler(&self) -> TypedExpr {
|
||||
let var_context = "__context__";
|
||||
let var_transaction = "__transaction__";
|
||||
let var_redeemer = "__redeemer__";
|
||||
let var_purpose = "__purpose__";
|
||||
let var_purpose_arg = "__purpose_arg__";
|
||||
let var_datum = "__datum__";
|
||||
|
||||
TypedExpr::sequence(&[
|
||||
TypedExpr::let_(
|
||||
TypedExpr::local_var(var_context, Type::script_context()),
|
||||
TypedPattern::Constructor {
|
||||
is_record: false,
|
||||
location: Span::empty(),
|
||||
name: well_known::SCRIPT_CONTEXT_CONSTRUCTORS[0].to_string(),
|
||||
arguments: vec![
|
||||
CallArg::var(var_transaction),
|
||||
CallArg::var(var_redeemer),
|
||||
CallArg::var(var_purpose),
|
||||
],
|
||||
module: None,
|
||||
constructor: PatternConstructor::Record {
|
||||
name: well_known::SCRIPT_CONTEXT_CONSTRUCTORS[0].to_string(),
|
||||
field_map: None,
|
||||
},
|
||||
spread_location: None,
|
||||
tipo: Type::function(
|
||||
vec![Type::data(), Type::data(), Type::script_purpose()],
|
||||
Type::data(),
|
||||
),
|
||||
},
|
||||
Type::script_context(),
|
||||
),
|
||||
TypedExpr::When {
|
||||
location: Span::empty(),
|
||||
tipo: Type::bool(),
|
||||
subject: TypedExpr::local_var(var_purpose, Type::script_purpose()).into(),
|
||||
clauses: self
|
||||
.handlers
|
||||
.iter()
|
||||
.map(|handler| {
|
||||
let datum = if handler.name.as_str() == "spend" {
|
||||
handler.arguments.first()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let redeemer = handler
|
||||
.arguments
|
||||
.get(if datum.is_some() { 1 } else { 0 })
|
||||
.unwrap();
|
||||
|
||||
let purpose_arg = handler.arguments.iter().nth_back(1).unwrap();
|
||||
|
||||
let transaction = handler.arguments.last().unwrap();
|
||||
|
||||
let pattern = match handler.name.as_str() {
|
||||
"spend" => TypedPattern::spend_purpose(var_purpose_arg, var_datum),
|
||||
"mint" => TypedPattern::mint_purpose(var_purpose_arg),
|
||||
"withdraw" => TypedPattern::withdraw_purpose(var_purpose_arg),
|
||||
"publish" => TypedPattern::publish_purpose(var_purpose_arg),
|
||||
"propose" => TypedPattern::propose_purpose(var_purpose_arg),
|
||||
"vote" => TypedPattern::vote_purpose(var_purpose_arg),
|
||||
purpose => {
|
||||
unreachable!("unexpected/unknown purpose: {:?}", purpose)
|
||||
}
|
||||
};
|
||||
|
||||
let mut then = vec![];
|
||||
|
||||
// expect redeemer: tipo = __redeemer__
|
||||
then.push(TypedExpr::flexible_expect(
|
||||
TypedExpr::local_var(var_redeemer, Type::data()),
|
||||
TypedPattern::var(redeemer.get_variable_name().unwrap_or("_")),
|
||||
redeemer.tipo.clone(),
|
||||
));
|
||||
|
||||
// Cast the datum, if any
|
||||
if let Some(datum) = datum {
|
||||
// expect datum: tipo = __datum__
|
||||
then.push(TypedExpr::flexible_expect(
|
||||
TypedExpr::local_var(var_datum, Type::option(Type::data())),
|
||||
TypedPattern::var(datum.get_variable_name().unwrap_or("_")),
|
||||
datum.tipo.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
// let purpose_arg = __purpose_arg__
|
||||
if let Some(arg_name) = purpose_arg.get_variable_name() {
|
||||
then.push(TypedExpr::let_(
|
||||
TypedExpr::local_var(var_purpose_arg, Type::data()),
|
||||
TypedPattern::var(arg_name),
|
||||
purpose_arg.tipo.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
// let last_arg_name = __transaction__
|
||||
if let Some(arg_name) = transaction.get_variable_name() {
|
||||
then.push(TypedExpr::let_(
|
||||
TypedExpr::local_var(var_transaction, Type::data()),
|
||||
TypedPattern::var(arg_name),
|
||||
Type::data(),
|
||||
));
|
||||
}
|
||||
|
||||
then.push(handler.body.clone());
|
||||
|
||||
TypedClause {
|
||||
location: Span::empty(),
|
||||
pattern,
|
||||
then: TypedExpr::Sequence {
|
||||
location: Span::empty(),
|
||||
expressions: then,
|
||||
},
|
||||
}
|
||||
})
|
||||
.chain(std::iter::once(&self.fallback).map(|fallback| {
|
||||
let arg = fallback.arguments.first().unwrap();
|
||||
|
||||
let then = &[
|
||||
TypedExpr::let_(
|
||||
TypedExpr::local_var(var_context, arg.tipo.clone()),
|
||||
arg.get_variable_name().map(TypedPattern::var).unwrap_or(
|
||||
TypedPattern::Discard {
|
||||
name: var_context.to_string(),
|
||||
location: Span::empty(),
|
||||
},
|
||||
),
|
||||
arg.tipo.clone(),
|
||||
),
|
||||
fallback.body.clone(),
|
||||
];
|
||||
|
||||
TypedClause {
|
||||
location: Span::empty(),
|
||||
pattern: TypedPattern::var(var_context),
|
||||
then: TypedExpr::sequence(then),
|
||||
}
|
||||
}))
|
||||
.collect(),
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
|
||||
self.params
|
||||
.iter()
|
||||
.find_map(|arg| arg.find_node(byte_index))
|
||||
.or_else(|| self.fun.find_node(byte_index))
|
||||
.or_else(|| {
|
||||
self.other_fun
|
||||
.as_ref()
|
||||
.and_then(|f| f.find_node(byte_index))
|
||||
self.handlers
|
||||
.iter()
|
||||
.find_map(|func| func.find_node(byte_index))
|
||||
})
|
||||
.or_else(|| self.fallback.find_node(byte_index))
|
||||
}
|
||||
|
||||
pub fn into_function_definition<'a, F>(
|
||||
&'a self,
|
||||
pub fn into_function_definitions(
|
||||
&self,
|
||||
module_name: &str,
|
||||
select: F,
|
||||
) -> Option<(FunctionAccessKey, TypedFunction)>
|
||||
where
|
||||
F: Fn(&'a TypedFunction, Option<&'a TypedFunction>) -> Option<&'a TypedFunction> + 'a,
|
||||
{
|
||||
match select(&self.fun, self.other_fun.as_ref()) {
|
||||
None => None,
|
||||
Some(fun) => {
|
||||
let mut fun = fun.clone();
|
||||
) -> Vec<(FunctionAccessKey, TypedFunction)> {
|
||||
self.handlers
|
||||
.iter()
|
||||
.chain(std::iter::once(&self.fallback))
|
||||
.map(|handler| {
|
||||
let mut handler = handler.clone();
|
||||
|
||||
fun.arguments = self
|
||||
handler.arguments = self
|
||||
.params
|
||||
.clone()
|
||||
.into_iter()
|
||||
.chain(fun.arguments)
|
||||
.chain(handler.arguments)
|
||||
.collect();
|
||||
|
||||
Some((
|
||||
(
|
||||
FunctionAccessKey {
|
||||
module_name: module_name.to_string(),
|
||||
function_name: fun.name.clone(),
|
||||
function_name: TypedValidator::handler_name(
|
||||
self.name.as_str(),
|
||||
handler.name.as_str(),
|
||||
),
|
||||
},
|
||||
fun,
|
||||
))
|
||||
}
|
||||
}
|
||||
handler,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -731,12 +872,12 @@ pub enum Constant {
|
|||
impl Constant {
|
||||
pub fn tipo(&self) -> Rc<Type> {
|
||||
match self {
|
||||
Constant::Int { .. } => builtins::int(),
|
||||
Constant::String { .. } => builtins::string(),
|
||||
Constant::ByteArray { .. } => builtins::byte_array(),
|
||||
Constant::Int { .. } => Type::int(),
|
||||
Constant::String { .. } => Type::string(),
|
||||
Constant::ByteArray { .. } => Type::byte_array(),
|
||||
Constant::CurvePoint { point, .. } => match point.as_ref() {
|
||||
Curve::Bls12_381(Bls12_381Point::G1(_)) => builtins::g1_element(),
|
||||
Curve::Bls12_381(Bls12_381Point::G2(_)) => builtins::g2_element(),
|
||||
Curve::Bls12_381(Bls12_381Point::G1(_)) => Type::g1_element(),
|
||||
Curve::Bls12_381(Bls12_381Point::G2(_)) => Type::g2_element(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -776,6 +917,19 @@ impl TypedCallArg {
|
|||
}
|
||||
}
|
||||
|
||||
impl CallArg<TypedPattern> {
|
||||
pub fn var(name: &str) -> Self {
|
||||
CallArg {
|
||||
label: None,
|
||||
location: Span::empty(),
|
||||
value: TypedPattern::Var {
|
||||
location: Span::empty(),
|
||||
name: name.to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct RecordConstructor<T> {
|
||||
pub location: Span,
|
||||
|
@ -789,6 +943,19 @@ impl<A> RecordConstructor<A> {
|
|||
pub fn put_doc(&mut self, new_doc: String) {
|
||||
self.doc = Some(new_doc);
|
||||
}
|
||||
|
||||
pub fn known_enum(names: &[&str]) -> Vec<RecordConstructor<A>> {
|
||||
names
|
||||
.iter()
|
||||
.map(|name| RecordConstructor {
|
||||
location: Span::empty(),
|
||||
name: name.to_string(),
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
sugar: false,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
|
@ -889,6 +1056,21 @@ pub struct TypedArg {
|
|||
}
|
||||
|
||||
impl TypedArg {
|
||||
pub fn new(name: &str, tipo: Rc<Type>) -> Self {
|
||||
TypedArg {
|
||||
arg_name: ArgName::Named {
|
||||
name: name.to_string(),
|
||||
label: name.to_string(),
|
||||
location: Span::empty(),
|
||||
},
|
||||
location: Span::empty(),
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
tipo: tipo.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn put_doc(&mut self, new_doc: String) {
|
||||
self.doc = Some(new_doc);
|
||||
}
|
||||
|
@ -897,6 +1079,10 @@ impl TypedArg {
|
|||
self.arg_name.get_variable_name()
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> String {
|
||||
self.arg_name.get_name()
|
||||
}
|
||||
|
||||
pub fn is_capture(&self) -> bool {
|
||||
if let ArgName::Named {
|
||||
ref name, location, ..
|
||||
|
@ -1103,6 +1289,15 @@ impl Annotation {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn option(inner: Annotation) -> Self {
|
||||
Annotation::Constructor {
|
||||
name: "Option".to_string(),
|
||||
module: None,
|
||||
location: inner.location(),
|
||||
arguments: vec![inner],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_logically_equal(&self, other: &Annotation) -> bool {
|
||||
match self {
|
||||
Annotation::Constructor {
|
||||
|
@ -1279,6 +1474,88 @@ impl BinOp {
|
|||
pub type UntypedPattern = Pattern<(), ()>;
|
||||
pub type TypedPattern = Pattern<PatternConstructor, Rc<Type>>;
|
||||
|
||||
impl TypedPattern {
|
||||
pub fn var(name: &str) -> Self {
|
||||
TypedPattern::Var {
|
||||
name: name.to_string(),
|
||||
location: Span::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn constructor(name: &str, arguments: &[CallArg<TypedPattern>], tipo: Rc<Type>) -> Self {
|
||||
TypedPattern::Constructor {
|
||||
is_record: false,
|
||||
location: Span::empty(),
|
||||
name: name.to_string(),
|
||||
arguments: arguments.to_vec(),
|
||||
module: None,
|
||||
constructor: PatternConstructor::Record {
|
||||
name: name.to_string(),
|
||||
field_map: None,
|
||||
},
|
||||
spread_location: None,
|
||||
tipo: tipo.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mint_purpose(var_purpose_arg: &str) -> Self {
|
||||
TypedPattern::constructor(
|
||||
well_known::SCRIPT_PURPOSE_MINT,
|
||||
&[CallArg::var(var_purpose_arg)],
|
||||
Type::function(vec![Type::byte_array()], Type::script_purpose()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn spend_purpose(var_purpose_arg: &str, var_datum: &str) -> Self {
|
||||
TypedPattern::constructor(
|
||||
well_known::SCRIPT_PURPOSE_SPEND,
|
||||
&[CallArg::var(var_purpose_arg), CallArg::var(var_datum)],
|
||||
Type::function(
|
||||
vec![Type::data(), Type::option(Type::data())],
|
||||
Type::script_purpose(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn withdraw_purpose(var_purpose_arg: &str) -> Self {
|
||||
TypedPattern::constructor(
|
||||
well_known::SCRIPT_PURPOSE_WITHDRAW,
|
||||
&[CallArg::var(var_purpose_arg)],
|
||||
Type::function(vec![Type::data()], Type::script_purpose()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn publish_purpose(var_purpose_arg: &str) -> Self {
|
||||
TypedPattern::constructor(
|
||||
well_known::SCRIPT_PURPOSE_PUBLISH,
|
||||
&[
|
||||
CallArg::var("__discarded_purpose_ix__"),
|
||||
CallArg::var(var_purpose_arg),
|
||||
],
|
||||
Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn vote_purpose(var_purpose_arg: &str) -> Self {
|
||||
TypedPattern::constructor(
|
||||
well_known::SCRIPT_PURPOSE_VOTE,
|
||||
&[CallArg::var(var_purpose_arg)],
|
||||
Type::function(vec![Type::data()], Type::script_purpose()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn propose_purpose(var_purpose_arg: &str) -> Self {
|
||||
TypedPattern::constructor(
|
||||
well_known::SCRIPT_PURPOSE_PROPOSE,
|
||||
&[
|
||||
CallArg::var("__discarded_purpose_ix__"),
|
||||
CallArg::var(var_purpose_arg),
|
||||
],
|
||||
Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Pattern<Constructor, Type> {
|
||||
Int {
|
||||
|
@ -1490,8 +1767,8 @@ impl TypedPattern {
|
|||
// TODO: This function definition is weird, see where this is used and how.
|
||||
pub fn tipo(&self, value: &TypedExpr) -> Option<Rc<Type>> {
|
||||
match self {
|
||||
Pattern::Int { .. } => Some(builtins::int()),
|
||||
Pattern::ByteArray { .. } => Some(builtins::byte_array()),
|
||||
Pattern::Int { .. } => Some(Type::int()),
|
||||
Pattern::ByteArray { .. } => Some(Type::byte_array()),
|
||||
Pattern::Constructor { tipo, .. } => Some(tipo.clone()),
|
||||
Pattern::Var { .. } | Pattern::Assign { .. } | Pattern::Discard { .. } => {
|
||||
Some(value.tipo())
|
||||
|
@ -1689,8 +1966,8 @@ impl<'de> serde::Deserialize<'de> for Bls12_381Point {
|
|||
impl Bls12_381Point {
|
||||
pub fn tipo(&self) -> Rc<Type> {
|
||||
match self {
|
||||
Bls12_381Point::G1(_) => g1_element(),
|
||||
Bls12_381Point::G2(_) => g2_element(),
|
||||
Bls12_381Point::G1(_) => Type::g1_element(),
|
||||
Bls12_381Point::G2(_) => Type::g2_element(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
use crate::{
|
||||
ast::{Annotation, Span},
|
||||
tipo::{Type, TypeAliasAnnotation, TypeVar},
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
pub const BOOL: &str = "Bool";
|
||||
pub const BOOL_CONSTRUCTORS: &[&str] = &["False", "True"];
|
||||
pub const BYTE_ARRAY: &str = "ByteArray";
|
||||
pub const DATA: &str = "Data";
|
||||
pub const FUZZER: &str = "Fuzzer";
|
||||
pub const G1_ELEMENT: &str = "G1Element";
|
||||
pub const G2_ELEMENT: &str = "G2Element";
|
||||
pub const INT: &str = "Int";
|
||||
pub const LIST: &str = "List";
|
||||
pub const MILLER_LOOP_RESULT: &str = "MillerLoopResult";
|
||||
pub const OPTION: &str = "Option";
|
||||
pub const OPTION_CONSTRUCTORS: &[&str] = &["Some", "None"];
|
||||
pub const NEVER: &str = "Never";
|
||||
pub const NEVER_CONSTRUCTORS: &[&str] = &["__hole", "Never"];
|
||||
pub const ORDERING: &str = "Ordering";
|
||||
pub const ORDERING_CONSTRUCTORS: &[&str] = &["Less", "Equal", "Greater"];
|
||||
pub const PAIR: &str = "Pair";
|
||||
pub const PAIRS: &str = "Pairs";
|
||||
pub const PRNG: &str = "PRNG";
|
||||
pub const PRNG_CONSTRUCTORS: &[&str] = &["Seeded", "Replayed"];
|
||||
pub const REDEEMER_WRAPPER: &str = "RedeemerWrapper";
|
||||
pub const STRING: &str = "String";
|
||||
pub const VOID: &str = "Void";
|
||||
pub const VOID_CONSTRUCTORS: &[&str] = &["Void"];
|
||||
|
||||
pub const SCRIPT_CONTEXT: &str = "__ScriptContext";
|
||||
pub const SCRIPT_CONTEXT_CONSTRUCTORS: &[&str] = &["__ScriptContext"];
|
||||
pub const SCRIPT_CONTEXT_TRANSACTION: &str = "__Transaction";
|
||||
pub const SCRIPT_CONTEXT_REDEEMER: &str = "__Redeemer";
|
||||
pub const SCRIPT_CONTEXT_PURPOSE: &str = "__ScriptPurpose";
|
||||
|
||||
pub const SCRIPT_PURPOSE: &str = "__ScriptPurpose";
|
||||
pub const SCRIPT_PURPOSE_MINT: &str = "__Mint";
|
||||
pub const SCRIPT_PURPOSE_SPEND: &str = "__Spend";
|
||||
pub const SCRIPT_PURPOSE_WITHDRAW: &str = "__Withdraw";
|
||||
pub const SCRIPT_PURPOSE_PUBLISH: &str = "__Publish";
|
||||
pub const SCRIPT_PURPOSE_VOTE: &str = "__Vote";
|
||||
pub const SCRIPT_PURPOSE_PROPOSE: &str = "__Propose";
|
||||
pub const SCRIPT_PURPOSE_CONSTRUCTORS: &[&str] = &[
|
||||
SCRIPT_PURPOSE_MINT,
|
||||
SCRIPT_PURPOSE_SPEND,
|
||||
SCRIPT_PURPOSE_WITHDRAW,
|
||||
SCRIPT_PURPOSE_PUBLISH,
|
||||
SCRIPT_PURPOSE_VOTE,
|
||||
SCRIPT_PURPOSE_PROPOSE,
|
||||
];
|
||||
|
||||
pub const VALIDATOR_ELSE: &str = "else";
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Types
|
||||
|
||||
impl Type {
|
||||
pub fn data() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: DATA.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn int() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: INT.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn bool() -> Rc<Self> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: BOOL.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn byte_array() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: BYTE_ARRAY.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn g1_element() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: G1_ELEMENT.to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn g2_element() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: G2_ELEMENT.to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn miller_loop_result() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: MILLER_LOOP_RESULT.to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn tuple(elems: Vec<Rc<Type>>) -> Rc<Type> {
|
||||
Rc::new(Type::Tuple { elems, alias: None })
|
||||
}
|
||||
|
||||
pub fn pair(fst: Rc<Type>, snd: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::Pair {
|
||||
fst,
|
||||
snd,
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn script_purpose() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: SCRIPT_PURPOSE.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn script_context() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: SCRIPT_CONTEXT.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn prng() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: PRNG.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fuzzer(a: Rc<Type>) -> Rc<Type> {
|
||||
let prng_annotation = Annotation::Constructor {
|
||||
location: Span::empty(),
|
||||
module: None,
|
||||
name: PRNG.to_string(),
|
||||
arguments: vec![],
|
||||
};
|
||||
|
||||
Rc::new(Type::Fn {
|
||||
args: vec![Type::prng()],
|
||||
ret: Type::option(Type::tuple(vec![Type::prng(), a])),
|
||||
alias: Some(
|
||||
TypeAliasAnnotation {
|
||||
alias: FUZZER.to_string(),
|
||||
parameters: vec!["a".to_string()],
|
||||
annotation: Annotation::Fn {
|
||||
location: Span::empty(),
|
||||
arguments: vec![prng_annotation.clone()],
|
||||
ret: Annotation::Constructor {
|
||||
location: Span::empty(),
|
||||
module: None,
|
||||
name: OPTION.to_string(),
|
||||
arguments: vec![Annotation::Tuple {
|
||||
location: Span::empty(),
|
||||
elems: vec![
|
||||
prng_annotation,
|
||||
Annotation::Var {
|
||||
location: Span::empty(),
|
||||
name: "a".to_string(),
|
||||
},
|
||||
],
|
||||
}],
|
||||
}
|
||||
.into(),
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn map(k: Rc<Type>, v: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: LIST.to_string(),
|
||||
args: vec![Type::pair(k, v)],
|
||||
alias: Some(
|
||||
TypeAliasAnnotation {
|
||||
alias: PAIRS.to_string(),
|
||||
parameters: vec!["k".to_string(), "v".to_string()],
|
||||
annotation: Annotation::Constructor {
|
||||
location: Span::empty(),
|
||||
module: None,
|
||||
name: LIST.to_string(),
|
||||
arguments: vec![Annotation::Pair {
|
||||
location: Span::empty(),
|
||||
fst: Box::new(Annotation::Var {
|
||||
location: Span::empty(),
|
||||
name: "k".to_string(),
|
||||
}),
|
||||
snd: Box::new(Annotation::Var {
|
||||
location: Span::empty(),
|
||||
name: "v".to_string(),
|
||||
}),
|
||||
}],
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn list(t: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: t.contains_opaque(),
|
||||
name: LIST.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![t],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn string() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: STRING.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn void() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: VOID.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn option(a: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: a.contains_opaque(),
|
||||
name: OPTION.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![a],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn never() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: NEVER.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ordering() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: ORDERING.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn function(args: Vec<Rc<Type>>, ret: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::Fn {
|
||||
ret,
|
||||
args,
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generic_var(id: u64) -> Rc<Type> {
|
||||
let tipo = Rc::new(RefCell::new(TypeVar::Generic { id }));
|
||||
|
||||
Rc::new(Type::Var { tipo, alias: None })
|
||||
}
|
||||
|
||||
pub fn unbound_var(id: u64) -> Rc<Type> {
|
||||
let tipo = Rc::new(RefCell::new(TypeVar::Unbound { id }));
|
||||
|
||||
Rc::new(Type::Var { tipo, alias: None })
|
||||
}
|
||||
|
||||
pub fn wrapped_redeemer(redeemer: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: REDEEMER_WRAPPER.to_string(),
|
||||
args: vec![redeemer],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,18 +1,17 @@
|
|||
use crate::tipo::ValueConstructorVariant;
|
||||
pub(crate) use crate::{
|
||||
ast::{
|
||||
self, Annotation, ArgBy, ArgName, AssignmentPattern, BinOp, Bls12_381Point,
|
||||
self, Annotation, ArgBy, ArgName, AssignmentKind, AssignmentPattern, BinOp, Bls12_381Point,
|
||||
ByteArrayFormatPreference, CallArg, Curve, DataType, DataTypeKey, DefinitionLocation,
|
||||
Located, LogicalOpChainKind, ParsedCallArg, Pattern, RecordConstructorArg,
|
||||
RecordUpdateSpread, Span, TraceKind, TypedArg, TypedAssignmentKind, TypedClause,
|
||||
TypedDataType, TypedIfBranch, TypedRecordUpdateArg, UnOp, UntypedArg,
|
||||
TypedDataType, TypedIfBranch, TypedPattern, TypedRecordUpdateArg, UnOp, UntypedArg,
|
||||
UntypedAssignmentKind, UntypedClause, UntypedIfBranch, UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::void,
|
||||
parser::token::Base,
|
||||
tipo::{
|
||||
check_replaceable_opaque_type, convert_opaque_type, lookup_data_type_by_tipo,
|
||||
ModuleValueConstructor, PatternConstructor, Type, TypeVar, ValueConstructor,
|
||||
ValueConstructorVariant,
|
||||
},
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
|
@ -201,6 +200,52 @@ impl<T> From<Vec1Ref<T>> for Vec1<T> {
|
|||
}
|
||||
|
||||
impl TypedExpr {
|
||||
pub fn sequence(exprs: &[TypedExpr]) -> Self {
|
||||
TypedExpr::Sequence {
|
||||
location: Span::empty(),
|
||||
expressions: exprs.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn let_(value: Self, pattern: TypedPattern, tipo: Rc<Type>) -> Self {
|
||||
TypedExpr::Assignment {
|
||||
location: Span::empty(),
|
||||
tipo: tipo.clone(),
|
||||
value: value.into(),
|
||||
pattern,
|
||||
kind: AssignmentKind::let_(),
|
||||
}
|
||||
}
|
||||
|
||||
// Create an expect assignment, unless the target type is `Data`; then fallback to a let.
|
||||
pub fn flexible_expect(value: Self, pattern: TypedPattern, tipo: Rc<Type>) -> Self {
|
||||
TypedExpr::Assignment {
|
||||
location: Span::empty(),
|
||||
tipo: tipo.clone(),
|
||||
value: value.into(),
|
||||
pattern,
|
||||
kind: if tipo.is_data() {
|
||||
AssignmentKind::let_()
|
||||
} else {
|
||||
AssignmentKind::expect()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn local_var(name: &str, tipo: Rc<Type>) -> Self {
|
||||
TypedExpr::Var {
|
||||
location: Span::empty(),
|
||||
constructor: ValueConstructor {
|
||||
public: true,
|
||||
variant: ValueConstructorVariant::LocalVariable {
|
||||
location: Span::empty(),
|
||||
},
|
||||
tipo: tipo.clone(),
|
||||
},
|
||||
name: name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tipo(&self) -> Rc<Type> {
|
||||
match self {
|
||||
Self::Var { constructor, .. } => constructor.tipo.clone(),
|
||||
|
@ -224,9 +269,10 @@ impl TypedExpr {
|
|||
| Self::RecordAccess { tipo, .. }
|
||||
| Self::RecordUpdate { tipo, .. }
|
||||
| Self::CurvePoint { tipo, .. } => tipo.clone(),
|
||||
Self::Pipeline { expressions, .. } | Self::Sequence { expressions, .. } => {
|
||||
expressions.last().map(TypedExpr::tipo).unwrap_or_else(void)
|
||||
}
|
||||
Self::Pipeline { expressions, .. } | Self::Sequence { expressions, .. } => expressions
|
||||
.last()
|
||||
.map(TypedExpr::tipo)
|
||||
.unwrap_or_else(Type::void),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,6 +287,10 @@ impl TypedExpr {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn is_error_term(&self) -> bool {
|
||||
matches!(self, Self::ErrorTerm { .. })
|
||||
}
|
||||
|
||||
/// Returns `true` if the typed expr is [`Assignment`].
|
||||
pub fn is_assignment(&self) -> bool {
|
||||
matches!(self, Self::Assignment { .. })
|
||||
|
@ -487,7 +537,7 @@ impl TypedExpr {
|
|||
module: String::new(),
|
||||
constructors_count: 1,
|
||||
},
|
||||
tipo: void(),
|
||||
tipo: Type::void(),
|
||||
},
|
||||
location,
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@ use crate::{
|
|||
Annotation, ArgBy, ArgName, ArgVia, AssignmentKind, AssignmentPattern, BinOp,
|
||||
ByteArrayFormatPreference, CallArg, Constant, CurveType, DataType, Definition, Function,
|
||||
LogicalOpChainKind, ModuleConstant, OnTestFailure, Pattern, RecordConstructor,
|
||||
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, UnOp,
|
||||
UnqualifiedImport, UntypedArg, UntypedArgVia, UntypedAssignmentKind, UntypedClause,
|
||||
UntypedDefinition, UntypedFunction, UntypedIfBranch, UntypedModule, UntypedPattern,
|
||||
UntypedRecordUpdateArg, Use, Validator, CAPTURE_VARIABLE,
|
||||
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg,
|
||||
TypedValidator, UnOp, UnqualifiedImport, UntypedArg, UntypedArgVia, UntypedAssignmentKind,
|
||||
UntypedClause, UntypedDefinition, UntypedFunction, UntypedIfBranch, UntypedModule,
|
||||
UntypedPattern, UntypedRecordUpdateArg, Use, Validator, CAPTURE_VARIABLE,
|
||||
},
|
||||
docvec,
|
||||
expr::{FnStyle, UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR},
|
||||
|
@ -232,15 +232,24 @@ impl<'comments> Formatter<'comments> {
|
|||
return_annotation,
|
||||
end_position,
|
||||
..
|
||||
}) => self.definition_fn(public, name, args, return_annotation, body, *end_position),
|
||||
}) => self.definition_fn(
|
||||
public,
|
||||
name,
|
||||
args,
|
||||
return_annotation,
|
||||
body,
|
||||
*end_position,
|
||||
false,
|
||||
),
|
||||
|
||||
Definition::Validator(Validator {
|
||||
end_position,
|
||||
fun,
|
||||
other_fun,
|
||||
handlers,
|
||||
fallback,
|
||||
params,
|
||||
name,
|
||||
..
|
||||
}) => self.definition_validator(params, fun, other_fun, *end_position),
|
||||
}) => self.definition_validator(name, params, handlers, fallback, *end_position),
|
||||
|
||||
Definition::Test(Function {
|
||||
name,
|
||||
|
@ -512,16 +521,29 @@ impl<'comments> Formatter<'comments> {
|
|||
return_annotation: &'a Option<Annotation>,
|
||||
body: &'a UntypedExpr,
|
||||
end_location: usize,
|
||||
is_validator: bool,
|
||||
) -> Document<'a> {
|
||||
// Fn name and args
|
||||
let head = pub_(*public)
|
||||
.append("fn ")
|
||||
.append(name)
|
||||
.append(wrap_args(args.iter().map(|e| (self.fn_arg(e), false))));
|
||||
let head = if !is_validator {
|
||||
pub_(*public)
|
||||
.append("fn ")
|
||||
.append(name)
|
||||
.append(wrap_args(args.iter().map(|e| (self.fn_arg(e), false))))
|
||||
} else {
|
||||
name.to_doc()
|
||||
.append(wrap_args(args.iter().map(|e| (self.fn_arg(e), false))))
|
||||
};
|
||||
|
||||
// Add return annotation
|
||||
let head = match return_annotation {
|
||||
Some(anno) => head.append(" -> ").append(self.annotation(anno)),
|
||||
Some(anno) => {
|
||||
let is_bool = anno.is_logically_equal(&Annotation::boolean(Span::empty()));
|
||||
if is_validator && is_bool {
|
||||
head
|
||||
} else {
|
||||
head.append(" -> ").append(self.annotation(anno))
|
||||
}
|
||||
}
|
||||
None => head,
|
||||
}
|
||||
.group();
|
||||
|
@ -581,57 +603,73 @@ impl<'comments> Formatter<'comments> {
|
|||
|
||||
fn definition_validator<'a>(
|
||||
&mut self,
|
||||
name: &'a str,
|
||||
params: &'a [UntypedArg],
|
||||
fun: &'a UntypedFunction,
|
||||
other_fun: &'a Option<UntypedFunction>,
|
||||
handlers: &'a [UntypedFunction],
|
||||
fallback: &'a UntypedFunction,
|
||||
end_position: usize,
|
||||
) -> Document<'a> {
|
||||
// validator(params)
|
||||
let v_head = "validator".to_doc().append(if !params.is_empty() {
|
||||
wrap_args(params.iter().map(|e| (self.fn_arg(e), false)))
|
||||
} else {
|
||||
nil()
|
||||
});
|
||||
// validator name(params)
|
||||
let v_head = "validator"
|
||||
.to_doc()
|
||||
.append(" ")
|
||||
.append(name)
|
||||
.append(if !params.is_empty() {
|
||||
wrap_args(params.iter().map(|e| (self.fn_arg(e), false)))
|
||||
} else {
|
||||
nil()
|
||||
});
|
||||
|
||||
let fun_comments = self.pop_comments(fun.location.start);
|
||||
let fun_doc_comments = self.doc_comments(fun.location.start);
|
||||
let first_fn = self
|
||||
.definition_fn(
|
||||
&fun.public,
|
||||
&fun.name,
|
||||
&fun.arguments,
|
||||
&fun.return_annotation,
|
||||
&fun.body,
|
||||
fun.end_position,
|
||||
)
|
||||
.group();
|
||||
let first_fn = commented(fun_doc_comments.append(first_fn).group(), fun_comments);
|
||||
let mut handler_docs = vec![];
|
||||
|
||||
let other_fn = match other_fun {
|
||||
None => nil(),
|
||||
Some(other) => {
|
||||
let other_comments = self.pop_comments(other.location.start);
|
||||
let other_doc_comments = self.doc_comments(other.location.start);
|
||||
for handler in handlers.iter() {
|
||||
let fun_comments = self.pop_comments(handler.location.start);
|
||||
let fun_doc_comments = self.doc_comments(handler.location.start);
|
||||
|
||||
let other_fn = self
|
||||
.definition_fn(
|
||||
&other.public,
|
||||
&other.name,
|
||||
&other.arguments,
|
||||
&other.return_annotation,
|
||||
&other.body,
|
||||
other.end_position,
|
||||
)
|
||||
.group();
|
||||
let first_fn = self
|
||||
.definition_fn(
|
||||
&handler.public,
|
||||
&handler.name,
|
||||
&handler.arguments,
|
||||
&handler.return_annotation,
|
||||
&handler.body,
|
||||
handler.end_position,
|
||||
true,
|
||||
)
|
||||
.group();
|
||||
|
||||
commented(other_doc_comments.append(other_fn).group(), other_comments)
|
||||
}
|
||||
};
|
||||
let first_fn = commented(fun_doc_comments.append(first_fn).group(), fun_comments);
|
||||
|
||||
let v_body = line()
|
||||
.append(first_fn)
|
||||
.append(if other_fun.is_some() { lines(2) } else { nil() })
|
||||
.append(other_fn);
|
||||
handler_docs.push(first_fn);
|
||||
}
|
||||
|
||||
let is_exhaustive = handlers.len() >= TypedValidator::available_handler_names().len() - 1;
|
||||
|
||||
if !is_exhaustive || !fallback.is_default_fallback() {
|
||||
let fallback_comments = self.pop_comments(fallback.location.start);
|
||||
let fallback_doc_comments = self.doc_comments(fallback.location.start);
|
||||
|
||||
let fallback_fn = self
|
||||
.definition_fn(
|
||||
&fallback.public,
|
||||
&fallback.name,
|
||||
&fallback.arguments,
|
||||
&fallback.return_annotation,
|
||||
&fallback.body,
|
||||
fallback.end_position,
|
||||
true,
|
||||
)
|
||||
.group();
|
||||
|
||||
let fallback_fn = commented(
|
||||
fallback_doc_comments.append(fallback_fn).group(),
|
||||
fallback_comments,
|
||||
);
|
||||
|
||||
handler_docs.push(fallback_fn);
|
||||
}
|
||||
|
||||
let v_body = line().append(join(handler_docs, lines(2)));
|
||||
|
||||
let v_body = match printed_comments(self.pop_comments(end_position), false) {
|
||||
Some(comments) => v_body.append(lines(2)).append(comments).nest(INDENT),
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
Span, TraceLevel, Tracing, TypedArg, TypedClause, TypedDataType, TypedFunction,
|
||||
TypedPattern, TypedValidator, UnOp,
|
||||
},
|
||||
builtins::{bool, byte_array, data, int, list, pair, void, PRELUDE},
|
||||
builtins::PRELUDE,
|
||||
expr::TypedExpr,
|
||||
gen_uplc::{
|
||||
air::ExpectLevel,
|
||||
|
@ -114,66 +114,15 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn generate(
|
||||
&mut self,
|
||||
TypedValidator {
|
||||
fun,
|
||||
other_fun,
|
||||
params,
|
||||
..
|
||||
}: &TypedValidator,
|
||||
module_name: &str,
|
||||
) -> Program<Name> {
|
||||
let mut air_tree_fun = self.build(&fun.body, module_name, &[]);
|
||||
pub fn generate(&mut self, validator: &TypedValidator, module_name: &str) -> Program<Name> {
|
||||
let air_tree_fun = wrap_validator_condition(
|
||||
self.build(&validator.into_script_context_handler(), module_name, &[]),
|
||||
self.tracing,
|
||||
);
|
||||
|
||||
air_tree_fun = wrap_validator_condition(air_tree_fun, self.tracing);
|
||||
let air_tree_fun = AirTree::anon_func(vec!["__context__".to_string()], air_tree_fun, true);
|
||||
|
||||
let (src_code, lines) = self.module_src.get(module_name).unwrap();
|
||||
|
||||
let mut validator_args_tree =
|
||||
self.check_validator_args(&fun.arguments, true, air_tree_fun, src_code, lines);
|
||||
|
||||
if let Some(other) = other_fun {
|
||||
let mut air_tree_fun_other = self.build(&other.body, module_name, &[]);
|
||||
|
||||
air_tree_fun_other = wrap_validator_condition(air_tree_fun_other, self.tracing);
|
||||
|
||||
let validator_args_tree_other = self.check_validator_args(
|
||||
&other.arguments,
|
||||
true,
|
||||
air_tree_fun_other,
|
||||
src_code,
|
||||
lines,
|
||||
);
|
||||
|
||||
let (spend, spend_name, mint, mint_name) =
|
||||
if other.arguments.len() > fun.arguments.len() {
|
||||
(
|
||||
validator_args_tree_other,
|
||||
other.name.clone(),
|
||||
validator_args_tree,
|
||||
fun.name.clone(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
validator_args_tree,
|
||||
fun.name.clone(),
|
||||
validator_args_tree_other,
|
||||
other.name.clone(),
|
||||
)
|
||||
};
|
||||
|
||||
validator_args_tree = AirTree::multi_validator(mint_name, mint, spend_name, spend);
|
||||
|
||||
// Special Case with multi_validators
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string());
|
||||
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_INDEX_EXPOSER.to_string());
|
||||
}
|
||||
|
||||
validator_args_tree = AirTree::no_op(validator_args_tree);
|
||||
let validator_args_tree = AirTree::no_op(air_tree_fun);
|
||||
|
||||
let full_tree = self.hoist_functions_to_validator(validator_args_tree);
|
||||
|
||||
|
@ -181,9 +130,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let full_vec = full_tree.to_vec();
|
||||
|
||||
let mut term = self.uplc_code_gen(full_vec);
|
||||
let term = self.uplc_code_gen(full_vec);
|
||||
|
||||
term = cast_validator_args(term, params);
|
||||
let term = cast_validator_args(term, &validator.params);
|
||||
|
||||
self.finalize(term)
|
||||
}
|
||||
|
@ -278,7 +227,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
self.special_functions.insert_new_function(
|
||||
msg_func_name.clone(),
|
||||
Term::Error.delayed_trace(Term::string(msg)).delay(),
|
||||
void(),
|
||||
Type::void(),
|
||||
);
|
||||
Some(self.special_functions.use_function_tree(msg_func_name))
|
||||
}
|
||||
|
@ -683,17 +632,21 @@ impl<'a> CodeGenerator<'a> {
|
|||
let function_name = format!("__access_index_{}", *index);
|
||||
|
||||
if self.code_gen_functions.get(&function_name).is_none() {
|
||||
let mut body = AirTree::local_var("__fields", list(data()));
|
||||
let mut body = AirTree::local_var("__fields", Type::list(Type::data()));
|
||||
|
||||
for _ in 0..*index {
|
||||
body = AirTree::builtin(
|
||||
DefaultFunction::TailList,
|
||||
list(data()),
|
||||
Type::list(Type::data()),
|
||||
vec![body],
|
||||
)
|
||||
}
|
||||
|
||||
body = AirTree::builtin(DefaultFunction::HeadList, data(), vec![body]);
|
||||
body = AirTree::builtin(
|
||||
DefaultFunction::HeadList,
|
||||
Type::data(),
|
||||
vec![body],
|
||||
);
|
||||
|
||||
self.code_gen_functions.insert(
|
||||
function_name.clone(),
|
||||
|
@ -707,7 +660,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
let list_of_fields = AirTree::call(
|
||||
self.special_functions
|
||||
.use_function_tree(CONSTR_FIELDS_EXPOSER.to_string()),
|
||||
list(data()),
|
||||
Type::list(Type::data()),
|
||||
vec![self.build(record, module_build_name, &[])],
|
||||
);
|
||||
|
||||
|
@ -822,17 +775,21 @@ impl<'a> CodeGenerator<'a> {
|
|||
let function_name = format!("__access_index_{}", *index);
|
||||
|
||||
if self.code_gen_functions.get(&function_name).is_none() {
|
||||
let mut body = AirTree::local_var("__fields", list(data()));
|
||||
let mut body = AirTree::local_var("__fields", Type::list(Type::data()));
|
||||
|
||||
for _ in 0..*index {
|
||||
body = AirTree::builtin(
|
||||
DefaultFunction::TailList,
|
||||
list(data()),
|
||||
Type::list(Type::data()),
|
||||
vec![body],
|
||||
)
|
||||
}
|
||||
|
||||
body = AirTree::builtin(DefaultFunction::HeadList, data(), vec![body]);
|
||||
body = AirTree::builtin(
|
||||
DefaultFunction::HeadList,
|
||||
Type::data(),
|
||||
vec![body],
|
||||
);
|
||||
|
||||
self.code_gen_functions.insert(
|
||||
function_name.clone(),
|
||||
|
@ -941,7 +898,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
let otherwise = match &props.otherwise {
|
||||
Some(x) => x.clone(),
|
||||
// (delay (error ))
|
||||
None => AirTree::anon_func(vec![], AirTree::error(void(), false), true),
|
||||
None => AirTree::anon_func(vec![], AirTree::error(Type::void(), false), true),
|
||||
};
|
||||
|
||||
match pattern {
|
||||
|
@ -957,10 +914,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let expect = AirTree::binop(
|
||||
BinOp::Eq,
|
||||
bool(),
|
||||
Type::bool(),
|
||||
AirTree::int(expected_int),
|
||||
AirTree::local_var(&name, int()),
|
||||
int(),
|
||||
AirTree::local_var(&name, Type::int()),
|
||||
Type::int(),
|
||||
);
|
||||
|
||||
assign_casted_value(
|
||||
|
@ -979,10 +936,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let expect = AirTree::binop(
|
||||
BinOp::Eq,
|
||||
bool(),
|
||||
Type::bool(),
|
||||
AirTree::byte_array(expected_bytes.clone()),
|
||||
AirTree::local_var(&name, byte_array()),
|
||||
byte_array(),
|
||||
AirTree::local_var(&name, Type::byte_array()),
|
||||
Type::byte_array(),
|
||||
);
|
||||
|
||||
assign_casted_value(
|
||||
|
@ -1369,7 +1326,13 @@ impl<'a> CodeGenerator<'a> {
|
|||
type_map.insert(index, field_type);
|
||||
}
|
||||
|
||||
assert!(type_map.len() >= arguments.len());
|
||||
assert!(
|
||||
type_map.len() >= arguments.len(),
|
||||
"type map len: {}, arguments len: {}; for constructor {:?}",
|
||||
type_map.len(),
|
||||
arguments.len(),
|
||||
name,
|
||||
);
|
||||
|
||||
let mut fields = vec![];
|
||||
|
||||
|
@ -1471,7 +1434,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
.unwrap_or_else(|| unreachable!("Failed to find definition for {}", name));
|
||||
|
||||
let then = if props.kind.is_expect()
|
||||
&& (data_type.constructors.len() > 1 || props.full_check)
|
||||
&& (data_type.constructors.len() > 1
|
||||
|| props.full_check
|
||||
|| data_type.is_never())
|
||||
{
|
||||
let (index, _) = data_type
|
||||
.constructors
|
||||
|
@ -1484,7 +1449,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
AirTree::when(
|
||||
&subject_name,
|
||||
void(),
|
||||
Type::void(),
|
||||
tipo.clone(),
|
||||
AirTree::local_var(&constructor_name, tipo.clone()),
|
||||
AirTree::assert_constr_index(
|
||||
|
@ -1496,8 +1461,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
)
|
||||
} else {
|
||||
assert!(
|
||||
data_type.constructors.len() == 1,
|
||||
"data_type={data_type:#?}"
|
||||
data_type.constructors.len() == 1 || data_type.is_never(),
|
||||
"attempted let-assignment on a type with more or less than 1 constructor: \nis_expect? {}\nfull_check? {}\ndata_type={data_type:#?}\n{}",
|
||||
props.kind.is_expect(),
|
||||
props.full_check,
|
||||
name,
|
||||
);
|
||||
then
|
||||
};
|
||||
|
@ -1609,7 +1577,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
otherwise: AirTree,
|
||||
depth: usize,
|
||||
) -> AirTree {
|
||||
assert!(tipo.get_generic().is_none());
|
||||
assert!(
|
||||
tipo.get_generic().is_none(),
|
||||
"left-hand side of expect is generic: {}",
|
||||
tipo.to_pretty(0)
|
||||
);
|
||||
// Shouldn't be needed but still here just in case
|
||||
// this function is called from anywhere else besides assignment
|
||||
let tipo = &convert_opaque_type(tipo, &self.data_types, true);
|
||||
|
@ -1650,11 +1622,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
defined_data_types,
|
||||
location,
|
||||
AirTree::call(
|
||||
AirTree::local_var(format!("__curried_expect_on_list_{}", depth), void()),
|
||||
void(),
|
||||
AirTree::local_var(
|
||||
format!("__curried_expect_on_list_{}", depth),
|
||||
Type::void(),
|
||||
),
|
||||
Type::void(),
|
||||
vec![AirTree::builtin(
|
||||
DefaultFunction::TailList,
|
||||
list(data()),
|
||||
Type::list(Type::data()),
|
||||
vec![AirTree::local_var(
|
||||
format!("__list_{}", depth),
|
||||
tipo.clone(),
|
||||
|
@ -1689,7 +1664,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
&pair_name,
|
||||
AirTree::builtin(
|
||||
DefaultFunction::HeadList,
|
||||
pair(data(), data()),
|
||||
Type::pair(Type::data(), Type::data()),
|
||||
vec![AirTree::local_var(
|
||||
format!("__list_{}", depth),
|
||||
tipo.clone(),
|
||||
|
@ -1733,7 +1708,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
let func_call = AirTree::call(
|
||||
AirTree::var(
|
||||
ValueConstructor::public(
|
||||
void(),
|
||||
Type::void(),
|
||||
ValueConstructorVariant::ModuleFn {
|
||||
name: EXPECT_ON_LIST.to_string(),
|
||||
field_map: None,
|
||||
|
@ -1746,7 +1721,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
EXPECT_ON_LIST,
|
||||
"",
|
||||
),
|
||||
void(),
|
||||
Type::void(),
|
||||
vec![AirTree::local_var(&map_name, tipo.clone()), unwrap_function],
|
||||
);
|
||||
|
||||
|
@ -1826,7 +1801,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
&item_name,
|
||||
AirTree::builtin(
|
||||
DefaultFunction::HeadList,
|
||||
data(),
|
||||
Type::data(),
|
||||
vec![AirTree::local_var(
|
||||
format!("__list_{}", depth),
|
||||
tipo.clone(),
|
||||
|
@ -1835,7 +1810,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::soft_cast_assignment(
|
||||
&item_name,
|
||||
inner_list_type.clone(),
|
||||
AirTree::local_var(&item_name, data()),
|
||||
AirTree::local_var(&item_name, Type::data()),
|
||||
self.expect_type_assign(
|
||||
inner_list_type,
|
||||
AirTree::local_var(&item_name, inner_list_type.clone()),
|
||||
|
@ -1844,12 +1819,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::call(
|
||||
AirTree::local_var(
|
||||
format!("__curried_expect_on_list_{}", depth),
|
||||
void(),
|
||||
Type::void(),
|
||||
),
|
||||
void(),
|
||||
Type::void(),
|
||||
vec![AirTree::builtin(
|
||||
DefaultFunction::TailList,
|
||||
list(data()),
|
||||
Type::list(Type::data()),
|
||||
vec![AirTree::local_var(
|
||||
format!("__list_{}", depth),
|
||||
tipo.clone(),
|
||||
|
@ -1893,7 +1868,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
let func_call = AirTree::call(
|
||||
AirTree::var(
|
||||
ValueConstructor::public(
|
||||
void(),
|
||||
Type::void(),
|
||||
ValueConstructorVariant::ModuleFn {
|
||||
name: EXPECT_ON_LIST.to_string(),
|
||||
field_map: None,
|
||||
|
@ -1906,7 +1881,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
EXPECT_ON_LIST,
|
||||
"",
|
||||
),
|
||||
void(),
|
||||
Type::void(),
|
||||
vec![
|
||||
AirTree::local_var(&list_name, tipo.clone()),
|
||||
unwrap_function,
|
||||
|
@ -1997,14 +1972,28 @@ impl<'a> CodeGenerator<'a> {
|
|||
let current_defined = defined_data_types.clone();
|
||||
let mut diff_defined_types = vec![];
|
||||
|
||||
let var_then =
|
||||
AirTree::call(AirTree::local_var("then_delayed", void()), void(), vec![]);
|
||||
let var_then = AirTree::call(
|
||||
AirTree::local_var("then_delayed", Type::void()),
|
||||
Type::void(),
|
||||
vec![],
|
||||
);
|
||||
|
||||
let otherwise_delayed = AirTree::local_var("otherwise_delayed", void());
|
||||
let otherwise_delayed = AirTree::local_var("otherwise_delayed", Type::void());
|
||||
|
||||
let is_never = data_type.is_never();
|
||||
|
||||
let constr_clauses = data_type.constructors.iter().enumerate().rfold(
|
||||
otherwise_delayed.clone(),
|
||||
|acc, (index, constr)| {
|
||||
// NOTE: For the Never type, we have an placeholder first constructor
|
||||
// that must be ignored. The Never type is considered to have only one
|
||||
// constructor starting at index 1 so it shouldn't be possible to
|
||||
// cast from Data into the first constructor. There's virtually no
|
||||
// constructor at index 0.
|
||||
if is_never && index == 0 {
|
||||
return acc;
|
||||
}
|
||||
|
||||
let mut constr_args = vec![];
|
||||
|
||||
let constr_then = constr.arguments.iter().enumerate().rfold(
|
||||
|
@ -2081,13 +2070,13 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let when_expr = AirTree::when(
|
||||
format!("__subject_span_{}_{}", location.start, location.end),
|
||||
void(),
|
||||
Type::void(),
|
||||
tipo.clone(),
|
||||
AirTree::local_var(
|
||||
format!("__constr_var_span_{}_{}", location.start, location.end),
|
||||
tipo.clone(),
|
||||
),
|
||||
AirTree::call(constr_clauses, void(), vec![]),
|
||||
AirTree::call(constr_clauses, Type::void(), vec![]),
|
||||
);
|
||||
|
||||
let func_body = AirTree::let_assignment(
|
||||
|
@ -2140,7 +2129,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
"",
|
||||
);
|
||||
|
||||
AirTree::call(func_var, void(), args)
|
||||
AirTree::call(func_var, Type::void(), args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2193,7 +2182,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
),
|
||||
)
|
||||
} else if let Some(data_type) = data_type {
|
||||
if data_type.constructors.len() > 1 {
|
||||
if data_type.constructors.len() > 1 && !data_type.is_never() {
|
||||
AirTree::clause(
|
||||
&props.original_subject_name,
|
||||
clause_cond,
|
||||
|
@ -2664,7 +2653,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
// Since check_last_item is false this will never get added to the final uplc anyway
|
||||
ExpectLevel::None,
|
||||
elems_then,
|
||||
AirTree::error(void(), false),
|
||||
AirTree::error(Type::void(), false),
|
||||
)
|
||||
} else {
|
||||
assert!(defined_tails.len() >= elems.len());
|
||||
|
@ -2745,7 +2734,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
||||
false,
|
||||
next_then,
|
||||
AirTree::error(void(), false),
|
||||
AirTree::error(Type::void(), false),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -2775,7 +2764,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
)
|
||||
});
|
||||
|
||||
assert!(!data_type.constructors.is_empty());
|
||||
assert!(
|
||||
!data_type.constructors.is_empty(),
|
||||
"{}\n{constructor:#?}\n{data_type:#?}",
|
||||
subject_tipo.to_pretty(0)
|
||||
);
|
||||
|
||||
let (constr_index, _) = data_type
|
||||
.constructors
|
||||
|
@ -2872,7 +2865,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
||||
false,
|
||||
next_then,
|
||||
AirTree::error(void(), false),
|
||||
AirTree::error(Type::void(), false),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -3001,7 +2994,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(&props.clause_var_name, subject_tipo.clone()),
|
||||
false,
|
||||
tuple_name_assigns,
|
||||
AirTree::error(void(), false),
|
||||
AirTree::error(Type::void(), false),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
|
@ -3029,7 +3022,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::clause_guard(
|
||||
&props.original_subject_name,
|
||||
AirTree::int(value),
|
||||
int(),
|
||||
Type::int(),
|
||||
then,
|
||||
)
|
||||
}
|
||||
|
@ -3038,7 +3031,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::clause_guard(
|
||||
&props.original_subject_name,
|
||||
AirTree::byte_array(value.clone()),
|
||||
byte_array(),
|
||||
Type::byte_array(),
|
||||
then,
|
||||
)
|
||||
}
|
||||
|
@ -3163,14 +3156,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::clause_guard(
|
||||
&props.original_subject_name,
|
||||
AirTree::bool(constr_name == "True"),
|
||||
bool(),
|
||||
Type::bool(),
|
||||
then,
|
||||
)
|
||||
} else if subject_tipo.is_void() {
|
||||
AirTree::clause_guard(
|
||||
&props.original_subject_name,
|
||||
AirTree::void(),
|
||||
void(),
|
||||
Type::void(),
|
||||
then,
|
||||
)
|
||||
} else {
|
||||
|
@ -3242,7 +3235,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
arg_names.push(arg_name.clone());
|
||||
|
||||
let param = AirTree::local_var(&arg_name, data());
|
||||
let param = AirTree::local_var(&arg_name, Type::data());
|
||||
|
||||
let actual_type = convert_opaque_type(&arg.tipo, &self.data_types, true);
|
||||
|
||||
|
@ -3267,7 +3260,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
self.special_functions.insert_new_function(
|
||||
msg_func_name.clone(),
|
||||
Term::Error.delayed_trace(Term::string(msg)).delay(),
|
||||
void(),
|
||||
Type::void(),
|
||||
);
|
||||
|
||||
Some(self.special_functions.use_function_tree(msg_func_name))
|
||||
|
@ -3283,7 +3276,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
inner_then,
|
||||
&actual_type,
|
||||
AssignmentProperties {
|
||||
value_type: data(),
|
||||
value_type: Type::data(),
|
||||
kind: AssignmentKind::expect(),
|
||||
remove_unused: false,
|
||||
full_check: true,
|
||||
|
@ -4036,9 +4029,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
.get(&generic_function_key.function_name)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Missing function definition for {}. Known definitions: {:?}",
|
||||
"Missing function definition for {}. Known functions: {:?}",
|
||||
generic_function_key.function_name,
|
||||
self.code_gen_functions.keys(),
|
||||
self.functions.keys(),
|
||||
)
|
||||
});
|
||||
|
||||
|
@ -5604,8 +5597,18 @@ impl<'a> CodeGenerator<'a> {
|
|||
} => {
|
||||
let tail_name_prefix = "__tail_index";
|
||||
|
||||
let data_type = lookup_data_type_by_tipo(&self.data_types, &tipo)
|
||||
.unwrap_or_else(|| panic!("HOW DID YOU DO THIS ON BOOL OR VOID"));
|
||||
let data_type =
|
||||
lookup_data_type_by_tipo(&self.data_types, &tipo).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Attempted record update on an unknown type!\ntype: {:#?}",
|
||||
tipo
|
||||
)
|
||||
});
|
||||
|
||||
assert!(
|
||||
!data_type.is_never(),
|
||||
"Attempted record update on a Never type.",
|
||||
);
|
||||
|
||||
let constructor_field_count = data_type.constructors[0].arguments.len();
|
||||
let record = arg_stack.pop().unwrap();
|
||||
|
|
|
@ -7,7 +7,6 @@ use crate::{
|
|||
Constant, DataTypeKey, FunctionAccessKey, Pattern, Span, TraceLevel, TypedArg,
|
||||
TypedAssignmentKind, TypedClause, TypedDataType, TypedPattern,
|
||||
},
|
||||
builtins::{data, function, int, list, void},
|
||||
expr::TypedExpr,
|
||||
line_numbers::{LineColumn, LineNumbers},
|
||||
tipo::{
|
||||
|
@ -212,7 +211,7 @@ impl CodeGenSpecialFuncs {
|
|||
Term::snd_pair()
|
||||
.apply(Term::unconstr_data().apply(Term::var("__constr_var")))
|
||||
.lambda("__constr_var"),
|
||||
function(vec![data()], list(data())),
|
||||
Type::function(vec![Type::data()], Type::list(Type::data())),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -222,7 +221,7 @@ impl CodeGenSpecialFuncs {
|
|||
Term::fst_pair()
|
||||
.apply(Term::unconstr_data().apply(Term::var("__constr_var")))
|
||||
.lambda("__constr_var"),
|
||||
function(vec![data()], int()),
|
||||
Type::function(vec![Type::data()], Type::int()),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -784,7 +783,7 @@ pub fn rearrange_list_clauses(
|
|||
tipo: tipo.clone(),
|
||||
text: Box::new(TypedExpr::String {
|
||||
location: Span::empty(),
|
||||
tipo: crate::builtins::string(),
|
||||
tipo: Type::string(),
|
||||
value: format!("Clause hole found for {index} elements."),
|
||||
}),
|
||||
then: Box::new(TypedExpr::ErrorTerm {
|
||||
|
@ -1688,15 +1687,15 @@ pub fn cast_validator_args(term: Term<Name>, arguments: &[TypedArg]) -> Term<Nam
|
|||
|
||||
pub fn wrap_validator_condition(air_tree: AirTree, trace: TraceLevel) -> AirTree {
|
||||
let otherwise = match trace {
|
||||
TraceLevel::Silent | TraceLevel::Compact => AirTree::error(void(), true),
|
||||
TraceLevel::Silent | TraceLevel::Compact => AirTree::error(Type::void(), true),
|
||||
TraceLevel::Verbose => AirTree::trace(
|
||||
AirTree::string("Validator returned false"),
|
||||
void(),
|
||||
AirTree::error(void(), true),
|
||||
Type::void(),
|
||||
AirTree::error(Type::void(), true),
|
||||
),
|
||||
};
|
||||
|
||||
AirTree::if_branch(void(), air_tree, AirTree::void(), otherwise)
|
||||
AirTree::if_branch(Type::void(), air_tree, AirTree::void(), otherwise)
|
||||
}
|
||||
|
||||
pub fn extract_constant(term: &Term<Name>) -> Option<Rc<UplcConstant>> {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use super::air::{Air, ExpectLevel};
|
||||
use crate::{
|
||||
ast::{BinOp, Curve, Span, UnOp},
|
||||
builtins::{bool, byte_array, data, int, list, string, void},
|
||||
tipo::{Type, ValueConstructor, ValueConstructorVariant},
|
||||
};
|
||||
use indexmap::IndexSet;
|
||||
|
@ -113,7 +112,7 @@ pub enum AirMsg {
|
|||
impl AirMsg {
|
||||
pub fn to_air_tree(&self) -> AirTree {
|
||||
match self {
|
||||
AirMsg::LocalVar(name) => AirTree::local_var(name, string()),
|
||||
AirMsg::LocalVar(name) => AirTree::local_var(name, Type::string()),
|
||||
AirMsg::Msg(msg) => AirTree::string(msg),
|
||||
}
|
||||
}
|
||||
|
@ -862,8 +861,8 @@ impl AirTree {
|
|||
AirTree::var(
|
||||
ValueConstructor::public(
|
||||
Type::Fn {
|
||||
args: vec![list(data())],
|
||||
ret: data(),
|
||||
args: vec![Type::list(Type::data())],
|
||||
ret: Type::data(),
|
||||
alias: None,
|
||||
}
|
||||
.into(),
|
||||
|
@ -879,7 +878,7 @@ impl AirTree {
|
|||
function_name,
|
||||
"",
|
||||
),
|
||||
data(),
|
||||
Type::data(),
|
||||
vec![list_of_fields],
|
||||
),
|
||||
tipo.clone(),
|
||||
|
@ -984,7 +983,7 @@ impl AirTree {
|
|||
} else {
|
||||
DefaultFunction::SndPair
|
||||
},
|
||||
data(),
|
||||
Type::data(),
|
||||
vec![tuple],
|
||||
),
|
||||
tipo.clone(),
|
||||
|
@ -1039,9 +1038,9 @@ impl AirTree {
|
|||
}
|
||||
|
||||
pub fn expect_on_list2() -> AirTree {
|
||||
let inner_expect_on_list = AirTree::local_var(INNER_EXPECT_ON_LIST, void());
|
||||
let inner_expect_on_list = AirTree::local_var(INNER_EXPECT_ON_LIST, Type::void());
|
||||
|
||||
let list_var = AirTree::local_var("__list_to_check", list(data()));
|
||||
let list_var = AirTree::local_var("__list_to_check", Type::list(Type::data()));
|
||||
|
||||
AirTree::let_assignment(
|
||||
INNER_EXPECT_ON_LIST,
|
||||
|
@ -1051,13 +1050,13 @@ impl AirTree {
|
|||
"__list_to_check".to_string(),
|
||||
],
|
||||
AirTree::call(
|
||||
AirTree::local_var("__check_with", void()),
|
||||
void(),
|
||||
AirTree::local_var("__check_with", Type::void()),
|
||||
Type::void(),
|
||||
vec![
|
||||
list_var.clone(),
|
||||
AirTree::call(
|
||||
inner_expect_on_list.clone(),
|
||||
void(),
|
||||
Type::void(),
|
||||
vec![inner_expect_on_list.clone()],
|
||||
),
|
||||
],
|
||||
|
@ -1066,27 +1065,27 @@ impl AirTree {
|
|||
),
|
||||
AirTree::call(
|
||||
inner_expect_on_list.clone(),
|
||||
void(),
|
||||
Type::void(),
|
||||
vec![inner_expect_on_list, list_var],
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn expect_on_list() -> AirTree {
|
||||
let list_var = AirTree::local_var("__list_to_check", list(data()));
|
||||
let list_var = AirTree::local_var("__list_to_check", Type::list(Type::data()));
|
||||
|
||||
let head_list = AirTree::builtin(DefaultFunction::HeadList, data(), vec![list_var]);
|
||||
let head_list = AirTree::builtin(DefaultFunction::HeadList, Type::data(), vec![list_var]);
|
||||
|
||||
let expect_on_head = AirTree::call(
|
||||
AirTree::local_var("__check_with", void()),
|
||||
void(),
|
||||
AirTree::local_var("__check_with", Type::void()),
|
||||
Type::void(),
|
||||
vec![head_list],
|
||||
);
|
||||
|
||||
let next_call = AirTree::call(
|
||||
AirTree::var(
|
||||
ValueConstructor::public(
|
||||
void(),
|
||||
Type::void(),
|
||||
ValueConstructorVariant::ModuleFn {
|
||||
name: EXPECT_ON_LIST.to_string(),
|
||||
field_map: None,
|
||||
|
@ -1099,14 +1098,17 @@ impl AirTree {
|
|||
EXPECT_ON_LIST,
|
||||
"",
|
||||
),
|
||||
void(),
|
||||
Type::void(),
|
||||
vec![
|
||||
AirTree::builtin(
|
||||
DefaultFunction::TailList,
|
||||
list(data()),
|
||||
vec![AirTree::local_var("__list_to_check", list(data()))],
|
||||
Type::list(Type::data()),
|
||||
vec![AirTree::local_var(
|
||||
"__list_to_check",
|
||||
Type::list(Type::data()),
|
||||
)],
|
||||
),
|
||||
AirTree::local_var("__check_with", void()),
|
||||
AirTree::local_var("__check_with", Type::void()),
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -1114,7 +1116,7 @@ impl AirTree {
|
|||
|
||||
AirTree::list_clause(
|
||||
"__list_to_check",
|
||||
void(),
|
||||
Type::void(),
|
||||
AirTree::void(),
|
||||
assign,
|
||||
None,
|
||||
|
@ -1675,10 +1677,10 @@ impl AirTree {
|
|||
|
||||
pub fn return_type(&self) -> Rc<Type> {
|
||||
match self {
|
||||
AirTree::Int { .. } => int(),
|
||||
AirTree::String { .. } => string(),
|
||||
AirTree::ByteArray { .. } => byte_array(),
|
||||
AirTree::Bool { .. } => bool(),
|
||||
AirTree::Int { .. } => Type::int(),
|
||||
AirTree::String { .. } => Type::string(),
|
||||
AirTree::ByteArray { .. } => Type::byte_array(),
|
||||
AirTree::Bool { .. } => Type::bool(),
|
||||
AirTree::CurvePoint { point } => point.tipo(),
|
||||
AirTree::List { tipo, .. }
|
||||
| AirTree::Tuple { tipo, .. }
|
||||
|
@ -1693,14 +1695,14 @@ impl AirTree {
|
|||
| AirTree::RecordUpdate { tipo, .. }
|
||||
| AirTree::ErrorTerm { tipo, .. }
|
||||
| AirTree::Trace { tipo, .. } => tipo.clone(),
|
||||
AirTree::Void => void(),
|
||||
AirTree::Void => Type::void(),
|
||||
AirTree::Var { constructor, .. } => constructor.tipo.clone(),
|
||||
AirTree::Fn { func_body, .. } => func_body.return_type(),
|
||||
AirTree::UnOp { op, .. } => match op {
|
||||
UnOp::Not => bool(),
|
||||
UnOp::Negate => int(),
|
||||
UnOp::Not => Type::bool(),
|
||||
UnOp::Negate => Type::int(),
|
||||
},
|
||||
AirTree::CastToData { .. } => data(),
|
||||
AirTree::CastToData { .. } => Type::data(),
|
||||
AirTree::Clause { then, .. }
|
||||
| AirTree::ListClause { then, .. }
|
||||
| AirTree::WrapClause { then, .. }
|
||||
|
@ -1725,7 +1727,7 @@ impl AirTree {
|
|||
| AirTree::FieldsEmpty { then, .. }
|
||||
| AirTree::ListEmpty { then, .. }
|
||||
| AirTree::NoOp { then } => then.return_type(),
|
||||
AirTree::MultiValidator { .. } => void(),
|
||||
AirTree::MultiValidator { .. } => Type::void(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{error::ParseError, token::Token};
|
||||
use crate::{
|
||||
ast,
|
||||
builtins::{PAIR, PRELUDE},
|
||||
ast::{self, well_known},
|
||||
builtins::PRELUDE,
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
|
@ -19,7 +19,7 @@ pub fn parser() -> impl Parser<Token, ast::Annotation, Error = ParseError> {
|
|||
select! {Token::Name { name } if name == PRELUDE => name}
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not()
|
||||
.then_ignore(select! {Token::UpName { name } if name == PAIR => name})
|
||||
.then_ignore(select! {Token::UpName { name } if name == well_known::PAIR => name})
|
||||
.ignore_then(
|
||||
expression
|
||||
.clone()
|
||||
|
|
|
@ -1,78 +1,36 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/validator.rs
|
||||
description: "Code:\n\nvalidator {\n fn foo(datum, rdmr, ctx) {\n True\n }\n\n fn bar(rdmr, ctx) {\n True\n }\n}\n"
|
||||
description: "Code:\n\nvalidator thing {\n spend (datum, rdmr, ctx) {\n True\n }\n\n mint (rdmr, ctx) {\n True\n }\n}\n"
|
||||
---
|
||||
Validator(
|
||||
Validator {
|
||||
doc: None,
|
||||
end_position: 90,
|
||||
fun: Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 21..26,
|
||||
},
|
||||
),
|
||||
location: 21..26,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 28..32,
|
||||
},
|
||||
),
|
||||
location: 28..32,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 34..37,
|
||||
},
|
||||
),
|
||||
location: 34..37,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 45..49,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 14..38,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 52,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
other_fun: Some(
|
||||
end_position: 95,
|
||||
handlers: [
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 64..68,
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 27..32,
|
||||
},
|
||||
),
|
||||
location: 64..68,
|
||||
location: 27..32,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 34..38,
|
||||
},
|
||||
),
|
||||
location: 34..38,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
|
@ -82,30 +40,122 @@ Validator(
|
|||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 70..73,
|
||||
location: 40..43,
|
||||
},
|
||||
),
|
||||
location: 70..73,
|
||||
location: 40..43,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 81..85,
|
||||
location: 51..55,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 57..74,
|
||||
name: "bar",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
location: 20..44,
|
||||
name: "spend",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 26..44,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 88,
|
||||
end_position: 58,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
),
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 69..73,
|
||||
},
|
||||
),
|
||||
location: 69..73,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 75..78,
|
||||
},
|
||||
),
|
||||
location: 75..78,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 86..90,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 63..79,
|
||||
name: "mint",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 68..79,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 93,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
],
|
||||
location: 0..9,
|
||||
name: "thing",
|
||||
params: [],
|
||||
fallback: Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Discarded {
|
||||
name: "_",
|
||||
label: "_",
|
||||
location: 0..9,
|
||||
},
|
||||
),
|
||||
location: 0..9,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: ErrorTerm {
|
||||
location: 0..9,
|
||||
},
|
||||
doc: None,
|
||||
location: 0..9,
|
||||
name: "else",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 0..9,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 8,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/validator.rs
|
||||
description: "Code:\n\nvalidator thing {\n spend (datum, rdmr, ctx) {\n True\n }\n\n mint (rdmr, ctx) {\n True\n }\n\n else (_) {\n fail\n }\n}\n"
|
||||
---
|
||||
Validator(
|
||||
Validator {
|
||||
doc: None,
|
||||
end_position: 122,
|
||||
handlers: [
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 27..32,
|
||||
},
|
||||
),
|
||||
location: 27..32,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 34..38,
|
||||
},
|
||||
),
|
||||
location: 34..38,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 40..43,
|
||||
},
|
||||
),
|
||||
location: 40..43,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 51..55,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 20..44,
|
||||
name: "spend",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 26..44,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 58,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 69..73,
|
||||
},
|
||||
),
|
||||
location: 69..73,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 75..78,
|
||||
},
|
||||
),
|
||||
location: 75..78,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 86..90,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 63..79,
|
||||
name: "mint",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 68..79,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 93,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
],
|
||||
location: 0..9,
|
||||
name: "thing",
|
||||
params: [],
|
||||
fallback: Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Discarded {
|
||||
name: "_",
|
||||
label: "_",
|
||||
location: 104..105,
|
||||
},
|
||||
),
|
||||
location: 104..105,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: ErrorTerm {
|
||||
location: 113..117,
|
||||
},
|
||||
doc: None,
|
||||
location: 103..106,
|
||||
name: "else",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 103..106,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 120,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
},
|
||||
)
|
|
@ -1,68 +1,112 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/validator.rs
|
||||
description: "Code:\n\nvalidator {\n fn foo(datum, rdmr, ctx) {\n True\n }\n}\n"
|
||||
description: "Code:\n\nvalidator hello {\n spend (datum, rdmr, ctx) {\n True\n }\n}\n"
|
||||
---
|
||||
Validator(
|
||||
Validator {
|
||||
doc: None,
|
||||
end_position: 54,
|
||||
fun: Function {
|
||||
end_position: 60,
|
||||
handlers: [
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 27..32,
|
||||
},
|
||||
),
|
||||
location: 27..32,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 34..38,
|
||||
},
|
||||
),
|
||||
location: 34..38,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 40..43,
|
||||
},
|
||||
),
|
||||
location: 40..43,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 51..55,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 20..44,
|
||||
name: "spend",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 26..44,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 58,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
],
|
||||
location: 0..9,
|
||||
name: "hello",
|
||||
params: [],
|
||||
fallback: Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 21..26,
|
||||
Discarded {
|
||||
name: "_",
|
||||
label: "_",
|
||||
location: 0..9,
|
||||
},
|
||||
),
|
||||
location: 21..26,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 28..32,
|
||||
},
|
||||
),
|
||||
location: 28..32,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 34..37,
|
||||
},
|
||||
),
|
||||
location: 34..37,
|
||||
location: 0..9,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 45..49,
|
||||
name: "True",
|
||||
body: ErrorTerm {
|
||||
location: 0..9,
|
||||
},
|
||||
doc: None,
|
||||
location: 14..38,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
location: 0..9,
|
||||
name: "else",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 0..9,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 52,
|
||||
end_position: 8,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
other_fun: None,
|
||||
location: 0..9,
|
||||
params: [],
|
||||
},
|
||||
)
|
||||
|
|
|
@ -1,66 +1,112 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use super::function::param;
|
||||
use crate::{
|
||||
ast,
|
||||
parser::{error::ParseError, token::Token},
|
||||
ast::{self, well_known},
|
||||
expr::UntypedExpr,
|
||||
parser::{annotation, error::ParseError, expr, token::Token},
|
||||
};
|
||||
|
||||
use super::function;
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
just(Token::Validator)
|
||||
.ignore_then(
|
||||
function::param(true)
|
||||
.ignore_then(select! {Token::Name {name} => name})
|
||||
.then(
|
||||
param(true)
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.map_with_span(|arguments, span| (arguments, span))
|
||||
.or_not(),
|
||||
)
|
||||
// so far: validator my_validator(arg1: Whatever)
|
||||
.then(
|
||||
function()
|
||||
select! {Token::Name {name} => name}
|
||||
.then(args_and_body())
|
||||
.map_with_span(|(name, mut function), span| {
|
||||
function.name = name;
|
||||
function.location.start = span.start;
|
||||
|
||||
function
|
||||
})
|
||||
.repeated()
|
||||
.at_least(1)
|
||||
.at_most(2)
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace))
|
||||
.map(|defs| {
|
||||
defs.into_iter().map(|def| {
|
||||
let ast::UntypedDefinition::Fn(fun) = def else {
|
||||
unreachable!("It should be a fn definition");
|
||||
};
|
||||
.then(
|
||||
just(Token::Else)
|
||||
.ignore_then(args_and_body().map_with_span(|mut function, span| {
|
||||
function.name = well_known::VALIDATOR_ELSE.to_string();
|
||||
function.location.start = span.start;
|
||||
|
||||
fun
|
||||
})
|
||||
}),
|
||||
function
|
||||
}))
|
||||
.or_not(),
|
||||
)
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.map_with_span(|(opt_extra_params, mut functions), span| {
|
||||
let (params, params_span) = opt_extra_params.unwrap_or((
|
||||
vec![],
|
||||
ast::Span {
|
||||
start: 0,
|
||||
end: span.start + "validator".len(),
|
||||
},
|
||||
));
|
||||
.map_with_span(
|
||||
|((name, opt_extra_params), (handlers, opt_catch_all)), span| {
|
||||
let (params, params_span) = opt_extra_params.unwrap_or((
|
||||
vec![],
|
||||
ast::Span {
|
||||
start: 0,
|
||||
end: span.start + "validator".len(),
|
||||
},
|
||||
));
|
||||
|
||||
let fun = functions
|
||||
.next()
|
||||
.expect("unwrapping safe because there's 'at_least(1)' function");
|
||||
|
||||
let other_fun = functions.next();
|
||||
|
||||
ast::UntypedDefinition::Validator(ast::Validator {
|
||||
doc: None,
|
||||
fun,
|
||||
other_fun,
|
||||
location: ast::Span {
|
||||
let location = ast::Span {
|
||||
start: span.start,
|
||||
// capture the span from the optional params
|
||||
end: params_span.end,
|
||||
},
|
||||
params,
|
||||
end_position: span.end - 1,
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
ast::UntypedDefinition::Validator(ast::Validator {
|
||||
doc: None,
|
||||
name,
|
||||
handlers,
|
||||
location,
|
||||
params,
|
||||
end_position: span.end - 1,
|
||||
fallback: opt_catch_all
|
||||
.unwrap_or(ast::UntypedValidator::default_fallback(location)),
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn args_and_body() -> impl Parser<Token, ast::UntypedFunction, Error = ParseError> {
|
||||
param(false)
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.map_with_span(|arguments, span| (arguments, span))
|
||||
.then(just(Token::RArrow).ignore_then(annotation()).or_not())
|
||||
.then(
|
||||
expr::sequence()
|
||||
.or_not()
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.map_with_span(
|
||||
|(((arguments, args_span), return_annotation), body), span| {
|
||||
let location = ast::Span {
|
||||
start: span.start,
|
||||
end: return_annotation
|
||||
.as_ref()
|
||||
.map(|l| l.location().end)
|
||||
.unwrap_or_else(|| args_span.end),
|
||||
};
|
||||
|
||||
ast::Function {
|
||||
arguments,
|
||||
body: body.unwrap_or_else(|| UntypedExpr::todo(None, span)),
|
||||
doc: None,
|
||||
location,
|
||||
end_position: span.end - 1,
|
||||
name: "temp".to_string(),
|
||||
public: true,
|
||||
return_annotation: return_annotation
|
||||
.or(Some(ast::Annotation::boolean(location))),
|
||||
return_type: (),
|
||||
on_test_failure: ast::OnTestFailure::FailImmediately,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -71,8 +117,8 @@ mod tests {
|
|||
fn validator() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
validator {
|
||||
fn foo(datum, rdmr, ctx) {
|
||||
validator hello {
|
||||
spend (datum, rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -84,16 +130,37 @@ mod tests {
|
|||
fn double_validator() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
validator {
|
||||
fn foo(datum, rdmr, ctx) {
|
||||
validator thing {
|
||||
spend (datum, rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
|
||||
fn bar(rdmr, ctx) {
|
||||
mint (rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fallback() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
validator thing {
|
||||
spend (datum, rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
|
||||
mint (rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
|
||||
else (_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{
|
||||
builtins::{PAIR, PRELUDE},
|
||||
ast::well_known,
|
||||
builtins::PRELUDE,
|
||||
expr::UntypedExpr,
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
|
@ -11,7 +12,7 @@ pub fn parser(
|
|||
select! {Token::Name { name } if name == PRELUDE => name}
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not()
|
||||
.then_ignore(select! {Token::UpName { name } if name == PAIR => name})
|
||||
.then_ignore(select! {Token::UpName { name } if name == well_known::PAIR => name})
|
||||
.ignore_then(
|
||||
r.clone()
|
||||
.separated_by(just(Token::Comma))
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{
|
||||
ast::UntypedPattern,
|
||||
builtins::PAIR,
|
||||
ast::{well_known, UntypedPattern},
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
@ -8,7 +7,7 @@ use chumsky::prelude::*;
|
|||
pub fn parser(
|
||||
pattern: Recursive<'_, Token, UntypedPattern, ParseError>,
|
||||
) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ {
|
||||
select! {Token::UpName { name } if name == PAIR => name}
|
||||
select! {Token::UpName { name } if name == well_known::PAIR => name}
|
||||
.ignore_then(choice((
|
||||
just(Token::LeftParen),
|
||||
just(Token::NewLineLeftParen),
|
||||
|
|
|
@ -175,6 +175,6 @@ macro_rules! assert_format {
|
|||
let (module2, extra2) = $crate::parser::module(&out, $crate::ast::ModuleKind::Lib).unwrap();
|
||||
let mut out2 = String::new();
|
||||
$crate::format::pretty(&mut out2, module2, extra2, &out);
|
||||
assert_eq!(out, out2, "formatting isn't idempotent");
|
||||
pretty_assertions::assert_eq!(out, out2, "formatting isn't idempotent");
|
||||
};
|
||||
}
|
||||
|
|
|
@ -111,8 +111,8 @@ fn bls12_381_ml_result_in_data_type() {
|
|||
#[test]
|
||||
fn validator_illegal_return_type() {
|
||||
let source_code = r#"
|
||||
validator {
|
||||
fn foo(d, r, c) {
|
||||
validator foo {
|
||||
spend(d, r, c) -> Int {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ fn implicitly_discard_void() {
|
|||
#[test]
|
||||
fn validator_illegal_arity() {
|
||||
let source_code = r#"
|
||||
validator {
|
||||
fn foo(c) {
|
||||
validator foo {
|
||||
mint(c) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -318,19 +318,17 @@ fn mark_constructors_as_used_via_field_access() {
|
|||
bar: Int,
|
||||
}
|
||||
|
||||
validator {
|
||||
fn foo(d: Datum, _r, _c) {
|
||||
when d is {
|
||||
D0(params) -> params.foo == 1
|
||||
D1(_params) -> False
|
||||
}
|
||||
fn spend(d: Datum, _r, _c) {
|
||||
when d is {
|
||||
D0(params) -> params.foo == 1
|
||||
D1(_params) -> False
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let (warnings, _) = check_validator(parse(source_code)).unwrap();
|
||||
let (warnings, _) = check(parse(source_code)).unwrap();
|
||||
|
||||
assert_eq!(warnings.len(), 1)
|
||||
assert_eq!(warnings.len(), 2)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -359,8 +357,8 @@ fn expect_multi_patterns() {
|
|||
#[test]
|
||||
fn validator_correct_form() {
|
||||
let source_code = r#"
|
||||
validator {
|
||||
fn foo(d, r, c) {
|
||||
validator foo {
|
||||
spend(d: Option<Data>, r, oref, c) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -372,8 +370,8 @@ fn validator_correct_form() {
|
|||
#[test]
|
||||
fn validator_in_lib_warning() {
|
||||
let source_code = r#"
|
||||
validator {
|
||||
fn foo(c) {
|
||||
validator foo {
|
||||
spend(c) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -390,12 +388,12 @@ fn validator_in_lib_warning() {
|
|||
#[test]
|
||||
fn multi_validator() {
|
||||
let source_code = r#"
|
||||
validator(foo: ByteArray, bar: Int) {
|
||||
fn spend(_d, _r, _c) {
|
||||
validator foo(foo: ByteArray, bar: Int) {
|
||||
spend(_d: Option<Data>, _r, _oref, _c) {
|
||||
foo == #"aabb"
|
||||
}
|
||||
|
||||
fn mint(_r, _c) {
|
||||
mint(_r, _p, _c) {
|
||||
bar == 0
|
||||
}
|
||||
}
|
||||
|
@ -409,12 +407,12 @@ fn multi_validator() {
|
|||
#[test]
|
||||
fn multi_validator_warning() {
|
||||
let source_code = r#"
|
||||
validator(foo: ByteArray, bar: Int) {
|
||||
fn spend(_d, _r, _c) {
|
||||
validator foo(foo: ByteArray, bar: Int) {
|
||||
spend(_d: Option<Data>, _r, _oref, _c) {
|
||||
foo == #"aabb"
|
||||
}
|
||||
|
||||
fn mint(_r, _c) {
|
||||
mint(_r, _p, _c) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -459,8 +457,8 @@ fn exhaustiveness_simple() {
|
|||
#[test]
|
||||
fn validator_args_no_annotation() {
|
||||
let source_code = r#"
|
||||
validator(d) {
|
||||
fn foo(a, b, c) {
|
||||
validator hello(d) {
|
||||
spend(a: Option<Data>, b, oref, c) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -477,9 +475,13 @@ fn validator_args_no_annotation() {
|
|||
assert!(param.tipo.is_data());
|
||||
});
|
||||
|
||||
validator.fun.arguments.iter().for_each(|arg| {
|
||||
assert!(arg.tipo.is_data());
|
||||
})
|
||||
validator.handlers[0]
|
||||
.arguments
|
||||
.iter()
|
||||
.skip(1)
|
||||
.for_each(|arg| {
|
||||
assert!(arg.tipo.is_data());
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2472,9 +2474,11 @@ fn validator_private_type_leak() {
|
|||
bar: Int,
|
||||
}
|
||||
|
||||
validator {
|
||||
pub fn bar(datum: Datum, redeemer: Redeemer, _ctx) {
|
||||
datum.foo == redeemer.bar
|
||||
validator bar {
|
||||
spend(datum: Option<Datum>, redeemer: Redeemer, _oref, _ctx) {
|
||||
expect Some(d) = datum
|
||||
|
||||
d.foo == redeemer.bar
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
@ -2496,30 +2500,11 @@ fn validator_public() {
|
|||
bar: Int,
|
||||
}
|
||||
|
||||
validator {
|
||||
pub fn bar(datum: Datum, redeemer: Redeemer, _ctx) {
|
||||
datum.foo == redeemer.bar
|
||||
}
|
||||
}
|
||||
"#;
|
||||
validator bar {
|
||||
spend(datum: Option<Datum>, redeemer: Redeemer, _oref, _ctx) {
|
||||
expect Some(d) = datum
|
||||
|
||||
assert!(check_validator(parse(source_code)).is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_private_everything() {
|
||||
let source_code = r#"
|
||||
type Datum {
|
||||
foo: Int,
|
||||
}
|
||||
|
||||
type Redeemer {
|
||||
bar: Int,
|
||||
}
|
||||
|
||||
validator {
|
||||
fn bar(datum: Datum, redeemer: Redeemer, _ctx) {
|
||||
datum.foo == redeemer.bar
|
||||
d.foo == redeemer.bar
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
@ -3065,3 +3050,173 @@ fn test_return_illegal() {
|
|||
Err((_, Error::IllegalTestType { .. }))
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_by_name() {
|
||||
let source_code = r#"
|
||||
validator foo {
|
||||
mint(_redeemer: Data, policy_id: ByteArray, _self: Data) {
|
||||
policy_id == "foo"
|
||||
}
|
||||
}
|
||||
|
||||
test test_1() {
|
||||
foo.mint(Void, "foo", Void)
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(check_validator(parse(source_code)).is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_by_name_unknown_handler() {
|
||||
let source_code = r#"
|
||||
validator foo {
|
||||
mint(_redeemer: Data, policy_id: ByteArray, _self: Data) {
|
||||
policy_id == "foo"
|
||||
}
|
||||
}
|
||||
|
||||
test foo() {
|
||||
foo.bar(Void, "foo", Void)
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check_validator(parse(source_code)),
|
||||
Err((_, Error::UnknownValidatorHandler { .. }))
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_by_name_module_duplicate() {
|
||||
let source_code = r#"
|
||||
use aiken/builtin
|
||||
|
||||
validator builtin {
|
||||
mint(_redeemer: Data, _policy_id: ByteArray, _self: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check_validator(parse(source_code)),
|
||||
Err((_, Error::DuplicateName { .. }))
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_by_name_validator_duplicate_1() {
|
||||
let source_code = r#"
|
||||
validator foo {
|
||||
mint(_redeemer: Data, _policy_id: ByteArray, _self: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
||||
validator foo {
|
||||
mint(_redeemer: Data, _policy_id: ByteArray, _self: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check_validator(parse(source_code)),
|
||||
Err((_, Error::DuplicateName { .. }))
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validator_by_name_validator_duplicate_2() {
|
||||
let source_code = r#"
|
||||
validator foo {
|
||||
mint(_redeemer: Data, _policy_id: ByteArray, _self: Data) {
|
||||
True
|
||||
}
|
||||
|
||||
mint(_redeemer: Data, _policy_id: ByteArray, _self: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check_validator(parse(source_code)),
|
||||
Err((_, Error::DuplicateName { .. }))
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exhaustive_handlers() {
|
||||
let source_code = r#"
|
||||
validator foo {
|
||||
mint(_redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
spend(_datum, _redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
withdraw(_redeemer, _account, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
publish(_redeemer, _certificate, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
vote(_redeemer, _voter, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
propose(_redeemer, _proposal, _self) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(check_validator(parse(source_code)).is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extraneous_fallback_on_exhaustive_handlers() {
|
||||
let source_code = r#"
|
||||
validator foo {
|
||||
mint(_redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
spend(_datum, _redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
withdraw(_redeemer, _account, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
publish(_redeemer, _certificate, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
vote(_redeemer, _voter, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
propose(_redeemer, _proposal, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
else (_) -> Bool {
|
||||
fail
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check_validator(parse(source_code)),
|
||||
Err((_, Error::UnexpectedValidatorFallback { .. }))
|
||||
))
|
||||
}
|
||||
|
|
|
@ -198,18 +198,18 @@ fn format_preserve_newline_after_bool_expect() {
|
|||
fn format_validator() {
|
||||
assert_format!(
|
||||
r#"
|
||||
validator ( ) {
|
||||
validator thing ( ) {
|
||||
// What is the purpose of life
|
||||
|
||||
fn foo (d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
spend(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
||||
// What?
|
||||
validator {
|
||||
validator foo {
|
||||
/// Some documentation for foo
|
||||
fn foo() {
|
||||
foo() {
|
||||
Void
|
||||
}
|
||||
|
||||
|
@ -223,12 +223,12 @@ fn format_validator() {
|
|||
fn format_double_validator() {
|
||||
assert_format!(
|
||||
r#"
|
||||
validator ( param1 : ByteArray ) {
|
||||
fn foo (d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
validator foo( param1 : ByteArray ) {
|
||||
spend(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
True
|
||||
}
|
||||
/// This is bar
|
||||
fn bar(r: Redeemer, ctx : ScriptContext ) -> Bool { True }
|
||||
mint(r: Redeemer, ctx : ScriptContext ) -> Bool { True }
|
||||
}
|
||||
"#
|
||||
);
|
||||
|
@ -238,12 +238,12 @@ fn format_double_validator() {
|
|||
fn format_double_validator_public() {
|
||||
assert_format!(
|
||||
r#"
|
||||
validator ( param1 : ByteArray ) {
|
||||
pub fn foo (d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
validator foo ( param1 : ByteArray ) {
|
||||
spend(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
True
|
||||
}
|
||||
/// This is bar
|
||||
pub fn bar(r: Redeemer, ctx : ScriptContext ) -> Bool { True }
|
||||
mint(r: Redeemer, ctx : ScriptContext ) -> Bool { True }
|
||||
}
|
||||
"#
|
||||
);
|
||||
|
@ -967,20 +967,20 @@ fn format_anon_fn_pattern() {
|
|||
fn format_validator_pattern() {
|
||||
assert_format!(
|
||||
r#"
|
||||
validator(Foo { a, b, .. }) {
|
||||
fn foo() { todo }
|
||||
validator foo(Foo { a, b, .. }) {
|
||||
spend() { todo }
|
||||
}
|
||||
|
||||
validator([Bar] : List<Bar>) {
|
||||
fn bar() { todo }
|
||||
validator foo([Bar] : List<Bar>) {
|
||||
spend() { todo }
|
||||
}
|
||||
|
||||
validator((Baz, Baz) as x) {
|
||||
fn baz() { todo }
|
||||
validator foo((Baz, Baz) as x) {
|
||||
mint() { todo }
|
||||
}
|
||||
|
||||
validator((fst, snd) as x: Pair<Int, Int>) {
|
||||
fn fiz() { todo }
|
||||
validator fiz((fst, snd) as x: Pair<Int, Int>) {
|
||||
spend() { todo }
|
||||
}
|
||||
"#
|
||||
);
|
||||
|
@ -1140,3 +1140,110 @@ fn format_long_pair() {
|
|||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_validator_exhaustive_handlers() {
|
||||
assert_format!(
|
||||
r#"
|
||||
validator foo {
|
||||
mint(_redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
spend(_datum, _redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
withdraw(_redeemer, _account, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
publish(_redeemer, _certificate, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
vote(_redeemer, _voter, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
propose(_redeemer, _proposal, _self) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_validator_exhaustive_handlers_extra_default_fallback() {
|
||||
assert_format!(
|
||||
r#"
|
||||
validator foo {
|
||||
mint(_redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
spend(_datum, _redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
withdraw(_redeemer, _account, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
publish(_redeemer, _certificate, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
vote(_redeemer, _voter, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
propose(_redeemer, _proposal, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_validator_exhaustive_handlers_extra_non_default_fallback() {
|
||||
assert_format!(
|
||||
r#"
|
||||
validator foo {
|
||||
mint(_redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
spend(_datum, _redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
withdraw(_redeemer, _account, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
publish(_redeemer, _certificate, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
vote(_redeemer, _voter, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
propose(_redeemer, _proposal, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
else(_) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\n validator ( param1 : ByteArray ) {\n fn foo (d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {\n True\n }\n /// This is bar\nfn bar(r: Redeemer, ctx : ScriptContext ) -> Bool { True }\n }\n"
|
||||
description: "Code:\n\n validator foo( param1 : ByteArray ) {\n spend(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {\n True\n }\n /// This is bar\nmint(r: Redeemer, ctx : ScriptContext ) -> Bool { True }\n }\n"
|
||||
---
|
||||
validator(param1: ByteArray) {
|
||||
fn foo(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
validator foo(param1: ByteArray) {
|
||||
spend(d: Datum, r: Redeemer, ctx: ScriptContext) {
|
||||
True
|
||||
}
|
||||
|
||||
/// This is bar
|
||||
fn bar(r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
mint(r: Redeemer, ctx: ScriptContext) {
|
||||
True
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\n validator ( param1 : ByteArray ) {\n pub fn foo (d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {\n True\n }\n /// This is bar\npub fn bar(r: Redeemer, ctx : ScriptContext ) -> Bool { True }\n }\n"
|
||||
description: "Code:\n\n validator foo ( param1 : ByteArray ) {\n spend(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {\n True\n }\n /// This is bar\nmint(r: Redeemer, ctx : ScriptContext ) -> Bool { True }\n }\n"
|
||||
---
|
||||
validator(param1: ByteArray) {
|
||||
pub fn foo(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
validator foo(param1: ByteArray) {
|
||||
spend(d: Datum, r: Redeemer, ctx: ScriptContext) {
|
||||
True
|
||||
}
|
||||
|
||||
/// This is bar
|
||||
pub fn bar(r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
mint(r: Redeemer, ctx: ScriptContext) {
|
||||
True
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nvalidator ( ) {\n// What is the purpose of life\n\nfn foo (d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {\nTrue\n}\n}\n\n// What?\nvalidator {\n /// Some documentation for foo\n fn foo() {\n Void\n }\n\n // I am lost\n}\n"
|
||||
description: "Code:\n\nvalidator thing ( ) {\n// What is the purpose of life\n\nspend(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {\nTrue\n}\n}\n\n// What?\nvalidator foo {\n /// Some documentation for foo\n foo() {\n Void\n }\n\n // I am lost\n}\n"
|
||||
---
|
||||
validator {
|
||||
validator thing {
|
||||
// What is the purpose of life
|
||||
|
||||
fn foo(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
|
||||
spend(d: Datum, r: Redeemer, ctx: ScriptContext) {
|
||||
True
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
||||
// What?
|
||||
validator {
|
||||
validator foo {
|
||||
/// Some documentation for foo
|
||||
fn foo() {
|
||||
foo() {
|
||||
Void
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
|
||||
// I am lost
|
||||
}
|
||||
|
|
29
crates/aiken-lang/src/tests/snapshots/format_validator_exhaustive_handlers.snap
vendored
Normal file
29
crates/aiken-lang/src/tests/snapshots/format_validator_exhaustive_handlers.snap
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nvalidator foo {\n mint(_redeemer, _policy_id, _self) {\n True\n }\n\n spend(_datum, _redeemer, _policy_id, _self) {\n True\n }\n\n withdraw(_redeemer, _account, _self) {\n True\n }\n\n publish(_redeemer, _certificate, _self) {\n True\n }\n\n vote(_redeemer, _voter, _self) {\n True\n }\n\n propose(_redeemer, _proposal, _self) {\n True\n }\n}\n"
|
||||
---
|
||||
validator foo {
|
||||
mint(_redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
spend(_datum, _redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
withdraw(_redeemer, _account, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
publish(_redeemer, _certificate, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
vote(_redeemer, _voter, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
propose(_redeemer, _proposal, _self) {
|
||||
True
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nvalidator foo {\n mint(_redeemer, _policy_id, _self) {\n True\n }\n\n spend(_datum, _redeemer, _policy_id, _self) {\n True\n }\n\n withdraw(_redeemer, _account, _self) {\n True\n }\n\n publish(_redeemer, _certificate, _self) {\n True\n }\n\n vote(_redeemer, _voter, _self) {\n True\n }\n\n propose(_redeemer, _proposal, _self) {\n True\n }\n\n else(_) {\n fail\n }\n}\n"
|
||||
---
|
||||
validator foo {
|
||||
mint(_redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
spend(_datum, _redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
withdraw(_redeemer, _account, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
publish(_redeemer, _certificate, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
vote(_redeemer, _voter, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
propose(_redeemer, _proposal, _self) {
|
||||
True
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nvalidator foo {\n mint(_redeemer, _policy_id, _self) {\n True\n }\n\n spend(_datum, _redeemer, _policy_id, _self) {\n True\n }\n\n withdraw(_redeemer, _account, _self) {\n True\n }\n\n publish(_redeemer, _certificate, _self) {\n True\n }\n\n vote(_redeemer, _voter, _self) {\n True\n }\n\n propose(_redeemer, _proposal, _self) {\n True\n }\n\n else(_) {\n True\n }\n}\n"
|
||||
---
|
||||
validator foo {
|
||||
mint(_redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
spend(_datum, _redeemer, _policy_id, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
withdraw(_redeemer, _account, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
publish(_redeemer, _certificate, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
vote(_redeemer, _voter, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
propose(_redeemer, _proposal, _self) {
|
||||
True
|
||||
}
|
||||
|
||||
else(_) {
|
||||
True
|
||||
}
|
||||
}
|
|
@ -1,27 +1,43 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nvalidator(Foo { a, b, .. }) {\n fn foo() { todo }\n}\n\nvalidator([Bar] : List<Bar>) {\n fn bar() { todo }\n}\n\nvalidator((Baz, Baz) as x) {\n fn baz() { todo }\n}\n\nvalidator((fst, snd) as x: Pair<Int, Int>) {\n fn fiz() { todo }\n}\n"
|
||||
description: "Code:\n\nvalidator foo(Foo { a, b, .. }) {\n spend() { todo }\n}\n\nvalidator foo([Bar] : List<Bar>) {\n spend() { todo }\n}\n\nvalidator foo((Baz, Baz) as x) {\n mint() { todo }\n}\n\nvalidator fiz((fst, snd) as x: Pair<Int, Int>) {\n spend() { todo }\n}\n"
|
||||
---
|
||||
validator(Foo { a, b, .. }) {
|
||||
fn foo() {
|
||||
validator foo(Foo { a, b, .. }) {
|
||||
spend() {
|
||||
todo
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
||||
validator([Bar]: List<Bar>) {
|
||||
fn bar() {
|
||||
validator foo([Bar]: List<Bar>) {
|
||||
spend() {
|
||||
todo
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
||||
validator((Baz, Baz) as x) {
|
||||
fn baz() {
|
||||
validator foo((Baz, Baz) as x) {
|
||||
mint() {
|
||||
todo
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
||||
validator((fst, snd) as x: Pair<Int, Int>) {
|
||||
fn fiz() {
|
||||
validator fiz((fst, snd) as x: Pair<Int, Int>) {
|
||||
spend() {
|
||||
todo
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use self::{environment::Environment, pretty::Printer};
|
||||
use crate::{
|
||||
ast::{
|
||||
Annotation, Constant, DataType, DataTypeKey, DefinitionLocation, ModuleKind, Span,
|
||||
TypedDataType,
|
||||
well_known, Annotation, Constant, DataType, DataTypeKey, DefinitionLocation, ModuleKind,
|
||||
Span, TypedDataType,
|
||||
},
|
||||
builtins::{G1_ELEMENT, G2_ELEMENT, MILLER_LOOP_RESULT},
|
||||
tipo::fields::FieldMap,
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
|
@ -23,6 +22,8 @@ mod pattern;
|
|||
mod pipe;
|
||||
pub mod pretty;
|
||||
|
||||
pub use environment::collapse_links;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct TypeAliasAnnotation {
|
||||
pub alias: String,
|
||||
|
@ -304,7 +305,7 @@ impl Type {
|
|||
|
||||
pub fn is_int(&self) -> bool {
|
||||
match self {
|
||||
Self::App { module, name, .. } if "Int" == name && module.is_empty() => true,
|
||||
Self::App { module, name, .. } if well_known::INT == name && module.is_empty() => true,
|
||||
Self::Var { tipo, .. } => tipo.borrow().is_int(),
|
||||
_ => false,
|
||||
}
|
||||
|
@ -312,7 +313,11 @@ impl Type {
|
|||
|
||||
pub fn is_bytearray(&self) -> bool {
|
||||
match self {
|
||||
Self::App { module, name, .. } if "ByteArray" == name && module.is_empty() => true,
|
||||
Self::App { module, name, .. }
|
||||
if well_known::BYTE_ARRAY == name && module.is_empty() =>
|
||||
{
|
||||
true
|
||||
}
|
||||
Self::Var { tipo, .. } => tipo.borrow().is_bytearray(),
|
||||
_ => false,
|
||||
}
|
||||
|
@ -320,7 +325,7 @@ impl Type {
|
|||
|
||||
pub fn is_bls381_12_g1(&self) -> bool {
|
||||
match self {
|
||||
Self::App { module, name, .. } => G1_ELEMENT == name && module.is_empty(),
|
||||
Self::App { module, name, .. } => well_known::G1_ELEMENT == name && module.is_empty(),
|
||||
|
||||
Self::Var { tipo, .. } => tipo.borrow().is_bls381_12_g1(),
|
||||
_ => false,
|
||||
|
@ -329,7 +334,7 @@ impl Type {
|
|||
|
||||
pub fn is_bls381_12_g2(&self) -> bool {
|
||||
match self {
|
||||
Self::App { module, name, .. } => G2_ELEMENT == name && module.is_empty(),
|
||||
Self::App { module, name, .. } => well_known::G2_ELEMENT == name && module.is_empty(),
|
||||
|
||||
Self::Var { tipo, .. } => tipo.borrow().is_bls381_12_g2(),
|
||||
_ => false,
|
||||
|
@ -338,7 +343,9 @@ impl Type {
|
|||
|
||||
pub fn is_ml_result(&self) -> bool {
|
||||
match self {
|
||||
Self::App { module, name, .. } => MILLER_LOOP_RESULT == name && module.is_empty(),
|
||||
Self::App { module, name, .. } => {
|
||||
well_known::MILLER_LOOP_RESULT == name && module.is_empty()
|
||||
}
|
||||
|
||||
Self::Var { tipo, .. } => tipo.borrow().is_ml_result(),
|
||||
_ => false,
|
||||
|
@ -422,31 +429,33 @@ impl Type {
|
|||
}
|
||||
|
||||
pub fn is_generic(&self) -> bool {
|
||||
match self {
|
||||
Self::App { args, .. } => {
|
||||
let mut is_a_generic = false;
|
||||
for arg in args {
|
||||
is_a_generic = is_a_generic || arg.is_generic();
|
||||
}
|
||||
is_a_generic
|
||||
}
|
||||
!self.collect_generics().is_empty()
|
||||
}
|
||||
|
||||
Self::Var { tipo, .. } => tipo.borrow().is_generic(),
|
||||
Self::Tuple { elems, .. } => {
|
||||
let mut is_a_generic = false;
|
||||
for elem in elems {
|
||||
is_a_generic = is_a_generic || elem.is_generic();
|
||||
pub fn collect_generics(&self) -> Vec<Rc<Type>> {
|
||||
match self {
|
||||
Self::App { args, .. } => args.iter().flat_map(|arg| arg.collect_generics()).collect(),
|
||||
Self::Var { tipo, .. } => {
|
||||
if tipo.borrow().is_generic() {
|
||||
vec![self.clone().into()]
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
is_a_generic
|
||||
}
|
||||
Self::Fn { args, ret, .. } => {
|
||||
let mut is_a_generic = false;
|
||||
for arg in args {
|
||||
is_a_generic = is_a_generic || arg.is_generic();
|
||||
}
|
||||
is_a_generic || ret.is_generic()
|
||||
Self::Tuple { elems, .. } => elems
|
||||
.iter()
|
||||
.flat_map(|arg| arg.collect_generics())
|
||||
.collect(),
|
||||
Self::Fn { args, ret, .. } => args
|
||||
.iter()
|
||||
.chain(std::iter::once(ret))
|
||||
.flat_map(|arg| arg.collect_generics())
|
||||
.collect(),
|
||||
Self::Pair { fst, snd, .. } => {
|
||||
let mut generics = fst.collect_generics();
|
||||
generics.extend(snd.collect_generics());
|
||||
generics
|
||||
}
|
||||
Self::Pair { fst, snd, .. } => fst.is_generic() || snd.is_generic(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1068,7 +1077,7 @@ impl TypeVar {
|
|||
match self {
|
||||
TypeVar::Generic { .. } => true,
|
||||
TypeVar::Link { tipo } => tipo.is_generic(),
|
||||
_ => false,
|
||||
TypeVar::Unbound { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1118,6 +1127,51 @@ impl ValueConstructor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn known_enum(
|
||||
values: &mut HashMap<String, Self>,
|
||||
tipo: Rc<Type>,
|
||||
constructors: &[&str],
|
||||
) -> Vec<String> {
|
||||
for constructor in constructors {
|
||||
values.insert(
|
||||
constructor.to_string(),
|
||||
ValueConstructor::public(
|
||||
tipo.clone(),
|
||||
ValueConstructorVariant::known_enum_variant(constructor, constructors.len(), 0),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
constructors
|
||||
.iter()
|
||||
.map(|constructor| constructor.to_string())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn known_adt(
|
||||
values: &mut HashMap<String, Self>,
|
||||
constructors: &[(&str, Rc<Type>)],
|
||||
) -> Vec<String> {
|
||||
for (constructor, tipo) in constructors {
|
||||
values.insert(
|
||||
constructor.to_string(),
|
||||
ValueConstructor::public(
|
||||
tipo.clone(),
|
||||
ValueConstructorVariant::known_enum_variant(
|
||||
constructor,
|
||||
constructors.len(),
|
||||
tipo.fn_arity().unwrap_or(0),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
constructors
|
||||
.iter()
|
||||
.map(|(constructor, _)| constructor.to_string())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn field_map(&self) -> Option<&FieldMap> {
|
||||
match &self.variant {
|
||||
ValueConstructorVariant::ModuleFn { field_map, .. }
|
||||
|
@ -1248,6 +1302,17 @@ impl ValueConstructorVariant {
|
|||
pub fn is_local_variable(&self) -> bool {
|
||||
matches!(self, Self::LocalVariable { .. })
|
||||
}
|
||||
|
||||
pub fn known_enum_variant(name: &str, constructors_count: usize, arity: usize) -> Self {
|
||||
ValueConstructorVariant::Record {
|
||||
module: "".into(),
|
||||
name: name.to_string(),
|
||||
field_map: None::<FieldMap>,
|
||||
arity,
|
||||
location: Span::empty(),
|
||||
constructors_count: constructors_count as u16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
@ -1271,6 +1336,18 @@ pub struct TypeConstructor {
|
|||
pub tipo: Rc<Type>,
|
||||
}
|
||||
|
||||
impl TypeConstructor {
|
||||
pub fn primitive(tipo: Rc<Type>) -> Self {
|
||||
TypeConstructor {
|
||||
location: Span::empty(),
|
||||
parameters: tipo.collect_generics(),
|
||||
tipo,
|
||||
module: "".to_string(),
|
||||
public: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct AccessorsMap {
|
||||
pub public: bool,
|
||||
|
|
|
@ -9,10 +9,9 @@ use crate::{
|
|||
ast::{
|
||||
self, Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind,
|
||||
RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition, TypedFunction,
|
||||
TypedPattern, UnqualifiedImport, UntypedArg, UntypedDefinition, UntypedFunction, Use,
|
||||
Validator, PIPE_VARIABLE,
|
||||
TypedPattern, TypedValidator, UnqualifiedImport, UntypedArg, UntypedDefinition,
|
||||
UntypedFunction, Use, Validator, PIPE_VARIABLE,
|
||||
},
|
||||
builtins::{function, generic_var, pair, tuple, unbound_var},
|
||||
tipo::{fields::FieldMap, TypeAliasAnnotation},
|
||||
IdGenerator,
|
||||
};
|
||||
|
@ -58,6 +57,9 @@ pub struct Environment<'a> {
|
|||
/// Top-level function definitions from the module
|
||||
pub module_functions: HashMap<String, &'a UntypedFunction>,
|
||||
|
||||
/// Top-level validator definitions from the module
|
||||
pub module_validators: HashMap<String, (Span, Vec<String>)>,
|
||||
|
||||
/// Top-level functions that have been inferred
|
||||
pub inferred_functions: HashMap<String, TypedFunction>,
|
||||
|
||||
|
@ -183,7 +185,7 @@ impl<'a> Environment<'a> {
|
|||
|
||||
if let Some((args, ret)) = new_value {
|
||||
*tipo.borrow_mut() = TypeVar::Link {
|
||||
tipo: function(args.clone(), ret.clone()),
|
||||
tipo: Type::function(args.clone(), ret.clone()),
|
||||
};
|
||||
|
||||
return Ok((args, Type::with_alias(ret, alias.clone())));
|
||||
|
@ -307,32 +309,51 @@ impl<'a> Environment<'a> {
|
|||
Definition::Validator(Validator {
|
||||
doc,
|
||||
end_position,
|
||||
fun,
|
||||
other_fun,
|
||||
handlers,
|
||||
name,
|
||||
mut fallback,
|
||||
location,
|
||||
params,
|
||||
}) => {
|
||||
let Definition::Fn(fun) =
|
||||
self.generalise_definition(Definition::Fn(fun), module_name)
|
||||
let handlers = handlers
|
||||
.into_iter()
|
||||
.map(|mut fun| {
|
||||
let handler_name = TypedValidator::handler_name(&name, &fun.name);
|
||||
|
||||
let old_name = fun.name;
|
||||
fun.name = handler_name;
|
||||
|
||||
let Definition::Fn(mut fun) =
|
||||
self.generalise_definition(Definition::Fn(fun), module_name)
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
fun.name = old_name;
|
||||
|
||||
fun
|
||||
})
|
||||
.collect();
|
||||
|
||||
let fallback_name = TypedValidator::handler_name(&name, &fallback.name);
|
||||
|
||||
let old_name = fallback.name;
|
||||
fallback.name = fallback_name;
|
||||
|
||||
let Definition::Fn(mut fallback) =
|
||||
self.generalise_definition(Definition::Fn(fallback), module_name)
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let other_fun = other_fun.map(|other_fun| {
|
||||
let Definition::Fn(other_fun) =
|
||||
self.generalise_definition(Definition::Fn(other_fun), module_name)
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
other_fun
|
||||
});
|
||||
fallback.name = old_name;
|
||||
|
||||
Definition::Validator(Validator {
|
||||
doc,
|
||||
name,
|
||||
end_position,
|
||||
fun,
|
||||
other_fun,
|
||||
handlers,
|
||||
fallback,
|
||||
location,
|
||||
params,
|
||||
})
|
||||
|
@ -671,7 +692,7 @@ impl<'a> Environment<'a> {
|
|||
}
|
||||
|
||||
Type::Fn { args, ret, alias } => Type::with_alias(
|
||||
function(
|
||||
Type::function(
|
||||
args.iter()
|
||||
.map(|t| self.instantiate(t.clone(), ids, hydrator))
|
||||
.collect(),
|
||||
|
@ -681,7 +702,7 @@ impl<'a> Environment<'a> {
|
|||
),
|
||||
|
||||
Type::Tuple { elems, alias } => Type::with_alias(
|
||||
tuple(
|
||||
Type::tuple(
|
||||
elems
|
||||
.iter()
|
||||
.map(|t| self.instantiate(t.clone(), ids, hydrator))
|
||||
|
@ -690,7 +711,7 @@ impl<'a> Environment<'a> {
|
|||
alias.clone(),
|
||||
),
|
||||
Type::Pair { fst, snd, alias } => Type::with_alias(
|
||||
pair(
|
||||
Type::pair(
|
||||
self.instantiate(fst.clone(), ids, hydrator),
|
||||
self.instantiate(snd.clone(), ids, hydrator),
|
||||
),
|
||||
|
@ -758,6 +779,7 @@ impl<'a> Environment<'a> {
|
|||
module_types_constructors: prelude.types_constructors.clone(),
|
||||
module_values: HashMap::new(),
|
||||
module_functions: HashMap::new(),
|
||||
module_validators: HashMap::new(),
|
||||
imported_modules: HashMap::new(),
|
||||
unused_modules: HashMap::new(),
|
||||
unqualified_imported_names: HashMap::new(),
|
||||
|
@ -776,13 +798,13 @@ impl<'a> Environment<'a> {
|
|||
|
||||
/// Create a new generic type that can stand in for any type.
|
||||
pub fn new_generic_var(&mut self) -> Rc<Type> {
|
||||
generic_var(self.next_uid())
|
||||
Type::generic_var(self.next_uid())
|
||||
}
|
||||
|
||||
/// Create a new unbound type that is a specific type, we just don't
|
||||
/// know which one yet.
|
||||
pub fn new_unbound_var(&mut self) -> Rc<Type> {
|
||||
unbound_var(self.next_uid())
|
||||
Type::unbound_var(self.next_uid())
|
||||
}
|
||||
|
||||
pub fn next_uid(&mut self) -> u64 {
|
||||
|
@ -815,9 +837,7 @@ impl<'a> Environment<'a> {
|
|||
let module_info = self.find_module(module, *location)?;
|
||||
|
||||
if module_info.kind.is_validator()
|
||||
&& (self.current_kind.is_lib()
|
||||
|| self.current_kind.is_env()
|
||||
|| !self.current_module.starts_with("tests"))
|
||||
&& (self.current_kind.is_lib() || self.current_kind.is_env())
|
||||
{
|
||||
return Err(Error::ValidatorImported {
|
||||
location: *location,
|
||||
|
@ -1162,12 +1182,12 @@ impl<'a> Environment<'a> {
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
fn register_function(
|
||||
&mut self,
|
||||
name: &'a str,
|
||||
name: &str,
|
||||
arguments: &[UntypedArg],
|
||||
return_annotation: &Option<Annotation>,
|
||||
module_name: &String,
|
||||
hydrators: &mut HashMap<String, Hydrator>,
|
||||
names: &mut HashMap<&'a str, &'a Span>,
|
||||
names: &mut HashMap<String, &'a Span>,
|
||||
location: &'a Span,
|
||||
) -> Result<(), Error> {
|
||||
assert_unique_value_name(names, name, location)?;
|
||||
|
@ -1195,7 +1215,7 @@ impl<'a> Environment<'a> {
|
|||
|
||||
let return_type = hydrator.type_from_option_annotation(return_annotation, self)?;
|
||||
|
||||
let tipo = function(arg_types, return_type);
|
||||
let tipo = Type::function(arg_types, return_type);
|
||||
|
||||
// Keep track of which types we create from annotations so we can know
|
||||
// which generic types not to instantiate later when performing
|
||||
|
@ -1224,7 +1244,7 @@ impl<'a> Environment<'a> {
|
|||
def: &'a UntypedDefinition,
|
||||
module_name: &String,
|
||||
hydrators: &mut HashMap<String, Hydrator>,
|
||||
names: &mut HashMap<&'a str, &'a Span>,
|
||||
names: &mut HashMap<String, &'a Span>,
|
||||
kind: ModuleKind,
|
||||
) -> Result<(), Error> {
|
||||
match def {
|
||||
|
@ -1247,58 +1267,104 @@ impl<'a> Environment<'a> {
|
|||
}
|
||||
|
||||
Definition::Validator(Validator {
|
||||
fun,
|
||||
other_fun,
|
||||
handlers,
|
||||
fallback,
|
||||
params,
|
||||
name,
|
||||
doc: _,
|
||||
location: _,
|
||||
location,
|
||||
end_position: _,
|
||||
}) if kind.is_validator() => {
|
||||
let default_annotation = |mut arg: UntypedArg| {
|
||||
let default_annotation = |mut arg: UntypedArg, ann: Annotation| {
|
||||
if arg.annotation.is_none() {
|
||||
arg.annotation = Some(Annotation::data(arg.location));
|
||||
|
||||
arg.annotation = Some(ann);
|
||||
arg
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
};
|
||||
|
||||
let temp_params: Vec<UntypedArg> = params
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(fun.arguments.clone())
|
||||
.map(default_annotation)
|
||||
.collect();
|
||||
let mut handler_names = vec![];
|
||||
|
||||
self.register_function(
|
||||
&fun.name,
|
||||
&temp_params,
|
||||
&fun.return_annotation,
|
||||
module_name,
|
||||
hydrators,
|
||||
names,
|
||||
&fun.location,
|
||||
)?;
|
||||
let params_len = params.len();
|
||||
|
||||
if let Some(other) = other_fun {
|
||||
for handler in handlers {
|
||||
let temp_params: Vec<UntypedArg> = params
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(other.arguments.clone())
|
||||
.map(default_annotation)
|
||||
.chain(handler.arguments.clone())
|
||||
.enumerate()
|
||||
.map(|(ix, arg)| {
|
||||
let is_datum = handler.is_spend() && ix == params_len;
|
||||
let is_mint_policy = handler.is_mint() && ix == params_len + 1;
|
||||
let location = arg.location;
|
||||
default_annotation(
|
||||
arg,
|
||||
if is_datum {
|
||||
Annotation::option(Annotation::data(location))
|
||||
} else if is_mint_policy {
|
||||
Annotation::bytearray(location)
|
||||
} else {
|
||||
Annotation::data(location)
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
handler_names.push(handler.name.clone());
|
||||
|
||||
self.register_function(
|
||||
&other.name,
|
||||
&TypedValidator::handler_name(name.as_str(), handler.name.as_str()),
|
||||
&temp_params,
|
||||
&other.return_annotation,
|
||||
&handler.return_annotation,
|
||||
module_name,
|
||||
hydrators,
|
||||
names,
|
||||
&other.location,
|
||||
&handler.location,
|
||||
)?;
|
||||
}
|
||||
|
||||
let temp_params: Vec<UntypedArg> = params
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(fallback.arguments.clone())
|
||||
.map(|arg| {
|
||||
let location = arg.location;
|
||||
default_annotation(arg, Annotation::data(location))
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.register_function(
|
||||
&TypedValidator::handler_name(name.as_str(), fallback.name.as_str()),
|
||||
&temp_params,
|
||||
&fallback.return_annotation,
|
||||
module_name,
|
||||
hydrators,
|
||||
names,
|
||||
&fallback.location,
|
||||
)?;
|
||||
|
||||
handler_names.push(fallback.name.clone());
|
||||
|
||||
let err_duplicate_name = |previous_location: Span| {
|
||||
Err(Error::DuplicateName {
|
||||
name: name.to_string(),
|
||||
previous_location,
|
||||
location: location.map_end(|end| end + 1 + name.len()),
|
||||
})
|
||||
};
|
||||
|
||||
if let Some((previous_location, _)) = self.imported_modules.get(name) {
|
||||
return err_duplicate_name(*previous_location);
|
||||
}
|
||||
|
||||
match self
|
||||
.module_validators
|
||||
.insert(name.to_string(), (*location, handler_names))
|
||||
{
|
||||
Some((previous_location, _)) => err_duplicate_name(previous_location),
|
||||
None => Ok(()),
|
||||
}?
|
||||
}
|
||||
|
||||
Definition::Validator(Validator { location, .. }) => {
|
||||
|
@ -1395,7 +1461,7 @@ impl<'a> Environment<'a> {
|
|||
// Insert constructor function into module scope
|
||||
let typ = match constructor.arguments.len() {
|
||||
0 => typ.clone(),
|
||||
_ => function(args_types, typ.clone()),
|
||||
_ => Type::function(args_types, typ.clone()),
|
||||
};
|
||||
|
||||
let constructor_info = ValueConstructorVariant::Record {
|
||||
|
@ -1910,11 +1976,11 @@ fn assert_unique_type_name<'a>(
|
|||
}
|
||||
|
||||
fn assert_unique_value_name<'a>(
|
||||
names: &mut HashMap<&'a str, &'a Span>,
|
||||
name: &'a str,
|
||||
names: &mut HashMap<String, &'a Span>,
|
||||
name: &str,
|
||||
location: &'a Span,
|
||||
) -> Result<(), Error> {
|
||||
match names.insert(name, location) {
|
||||
match names.insert(name.to_string(), location) {
|
||||
Some(previous_location) => Err(Error::DuplicateName {
|
||||
name: name.to_string(),
|
||||
previous_location: *previous_location,
|
||||
|
@ -1925,11 +1991,11 @@ fn assert_unique_value_name<'a>(
|
|||
}
|
||||
|
||||
fn assert_unique_const_name<'a>(
|
||||
names: &mut HashMap<&'a str, &'a Span>,
|
||||
name: &'a str,
|
||||
names: &mut HashMap<String, &'a Span>,
|
||||
name: &str,
|
||||
location: &'a Span,
|
||||
) -> Result<(), Error> {
|
||||
match names.insert(name, location) {
|
||||
match names.insert(name.to_string(), location) {
|
||||
Some(previous_location) => Err(Error::DuplicateConstName {
|
||||
name: name.to_string(),
|
||||
previous_location: *previous_location,
|
||||
|
@ -1948,7 +2014,7 @@ pub(super) fn assert_no_labeled_arguments<A>(args: &[CallArg<A>]) -> Option<(Spa
|
|||
None
|
||||
}
|
||||
|
||||
pub(super) fn collapse_links(t: Rc<Type>) -> Rc<Type> {
|
||||
pub fn collapse_links(t: Rc<Type>) -> Rc<Type> {
|
||||
if let Type::Var { tipo, alias } = t.deref() {
|
||||
if let TypeVar::Link { tipo } = tipo.borrow().deref() {
|
||||
return Type::with_alias(tipo.clone(), alias.clone());
|
||||
|
@ -1993,7 +2059,7 @@ pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> {
|
|||
match t.deref() {
|
||||
Type::Var { tipo, alias } => Type::with_alias(
|
||||
match tipo.borrow().deref() {
|
||||
TypeVar::Unbound { id } => generic_var(*id),
|
||||
TypeVar::Unbound { id } => Type::generic_var(*id),
|
||||
TypeVar::Link { tipo } => generalise(tipo.clone(), ctx_level),
|
||||
TypeVar::Generic { .. } => Rc::new(Type::Var {
|
||||
tipo: tipo.clone(),
|
||||
|
@ -2027,7 +2093,7 @@ pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> {
|
|||
}
|
||||
|
||||
Type::Fn { args, ret, alias } => Type::with_alias(
|
||||
function(
|
||||
Type::function(
|
||||
args.iter()
|
||||
.map(|t| generalise(t.clone(), ctx_level))
|
||||
.collect(),
|
||||
|
@ -2037,7 +2103,7 @@ pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> {
|
|||
),
|
||||
|
||||
Type::Tuple { elems, alias } => Type::with_alias(
|
||||
tuple(
|
||||
Type::tuple(
|
||||
elems
|
||||
.iter()
|
||||
.map(|t| generalise(t.clone(), ctx_level))
|
||||
|
@ -2046,7 +2112,7 @@ pub(crate) fn generalise(t: Rc<Type>, ctx_level: usize) -> Rc<Type> {
|
|||
alias.clone(),
|
||||
),
|
||||
Type::Pair { fst, snd, alias } => Type::with_alias(
|
||||
pair(
|
||||
Type::pair(
|
||||
generalise(fst.clone(), ctx_level),
|
||||
generalise(snd.clone(), ctx_level),
|
||||
),
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::{
|
|||
pretty::Documentable,
|
||||
};
|
||||
use indoc::formatdoc;
|
||||
use itertools::Itertools;
|
||||
use miette::{Diagnostic, LabeledSpan};
|
||||
use ordinal::Ordinal;
|
||||
use owo_colors::{
|
||||
|
@ -489,15 +490,21 @@ If you really meant to return that last expression, try to replace it with the f
|
|||
name: String,
|
||||
},
|
||||
|
||||
#[error("I found a multi-validator where both take the same number of arguments.\n")]
|
||||
#[diagnostic(code("illegal::multi_validator"))]
|
||||
#[diagnostic(help("Multi-validators cannot take the same number of arguments. One must take 3 arguments\nand the other must take 2 arguments. Both of these take {} arguments.", count.to_string().purple()))]
|
||||
MultiValidatorEqualArgs {
|
||||
#[label("{} here", count)]
|
||||
#[error(
|
||||
"I stumbled upon an invalid (non-local) clause guard '{}'.\n",
|
||||
name.if_supports_color(Stdout, |s| s.purple())
|
||||
)]
|
||||
#[diagnostic(url(
|
||||
"https://aiken-lang.org/language-tour/control-flow#checking-equality-and-ordering-in-patterns"
|
||||
))]
|
||||
#[diagnostic(code("illegal::clause_guard"))]
|
||||
#[diagnostic(help(
|
||||
"There are some conditions regarding what can be used in a guard. Values must be either local to the function, or defined as module constants. You can't use functions or records in there."
|
||||
))]
|
||||
NonLocalClauseGuardVariable {
|
||||
#[label]
|
||||
location: Span,
|
||||
#[label("and {} here", count)]
|
||||
other_location: Span,
|
||||
count: usize,
|
||||
name: String,
|
||||
},
|
||||
|
||||
#[error("I tripped over an attempt to access elements on something that isn't indexable.\n")]
|
||||
|
@ -1021,7 +1028,8 @@ The best thing to do from here is to remove it."#))]
|
|||
))]
|
||||
IncorrectValidatorArity {
|
||||
count: u32,
|
||||
#[label("{} arguments", if *count < 2 { "not enough" } else { "too many" })]
|
||||
expected: u32,
|
||||
#[label("{} arguments", if count < expected { "not enough" } else { "too many" })]
|
||||
location: Span,
|
||||
},
|
||||
|
||||
|
@ -1063,6 +1071,46 @@ The best thing to do from here is to remove it."#))]
|
|||
function: UntypedFunction,
|
||||
location: Span,
|
||||
},
|
||||
|
||||
#[error("I found a validator handler referring to an unknown purpose.\n")]
|
||||
#[diagnostic(code("unknown::purpose"))]
|
||||
#[diagnostic(help(
|
||||
"Handler must be named after a known purpose. Here is a list of available purposes:\n{}",
|
||||
available_purposes
|
||||
.iter()
|
||||
.map(|p| format!("-> {}", p.if_supports_color(Stdout, |s| s.green())))
|
||||
.join("\n")
|
||||
))]
|
||||
UnknownPurpose {
|
||||
#[label("unknown purpose")]
|
||||
location: Span,
|
||||
available_purposes: Vec<String>,
|
||||
},
|
||||
|
||||
#[error("I could not find an appropriate handler in the validator definition\n")]
|
||||
#[diagnostic(code("unknown::handler"))]
|
||||
#[diagnostic(help(
|
||||
"When referring to a validator handler via record access, you must refer to one of the declared handlers:\n{}",
|
||||
available_handlers
|
||||
.iter()
|
||||
.map(|p| format!("-> {}", p.if_supports_color(Stdout, |s| s.green())))
|
||||
.join("\n")
|
||||
))]
|
||||
UnknownValidatorHandler {
|
||||
#[label("unknown validator handler")]
|
||||
location: Span,
|
||||
available_handlers: Vec<String>,
|
||||
},
|
||||
|
||||
#[error("I caught an extraneous fallback handler in an already exhaustive validator\n")]
|
||||
#[diagnostic(code("extraneous::fallback"))]
|
||||
#[diagnostic(help(
|
||||
"Validator handlers must be exhaustive and either cover all purposes, or provide a fallback handler. Here, you have successfully covered all script purposes with your handler, but left an extraneous fallback branch. I cannot let that happen, but removing it for you would probably be deemed rude. So please, remove the fallback."
|
||||
))]
|
||||
UnexpectedValidatorFallback {
|
||||
#[label("redundant fallback handler")]
|
||||
fallback: Span,
|
||||
},
|
||||
}
|
||||
|
||||
impl ExtraData for Error {
|
||||
|
@ -1093,7 +1141,7 @@ impl ExtraData for Error {
|
|||
| Error::LastExpressionIsAssignment { .. }
|
||||
| Error::LogicalOpChainMissingExpr { .. }
|
||||
| Error::MissingVarInAlternativePattern { .. }
|
||||
| Error::MultiValidatorEqualArgs { .. }
|
||||
| Error::NonLocalClauseGuardVariable { .. }
|
||||
| Error::NotIndexable { .. }
|
||||
| Error::NotExhaustivePatternMatch { .. }
|
||||
| Error::NotFn { .. }
|
||||
|
@ -1122,6 +1170,9 @@ impl ExtraData for Error {
|
|||
| Error::UnexpectedMultiPatternAssignment { .. }
|
||||
| Error::ExpectOnOpaqueType { .. }
|
||||
| Error::ValidatorMustReturnBool { .. }
|
||||
| Error::UnknownPurpose { .. }
|
||||
| Error::UnknownValidatorHandler { .. }
|
||||
| Error::UnexpectedValidatorFallback { .. }
|
||||
| Error::MustInferFirst { .. } => None,
|
||||
|
||||
Error::UnknownType { name, .. }
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::{
|
||||
ast,
|
||||
builtins::{self},
|
||||
tipo::{self, environment::Environment, error::Error},
|
||||
tipo::{self, environment::Environment, error::Error, Type},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use std::{collections::BTreeMap, iter, ops::Deref};
|
||||
|
@ -500,8 +499,8 @@ fn pretty_tail(tail: Pattern) -> String {
|
|||
}
|
||||
|
||||
fn list_constructors() -> Vec<tipo::ValueConstructor> {
|
||||
let list_parameter = builtins::generic_var(0);
|
||||
let list_type = builtins::list(list_parameter);
|
||||
let list_parameter = Type::generic_var(0);
|
||||
let list_type = Type::list(list_parameter);
|
||||
|
||||
vec![
|
||||
tipo::ValueConstructor {
|
||||
|
|
|
@ -14,13 +14,10 @@ use crate::{
|
|||
ByteArrayFormatPreference, CallArg, Constant, Curve, Function, IfBranch,
|
||||
LogicalOpChainKind, Pattern, RecordUpdateSpread, Span, TraceKind, TraceLevel, Tracing,
|
||||
TypedArg, TypedCallArg, TypedClause, TypedIfBranch, TypedPattern, TypedRecordUpdateArg,
|
||||
UnOp, UntypedArg, UntypedAssignmentKind, UntypedClause, UntypedFunction, UntypedIfBranch,
|
||||
UntypedPattern, UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::{
|
||||
bool, byte_array, data, from_default_function, function, g1_element, g2_element, int, list,
|
||||
pair, string, tuple, void, BUILTIN,
|
||||
TypedValidator, UnOp, UntypedArg, UntypedAssignmentKind, UntypedClause, UntypedFunction,
|
||||
UntypedIfBranch, UntypedPattern, UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::{from_default_function, BUILTIN},
|
||||
expr::{FnStyle, TypedExpr, UntypedExpr},
|
||||
format,
|
||||
tipo::{fields::FieldMap, DefaultFunction, PatternConstructor, TypeVar},
|
||||
|
@ -163,7 +160,7 @@ pub(crate) fn infer_function(
|
|||
|
||||
let args_types = arguments.iter().map(|a| a.tipo.clone()).collect();
|
||||
|
||||
let tipo = function(args_types, return_type);
|
||||
let tipo = Type::function(args_types, return_type);
|
||||
|
||||
let safe_to_generalise = !expr_typer.ungeneralised_function_used;
|
||||
|
||||
|
@ -594,15 +591,15 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Ok(TypedExpr::ByteArray {
|
||||
location,
|
||||
bytes,
|
||||
tipo: byte_array(),
|
||||
tipo: Type::byte_array(),
|
||||
})
|
||||
}
|
||||
|
||||
fn infer_curve_point(&mut self, curve: Curve, location: Span) -> Result<TypedExpr, Error> {
|
||||
let tipo = match curve {
|
||||
Curve::Bls12_381(point) => match point {
|
||||
Bls12_381Point::G1(_) => g1_element(),
|
||||
Bls12_381Point::G2(_) => g2_element(),
|
||||
Bls12_381Point::G1(_) => Type::g1_element(),
|
||||
Bls12_381Point::G2(_) => Type::g2_element(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -631,7 +628,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
module: String::new(),
|
||||
constructors_count: 2,
|
||||
},
|
||||
tipo: bool(),
|
||||
tipo: Type::bool(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -648,14 +645,14 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
module: String::new(),
|
||||
constructors_count: 2,
|
||||
},
|
||||
tipo: bool(),
|
||||
tipo: Type::bool(),
|
||||
},
|
||||
};
|
||||
|
||||
let text = match self.tracing.trace_level(false) {
|
||||
TraceLevel::Verbose => Some(TypedExpr::String {
|
||||
location,
|
||||
tipo: string(),
|
||||
tipo: Type::string(),
|
||||
value: format!(
|
||||
"{} ? False",
|
||||
format::Formatter::new()
|
||||
|
@ -668,7 +665,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
|
||||
let typed_value = self.infer(value)?;
|
||||
|
||||
self.unify(bool(), typed_value.tipo(), typed_value.location(), false)?;
|
||||
self.unify(
|
||||
Type::bool(),
|
||||
typed_value.tipo(),
|
||||
typed_value.location(),
|
||||
false,
|
||||
)?;
|
||||
|
||||
match text {
|
||||
None => Ok(typed_value),
|
||||
|
@ -682,11 +684,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
}],
|
||||
final_else: Box::new(TypedExpr::Trace {
|
||||
location,
|
||||
tipo: bool(),
|
||||
tipo: Type::bool(),
|
||||
text: Box::new(text),
|
||||
then: Box::new(var_false),
|
||||
}),
|
||||
tipo: bool(),
|
||||
tipo: Type::bool(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -714,22 +716,22 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
return Ok(TypedExpr::BinOp {
|
||||
location,
|
||||
name,
|
||||
tipo: bool(),
|
||||
tipo: Type::bool(),
|
||||
left: Box::new(left),
|
||||
right: Box::new(right),
|
||||
});
|
||||
}
|
||||
BinOp::And => (bool(), bool()),
|
||||
BinOp::Or => (bool(), bool()),
|
||||
BinOp::LtInt => (int(), bool()),
|
||||
BinOp::LtEqInt => (int(), bool()),
|
||||
BinOp::GtEqInt => (int(), bool()),
|
||||
BinOp::GtInt => (int(), bool()),
|
||||
BinOp::AddInt => (int(), int()),
|
||||
BinOp::SubInt => (int(), int()),
|
||||
BinOp::MultInt => (int(), int()),
|
||||
BinOp::DivInt => (int(), int()),
|
||||
BinOp::ModInt => (int(), int()),
|
||||
BinOp::And => (Type::bool(), Type::bool()),
|
||||
BinOp::Or => (Type::bool(), Type::bool()),
|
||||
BinOp::LtInt => (Type::int(), Type::bool()),
|
||||
BinOp::LtEqInt => (Type::int(), Type::bool()),
|
||||
BinOp::GtEqInt => (Type::int(), Type::bool()),
|
||||
BinOp::GtInt => (Type::int(), Type::bool()),
|
||||
BinOp::AddInt => (Type::int(), Type::int()),
|
||||
BinOp::SubInt => (Type::int(), Type::int()),
|
||||
BinOp::MultInt => (Type::int(), Type::int()),
|
||||
BinOp::DivInt => (Type::int(), Type::int()),
|
||||
BinOp::ModInt => (Type::int(), Type::int()),
|
||||
};
|
||||
|
||||
let left = self.infer(left)?;
|
||||
|
@ -896,8 +898,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
let value = self.infer(value)?;
|
||||
|
||||
let tipo = match op {
|
||||
UnOp::Not => bool(),
|
||||
UnOp::Negate => int(),
|
||||
UnOp::Not => Type::bool(),
|
||||
UnOp::Negate => Type::int(),
|
||||
};
|
||||
|
||||
self.unify(tipo.clone(), value.tipo(), value.location(), false)?;
|
||||
|
@ -916,6 +918,28 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
label: String,
|
||||
access_location: Span,
|
||||
) -> Result<TypedExpr, Error> {
|
||||
if let UntypedExpr::Var { ref name, location } = container {
|
||||
if let Some((_, available_handlers)) = self
|
||||
.environment
|
||||
.module_validators
|
||||
.get(name.as_str())
|
||||
.cloned()
|
||||
{
|
||||
return self
|
||||
.infer_var(
|
||||
TypedValidator::handler_name(name.as_str(), label.as_str()),
|
||||
location,
|
||||
)
|
||||
.map_err(|err| match err {
|
||||
Error::UnknownVariable { .. } => Error::UnknownValidatorHandler {
|
||||
location: access_location.map(|_start, end| (location.end, end)),
|
||||
available_handlers,
|
||||
},
|
||||
_ => err,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to infer the container as a record access. If that fails, we may be shadowing the name
|
||||
// of an imported module, so attempt to infer the container as a module access.
|
||||
// TODO: Remove this cloning
|
||||
|
@ -1603,7 +1627,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
let condition = self.infer(branch.condition.clone())?;
|
||||
|
||||
self.unify(
|
||||
bool(),
|
||||
Type::bool(),
|
||||
condition.tipo(),
|
||||
condition.type_defining_location(),
|
||||
false,
|
||||
|
@ -1647,7 +1671,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
|
||||
let args_types = args.iter().map(|a| a.tipo.clone()).collect();
|
||||
|
||||
let tipo = function(args_types, return_type);
|
||||
let tipo = Type::function(args_types, return_type);
|
||||
|
||||
Ok(TypedExpr::Fn {
|
||||
location,
|
||||
|
@ -1745,7 +1769,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
TypedExpr::UInt {
|
||||
location,
|
||||
value,
|
||||
tipo: int(),
|
||||
tipo: Type::int(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1772,7 +1796,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
ensure_serialisable(false, tipo.clone(), location)?;
|
||||
|
||||
// Type check the ..tail, if there is one
|
||||
let tipo = list(tipo);
|
||||
let tipo = Type::list(tipo);
|
||||
|
||||
let tail = match tail {
|
||||
Some(tail) => {
|
||||
|
@ -1807,7 +1831,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
let typed_expression = self.infer(expression)?;
|
||||
|
||||
self.unify(
|
||||
bool(),
|
||||
Type::bool(),
|
||||
typed_expression.tipo(),
|
||||
typed_expression.location(),
|
||||
false,
|
||||
|
@ -1831,7 +1855,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
.rev()
|
||||
.reduce(|acc, typed_expression| TypedExpr::BinOp {
|
||||
location,
|
||||
tipo: bool(),
|
||||
tipo: Type::bool(),
|
||||
name,
|
||||
left: typed_expression.into(),
|
||||
right: acc.into(),
|
||||
|
@ -2151,7 +2175,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
TypedExpr::String {
|
||||
location,
|
||||
value,
|
||||
tipo: string(),
|
||||
tipo: Type::string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2169,7 +2193,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
|
||||
Ok(TypedExpr::Pair {
|
||||
location,
|
||||
tipo: pair(typed_fst.tipo(), typed_snd.tipo()),
|
||||
tipo: Type::pair(typed_fst.tipo(), typed_snd.tipo()),
|
||||
fst: typed_fst.into(),
|
||||
snd: typed_snd.into(),
|
||||
})
|
||||
|
@ -2187,7 +2211,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
typed_elems.push(typed_elem);
|
||||
}
|
||||
|
||||
let tipo = tuple(typed_elems.iter().map(|e| e.tipo()).collect());
|
||||
let tipo = Type::tuple(typed_elems.iter().map(|e| e.tipo()).collect());
|
||||
|
||||
Ok(TypedExpr::Tuple {
|
||||
location,
|
||||
|
@ -2255,9 +2279,14 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
|
||||
fn infer_trace_arg(&mut self, arg: UntypedExpr) -> Result<TypedExpr, Error> {
|
||||
let typed_arg = self.infer(arg)?;
|
||||
match self.unify(string(), typed_arg.tipo(), typed_arg.location(), false) {
|
||||
match self.unify(
|
||||
Type::string(),
|
||||
typed_arg.tipo(),
|
||||
typed_arg.location(),
|
||||
false,
|
||||
) {
|
||||
Err(_) => {
|
||||
self.unify(data(), typed_arg.tipo(), typed_arg.location(), true)?;
|
||||
self.unify(Type::data(), typed_arg.tipo(), typed_arg.location(), true)?;
|
||||
Ok(diagnose_expr(typed_arg))
|
||||
}
|
||||
Ok(()) => Ok(typed_arg),
|
||||
|
@ -2291,7 +2320,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
TraceLevel::Silent => Ok(then),
|
||||
TraceLevel::Compact => {
|
||||
let text = self.infer(label)?;
|
||||
self.unify(string(), text.tipo(), text.location(), false)?;
|
||||
self.unify(Type::string(), text.tipo(), text.location(), false)?;
|
||||
Ok(TypedExpr::Trace {
|
||||
location,
|
||||
tipo,
|
||||
|
@ -2307,7 +2336,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
} else {
|
||||
let delimiter = |ix| TypedExpr::String {
|
||||
location: Span::empty(),
|
||||
tipo: string(),
|
||||
tipo: Type::string(),
|
||||
value: if ix == 0 { ": " } else { ", " }.to_string(),
|
||||
};
|
||||
typed_arguments
|
||||
|
@ -2594,7 +2623,7 @@ fn assert_assignment(expr: TypedExpr) -> Result<TypedExpr, Error> {
|
|||
if expr.tipo().is_void() {
|
||||
return Ok(TypedExpr::Assignment {
|
||||
location: expr.location(),
|
||||
tipo: void(),
|
||||
tipo: Type::void(),
|
||||
value: expr.clone().into(),
|
||||
pattern: Pattern::Constructor {
|
||||
is_record: false,
|
||||
|
@ -2607,7 +2636,7 @@ fn assert_assignment(expr: TypedExpr) -> Result<TypedExpr, Error> {
|
|||
arguments: vec![],
|
||||
module: None,
|
||||
spread_location: None,
|
||||
tipo: void(),
|
||||
tipo: Type::void(),
|
||||
},
|
||||
kind: AssignmentKind::let_(),
|
||||
});
|
||||
|
@ -2713,7 +2742,7 @@ fn diagnose_expr(expr: TypedExpr) -> TypedExpr {
|
|||
name: "diagnostic".to_string(),
|
||||
constructor: ValueConstructor {
|
||||
public: true,
|
||||
tipo: function(vec![data(), byte_array()], byte_array()),
|
||||
tipo: Type::function(vec![Type::data(), Type::byte_array()], Type::byte_array()),
|
||||
variant: ValueConstructorVariant::ModuleFn {
|
||||
name: "diagnostic".to_string(),
|
||||
field_map: None,
|
||||
|
@ -2728,13 +2757,13 @@ fn diagnose_expr(expr: TypedExpr) -> TypedExpr {
|
|||
let location = expr.location();
|
||||
|
||||
TypedExpr::Call {
|
||||
tipo: string(),
|
||||
tipo: Type::string(),
|
||||
fun: Box::new(decode_utf8.clone()),
|
||||
args: vec![CallArg {
|
||||
label: None,
|
||||
location: expr.location(),
|
||||
value: TypedExpr::Call {
|
||||
tipo: byte_array(),
|
||||
tipo: Type::byte_array(),
|
||||
fun: Box::new(diagnostic.clone()),
|
||||
args: vec![
|
||||
CallArg {
|
||||
|
@ -2746,7 +2775,7 @@ fn diagnose_expr(expr: TypedExpr) -> TypedExpr {
|
|||
label: None,
|
||||
location,
|
||||
value: TypedExpr::ByteArray {
|
||||
tipo: byte_array(),
|
||||
tipo: Type::byte_array(),
|
||||
bytes: vec![],
|
||||
location,
|
||||
},
|
||||
|
@ -2785,7 +2814,7 @@ fn append_string_expr(left: TypedExpr, right: TypedExpr) -> TypedExpr {
|
|||
|
||||
TypedExpr::Call {
|
||||
location: Span::empty(),
|
||||
tipo: string(),
|
||||
tipo: Type::string(),
|
||||
fun: Box::new(append_string.clone()),
|
||||
args: vec![
|
||||
CallArg {
|
||||
|
|
|
@ -3,11 +3,7 @@ use super::{
|
|||
error::{Error, Warning},
|
||||
Type, TypeConstructor,
|
||||
};
|
||||
use crate::{
|
||||
ast::Annotation,
|
||||
builtins::{function, pair, tuple},
|
||||
tipo::Span,
|
||||
};
|
||||
use crate::{ast::Annotation, tipo::Span};
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
/// The Hydrator takes an AST representing a type (i.e. a type annotation
|
||||
|
@ -201,7 +197,7 @@ impl Hydrator {
|
|||
|
||||
let ret = self.do_type_from_annotation(ret, environment, unbounds)?;
|
||||
|
||||
Ok(function(args, ret))
|
||||
Ok(Type::function(args, ret))
|
||||
}
|
||||
|
||||
Annotation::Var { name, location, .. } => match self.created_type_variables.get(name) {
|
||||
|
@ -244,13 +240,13 @@ impl Hydrator {
|
|||
typed_elems.push(typed_elem)
|
||||
}
|
||||
|
||||
Ok(tuple(typed_elems))
|
||||
Ok(Type::tuple(typed_elems))
|
||||
}
|
||||
Annotation::Pair { fst, snd, .. } => {
|
||||
let fst = self.do_type_from_annotation(fst, environment, unbounds)?;
|
||||
let snd = self.do_type_from_annotation(snd, environment, unbounds)?;
|
||||
|
||||
Ok(pair(fst, snd))
|
||||
Ok(Type::pair(fst, snd))
|
||||
}
|
||||
}?;
|
||||
|
||||
|
|
|
@ -9,10 +9,9 @@ use crate::{
|
|||
ast::{
|
||||
Annotation, ArgName, ArgVia, DataType, Definition, Function, ModuleConstant, ModuleKind,
|
||||
RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedArg, TypedDefinition,
|
||||
TypedFunction, TypedModule, UntypedDefinition, UntypedModule, Use, Validator,
|
||||
TypedModule, TypedValidator, UntypedArg, UntypedDefinition, UntypedModule,
|
||||
UntypedValidator, Use, Validator,
|
||||
},
|
||||
builtins,
|
||||
builtins::{fuzzer, generic_var},
|
||||
tipo::{expr::infer_function, Span, Type, TypeVar},
|
||||
IdGenerator,
|
||||
};
|
||||
|
@ -172,138 +171,151 @@ fn infer_definition(
|
|||
doc,
|
||||
location,
|
||||
end_position,
|
||||
mut fun,
|
||||
other_fun,
|
||||
handlers,
|
||||
mut fallback,
|
||||
params,
|
||||
name,
|
||||
}) => {
|
||||
let params_length = params.len();
|
||||
let temp_params = params.iter().cloned().chain(fun.arguments);
|
||||
fun.arguments = temp_params.collect();
|
||||
|
||||
environment.in_new_scope(|environment| {
|
||||
let preregistered_fn = environment
|
||||
.get_variable(&fun.name)
|
||||
.expect("Could not find preregistered type for function");
|
||||
let fallback_name = TypedValidator::handler_name(&name, &fallback.name);
|
||||
|
||||
let preregistered_type = preregistered_fn.tipo.clone();
|
||||
put_params_in_scope(&fallback_name, environment, ¶ms);
|
||||
|
||||
let (args_types, _return_type) = preregistered_type
|
||||
.function_types()
|
||||
.expect("Preregistered type for fn was not a fn");
|
||||
let mut typed_handlers = vec![];
|
||||
|
||||
for (ix, (arg, t)) in params
|
||||
.iter()
|
||||
.zip(args_types[0..params.len()].iter())
|
||||
.enumerate()
|
||||
{
|
||||
match &arg.arg_name(ix) {
|
||||
ArgName::Named {
|
||||
name,
|
||||
label: _,
|
||||
location: _,
|
||||
} if arg.is_validator_param => {
|
||||
environment.insert_variable(
|
||||
name.to_string(),
|
||||
ValueConstructorVariant::LocalVariable {
|
||||
location: arg.location,
|
||||
},
|
||||
t.clone(),
|
||||
);
|
||||
for mut handler in handlers {
|
||||
let typed_fun = environment.in_new_scope(|environment| {
|
||||
let temp_params = params.iter().cloned().chain(handler.arguments);
|
||||
handler.arguments = temp_params.collect();
|
||||
|
||||
environment.init_usage(
|
||||
name.to_string(),
|
||||
EntityKind::Variable,
|
||||
arg.location,
|
||||
);
|
||||
}
|
||||
ArgName::Named { .. } | ArgName::Discarded { .. } => (),
|
||||
};
|
||||
}
|
||||
let handler_name = TypedValidator::handler_name(&name, &handler.name);
|
||||
|
||||
let mut typed_fun =
|
||||
infer_function(&fun, module_name, hydrators, environment, tracing)?;
|
||||
let old_name = handler.name;
|
||||
handler.name = handler_name;
|
||||
|
||||
if !typed_fun.return_type.is_bool() {
|
||||
return Err(Error::ValidatorMustReturnBool {
|
||||
return_type: typed_fun.return_type.clone(),
|
||||
location: typed_fun.location,
|
||||
});
|
||||
}
|
||||
let mut typed_fun =
|
||||
infer_function(&handler, module_name, hydrators, environment, tracing)?;
|
||||
|
||||
let typed_params = typed_fun
|
||||
.arguments
|
||||
.drain(0..params_length)
|
||||
.map(|mut arg| {
|
||||
if arg.tipo.is_unbound() {
|
||||
arg.tipo = builtins::data();
|
||||
}
|
||||
typed_fun.name = old_name;
|
||||
|
||||
arg
|
||||
})
|
||||
.collect();
|
||||
|
||||
if typed_fun.arguments.len() < 2 || typed_fun.arguments.len() > 3 {
|
||||
return Err(Error::IncorrectValidatorArity {
|
||||
count: typed_fun.arguments.len() as u32,
|
||||
location: typed_fun.location,
|
||||
});
|
||||
}
|
||||
|
||||
for arg in typed_fun.arguments.iter_mut() {
|
||||
if arg.tipo.is_unbound() {
|
||||
arg.tipo = builtins::data();
|
||||
}
|
||||
}
|
||||
|
||||
let typed_other_fun = other_fun
|
||||
.map(|mut other| -> Result<TypedFunction, Error> {
|
||||
let params = params.into_iter().chain(other.arguments);
|
||||
other.arguments = params.collect();
|
||||
|
||||
let mut other_typed_fun =
|
||||
infer_function(&other, module_name, hydrators, environment, tracing)?;
|
||||
|
||||
if !other_typed_fun.return_type.is_bool() {
|
||||
if !typed_fun.return_type.is_bool() {
|
||||
return Err(Error::ValidatorMustReturnBool {
|
||||
return_type: other_typed_fun.return_type.clone(),
|
||||
location: other_typed_fun.location,
|
||||
});
|
||||
}
|
||||
|
||||
other_typed_fun.arguments.drain(0..params_length);
|
||||
|
||||
if other_typed_fun.arguments.len() < 2
|
||||
|| other_typed_fun.arguments.len() > 3
|
||||
{
|
||||
return Err(Error::IncorrectValidatorArity {
|
||||
count: other_typed_fun.arguments.len() as u32,
|
||||
location: other_typed_fun.location,
|
||||
});
|
||||
}
|
||||
|
||||
if typed_fun.arguments.len() == other_typed_fun.arguments.len() {
|
||||
return Err(Error::MultiValidatorEqualArgs {
|
||||
return_type: typed_fun.return_type.clone(),
|
||||
location: typed_fun.location,
|
||||
other_location: other_typed_fun.location,
|
||||
count: other_typed_fun.arguments.len(),
|
||||
});
|
||||
}
|
||||
|
||||
for arg in other_typed_fun.arguments.iter_mut() {
|
||||
typed_fun.arguments.drain(0..params_length);
|
||||
|
||||
if !typed_fun.has_valid_purpose_name() {
|
||||
return Err(Error::UnknownPurpose {
|
||||
location: typed_fun
|
||||
.location
|
||||
.map(|start, _end| (start, start + typed_fun.name.len())),
|
||||
available_purposes: TypedValidator::available_handler_names(),
|
||||
});
|
||||
}
|
||||
|
||||
if typed_fun.arguments.len() != typed_fun.validator_arity() {
|
||||
return Err(Error::IncorrectValidatorArity {
|
||||
count: typed_fun.arguments.len() as u32,
|
||||
expected: typed_fun.validator_arity() as u32,
|
||||
location: typed_fun.location,
|
||||
});
|
||||
}
|
||||
|
||||
if typed_fun.is_spend() && !typed_fun.arguments[0].tipo.is_option() {
|
||||
return Err(Error::CouldNotUnify {
|
||||
location: typed_fun.arguments[0].location,
|
||||
expected: Type::option(typed_fun.arguments[0].tipo.clone()),
|
||||
given: typed_fun.arguments[0].tipo.clone(),
|
||||
situation: None,
|
||||
rigid_type_names: Default::default(),
|
||||
});
|
||||
}
|
||||
|
||||
for arg in typed_fun.arguments.iter_mut() {
|
||||
if arg.tipo.is_unbound() {
|
||||
arg.tipo = builtins::data();
|
||||
arg.tipo = Type::data();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(other_typed_fun)
|
||||
})
|
||||
.transpose()?;
|
||||
Ok(typed_fun)
|
||||
})?;
|
||||
|
||||
typed_handlers.push(typed_fun);
|
||||
}
|
||||
|
||||
// NOTE: Duplicates are handled when registering handler names. So if we have N
|
||||
// typed handlers, they are different. The -1 represents takes out the fallback
|
||||
// handler name.
|
||||
let is_exhaustive =
|
||||
typed_handlers.len() >= TypedValidator::available_handler_names().len() - 1;
|
||||
|
||||
if is_exhaustive
|
||||
&& fallback != UntypedValidator::default_fallback(fallback.location)
|
||||
{
|
||||
return Err(Error::UnexpectedValidatorFallback {
|
||||
fallback: fallback.location,
|
||||
});
|
||||
}
|
||||
|
||||
let (typed_params, typed_fallback) = environment.in_new_scope(|environment| {
|
||||
let temp_params = params.iter().cloned().chain(fallback.arguments);
|
||||
fallback.arguments = temp_params.collect();
|
||||
|
||||
let old_name = fallback.name;
|
||||
fallback.name = fallback_name;
|
||||
|
||||
let mut typed_fallback =
|
||||
infer_function(&fallback, module_name, hydrators, environment, tracing)?;
|
||||
|
||||
typed_fallback.name = old_name;
|
||||
|
||||
if !typed_fallback.return_type.is_bool() {
|
||||
return Err(Error::ValidatorMustReturnBool {
|
||||
return_type: typed_fallback.return_type.clone(),
|
||||
location: typed_fallback.location,
|
||||
});
|
||||
}
|
||||
|
||||
let typed_params = typed_fallback
|
||||
.arguments
|
||||
.drain(0..params_length)
|
||||
.map(|mut arg| {
|
||||
if arg.tipo.is_unbound() {
|
||||
arg.tipo = Type::data();
|
||||
}
|
||||
|
||||
arg
|
||||
})
|
||||
.collect();
|
||||
|
||||
if typed_fallback.arguments.len() != 1 {
|
||||
return Err(Error::IncorrectValidatorArity {
|
||||
count: typed_fallback.arguments.len() as u32,
|
||||
expected: 1,
|
||||
location: typed_fallback.location,
|
||||
});
|
||||
}
|
||||
|
||||
for arg in typed_fallback.arguments.iter_mut() {
|
||||
if arg.tipo.is_unbound() {
|
||||
arg.tipo = Type::data();
|
||||
}
|
||||
}
|
||||
|
||||
Ok((typed_params, typed_fallback))
|
||||
})?;
|
||||
|
||||
Ok(Definition::Validator(Validator {
|
||||
doc,
|
||||
end_position,
|
||||
fun: typed_fun,
|
||||
other_fun: typed_other_fun,
|
||||
handlers: typed_handlers,
|
||||
fallback: typed_fallback,
|
||||
name,
|
||||
location,
|
||||
params: typed_params,
|
||||
}))
|
||||
|
@ -394,14 +406,14 @@ fn infer_definition(
|
|||
|
||||
let is_bool = environment.unify(
|
||||
typed_f.return_type.clone(),
|
||||
builtins::bool(),
|
||||
Type::bool(),
|
||||
typed_f.location,
|
||||
false,
|
||||
);
|
||||
|
||||
let is_void = environment.unify(
|
||||
typed_f.return_type.clone(),
|
||||
builtins::void(),
|
||||
Type::void(),
|
||||
typed_f.location,
|
||||
false,
|
||||
);
|
||||
|
@ -653,10 +665,10 @@ fn infer_fuzzer(
|
|||
) -> Result<(Annotation, Rc<Type>), Error> {
|
||||
let could_not_unify = || Error::CouldNotUnify {
|
||||
location: *location,
|
||||
expected: fuzzer(
|
||||
expected: Type::fuzzer(
|
||||
expected_inner_type
|
||||
.clone()
|
||||
.unwrap_or_else(|| generic_var(0)),
|
||||
.unwrap_or_else(|| Type::generic_var(0)),
|
||||
),
|
||||
given: tipo.clone(),
|
||||
situation: None,
|
||||
|
@ -692,7 +704,7 @@ fn infer_fuzzer(
|
|||
// `unify` now that we have figured out the type carried by the fuzzer.
|
||||
environment.unify(
|
||||
tipo.clone(),
|
||||
fuzzer(wrapped.clone()),
|
||||
Type::fuzzer(wrapped.clone()),
|
||||
*location,
|
||||
false,
|
||||
)?;
|
||||
|
@ -779,3 +791,40 @@ fn annotate_fuzzer(tipo: &Type, location: &Span) -> Result<Annotation, Error> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn put_params_in_scope(name: &str, environment: &mut Environment, params: &[UntypedArg]) {
|
||||
let preregistered_fn = environment
|
||||
.get_variable(name)
|
||||
.expect("Could not find preregistered type for function");
|
||||
|
||||
let preregistered_type = preregistered_fn.tipo.clone();
|
||||
|
||||
let (args_types, _return_type) = preregistered_type
|
||||
.function_types()
|
||||
.expect("Preregistered type for fn was not a fn");
|
||||
|
||||
for (ix, (arg, t)) in params
|
||||
.iter()
|
||||
.zip(args_types[0..params.len()].iter())
|
||||
.enumerate()
|
||||
{
|
||||
match &arg.arg_name(ix) {
|
||||
ArgName::Named {
|
||||
name,
|
||||
label: _,
|
||||
location: _,
|
||||
} if arg.is_validator_param => {
|
||||
environment.insert_variable(
|
||||
name.to_string(),
|
||||
ValueConstructorVariant::LocalVariable {
|
||||
location: arg.location,
|
||||
},
|
||||
t.clone(),
|
||||
);
|
||||
|
||||
environment.init_usage(name.to_string(), EntityKind::Variable, arg.location);
|
||||
}
|
||||
ArgName::Named { .. } | ArgName::Discarded { .. } => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,7 @@ use super::{
|
|||
hydrator::Hydrator,
|
||||
PatternConstructor, Type, ValueConstructorVariant,
|
||||
};
|
||||
use crate::{
|
||||
ast::{CallArg, Pattern, Span, TypedPattern, UntypedPattern},
|
||||
builtins::{byte_array, int, list, pair, tuple},
|
||||
};
|
||||
use crate::ast::{CallArg, Pattern, Span, TypedPattern, UntypedPattern};
|
||||
use itertools::Itertools;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
|
@ -190,7 +187,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
value,
|
||||
base,
|
||||
} => {
|
||||
self.environment.unify(tipo, int(), location, false)?;
|
||||
self.environment.unify(tipo, Type::int(), location, false)?;
|
||||
|
||||
Ok(Pattern::Int {
|
||||
location,
|
||||
|
@ -205,7 +202,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
preferred_format,
|
||||
} => {
|
||||
self.environment
|
||||
.unify(tipo, byte_array(), location, false)?;
|
||||
.unify(tipo, Type::byte_array(), location, false)?;
|
||||
|
||||
Ok(Pattern::ByteArray {
|
||||
location,
|
||||
|
@ -231,7 +228,12 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
.try_collect()?;
|
||||
|
||||
let tail = match tail {
|
||||
Some(tail) => Some(Box::new(self.unify(*tail, list(tipo), None, false)?)),
|
||||
Some(tail) => Some(Box::new(self.unify(
|
||||
*tail,
|
||||
Type::list(tipo),
|
||||
None,
|
||||
false,
|
||||
)?)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
|
@ -243,7 +245,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
}
|
||||
|
||||
None => Err(Error::CouldNotUnify {
|
||||
given: list(self.environment.new_unbound_var()),
|
||||
given: Type::list(self.environment.new_unbound_var()),
|
||||
expected: tipo.clone(),
|
||||
situation: None,
|
||||
location,
|
||||
|
@ -267,7 +269,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
let t_snd = self.environment.new_unbound_var();
|
||||
|
||||
self.environment.unify(
|
||||
pair(t_fst.clone(), t_snd.clone()),
|
||||
Type::pair(t_fst.clone(), t_snd.clone()),
|
||||
tipo,
|
||||
location,
|
||||
false,
|
||||
|
@ -280,7 +282,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
}
|
||||
|
||||
_ => Err(Error::CouldNotUnify {
|
||||
given: pair(
|
||||
given: Type::pair(
|
||||
self.environment.new_unbound_var(),
|
||||
self.environment.new_unbound_var(),
|
||||
),
|
||||
|
@ -322,8 +324,12 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
.map(|_| self.environment.new_unbound_var())
|
||||
.collect();
|
||||
|
||||
self.environment
|
||||
.unify(tuple(elems_types.clone()), tipo, location, false)?;
|
||||
self.environment.unify(
|
||||
Type::tuple(elems_types.clone()),
|
||||
tipo,
|
||||
location,
|
||||
false,
|
||||
)?;
|
||||
|
||||
let mut patterns = vec![];
|
||||
|
||||
|
@ -345,7 +351,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
.collect();
|
||||
|
||||
Err(Error::CouldNotUnify {
|
||||
given: tuple(elems_types),
|
||||
given: Type::tuple(elems_types),
|
||||
expected: tipo,
|
||||
situation: None,
|
||||
location,
|
||||
|
|
|
@ -5,7 +5,6 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
ast::{AssignmentKind, CallArg, Pattern, Span, PIPE_VARIABLE},
|
||||
builtins::function,
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
};
|
||||
use std::{ops::Deref, rc::Rc};
|
||||
|
@ -257,7 +256,7 @@ impl<'a, 'b, 'c> PipeTyper<'a, 'b, 'c> {
|
|||
.environment
|
||||
.unify(
|
||||
func.tipo(),
|
||||
function(vec![self.argument_type.clone()], return_type.clone()),
|
||||
Type::function(vec![self.argument_type.clone()], return_type.clone()),
|
||||
func.location(),
|
||||
if let Type::Fn { args, .. } = func.tipo().deref() {
|
||||
if let Some(typ) = args.first() {
|
||||
|
|
|
@ -296,10 +296,7 @@ fn resolve_alias(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
builtins::{function, int},
|
||||
tipo::Span,
|
||||
};
|
||||
use crate::tipo::{Span, Type};
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::cell::RefCell;
|
||||
|
||||
|
@ -490,7 +487,7 @@ mod tests {
|
|||
"?",
|
||||
);
|
||||
assert_string!(
|
||||
function(
|
||||
Type::function(
|
||||
vec![Rc::new(Type::Var {
|
||||
tipo: Rc::new(RefCell::new(TypeVar::Unbound { id: 78 })),
|
||||
alias: None,
|
||||
|
@ -503,7 +500,7 @@ mod tests {
|
|||
"fn(?) -> ?",
|
||||
);
|
||||
assert_string!(
|
||||
function(
|
||||
Type::function(
|
||||
vec![Rc::new(Type::Var {
|
||||
tipo: Rc::new(RefCell::new(TypeVar::Generic { id: 78 })),
|
||||
alias: None,
|
||||
|
@ -692,10 +689,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn function_test() {
|
||||
assert_eq!(pretty_print(function(vec![], int())), "fn() -> Int");
|
||||
assert_eq!(
|
||||
pretty_print(Type::function(vec![], Type::int())),
|
||||
"fn() -> Int"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
pretty_print(function(vec![int(), int(), int()], int())),
|
||||
pretty_print(Type::function(
|
||||
vec![Type::int(), Type::int(), Type::int()],
|
||||
Type::int()
|
||||
)),
|
||||
"fn(Int, Int, Int) -> Int"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ impl From<&Config> for Preamble {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use aiken_lang::builtins;
|
||||
use aiken_lang::tipo::Type;
|
||||
use schema::{Data, Declaration, Items, Schema};
|
||||
use serde_json::{self, json};
|
||||
use std::collections::HashMap;
|
||||
|
@ -225,17 +225,17 @@ mod tests {
|
|||
fn serialize_with_definitions() {
|
||||
let mut definitions = Definitions::new();
|
||||
definitions
|
||||
.register::<_, Error>(&builtins::int(), &HashMap::new(), |_| {
|
||||
.register::<_, Error>(&Type::int(), &HashMap::new(), |_| {
|
||||
Ok(Schema::Data(Data::Integer).into())
|
||||
})
|
||||
.unwrap();
|
||||
definitions
|
||||
.register::<_, Error>(
|
||||
&builtins::list(builtins::byte_array()),
|
||||
&Type::list(Type::byte_array()),
|
||||
&HashMap::new(),
|
||||
|definitions| {
|
||||
let ref_bytes = definitions.register::<_, Error>(
|
||||
&builtins::byte_array(),
|
||||
&Type::byte_array(),
|
||||
&HashMap::new(),
|
||||
|_| Ok(Schema::Data(Data::Bytes).into()),
|
||||
)?;
|
||||
|
|
|
@ -4,7 +4,6 @@ use crate::{
|
|||
};
|
||||
use aiken_lang::{
|
||||
ast::{Definition, TypedDataType, TypedDefinition},
|
||||
builtins::wrapped_redeemer,
|
||||
tipo::{pretty, Type, TypeVar},
|
||||
};
|
||||
use owo_colors::{OwoColorize, Stream::Stdout};
|
||||
|
@ -142,7 +141,7 @@ impl Annotated<Schema> {
|
|||
) -> Reference {
|
||||
definitions
|
||||
.register(
|
||||
&wrapped_redeemer(type_info),
|
||||
&Type::wrapped_redeemer(type_info),
|
||||
&HashMap::new(),
|
||||
|_| {
|
||||
Ok::<_, Error>(Annotated {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\npub type Foo {\n foo: Int\n}\n\nvalidator {\n fn annotated_data(datum: Data<Foo>, redeemer: Data, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\npub type Foo {\n foo: Int\n}\n\nvalidator annotated_data {\n spend(datum: Option<Data<Foo>>, redeemer: Data, output_reference: Data, transpose: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.annotated_data",
|
||||
"title": "test_module.annotated_data.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\nvalidator {\n fn generics(redeemer: a, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\nvalidator generics {\n mint(redeemer: a, policy_id: ByteArray, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
Schema {
|
||||
error: Error {
|
||||
|
@ -16,7 +16,7 @@ Schema {
|
|||
},
|
||||
],
|
||||
},
|
||||
location: 26..37,
|
||||
location: 28..39,
|
||||
source_code: NamedSource {
|
||||
name: "",
|
||||
source: "<redacted>",
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\ntype Either<left, right> {\n Left(left)\n Right(right)\n}\n\ntype Interval<a> {\n Finite(a)\n Infinite\n}\n\nvalidator {\n fn generics(redeemer: Either<ByteArray, Interval<Int>>, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\npub type Either<left, right> {\n Left(left)\n Right(right)\n}\n\npub type Interval<a> {\n Finite(a)\n Infinite\n}\n\nvalidator generics {\n spend(datum: Option<Data>, redeemer: Either<ByteArray, Interval<Int>>, output_reference: Data, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.generics",
|
||||
"title": "test_module.generics.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Data"
|
||||
}
|
||||
},
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
|
@ -16,6 +22,10 @@ description: "Code:\n\ntype Either<left, right> {\n Left(left)\n Right(rig
|
|||
"ByteArray": {
|
||||
"dataType": "bytes"
|
||||
},
|
||||
"Data": {
|
||||
"title": "Data",
|
||||
"description": "Any Plutus data."
|
||||
},
|
||||
"Int": {
|
||||
"dataType": "integer"
|
||||
},
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\ntype Dict<key, value> {\n inner: List<(ByteArray, value)>\n}\n\ntype UUID { UUID }\n\nvalidator {\n fn list_2_tuples_as_list(redeemer: Dict<UUID, Int>, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\npub type Dict<key, value> {\n inner: List<(ByteArray, value)>\n}\n\npub type UUID { UUID }\n\nvalidator list_2_tuples_as_list {\n mint(redeemer: Dict<UUID, Int>, policy_id: ByteArray, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.list_2_tuples_as_list",
|
||||
"title": "test_module.list_2_tuples_as_list.mint",
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\ntype Dict<key, value> {\n inner: List<Pair<ByteArray, value>>\n}\n\ntype UUID { UUID }\n\nvalidator {\n fn list_pairs_as_map(redeemer: Dict<UUID, Int>, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\npub type Dict<key, value> {\n inner: List<Pair<ByteArray, value>>\n}\n\npub type UUID { UUID }\n\nvalidator list_pairs_as_map {\n spend(datum: Option<Data>, redeemer: Dict<UUID, Int>, _output_reference: Data, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.list_pairs_as_map",
|
||||
"title": "test_module.list_pairs_as_map.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Data"
|
||||
}
|
||||
},
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
|
@ -16,6 +22,10 @@ description: "Code:\n\ntype Dict<key, value> {\n inner: List<Pair<ByteArray,
|
|||
"ByteArray": {
|
||||
"dataType": "bytes"
|
||||
},
|
||||
"Data": {
|
||||
"title": "Data",
|
||||
"description": "Any Plutus data."
|
||||
},
|
||||
"Int": {
|
||||
"dataType": "integer"
|
||||
},
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\nvalidator {\n fn mint(redeemer: Data, ctx: Data) {\n True\n }\n}\n// "
|
||||
description: "Code:\n\nvalidator thing {\n mint(redeemer: Data, policy_id: ByteArray, transaction: Data) {\n True\n }\n}\n// "
|
||||
---
|
||||
{
|
||||
"title": "test_module.mint",
|
||||
"title": "test_module.thing.mint",
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\nvalidator(utxo_ref: Int) {\n fn mint(redeemer: Data, ctx: Data) {\n True\n }\n}\n// "
|
||||
description: "Code:\n\nvalidator thing(utxo_ref: Int) {\n mint(redeemer: Data, policy_id: ByteArray, transaction: Data) {\n True\n }\n}\n// "
|
||||
---
|
||||
{
|
||||
"title": "test_module.mint",
|
||||
"title": "test_module.thing.mint",
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\npub type Foo {\n foo: Data\n}\n\nvalidator {\n fn nested_data(datum: Foo, redeemer: Int, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\npub type Foo {\n foo: Data\n}\n\nvalidator nested_data {\n spend(datum: Option<Foo>, redeemer: Int, output_reference: Data, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.nested_data",
|
||||
"title": "test_module.nested_data.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\npub opaque type Rational {\n numerator: Int,\n denominator: Int,\n}\n\nvalidator {\n fn opaque_singleton_multi_variants(redeemer: Rational, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\npub opaque type Rational {\n numerator: Int,\n denominator: Int,\n}\n\nvalidator opaque_singleton_multi_variants {\n spend(datum: Option<Data>, redeemer: Rational, oref: Data, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
Schema {
|
||||
error: Error {
|
||||
|
@ -16,7 +16,7 @@ Schema {
|
|||
},
|
||||
],
|
||||
},
|
||||
location: 117..135,
|
||||
location: 141..159,
|
||||
source_code: NamedSource {
|
||||
name: "",
|
||||
source: "<redacted>",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\npub opaque type Dict<key, value> {\n inner: List<(ByteArray, value)>\n}\n\ntype UUID { UUID }\n\nvalidator {\n fn opaque_singleton_variants(redeemer: Dict<UUID, Int>, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\npub opaque type Dict<key, value> {\n inner: List<(ByteArray, value)>\n}\n\npub type UUID { UUID }\n\nvalidator opaque_singleton_variants {\n spend(datum: Option<Data>, redeemer: Dict<UUID, Int>, output_reference: Data, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
Schema {
|
||||
error: Error {
|
||||
|
@ -16,7 +16,7 @@ Schema {
|
|||
tipo: RefCell {
|
||||
value: Link {
|
||||
tipo: App {
|
||||
public: false,
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "test_module",
|
||||
name: "UUID",
|
||||
|
@ -47,7 +47,7 @@ Schema {
|
|||
},
|
||||
],
|
||||
},
|
||||
location: 137..162,
|
||||
location: 165..190,
|
||||
source_code: NamedSource {
|
||||
name: "",
|
||||
source: "<redacted>",
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\npub type LinkedList<a> {\n Cons(a, LinkedList<a>)\n Nil\n}\n\npub type Foo {\n Foo {\n foo: LinkedList<Bool>,\n }\n Bar {\n bar: Int,\n baz: (ByteArray, List<LinkedList<Int>>)\n }\n}\n\nvalidator {\n fn recursive_generic_types(datum: Foo, redeemer: LinkedList<Int>, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\npub type LinkedList<a> {\n Cons(a, LinkedList<a>)\n Nil\n}\n\npub type Foo {\n Foo {\n foo: LinkedList<Bool>,\n }\n Bar {\n bar: Int,\n baz: (ByteArray, List<LinkedList<Int>>)\n }\n}\n\nvalidator recursive_generic_types {\n spend(datum: Option<Foo>, redeemer: LinkedList<Int>, output_reference: Data, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.recursive_generic_types",
|
||||
"title": "test_module.recursive_generic_types.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\npub type Expr {\n Val(Int)\n Sum(Expr, Expr)\n Mul(Expr, Expr)\n}\n\nvalidator {\n fn recursive_types(redeemer: Expr, ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\npub type Expr {\n Val(Int)\n Sum(Expr, Expr)\n Mul(Expr, Expr)\n}\n\nvalidator recursive_types {\n spend(datum: Option<Data>, redeemer: Expr, output_reference: Data, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.recursive_types",
|
||||
"title": "test_module.recursive_types.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Data"
|
||||
}
|
||||
},
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
|
@ -13,6 +19,10 @@ description: "Code:\n\npub type Expr {\n Val(Int)\n Sum(Expr, Expr)\n Mul(Exp
|
|||
"compiledCode": "<redacted>",
|
||||
"hash": "<redacted>",
|
||||
"definitions": {
|
||||
"Data": {
|
||||
"title": "Data",
|
||||
"description": "Any Plutus data."
|
||||
},
|
||||
"Int": {
|
||||
"dataType": "integer"
|
||||
},
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\n/// On-chain state\ntype State {\n /// The contestation period as a number of seconds\n contestationPeriod: ContestationPeriod,\n /// List of public key hashes of all participants\n parties: List<Party>,\n utxoHash: Hash<Blake2b_256>,\n}\n\n/// A Hash digest for a given algorithm.\ntype Hash<alg> = ByteArray\n\ntype Blake2b_256 { Blake2b_256 }\n\n/// Whatever\ntype ContestationPeriod {\n /// A positive, non-zero number of seconds.\n ContestationPeriod(Int)\n}\n\ntype Party =\n ByteArray\n\ntype Input {\n CollectCom\n Close\n /// Abort a transaction\n Abort\n}\n\nvalidator {\n fn simplified_hydra(datum: State, redeemer: Input, ctx: Data) {\n True\n }\n}\n"
|
||||
description: "Code:\n\n/// On-chain state\npub type State {\n /// The contestation period as a number of seconds\n contestationPeriod: ContestationPeriod,\n /// List of public key hashes of all participants\n parties: List<Party>,\n utxoHash: Hash<Blake2b_256>,\n}\n\n/// A Hash digest for a given algorithm.\npub type Hash<alg> = ByteArray\n\npub type Blake2b_256 { Blake2b_256 }\n\n/// Whatever\npub type ContestationPeriod {\n /// A positive, non-zero number of seconds.\n ContestationPeriod(Int)\n}\n\npub type Party =\n ByteArray\n\npub type Input {\n CollectCom\n Close\n /// Abort a transaction\n Abort\n}\n\nvalidator simplified_hydra {\n spend(datum: Option<State>, redeemer: Input, output_reference: Data, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.simplified_hydra",
|
||||
"title": "test_module.simplified_hydra.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\nvalidator {\n fn tuples(datum: (Int, ByteArray), redeemer: (Int, Int, Int), ctx: Void) {\n True\n }\n}\n"
|
||||
description: "Code:\n\nvalidator tuples {\n spend(datum: Option<(Int, ByteArray)>, redeemer: (Int, Int, Int), output_reference: Data, transaction: Data) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.tuples",
|
||||
"title": "test_module.tuples.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
|
|
|
@ -7,10 +7,10 @@ use super::{
|
|||
};
|
||||
use crate::module::{CheckedModule, CheckedModules};
|
||||
use aiken_lang::{
|
||||
ast::{Annotation, TypedArg, TypedFunction, TypedValidator},
|
||||
ast::{well_known, Annotation, TypedArg, TypedFunction, TypedValidator},
|
||||
gen_uplc::CodeGenerator,
|
||||
plutus_version::PlutusVersion,
|
||||
tipo::Type,
|
||||
tipo::{collapse_links, Type},
|
||||
};
|
||||
use miette::NamedSource;
|
||||
use serde;
|
||||
|
@ -30,7 +30,8 @@ pub struct Validator {
|
|||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub datum: Option<Parameter>,
|
||||
|
||||
pub redeemer: Parameter,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub redeemer: Option<Parameter>,
|
||||
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
#[serde(default)]
|
||||
|
@ -52,29 +53,33 @@ impl Validator {
|
|||
def: &TypedValidator,
|
||||
plutus_version: &PlutusVersion,
|
||||
) -> Vec<Result<Validator, Error>> {
|
||||
let is_multi_validator = def.other_fun.is_some();
|
||||
|
||||
let mut program = MemoProgram::new();
|
||||
|
||||
let mut validators = vec![Validator::create_validator_blueprint(
|
||||
generator,
|
||||
modules,
|
||||
module,
|
||||
def,
|
||||
&def.fun,
|
||||
is_multi_validator,
|
||||
&mut program,
|
||||
plutus_version,
|
||||
)];
|
||||
let mut validators = vec![];
|
||||
|
||||
if let Some(ref other_func) = def.other_fun {
|
||||
for handler in &def.handlers {
|
||||
validators.push(Validator::create_validator_blueprint(
|
||||
generator,
|
||||
modules,
|
||||
module,
|
||||
def,
|
||||
other_func,
|
||||
is_multi_validator,
|
||||
handler,
|
||||
&mut program,
|
||||
plutus_version,
|
||||
));
|
||||
}
|
||||
|
||||
// NOTE: Only push the fallback if all other validators have been successfully
|
||||
// generated. Otherwise, we may fall into scenarios where we cannot generate validators
|
||||
// (e.g. due to the presence of generics in datum/redeemer), which won't be caught by
|
||||
// the else branch since it lacks arguments.
|
||||
if validators.iter().all(|v| v.is_ok()) {
|
||||
validators.push(Validator::create_validator_blueprint(
|
||||
generator,
|
||||
modules,
|
||||
module,
|
||||
def,
|
||||
&def.fallback,
|
||||
&mut program,
|
||||
plutus_version,
|
||||
));
|
||||
|
@ -90,13 +95,9 @@ impl Validator {
|
|||
module: &CheckedModule,
|
||||
def: &TypedValidator,
|
||||
func: &TypedFunction,
|
||||
is_multi_validator: bool,
|
||||
program: &mut MemoProgram,
|
||||
plutus_version: &PlutusVersion,
|
||||
) -> Result<Validator, Error> {
|
||||
let mut args = func.arguments.iter().rev();
|
||||
let (_, redeemer, datum) = (args.next(), args.next().unwrap(), args.next());
|
||||
|
||||
let mut definitions = Definitions::new();
|
||||
|
||||
let parameters = def
|
||||
|
@ -123,53 +124,81 @@ impl Validator {
|
|||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let datum = datum
|
||||
.map(|datum| {
|
||||
Annotated::from_type(
|
||||
modules.into(),
|
||||
tipo_or_annotation(module, datum),
|
||||
&mut definitions,
|
||||
)
|
||||
.map_err(|error| Error::Schema {
|
||||
error,
|
||||
location: datum.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
),
|
||||
})
|
||||
})
|
||||
.transpose()?
|
||||
.map(|schema| Parameter {
|
||||
title: datum.map(|datum| datum.arg_name.get_label()),
|
||||
schema,
|
||||
});
|
||||
let (datum, redeemer) = if func.name == well_known::VALIDATOR_ELSE {
|
||||
(None, None)
|
||||
} else {
|
||||
let mut args = func.arguments.iter().rev();
|
||||
|
||||
let redeemer = Annotated::from_type(
|
||||
modules.into(),
|
||||
tipo_or_annotation(module, redeemer),
|
||||
&mut definitions,
|
||||
)
|
||||
.map_err(|error| Error::Schema {
|
||||
error,
|
||||
location: redeemer.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
),
|
||||
})
|
||||
.map(|schema| Parameter {
|
||||
title: Some(redeemer.arg_name.get_label()),
|
||||
schema: match datum {
|
||||
Some(..) if is_multi_validator => {
|
||||
Annotated::as_wrapped_redeemer(&mut definitions, schema, redeemer.tipo.clone())
|
||||
}
|
||||
_ => schema,
|
||||
},
|
||||
})?;
|
||||
let (_, _, redeemer, datum) = (
|
||||
args.next(),
|
||||
args.next(),
|
||||
args.next().expect("redeemer is always present"),
|
||||
args.next(),
|
||||
);
|
||||
|
||||
let datum = datum
|
||||
.map(|datum| {
|
||||
match datum.tipo.as_ref() {
|
||||
Type::App { module: module_name, name, args, .. } if module_name.is_empty() && name == well_known::OPTION => {
|
||||
let annotation = if let Some(Annotation::Constructor { arguments, .. }) = datum.annotation.as_ref() {
|
||||
arguments.first().cloned().expect("Datum isn't an option but should be; this should have been caught by the type-checker!")
|
||||
} else {
|
||||
Annotation::data(datum.location)
|
||||
};
|
||||
|
||||
Annotated::from_type(
|
||||
modules.into(),
|
||||
tipo_or_annotation(module, &TypedArg {
|
||||
arg_name: datum.arg_name.clone(),
|
||||
location: datum.location,
|
||||
annotation: Some(annotation),
|
||||
doc: datum.doc.clone(),
|
||||
is_validator_param: datum.is_validator_param,
|
||||
tipo: args.first().expect("Option always have a single type argument.").clone()
|
||||
}),
|
||||
&mut definitions,
|
||||
)
|
||||
.map_err(|error| Error::Schema {
|
||||
error,
|
||||
location: datum.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
),
|
||||
})
|
||||
},
|
||||
_ => panic!("Datum isn't an option but should be; this should have been caught by the type-checker!"),
|
||||
}
|
||||
})
|
||||
.transpose()?
|
||||
.map(|schema| Parameter {
|
||||
title: datum.map(|datum| datum.arg_name.get_label()),
|
||||
schema,
|
||||
});
|
||||
|
||||
let redeemer = Annotated::from_type(
|
||||
modules.into(),
|
||||
tipo_or_annotation(module, redeemer),
|
||||
&mut definitions,
|
||||
)
|
||||
.map_err(|error| Error::Schema {
|
||||
error,
|
||||
location: redeemer.location,
|
||||
source_code: NamedSource::new(
|
||||
module.input_path.display().to_string(),
|
||||
module.code.clone(),
|
||||
),
|
||||
})
|
||||
.map(|schema| Parameter {
|
||||
title: Some(redeemer.arg_name.get_label()),
|
||||
schema,
|
||||
})?;
|
||||
|
||||
(datum, Some(redeemer))
|
||||
};
|
||||
|
||||
Ok(Validator {
|
||||
title: format!("{}.{}", &module.name, &func.name),
|
||||
title: format!("{}.{}.{}", &module.name, &def.name, &func.name,),
|
||||
description: func.doc.clone(),
|
||||
parameters,
|
||||
datum,
|
||||
|
@ -185,7 +214,7 @@ impl Validator {
|
|||
}
|
||||
|
||||
pub fn tipo_or_annotation<'a>(module: &'a CheckedModule, arg: &'a TypedArg) -> &'a Type {
|
||||
match *arg.tipo.borrow() {
|
||||
match collapse_links(arg.tipo.clone()).borrow() {
|
||||
Type::App {
|
||||
module: ref module_name,
|
||||
name: ref type_name,
|
||||
|
@ -274,7 +303,7 @@ mod tests {
|
|||
use aiken_lang::{
|
||||
self,
|
||||
ast::{TraceLevel, Tracing},
|
||||
builtins,
|
||||
tipo::Type,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use uplc::ast as uplc_ast;
|
||||
|
@ -296,7 +325,7 @@ mod tests {
|
|||
|
||||
let validators = Validator::from_checked_module(&modules, &mut generator, validator, def, &PlutusVersion::default());
|
||||
|
||||
if validators.len() > 1 {
|
||||
if validators.len() > 2 {
|
||||
panic!("Multi-validator given to test bench. Don't do that.")
|
||||
}
|
||||
|
||||
|
@ -338,7 +367,7 @@ mod tests {
|
|||
// "dataType": "integer"
|
||||
// }
|
||||
definitions
|
||||
.register::<_, Error>(&builtins::int(), &HashMap::new(), |_| {
|
||||
.register::<_, Error>(&Type::int(), &HashMap::new(), |_| {
|
||||
Ok(Schema::Data(Data::Integer).into())
|
||||
})
|
||||
.unwrap();
|
||||
|
@ -349,7 +378,7 @@ mod tests {
|
|||
// "dataType": "bytes"
|
||||
// }
|
||||
definitions
|
||||
.register::<_, Error>(&builtins::byte_array(), &HashMap::new(), |_| {
|
||||
.register::<_, Error>(&Type::byte_array(), &HashMap::new(), |_| {
|
||||
Ok(Schema::Data(Data::Bytes).into())
|
||||
})
|
||||
.unwrap();
|
||||
|
@ -396,8 +425,8 @@ mod tests {
|
|||
fn mint_basic() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
validator {
|
||||
fn mint(redeemer: Data, ctx: Data) {
|
||||
validator thing {
|
||||
mint(redeemer: Data, policy_id: ByteArray, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -409,8 +438,8 @@ mod tests {
|
|||
fn mint_parameterized() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
validator(utxo_ref: Int) {
|
||||
fn mint(redeemer: Data, ctx: Data) {
|
||||
validator thing(utxo_ref: Int) {
|
||||
mint(redeemer: Data, policy_id: ByteArray, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +452,7 @@ mod tests {
|
|||
assert_validator!(
|
||||
r#"
|
||||
/// On-chain state
|
||||
type State {
|
||||
pub type State {
|
||||
/// The contestation period as a number of seconds
|
||||
contestationPeriod: ContestationPeriod,
|
||||
/// List of public key hashes of all participants
|
||||
|
@ -432,28 +461,28 @@ mod tests {
|
|||
}
|
||||
|
||||
/// A Hash digest for a given algorithm.
|
||||
type Hash<alg> = ByteArray
|
||||
pub type Hash<alg> = ByteArray
|
||||
|
||||
type Blake2b_256 { Blake2b_256 }
|
||||
pub type Blake2b_256 { Blake2b_256 }
|
||||
|
||||
/// Whatever
|
||||
type ContestationPeriod {
|
||||
pub type ContestationPeriod {
|
||||
/// A positive, non-zero number of seconds.
|
||||
ContestationPeriod(Int)
|
||||
}
|
||||
|
||||
type Party =
|
||||
pub type Party =
|
||||
ByteArray
|
||||
|
||||
type Input {
|
||||
pub type Input {
|
||||
CollectCom
|
||||
Close
|
||||
/// Abort a transaction
|
||||
Abort
|
||||
}
|
||||
|
||||
validator {
|
||||
fn simplified_hydra(datum: State, redeemer: Input, ctx: Data) {
|
||||
validator simplified_hydra {
|
||||
spend(datum: Option<State>, redeemer: Input, output_reference: Data, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -465,8 +494,8 @@ mod tests {
|
|||
fn tuples() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
validator {
|
||||
fn tuples(datum: (Int, ByteArray), redeemer: (Int, Int, Int), ctx: Void) {
|
||||
validator tuples {
|
||||
spend(datum: Option<(Int, ByteArray)>, redeemer: (Int, Int, Int), output_reference: Data, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -478,18 +507,18 @@ mod tests {
|
|||
fn generics() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
type Either<left, right> {
|
||||
pub type Either<left, right> {
|
||||
Left(left)
|
||||
Right(right)
|
||||
}
|
||||
|
||||
type Interval<a> {
|
||||
pub type Interval<a> {
|
||||
Finite(a)
|
||||
Infinite
|
||||
}
|
||||
|
||||
validator {
|
||||
fn generics(redeemer: Either<ByteArray, Interval<Int>>, ctx: Void) {
|
||||
validator generics {
|
||||
spend(datum: Option<Data>, redeemer: Either<ByteArray, Interval<Int>>, output_reference: Data, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -501,8 +530,8 @@ mod tests {
|
|||
fn free_vars() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
validator {
|
||||
fn generics(redeemer: a, ctx: Void) {
|
||||
validator generics {
|
||||
mint(redeemer: a, policy_id: ByteArray, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -514,14 +543,14 @@ mod tests {
|
|||
fn list_2_tuples_as_list() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
type Dict<key, value> {
|
||||
pub type Dict<key, value> {
|
||||
inner: List<(ByteArray, value)>
|
||||
}
|
||||
|
||||
type UUID { UUID }
|
||||
pub type UUID { UUID }
|
||||
|
||||
validator {
|
||||
fn list_2_tuples_as_list(redeemer: Dict<UUID, Int>, ctx: Void) {
|
||||
validator list_2_tuples_as_list {
|
||||
mint(redeemer: Dict<UUID, Int>, policy_id: ByteArray, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -533,14 +562,14 @@ mod tests {
|
|||
fn list_pairs_as_map() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
type Dict<key, value> {
|
||||
pub type Dict<key, value> {
|
||||
inner: List<Pair<ByteArray, value>>
|
||||
}
|
||||
|
||||
type UUID { UUID }
|
||||
pub type UUID { UUID }
|
||||
|
||||
validator {
|
||||
fn list_pairs_as_map(redeemer: Dict<UUID, Int>, ctx: Void) {
|
||||
validator list_pairs_as_map {
|
||||
spend(datum: Option<Data>, redeemer: Dict<UUID, Int>, _output_reference: Data, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -556,10 +585,10 @@ mod tests {
|
|||
inner: List<(ByteArray, value)>
|
||||
}
|
||||
|
||||
type UUID { UUID }
|
||||
pub type UUID { UUID }
|
||||
|
||||
validator {
|
||||
fn opaque_singleton_variants(redeemer: Dict<UUID, Int>, ctx: Void) {
|
||||
validator opaque_singleton_variants {
|
||||
spend(datum: Option<Data>, redeemer: Dict<UUID, Int>, output_reference: Data, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -576,8 +605,8 @@ mod tests {
|
|||
denominator: Int,
|
||||
}
|
||||
|
||||
validator {
|
||||
fn opaque_singleton_multi_variants(redeemer: Rational, ctx: Void) {
|
||||
validator opaque_singleton_multi_variants {
|
||||
spend(datum: Option<Data>, redeemer: Rational, oref: Data, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -593,8 +622,8 @@ mod tests {
|
|||
foo: Data
|
||||
}
|
||||
|
||||
validator {
|
||||
fn nested_data(datum: Foo, redeemer: Int, ctx: Void) {
|
||||
validator nested_data {
|
||||
spend(datum: Option<Foo>, redeemer: Int, output_reference: Data, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -612,8 +641,8 @@ mod tests {
|
|||
Mul(Expr, Expr)
|
||||
}
|
||||
|
||||
validator {
|
||||
fn recursive_types(redeemer: Expr, ctx: Void) {
|
||||
validator recursive_types {
|
||||
spend(datum: Option<Data>, redeemer: Expr, output_reference: Data, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -640,8 +669,8 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
validator {
|
||||
fn recursive_generic_types(datum: Foo, redeemer: LinkedList<Int>, ctx: Void) {
|
||||
validator recursive_generic_types {
|
||||
spend(datum: Option<Foo>, redeemer: LinkedList<Int>, output_reference: Data, transaction: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -657,8 +686,8 @@ mod tests {
|
|||
foo: Int
|
||||
}
|
||||
|
||||
validator {
|
||||
fn annotated_data(datum: Data<Foo>, redeemer: Data, ctx: Void) {
|
||||
validator annotated_data {
|
||||
spend(datum: Option<Data<Foo>>, redeemer: Data, output_reference: Data, transpose: Data) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
|
|
@ -390,8 +390,8 @@ impl CheckedModule {
|
|||
}
|
||||
Definition::Validator(Validator {
|
||||
params,
|
||||
fun,
|
||||
other_fun,
|
||||
handlers,
|
||||
fallback,
|
||||
..
|
||||
}) => {
|
||||
for param in params {
|
||||
|
@ -404,18 +404,8 @@ impl CheckedModule {
|
|||
}
|
||||
}
|
||||
|
||||
for argument in fun.arguments.iter_mut() {
|
||||
let docs: Vec<&str> =
|
||||
comments_before(&mut doc_comments, argument.location.start, &self.code);
|
||||
|
||||
if !docs.is_empty() {
|
||||
let doc = docs.join("\n");
|
||||
argument.put_doc(doc);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fun) = other_fun {
|
||||
for argument in fun.arguments.iter_mut() {
|
||||
for handler in handlers.iter_mut() {
|
||||
for argument in handler.arguments.iter_mut() {
|
||||
let docs: Vec<&str> = comments_before(
|
||||
&mut doc_comments,
|
||||
argument.location.start,
|
||||
|
@ -428,6 +418,16 @@ impl CheckedModule {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for argument in fallback.arguments.iter_mut() {
|
||||
let docs: Vec<&str> =
|
||||
comments_before(&mut doc_comments, argument.location.start, &self.code);
|
||||
|
||||
if !docs.is_empty() {
|
||||
let doc = docs.join("\n");
|
||||
argument.put_doc(doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -463,6 +463,7 @@ impl CheckedModules {
|
|||
modules
|
||||
}
|
||||
|
||||
// todo: this might need fixing
|
||||
pub fn validators(&self) -> impl Iterator<Item = (&CheckedModule, &TypedValidator)> {
|
||||
let mut items = vec![];
|
||||
|
||||
|
@ -478,12 +479,12 @@ impl CheckedModules {
|
|||
(
|
||||
left.0.package.to_string(),
|
||||
left.0.name.to_string(),
|
||||
left.1.fun.name.to_string(),
|
||||
left.1.name.to_string(),
|
||||
)
|
||||
.cmp(&(
|
||||
right.0.package.to_string(),
|
||||
right.0.name.to_string(),
|
||||
right.1.fun.name.to_string(),
|
||||
right.1.name.to_string(),
|
||||
))
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use aiken_lang::ast::OnTestFailure;
|
||||
pub(crate) use aiken_lang::{
|
||||
ast::{BinOp, DataTypeKey, IfBranch, Span, TypedArg, TypedDataType, TypedTest},
|
||||
builtins::bool,
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
format::Formatter,
|
||||
gen_uplc::CodeGenerator,
|
||||
|
@ -1056,7 +1055,7 @@ impl TryFrom<TypedExpr> for Assertion<TypedExpr> {
|
|||
left,
|
||||
right,
|
||||
..
|
||||
} if tipo == bool() => {
|
||||
} if tipo == Type::bool() => {
|
||||
// 'and' and 'or' are left-associative operators.
|
||||
match (*right).clone().try_into() {
|
||||
Ok(Assertion {
|
||||
|
@ -1094,7 +1093,7 @@ impl TryFrom<TypedExpr> for Assertion<TypedExpr> {
|
|||
let then_is_true = match body {
|
||||
TypedExpr::Var {
|
||||
name, constructor, ..
|
||||
} => name == "True" && constructor.tipo == bool(),
|
||||
} => name == "True" && constructor.tipo == Type::bool(),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
@ -1102,7 +1101,7 @@ impl TryFrom<TypedExpr> for Assertion<TypedExpr> {
|
|||
TypedExpr::Trace { then, .. } => match *then {
|
||||
TypedExpr::Var {
|
||||
name, constructor, ..
|
||||
} => name == "False" && constructor.tipo == bool(),
|
||||
} => name == "False" && constructor.tipo == Type::bool(),
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,78 +5,120 @@ use std::string::FromUtf8Error;
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, thiserror::Error, miette::Diagnostic)]
|
||||
pub enum Error {
|
||||
#[error("Over budget mem: {} & cpu: {}", .0.mem, .0.cpu)]
|
||||
#[error("execution went over budget\n{:>13} {}\n{:>13} {}", "Mem", .0.mem, "CPU", .0.cpu)]
|
||||
OutOfExError(ExBudget),
|
||||
#[error("Invalid Stepkind: {0}")]
|
||||
#[error("invalid step kind: {0}")]
|
||||
InvalidStepKind(u8),
|
||||
#[error("Cannot evaluate an open term:\\n\\n{}", .0.to_pretty())]
|
||||
#[error(
|
||||
"cannot evaluate an open term:\n{:>13} {}",
|
||||
"Term",
|
||||
indent(redacted(.0.to_pretty(), 10)),
|
||||
)]
|
||||
OpenTermEvaluated(Term<NamedDeBruijn>),
|
||||
#[error("The validator crashed / exited prematurely")]
|
||||
#[error("the validator crashed / exited prematurely")]
|
||||
EvaluationFailure,
|
||||
#[error(
|
||||
"Attempted to instantiate a non-polymorphic term\n{:>13} {}",
|
||||
"attempted to instantiate a non-polymorphic term\n{:>13} {}",
|
||||
"Term",
|
||||
indent(redacted(format!("{:#?}", .0), 10)),
|
||||
)]
|
||||
NonPolymorphicInstantiation(Value),
|
||||
#[error(
|
||||
"Attempted to apply an argument to a non-function\n{:>13} {}\n{:>13} {}",
|
||||
"attempted to apply an argument to a non-function\n{:>13} {}\n{:>13} {}",
|
||||
"Thing",
|
||||
indent(redacted(format!("{:#?}", .0), 5)),
|
||||
"Argument",
|
||||
indent(redacted(format!("{:#?}", .1), 5)),
|
||||
)]
|
||||
NonFunctionalApplication(Value, Value),
|
||||
#[error("Attempted to case a non-const:\n\n{0:#?}")]
|
||||
#[error(
|
||||
"attempted to case a non-const\n{:>13} {}",
|
||||
"Value",
|
||||
indent(redacted(format!("{:#?}", .0), 10)),
|
||||
)]
|
||||
NonConstrScrutinized(Value),
|
||||
#[error("Cases: {0:#?}\n\n are missing branch for constr:\n\n{1:#?}")]
|
||||
MissingCaseBranch(Vec<Term<NamedDeBruijn>>, Value),
|
||||
#[error("Type mismatch expected '{0}' got '{1}'")]
|
||||
#[error("type mismatch\n{:>13} {0}\n{:>13} {1}", "Expected", "Got")]
|
||||
TypeMismatch(Type, Type),
|
||||
#[error("Type mismatch expected '(list a)' got '{0}'")]
|
||||
#[error("type mismatch\n{:>13} (list a)\n{:>13} {0}", "Expected", "Got")]
|
||||
ListTypeMismatch(Type),
|
||||
#[error("Type mismatch expected '(pair a b)' got '{0}'")]
|
||||
#[error("type mismatch\n{:>13}(pair a b)\n{:>13} {0}", "Expected", "Got")]
|
||||
PairTypeMismatch(Type),
|
||||
#[error("Empty List:\n\n{0:#?}")]
|
||||
#[error(
|
||||
"unexpected empty list\n{:>13} {}",
|
||||
"List",
|
||||
indent(redacted(format!("{:#?}", .0), 10)),
|
||||
)]
|
||||
EmptyList(Value),
|
||||
#[error(
|
||||
"A builtin received a term argument when something else was expected:\n\n{0}\n\nYou probably forgot to wrap the builtin with a force."
|
||||
"a builtin received a term argument when something else was expected\n{:>13} {}\n{:>13} You probably forgot to wrap the builtin with a force.",
|
||||
"Term",
|
||||
indent(redacted(format!("{:#?}", .0), 10)),
|
||||
"Hint"
|
||||
)]
|
||||
UnexpectedBuiltinTermArgument(Term<NamedDeBruijn>),
|
||||
#[error(
|
||||
"A builtin expected a term argument, but something else was received:\n\n{0}\n\nYou probably have an extra force wrapped around a builtin"
|
||||
"a builtin expected a term argument, but something else was received:\n{:>13} {}\n{:>13} You probably have an extra force wrapped around a builtin",
|
||||
"Term",
|
||||
indent(redacted(format!("{:#?}", .0), 10)),
|
||||
"Hint"
|
||||
)]
|
||||
BuiltinTermArgumentExpected(Term<NamedDeBruijn>),
|
||||
#[error("Unable to unlift value because it is not a constant:\n\n{0:#?}")]
|
||||
#[error(
|
||||
"Unable to unlift value because it is not a constant\n{:>13} {}",
|
||||
"Value",
|
||||
indent(redacted(format!("{:#?}", .0), 10)),
|
||||
)]
|
||||
NotAConstant(Value),
|
||||
#[error("The evaluation never reached a final state")]
|
||||
MachineNeverReachedDone,
|
||||
#[error("integerToByteString encountered negative size {0}")]
|
||||
#[error("integerToByteString encountered negative size\n{:>13} {0}", "Size")]
|
||||
IntegerToByteStringNegativeSize(BigInt),
|
||||
#[error("integerToByteString encountered negative input {0}")]
|
||||
#[error("integerToByteString encountered negative input\n{:>13} {0}", "Input")]
|
||||
IntegerToByteStringNegativeInput(BigInt),
|
||||
#[error("integerToByteString encountered size {0} which is bigger than the max size of {1}")]
|
||||
#[error(
|
||||
"bytes size beyond limit when converting from integer\n{:>13} {0}\n{:>13} {1}",
|
||||
"Size",
|
||||
"Maximum"
|
||||
)]
|
||||
IntegerToByteStringSizeTooBig(BigInt, i64),
|
||||
#[error("integerToByteString encountered size {0} which is not enough space for {1} bytes")]
|
||||
#[error(
|
||||
"bytes size below limit when converting from integer\n{:>13} {0}\n{:>13} {1}",
|
||||
"Size",
|
||||
"Minimum"
|
||||
)]
|
||||
IntegerToByteStringSizeTooSmall(BigInt, usize),
|
||||
#[error("Decoding utf8")]
|
||||
Utf8(#[from] FromUtf8Error),
|
||||
#[error("Out of Bounds\n\nindex: {}\nbytestring: {}\npossible: 0 - {}", .0, hex::encode(.1), .1.len() - 1)]
|
||||
#[error(
|
||||
"Out of Bounds\n{:>13} {}\nb{:>13} {}\n{:>13} 0 - {}",
|
||||
"Index",
|
||||
.0,
|
||||
"ByteArray",
|
||||
hex::encode(.1),
|
||||
"Allowed",
|
||||
.1.len() - 1
|
||||
)]
|
||||
ByteStringOutOfBounds(BigInt, Vec<u8>),
|
||||
#[error("Attempt to consByteString something than isn't a byte between [0-255]: {0}")]
|
||||
#[error(
|
||||
"attempt to consByteString something than isn't a byte between [0-255]\n{:>13} {0}",
|
||||
"Found"
|
||||
)]
|
||||
ByteStringConsNotAByte(BigInt),
|
||||
#[error("Divide By Zero\n\n{0} / {1}")]
|
||||
#[error("divide By Zero: {0} / {1}")]
|
||||
DivideByZero(BigInt, BigInt),
|
||||
#[error("Ed25519S PublicKey should be 32 bytes but it was {0}")]
|
||||
UnexpectedEd25519PublicKeyLength(usize),
|
||||
#[error("Ed25519S Signature should be 64 bytes but it was {0}")]
|
||||
UnexpectedEd25519SignatureLength(usize),
|
||||
#[error(
|
||||
"Failed to deserialise PlutusData using {0}:\n\n{}",
|
||||
redacted(format!("{:#?}", .1), 10),
|
||||
"failed to deserialise PlutusData using {0}\n{:>13} {}",
|
||||
"Value",
|
||||
indent(redacted(format!("{:#?}", .1), 10)),
|
||||
)]
|
||||
DeserialisationError(String, Value),
|
||||
#[error("Integer overflow")]
|
||||
#[error("integer overflow")]
|
||||
OverflowError,
|
||||
#[error("blst error {0:?}")]
|
||||
Blst(blst::BLST_ERROR),
|
||||
|
|
|
@ -100,7 +100,7 @@ pub fn eval_phase_two_raw(
|
|||
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, tx_bytes))
|
||||
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, tx_bytes))?;
|
||||
|
||||
let cost_mdls = cost_mdls_bytes.map(|x| CostMdls::decode_fragment(x)).transpose()?;
|
||||
let cost_mdls = cost_mdls_bytes.map(CostMdls::decode_fragment).transpose()?;
|
||||
|
||||
let budget = ExBudget {
|
||||
cpu: initial_budget.0 as i64,
|
||||
|
|
|
@ -46,15 +46,7 @@ pub fn eval_redeemer(
|
|||
.apply_data(redeemer.data.clone())
|
||||
.apply_data(script_context.to_plutus_data()),
|
||||
|
||||
// FIXME: Temporary, but needed until https://github.com/aiken-lang/aiken/pull/977
|
||||
// is implemented.
|
||||
ScriptContext::V3 { .. } => if let Some(datum) = datum {
|
||||
program.apply_data(datum)
|
||||
} else {
|
||||
program
|
||||
}
|
||||
.apply_data(redeemer.data.clone())
|
||||
.apply_data(script_context.to_plutus_data()),
|
||||
ScriptContext::V3 { .. } => program.apply_data(script_context.to_plutus_data()),
|
||||
};
|
||||
|
||||
let mut eval_result = if let Some(costs) = cost_mdl_opt {
|
||||
|
|
|
@ -570,20 +570,9 @@ Constr(
|
|||
),
|
||||
Constr(
|
||||
Constr {
|
||||
tag: 121,
|
||||
tag: 122,
|
||||
any_constructor: None,
|
||||
fields: [
|
||||
BigInt(
|
||||
Int(
|
||||
Int(
|
||||
Int {
|
||||
neg: false,
|
||||
val: 3000000,
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
fields: [],
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -638,20 +627,9 @@ Constr(
|
|||
),
|
||||
Constr(
|
||||
Constr {
|
||||
tag: 121,
|
||||
tag: 122,
|
||||
any_constructor: None,
|
||||
fields: [
|
||||
BigInt(
|
||||
Int(
|
||||
Int(
|
||||
Int {
|
||||
neg: false,
|
||||
val: 3000000,
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
fields: [],
|
||||
},
|
||||
),
|
||||
],
|
||||
|
|
|
@ -52,6 +52,8 @@ struct WithArrayRational<'a, T>(&'a T);
|
|||
|
||||
struct WithPartialCertificates<'a, T>(&'a T);
|
||||
|
||||
struct WithNeverRegistrationDeposit<'a, T>(&'a T);
|
||||
|
||||
pub trait ToPlutusData {
|
||||
fn to_plutus_data(&self) -> PlutusData;
|
||||
}
|
||||
|
@ -203,6 +205,29 @@ impl<'a> ToPlutusData for WithWrappedTransactionId<'a, KeyValuePairs<ScriptPurpo
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithNeverRegistrationDeposit<'a, Vec<Certificate>> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
self.0
|
||||
.iter()
|
||||
.map(WithNeverRegistrationDeposit)
|
||||
.collect::<Vec<_>>()
|
||||
.to_plutus_data()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToPlutusData for WithNeverRegistrationDeposit<'a, KeyValuePairs<ScriptPurpose, Redeemer>> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![];
|
||||
for (key, value) in self.0.iter() {
|
||||
data_vec.push((
|
||||
WithNeverRegistrationDeposit(key).to_plutus_data(),
|
||||
value.to_plutus_data(),
|
||||
))
|
||||
}
|
||||
PlutusData::Map(KeyValuePairs::Def(data_vec))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ToPlutusData> ToPlutusData for Option<A> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
|
@ -549,14 +574,16 @@ impl<'a> ToPlutusData for WithPartialCertificates<'a, Certificate> {
|
|||
vec![pool_keyhash.to_plutus_data(), epoch.to_plutus_data()],
|
||||
),
|
||||
|
||||
certificate => unreachable!("unexpected in V1/V2 script context: {certificate:?}"),
|
||||
certificate => {
|
||||
unreachable!("unexpected certificate type in V1/V2 script context: {certificate:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPlutusData for Certificate {
|
||||
impl<'a> ToPlutusData for WithNeverRegistrationDeposit<'a, Certificate> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
match self.0 {
|
||||
Certificate::StakeRegistration(stake_credential) => wrap_multiple_with_constr(
|
||||
0,
|
||||
vec![
|
||||
|
@ -565,11 +592,11 @@ impl ToPlutusData for Certificate {
|
|||
],
|
||||
),
|
||||
|
||||
Certificate::Reg(stake_credential, deposit) => wrap_multiple_with_constr(
|
||||
Certificate::Reg(stake_credential, _) => wrap_multiple_with_constr(
|
||||
0,
|
||||
vec![
|
||||
stake_credential.to_plutus_data(),
|
||||
Some(*deposit).to_plutus_data(),
|
||||
None::<PlutusData>.to_plutus_data(),
|
||||
],
|
||||
),
|
||||
|
||||
|
@ -581,11 +608,11 @@ impl ToPlutusData for Certificate {
|
|||
],
|
||||
),
|
||||
|
||||
Certificate::UnReg(stake_credential, deposit) => wrap_multiple_with_constr(
|
||||
Certificate::UnReg(stake_credential, _) => wrap_multiple_with_constr(
|
||||
1,
|
||||
vec![
|
||||
stake_credential.to_plutus_data(),
|
||||
Some(*deposit).to_plutus_data(),
|
||||
None::<PlutusData>.to_plutus_data(),
|
||||
],
|
||||
),
|
||||
|
||||
|
@ -835,32 +862,44 @@ impl ToPlutusData for TxInInfo {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: This is a _small_ abuse of the 'WithWrappedTransactionId'. We know the wrapped
|
||||
// is needed for V1 and V2, and it also appears that for V1 and V2, the certifying
|
||||
// purpose mustn't include the certificate index. So, we also short-circuit it here.
|
||||
impl<'a> ToPlutusData for WithWrappedTransactionId<'a, ScriptPurpose> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self.0 {
|
||||
ScriptPurpose::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()),
|
||||
ScriptPurpose::Spending(out_ref, ()) => {
|
||||
wrap_with_constr(1, WithWrappedTransactionId(out_ref).to_plutus_data())
|
||||
}
|
||||
// NOTE: This is a _small_ abuse of the 'WithWrappedTransactionId'. We know the wrapped
|
||||
// is needed for V1 and V2, and it also appears that for V1 and V2, the certifying
|
||||
// purpose mustn't include the certificate index. So, we also short-circuit it here.
|
||||
ScriptPurpose::Certifying(_, dcert) => wrap_with_constr(3, dcert.to_plutus_data()),
|
||||
otherwise => otherwise.to_plutus_data(),
|
||||
ScriptPurpose::Rewarding(stake_credential) => {
|
||||
wrap_with_constr(2, stake_credential.to_plutus_data())
|
||||
}
|
||||
ScriptPurpose::Certifying(_, dcert) => {
|
||||
wrap_with_constr(3, WithPartialCertificates(dcert).to_plutus_data())
|
||||
}
|
||||
purpose => {
|
||||
unreachable!("unsupported purpose for V1 or V2 script context: {purpose:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPlutusData for ScriptPurpose {
|
||||
impl<'a> ToPlutusData for WithNeverRegistrationDeposit<'a, ScriptPurpose> {
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
match self.0 {
|
||||
ScriptPurpose::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()),
|
||||
ScriptPurpose::Spending(out_ref, ()) => wrap_with_constr(1, out_ref.to_plutus_data()),
|
||||
ScriptPurpose::Rewarding(stake_credential) => {
|
||||
wrap_with_constr(2, stake_credential.to_plutus_data())
|
||||
}
|
||||
ScriptPurpose::Certifying(ix, dcert) => {
|
||||
wrap_multiple_with_constr(3, vec![ix.to_plutus_data(), dcert.to_plutus_data()])
|
||||
}
|
||||
ScriptPurpose::Certifying(ix, dcert) => wrap_multiple_with_constr(
|
||||
3,
|
||||
vec![
|
||||
ix.to_plutus_data(),
|
||||
WithNeverRegistrationDeposit(dcert).to_plutus_data(),
|
||||
],
|
||||
),
|
||||
ScriptPurpose::Voting(voter) => {
|
||||
wrap_multiple_with_constr(4, vec![voter.to_plutus_data()])
|
||||
}
|
||||
|
@ -1240,12 +1279,12 @@ impl ToPlutusData for Vote {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> ToPlutusData for ScriptInfo<T>
|
||||
impl<'a, T> ToPlutusData for WithNeverRegistrationDeposit<'a, ScriptInfo<T>>
|
||||
where
|
||||
T: ToPlutusData,
|
||||
{
|
||||
fn to_plutus_data(&self) -> PlutusData {
|
||||
match self {
|
||||
match self.0 {
|
||||
ScriptInfo::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()),
|
||||
ScriptInfo::Spending(out_ref, datum) => {
|
||||
wrap_multiple_with_constr(1, vec![out_ref.to_plutus_data(), datum.to_plutus_data()])
|
||||
|
@ -1253,9 +1292,13 @@ where
|
|||
ScriptInfo::Rewarding(stake_credential) => {
|
||||
wrap_with_constr(2, stake_credential.to_plutus_data())
|
||||
}
|
||||
ScriptInfo::Certifying(ix, dcert) => {
|
||||
wrap_multiple_with_constr(3, vec![ix.to_plutus_data(), dcert.to_plutus_data()])
|
||||
}
|
||||
ScriptInfo::Certifying(ix, dcert) => wrap_multiple_with_constr(
|
||||
3,
|
||||
vec![
|
||||
ix.to_plutus_data(),
|
||||
WithNeverRegistrationDeposit(dcert).to_plutus_data(),
|
||||
],
|
||||
),
|
||||
ScriptInfo::Voting(voter) => wrap_multiple_with_constr(4, vec![voter.to_plutus_data()]),
|
||||
ScriptInfo::Proposing(ix, procedure) => {
|
||||
wrap_multiple_with_constr(5, vec![ix.to_plutus_data(), procedure.to_plutus_data()])
|
||||
|
@ -1311,11 +1354,11 @@ impl ToPlutusData for TxInfo {
|
|||
tx_info.outputs.to_plutus_data(),
|
||||
tx_info.fee.to_plutus_data(),
|
||||
tx_info.mint.to_plutus_data(),
|
||||
tx_info.certificates.to_plutus_data(),
|
||||
WithNeverRegistrationDeposit(&tx_info.certificates).to_plutus_data(),
|
||||
tx_info.withdrawals.to_plutus_data(),
|
||||
tx_info.valid_range.to_plutus_data(),
|
||||
tx_info.signatories.to_plutus_data(),
|
||||
tx_info.redeemers.to_plutus_data(),
|
||||
WithNeverRegistrationDeposit(&tx_info.redeemers).to_plutus_data(),
|
||||
tx_info.data.to_plutus_data(),
|
||||
tx_info.id.to_plutus_data(),
|
||||
tx_info.votes.to_plutus_data(),
|
||||
|
@ -1347,7 +1390,7 @@ impl ToPlutusData for ScriptContext {
|
|||
vec![
|
||||
tx_info.to_plutus_data(),
|
||||
redeemer.to_plutus_data(),
|
||||
purpose.to_plutus_data(),
|
||||
WithNeverRegistrationDeposit(purpose).to_plutus_data(),
|
||||
],
|
||||
),
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ pub fn filter(xs: List<a>, f: fn(a) -> Bool) -> List<a> {
|
|||
}
|
||||
|
||||
test filter_1() {
|
||||
filter([1,
|
||||
2, 3, 4, 5, 6], fn(x) { builtin.mod_integer(x, 2) == 0 }) == [2, 4, 6]
|
||||
filter([1, 2, 3, 4, 5, 6], fn(x) { builtin.mod_integer(x, 2) == 0 }) == [
|
||||
2, 4, 6,
|
||||
]
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
[[requirements]]
|
||||
name = "aiken-lang/stdlib"
|
||||
version = "main"
|
||||
version = "v2"
|
||||
source = "github"
|
||||
|
||||
[[packages]]
|
||||
name = "aiken-lang/stdlib"
|
||||
version = "main"
|
||||
version = "v2"
|
||||
requirements = []
|
||||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158432, nanos_since_epoch = 10066000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@v2" = [{ secs_since_epoch = 1724777134, nanos_since_epoch = 232157000 }, "cdbbce58b61deb385e7ea787a2e0fc2dc8fe94db9999e0e6275bc9c70e5796be"]
|
||||
|
|
|
@ -3,5 +3,5 @@ version = "0.0.0"
|
|||
|
||||
[[dependencies]]
|
||||
name = 'aiken-lang/stdlib'
|
||||
version = 'main'
|
||||
version = 'v2'
|
||||
source = 'github'
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
"plutusVersion": "v2",
|
||||
"compiler": {
|
||||
"name": "Aiken",
|
||||
"version": "v1.0.31-alpha+6e4a16d"
|
||||
"version": "v1.0.31-alpha+4003343"
|
||||
}
|
||||
},
|
||||
"validators": [
|
||||
{
|
||||
"title": "spend.mint",
|
||||
"title": "spend.bar.mint",
|
||||
"redeemer": {
|
||||
"title": "_redeemer",
|
||||
"schema": {
|
||||
|
@ -21,15 +21,28 @@
|
|||
{
|
||||
"title": "output_reference",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/aiken~1transaction~1OutputReference"
|
||||
"$ref": "#/definitions/cardano~1transaction~1OutputReference"
|
||||
}
|
||||
}
|
||||
],
|
||||
"compiledCode": "589e0100003232323232323222322533300553330053370e900018031baa3232330010013758600460126ea8c008c024dd50019129998058008a6103d87a800013232533300a3375e600a60186ea80080244cdd2a40006601c00497ae0133004004001300f002300d0012300b00114a229405261365653330033370e900018021baa00115333006300537540022930b0b2b9a5573aaae7955cfaba05742ae881",
|
||||
"hash": "0241f73ef186e53566d1b5a81eca50049b0d86833e6b88fe26b1e4bc"
|
||||
"compiledCode": "58c90100003232323232323222533300332323232325332330093001300a375400426464a666016600660186ea8c8c8cc004004dd6180118079baa00922533301100114c0103d87a80001323253330103375e600a60246ea800803c4cdd2a40006602800497ae0133004004001301500230130012301100114a229414ccc028c008c02cdd50020a99980698061baa00414985858dd7180718059baa002370e90000b1806180680118058009805801180480098029baa00114984d9595cd2ab9d5573caae7d5d02ba157441",
|
||||
"hash": "2edaecec5a072cd65b12395410ce6da7cafaffdf70506cbcb40b4df8"
|
||||
},
|
||||
{
|
||||
"title": "spend.spend",
|
||||
"title": "spend.bar.else",
|
||||
"parameters": [
|
||||
{
|
||||
"title": "output_reference",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/cardano~1transaction~1OutputReference"
|
||||
}
|
||||
}
|
||||
],
|
||||
"compiledCode": "58c90100003232323232323222533300332323232325332330093001300a375400426464a666016600660186ea8c8c8cc004004dd6180118079baa00922533301100114c0103d87a80001323253330103375e600a60246ea800803c4cdd2a40006602800497ae0133004004001301500230130012301100114a229414ccc028c008c02cdd50020a99980698061baa00414985858dd7180718059baa002370e90000b1806180680118058009805801180480098029baa00114984d9595cd2ab9d5573caae7d5d02ba157441",
|
||||
"hash": "2edaecec5a072cd65b12395410ce6da7cafaffdf70506cbcb40b4df8"
|
||||
},
|
||||
{
|
||||
"title": "spend.foo.spend",
|
||||
"datum": {
|
||||
"title": "_datum",
|
||||
"schema": {
|
||||
|
@ -42,8 +55,13 @@
|
|||
"$ref": "#/definitions/Data"
|
||||
}
|
||||
},
|
||||
"compiledCode": "58ef01000032323232323232222533300432330010013758601460166016600e6ea8c028c01cdd50011129998048008a501325333007333007533300a3253330083370e900118049baa00114bd6f7b63009bab300d300a375400264660020026eacc034c038c028dd518068019129998060008a60103d87a8000132323232533300d33722911050000000000000021533300d3371e91010500000000000000213374a9000198089ba60014bd700a6103d87a80001330060060033756601c0066eb8c030008c040008c0380045288a504a094452889980180180098060008a4c26cacae6955ceaab9e5573eae815d0aba21",
|
||||
"hash": "f56561e01063b11146809755d9907147e79d3166aa5c65fba4040fd1"
|
||||
"compiledCode": "5901230100003232323232323225333002323232323253330073370e900118041baa001132323232330010013758602060226022601a6ea8020894ccc03c0045280992999806999806a99980819299980719b8748008c03cdd50008a5eb7bdb1804dd5980998081baa001323300100137566026602860206ea8c04c00c894ccc048004530103d87a800013232323253330133372291105000000000000002153330133371e91010500000000000000213374a90001980b9ba60014bd700a6103d87a8000133006006003375660280066eb8c048008c058008c0500045288a504a0944528899801801800980900098071807801180680098049baa00116300b300c002300a001300a00230080013004375400229309b2b2b9a5573aaae7955cfaba05742ae881",
|
||||
"hash": "cf024265a1ff4ab129cef178c64b8c4cab25d62129242e01e29bb3d1"
|
||||
},
|
||||
{
|
||||
"title": "spend.foo.else",
|
||||
"compiledCode": "5901230100003232323232323225333002323232323253330073370e900118041baa001132323232330010013758602060226022601a6ea8020894ccc03c0045280992999806999806a99980819299980719b8748008c03cdd50008a5eb7bdb1804dd5980998081baa001323300100137566026602860206ea8c04c00c894ccc048004530103d87a800013232323253330133372291105000000000000002153330133371e91010500000000000000213374a90001980b9ba60014bd700a6103d87a8000133006006003375660280066eb8c048008c058008c0500045288a504a0944528899801801800980900098071807801180680098049baa00116300b300c002300a001300a00230080013004375400229309b2b2b9a5573aaae7955cfaba05742ae881",
|
||||
"hash": "cf024265a1ff4ab129cef178c64b8c4cab25d62129242e01e29bb3d1"
|
||||
}
|
||||
],
|
||||
"definitions": {
|
||||
|
@ -68,7 +86,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"aiken/transaction/OutputReference": {
|
||||
"cardano/transaction/OutputReference": {
|
||||
"title": "OutputReference",
|
||||
"description": "An `OutputReference` is a unique reference to an output on-chain. The `output_index`\n corresponds to the position in the output list of the transaction (identified by its id)\n that produced that output",
|
||||
"anyOf": [
|
||||
|
@ -79,7 +97,7 @@
|
|||
"fields": [
|
||||
{
|
||||
"title": "transaction_id",
|
||||
"$ref": "#/definitions/aiken~1transaction~1TransactionId"
|
||||
"$ref": "#/definitions/ByteArray"
|
||||
},
|
||||
{
|
||||
"title": "output_index",
|
||||
|
@ -88,23 +106,6 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"aiken/transaction/TransactionId": {
|
||||
"title": "TransactionId",
|
||||
"description": "A unique transaction identifier, as the hash of a transaction body. Note that the transaction id\n isn't a direct hash of the `Transaction` as visible on-chain. Rather, they correspond to hash\n digests of transaction body as they are serialized on the network.",
|
||||
"anyOf": [
|
||||
{
|
||||
"title": "TransactionId",
|
||||
"dataType": "constructor",
|
||||
"index": 0,
|
||||
"fields": [
|
||||
{
|
||||
"title": "hash",
|
||||
"$ref": "#/definitions/ByteArray"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +1,33 @@
|
|||
use aiken/dict
|
||||
use aiken/list
|
||||
use aiken/transaction.{Output, OutputReference, ScriptContext}
|
||||
use aiken/transaction/value.{PolicyId}
|
||||
use aiken/collection/dict
|
||||
use aiken/collection/list
|
||||
use cardano/assets.{PolicyId}
|
||||
use cardano/transaction.{Output, OutputReference, Transaction}
|
||||
|
||||
const my_policy_id: PolicyId = #"0000000000"
|
||||
|
||||
pub fn has_policy_id(self: Output, policy_id: PolicyId) -> Bool {
|
||||
self.value
|
||||
|> value.tokens(policy_id)
|
||||
|> assets.tokens(policy_id)
|
||||
|> dict.is_empty
|
||||
|> not
|
||||
}
|
||||
|
||||
validator {
|
||||
fn spend(_datum: Data, _redeemer: Data, ctx: ScriptContext) -> Bool {
|
||||
ctx.transaction.outputs
|
||||
validator foo {
|
||||
spend(_datum: Option<Data>, _redeemer: Data, _o_ref: Data, self: Transaction) {
|
||||
self.outputs
|
||||
|> list.any(has_policy_id(_, my_policy_id))
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
||||
validator(output_reference: OutputReference) {
|
||||
fn mint(_redeemer: Void, ctx: ScriptContext) -> Bool {
|
||||
validator bar(output_reference: OutputReference) {
|
||||
mint(_redeemer: Void, _policy_id, self: Transaction) {
|
||||
when
|
||||
list.find(
|
||||
ctx.transaction.inputs,
|
||||
self.inputs,
|
||||
fn(input) { input.output_reference == output_reference },
|
||||
)
|
||||
is {
|
||||
|
@ -31,4 +35,8 @@ validator(output_reference: OutputReference) {
|
|||
None -> False
|
||||
}
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ test expect_ford1() {
|
|||
],
|
||||
)
|
||||
expect Ford { owner, wheels, truck_bed_limit, .. }: Car = initial_car
|
||||
owner == #"" && ( wheels == 4 && truck_bed_limit == 10000 )
|
||||
owner == #"" && wheels == 4 && truck_bed_limit == 10000
|
||||
}
|
||||
|
||||
test expect_ford2() {
|
||||
|
@ -42,14 +42,14 @@ test expect_ford2() {
|
|||
car_doors: [],
|
||||
}
|
||||
expect Ford { owner, wheels, remote_connect, .. } = initial_car
|
||||
owner == #"2222222222" && ( wheels == 6 && remote_connect == #"" )
|
||||
owner == #"2222222222" && wheels == 6 && remote_connect == #""
|
||||
}
|
||||
|
||||
test expect_list1() {
|
||||
let initial_car =
|
||||
[5, 6, 7]
|
||||
expect [a, b, c] = initial_car
|
||||
a == 5 && ( b == 6 && c == 7 )
|
||||
a == 5 && b == 6 && c == 7
|
||||
}
|
||||
|
||||
test expect_list2() {
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
"plutusVersion": "v2",
|
||||
"compiler": {
|
||||
"name": "Aiken",
|
||||
"version": "v1.0.31-alpha+6e4a16d"
|
||||
"version": "v1.0.31-alpha+4003343"
|
||||
}
|
||||
},
|
||||
"validators": [
|
||||
{
|
||||
"title": "foo.spend",
|
||||
"title": "foo.foo.spend",
|
||||
"datum": {
|
||||
"title": "_datum",
|
||||
"schema": {
|
||||
|
@ -23,8 +23,13 @@
|
|||
"$ref": "#/definitions/Void"
|
||||
}
|
||||
},
|
||||
"compiledCode": "585201000032323232232232253330064a229309b2b299980219b8748000c014dd50008a99980398031baa001149858594ccc008cdc3a400060066ea800454ccc014c010dd50008a4c2c2cae6955ceaab9e5573f",
|
||||
"hash": "84a516ff1f146f698164b5e64ff813e4e22ba2fa35491f2dc3d70935"
|
||||
"compiledCode": "587601000032323232323225333002323232323253330073370e900118041baa0011323232324a2a66601466e1d2000300b375400a2a66601a60186ea80145261616300d300e002300c001300937540022c6014601600460120026012004600e00260086ea8004526136565734aae7555cf2ab9f5742ae89",
|
||||
"hash": "c613c8326fea00dff179b7108f248b60c155881bbce544d84fe573e1"
|
||||
},
|
||||
{
|
||||
"title": "foo.foo.else",
|
||||
"compiledCode": "587601000032323232323225333002323232323253330073370e900118041baa0011323232324a2a66601466e1d2000300b375400a2a66601a60186ea80145261616300d300e002300c001300937540022c6014601600460120026012004600e00260086ea8004526136565734aae7555cf2ab9f5742ae89",
|
||||
"hash": "c613c8326fea00dff179b7108f248b60c155881bbce544d84fe573e1"
|
||||
}
|
||||
],
|
||||
"definitions": {
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
validator {
|
||||
fn spend(_datum: Void, _redeemer: Void, _ctx: Void) -> Bool {
|
||||
validator foo {
|
||||
spend(_datum: Option<Void>, _redeemer: Void, oref: Data, _tx: Void) {
|
||||
True
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
||||
test foo() {
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158433, nanos_since_epoch = 380614000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776969, nanos_since_epoch = 835808000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158435, nanos_since_epoch = 363713000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776974, nanos_since_epoch = 866167000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158434, nanos_since_epoch = 837171000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776995, nanos_since_epoch = 750600000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158435, nanos_since_epoch = 367316000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776974, nanos_since_epoch = 455232000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158436, nanos_since_epoch = 571367000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724777001, nanos_since_epoch = 587403000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -322,7 +322,7 @@ test get_proof_4() {
|
|||
let h1: ByteArray = get_proof_item_value(p1)
|
||||
let h2: ByteArray = get_proof_item_value(p2)
|
||||
|
||||
size_match && ( h1 == hash_fn(cat) && h2 == right_node_hash )
|
||||
size_match && h1 == hash_fn(cat) && h2 == right_node_hash
|
||||
}
|
||||
|
||||
fn do_from_list(
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158436, nanos_since_epoch = 551807000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776997, nanos_since_epoch = 900786000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158435, nanos_since_epoch = 941669000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724777000, nanos_since_epoch = 47370000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158437, nanos_since_epoch = 43333000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776959, nanos_since_epoch = 949879000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
[[requirements]]
|
||||
name = "aiken-lang/stdlib"
|
||||
version = "main"
|
||||
version = "v2"
|
||||
source = "github"
|
||||
|
||||
[[packages]]
|
||||
name = "aiken-lang/stdlib"
|
||||
version = "main"
|
||||
version = "v2"
|
||||
requirements = []
|
||||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158434, nanos_since_epoch = 487166000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@v2" = [{ secs_since_epoch = 1724776963, nanos_since_epoch = 265617000 }, "cdbbce58b61deb385e7ea787a2e0fc2dc8fe94db9999e0e6275bc9c70e5796be"]
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
name = "aiken-lang/acceptance_test_071"
|
||||
plutusVersion = "v3"
|
||||
version = "0.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
name = 'aiken-lang/stdlib'
|
||||
version = 'main'
|
||||
version = 'v2'
|
||||
source = 'github'
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
"plutusVersion": "v2",
|
||||
"compiler": {
|
||||
"name": "Aiken",
|
||||
"version": "v1.0.31-alpha+6e4a16d"
|
||||
"version": "v1.0.31-alpha+4003343"
|
||||
}
|
||||
},
|
||||
"validators": [
|
||||
{
|
||||
"title": "spend.pool_contract",
|
||||
"title": "spend.foo.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
|
@ -23,8 +23,13 @@
|
|||
"$ref": "#/definitions/spend~1PoolRedeemer"
|
||||
}
|
||||
},
|
||||
"compiledCode": "5904170100003232323232323232232325333004300230053754006264a6660100022c264a66666601a002264a6660140022c264a66666601e0022c2c2c26464a66601a0022c264a6666660240022c2c2c264a66601e6024006266601200e24a66601a6016601c6ea80044c94ccc044004584c94cccccc05800454ccc048c0540084c8c8c94ccc048c0400044c94ccc058004584c94cccccc06c0045858584c94ccc060c06c00c5401458dd68008b180c000980a1baa004153330123003001132533301600116132533333301b00115333017301a00215333014301230153754002264a6660300022c264a66666603a002264a6660340022c264a66666603e0022c2c2c264a666038603e006266602c0082a0122c2c6eb400458c070004c07000858585858c068004c058dd50008b0b0b0b0b0b180c000980a1baa004153330123370e9002000899299980b0008b099299999980d8008a99980b980d0010a99980a1809180a9baa001132533301800116132533333301d001132533301a00116132533333301f001161616132533301c301f0031333016004150091616375a0022c603800260380042c2c2c2c6034002602c6ea8004585858585858c060004c050dd50020b18091baa0031253330113232325333014301200114a226464646464a666032601400c26464a666036601860386ea80044c8c8c94ccc078c070c07cdd5000899192999810180f18109baa0011324a2604a60446ea800458cc01c03c00cc08cc080dd50008b198038068009804244101ff003020301d37540022940c00cc070dd5005180f180d9baa00713232533301b300c301c37540022646464a66603c6038603e6ea80044c8c94ccc080c078c084dd50008992513025302237540022c6600e01e006604660406ea800458cc01c034004c021220101ff003020301d37540022940c00cc070dd5005180f180d9baa00722330053758601260386ea8c024c070dd5001119baf300a301d37546008603a6ea80040088c074c07800488cc00cdd6180e980f180f180d1baa3007301a3754004466ebcc020c06cdd500080111191980080080191299980e0008a6103d87a800013232533301b300500213374a90001980f80125eb804cc010010004c080008c0780048cdd2a40006603266e95200233019375200297ae0330194c103d87a80004bd70180a1baa00130013014375400c4602e00229309b2b1b87480085858585858c04c004c03cdd50008b0b0b1bad00116300f001300f003375a0022c601800260180042c2c2c2c6014002600c6ea800c588894ccc018c010c01cdd5001899299980500080109929999998078008018018018018991929998068008028992999999809000803003003003099299980798090018a8040039bae001300f001300f003375c002601800260106ea800c004dc3a4000ae6955ceaab9e5573eae815d0aba25749",
|
||||
"hash": "640debfa5063d2e3fd7f23e9777aaf3a0f575a99972ccda8748a49c0"
|
||||
"compiledCode": "5903a2010000323232323232323225333002323232323253323300830013009375400426464646464a66601a6004601c6ea80204c94ccc044004584c94cccccc05800454ccc048c0540084c8c94ccc044c0180044c94ccc054004584c94cccccc0680045858584c94ccc05cc06800c5401458dd68008b180b80098099baa00315333011300a001132533301500116132533333301a00115333016301900215333013300830143754002264a66602e0022c264a666666038002264a6660320022c264a66666603c0022c2c2c264a666036603c00626660180082a0122c2c6eb400458c06c004c06c00858585858c064004c054dd50008b0b0b0b0b0b180b80098099baa003153330113370e9002000899299980a8008b099299999980d0008a99980b180c8010a9998099804180a1baa001132533301700116132533333301c001132533301900116132533333301e001161616132533301b301e003133300c004150091616375a0022c603600260360042c2c2c2c6032002602a6ea8004585858585858c05c004c04cdd50018b18089baa0021533300f30043010375400a264646464a666026601000229444c8c8c8c94ccc05cc0400144c8c8c94ccc068c03cc06cdd500089919299980e1808980e9baa0011324a26042603c6ea800458cc01406000cc07cc070dd50008b1980200b0009802a44101ff00301c3019375400c2646464a666034601e60366ea80044c8c94ccc070c044c074dd50008992513021301e37540022c6600a030006603e60386ea800458cc010058004c015220101ff00301c3019375400c44660086eb0c020c068dd5001119baf3009301b3754603c603e60366ea800400888cc00cdd6180e180e980e980c9baa00223375e601060346ea800400888c8cc00400400c894ccc06c004530103d87a800013232533301a300500213374a90001980f00125eb804cc010010004c07c008c0740048cdd2a40006603066e95200233018375200297ae0330184c103d87a80004bd7018099baa0013001301337540184602c002602860226ea8014585858585858c04c004c03cdd50040b1112999807980218081baa00313253330130010021325333333018001003003003003132325333016001005132533333301b0010060060060061325333018301b00315008007375c002603000260300066eb8004c054004c044dd50018009b8748000c03cc040008c038004c028dd50011b874800858c02cc030008c028004c028008c020004c010dd50008a4c26cacae6955ceaab9e5573eae815d0aba257481",
|
||||
"hash": "10e8faa163e7c7699b978c2df5f2b1fadc9796e866d67b88799def6e"
|
||||
},
|
||||
{
|
||||
"title": "spend.foo.else",
|
||||
"compiledCode": "5903a2010000323232323232323225333002323232323253323300830013009375400426464646464a66601a6004601c6ea80204c94ccc044004584c94cccccc05800454ccc048c0540084c8c94ccc044c0180044c94ccc054004584c94cccccc0680045858584c94ccc05cc06800c5401458dd68008b180b80098099baa00315333011300a001132533301500116132533333301a00115333016301900215333013300830143754002264a66602e0022c264a666666038002264a6660320022c264a66666603c0022c2c2c264a666036603c00626660180082a0122c2c6eb400458c06c004c06c00858585858c064004c054dd50008b0b0b0b0b0b180b80098099baa003153330113370e9002000899299980a8008b099299999980d0008a99980b180c8010a9998099804180a1baa001132533301700116132533333301c001132533301900116132533333301e001161616132533301b301e003133300c004150091616375a0022c603600260360042c2c2c2c6032002602a6ea8004585858585858c05c004c04cdd50018b18089baa0021533300f30043010375400a264646464a666026601000229444c8c8c8c94ccc05cc0400144c8c8c94ccc068c03cc06cdd500089919299980e1808980e9baa0011324a26042603c6ea800458cc01406000cc07cc070dd50008b1980200b0009802a44101ff00301c3019375400c2646464a666034601e60366ea80044c8c94ccc070c044c074dd50008992513021301e37540022c6600a030006603e60386ea800458cc010058004c015220101ff00301c3019375400c44660086eb0c020c068dd5001119baf3009301b3754603c603e60366ea800400888cc00cdd6180e180e980e980c9baa00223375e601060346ea800400888c8cc00400400c894ccc06c004530103d87a800013232533301a300500213374a90001980f00125eb804cc010010004c07c008c0740048cdd2a40006603066e95200233018375200297ae0330184c103d87a80004bd7018099baa0013001301337540184602c002602860226ea8014585858585858c04c004c03cdd50040b1112999807980218081baa00313253330130010021325333333018001003003003003132325333016001005132533333301b0010060060060061325333018301b00315008007375c002603000260300066eb8004c054004c044dd50018009b8748000c03cc040008c038004c028dd50011b874800858c02cc030008c028004c028008c020004c010dd50008a4c26cacae6955ceaab9e5573eae815d0aba257481",
|
||||
"hash": "10e8faa163e7c7699b978c2df5f2b1fadc9796e866d67b88799def6e"
|
||||
}
|
||||
],
|
||||
"definitions": {
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
use aiken/collection/list
|
||||
use aiken/hash.{Blake2b_224, Hash}
|
||||
use aiken/interval.{Finite}
|
||||
use aiken/list
|
||||
use aiken/option
|
||||
use aiken/transaction.{
|
||||
Datum, InlineDatum, Input, Mint, Output, OutputReference, ScriptContext, Spend,
|
||||
Transaction, TransactionId, ValidityRange,
|
||||
}
|
||||
use aiken/transaction/credential.{
|
||||
Address, Script, ScriptCredential, VerificationKey, VerificationKeyCredential,
|
||||
}
|
||||
use aiken/transaction/value.{
|
||||
use cardano/assets.{
|
||||
AssetName, PolicyId, Value, add, flatten, from_asset, negate, quantity_of,
|
||||
}
|
||||
use cardano/credential.{Address, Script, VerificationKey}
|
||||
use cardano/transaction.{
|
||||
Datum, InlineDatum, Input, Output, OutputReference, Transaction, TransactionId,
|
||||
ValidityRange,
|
||||
}
|
||||
|
||||
// Datum/Redeemer pool
|
||||
pub type PoolDatum {
|
||||
|
@ -20,7 +18,7 @@ pub type PoolDatum {
|
|||
lent_out: Int,
|
||||
}
|
||||
|
||||
type PoolRedeemer {
|
||||
pub type PoolRedeemer {
|
||||
action: PoolRedeemerType,
|
||||
}
|
||||
|
||||
|
@ -45,67 +43,73 @@ pub type CurrencySymbol {
|
|||
asset_name: AssetName,
|
||||
}
|
||||
|
||||
pub fn get_output(ctx: ScriptContext, address: Address) -> Option<Output> {
|
||||
list.find(ctx.transaction.outputs, fn(output) { output.address == address })
|
||||
pub fn get_output(transaction: Transaction, address: Address) -> Option<Output> {
|
||||
list.find(transaction.outputs, fn(output) { output.address == address })
|
||||
}
|
||||
|
||||
pub fn get_input(ctx: ScriptContext, address: Address) -> Option<Input> {
|
||||
list.find(
|
||||
ctx.transaction.inputs,
|
||||
fn(input) { input.output.address == address },
|
||||
)
|
||||
pub fn get_input(transaction: Transaction, address: Address) -> Option<Input> {
|
||||
list.find(transaction.inputs, fn(input) { input.output.address == address })
|
||||
}
|
||||
|
||||
pub fn scripthash_address(scripthash: ByteArray) {
|
||||
Address {
|
||||
payment_credential: ScriptCredential(scripthash),
|
||||
stake_credential: None,
|
||||
}
|
||||
Address { payment_credential: Script(scripthash), stake_credential: None }
|
||||
}
|
||||
|
||||
pub fn validate_pool_deposit(
|
||||
ctx: ScriptContext,
|
||||
transaction: Transaction,
|
||||
output_reference: OutputReference,
|
||||
datum: PoolDatum,
|
||||
redeemer: PoolDepositRedeemer,
|
||||
) -> Bool {
|
||||
let validator_address = scripthash_address(#"ff")
|
||||
|
||||
expect Some(pool_output) = get_output(ctx, validator_address)
|
||||
expect Some(pool_input) = get_input(ctx, validator_address)
|
||||
expect Some(pool_output) = get_output(transaction, validator_address)
|
||||
expect Some(pool_input) = get_input(transaction, validator_address)
|
||||
|
||||
True
|
||||
}
|
||||
|
||||
pub fn validate_pool_borrow(
|
||||
ctx: ScriptContext,
|
||||
transaction: Transaction,
|
||||
output_reference: OutputReference,
|
||||
datum: PoolDatum,
|
||||
redeemer: PoolBorrowRedeemer,
|
||||
) -> Bool {
|
||||
let validator_address = scripthash_address(#"ff")
|
||||
|
||||
expect Some(pool_output) = get_output(ctx, validator_address)
|
||||
expect Some(pool_input) = get_input(ctx, validator_address)
|
||||
expect Some(pool_output) = get_output(transaction, validator_address)
|
||||
expect Some(pool_input) = get_input(transaction, validator_address)
|
||||
True
|
||||
}
|
||||
|
||||
validator {
|
||||
fn pool_contract(datum: PoolDatum, redeemer: PoolRedeemer, ctx: ScriptContext) {
|
||||
validator foo {
|
||||
spend(
|
||||
datum: Option<PoolDatum>,
|
||||
redeemer: PoolRedeemer,
|
||||
output_ref: OutputReference,
|
||||
transaction: Transaction,
|
||||
) {
|
||||
expect Some(datum) = datum
|
||||
when redeemer.action is {
|
||||
PoolWithdraw(_) -> True
|
||||
PoolDeposit(pool_deposit_redeemer) ->
|
||||
when ctx.purpose is {
|
||||
Spend(output_ref) ->
|
||||
validate_pool_deposit(ctx, output_ref, datum, pool_deposit_redeemer)
|
||||
_ -> False
|
||||
}
|
||||
validate_pool_deposit(
|
||||
transaction,
|
||||
output_ref,
|
||||
datum,
|
||||
pool_deposit_redeemer,
|
||||
)
|
||||
PoolBorrow(pool_borrow_redeemer) ->
|
||||
when ctx.purpose is {
|
||||
Spend(output_ref) ->
|
||||
validate_pool_borrow(ctx, output_ref, datum, pool_borrow_redeemer)
|
||||
_ -> False
|
||||
}
|
||||
validate_pool_borrow(
|
||||
transaction,
|
||||
output_ref,
|
||||
datum,
|
||||
pool_borrow_redeemer,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158434, nanos_since_epoch = 466737000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776989, nanos_since_epoch = 656788000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158432, nanos_since_epoch = 54533000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776984, nanos_since_epoch = 618944000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158437, nanos_since_epoch = 127361000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776985, nanos_since_epoch = 375340000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
[[requirements]]
|
||||
name = "aiken-lang/stdlib"
|
||||
version = "main"
|
||||
version = "v2"
|
||||
source = "github"
|
||||
|
||||
[[packages]]
|
||||
name = "aiken-lang/stdlib"
|
||||
version = "main"
|
||||
version = "v2"
|
||||
requirements = []
|
||||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158435, nanos_since_epoch = 59914000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@v2" = [{ secs_since_epoch = 1724776958, nanos_since_epoch = 450634000 }, "cdbbce58b61deb385e7ea787a2e0fc2dc8fe94db9999e0e6275bc9c70e5796be"]
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
name = "aiken-lang/acceptance_test_077"
|
||||
plutusVersion = "v3"
|
||||
version = "0.0.0"
|
||||
|
||||
[[dependencies]]
|
||||
name = 'aiken-lang/stdlib'
|
||||
version = 'main'
|
||||
version = 'v2'
|
||||
source = 'github'
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
"plutusVersion": "v2",
|
||||
"compiler": {
|
||||
"name": "Aiken",
|
||||
"version": "v1.0.31-alpha+6e4a16d"
|
||||
"version": "v1.0.31-alpha+4003343"
|
||||
}
|
||||
},
|
||||
"validators": [
|
||||
{
|
||||
"title": "spend.gift_card",
|
||||
"title": "spend.foo.mint",
|
||||
"redeemer": {
|
||||
"title": "rdmr",
|
||||
"schema": {
|
||||
|
@ -27,15 +27,34 @@
|
|||
{
|
||||
"title": "utxo_ref",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/aiken~1transaction~1OutputReference"
|
||||
"$ref": "#/definitions/cardano~1transaction~1OutputReference"
|
||||
}
|
||||
}
|
||||
],
|
||||
"compiledCode": "5901ce010000323232323232322322232323232533300930040011533300c300b375400a2a0042c2a66601260060022a66601860166ea8014540085858c024dd50020929998041919192999805980318061baa00113232323253330123015002132325333011300c3012375401a2a666022646600200200c44a66602c00229404c94ccc050cdd7980c980b1baa301900201114a226600600600260320022a6660226016002266e3c00803c5280b0b1bad3012002375c60200022c602600264a66601c6010601e6ea800452f5bded8c026eacc04cc040dd500099191980080099198008009bab3015301630163016301600522533301400114bd6f7b630099191919299980a99b9148900002153330153371e91010000210031005133019337606ea4008dd3000998030030019bab3016003375c60280046030004602c00244a666026002298103d87a800013232323253330143372200e0042a66602866e3c01c0084cdd2a4000660306e980052f5c02980103d87a80001330060060033756602a0066eb8c04c008c05c008c054004dd7180918079baa00337586022002601a6ea800858c03cc040008c038004c028dd50008a4c26cac6e1d2002370e90001bae0015734aae7555cf2ab9f5740ae855d11",
|
||||
"hash": "4ef9bf69c108d6abd0a5af057a519df56d7fb333de428563810495a0"
|
||||
"compiledCode": "59018501000032323232323232232225333005323232323253323300b3001300c3754004264646464a66601e600a0022a66602460226ea801c540085854ccc03cc00c00454ccc048c044dd50038a8010b0b18079baa006132323232533301430170021323253330133009301437540162a666026646600200200c44a66603000229404c94ccc058cdd7980d980c1baa301b00201314a226600600600260360022a666026600e002266e3c0080445280b0b1bad3014002375c60240022c602a00264a666020600860226ea800452f5bded8c026eacc054c048dd500099198008009bab3015301630163016301600322533301400114c103d87a80001323232325333015337220140042a66602a66e3c0280084cdd2a4000660326e980052f5c02980103d87a80001330060060033756602c0066eb8c050008c060008c058004dd6180980098079baa007370e90011bae3010300d37540046e1d200016300e300f002300d001300d002300b0013007375400229309b2b1bae0015734aae7555cf2ab9f5740ae855d11",
|
||||
"hash": "784b2caa5e99b3d37361e3c3d51e7fd39f616025037eee525b73c5da"
|
||||
},
|
||||
{
|
||||
"title": "spend2.backtrace",
|
||||
"title": "spend.foo.else",
|
||||
"parameters": [
|
||||
{
|
||||
"title": "token_name",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ByteArray"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "utxo_ref",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/cardano~1transaction~1OutputReference"
|
||||
}
|
||||
}
|
||||
],
|
||||
"compiledCode": "59018501000032323232323232232225333005323232323253323300b3001300c3754004264646464a66601e600a0022a66602460226ea801c540085854ccc03cc00c00454ccc048c044dd50038a8010b0b18079baa006132323232533301430170021323253330133009301437540162a666026646600200200c44a66603000229404c94ccc058cdd7980d980c1baa301b00201314a226600600600260360022a666026600e002266e3c0080445280b0b1bad3014002375c60240022c602a00264a666020600860226ea800452f5bded8c026eacc054c048dd500099198008009bab3015301630163016301600322533301400114c103d87a80001323232325333015337220140042a66602a66e3c0280084cdd2a4000660326e980052f5c02980103d87a80001330060060033756602c0066eb8c050008c060008c058004dd6180980098079baa007370e90011bae3010300d37540046e1d200016300e300f002300d001300d002300b0013007375400229309b2b1bae0015734aae7555cf2ab9f5740ae855d11",
|
||||
"hash": "784b2caa5e99b3d37361e3c3d51e7fd39f616025037eee525b73c5da"
|
||||
},
|
||||
{
|
||||
"title": "spend2.foo.spend",
|
||||
"datum": {
|
||||
"title": "_datum",
|
||||
"schema": {
|
||||
|
@ -48,8 +67,13 @@
|
|||
"$ref": "#/definitions/Void"
|
||||
}
|
||||
},
|
||||
"compiledCode": "58ac010000323232323232322323223225333007533300730053008375464660020026eb0c034c038c038c028dd5180698051baa00222533300c00114c0103d87a800013232533300b4a2266e9520003300f0024bd70099802002000980800118070008a511614984d9594ccc014c00cc018dd50008a99980418039baa001149858594ccc00cc004c010dd50010a99980318029baa00214985858dc3a4000ae6955ceaab9e5573eae815d0aba201",
|
||||
"hash": "c58d31e63ad2d807c2188dfb1deafc433fe0f6a867e5cf8df68f068f"
|
||||
"compiledCode": "58c70100003232323232323225333002323232323253330073370e900118041baa001132323232533300b3370e900018061baa32330010013758602260246024601c6ea8024894ccc0400045300103d87a800013232533300f4a2266e952000330130024bd70099802002000980a00118090008a5116533300a3370e900018059baa0051533300d300c375400a2930b0b18071807801180680098049baa00116300b300c002300a001300a00230080013004375400229309b2b2b9a5573aaae7955cfaba05742ae881",
|
||||
"hash": "c4700bfdb383c890d2a4c4505d3fc6d4b51e1998c3f33dd83e12ba44"
|
||||
},
|
||||
{
|
||||
"title": "spend2.foo.else",
|
||||
"compiledCode": "58c70100003232323232323225333002323232323253330073370e900118041baa001132323232533300b3370e900018061baa32330010013758602260246024601c6ea8024894ccc0400045300103d87a800013232533300f4a2266e952000330130024bd70099802002000980a00118090008a5116533300a3370e900018059baa0051533300d300c375400a2930b0b18071807801180680098049baa00116300b300c002300a001300a00230080013004375400229309b2b2b9a5573aaae7955cfaba05742ae881",
|
||||
"hash": "c4700bfdb383c890d2a4c4505d3fc6d4b51e1998c3f33dd83e12ba44"
|
||||
}
|
||||
],
|
||||
"definitions": {
|
||||
|
@ -70,7 +94,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"aiken/transaction/OutputReference": {
|
||||
"cardano/transaction/OutputReference": {
|
||||
"title": "OutputReference",
|
||||
"description": "An `OutputReference` is a unique reference to an output on-chain. The `output_index`\n corresponds to the position in the output list of the transaction (identified by its id)\n that produced that output",
|
||||
"anyOf": [
|
||||
|
@ -81,7 +105,7 @@
|
|||
"fields": [
|
||||
{
|
||||
"title": "transaction_id",
|
||||
"$ref": "#/definitions/aiken~1transaction~1TransactionId"
|
||||
"$ref": "#/definitions/ByteArray"
|
||||
},
|
||||
{
|
||||
"title": "output_index",
|
||||
|
@ -91,23 +115,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"aiken/transaction/TransactionId": {
|
||||
"title": "TransactionId",
|
||||
"description": "A unique transaction identifier, as the hash of a transaction body. Note that the transaction id\n isn't a direct hash of the `Transaction` as visible on-chain. Rather, they correspond to hash\n digests of transaction body as they are serialized on the network.",
|
||||
"anyOf": [
|
||||
{
|
||||
"title": "TransactionId",
|
||||
"dataType": "constructor",
|
||||
"index": 0,
|
||||
"fields": [
|
||||
{
|
||||
"title": "hash",
|
||||
"$ref": "#/definitions/ByteArray"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"spend/Action": {
|
||||
"title": "Action",
|
||||
"anyOf": [
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
use aiken/dict
|
||||
use aiken/list.{find, foldr}
|
||||
use aiken/transaction.{Input,
|
||||
OutputReference, ScriptContext, Spend, Transaction} as tx
|
||||
use aiken/transaction/value.{add, zero}
|
||||
use aiken/collection/dict
|
||||
use aiken/collection/list.{find, foldr}
|
||||
use cardano/assets.{PolicyId, add, zero}
|
||||
use cardano/transaction.{Input, OutputReference, Transaction} as tx
|
||||
|
||||
type Action {
|
||||
pub type Action {
|
||||
Mint
|
||||
Burn
|
||||
}
|
||||
|
||||
validator(token_name: ByteArray, utxo_ref: OutputReference) {
|
||||
fn gift_card(rdmr: Action, ctx: ScriptContext) -> Bool {
|
||||
let ScriptContext { transaction, purpose } = ctx
|
||||
expect tx.Mint(policy_id) = purpose
|
||||
validator foo(token_name: ByteArray, utxo_ref: OutputReference) {
|
||||
mint(rdmr: Action, policy_id: PolicyId, transaction: Transaction) {
|
||||
let Transaction { inputs, mint, .. } = transaction
|
||||
expect [Pair(asset_name, amount)] =
|
||||
mint
|
||||
|> value.from_minted_value
|
||||
|> value.tokens(policy_id)
|
||||
|> assets.tokens(policy_id)
|
||||
|> dict.to_pairs()
|
||||
when rdmr is {
|
||||
Mint -> {
|
||||
|
@ -28,4 +24,8 @@ validator(token_name: ByteArray, utxo_ref: OutputReference) {
|
|||
Burn -> todo @"burn"
|
||||
}
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,24 @@
|
|||
use aiken/list
|
||||
use aiken/transaction.{Output, ScriptContext}
|
||||
use aiken/collection/list
|
||||
use cardano/transaction.{Output, Transaction}
|
||||
|
||||
validator {
|
||||
fn backtrace(_datum: Void, _redeemer: Void, context: ScriptContext) -> Bool {
|
||||
expect Some(_) = list.find(context.transaction.outputs, fn(_) { True })
|
||||
let _ = find_stuff(context)
|
||||
validator foo {
|
||||
spend(
|
||||
_datum: Option<Void>,
|
||||
_redeemer: Void,
|
||||
_ref: Data,
|
||||
transaction: Transaction,
|
||||
) {
|
||||
expect Some(_) = list.find(transaction.outputs, fn(_) { True })
|
||||
let _ = find_stuff(transaction)
|
||||
True
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
||||
fn find_stuff(context: ScriptContext) -> Output {
|
||||
expect Some(stuff) = list.find(context.transaction.outputs, fn(_) { True })
|
||||
fn find_stuff(transaction: Transaction) -> Output {
|
||||
expect Some(stuff) = list.find(transaction.outputs, fn(_) { True })
|
||||
stuff
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
"plutusVersion": "v2",
|
||||
"compiler": {
|
||||
"name": "Aiken",
|
||||
"version": "v1.0.31-alpha+6e4a16d"
|
||||
"version": "v1.0.31-alpha+4003343"
|
||||
}
|
||||
},
|
||||
"validators": [
|
||||
{
|
||||
"title": "foo.spend",
|
||||
"title": "foo.foo.spend",
|
||||
"datum": {
|
||||
"title": "datum",
|
||||
"schema": {
|
||||
|
@ -20,42 +20,32 @@
|
|||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/RedeemerWrapper$Int"
|
||||
"$ref": "#/definitions/Int"
|
||||
}
|
||||
},
|
||||
"compiledCode": "5850010000323232322253330033370e900018021baa001153330033370e6eb4009205414984d9584c8c894ccc018cdc399b800030024815052613656375a600e600c6ea8008dd68012b9a5573aaae795d09",
|
||||
"hash": "dcac7ebcaf29721b4b48cc73775fa91939ad9015ea267b697e92b051"
|
||||
"compiledCode": "589a01000032323232322533300232323232323253330083370e9001000899191919299980619b8748000c034dd5001099b87337006eb4c03cc038dd5001000a40a82c6eb4018c034c038008c030004c028dd50010a99980419b87480000044c8cdc39bad00448150dd7180598051baa00216300837540026012601400460100026010004600c00260086ea8004526136565734aae7555cf2ba15745",
|
||||
"hash": "86f0253dd8dd836d6588f5794eb8f08edd4476df28b607553126846e"
|
||||
},
|
||||
{
|
||||
"title": "foo.mint",
|
||||
"title": "foo.foo.mint",
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Int"
|
||||
}
|
||||
},
|
||||
"compiledCode": "5850010000323232322253330033370e900018021baa001153330033370e6eb4009205414984d9584c8c894ccc018cdc399b800030024815052613656375a600e600c6ea8008dd68012b9a5573aaae795d09",
|
||||
"hash": "dcac7ebcaf29721b4b48cc73775fa91939ad9015ea267b697e92b051"
|
||||
"compiledCode": "589a01000032323232322533300232323232323253330083370e9001000899191919299980619b8748000c034dd5001099b87337006eb4c03cc038dd5001000a40a82c6eb4018c034c038008c030004c028dd50010a99980419b87480000044c8cdc39bad00448150dd7180598051baa00216300837540026012601400460100026010004600c00260086ea8004526136565734aae7555cf2ba15745",
|
||||
"hash": "86f0253dd8dd836d6588f5794eb8f08edd4476df28b607553126846e"
|
||||
},
|
||||
{
|
||||
"title": "foo.foo.else",
|
||||
"compiledCode": "589a01000032323232322533300232323232323253330083370e9001000899191919299980619b8748000c034dd5001099b87337006eb4c03cc038dd5001000a40a82c6eb4018c034c038008c030004c028dd50010a99980419b87480000044c8cdc39bad00448150dd7180598051baa00216300837540026012601400460100026010004600c00260086ea8004526136565734aae7555cf2ba15745",
|
||||
"hash": "86f0253dd8dd836d6588f5794eb8f08edd4476df28b607553126846e"
|
||||
}
|
||||
],
|
||||
"definitions": {
|
||||
"Int": {
|
||||
"dataType": "integer"
|
||||
},
|
||||
"RedeemerWrapper$Int": {
|
||||
"title": "Wrapped Redeemer",
|
||||
"description": "A redeemer wrapped in an extra constructor to make multi-validator detection possible on-chain.",
|
||||
"anyOf": [
|
||||
{
|
||||
"dataType": "constructor",
|
||||
"index": 1,
|
||||
"fields": [
|
||||
{
|
||||
"$ref": "#/definitions/Int"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,14 @@
|
|||
validator {
|
||||
fn spend(datum: Int, redeemer: Int, _context: Data) {
|
||||
validator foo {
|
||||
spend(datum: Option<Int>, redeemer: Int, _ref: Data, _transaction: Data) {
|
||||
expect Some(datum) = datum
|
||||
datum + redeemer == 42
|
||||
}
|
||||
|
||||
fn mint(redeemer: Int, _context: Data) {
|
||||
mint(redeemer: Int, _policy: ByteArray, _transaction: Data) {
|
||||
redeemer == 42
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158431, nanos_since_epoch = 785683000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776965, nanos_since_epoch = 937696000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158433, nanos_since_epoch = 377116000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776958, nanos_since_epoch = 302886000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158433, nanos_since_epoch = 339674000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1724776958, nanos_since_epoch = 249560000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
[[requirements]]
|
||||
name = "aiken-lang/stdlib"
|
||||
version = "main"
|
||||
version = "v2"
|
||||
source = "github"
|
||||
|
||||
[[packages]]
|
||||
name = "aiken-lang/stdlib"
|
||||
version = "main"
|
||||
version = "v2"
|
||||
requirements = []
|
||||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1723158437, nanos_since_epoch = 77334000 }, "5e58899446492a704d0927a43299139856bef746e697b55895ba34206fa28452"]
|
||||
"aiken-lang/stdlib@v2" = [{ secs_since_epoch = 1724776991, nanos_since_epoch = 269398000 }, "cdbbce58b61deb385e7ea787a2e0fc2dc8fe94db9999e0e6275bc9c70e5796be"]
|
||||
|
|
|
@ -4,5 +4,5 @@ description = ""
|
|||
|
||||
[[dependencies]]
|
||||
name = 'aiken-lang/stdlib'
|
||||
version = 'main'
|
||||
version = 'v2'
|
||||
source = 'github'
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
"plutusVersion": "v2",
|
||||
"compiler": {
|
||||
"name": "Aiken",
|
||||
"version": "v1.0.31-alpha+6e4a16d"
|
||||
"version": "v1.0.31-alpha+4003343"
|
||||
}
|
||||
},
|
||||
"validators": [
|
||||
{
|
||||
"title": "other.validate",
|
||||
"title": "other.validate.spend",
|
||||
"datum": {
|
||||
"title": "raw_datum",
|
||||
"schema": {
|
||||
|
@ -23,8 +23,13 @@
|
|||
"$ref": "#/definitions/Data"
|
||||
}
|
||||
},
|
||||
"compiledCode": "5902b1010000323232323232322225333004323232533300730033008375400c264a6660160022c264a66666601e0022a666018601c00426464a666016600e002264a66601e0022c264a6666660260022a66602060240042a66601a6012601c6ea80044c94ccc044004584c94cccccc05400454ccc048c05000854ccc03cc02cc040dd500089929998098008b099299999980b800899299980a8008b099299999980c8008a99980b180c001099980680189919299980a9808800899299980c8008b099299999980e8008a99980d180e00109919299980c980a800899299980e8008b09929999998108008a99980f1810001099980a8008a8020b0b0b0b0b0b180f000980d9baa003153330193014001132533301d001161325333333021001161616132325333020001161325333333024001161616132325333023001161325333333027001161616132533302530270031500b16375a0022c604800260480066eb400458c084004c08400cdd68008b180f000980d9baa00316301937540042a0082c2c2c2c2c6034002602e6ea800c54ccc054c04000454ccc060c05cdd50018a8010b0b180a9baa0021500a16161616161630160013016002161616163014001301137540022c2c2c2c2c2c6024002601e6ea8004585858585858c040004c034dd50018a99980598030008a99980718069baa003150021616300b37540042a666012600a60146ea8c034c02cdd50040a5114a02c2c2c2c2c601800260126ea801858888c94ccc028c0180044c94ccc03800400c4c94cccccc0480040100100100104c94ccc040c04800c54018014dd7000980780098061baa0041533300a3005001132533300e00100313253333330120010040040040041325333010301200315006005375c002601e00260186ea8010008c028dd50019b8748008dc3a400029309b2b2b9a5573aaae7955cfaba15744ae91",
|
||||
"hash": "22fcdd5defc5c63e55afed5ee2e88c9c695809f8b1e99342e045438d"
|
||||
"compiledCode": "5902fd010000323232323232322533300232323232325332330083001300937540042646464a664660186002601a6ea80084c8c94ccc038c00cc03cdd500109929998090008b099299999980b0008a999809980a8010991929998091803800899299980b0008b099299999980d0008a99980b980c8010a99980a1804980a9baa001132533301800116132533333301c00115333019301b00215333016300b30173754002264a6660340022c264a66666603c002264a6660380022c264a6666660400022a66603a603e004266601a00626464a6660386022002264a6660400022c264a6666660480022a666042604600426464a666040602a002264a6660480022c264a6666660500022a66604a604e004266602a0022a0082c2c2c2c2c2c604a00260446ea800c54ccc080c0640044c94ccc090004584c94cccccc0a00045858584c8c94ccc09c004584c94cccccc0ac0045858584c8c94ccc0a8004584c94cccccc0b80045858584c94ccc0b0c0b800c5402c58dd68008b181580098158019bad0011630280013028003375a0022c604a00260446ea800c58c080dd50010a8020b0b0b0b0b1810800980f1baa0031533301c30150011533301f301e37540062a0042c2c60386ea800854028585858585858c074004c07400858585858c06c004c060dd50008b0b0b0b0b0b180c800980b1baa0011616161616163017001301437540062a66602460160022a66602a60286ea800c540085858c048dd50010a999808180298089baa30143012375400829445280b0b0b0b0b180980098081baa002162223253330113006001132533301500100313253333330190010040040040041325333017301900315006005375c002602c00260266ea801054ccc044c0280044c94ccc05400400c4c94cccccc0640040100100100104c94ccc05cc06400c54018014dd7000980b00098099baa004002301137540066020601c6ea8008dc3a40002c601c601e004601a00260146ea8008dc3a40042c6014601600460120026012004600e00260086ea8004526136565734aae7555cf2ab9f5742ae895d21",
|
||||
"hash": "a63866b5537d618101fccdf892f6bb58f0f1092bc483bfedca3a813e"
|
||||
},
|
||||
{
|
||||
"title": "other.validate.else",
|
||||
"compiledCode": "5902fd010000323232323232322533300232323232325332330083001300937540042646464a664660186002601a6ea80084c8c94ccc038c00cc03cdd500109929998090008b099299999980b0008a999809980a8010991929998091803800899299980b0008b099299999980d0008a99980b980c8010a99980a1804980a9baa001132533301800116132533333301c00115333019301b00215333016300b30173754002264a6660340022c264a66666603c002264a6660380022c264a6666660400022a66603a603e004266601a00626464a6660386022002264a6660400022c264a6666660480022a666042604600426464a666040602a002264a6660480022c264a6666660500022a66604a604e004266602a0022a0082c2c2c2c2c2c604a00260446ea800c54ccc080c0640044c94ccc090004584c94cccccc0a00045858584c8c94ccc09c004584c94cccccc0ac0045858584c8c94ccc0a8004584c94cccccc0b80045858584c94ccc0b0c0b800c5402c58dd68008b181580098158019bad0011630280013028003375a0022c604a00260446ea800c58c080dd50010a8020b0b0b0b0b1810800980f1baa0031533301c30150011533301f301e37540062a0042c2c60386ea800854028585858585858c074004c07400858585858c06c004c060dd50008b0b0b0b0b0b180c800980b1baa0011616161616163017001301437540062a66602460160022a66602a60286ea800c540085858c048dd50010a999808180298089baa30143012375400829445280b0b0b0b0b180980098081baa002162223253330113006001132533301500100313253333330190010040040040041325333017301900315006005375c002602c00260266ea801054ccc044c0280044c94ccc05400400c4c94cccccc0640040100100100104c94ccc05cc06400c54018014dd7000980b00098099baa004002301137540066020601c6ea8008dc3a40002c601c601e004601a00260146ea8008dc3a40042c6014601600460120026012004600e00260086ea8004526136565734aae7555cf2ab9f5742ae895d21",
|
||||
"hash": "a63866b5537d618101fccdf892f6bb58f0f1092bc483bfedca3a813e"
|
||||
}
|
||||
],
|
||||
"definitions": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use aiken/transaction.{ScriptContext}
|
||||
use aiken/transaction/credential.{Address}
|
||||
use cardano/credential.{Address}
|
||||
use cardano/transaction.{Transaction}
|
||||
|
||||
type TestData {
|
||||
addr: Address,
|
||||
|
@ -9,13 +9,18 @@ type TestDatum {
|
|||
data: Option<TestData>,
|
||||
}
|
||||
|
||||
validator {
|
||||
fn validate(raw_datum: Data, _redeemer: Data, _context: ScriptContext) -> Bool {
|
||||
expect datum: TestDatum = raw_datum
|
||||
validator validate {
|
||||
spend(raw_datum: Option<Data>, _redeemer: Data, oref: Data, _tx: Transaction) {
|
||||
expect Some(datum): Option<Data> = raw_datum
|
||||
expect datum: TestDatum = datum
|
||||
let TestDatum { data } = datum
|
||||
when data is {
|
||||
Some(_) -> True
|
||||
None -> False
|
||||
}
|
||||
}
|
||||
|
||||
else(_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue