fix: constrs that contain fields now work when passed as an arg to a function.

Convert acceptance test 22

Create test for passing constr as a function
This commit is contained in:
microproofs 2023-05-30 14:52:28 -04:00 committed by Lucas
parent 26a607eb00
commit a65821d5ab
2 changed files with 222 additions and 15 deletions

View File

@ -3809,34 +3809,59 @@ impl<'a> CodeGenerator<'a> {
)
.unwrap();
let (constr_index, _) = data_type
let (constr_index, constr_type) = data_type
.constructors
.iter()
.enumerate()
.find(|(_, x)| x.name == *constr_name)
.unwrap();
let fields = Term::empty_list();
let mut term = Term::empty_list();
let mut term = Term::constr_data()
.apply(Term::integer(constr_index.try_into().unwrap()))
.apply(fields);
if constr_type.arguments.is_empty() {
term = Term::constr_data()
.apply(Term::integer(constr_index.try_into().unwrap()))
.apply(term);
let mut program: Program<Name> = Program {
version: (1, 0, 0),
term,
};
let mut program: Program<Name> = Program {
version: (1, 0, 0),
term,
};
let mut interner = Interner::new();
let mut interner = Interner::new();
interner.program(&mut program);
interner.program(&mut program);
let eval_program: Program<NamedDeBruijn> = program.try_into().unwrap();
let eval_program: Program<NamedDeBruijn> =
program.try_into().unwrap();
let evaluated_term: Term<NamedDeBruijn> =
eval_program.eval(ExBudget::default()).result().unwrap();
term = evaluated_term.try_into().unwrap();
let evaluated_term: Term<NamedDeBruijn> =
eval_program.eval(ExBudget::default()).result().unwrap();
term = evaluated_term.try_into().unwrap();
} else {
for (index, arg) in constr_type.arguments.iter().enumerate().rev() {
term = Term::mk_cons()
.apply(builder::convert_type_to_data(
Term::var(
arg.label
.clone()
.unwrap_or_else(|| format!("arg_{index}")),
),
&arg.tipo,
))
.apply(term);
}
term = Term::constr_data()
.apply(Term::integer(constr_index.into()))
.apply(term);
for (index, arg) in constr_type.arguments.iter().enumerate().rev() {
term = term.lambda(
arg.label.clone().unwrap_or_else(|| format!("arg_{index}")),
)
}
}
arg_stack.push(term);
}
}
@ -4569,9 +4594,11 @@ impl<'a> CodeGenerator<'a> {
..
} => {
let mut arg_vec = vec![];
for _ in 0..count {
arg_vec.push(arg_stack.pop().unwrap());
}
let mut term = Term::empty_list();
for (index, arg) in arg_vec.iter().enumerate().rev() {

View File

@ -2374,3 +2374,183 @@ fn acceptance_test_20_map_some() {
false,
);
}
#[test]
fn acceptance_test_22_filter_map() {
let src = r#"
pub fn foldr(xs: List<a>, f: fn(a, b) -> b, zero: b) -> b {
when xs is {
[] ->
zero
[x, ..rest] ->
f(x, foldr(rest, f, zero))
}
}
pub fn filter_map(xs: List<a>, f: fn(a) -> Option<b>) -> List<b> {
foldr(
xs,
fn(x, ys) {
when f(x) is {
None ->
ys
Some(y) ->
[y, ..ys]
}
},
[],
)
}
test filter_map_1() {
filter_map([], fn(_) { Some(43) }) == []
}
"#;
assert_uplc(
src,
Term::equals_data()
.apply(
Term::list_data().apply(
Term::var("filter_map")
.lambda("filter_map")
.apply(
Term::var("foldr")
.apply(Term::var("xs"))
.apply(
Term::equals_integer()
.apply(Term::integer(1.into()))
.apply(Term::var("subject_index"))
.delayed_if_else(
Term::var("ys"),
Term::mk_cons()
.apply(Term::i_data().apply(Term::var("y")))
.apply(Term::var("ys"))
.lambda("y")
.apply(
Term::un_i_data().apply(
Term::head_list()
.apply(Term::var("subject_fields")),
),
)
.lambda("subject_fields")
.apply(
Term::var(CONSTR_FIELDS_EXPOSER)
.apply(Term::var("subject")),
),
)
.lambda("subject_index")
.apply(
Term::var(CONSTR_INDEX_EXPOSER)
.apply(Term::var("subject")),
)
.lambda("subject")
.apply(Term::var("f").apply(Term::var("x")))
.lambda("ys")
.lambda("x"),
)
.apply(Term::empty_list())
.lambda("f")
.lambda("xs"),
)
.lambda("foldr")
.apply(Term::var("foldr").apply(Term::var("foldr")))
.lambda("foldr")
.apply(
Term::var("xs")
.delayed_choose_list(
Term::var("zero"),
Term::var("f")
.apply(Term::var("x"))
.apply(
Term::var("foldr")
.apply(Term::var("foldr"))
.apply(Term::var("rest"))
.apply(Term::var("f"))
.apply(Term::var("zero")),
)
.lambda("rest")
.apply(Term::tail_list().apply(Term::var("xs")))
.lambda("x")
.apply(Term::head_list().apply(Term::var("xs"))),
)
.lambda("zero")
.lambda("f")
.lambda("xs")
.lambda("foldr"),
)
.apply(Term::empty_list())
.apply(
Term::data(Data::constr(0, vec![Data::integer(42.into())])).lambda("_"),
),
),
)
.apply(Term::list_data().apply(Term::empty_list()))
.constr_get_field()
.constr_fields_exposer()
.constr_index_exposer(),
false,
);
}
#[test]
fn pass_constr_as_function() {
let src = r#"
type Make {
a: Int,
b: SubMake
}
type SubMake {
c: Int
}
fn hi(sm: SubMake, to_make: fn (Int, SubMake) -> Make) -> Make {
to_make(3, sm)
}
test cry() {
Make(3, SubMake(1)) == hi(SubMake(1), Make)
}
"#;
assert_uplc(
src,
Term::equals_data()
.apply(Term::data(Data::constr(
0,
vec![
Data::integer(3.into()),
Data::constr(0, vec![Data::integer(1.into())]),
],
)))
.apply(
Term::var("hi")
.lambda("hi")
.apply(
Term::var("to_make")
.apply(Term::integer(3.into()))
.apply(Term::var("sm"))
.lambda("to_make")
.lambda("sm"),
)
.apply(Term::data(Data::constr(0, vec![Data::integer(1.into())])))
.apply(
Term::constr_data()
.apply(Term::integer(0.into()))
.apply(
Term::mk_cons()
.apply(Term::i_data().apply(Term::var("a")))
.apply(
Term::mk_cons()
.apply(Term::var("b"))
.apply(Term::empty_list()),
),
)
.lambda("b")
.lambda("a"),
),
),
false,
);
}