Start work on revamping assignment so we can handle soft casting properly
This commit is contained in:
parent
9ea54afd12
commit
dd5badd884
|
@ -38,6 +38,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
IdGenerator,
|
IdGenerator,
|
||||||
};
|
};
|
||||||
|
use builder::unknown_data_to_type;
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use petgraph::{algo, Graph};
|
use petgraph::{algo, Graph};
|
||||||
|
@ -271,17 +272,16 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let msg_func_name = msg.split_whitespace().join("");
|
let msg_func_name = msg.split_whitespace().join("");
|
||||||
|
|
||||||
self.special_functions.insert_new_function(
|
if msg_func_name.is_empty() {
|
||||||
msg_func_name.clone(),
|
None
|
||||||
if msg.is_empty() {
|
} else {
|
||||||
Term::Error.delay()
|
self.special_functions.insert_new_function(
|
||||||
} else {
|
msg_func_name.clone(),
|
||||||
Term::Error.delayed_trace(Term::string(msg)).delay()
|
Term::Error.delayed_trace(Term::string(msg)).delay(),
|
||||||
},
|
void(),
|
||||||
void(),
|
);
|
||||||
);
|
Some(self.special_functions.use_function_tree(msg_func_name))
|
||||||
|
}
|
||||||
self.special_functions.use_function_tree(msg_func_name)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (then, context) = context.split_first().unwrap();
|
let (then, context) = context.split_first().unwrap();
|
||||||
|
@ -569,7 +569,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
kind: AssignmentKind::let_(),
|
kind: AssignmentKind::let_(),
|
||||||
remove_unused: false,
|
remove_unused: false,
|
||||||
full_check: false,
|
full_check: false,
|
||||||
otherwise: AirTree::error(void(), false),
|
otherwise: None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -625,43 +625,47 @@ impl<'a> CodeGenerator<'a> {
|
||||||
//
|
//
|
||||||
// if <expr:condition> is <pattern>: <annotation> { <expr:body> }
|
// if <expr:condition> is <pattern>: <annotation> { <expr:body> }
|
||||||
// [(builtin ifThenElse) (condition is pattern) (body) (else) ]
|
// [(builtin ifThenElse) (condition is pattern) (body) (else) ]
|
||||||
TypedExpr::If {
|
a @ TypedExpr::If {
|
||||||
branches,
|
branches,
|
||||||
final_else,
|
final_else,
|
||||||
tipo,
|
tipo,
|
||||||
..
|
..
|
||||||
} => branches.iter().rfold(
|
} => {
|
||||||
self.build(final_else, module_build_name, &[]),
|
println!("A: {:#?}", a);
|
||||||
|acc, branch| {
|
branches.iter().rfold(
|
||||||
let condition = self.build(&branch.condition, module_build_name, &[]);
|
self.build(final_else, module_build_name, &[]),
|
||||||
let body = self.build(&branch.body, module_build_name, &[]);
|
|acc, branch| {
|
||||||
|
let condition = self.build(&branch.condition, module_build_name, &[]);
|
||||||
|
let body = self.build(&branch.body, module_build_name, &[]);
|
||||||
|
|
||||||
match &branch.is {
|
match &branch.is {
|
||||||
Some((pattern, tipo)) => {
|
Some((pattern, tipo)) => {
|
||||||
AirTree::let_assignment(
|
println!("PATTERN TYPE: {:#?}", pattern);
|
||||||
"acc_var",
|
println!("Branch TYPE: {:#?}", tipo);
|
||||||
// use anon function as a delay to avoid evaluating the acc
|
AirTree::let_assignment(
|
||||||
AirTree::anon_func(vec![], acc, true),
|
"acc_var",
|
||||||
self.assignment(
|
// use anon function as a delay to avoid evaluating the acc
|
||||||
pattern,
|
AirTree::anon_func(vec![], acc, true),
|
||||||
condition,
|
self.assignment(
|
||||||
body,
|
pattern,
|
||||||
tipo,
|
condition,
|
||||||
AssignmentProperties {
|
body,
|
||||||
value_type: branch.condition.tipo(),
|
tipo,
|
||||||
kind: AssignmentKind::Expect { backpassing: () },
|
AssignmentProperties {
|
||||||
remove_unused: false,
|
value_type: branch.condition.tipo(),
|
||||||
full_check: true,
|
kind: AssignmentKind::Expect { backpassing: () },
|
||||||
otherwise: AirTree::local_var("acc_var", void()),
|
remove_unused: false,
|
||||||
},
|
full_check: true,
|
||||||
),
|
otherwise: AirTree::local_var("acc_var", void()),
|
||||||
)
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => AirTree::if_branch(tipo.clone(), condition, body, acc),
|
||||||
}
|
}
|
||||||
None => AirTree::if_branch(tipo.clone(), condition, body, acc),
|
},
|
||||||
}
|
)
|
||||||
},
|
}
|
||||||
),
|
|
||||||
|
|
||||||
TypedExpr::RecordAccess {
|
TypedExpr::RecordAccess {
|
||||||
tipo,
|
tipo,
|
||||||
index,
|
index,
|
||||||
|
@ -890,7 +894,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
pub fn assignment(
|
pub fn assignment(
|
||||||
&mut self,
|
&mut self,
|
||||||
pattern: &TypedPattern,
|
pattern: &TypedPattern,
|
||||||
mut value: AirTree,
|
value: AirTree,
|
||||||
then: AirTree,
|
then: AirTree,
|
||||||
tipo: &Rc<Type>,
|
tipo: &Rc<Type>,
|
||||||
props: AssignmentProperties,
|
props: AssignmentProperties,
|
||||||
|
@ -906,41 +910,90 @@ impl<'a> CodeGenerator<'a> {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Cast value to or from data so we don't have to worry from this point onward
|
// Cast value to or from data so we don't have to worry from this point onward
|
||||||
if props.value_type.is_data() && props.kind.is_expect() && !tipo.is_data() {
|
let assign_casted_value = |name, value, then| {
|
||||||
value = AirTree::cast_from_data(value, tipo.clone(), props.otherwise.clone(), true);
|
if props.value_type.is_data() && props.kind.is_expect() && !tipo.is_data() {
|
||||||
} else if !props.value_type.is_data() && tipo.is_data() {
|
if props.otherwise.is_some() {
|
||||||
value = AirTree::cast_to_data(value, props.value_type.clone());
|
AirTree::soft_cast_assignment(
|
||||||
}
|
name,
|
||||||
|
tipo.clone(),
|
||||||
|
value,
|
||||||
|
then,
|
||||||
|
props.otherwise.as_ref().unwrap().clone(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AirTree::let_assignment(
|
||||||
|
name,
|
||||||
|
AirTree::cast_from_data(value, tipo.clone(), true),
|
||||||
|
then,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if !props.value_type.is_data() && tipo.is_data() {
|
||||||
|
AirTree::let_assignment(
|
||||||
|
name,
|
||||||
|
AirTree::cast_to_data(value, props.value_type.clone()),
|
||||||
|
then,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
AirTree::let_assignment(name, value, then)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let otherwise = match &props.otherwise {
|
||||||
|
Some(x) => x.clone(),
|
||||||
|
// (delay (error ))
|
||||||
|
None => AirTree::anon_func(vec![], AirTree::error(void(), false), true),
|
||||||
|
};
|
||||||
|
|
||||||
match pattern {
|
match pattern {
|
||||||
Pattern::Int {
|
Pattern::Int {
|
||||||
value: expected_int,
|
value: expected_int,
|
||||||
location,
|
location,
|
||||||
..
|
..
|
||||||
} => AirTree::assign_literal_pattern(
|
} => {
|
||||||
format!(
|
let name = format!(
|
||||||
"__expected_by_{}_span_{}_{}",
|
"__expected_by_{}_span_{}_{}",
|
||||||
expected_int, location.start, location.end
|
expected_int, location.start, location.end
|
||||||
),
|
);
|
||||||
AirTree::int(expected_int),
|
|
||||||
value,
|
let expect = AirTree::binop(
|
||||||
int(),
|
BinOp::Eq,
|
||||||
props,
|
bool(),
|
||||||
then,
|
AirTree::int(expected_int),
|
||||||
),
|
AirTree::local_var(&name, int()),
|
||||||
|
int(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assign_casted_value(
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
AirTree::assert_bool(true, expect, then, otherwise),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Pattern::ByteArray {
|
Pattern::ByteArray {
|
||||||
location,
|
|
||||||
value: expected_bytes,
|
value: expected_bytes,
|
||||||
|
location,
|
||||||
..
|
..
|
||||||
} => AirTree::assign_literal_pattern(
|
} => {
|
||||||
format!("__expected_bytes_span_{}_{}", location.start, location.end),
|
let name = format!(
|
||||||
AirTree::byte_array(expected_bytes.clone()),
|
"__expected_bytes_span_{}_{}",
|
||||||
value,
|
location.start, location.end
|
||||||
byte_array(),
|
);
|
||||||
props,
|
|
||||||
then,
|
let expect = AirTree::binop(
|
||||||
),
|
BinOp::Eq,
|
||||||
|
bool(),
|
||||||
|
AirTree::byte_array(expected_bytes),
|
||||||
|
AirTree::local_var(&name, byte_string()),
|
||||||
|
byte_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assign_casted_value(
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
AirTree::assert_bool(true, expect, then, otherwise),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Pattern::Var { name, .. } => {
|
Pattern::Var { name, .. } => {
|
||||||
if props.full_check {
|
if props.full_check {
|
||||||
|
@ -951,26 +1004,28 @@ impl<'a> CodeGenerator<'a> {
|
||||||
let val = AirTree::local_var(name, tipo.clone());
|
let val = AirTree::local_var(name, tipo.clone());
|
||||||
|
|
||||||
if non_opaque_tipo.is_primitive() {
|
if non_opaque_tipo.is_primitive() {
|
||||||
AirTree::let_assignment(name, value, then)
|
assign_casted_value(name.clone(), value, then)
|
||||||
} else {
|
} else {
|
||||||
let expect = self.expect_type_assign(
|
assign_casted_value(
|
||||||
&non_opaque_tipo,
|
name.clone(),
|
||||||
val,
|
value,
|
||||||
&mut index_map,
|
self.expect_type_assign(
|
||||||
pattern.location(),
|
&non_opaque_tipo,
|
||||||
props.otherwise,
|
val,
|
||||||
);
|
&mut index_map,
|
||||||
|
pattern.location(),
|
||||||
let assign_expect = AirTree::let_assignment("_", expect, then);
|
then,
|
||||||
|
otherwise,
|
||||||
AirTree::let_assignment(name, value, assign_expect)
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AirTree::let_assignment(name, value, then)
|
assign_casted_value(name.clone(), value, then)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern::Assign { name, pattern, .. } => {
|
Pattern::Assign { name, pattern, .. } => {
|
||||||
|
// Don't need any data casting for Assign
|
||||||
let inner_pattern = self.assignment(
|
let inner_pattern = self.assignment(
|
||||||
pattern,
|
pattern,
|
||||||
AirTree::local_var(name, tipo.clone()),
|
AirTree::local_var(name, tipo.clone()),
|
||||||
|
@ -983,30 +1038,31 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
Pattern::Discard { name, .. } => {
|
Pattern::Discard { name, .. } => {
|
||||||
if props.full_check {
|
if props.full_check {
|
||||||
let name = &format!("__discard_expect_{}", name);
|
let name = format!("__discard_expect_{}", name);
|
||||||
let mut index_map = IndexMap::new();
|
let mut index_map = IndexMap::new();
|
||||||
|
|
||||||
let non_opaque_tipo = convert_opaque_type(tipo, &self.data_types, true);
|
let non_opaque_tipo = convert_opaque_type(tipo, &self.data_types, true);
|
||||||
|
|
||||||
let val = AirTree::local_var(name, tipo.clone());
|
let val = AirTree::local_var(&name, tipo.clone());
|
||||||
|
|
||||||
if non_opaque_tipo.is_primitive() {
|
if non_opaque_tipo.is_primitive() {
|
||||||
AirTree::let_assignment(name, value, then)
|
assign_casted_value(name, value, then)
|
||||||
} else {
|
} else {
|
||||||
let expect = self.expect_type_assign(
|
assign_casted_value(
|
||||||
&non_opaque_tipo,
|
name,
|
||||||
val,
|
value,
|
||||||
&mut index_map,
|
self.expect_type_assign(
|
||||||
pattern.location(),
|
&non_opaque_tipo,
|
||||||
props.otherwise,
|
val,
|
||||||
);
|
&mut index_map,
|
||||||
|
pattern.location(),
|
||||||
let assignment = AirTree::let_assignment("_", expect, then);
|
then,
|
||||||
|
otherwise,
|
||||||
AirTree::let_assignment(name, value, assignment)
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else if !props.remove_unused {
|
} else if !props.remove_unused {
|
||||||
AirTree::let_assignment(name, value, then)
|
assign_casted_value(name.clone(), value, then)
|
||||||
} else {
|
} else {
|
||||||
then
|
then
|
||||||
}
|
}
|
||||||
|
@ -1030,6 +1086,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
Some(tail) => {
|
Some(tail) => {
|
||||||
let tail_name = match tail.as_ref() {
|
let tail_name = match tail.as_ref() {
|
||||||
Pattern::Var { name, .. } => name.to_string(),
|
Pattern::Var { name, .. } => name.to_string(),
|
||||||
|
// This Pattern one doesn't even make sense
|
||||||
Pattern::Assign { name, .. } => name.to_string(),
|
Pattern::Assign { name, .. } => name.to_string(),
|
||||||
Pattern::Discard { name, .. } => {
|
Pattern::Discard { name, .. } => {
|
||||||
if props.full_check {
|
if props.full_check {
|
||||||
|
@ -1038,6 +1095,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
"_".to_string()
|
"_".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// This should be unreachable
|
||||||
_ => format!(
|
_ => format!(
|
||||||
"tail_span_{}_{}",
|
"tail_span_{}_{}",
|
||||||
tail.location().start,
|
tail.location().start,
|
||||||
|
@ -1056,6 +1114,9 @@ impl<'a> CodeGenerator<'a> {
|
||||||
AssignmentProperties {
|
AssignmentProperties {
|
||||||
value_type: tipo.clone(),
|
value_type: tipo.clone(),
|
||||||
kind: props.kind,
|
kind: props.kind,
|
||||||
|
// The reason the top level of recursion might have remove_unused
|
||||||
|
// false is to deal with expect _ = thing
|
||||||
|
// next_thing
|
||||||
remove_unused: true,
|
remove_unused: true,
|
||||||
full_check: props.full_check,
|
full_check: props.full_check,
|
||||||
otherwise: props.otherwise.clone(),
|
otherwise: props.otherwise.clone(),
|
||||||
|
@ -1120,21 +1181,37 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
elems.reverse();
|
elems.reverse();
|
||||||
|
|
||||||
|
let name = format!(
|
||||||
|
"__List_span_{}_{}",
|
||||||
|
pattern.location().start,
|
||||||
|
pattern.location().end
|
||||||
|
);
|
||||||
|
|
||||||
|
let casted_var = AirTree::local_var(&name, tipo.clone());
|
||||||
|
|
||||||
if elements.is_empty() {
|
if elements.is_empty() {
|
||||||
AirTree::list_empty(value, then, props.otherwise.clone())
|
assign_casted_value(
|
||||||
} else {
|
name,
|
||||||
AirTree::list_access(
|
|
||||||
elems,
|
|
||||||
tipo.clone(),
|
|
||||||
tail.is_some(),
|
|
||||||
value,
|
value,
|
||||||
if props.full_check {
|
AirTree::list_empty(casted_var, then, otherwise),
|
||||||
ExpectLevel::Full
|
)
|
||||||
} else {
|
} else {
|
||||||
ExpectLevel::Items
|
assign_casted_value(
|
||||||
},
|
name,
|
||||||
then,
|
value,
|
||||||
props.otherwise.clone(),
|
AirTree::list_access(
|
||||||
|
elems,
|
||||||
|
tipo.clone(),
|
||||||
|
tail.is_some(),
|
||||||
|
casted_var,
|
||||||
|
if props.full_check {
|
||||||
|
ExpectLevel::Full
|
||||||
|
} else {
|
||||||
|
ExpectLevel::Items
|
||||||
|
},
|
||||||
|
then,
|
||||||
|
otherwise,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1214,8 +1291,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
// This `value` is either value param that was passed in or
|
// This `value` is either value param that was passed in or
|
||||||
// local var
|
// local var
|
||||||
let constructor_name = format!(
|
let constructor_name = format!(
|
||||||
"__constructor_{}_span_{}_{}",
|
"Pair_span_{}_{}",
|
||||||
"Pair",
|
|
||||||
pattern.location().start,
|
pattern.location().start,
|
||||||
pattern.location().end
|
pattern.location().end
|
||||||
);
|
);
|
||||||
|
@ -1238,11 +1314,11 @@ impl<'a> CodeGenerator<'a> {
|
||||||
local_value,
|
local_value,
|
||||||
props.full_check,
|
props.full_check,
|
||||||
then,
|
then,
|
||||||
props.otherwise.clone(),
|
otherwise,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
AirTree::let_assignment(constructor_name, value, then)
|
assign_casted_value(constructor_name, value, then)
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern::Constructor {
|
Pattern::Constructor {
|
||||||
|
@ -1251,13 +1327,25 @@ impl<'a> CodeGenerator<'a> {
|
||||||
} if tipo.is_bool() => {
|
} if tipo.is_bool() => {
|
||||||
assert!(props.kind.is_expect());
|
assert!(props.kind.is_expect());
|
||||||
|
|
||||||
AirTree::assert_bool(name == "True", value, then, props.otherwise.clone())
|
let name_var = format!(
|
||||||
|
"__Bool_{}_{}",
|
||||||
|
pattern.location().start,
|
||||||
|
pattern.location().end
|
||||||
|
);
|
||||||
|
|
||||||
|
let local_var = AirTree::local_var(&name_var, tipo.clone());
|
||||||
|
|
||||||
|
assign_casted_value(
|
||||||
|
name_var,
|
||||||
|
value,
|
||||||
|
AirTree::assert_bool(name == "True", local_var, then, otherwise),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern::Constructor { .. } if tipo.is_void() => {
|
Pattern::Constructor { .. } if tipo.is_void() => {
|
||||||
// Void type is checked when casting from data
|
// Void type is checked when casting from data
|
||||||
// So we just assign the value and move on
|
// So we just assign the value and move on
|
||||||
AirTree::let_assignment("_", value, then)
|
assign_casted_value("_".to_string(), value, then)
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern::Constructor {
|
Pattern::Constructor {
|
||||||
|
@ -1376,7 +1464,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
local_value,
|
local_value,
|
||||||
props.full_check,
|
props.full_check,
|
||||||
then,
|
then,
|
||||||
props.otherwise.clone(),
|
otherwise.clone(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1404,7 +1492,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
index,
|
index,
|
||||||
AirTree::local_var(&subject_name, tipo.clone()),
|
AirTree::local_var(&subject_name, tipo.clone()),
|
||||||
then,
|
then,
|
||||||
props.otherwise.clone(),
|
otherwise,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1415,7 +1503,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
then
|
then
|
||||||
};
|
};
|
||||||
|
|
||||||
AirTree::let_assignment(constructor_name, value, then)
|
assign_casted_value(constructor_name, value, then)
|
||||||
}
|
}
|
||||||
|
|
||||||
Pattern::Tuple {
|
Pattern::Tuple {
|
||||||
|
@ -1487,13 +1575,25 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
// This `value` is either value param that was passed in or local var
|
// This `value` is either value param that was passed in or local var
|
||||||
|
|
||||||
AirTree::tuple_access(
|
let name = format!(
|
||||||
fields,
|
"__Tuple_span_{}_{}",
|
||||||
tipo.clone(),
|
pattern.location().start,
|
||||||
|
pattern.location().end
|
||||||
|
);
|
||||||
|
|
||||||
|
let local_var = AirTree::local_var(&name, tipo.clone());
|
||||||
|
|
||||||
|
assign_casted_value(
|
||||||
|
name,
|
||||||
value,
|
value,
|
||||||
props.full_check,
|
AirTree::tuple_access(
|
||||||
then,
|
fields,
|
||||||
props.otherwise.clone(),
|
tipo.clone(),
|
||||||
|
local_var,
|
||||||
|
props.full_check,
|
||||||
|
then,
|
||||||
|
otherwise,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1505,6 +1605,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
value: AirTree,
|
value: AirTree,
|
||||||
defined_data_types: &mut IndexMap<String, u64>,
|
defined_data_types: &mut IndexMap<String, u64>,
|
||||||
location: Span,
|
location: Span,
|
||||||
|
then: AirTree,
|
||||||
otherwise: AirTree,
|
otherwise: AirTree,
|
||||||
) -> AirTree {
|
) -> AirTree {
|
||||||
assert!(tipo.get_generic().is_none());
|
assert!(tipo.get_generic().is_none());
|
||||||
|
@ -1621,27 +1722,29 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
let mut tuple_expect_items = vec![];
|
let mut tuple_expect_items = vec![];
|
||||||
|
|
||||||
let then = tuple_inner_types.iter().enumerate().rfold(
|
let then =
|
||||||
AirTree::void(),
|
tuple_inner_types
|
||||||
|then, (index, arg)| {
|
.iter()
|
||||||
let tuple_index_name = format!(
|
.enumerate()
|
||||||
"__tuple_index_{}_span_{}_{}",
|
.rfold(then, |then, (index, arg)| {
|
||||||
index, location.start, location.end
|
let tuple_index_name = format!(
|
||||||
);
|
"__tuple_index_{}_span_{}_{}",
|
||||||
|
index, location.start, location.end
|
||||||
|
);
|
||||||
|
|
||||||
let expect_tuple_item = self.expect_type_assign(
|
let expect_tuple_item = self.expect_type_assign(
|
||||||
arg,
|
arg,
|
||||||
AirTree::local_var(&tuple_index_name, arg.clone()),
|
AirTree::local_var(&tuple_index_name, arg.clone()),
|
||||||
defined_data_types,
|
defined_data_types,
|
||||||
location,
|
location,
|
||||||
otherwise.clone(),
|
then,
|
||||||
);
|
otherwise.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
tuple_expect_items.push(tuple_index_name);
|
tuple_expect_items.push(tuple_index_name);
|
||||||
|
|
||||||
AirTree::let_assignment("_", expect_tuple_item, then)
|
expect_tuple_item
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
tuple_expect_items.reverse();
|
tuple_expect_items.reverse();
|
||||||
|
|
||||||
|
@ -1663,11 +1766,53 @@ impl<'a> CodeGenerator<'a> {
|
||||||
let inner_list_type = &tipo.get_inner_types()[0];
|
let inner_list_type = &tipo.get_inner_types()[0];
|
||||||
|
|
||||||
if inner_list_type.is_data() {
|
if inner_list_type.is_data() {
|
||||||
value
|
then
|
||||||
} else {
|
} else {
|
||||||
let list_name = format!("__list_span_{}_{}", location.start, location.end);
|
let list_name = format!("__list_span_{}_{}", location.start, location.end);
|
||||||
let item_name = format!("__item_span_{}_{}", location.start, location.end);
|
let item_name = format!("__item_span_{}_{}", location.start, location.end);
|
||||||
|
|
||||||
|
let g = AirTree::anon_func(
|
||||||
|
vec!["__list".to_string(), "__curried_expect_on_list".to_string()],
|
||||||
|
AirTree::list_empty(
|
||||||
|
AirTree::local_var("__list", tipo.clone()),
|
||||||
|
then,
|
||||||
|
AirTree::let_assignment(
|
||||||
|
&item_name,
|
||||||
|
AirTree::builtin(
|
||||||
|
DefaultFunction::HeadList,
|
||||||
|
data(),
|
||||||
|
vec![AirTree::local_var("__list", tipo.clone())],
|
||||||
|
),
|
||||||
|
AirTree::let_assignment(
|
||||||
|
&item_name,
|
||||||
|
self.expect_type_assign(
|
||||||
|
inner_list_type,
|
||||||
|
AirTree::cast_from_data(
|
||||||
|
AirTree::local_var(item_name, data()),
|
||||||
|
inner_list_type.clone(),
|
||||||
|
otherwise.clone(),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
defined_data_types,
|
||||||
|
location,
|
||||||
|
AirTree::void(),
|
||||||
|
otherwise,
|
||||||
|
),
|
||||||
|
AirTree::call(
|
||||||
|
AirTree::local_var("__curried_expect_on_list", void()),
|
||||||
|
void(),
|
||||||
|
vec![AirTree::builtin(
|
||||||
|
DefaultFunction::TailList,
|
||||||
|
list(data()),
|
||||||
|
vec![AirTree::local_var("__list", tipo.clone())],
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
let expect_item = self.expect_type_assign(
|
let expect_item = self.expect_type_assign(
|
||||||
inner_list_type,
|
inner_list_type,
|
||||||
AirTree::cast_from_data(
|
AirTree::cast_from_data(
|
||||||
|
@ -4051,7 +4196,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
if otherwise == Term::Error.delay() {
|
if otherwise == Term::Error.delay() {
|
||||||
builder::unknown_data_to_type(term, tipo)
|
builder::unknown_data_to_type(term, tipo)
|
||||||
} else {
|
} else {
|
||||||
builder::unknown_data_to_type_otherwise(term, tipo, otherwise)
|
builder::softcast_data_to_type_otherwise(term, tipo, otherwise)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4766,14 +4911,8 @@ impl<'a> CodeGenerator<'a> {
|
||||||
Air::CastFromData { tipo, full_cast } => {
|
Air::CastFromData { tipo, full_cast } => {
|
||||||
let mut term = arg_stack.pop().unwrap();
|
let mut term = arg_stack.pop().unwrap();
|
||||||
|
|
||||||
let otherwise = if full_cast {
|
|
||||||
arg_stack.pop().unwrap()
|
|
||||||
} else {
|
|
||||||
Term::Error.delay()
|
|
||||||
};
|
|
||||||
|
|
||||||
term = if full_cast {
|
term = if full_cast {
|
||||||
convert_data_to_type(term, &tipo, otherwise)
|
unknown_data_to_type(term, &tipo)
|
||||||
} else {
|
} else {
|
||||||
known_data_to_type(term, &tipo)
|
known_data_to_type(term, &tipo)
|
||||||
};
|
};
|
||||||
|
|
|
@ -101,6 +101,10 @@ pub enum Air {
|
||||||
Let {
|
Let {
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
SoftCastLet {
|
||||||
|
name: String,
|
||||||
|
tipo: Rc<Type>,
|
||||||
|
},
|
||||||
CastFromData {
|
CastFromData {
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
full_cast: bool,
|
full_cast: bool,
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub struct AssignmentProperties {
|
||||||
pub kind: TypedAssignmentKind,
|
pub kind: TypedAssignmentKind,
|
||||||
pub remove_unused: bool,
|
pub remove_unused: bool,
|
||||||
pub full_check: bool,
|
pub full_check: bool,
|
||||||
pub otherwise: AirTree,
|
pub otherwise: Option<AirTree>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -948,9 +948,11 @@ pub fn unknown_data_to_type(term: Term<Name>, field_type: &Type) -> Term<Name> {
|
||||||
/// Due to the nature of the types BLS12_381_G1Element and BLS12_381_G2Element and String coming from bytearray
|
/// Due to the nature of the types BLS12_381_G1Element and BLS12_381_G2Element and String coming from bytearray
|
||||||
/// We don't have error handling if the bytearray is not properly aligned to the type. Oh well lol
|
/// We don't have error handling if the bytearray is not properly aligned to the type. Oh well lol
|
||||||
/// For BLS12_381_G1Element and BLS12_381_G2Element, hash to group exists so just adopt that.
|
/// For BLS12_381_G1Element and BLS12_381_G2Element, hash to group exists so just adopt that.
|
||||||
pub fn unknown_data_to_type_otherwise(
|
pub fn softcast_data_to_type_otherwise(
|
||||||
term: Term<Name>,
|
value: Term<Name>,
|
||||||
|
name: &String,
|
||||||
field_type: &Type,
|
field_type: &Type,
|
||||||
|
then: Term<Name>,
|
||||||
otherwise_delayed: Term<Name>,
|
otherwise_delayed: Term<Name>,
|
||||||
) -> Term<Name> {
|
) -> Term<Name> {
|
||||||
let uplc_type = field_type.get_uplc_type();
|
let uplc_type = field_type.get_uplc_type();
|
||||||
|
@ -961,59 +963,67 @@ pub fn unknown_data_to_type_otherwise(
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
Term::un_i_data().apply(Term::var("__val")).delay(),
|
then.lambda(name)
|
||||||
|
.apply(Term::un_i_data().apply(Term::var("__val")))
|
||||||
|
.delay(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
Some(UplcType::ByteString) => Term::var("__val")
|
Some(UplcType::ByteString) => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
Term::un_b_data().apply(Term::var("__val")).delay(),
|
then.lambda(name)
|
||||||
|
.apply(Term::un_b_data().apply(Term::var("__val")))
|
||||||
|
.delay(),
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
Some(UplcType::String) => Term::var("__val")
|
Some(UplcType::String) => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
Term::decode_utf8()
|
then.lambda(name)
|
||||||
.apply(Term::un_b_data().apply(Term::var("__val")))
|
.apply(Term::decode_utf8().apply(Term::un_b_data().apply(Term::var("__val"))))
|
||||||
.delay(),
|
.delay(),
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
|
|
||||||
Some(UplcType::List(_)) if field_type.is_map() => Term::var("__val")
|
Some(UplcType::List(_)) if field_type.is_map() => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
Term::unmap_data().apply(Term::var("__val")).delay(),
|
then.lambda(name)
|
||||||
|
.apply(Term::unmap_data().apply(Term::var("__val")))
|
||||||
|
.delay(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
Some(UplcType::List(_)) => Term::var("__val")
|
Some(UplcType::List(_)) => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
Term::unlist_data().apply(Term::var("__val")).delay(),
|
then.lambda(name)
|
||||||
|
.apply(Term::unlist_data().apply(Term::var("__val")))
|
||||||
|
.delay(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
|
|
||||||
Some(UplcType::Bls12_381G1Element) => Term::var("__val")
|
Some(UplcType::Bls12_381G1Element) => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
|
@ -1021,26 +1031,32 @@ pub fn unknown_data_to_type_otherwise(
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
Term::bls12_381_g1_uncompress()
|
then.lambda(name)
|
||||||
.apply(Term::un_b_data().apply(Term::var("__val")))
|
.apply(
|
||||||
|
Term::bls12_381_g1_uncompress()
|
||||||
|
.apply(Term::un_b_data().apply(Term::var("__val"))),
|
||||||
|
)
|
||||||
.delay(),
|
.delay(),
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
Some(UplcType::Bls12_381G2Element) => Term::var("__val")
|
Some(UplcType::Bls12_381G2Element) => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
Term::bls12_381_g2_uncompress()
|
then.lambda(name)
|
||||||
.apply(Term::un_b_data().apply(Term::var("__val")))
|
.apply(
|
||||||
|
Term::bls12_381_g2_uncompress()
|
||||||
|
.apply(Term::un_b_data().apply(Term::var("__val"))),
|
||||||
|
)
|
||||||
.delay(),
|
.delay(),
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
Some(UplcType::Bls12_381MlResult) => panic!("ML Result not supported"),
|
Some(UplcType::Bls12_381MlResult) => panic!("ML Result not supported"),
|
||||||
Some(UplcType::Pair(_, _)) => Term::var("__val")
|
Some(UplcType::Pair(_, _)) => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
|
@ -1055,11 +1071,18 @@ pub fn unknown_data_to_type_otherwise(
|
||||||
Term::tail_list()
|
Term::tail_list()
|
||||||
.apply(Term::var("__tail"))
|
.apply(Term::var("__tail"))
|
||||||
.choose_list(
|
.choose_list(
|
||||||
Term::mk_pair_data()
|
then.lambda(name)
|
||||||
.apply(
|
.apply(
|
||||||
Term::head_list().apply(Term::var("__list_data")),
|
Term::mk_pair_data()
|
||||||
|
.apply(
|
||||||
|
Term::head_list()
|
||||||
|
.apply(Term::var("__list_data")),
|
||||||
|
)
|
||||||
|
.apply(
|
||||||
|
Term::head_list()
|
||||||
|
.apply(Term::var("__tail")),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.apply(Term::head_list().apply(Term::var("__tail")))
|
|
||||||
.delay(),
|
.delay(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
)
|
)
|
||||||
|
@ -1080,25 +1103,22 @@ pub fn unknown_data_to_type_otherwise(
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
Some(UplcType::Bool) => Term::var("__val")
|
Some(UplcType::Bool) => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
Term::snd_pair()
|
Term::snd_pair()
|
||||||
.apply(Term::var("__pair__"))
|
.apply(Term::var("__pair__"))
|
||||||
.choose_list(
|
.choose_list(
|
||||||
Term::equals_integer()
|
Term::less_than_equals_integer()
|
||||||
.apply(Term::integer(1.into()))
|
.apply(Term::integer(2.into()))
|
||||||
.apply(Term::fst_pair().apply(Term::var("__pair__")))
|
.apply(Term::fst_pair().apply(Term::var("__pair__")))
|
||||||
.delayed_if_then_else(
|
.delayed_if_then_else(
|
||||||
Term::bool(true),
|
otherwise_delayed.clone(),
|
||||||
Term::equals_integer()
|
then.lambda(name).apply(
|
||||||
.apply(Term::integer(0.into()))
|
Term::equals_integer()
|
||||||
.apply(Term::fst_pair().apply(Term::var("__pair__")))
|
.apply(Term::fst_pair().apply(Term::var("__pair__")))
|
||||||
.if_then_else(
|
.apply(Term::integer(1.into())),
|
||||||
Term::bool(false).delay(),
|
),
|
||||||
otherwise_delayed.clone(),
|
|
||||||
)
|
|
||||||
.force(),
|
|
||||||
)
|
)
|
||||||
.delay(),
|
.delay(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
|
@ -1114,7 +1134,7 @@ pub fn unknown_data_to_type_otherwise(
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
Some(UplcType::Unit) => Term::var("__val")
|
Some(UplcType::Unit) => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
Term::equals_integer()
|
Term::equals_integer()
|
||||||
|
@ -1123,7 +1143,10 @@ pub fn unknown_data_to_type_otherwise(
|
||||||
.if_then_else(
|
.if_then_else(
|
||||||
Term::snd_pair()
|
Term::snd_pair()
|
||||||
.apply(Term::unconstr_data().apply(Term::var("__val")))
|
.apply(Term::unconstr_data().apply(Term::var("__val")))
|
||||||
.choose_list(Term::unit().delay(), otherwise_delayed.clone())
|
.choose_list(
|
||||||
|
then.lambda(name).apply(Term::unit()).delay(),
|
||||||
|
otherwise_delayed.clone(),
|
||||||
|
)
|
||||||
.force()
|
.force()
|
||||||
.delay(),
|
.delay(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
|
@ -1137,13 +1160,13 @@ pub fn unknown_data_to_type_otherwise(
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
|
|
||||||
Some(UplcType::Data) => term,
|
Some(UplcType::Data) => then.lambda(name).apply(value),
|
||||||
// constr type
|
// constr type
|
||||||
None => Term::var("__val")
|
None => Term::var("__val")
|
||||||
.choose_data(
|
.choose_data(
|
||||||
Term::var("__val").delay(),
|
then.lambda(name).apply(Term::var("__val")).delay(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
|
@ -1151,7 +1174,7 @@ pub fn unknown_data_to_type_otherwise(
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda("__val")
|
.lambda("__val")
|
||||||
.apply(term),
|
.apply(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1354,30 +1377,32 @@ pub fn list_access_to_uplc(
|
||||||
|
|
||||||
let tail_name = |id| format!("tail_id_{}", id);
|
let tail_name = |id| format!("tail_id_{}", id);
|
||||||
|
|
||||||
let head_item = |name, tipo: &Rc<Type>, tail_name: &str| {
|
let head_item = |name, tipo: &Rc<Type>, tail_name: &str, then: Term<Name>| {
|
||||||
if name == "_" {
|
if name == "_" {
|
||||||
Term::unit()
|
then
|
||||||
} else if tipo.is_pair() && is_list_accessor {
|
} else if tipo.is_pair() && is_list_accessor {
|
||||||
Term::head_list().apply(Term::var(tail_name.to_string()))
|
Term::head_list().apply(Term::var(tail_name.to_string()))
|
||||||
} else if matches!(expect_level, ExpectLevel::Full) {
|
} else if matches!(expect_level, ExpectLevel::Full) {
|
||||||
// Expect level is full so we have an unknown piece of data to cast
|
// Expect level is full so we have an unknown piece of data to cast
|
||||||
if otherwise_delayed == Term::Error.delay() {
|
if otherwise_delayed == Term::Error.delay() {
|
||||||
unknown_data_to_type(
|
then.lambda(name).apply(unknown_data_to_type(
|
||||||
Term::head_list().apply(Term::var(tail_name.to_string())),
|
Term::head_list().apply(Term::var(tail_name.to_string())),
|
||||||
&tipo.to_owned(),
|
&tipo.to_owned(),
|
||||||
)
|
))
|
||||||
} else {
|
} else {
|
||||||
unknown_data_to_type_otherwise(
|
softcast_data_to_type_otherwise(
|
||||||
Term::head_list().apply(Term::var(tail_name.to_string())),
|
Term::head_list().apply(Term::var(tail_name.to_string())),
|
||||||
|
name,
|
||||||
&tipo.to_owned(),
|
&tipo.to_owned(),
|
||||||
|
then,
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
known_data_to_type(
|
then.lambda(name).apply(known_data_to_type(
|
||||||
Term::head_list().apply(Term::var(tail_name.to_string())),
|
Term::head_list().apply(Term::var(tail_name.to_string())),
|
||||||
&tipo.to_owned(),
|
&tipo.to_owned(),
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1399,48 +1424,56 @@ pub fn list_access_to_uplc(
|
||||||
// case for no tail, but last item
|
// case for no tail, but last item
|
||||||
let tail_name = tail_name(id);
|
let tail_name = tail_name(id);
|
||||||
|
|
||||||
let head_item = head_item(name, tipo, &tail_name);
|
// let head_item = head_item(name, tipo, &tail_name);
|
||||||
|
|
||||||
match expect_level {
|
match expect_level {
|
||||||
ExpectLevel::None => acc.lambda(name).apply(head_item).lambda(tail_name),
|
ExpectLevel::None => {
|
||||||
|
head_item(name, tipo, &tail_name, acc).lambda(tail_name)
|
||||||
|
}
|
||||||
|
|
||||||
ExpectLevel::Full | ExpectLevel::Items => {
|
ExpectLevel::Full | ExpectLevel::Items => {
|
||||||
if otherwise_delayed == Term::Error.delay() && tail_present {
|
if otherwise_delayed == Term::Error.delay() && tail_present {
|
||||||
// No need to check last item if tail was present
|
// No need to check last item if tail was present
|
||||||
acc.lambda(name).apply(head_item).lambda(tail_name)
|
head_item(name, tipo, &tail_name, acc).lambda(tail_name)
|
||||||
} else if tail_present {
|
} else if tail_present {
|
||||||
// Custom error instead of trying to do head_item on a possibly empty list.
|
// Custom error instead of trying to do head_item on a possibly empty list.
|
||||||
Term::var(tail_name.to_string())
|
Term::var(tail_name.to_string())
|
||||||
.choose_list(
|
.choose_list(
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
acc.lambda(name).apply(head_item).delay(),
|
head_item(name, tipo, &tail_name, acc).delay(),
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda(tail_name)
|
.lambda(tail_name)
|
||||||
} else if otherwise_delayed == Term::Error.delay() {
|
} else if otherwise_delayed == Term::Error.delay() {
|
||||||
// Check head is last item in this list
|
// Check head is last item in this list
|
||||||
Term::tail_list()
|
head_item(
|
||||||
.apply(Term::var(tail_name.to_string()))
|
name,
|
||||||
.choose_list(acc.delay(), Term::Error.delay())
|
tipo,
|
||||||
.force()
|
&tail_name,
|
||||||
.lambda(name)
|
Term::tail_list()
|
||||||
.apply(head_item)
|
.apply(Term::var(tail_name.to_string()))
|
||||||
.lambda(tail_name)
|
.choose_list(acc.delay(), Term::Error.delay())
|
||||||
|
.force(),
|
||||||
|
)
|
||||||
|
.lambda(tail_name)
|
||||||
} else {
|
} else {
|
||||||
// Custom error if list is not empty after this head
|
// Custom error if list is not empty after this head
|
||||||
Term::var(tail_name.to_string())
|
head_item(
|
||||||
.choose_list(
|
name,
|
||||||
otherwise_delayed.clone(),
|
tipo,
|
||||||
Term::tail_list()
|
&tail_name,
|
||||||
.apply(Term::var(tail_name.to_string()))
|
Term::var(tail_name.to_string())
|
||||||
.choose_list(acc.delay(), otherwise_delayed.clone())
|
.choose_list(
|
||||||
.force()
|
otherwise_delayed.clone(),
|
||||||
.lambda(name)
|
Term::tail_list()
|
||||||
.apply(head_item)
|
.apply(Term::var(tail_name.to_string()))
|
||||||
.delay(),
|
.choose_list(acc.delay(), otherwise_delayed.clone())
|
||||||
)
|
.force(),
|
||||||
.force()
|
)
|
||||||
.lambda(tail_name)
|
.delay(),
|
||||||
|
)
|
||||||
|
.force()
|
||||||
|
.lambda(tail_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1450,26 +1483,33 @@ pub fn list_access_to_uplc(
|
||||||
// case for every item except the last item
|
// case for every item except the last item
|
||||||
let tail_name = tail_name(id);
|
let tail_name = tail_name(id);
|
||||||
|
|
||||||
let head_item = head_item(name, tipo, &tail_name);
|
// let head_item = head_item(name, tipo, &tail_name);
|
||||||
|
|
||||||
if matches!(expect_level, ExpectLevel::None)
|
if matches!(expect_level, ExpectLevel::None)
|
||||||
|| otherwise_delayed == Term::Error.delay()
|
|| otherwise_delayed == Term::Error.delay()
|
||||||
{
|
{
|
||||||
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string())))
|
head_item(
|
||||||
.lambda(name)
|
name,
|
||||||
.apply(head_item)
|
tipo,
|
||||||
.lambda(tail_name)
|
&tail_name,
|
||||||
|
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string()))),
|
||||||
|
)
|
||||||
|
.lambda(tail_name)
|
||||||
} else {
|
} else {
|
||||||
// case for a custom error if the list is empty at this point
|
// case for a custom error if the list is empty at this point
|
||||||
|
|
||||||
Term::var(tail_name.to_string())
|
Term::var(tail_name.to_string())
|
||||||
.choose_list(
|
.choose_list(
|
||||||
otherwise_delayed.clone(),
|
otherwise_delayed.clone(),
|
||||||
acc.apply(
|
head_item(
|
||||||
Term::tail_list().apply(Term::var(tail_name.to_string())),
|
name,
|
||||||
)
|
tipo,
|
||||||
.lambda(name)
|
&tail_name,
|
||||||
.apply(head_item)
|
acc.apply(
|
||||||
.delay(),
|
Term::tail_list().apply(Term::var(tail_name.to_string())),
|
||||||
|
)
|
||||||
|
.delay(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.force()
|
.force()
|
||||||
.lambda(tail_name)
|
.lambda(tail_name)
|
||||||
|
|
|
@ -125,6 +125,13 @@ pub enum AirTree {
|
||||||
value: Box<AirTree>,
|
value: Box<AirTree>,
|
||||||
then: Box<AirTree>,
|
then: Box<AirTree>,
|
||||||
},
|
},
|
||||||
|
SoftCastLet {
|
||||||
|
name: String,
|
||||||
|
tipo: Rc<Type>,
|
||||||
|
value: Box<AirTree>,
|
||||||
|
then: Box<AirTree>,
|
||||||
|
otherwise: Box<AirTree>,
|
||||||
|
},
|
||||||
DefineFunc {
|
DefineFunc {
|
||||||
func_name: String,
|
func_name: String,
|
||||||
module_name: String,
|
module_name: String,
|
||||||
|
@ -312,7 +319,6 @@ pub enum AirTree {
|
||||||
CastFromData {
|
CastFromData {
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
value: Box<AirTree>,
|
value: Box<AirTree>,
|
||||||
otherwise: Box<AirTree>,
|
|
||||||
full_cast: bool,
|
full_cast: bool,
|
||||||
},
|
},
|
||||||
CastToData {
|
CastToData {
|
||||||
|
@ -589,39 +595,26 @@ impl AirTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_literal_pattern(
|
pub fn soft_cast_assignment(
|
||||||
name: String,
|
name: impl ToString,
|
||||||
pattern: AirTree,
|
|
||||||
rhs: AirTree,
|
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
props: AssignmentProperties,
|
value: AirTree,
|
||||||
then: AirTree,
|
then: AirTree,
|
||||||
|
otherwise: AirTree,
|
||||||
) -> AirTree {
|
) -> AirTree {
|
||||||
assert!(props.kind.is_expect());
|
AirTree::SoftCastLet {
|
||||||
|
name: name.to_string(),
|
||||||
let expect = AirTree::binop(
|
|
||||||
BinOp::Eq,
|
|
||||||
bool(),
|
|
||||||
pattern,
|
|
||||||
AirTree::local_var(&name, tipo.clone()),
|
|
||||||
tipo,
|
tipo,
|
||||||
);
|
value: value.into(),
|
||||||
|
then: then.into(),
|
||||||
let expr = AirTree::let_assignment(name, rhs, expect);
|
otherwise: otherwise.into(),
|
||||||
|
}
|
||||||
AirTree::assert_bool(true, expr, then, props.otherwise.clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cast_from_data(
|
pub fn cast_from_data(value: AirTree, tipo: Rc<Type>, full_cast: bool) -> AirTree {
|
||||||
value: AirTree,
|
|
||||||
tipo: Rc<Type>,
|
|
||||||
otherwise: AirTree,
|
|
||||||
full_cast: bool,
|
|
||||||
) -> AirTree {
|
|
||||||
AirTree::CastFromData {
|
AirTree::CastFromData {
|
||||||
tipo,
|
tipo,
|
||||||
value: value.into(),
|
value: value.into(),
|
||||||
otherwise: otherwise.into(),
|
|
||||||
full_cast,
|
full_cast,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -888,7 +881,6 @@ impl AirTree {
|
||||||
vec![list_of_fields],
|
vec![list_of_fields],
|
||||||
),
|
),
|
||||||
tipo.clone(),
|
tipo.clone(),
|
||||||
AirTree::error(void(), false),
|
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -994,7 +986,6 @@ impl AirTree {
|
||||||
vec![tuple],
|
vec![tuple],
|
||||||
),
|
),
|
||||||
tipo.clone(),
|
tipo.clone(),
|
||||||
AirTree::error(void(), false),
|
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1045,6 +1036,32 @@ impl AirTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expect_on_list2() -> AirTree {
|
||||||
|
let expect_on_list = AirTree::var(
|
||||||
|
ValueConstructor::public(
|
||||||
|
void(),
|
||||||
|
ValueConstructorVariant::ModuleFn {
|
||||||
|
name: EXPECT_ON_LIST.to_string(),
|
||||||
|
field_map: None,
|
||||||
|
module: "".to_string(),
|
||||||
|
arity: 1,
|
||||||
|
location: Span::empty(),
|
||||||
|
builtin: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
EXPECT_ON_LIST,
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
|
||||||
|
let list_var = AirTree::local_var("__list_to_check", list(data()));
|
||||||
|
|
||||||
|
AirTree::call(
|
||||||
|
AirTree::local_var("__check_with", void()),
|
||||||
|
void(),
|
||||||
|
vec![list_var, expect_on_list],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expect_on_list() -> AirTree {
|
pub fn expect_on_list() -> AirTree {
|
||||||
let list_var = AirTree::local_var("__list_to_check", list(data()));
|
let list_var = AirTree::local_var("__list_to_check", list(data()));
|
||||||
|
|
||||||
|
@ -1108,6 +1125,21 @@ impl AirTree {
|
||||||
value.create_air_vec(air_vec);
|
value.create_air_vec(air_vec);
|
||||||
then.create_air_vec(air_vec);
|
then.create_air_vec(air_vec);
|
||||||
}
|
}
|
||||||
|
AirTree::SoftCastLet {
|
||||||
|
name,
|
||||||
|
tipo,
|
||||||
|
value,
|
||||||
|
then,
|
||||||
|
otherwise,
|
||||||
|
} => {
|
||||||
|
air_vec.push(Air::SoftCastLet {
|
||||||
|
name: name.clone(),
|
||||||
|
tipo: tipo.clone(),
|
||||||
|
});
|
||||||
|
value.create_air_vec(air_vec);
|
||||||
|
then.create_air_vec(air_vec);
|
||||||
|
otherwise.create_air_vec(air_vec);
|
||||||
|
}
|
||||||
AirTree::DefineFunc {
|
AirTree::DefineFunc {
|
||||||
func_name,
|
func_name,
|
||||||
module_name,
|
module_name,
|
||||||
|
@ -1457,7 +1489,6 @@ impl AirTree {
|
||||||
AirTree::CastFromData {
|
AirTree::CastFromData {
|
||||||
tipo,
|
tipo,
|
||||||
value,
|
value,
|
||||||
otherwise,
|
|
||||||
full_cast,
|
full_cast,
|
||||||
} => {
|
} => {
|
||||||
air_vec.push(Air::CastFromData {
|
air_vec.push(Air::CastFromData {
|
||||||
|
@ -1466,9 +1497,6 @@ impl AirTree {
|
||||||
});
|
});
|
||||||
|
|
||||||
value.create_air_vec(air_vec);
|
value.create_air_vec(air_vec);
|
||||||
if *full_cast {
|
|
||||||
otherwise.create_air_vec(air_vec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AirTree::CastToData { tipo, value } => {
|
AirTree::CastToData { tipo, value } => {
|
||||||
air_vec.push(Air::CastToData { tipo: tipo.clone() });
|
air_vec.push(Air::CastToData { tipo: tipo.clone() });
|
||||||
|
@ -1670,6 +1698,7 @@ impl AirTree {
|
||||||
| AirTree::PairClause { then, .. }
|
| AirTree::PairClause { then, .. }
|
||||||
| AirTree::Finally { then, .. }
|
| AirTree::Finally { then, .. }
|
||||||
| AirTree::Let { then, .. }
|
| AirTree::Let { then, .. }
|
||||||
|
| AirTree::SoftCastLet { then, .. }
|
||||||
| AirTree::DefineFunc { then, .. }
|
| AirTree::DefineFunc { then, .. }
|
||||||
| AirTree::DefineCyclicFuncs { then, .. }
|
| AirTree::DefineCyclicFuncs { then, .. }
|
||||||
| AirTree::AssertConstr { then, .. }
|
| AirTree::AssertConstr { then, .. }
|
||||||
|
@ -1715,7 +1744,8 @@ impl AirTree {
|
||||||
| AirTree::Constr { tipo, .. }
|
| AirTree::Constr { tipo, .. }
|
||||||
| AirTree::ErrorTerm { tipo, .. }
|
| AirTree::ErrorTerm { tipo, .. }
|
||||||
| AirTree::Trace { tipo, .. }
|
| AirTree::Trace { tipo, .. }
|
||||||
| AirTree::Pair { tipo, .. } => vec![tipo],
|
| AirTree::Pair { tipo, .. }
|
||||||
|
| AirTree::SoftCastLet { tipo, .. } => vec![tipo],
|
||||||
|
|
||||||
AirTree::FieldsExpose { indices, .. } => {
|
AirTree::FieldsExpose { indices, .. } => {
|
||||||
let mut types = vec![];
|
let mut types = vec![];
|
||||||
|
@ -1821,6 +1851,30 @@ impl AirTree {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AirTree::SoftCastLet {
|
||||||
|
name: _,
|
||||||
|
tipo: _,
|
||||||
|
value,
|
||||||
|
then: _,
|
||||||
|
otherwise,
|
||||||
|
} => {
|
||||||
|
value.do_traverse_tree_with(
|
||||||
|
tree_path,
|
||||||
|
current_depth + 1,
|
||||||
|
Fields::ThirdField,
|
||||||
|
with,
|
||||||
|
apply_with_func_last,
|
||||||
|
);
|
||||||
|
|
||||||
|
otherwise.do_traverse_tree_with(
|
||||||
|
tree_path,
|
||||||
|
current_depth + 1,
|
||||||
|
Fields::FifthField,
|
||||||
|
with,
|
||||||
|
apply_with_func_last,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
AirTree::AssertConstr {
|
AirTree::AssertConstr {
|
||||||
constr_index: _,
|
constr_index: _,
|
||||||
constr,
|
constr,
|
||||||
|
@ -2291,7 +2345,6 @@ impl AirTree {
|
||||||
AirTree::CastFromData {
|
AirTree::CastFromData {
|
||||||
tipo: _,
|
tipo: _,
|
||||||
value,
|
value,
|
||||||
otherwise: _,
|
|
||||||
full_cast: _,
|
full_cast: _,
|
||||||
} => {
|
} => {
|
||||||
value.do_traverse_tree_with(
|
value.do_traverse_tree_with(
|
||||||
|
@ -2560,6 +2613,21 @@ impl AirTree {
|
||||||
apply_with_func_last,
|
apply_with_func_last,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
AirTree::SoftCastLet {
|
||||||
|
name: _,
|
||||||
|
tipo: _,
|
||||||
|
value: _,
|
||||||
|
then,
|
||||||
|
otherwise: _,
|
||||||
|
} => {
|
||||||
|
then.do_traverse_tree_with(
|
||||||
|
tree_path,
|
||||||
|
current_depth + 1,
|
||||||
|
Fields::FourthField,
|
||||||
|
with,
|
||||||
|
apply_with_func_last,
|
||||||
|
);
|
||||||
|
}
|
||||||
AirTree::AssertConstr {
|
AirTree::AssertConstr {
|
||||||
constr_index: _,
|
constr_index: _,
|
||||||
constr: _,
|
constr: _,
|
||||||
|
@ -2806,6 +2874,18 @@ impl AirTree {
|
||||||
Fields::ThirdField => then.as_mut().do_find_air_tree_node(tree_path_iter),
|
Fields::ThirdField => then.as_mut().do_find_air_tree_node(tree_path_iter),
|
||||||
_ => panic!("Tree Path index outside tree children nodes"),
|
_ => panic!("Tree Path index outside tree children nodes"),
|
||||||
},
|
},
|
||||||
|
AirTree::SoftCastLet {
|
||||||
|
name: _,
|
||||||
|
tipo: _,
|
||||||
|
value,
|
||||||
|
then,
|
||||||
|
otherwise,
|
||||||
|
} => match field {
|
||||||
|
Fields::ThirdField => value.as_mut().do_find_air_tree_node(tree_path_iter),
|
||||||
|
Fields::FourthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
|
||||||
|
Fields::FifthField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
|
||||||
|
_ => panic!("Tree Path index outside tree children nodes"),
|
||||||
|
},
|
||||||
AirTree::AssertConstr {
|
AirTree::AssertConstr {
|
||||||
constr_index: _,
|
constr_index: _,
|
||||||
constr,
|
constr,
|
||||||
|
@ -3011,11 +3091,9 @@ impl AirTree {
|
||||||
AirTree::CastFromData {
|
AirTree::CastFromData {
|
||||||
tipo: _,
|
tipo: _,
|
||||||
value,
|
value,
|
||||||
otherwise,
|
|
||||||
full_cast: _,
|
full_cast: _,
|
||||||
} => match field {
|
} => match field {
|
||||||
Fields::SecondField => value.as_mut().do_find_air_tree_node(tree_path_iter),
|
Fields::SecondField => value.as_mut().do_find_air_tree_node(tree_path_iter),
|
||||||
Fields::ThirdField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
|
|
||||||
_ => panic!("Tree Path index outside tree children nodes"),
|
_ => panic!("Tree Path index outside tree children nodes"),
|
||||||
},
|
},
|
||||||
AirTree::CastToData { tipo: _, value } => match field {
|
AirTree::CastToData { tipo: _, value } => match field {
|
||||||
|
|
Loading…
Reference in New Issue