feat: refactor code gen to avoid builtin errors when tracing is turned on
This commit is contained in:
parent
b50e4ab63a
commit
956c3d6cf0
|
@ -24,13 +24,16 @@ use crate::{
|
||||||
},
|
},
|
||||||
builtins::{bool, data, int, list, string, void},
|
builtins::{bool, data, int, list, string, void},
|
||||||
expr::TypedExpr,
|
expr::TypedExpr,
|
||||||
gen_uplc::builder::{
|
gen_uplc::{
|
||||||
|
air::ExpectLevel,
|
||||||
|
builder::{
|
||||||
check_replaceable_opaque_type, convert_opaque_type, erase_opaque_type_operations,
|
check_replaceable_opaque_type, convert_opaque_type, erase_opaque_type_operations,
|
||||||
find_and_replace_generics, find_list_clause_or_default_first, get_arg_type_name,
|
find_and_replace_generics, find_list_clause_or_default_first, get_arg_type_name,
|
||||||
get_generic_id_and_type, get_generic_variant_name, get_line_columns_by_span,
|
get_generic_id_and_type, get_generic_variant_name, get_line_columns_by_span,
|
||||||
get_src_code_by_span, monomorphize, pattern_has_conditions, wrap_as_multi_validator,
|
get_src_code_by_span, monomorphize, pattern_has_conditions, wrap_as_multi_validator,
|
||||||
wrap_validator_condition, CodeGenFunction, SpecificClause,
|
wrap_validator_condition, CodeGenFunction, SpecificClause,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
line_numbers::LineNumbers,
|
line_numbers::LineNumbers,
|
||||||
tipo::{
|
tipo::{
|
||||||
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
|
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
|
||||||
|
@ -840,7 +843,7 @@ 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() {
|
if props.value_type.is_data() && props.kind.is_expect() && !tipo.is_data() {
|
||||||
value = AirTree::cast_from_data(value, tipo.clone());
|
value = AirTree::cast_from_data(value, tipo.clone(), props.msg_func.clone());
|
||||||
} else if !props.value_type.is_data() && tipo.is_data() {
|
} else if !props.value_type.is_data() && tipo.is_data() {
|
||||||
value = AirTree::cast_to_data(value, props.value_type.clone());
|
value = AirTree::cast_to_data(value, props.value_type.clone());
|
||||||
}
|
}
|
||||||
|
@ -1050,7 +1053,11 @@ impl<'a> CodeGenerator<'a> {
|
||||||
tail.is_some(),
|
tail.is_some(),
|
||||||
value,
|
value,
|
||||||
props.msg_func,
|
props.msg_func,
|
||||||
true,
|
if props.full_check {
|
||||||
|
ExpectLevel::Full
|
||||||
|
} else {
|
||||||
|
ExpectLevel::Items
|
||||||
|
},
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1345,8 +1352,8 @@ impl<'a> CodeGenerator<'a> {
|
||||||
vec![fst_name.clone(), snd_name.clone()],
|
vec![fst_name.clone(), snd_name.clone()],
|
||||||
inner_list_type.clone(),
|
inner_list_type.clone(),
|
||||||
AirTree::local_var(&pair_name, inner_list_type.clone()),
|
AirTree::local_var(&pair_name, inner_list_type.clone()),
|
||||||
None,
|
msg_func.clone(),
|
||||||
false,
|
msg_func.is_some(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let expect_fst = self.expect_type_assign(
|
let expect_fst = self.expect_type_assign(
|
||||||
|
@ -1431,6 +1438,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
AirTree::cast_from_data(
|
AirTree::cast_from_data(
|
||||||
AirTree::local_var(&item_name, data()),
|
AirTree::local_var(&item_name, data()),
|
||||||
inner_list_type.clone(),
|
inner_list_type.clone(),
|
||||||
|
msg_func.clone(),
|
||||||
),
|
),
|
||||||
defined_data_types,
|
defined_data_types,
|
||||||
location,
|
location,
|
||||||
|
@ -2291,7 +2299,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
// So for the msg we pass in empty string if tracing is on
|
// So for the msg we pass in empty string if tracing is on
|
||||||
// Since check_last_item is false this will never get added to the final uplc anyway
|
// Since check_last_item is false this will never get added to the final uplc anyway
|
||||||
None,
|
None,
|
||||||
false,
|
ExpectLevel::None,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
assert!(defined_tails.len() >= defined_heads.len());
|
assert!(defined_tails.len() >= defined_heads.len());
|
||||||
|
@ -4042,7 +4050,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
// tipo here refers to the list type while the actual return
|
// tipo here refers to the list type while the actual return
|
||||||
// type is nothing since this is an assignment over some expression
|
// type is nothing since this is an assignment over some expression
|
||||||
tipo,
|
tipo,
|
||||||
is_expect,
|
expect_level,
|
||||||
} => {
|
} => {
|
||||||
let value = arg_stack.pop().unwrap();
|
let value = arg_stack.pop().unwrap();
|
||||||
|
|
||||||
|
@ -4071,8 +4079,8 @@ impl<'a> CodeGenerator<'a> {
|
||||||
&names_types,
|
&names_types,
|
||||||
tail,
|
tail,
|
||||||
term,
|
term,
|
||||||
is_expect && !tail,
|
|
||||||
true,
|
true,
|
||||||
|
expect_level,
|
||||||
error_term,
|
error_term,
|
||||||
)
|
)
|
||||||
.apply(value);
|
.apply(value);
|
||||||
|
@ -4495,12 +4503,16 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
Some(term)
|
Some(term)
|
||||||
}
|
}
|
||||||
Air::CastFromData { tipo } => {
|
Air::CastFromData { tipo, .. } => {
|
||||||
let mut term = arg_stack.pop().unwrap();
|
let mut term = arg_stack.pop().unwrap();
|
||||||
|
|
||||||
if extract_constant(&term).is_some() {
|
term = if error_term == Term::Error {
|
||||||
term = builder::convert_data_to_type(term, &tipo);
|
builder::convert_data_to_type(term, &tipo)
|
||||||
|
} else {
|
||||||
|
builder::convert_data_to_type_debug(term, &tipo, error_term)
|
||||||
|
};
|
||||||
|
|
||||||
|
if extract_constant(&term).is_some() {
|
||||||
let mut program: Program<Name> = Program {
|
let mut program: Program<Name> = Program {
|
||||||
version: (1, 0, 0),
|
version: (1, 0, 0),
|
||||||
term,
|
term,
|
||||||
|
@ -4515,8 +4527,6 @@ impl<'a> CodeGenerator<'a> {
|
||||||
let evaluated_term: Term<NamedDeBruijn> =
|
let evaluated_term: Term<NamedDeBruijn> =
|
||||||
eval_program.eval(ExBudget::default()).result().unwrap();
|
eval_program.eval(ExBudget::default()).result().unwrap();
|
||||||
term = evaluated_term.try_into().unwrap();
|
term = evaluated_term.try_into().unwrap();
|
||||||
} else {
|
|
||||||
term = builder::convert_data_to_type(term, &tipo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(term)
|
Some(term)
|
||||||
|
@ -4979,8 +4989,8 @@ impl<'a> CodeGenerator<'a> {
|
||||||
&names_types,
|
&names_types,
|
||||||
false,
|
false,
|
||||||
term,
|
term,
|
||||||
is_expect,
|
|
||||||
false,
|
false,
|
||||||
|
is_expect.into(),
|
||||||
error_term,
|
error_term,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -5213,19 +5223,35 @@ impl<'a> CodeGenerator<'a> {
|
||||||
if names[1] != "_" {
|
if names[1] != "_" {
|
||||||
term = term
|
term = term
|
||||||
.lambda(names[1].clone())
|
.lambda(names[1].clone())
|
||||||
.apply(builder::convert_data_to_type(
|
.apply(if error_term != Term::Error {
|
||||||
|
builder::convert_data_to_type_debug(
|
||||||
Term::snd_pair().apply(Term::var(format!("__tuple_{list_id}"))),
|
Term::snd_pair().apply(Term::var(format!("__tuple_{list_id}"))),
|
||||||
&inner_types[1],
|
&inner_types[1],
|
||||||
));
|
error_term.clone(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
builder::convert_data_to_type(
|
||||||
|
Term::snd_pair().apply(Term::var(format!("__tuple_{list_id}"))),
|
||||||
|
&inner_types[1],
|
||||||
|
)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if names[0] != "_" {
|
if names[0] != "_" {
|
||||||
term = term
|
term = term
|
||||||
.lambda(names[0].clone())
|
.lambda(names[0].clone())
|
||||||
.apply(builder::convert_data_to_type(
|
.apply(if error_term != Term::Error {
|
||||||
Term::fst_pair().apply(Term::var(format!("__tuple_{list_id}"))),
|
builder::convert_data_to_type_debug(
|
||||||
&inner_types[0],
|
Term::snd_pair().apply(Term::var(format!("__tuple_{list_id}"))),
|
||||||
))
|
&inner_types[1],
|
||||||
|
error_term,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
builder::convert_data_to_type(
|
||||||
|
Term::snd_pair().apply(Term::var(format!("__tuple_{list_id}"))),
|
||||||
|
&inner_types[1],
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
term = term.lambda(format!("__tuple_{list_id}")).apply(value);
|
term = term.lambda(format!("__tuple_{list_id}")).apply(value);
|
||||||
|
@ -5250,8 +5276,8 @@ impl<'a> CodeGenerator<'a> {
|
||||||
&names_types,
|
&names_types,
|
||||||
false,
|
false,
|
||||||
term,
|
term,
|
||||||
is_expect,
|
|
||||||
false,
|
false,
|
||||||
|
is_expect.into(),
|
||||||
error_term,
|
error_term,
|
||||||
)
|
)
|
||||||
.apply(value);
|
.apply(value);
|
||||||
|
|
|
@ -7,6 +7,23 @@ use crate::{
|
||||||
tipo::{Type, ValueConstructor},
|
tipo::{Type, ValueConstructor},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
|
pub enum ExpectLevel {
|
||||||
|
Full,
|
||||||
|
Items,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for ExpectLevel {
|
||||||
|
fn from(value: bool) -> Self {
|
||||||
|
if value {
|
||||||
|
ExpectLevel::Full
|
||||||
|
} else {
|
||||||
|
ExpectLevel::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Air {
|
pub enum Air {
|
||||||
// Primitives
|
// Primitives
|
||||||
|
@ -83,6 +100,7 @@ pub enum Air {
|
||||||
},
|
},
|
||||||
CastFromData {
|
CastFromData {
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
|
is_expect: bool,
|
||||||
},
|
},
|
||||||
CastToData {
|
CastToData {
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
|
@ -159,7 +177,7 @@ pub enum Air {
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
names: Vec<String>,
|
names: Vec<String>,
|
||||||
tail: bool,
|
tail: bool,
|
||||||
is_expect: bool,
|
expect_level: ExpectLevel,
|
||||||
},
|
},
|
||||||
ListExpose {
|
ListExpose {
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
|
|
|
@ -30,7 +30,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
air::Air,
|
air::{Air, ExpectLevel},
|
||||||
tree::{AirExpression, AirMsg, AirStatement, AirTree, TreePath},
|
tree::{AirExpression, AirMsg, AirStatement, AirTree, TreePath},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1237,6 +1237,140 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Rc<Type>) -> Term<Nam
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn convert_data_to_type_debug(
|
||||||
|
term: Term<Name>,
|
||||||
|
field_type: &Rc<Type>,
|
||||||
|
error_term: Term<Name>,
|
||||||
|
) -> Term<Name> {
|
||||||
|
if field_type.is_int() {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
Term::un_i_data().apply(Term::var("__val")),
|
||||||
|
error_term.clone(),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_bytearray() {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
Term::un_b_data().apply(Term::var("__val")),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_void() {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
Term::equals_integer()
|
||||||
|
.apply(Term::integer(0.into()))
|
||||||
|
.apply(Term::fst_pair().apply(Term::unconstr_data().apply(Term::var("__val"))))
|
||||||
|
.delayed_if_then_else(Term::unit(), Term::Error),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_map() {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
error_term.clone(),
|
||||||
|
Term::unmap_data().apply(Term::var("__val")),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_string() {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
Term::Builtin(DefaultFunction::DecodeUtf8)
|
||||||
|
.apply(Term::un_b_data().apply(Term::var("__val"))),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_tuple() && matches!(field_type.get_uplc_type(), UplcType::Pair(_, _)) {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
Term::mk_pair_data()
|
||||||
|
.apply(Term::head_list().apply(Term::var("__list_data")))
|
||||||
|
.apply(Term::head_list().apply(Term::var("__tail")))
|
||||||
|
.lambda("__tail")
|
||||||
|
.apply(Term::tail_list().apply(Term::var("__list_data")))
|
||||||
|
.lambda("__list_data")
|
||||||
|
.apply(Term::unlist_data().apply(Term::var("__val"))),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_list() || field_type.is_tuple() {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
Term::unlist_data().apply(Term::var("__val")),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_bool() {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
Term::equals_integer()
|
||||||
|
.apply(Term::integer(1.into()))
|
||||||
|
.apply(Term::fst_pair().apply(Term::unconstr_data().apply(Term::var("__val")))),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_bls381_12_g1() {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
Term::bls12_381_g1_uncompress().apply(Term::un_b_data().apply(Term::var("__val"))),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_bls381_12_g2() {
|
||||||
|
Term::var("__val")
|
||||||
|
.delayed_choose_data(
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
error_term.clone(),
|
||||||
|
Term::bls12_381_g2_uncompress().apply(Term::un_b_data().apply(Term::var("__val"))),
|
||||||
|
)
|
||||||
|
.lambda("__val")
|
||||||
|
.apply(term)
|
||||||
|
} else if field_type.is_ml_result() {
|
||||||
|
panic!("ML Result not supported")
|
||||||
|
} else {
|
||||||
|
term
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn convert_constants_to_data(constants: Vec<Rc<UplcConstant>>) -> Vec<UplcConstant> {
|
pub fn convert_constants_to_data(constants: Vec<Rc<UplcConstant>>) -> Vec<UplcConstant> {
|
||||||
let mut new_constants = vec![];
|
let mut new_constants = vec![];
|
||||||
for constant in constants {
|
for constant in constants {
|
||||||
|
@ -1391,8 +1525,8 @@ pub fn list_access_to_uplc(
|
||||||
names_types_ids: &[(String, Rc<Type>, u64)],
|
names_types_ids: &[(String, Rc<Type>, u64)],
|
||||||
tail: bool,
|
tail: bool,
|
||||||
term: Term<Name>,
|
term: Term<Name>,
|
||||||
check_last_item: bool,
|
|
||||||
is_list_accessor: bool,
|
is_list_accessor: bool,
|
||||||
|
expect_level: ExpectLevel,
|
||||||
error_term: Term<Name>,
|
error_term: Term<Name>,
|
||||||
) -> Term<Name> {
|
) -> Term<Name> {
|
||||||
let names_len = names_types_ids.len();
|
let names_len = names_types_ids.len();
|
||||||
|
@ -1404,7 +1538,10 @@ pub fn list_access_to_uplc(
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
// If the the is just discards and check_last_item then we check for empty list
|
// If the the is just discards and check_last_item then we check for empty list
|
||||||
if no_tailing_discards.is_empty() && !tail && check_last_item {
|
if no_tailing_discards.is_empty()
|
||||||
|
&& !tail
|
||||||
|
&& matches!(expect_level, ExpectLevel::Full | ExpectLevel::Items)
|
||||||
|
{
|
||||||
return Term::var("empty_list")
|
return Term::var("empty_list")
|
||||||
.delayed_choose_list(term, error_term)
|
.delayed_choose_list(term, error_term)
|
||||||
.lambda("empty_list");
|
.lambda("empty_list");
|
||||||
|
@ -1426,6 +1563,12 @@ pub fn list_access_to_uplc(
|
||||||
let head_list =
|
let head_list =
|
||||||
if matches!(tipo.get_uplc_type(), UplcType::Pair(_, _)) && is_list_accessor {
|
if matches!(tipo.get_uplc_type(), UplcType::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) && error_term != Term::Error {
|
||||||
|
convert_data_to_type_debug(
|
||||||
|
Term::head_list().apply(Term::var(tail_name.to_string())),
|
||||||
|
&tipo.to_owned(),
|
||||||
|
error_term.clone(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
convert_data_to_type(
|
convert_data_to_type(
|
||||||
Term::head_list().apply(Term::var(tail_name.to_string())),
|
Term::head_list().apply(Term::var(tail_name.to_string())),
|
||||||
|
@ -1442,7 +1585,7 @@ pub fn list_access_to_uplc(
|
||||||
// case for no tail
|
// case for no tail
|
||||||
// name is guaranteed to not be discard at this point
|
// name is guaranteed to not be discard at this point
|
||||||
|
|
||||||
if check_last_item {
|
if matches!(expect_level, ExpectLevel::Full | ExpectLevel::Items) {
|
||||||
Term::tail_list()
|
Term::tail_list()
|
||||||
.apply(Term::var(tail_name.to_string()))
|
.apply(Term::var(tail_name.to_string()))
|
||||||
.delayed_choose_list(acc, error_term.clone())
|
.delayed_choose_list(acc, error_term.clone())
|
||||||
|
@ -1453,8 +1596,30 @@ pub fn list_access_to_uplc(
|
||||||
acc.lambda(name).apply(head_list).lambda(tail_name)
|
acc.lambda(name).apply(head_list).lambda(tail_name)
|
||||||
}
|
}
|
||||||
} else if name == "_" {
|
} else if name == "_" {
|
||||||
|
if matches!(expect_level, ExpectLevel::Full | ExpectLevel::Items)
|
||||||
|
&& error_term != Term::Error
|
||||||
|
{
|
||||||
|
Term::var(tail_name.to_string())
|
||||||
|
.delayed_choose_list(
|
||||||
|
error_term.clone(),
|
||||||
|
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string()))),
|
||||||
|
)
|
||||||
|
.lambda(tail_name)
|
||||||
|
} else {
|
||||||
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string())))
|
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string())))
|
||||||
.lambda(tail_name)
|
.lambda(tail_name)
|
||||||
|
}
|
||||||
|
} else if matches!(expect_level, ExpectLevel::Full | ExpectLevel::Items)
|
||||||
|
&& error_term != Term::Error
|
||||||
|
{
|
||||||
|
Term::var(tail_name.to_string())
|
||||||
|
.delayed_choose_list(
|
||||||
|
error_term.clone(),
|
||||||
|
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string())))
|
||||||
|
.lambda(name)
|
||||||
|
.apply(head_list),
|
||||||
|
)
|
||||||
|
.lambda(tail_name)
|
||||||
} else {
|
} else {
|
||||||
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string())))
|
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string())))
|
||||||
.lambda(name)
|
.lambda(name)
|
||||||
|
@ -1791,9 +1956,14 @@ pub fn air_holds_msg(air: &Air) -> bool {
|
||||||
Air::AssertConstr { .. } | Air::AssertBool { .. } | Air::FieldsEmpty | Air::ListEmpty => {
|
Air::AssertConstr { .. } | Air::AssertBool { .. } | Air::FieldsEmpty | Air::ListEmpty => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
Air::FieldsExpose { is_expect, .. }
|
Air::FieldsExpose { is_expect, .. }
|
||||||
| Air::ListAccessor { is_expect, .. }
|
| Air::TupleAccessor { is_expect, .. }
|
||||||
| Air::TupleAccessor { is_expect, .. } => *is_expect,
|
| Air::CastFromData { is_expect, .. } => *is_expect,
|
||||||
|
|
||||||
|
Air::ListAccessor { expect_level, .. } => {
|
||||||
|
matches!(expect_level, ExpectLevel::Full | ExpectLevel::Items)
|
||||||
|
}
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
tipo::{Type, ValueConstructor, ValueConstructorVariant},
|
tipo::{Type, ValueConstructor, ValueConstructorVariant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::air::Air;
|
use super::air::{Air, ExpectLevel};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct TreePath {
|
pub struct TreePath {
|
||||||
|
@ -179,7 +179,7 @@ pub enum AirStatement {
|
||||||
names: Vec<String>,
|
names: Vec<String>,
|
||||||
tail: bool,
|
tail: bool,
|
||||||
list: Box<AirTree>,
|
list: Box<AirTree>,
|
||||||
is_expect: bool,
|
expect_level: ExpectLevel,
|
||||||
msg: Option<AirMsg>,
|
msg: Option<AirMsg>,
|
||||||
},
|
},
|
||||||
ListExpose {
|
ListExpose {
|
||||||
|
@ -272,6 +272,7 @@ pub enum AirExpression {
|
||||||
CastFromData {
|
CastFromData {
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
value: Box<AirTree>,
|
value: Box<AirTree>,
|
||||||
|
msg: Option<AirMsg>,
|
||||||
},
|
},
|
||||||
CastToData {
|
CastToData {
|
||||||
tipo: Rc<Type>,
|
tipo: Rc<Type>,
|
||||||
|
@ -502,10 +503,11 @@ impl AirTree {
|
||||||
hoisted_over: None,
|
hoisted_over: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn cast_from_data(value: AirTree, tipo: Rc<Type>) -> AirTree {
|
pub fn cast_from_data(value: AirTree, tipo: Rc<Type>, msg: Option<AirMsg>) -> AirTree {
|
||||||
AirTree::Expression(AirExpression::CastFromData {
|
AirTree::Expression(AirExpression::CastFromData {
|
||||||
tipo,
|
tipo,
|
||||||
value: value.into(),
|
value: value.into(),
|
||||||
|
msg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn cast_to_data(value: AirTree, tipo: Rc<Type>) -> AirTree {
|
pub fn cast_to_data(value: AirTree, tipo: Rc<Type>) -> AirTree {
|
||||||
|
@ -733,6 +735,7 @@ impl AirTree {
|
||||||
vec![list_of_fields],
|
vec![list_of_fields],
|
||||||
),
|
),
|
||||||
tipo.clone(),
|
tipo.clone(),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,7 +761,7 @@ impl AirTree {
|
||||||
tail: bool,
|
tail: bool,
|
||||||
list: AirTree,
|
list: AirTree,
|
||||||
msg: Option<AirMsg>,
|
msg: Option<AirMsg>,
|
||||||
is_expect: bool,
|
expect_level: ExpectLevel,
|
||||||
) -> AirTree {
|
) -> AirTree {
|
||||||
AirTree::Statement {
|
AirTree::Statement {
|
||||||
statement: AirStatement::ListAccessor {
|
statement: AirStatement::ListAccessor {
|
||||||
|
@ -766,7 +769,7 @@ impl AirTree {
|
||||||
names,
|
names,
|
||||||
tail,
|
tail,
|
||||||
list: list.into(),
|
list: list.into(),
|
||||||
is_expect,
|
expect_level,
|
||||||
msg,
|
msg,
|
||||||
},
|
},
|
||||||
hoisted_over: None,
|
hoisted_over: None,
|
||||||
|
@ -816,6 +819,7 @@ impl AirTree {
|
||||||
vec![tuple],
|
vec![tuple],
|
||||||
),
|
),
|
||||||
tipo.clone(),
|
tipo.clone(),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn error(tipo: Rc<Type>, validator: bool) -> AirTree {
|
pub fn error(tipo: Rc<Type>, validator: bool) -> AirTree {
|
||||||
|
@ -1069,13 +1073,13 @@ impl AirTree {
|
||||||
tail,
|
tail,
|
||||||
list,
|
list,
|
||||||
msg,
|
msg,
|
||||||
is_expect,
|
expect_level,
|
||||||
} => {
|
} => {
|
||||||
air_vec.push(Air::ListAccessor {
|
air_vec.push(Air::ListAccessor {
|
||||||
tipo: tipo.clone(),
|
tipo: tipo.clone(),
|
||||||
names: names.clone(),
|
names: names.clone(),
|
||||||
tail: *tail,
|
tail: *tail,
|
||||||
is_expect: *is_expect,
|
expect_level: *expect_level,
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(msg) = msg {
|
if let Some(msg) = msg {
|
||||||
|
@ -1227,8 +1231,16 @@ impl AirTree {
|
||||||
air_vec.push(Air::UnOp { op: *op });
|
air_vec.push(Air::UnOp { op: *op });
|
||||||
arg.create_air_vec(air_vec);
|
arg.create_air_vec(air_vec);
|
||||||
}
|
}
|
||||||
AirExpression::CastFromData { tipo, value } => {
|
AirExpression::CastFromData { tipo, value, msg } => {
|
||||||
air_vec.push(Air::CastFromData { tipo: tipo.clone() });
|
air_vec.push(Air::CastFromData {
|
||||||
|
tipo: tipo.clone(),
|
||||||
|
is_expect: msg.is_some(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(msg) = msg {
|
||||||
|
msg.to_air_tree().create_air_vec(air_vec);
|
||||||
|
}
|
||||||
|
|
||||||
value.create_air_vec(air_vec);
|
value.create_air_vec(air_vec);
|
||||||
}
|
}
|
||||||
AirExpression::CastToData { tipo, value } => {
|
AirExpression::CastToData { tipo, value } => {
|
||||||
|
|
Loading…
Reference in New Issue