DRY handlers generation from validator
This commit is contained in:
parent
047f422d0d
commit
f9acbd3bcb
|
@ -472,6 +472,154 @@ impl TypedValidator {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// FIXME: This is only needed if there's non-exhaustive patterns
|
||||||
|
// above.
|
||||||
|
.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<'_>> {
|
pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
|
||||||
self.params
|
self.params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -697,6 +845,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)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct RecordConstructor<T> {
|
pub struct RecordConstructor<T> {
|
||||||
pub location: Span,
|
pub location: Span,
|
||||||
|
@ -823,6 +984,21 @@ pub struct TypedArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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) {
|
pub fn put_doc(&mut self, new_doc: String) {
|
||||||
self.doc = Some(new_doc);
|
self.doc = Some(new_doc);
|
||||||
}
|
}
|
||||||
|
@ -1217,6 +1393,88 @@ impl BinOp {
|
||||||
pub type UntypedPattern = Pattern<(), ()>;
|
pub type UntypedPattern = Pattern<(), ()>;
|
||||||
pub type TypedPattern = Pattern<PatternConstructor, Rc<Type>>;
|
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)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum Pattern<Constructor, Type> {
|
pub enum Pattern<Constructor, Type> {
|
||||||
Int {
|
Int {
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
pub(crate) use crate::{
|
pub(crate) use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
self, Annotation, ArgBy, ArgName, AssignmentPattern, BinOp, Bls12_381Point,
|
self, Annotation, ArgBy, ArgName, AssignmentKind, AssignmentPattern, BinOp, Bls12_381Point,
|
||||||
ByteArrayFormatPreference, CallArg, Curve, DataType, DataTypeKey, DefinitionLocation,
|
ByteArrayFormatPreference, CallArg, Curve, DataType, DataTypeKey, DefinitionLocation,
|
||||||
Located, LogicalOpChainKind, ParsedCallArg, Pattern, RecordConstructorArg,
|
Located, LogicalOpChainKind, ParsedCallArg, Pattern, RecordConstructorArg,
|
||||||
RecordUpdateSpread, Span, TraceKind, TypedArg, TypedAssignmentKind, TypedClause,
|
RecordUpdateSpread, Span, TraceKind, TypedArg, TypedAssignmentKind, TypedClause,
|
||||||
TypedDataType, TypedIfBranch, TypedRecordUpdateArg, UnOp, UntypedArg,
|
TypedDataType, TypedIfBranch, TypedPattern, TypedRecordUpdateArg, UnOp, UntypedArg,
|
||||||
UntypedAssignmentKind, UntypedClause, UntypedIfBranch, UntypedRecordUpdateArg,
|
UntypedAssignmentKind, UntypedClause, UntypedIfBranch, UntypedRecordUpdateArg,
|
||||||
},
|
},
|
||||||
parser::token::Base,
|
parser::token::Base,
|
||||||
tipo::{
|
tipo::{
|
||||||
check_replaceable_opaque_type, convert_opaque_type, lookup_data_type_by_tipo,
|
check_replaceable_opaque_type, convert_opaque_type, lookup_data_type_by_tipo,
|
||||||
ModuleValueConstructor, PatternConstructor, Type, TypeVar, ValueConstructor,
|
ModuleValueConstructor, PatternConstructor, Type, TypeVar, ValueConstructor,
|
||||||
|
ValueConstructorVariant,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
@ -199,6 +200,52 @@ impl<T> From<Vec1Ref<T>> for Vec1<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedExpr {
|
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> {
|
pub fn tipo(&self) -> Rc<Type> {
|
||||||
match self {
|
match self {
|
||||||
Self::Var { constructor, .. } => constructor.tipo.clone(),
|
Self::Var { constructor, .. } => constructor.tipo.clone(),
|
||||||
|
|
|
@ -13,9 +13,9 @@ use self::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
well_known, ArgName, AssignmentKind, BinOp, Bls12_381Point, CallArg, Curve, DataTypeKey,
|
AssignmentKind, BinOp, Bls12_381Point, Curve, DataTypeKey, FunctionAccessKey, Pattern,
|
||||||
FunctionAccessKey, OnTestFailure, Pattern, Span, TraceLevel, Tracing, TypedArg,
|
Span, TraceLevel, Tracing, TypedArg, TypedClause, TypedDataType, TypedFunction,
|
||||||
TypedClause, TypedDataType, TypedFunction, TypedPattern, TypedValidator, UnOp,
|
TypedPattern, TypedValidator, UnOp,
|
||||||
},
|
},
|
||||||
builtins::PRELUDE,
|
builtins::PRELUDE,
|
||||||
expr::TypedExpr,
|
expr::TypedExpr,
|
||||||
|
@ -114,501 +114,11 @@ impl<'a> CodeGenerator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(
|
pub fn generate(&mut self, validator: &TypedValidator, module_name: &str) -> Program<Name> {
|
||||||
&mut self,
|
let air_tree_fun = wrap_validator_condition(
|
||||||
TypedValidator {
|
self.build(&validator.into_script_context_handler(), module_name, &[]),
|
||||||
handlers,
|
self.tracing,
|
||||||
fallback,
|
);
|
||||||
params,
|
|
||||||
..
|
|
||||||
}: &TypedValidator,
|
|
||||||
module_name: &str,
|
|
||||||
) -> Program<Name> {
|
|
||||||
let fun = TypedFunction {
|
|
||||||
arguments: vec![TypedArg {
|
|
||||||
arg_name: ArgName::Named {
|
|
||||||
name: "__context__".to_string(),
|
|
||||||
label: "__context__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
location: Span::empty(),
|
|
||||||
annotation: None,
|
|
||||||
doc: None,
|
|
||||||
is_validator_param: false,
|
|
||||||
tipo: Type::data(),
|
|
||||||
}],
|
|
||||||
body: TypedExpr::Sequence {
|
|
||||||
location: Span::empty(),
|
|
||||||
expressions: vec![
|
|
||||||
TypedExpr::Assignment {
|
|
||||||
location: Span::empty(),
|
|
||||||
tipo: Type::script_context(),
|
|
||||||
value: TypedExpr::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
constructor: ValueConstructor {
|
|
||||||
public: true,
|
|
||||||
variant: ValueConstructorVariant::LocalVariable {
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
tipo: Type::script_context(),
|
|
||||||
},
|
|
||||||
name: "__context__".to_string(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pattern: TypedPattern::Constructor {
|
|
||||||
is_record: false,
|
|
||||||
location: Span::empty(),
|
|
||||||
name: "ScriptContext".to_string(),
|
|
||||||
arguments: vec![
|
|
||||||
CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
name: "__transaction__".to_string(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
name: "__redeemer__".to_string(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
name: "__purpose__".to_string(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
module: None,
|
|
||||||
constructor: PatternConstructor::Record {
|
|
||||||
name: "ScriptContext".to_string(),
|
|
||||||
field_map: None,
|
|
||||||
},
|
|
||||||
spread_location: None,
|
|
||||||
tipo: Type::function(
|
|
||||||
vec![Type::data(), Type::data(), Type::script_purpose()],
|
|
||||||
Type::data(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
kind: AssignmentKind::let_(),
|
|
||||||
},
|
|
||||||
TypedExpr::When {
|
|
||||||
location: Span::empty(),
|
|
||||||
tipo: Type::bool(),
|
|
||||||
subject: TypedExpr::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
constructor: ValueConstructor {
|
|
||||||
public: true,
|
|
||||||
variant: ValueConstructorVariant::LocalVariable {
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
tipo: Type::script_purpose(),
|
|
||||||
},
|
|
||||||
name: "__purpose__".to_string(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
clauses: 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();
|
|
||||||
|
|
||||||
// handler
|
|
||||||
//
|
|
||||||
// spend(datum: Option<Datum>, redeemer, oref, anything) => Spend(datum, redeemer, oref, transaction)
|
|
||||||
// spend(datum: Datum) => Spend(datum, redeemer, oref, transaction)
|
|
||||||
// spend(redeemer) => Spend(__datum__, redeemer, oref, transaction)
|
|
||||||
|
|
||||||
let pattern = match handler.name.as_str() {
|
|
||||||
"spend" => TypedPattern::Constructor {
|
|
||||||
is_record: false,
|
|
||||||
location: Span::empty(),
|
|
||||||
name: well_known::SCRIPT_PURPOSE_SPEND.to_string(),
|
|
||||||
arguments: vec![
|
|
||||||
CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
name: "__purpose_arg__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
name: "__datum__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
module: None,
|
|
||||||
constructor: PatternConstructor::Record {
|
|
||||||
name: well_known::SCRIPT_PURPOSE_SPEND.to_string(),
|
|
||||||
field_map: None,
|
|
||||||
},
|
|
||||||
spread_location: None,
|
|
||||||
tipo: Type::function(
|
|
||||||
vec![Type::data(), Type::option(Type::data())],
|
|
||||||
Type::script_purpose(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
"mint" => TypedPattern::Constructor {
|
|
||||||
is_record: false,
|
|
||||||
location: Span::empty(),
|
|
||||||
name: well_known::SCRIPT_PURPOSE_MINT.to_string(),
|
|
||||||
arguments: vec![CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
name: "__purpose_arg__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
module: None,
|
|
||||||
constructor: PatternConstructor::Record {
|
|
||||||
name: well_known::SCRIPT_PURPOSE_MINT.to_string(),
|
|
||||||
field_map: None,
|
|
||||||
},
|
|
||||||
spread_location: None,
|
|
||||||
tipo: Type::function(
|
|
||||||
vec![Type::byte_array()],
|
|
||||||
Type::script_purpose(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
"withdraw" => TypedPattern::Constructor {
|
|
||||||
is_record: false,
|
|
||||||
location: Span::empty(),
|
|
||||||
name: well_known::SCRIPT_PURPOSE_WITHDRAW.to_string(),
|
|
||||||
arguments: vec![CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
name: "__purpose_arg__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
module: None,
|
|
||||||
constructor: PatternConstructor::Record {
|
|
||||||
name: well_known::SCRIPT_PURPOSE_WITHDRAW.to_string(),
|
|
||||||
field_map: None,
|
|
||||||
},
|
|
||||||
spread_location: None,
|
|
||||||
tipo: Type::function(
|
|
||||||
vec![Type::data()],
|
|
||||||
Type::script_purpose(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
"publish" => TypedPattern::Constructor {
|
|
||||||
is_record: false,
|
|
||||||
location: Span::empty(),
|
|
||||||
name: well_known::SCRIPT_PURPOSE_PUBLISH.to_string(),
|
|
||||||
arguments: vec![
|
|
||||||
CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
name: "__purpose_arg_ix__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
name: "__purpose_arg__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
module: None,
|
|
||||||
constructor: PatternConstructor::Record {
|
|
||||||
name: well_known::SCRIPT_PURPOSE_PUBLISH.to_string(),
|
|
||||||
field_map: None,
|
|
||||||
},
|
|
||||||
spread_location: None,
|
|
||||||
tipo: Type::function(
|
|
||||||
vec![Type::int(), Type::data()],
|
|
||||||
Type::script_purpose(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
"vote" => TypedPattern::Constructor {
|
|
||||||
is_record: false,
|
|
||||||
location: Span::empty(),
|
|
||||||
name: well_known::SCRIPT_PURPOSE_VOTE.to_string(),
|
|
||||||
arguments: vec![CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
name: "__purpose_arg__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
module: None,
|
|
||||||
constructor: PatternConstructor::Record {
|
|
||||||
name: well_known::SCRIPT_PURPOSE_VOTE.to_string(),
|
|
||||||
field_map: None,
|
|
||||||
},
|
|
||||||
spread_location: None,
|
|
||||||
tipo: Type::function(
|
|
||||||
vec![Type::data()],
|
|
||||||
Type::script_purpose(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
"propose" => TypedPattern::Constructor {
|
|
||||||
is_record: false,
|
|
||||||
location: Span::empty(),
|
|
||||||
name: well_known::SCRIPT_PURPOSE_PROPOSE.to_string(),
|
|
||||||
arguments: vec![
|
|
||||||
CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
name: "__purpose_arg_ix__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CallArg {
|
|
||||||
label: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
value: TypedPattern::Var {
|
|
||||||
name: "__purpose_arg__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
module: None,
|
|
||||||
constructor: PatternConstructor::Record {
|
|
||||||
name: well_known::SCRIPT_PURPOSE_PROPOSE.to_string(),
|
|
||||||
field_map: None,
|
|
||||||
},
|
|
||||||
spread_location: None,
|
|
||||||
tipo: Type::function(
|
|
||||||
vec![Type::int(), Type::data()],
|
|
||||||
Type::script_purpose(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
purpose => {
|
|
||||||
unreachable!("unexpected/unknown purpose: {:?}", purpose)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut then = vec![];
|
|
||||||
|
|
||||||
// expect redeemer: tipo = __redeemer__
|
|
||||||
then.push(TypedExpr::Assignment {
|
|
||||||
location: Span::empty(),
|
|
||||||
tipo: redeemer.tipo.clone(),
|
|
||||||
value: TypedExpr::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
constructor: ValueConstructor {
|
|
||||||
public: true,
|
|
||||||
variant: ValueConstructorVariant::LocalVariable {
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
tipo: Type::data(),
|
|
||||||
},
|
|
||||||
name: "__redeemer__".to_string(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pattern: TypedPattern::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
name: redeemer
|
|
||||||
.get_variable_name()
|
|
||||||
.unwrap_or("_")
|
|
||||||
.to_string(),
|
|
||||||
},
|
|
||||||
kind: if redeemer.tipo.is_data() {
|
|
||||||
AssignmentKind::let_()
|
|
||||||
} else {
|
|
||||||
AssignmentKind::expect()
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Cast the datum, if any
|
|
||||||
if let Some(datum) = datum {
|
|
||||||
// expect datum: tipo = __datum__
|
|
||||||
then.push(TypedExpr::Assignment {
|
|
||||||
location: Span::empty(),
|
|
||||||
tipo: datum.tipo.clone(),
|
|
||||||
value: TypedExpr::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
constructor: ValueConstructor {
|
|
||||||
public: true,
|
|
||||||
variant: ValueConstructorVariant::LocalVariable {
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
tipo: Type::option(Type::data()),
|
|
||||||
},
|
|
||||||
name: "__datum__".to_string(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pattern: TypedPattern::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
name: datum
|
|
||||||
.get_variable_name()
|
|
||||||
.unwrap_or("_")
|
|
||||||
.to_string(),
|
|
||||||
},
|
|
||||||
kind: if redeemer.tipo.is_data() {
|
|
||||||
AssignmentKind::let_()
|
|
||||||
} else {
|
|
||||||
AssignmentKind::expect()
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// let purpose_arg = __purpose_arg__
|
|
||||||
if let Some(arg_name) = purpose_arg.get_variable_name() {
|
|
||||||
then.push(TypedExpr::Assignment {
|
|
||||||
location: Span::empty(),
|
|
||||||
tipo: purpose_arg.tipo.clone(),
|
|
||||||
value: TypedExpr::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
constructor: ValueConstructor {
|
|
||||||
public: true,
|
|
||||||
variant: ValueConstructorVariant::LocalVariable {
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
tipo: Type::data(),
|
|
||||||
},
|
|
||||||
name: "__purpose_arg__".to_string(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pattern: TypedPattern::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
name: arg_name.to_string(),
|
|
||||||
},
|
|
||||||
kind: AssignmentKind::let_(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// let last_arg_name = __transaction__
|
|
||||||
if let Some(arg_name) = transaction.get_variable_name() {
|
|
||||||
then.push(TypedExpr::Assignment {
|
|
||||||
location: Span::empty(),
|
|
||||||
tipo: transaction.tipo.clone(),
|
|
||||||
value: TypedExpr::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
constructor: ValueConstructor {
|
|
||||||
public: true,
|
|
||||||
variant: ValueConstructorVariant::LocalVariable {
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
tipo: Type::data(),
|
|
||||||
},
|
|
||||||
name: "__transaction__".to_string(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pattern: TypedPattern::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
name: arg_name.to_string(),
|
|
||||||
},
|
|
||||||
kind: AssignmentKind::let_(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
then.push(handler.body.clone());
|
|
||||||
|
|
||||||
TypedClause {
|
|
||||||
location: Span::empty(),
|
|
||||||
pattern,
|
|
||||||
then: TypedExpr::Sequence {
|
|
||||||
location: Span::empty(),
|
|
||||||
expressions: then,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// FIXME: This is only needed if there's non-exhaustive patterns
|
|
||||||
// above.
|
|
||||||
.chain(std::iter::once(fallback).map(|fallback| {
|
|
||||||
let pattern = TypedPattern::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
name: "__context__".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let arg = fallback.arguments.first().unwrap();
|
|
||||||
|
|
||||||
let then = vec![
|
|
||||||
TypedExpr::Assignment {
|
|
||||||
location: Span::empty(),
|
|
||||||
tipo: arg.tipo.clone(),
|
|
||||||
value: TypedExpr::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
constructor: ValueConstructor {
|
|
||||||
public: true,
|
|
||||||
variant: ValueConstructorVariant::LocalVariable {
|
|
||||||
location: Span::empty(),
|
|
||||||
},
|
|
||||||
tipo: arg.tipo.clone(),
|
|
||||||
},
|
|
||||||
name: "__context__".to_string(),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pattern: arg
|
|
||||||
.get_variable_name()
|
|
||||||
.map(|name| TypedPattern::Var {
|
|
||||||
location: Span::empty(),
|
|
||||||
name: name.to_string(),
|
|
||||||
})
|
|
||||||
.unwrap_or(TypedPattern::Discard {
|
|
||||||
name: "__context__".to_string(),
|
|
||||||
location: Span::empty(),
|
|
||||||
}),
|
|
||||||
kind: AssignmentKind::let_(),
|
|
||||||
},
|
|
||||||
fallback.body.clone(),
|
|
||||||
];
|
|
||||||
|
|
||||||
TypedClause {
|
|
||||||
location: Span::empty(),
|
|
||||||
pattern,
|
|
||||||
then: TypedExpr::Sequence {
|
|
||||||
location: Span::empty(),
|
|
||||||
expressions: then,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.collect(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
doc: None,
|
|
||||||
location: Span::empty(),
|
|
||||||
name: "wrapper_validator".to_string(),
|
|
||||||
public: true,
|
|
||||||
return_annotation: None,
|
|
||||||
return_type: Type::bool(),
|
|
||||||
end_position: 0,
|
|
||||||
on_test_failure: OnTestFailure::FailImmediately,
|
|
||||||
};
|
|
||||||
|
|
||||||
let air_tree_fun =
|
|
||||||
wrap_validator_condition(self.build(&fun.body, module_name, &[]), self.tracing);
|
|
||||||
|
|
||||||
let air_tree_fun = AirTree::anon_func(vec!["__context__".to_string()], air_tree_fun, true);
|
let air_tree_fun = AirTree::anon_func(vec!["__context__".to_string()], air_tree_fun, true);
|
||||||
|
|
||||||
|
@ -622,7 +132,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let term = self.uplc_code_gen(full_vec);
|
let term = self.uplc_code_gen(full_vec);
|
||||||
|
|
||||||
let term = cast_validator_args(term, params);
|
let term = cast_validator_args(term, &validator.params);
|
||||||
|
|
||||||
self.finalize(term)
|
self.finalize(term)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1132,7 +1132,7 @@ impl ValueConstructor {
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
constructors: &[&str],
|
constructors: &[&str],
|
||||||
) -> Vec<String> {
|
) -> Vec<String> {
|
||||||
for constructor in &constructors[..] {
|
for constructor in constructors {
|
||||||
values.insert(
|
values.insert(
|
||||||
constructor.to_string(),
|
constructor.to_string(),
|
||||||
ValueConstructor::public(
|
ValueConstructor::public(
|
||||||
|
@ -1143,7 +1143,7 @@ impl ValueConstructor {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructors
|
constructors
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|constructor| constructor.to_string())
|
.map(|constructor| constructor.to_string())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -1152,7 +1152,7 @@ impl ValueConstructor {
|
||||||
values: &mut HashMap<String, Self>,
|
values: &mut HashMap<String, Self>,
|
||||||
constructors: &[(&str, Rc<Type>)],
|
constructors: &[(&str, Rc<Type>)],
|
||||||
) -> Vec<String> {
|
) -> Vec<String> {
|
||||||
for (constructor, tipo) in &constructors[..] {
|
for (constructor, tipo) in constructors {
|
||||||
values.insert(
|
values.insert(
|
||||||
constructor.to_string(),
|
constructor.to_string(),
|
||||||
ValueConstructor::public(
|
ValueConstructor::public(
|
||||||
|
@ -1167,7 +1167,7 @@ impl ValueConstructor {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructors
|
constructors
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|(constructor, _)| constructor.to_string())
|
.map(|(constructor, _)| constructor.to_string())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
||||||
[etags]
|
[etags]
|
||||||
"aiken-lang/stdlib@v2" = [{ secs_since_epoch = 1723818477, nanos_since_epoch = 540444000 }, "cdbbce58b61deb385e7ea787a2e0fc2dc8fe94db9999e0e6275bc9c70e5796be"]
|
"aiken-lang/stdlib@v2" = [{ secs_since_epoch = 1723824703, nanos_since_epoch = 979555000 }, "cdbbce58b61deb385e7ea787a2e0fc2dc8fe94db9999e0e6275bc9c70e5796be"]
|
||||||
|
|
Loading…
Reference in New Issue