feat: add tuples and streamline conversion of types to and from data
This commit is contained in:
parent
d8ff574045
commit
2f7131e9b8
|
@ -45,20 +45,16 @@ pub enum Air {
|
|||
tail: bool,
|
||||
},
|
||||
|
||||
Tail {
|
||||
scope: Vec<u64>,
|
||||
name: String,
|
||||
prev_tail_name: String,
|
||||
},
|
||||
|
||||
ListAccessor {
|
||||
scope: Vec<u64>,
|
||||
tipo: Arc<Type>,
|
||||
names: Vec<String>,
|
||||
tail: bool,
|
||||
},
|
||||
|
||||
ListExpose {
|
||||
scope: Vec<u64>,
|
||||
tipo: Arc<Type>,
|
||||
tail_head_names: Vec<(String, String)>,
|
||||
tail: Option<(String, String)>,
|
||||
},
|
||||
|
@ -120,13 +116,6 @@ pub enum Air {
|
|||
name: String,
|
||||
},
|
||||
|
||||
// Try {
|
||||
// scope: Vec<u64>,
|
||||
// tipo: Arc<Type>,
|
||||
// value: Box<Self>,
|
||||
// then: Box<Self>,
|
||||
// pattern: Pattern<PatternConstructor, Arc<Type>>,
|
||||
// },
|
||||
When {
|
||||
scope: Vec<u64>,
|
||||
tipo: Arc<Type>,
|
||||
|
@ -196,13 +185,11 @@ pub enum Air {
|
|||
// module_alias: String,
|
||||
// constructor: ModuleValueConstructor,
|
||||
// },
|
||||
|
||||
// Tuple {
|
||||
// scope: Vec<u64>,
|
||||
//
|
||||
// tipo: Arc<Type>,
|
||||
// elems: Vec<Self>,
|
||||
// },
|
||||
Tuple {
|
||||
scope: Vec<u64>,
|
||||
tipo: Arc<Type>,
|
||||
count: usize,
|
||||
},
|
||||
|
||||
// TupleIndex {
|
||||
// scope: Vec<u64>,
|
||||
|
@ -242,7 +229,6 @@ impl Air {
|
|||
| Air::ByteArray { scope, .. }
|
||||
| Air::Var { scope, .. }
|
||||
| Air::List { scope, .. }
|
||||
| Air::Tail { scope, .. }
|
||||
| Air::ListAccessor { scope, .. }
|
||||
| Air::ListExpose { scope, .. }
|
||||
| Air::Call { scope, .. }
|
||||
|
@ -265,6 +251,7 @@ impl Air {
|
|||
| Air::Fields { scope, .. }
|
||||
| Air::RecordAccess { scope, .. }
|
||||
| Air::FieldsExpose { scope, .. }
|
||||
| Air::Tuple { scope, .. }
|
||||
| Air::Todo { scope, .. }
|
||||
| Air::Record { scope, .. }
|
||||
| Air::RecordUpdate { scope, .. }
|
||||
|
|
|
@ -135,6 +135,43 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_map(&self) -> bool {
|
||||
match self {
|
||||
Self::App {
|
||||
module, name, args, ..
|
||||
} if "List" == name && module.is_empty() => {
|
||||
if let Type::Tuple { elems } = &*args[0] {
|
||||
elems.len() == 2
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
Self::Var { tipo } => tipo.borrow().is_map(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_tuple(&self) -> bool {
|
||||
matches!(self, Self::Tuple { .. })
|
||||
}
|
||||
|
||||
pub fn get_inner_type(&self) -> Vec<Arc<Type>> {
|
||||
if self.is_list() {
|
||||
match self {
|
||||
Self::App { args, .. } => args.clone(),
|
||||
Self::Var { tipo } => tipo.borrow().get_inner_type(),
|
||||
_ => vec![],
|
||||
}
|
||||
} else if self.is_tuple() {
|
||||
match self {
|
||||
Self::Tuple { elems } => elems.to_vec(),
|
||||
_ => vec![],
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_uplc_type(&self) -> UplcType {
|
||||
if self.is_int() {
|
||||
UplcType::Integer
|
||||
|
@ -144,21 +181,21 @@ impl Type {
|
|||
UplcType::String
|
||||
} else if self.is_bool() {
|
||||
UplcType::Bool
|
||||
} else if self.is_map() {
|
||||
UplcType::List(UplcType::Pair(UplcType::Data.into(), UplcType::Data.into()).into())
|
||||
} else if self.is_list() {
|
||||
let args_type = match self {
|
||||
Self::App {
|
||||
module, name, args, ..
|
||||
} if "List" == name && module.is_empty() => args[0].clone(),
|
||||
Self::Var { tipo } => {
|
||||
if let TypeVar::Link { tipo } = tipo.borrow().clone() {
|
||||
tipo
|
||||
UplcType::List(UplcType::Data.into())
|
||||
} else if self.is_tuple() {
|
||||
match self {
|
||||
Self::Tuple { elems } => {
|
||||
if elems.len() == 2 {
|
||||
UplcType::Pair(UplcType::Data.into(), UplcType::Data.into())
|
||||
} else {
|
||||
todo!()
|
||||
UplcType::List(UplcType::Data.into())
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
UplcType::List(Box::new(args_type.get_uplc_type()))
|
||||
}
|
||||
} else {
|
||||
UplcType::Data
|
||||
}
|
||||
|
@ -334,6 +371,20 @@ impl TypeVar {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_map(&self) -> bool {
|
||||
match self {
|
||||
Self::Link { tipo } => tipo.is_map(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_inner_type(&self) -> Vec<Arc<Type>> {
|
||||
match self {
|
||||
Self::Link { tipo } => tipo.get_inner_type(),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
|
|
@ -8,7 +8,9 @@ use uplc::{
|
|||
Constant as UplcConstant, Name, Program, Term, Type as UplcType,
|
||||
},
|
||||
builtins::DefaultFunction,
|
||||
machine::runtime::convert_constr_to_tag,
|
||||
parser::interner::Interner,
|
||||
BigInt, Constr, PlutusData,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -525,7 +527,23 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
TypedExpr::RecordUpdate { .. } => todo!(),
|
||||
TypedExpr::Negate { .. } => todo!(),
|
||||
TypedExpr::Tuple { .. } => todo!(),
|
||||
TypedExpr::Tuple { elems, tipo, .. } => {
|
||||
ir_stack.push(Air::Tuple {
|
||||
scope: scope.clone(),
|
||||
tipo: tipo.clone(),
|
||||
count: elems.len(),
|
||||
});
|
||||
|
||||
let mut elems_air = vec![];
|
||||
|
||||
for elem in elems {
|
||||
let mut scope = scope.clone();
|
||||
scope.push(self.id_gen.next());
|
||||
self.build_ir(elem, &mut elems_air, scope);
|
||||
}
|
||||
|
||||
ir_stack.append(&mut elems_air);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -731,7 +749,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
pattern_vec: &mut Vec<Air>,
|
||||
values: &mut Vec<Air>,
|
||||
clause_properties: ClauseProperties,
|
||||
_tipo: &Type,
|
||||
tipo: &Type,
|
||||
scope: Vec<u64>,
|
||||
) {
|
||||
match pattern {
|
||||
|
@ -821,12 +839,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
pattern_vec.push(Air::ListExpose {
|
||||
scope,
|
||||
tipo: tipo.clone().into(),
|
||||
tail_head_names,
|
||||
tail: Some((tail_var, tail_name)),
|
||||
});
|
||||
} else {
|
||||
pattern_vec.push(Air::ListExpose {
|
||||
scope,
|
||||
tipo: tipo.clone().into(),
|
||||
tail_head_names,
|
||||
tail: None,
|
||||
});
|
||||
|
@ -1066,13 +1086,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
pattern: &Pattern<tipo::PatternConstructor, Arc<Type>>,
|
||||
pattern_vec: &mut Vec<Air>,
|
||||
value_vec: &mut Vec<Air>,
|
||||
_tipo: &Type,
|
||||
tipo: &Type,
|
||||
kind: AssignmentKind,
|
||||
scope: Vec<u64>,
|
||||
) {
|
||||
match pattern {
|
||||
Pattern::Int { .. } => todo!(),
|
||||
Pattern::String { .. } => todo!(),
|
||||
Pattern::Int { .. } | Pattern::String { .. } => unreachable!(),
|
||||
Pattern::Var { name, .. } => {
|
||||
pattern_vec.push(Air::Assignment {
|
||||
name: name.clone(),
|
||||
|
@ -1084,12 +1103,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
Pattern::VarUsage { .. } => todo!(),
|
||||
Pattern::Assign { .. } => todo!(),
|
||||
Pattern::Discard { .. } => todo!(),
|
||||
Pattern::Discard { .. } => {
|
||||
self.pattern_ir(pattern, pattern_vec, value_vec, tipo, scope)
|
||||
}
|
||||
list @ Pattern::List { .. } => {
|
||||
self.pattern_ir(list, pattern_vec, value_vec, scope);
|
||||
self.pattern_ir(list, pattern_vec, value_vec, tipo, scope);
|
||||
}
|
||||
Pattern::Constructor { .. } => {
|
||||
self.pattern_ir(pattern, pattern_vec, value_vec, scope);
|
||||
self.pattern_ir(pattern, pattern_vec, value_vec, tipo, scope);
|
||||
}
|
||||
Pattern::Tuple { .. } => todo!(),
|
||||
}
|
||||
|
@ -1100,6 +1121,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
pattern: &Pattern<tipo::PatternConstructor, Arc<tipo::Type>>,
|
||||
pattern_vec: &mut Vec<Air>,
|
||||
values: &mut Vec<Air>,
|
||||
tipo: &Type,
|
||||
scope: Vec<u64>,
|
||||
) {
|
||||
match pattern {
|
||||
|
@ -1142,7 +1164,13 @@ impl<'a> CodeGenerator<'a> {
|
|||
name: item_name,
|
||||
scope: scope.clone(),
|
||||
});
|
||||
self.pattern_ir(a, &mut elements_vec, &mut var_vec, scope.clone());
|
||||
self.pattern_ir(
|
||||
a,
|
||||
&mut elements_vec,
|
||||
&mut var_vec,
|
||||
&tipo.get_inner_type()[0],
|
||||
scope.clone(),
|
||||
);
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
|
@ -1160,6 +1188,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
names,
|
||||
tail: tail.is_some(),
|
||||
scope,
|
||||
tipo: tipo.clone().into(),
|
||||
});
|
||||
|
||||
pattern_vec.append(values);
|
||||
|
@ -1241,6 +1270,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
),
|
||||
name: constr_name.clone(),
|
||||
}],
|
||||
tipo,
|
||||
scope.clone(),
|
||||
);
|
||||
|
||||
|
@ -1305,6 +1335,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
),
|
||||
name: constr_name.clone(),
|
||||
}],
|
||||
tipo,
|
||||
scope.clone(),
|
||||
);
|
||||
|
||||
|
@ -1371,11 +1402,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
Air::Var {
|
||||
name, constructor, ..
|
||||
} => match constructor.variant {
|
||||
ValueConstructorVariant::LocalVariable { .. } => arg_stack.push(Term::Var(Name {
|
||||
} => {
|
||||
match constructor.variant {
|
||||
ValueConstructorVariant::LocalVariable { .. } => {
|
||||
arg_stack.push(Term::Var(Name {
|
||||
text: name,
|
||||
unique: 0.into(),
|
||||
})),
|
||||
}))
|
||||
}
|
||||
ValueConstructorVariant::ModuleConstant { .. } => {
|
||||
unreachable!()
|
||||
}
|
||||
|
@ -1416,7 +1450,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
};
|
||||
|
||||
if data_type_key.defined_type == "Bool" {
|
||||
arg_stack.push(Term::Constant(UplcConstant::Bool(constr_name == "True")));
|
||||
arg_stack
|
||||
.push(Term::Constant(UplcConstant::Bool(constr_name == "True")));
|
||||
} else {
|
||||
let data_type = self.data_types.get(&data_type_key).unwrap();
|
||||
let (constr_index, _constr) = data_type
|
||||
|
@ -1445,60 +1480,19 @@ impl<'a> CodeGenerator<'a> {
|
|||
.zip(args_type)
|
||||
.rev()
|
||||
{
|
||||
let arg_to_data = if field.1.as_ref().is_bytearray() {
|
||||
Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::BData).into(),
|
||||
argument: Term::Var(Name {
|
||||
text: field.0 .0.clone(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
} else if field.1.as_ref().is_int() {
|
||||
Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::IData).into(),
|
||||
argument: Term::Var(Name {
|
||||
text: field.0 .0.clone(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
} else if field.1.as_ref().is_list() {
|
||||
Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::ListData).into(),
|
||||
argument: Term::Var(Name {
|
||||
text: field.0 .0.clone(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
} else if field.1.as_ref().is_string() {
|
||||
Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::BData).into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::DecodeUtf8)
|
||||
.into(),
|
||||
argument: Term::Var(Name {
|
||||
text: field.0 .0.clone(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
} else {
|
||||
Term::Var(Name {
|
||||
text: field.0 .0.clone(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
};
|
||||
|
||||
fields = Term::Apply {
|
||||
function: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::MkCons)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: arg_to_data.into(),
|
||||
argument: convert_type_to_data(
|
||||
Term::Var(Name {
|
||||
text: field.0 .0.clone(),
|
||||
unique: 0.into(),
|
||||
}),
|
||||
field.1,
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: fields.into(),
|
||||
|
@ -1538,7 +1532,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
arg_stack.push(term);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
Air::Discard { .. } => {
|
||||
arg_stack.push(Term::Constant(UplcConstant::Unit));
|
||||
}
|
||||
|
@ -1558,15 +1553,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
let list_type = match tipo.deref() {
|
||||
Type::App { args, .. } => &args[0],
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let list_type = tipo.get_inner_type()[0].clone();
|
||||
|
||||
if constants.len() == args.len() && !tail {
|
||||
let list = Term::Constant(UplcConstant::ProtoList(
|
||||
list_type.get_uplc_type(),
|
||||
constants,
|
||||
UplcType::Data,
|
||||
convert_constants_to_data(constants),
|
||||
));
|
||||
|
||||
arg_stack.push(list);
|
||||
|
@ -1574,7 +1566,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
let mut term = if tail {
|
||||
arg_stack.pop().unwrap()
|
||||
} else {
|
||||
Term::Constant(UplcConstant::ProtoList(list_type.get_uplc_type(), vec![]))
|
||||
Term::Constant(UplcConstant::ProtoList(UplcType::Data, vec![]))
|
||||
};
|
||||
|
||||
for arg in args {
|
||||
|
@ -1584,7 +1576,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
Term::Builtin(DefaultFunction::MkCons).into(),
|
||||
)
|
||||
.into(),
|
||||
argument: arg.into(),
|
||||
argument: convert_type_to_data(arg, &list_type).into(),
|
||||
}
|
||||
.into(),
|
||||
argument: term.into(),
|
||||
|
@ -1593,9 +1585,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
arg_stack.push(term);
|
||||
}
|
||||
}
|
||||
|
||||
Air::Tail { .. } => todo!(),
|
||||
Air::ListAccessor { names, tail, .. } => {
|
||||
Air::ListAccessor {
|
||||
names, tail, tipo, ..
|
||||
} => {
|
||||
let value = arg_stack.pop().unwrap();
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
|
@ -1621,6 +1613,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
tail,
|
||||
current_index,
|
||||
term,
|
||||
&tipo.get_inner_type()[0],
|
||||
)
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
|
@ -1635,11 +1628,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
argument: convert_data_to_type(
|
||||
Term::Apply {
|
||||
function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into())
|
||||
.into(),
|
||||
argument: value.into(),
|
||||
}
|
||||
},
|
||||
&tipo.get_inner_type()[0],
|
||||
)
|
||||
.into(),
|
||||
};
|
||||
|
||||
|
@ -1648,10 +1644,13 @@ impl<'a> CodeGenerator<'a> {
|
|||
Air::ListExpose {
|
||||
tail_head_names,
|
||||
tail,
|
||||
tipo,
|
||||
..
|
||||
} => {
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
let list_type = tipo.get_inner_type()[0].clone();
|
||||
|
||||
if let Some((tail_var, tail_name)) = tail {
|
||||
term = Term::Apply {
|
||||
function: Term::Lambda {
|
||||
|
@ -1683,14 +1682,19 @@ impl<'a> CodeGenerator<'a> {
|
|||
body: term.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
|
||||
argument: convert_data_to_type(
|
||||
Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: Term::Var(Name {
|
||||
text: tail_var,
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
},
|
||||
&list_type,
|
||||
)
|
||||
.into(),
|
||||
};
|
||||
}
|
||||
|
@ -2391,7 +2395,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
.into(),
|
||||
}
|
||||
} else if tipo.is_list() {
|
||||
unreachable!()
|
||||
todo!()
|
||||
} else {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::EqualsInteger.into(),
|
||||
|
@ -2483,22 +2487,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
argument: Term::Constant(UplcConstant::Integer(index.into())).into(),
|
||||
};
|
||||
|
||||
if tipo.is_int() {
|
||||
term = Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::UnIData).into(),
|
||||
argument: term.into(),
|
||||
};
|
||||
} else if tipo.is_bytearray() {
|
||||
term = Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::UnBData).into(),
|
||||
argument: term.into(),
|
||||
};
|
||||
} else if tipo.is_list() {
|
||||
term = Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::UnListData).into(),
|
||||
argument: term.into(),
|
||||
};
|
||||
}
|
||||
term = convert_data_to_type(term, &tipo);
|
||||
|
||||
arg_stack.push(term);
|
||||
}
|
||||
|
@ -2530,40 +2519,6 @@ impl<'a> CodeGenerator<'a> {
|
|||
unique: 0.into(),
|
||||
});
|
||||
|
||||
let unwrapper = if highest.2.is_int() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnIData.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
|
||||
argument: last_prev_tail.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
} else if highest.2.is_bytearray() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnBData.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
|
||||
argument: last_prev_tail.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
} else if highest.2.is_list() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnListData.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
|
||||
argument: last_prev_tail.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
} else {
|
||||
Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
|
||||
argument: last_prev_tail.into(),
|
||||
}
|
||||
};
|
||||
|
||||
body = Term::Apply {
|
||||
function: Term::Lambda {
|
||||
parameter_name: Name {
|
||||
|
@ -2573,7 +2528,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
body: body.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: unwrapper.into(),
|
||||
argument: convert_data_to_type(
|
||||
Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
|
||||
argument: last_prev_tail.into(),
|
||||
},
|
||||
&highest.2,
|
||||
)
|
||||
.into(),
|
||||
};
|
||||
|
||||
let mut current_field = None;
|
||||
|
@ -2600,47 +2562,15 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
if let Some(ref field) = current_field {
|
||||
if field.0 == index {
|
||||
let unwrapper = if field.2.is_int() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnIData.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: prev_tail.clone().into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
} else if field.2.is_bytearray() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnBData.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: prev_tail.clone().into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
} else if field.2.is_list() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnListData.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: prev_tail.clone().into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
} else {
|
||||
let unwrapper = convert_data_to_type(
|
||||
Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: prev_tail.clone().into(),
|
||||
}
|
||||
};
|
||||
},
|
||||
&field.2,
|
||||
);
|
||||
|
||||
body = Term::Apply {
|
||||
function: Term::Lambda {
|
||||
|
@ -2740,6 +2670,64 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
arg_stack.push(body);
|
||||
}
|
||||
Air::Tuple { tipo, count, .. } => {
|
||||
let mut args = vec![];
|
||||
|
||||
for _ in 0..count {
|
||||
let arg = arg_stack.pop().unwrap();
|
||||
args.push(arg);
|
||||
}
|
||||
let mut constants = vec![];
|
||||
for arg in &args {
|
||||
if let Term::Constant(c) = arg {
|
||||
constants.push(c.clone())
|
||||
}
|
||||
}
|
||||
|
||||
let tuple_sub_types = tipo.get_inner_type();
|
||||
|
||||
if constants.len() == args.len() {
|
||||
let data_constants = convert_constants_to_data(constants);
|
||||
|
||||
if count == 2 {
|
||||
let term = Term::Constant(UplcConstant::ProtoPair(
|
||||
UplcType::Data,
|
||||
UplcType::Data,
|
||||
data_constants[0].clone().into(),
|
||||
data_constants[1].clone().into(),
|
||||
));
|
||||
arg_stack.push(term);
|
||||
} else {
|
||||
let term =
|
||||
Term::Constant(UplcConstant::ProtoList(UplcType::Data, data_constants));
|
||||
arg_stack.push(term);
|
||||
}
|
||||
} else if count == 2 {
|
||||
let term = Term::Apply {
|
||||
function: Term::Apply {
|
||||
function: DefaultFunction::MkPairData.into(),
|
||||
argument: convert_type_to_data(args[0].clone(), &tuple_sub_types[0])
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: convert_type_to_data(args[1].clone(), &tuple_sub_types[1]).into(),
|
||||
};
|
||||
arg_stack.push(term);
|
||||
} else {
|
||||
let mut term = Term::Constant(UplcConstant::ProtoList(UplcType::Data, vec![]));
|
||||
for (arg, tipo) in args.into_iter().zip(tuple_sub_types.into_iter()) {
|
||||
term = Term::Apply {
|
||||
function: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::MkCons).into(),
|
||||
argument: convert_type_to_data(arg, &tipo).into(),
|
||||
}
|
||||
.into(),
|
||||
argument: term.into(),
|
||||
};
|
||||
}
|
||||
arg_stack.push(term);
|
||||
}
|
||||
}
|
||||
Air::Todo { .. } => {
|
||||
arg_stack.push(Term::Error);
|
||||
}
|
||||
|
@ -3055,6 +3043,35 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_constants_to_data(constants: Vec<UplcConstant>) -> Vec<UplcConstant> {
|
||||
let mut new_constants = vec![];
|
||||
for constant in constants {
|
||||
let constant = match constant {
|
||||
UplcConstant::Integer(i) => {
|
||||
UplcConstant::Data(PlutusData::BigInt(BigInt::Int((i).try_into().unwrap())))
|
||||
}
|
||||
UplcConstant::ByteString(b) => {
|
||||
UplcConstant::Data(PlutusData::BoundedBytes(b.try_into().unwrap()))
|
||||
}
|
||||
UplcConstant::String(s) => UplcConstant::Data(PlutusData::BoundedBytes(
|
||||
s.as_bytes().to_vec().try_into().unwrap(),
|
||||
)),
|
||||
|
||||
UplcConstant::Bool(b) => UplcConstant::Data(PlutusData::Constr(Constr {
|
||||
tag: u64::from(b),
|
||||
any_constructor: None,
|
||||
fields: vec![],
|
||||
})),
|
||||
UplcConstant::ProtoList(_, _) => todo!(),
|
||||
UplcConstant::ProtoPair(_, _, _, _) => todo!(),
|
||||
UplcConstant::Data(_) => todo!(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
new_constants.push(constant);
|
||||
}
|
||||
new_constants
|
||||
}
|
||||
|
||||
fn constants_ir(literal: &Constant<Arc<Type>, String>, ir_stack: &mut Vec<Air>, scope: Vec<u64>) {
|
||||
match literal {
|
||||
Constant::Int { value, .. } => {
|
||||
|
@ -3149,6 +3166,7 @@ fn list_access_to_uplc(
|
|||
tail: bool,
|
||||
current_index: usize,
|
||||
term: Term<Name>,
|
||||
tipo: &Type,
|
||||
) -> Term<Name> {
|
||||
let (first, names) = names.split_first().unwrap();
|
||||
|
||||
|
@ -3190,14 +3208,21 @@ fn list_access_to_uplc(
|
|||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into()).into(),
|
||||
argument: convert_data_to_type(
|
||||
Term::Apply {
|
||||
function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into())
|
||||
.into(),
|
||||
argument: Term::Var(Name {
|
||||
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
|
||||
text: format!(
|
||||
"tail_index_{}_{}",
|
||||
current_index, id_list[current_index]
|
||||
),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
},
|
||||
&Arc::new(tipo.clone()),
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
|
@ -3248,6 +3273,7 @@ fn list_access_to_uplc(
|
|||
tail,
|
||||
current_index + 1,
|
||||
term,
|
||||
tipo,
|
||||
)
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
|
@ -3436,3 +3462,240 @@ fn rearrange_clauses(
|
|||
|
||||
final_clauses
|
||||
}
|
||||
|
||||
fn convert_type_to_data(term: Term<Name>, field_type: &Arc<Type>) -> Term<Name> {
|
||||
if field_type.is_bytearray() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::BData.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
} else if field_type.is_int() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::IData.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
} else if field_type.is_map() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::MapData.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
} else if field_type.is_list() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::ListData.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
} else if field_type.is_string() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::BData.into(),
|
||||
argument: Term::Apply {
|
||||
function: DefaultFunction::EncodeUtf8.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
} else if field_type.is_tuple() {
|
||||
match field_type.get_uplc_type() {
|
||||
UplcType::List(_) => Term::Apply {
|
||||
function: DefaultFunction::ListData.into(),
|
||||
argument: term.into(),
|
||||
},
|
||||
UplcType::Pair(_, _) => Term::Apply {
|
||||
function: Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: "__pair".to_string(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: Term::Apply {
|
||||
function: DefaultFunction::ListData.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::MkCons)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::FstPair)
|
||||
.force_wrap()
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: Term::Var(Name {
|
||||
text: "__pair".to_string(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
|
||||
argument: Term::Apply {
|
||||
function: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::MkCons)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::SndPair)
|
||||
.force_wrap()
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: Term::Var(Name {
|
||||
text: "__pair".to_string(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: Term::Constant(UplcConstant::ProtoList(
|
||||
UplcType::Data,
|
||||
vec![],
|
||||
))
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: term.into(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else if field_type.is_bool() {
|
||||
Term::Apply {
|
||||
function: Term::Apply {
|
||||
function: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::IfThenElse)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: Term::Constant(UplcConstant::Data(PlutusData::Constr(Constr {
|
||||
tag: convert_constr_to_tag(1),
|
||||
any_constructor: None,
|
||||
fields: vec![],
|
||||
})))
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: Term::Constant(UplcConstant::Data(PlutusData::Constr(Constr {
|
||||
tag: convert_constr_to_tag(0),
|
||||
any_constructor: None,
|
||||
fields: vec![],
|
||||
})))
|
||||
.into(),
|
||||
}
|
||||
} else {
|
||||
term
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Name> {
|
||||
if field_type.is_int() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnIData.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
} else if field_type.is_bytearray() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnBData.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
} else if field_type.is_map() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnMapData.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
} else if field_type.is_list() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::UnListData.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
} else if field_type.is_string() {
|
||||
Term::Apply {
|
||||
function: DefaultFunction::DecodeUtf8.into(),
|
||||
argument: Term::Apply {
|
||||
function: DefaultFunction::UnBData.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
} else if field_type.is_tuple() {
|
||||
match field_type.get_uplc_type() {
|
||||
UplcType::List(_) => Term::Apply {
|
||||
function: DefaultFunction::UnListData.into(),
|
||||
argument: term.into(),
|
||||
},
|
||||
UplcType::Pair(_, _) => Term::Apply {
|
||||
function: Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: "__list_data".to_string(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: Term::Apply {
|
||||
function: Term::Lambda {
|
||||
parameter_name: Name {
|
||||
text: "__tail".to_string(),
|
||||
unique: 0.into(),
|
||||
},
|
||||
body: Term::Apply {
|
||||
function: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::MkPairData).into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: Term::Var(Name {
|
||||
text: "__list_data".to_string(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::HeadList)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: Term::Var(Name {
|
||||
text: "__tail".to_string(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::TailList).force_wrap().into(),
|
||||
argument: Term::Var(Name {
|
||||
text: "__list_data".to_string(),
|
||||
unique: 0.into(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.into(),
|
||||
argument: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::UnListData)
|
||||
.force_wrap()
|
||||
.into(),
|
||||
argument: term.into(),
|
||||
}
|
||||
.into(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
term
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
|
||||
pub mod cost_model;
|
||||
mod error;
|
||||
mod runtime;
|
||||
pub mod runtime;
|
||||
|
||||
use cost_model::{ExBudget, StepKind};
|
||||
pub use error::Error;
|
||||
|
|
|
@ -853,7 +853,7 @@ impl DefaultFunction {
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_tag_to_constr(tag: i128) -> i128 {
|
||||
pub fn convert_tag_to_constr(tag: i128) -> i128 {
|
||||
if tag < 128 {
|
||||
tag - 121
|
||||
} else if (1280..1401).contains(&tag) {
|
||||
|
@ -863,7 +863,7 @@ fn convert_tag_to_constr(tag: i128) -> i128 {
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_constr_to_tag(constr: u64) -> u64 {
|
||||
pub fn convert_constr_to_tag(constr: u64) -> u64 {
|
||||
if constr < 7 {
|
||||
constr + 121
|
||||
} else if constr < 128 {
|
||||
|
|
|
@ -18,9 +18,8 @@
|
|||
(lam
|
||||
__constr_get_field
|
||||
[
|
||||
[
|
||||
[
|
||||
(force (builtin ifThenElse))
|
||||
(lam
|
||||
x
|
||||
[
|
||||
[
|
||||
(builtin equalsByteString)
|
||||
|
@ -35,12 +34,28 @@
|
|||
]
|
||||
]
|
||||
]
|
||||
(con bytestring #0102)
|
||||
[
|
||||
(builtin unBData)
|
||||
[
|
||||
[
|
||||
__constr_get_field
|
||||
[ __constr_fields_exposer rdmr ]
|
||||
]
|
||||
(con integer 0)
|
||||
]
|
||||
]
|
||||
(con bool False)
|
||||
]
|
||||
(con bool True)
|
||||
)
|
||||
[
|
||||
[
|
||||
(builtin mkCons)
|
||||
[ (builtin bData) (con bytestring #f4) ]
|
||||
]
|
||||
[
|
||||
[ (builtin mkCons) rdmr ]
|
||||
[ [ (builtin mkCons) datum ] (con listdata []) ]
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
(lam
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use sample
|
||||
|
||||
pub fn spend(datum: sample.Datum, rdmr: sample.Redeemer, _ctx: Nil) -> Bool {
|
||||
let x = #(datum, rdmr, #[244])
|
||||
|
||||
datum.random == rdmr.signer
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue