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

@@ -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 {