refactor the rest of the term builders to use more concise code

This commit is contained in:
Kasey White
2023-03-20 22:33:27 -04:00
committed by Lucas
parent 7c3750bbb4
commit 6e5b24a937
10 changed files with 346 additions and 1142 deletions

View File

@@ -4,10 +4,7 @@ use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use uplc::{
ast::{
builder::{
apply_wrap, constr_index_exposer, delayed_choose_list, delayed_if_else, if_else,
CONSTR_FIELDS_EXPOSER,
},
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER},
Constant as UplcConstant, Name, Term, Type as UplcType,
},
builtins::DefaultFunction,
@@ -191,79 +188,39 @@ impl ClauseProperties {
pub fn convert_type_to_data(term: Term<Name>, field_type: &Arc<Type>) -> Term<Name> {
if field_type.is_bytearray() {
apply_wrap(DefaultFunction::BData.into(), term)
Term::b_data().apply(term)
} else if field_type.is_int() {
apply_wrap(DefaultFunction::IData.into(), term)
Term::i_data().apply(term)
} else if field_type.is_void() {
apply_wrap(
apply_wrap(Term::Builtin(DefaultFunction::ChooseUnit).force(), term),
Term::Constant(
UplcConstant::Data(PlutusData::Constr(Constr {
tag: convert_constr_to_tag(0).unwrap(),
any_constructor: None,
fields: vec![],
}))
.into(),
),
)
term.choose_unit(Term::Constant(
UplcConstant::Data(PlutusData::Constr(Constr {
tag: convert_constr_to_tag(0).unwrap(),
any_constructor: None,
fields: vec![],
}))
.into(),
))
} else if field_type.is_map() {
apply_wrap(DefaultFunction::MapData.into(), term)
Term::map_data().apply(term)
} else if field_type.is_string() {
apply_wrap(
DefaultFunction::BData.into(),
apply_wrap(DefaultFunction::EncodeUtf8.into(), term),
)
Term::b_data().apply(Term::Builtin(DefaultFunction::EncodeUtf8).apply(term))
} else if field_type.is_tuple() && matches!(field_type.get_uplc_type(), UplcType::Pair(_, _)) {
apply_wrap(
Term::Lambda {
parameter_name: Name {
text: "__pair".to_string(),
unique: 0.into(),
}
.into(),
body: apply_wrap(
DefaultFunction::ListData.into(),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force(),
apply_wrap(
Term::Builtin(DefaultFunction::FstPair).force().force(),
Term::Var(
Name {
text: "__pair".to_string(),
unique: 0.into(),
}
.into(),
),
),
),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force(),
apply_wrap(
Term::Builtin(DefaultFunction::SndPair).force().force(),
Term::Var(
Name {
text: "__pair".to_string(),
unique: 0.into(),
}
.into(),
),
),
),
Term::Constant(UplcConstant::ProtoList(UplcType::Data, vec![]).into()),
),
Term::list_data()
.apply(
Term::mk_cons()
.apply(Term::fst_pair().apply(Term::var("__pair".to_string())))
.apply(
Term::mk_cons()
.apply(Term::snd_pair().apply(Term::var("__pair".to_string())))
.apply(Term::empty_list()),
),
)
.into(),
},
term,
)
)
.lambda("__pair".to_string())
.apply(term)
} else if field_type.is_list() || field_type.is_tuple() {
apply_wrap(DefaultFunction::ListData.into(), term)
Term::list_data().apply(term)
} else if field_type.is_bool() {
if_else(
term,
term.if_else(
Term::Constant(
UplcConstant::Data(PlutusData::Constr(Constr {
tag: convert_constr_to_tag(1).unwrap(),
@@ -288,101 +245,32 @@ pub fn convert_type_to_data(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Name> {
if field_type.is_int() {
apply_wrap(DefaultFunction::UnIData.into(), term)
Term::un_i_data().apply(term)
} else if field_type.is_bytearray() {
apply_wrap(DefaultFunction::UnBData.into(), term)
Term::un_b_data().apply(term)
} else if field_type.is_void() {
delayed_if_else(
apply_wrap(
apply_wrap(
DefaultFunction::EqualsInteger.into(),
Term::Constant(UplcConstant::Integer(0.into()).into()),
),
apply_wrap(
Term::Builtin(DefaultFunction::FstPair).force().force(),
apply_wrap(DefaultFunction::UnConstrData.into(), term),
),
),
Term::Constant(UplcConstant::Unit.into()),
Term::Error,
)
Term::equals_integer()
.apply(Term::integer(0.into()))
.apply(Term::fst_pair().apply(Term::unconstr_data().apply(term)))
.delayed_if_else(Term::unit(), Term::Error)
} else if field_type.is_map() {
apply_wrap(DefaultFunction::UnMapData.into(), term)
Term::unmap_data().apply(term)
} else if field_type.is_string() {
apply_wrap(
DefaultFunction::DecodeUtf8.into(),
apply_wrap(DefaultFunction::UnBData.into(), term),
)
Term::Builtin(DefaultFunction::DecodeUtf8).apply(Term::un_b_data().apply(term))
} else if field_type.is_tuple() && matches!(field_type.get_uplc_type(), UplcType::Pair(_, _)) {
apply_wrap(
Term::Lambda {
parameter_name: Name {
text: "__list_data".to_string(),
unique: 0.into(),
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: "__tail".to_string(),
unique: 0.into(),
}
.into(),
body: apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkPairData),
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: "__list_data".to_string(),
unique: 0.into(),
}
.into(),
),
),
),
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: "__tail".to_string(),
unique: 0.into(),
}
.into(),
),
),
)
.into(),
},
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: "__list_data".to_string(),
unique: 0.into(),
}
.into(),
),
),
)
.into(),
},
apply_wrap(Term::Builtin(DefaultFunction::UnListData), term),
)
Term::mk_pair_data()
.apply(Term::head_list().apply(Term::var("__list_data")))
.apply(Term::head_list().apply(Term::var("__tail".to_string())))
.lambda("__tail".to_string())
.apply(Term::tail_list().apply(Term::var("__list_data")))
.lambda("__list_data")
.apply(Term::unlist_data().apply(term))
} else if field_type.is_list() || field_type.is_tuple() {
apply_wrap(DefaultFunction::UnListData.into(), term)
Term::unlist_data().apply(term)
} else if field_type.is_bool() {
apply_wrap(
apply_wrap(
DefaultFunction::EqualsInteger.into(),
Term::Constant(UplcConstant::Integer(1.into()).into()),
),
apply_wrap(
Term::Builtin(DefaultFunction::FstPair).force().force(),
apply_wrap(DefaultFunction::UnConstrData.into(), term),
),
)
Term::equals_integer()
.apply(Term::integer(1.into()))
.apply(Term::fst_pair().apply(Term::unconstr_data().apply(term)))
} else {
term
}
@@ -564,246 +452,97 @@ pub fn list_access_to_uplc(
if let Some((first, names)) = names.split_first() {
let (current_tipo, tipos) = tipos.split_first().unwrap();
let head_list = if matches!(current_tipo.get_uplc_type(), UplcType::Pair(_, _))
&& is_list_accessor
{
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
}
.into(),
),
)
} else {
convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
),
),
&current_tipo.to_owned(),
)
};
let head_list =
if matches!(current_tipo.get_uplc_type(), UplcType::Pair(_, _)) && is_list_accessor {
Term::head_list().apply(Term::var(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
)))
} else {
convert_data_to_type(
Term::head_list().apply(Term::var(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))),
&current_tipo.to_owned(),
)
};
if names.len() == 1 && tail {
if first == "_" && names[0] == "_" {
Term::Lambda {
parameter_name: Name {
text: "_".to_string(),
unique: 0.into(),
}
.into(),
body: term.into(),
}
term.lambda("_".to_string())
} else if first == "_" {
Term::Lambda {
parameter_name: Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: names[0].clone(),
unique: 0.into(),
}
.into(),
body: term.into(),
},
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
),
),
)
.into(),
}
term.lambda(names[0].clone())
.apply(Term::tail_list().apply(Term::var(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))))
.lambda(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))
} else if names[0] == "_" {
Term::Lambda {
parameter_name: Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: first.clone(),
unique: 0.into(),
}
.into(),
body: term.into(),
},
head_list,
)
.into(),
}
term.lambda(first.clone()).apply(head_list).lambda(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))
} else {
Term::Lambda {
parameter_name: Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: first.clone(),
unique: 0.into(),
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: names[0].clone(),
unique: 0.into(),
}
.into(),
body: term.into(),
},
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
),
),
)
.into(),
},
head_list,
)
.into(),
}
term.lambda(names[0].clone())
.apply(Term::tail_list().apply(Term::var(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))))
.lambda(first.clone())
.apply(head_list)
.lambda(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))
}
} else if names.is_empty() {
if first == "_" {
Term::Lambda {
parameter_name: Name {
text: if check_last_item {
format!("tail_index_{}_{}", current_index, id_list[current_index])
} else {
"_".to_string()
},
unique: 0.into(),
}
.into(),
body: if check_last_item {
delayed_choose_list(
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
),
),
if check_last_item {
Term::tail_list()
.apply(Term::var(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
)))
.delayed_choose_list(
term,
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::Trace).force(),
Term::Constant(
UplcConstant::String(
"List/Tuple/Constr contains more items than expected"
.to_string(),
)
.into(),
),
),
Term::Delay(Term::Error.into()),
)
.force(),
Term::Error.trace(
"List/Tuple/Constr contains more items than expected".to_string(),
),
)
.into()
} else {
term.into()
},
} else {
term
}
.lambda(if check_last_item {
format!("tail_index_{}_{}", current_index, id_list[current_index])
} else {
"_".to_string()
})
} else {
Term::Lambda {
parameter_name: Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
if check_last_item {
Term::tail_list()
.apply(Term::var(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
)))
.delayed_choose_list(
term,
Term::Error.trace(
"List/Tuple/Constr contains more items than expected".to_string(),
),
)
} else {
term
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: first.clone(),
unique: 0.into(),
}
.into(),
body: if check_last_item {
delayed_choose_list(
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
),
),
term,
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::Trace).force(),
Term::Constant(
UplcConstant::String(
"List/Tuple/Constr contains more items than it expected"
.to_string(),
)
.into(),
),
),
Term::Delay(Term::Error.into()),
)
.force(),
)
.into()
} else {
term.into()
},
},
head_list,
)
.into(),
}
.lambda(first.clone())
.apply(head_list)
.lambda(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))
}
} else if first == "_" {
let mut list_access_inner = list_access_to_uplc(
@@ -825,33 +564,15 @@ pub fn list_access_to_uplc(
if &parameter_name.text == "_" {
body.as_ref().clone()
} else {
Term::Lambda {
parameter_name: Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
body: apply_wrap(
list_access_inner,
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
),
),
)
.into(),
}
list_access_inner
.apply(Term::tail_list().apply(Term::var(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))))
.lambda(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))
}
}
_ => list_access_inner,
@@ -859,14 +580,7 @@ pub fn list_access_to_uplc(
match &list_access_inner {
Term::Lambda { .. } => list_access_inner,
_ => Term::Lambda {
parameter_name: Name {
text: "_".to_string(),
unique: 0.into(),
}
.into(),
body: list_access_inner.into(),
},
_ => list_access_inner.lambda("_".to_string()),
}
} else {
let mut list_access_inner = list_access_to_uplc(
@@ -886,88 +600,35 @@ pub fn list_access_to_uplc(
body,
} => {
if &parameter_name.text == "_" {
Term::Lambda {
parameter_name: Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: first.clone(),
unique: 0.into(),
}
.into(),
body: body.as_ref().clone().into(),
},
head_list,
)
.into(),
}
body.as_ref()
.clone()
.lambda(first.clone())
.apply(head_list)
.lambda(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))
} else {
Term::Lambda {
parameter_name: Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: first.clone(),
unique: 0.into(),
}
.into(),
body: apply_wrap(
list_access_inner,
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}
.into(),
),
),
)
.into(),
},
head_list,
)
.into(),
}
list_access_inner
.apply(Term::tail_list().apply(Term::var(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))))
.lambda(first.clone())
.apply(head_list)
.lambda(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
))
}
}
_ => Term::Lambda {
parameter_name: Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: first.clone(),
unique: 0.into(),
}
.into(),
body: list_access_inner.into(),
},
head_list,
)
.into(),
},
_ => list_access_inner
.lambda(first.clone())
.apply(head_list)
.lambda(format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
)),
};
list_access_inner
}
@@ -1316,36 +977,15 @@ pub fn wrap_validator_args(term: Term<Name>, arguments: &[TypedArg]) -> Term<Nam
let mut term = term;
for arg in arguments.iter().rev() {
if !matches!(arg.tipo.get_uplc_type(), UplcType::Data) {
term = apply_wrap(
Term::Lambda {
parameter_name: Name {
text: arg.arg_name.get_variable_name().unwrap_or("_").to_string(),
unique: 0.into(),
}
.into(),
body: term.into(),
},
convert_data_to_type(
Term::Var(
Name {
text: arg.arg_name.get_variable_name().unwrap_or("_").to_string(),
unique: 0.into(),
}
.into(),
),
term = term
.lambda(arg.arg_name.get_variable_name().unwrap_or("_").to_string())
.apply(convert_data_to_type(
Term::var(arg.arg_name.get_variable_name().unwrap_or("_").to_string()),
&arg.tipo,
),
);
));
}
term = Term::Lambda {
parameter_name: Name {
text: arg.arg_name.get_variable_name().unwrap_or("_").to_string(),
unique: 0.into(),
}
.into(),
body: term.into(),
}
term = term.lambda(arg.arg_name.get_variable_name().unwrap_or("_").to_string())
}
term
}
@@ -1353,7 +993,7 @@ pub fn wrap_validator_args(term: Term<Name>, arguments: &[TypedArg]) -> Term<Nam
pub fn wrap_as_multi_validator(spend: Term<Name>, mint: Term<Name>) -> Term<Name> {
Term::equals_integer()
.apply(Term::integer(0.into()))
.apply(constr_index_exposer(Term::var("__second_arg")))
.apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("__second_arg")))
.delayed_if_else(
mint.apply(Term::var("__first_arg"))
.apply(Term::var("__second_arg")),

View File

@@ -5,8 +5,8 @@ use itertools::Itertools;
use uplc::{
ast::{
builder::{
self, apply_wrap, assert_on_list, constr_index_exposer, final_wrapper,
repeat_tail_list, ASSERT_ON_LIST, CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD,
self, assert_on_list, final_wrapper, repeat_tail_list, ASSERT_ON_LIST,
CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD, CONSTR_INDEX_EXPOSER,
},
Constant as UplcConstant, Name, NamedDeBruijn, Program, Term, Type as UplcType,
},
@@ -97,12 +97,6 @@ impl<'a> CodeGenerator<'a> {
let mut term = self.uplc_code_gen(&mut ir_stack);
if self.needs_field_access {
term = builder::constr_get_field(term);
term = builder::constr_fields_exposer(term);
}
// Wrap the validator body if ifThenElse term unit error
term = final_wrapper(term);
@@ -134,9 +128,7 @@ impl<'a> CodeGenerator<'a> {
};
term = wrap_as_multi_validator(spend, mint);
term = builder::constr_get_field(term);
term = builder::constr_fields_exposer(term);
self.needs_field_access = true;
}
term = wrap_validator_args(term, params);
@@ -154,24 +146,26 @@ impl<'a> CodeGenerator<'a> {
self.convert_opaque_type_to_inner_ir(&mut ir_stack);
let mut term = self.uplc_code_gen(&mut ir_stack);
if self.needs_field_access {
term = builder::constr_get_field(term);
term = builder::constr_fields_exposer(term);
}
let term = self.uplc_code_gen(&mut ir_stack);
self.finalize(term, false)
}
fn finalize(&mut self, term: Term<Name>, wrap_as_validator: bool) -> Program<Name> {
let term = if wrap_as_validator || self.used_data_assert_on_list {
let mut term = if wrap_as_validator || self.used_data_assert_on_list {
assert_on_list(term)
} else {
term
};
if self.needs_field_access {
term = builder::constr_get_field(term);
term = builder::constr_fields_exposer(term);
term = builder::constr_index_exposer(term);
}
let mut program = Program {
version: (1, 0, 0),
term,
@@ -708,8 +702,6 @@ impl<'a> CodeGenerator<'a> {
tipo,
..
} => {
self.needs_field_access = true;
ir_stack.push(Air::RecordAccess {
scope: scope.clone(),
record_index: *index,
@@ -4508,41 +4500,31 @@ impl<'a> CodeGenerator<'a> {
.apply(right)
.if_else(Term::bool(false), Term::bool(true))
}
BinOp::LtInt => apply_wrap(
apply_wrap(DefaultFunction::LessThanInteger.into(), left),
right,
),
BinOp::LtEqInt => apply_wrap(
apply_wrap(DefaultFunction::LessThanEqualsInteger.into(), left),
right,
),
BinOp::GtEqInt => apply_wrap(
apply_wrap(DefaultFunction::LessThanEqualsInteger.into(), right),
left,
),
BinOp::GtInt => apply_wrap(
apply_wrap(DefaultFunction::LessThanInteger.into(), right),
left,
),
BinOp::AddInt => {
apply_wrap(apply_wrap(DefaultFunction::AddInteger.into(), left), right)
}
BinOp::SubInt => apply_wrap(
apply_wrap(DefaultFunction::SubtractInteger.into(), left),
right,
),
BinOp::MultInt => apply_wrap(
apply_wrap(DefaultFunction::MultiplyInteger.into(), left),
right,
),
BinOp::DivInt => apply_wrap(
apply_wrap(DefaultFunction::DivideInteger.into(), left),
right,
),
BinOp::ModInt => {
apply_wrap(apply_wrap(DefaultFunction::ModInteger.into(), left), right)
}
BinOp::LtInt => Term::Builtin(DefaultFunction::LessThanInteger)
.apply(left)
.apply(right),
BinOp::LtEqInt => Term::Builtin(DefaultFunction::LessThanEqualsInteger)
.apply(left)
.apply(right),
BinOp::GtEqInt => Term::Builtin(DefaultFunction::LessThanEqualsInteger)
.apply(right)
.apply(left),
BinOp::GtInt => Term::Builtin(DefaultFunction::LessThanInteger)
.apply(right)
.apply(left),
BinOp::AddInt => Term::add_integer().apply(left).apply(right),
BinOp::SubInt => Term::Builtin(DefaultFunction::SubtractInteger)
.apply(left)
.apply(right),
BinOp::MultInt => Term::Builtin(DefaultFunction::MultiplyInteger)
.apply(left)
.apply(right),
BinOp::DivInt => Term::Builtin(DefaultFunction::DivideInteger)
.apply(left)
.apply(right),
BinOp::ModInt => Term::Builtin(DefaultFunction::ModInteger)
.apply(left)
.apply(right),
};
arg_stack.push(term);
}
@@ -4607,6 +4589,7 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term);
}
Air::AssertConstr { constr_index, .. } => {
self.needs_field_access = true;
let constr = arg_stack.pop().unwrap();
let mut term = arg_stack.pop().unwrap();
@@ -4616,7 +4599,7 @@ impl<'a> CodeGenerator<'a> {
term = Term::equals_integer()
.apply(Term::integer(constr_index.into()))
.apply(constr_index_exposer(constr))
.apply(Term::var(CONSTR_INDEX_EXPOSER.to_string()).apply(constr))
.delayed_if_else(term, error_term);
arg_stack.push(term);
@@ -4638,6 +4621,7 @@ impl<'a> CodeGenerator<'a> {
Air::When {
subject_name, tipo, ..
} => {
self.needs_field_access = true;
let subject = arg_stack.pop().unwrap();
let subject = if tipo.is_int()
@@ -4649,7 +4633,7 @@ impl<'a> CodeGenerator<'a> {
{
subject
} else {
constr_index_exposer(subject)
Term::var(CONSTR_INDEX_EXPOSER).apply(subject)
};
let mut term = arg_stack.pop().unwrap();
@@ -4813,7 +4797,7 @@ impl<'a> CodeGenerator<'a> {
} else {
Term::equals_integer()
.apply(checker)
.apply(constr_index_exposer(Term::var(subject_name)))
.apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var(subject_name)))
};
let term = condition
@@ -5031,6 +5015,7 @@ impl<'a> CodeGenerator<'a> {
indices,
..
} => {
self.needs_field_access = true;
let tail_name_prefix = "__tail_index".to_string();
let record = arg_stack.pop().unwrap();
@@ -5105,7 +5090,6 @@ impl<'a> CodeGenerator<'a> {
term = term.lambda(tail_name).apply(tail_list);
}
self.needs_field_access = true;
term = term
.lambda(prev_tail_name)
.apply(Term::var(CONSTR_FIELDS_EXPOSER.to_string()).apply(record));

View File

@@ -50,6 +50,10 @@ impl Term<Name> {
Term::Constant(Constant::Bool(b).into())
}
pub fn unit() -> Self {
Term::Constant(Constant::Unit.into())
}
pub fn empty_list() -> Self {
Term::Constant(Constant::ProtoList(Type::Data, vec![]).into())
}
@@ -80,6 +84,26 @@ impl Term<Name> {
Term::Builtin(DefaultFunction::IData)
}
pub fn unconstr_data() -> Self {
Term::Builtin(DefaultFunction::UnConstrData)
}
pub fn un_i_data() -> Self {
Term::Builtin(DefaultFunction::UnIData)
}
pub fn un_b_data() -> Self {
Term::Builtin(DefaultFunction::UnBData)
}
pub fn unmap_data() -> Self {
Term::Builtin(DefaultFunction::UnMapData)
}
pub fn unlist_data() -> Self {
Term::Builtin(DefaultFunction::UnListData)
}
pub fn equals_integer() -> Self {
Term::Builtin(DefaultFunction::EqualsInteger)
}
@@ -145,6 +169,21 @@ impl Term<Name> {
.apply(else_term)
}
pub fn choose_unit(self, then_term: Self) -> Self {
Term::Builtin(DefaultFunction::ChooseUnit)
.force()
.apply(self)
.apply(then_term)
}
pub fn delayed_choose_unit(self, then_term: Self) -> Self {
Term::Builtin(DefaultFunction::ChooseUnit)
.force()
.apply(self)
.apply(then_term.delay())
.force()
}
pub fn delayed_if_else(self, then_term: Self, else_term: Self) -> Self {
Term::Builtin(DefaultFunction::IfThenElse)
.force()
@@ -173,540 +212,93 @@ impl Term<Name> {
}
}
pub fn apply_wrap(function: Term<Name>, arg: Term<Name>) -> Term<Name> {
Term::Apply {
function: function.into(),
argument: arg.into(),
}
}
pub fn final_wrapper(term: Term<Name>) -> Term<Name> {
Term::Force(
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Force(Term::Builtin(DefaultFunction::IfThenElse).into()).into(),
argument: term.into(),
}
.into(),
argument: Term::Delay(Term::Constant(Constant::Unit.into()).into()).into(),
}
.into(),
argument: Term::Delay(Term::Error.into()).into(),
}
.into(),
)
term.delayed_if_else(Term::unit(), Term::Error)
}
pub fn assert_on_list(term: Term<Name>) -> Term<Name> {
apply_wrap(
Term::Lambda {
parameter_name: Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}
.into(),
body: apply_wrap(
Term::Lambda {
parameter_name: Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}
.into(),
body: term.into(),
},
apply_wrap(
Term::Var(
Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}
.into(),
),
Term::Var(
Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}
.into(),
),
),
)
.into(),
},
Term::Lambda {
parameter_name: Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}
.into(),
body: Term::Lambda {
parameter_name: Name {
text: "list_to_check".to_string(),
unique: 0.into(),
}
.into(),
body: Term::Lambda {
parameter_name: Name {
text: "check_with".to_string(),
unique: 0.into(),
}
.into(),
body: delayed_choose_list(
Term::Var(
Name {
text: "list_to_check".to_string(),
unique: 0.into(),
}
.into(),
term.lambda(ASSERT_ON_LIST.to_string())
.apply(Term::var(ASSERT_ON_LIST.to_string()).apply(Term::var(ASSERT_ON_LIST.to_string())))
.lambda(ASSERT_ON_LIST.to_string())
.apply(
Term::var("__list_to_check".to_string())
.delayed_choose_list(
Term::unit(),
Term::var("__check_with".to_string())
.apply(Term::head_list().apply(Term::var("__list_to_check".to_string())))
.choose_unit(
Term::var(ASSERT_ON_LIST.to_string())
.apply(Term::var(ASSERT_ON_LIST.to_string()))
.apply(
Term::tail_list()
.apply(Term::var("__list_to_check".to_string())),
)
.apply(Term::var("__check_with".to_string())),
),
Term::Constant(Constant::Unit.into()),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::ChooseUnit).force(),
apply_wrap(
Term::Var(
Name {
text: "check_with".to_string(),
unique: 0.into(),
}
.into(),
),
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: "list_to_check".to_string(),
unique: 0.into(),
}
.into(),
),
),
),
),
apply_wrap(
apply_wrap(
apply_wrap(
Term::Var(
Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}
.into(),
),
Term::Var(
Name {
text: ASSERT_ON_LIST.to_string(),
unique: 0.into(),
}
.into(),
),
),
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: "list_to_check".to_string(),
unique: 0.into(),
}
.into(),
),
),
),
Term::Var(
Name {
text: "check_with".to_string(),
unique: 0.into(),
}
.into(),
),
),
),
)
.into(),
}
.into(),
}
.into(),
},
)
)
.lambda("__check_with".to_string())
.lambda("__list_to_check".to_string())
.lambda(ASSERT_ON_LIST),
)
}
pub fn constr_fields_exposer(term: Term<Name>) -> Term<Name> {
Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: CONSTR_FIELDS_EXPOSER.to_string(),
unique: 0.into(),
}
.into(),
body: term.into(),
}
.into(),
argument: Term::Lambda {
parameter_name: Name {
text: "__constr_var".to_string(),
unique: 0.into(),
}
.into(),
body: Term::Apply {
function: Term::Force(
Term::Force(Term::Builtin(DefaultFunction::SndPair).into()).into(),
)
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::UnConstrData).into(),
argument: Term::Var(
Name {
text: "__constr_var".to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
}
.into(),
}
.into(),
}
.into(),
}
term.lambda(CONSTR_FIELDS_EXPOSER.to_string()).apply(
Term::snd_pair()
.apply(Term::unconstr_data().apply(Term::var("__constr_var".to_string())))
.lambda("__constr_var"),
)
}
pub fn constr_index_exposer(term: Term<Name>) -> Term<Name> {
Term::Apply {
function: Term::Force(Term::Force(Term::Builtin(DefaultFunction::FstPair).into()).into())
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::UnConstrData).into(),
argument: term.into(),
}
.into(),
}
term.lambda(CONSTR_INDEX_EXPOSER.to_string()).apply(
Term::fst_pair()
.apply(Term::unconstr_data().apply(Term::var("__constr_var".to_string())))
.lambda("__constr_var".to_string()),
)
}
pub fn constr_get_field(term: Term<Name>) -> Term<Name> {
Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: CONSTR_GET_FIELD.to_string(),
unique: 0.into(),
}
.into(),
body: term.into(),
}
.into(),
argument: Term::Lambda {
parameter_name: Name {
text: "__constr_list".to_string(),
unique: 0.into(),
}
.into(),
body: Term::Lambda {
parameter_name: Name {
text: "__arg_number".to_string(),
unique: 0.into(),
}
.into(),
body: Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: "__recurse".to_string(),
unique: 0.into(),
}
.into(),
body: Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Var(
Name {
text: "__recurse".to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
argument: Term::Var(
Name {
text: "__recurse".to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
}
.into(),
// Start recursive with index 0 of list
argument: Term::Constant(Constant::Integer(0.into()).into()).into(),
}
.into(),
argument: Term::Var(
Name {
text: "__constr_list".to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
}
.into(),
}
.into(),
argument: Term::Lambda {
parameter_name: Name {
text: "__self_recursor".to_string(),
unique: 0.into(),
}
.into(),
body: Term::Lambda {
parameter_name: Name {
text: "__current_arg_number".to_string(),
unique: 0.into(),
}
.into(),
body: Term::Lambda {
parameter_name: Name {
text: "__list_of_constr_args".to_string(),
unique: 0.into(),
}
.into(),
body: Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Force(
Term::Builtin(DefaultFunction::IfThenElse)
.into(),
)
.into(),
argument: Term::Apply {
function: Term::Apply {
function: Term::Builtin(
DefaultFunction::EqualsInteger,
)
.into(),
argument: Term::Var(
Name {
text: "__arg_number".to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
}
.into(),
argument: Term::Var(
Name {
text: "__current_arg_number"
.to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
}
.into(),
}
.into(),
argument: Term::Force(
Term::Builtin(DefaultFunction::HeadList).into(),
)
.into(),
}
.into(),
argument: Term::Lambda {
parameter_name: Name {
text: "__current_list_of_constr_args".to_string(),
unique: 0.into(),
}
.into(),
body: Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Var(
Name {
text: "__self_recursor".to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
argument: Term::Var(
Name {
text: "__self_recursor".to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
}
.into(),
argument: Term::Apply {
function: Term::Apply {
function: Term::Builtin(
DefaultFunction::AddInteger,
)
.into(),
argument: Term::Var(
Name {
text: "__current_arg_number"
.to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
}
.into(),
argument: Term::Constant(
Constant::Integer(1.into()).into(),
)
.into(),
}
.into(),
}
.into(),
argument: Term::Apply {
function: Term::Force(
Term::Builtin(DefaultFunction::TailList)
.into(),
)
.into(),
argument: Term::Var(
Name {
text: "__current_list_of_constr_args"
.to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
}
.into(),
}
.into(),
}
.into(),
}
.into(),
argument: Term::Var(
Name {
text: "__list_of_constr_args".to_string(),
unique: 0.into(),
}
.into(),
)
.into(),
}
.into(),
}
.into(),
}
.into(),
}
.into(),
}
.into(),
}
.into(),
}
.into(),
}
}
pub fn delayed_if_else(
condition: Term<Name>,
then_term: Term<Name>,
else_term: Term<Name>,
) -> Term<Name> {
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::IfThenElse).force().into(),
argument: condition.into(),
}
.into(),
argument: Term::Delay(then_term.into()).into(),
}
.into(),
argument: Term::Delay(else_term.into()).into(),
}
.force()
}
pub fn if_else(condition: Term<Name>, then_term: Term<Name>, else_term: Term<Name>) -> Term<Name> {
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::IfThenElse).force().into(),
argument: condition.into(),
}
.into(),
argument: then_term.into(),
}
.into(),
argument: else_term.into(),
}
}
pub fn delayed_choose_list(
list: Term<Name>,
empty_list_term: Term<Name>,
else_term: Term<Name>,
) -> Term<Name> {
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::ChooseList)
.force()
.force()
.into(),
argument: list.into(),
}
.into(),
argument: Term::Delay(empty_list_term.into()).into(),
}
.into(),
argument: Term::Delay(else_term.into()).into(),
}
.force()
}
pub fn choose_list(
list: Term<Name>,
empty_list_term: Term<Name>,
else_term: Term<Name>,
) -> Term<Name> {
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::ChooseList)
.force()
.force()
.into(),
argument: list.into(),
}
.into(),
argument: empty_list_term.into(),
}
.into(),
argument: else_term.into(),
}
term.lambda(CONSTR_GET_FIELD.to_string())
.apply(
Term::var(CONSTR_GET_FIELD.to_string())
.apply(Term::var(CONSTR_GET_FIELD.to_string()))
.apply(Term::integer(0.into())),
)
.lambda(CONSTR_GET_FIELD)
.apply(
Term::equals_integer()
.apply(Term::var("__wanted_arg".to_string()))
.apply(Term::var("__current_arg_number".to_string()))
.if_else(
Term::head_list(),
Term::var(CONSTR_GET_FIELD)
.apply(Term::var(CONSTR_GET_FIELD))
.apply(
Term::add_integer()
.apply(Term::var("__current_arg_number".to_string()))
.apply(Term::integer(1.into())),
)
.apply(
Term::tail_list()
.apply(Term::var("__current_list_of_constr_args".to_string())),
)
.apply(Term::var("__wanted_arg"))
.lambda("__current_list_of_constr_args".to_string()),
)
.apply(Term::var("__list_of_constr_args".to_string()))
.lambda("__wanted_arg".to_string())
.lambda("__list_of_constr_args")
.lambda("__current_arg_number".to_string())
.lambda(CONSTR_GET_FIELD.to_string()),
)
}
pub fn repeat_tail_list(term: Term<Name>, repeat: usize) -> Term<Name> {
let mut term = term;
for _ in 0..repeat {
term = Term::Apply {
function: Term::Builtin(DefaultFunction::TailList).force().into(),
argument: term.into(),
};
term = Term::tail_list().apply(term);
}
term
}

View File

@@ -4,7 +4,7 @@ use indexmap::IndexMap;
use itertools::Itertools;
use crate::{
ast::{builder::apply_wrap, Name, Program, Term},
ast::{Name, Program, Term},
builtins::DefaultFunction,
};
// use crate::builtins::{DefaultFunction};
@@ -33,21 +33,13 @@ impl Program<Name> {
for default_func_index in builtin_map.keys().sorted().cloned() {
let default_func: DefaultFunction = default_func_index.try_into().unwrap();
term = apply_wrap(
Term::Lambda {
parameter_name: Name {
text: format!("__{}_wrapped", default_func.aiken_name()),
unique: 0.into(),
}
.into(),
body: term.into(),
},
if default_func.force_count() == 1 {
term = term
.lambda(format!("__{}_wrapped", default_func.aiken_name()))
.apply(if default_func.force_count() == 1 {
Term::Builtin(default_func).force()
} else {
Term::Builtin(default_func).force().force()
},
);
});
}
Program {