chore: fix up when tuple deconstruction test

add inline test for optimization tests
add some more builder functions
This commit is contained in:
microproofs 2023-05-11 18:06:46 -04:00
parent 1fb31e246c
commit c3eab4cc2a
3 changed files with 383 additions and 258 deletions

View File

@ -9,6 +9,7 @@ use aiken_lang::{
}; };
use uplc::{ use uplc::{
ast::{Constant, Data, DeBruijn, Name, Program, Term, Type}, ast::{Constant, Data, DeBruijn, Name, Program, Term, Type},
builder::CONSTR_GET_FIELD,
machine::cost_model::ExBudget, machine::cost_model::ExBudget,
optimize, optimize,
}; };
@ -1373,228 +1374,265 @@ fn acceptance_test_14_list_creation() {
); );
} }
// #[test] #[test]
// fn when_tuple_deconstruction() { fn when_tuple_deconstruction() {
// let src = r#" let src = r#"
// type Thing { type Thing {
// idx: Int, idx: Int,
// } }
// type Datum { type Datum {
// A(Thing) A(Thing)
// B B
// } }
// type RedSpend { type RedSpend {
// Spend(Int) Spend(Int)
// Buy Buy
// } }
// validator { validator {
// fn spend(dat: Datum, red: RedSpend, ctx: Data) { fn spend(dat: Datum, red: RedSpend, ctx: Data) {
// when (dat, red) is { when (dat, red) is {
// (A(a), Spend(x)) -> (A(a), Spend(x)) ->
// (a.idx == x)? (a.idx == x)?
// (_, _) -> (_, _) ->
// True True
// } }
// } }
// } }
// "#; "#;
// assert_uplc( assert_uplc(
// src, src,
// Term::equals_integer() Term::equals_integer()
// .apply(Term::integer(0.into())) .apply(Term::integer(0.into()))
// .apply(Term::var("constr_index_exposer").apply(Term::var("dat"))) .apply(Term::var("constr_index_exposer").apply(Term::var("dat")))
// .if_else( .if_else(
// Term::equals_integer() Term::equals_integer()
// .apply(Term::integer(0.into())) .apply(Term::integer(0.into()))
// .apply(Term::var("constr_index_exposer").apply(Term::var("red"))) .apply(Term::var("constr_index_exposer").apply(Term::var("red")))
// .if_else( .if_else(
// Term::equals_integer() Term::equals_integer()
// .apply( .apply(
// Term::un_i_data().apply( Term::un_i_data().apply(
// Term::var("constr_get_field") Term::var("constr_get_field")
// .apply( .apply(
// Term::var("constr_fields_exposer") Term::var("constr_fields_exposer")
// .apply(Term::var("a")), .apply(Term::var("a")),
// ) )
// .apply(Term::integer(0.into())), .apply(Term::integer(0.into())),
// ), ),
// ) )
// .apply(Term::var("x")) .apply(Term::var("x"))
// .lambda("x") .lambda("x")
// .apply( .apply(
// Term::un_i_data() Term::un_i_data()
// .apply(Term::head_list().apply(Term::var("red_constr_fields"))), .apply(Term::head_list().apply(Term::var("red_constr_fields"))),
// ) )
// .lambda("red_constr_fields") .lambda("red_constr_fields")
// .apply(Term::var("constr_fields_exposer").apply(Term::var("red"))) .apply(Term::var("constr_fields_exposer").apply(Term::var("red")))
// .delay(), .delay(),
// Term::var("other_clauses"), Term::var("other_clauses"),
// ) )
// .force() .force()
// .lambda("a") .lambda("a")
// .apply(Term::head_list().apply(Term::var("dat_constr_fields"))) .apply(Term::head_list().apply(Term::var("dat_constr_fields")))
// .lambda("dat_constr_fields") .lambda("dat_constr_fields")
// .apply(Term::var("constr_fields_exposer").apply(Term::var("dat"))) .apply(Term::var("constr_fields_exposer").apply(Term::var("dat")))
// .delay(), .delay(),
// Term::var("other_clauses"), Term::var("other_clauses"),
// ) )
// .force() .force()
// .lambda("other_clauses") .lambda("other_clauses")
// .apply(Term::bool(true).delay()) .apply(Term::bool(true).delay())
// .lambda("dat") .lambda("dat")
// .apply(Term::fst_pair().apply(Term::var("pair_subject"))) .apply(Term::fst_pair().apply(Term::var("pair_subject")))
// .lambda("red") .lambda("red")
// .apply(Term::snd_pair().apply(Term::var("pair_subject"))) .apply(Term::snd_pair().apply(Term::var("pair_subject")))
// .lambda("pair_subject") .lambda("pair_subject")
// .apply( .apply(
// Term::mk_pair_data() Term::mk_pair_data()
// .apply(Term::var("dat")) .apply(Term::var("dat"))
// .apply(Term::var("red")), .apply(Term::var("red")),
// ) )
// .delayed_if_else(Term::unit(), Term::Error) .delayed_if_else(Term::unit(), Term::Error)
// .lambda("dat") .lambda("dat")
// .apply( .apply(
// Term::var("expect_Datum") Term::var("dat").lambda("_").apply(
// .lambda("expect_Datum") Term::var("expect_Datum")
// .apply( .lambda("expect_Datum")
// Term::equals_integer() .apply(
// .apply(Term::integer(0.into())) Term::equals_integer()
// .apply(Term::var("constr_index_exposer").apply(Term::var("dat"))) .apply(Term::integer(0.into()))
// .delayed_if_else( .apply(Term::var("subject"))
// Term::tail_list() .delayed_if_else(
// .apply(Term::var("dat_constr_fields")) Term::tail_list()
// .delayed_choose_list( .apply(Term::var("dat_constr_fields"))
// Term::var("expect_Thing") .delayed_choose_list(
// .apply(Term::var("field_1")) Term::unit().lambda("_").apply(
// .choose_unit(Term::unit()) Term::var("expect_Thing")
// .lambda("field_1") .apply(Term::var("field_1")),
// .apply( ),
// Term::head_list() Term::Error.trace(Term::string("List/Tuple/Constr contains more items than expected")),
// .apply(Term::var("dat_constr_fields")), )
// ), .lambda("field_1")
// Term::Error.trace(Term::string("Expected...")), .apply(
// ) Term::head_list().apply(Term::var("dat_constr_fields")),
// .lambda("dat_constr_fields") )
// .apply( .lambda("dat_constr_fields")
// Term::var("constr_fields_exposer").apply(Term::var("dat")), .apply(
// ), Term::var("constr_fields_exposer")
// Term::equals_integer() .apply(Term::var("dat")),
// .apply(Term::integer(1.into())) ),
// .apply( Term::equals_integer()
// Term::var("constr_index_exposer").apply(Term::var("dat")), .apply(Term::integer(1.into()))
// ) .apply(Term::var("subject"))
// .delayed_if_else( .delayed_if_else(
// Term::unit().lambda("_").apply( Term::var("constr_fields_exposer")
// Term::var("constr_fields_exposer") .apply(Term::var("dat"))
// .apply(Term::var("dat")) .delayed_choose_list(
// .delayed_choose_list( Term::unit(),
// Term::unit(), Term::Error
// Term::Error .trace(Term::string("Expected no fields for Constr"))
// .trace(Term::string("Expected......")), ),
// ), Term::Error.trace(Term::string("Constr index did not match any type variant")),
// ), ),
// Term::Error.trace(Term::string("Expected...")), )
// ), .lambda("subject")
// ) .apply(Term::var("constr_index_exposer").apply(Term::var("dat")))
// .lambda("dat"), .lambda("dat"),
// ) )
// .lambda("expect_Thing") .lambda("expect_Thing")
// .apply( .apply(
// Term::equals_integer() Term::equals_integer()
// .apply(Term::integer(0.into())) .apply(Term::integer(0.into()))
// .apply(Term::var("constr_index_exposer").apply(Term::var("field_1"))) .apply(Term::var("subject"))
// .delayed_if_else( .delayed_if_else(
// Term::tail_list() Term::tail_list()
// .apply(Term::var("field_1_constr_fields")) .apply(Term::var("field_1_constr_fields"))
// .delayed_choose_list( .delayed_choose_list(
// Term::unit().lambda("_").apply( Term::unit(),
// Term::un_i_data().apply( Term::Error.trace(Term::string("List/Tuple/Constr contains more items than expected")),
// Term::head_list() )
// .apply(Term::var("field_1_constr_fields")), .lambda("idx")
// ), .apply(
// ), Term::un_i_data().apply(
// Term::Error.trace(Term::string("Expected...")), Term::head_list()
// ) .apply(Term::var("field_1_constr_fields")),
// .lambda("field_1_constr_fields") ),
// .apply( )
// Term::var("constr_fields_exposer") .lambda("field_1_constr_fields")
// .apply(Term::var("field_1")), .apply(
// ), Term::var("constr_fields_exposer")
// Term::Error.trace(Term::string("Expected...")), .apply(Term::var("field_1")),
// ) ),
// .lambda("field_1"), Term::Error.trace(Term::string(
// ) "Constr index did not match any type variant",
// .apply(Term::var("dat")) )),
// .choose_unit(Term::var("dat")), )
// ) .lambda("subject")
// .lambda("red") .apply(
// .apply( Term::var("constr_index_exposer").apply(Term::var("field_1")),
// Term::var("expect_RedSpend") )
// .lambda("expect_RedSpend") .lambda("field_1"),
// .apply( )
// Term::equals_integer() .apply(Term::var("dat")),
// .apply(Term::integer(0.into())) ),
// .apply(Term::var("constr_index_exposer").apply(Term::var("red"))) )
// .delayed_if_else( .lambda("red")
// Term::tail_list() .apply(
// .apply(Term::var("red_constr_fields")) Term::var("red").lambda("_").apply(
// .delayed_choose_list( Term::var("expect_RedSpend")
// Term::unit().lambda("_").apply(Term::un_i_data().apply( .lambda("expect_RedSpend")
// Term::head_list().apply(Term::var("red_constr_fields")), .apply(
// )), Term::equals_integer()
// Term::Error.trace(Term::string("Too many items")), .apply(Term::integer(0.into()))
// ) .apply(Term::var("subject"))
// .lambda("red_constr_fields") .delayed_if_else(
// .apply( Term::tail_list()
// Term::var("constr_fields_exposer").apply(Term::var("red")), .apply(Term::var("red_constr_fields"))
// ), .delayed_choose_list(
// Term::equals_integer() Term::unit(),
// .apply(Term::integer(1.into())) Term::Error.trace(Term::string("List/Tuple/Constr contains more items than expected")),
// .apply( )
// Term::var("constr_index_exposer").apply(Term::var("red")), .lambda("field_1")
// ) .apply(Term::un_i_data().apply(
// .delayed_if_else( Term::head_list().apply(Term::var("red_constr_fields")),
// Term::var("constr_fields_exposer") ))
// .apply(Term::var("red")) .lambda("red_constr_fields")
// .delayed_choose_list( .apply(
// Term::unit(), Term::var("constr_fields_exposer")
// Term::Error.trace(Term::string("Expected......")), .apply(Term::var("red")),
// ), ),
// Term::Error.trace(Term::string("Expected...")), Term::equals_integer()
// ), .apply(Term::integer(1.into()))
// ) .apply(Term::var("subject"))
// .lambda("red"), .delayed_if_else(
// ) Term::var("constr_fields_exposer")
// .apply(Term::var("red")) .apply(Term::var("red"))
// .choose_unit(Term::var("red")), .delayed_choose_list(
// ) Term::unit(),
// .lambda("ctx") Term::Error
// .lambda("red") .trace(Term::string("Expected no fields for Constr"))
// .lambda("dat") ),
// .lambda("constr_get_field") Term::Error.trace(Term::string("Constr index did not match any type variant")),
// .apply( ),
// Term::var("constr_get_field") )
// .apply(Term::var("constr_get_field")) .lambda("subject")
// .apply(Term::integer(0.into())), .apply(Term::var("constr_index_exposer").apply(Term::var("red")))
// ) .lambda("red"),
// .lambda("constr_get_field") )
// .apply(Term::bool(false).lambda("x")) .apply(Term::var("red")),
// .lambda("constr_fields_exposer") ),
// .apply( )
// Term::snd_pair() .lambda("ctx")
// .apply(Term::unconstr_data().apply(Term::var("x"))) .lambda("red")
// .lambda("x"), .lambda("dat")
// ) .lambda("constr_get_field")
// .lambda("constr_index_exposer") .apply(
// .apply( Term::var("constr_get_field")
// Term::fst_pair() .apply(Term::var("constr_get_field"))
// .apply(Term::unconstr_data().apply(Term::var("x"))) .apply(Term::integer(0.into())),
// .lambda("x"), )
// ), .lambda("constr_get_field")
// false, .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"))
.apply(Term::integer(1.into())),
)
.apply(
Term::tail_list().apply(Term::var("__current_list_of_constr_args")),
)
.apply(Term::var("__wanted_arg"))
.lambda("__current_list_of_constr_args"),
)
.apply(Term::var("__list_of_constr_args"))
.lambda("__wanted_arg")
.lambda("__list_of_constr_args")
.lambda("__current_arg_number")
.lambda(CONSTR_GET_FIELD),
)
.lambda("constr_fields_exposer")
.apply(
Term::snd_pair()
.apply(Term::unconstr_data().apply(Term::var("x")))
.lambda("x"),
)
.lambda("constr_index_exposer")
.apply(
Term::fst_pair()
.apply(Term::unconstr_data().apply(Term::var("x")))
.lambda("x"),
),
false,
);
}

