feat(gen_uplc): introduce scope new type

* new module scope which holds some ancestor logic
* rework some things to truly hide scope increments

Co-authored-by: Kasey White <kwhitemsg@gmail.com>
This commit is contained in:
rvcas 2023-03-22 22:33:49 -04:00 committed by Lucas
parent ca0d896b8d
commit 33a3c5dc13
6 changed files with 519 additions and 392 deletions

View File

@ -4,7 +4,7 @@ use indexmap::{IndexMap, IndexSet};
use itertools::Itertools; use itertools::Itertools;
use uplc::{ use uplc::{
ast::{Constant as UplcConstant, Name, NamedDeBruijn, Program, Term, Type as UplcType}, ast::{Constant as UplcConstant, Name, NamedDeBruijn, Program, Term, Type as UplcType},
builder::{ASSERT_ON_LIST, CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD, CONSTR_INDEX_EXPOSER}, builder::{CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD, CONSTR_INDEX_EXPOSER, EXPECT_ON_LIST},
builtins::DefaultFunction, builtins::DefaultFunction,
machine::cost_model::ExBudget, machine::cost_model::ExBudget,
optimize::aiken_optimize_and_intern, optimize::aiken_optimize_and_intern,
@ -27,6 +27,7 @@ use crate::{
pub mod air; pub mod air;
pub mod builder; pub mod builder;
pub mod scope;
pub mod stack; pub mod stack;
use air::Air; use air::Air;
@ -185,14 +186,15 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::String { value, .. } => ir_stack.string(value.to_string()), TypedExpr::String { value, .. } => ir_stack.string(value.to_string()),
TypedExpr::ByteArray { bytes, .. } => ir_stack.byte_array(bytes.to_vec()), TypedExpr::ByteArray { bytes, .. } => ir_stack.byte_array(bytes.to_vec()),
TypedExpr::Pipeline { expressions, .. } | TypedExpr::Sequence { expressions, .. } => { TypedExpr::Pipeline { expressions, .. } | TypedExpr::Sequence { expressions, .. } => {
let stacks = Vec::new(); let mut stacks = Vec::new();
for (index, expr) in expressions.iter().enumerate() { for (index, expr) in expressions.iter().enumerate() {
if index == 0 { if index == 0 {
self.build_ir(expr, ir_stack); self.build_ir(expr, ir_stack);
} else { } else {
let mut stack = ir_stack.in_new_scope(); let mut stack = ir_stack.empty_with_scope();
self.build_ir(expr, &mut stack); self.build_ir(expr, &mut stack);
stacks.push(stack);
} }
} }
@ -215,7 +217,7 @@ impl<'a> CodeGenerator<'a> {
} }
}, },
TypedExpr::Fn { args, body, .. } => { TypedExpr::Fn { args, body, .. } => {
let mut body_stack = ir_stack.in_new_scope(); let mut body_stack = ir_stack.empty_with_scope();
self.build_ir(body, &mut body_stack); self.build_ir(body, &mut body_stack);
@ -234,7 +236,7 @@ impl<'a> CodeGenerator<'a> {
} => { } => {
let stacks = Vec::new(); let stacks = Vec::new();
for element in elements { for element in elements {
let mut stack = ir_stack.in_new_scope(); let mut stack = ir_stack.empty_with_scope();
self.build_ir(element, &mut stack); self.build_ir(element, &mut stack);
@ -242,7 +244,7 @@ impl<'a> CodeGenerator<'a> {
} }
let tail = tail.as_ref().map(|tail| { let tail = tail.as_ref().map(|tail| {
let mut tail_stack = ir_stack.in_new_scope(); let mut tail_stack = ir_stack.empty_with_scope();
self.build_ir(tail, &mut tail_stack); self.build_ir(tail, &mut tail_stack);
@ -276,7 +278,7 @@ impl<'a> CodeGenerator<'a> {
let stacks = Vec::new(); let stacks = Vec::new();
for (arg, func_type) in args.iter().zip(fun_arg_types) { for (arg, func_type) in args.iter().zip(fun_arg_types) {
let mut stack = ir_stack.in_new_scope(); let mut stack = ir_stack.empty_with_scope();
if func_type.is_data() && !arg.value.tipo().is_data() { if func_type.is_data() && !arg.value.tipo().is_data() {
stack.wrap_data(arg.value.tipo()); stack.wrap_data(arg.value.tipo());
@ -301,7 +303,7 @@ impl<'a> CodeGenerator<'a> {
let stacks = Vec::new(); let stacks = Vec::new();
for (arg, func_type) in args.iter().zip(fun_arg_types) { for (arg, func_type) in args.iter().zip(fun_arg_types) {
let mut stack = ir_stack.in_new_scope(); let mut stack = ir_stack.empty_with_scope();
if func_type.is_data() && !arg.value.tipo().is_data() { if func_type.is_data() && !arg.value.tipo().is_data() {
stack.wrap_data(arg.value.tipo()); stack.wrap_data(arg.value.tipo());
@ -341,7 +343,7 @@ impl<'a> CodeGenerator<'a> {
let mut stacks = Vec::new(); let mut stacks = Vec::new();
for (arg, func_type) in args.iter().zip(fun_arg_types) { for (arg, func_type) in args.iter().zip(fun_arg_types) {
let mut stack = ir_stack.in_new_scope(); let mut stack = ir_stack.empty_with_scope();
if func_type.is_data() && !arg.value.tipo().is_data() { if func_type.is_data() && !arg.value.tipo().is_data() {
stack.wrap_data(arg.value.tipo()); stack.wrap_data(arg.value.tipo());
@ -366,7 +368,7 @@ impl<'a> CodeGenerator<'a> {
let mut stacks = Vec::new(); let mut stacks = Vec::new();
for (arg, func_type) in args.iter().zip(fun_arg_types) { for (arg, func_type) in args.iter().zip(fun_arg_types) {
let mut stack = ir_stack.in_new_scope(); let mut stack = ir_stack.empty_with_scope();
if func_type.is_data() && !arg.value.tipo().is_data() { if func_type.is_data() && !arg.value.tipo().is_data() {
stack.wrap_data(arg.value.tipo()); stack.wrap_data(arg.value.tipo());
@ -385,7 +387,7 @@ impl<'a> CodeGenerator<'a> {
_ => {} _ => {}
} }
let mut fun_stack = ir_stack.in_new_scope(); let mut fun_stack = ir_stack.empty_with_scope();
self.build_ir(fun, &mut fun_stack); self.build_ir(fun, &mut fun_stack);
@ -393,7 +395,7 @@ impl<'a> CodeGenerator<'a> {
let mut stacks = Vec::new(); let mut stacks = Vec::new();
for (arg, func_type) in args.iter().zip(fun_arg_types) { for (arg, func_type) in args.iter().zip(fun_arg_types) {
let mut stack = ir_stack.in_new_scope(); let mut stack = ir_stack.empty_with_scope();
if func_type.is_data() && !arg.value.tipo().is_data() { if func_type.is_data() && !arg.value.tipo().is_data() {
stack.wrap_data(arg.value.tipo()); stack.wrap_data(arg.value.tipo());
@ -407,8 +409,8 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::BinOp { TypedExpr::BinOp {
name, left, right, .. name, left, right, ..
} => { } => {
let mut left_stack = ir_stack.in_new_scope(); let mut left_stack = ir_stack.empty_with_scope();
let mut right_stack = ir_stack.in_new_scope(); let mut right_stack = ir_stack.empty_with_scope();
self.build_ir(left, &mut left_stack); self.build_ir(left, &mut left_stack);
self.build_ir(right, &mut right_stack); self.build_ir(right, &mut right_stack);
@ -422,8 +424,8 @@ impl<'a> CodeGenerator<'a> {
tipo, tipo,
.. ..
} => { } => {
let mut value_stack = ir_stack.in_new_scope(); let mut value_stack = ir_stack.empty_with_scope();
let mut pattern_stack = ir_stack.in_new_scope(); let mut pattern_stack = ir_stack.empty_with_scope();
let mut replaced_type = tipo.clone(); let mut replaced_type = tipo.clone();
builder::replace_opaque_type(&mut replaced_type, self.data_types.clone()); builder::replace_opaque_type(&mut replaced_type, self.data_types.clone());
@ -1756,17 +1758,17 @@ impl<'a> CodeGenerator<'a> {
&& !tipo.is_data() && !tipo.is_data()
&& !pattern.is_discard() && !pattern.is_discard()
{ {
let mut wrap_stack = pattern_stack.in_new_scope(); let mut wrap_stack = pattern_stack.empty_with_scope();
wrap_stack.un_wrap_data(tipo.clone().into()); wrap_stack.un_wrap_data(tipo.clone().into());
wrap_stack.merge(value_stack); wrap_stack.merge_child(value_stack);
wrap_stack wrap_stack
} else if !assignment_properties.value_type.is_data() } else if !assignment_properties.value_type.is_data()
&& tipo.is_data() && tipo.is_data()
&& !pattern.is_discard() && !pattern.is_discard()
{ {
let mut wrap_stack = pattern_stack.in_new_scope(); let mut wrap_stack = pattern_stack.empty_with_scope();
wrap_stack.wrap_data(assignment_properties.value_type.clone()); wrap_stack.wrap_data(assignment_properties.value_type.clone());
wrap_stack.merge(value_stack); wrap_stack.merge_child(value_stack);
wrap_stack wrap_stack
} else { } else {
value_stack value_stack
@ -1775,24 +1777,24 @@ impl<'a> CodeGenerator<'a> {
match pattern { match pattern {
Pattern::Int { .. } => todo!(), Pattern::Int { .. } => todo!(),
Pattern::Var { name, .. } => { Pattern::Var { name, .. } => {
let assert_value_stack = value_stack.in_new_scope(); let expect_value_stack = value_stack.empty_with_scope();
pattern_stack.let_assignment(name, value_stack); pattern_stack.let_assignment(name, value_stack);
if matches!(assignment_properties.kind, AssignmentKind::Expect) if matches!(assignment_properties.kind, AssignmentKind::Expect)
&& assignment_properties.value_type.is_data() && assignment_properties.value_type.is_data()
&& !tipo.is_data() && !tipo.is_data()
{ {
let mut assert_stack = pattern_stack.in_new_scope(); let mut expect_stack = pattern_stack.empty_with_scope();
self.recursive_assert_pattern( self.expect_pattern(
pattern, pattern,
&mut assert_stack, &mut expect_stack,
assert_value_stack, expect_value_stack,
tipo, tipo,
assignment_properties, assignment_properties,
); );
pattern_stack.merge(assert_stack); pattern_stack.merge(expect_stack);
} }
} }
Pattern::Assign { .. } => todo!("Assign not yet implemented"), Pattern::Assign { .. } => todo!("Assign not yet implemented"),
@ -1804,7 +1806,7 @@ impl<'a> CodeGenerator<'a> {
&& assignment_properties.value_type.is_data() && assignment_properties.value_type.is_data()
&& !tipo.is_data() && !tipo.is_data()
{ {
self.recursive_assert_pattern( self.expect_pattern(
list, list,
pattern_vec, pattern_vec,
value_vec, value_vec,
@ -1828,7 +1830,7 @@ impl<'a> CodeGenerator<'a> {
&& assignment_properties.value_type.is_data() && assignment_properties.value_type.is_data()
&& !tipo.is_data() && !tipo.is_data()
{ {
self.recursive_assert_pattern( self.expect_pattern(
constr, constr,
pattern_vec, pattern_vec,
value_vec, value_vec,
@ -1852,7 +1854,7 @@ impl<'a> CodeGenerator<'a> {
&& assignment_properties.value_type.is_data() && assignment_properties.value_type.is_data()
&& !tipo.is_data() && !tipo.is_data()
{ {
self.recursive_assert_pattern( self.expect_pattern(
tuple, tuple,
pattern_vec, pattern_vec,
value_vec, value_vec,
@ -2165,10 +2167,10 @@ impl<'a> CodeGenerator<'a> {
} }
} }
pub fn recursive_assert_pattern( pub fn expect_pattern(
&mut self, &mut self,
pattern: &Pattern<PatternConstructor, Arc<Type>>, pattern: &Pattern<PatternConstructor, Arc<Type>>,
assert_stack: &mut AirStack, expect_stack: &mut AirStack,
value_stack: AirStack, value_stack: AirStack,
tipo: &Type, tipo: &Type,
assignment_properties: AssignmentProperties, assignment_properties: AssignmentProperties,
@ -2176,51 +2178,52 @@ impl<'a> CodeGenerator<'a> {
match pattern { match pattern {
Pattern::Int { .. } => unreachable!(), Pattern::Int { .. } => unreachable!(),
Pattern::Var { name, .. } => { Pattern::Var { name, .. } => {
assert_stack.merge(value_stack); expect_stack.merge(value_stack);
self.recursive_assert_tipo(tipo, assert_stack, name); self.expect_type(tipo, expect_stack, name);
} }
Pattern::Assign { .. } => todo!(), Pattern::Assign { .. } => todo!(),
Pattern::Discard { .. } => unreachable!(), Pattern::Discard { .. } => unreachable!(),
Pattern::List { elements, tail, .. } => { Pattern::List { elements, tail, .. } => {
let mut assert_list_vec = vec![];
let inner_list_type = &tipo.get_inner_types()[0]; let inner_list_type = &tipo.get_inner_types()[0];
let mut names = vec![]; let mut names = vec![];
let mut expect_list_stacks = vec![];
for element in elements { for element in elements {
match element { match element {
Pattern::Var { name, .. } => { Pattern::Var { name, .. } => {
names.push(name.clone()); names.push(name.clone());
} }
Pattern::Assign { .. } => todo!(), Pattern::Assign { .. } => todo!(),
l @ (Pattern::List { .. } element_pattern @ (Pattern::List { .. }
| Pattern::Constructor { .. } | Pattern::Constructor { .. }
| Pattern::Tuple { .. }) => { | Pattern::Tuple { .. }) => {
let name = format!("list_item_id_{}", self.id_gen.next()); let name = format!("list_item_id_{}", self.id_gen.next());
names.push(name.clone()); names.push(name.clone());
self.recursive_assert_pattern( let mut element_stack = expect_stack.empty_with_scope();
l, let mut value_stack = element_stack.empty_with_scope();
&mut assert_list_vec,
&mut vec![Air::Var { value_stack.local_var(tipo.clone().into(), name);
scope: scope.clone(),
constructor: ValueConstructor::public( self.expect_pattern(
tipo.clone().into(), element_pattern,
ValueConstructorVariant::LocalVariable { &mut element_stack,
location: Span::empty(), value_stack,
},
),
name,
variant_name: String::new(),
}],
inner_list_type, inner_list_type,
assignment_properties.clone(), assignment_properties.clone(),
scope.clone(),
); );
expect_list_stacks.push(element_stack);
} }
_ => {} _ => {}
} }
} }
let mut tail_stack = expect_stack.empty_with_scope();
let name = if let Some(tail) = tail { let name = if let Some(tail) = tail {
match &**tail { match &**tail {
Pattern::Var { name, .. } => name.clone(), Pattern::Var { name, .. } => name.clone(),
@ -2230,21 +2233,13 @@ impl<'a> CodeGenerator<'a> {
format!("__tail_{}", self.id_gen.next()) format!("__tail_{}", self.id_gen.next())
}; };
self.recursive_assert_tipo(tipo, &mut assert_list_vec, &name, scope.clone()); self.expect_type(tipo, &mut tail_stack, &name);
names.push(name); names.push(name);
pattern_vec.push(Air::ListAccessor { expect_stack.list_accessor(tipo.clone().into(), names, true, false, value_stack);
scope,
tipo: tipo.clone().into(),
names,
tail: true,
check_last_item: false,
});
pattern_vec.append(value_vec); expect_stack.merge_children(expect_list_stacks);
pattern_vec.append(&mut assert_list_vec);
} }
Pattern::Constructor { Pattern::Constructor {
arguments, arguments,
@ -2306,17 +2301,19 @@ impl<'a> CodeGenerator<'a> {
current_index += 1; current_index += 1;
} else { } else {
let id_next = self.id_gen.next(); let id_next = self.id_gen.next();
final_args.push((format!("__field_{index}_{id_next}"), index)); final_args.push((format!("__field_{index}_{id_next}"), index));
self.recursive_assert_tipo(
self.expect_type(
type_map.get(&index).unwrap(), type_map.get(&index).unwrap(),
&mut nested_pattern, &mut nested_pattern,
&format!("__field_{index}_{id_next}"), &format!("__field_{index}_{id_next}"),
scope.clone(),
) )
} }
} }
let constr_var = format!("__constr_{}", self.id_gen.next()); let constr_var = format!("__constr_{}", self.id_gen.next());
pattern_vec.push(Air::Let { pattern_vec.push(Air::Let {
scope: scope.clone(), scope: scope.clone(),
name: constr_var.clone(), name: constr_var.clone(),
@ -2411,11 +2408,10 @@ impl<'a> CodeGenerator<'a> {
} else { } else {
let id_next = self.id_gen.next(); let id_next = self.id_gen.next();
final_args.push((format!("__tuple_{index}_{id_next}"), index)); final_args.push((format!("__tuple_{index}_{id_next}"), index));
self.recursive_assert_tipo( self.expect_type(
type_map.get(&index).unwrap(), type_map.get(&index).unwrap(),
&mut nested_pattern, &mut nested_pattern,
&format!("__tuple_{index}_{id_next}"), &format!("__tuple_{index}_{id_next}"),
scope.clone(),
) )
} }
} }
@ -2436,7 +2432,7 @@ impl<'a> CodeGenerator<'a> {
} }
} }
fn recursive_assert_tipo(&mut self, tipo: &Type, assert_vec: &mut AirStack, name: &str) { fn expect_type(&mut self, tipo: &Type, expect_stack: &mut AirStack, name: &str) {
let mut tipo = tipo.clone().into(); let mut tipo = tipo.clone().into();
builder::replace_opaque_type(&mut tipo, self.data_types.clone()); builder::replace_opaque_type(&mut tipo, self.data_types.clone());
@ -2455,231 +2451,103 @@ impl<'a> CodeGenerator<'a> {
let inner_list_type = &tipo.get_inner_types()[0]; let inner_list_type = &tipo.get_inner_types()[0];
let inner_pair_types = inner_list_type.get_inner_types(); let inner_pair_types = inner_list_type.get_inner_types();
assert_vec.push(Air::Builtin { let mut unwrap_function_stack = expect_stack.empty_with_scope();
scope: scope.clone(), let mut pair_access_stack = unwrap_function_stack.empty_with_scope();
func: DefaultFunction::ChooseUnit, let mut local_var_stack = pair_access_stack.empty_with_scope();
tipo: tipo.clone(),
count: DefaultFunction::ChooseUnit.arity(),
});
assert_vec.push(Air::Call { local_var_stack.local_var(inner_list_type.clone(), format!("__pair_{new_id}"));
scope: scope.clone(),
count: 2,
tipo: tipo.clone(),
});
assert_vec.push(Air::Var { pair_access_stack.tuple_accessor(
scope: scope.clone(), inner_list_type.clone(),
constructor: ValueConstructor::public( vec![
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: ASSERT_ON_LIST.to_string(),
variant_name: String::new(),
});
assert_vec.push(Air::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: name.to_owned(),
variant_name: String::new(),
});
assert_vec.push(Air::Fn {
scope: scope.clone(),
params: vec![format!("__pair_{new_id}")],
});
assert_vec.push(Air::TupleAccessor {
scope: scope.clone(),
names: vec![
format!("__pair_fst_{}", id_pair.0), format!("__pair_fst_{}", id_pair.0),
format!("__pair_snd_{}", id_pair.1), format!("__pair_snd_{}", id_pair.1),
], ],
tipo: inner_list_type.clone(), false,
check_last_item: false, local_var_stack,
}); );
assert_vec.push(Air::Var { self.expect_type(
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: format!("__pair_{new_id}"),
variant_name: String::new(),
});
self.recursive_assert_tipo(
&inner_pair_types[0], &inner_pair_types[0],
assert_vec, &mut pair_access_stack,
&format!("__pair_fst_{}", id_pair.0), &format!("__pair_fst_{}", id_pair.0),
scope.clone(),
); );
self.recursive_assert_tipo( self.expect_type(
&inner_pair_types[1], &inner_pair_types[1],
assert_vec, &mut pair_access_stack,
&format!("__pair_snd_{}", id_pair.1), &format!("__pair_snd_{}", id_pair.1),
scope.clone(),
); );
assert_vec.push(Air::Void { scope }); unwrap_function_stack
.anonymous_function(vec![format!("__pair_{new_id}")], pair_access_stack);
expect_stack.expect_list_from_data(tipo.clone(), name, unwrap_function_stack);
expect_stack.void();
} else if tipo.is_list() { } 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 new_id = self.id_gen.next();
let inner_list_type = &tipo.get_inner_types()[0]; let inner_list_type = &tipo.get_inner_types()[0];
assert_vec.push(Air::Builtin { let mut unwrap_function_stack = expect_stack.empty_with_scope();
scope: scope.clone(), let mut list_access_stack = unwrap_function_stack.empty_with_scope();
func: DefaultFunction::ChooseUnit, let mut local_var_stack = list_access_stack.empty_with_scope();
tipo: tipo.clone(),
count: DefaultFunction::ChooseUnit.arity(),
});
assert_vec.push(Air::Call { local_var_stack.un_wrap_data(inner_list_type.clone());
scope: scope.clone(), local_var_stack.local_var(inner_list_type.clone(), format!("__list_item_{new_id}"));
count: 2,
tipo: tipo.clone(),
});
assert_vec.push(Air::Var { list_access_stack.let_assignment(format!("__list_item_{new_id}"), local_var_stack);
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: ASSERT_ON_LIST.to_string(),
variant_name: String::new(),
});
assert_vec.push(Air::Var { self.expect_type(
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: name.to_owned(),
variant_name: String::new(),
});
assert_vec.push(Air::Fn {
scope: scope.clone(),
params: vec![format!("__list_item_{new_id}")],
});
assert_vec.push(Air::Let {
scope: scope.clone(),
name: format!("__list_item_{new_id}"),
});
assert_vec.push(Air::UnWrapData {
scope: scope.clone(),
tipo: inner_list_type.clone(),
});
assert_vec.push(Air::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: format!("__list_item_{new_id}"),
variant_name: String::new(),
});
self.recursive_assert_tipo(
inner_list_type, inner_list_type,
assert_vec, &mut list_access_stack,
&format!("__list_item_{new_id}"), &format!("__list_item_{new_id}"),
scope.clone(),
); );
assert_vec.push(Air::Void { scope }); unwrap_function_stack
.anonymous_function(vec![format!("__list_item_{new_id}")], list_access_stack);
expect_stack.expect_list_from_data(tipo.clone(), name, unwrap_function_stack);
expect_stack.void();
} else if tipo.is_tuple() { } else if tipo.is_tuple() {
let tuple_inner_types = tipo.get_inner_types(); let tuple_inner_types = tipo.get_inner_types();
let mut new_id_list = vec![]; let mut new_id_list = vec![];
for (index, _) in tuple_inner_types.iter().enumerate() { for (index, _) in tuple_inner_types.iter().enumerate() {
new_id_list.push((index, self.id_gen.next())); new_id_list.push((index, self.id_gen.next()));
} }
assert_vec.push(Air::TupleAccessor { let mut local_var_stack = expect_stack.empty_with_scope();
scope: scope.clone(),
names: new_id_list local_var_stack.local_var(tipo, name);
let names = new_id_list
.iter() .iter()
.map(|(index, id)| format!("__tuple_index_{index}_{id}")) .map(|(index, id)| format!("__tuple_index_{index}_{id}"))
.collect_vec(), .collect();
tipo: tipo.clone(),
check_last_item: true,
});
assert_vec.push(Air::Var { expect_stack.tuple_accessor(tipo, names, true, local_var_stack);
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: name.to_owned(),
variant_name: String::new(),
});
for (index, name) in new_id_list for (index, name) in new_id_list
.into_iter() .into_iter()
.map(|(index, id)| (index, format!("__tuple_index_{index}_{id}"))) .map(|(index, id)| (index, format!("__tuple_index_{index}_{id}")))
{ {
self.recursive_assert_tipo( self.expect_type(&tuple_inner_types[index], expect_stack, &name);
&tuple_inner_types[index],
assert_vec,
&name,
scope.clone(),
);
} }
} else { } else {
let data_type = let data_type =
builder::lookup_data_type_by_tipo(self.data_types.clone(), &tipo).unwrap(); builder::lookup_data_type_by_tipo(self.data_types.clone(), &tipo).unwrap();
let new_id = self.id_gen.next(); let new_id = self.id_gen.next();
assert_vec.push(Air::Builtin { // START HERE
scope: scope.clone(), let mut arg_stack = expect_stack.empty_with_scope();
func: DefaultFunction::ChooseUnit, let mut clause_stack = expect_stack.empty_with_scope();
tipo: tipo.clone(), let mut when_stack = expect_stack.empty_with_scope();
count: DefaultFunction::ChooseUnit.arity(), let mut trace_stack = expect_stack.empty_with_scope();
}); let mut subject_stack = expect_stack.empty_with_scope();
assert_vec.push(Air::When {
scope: scope.clone(),
tipo: tipo.clone(),
subject_name: format!("__subject_{new_id}"),
});
assert_vec.push(Air::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: name.to_owned(),
variant_name: String::new(),
});
for (index, constr) in data_type.constructors.iter().enumerate() { for (index, constr) in data_type.constructors.iter().enumerate() {
let arg_indices = constr let arg_indices = constr
@ -2691,65 +2559,50 @@ impl<'a> CodeGenerator<'a> {
.label .label
.clone() .clone()
.unwrap_or(format!("__field_{index}_{new_id}")); .unwrap_or(format!("__field_{index}_{new_id}"));
(index, arg_name, arg.tipo.clone()) (index, arg_name, arg.tipo.clone())
}) })
.collect_vec(); .collect_vec();
assert_vec.push(Air::Clause { for (index, name, tipo) in arg_indices {
scope: scope.clone(), self.expect_type(&tipo, &mut arg_stack, &name);
tipo: tipo.clone(),
subject_name: format!("__subject_{new_id}"),
complex_clause: false,
});
assert_vec.push(Air::Int {
scope: scope.clone(),
value: index.to_string(),
});
if !arg_indices.is_empty() {
assert_vec.push(Air::FieldsExpose {
scope: scope.clone(),
indices: arg_indices.clone(),
check_last_item: true,
});
assert_vec.push(Air::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: name.to_owned(),
variant_name: String::new(),
});
} }
for (_, name, tipo) in arg_indices { arg_stack = if !arg_indices.is_empty() {
self.recursive_assert_tipo(&tipo, assert_vec, &name, scope.clone()); arg_stack.local_var(tipo, name);
let field_expose_stack = expect_stack.empty_with_scope();
field_expose_stack.fields_expose(arg_indices.clone(), true, arg_stack);
field_expose_stack
} else {
arg_stack
};
arg_stack.void();
clause_stack.clause(tipo, format!("__subject_{new_id}"), index, false, arg_stack);
} }
assert_vec.push(Air::Void { trace_stack.trace(tipo.clone());
scope: scope.clone(),
});
}
assert_vec.push(Air::Trace { trace_stack.string("Constr index did not match any type variant");
scope: scope.clone(),
tipo: tipo.clone(),
});
assert_vec.push(Air::String { trace_stack.error(tipo.clone());
scope: scope.clone(),
value: "Constr index did not match any type variant".to_string(),
});
assert_vec.push(Air::ErrorTerm { subject_stack.local_var(tipo, name);
scope,
tipo: tipo.clone(), when_stack.when(
}); tipo,
format!("__subject_{new_id}"),
subject_stack,
clause_stack,
trace_stack,
);
// Only used here
expect_stack.expect_constr_from_data(tipo.clone(), when_stack);
} }
} }
@ -2774,7 +2627,7 @@ impl<'a> CodeGenerator<'a> {
&& assignment_properties.value_type.is_data() && assignment_properties.value_type.is_data()
&& !tipo.is_data() && !tipo.is_data()
{ {
self.recursive_assert_pattern( self.expect_pattern(
a, a,
nested_pattern, nested_pattern,
&mut vec![Air::Var { &mut vec![Air::Var {
@ -2827,7 +2680,7 @@ impl<'a> CodeGenerator<'a> {
&& assignment_properties.value_type.is_data() && assignment_properties.value_type.is_data()
&& !tipo.is_data() && !tipo.is_data()
{ {
self.recursive_assert_pattern( self.expect_pattern(
a, a,
nested_pattern, nested_pattern,
&mut vec![Air::Var { &mut vec![Air::Var {
@ -2876,7 +2729,7 @@ impl<'a> CodeGenerator<'a> {
&& assignment_properties.value_type.is_data() && assignment_properties.value_type.is_data()
&& !tipo.is_data() && !tipo.is_data()
{ {
self.recursive_assert_pattern( self.expect_pattern(
a, a,
nested_pattern, nested_pattern,
&mut vec![Air::Var { &mut vec![Air::Var {

View File

@ -7,53 +7,55 @@ use crate::{
tipo::{Type, ValueConstructor}, tipo::{Type, ValueConstructor},
}; };
use super::scope::Scope;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Air { pub enum Air {
// Primitives // Primitives
Int { Int {
scope: Vec<u64>, scope: Scope,
value: String, value: String,
}, },
String { String {
scope: Vec<u64>, scope: Scope,
value: String, value: String,
}, },
ByteArray { ByteArray {
scope: Vec<u64>, scope: Scope,
bytes: Vec<u8>, bytes: Vec<u8>,
}, },
Bool { Bool {
scope: Vec<u64>, scope: Scope,
value: bool, value: bool,
}, },
List { List {
scope: Vec<u64>, scope: Scope,
count: usize, count: usize,
tipo: Arc<Type>, tipo: Arc<Type>,
tail: bool, tail: bool,
}, },
Tuple { Tuple {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
count: usize, count: usize,
}, },
Void { Void {
scope: Vec<u64>, scope: Scope,
}, },
Var { Var {
scope: Vec<u64>, scope: Scope,
constructor: ValueConstructor, constructor: ValueConstructor,
name: String, name: String,
variant_name: String, variant_name: String,
}, },
// Functions // Functions
Call { Call {
scope: Vec<u64>, scope: Scope,
count: usize, count: usize,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
DefineFunc { DefineFunc {
scope: Vec<u64>, scope: Scope,
func_name: String, func_name: String,
module_name: String, module_name: String,
params: Vec<String>, params: Vec<String>,
@ -61,70 +63,70 @@ pub enum Air {
variant_name: String, variant_name: String,
}, },
Fn { Fn {
scope: Vec<u64>, scope: Scope,
params: Vec<String>, params: Vec<String>,
}, },
Builtin { Builtin {
scope: Vec<u64>, scope: Scope,
count: usize, count: usize,
func: DefaultFunction, func: DefaultFunction,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
// Operators // Operators
BinOp { BinOp {
scope: Vec<u64>, scope: Scope,
name: BinOp, name: BinOp,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
UnOp { UnOp {
scope: Vec<u64>, scope: Scope,
op: UnOp, op: UnOp,
}, },
// Assignment // Assignment
Let { Let {
scope: Vec<u64>, scope: Scope,
name: String, name: String,
}, },
UnWrapData { UnWrapData {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
WrapData { WrapData {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
AssertConstr { AssertConstr {
scope: Vec<u64>, scope: Scope,
constr_index: usize, constr_index: usize,
}, },
AssertBool { AssertBool {
scope: Vec<u64>, scope: Scope,
is_true: bool, is_true: bool,
}, },
// When // When
When { When {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
subject_name: String, subject_name: String,
}, },
Clause { Clause {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
subject_name: String, subject_name: String,
complex_clause: bool, complex_clause: bool,
}, },
ListClause { ListClause {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
tail_name: String, tail_name: String,
next_tail_name: Option<String>, next_tail_name: Option<String>,
complex_clause: bool, complex_clause: bool,
}, },
WrapClause { WrapClause {
scope: Vec<u64>, scope: Scope,
}, },
TupleClause { TupleClause {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
indices: IndexSet<(usize, String)>, indices: IndexSet<(usize, String)>,
predefined_indices: IndexSet<(usize, String)>, predefined_indices: IndexSet<(usize, String)>,
@ -133,88 +135,88 @@ pub enum Air {
complex_clause: bool, complex_clause: bool,
}, },
ClauseGuard { ClauseGuard {
scope: Vec<u64>, scope: Scope,
subject_name: String, subject_name: String,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
ListClauseGuard { ListClauseGuard {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
tail_name: String, tail_name: String,
next_tail_name: Option<String>, next_tail_name: Option<String>,
inverse: bool, inverse: bool,
}, },
Finally { Finally {
scope: Vec<u64>, scope: Scope,
}, },
// If // If
If { If {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
// Record Creation // Record Creation
Record { Record {
scope: Vec<u64>, scope: Scope,
tag: usize, tag: usize,
tipo: Arc<Type>, tipo: Arc<Type>,
count: usize, count: usize,
}, },
RecordUpdate { RecordUpdate {
scope: Vec<u64>, scope: Scope,
highest_index: usize, highest_index: usize,
indices: Vec<(usize, Arc<Type>)>, indices: Vec<(usize, Arc<Type>)>,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
// Field Access // Field Access
RecordAccess { RecordAccess {
scope: Vec<u64>, scope: Scope,
record_index: u64, record_index: u64,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
FieldsExpose { FieldsExpose {
scope: Vec<u64>, scope: Scope,
indices: Vec<(usize, String, Arc<Type>)>, indices: Vec<(usize, String, Arc<Type>)>,
check_last_item: bool, check_last_item: bool,
}, },
// ListAccess // ListAccess
ListAccessor { ListAccessor {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
names: Vec<String>, names: Vec<String>,
tail: bool, tail: bool,
check_last_item: bool, check_last_item: bool,
}, },
ListExpose { ListExpose {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
tail_head_names: Vec<(String, String)>, tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>, tail: Option<(String, String)>,
}, },
// Tuple Access // Tuple Access
TupleAccessor { TupleAccessor {
scope: Vec<u64>, scope: Scope,
names: Vec<String>, names: Vec<String>,
tipo: Arc<Type>, tipo: Arc<Type>,
check_last_item: bool, check_last_item: bool,
}, },
TupleIndex { TupleIndex {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
tuple_index: usize, tuple_index: usize,
}, },
// Misc. // Misc.
ErrorTerm { ErrorTerm {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
Trace { Trace {
scope: Vec<u64>, scope: Scope,
tipo: Arc<Type>, tipo: Arc<Type>,
}, },
} }
impl Air { impl Air {
pub fn scope(&self) -> Vec<u64> { pub fn scope(&self) -> Scope {
match self { match self {
Air::Int { scope, .. } Air::Int { scope, .. }
| Air::String { scope, .. } | Air::String { scope, .. }
@ -256,7 +258,7 @@ impl Air {
| Air::Trace { scope, .. } => scope.clone(), | Air::Trace { scope, .. } => scope.clone(),
} }
} }
pub fn scope_mut(&mut self) -> &mut Vec<u64> { pub fn scope_mut(&mut self) -> &mut Scope {
match self { match self {
Air::Int { scope, .. } Air::Int { scope, .. }
| Air::String { scope, .. } | Air::String { scope, .. }

View File

@ -636,29 +636,6 @@ pub fn list_access_to_uplc(
} }
} }
pub fn get_common_ancestor(scope: &[u64], scope_prev: &[u64]) -> Vec<u64> {
let longest_length = if scope.len() >= scope_prev.len() {
scope.len()
} else {
scope_prev.len()
};
if *scope == *scope_prev {
return scope.to_vec();
}
for index in 0..longest_length {
if scope.get(index).is_none() {
return scope.to_vec();
} else if scope_prev.get(index).is_none() {
return scope_prev.to_vec();
} else if scope[index] != scope_prev[index] {
return scope[0..index].to_vec();
}
}
vec![]
}
pub fn check_when_pattern_needs( pub fn check_when_pattern_needs(
pattern: &Pattern<PatternConstructor, Arc<Type>>, pattern: &Pattern<PatternConstructor, Arc<Type>>,
clause_properties: &mut ClauseProperties, clause_properties: &mut ClauseProperties,

View File

@ -0,0 +1,65 @@
#[derive(Debug, Clone, Default)]
pub struct Scope(Vec<u64>);
impl Scope {
pub fn push(&mut self, value: u64) {
self.0.push(value);
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn replace(&mut self, pattern: &Scope, replacement: Scope) {
let mut result = Vec::new();
let mut index = 0;
let mut pattern_index = 0;
let mut no_matches = true;
while index < self.0.len() {
if self.0[index] == pattern.0[pattern_index] {
if pattern_index == pattern.0.len() - 1 {
no_matches = false;
result.extend(replacement.0.clone());
pattern_index = 0;
} else {
pattern_index += 1;
}
} else {
result.push(self.0[index]);
pattern_index = 0;
}
index += 1;
}
if no_matches {
replacement.0.extend(self.0);
self.0 = replacement.0;
} else {
self.0 = result;
}
}
pub fn common_ancestor(&self, other: &Self) -> Scope {
let longest_length = self.0.len().max(other.0.len());
if *self.0 == *other.0 {
return self.clone();
}
for index in 0..longest_length {
if self.0.get(index).is_none() {
return self.clone();
} else if other.0.get(index).is_none() {
return other.clone();
} else if self.0[index] != other.0[index] {
return Scope(self.0[0..index].to_vec());
}
}
Scope::default()
}
}

View File

@ -1,30 +1,34 @@
use std::sync::Arc; use std::sync::Arc;
use uplc::builtins::DefaultFunction; use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction};
use crate::{ use crate::{
tipo::{Type, ValueConstructor}, ast::Span,
tipo::{Type, ValueConstructor, ValueConstructorVariant},
IdGenerator, IdGenerator,
}; };
use super::air::Air; use super::{air::Air, scope::Scope};
/// A builder for [`Air`].
pub struct AirStack<'a> { pub struct AirStack<'a> {
pub id_gen: &'a mut IdGenerator, pub id_gen: &'a mut IdGenerator,
pub scope: Vec<u64>, pub scope: Scope,
pub air: Vec<Air>, pub air: Vec<Air>,
} }
impl<'a> AirStack<'a> { impl<'a> AirStack<'a> {
/// Create a new [`AirStack`] with an [`IdGenerator`]
pub fn new(id_gen: &'a mut IdGenerator) -> Self { pub fn new(id_gen: &'a mut IdGenerator) -> Self {
AirStack { AirStack {
id_gen, id_gen,
scope: vec![id_gen.next()], scope: Scope::default(),
air: vec![], air: vec![],
} }
} }
pub fn with_scope(id_gen: &'a mut IdGenerator, scope: Vec<u64>) -> Self { /// Create a new [`AirStack`] with an [`IdGenerator`] and [`Scope`].
pub fn with_scope(id_gen: &'a mut IdGenerator, scope: Scope) -> Self {
AirStack { AirStack {
id_gen, id_gen,
scope, scope,
@ -32,22 +36,37 @@ impl<'a> AirStack<'a> {
} }
} }
pub fn in_new_scope(&mut self) -> Self { /// Create a new empty [`AirStack`] with the current stack's scope.
let mut new_stack = AirStack::with_scope(&mut self.id_gen, self.scope.clone()); pub fn empty_with_scope(&mut self) -> Self {
AirStack::with_scope(&mut self.id_gen, self.scope.clone())
new_stack.new_scope();
new_stack
} }
pub fn new_scope(&mut self) { /// Increment the [`Scope`]
fn new_scope(&mut self) {
self.scope.push(self.id_gen.next()); self.scope.push(self.id_gen.next());
} }
/// Merge two [`AirStack`]'s together while maintaining the current stack's [`Scope`]
pub fn merge(&mut self, mut other: AirStack) { pub fn merge(&mut self, mut other: AirStack) {
self.air.append(&mut other.air); self.air.append(&mut other.air);
} }
pub fn merge_child(&mut self, mut other: AirStack) {
let pattern = self.scope.common_ancestor(&other.scope);
for ir in other.air.iter_mut() {
ir.scope_mut().replace(&pattern, self.scope.clone());
}
self.merge(other);
}
pub fn merge_children(&mut self, stacks: Vec<AirStack>) {
for stack in stacks {
self.merge_child(stack)
}
}
pub fn sequence(&mut self, stacks: Vec<AirStack>) { pub fn sequence(&mut self, stacks: Vec<AirStack>) {
for stack in stacks { for stack in stacks {
self.merge(stack) self.merge(stack)
@ -55,20 +74,26 @@ impl<'a> AirStack<'a> {
} }
pub fn integer(&mut self, value: String) { pub fn integer(&mut self, value: String) {
self.new_scope();
self.air.push(Air::Int { self.air.push(Air::Int {
scope: self.scope.clone(), scope: self.scope.clone(),
value, value,
}); });
} }
pub fn string(&mut self, value: String) { pub fn string(&mut self, value: impl ToString) {
self.new_scope();
self.air.push(Air::String { self.air.push(Air::String {
scope: self.scope.clone(), scope: self.scope.clone(),
value, value: value.to_string(),
}); });
} }
pub fn byte_array(&mut self, bytes: Vec<u8>) { pub fn byte_array(&mut self, bytes: Vec<u8>) {
self.new_scope();
self.air.push(Air::ByteArray { self.air.push(Air::ByteArray {
scope: self.scope.clone(), scope: self.scope.clone(),
bytes, bytes,
@ -76,6 +101,8 @@ impl<'a> AirStack<'a> {
} }
pub fn builtin(&mut self, func: DefaultFunction, tipo: Arc<Type>, args: Vec<AirStack>) { pub fn builtin(&mut self, func: DefaultFunction, tipo: Arc<Type>, args: Vec<AirStack>) {
self.new_scope();
self.air.push(Air::Builtin { self.air.push(Air::Builtin {
scope: self.scope.clone(), scope: self.scope.clone(),
count: args.len(), count: args.len(),
@ -83,7 +110,7 @@ impl<'a> AirStack<'a> {
tipo, tipo,
}); });
self.sequence(args); self.merge_children(args);
} }
pub fn var( pub fn var(
@ -92,6 +119,8 @@ impl<'a> AirStack<'a> {
name: impl ToString, name: impl ToString,
variant_name: impl ToString, variant_name: impl ToString,
) { ) {
self.new_scope();
self.air.push(Air::Var { self.air.push(Air::Var {
scope: self.scope.clone(), scope: self.scope.clone(),
constructor, constructor,
@ -100,16 +129,36 @@ impl<'a> AirStack<'a> {
}); });
} }
pub fn local_var(&mut self, tipo: Arc<Type>, name: impl ToString) {
self.new_scope();
self.air.push(Air::Var {
scope: self.scope.clone(),
constructor: ValueConstructor::public(
tipo,
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: name.to_string(),
variant_name: String::new(),
});
}
pub fn anonymous_function(&mut self, params: Vec<String>, body: AirStack) { pub fn anonymous_function(&mut self, params: Vec<String>, body: AirStack) {
self.new_scope();
self.air.push(Air::Fn { self.air.push(Air::Fn {
scope: self.scope.clone(), scope: self.scope.clone(),
params, params,
}); });
self.merge(body); self.merge_child(body);
} }
pub fn list(&mut self, tipo: Arc<Type>, elements: Vec<AirStack>, tail: Option<AirStack>) { pub fn list(&mut self, tipo: Arc<Type>, elements: Vec<AirStack>, tail: Option<AirStack>) {
self.new_scope();
self.air.push(Air::List { self.air.push(Air::List {
scope: self.scope.clone(), scope: self.scope.clone(),
count: elements.len(), count: elements.len(),
@ -117,14 +166,16 @@ impl<'a> AirStack<'a> {
tail: tail.is_some(), tail: tail.is_some(),
}); });
self.sequence(elements); self.merge_children(elements);
if let Some(tail) = tail { if let Some(tail) = tail {
self.merge(tail); self.merge_child(tail);
} }
} }
pub fn record(&mut self, tipo: Arc<Type>, tag: usize, fields: Vec<AirStack>) { pub fn record(&mut self, tipo: Arc<Type>, tag: usize, fields: Vec<AirStack>) {
self.new_scope();
self.air.push(Air::Record { self.air.push(Air::Record {
scope: self.scope.clone(), scope: self.scope.clone(),
tag, tag,
@ -132,19 +183,21 @@ impl<'a> AirStack<'a> {
count: fields.len(), count: fields.len(),
}); });
self.sequence(fields); self.merge_children(fields);
} }
pub fn call(&mut self, tipo: Arc<Type>, fun: AirStack, args: Vec<AirStack>) { pub fn call(&mut self, tipo: Arc<Type>, fun: AirStack, args: Vec<AirStack>) {
self.new_scope();
self.air.push(Air::Call { self.air.push(Air::Call {
scope: self.scope.clone(), scope: self.scope.clone(),
count: args.len(), count: args.len(),
tipo, tipo,
}); });
self.merge(fun); self.merge_child(fun);
self.sequence(args); self.merge_children(args);
} }
pub fn binop( pub fn binop(
@ -154,26 +207,62 @@ impl<'a> AirStack<'a> {
left: AirStack, left: AirStack,
right: AirStack, right: AirStack,
) { ) {
self.new_scope();
self.air.push(Air::BinOp { self.air.push(Air::BinOp {
scope: self.scope.clone(), scope: self.scope.clone(),
name, name,
tipo, tipo,
}); });
self.merge(left); self.merge_child(left);
self.merge(right); self.merge_child(right);
} }
pub fn let_assignment(&mut self, name: impl ToString, value: AirStack) { pub fn let_assignment(&mut self, name: impl ToString, value: AirStack) {
self.new_scope();
self.air.push(Air::Let { self.air.push(Air::Let {
scope: self.scope.clone(), scope: self.scope.clone(),
name: name.to_string(), name: name.to_string(),
}); });
self.merge(value); self.merge_child(value);
}
pub fn expect_list_from_data(
&mut self,
tipo: Arc<Type>,
name: impl ToString,
unwrap_function: AirStack,
) {
self.new_scope();
self.air.push(Air::Builtin {
scope: self.scope.clone(),
func: DefaultFunction::ChooseUnit,
tipo: tipo.clone(),
count: DefaultFunction::ChooseUnit.arity(),
});
self.new_scope();
self.air.push(Air::Call {
scope: self.scope.clone(),
count: 2,
tipo,
});
self.local_var(tipo.clone(), EXPECT_ON_LIST);
self.local_var(tipo, name);
self.merge_child(unwrap_function);
} }
pub fn wrap_data(&mut self, tipo: Arc<Type>) { pub fn wrap_data(&mut self, tipo: Arc<Type>) {
self.new_scope();
self.air.push(Air::WrapData { self.air.push(Air::WrapData {
scope: self.scope.clone(), scope: self.scope.clone(),
tipo, tipo,
@ -181,9 +270,150 @@ impl<'a> AirStack<'a> {
} }
pub fn un_wrap_data(&mut self, tipo: Arc<Type>) { pub fn un_wrap_data(&mut self, tipo: Arc<Type>) {
self.new_scope();
self.air.push(Air::UnWrapData { self.air.push(Air::UnWrapData {
scope: self.scope.clone(), scope: self.scope.clone(),
tipo, tipo,
}) })
} }
pub fn void(&mut self) {
self.new_scope();
self.air.push(Air::Void {
scope: self.scope.clone(),
})
}
pub fn tuple_accessor(
&mut self,
tipo: Arc<Type>,
names: Vec<String>,
check_last_item: bool,
value: AirStack,
) {
self.new_scope();
self.air.push(Air::TupleAccessor {
scope: self.scope.clone(),
names,
tipo,
check_last_item,
});
self.merge_child(value);
}
pub fn fields_expose(
&mut self,
indices: Vec<(usize, String, Arc<Type>)>,
check_last_item: bool,
value: AirStack,
) {
self.new_scope();
self.air.push(Air::FieldsExpose {
scope: self.scope.clone(),
indices,
check_last_item,
});
self.merge_child(value);
}
pub fn clause(
&mut self,
tipo: Arc<Type>,
subject_name: impl ToString,
tag: usize,
complex_clause: bool,
body: AirStack,
) {
self.new_scope();
self.air.push(Air::Clause {
scope: self.scope.clone(),
subject_name: subject_name.to_string(),
complex_clause,
tipo,
});
self.integer(tag.to_string());
self.merge_child(body);
}
pub fn trace(&mut self, tipo: Arc<Type>) {
self.new_scope();
self.air.push(Air::Trace {
scope: self.scope.clone(),
tipo,
})
}
pub fn error(&mut self, tipo: Arc<Type>) {
self.new_scope();
self.air.push(Air::ErrorTerm {
scope: self.scope.clone(),
tipo,
})
}
pub fn expect_constr_from_data(&mut self, tipo: Arc<Type>, when_stack: AirStack) {
self.new_scope();
self.air.push(Air::Builtin {
scope: self.scope.clone(),
func: DefaultFunction::ChooseUnit,
tipo: tipo.clone(),
count: DefaultFunction::ChooseUnit.arity(),
});
self.merge_child(when_stack);
}
pub fn when(
&mut self,
tipo: Arc<Type>,
subject_name: impl ToString,
subject_stack: AirStack,
clauses_stack: AirStack,
else_stack: AirStack,
) {
self.new_scope();
self.air.push(Air::When {
scope: self.scope.clone(),
subject_name: subject_name.to_string(),
tipo,
});
self.merge_child(subject_stack);
self.merge_child(clauses_stack);
self.merge_child(else_stack);
}
pub fn list_accessor(
&mut self,
tipo: Arc<Type>,
names: Vec<String>,
tail: bool,
check_last_item: bool,
value: AirStack,
) {
self.new_scope();
self.air.push(Air::ListAccessor {
scope: self.scope.clone(),
names,
tail,
check_last_item,
tipo,
});
self.merge_child(value);
}
} }

View File

@ -6,7 +6,7 @@ use crate::{
pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer"; pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer";
pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer"; pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer";
pub const CONSTR_GET_FIELD: &str = "__constr_get_field"; pub const CONSTR_GET_FIELD: &str = "__constr_get_field";
pub const ASSERT_ON_LIST: &str = "__assert_on_list"; pub const EXPECT_ON_LIST: &str = "__expect_on_list";
impl Term<Name> { impl Term<Name> {
pub fn apply(self, arg: Self) -> Self { pub fn apply(self, arg: Self) -> Self {
@ -213,11 +213,11 @@ impl Term<Name> {
} }
pub fn assert_on_list(self) -> Term<Name> { pub fn assert_on_list(self) -> Term<Name> {
self.lambda(ASSERT_ON_LIST.to_string()) self.lambda(EXPECT_ON_LIST.to_string())
.apply( .apply(
Term::var(ASSERT_ON_LIST.to_string()).apply(Term::var(ASSERT_ON_LIST.to_string())), Term::var(EXPECT_ON_LIST.to_string()).apply(Term::var(EXPECT_ON_LIST.to_string())),
) )
.lambda(ASSERT_ON_LIST.to_string()) .lambda(EXPECT_ON_LIST.to_string())
.apply( .apply(
Term::var("__list_to_check".to_string()) Term::var("__list_to_check".to_string())
.delayed_choose_list( .delayed_choose_list(
@ -227,8 +227,8 @@ impl Term<Name> {
Term::head_list().apply(Term::var("__list_to_check".to_string())), Term::head_list().apply(Term::var("__list_to_check".to_string())),
) )
.choose_unit( .choose_unit(
Term::var(ASSERT_ON_LIST.to_string()) Term::var(EXPECT_ON_LIST.to_string())
.apply(Term::var(ASSERT_ON_LIST.to_string())) .apply(Term::var(EXPECT_ON_LIST.to_string()))
.apply( .apply(
Term::tail_list() Term::tail_list()
.apply(Term::var("__list_to_check".to_string())), .apply(Term::var("__list_to_check".to_string())),
@ -238,7 +238,7 @@ impl Term<Name> {
) )
.lambda("__check_with".to_string()) .lambda("__check_with".to_string())
.lambda("__list_to_check".to_string()) .lambda("__list_to_check".to_string())
.lambda(ASSERT_ON_LIST), .lambda(EXPECT_ON_LIST),
) )
} }