chore: move assignment_air_tree and expect_type to gen_uplc
feat: add is_primitive check to types
This commit is contained in:
parent
cd726b561e
commit
7cee9a4d15
|
@ -4,6 +4,7 @@ use uplc::builtins::DefaultFunction;
|
|||
|
||||
use crate::{
|
||||
ast::{BinOp, Span, UnOp},
|
||||
builtins::{data, list, void},
|
||||
tipo::{Type, ValueConstructor, ValueConstructorVariant},
|
||||
};
|
||||
|
||||
|
@ -655,6 +656,7 @@ impl AirTree {
|
|||
| AirStatement::NoOp { hoisted_over }
|
||||
| AirStatement::ListExpose { hoisted_over, .. }
|
||||
| AirStatement::TupleAccessor { hoisted_over, .. } => {
|
||||
assert!(hoisted_over.is_none());
|
||||
*hoisted_over = Some(next_exp).into();
|
||||
assignment
|
||||
}
|
||||
|
@ -675,6 +677,56 @@ impl AirTree {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expect_on_list() -> AirTree {
|
||||
// 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(),
|
||||
// });
|
||||
|
||||
let list_var = AirTree::local_var("__list_to_check", list(data()));
|
||||
|
||||
let head_list = AirTree::builtin(DefaultFunction::HeadList, data(), vec![list_var]);
|
||||
|
||||
let expect_on_head = AirTree::call(
|
||||
AirTree::local_var("__check_with", void()),
|
||||
void(),
|
||||
vec![head_list],
|
||||
);
|
||||
todo!()
|
||||
|
||||
// self.list_clause(void(), "__list_to_check", None, false, void_stack);
|
||||
|
||||
// self.choose_unit(check_with_stack);
|
||||
|
||||
// expect_stack.var(
|
||||
// ValueConstructor::public(
|
||||
// void(),
|
||||
// ValueConstructorVariant::ModuleFn {
|
||||
// name: EXPECT_ON_LIST.to_string(),
|
||||
// field_map: None,
|
||||
// module: "".to_string(),
|
||||
// arity: 2,
|
||||
// location: Span::empty(),
|
||||
// builtin: None,
|
||||
// },
|
||||
// ),
|
||||
// EXPECT_ON_LIST,
|
||||
// "",
|
||||
// );
|
||||
|
||||
// arg_stack1.local_var(list(data()), "__list_to_check");
|
||||
|
||||
// arg_stack2.local_var(void(), "__check_with");
|
||||
|
||||
// tail_stack.builtin(DefaultFunction::TailList, list(data()), vec![arg_stack1]);
|
||||
|
||||
// self.call(void(), expect_stack, vec![tail_stack, arg_stack2])
|
||||
}
|
||||
|
||||
pub fn to_air_vec(_air_vec: &mut Vec<Air>, tree: AirTree) {
|
||||
match tree {
|
||||
AirTree::Statement(_) => todo!(),
|
||||
|
|
|
@ -1,21 +1,38 @@
|
|||
mod builder;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
use uplc::ast::{Name, Program, Term};
|
||||
use uplc::{
|
||||
ast::{Name, Program, Term},
|
||||
builder::EXPECT_ON_LIST,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast::{AssignmentKind, Span, TypedDataType, TypedFunction, TypedValidator},
|
||||
ast::{
|
||||
AssignmentKind, BinOp, DataType, Pattern, Span, TypedDataType, TypedFunction,
|
||||
TypedValidator,
|
||||
},
|
||||
builtins::{int, void},
|
||||
expr::TypedExpr,
|
||||
gen_uplc::{
|
||||
air::Air,
|
||||
builder::{self as build, AssignmentProperties, DataTypeKey, FunctionAccessKey},
|
||||
tree::AirTree,
|
||||
CodeGenFunction,
|
||||
},
|
||||
tipo::{ModuleValueConstructor, TypeInfo, ValueConstructor, ValueConstructorVariant},
|
||||
tipo::{
|
||||
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
|
||||
ValueConstructorVariant,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CodeGenFunction {
|
||||
Function(AirTree, Vec<String>),
|
||||
Link(String),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CodeGenerator<'a> {
|
||||
defined_functions: IndexMap<FunctionAccessKey, ()>,
|
||||
|
@ -67,6 +84,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
|
||||
pub fn generate_test(&mut self, test_body: &TypedExpr) -> Program<Name> {
|
||||
let mut air_tree = self.build(test_body);
|
||||
air_tree = AirTree::hoist_over(AirTree::no_op(), air_tree);
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -236,11 +256,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let air_value = self.build(value);
|
||||
|
||||
builder::assignment_air_tree(
|
||||
self.assignment_air_tree(
|
||||
pattern,
|
||||
air_value,
|
||||
tipo,
|
||||
&self.data_types,
|
||||
AssignmentProperties {
|
||||
value_type: value.tipo(),
|
||||
kind: *kind,
|
||||
|
@ -270,11 +289,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let subject_val = self.build(subject);
|
||||
|
||||
let assignment = builder::assignment_air_tree(
|
||||
let assignment = self.assignment_air_tree(
|
||||
&last_clause.pattern,
|
||||
subject_val,
|
||||
tipo,
|
||||
&self.data_types,
|
||||
AssignmentProperties {
|
||||
value_type: subject.tipo(),
|
||||
kind: AssignmentKind::Let,
|
||||
|
@ -425,4 +443,513 @@ impl<'a> CodeGenerator<'a> {
|
|||
TypedExpr::UnOp { value, op, .. } => AirTree::unop(*op, self.build(value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assignment_air_tree(
|
||||
&mut self,
|
||||
pattern: &Pattern<PatternConstructor, Arc<Type>>,
|
||||
mut value: AirTree,
|
||||
tipo: &Arc<Type>,
|
||||
props: AssignmentProperties,
|
||||
) -> AirTree {
|
||||
if props.value_type.is_data() && props.kind.is_expect() && !tipo.is_data() {
|
||||
value = AirTree::unwrap_data(value, tipo.clone());
|
||||
} else if !props.value_type.is_data() && tipo.is_data() {
|
||||
value = AirTree::wrap_data(value, tipo.clone());
|
||||
}
|
||||
|
||||
match pattern {
|
||||
Pattern::Int {
|
||||
value: expected_int,
|
||||
location,
|
||||
..
|
||||
} => {
|
||||
if props.kind.is_expect() {
|
||||
let name = format!(
|
||||
"__expected_by_{}_span_{}_{}",
|
||||
expected_int, location.start, location.end
|
||||
);
|
||||
let assignment = AirTree::let_assignment(&name, value);
|
||||
|
||||
let expect = AirTree::binop(
|
||||
BinOp::Eq,
|
||||
int(),
|
||||
AirTree::int(expected_int),
|
||||
AirTree::local_var(name, int()),
|
||||
);
|
||||
AirTree::assert_bool(true, AirTree::hoist_over(assignment, expect))
|
||||
} else {
|
||||
unreachable!("Code Gen should never reach here")
|
||||
}
|
||||
}
|
||||
Pattern::Var { name, .. } => {
|
||||
if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() {
|
||||
let mut index_map = IndexMap::new();
|
||||
let tipo = builder::convert_opaque_type();
|
||||
let assignment = AirTree::let_assignment(name, value);
|
||||
let val = AirTree::local_var(name, tipo.clone());
|
||||
|
||||
if tipo.is_primitive() {
|
||||
AirTree::let_assignment(name, AirTree::hoist_over(assignment, val))
|
||||
} else {
|
||||
let expect = self.expect_type(
|
||||
&tipo,
|
||||
val.clone(),
|
||||
&mut index_map,
|
||||
pattern.location(),
|
||||
);
|
||||
let assign =
|
||||
AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect));
|
||||
AirTree::let_assignment(name, AirTree::hoist_over(assign, val))
|
||||
}
|
||||
} else {
|
||||
AirTree::let_assignment(name, value)
|
||||
}
|
||||
}
|
||||
Pattern::Assign { name, pattern, .. } => {
|
||||
let inner_pattern = self.assignment_air_tree(
|
||||
pattern,
|
||||
AirTree::local_var(name, tipo.clone()),
|
||||
tipo,
|
||||
props,
|
||||
);
|
||||
let assign = AirTree::let_assignment(name, value);
|
||||
|
||||
AirTree::UnhoistedSequence(vec![assign, inner_pattern])
|
||||
}
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() {
|
||||
let mut index_map = IndexMap::new();
|
||||
let tipo = builder::convert_opaque_type();
|
||||
let assignment = AirTree::let_assignment(name, value);
|
||||
let val = AirTree::local_var(name, tipo.clone());
|
||||
if tipo.is_primitive() {
|
||||
AirTree::let_assignment(name, AirTree::hoist_over(assignment, val))
|
||||
} else {
|
||||
let expect = self.expect_type(
|
||||
&tipo,
|
||||
val.clone(),
|
||||
&mut index_map,
|
||||
pattern.location(),
|
||||
);
|
||||
let assign =
|
||||
AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect));
|
||||
AirTree::let_assignment(name, AirTree::hoist_over(assign, val))
|
||||
}
|
||||
} else if !props.remove_unused {
|
||||
AirTree::let_assignment(name, value)
|
||||
} else {
|
||||
AirTree::no_op()
|
||||
}
|
||||
}
|
||||
Pattern::List { elements, tail, .. } => {
|
||||
assert!(tipo.is_list());
|
||||
assert!(props.kind.is_expect());
|
||||
let list_elem_types = tipo.get_inner_types();
|
||||
|
||||
let list_elem_type = list_elem_types
|
||||
.get(0)
|
||||
.unwrap_or_else(|| unreachable!("No list element type?"));
|
||||
|
||||
let mut elems = elements
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, elem)| {
|
||||
let elem_name = match elem {
|
||||
Pattern::Var { name, .. } => name.to_string(),
|
||||
Pattern::Assign { name, .. } => name.to_string(),
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.kind.is_expect()
|
||||
&& props.value_type.is_data()
|
||||
&& !tipo.is_data()
|
||||
{
|
||||
format!("__discard_{}", name)
|
||||
} else {
|
||||
"_".to_string()
|
||||
}
|
||||
}
|
||||
_ => format!(
|
||||
"elem_{}_span_{}_{}",
|
||||
index,
|
||||
elem.location().start,
|
||||
elem.location().end
|
||||
),
|
||||
};
|
||||
|
||||
let val = AirTree::local_var(&elem_name, list_elem_type.clone());
|
||||
|
||||
(
|
||||
elem_name,
|
||||
self.assignment_air_tree(
|
||||
elem,
|
||||
val,
|
||||
list_elem_type,
|
||||
AssignmentProperties {
|
||||
value_type: props.value_type.clone(),
|
||||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
// If Some then push tail onto elems
|
||||
tail.iter().for_each(|tail| {
|
||||
let tail_name = match tail.as_ref() {
|
||||
Pattern::Var { name, .. } => name.to_string(),
|
||||
Pattern::Assign { name, .. } => name.to_string(),
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.kind.is_expect()
|
||||
&& props.value_type.is_data()
|
||||
&& !tipo.is_data()
|
||||
{
|
||||
format!("__discard_{}", name)
|
||||
} else {
|
||||
"_".to_string()
|
||||
}
|
||||
}
|
||||
_ => format!(
|
||||
"tail_span_{}_{}",
|
||||
tail.location().start,
|
||||
tail.location().end
|
||||
),
|
||||
};
|
||||
|
||||
let val = AirTree::local_var(&tail_name, tipo.clone());
|
||||
|
||||
elems.push((
|
||||
tail_name,
|
||||
self.assignment_air_tree(
|
||||
tail,
|
||||
val,
|
||||
tipo,
|
||||
AssignmentProperties {
|
||||
value_type: props.value_type.clone(),
|
||||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
},
|
||||
),
|
||||
));
|
||||
});
|
||||
|
||||
let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec();
|
||||
|
||||
let mut sequence = vec![AirTree::list_access(
|
||||
names,
|
||||
tipo.clone(),
|
||||
tail.is_some(),
|
||||
tail.is_none(),
|
||||
value,
|
||||
)];
|
||||
|
||||
sequence.append(&mut elems.into_iter().map(|(_, elem)| elem).collect_vec());
|
||||
|
||||
AirTree::UnhoistedSequence(sequence)
|
||||
}
|
||||
Pattern::Constructor {
|
||||
arguments,
|
||||
constructor,
|
||||
name,
|
||||
..
|
||||
} => {
|
||||
let mut sequence = vec![];
|
||||
|
||||
if tipo.is_bool() {
|
||||
assert!(props.kind.is_expect());
|
||||
|
||||
sequence.push(AirTree::assert_bool(name == "True", value));
|
||||
|
||||
AirTree::UnhoistedSequence(sequence)
|
||||
} else if tipo.is_void() {
|
||||
todo!()
|
||||
} else {
|
||||
if props.kind.is_expect() {
|
||||
let data_type = build::lookup_data_type_by_tipo(&self.data_types, tipo)
|
||||
.unwrap_or_else(|| panic!("Failed to find definition for {}", name));
|
||||
|
||||
if data_type.constructors.len() > 1
|
||||
|| (!tipo.is_data() && props.value_type.is_data())
|
||||
{
|
||||
let (index, _) = data_type
|
||||
.constructors
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, constr)| constr.name == *name)
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Found constructor type {} with 0 constructors", name)
|
||||
});
|
||||
|
||||
let constructor_name = format!(
|
||||
"__constructor_{}_span_{}_{}",
|
||||
name,
|
||||
pattern.location().start,
|
||||
pattern.location().end
|
||||
);
|
||||
|
||||
// I'm consuming `value` here
|
||||
let constructor_val = AirTree::let_assignment(&constructor_name, value);
|
||||
|
||||
sequence.push(constructor_val);
|
||||
|
||||
let assert_constr = AirTree::assert_constr_index(
|
||||
index,
|
||||
AirTree::local_var(&constructor_name, tipo.clone()),
|
||||
);
|
||||
|
||||
sequence.push(assert_constr);
|
||||
|
||||
//I'm reusing the `value` pointer
|
||||
value = AirTree::local_var(constructor_name, tipo.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let field_map = match constructor {
|
||||
PatternConstructor::Record { field_map, .. } => field_map.clone(),
|
||||
};
|
||||
|
||||
let mut type_map: IndexMap<usize, Arc<Type>> = IndexMap::new();
|
||||
|
||||
println!("tipo is {tipo:#?}");
|
||||
|
||||
for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() {
|
||||
let field_type = arg.clone();
|
||||
type_map.insert(index, field_type);
|
||||
}
|
||||
|
||||
let fields = arguments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, arg)| {
|
||||
let label = arg.label.clone().unwrap_or_default();
|
||||
|
||||
let field_index = if let Some(field_map) = &field_map {
|
||||
*field_map.fields.get(&label).map(|x| &x.0).unwrap_or(&index)
|
||||
} else {
|
||||
index
|
||||
};
|
||||
|
||||
let field_name = match &arg.value {
|
||||
Pattern::Var { name, .. } => name.to_string(),
|
||||
Pattern::Assign { name, .. } => name.to_string(),
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.kind.is_expect()
|
||||
&& props.value_type.is_data()
|
||||
&& !tipo.is_data()
|
||||
{
|
||||
format!("__discard_{}", name)
|
||||
} else {
|
||||
"_".to_string()
|
||||
}
|
||||
}
|
||||
_ => format!(
|
||||
"field_{}_span_{}_{}",
|
||||
field_index,
|
||||
arg.value.location().start,
|
||||
arg.value.location().end
|
||||
),
|
||||
};
|
||||
|
||||
let arg_type = type_map.get(&field_index).unwrap_or_else(|| {
|
||||
unreachable!(
|
||||
"Missing type for field {} of constr {}",
|
||||
field_index, name
|
||||
)
|
||||
});
|
||||
|
||||
let val = AirTree::local_var(field_name.to_string(), arg_type.clone());
|
||||
|
||||
(
|
||||
field_index,
|
||||
field_name,
|
||||
arg_type.clone(),
|
||||
self.assignment_air_tree(
|
||||
&arg.value,
|
||||
val,
|
||||
arg_type,
|
||||
AssignmentProperties {
|
||||
value_type: props.value_type.clone(),
|
||||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
let indices = fields
|
||||
.iter()
|
||||
.map(|(index, name, tipo, _)| (*index, name.to_string(), tipo.clone()))
|
||||
.collect_vec();
|
||||
|
||||
// This `value` is either value param that was passed in or
|
||||
// local var
|
||||
sequence.push(AirTree::fields_expose(indices, false, value));
|
||||
|
||||
sequence.append(
|
||||
&mut fields
|
||||
.into_iter()
|
||||
.map(|(_, _, _, field)| field)
|
||||
.collect_vec(),
|
||||
);
|
||||
|
||||
AirTree::UnhoistedSequence(sequence)
|
||||
}
|
||||
}
|
||||
Pattern::Tuple {
|
||||
elems, location, ..
|
||||
} => {
|
||||
let mut type_map: IndexMap<usize, Arc<Type>> = IndexMap::new();
|
||||
|
||||
let mut sequence = vec![];
|
||||
|
||||
for (index, arg) in tipo.get_inner_types().iter().enumerate() {
|
||||
let field_type = arg.clone();
|
||||
type_map.insert(index, field_type);
|
||||
}
|
||||
|
||||
let elems = elems
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, arg)| {
|
||||
let tuple_name = match &arg {
|
||||
Pattern::Var { name, .. } => name.to_string(),
|
||||
Pattern::Assign { name, .. } => name.to_string(),
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.kind.is_expect()
|
||||
&& props.value_type.is_data()
|
||||
&& !tipo.is_data()
|
||||
{
|
||||
format!("__discard_{}", name)
|
||||
} else {
|
||||
"_".to_string()
|
||||
}
|
||||
}
|
||||
_ => format!(
|
||||
"tuple_{}_span_{}_{}",
|
||||
index,
|
||||
arg.location().start,
|
||||
arg.location().end
|
||||
),
|
||||
};
|
||||
|
||||
let arg_type = type_map.get(&index).unwrap_or_else(|| {
|
||||
unreachable!(
|
||||
"Missing type for tuple index {} of tuple_span_{}_{}",
|
||||
index, location.start, location.end
|
||||
)
|
||||
});
|
||||
|
||||
let val = AirTree::local_var(tuple_name.to_string(), arg_type.clone());
|
||||
|
||||
(
|
||||
tuple_name,
|
||||
self.assignment_air_tree(
|
||||
arg,
|
||||
val,
|
||||
arg_type,
|
||||
AssignmentProperties {
|
||||
value_type: props.value_type.clone(),
|
||||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
let indices = elems.iter().map(|(name, _)| name.to_string()).collect_vec();
|
||||
|
||||
// This `value` is either value param that was passed in or
|
||||
// local var
|
||||
sequence.push(AirTree::tuple_access(indices, tipo.clone(), false, value));
|
||||
|
||||
sequence.append(&mut elems.into_iter().map(|(_, field)| field).collect_vec());
|
||||
|
||||
AirTree::UnhoistedSequence(sequence)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_type(
|
||||
&mut self,
|
||||
tipo: &Arc<Type>,
|
||||
value: AirTree,
|
||||
defined_data_types: &mut IndexMap<String, u64>,
|
||||
location: Span,
|
||||
) -> AirTree {
|
||||
assert!(tipo.get_generic().is_none());
|
||||
if tipo.is_primitive() {
|
||||
AirTree::void()
|
||||
} else if tipo.is_map() {
|
||||
assert!(!tipo.get_inner_types().is_empty());
|
||||
let inner_list_type = &tipo.get_inner_types()[0];
|
||||
let inner_pair_types = inner_list_type.get_inner_types();
|
||||
assert!(inner_pair_types.len() == 2);
|
||||
|
||||
let map_name = format!("__map_span_{}_{}", location.start, location.end);
|
||||
let pair_name = format!("__pair_span_{}_{}", location.start, location.end);
|
||||
let fst_name = format!("__pair_fst_span_{}_{}", location.start, location.end);
|
||||
let snd_name = format!("__pair_snd_span_{}_{}", location.start, location.end);
|
||||
|
||||
let assign = AirTree::let_assignment(&map_name, value);
|
||||
|
||||
let tuple_access = AirTree::tuple_access(
|
||||
vec![fst_name.clone(), snd_name.clone()],
|
||||
inner_list_type.clone(),
|
||||
false,
|
||||
AirTree::local_var(&pair_name, inner_list_type.clone()),
|
||||
);
|
||||
|
||||
let expect_fst = self.expect_type(
|
||||
&inner_pair_types[0],
|
||||
AirTree::local_var(fst_name, inner_pair_types[0].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
);
|
||||
|
||||
let expect_snd = self.expect_type(
|
||||
&inner_pair_types[1],
|
||||
AirTree::local_var(snd_name, inner_pair_types[1].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
);
|
||||
|
||||
let anon_func_body = AirTree::hoist_over(
|
||||
AirTree::UnhoistedSequence(vec![
|
||||
tuple_access,
|
||||
AirTree::let_assignment("_", expect_fst),
|
||||
AirTree::let_assignment("_", expect_snd),
|
||||
]),
|
||||
AirTree::void(),
|
||||
);
|
||||
|
||||
let unwrap_function = AirTree::anon_func(vec![pair_name], anon_func_body);
|
||||
|
||||
let function = self.code_gen_functions.get(EXPECT_ON_LIST);
|
||||
|
||||
if function.is_none() {
|
||||
let expect_list_func = AirTree::expect_on_list();
|
||||
self.code_gen_functions.insert(
|
||||
EXPECT_ON_LIST.to_string(),
|
||||
CodeGenFunction::Function(expect_list_func, vec![]),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(counter) = defined_data_types.get_mut(EXPECT_ON_LIST) {
|
||||
*counter += 1
|
||||
} else {
|
||||
defined_data_types.insert(EXPECT_ON_LIST.to_string(), 1);
|
||||
}
|
||||
|
||||
let func_call = AirTree::call(
|
||||
AirTree::local_var(EXPECT_ON_LIST, void()),
|
||||
void(),
|
||||
vec![AirTree::local_var(map_name, tipo.clone()), unwrap_function],
|
||||
);
|
||||
|
||||
AirTree::hoist_over(assign, func_call)
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,363 +1,11 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
ast::{BinOp, Constant, DataType, Pattern},
|
||||
builtins::int,
|
||||
gen_uplc::{
|
||||
builder::{self, AssignmentProperties, DataTypeKey},
|
||||
tree::AirTree,
|
||||
},
|
||||
ast::{Constant, Pattern},
|
||||
gen_uplc::{builder::AssignmentProperties, tree::AirTree},
|
||||
tipo::{PatternConstructor, Type},
|
||||
};
|
||||
|
||||
pub fn assignment_air_tree(
|
||||
pattern: &Pattern<PatternConstructor, Arc<Type>>,
|
||||
mut value: AirTree,
|
||||
tipo: &Arc<Type>,
|
||||
data_types: &IndexMap<DataTypeKey, &DataType<Arc<Type>>>,
|
||||
props: AssignmentProperties,
|
||||
) -> AirTree {
|
||||
if props.value_type.is_data() && props.kind.is_expect() && !tipo.is_data() {
|
||||
value = AirTree::unwrap_data(value, tipo.clone());
|
||||
} else if !props.value_type.is_data() && tipo.is_data() {
|
||||
value = AirTree::wrap_data(value, tipo.clone());
|
||||
}
|
||||
|
||||
match pattern {
|
||||
Pattern::Int {
|
||||
value: expected_int,
|
||||
location,
|
||||
..
|
||||
} => {
|
||||
if props.kind.is_expect() {
|
||||
let name = format!(
|
||||
"__expected_by_{}_span_{}_{}",
|
||||
expected_int, location.start, location.end
|
||||
);
|
||||
let assignment = AirTree::let_assignment(&name, value);
|
||||
|
||||
let expect = AirTree::binop(
|
||||
BinOp::Eq,
|
||||
int(),
|
||||
AirTree::int(expected_int),
|
||||
AirTree::local_var(name, int()),
|
||||
);
|
||||
AirTree::assert_bool(true, AirTree::hoist_over(assignment, expect))
|
||||
} else {
|
||||
unreachable!("Code Gen should never reach here")
|
||||
}
|
||||
}
|
||||
Pattern::Var { name, .. } => {
|
||||
if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() {
|
||||
let mut index_map = IndexMap::new();
|
||||
let tipo = convert_opaque_type();
|
||||
let assignment = AirTree::let_assignment(name, value);
|
||||
let val = AirTree::local_var(name, tipo.clone());
|
||||
let expect = expect_type(&tipo, val.clone(), &mut index_map);
|
||||
let assign = AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect));
|
||||
AirTree::let_assignment(name, AirTree::hoist_over(assign, val))
|
||||
} else {
|
||||
AirTree::let_assignment(name, value)
|
||||
}
|
||||
}
|
||||
Pattern::Assign { name, pattern, .. } => {
|
||||
let inner_pattern = assignment_air_tree(
|
||||
pattern,
|
||||
AirTree::local_var(name, tipo.clone()),
|
||||
tipo,
|
||||
data_types,
|
||||
props,
|
||||
);
|
||||
let assign = AirTree::let_assignment(name, value);
|
||||
|
||||
AirTree::UnhoistedSequence(vec![assign, inner_pattern])
|
||||
}
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() {
|
||||
let mut index_map = IndexMap::new();
|
||||
let tipo = convert_opaque_type();
|
||||
let assignment = AirTree::let_assignment(name, value);
|
||||
let val = AirTree::local_var(name, tipo.clone());
|
||||
let expect = expect_type(&tipo, val.clone(), &mut index_map);
|
||||
let assign = AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect));
|
||||
AirTree::let_assignment(name, AirTree::hoist_over(assign, val))
|
||||
} else if !props.remove_unused {
|
||||
AirTree::let_assignment(name, value)
|
||||
} else {
|
||||
AirTree::no_op()
|
||||
}
|
||||
}
|
||||
Pattern::List { elements, tail, .. } => {
|
||||
assert!(tipo.is_list());
|
||||
assert!(props.kind.is_expect());
|
||||
let list_elem_types = tipo.get_inner_types();
|
||||
|
||||
let list_elem_type = list_elem_types
|
||||
.get(0)
|
||||
.unwrap_or_else(|| unreachable!("No list element type?"));
|
||||
|
||||
let mut elems = elements
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, elem)| {
|
||||
let elem_name = match elem {
|
||||
Pattern::Var { name, .. } => name.to_string(),
|
||||
Pattern::Assign { name, .. } => name.to_string(),
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.kind.is_expect()
|
||||
&& props.value_type.is_data()
|
||||
&& !tipo.is_data()
|
||||
{
|
||||
format!("__discard_{}", name)
|
||||
} else {
|
||||
"_".to_string()
|
||||
}
|
||||
}
|
||||
_ => format!(
|
||||
"elem_{}_span_{}_{}",
|
||||
index,
|
||||
elem.location().start,
|
||||
elem.location().end
|
||||
),
|
||||
};
|
||||
|
||||
let val = AirTree::local_var(&elem_name, list_elem_type.clone());
|
||||
|
||||
(
|
||||
elem_name,
|
||||
assignment_air_tree(
|
||||
elem,
|
||||
val,
|
||||
list_elem_type,
|
||||
data_types,
|
||||
AssignmentProperties {
|
||||
value_type: props.value_type.clone(),
|
||||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
// If Some then push tail onto elems
|
||||
tail.iter().for_each(|tail| {
|
||||
let tail_name = match tail.as_ref() {
|
||||
Pattern::Var { name, .. } => name.to_string(),
|
||||
Pattern::Assign { name, .. } => name.to_string(),
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() {
|
||||
format!("__discard_{}", name)
|
||||
} else {
|
||||
"_".to_string()
|
||||
}
|
||||
}
|
||||
_ => format!(
|
||||
"tail_span_{}_{}",
|
||||
tail.location().start,
|
||||
tail.location().end
|
||||
),
|
||||
};
|
||||
|
||||
let val = AirTree::local_var(&tail_name, tipo.clone());
|
||||
|
||||
elems.push((
|
||||
tail_name,
|
||||
assignment_air_tree(
|
||||
tail,
|
||||
val,
|
||||
tipo,
|
||||
data_types,
|
||||
AssignmentProperties {
|
||||
value_type: props.value_type.clone(),
|
||||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
},
|
||||
),
|
||||
));
|
||||
});
|
||||
|
||||
let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec();
|
||||
|
||||
let mut sequence = vec![AirTree::list_access(
|
||||
names,
|
||||
tipo.clone(),
|
||||
tail.is_some(),
|
||||
tail.is_none(),
|
||||
value,
|
||||
)];
|
||||
|
||||
sequence.append(&mut elems.into_iter().map(|(_, elem)| elem).collect_vec());
|
||||
|
||||
AirTree::UnhoistedSequence(sequence)
|
||||
}
|
||||
Pattern::Constructor {
|
||||
arguments,
|
||||
constructor,
|
||||
name,
|
||||
..
|
||||
} => {
|
||||
let mut sequence = vec![];
|
||||
|
||||
if tipo.is_bool() {
|
||||
assert!(props.kind.is_expect());
|
||||
|
||||
sequence.push(AirTree::assert_bool(name == "True", value));
|
||||
|
||||
AirTree::UnhoistedSequence(sequence)
|
||||
} else if tipo.is_void() {
|
||||
todo!()
|
||||
} else {
|
||||
if props.kind.is_expect() {
|
||||
let data_type = builder::lookup_data_type_by_tipo(data_types, tipo)
|
||||
.unwrap_or_else(|| panic!("Failed to find definition for {}", name));
|
||||
|
||||
if data_type.constructors.len() > 1
|
||||
|| (!tipo.is_data() && props.value_type.is_data())
|
||||
{
|
||||
let (index, _) = data_type
|
||||
.constructors
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, constr)| constr.name == *name)
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Found constructor type {} with 0 constructors", name)
|
||||
});
|
||||
|
||||
let constructor_name = format!(
|
||||
"__constructor_{}_span_{}_{}",
|
||||
name,
|
||||
pattern.location().start,
|
||||
pattern.location().end
|
||||
);
|
||||
|
||||
// I'm moving `value` here
|
||||
let constructor_val = AirTree::let_assignment(&constructor_name, value);
|
||||
|
||||
sequence.push(constructor_val);
|
||||
|
||||
let assert_constr = AirTree::assert_constr_index(
|
||||
index,
|
||||
AirTree::local_var(&constructor_name, tipo.clone()),
|
||||
);
|
||||
|
||||
sequence.push(assert_constr);
|
||||
|
||||
//I'm reusing the `value` pointer
|
||||
value = AirTree::local_var(constructor_name, tipo.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let field_map = match constructor {
|
||||
PatternConstructor::Record { field_map, .. } => field_map.clone(),
|
||||
};
|
||||
|
||||
let mut type_map: IndexMap<usize, Arc<Type>> = IndexMap::new();
|
||||
|
||||
println!("tipo is {tipo:#?}");
|
||||
|
||||
for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() {
|
||||
let field_type = arg.clone();
|
||||
type_map.insert(index, field_type);
|
||||
}
|
||||
|
||||
let fields = arguments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, arg)| {
|
||||
let label = arg.label.clone().unwrap_or_default();
|
||||
|
||||
let field_index = if let Some(field_map) = &field_map {
|
||||
*field_map.fields.get(&label).map(|x| &x.0).unwrap_or(&index)
|
||||
} else {
|
||||
index
|
||||
};
|
||||
|
||||
let field_name = match &arg.value {
|
||||
Pattern::Var { name, .. } => name.to_string(),
|
||||
Pattern::Assign { name, .. } => name.to_string(),
|
||||
Pattern::Discard { name, .. } => {
|
||||
if props.kind.is_expect()
|
||||
&& props.value_type.is_data()
|
||||
&& !tipo.is_data()
|
||||
{
|
||||
format!("__discard_{}", name)
|
||||
} else {
|
||||
"_".to_string()
|
||||
}
|
||||
}
|
||||
_ => format!(
|
||||
"field_{}_span_{}_{}",
|
||||
field_index,
|
||||
arg.value.location().start,
|
||||
arg.value.location().end
|
||||
),
|
||||
};
|
||||
|
||||
let arg_type = type_map.get(&field_index).unwrap_or_else(|| {
|
||||
unreachable!(
|
||||
"Missing type for field {} of constr {}",
|
||||
field_index, name
|
||||
)
|
||||
});
|
||||
|
||||
let val = AirTree::local_var(field_name.to_string(), arg_type.clone());
|
||||
|
||||
(
|
||||
field_index,
|
||||
field_name,
|
||||
arg_type.clone(),
|
||||
assignment_air_tree(
|
||||
&arg.value,
|
||||
val,
|
||||
arg_type,
|
||||
data_types,
|
||||
AssignmentProperties {
|
||||
value_type: props.value_type.clone(),
|
||||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
let indices = fields
|
||||
.iter()
|
||||
.map(|(index, name, tipo, _)| (*index, name.to_string(), tipo.clone()))
|
||||
.collect_vec();
|
||||
|
||||
// This `value` is either value param that was passed in or
|
||||
// local var
|
||||
sequence.push(AirTree::fields_expose(indices, false, value));
|
||||
|
||||
sequence.append(
|
||||
&mut fields
|
||||
.into_iter()
|
||||
.map(|(_, _, _, field)| field)
|
||||
.collect_vec(),
|
||||
);
|
||||
|
||||
AirTree::UnhoistedSequence(sequence)
|
||||
}
|
||||
}
|
||||
Pattern::Tuple { elems, .. } => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_type(
|
||||
tipo: &Arc<Type>,
|
||||
value: AirTree,
|
||||
defined_data_types: &mut IndexMap<String, u64>,
|
||||
) -> AirTree {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn convert_opaque_type() -> Arc<Type> {
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -89,6 +89,15 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_primitive(&self) -> bool {
|
||||
self.is_bool()
|
||||
|| self.is_bytearray()
|
||||
|| self.is_int()
|
||||
|| self.is_string()
|
||||
|| self.is_void()
|
||||
|| self.is_data()
|
||||
}
|
||||
|
||||
pub fn is_void(&self) -> bool {
|
||||
match self {
|
||||
Self::App { module, name, .. } if "Void" == name && module.is_empty() => true,
|
||||
|
|
Loading…
Reference in New Issue