changed assert_on_list from being defined at uplc level to being defined at air level to enable proper hoisting

This commit is contained in:
Kasey White
2023-04-04 14:58:04 -04:00
committed by Kasey
parent f4ba6b8985
commit abd97f0ade
3 changed files with 234 additions and 28 deletions

View File

@@ -3,7 +3,9 @@ use std::{rc::Rc, sync::Arc};
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use uplc::{
ast::{Constant as UplcConstant, Name, NamedDeBruijn, Program, Term, Type as UplcType},
ast::{
Constant as UplcConstant, DeBruijn, Name, NamedDeBruijn, Program, Term, Type as UplcType,
},
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD, CONSTR_INDEX_EXPOSER},
builtins::DefaultFunction,
machine::cost_model::ExBudget,
@@ -37,6 +39,13 @@ use builder::{
use self::{builder::replace_opaque_type, scope::Scope, stack::AirStack};
#[derive(Clone, Debug)]
pub struct CodeGenFunction {
air: Vec<Air>,
dependencies: Vec<String>,
recursive: bool,
}
#[derive(Clone)]
pub struct CodeGenerator<'a> {
defined_functions: IndexMap<FunctionAccessKey, ()>,
@@ -45,8 +54,9 @@ pub struct CodeGenerator<'a> {
module_types: IndexMap<&'a String, &'a TypeInfo>,
id_gen: Rc<IdGenerator>,
needs_field_access: bool,
used_data_assert_on_list: bool,
code_gen_functions: IndexMap<String, CodeGenFunction>,
zero_arg_functions: IndexMap<FunctionAccessKey, Vec<Air>>,
uplc_to_function: IndexMap<Program<DeBruijn>, FunctionAccessKey>,
}
impl<'a> CodeGenerator<'a> {
@@ -60,19 +70,21 @@ impl<'a> CodeGenerator<'a> {
functions,
data_types,
module_types,
id_gen: IdGenerator::new().into(),
needs_field_access: false,
used_data_assert_on_list: false,
id_gen: IdGenerator::new().into(),
code_gen_functions: IndexMap::new(),
zero_arg_functions: IndexMap::new(),
uplc_to_function: IndexMap::new(),
}
}
pub fn reset(&mut self) {
self.needs_field_access = false;
self.used_data_assert_on_list = false;
self.code_gen_functions = IndexMap::new();
self.zero_arg_functions = IndexMap::new();
self.id_gen = IdGenerator::new().into();
self.needs_field_access = false;
self.defined_functions = IndexMap::new();
self.uplc_to_function = IndexMap::new();
}
pub fn generate(
@@ -157,11 +169,13 @@ impl<'a> CodeGenerator<'a> {
}
fn finalize(&mut self, term: Term<Name>, wrap_as_validator: bool) -> Program<Name> {
let mut term = if wrap_as_validator || self.used_data_assert_on_list {
term.assert_on_list()
} else {
term
};
// let mut term = if self.used_data_assert_on_list {
// term.assert_on_list()
// } else {
// term
// };
let mut term = term;
if self.needs_field_access {
term = term
@@ -197,14 +211,10 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::Pipeline { expressions, .. } | TypedExpr::Sequence { expressions, .. } => {
let mut stacks = Vec::new();
for (index, expr) in expressions.iter().enumerate() {
if index == 0 {
self.build(expr, ir_stack);
} else {
let mut stack = ir_stack.empty_with_scope();
self.build(expr, &mut stack);
stacks.push(stack);
}
for expr in expressions.iter() {
let mut stack = ir_stack.empty_with_scope();
self.build(expr, &mut stack);
stacks.push(stack);
}
ir_stack.sequence(stacks);
@@ -1638,6 +1648,8 @@ impl<'a> CodeGenerator<'a> {
{
let mut expect_stack = pattern_stack.empty_with_scope();
println!("GETTING 2 HERE");
self.expect_pattern(
pattern,
&mut expect_stack,
@@ -2225,7 +2237,7 @@ impl<'a> CodeGenerator<'a> {
|| tipo.is_data()
{
} else if tipo.is_map() {
self.used_data_assert_on_list = true;
// self.used_data_assert_on_list = true;
let new_id = self.id_gen.next();
let id_pair = (self.id_gen.next(), self.id_gen.next());
let inner_list_type = &tipo.get_inner_types()[0];
@@ -2266,7 +2278,7 @@ impl<'a> CodeGenerator<'a> {
expect_stack.void();
} else if tipo.is_list() {
self.used_data_assert_on_list = true;
// self.used_data_assert_on_list = true;
let new_id = self.id_gen.next();
let inner_list_type = &tipo.get_inner_types()[0];
@@ -4813,8 +4825,9 @@ impl<'a> CodeGenerator<'a> {
param_stack.local_var(data(), arg.arg_name.get_variable_name().unwrap_or("_"));
let mut actual_type = arg.tipo.clone();
println!("GETTING HERE");
replace_opaque_type(&mut actual_type, self.data_types.clone());
println!("ALSO HERE. TYPE IS {:#?}", actual_type);
self.assignment(
&Pattern::Var {
@@ -4834,6 +4847,8 @@ impl<'a> CodeGenerator<'a> {
arg.arg_name.get_variable_name().unwrap_or("_").to_string(),
);
println!("CONTINUING HERE");
let mut air_vec = air_stack.complete();
term = term

View File

@@ -5,7 +5,7 @@ use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction};
use crate::{
ast::Span,
builtins::void,
builtins::{data, list, void},
tipo::{Type, ValueConstructor, ValueConstructorVariant},
IdGenerator,
};
@@ -706,13 +706,73 @@ impl AirStack {
self.merge_child(value_stack);
}
pub fn assert_on_list(&mut self) {
let mut head_stack = self.empty_with_scope();
let mut tail_stack = self.empty_with_scope();
let mut check_with_stack = self.empty_with_scope();
let mut expect_stack = self.empty_with_scope();
let mut var_stack = self.empty_with_scope();
let mut void_stack = self.empty_with_scope();
let mut fun_stack = self.empty_with_scope();
let mut arg_stack1 = self.empty_with_scope();
let mut arg_stack2 = self.empty_with_scope();
self.air.push(Air::DefineFunc {
scope: self.scope.clone(),
func_name: EXPECT_ON_LIST.to_string(),
module_name: "".to_string(),
params: vec!["__list_to_check".to_string(), "__check_with".to_string()],
recursive: true,
variant_name: "".to_string(),
});
var_stack.local_var(list(data()), "__list_to_check");
head_stack.builtin(DefaultFunction::HeadList, data(), vec![var_stack]);
fun_stack.local_var(void(), "__check_with".to_string());
check_with_stack.call(void(), fun_stack, vec![head_stack]);
void_stack.void();
void_stack.void();
self.list_clause(
void(),
"__list_to_check".to_string(),
None,
false,
void_stack,
);
self.choose_unit(check_with_stack);
expect_stack.local_var(void(), EXPECT_ON_LIST.to_string());
arg_stack1.local_var(list(data()), "__list_to_check".to_string());
arg_stack2.local_var(void(), "__check_with".to_string());
tail_stack.builtin(DefaultFunction::TailList, list(data()), vec![arg_stack1]);
self.call(void(), expect_stack, vec![tail_stack, arg_stack2])
}
}
#[cfg(test)]
mod test {
use std::rc::Rc;
use crate::{gen_uplc::air::Air, IdGenerator};
use uplc::builtins::DefaultFunction;
use crate::{
ast::Span,
builtins::{data, list, void},
gen_uplc::air::Air,
tipo::{ValueConstructor, ValueConstructorVariant},
IdGenerator,
};
use super::AirStack;
@@ -812,4 +872,135 @@ mod test {
],
)
}
#[test]
fn assert_on_list_matches_air() {
let id_gen: Rc<IdGenerator> = IdGenerator::new().into();
let scope = vec![id_gen.next()];
let mut stack1 = AirStack {
id_gen,
scope: scope.into(),
air: vec![],
};
stack1.assert_on_list();
println!("{:#?}", stack1);
let air_vec = vec![
Air::DefineFunc {
scope: vec![0].into(),
func_name: "__expect_on_list".to_string(),
module_name: "".to_string(),
params: vec!["__list_to_check".to_string(), "__check_with".to_string()],
recursive: true,
variant_name: "".to_string(),
},
Air::ListClause {
scope: vec![0, 7].into(),
tipo: void(),
tail_name: "__list_to_check".to_string(),
next_tail_name: None,
complex_clause: false,
},
Air::Void {
scope: vec![0, 7, 5].into(),
},
Air::Void {
scope: vec![0, 7, 5, 6].into(),
},
Air::Builtin {
scope: vec![0, 7, 8].into(),
count: 2,
func: DefaultFunction::ChooseUnit,
tipo: void(),
},
Air::Call {
scope: vec![0, 7, 8, 4].into(),
count: 1,
tipo: void(),
},
Air::Var {
scope: vec![0, 7, 8, 4, 3].into(),
constructor: ValueConstructor {
public: true,
variant: ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
tipo: void(),
},
name: "__check_with".to_string(),
variant_name: "".to_string(),
},
Air::Builtin {
scope: vec![0, 7, 8, 4, 2].into(),
count: 1,
func: DefaultFunction::HeadList,
tipo: data(),
},
Air::Var {
scope: vec![0, 7, 8, 4, 2, 1].into(),
constructor: ValueConstructor {
public: true,
variant: ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
tipo: list(data()),
},
name: "__list_to_check".to_string(),
variant_name: "".to_string(),
},
Air::Call {
scope: vec![0, 7, 8, 13].into(),
count: 2,
tipo: void(),
},
Air::Var {
scope: vec![0, 7, 8, 13, 9].into(),
constructor: ValueConstructor {
public: true,
variant: ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
tipo: void(),
},
name: "__expect_on_list".to_string(),
variant_name: "".to_string(),
},
Air::Builtin {
scope: vec![0, 7, 8, 13, 12].into(),
count: 1,
func: DefaultFunction::TailList,
tipo: list(data()),
},
Air::Var {
scope: vec![0, 7, 8, 13, 12, 10].into(),
constructor: ValueConstructor {
public: true,
variant: ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
tipo: list(data()),
},
name: "__list_to_check".to_string(),
variant_name: "".to_string(),
},
Air::Var {
scope: vec![0, 7, 8, 13, 11].into(),
constructor: ValueConstructor {
public: true,
variant: ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
tipo: void(),
},
name: "__check_with".to_string(),
variant_name: "".to_string(),
},
];
assert_eq!(stack1.air, air_vec)
}
}