feat: add support for validator arguments

feat: finish expect type on data constr
fix: tuple clause was exposing all items regardless of discard
fix: tuple clause was not receiving complex_clause flag
fix: condition for assert where constructor had 0 args was tripping assert
fix: had to rearrange var and discard assignment to ensure correct val is returned
fix: binop had the wrong type
This commit is contained in:
microproofs 2023-07-12 16:40:16 -04:00 committed by Kasey
parent 7d4e136467
commit 2b7e7ead1c
1 changed files with 243 additions and 43 deletions

View File

@ -13,19 +13,19 @@ use uplc::{
use crate::{ use crate::{
ast::{ ast::{
AssignmentKind, BinOp, Pattern, Span, TypedClause, TypedDataType, TypedFunction, AssignmentKind, BinOp, Pattern, Span, TypedArg, TypedClause, TypedDataType, TypedFunction,
TypedValidator, TypedValidator,
}, },
builtins::{bool, int, void}, builtins::{bool, data, int, void},
expr::TypedExpr, expr::TypedExpr,
gen_uplc::{ gen_uplc::{
air::Air, air::Air,
builder::{ builder::{
self as build, get_arg_type_name, AssignmentProperties, ClauseProperties, DataTypeKey, self as build, get_arg_type_name, wrap_validator_args, AssignmentProperties,
FunctionAccessKey, SpecificClause, ClauseProperties, DataTypeKey, FunctionAccessKey, SpecificClause,
}, },
}, },
gen_uplc2::builder::{convert_opaque_type, get_generic_id_and_type}, gen_uplc2::builder::{convert_opaque_type, find_and_replace_generics, get_generic_id_and_type},
tipo::{ tipo::{
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor, ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
ValueConstructorVariant, ValueConstructorVariant,
@ -81,12 +81,19 @@ impl<'a> CodeGenerator<'a> {
pub fn generate( pub fn generate(
&mut self, &mut self,
TypedValidator { TypedValidator {
fun: _, fun,
other_fun: _, other_fun,
params: _, params,
.. ..
}: &TypedValidator, }: &TypedValidator,
) -> Program<Name> { ) -> Program<Name> {
let air_tree_fun = self.build(&fun.body);
let mut validator_args_tree = self.check_validator_args(&fun.arguments, true, air_tree_fun);
validator_args_tree = AirTree::no_op().hoist_over(validator_args_tree);
println!("{:#?}", validator_args_tree);
println!("{:#?}", validator_args_tree.to_vec());
todo!() todo!()
} }
@ -264,12 +271,8 @@ impl<'a> CodeGenerator<'a> {
} }
}, },
TypedExpr::BinOp { TypedExpr::BinOp {
name, name, left, right, ..
tipo, } => AirTree::binop(*name, left.tipo(), self.build(left), self.build(right)),
left,
right,
..
} => AirTree::binop(*name, tipo.clone(), self.build(left), self.build(right)),
TypedExpr::Assignment { TypedExpr::Assignment {
tipo, tipo,
@ -545,6 +548,7 @@ impl<'a> CodeGenerator<'a> {
if props.full_check { if props.full_check {
let mut index_map = IndexMap::new(); let mut index_map = IndexMap::new();
let tipo = convert_opaque_type(tipo, &self.data_types); let tipo = convert_opaque_type(tipo, &self.data_types);
let assignment = AirTree::let_assignment(name, value); let assignment = AirTree::let_assignment(name, value);
let val = AirTree::local_var(name, tipo.clone()); let val = AirTree::local_var(name, tipo.clone());
@ -557,8 +561,12 @@ impl<'a> CodeGenerator<'a> {
&mut index_map, &mut index_map,
pattern.location(), pattern.location(),
); );
let assign = AirTree::let_assignment("_", assignment.hoist_over(expect));
AirTree::let_assignment(name, assign.hoist_over(val)) let assign_expect = AirTree::let_assignment("_", expect);
AirTree::let_assignment(
name,
assignment.hoist_over(assign_expect.hoist_over(val)),
)
} }
} else { } else {
AirTree::let_assignment(name, value) AirTree::let_assignment(name, value)
@ -587,8 +595,12 @@ impl<'a> CodeGenerator<'a> {
&mut index_map, &mut index_map,
pattern.location(), pattern.location(),
); );
let assign = AirTree::let_assignment("_", assignment.hoist_over(expect));
AirTree::let_assignment(name, assign.hoist_over(val)) let assign_expect = AirTree::let_assignment("_", expect);
AirTree::let_assignment(
name,
assignment.hoist_over(assign_expect.hoist_over(val)),
)
} }
} else if !props.remove_unused { } else if !props.remove_unused {
AirTree::let_assignment(name, value) AirTree::let_assignment(name, value)
@ -688,13 +700,13 @@ impl<'a> CodeGenerator<'a> {
let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec(); let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec();
let mut sequence = vec![AirTree::list_access( let list_access = if elements.is_empty() {
names, AirTree::let_assignment("_", AirTree::list_empty(value))
tipo.clone(), } else {
tail.is_some(), AirTree::list_access(names, tipo.clone(), tail.is_some(), tail.is_none(), value)
tail.is_none(), };
value,
)]; let mut sequence = vec![list_access];
sequence.append(&mut elems.into_iter().map(|(_, elem)| elem).collect_vec()); sequence.append(&mut elems.into_iter().map(|(_, elem)| elem).collect_vec());
@ -1137,29 +1149,163 @@ impl<'a> CodeGenerator<'a> {
.map(|arg| get_arg_type_name(arg)) .map(|arg| get_arg_type_name(arg))
.join("_"); .join("_");
// TODO calculate the variant name. let mono_types: IndexMap<u64, Arc<Type>> = if !data_type.typed_parameters.is_empty() {
data_type
.typed_parameters
.iter()
.zip(tipo.arg_types().unwrap())
.flat_map(|item| get_generic_id_and_type(item.0, &item.1))
.collect()
} else {
vec![].into_iter().collect()
};
let data_type_name = format!("__expect_{}_{}", data_type.name, data_type_variant); let data_type_name = format!("__expect_{}_{}", data_type.name, data_type_variant);
let function = self.code_gen_functions.get(&data_type_name); let function = self.code_gen_functions.get(&data_type_name);
let error_term = if self.tracing {
AirTree::trace(
AirTree::string("Constr index did not match any type variant"),
tipo.clone(),
AirTree::error(tipo.clone()),
)
} else {
AirTree::error(tipo.clone())
};
if function.is_none() && defined_data_types.get(&data_type_name).is_none() { if function.is_none() && defined_data_types.get(&data_type_name).is_none() {
defined_data_types.insert(data_type_name.clone(), 1); defined_data_types.insert(data_type_name.clone(), 1);
let mono_types: IndexMap<u64, Arc<Type>> = if !data_type.typed_parameters.is_empty() let current_defined = defined_data_types.clone();
{ let mut diff_defined_types = vec![];
data_type
.typed_parameters
.iter()
.zip(tipo.arg_types().unwrap())
.flat_map(|item| get_generic_id_and_type(item.0, &item.1))
.collect()
} else {
vec![].into_iter().collect()
};
let current_defined_state = defined_data_types.clone(); let constr_clauses = data_type.constructors.iter().enumerate().rfold(
// let mut diff_defined_types = IndexMap::new(); error_term,
|acc, (index, constr)| {
let constr_args = constr
.arguments
.iter()
.enumerate()
.map(|(index, arg)| {
let arg_name =
arg.label.clone().unwrap_or(format!("__field_{index}"));
todo!() let arg_tipo = find_and_replace_generics(&arg.tipo, &mono_types);
let assign = AirTree::let_assignment(
"_",
self.expect_type_assign(
&arg_tipo,
AirTree::local_var(&arg_name, arg_tipo.clone()),
defined_data_types,
location,
),
);
(index, arg_name, arg_tipo, assign)
})
.collect_vec();
let indices = constr_args
.iter()
.map(|(index, arg_name, arg_tipo, _)| {
(*index, arg_name.clone(), (*arg_tipo).clone())
})
.collect_vec();
let mut assigns = constr_args
.into_iter()
.map(|(_, _, _, assign)| assign)
.collect_vec();
if assigns.is_empty() {
let empty = AirTree::fields_empty(AirTree::local_var(
format!("__constr_var_span_{}_{}", location.start, location.end),
tipo.clone(),
));
assigns.insert(0, AirTree::let_assignment("_", empty));
} else {
let expose = AirTree::fields_expose(
indices,
true,
AirTree::local_var(
format!(
"__constr_var_span_{}_{}",
location.start, location.end
),
tipo.clone(),
),
);
assigns.insert(0, expose);
};
let then = AirTree::UnhoistedSequence(assigns).hoist_over(AirTree::void());
AirTree::clause(
format!("__subject_span_{}_{}", location.start, location.end),
AirTree::int(index),
tipo.clone(),
then,
acc,
false,
)
},
);
let overhead_assign = AirTree::let_assignment(
format!("__constr_var_span_{}_{}", location.start, location.end),
AirTree::local_var("__param_0", tipo.clone()),
);
let when_expr = AirTree::when(
format!("__subject_span_{}_{}", location.start, location.end),
tipo.clone(),
AirTree::local_var(
format!("__constr_var_span_{}_{}", location.start, location.end),
tipo.clone(),
),
constr_clauses,
);
let func_body = overhead_assign.hoist_over(when_expr);
for (inner_data_type, inner_count) in defined_data_types.iter() {
if let Some(prev_count) = current_defined.get(inner_data_type) {
if inner_count - prev_count > 0 {
diff_defined_types.push(inner_data_type.to_string());
}
} else {
diff_defined_types.push(inner_data_type.to_string());
}
}
let recursive = diff_defined_types.contains(&data_type_name);
// remove self from dependencies
if recursive {
diff_defined_types.remove(
diff_defined_types
.iter()
.position(|item| item == &data_type_name)
.unwrap(),
);
}
let code_gen_func = CodeGenFunction::Function(
AirTree::define_func(
&data_type_name,
"",
"",
vec!["__param_0".to_string()],
recursive,
func_body,
),
diff_defined_types,
);
self.code_gen_functions
.insert(data_type_name.clone(), code_gen_func);
} else if let Some(counter) = defined_data_types.get_mut(&data_type_name) { } else if let Some(counter) = defined_data_types.get_mut(&data_type_name) {
*counter += 1; *counter += 1;
} else { } else {
@ -1628,7 +1774,10 @@ impl<'a> CodeGenerator<'a> {
if subject_tipo.is_bool() { if subject_tipo.is_bool() {
(AirTree::bool(name == "True"), AirTree::no_op()) (AirTree::bool(name == "True"), AirTree::no_op())
} else { } else {
assert!(matches!(function_tipo.as_ref().clone(), Type::Fn { .. })); assert!(
matches!(function_tipo.as_ref().clone(), Type::Fn { .. })
|| matches!(function_tipo.as_ref().clone(), Type::App { .. })
);
let data_type = build::lookup_data_type_by_tipo(&self.data_types, subject_tipo) let data_type = build::lookup_data_type_by_tipo(&self.data_types, subject_tipo)
.unwrap_or_else(|| { .unwrap_or_else(|| {
unreachable!( unreachable!(
@ -1765,6 +1914,8 @@ impl<'a> CodeGenerator<'a> {
&mut tuple_props, &mut tuple_props,
); );
props.complex_clause = props.complex_clause || tuple_props.complex_clause;
(elem_name, index, elem) (elem_name, index, elem)
}) })
.collect_vec(); .collect_vec();
@ -1784,10 +1935,10 @@ impl<'a> CodeGenerator<'a> {
name_index_assigns.iter().for_each(|(name, index, _)| { name_index_assigns.iter().for_each(|(name, index, _)| {
if let Some((index, prev_name)) = defined_indices if let Some((index, prev_name)) = defined_indices
.iter() .iter()
.find(|(defined_index, _)| defined_index == index) .find(|(defined_index, nm)| defined_index == index)
{ {
previous_defined_names.push((*index, prev_name.clone(), name.clone())); previous_defined_names.push((*index, prev_name.clone(), name.clone()));
} else { } else if name != "_" {
assert!(defined_indices.insert((*index, name.clone()))); assert!(defined_indices.insert((*index, name.clone())));
} }
}); });
@ -1991,4 +2142,53 @@ impl<'a> CodeGenerator<'a> {
} }
} }
} }
pub fn check_validator_args(
&mut self,
arguments: &[TypedArg],
has_context: bool,
body: AirTree,
) -> AirTree {
let checked_args = arguments
.iter()
.enumerate()
.map(|(index, arg)| {
let arg_name = arg.arg_name.get_variable_name().unwrap_or("_").to_string();
if !(has_context && index == arguments.len() - 1) && &arg_name != "_" {
let param = AirTree::local_var(&arg_name, data());
let actual_type = convert_opaque_type(&arg.tipo, &self.data_types);
let assign = self.assignment(
&Pattern::Var {
location: Span::empty(),
name: arg_name.to_string(),
},
param,
&actual_type,
AssignmentProperties {
value_type: data(),
kind: AssignmentKind::Expect,
remove_unused: false,
full_check: true,
},
);
(arg_name, assign)
} else {
(arg_name, AirTree::no_op())
}
})
.collect_vec();
let arg_names = checked_args
.iter()
.map(|(name, _)| name.to_string())
.collect_vec();
let arg_assigns =
AirTree::UnhoistedSequence(checked_args.into_iter().map(|(_, arg)| arg).collect_vec());
AirTree::anon_func(arg_names, arg_assigns.hoist_over(body))
}
} }