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<'_>> {
|
||||
self.params
|
||||
.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)]
|
||||
pub struct RecordConstructor<T> {
|
||||
pub location: Span,
|
||||
|
@ -823,6 +984,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);
|
||||
}
|
||||
|
@ -1217,6 +1393,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 {
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
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,
|
||||
},
|
||||
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;
|
||||
|
@ -199,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(),
|
||||
|
|
|
@ -13,9 +13,9 @@ use self::{
|
|||
};
|
||||
use crate::{
|
||||
ast::{
|
||||
well_known, ArgName, AssignmentKind, BinOp, Bls12_381Point, CallArg, Curve, DataTypeKey,
|
||||
FunctionAccessKey, OnTestFailure, Pattern, Span, TraceLevel, Tracing, TypedArg,
|
||||
TypedClause, TypedDataType, TypedFunction, TypedPattern, TypedValidator, UnOp,
|
||||
AssignmentKind, BinOp, Bls12_381Point, Curve, DataTypeKey, FunctionAccessKey, Pattern,
|
||||
Span, TraceLevel, Tracing, TypedArg, TypedClause, TypedDataType, TypedFunction,
|
||||
TypedPattern, TypedValidator, UnOp,
|
||||
},
|
||||
builtins::PRELUDE,
|
||||
expr::TypedExpr,
|
||||
|
@ -114,501 +114,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn generate(
|
||||
&mut self,
|
||||
TypedValidator {
|
||||
handlers,
|
||||
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);
|
||||
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,
|
||||
);
|
||||
|
||||
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 = cast_validator_args(term, params);
|
||||
let term = cast_validator_args(term, &validator.params);
|
||||
|
||||
self.finalize(term)
|
||||
}
|
||||
|
|
|
@ -1132,7 +1132,7 @@ impl ValueConstructor {
|
|||
tipo: Rc<Type>,
|
||||
constructors: &[&str],
|
||||
) -> Vec<String> {
|
||||
for constructor in &constructors[..] {
|
||||
for constructor in constructors {
|
||||
values.insert(
|
||||
constructor.to_string(),
|
||||
ValueConstructor::public(
|
||||
|
@ -1143,7 +1143,7 @@ impl ValueConstructor {
|
|||
}
|
||||
|
||||
constructors
|
||||
.into_iter()
|
||||
.iter()
|
||||
.map(|constructor| constructor.to_string())
|
||||
.collect()
|
||||
}
|
||||
|
@ -1152,7 +1152,7 @@ impl ValueConstructor {
|
|||
values: &mut HashMap<String, Self>,
|
||||
constructors: &[(&str, Rc<Type>)],
|
||||
) -> Vec<String> {
|
||||
for (constructor, tipo) in &constructors[..] {
|
||||
for (constructor, tipo) in constructors {
|
||||
values.insert(
|
||||
constructor.to_string(),
|
||||
ValueConstructor::public(
|
||||
|
@ -1167,7 +1167,7 @@ impl ValueConstructor {
|
|||
}
|
||||
|
||||
constructors
|
||||
.into_iter()
|
||||
.iter()
|
||||
.map(|(constructor, _)| constructor.to_string())
|
||||
.collect()
|
||||
}
|
||||
|
|
|
@ -13,4 +13,4 @@ requirements = []
|
|||
source = "github"
|
||||
|
||||
[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