View File

@ -10,6 +10,7 @@ pub const CONSTR_GET_FIELD: &str = "__constr_get_field";
pub const EXPECT_ON_LIST: &str = "__expect_on_list"; pub const EXPECT_ON_LIST: &str = "__expect_on_list";
impl<T> Term<T> { impl<T> Term<T> {
// Terms
pub fn apply(self, arg: Self) -> Self { pub fn apply(self, arg: Self) -> Self {
Term::Apply { Term::Apply {
function: self.into(), function: self.into(),
@ -25,6 +26,7 @@ impl<T> Term<T> {
Term::Delay(self.into()) Term::Delay(self.into())
} }
// Primitives
pub fn integer(i: num_bigint::BigInt) -> Self { pub fn integer(i: num_bigint::BigInt) -> Self {
Term::Constant(Constant::Integer(i).into()) Term::Constant(Constant::Integer(i).into())
} }
@ -75,6 +77,7 @@ impl<T> Term<T> {
) )
} }
// Builtins
pub fn constr_data() -> Self { pub fn constr_data() -> Self {
Term::Builtin(DefaultFunction::ConstrData) Term::Builtin(DefaultFunction::ConstrData)
} }
@ -135,6 +138,14 @@ impl<T> Term<T> {
Term::Builtin(DefaultFunction::EqualsByteString) Term::Builtin(DefaultFunction::EqualsByteString)
} }
pub fn less_than_bytearray() -> Self {
Term::Builtin(DefaultFunction::LessThanByteString)
}
pub fn less_than_equals_bytearray() -> Self {
Term::Builtin(DefaultFunction::LessThanEqualsByteString)
}
pub fn equals_data() -> Self { pub fn equals_data() -> Self {
Term::Builtin(DefaultFunction::EqualsData) Term::Builtin(DefaultFunction::EqualsData)
} }
@ -159,6 +170,58 @@ impl<T> Term<T> {
Term::Builtin(DefaultFunction::LengthOfByteString) Term::Builtin(DefaultFunction::LengthOfByteString)
} }
pub fn cons_bytearray() -> Self {
Term::Builtin(DefaultFunction::ConsByteString)
}
pub fn slice_bytearray() -> Self {
Term::Builtin(DefaultFunction::SliceByteString)
}
pub fn append_bytearray() -> Self {
Term::Builtin(DefaultFunction::AppendByteString)
}
pub fn index_bytearray() -> Self {
Term::Builtin(DefaultFunction::IndexByteString)
}
pub fn sha2_256() -> Self {
Term::Builtin(DefaultFunction::Sha2_256)
}
pub fn sha3_256() -> Self {
Term::Builtin(DefaultFunction::Sha3_256)
}
pub fn blake2b_256() -> Self {
Term::Builtin(DefaultFunction::Blake2b_256)
}
pub fn verify_ed25519_signature() -> Self {
Term::Builtin(DefaultFunction::VerifyEd25519Signature)
}
pub fn verify_ecdsa_secp256k1_signature() -> Self {
Term::Builtin(DefaultFunction::VerifyEcdsaSecp256k1Signature)
}
pub fn verify_schnorr_secp256k1_signature() -> Self {
Term::Builtin(DefaultFunction::VerifySchnorrSecp256k1Signature)
}
pub fn decode_utf8() -> Self {
Term::Builtin(DefaultFunction::DecodeUtf8)
}
pub fn append_string() -> Self {
Term::Builtin(DefaultFunction::AppendString)
}
pub fn encode_utf8() -> Self {
Term::Builtin(DefaultFunction::EncodeUtf8)
}
pub fn head_list() -> Self { pub fn head_list() -> Self {
Term::Builtin(DefaultFunction::HeadList).force() Term::Builtin(DefaultFunction::HeadList).force()
} }
@ -266,83 +329,75 @@ impl Term<Name> {
} }
pub fn constr_fields_exposer(self) -> Self { pub fn constr_fields_exposer(self) -> Self {
self.lambda(CONSTR_FIELDS_EXPOSER.to_string()).apply( self.lambda(CONSTR_FIELDS_EXPOSER).apply(
Term::snd_pair() Term::snd_pair()
.apply(Term::unconstr_data().apply(Term::var("__constr_var".to_string()))) .apply(Term::unconstr_data().apply(Term::var("__constr_var")))
.lambda("__constr_var"), .lambda("__constr_var"),
) )
} }
pub fn constr_index_exposer(self) -> Self { pub fn constr_index_exposer(self) -> Self {
self.lambda(CONSTR_INDEX_EXPOSER.to_string()).apply( self.lambda(CONSTR_INDEX_EXPOSER).apply(
Term::fst_pair() Term::fst_pair()
.apply(Term::unconstr_data().apply(Term::var("__constr_var".to_string()))) .apply(Term::unconstr_data().apply(Term::var("__constr_var")))
.lambda("__constr_var".to_string()), .lambda("__constr_var"),
) )
} }
pub fn constr_get_field(self) -> Self { pub fn constr_get_field(self) -> Self {
self.lambda(CONSTR_GET_FIELD.to_string()) self.lambda(CONSTR_GET_FIELD)
.apply( .apply(
Term::var(CONSTR_GET_FIELD.to_string()) Term::var(CONSTR_GET_FIELD)
.apply(Term::var(CONSTR_GET_FIELD.to_string())) .apply(Term::var(CONSTR_GET_FIELD))
.apply(Term::integer(0.into())), .apply(Term::integer(0.into())),
) )
.lambda(CONSTR_GET_FIELD) .lambda(CONSTR_GET_FIELD)
.apply( .apply(
Term::equals_integer() Term::equals_integer()
.apply(Term::var("__wanted_arg".to_string())) .apply(Term::var("__wanted_arg"))
.apply(Term::var("__current_arg_number".to_string())) .apply(Term::var("__current_arg_number"))
.if_else( .if_else(
Term::head_list(), Term::head_list(),
Term::var(CONSTR_GET_FIELD) Term::var(CONSTR_GET_FIELD)
.apply(Term::var(CONSTR_GET_FIELD)) .apply(Term::var(CONSTR_GET_FIELD))
.apply( .apply(
Term::add_integer() Term::add_integer()
.apply(Term::var("__current_arg_number".to_string())) .apply(Term::var("__current_arg_number"))
.apply(Term::integer(1.into())), .apply(Term::integer(1.into())),
) )
.apply( .apply(
Term::tail_list() Term::tail_list().apply(Term::var("__current_list_of_constr_args")),
.apply(Term::var("__current_list_of_constr_args".to_string())),
) )
.apply(Term::var("__wanted_arg")) .apply(Term::var("__wanted_arg"))
.lambda("__current_list_of_constr_args".to_string()), .lambda("__current_list_of_constr_args"),
) )
.apply(Term::var("__list_of_constr_args".to_string())) .apply(Term::var("__list_of_constr_args"))
.lambda("__wanted_arg".to_string()) .lambda("__wanted_arg")
.lambda("__list_of_constr_args") .lambda("__list_of_constr_args")
.lambda("__current_arg_number".to_string()) .lambda("__current_arg_number")
.lambda(CONSTR_GET_FIELD.to_string()), .lambda(CONSTR_GET_FIELD),
) )
} }
pub fn assert_on_list(self) -> Self { pub fn assert_on_list(self) -> Self {
self.lambda(EXPECT_ON_LIST.to_string()) self.lambda(EXPECT_ON_LIST)
.apply(Term::var(EXPECT_ON_LIST).apply(Term::var(EXPECT_ON_LIST)))
.lambda(EXPECT_ON_LIST)
.apply( .apply(
Term::var(EXPECT_ON_LIST.to_string()).apply(Term::var(EXPECT_ON_LIST.to_string())), Term::var("__list_to_check")
)
.lambda(EXPECT_ON_LIST.to_string())
.apply(
Term::var("__list_to_check".to_string())
.delayed_choose_list( .delayed_choose_list(
Term::unit(), Term::unit(),
Term::var("__check_with".to_string()) Term::var("__check_with")
.apply( .apply(Term::head_list().apply(Term::var("__list_to_check")))
Term::head_list().apply(Term::var("__list_to_check".to_string())),
)
.choose_unit( .choose_unit(
Term::var(EXPECT_ON_LIST.to_string()) Term::var(EXPECT_ON_LIST)
.apply(Term::var(EXPECT_ON_LIST.to_string())) .apply(Term::var(EXPECT_ON_LIST))
.apply( .apply(Term::tail_list().apply(Term::var("__list_to_check")))
Term::tail_list() .apply(Term::var("__check_with")),
.apply(Term::var("__list_to_check".to_string())),
)
.apply(Term::var("__check_with".to_string())),
), ),
) )
.lambda("__check_with".to_string()) .lambda("__check_with")
.lambda("__list_to_check".to_string()) .lambda("__list_to_check")
.lambda(EXPECT_ON_LIST), .lambda(EXPECT_ON_LIST),
) )
} }

View File

@ -840,4 +840,36 @@ mod test {
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
#[test]
fn inline_reduce_delay_sha() {
let mut program: Program<Name> = Program {
version: (1, 0, 0),
term: Term::sha2_256()
.apply(Term::var("x"))
.lambda("x")
.apply(Term::byte_string(vec![]).delay()),
};
let mut interner = Interner::new();
interner.program(&mut program);
let mut expected = Program {
version: (1, 0, 0),
term: Term::sha2_256().apply(Term::byte_string(vec![]).delay()),
};
let mut interner = Interner::new();
interner.program(&mut expected);
let expected: Program<NamedDeBruijn> = expected.try_into().unwrap();
let actual = program.inline_reduce();
let actual: Program<NamedDeBruijn> = actual.try_into().unwrap();
assert_eq!(actual, expected);
}
} }