feat: code gen support for if/is
Co-authored-by: Kasey White <kwhitemsg@gmail.com>
This commit is contained in:
parent
1b8805825b
commit
5024bd3f9c
|
@ -5,7 +5,7 @@ pub mod tree;
|
|||
use self::{
|
||||
air::Air,
|
||||
builder::{
|
||||
air_holds_msg, cast_validator_args, constants_ir, convert_type_to_data, extract_constant,
|
||||
cast_validator_args, constants_ir, convert_type_to_data, extract_constant,
|
||||
modify_cyclic_calls, modify_self_calls, rearrange_list_clauses, AssignmentProperties,
|
||||
ClauseProperties, CodeGenSpecialFuncs, CycleFunctionNames, HoistableFunction, Variant,
|
||||
},
|
||||
|
@ -42,6 +42,7 @@ use indexmap::{IndexMap, IndexSet};
|
|||
use itertools::Itertools;
|
||||
use petgraph::{algo, Graph};
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use uplc::{
|
||||
ast::{Constant as UplcConstant, Name, NamedDeBruijn, Program, Term, Type as UplcType},
|
||||
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER, EXPECT_ON_LIST},
|
||||
|
@ -258,18 +259,23 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let air_value = self.build(value, module_build_name, &[]);
|
||||
|
||||
let msg_func = match self.tracing {
|
||||
TraceLevel::Silent => None,
|
||||
TraceLevel::Verbose | TraceLevel::Compact => {
|
||||
if kind.is_expect() {
|
||||
let otherwise = match (self.tracing, kind) {
|
||||
(
|
||||
TraceLevel::Silent,
|
||||
AssignmentKind::Let { .. } | AssignmentKind::Expect { .. },
|
||||
) => AirTree::error(void(), false),
|
||||
|
||||
(TraceLevel::Compact | TraceLevel::Verbose, AssignmentKind::Let { .. }) => {
|
||||
AirTree::error(void(), false)
|
||||
}
|
||||
|
||||
(TraceLevel::Verbose | TraceLevel::Compact, AssignmentKind::Expect { .. }) => {
|
||||
let msg = match self.tracing {
|
||||
TraceLevel::Silent => unreachable!("excluded from pattern guards"),
|
||||
TraceLevel::Compact => get_line_columns_by_span(
|
||||
module_build_name,
|
||||
location,
|
||||
&self.module_src,
|
||||
)
|
||||
.to_string(),
|
||||
TraceLevel::Compact => {
|
||||
get_line_columns_by_span(module_build_name, location, &self.module_src)
|
||||
.to_string()
|
||||
}
|
||||
TraceLevel::Verbose => {
|
||||
get_src_code_by_span(module_build_name, location, &self.module_src)
|
||||
}
|
||||
|
@ -283,10 +289,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
string(),
|
||||
);
|
||||
|
||||
Some(self.special_functions.use_function_msg(msg_func_name))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let msg_string =
|
||||
AirTree::string(self.special_functions.use_function_string(msg_func_name));
|
||||
|
||||
AirTree::trace(msg_string, void(), AirTree::error(void(), false))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -304,7 +310,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: *kind,
|
||||
remove_unused: kind.is_let(),
|
||||
full_check: !tipo.is_data() && value.tipo().is_data() && kind.is_expect(),
|
||||
msg_func,
|
||||
otherwise,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -574,7 +580,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: AssignmentKind::let_(),
|
||||
remove_unused: false,
|
||||
full_check: false,
|
||||
msg_func: None,
|
||||
otherwise: AirTree::error(void(), false),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -625,24 +631,39 @@ impl<'a> CodeGenerator<'a> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
// let pattern = branch.condition
|
||||
// branch.body
|
||||
//
|
||||
// if <expr:condition> is <pattern>: <annotation> { <expr:body> }
|
||||
// [(builtin ifThenElse) (condition is pattern) (body) (else) ]
|
||||
TypedExpr::If {
|
||||
branches,
|
||||
final_else,
|
||||
tipo,
|
||||
..
|
||||
} => AirTree::if_branches(
|
||||
branches
|
||||
.iter()
|
||||
.map(|branch| {
|
||||
(
|
||||
self.build(&branch.condition, module_build_name, &[]),
|
||||
self.build(&branch.body, module_build_name, &[]),
|
||||
)
|
||||
})
|
||||
.collect_vec(),
|
||||
tipo.clone(),
|
||||
} => branches.iter().rfold(
|
||||
self.build(final_else, 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 {
|
||||
Some(pattern) => self.assignment(
|
||||
pattern,
|
||||
condition,
|
||||
body,
|
||||
&pattern.tipo(&branch.condition).unwrap(),
|
||||
AssignmentProperties {
|
||||
value_type: branch.condition.tipo(),
|
||||
kind: AssignmentKind::Expect { backpassing: () },
|
||||
remove_unused: false,
|
||||
full_check: true,
|
||||
otherwise: acc,
|
||||
},
|
||||
),
|
||||
None => AirTree::if_branch(tipo.clone(), condition, body, acc),
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
TypedExpr::RecordAccess {
|
||||
|
@ -878,7 +899,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
// 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() {
|
||||
value = AirTree::cast_from_data(value, tipo.clone(), props.msg_func.clone());
|
||||
value = AirTree::cast_from_data(value, tipo.clone(), props.otherwise.clone());
|
||||
} else if !props.value_type.is_data() && tipo.is_data() {
|
||||
value = AirTree::cast_to_data(value, props.value_type.clone());
|
||||
}
|
||||
|
@ -906,7 +927,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let expr = AirTree::let_assignment(name, value, expect);
|
||||
|
||||
AirTree::assert_bool(true, expr, props.msg_func.clone(), then)
|
||||
AirTree::assert_bool(true, expr, then, props.otherwise.clone())
|
||||
}
|
||||
|
||||
Pattern::Var { name, .. } => {
|
||||
|
@ -925,7 +946,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
val,
|
||||
&mut index_map,
|
||||
pattern.location(),
|
||||
props.msg_func,
|
||||
props.otherwise,
|
||||
);
|
||||
|
||||
let assign_expect = AirTree::let_assignment("_", expect, then);
|
||||
|
@ -965,7 +986,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
val,
|
||||
&mut index_map,
|
||||
pattern.location(),
|
||||
props.msg_func,
|
||||
props.otherwise,
|
||||
);
|
||||
|
||||
let assignment = AirTree::let_assignment("_", expect, then);
|
||||
|
@ -975,7 +996,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
} else if !props.remove_unused {
|
||||
AirTree::let_assignment(name, value, then)
|
||||
} else {
|
||||
AirTree::no_op(then)
|
||||
then
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1025,7 +1046,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
msg_func: props.msg_func.clone(),
|
||||
otherwise: props.otherwise.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -1073,7 +1094,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
msg_func: props.msg_func.clone(),
|
||||
otherwise: props.otherwise.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -1088,20 +1109,20 @@ impl<'a> CodeGenerator<'a> {
|
|||
elems.reverse();
|
||||
|
||||
if elements.is_empty() {
|
||||
AirTree::list_empty(value, props.msg_func, then)
|
||||
AirTree::list_empty(value, then, props.otherwise.clone())
|
||||
} else {
|
||||
AirTree::list_access(
|
||||
elems,
|
||||
tipo.clone(),
|
||||
tail.is_some(),
|
||||
value,
|
||||
props.msg_func,
|
||||
if props.full_check {
|
||||
ExpectLevel::Full
|
||||
} else {
|
||||
ExpectLevel::Items
|
||||
},
|
||||
then,
|
||||
props.otherwise.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1164,7 +1185,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
msg_func: props.msg_func.clone(),
|
||||
otherwise: props.otherwise.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -1190,11 +1211,6 @@ impl<'a> CodeGenerator<'a> {
|
|||
let local_value = AirTree::local_var(&constructor_name, tipo.clone());
|
||||
|
||||
let then = {
|
||||
let (is_expect, msg) = if props.full_check {
|
||||
(true, props.msg_func.clone())
|
||||
} else {
|
||||
(false, None)
|
||||
};
|
||||
assert!(fields.len() == 2);
|
||||
|
||||
AirTree::pair_access(
|
||||
|
@ -1208,9 +1224,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
.unwrap(),
|
||||
tipo.clone(),
|
||||
local_value,
|
||||
msg,
|
||||
is_expect,
|
||||
props.full_check,
|
||||
then,
|
||||
props.otherwise.clone(),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -1223,7 +1239,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
} if tipo.is_bool() => {
|
||||
assert!(props.kind.is_expect());
|
||||
|
||||
AirTree::assert_bool(name == "True", value, props.msg_func, then)
|
||||
AirTree::assert_bool(name == "True", value, then, props.otherwise.clone())
|
||||
}
|
||||
|
||||
Pattern::Constructor { .. } if tipo.is_void() => {
|
||||
|
@ -1308,7 +1324,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
msg_func: props.msg_func.clone(),
|
||||
otherwise: props.otherwise.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -1336,12 +1352,13 @@ impl<'a> CodeGenerator<'a> {
|
|||
let then = if check_replaceable_opaque_type(tipo, &self.data_types) {
|
||||
AirTree::let_assignment(&fields[0].1, local_value, then)
|
||||
} else {
|
||||
let (is_expect, msg) = if props.full_check {
|
||||
(true, props.msg_func.clone())
|
||||
} else {
|
||||
(false, None)
|
||||
};
|
||||
AirTree::fields_expose(fields, local_value, msg, is_expect, then)
|
||||
AirTree::fields_expose(
|
||||
fields,
|
||||
local_value,
|
||||
props.full_check,
|
||||
then,
|
||||
props.otherwise.clone(),
|
||||
)
|
||||
};
|
||||
|
||||
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
|
||||
|
@ -1362,10 +1379,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::assert_constr_index(
|
||||
index,
|
||||
AirTree::local_var(&constructor_name, tipo.clone()),
|
||||
props.msg_func,
|
||||
then,
|
||||
props.otherwise.clone(),
|
||||
)
|
||||
} else {
|
||||
assert!(data_type.constructors.len() == 1);
|
||||
then
|
||||
};
|
||||
|
||||
|
@ -1425,7 +1443,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: props.kind,
|
||||
remove_unused: true,
|
||||
full_check: props.full_check,
|
||||
msg_func: props.msg_func.clone(),
|
||||
otherwise: props.otherwise.clone(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -1439,15 +1457,16 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
fields.reverse();
|
||||
|
||||
let (is_expect, msg) = if props.full_check {
|
||||
(true, props.msg_func)
|
||||
} else {
|
||||
(false, None)
|
||||
};
|
||||
|
||||
// This `value` is either value param that was passed in or local var
|
||||
|
||||
AirTree::tuple_access(fields, tipo.clone(), value, msg, is_expect, then)
|
||||
AirTree::tuple_access(
|
||||
fields,
|
||||
tipo.clone(),
|
||||
value,
|
||||
props.full_check,
|
||||
then,
|
||||
props.otherwise.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1458,7 +1477,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
value: AirTree,
|
||||
defined_data_types: &mut IndexMap<String, u64>,
|
||||
location: Span,
|
||||
msg_func: Option<AirMsg>,
|
||||
otherwise: AirTree,
|
||||
) -> AirTree {
|
||||
assert!(tipo.get_generic().is_none());
|
||||
// Shouldn't be needed but still here just in case
|
||||
|
@ -1468,6 +1487,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
match uplc_type {
|
||||
// primitives
|
||||
// Untyped Data
|
||||
Some(
|
||||
UplcType::Integer
|
||||
| UplcType::String
|
||||
|
@ -1476,10 +1496,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
| UplcType::Unit
|
||||
| UplcType::Bls12_381G1Element
|
||||
| UplcType::Bls12_381G2Element
|
||||
| UplcType::Bls12_381MlResult,
|
||||
| UplcType::Bls12_381MlResult
|
||||
| UplcType::Data,
|
||||
) => value,
|
||||
// Untyped Data
|
||||
Some(UplcType::Data) => value,
|
||||
|
||||
// Map type
|
||||
Some(UplcType::List(_)) if tipo.is_map() => {
|
||||
|
@ -1500,7 +1519,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(fst_name.clone(), inner_pair_types[0].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
otherwise.clone(),
|
||||
);
|
||||
|
||||
let expect_snd = self.expect_type_assign(
|
||||
|
@ -1508,7 +1527,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(snd_name.clone(), inner_pair_types[1].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
otherwise.clone(),
|
||||
);
|
||||
|
||||
let anon_func_body = AirTree::pair_access(
|
||||
|
@ -1516,9 +1535,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
Some(snd_name),
|
||||
inner_list_type.clone(),
|
||||
AirTree::local_var(&pair_name, inner_list_type.clone()),
|
||||
msg_func.clone(),
|
||||
true,
|
||||
AirTree::let_assignment("_", expect_fst, expect_snd),
|
||||
otherwise.clone(),
|
||||
);
|
||||
|
||||
let unwrap_function = AirTree::anon_func(vec![pair_name], anon_func_body);
|
||||
|
@ -1587,7 +1606,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(&tuple_index_name, arg.clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
otherwise.clone(),
|
||||
);
|
||||
|
||||
tuple_expect_items.push(tuple_index_name);
|
||||
|
@ -1602,9 +1621,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
tuple_expect_items,
|
||||
tipo.clone(),
|
||||
AirTree::local_var(&tuple_name, tipo.clone()),
|
||||
msg_func,
|
||||
true,
|
||||
then,
|
||||
otherwise,
|
||||
);
|
||||
|
||||
AirTree::let_assignment(&tuple_name, value, tuple_access)
|
||||
|
@ -1626,11 +1645,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::cast_from_data(
|
||||
AirTree::local_var(&item_name, data()),
|
||||
inner_list_type.clone(),
|
||||
msg_func.clone(),
|
||||
otherwise.clone(),
|
||||
),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func,
|
||||
otherwise,
|
||||
);
|
||||
|
||||
let anon_func_body = expect_item;
|
||||
|
@ -1701,7 +1720,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(fst_name.clone(), tuple_inner_types[0].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
otherwise.clone(),
|
||||
);
|
||||
|
||||
let expect_snd = self.expect_type_assign(
|
||||
|
@ -1709,7 +1728,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(snd_name.clone(), tuple_inner_types[1].clone()),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_func.clone(),
|
||||
otherwise.clone(),
|
||||
);
|
||||
|
||||
let pair_access = AirTree::pair_access(
|
||||
|
@ -1717,9 +1736,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
Some(snd_name.clone()),
|
||||
tipo.clone(),
|
||||
AirTree::local_var(&pair_name, tipo.clone()),
|
||||
msg_func.clone(),
|
||||
true,
|
||||
AirTree::let_assignment("_", expect_fst, expect_snd),
|
||||
otherwise,
|
||||
);
|
||||
|
||||
AirTree::let_assignment(&pair_name, value, pair_access)
|
||||
|
@ -1800,7 +1819,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::local_var(arg_name, arg_tipo),
|
||||
defined_data_types,
|
||||
location,
|
||||
msg_term.clone(),
|
||||
otherwise.clone(),
|
||||
),
|
||||
then,
|
||||
)
|
||||
|
@ -1830,9 +1849,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
),
|
||||
tipo.clone(),
|
||||
),
|
||||
msg_term.clone(),
|
||||
true,
|
||||
constr_then,
|
||||
otherwise.clone(),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -1895,12 +1914,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let args = match self.tracing {
|
||||
TraceLevel::Silent => vec![value],
|
||||
TraceLevel::Compact | TraceLevel::Verbose => vec![
|
||||
value,
|
||||
msg_func
|
||||
.expect("should be unreachable: no msg func with tracing enabled.")
|
||||
.to_air_tree(),
|
||||
],
|
||||
TraceLevel::Compact | TraceLevel::Verbose => vec![value, otherwise],
|
||||
};
|
||||
|
||||
let module_fn = ValueConstructorVariant::ModuleFn {
|
||||
|
@ -2459,9 +2473,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
// 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,
|
||||
ExpectLevel::None,
|
||||
elems_then,
|
||||
AirTree::error(void(), false),
|
||||
)
|
||||
} else {
|
||||
assert!(defined_tails.len() >= elems.len());
|
||||
|
@ -2540,9 +2554,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
name_index_assigns[1].0.clone(),
|
||||
subject_tipo.clone(),
|
||||
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
||||
None,
|
||||
false,
|
||||
next_then,
|
||||
AirTree::error(void(), false),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -2667,9 +2681,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::fields_expose(
|
||||
fields,
|
||||
AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()),
|
||||
None,
|
||||
false,
|
||||
next_then,
|
||||
AirTree::error(void(), false),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -2796,9 +2810,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
names,
|
||||
subject_tipo.clone(),
|
||||
AirTree::local_var(&props.clause_var_name, subject_tipo.clone()),
|
||||
None,
|
||||
false,
|
||||
tuple_name_assigns,
|
||||
AirTree::error(void(), false),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
|
@ -3034,8 +3048,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let actual_type = convert_opaque_type(&arg.tipo, &self.data_types, true);
|
||||
|
||||
let msg_func = match self.tracing {
|
||||
TraceLevel::Silent => None,
|
||||
let otherwise = match self.tracing {
|
||||
TraceLevel::Silent => AirTree::error(void(), false),
|
||||
TraceLevel::Compact | TraceLevel::Verbose => {
|
||||
let msg = match self.tracing {
|
||||
TraceLevel::Silent => {
|
||||
|
@ -3059,7 +3073,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
string(),
|
||||
);
|
||||
|
||||
Some(self.special_functions.use_function_msg(msg_func_name))
|
||||
let msg_string = AirTree::string(
|
||||
self.special_functions.use_function_string(msg_func_name),
|
||||
);
|
||||
|
||||
AirTree::trace(msg_string, void(), AirTree::error(void(), false))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3076,7 +3094,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
kind: AssignmentKind::expect(),
|
||||
remove_unused: false,
|
||||
full_check: true,
|
||||
msg_func,
|
||||
otherwise,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -4017,24 +4035,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
|
||||
fn gen_uplc(&mut self, ir: Air, arg_stack: &mut Vec<Term<Name>>) -> Option<Term<Name>> {
|
||||
// Going to mark the changes made to code gen after air tree implementation
|
||||
let error_term = match self.tracing {
|
||||
TraceLevel::Silent => Term::Error,
|
||||
TraceLevel::Compact | TraceLevel::Verbose => {
|
||||
if air_holds_msg(&ir) {
|
||||
let msg = arg_stack.pop().unwrap();
|
||||
Term::Error.delayed_trace(msg)
|
||||
} else {
|
||||
Term::Error
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let convert_data_to_type = |term, tipo| {
|
||||
if error_term == Term::Error {
|
||||
let convert_data_to_type = |term, tipo, otherwise| {
|
||||
if otherwise == Term::Error {
|
||||
builder::unknown_data_to_type(term, tipo)
|
||||
} else {
|
||||
builder::unknown_data_to_type_debug(term, tipo, error_term.clone())
|
||||
builder::unknown_data_to_type_otherwise(term, tipo, otherwise)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4337,6 +4342,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
let otherwise = if matches!(expect_level, ExpectLevel::Full | ExpectLevel::Items) {
|
||||
arg_stack.pop().unwrap()
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
let list_id = self.id_gen.next();
|
||||
|
||||
let mut id_list = vec![];
|
||||
|
@ -4362,7 +4373,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
term,
|
||||
true,
|
||||
expect_level,
|
||||
error_term,
|
||||
otherwise,
|
||||
)
|
||||
.apply(value);
|
||||
|
||||
|
@ -4774,8 +4785,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
Air::CastFromData { tipo, .. } => {
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
let otherwise = arg_stack.pop().unwrap();
|
||||
|
||||
term = convert_data_to_type(term, &tipo);
|
||||
term = convert_data_to_type(term, &tipo, otherwise);
|
||||
|
||||
if extract_constant(&term).is_some() {
|
||||
let mut program: Program<Name> = Program {
|
||||
|
@ -4834,6 +4846,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
let constr = arg_stack.pop().unwrap();
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
let otherwise = arg_stack.pop().unwrap();
|
||||
|
||||
term = Term::equals_integer()
|
||||
.apply(Term::integer(constr_index.into()))
|
||||
|
@ -4844,7 +4857,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
)
|
||||
.apply(constr),
|
||||
)
|
||||
.delayed_if_then_else(term, error_term);
|
||||
.delayed_if_then_else(term, otherwise);
|
||||
|
||||
Some(term)
|
||||
}
|
||||
|
@ -4852,11 +4865,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
let otherwise = arg_stack.pop().unwrap();
|
||||
|
||||
if is_true {
|
||||
term = value.delayed_if_then_else(term, error_term)
|
||||
term = value.delayed_if_then_else(term, otherwise)
|
||||
} else {
|
||||
term = value.delayed_if_then_else(error_term, term)
|
||||
term = value.delayed_if_then_else(otherwise, term)
|
||||
}
|
||||
Some(term)
|
||||
}
|
||||
|
@ -5286,6 +5300,13 @@ impl<'a> CodeGenerator<'a> {
|
|||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
|
||||
let otherwise = if is_expect {
|
||||
arg_stack.pop().unwrap()
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
let list_id = self.id_gen.next();
|
||||
|
||||
id_list.push(list_id);
|
||||
|
@ -5313,7 +5334,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
term,
|
||||
false,
|
||||
is_expect.into(),
|
||||
error_term,
|
||||
otherwise,
|
||||
);
|
||||
|
||||
term = term.apply(
|
||||
|
@ -5333,13 +5354,14 @@ impl<'a> CodeGenerator<'a> {
|
|||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
let otherwise = arg_stack.pop().unwrap();
|
||||
|
||||
term = Term::var(
|
||||
self.special_functions
|
||||
.use_function_uplc(CONSTR_FIELDS_EXPOSER.to_string()),
|
||||
)
|
||||
.apply(value)
|
||||
.delayed_choose_list(term, error_term);
|
||||
.delayed_choose_list(term, otherwise);
|
||||
|
||||
Some(term)
|
||||
}
|
||||
|
@ -5347,8 +5369,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
let otherwise = arg_stack.pop().unwrap();
|
||||
|
||||
term = value.delayed_choose_list(term, error_term);
|
||||
term = value.delayed_choose_list(term, otherwise);
|
||||
|
||||
Some(term)
|
||||
}
|
||||
|
@ -5545,6 +5568,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
let otherwise = if is_expect {
|
||||
arg_stack.pop().unwrap()
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
let list_id = self.id_gen.next();
|
||||
|
||||
let mut id_list = vec![];
|
||||
|
@ -5567,7 +5595,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
term,
|
||||
false,
|
||||
is_expect.into(),
|
||||
error_term,
|
||||
otherwise,
|
||||
)
|
||||
.apply(value);
|
||||
|
||||
|
@ -5583,6 +5611,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let mut term = arg_stack.pop().unwrap();
|
||||
let otherwise = if is_expect {
|
||||
arg_stack.pop().unwrap()
|
||||
} else {
|
||||
Term::Error
|
||||
};
|
||||
|
||||
let list_id = self.id_gen.next();
|
||||
|
||||
if let Some(name) = snd {
|
||||
|
@ -5590,6 +5624,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
convert_data_to_type(
|
||||
Term::snd_pair().apply(Term::var(format!("__pair_{list_id}"))),
|
||||
&inner_types[1],
|
||||
otherwise.clone(),
|
||||
)
|
||||
} else {
|
||||
known_data_to_type(
|
||||
|
@ -5604,6 +5639,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
convert_data_to_type(
|
||||
Term::fst_pair().apply(Term::var(format!("__pair_{list_id}"))),
|
||||
&inner_types[0],
|
||||
otherwise,
|
||||
)
|
||||
} else {
|
||||
known_data_to_type(
|
||||
|
|
|
@ -102,7 +102,6 @@ pub enum Air {
|
|||
},
|
||||
CastFromData {
|
||||
tipo: Rc<Type>,
|
||||
is_expect: bool,
|
||||
},
|
||||
CastToData {
|
||||
tipo: Rc<Type>,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::{
|
||||
air::{Air, ExpectLevel},
|
||||
air::ExpectLevel,
|
||||
tree::{AirMsg, AirTree, TreePath},
|
||||
};
|
||||
use crate::{
|
||||
|
@ -71,7 +71,7 @@ pub struct AssignmentProperties {
|
|||
pub kind: TypedAssignmentKind,
|
||||
pub remove_unused: bool,
|
||||
pub full_check: bool,
|
||||
pub msg_func: Option<AirMsg>,
|
||||
pub otherwise: AirTree,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -233,6 +233,14 @@ impl CodeGenSpecialFuncs {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn use_function_string(&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 use_function_tree(&mut self, func_name: String) -> AirTree {
|
||||
if !self.used_funcs.contains(&func_name) {
|
||||
self.used_funcs.push(func_name.to_string());
|
||||
|
@ -1035,7 +1043,7 @@ 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
|
||||
/// 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.
|
||||
pub fn unknown_data_to_type_debug(
|
||||
pub fn unknown_data_to_type_otherwise(
|
||||
term: Term<Name>,
|
||||
field_type: &Type,
|
||||
error_term: Term<Name>,
|
||||
|
@ -1362,7 +1370,7 @@ pub fn list_access_to_uplc(
|
|||
term: Term<Name>,
|
||||
is_list_accessor: bool,
|
||||
expect_level: ExpectLevel,
|
||||
error_term: Term<Name>,
|
||||
otherwise: Term<Name>,
|
||||
) -> Term<Name> {
|
||||
let names_len = names_types_ids.len();
|
||||
|
||||
|
@ -1393,7 +1401,7 @@ pub fn list_access_to_uplc(
|
|||
}
|
||||
|
||||
return Term::var("empty_list")
|
||||
.delayed_choose_list(term, error_term)
|
||||
.delayed_choose_list(term, otherwise)
|
||||
.lambda("empty_list");
|
||||
}
|
||||
|
||||
|
@ -1412,16 +1420,16 @@ pub fn list_access_to_uplc(
|
|||
Term::head_list().apply(Term::var(tail_name.to_string()))
|
||||
} else if matches!(expect_level, ExpectLevel::Full) {
|
||||
// Expect level is full so we have an unknown piece of data to cast
|
||||
if error_term == Term::Error {
|
||||
if otherwise == Term::Error {
|
||||
unknown_data_to_type(
|
||||
Term::head_list().apply(Term::var(tail_name.to_string())),
|
||||
&tipo.to_owned(),
|
||||
)
|
||||
} else {
|
||||
unknown_data_to_type_debug(
|
||||
unknown_data_to_type_otherwise(
|
||||
Term::head_list().apply(Term::var(tail_name.to_string())),
|
||||
&tipo.to_owned(),
|
||||
error_term.clone(),
|
||||
otherwise.clone(),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
@ -1456,22 +1464,22 @@ pub fn list_access_to_uplc(
|
|||
ExpectLevel::None => acc.lambda(name).apply(head_item).lambda(tail_name),
|
||||
|
||||
ExpectLevel::Full | ExpectLevel::Items => {
|
||||
if error_term == Term::Error && tail_present {
|
||||
if otherwise == Term::Error && tail_present {
|
||||
// No need to check last item if tail was present
|
||||
acc.lambda(name).apply(head_item).lambda(tail_name)
|
||||
} else if tail_present {
|
||||
// Custom error instead of trying to do head_item on a possibly empty list.
|
||||
Term::var(tail_name.to_string())
|
||||
.delayed_choose_list(
|
||||
error_term.clone(),
|
||||
otherwise.clone(),
|
||||
acc.lambda(name).apply(head_item),
|
||||
)
|
||||
.lambda(tail_name)
|
||||
} else if error_term == Term::Error {
|
||||
} else if otherwise == Term::Error {
|
||||
// Check head is last item in this list
|
||||
Term::tail_list()
|
||||
.apply(Term::var(tail_name.to_string()))
|
||||
.delayed_choose_list(acc, error_term.clone())
|
||||
.delayed_choose_list(acc, otherwise.clone())
|
||||
.lambda(name)
|
||||
.apply(head_item)
|
||||
.lambda(tail_name)
|
||||
|
@ -1479,10 +1487,10 @@ pub fn list_access_to_uplc(
|
|||
// Custom error if list is not empty after this head
|
||||
Term::var(tail_name.to_string())
|
||||
.delayed_choose_list(
|
||||
error_term.clone(),
|
||||
otherwise.clone(),
|
||||
Term::tail_list()
|
||||
.apply(Term::var(tail_name.to_string()))
|
||||
.delayed_choose_list(acc, error_term.clone())
|
||||
.delayed_choose_list(acc, otherwise.clone())
|
||||
.lambda(name)
|
||||
.apply(head_item),
|
||||
)
|
||||
|
@ -1498,7 +1506,7 @@ pub fn list_access_to_uplc(
|
|||
|
||||
let head_item = head_item(name, tipo, &tail_name);
|
||||
|
||||
if matches!(expect_level, ExpectLevel::None) || error_term == Term::Error {
|
||||
if matches!(expect_level, ExpectLevel::None) || otherwise == Term::Error {
|
||||
acc.apply(Term::tail_list().apply(Term::var(tail_name.to_string())))
|
||||
.lambda(name)
|
||||
.apply(head_item)
|
||||
|
@ -1507,7 +1515,7 @@ pub fn list_access_to_uplc(
|
|||
// case for a custom error if the list is empty at this point
|
||||
Term::var(tail_name.to_string())
|
||||
.delayed_choose_list(
|
||||
error_term.clone(),
|
||||
otherwise.clone(),
|
||||
acc.apply(
|
||||
Term::tail_list().apply(Term::var(tail_name.to_string())),
|
||||
)
|
||||
|
@ -1778,7 +1786,6 @@ pub fn cast_validator_args(term: Term<Name>, arguments: &[TypedArg]) -> Term<Nam
|
|||
}
|
||||
|
||||
pub fn wrap_validator_condition(air_tree: AirTree, trace: TraceLevel) -> AirTree {
|
||||
let success_branch = vec![(air_tree, AirTree::void())];
|
||||
let otherwise = match trace {
|
||||
TraceLevel::Silent | TraceLevel::Compact => AirTree::error(void(), true),
|
||||
TraceLevel::Verbose => AirTree::trace(
|
||||
|
@ -1788,7 +1795,7 @@ pub fn wrap_validator_condition(air_tree: AirTree, trace: TraceLevel) -> AirTree
|
|||
),
|
||||
};
|
||||
|
||||
AirTree::if_branches(success_branch, void(), otherwise)
|
||||
AirTree::if_branch(void(), air_tree, AirTree::void(), otherwise)
|
||||
}
|
||||
|
||||
pub fn extract_constant(term: &Term<Name>) -> Option<Rc<UplcConstant>> {
|
||||
|
@ -1841,22 +1848,3 @@ pub fn get_line_columns_by_span(
|
|||
.line_and_column_number(span.start)
|
||||
.expect("Out of bounds span")
|
||||
}
|
||||
|
||||
pub fn air_holds_msg(air: &Air) -> bool {
|
||||
match air {
|
||||
Air::AssertConstr { .. } | Air::AssertBool { .. } | Air::FieldsEmpty | Air::ListEmpty => {
|
||||
true
|
||||
}
|
||||
|
||||
Air::FieldsExpose { is_expect, .. }
|
||||
| Air::TupleAccessor { is_expect, .. }
|
||||
| Air::PairAccessor { is_expect, .. }
|
||||
| Air::CastFromData { is_expect, .. } => *is_expect,
|
||||
|
||||
Air::ListAccessor { expect_level, .. } => {
|
||||
matches!(expect_level, ExpectLevel::Full | ExpectLevel::Items)
|
||||
}
|
||||
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,14 +133,14 @@ pub enum AirTree {
|
|||
AssertConstr {
|
||||
constr_index: usize,
|
||||
constr: Box<AirTree>,
|
||||
msg: Option<AirMsg>,
|
||||
then: Box<AirTree>,
|
||||
otherwise: Box<AirTree>,
|
||||
},
|
||||
AssertBool {
|
||||
is_true: bool,
|
||||
value: Box<AirTree>,
|
||||
msg: Option<AirMsg>,
|
||||
then: Box<AirTree>,
|
||||
otherwise: Box<AirTree>,
|
||||
},
|
||||
// Clause Guards
|
||||
ClauseGuard {
|
||||
|
@ -174,8 +174,8 @@ pub enum AirTree {
|
|||
indices: Vec<(usize, String, Rc<Type>)>,
|
||||
record: Box<AirTree>,
|
||||
is_expect: bool,
|
||||
msg: Option<AirMsg>,
|
||||
then: Box<AirTree>,
|
||||
otherwise: Box<AirTree>,
|
||||
},
|
||||
// List Access
|
||||
ListAccessor {
|
||||
|
@ -184,8 +184,8 @@ pub enum AirTree {
|
|||
tail: bool,
|
||||
list: Box<AirTree>,
|
||||
expect_level: ExpectLevel,
|
||||
msg: Option<AirMsg>,
|
||||
then: Box<AirTree>,
|
||||
otherwise: Box<AirTree>,
|
||||
},
|
||||
ListExpose {
|
||||
tipo: Rc<Type>,
|
||||
|
@ -199,8 +199,8 @@ pub enum AirTree {
|
|||
tipo: Rc<Type>,
|
||||
tuple: Box<AirTree>,
|
||||
is_expect: bool,
|
||||
msg: Option<AirMsg>,
|
||||
then: Box<AirTree>,
|
||||
otherwise: Box<AirTree>,
|
||||
},
|
||||
// Pair Access
|
||||
PairAccessor {
|
||||
|
@ -208,9 +208,9 @@ pub enum AirTree {
|
|||
snd: Option<String>,
|
||||
tipo: Rc<Type>,
|
||||
is_expect: bool,
|
||||
msg: Option<AirMsg>,
|
||||
pair: Box<AirTree>,
|
||||
then: Box<AirTree>,
|
||||
otherwise: Box<AirTree>,
|
||||
},
|
||||
// Misc.
|
||||
FieldsEmpty {
|
||||
|
@ -220,8 +220,8 @@ pub enum AirTree {
|
|||
},
|
||||
ListEmpty {
|
||||
list: Box<AirTree>,
|
||||
msg: Option<AirMsg>,
|
||||
then: Box<AirTree>,
|
||||
otherwise: Box<AirTree>,
|
||||
},
|
||||
NoOp {
|
||||
then: Box<AirTree>,
|
||||
|
@ -297,7 +297,7 @@ pub enum AirTree {
|
|||
CastFromData {
|
||||
tipo: Rc<Type>,
|
||||
value: Box<AirTree>,
|
||||
msg: Option<AirMsg>,
|
||||
otherwise: Box<AirTree>,
|
||||
},
|
||||
CastToData {
|
||||
tipo: Rc<Type>,
|
||||
|
@ -359,7 +359,7 @@ pub enum AirTree {
|
|||
// If
|
||||
If {
|
||||
tipo: Rc<Type>,
|
||||
pattern: Box<AirTree>,
|
||||
condition: Box<AirTree>,
|
||||
then: Box<AirTree>,
|
||||
otherwise: Box<AirTree>,
|
||||
},
|
||||
|
@ -390,6 +390,10 @@ pub enum AirTree {
|
|||
}
|
||||
|
||||
impl AirTree {
|
||||
pub fn is_error(&self) -> bool {
|
||||
matches!(self, AirTree::ErrorTerm { .. })
|
||||
}
|
||||
|
||||
pub fn int(value: impl ToString) -> AirTree {
|
||||
AirTree::Int {
|
||||
value: value.to_string(),
|
||||
|
@ -562,11 +566,11 @@ impl AirTree {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn cast_from_data(value: AirTree, tipo: Rc<Type>, msg: Option<AirMsg>) -> AirTree {
|
||||
pub fn cast_from_data(value: AirTree, tipo: Rc<Type>, otherwise: AirTree) -> AirTree {
|
||||
AirTree::CastFromData {
|
||||
tipo,
|
||||
value: value.into(),
|
||||
msg,
|
||||
otherwise: otherwise.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -580,28 +584,28 @@ impl AirTree {
|
|||
pub fn assert_constr_index(
|
||||
constr_index: usize,
|
||||
constr: AirTree,
|
||||
msg: Option<AirMsg>,
|
||||
then: AirTree,
|
||||
otherwise: AirTree,
|
||||
) -> AirTree {
|
||||
AirTree::AssertConstr {
|
||||
constr_index,
|
||||
constr: constr.into(),
|
||||
msg,
|
||||
then: then.into(),
|
||||
otherwise: otherwise.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_bool(
|
||||
is_true: bool,
|
||||
value: AirTree,
|
||||
msg: Option<AirMsg>,
|
||||
then: AirTree,
|
||||
otherwise: AirTree,
|
||||
) -> AirTree {
|
||||
AirTree::AssertBool {
|
||||
is_true,
|
||||
value: value.into(),
|
||||
msg,
|
||||
then: then.into(),
|
||||
otherwise: otherwise.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -771,31 +775,18 @@ impl AirTree {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn if_branches(
|
||||
mut branches: Vec<(AirTree, AirTree)>,
|
||||
pub fn if_branch(
|
||||
tipo: Rc<Type>,
|
||||
condition: AirTree,
|
||||
branch: AirTree,
|
||||
otherwise: AirTree,
|
||||
) -> AirTree {
|
||||
assert!(!branches.is_empty());
|
||||
let last_if = branches.pop().unwrap();
|
||||
|
||||
let mut final_if = AirTree::If {
|
||||
tipo: tipo.clone(),
|
||||
pattern: Box::new(last_if.0),
|
||||
then: Box::new(last_if.1),
|
||||
AirTree::If {
|
||||
tipo,
|
||||
condition: condition.into(),
|
||||
then: branch.into(),
|
||||
otherwise: otherwise.into(),
|
||||
};
|
||||
|
||||
while let Some(branch) = branches.pop() {
|
||||
final_if = AirTree::If {
|
||||
tipo: tipo.clone(),
|
||||
pattern: Box::new(branch.0),
|
||||
then: Box::new(branch.1),
|
||||
otherwise: final_if.into(),
|
||||
};
|
||||
}
|
||||
|
||||
final_if
|
||||
}
|
||||
|
||||
pub fn create_constr(tag: usize, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree {
|
||||
|
@ -845,23 +836,23 @@ impl AirTree {
|
|||
vec![list_of_fields],
|
||||
),
|
||||
tipo.clone(),
|
||||
None,
|
||||
AirTree::error(void(), false),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn fields_expose(
|
||||
indices: Vec<(usize, String, Rc<Type>)>,
|
||||
record: AirTree,
|
||||
msg: Option<AirMsg>,
|
||||
is_expect: bool,
|
||||
then: AirTree,
|
||||
otherwise: AirTree,
|
||||
) -> AirTree {
|
||||
AirTree::FieldsExpose {
|
||||
indices,
|
||||
record: record.into(),
|
||||
msg,
|
||||
is_expect,
|
||||
then: then.into(),
|
||||
otherwise: otherwise.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -870,9 +861,10 @@ impl AirTree {
|
|||
tipo: Rc<Type>,
|
||||
tail: bool,
|
||||
list: AirTree,
|
||||
msg: Option<AirMsg>,
|
||||
|
||||
expect_level: ExpectLevel,
|
||||
then: AirTree,
|
||||
otherwise: AirTree,
|
||||
) -> AirTree {
|
||||
AirTree::ListAccessor {
|
||||
tipo,
|
||||
|
@ -880,8 +872,8 @@ impl AirTree {
|
|||
tail,
|
||||
list: list.into(),
|
||||
expect_level,
|
||||
msg,
|
||||
then: then.into(),
|
||||
otherwise: otherwise.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -903,17 +895,17 @@ impl AirTree {
|
|||
names: Vec<String>,
|
||||
tipo: Rc<Type>,
|
||||
tuple: AirTree,
|
||||
msg: Option<AirMsg>,
|
||||
is_expect: bool,
|
||||
then: AirTree,
|
||||
otherwise: AirTree,
|
||||
) -> AirTree {
|
||||
AirTree::TupleAccessor {
|
||||
names,
|
||||
tipo,
|
||||
tuple: tuple.into(),
|
||||
msg,
|
||||
is_expect,
|
||||
then: then.into(),
|
||||
otherwise: otherwise.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -922,18 +914,18 @@ impl AirTree {
|
|||
snd: Option<String>,
|
||||
tipo: Rc<Type>,
|
||||
pair: AirTree,
|
||||
msg: Option<AirMsg>,
|
||||
is_expect: bool,
|
||||
then: AirTree,
|
||||
otherwise: AirTree,
|
||||
) -> AirTree {
|
||||
AirTree::PairAccessor {
|
||||
fst,
|
||||
snd,
|
||||
tipo,
|
||||
is_expect,
|
||||
msg,
|
||||
pair: pair.into(),
|
||||
then: then.into(),
|
||||
otherwise: otherwise.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -949,7 +941,7 @@ impl AirTree {
|
|||
vec![tuple],
|
||||
),
|
||||
tipo.clone(),
|
||||
None,
|
||||
AirTree::error(void(), false),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -976,11 +968,12 @@ impl AirTree {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn list_empty(list: AirTree, msg: Option<AirMsg>, then: AirTree) -> AirTree {
|
||||
pub fn list_empty(list: AirTree, then: AirTree, otherwise: AirTree) -> AirTree {
|
||||
AirTree::ListEmpty {
|
||||
list: list.into(),
|
||||
msg,
|
||||
|
||||
then: then.into(),
|
||||
otherwise: otherwise.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1114,8 +1107,8 @@ impl AirTree {
|
|||
AirTree::AssertConstr {
|
||||
constr,
|
||||
constr_index,
|
||||
msg,
|
||||
then,
|
||||
otherwise,
|
||||
} => {
|
||||
air_vec.push(Air::AssertConstr {
|
||||
constr_index: *constr_index,
|
||||
|
@ -1123,27 +1116,21 @@ impl AirTree {
|
|||
// msg is first so we can pop it off first in uplc_gen
|
||||
// if traces are on
|
||||
|
||||
if let Some(msg) = msg {
|
||||
msg.to_air_tree().create_air_vec(air_vec);
|
||||
}
|
||||
|
||||
constr.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
otherwise.create_air_vec(air_vec);
|
||||
}
|
||||
AirTree::AssertBool {
|
||||
is_true,
|
||||
value,
|
||||
msg,
|
||||
then,
|
||||
otherwise,
|
||||
} => {
|
||||
air_vec.push(Air::AssertBool { is_true: *is_true });
|
||||
|
||||
if let Some(msg) = msg {
|
||||
msg.to_air_tree().create_air_vec(air_vec);
|
||||
}
|
||||
|
||||
value.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
otherwise.create_air_vec(air_vec);
|
||||
}
|
||||
AirTree::ClauseGuard {
|
||||
subject_name,
|
||||
|
@ -1205,30 +1192,29 @@ impl AirTree {
|
|||
AirTree::FieldsExpose {
|
||||
indices,
|
||||
record,
|
||||
msg,
|
||||
is_expect,
|
||||
then,
|
||||
otherwise,
|
||||
} => {
|
||||
air_vec.push(Air::FieldsExpose {
|
||||
indices: indices.clone(),
|
||||
is_expect: *is_expect,
|
||||
});
|
||||
|
||||
if let Some(msg) = msg {
|
||||
msg.to_air_tree().create_air_vec(air_vec);
|
||||
}
|
||||
|
||||
record.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
if *is_expect {
|
||||
otherwise.create_air_vec(air_vec);
|
||||
}
|
||||
}
|
||||
AirTree::ListAccessor {
|
||||
tipo,
|
||||
names,
|
||||
tail,
|
||||
list,
|
||||
msg,
|
||||
expect_level,
|
||||
then,
|
||||
otherwise,
|
||||
} => {
|
||||
air_vec.push(Air::ListAccessor {
|
||||
tipo: tipo.clone(),
|
||||
|
@ -1237,12 +1223,11 @@ impl AirTree {
|
|||
expect_level: *expect_level,
|
||||
});
|
||||
|
||||
if let Some(msg) = msg {
|
||||
msg.to_air_tree().create_air_vec(air_vec);
|
||||
}
|
||||
|
||||
list.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
if matches!(expect_level, ExpectLevel::Full | ExpectLevel::Items) {
|
||||
otherwise.create_air_vec(air_vec);
|
||||
}
|
||||
}
|
||||
AirTree::ListExpose {
|
||||
tipo,
|
||||
|
@ -1261,9 +1246,9 @@ impl AirTree {
|
|||
names,
|
||||
tipo,
|
||||
tuple,
|
||||
msg,
|
||||
is_expect,
|
||||
then,
|
||||
otherwise,
|
||||
} => {
|
||||
air_vec.push(Air::TupleAccessor {
|
||||
names: names.clone(),
|
||||
|
@ -1271,21 +1256,20 @@ impl AirTree {
|
|||
is_expect: *is_expect,
|
||||
});
|
||||
|
||||
if let Some(msg) = msg {
|
||||
msg.to_air_tree().create_air_vec(air_vec);
|
||||
}
|
||||
|
||||
tuple.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
if *is_expect {
|
||||
otherwise.create_air_vec(air_vec);
|
||||
}
|
||||
}
|
||||
AirTree::PairAccessor {
|
||||
fst,
|
||||
snd,
|
||||
tipo,
|
||||
is_expect,
|
||||
msg,
|
||||
pair,
|
||||
then,
|
||||
otherwise,
|
||||
} => {
|
||||
air_vec.push(Air::PairAccessor {
|
||||
fst: fst.clone(),
|
||||
|
@ -1294,12 +1278,11 @@ impl AirTree {
|
|||
is_expect: *is_expect,
|
||||
});
|
||||
|
||||
if let Some(msg) = msg {
|
||||
msg.to_air_tree().create_air_vec(air_vec);
|
||||
}
|
||||
|
||||
pair.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
if *is_expect {
|
||||
otherwise.create_air_vec(air_vec);
|
||||
}
|
||||
}
|
||||
AirTree::FieldsEmpty { constr, msg, then } => {
|
||||
air_vec.push(Air::FieldsEmpty);
|
||||
|
@ -1311,15 +1294,16 @@ impl AirTree {
|
|||
constr.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
}
|
||||
AirTree::ListEmpty { list, msg, then } => {
|
||||
AirTree::ListEmpty {
|
||||
list,
|
||||
then,
|
||||
otherwise,
|
||||
} => {
|
||||
air_vec.push(Air::ListEmpty);
|
||||
|
||||
if let Some(msg) = msg {
|
||||
msg.to_air_tree().create_air_vec(air_vec);
|
||||
}
|
||||
|
||||
list.create_air_vec(air_vec);
|
||||
then.create_air_vec(air_vec);
|
||||
otherwise.create_air_vec(air_vec);
|
||||
}
|
||||
AirTree::NoOp { then } => {
|
||||
air_vec.push(Air::NoOp);
|
||||
|
@ -1417,17 +1401,15 @@ impl AirTree {
|
|||
air_vec.push(Air::UnOp { op: *op });
|
||||
arg.create_air_vec(air_vec);
|
||||
}
|
||||
AirTree::CastFromData { tipo, value, msg } => {
|
||||
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);
|
||||
}
|
||||
AirTree::CastFromData {
|
||||
tipo,
|
||||
value,
|
||||
otherwise,
|
||||
} => {
|
||||
air_vec.push(Air::CastFromData { tipo: tipo.clone() });
|
||||
|
||||
value.create_air_vec(air_vec);
|
||||
otherwise.create_air_vec(air_vec);
|
||||
}
|
||||
AirTree::CastToData { tipo, value } => {
|
||||
air_vec.push(Air::CastToData { tipo: tipo.clone() });
|
||||
|
@ -1532,7 +1514,7 @@ impl AirTree {
|
|||
}
|
||||
AirTree::If {
|
||||
tipo,
|
||||
pattern,
|
||||
condition: pattern,
|
||||
then,
|
||||
otherwise,
|
||||
} => {
|
||||
|
@ -2174,7 +2156,7 @@ impl AirTree {
|
|||
);
|
||||
}
|
||||
AirTree::If {
|
||||
pattern,
|
||||
condition: pattern,
|
||||
then,
|
||||
otherwise,
|
||||
..
|
||||
|
@ -2590,7 +2572,7 @@ impl AirTree {
|
|||
}
|
||||
}
|
||||
AirTree::If {
|
||||
pattern,
|
||||
condition: pattern,
|
||||
then,
|
||||
otherwise,
|
||||
..
|
||||
|
|
Loading…
Reference in New Issue