feat: expects now print the line of code that failed
This commit is contained in:
parent
412945af3a
commit
355e38d6e2
|
@ -29,7 +29,7 @@ use crate::{
|
|||
find_and_replace_generics, find_list_clause_or_default_first, get_arg_type_name,
|
||||
get_generic_id_and_type, get_src_code_by_span, get_variant_name, monomorphize,
|
||||
pattern_has_conditions, wrap_as_multi_validator, wrap_validator_condition, CodeGenFunction,
|
||||
SpecificClause, CONSTR_INDEX_MISMATCH,
|
||||
SpecificClause,
|
||||
},
|
||||
tipo::{
|
||||
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
|
||||
|
@ -44,8 +44,7 @@ use self::{
|
|||
cast_validator_args, constants_ir, convert_type_to_data, extract_constant,
|
||||
lookup_data_type_by_tipo, modify_cyclic_calls, modify_self_calls, rearrange_list_clauses,
|
||||
AssignmentProperties, ClauseProperties, CodeGenSpecialFuncs, CycleFunctionNames,
|
||||
DataTypeKey, FunctionAccessKey, HoistableFunction, Variant, CONSTR_NOT_EMPTY,
|
||||
LIST_NOT_EMPTY, TOO_MANY_ITEMS,
|
||||
DataTypeKey, FunctionAccessKey, HoistableFunction, Variant,
|
||||
},
|
||||
tree::{AirExpression, AirTree, TreePath},
|
||||
};
|
||||
|
@ -133,7 +132,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
air_tree_fun = wrap_validator_condition(air_tree_fun, self.tracing);
|
||||
|
||||
let mut validator_args_tree = self.check_validator_args(&fun.arguments, true, air_tree_fun);
|
||||
let src_code = self.module_src.get(module_name).unwrap().clone();
|
||||
|
||||
let mut validator_args_tree =
|
||||
self.check_validator_args(&fun.arguments, true, air_tree_fun, &src_code);
|
||||
|
||||
validator_args_tree = AirTree::no_op().hoist_over(validator_args_tree);
|
||||
|
||||
|
@ -153,7 +155,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
air_tree_fun_other = wrap_validator_condition(air_tree_fun_other, self.tracing);
|
||||
|
||||
let mut validator_args_tree_other =
|
||||
self.check_validator_args(&other.arguments, true, air_tree_fun_other);
|
||||
self.check_validator_args(&other.arguments, true, air_tree_fun_other, &src_code);
|
||||
|
||||
validator_args_tree_other = AirTree::no_op().hoist_over(validator_args_tree_other);
|
||||
|
||||
|
@ -173,8 +175,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
};
|
||||
|
||||
// Special Case with multi_validators
|
||||
self.special_functions.use_function(CONSTR_FIELDS_EXPOSER);
|
||||
self.special_functions.use_function(CONSTR_INDEX_EXPOSER);
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string());
|
||||
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_INDEX_EXPOSER.to_string());
|
||||
|
||||
term = wrap_as_multi_validator(spend, mint, self.tracing, spend_name, mint_name);
|
||||
}
|
||||
|
@ -463,6 +468,22 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let air_value = self.build(value, module_name);
|
||||
|
||||
let msg = get_src_code_by_span(module_name, location, &self.module_src);
|
||||
|
||||
let msg_func_name = msg.split_whitespace().join("");
|
||||
|
||||
self.special_functions.insert_new_function(
|
||||
msg_func_name.clone(),
|
||||
Term::string(msg),
|
||||
string(),
|
||||
);
|
||||
|
||||
let msg_func = if self.tracing {
|
||||
self.special_functions.use_function_tree(msg_func_name)
|
||||
} else {
|
||||
AirTree::no_op()
|
||||
};
|
||||
|
||||
self.assignment(
|
||||
pattern,
|
||||
air_value,
|
||||
|
@ -472,8 +493,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: *kind,
|
||||
remove_unused: kind.is_let(),
|
||||
full_check: !tipo.is_data() && value.tipo().is_data() && kind.is_expect(),
|
||||
location: *location,
|
||||
module_name: module_name.clone(),
|
||||
msg_func,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -514,8 +534,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: AssignmentKind::Let,
|
||||
remove_unused: false,
|
||||
full_check: false,
|
||||
location: Span::empty(),
|
||||
module_name: module_name.clone(),
|
||||
msg_func: AirTree::no_op(),
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -621,10 +640,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
|
||||
let list_of_fields = AirTree::call(
|
||||
AirTree::local_var(
|
||||
self.special_functions.use_function(CONSTR_FIELDS_EXPOSER),
|
||||
void(),
|
||||
),
|
||||
self.special_functions
|
||||
.use_function_tree(CONSTR_FIELDS_EXPOSER.to_string()),
|
||||
list(data()),
|
||||
vec![self.build(record, module_name)],
|
||||
);
|
||||
|
@ -828,10 +845,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(name, int()),
|
||||
int(),
|
||||
);
|
||||
let msg =
|
||||
get_src_code_by_span(&props.module_name, &props.location, &self.module_src);
|
||||
|
||||
AirTree::assert_bool(true, assignment.hoist_over(expect), msg)
|
||||
AirTree::assert_bool(true, assignment.hoist_over(expect), props.msg_func.clone())
|
||||
}
|
||||
Pattern::Var { name, .. } => {
|
||||
if props.full_check {
|
||||
|
@ -851,6 +866,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
val,
|
||||
&mut index_map,
|
||||
pattern.location(),
|
||||
props.msg_func,
|
||||
);
|
||||
|
||||
let assign_expect = AirTree::let_assignment("_", expect);
|
||||
|
@ -890,6 +906,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
val,
|
||||
&mut index_map,
|
||||
pattern.location(),
|
||||
props.msg_func,
|
||||
);
|
||||
|
||||
let assign_expect = AirTree::let_assignment("_", expect);
|
||||
|
@ -948,8 +965,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
location: props.location,
|
||||
module_name: props.module_name.clone(),
|
||||
msg_func: props.msg_func.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -991,8 +1007,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
location: props.location,
|
||||
module_name: props.module_name.clone(),
|
||||
msg_func: props.msg_func.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -1005,9 +1020,15 @@ impl<'a> CodeGenerator<'a> {
|
|||
let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec();
|
||||
|
||||
let list_access = if elements.is_empty() {
|
||||
AirTree::list_empty(value)
|
||||
AirTree::list_empty(value, props.msg_func)
|
||||
} else {
|
||||
AirTree::list_access(names, tipo.clone(), tail.is_some(), tail.is_none(), value)
|
||||
AirTree::list_access(
|
||||
names,
|
||||
tipo.clone(),
|
||||
tail.is_some(),
|
||||
value,
|
||||
Some(props.msg_func),
|
||||
)
|
||||
};
|
||||
|
||||
let mut sequence = vec![list_access];
|
||||
|
@ -1027,10 +1048,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
if tipo.is_bool() {
|
||||
assert!(props.kind.is_expect());
|
||||
|
||||
let msg =
|
||||
get_src_code_by_span(&props.module_name, &props.location, &self.module_src);
|
||||
|
||||
AirTree::assert_bool(name == "True", value, msg)
|
||||
AirTree::assert_bool(name == "True", value, props.msg_func)
|
||||
} else if tipo.is_void() {
|
||||
AirTree::let_assignment("_", value)
|
||||
} else {
|
||||
|
@ -1062,16 +1080,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
sequence.push(constructor_val);
|
||||
|
||||
let msg = get_src_code_by_span(
|
||||
&props.module_name,
|
||||
&props.location,
|
||||
&self.module_src,
|
||||
);
|
||||
|
||||
let assert_constr = AirTree::assert_constr_index(
|
||||
index,
|
||||
AirTree::local_var(&constructor_name, tipo.clone()),
|
||||
msg,
|
||||
props.msg_func.clone(),
|
||||
);
|
||||
|
||||
sequence.push(assert_constr);
|
||||
|
@ -1147,8 +1159,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
location: props.location,
|
||||
module_name: props.module_name.clone(),
|
||||
msg_func: props.msg_func.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -1169,7 +1180,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
if check_replaceable_opaque_type(tipo, &self.data_types) {
|
||||
sequence.push(AirTree::let_assignment(&indices[0].1, value));
|
||||
} else {
|
||||
sequence.push(AirTree::fields_expose(indices, props.full_check, value));
|
||||
let msg = if props.full_check {
|
||||
Some(props.msg_func)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
sequence.push(AirTree::fields_expose(indices, value, msg));
|
||||
}
|
||||
|
||||
sequence.append(
|
||||
|
@ -1237,8 +1253,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
location: props.location,
|
||||
module_name: props.module_name.clone(),
|
||||
msg_func: props.msg_func.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -1251,14 +1266,15 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let indices = elems.iter().map(|(name, _)| name.to_string()).collect_vec();
|
||||
|
||||
let msg = if props.full_check {
|
||||
Some(props.msg_func)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// This `value` is either value param that was passed in or
|
||||
// local var
|
||||
sequence.push(AirTree::tuple_access(
|
||||
indices,
|
||||
tipo.clone(),
|
||||
props.full_check,
|
||||
value,
|
||||
));
|
||||
sequence.push(AirTree::tuple_access(indices, tipo.clone(), value, msg));
|
||||
|
||||
sequence.append(&mut elems.into_iter().map(|(_, field)| field).collect_vec());
|
||||
|
||||
|
@ -1273,6 +1289,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
value: AirTree,
|
||||
defined_data_types: &mut IndexMap<String, u64>,
|
||||
location: Span,
|
||||
msg_func: AirTree,
|
||||
) -> AirTree {
|
||||
assert!(tipo.get_generic().is_none());
|
||||
let tipo = &convert_opaque_type(tipo, &self.data_types);
|
||||
|
@ -1298,8 +1315,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
let tuple_access = AirTree::tuple_access(
|
||||
vec![fst_name.clone(), snd_name.clone()],
|
||||
inner_list_type.clone(),
|
||||
false,
|
||||
AirTree::local_var(&pair_name, inner_list_type.clone()),
|
||||
None,
|
||||
);
|
||||
|
||||
let expect_fst = self.expect_type_assign(
|
||||
|
@ -1307,6 +1324,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(fst_name, inner_pair_types[0].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
);
|
||||
|
||||
let expect_snd = self.expect_type_assign(
|
||||
|
@ -1314,6 +1332,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(snd_name, inner_pair_types[1].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
);
|
||||
|
||||
let anon_func_body = AirTree::UnhoistedSequence(vec![
|
||||
|
@ -1385,6 +1404,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func,
|
||||
);
|
||||
|
||||
let anon_func_body = expect_item;
|
||||
|
@ -1447,8 +1467,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
let tuple_access = AirTree::tuple_access(
|
||||
vec![fst_name.clone(), snd_name.clone()],
|
||||
tipo.clone(),
|
||||
false,
|
||||
AirTree::local_var(pair_name, tipo.clone()),
|
||||
None,
|
||||
);
|
||||
|
||||
let expect_fst = self.expect_type_assign(
|
||||
|
@ -1456,6 +1476,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(fst_name, tuple_inner_types[0].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
);
|
||||
|
||||
let expect_snd = self.expect_type_assign(
|
||||
|
@ -1463,6 +1484,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(snd_name, tuple_inner_types[1].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func,
|
||||
);
|
||||
|
||||
AirTree::UnhoistedSequence(vec![
|
||||
|
@ -1493,6 +1515,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(&tuple_index_name, arg.clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
);
|
||||
|
||||
(
|
||||
|
@ -1510,8 +1533,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
let tuple_access = AirTree::tuple_access(
|
||||
tuple_index_names,
|
||||
tipo.clone(),
|
||||
true,
|
||||
AirTree::local_var(tuple_name, tipo.clone()),
|
||||
Some(msg_func),
|
||||
);
|
||||
|
||||
let mut tuple_expects = tuple_expect_items
|
||||
|
@ -1553,10 +1576,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let error_term = if self.tracing {
|
||||
AirTree::trace(
|
||||
AirTree::local_var(
|
||||
self.special_functions.use_function(CONSTR_INDEX_MISMATCH),
|
||||
string(),
|
||||
),
|
||||
msg_func.clone(),
|
||||
tipo.clone(),
|
||||
AirTree::error(tipo.clone(), false),
|
||||
)
|
||||
|
@ -1590,6 +1610,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(&arg_name, arg_tipo.clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -1610,16 +1631,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
.collect_vec();
|
||||
|
||||
if assigns.is_empty() {
|
||||
let empty = AirTree::fields_empty(AirTree::local_var(
|
||||
format!("__constr_var_span_{}_{}", location.start, location.end),
|
||||
tipo.clone(),
|
||||
));
|
||||
|
||||
assigns.insert(0, empty);
|
||||
} else {
|
||||
let expose = AirTree::fields_expose(
|
||||
indices,
|
||||
true,
|
||||
let empty = AirTree::fields_empty(
|
||||
AirTree::local_var(
|
||||
format!(
|
||||
"__constr_var_span_{}_{}",
|
||||
|
@ -1627,6 +1639,21 @@ impl<'a> CodeGenerator<'a> {
|
|||
),
|
||||
tipo.clone(),
|
||||
),
|
||||
msg_func.clone(),
|
||||
);
|
||||
|
||||
assigns.insert(0, empty);
|
||||
} else {
|
||||
let expose = AirTree::fields_expose(
|
||||
indices,
|
||||
AirTree::local_var(
|
||||
format!(
|
||||
"__constr_var_span_{}_{}",
|
||||
location.start, location.end
|
||||
),
|
||||
tipo.clone(),
|
||||
),
|
||||
Some(msg_func.clone()),
|
||||
);
|
||||
|
||||
assigns.insert(0, expose);
|
||||
|
@ -2205,8 +2232,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
defined_heads,
|
||||
subject_tipo.clone(),
|
||||
tail.is_some(),
|
||||
false,
|
||||
AirTree::local_var(&props.original_subject_name, subject_tipo.clone()),
|
||||
// One special usage of list access here
|
||||
// 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
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
assert!(defined_tails.len() >= defined_heads.len());
|
||||
|
@ -2345,11 +2375,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
} else {
|
||||
AirTree::fields_expose(
|
||||
indices,
|
||||
false,
|
||||
AirTree::local_var(
|
||||
props.clause_var_name.clone(),
|
||||
subject_tipo.clone(),
|
||||
),
|
||||
None,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -2482,8 +2512,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::tuple_access(
|
||||
names,
|
||||
subject_tipo.clone(),
|
||||
false,
|
||||
AirTree::local_var(&props.original_subject_name, subject_tipo.clone()),
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -2668,17 +2698,39 @@ impl<'a> CodeGenerator<'a> {
|
|||
arguments: &[TypedArg],
|
||||
has_context: bool,
|
||||
body: AirTree,
|
||||
src_code: &str,
|
||||
) -> AirTree {
|
||||
let checked_args = arguments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, arg)| {
|
||||
let arg_name = arg.arg_name.get_variable_name().unwrap_or("_").to_string();
|
||||
let arg_span = arg.location;
|
||||
|
||||
if !(has_context && index == arguments.len() - 1) && &arg_name != "_" {
|
||||
let param = AirTree::local_var(&arg_name, data());
|
||||
|
||||
let actual_type = convert_opaque_type(&arg.tipo, &self.data_types);
|
||||
|
||||
let msg = src_code
|
||||
.get(arg_span.start..arg_span.end)
|
||||
.expect("Out of bounds span")
|
||||
.to_string();
|
||||
|
||||
let msg_func_name = msg.split_whitespace().join("");
|
||||
|
||||
self.special_functions.insert_new_function(
|
||||
msg_func_name.to_string(),
|
||||
Term::string(msg),
|
||||
string(),
|
||||
);
|
||||
|
||||
let msg_func = if self.tracing {
|
||||
self.special_functions.use_function_tree(msg_func_name)
|
||||
} else {
|
||||
AirTree::no_op()
|
||||
};
|
||||
|
||||
let assign = self.assignment(
|
||||
&Pattern::Var {
|
||||
location: Span::empty(),
|
||||
|
@ -2691,8 +2743,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: AssignmentKind::Expect,
|
||||
remove_unused: false,
|
||||
full_check: true,
|
||||
location: Span::empty(),
|
||||
module_name: String::new(),
|
||||
msg_func,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -3911,9 +3962,17 @@ impl<'a> CodeGenerator<'a> {
|
|||
// tipo here refers to the list type while the actual return
|
||||
// type is nothing since this is an assignment over some expression
|
||||
tipo,
|
||||
check_last_item,
|
||||
is_expect,
|
||||
} => {
|
||||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let error_term = if self.tracing && is_expect {
|
||||
let msg = arg_stack.pop().unwrap();
|
||||
Term::Error.delayed_trace(msg)
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
let list_id = self.id_gen.next();
|
||||
|
@ -3937,37 +3996,21 @@ impl<'a> CodeGenerator<'a> {
|
|||
.collect_vec();
|
||||
|
||||
if !names_empty {
|
||||
let error_term = if self.tracing {
|
||||
Term::Error.delayed_trace(Term::var(
|
||||
self.special_functions.use_function(TOO_MANY_ITEMS),
|
||||
))
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
term = builder::list_access_to_uplc(
|
||||
&names_types,
|
||||
&id_list,
|
||||
tail,
|
||||
0,
|
||||
term,
|
||||
check_last_item,
|
||||
is_expect && !tail,
|
||||
true,
|
||||
error_term,
|
||||
)
|
||||
.apply(value);
|
||||
|
||||
arg_stack.push(term);
|
||||
} else if check_last_item {
|
||||
let trace_term = if self.tracing {
|
||||
Term::Error.delayed_trace(Term::var(
|
||||
self.special_functions.use_function(LIST_NOT_EMPTY),
|
||||
))
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
term = value.delayed_choose_list(term, trace_term);
|
||||
} else if is_expect {
|
||||
term = value.delayed_choose_list(term, error_term);
|
||||
|
||||
arg_stack.push(term);
|
||||
} else {
|
||||
|
@ -4449,37 +4492,44 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
arg_stack.push(term);
|
||||
}
|
||||
Air::AssertConstr { constr_index, msg } => {
|
||||
Air::AssertConstr { constr_index } => {
|
||||
let constr = arg_stack.pop().unwrap();
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
let trace_term = if self.tracing {
|
||||
Term::Error.delayed_trace(Term::string(msg))
|
||||
let msg = arg_stack.pop().unwrap();
|
||||
Term::Error.delayed_trace(msg)
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
term = Term::equals_integer()
|
||||
.apply(Term::integer(constr_index.into()))
|
||||
.apply(
|
||||
Term::var(self.special_functions.use_function(CONSTR_INDEX_EXPOSER))
|
||||
Term::var(
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_INDEX_EXPOSER.to_string()),
|
||||
)
|
||||
.apply(constr),
|
||||
)
|
||||
.delayed_if_then_else(term, trace_term);
|
||||
|
||||
arg_stack.push(term);
|
||||
}
|
||||
Air::AssertBool { is_true, msg } => {
|
||||
Air::AssertBool { is_true } => {
|
||||
let value = arg_stack.pop().unwrap();
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
let trace_term = if self.tracing {
|
||||
Term::Error.delayed_trace(Term::string(msg))
|
||||
let msg = arg_stack.pop().unwrap();
|
||||
|
||||
Term::Error.delayed_trace(msg)
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
if is_true {
|
||||
term = value.delayed_if_then_else(term, trace_term)
|
||||
} else {
|
||||
|
@ -4504,7 +4554,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
{
|
||||
subject
|
||||
} else {
|
||||
Term::var(self.special_functions.use_function(CONSTR_INDEX_EXPOSER))
|
||||
Term::var(
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_INDEX_EXPOSER.to_string()),
|
||||
)
|
||||
.apply(subject)
|
||||
};
|
||||
|
||||
|
@ -4710,7 +4763,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
unreachable!()
|
||||
} else {
|
||||
Term::equals_integer().apply(checker).apply(
|
||||
Term::var(self.special_functions.use_function(CONSTR_INDEX_EXPOSER))
|
||||
Term::var(
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_INDEX_EXPOSER.to_string()),
|
||||
)
|
||||
.apply(Term::var(subject_name)),
|
||||
)
|
||||
};
|
||||
|
@ -4850,13 +4906,18 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
arg_stack.push(term);
|
||||
}
|
||||
Air::FieldsExpose {
|
||||
indices,
|
||||
check_last_item,
|
||||
} => {
|
||||
Air::FieldsExpose { indices, is_expect } => {
|
||||
let mut id_list = vec![];
|
||||
|
||||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let error_term = if self.tracing && is_expect {
|
||||
let msg = arg_stack.pop().unwrap();
|
||||
Term::Error.delayed_trace(msg)
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
let list_id = self.id_gen.next();
|
||||
|
||||
|
@ -4875,43 +4936,33 @@ impl<'a> CodeGenerator<'a> {
|
|||
.collect_vec();
|
||||
|
||||
if !indices.is_empty() {
|
||||
let error_term = if self.tracing {
|
||||
Term::Error.delayed_trace(Term::var(
|
||||
self.special_functions.use_function(TOO_MANY_ITEMS),
|
||||
))
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
term = builder::list_access_to_uplc(
|
||||
&names_types,
|
||||
&id_list,
|
||||
false,
|
||||
current_index,
|
||||
term,
|
||||
check_last_item,
|
||||
is_expect,
|
||||
false,
|
||||
error_term,
|
||||
);
|
||||
|
||||
term = term.apply(
|
||||
Term::var(self.special_functions.use_function(CONSTR_FIELDS_EXPOSER))
|
||||
Term::var(
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
|
||||
)
|
||||
.apply(value),
|
||||
);
|
||||
|
||||
arg_stack.push(term);
|
||||
} else if check_last_item {
|
||||
let trace_term = if self.tracing {
|
||||
Term::Error.delayed_trace(Term::var(
|
||||
self.special_functions.use_function(CONSTR_NOT_EMPTY),
|
||||
))
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
term = Term::var(self.special_functions.use_function(CONSTR_FIELDS_EXPOSER))
|
||||
} else if is_expect {
|
||||
term = Term::var(
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
|
||||
)
|
||||
.apply(value)
|
||||
.delayed_choose_list(term, trace_term);
|
||||
.delayed_choose_list(term, error_term);
|
||||
|
||||
arg_stack.push(term);
|
||||
} else {
|
||||
|
@ -4920,35 +4971,38 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
Air::FieldsEmpty => {
|
||||
let value = arg_stack.pop().unwrap();
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
let trace_term = if self.tracing {
|
||||
Term::Error.delayed_trace(Term::var(
|
||||
self.special_functions.use_function(CONSTR_NOT_EMPTY),
|
||||
))
|
||||
let error_term = if self.tracing {
|
||||
let msg = arg_stack.pop().unwrap();
|
||||
Term::Error.delayed_trace(msg)
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
term = Term::var(self.special_functions.use_function(CONSTR_FIELDS_EXPOSER))
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
term = Term::var(
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
|
||||
)
|
||||
.apply(value)
|
||||
.delayed_choose_list(term, trace_term);
|
||||
.delayed_choose_list(term, error_term);
|
||||
|
||||
arg_stack.push(term);
|
||||
}
|
||||
Air::ListEmpty => {
|
||||
let value = arg_stack.pop().unwrap();
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
let trace_term = if self.tracing {
|
||||
Term::Error.delayed_trace(Term::var(
|
||||
self.special_functions.use_function(LIST_NOT_EMPTY),
|
||||
))
|
||||
let error_term = if self.tracing {
|
||||
let msg = arg_stack.pop().unwrap();
|
||||
Term::Error.delayed_trace(msg)
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
term = value.delayed_choose_list(term, trace_term);
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
term = value.delayed_choose_list(term, error_term);
|
||||
|
||||
arg_stack.push(term);
|
||||
}
|
||||
|
@ -5095,7 +5149,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
|
||||
term = term.lambda(format!("{tail_name_prefix}_0")).apply(
|
||||
Term::var(self.special_functions.use_function(CONSTR_FIELDS_EXPOSER))
|
||||
Term::var(
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
|
||||
)
|
||||
.apply(record),
|
||||
);
|
||||
|
||||
|
@ -5128,10 +5185,18 @@ impl<'a> CodeGenerator<'a> {
|
|||
Air::TupleAccessor {
|
||||
tipo,
|
||||
names,
|
||||
check_last_item,
|
||||
is_expect,
|
||||
} => {
|
||||
let inner_types = tipo.get_inner_types();
|
||||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let error_term = if self.tracing && is_expect && !tipo.is_2_tuple() {
|
||||
let msg = arg_stack.pop().unwrap();
|
||||
Term::Error.delayed_trace(msg)
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
let list_id = self.id_gen.next();
|
||||
|
||||
|
@ -5169,31 +5234,21 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let names_types = names.into_iter().zip(inner_types).collect_vec();
|
||||
|
||||
let error_term = if self.tracing {
|
||||
Term::Error.delayed_trace(Term::var(
|
||||
self.special_functions.use_function(TOO_MANY_ITEMS),
|
||||
))
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
term = builder::list_access_to_uplc(
|
||||
&names_types,
|
||||
&id_list,
|
||||
false,
|
||||
0,
|
||||
term,
|
||||
check_last_item,
|
||||
is_expect,
|
||||
false,
|
||||
error_term,
|
||||
)
|
||||
.apply(value);
|
||||
|
||||
arg_stack.push(term);
|
||||
} else if check_last_item {
|
||||
unreachable!("HOW DID YOU DO THIS");
|
||||
} else {
|
||||
arg_stack.push(term);
|
||||
unreachable!("HOW DID YOU DO THIS");
|
||||
}
|
||||
}
|
||||
Air::Trace { .. } => {
|
||||
|
|
|
@ -89,11 +89,9 @@ pub enum Air {
|
|||
},
|
||||
AssertConstr {
|
||||
constr_index: usize,
|
||||
msg: String,
|
||||
},
|
||||
AssertBool {
|
||||
is_true: bool,
|
||||
msg: String,
|
||||
},
|
||||
// When
|
||||
When {
|
||||
|
@ -154,14 +152,14 @@ pub enum Air {
|
|||
// Field Access
|
||||
FieldsExpose {
|
||||
indices: Vec<(usize, String, Rc<Type>)>,
|
||||
check_last_item: bool,
|
||||
is_expect: bool,
|
||||
},
|
||||
// ListAccess
|
||||
ListAccessor {
|
||||
tipo: Rc<Type>,
|
||||
names: Vec<String>,
|
||||
tail: bool,
|
||||
check_last_item: bool,
|
||||
is_expect: bool,
|
||||
},
|
||||
ListExpose {
|
||||
tipo: Rc<Type>,
|
||||
|
@ -172,7 +170,7 @@ pub enum Air {
|
|||
TupleAccessor {
|
||||
names: Vec<String>,
|
||||
tipo: Rc<Type>,
|
||||
check_last_item: bool,
|
||||
is_expect: bool,
|
||||
},
|
||||
// Misc.
|
||||
ErrorTerm {
|
||||
|
|
|
@ -18,7 +18,7 @@ use crate::{
|
|||
AssignmentKind, DataType, Pattern, Span, TypedArg, TypedClause, TypedClauseGuard,
|
||||
TypedDataType, TypedPattern,
|
||||
},
|
||||
builtins::{bool, void},
|
||||
builtins::{bool, data, function, int, list, string, void},
|
||||
expr::TypedExpr,
|
||||
tipo::{PatternConstructor, TypeVar, ValueConstructor, ValueConstructorVariant},
|
||||
};
|
||||
|
@ -82,8 +82,7 @@ pub struct AssignmentProperties {
|
|||
pub kind: AssignmentKind,
|
||||
pub remove_unused: bool,
|
||||
pub full_check: bool,
|
||||
pub location: Span,
|
||||
pub module_name: String,
|
||||
pub msg_func: AirTree,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -193,7 +192,7 @@ impl ClauseProperties {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct CodeGenSpecialFuncs {
|
||||
pub used_funcs: Vec<String>,
|
||||
pub key_to_func: IndexMap<String, Term<Name>>,
|
||||
pub key_to_func: IndexMap<String, (Term<Name>, Rc<Type>)>,
|
||||
}
|
||||
|
||||
impl CodeGenSpecialFuncs {
|
||||
|
@ -202,46 +201,30 @@ impl CodeGenSpecialFuncs {
|
|||
|
||||
key_to_func.insert(
|
||||
CONSTR_FIELDS_EXPOSER.to_string(),
|
||||
(
|
||||
Term::snd_pair()
|
||||
.apply(Term::unconstr_data().apply(Term::var("__constr_var")))
|
||||
.lambda("__constr_var"),
|
||||
function(vec![data()], list(data())),
|
||||
),
|
||||
);
|
||||
|
||||
key_to_func.insert(
|
||||
CONSTR_INDEX_EXPOSER.to_string(),
|
||||
(
|
||||
Term::fst_pair()
|
||||
.apply(Term::unconstr_data().apply(Term::var("__constr_var")))
|
||||
.lambda("__constr_var"),
|
||||
function(vec![data()], int()),
|
||||
),
|
||||
);
|
||||
|
||||
key_to_func.insert(
|
||||
TOO_MANY_ITEMS.to_string(),
|
||||
(
|
||||
Term::string("List/Tuple/Constr contains more items than expected"),
|
||||
);
|
||||
|
||||
key_to_func.insert(
|
||||
LIST_NOT_EMPTY.to_string(),
|
||||
Term::string("Expected no items for List"),
|
||||
);
|
||||
|
||||
key_to_func.insert(
|
||||
CONSTR_NOT_EMPTY.to_string(),
|
||||
Term::string("Expected no fields for Constr"),
|
||||
);
|
||||
|
||||
key_to_func.insert(
|
||||
INCORRECT_BOOLEAN.to_string(),
|
||||
Term::string("Expected on incorrect Boolean variant"),
|
||||
);
|
||||
|
||||
key_to_func.insert(
|
||||
INCORRECT_CONSTR.to_string(),
|
||||
Term::string("Expected on incorrect Constr variant"),
|
||||
);
|
||||
|
||||
key_to_func.insert(
|
||||
CONSTR_INDEX_MISMATCH.to_string(),
|
||||
Term::string("Constr index didn't match a type variant"),
|
||||
string(),
|
||||
),
|
||||
);
|
||||
|
||||
CodeGenSpecialFuncs {
|
||||
|
@ -250,15 +233,26 @@ impl CodeGenSpecialFuncs {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn use_function(&mut self, func_name: &'static str) -> &'static str {
|
||||
if !self.used_funcs.contains(&func_name.to_string()) {
|
||||
pub fn use_function_tree(&mut self, func_name: String) -> AirTree {
|
||||
if !self.used_funcs.contains(&func_name) {
|
||||
self.used_funcs.push(func_name.to_string());
|
||||
}
|
||||
|
||||
let tipo = self.key_to_func.get(&func_name).unwrap().1.clone();
|
||||
|
||||
AirTree::local_var(func_name, tipo)
|
||||
}
|
||||
|
||||
pub fn use_function_uplc(&mut self, func_name: String) -> String {
|
||||
if !self.used_funcs.contains(&func_name) {
|
||||
self.used_funcs.push(func_name.to_string());
|
||||
}
|
||||
|
||||
func_name
|
||||
}
|
||||
|
||||
pub fn get_function(&self, func_name: &String) -> Term<Name> {
|
||||
self.key_to_func[func_name].clone()
|
||||
self.key_to_func[func_name].0.clone()
|
||||
}
|
||||
|
||||
pub fn apply_used_functions(&self, mut term: Term<Name>) -> Term<Name> {
|
||||
|
@ -267,6 +261,18 @@ impl CodeGenSpecialFuncs {
|
|||
}
|
||||
term
|
||||
}
|
||||
|
||||
pub fn insert_new_function(
|
||||
&mut self,
|
||||
func_name: String,
|
||||
function: Term<Name>,
|
||||
function_type: Rc<Type>,
|
||||
) {
|
||||
if !self.key_to_func.contains_key(&func_name) {
|
||||
self.key_to_func
|
||||
.insert(func_name, (function, function_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CodeGenSpecialFuncs {
|
||||
|
|
|
@ -127,12 +127,12 @@ pub enum AirStatement {
|
|||
AssertConstr {
|
||||
constr_index: usize,
|
||||
constr: Box<AirTree>,
|
||||
msg: String,
|
||||
msg: Box<AirTree>,
|
||||
},
|
||||
AssertBool {
|
||||
is_true: bool,
|
||||
value: Box<AirTree>,
|
||||
msg: String,
|
||||
msg: Box<AirTree>,
|
||||
},
|
||||
// Clause Guards
|
||||
ClauseGuard {
|
||||
|
@ -154,16 +154,16 @@ pub enum AirStatement {
|
|||
// Field Access
|
||||
FieldsExpose {
|
||||
indices: Vec<(usize, String, Rc<Type>)>,
|
||||
check_last_item: bool,
|
||||
record: Box<AirTree>,
|
||||
msg: Box<Option<AirTree>>,
|
||||
},
|
||||
// List Access
|
||||
ListAccessor {
|
||||
tipo: Rc<Type>,
|
||||
names: Vec<String>,
|
||||
tail: bool,
|
||||
check_last_item: bool,
|
||||
list: Box<AirTree>,
|
||||
msg: Box<Option<AirTree>>,
|
||||
},
|
||||
ListExpose {
|
||||
tipo: Rc<Type>,
|
||||
|
@ -174,15 +174,17 @@ pub enum AirStatement {
|
|||
TupleAccessor {
|
||||
names: Vec<String>,
|
||||
tipo: Rc<Type>,
|
||||
check_last_item: bool,
|
||||
tuple: Box<AirTree>,
|
||||
msg: Box<Option<AirTree>>,
|
||||
},
|
||||
// Misc.
|
||||
FieldsEmpty {
|
||||
constr: Box<AirTree>,
|
||||
msg: Box<AirTree>,
|
||||
},
|
||||
ListEmpty {
|
||||
list: Box<AirTree>,
|
||||
msg: Box<AirTree>,
|
||||
},
|
||||
NoOp,
|
||||
}
|
||||
|
@ -494,22 +496,22 @@ impl AirTree {
|
|||
value: value.into(),
|
||||
})
|
||||
}
|
||||
pub fn assert_constr_index(constr_index: usize, constr: AirTree, msg: String) -> AirTree {
|
||||
pub fn assert_constr_index(constr_index: usize, constr: AirTree, msg: AirTree) -> AirTree {
|
||||
AirTree::Statement {
|
||||
statement: AirStatement::AssertConstr {
|
||||
constr_index,
|
||||
constr: constr.into(),
|
||||
msg,
|
||||
msg: msg.into(),
|
||||
},
|
||||
hoisted_over: None,
|
||||
}
|
||||
}
|
||||
pub fn assert_bool(is_true: bool, value: AirTree, msg: String) -> AirTree {
|
||||
pub fn assert_bool(is_true: bool, value: AirTree, msg: AirTree) -> AirTree {
|
||||
AirTree::Statement {
|
||||
statement: AirStatement::AssertBool {
|
||||
is_true,
|
||||
value: value.into(),
|
||||
msg,
|
||||
msg: msg.into(),
|
||||
},
|
||||
hoisted_over: None,
|
||||
}
|
||||
|
@ -714,14 +716,14 @@ impl AirTree {
|
|||
|
||||
pub fn fields_expose(
|
||||
indices: Vec<(usize, String, Rc<Type>)>,
|
||||
check_last_item: bool,
|
||||
record: AirTree,
|
||||
msg: Option<AirTree>,
|
||||
) -> AirTree {
|
||||
AirTree::Statement {
|
||||
statement: AirStatement::FieldsExpose {
|
||||
indices,
|
||||
check_last_item,
|
||||
record: record.into(),
|
||||
msg: msg.into(),
|
||||
},
|
||||
hoisted_over: None,
|
||||
}
|
||||
|
@ -730,16 +732,16 @@ impl AirTree {
|
|||
names: Vec<String>,
|
||||
tipo: Rc<Type>,
|
||||
tail: bool,
|
||||
check_last_item: bool,
|
||||
list: AirTree,
|
||||
msg: Option<AirTree>,
|
||||
) -> AirTree {
|
||||
AirTree::Statement {
|
||||
statement: AirStatement::ListAccessor {
|
||||
tipo,
|
||||
names,
|
||||
tail,
|
||||
check_last_item,
|
||||
list: list.into(),
|
||||
msg: msg.into(),
|
||||
},
|
||||
hoisted_over: None,
|
||||
}
|
||||
|
@ -761,15 +763,15 @@ impl AirTree {
|
|||
pub fn tuple_access(
|
||||
names: Vec<String>,
|
||||
tipo: Rc<Type>,
|
||||
check_last_item: bool,
|
||||
tuple: AirTree,
|
||||
msg: Option<AirTree>,
|
||||
) -> AirTree {
|
||||
AirTree::Statement {
|
||||
statement: AirStatement::TupleAccessor {
|
||||
names,
|
||||
tipo,
|
||||
check_last_item,
|
||||
tuple: tuple.into(),
|
||||
msg: msg.into(),
|
||||
},
|
||||
hoisted_over: None,
|
||||
}
|
||||
|
@ -804,17 +806,21 @@ impl AirTree {
|
|||
hoisted_over: None,
|
||||
}
|
||||
}
|
||||
pub fn fields_empty(constr: AirTree) -> AirTree {
|
||||
pub fn fields_empty(constr: AirTree, msg: AirTree) -> AirTree {
|
||||
AirTree::Statement {
|
||||
statement: AirStatement::FieldsEmpty {
|
||||
constr: constr.into(),
|
||||
msg: msg.into(),
|
||||
},
|
||||
hoisted_over: None,
|
||||
}
|
||||
}
|
||||
pub fn list_empty(list: AirTree) -> AirTree {
|
||||
pub fn list_empty(list: AirTree, msg: AirTree) -> AirTree {
|
||||
AirTree::Statement {
|
||||
statement: AirStatement::ListEmpty { list: list.into() },
|
||||
statement: AirStatement::ListEmpty {
|
||||
list: list.into(),
|
||||
msg: msg.into(),
|
||||
},
|
||||
hoisted_over: None,
|
||||
}
|
||||
}
|
||||
|
@ -952,20 +958,18 @@ impl AirTree {
|
|||
} => {
|
||||
air_vec.push(Air::AssertConstr {
|
||||
constr_index: *constr_index,
|
||||
msg: msg.clone(),
|
||||
});
|
||||
constr.create_air_vec(air_vec);
|
||||
msg.create_air_vec(air_vec);
|
||||
}
|
||||
AirStatement::AssertBool {
|
||||
is_true,
|
||||
value,
|
||||
msg,
|
||||
} => {
|
||||
air_vec.push(Air::AssertBool {
|
||||
is_true: *is_true,
|
||||
msg: msg.clone(),
|
||||
});
|
||||
air_vec.push(Air::AssertBool { is_true: *is_true });
|
||||
value.create_air_vec(air_vec);
|
||||
msg.create_air_vec(air_vec);
|
||||
}
|
||||
AirStatement::ClauseGuard {
|
||||
subject_name,
|
||||
|
@ -1005,29 +1009,35 @@ impl AirTree {
|
|||
}
|
||||
AirStatement::FieldsExpose {
|
||||
indices,
|
||||
check_last_item,
|
||||
record,
|
||||
msg,
|
||||
} => {
|
||||
air_vec.push(Air::FieldsExpose {
|
||||
indices: indices.clone(),
|
||||
check_last_item: *check_last_item,
|
||||
is_expect: msg.is_some(),
|
||||
});
|
||||
record.create_air_vec(air_vec);
|
||||
msg.iter().for_each(|msg| {
|
||||
msg.create_air_vec(air_vec);
|
||||
});
|
||||
}
|
||||
AirStatement::ListAccessor {
|
||||
tipo,
|
||||
names,
|
||||
tail,
|
||||
check_last_item,
|
||||
list,
|
||||
msg,
|
||||
} => {
|
||||
air_vec.push(Air::ListAccessor {
|
||||
tipo: tipo.clone(),
|
||||
names: names.clone(),
|
||||
tail: *tail,
|
||||
check_last_item: *check_last_item,
|
||||
is_expect: msg.is_some(),
|
||||
});
|
||||
list.create_air_vec(air_vec);
|
||||
msg.iter().for_each(|msg| {
|
||||
msg.create_air_vec(air_vec);
|
||||
});
|
||||
}
|
||||
AirStatement::ListExpose {
|
||||
tipo,
|
||||
|
@ -1043,26 +1053,31 @@ impl AirTree {
|
|||
AirStatement::TupleAccessor {
|
||||
names,
|
||||
tipo,
|
||||
check_last_item,
|
||||
tuple,
|
||||
msg,
|
||||
} => {
|
||||
air_vec.push(Air::TupleAccessor {
|
||||
names: names.clone(),
|
||||
tipo: tipo.clone(),
|
||||
check_last_item: *check_last_item,
|
||||
is_expect: msg.is_some(),
|
||||
});
|
||||
tuple.create_air_vec(air_vec);
|
||||
msg.iter().for_each(|msg| {
|
||||
msg.create_air_vec(air_vec);
|
||||
});
|
||||
}
|
||||
AirStatement::NoOp => {
|
||||
air_vec.push(Air::NoOp);
|
||||
}
|
||||
AirStatement::FieldsEmpty { constr } => {
|
||||
AirStatement::FieldsEmpty { constr, msg } => {
|
||||
air_vec.push(Air::FieldsEmpty);
|
||||
constr.create_air_vec(air_vec);
|
||||
msg.create_air_vec(air_vec);
|
||||
}
|
||||
AirStatement::ListEmpty { list } => {
|
||||
AirStatement::ListEmpty { list, msg } => {
|
||||
air_vec.push(Air::ListEmpty);
|
||||
list.create_air_vec(air_vec);
|
||||
msg.create_air_vec(air_vec);
|
||||
}
|
||||
};
|
||||
exp.create_air_vec(air_vec);
|
||||
|
@ -1527,7 +1542,7 @@ impl AirTree {
|
|||
);
|
||||
}
|
||||
AirStatement::NoOp => {}
|
||||
AirStatement::FieldsEmpty { constr } => {
|
||||
AirStatement::FieldsEmpty { constr, .. } => {
|
||||
constr.do_traverse_tree_with(
|
||||
tree_path,
|
||||
current_depth + 1,
|
||||
|
@ -1536,7 +1551,7 @@ impl AirTree {
|
|||
apply_with_func_last,
|
||||
);
|
||||
}
|
||||
AirStatement::ListEmpty { list } => {
|
||||
AirStatement::ListEmpty { list, .. } => {
|
||||
list.do_traverse_tree_with(
|
||||
tree_path,
|
||||
current_depth + 1,
|
||||
|
@ -1997,7 +2012,7 @@ impl AirTree {
|
|||
}
|
||||
AirStatement::DefineFunc { .. } => unreachable!(),
|
||||
AirStatement::DefineCyclicFuncs { .. } => unreachable!(),
|
||||
AirStatement::FieldsEmpty { constr } => {
|
||||
AirStatement::FieldsEmpty { constr, .. } => {
|
||||
if *index == 0 {
|
||||
constr.as_mut().do_find_air_tree_node(tree_path_iter)
|
||||
} else if *index == 1 {
|
||||
|
@ -2006,7 +2021,7 @@ impl AirTree {
|
|||
panic!("Tree Path index outside tree children nodes")
|
||||
}
|
||||
}
|
||||
AirStatement::ListEmpty { list } => {
|
||||
AirStatement::ListEmpty { list, .. } => {
|
||||
if *index == 0 {
|
||||
list.as_mut().do_find_air_tree_node(tree_path_iter)
|
||||
} else if *index == 1 {
|
||||
|
|
Loading…
Reference in New Issue