aiken/crates/aiken-lang/src/gen_uplc/tree.rs

3133 lines
98 KiB
Rust

use super::air::{Air, ExpectLevel};
use crate::{
ast::{BinOp, Curve, Span, UnOp},
builtins::{bool, byte_array, data, int, list, string, void},
tipo::{Type, ValueConstructor, ValueConstructorVariant},
};
use indexmap::IndexSet;
use itertools::Itertools;
use std::{borrow::BorrowMut, rc::Rc, slice::Iter};
use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction};
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum Fields {
FirstField,
SecondField,
ThirdField,
FourthField,
FifthField,
SixthField,
SeventhField,
EighthField,
ArgsField(usize),
}
#[derive(Clone, Debug, PartialEq)]
pub struct TreePath {
path: Vec<(usize, Fields)>,
}
impl TreePath {
pub fn new() -> Self {
TreePath { path: vec![] }
}
pub fn is_empty(&self) -> bool {
self.path.is_empty()
}
pub fn push(&mut self, depth: usize, index: Fields) {
self.path.push((depth, index));
}
pub fn pop(&mut self) -> Option<(usize, Fields)> {
self.path.pop()
}
pub fn common_ancestor(&self, other: &Self) -> Self {
let mut common_ancestor = TreePath::new();
let mut self_iter = self.path.iter();
let mut other_iter = other.path.iter();
let mut self_next = self_iter.next();
let mut other_next = other_iter.next();
while self_next.is_some() && other_next.is_some() {
let self_next_level = self_next.unwrap();
let other_next_level = other_next.unwrap();
if self_next_level == other_next_level {
common_ancestor.push(self_next_level.0, self_next_level.1);
} else {
break;
}
self_next = self_iter.next();
other_next = other_iter.next();
}
common_ancestor
}
}
impl Default for TreePath {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct IndexCounter {
current_index: usize,
}
impl IndexCounter {
pub fn new() -> Self {
IndexCounter { current_index: 0 }
}
/// Returns the next of this [`IndexCounter`].
pub fn next_number(&mut self) -> usize {
let current_index = self.current_index;
self.current_index += 1;
current_index
}
}
impl Default for IndexCounter {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum AirMsg {
LocalVar(String),
Msg(String),
}
impl AirMsg {
pub fn to_air_tree(&self) -> AirTree {
match self {
AirMsg::LocalVar(name) => AirTree::local_var(name, string()),
AirMsg::Msg(msg) => AirTree::string(msg),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum AirTree {
// Statements
Let {
name: String,
value: Box<AirTree>,
then: Box<AirTree>,
},
DefineFunc {
func_name: String,
module_name: String,
params: Vec<String>,
recursive: bool,
recursive_nonstatic_params: Vec<String>,
variant_name: String,
func_body: Box<AirTree>,
then: Box<AirTree>,
},
DefineCyclicFuncs {
func_name: String,
module_name: String,
variant_name: String,
// params and body
contained_functions: Vec<(Vec<String>, AirTree)>,
then: Box<AirTree>,
},
// Assertions
AssertConstr {
constr_index: usize,
constr: Box<AirTree>,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
AssertBool {
is_true: bool,
value: Box<AirTree>,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
// Clause Guards
ClauseGuard {
subject_name: String,
subject_tipo: Rc<Type>,
pattern: Box<AirTree>,
then: Box<AirTree>,
},
ListClauseGuard {
subject_tipo: Rc<Type>,
tail_name: String,
next_tail_name: Option<String>,
inverse: bool,
then: Box<AirTree>,
},
TupleGuard {
subject_tipo: Rc<Type>,
indices: IndexSet<(usize, String)>,
subject_name: String,
then: Box<AirTree>,
},
PairGuard {
subject_tipo: Rc<Type>,
subject_name: String,
fst_name: Option<String>,
snd_name: Option<String>,
then: Box<AirTree>,
},
// Field Access
FieldsExpose {
indices: Vec<(usize, String, Rc<Type>)>,
record: Box<AirTree>,
is_expect: bool,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
// List Access
ListAccessor {
tipo: Rc<Type>,
names: Vec<String>,
tail: bool,
list: Box<AirTree>,
expect_level: ExpectLevel,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
ListExpose {
tipo: Rc<Type>,
tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>,
then: Box<AirTree>,
},
// Tuple Access
TupleAccessor {
names: Vec<String>,
tipo: Rc<Type>,
tuple: Box<AirTree>,
is_expect: bool,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
// Pair Access
PairAccessor {
fst: Option<String>,
snd: Option<String>,
tipo: Rc<Type>,
is_expect: bool,
pair: Box<AirTree>,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
// Misc.
FieldsEmpty {
constr: Box<AirTree>,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
ListEmpty {
list: Box<AirTree>,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
NoOp {
then: Box<AirTree>,
},
// End Statements
// Expressions
// Primitives
Int {
value: String,
},
String {
value: String,
},
ByteArray {
bytes: Vec<u8>,
},
CurvePoint {
point: Curve,
},
Bool {
value: bool,
},
List {
tipo: Rc<Type>,
tail: bool,
items: Vec<AirTree>,
},
Tuple {
tipo: Rc<Type>,
items: Vec<AirTree>,
},
Pair {
tipo: Rc<Type>,
fst: Box<AirTree>,
snd: Box<AirTree>,
},
Void,
Var {
constructor: ValueConstructor,
name: String,
variant_name: String,
},
// Functions
Call {
tipo: Rc<Type>,
func: Box<AirTree>,
args: Vec<AirTree>,
},
Fn {
params: Vec<String>,
func_body: Box<AirTree>,
allow_inline: bool,
},
Builtin {
func: DefaultFunction,
tipo: Rc<Type>,
args: Vec<AirTree>,
},
// Operators
BinOp {
name: BinOp,
tipo: Rc<Type>,
left: Box<AirTree>,
right: Box<AirTree>,
argument_tipo: Rc<Type>,
},
UnOp {
op: UnOp,
arg: Box<AirTree>,
},
CastFromData {
tipo: Rc<Type>,
value: Box<AirTree>,
otherwise: Box<AirTree>,
full_cast: bool,
},
CastToData {
tipo: Rc<Type>,
value: Box<AirTree>,
},
// When
When {
tipo: Rc<Type>,
subject_name: String,
subject: Box<AirTree>,
subject_tipo: Rc<Type>,
clauses: Box<AirTree>,
},
Clause {
subject_tipo: Rc<Type>,
subject_name: String,
complex_clause: bool,
pattern: Box<AirTree>,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
ListClause {
subject_tipo: Rc<Type>,
tail_name: String,
next_tail_name: Option<(String, String)>,
complex_clause: bool,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
WrapClause {
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
TupleClause {
subject_tipo: Rc<Type>,
indices: IndexSet<(usize, String)>,
predefined_indices: IndexSet<(usize, String)>,
subject_name: String,
complex_clause: bool,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
PairClause {
subject_tipo: Rc<Type>,
subject_name: String,
fst_name: Option<String>,
snd_name: Option<String>,
complex_clause: bool,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
Finally {
pattern: Box<AirTree>,
then: Box<AirTree>,
},
// If
If {
tipo: Rc<Type>,
condition: Box<AirTree>,
then: Box<AirTree>,
otherwise: Box<AirTree>,
},
// Record Creation
Constr {
tag: usize,
tipo: Rc<Type>,
args: Vec<AirTree>,
},
RecordUpdate {
highest_index: usize,
indices: Vec<(usize, Rc<Type>)>,
tipo: Rc<Type>,
record: Box<AirTree>,
args: Vec<AirTree>,
},
// Misc.
ErrorTerm {
tipo: Rc<Type>,
validator: bool,
},
Trace {
tipo: Rc<Type>,
msg: Box<AirTree>,
then: Box<AirTree>,
},
// End Expressions
MultiValidator {
two_arg_name: String,
two_arg: Box<AirTree>,
three_arg_name: String,
three_arg: Box<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(),
}
}
pub fn string(value: impl ToString) -> AirTree {
AirTree::String {
value: value.to_string(),
}
}
pub fn byte_array(bytes: Vec<u8>) -> AirTree {
AirTree::ByteArray { bytes }
}
pub fn curve(point: Curve) -> AirTree {
AirTree::CurvePoint { point }
}
pub fn bool(value: bool) -> AirTree {
AirTree::Bool { value }
}
pub fn list(mut items: Vec<AirTree>, tipo: Rc<Type>, tail: Option<AirTree>) -> AirTree {
if let Some(tail) = tail {
items.push(tail);
AirTree::List {
tipo,
tail: true,
items,
}
} else {
AirTree::List {
tipo,
tail: false,
items,
}
}
}
pub fn tuple(items: Vec<AirTree>, tipo: Rc<Type>) -> AirTree {
AirTree::Tuple { tipo, items }
}
pub fn pair(fst: AirTree, snd: AirTree, tipo: Rc<Type>) -> AirTree {
AirTree::Pair {
tipo,
fst: fst.into(),
snd: snd.into(),
}
}
pub fn void() -> AirTree {
AirTree::Void
}
pub fn var(
constructor: ValueConstructor,
name: impl ToString,
variant_name: impl ToString,
) -> AirTree {
AirTree::Var {
constructor,
name: name.to_string(),
variant_name: variant_name.to_string(),
}
}
pub fn local_var(name: impl ToString, tipo: Rc<Type>) -> AirTree {
AirTree::Var {
constructor: ValueConstructor::public(
tipo,
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: name.to_string(),
variant_name: "".to_string(),
}
}
pub fn call(func: AirTree, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Call {
tipo,
func: func.into(),
args,
}
}
#[allow(clippy::too_many_arguments)]
pub fn define_func(
func_name: impl ToString,
module_name: impl ToString,
variant_name: impl ToString,
params: Vec<String>,
recursive: bool,
recursive_nonstatic_params: Vec<String>,
func_body: AirTree,
then: AirTree,
) -> AirTree {
AirTree::DefineFunc {
func_name: func_name.to_string(),
module_name: module_name.to_string(),
params,
recursive,
recursive_nonstatic_params,
variant_name: variant_name.to_string(),
func_body: func_body.into(),
then: then.into(),
}
}
pub fn define_cyclic_func(
func_name: impl ToString,
module_name: impl ToString,
variant_name: impl ToString,
contained_functions: Vec<(Vec<String>, AirTree)>,
then: AirTree,
) -> AirTree {
AirTree::DefineCyclicFuncs {
func_name: func_name.to_string(),
module_name: module_name.to_string(),
variant_name: variant_name.to_string(),
contained_functions,
then: then.into(),
}
}
pub fn anon_func(params: Vec<String>, func_body: AirTree, allow_inline: bool) -> AirTree {
AirTree::Fn {
params,
func_body: func_body.into(),
allow_inline,
}
}
pub fn builtin(func: DefaultFunction, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Builtin { func, tipo, args }
}
pub fn binop(
op: BinOp,
tipo: Rc<Type>,
left: AirTree,
right: AirTree,
argument_tipo: Rc<Type>,
) -> AirTree {
AirTree::BinOp {
name: op,
tipo,
left: left.into(),
right: right.into(),
argument_tipo,
}
}
pub fn unop(op: UnOp, arg: AirTree) -> AirTree {
AirTree::UnOp {
op,
arg: arg.into(),
}
}
pub fn let_assignment(name: impl ToString, value: AirTree, then: AirTree) -> AirTree {
AirTree::Let {
name: name.to_string(),
value: value.into(),
then: then.into(),
}
}
pub fn cast_from_data(
value: AirTree,
tipo: Rc<Type>,
otherwise: AirTree,
full_cast: bool,
) -> AirTree {
AirTree::CastFromData {
tipo,
value: value.into(),
otherwise: otherwise.into(),
full_cast,
}
}
pub fn cast_to_data(value: AirTree, tipo: Rc<Type>) -> AirTree {
AirTree::CastToData {
tipo,
value: value.into(),
}
}
pub fn assert_constr_index(
constr_index: usize,
constr: AirTree,
then: AirTree,
otherwise: AirTree,
) -> AirTree {
AirTree::AssertConstr {
constr_index,
constr: constr.into(),
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn assert_bool(
is_true: bool,
value: AirTree,
then: AirTree,
otherwise: AirTree,
) -> AirTree {
AirTree::AssertBool {
is_true,
value: value.into(),
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn when(
subject_name: impl ToString,
tipo: Rc<Type>,
subject_tipo: Rc<Type>,
subject: AirTree,
clauses: AirTree,
) -> AirTree {
AirTree::When {
tipo,
subject_name: subject_name.to_string(),
subject: subject.into(),
subject_tipo,
clauses: clauses.into(),
}
}
pub fn clause(
subject_name: impl ToString,
pattern: AirTree,
subject_tipo: Rc<Type>,
then: AirTree,
otherwise: AirTree,
complex_clause: bool,
) -> AirTree {
AirTree::Clause {
subject_tipo,
subject_name: subject_name.to_string(),
complex_clause,
pattern: pattern.into(),
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn list_clause(
tail_name: impl ToString,
subject_tipo: Rc<Type>,
then: AirTree,
otherwise: AirTree,
next_tail_name: Option<(String, String)>,
complex_clause: bool,
) -> AirTree {
AirTree::ListClause {
subject_tipo,
tail_name: tail_name.to_string(),
next_tail_name,
complex_clause,
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn tuple_clause(
subject_name: impl ToString,
subject_tipo: Rc<Type>,
indices: IndexSet<(usize, String)>,
predefined_indices: IndexSet<(usize, String)>,
then: AirTree,
otherwise: AirTree,
complex_clause: bool,
) -> AirTree {
AirTree::TupleClause {
subject_tipo,
indices,
predefined_indices,
subject_name: subject_name.to_string(),
complex_clause,
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn pair_clause(
subject_name: impl ToString,
subject_tipo: Rc<Type>,
fst_name: Option<String>,
snd_name: Option<String>,
then: AirTree,
otherwise: AirTree,
complex_clause: bool,
) -> AirTree {
AirTree::PairClause {
subject_tipo,
subject_name: subject_name.to_string(),
fst_name,
snd_name,
complex_clause,
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn wrap_clause(then: AirTree, otherwise: AirTree) -> AirTree {
AirTree::WrapClause {
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn clause_guard(
subject_name: impl ToString,
pattern: AirTree,
subject_tipo: Rc<Type>,
then: AirTree,
) -> AirTree {
AirTree::ClauseGuard {
subject_name: subject_name.to_string(),
subject_tipo,
pattern: pattern.into(),
then: then.into(),
}
}
pub fn list_clause_guard(
tail_name: impl ToString,
subject_tipo: Rc<Type>,
inverse: bool,
next_tail_name: Option<String>,
then: AirTree,
) -> AirTree {
AirTree::ListClauseGuard {
subject_tipo,
tail_name: tail_name.to_string(),
next_tail_name,
inverse,
then: then.into(),
}
}
pub fn tuple_clause_guard(
subject_name: impl ToString,
subject_tipo: Rc<Type>,
indices: IndexSet<(usize, String)>,
then: AirTree,
) -> AirTree {
AirTree::TupleGuard {
indices,
subject_name: subject_name.to_string(),
subject_tipo,
then: then.into(),
}
}
pub fn pair_clause_guard(
subject_name: impl ToString,
subject_tipo: Rc<Type>,
fst_name: Option<String>,
snd_name: Option<String>,
then: AirTree,
) -> AirTree {
AirTree::PairGuard {
subject_name: subject_name.to_string(),
subject_tipo,
fst_name,
snd_name,
then: then.into(),
}
}
pub fn finally(pattern: AirTree, then: AirTree) -> AirTree {
AirTree::Finally {
pattern: pattern.into(),
then: then.into(),
}
}
pub fn if_branch(
tipo: Rc<Type>,
condition: AirTree,
branch: AirTree,
otherwise: AirTree,
) -> AirTree {
AirTree::If {
tipo,
condition: condition.into(),
then: branch.into(),
otherwise: otherwise.into(),
}
}
pub fn create_constr(tag: usize, tipo: Rc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Constr { tag, tipo, args }
}
pub fn record_update(
indices: Vec<(usize, Rc<Type>)>,
highest_index: usize,
tipo: Rc<Type>,
record: AirTree,
args: Vec<AirTree>,
) -> AirTree {
AirTree::RecordUpdate {
highest_index,
indices,
tipo,
record: record.into(),
args,
}
}
pub fn index_access(function_name: String, tipo: Rc<Type>, list_of_fields: AirTree) -> AirTree {
AirTree::cast_from_data(
AirTree::call(
AirTree::var(
ValueConstructor::public(
Type::Fn {
args: vec![list(data())],
ret: data(),
alias: None,
}
.into(),
ValueConstructorVariant::ModuleFn {
name: function_name.clone(),
field_map: None,
module: "".to_string(),
arity: 1,
location: Span::empty(),
builtin: None,
},
),
function_name,
"",
),
data(),
vec![list_of_fields],
),
tipo.clone(),
AirTree::error(void(), false),
false,
)
}
pub fn fields_expose(
indices: Vec<(usize, String, Rc<Type>)>,
record: AirTree,
is_expect: bool,
then: AirTree,
otherwise: AirTree,
) -> AirTree {
AirTree::FieldsExpose {
indices,
record: record.into(),
is_expect,
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn list_access(
names: Vec<String>,
tipo: Rc<Type>,
tail: bool,
list: AirTree,
expect_level: ExpectLevel,
then: AirTree,
otherwise: AirTree,
) -> AirTree {
AirTree::ListAccessor {
tipo,
names,
tail,
list: list.into(),
expect_level,
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn list_expose(
tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>,
tipo: Rc<Type>,
then: AirTree,
) -> AirTree {
AirTree::ListExpose {
tipo,
tail_head_names,
tail,
then: then.into(),
}
}
pub fn tuple_access(
names: Vec<String>,
tipo: Rc<Type>,
tuple: AirTree,
is_expect: bool,
then: AirTree,
otherwise: AirTree,
) -> AirTree {
AirTree::TupleAccessor {
names,
tipo,
tuple: tuple.into(),
is_expect,
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn pair_access(
fst: Option<String>,
snd: Option<String>,
tipo: Rc<Type>,
pair: AirTree,
is_expect: bool,
then: AirTree,
otherwise: AirTree,
) -> AirTree {
AirTree::PairAccessor {
fst,
snd,
tipo,
is_expect,
pair: pair.into(),
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn pair_index(index: usize, tipo: Rc<Type>, tuple: AirTree) -> AirTree {
AirTree::cast_from_data(
AirTree::builtin(
if index == 0 {
DefaultFunction::FstPair
} else {
DefaultFunction::SndPair
},
data(),
vec![tuple],
),
tipo.clone(),
AirTree::error(void(), false),
false,
)
}
pub fn error(tipo: Rc<Type>, validator: bool) -> AirTree {
AirTree::ErrorTerm { tipo, validator }
}
pub fn trace(msg: AirTree, tipo: Rc<Type>, then: AirTree) -> AirTree {
AirTree::Trace {
tipo,
msg: msg.into(),
then: then.into(),
}
}
pub fn no_op(then: AirTree) -> AirTree {
AirTree::NoOp { then: then.into() }
}
pub fn fields_empty(constr: AirTree, then: AirTree, otherwise: AirTree) -> AirTree {
AirTree::FieldsEmpty {
constr: constr.into(),
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn list_empty(list: AirTree, then: AirTree, otherwise: AirTree) -> AirTree {
AirTree::ListEmpty {
list: list.into(),
then: then.into(),
otherwise: otherwise.into(),
}
}
pub fn multi_validator(
two_arg_name: String,
two_arg: AirTree,
three_arg_name: String,
three_arg: AirTree,
) -> AirTree {
AirTree::MultiValidator {
two_arg_name,
two_arg: two_arg.into(),
three_arg_name,
three_arg: three_arg.into(),
}
}
pub fn expect_on_list() -> AirTree {
let list_var = AirTree::local_var("__list_to_check", list(data()));
let head_list = AirTree::builtin(DefaultFunction::HeadList, data(), vec![list_var]);
let expect_on_head = AirTree::call(
AirTree::local_var("__check_with", void()),
void(),
vec![head_list],
);
let next_call = AirTree::call(
AirTree::var(
ValueConstructor::public(
void(),
ValueConstructorVariant::ModuleFn {
name: EXPECT_ON_LIST.to_string(),
field_map: None,
module: "".to_string(),
arity: 1,
location: Span::empty(),
builtin: None,
},
),
EXPECT_ON_LIST,
"",
),
void(),
vec![
AirTree::builtin(
DefaultFunction::TailList,
list(data()),
vec![AirTree::local_var("__list_to_check", list(data()))],
),
AirTree::local_var("__check_with", void()),
],
);
let assign = AirTree::let_assignment("_", expect_on_head, next_call);
AirTree::list_clause(
"__list_to_check",
void(),
AirTree::void(),
assign,
None,
false,
)
}
pub fn to_vec(&self) -> Vec<Air> {
let mut air_vec = vec![];
self.create_air_vec(&mut air_vec);
air_vec
}
fn create_air_vec(&self, air_vec: &mut Vec<Air>) {
match self {
AirTree::Let { name, value, then } => {
air_vec.push(Air::Let { name: name.clone() });
value.create_air_vec(air_vec);
then.create_air_vec(air_vec);
}
AirTree::DefineFunc {
func_name,
module_name,
params,
recursive,
recursive_nonstatic_params,
variant_name,
func_body,
then,
} => {
air_vec.push(Air::DefineFunc {
func_name: func_name.clone(),
module_name: module_name.clone(),
params: params.clone(),
recursive: *recursive,
recursive_nonstatic_params: recursive_nonstatic_params.clone(),
variant_name: variant_name.clone(),
});
func_body.create_air_vec(air_vec);
then.create_air_vec(air_vec);
}
AirTree::DefineCyclicFuncs {
func_name,
module_name,
variant_name,
contained_functions,
then,
} => {
air_vec.push(Air::DefineCyclicFuncs {
func_name: func_name.clone(),
module_name: module_name.clone(),
variant_name: variant_name.clone(),
contained_functions: contained_functions
.iter()
.map(|(params, _)| params.clone())
.collect_vec(),
});
for (_, func_body) in contained_functions {
func_body.create_air_vec(air_vec);
}
then.create_air_vec(air_vec);
}
AirTree::AssertConstr {
constr,
constr_index,
then,
otherwise,
} => {
air_vec.push(Air::AssertConstr {
constr_index: *constr_index,
});
// msg is first so we can pop it off first in uplc_gen
// if traces are on
constr.create_air_vec(air_vec);
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::AssertBool {
is_true,
value,
then,
otherwise,
} => {
air_vec.push(Air::AssertBool { is_true: *is_true });
value.create_air_vec(air_vec);
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::ClauseGuard {
subject_name,
subject_tipo,
pattern,
then,
} => {
air_vec.push(Air::ClauseGuard {
subject_name: subject_name.clone(),
subject_tipo: subject_tipo.clone(),
});
pattern.create_air_vec(air_vec);
then.create_air_vec(air_vec);
}
AirTree::ListClauseGuard {
subject_tipo,
tail_name,
next_tail_name,
inverse,
then,
} => {
air_vec.push(Air::ListClauseGuard {
subject_tipo: subject_tipo.clone(),
tail_name: tail_name.clone(),
next_tail_name: next_tail_name.clone(),
inverse: *inverse,
});
then.create_air_vec(air_vec);
}
AirTree::TupleGuard {
subject_tipo,
indices,
subject_name,
then,
} => {
air_vec.push(Air::TupleGuard {
subject_tipo: subject_tipo.clone(),
indices: indices.clone(),
subject_name: subject_name.clone(),
});
then.create_air_vec(air_vec);
}
AirTree::PairGuard {
subject_tipo,
subject_name,
fst_name,
snd_name,
then,
} => {
air_vec.push(Air::PairGuard {
subject_tipo: subject_tipo.clone(),
subject_name: subject_name.clone(),
fst_name: fst_name.clone(),
snd_name: snd_name.clone(),
});
then.create_air_vec(air_vec);
}
AirTree::FieldsExpose {
indices,
record,
is_expect,
then,
otherwise,
} => {
air_vec.push(Air::FieldsExpose {
indices: indices.clone(),
is_expect: *is_expect,
});
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,
expect_level,
then,
otherwise,
} => {
air_vec.push(Air::ListAccessor {
tipo: tipo.clone(),
names: names.clone(),
tail: *tail,
expect_level: *expect_level,
});
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,
tail_head_names,
tail,
then,
} => {
air_vec.push(Air::ListExpose {
tipo: tipo.clone(),
tail_head_names: tail_head_names.clone(),
tail: tail.clone(),
});
then.create_air_vec(air_vec);
}
AirTree::TupleAccessor {
names,
tipo,
tuple,
is_expect,
then,
otherwise,
} => {
air_vec.push(Air::TupleAccessor {
names: names.clone(),
tipo: tipo.clone(),
is_expect: *is_expect,
});
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,
pair,
then,
otherwise,
} => {
air_vec.push(Air::PairAccessor {
fst: fst.clone(),
snd: snd.clone(),
tipo: tipo.clone(),
is_expect: *is_expect,
});
pair.create_air_vec(air_vec);
then.create_air_vec(air_vec);
if *is_expect {
otherwise.create_air_vec(air_vec);
}
}
AirTree::FieldsEmpty {
constr,
then,
otherwise,
} => {
air_vec.push(Air::FieldsEmpty);
constr.create_air_vec(air_vec);
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::ListEmpty {
list,
then,
otherwise,
} => {
air_vec.push(Air::ListEmpty);
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);
then.create_air_vec(air_vec);
}
AirTree::Int { value } => air_vec.push(Air::Int {
value: value.clone(),
}),
AirTree::String { value } => air_vec.push(Air::String {
value: value.clone(),
}),
AirTree::ByteArray { bytes } => air_vec.push(Air::ByteArray {
bytes: bytes.clone(),
}),
AirTree::CurvePoint { point } => air_vec.push(Air::CurvePoint { point: *point }),
AirTree::Bool { value } => air_vec.push(Air::Bool { value: *value }),
AirTree::List { tipo, tail, items } => {
air_vec.push(Air::List {
count: items.len(),
tipo: tipo.clone(),
tail: *tail,
});
for item in items {
item.create_air_vec(air_vec);
}
}
AirTree::Tuple { tipo, items } => {
air_vec.push(Air::Tuple {
tipo: tipo.clone(),
count: items.len(),
});
for item in items {
item.create_air_vec(air_vec);
}
}
AirTree::Pair { tipo, fst, snd } => {
air_vec.push(Air::Pair { tipo: tipo.clone() });
fst.create_air_vec(air_vec);
snd.create_air_vec(air_vec);
}
AirTree::Void => air_vec.push(Air::Void),
AirTree::Var {
constructor,
name,
variant_name,
} => air_vec.push(Air::Var {
constructor: constructor.clone(),
name: name.clone(),
variant_name: variant_name.clone(),
}),
AirTree::Call { tipo, func, args } => {
air_vec.push(Air::Call {
count: args.len(),
tipo: tipo.clone(),
});
func.create_air_vec(air_vec);
for arg in args {
arg.create_air_vec(air_vec);
}
}
AirTree::Fn {
params,
func_body,
allow_inline,
} => {
air_vec.push(Air::Fn {
params: params.clone(),
allow_inline: *allow_inline,
});
func_body.create_air_vec(air_vec);
}
AirTree::Builtin { func, tipo, args } => {
air_vec.push(Air::Builtin {
count: args.len(),
func: *func,
tipo: tipo.clone(),
});
for arg in args {
arg.create_air_vec(air_vec);
}
}
AirTree::BinOp {
name,
tipo,
left,
right,
argument_tipo,
} => {
air_vec.push(Air::BinOp {
name: *name,
tipo: tipo.clone(),
argument_tipo: argument_tipo.clone(),
});
left.create_air_vec(air_vec);
right.create_air_vec(air_vec);
}
AirTree::UnOp { op, arg } => {
air_vec.push(Air::UnOp { op: *op });
arg.create_air_vec(air_vec);
}
AirTree::CastFromData {
tipo,
value,
otherwise,
full_cast,
} => {
air_vec.push(Air::CastFromData {
tipo: tipo.clone(),
full_cast: *full_cast,
});
value.create_air_vec(air_vec);
if *full_cast {
otherwise.create_air_vec(air_vec);
}
}
AirTree::CastToData { tipo, value } => {
air_vec.push(Air::CastToData { tipo: tipo.clone() });
value.create_air_vec(air_vec);
}
AirTree::When {
tipo,
subject_name,
subject,
subject_tipo,
clauses,
} => {
air_vec.push(Air::When {
tipo: tipo.clone(),
subject_name: subject_name.clone(),
subject_tipo: subject_tipo.clone(),
});
subject.create_air_vec(air_vec);
clauses.create_air_vec(air_vec);
}
AirTree::Clause {
subject_tipo,
subject_name,
complex_clause,
pattern,
then,
otherwise,
} => {
air_vec.push(Air::Clause {
subject_tipo: subject_tipo.clone(),
subject_name: subject_name.clone(),
complex_clause: *complex_clause,
});
pattern.create_air_vec(air_vec);
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::ListClause {
subject_tipo,
tail_name,
next_tail_name,
complex_clause,
then,
otherwise,
} => {
air_vec.push(Air::ListClause {
subject_tipo: subject_tipo.clone(),
tail_name: tail_name.clone(),
next_tail_name: next_tail_name.clone(),
complex_clause: *complex_clause,
});
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::WrapClause { then, otherwise } => {
air_vec.push(Air::WrapClause);
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::TupleClause {
subject_tipo,
indices,
predefined_indices,
subject_name,
complex_clause,
then,
otherwise,
} => {
air_vec.push(Air::TupleClause {
subject_tipo: subject_tipo.clone(),
indices: indices.clone(),
predefined_indices: predefined_indices.clone(),
subject_name: subject_name.clone(),
complex_clause: *complex_clause,
});
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::PairClause {
subject_tipo,
subject_name,
fst_name,
snd_name,
complex_clause,
then,
otherwise,
} => {
air_vec.push(Air::PairClause {
subject_tipo: subject_tipo.clone(),
subject_name: subject_name.clone(),
fst_name: fst_name.clone(),
snd_name: snd_name.clone(),
complex_clause: *complex_clause,
});
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::Finally { pattern, then } => {
air_vec.push(Air::Finally);
pattern.create_air_vec(air_vec);
then.create_air_vec(air_vec);
}
AirTree::If {
tipo,
condition: pattern,
then,
otherwise,
} => {
air_vec.push(Air::If { tipo: tipo.clone() });
pattern.create_air_vec(air_vec);
then.create_air_vec(air_vec);
otherwise.create_air_vec(air_vec);
}
AirTree::Constr { tag, tipo, args } => {
air_vec.push(Air::Constr {
tag: *tag,
tipo: tipo.clone(),
count: args.len(),
});
for arg in args {
arg.create_air_vec(air_vec);
}
}
AirTree::RecordUpdate {
highest_index,
indices,
tipo,
record,
args,
} => {
air_vec.push(Air::RecordUpdate {
highest_index: *highest_index,
indices: indices.clone(),
tipo: tipo.clone(),
});
record.create_air_vec(air_vec);
for arg in args {
arg.create_air_vec(air_vec);
}
}
AirTree::ErrorTerm { tipo, validator } => air_vec.push(Air::ErrorTerm {
tipo: tipo.clone(),
validator: *validator,
}),
AirTree::Trace { tipo, msg, then } => {
air_vec.push(Air::Trace { tipo: tipo.clone() });
msg.create_air_vec(air_vec);
then.create_air_vec(air_vec);
}
AirTree::MultiValidator {
two_arg,
three_arg,
two_arg_name,
three_arg_name,
} => {
air_vec.push(Air::MultiValidator {
two_arg_name: two_arg_name.clone(),
three_arg_name: three_arg_name.clone(),
});
two_arg.create_air_vec(air_vec);
three_arg.create_air_vec(air_vec);
}
}
}
pub fn return_type(&self) -> Rc<Type> {
match self {
AirTree::Int { .. } => int(),
AirTree::String { .. } => string(),
AirTree::ByteArray { .. } => byte_array(),
AirTree::Bool { .. } => bool(),
AirTree::CurvePoint { point } => point.tipo(),
AirTree::List { tipo, .. }
| AirTree::Tuple { tipo, .. }
| AirTree::Pair { tipo, .. }
| AirTree::Call { tipo, .. }
| AirTree::Builtin { tipo, .. }
| AirTree::BinOp { tipo, .. }
| AirTree::CastFromData { tipo, .. }
| AirTree::When { tipo, .. }
| AirTree::If { tipo, .. }
| AirTree::Constr { tipo, .. }
| AirTree::RecordUpdate { tipo, .. }
| AirTree::ErrorTerm { tipo, .. }
| AirTree::Trace { tipo, .. } => tipo.clone(),
AirTree::Void => void(),
AirTree::Var { constructor, .. } => constructor.tipo.clone(),
AirTree::Fn { func_body, .. } => func_body.return_type(),
AirTree::UnOp { op, .. } => match op {
UnOp::Not => bool(),
UnOp::Negate => int(),
},
AirTree::CastToData { .. } => data(),
AirTree::Clause { then, .. }
| AirTree::ListClause { then, .. }
| AirTree::WrapClause { then, .. }
| AirTree::TupleClause { then, .. }
| AirTree::PairClause { then, .. }
| AirTree::Finally { then, .. }
| AirTree::Let { then, .. }
| AirTree::DefineFunc { then, .. }
| AirTree::DefineCyclicFuncs { then, .. }
| AirTree::AssertConstr { then, .. }
| AirTree::AssertBool { then, .. }
| AirTree::ClauseGuard { then, .. }
| AirTree::ListClauseGuard { then, .. }
| AirTree::TupleGuard { then, .. }
| AirTree::PairGuard { then, .. }
| AirTree::FieldsExpose { then, .. }
| AirTree::ListAccessor { then, .. }
| AirTree::ListExpose { then, .. }
| AirTree::TupleAccessor { then, .. }
| AirTree::PairAccessor { then, .. }
| AirTree::FieldsEmpty { then, .. }
| AirTree::ListEmpty { then, .. }
| AirTree::NoOp { then } => then.return_type(),
AirTree::MultiValidator { .. } => void(),
}
}
pub fn mut_held_types(&mut self) -> Vec<&mut Rc<Type>> {
match self {
AirTree::ClauseGuard { subject_tipo, .. }
| AirTree::ListClauseGuard { subject_tipo, .. }
| AirTree::PairGuard { subject_tipo, .. }
| AirTree::TupleGuard { subject_tipo, .. }
| AirTree::Clause { subject_tipo, .. }
| AirTree::ListClause { subject_tipo, .. }
| AirTree::TupleClause { subject_tipo, .. }
| AirTree::PairClause { subject_tipo, .. } => vec![subject_tipo],
AirTree::ListAccessor { tipo, .. }
| AirTree::ListExpose { tipo, .. }
| AirTree::TupleAccessor { tipo, .. }
| AirTree::PairAccessor { tipo, .. }
| AirTree::List { tipo, .. }
| AirTree::Tuple { tipo, .. }
| AirTree::Call { tipo, .. }
| AirTree::Builtin { tipo, .. }
| AirTree::CastFromData { tipo, .. }
| AirTree::CastToData { tipo, .. }
| AirTree::If { tipo, .. }
| AirTree::Constr { tipo, .. }
| AirTree::ErrorTerm { tipo, .. }
| AirTree::Trace { tipo, .. }
| AirTree::Pair { tipo, .. } => vec![tipo],
AirTree::FieldsExpose { indices, .. } => {
let mut types = vec![];
for (_, _, tipo) in indices {
types.push(tipo);
}
types
}
AirTree::Var { constructor, .. } => {
vec![constructor.tipo.borrow_mut()]
}
AirTree::BinOp {
tipo,
argument_tipo,
..
} => {
vec![tipo, argument_tipo]
}
AirTree::When {
tipo, subject_tipo, ..
} => vec![tipo, subject_tipo],
AirTree::RecordUpdate { tipo, indices, .. } => {
let mut types = vec![tipo];
for (_, tipo) in indices {
types.push(tipo);
}
types
}
AirTree::Let { .. }
| AirTree::DefineFunc { .. }
| AirTree::DefineCyclicFuncs { .. }
| AirTree::AssertConstr { .. }
| AirTree::AssertBool { .. }
| AirTree::FieldsEmpty { .. }
| AirTree::ListEmpty { .. }
| AirTree::NoOp { .. }
| AirTree::Int { .. }
| AirTree::String { .. }
| AirTree::ByteArray { .. }
| AirTree::CurvePoint { .. }
| AirTree::Bool { .. }
| AirTree::Void
| AirTree::Fn { .. }
| AirTree::UnOp { .. }
| AirTree::WrapClause { .. }
| AirTree::Finally { .. }
| AirTree::MultiValidator { .. } => vec![],
}
}
pub fn traverse_tree_with(
&mut self,
with: &mut impl FnMut(&mut AirTree, &TreePath),
apply_with_func_last: bool,
) {
let mut tree_path = TreePath::new();
self.do_traverse_tree_with(
&mut tree_path,
0,
Fields::FirstField,
with,
apply_with_func_last,
);
}
pub fn traverse_tree_with_path(
&mut self,
path: &mut TreePath,
current_depth: usize,
depth_index: Fields,
with: &mut impl FnMut(&mut AirTree, &TreePath),
apply_with_func_last: bool,
) {
self.do_traverse_tree_with(path, current_depth, depth_index, with, apply_with_func_last);
}
fn do_traverse_tree_with(
&mut self,
tree_path: &mut TreePath,
current_depth: usize,
field_index: Fields,
with: &mut impl FnMut(&mut AirTree, &TreePath),
apply_with_func_last: bool,
) {
tree_path.push(current_depth, field_index);
// Assignments'/Statements' values get traversed here
// Then the body under these assignments/statements get traversed later on
match self {
AirTree::Let {
name: _,
value,
then: _,
} => {
value.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
}
AirTree::AssertConstr {
constr_index: _,
constr,
then: _,
otherwise,
} => {
constr.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
)
}
AirTree::AssertBool {
is_true: _,
value,
then: _,
otherwise,
} => {
value.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
)
}
AirTree::ClauseGuard {
subject_name: _,
subject_tipo: _,
pattern,
then: _,
} => {
pattern.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
}
AirTree::FieldsExpose {
indices: _,
record,
is_expect: _,
then: _,
otherwise,
} => {
record.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FifthField,
with,
apply_with_func_last,
)
}
AirTree::ListAccessor {
tipo: _,
names: _,
tail: _,
list,
expect_level: _,
then: _,
otherwise,
} => {
list.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SeventhField,
with,
apply_with_func_last,
)
}
AirTree::TupleAccessor {
names: _,
tipo: _,
tuple,
is_expect: _,
then: _,
otherwise,
} => {
tuple.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SixthField,
with,
apply_with_func_last,
)
}
AirTree::PairAccessor {
fst: _,
snd: _,
tipo: _,
is_expect: _,
pair,
then: _,
otherwise,
} => {
pair.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FifthField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SeventhField,
with,
apply_with_func_last,
)
}
AirTree::FieldsEmpty {
constr,
then: _,
otherwise,
} => {
constr.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FirstField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
}
AirTree::ListEmpty {
list,
then: _,
otherwise,
} => {
list.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FirstField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
)
}
AirTree::When {
tipo: _,
subject_name: _,
subject,
subject_tipo: _,
clauses: _,
} => subject.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
),
AirTree::TupleClause {
subject_tipo: _,
indices: _,
predefined_indices: _,
subject_name: _,
complex_clause: _,
then: _,
otherwise,
} => {
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SeventhField,
with,
apply_with_func_last,
);
}
AirTree::PairClause {
subject_tipo: _,
subject_name: _,
fst_name: _,
snd_name: _,
complex_clause: _,
then: _,
otherwise,
} => {
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SeventhField,
with,
apply_with_func_last,
);
}
AirTree::DefineFunc { .. }
| AirTree::DefineCyclicFuncs { .. }
| AirTree::ListClauseGuard { .. }
| AirTree::TupleGuard { .. }
| AirTree::PairGuard { .. }
| AirTree::ListExpose { .. }
| AirTree::NoOp { .. }
| AirTree::Int { .. }
| AirTree::String { .. }
| AirTree::ByteArray { .. }
| AirTree::CurvePoint { .. }
| AirTree::Bool { .. }
| AirTree::List { .. }
| AirTree::Tuple { .. }
| AirTree::Pair { .. }
| AirTree::Void
| AirTree::Var { .. }
| AirTree::Call { .. }
| AirTree::Fn { .. }
| AirTree::Builtin { .. }
| AirTree::BinOp { .. }
| AirTree::UnOp { .. }
| AirTree::CastFromData { .. }
| AirTree::CastToData { .. }
| AirTree::Clause { .. }
| AirTree::ListClause { .. }
| AirTree::WrapClause { .. }
| AirTree::Finally { .. }
| AirTree::If { .. }
| AirTree::Constr { .. }
| AirTree::RecordUpdate { .. }
| AirTree::ErrorTerm { .. }
| AirTree::Trace { .. }
| AirTree::MultiValidator { .. } => {}
}
if !apply_with_func_last {
with(self, tree_path);
}
// Expressions or an assignment that hoist over a expression are traversed here
match self {
AirTree::NoOp { then } => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FirstField,
with,
apply_with_func_last,
);
}
AirTree::When {
tipo: _,
subject_name: _,
subject: _,
subject_tipo: _,
clauses,
} => {
clauses.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FifthField,
with,
apply_with_func_last,
);
}
AirTree::TupleClause {
subject_tipo: _,
indices: _,
predefined_indices: _,
subject_name: _,
complex_clause: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SixthField,
with,
apply_with_func_last,
);
}
AirTree::PairClause {
subject_tipo: _,
subject_name: _,
fst_name: _,
snd_name: _,
complex_clause: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SixthField,
with,
apply_with_func_last,
);
}
AirTree::List {
tipo: _,
tail: _,
items,
} => {
for (index, item) in items.iter_mut().enumerate() {
item.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ArgsField(index),
with,
apply_with_func_last,
);
}
}
AirTree::Tuple { tipo: _, items } => {
for (index, item) in items.iter_mut().enumerate() {
item.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ArgsField(index),
with,
apply_with_func_last,
);
}
}
AirTree::Pair { tipo: _, fst, snd } => {
fst.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
snd.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
}
AirTree::Call {
tipo: _,
func,
args,
} => {
func.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
for (index, arg) in args.iter_mut().enumerate() {
arg.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ArgsField(index),
with,
apply_with_func_last,
);
}
}
AirTree::Fn {
params: _,
func_body,
allow_inline: _,
} => {
func_body.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
}
AirTree::Builtin {
func: _,
tipo: _,
args,
} => {
for (index, arg) in args.iter_mut().enumerate() {
arg.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ArgsField(index),
with,
apply_with_func_last,
);
}
}
AirTree::BinOp {
name: _,
tipo: _,
left,
right,
argument_tipo: _,
} => {
left.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
right.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
);
}
AirTree::UnOp { op: _, arg } => {
arg.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
}
AirTree::CastFromData {
tipo: _,
value,
otherwise: _,
full_cast: _,
} => {
value.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
}
AirTree::CastToData { tipo: _, value } => {
value.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
}
AirTree::Clause {
subject_tipo: _,
subject_name: _,
complex_clause: _,
pattern,
then,
otherwise,
} => {
pattern.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
);
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FifthField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SixthField,
with,
apply_with_func_last,
);
}
AirTree::ListClause {
subject_tipo: _,
tail_name: _,
next_tail_name: _,
complex_clause: _,
then,
otherwise,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FifthField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SixthField,
with,
apply_with_func_last,
);
}
AirTree::WrapClause { then, otherwise } => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FirstField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
}
AirTree::Finally { pattern, then } => {
pattern.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FirstField,
with,
apply_with_func_last,
);
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
}
AirTree::If {
tipo: _,
condition: pattern,
then,
otherwise,
} => {
pattern.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
otherwise.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
);
}
AirTree::Constr {
tag: _,
tipo: _,
args,
} => {
for (index, arg) in args.iter_mut().enumerate() {
arg.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ArgsField(index),
with,
apply_with_func_last,
);
}
}
AirTree::RecordUpdate {
highest_index: _,
indices: _,
tipo: _,
record,
args,
} => {
record.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
);
for (index, arg) in args.iter_mut().enumerate() {
arg.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ArgsField(index),
with,
apply_with_func_last,
);
}
}
AirTree::Trace { tipo: _, msg, then } => {
msg.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
}
AirTree::DefineFunc {
func_name: _,
module_name: _,
params: _,
recursive: _,
recursive_nonstatic_params: _,
variant_name: _,
func_body,
then,
} => {
func_body.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SeventhField,
with,
apply_with_func_last,
);
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::EighthField,
with,
apply_with_func_last,
)
}
AirTree::DefineCyclicFuncs {
func_name: _,
module_name: _,
variant_name: _,
contained_functions,
then,
} => {
for (index, (_, func_body)) in contained_functions.iter_mut().enumerate() {
func_body.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ArgsField(index),
with,
apply_with_func_last,
);
}
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FifthField,
with,
apply_with_func_last,
);
}
AirTree::Int { .. }
| AirTree::String { .. }
| AirTree::ByteArray { .. }
| AirTree::CurvePoint { .. }
| AirTree::Bool { .. }
| AirTree::Void
| AirTree::Var { .. }
| AirTree::ErrorTerm { .. } => {}
AirTree::Let {
name: _,
value: _,
then,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
}
AirTree::AssertConstr {
constr_index: _,
constr: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
}
AirTree::AssertBool {
is_true: _,
value: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::ThirdField,
with,
apply_with_func_last,
);
}
AirTree::ClauseGuard {
subject_name: _,
subject_tipo: _,
pattern: _,
then,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
);
}
AirTree::ListClauseGuard {
subject_tipo: _,
tail_name: _,
next_tail_name: _,
inverse: _,
then,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FifthField,
with,
apply_with_func_last,
);
}
AirTree::TupleGuard {
subject_tipo: _,
indices: _,
subject_name: _,
then,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
);
}
AirTree::PairGuard {
subject_tipo: _,
subject_name: _,
fst_name: _,
snd_name: _,
then,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FifthField,
with,
apply_with_func_last,
);
}
AirTree::FieldsExpose {
indices: _,
record: _,
is_expect: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
);
}
AirTree::ListAccessor {
tipo: _,
names: _,
tail: _,
list: _,
expect_level: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SixthField,
with,
apply_with_func_last,
);
}
AirTree::ListExpose {
tipo: _,
tail_head_names: _,
tail: _,
then,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
);
}
AirTree::TupleAccessor {
names: _,
tipo: _,
tuple: _,
is_expect: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FifthField,
with,
apply_with_func_last,
);
}
AirTree::PairAccessor {
fst: _,
snd: _,
tipo: _,
is_expect: _,
pair: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SixthField,
with,
apply_with_func_last,
);
}
AirTree::FieldsEmpty {
constr: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
}
AirTree::ListEmpty {
list: _,
then,
otherwise: _,
} => {
then.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
}
AirTree::MultiValidator {
two_arg_name: _,
two_arg,
three_arg_name: _,
three_arg,
} => {
two_arg.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::SecondField,
with,
apply_with_func_last,
);
three_arg.do_traverse_tree_with(
tree_path,
current_depth + 1,
Fields::FourthField,
with,
apply_with_func_last,
)
}
}
if apply_with_func_last {
with(self, tree_path);
}
tree_path.pop();
}
/// Used in function hoisting to find the exact node to hoist over
pub fn find_air_tree_node<'a>(&'a mut self, tree_path: &TreePath) -> &'a mut AirTree {
let mut path_iter = tree_path.path.iter();
path_iter.next();
self.do_find_air_tree_node(&mut path_iter)
}
fn do_find_air_tree_node<'a>(
&'a mut self,
tree_path_iter: &mut Iter<(usize, Fields)>,
) -> &'a mut AirTree {
// For finding the air node we skip over the define func ops since those are added later on.
if let AirTree::DefineFunc { then, .. } | AirTree::DefineCyclicFuncs { then, .. } = self {
then.as_mut().do_find_air_tree_node(tree_path_iter)
} else if let Some((_depth, field)) = tree_path_iter.next() {
match self {
AirTree::Let {
name: _,
value,
then,
} => match field {
Fields::SecondField => value.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ThirdField => then.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::AssertConstr {
constr_index: _,
constr,
then,
otherwise,
} => match field {
Fields::SecondField => constr.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ThirdField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FourthField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::AssertBool {
is_true: _,
value,
then,
otherwise,
} => match field {
Fields::SecondField => value.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ThirdField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FourthField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::ClauseGuard {
subject_name: _,
subject_tipo: _,
pattern,
then,
} => match field {
Fields::ThirdField => pattern.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FourthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::ListClauseGuard {
subject_tipo: _,
tail_name: _,
next_tail_name: _,
inverse: _,
then,
} => match field {
Fields::FifthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::TupleGuard {
subject_tipo: _,
indices: _,
subject_name: _,
then,
} => match field {
Fields::FourthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::PairGuard {
subject_tipo: _,
subject_name: _,
fst_name: _,
snd_name: _,
then,
} => match field {
Fields::FifthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::FieldsExpose {
indices: _,
record,
is_expect: _,
then,
otherwise,
} => match field {
Fields::SecondField => record.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FourthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FifthField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::ListAccessor {
tipo: _,
names: _,
tail: _,
list,
expect_level: _,
then,
otherwise,
} => match field {
Fields::FourthField => list.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SixthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SeventhField => {
otherwise.as_mut().do_find_air_tree_node(tree_path_iter)
}
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::ListExpose {
tipo: _,
tail_head_names: _,
tail: _,
then,
} => match field {
Fields::FourthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::TupleAccessor {
names: _,
tipo: _,
tuple,
is_expect: _,
then,
otherwise,
} => match field {
Fields::ThirdField => tuple.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FifthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SixthField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::PairAccessor {
fst: _,
snd: _,
tipo: _,
is_expect: _,
pair,
then,
otherwise,
} => match field {
Fields::FifthField => pair.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SixthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SeventhField => {
otherwise.as_mut().do_find_air_tree_node(tree_path_iter)
}
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::NoOp { then } => match field {
Fields::FirstField => then.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::DefineFunc { .. } | AirTree::DefineCyclicFuncs { .. } => unreachable!(),
AirTree::FieldsEmpty {
constr,
then,
otherwise,
} => match field {
Fields::FirstField => constr.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SecondField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ThirdField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::ListEmpty {
list,
then,
otherwise,
} => match field {
Fields::FirstField => list.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SecondField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ThirdField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::List { items, .. }
| AirTree::Tuple { items, .. }
| AirTree::Builtin { args: items, .. }
| AirTree::Constr { args: items, .. } => match field {
Fields::ArgsField(index) => items
.get_mut(*index)
.expect("Tree Path index outside tree children nodes")
.do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::Pair { tipo: _, fst, snd } => match field {
Fields::SecondField => fst.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ThirdField => snd.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::Call {
tipo: _,
func,
args,
} => match field {
Fields::SecondField => func.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ArgsField(index) => args
.get_mut(*index)
.expect("Tree Path index outside tree children nodes")
.do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::Fn {
params: _,
func_body,
allow_inline: _,
} => match field {
Fields::SecondField => func_body.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::BinOp {
name: _,
tipo: _,
left,
right,
argument_tipo: _,
} => match field {
Fields::ThirdField => left.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FourthField => right.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::UnOp { op: _, arg } => match field {
Fields::SecondField => arg.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::CastFromData {
tipo: _,
value,
otherwise,
full_cast: _,
} => match field {
Fields::SecondField => value.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ThirdField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::CastToData { tipo: _, value } => match field {
Fields::SecondField => value.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::When {
tipo: _,
subject_name: _,
subject,
subject_tipo: _,
clauses,
} => match field {
Fields::ThirdField => subject.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FifthField => clauses.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::Clause {
subject_tipo: _,
subject_name: _,
complex_clause: _,
pattern,
then,
otherwise,
} => match field {
Fields::FourthField => pattern.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FifthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SixthField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::ListClause {
subject_tipo: _,
tail_name: _,
next_tail_name: _,
complex_clause: _,
then,
otherwise,
} => match field {
Fields::FifthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SixthField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::WrapClause { then, otherwise } => match field {
Fields::FirstField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SecondField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::TupleClause {
subject_tipo: _,
indices: _,
predefined_indices: _,
subject_name: _,
complex_clause: _,
then,
otherwise,
} => match field {
Fields::SixthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SeventhField => {
otherwise.as_mut().do_find_air_tree_node(tree_path_iter)
}
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::PairClause {
subject_tipo: _,
subject_name: _,
fst_name: _,
snd_name: _,
complex_clause: _,
then,
otherwise,
} => match field {
Fields::SixthField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SeventhField => {
otherwise.as_mut().do_find_air_tree_node(tree_path_iter)
}
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::Finally { pattern, then } => match field {
Fields::FirstField => pattern.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::SecondField => then.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::If {
tipo: _,
condition: pattern,
then,
otherwise,
} => match field {
Fields::SecondField => pattern.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ThirdField => then.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FourthField => otherwise.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::RecordUpdate {
highest_index: _,
indices: _,
tipo: _,
record,
args,
} => match field {
Fields::FourthField => record.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ArgsField(index) => args
.get_mut(*index)
.expect("Tree Path index outside tree children nodes")
.do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::Trace { tipo: _, msg, then } => match field {
Fields::SecondField => msg.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::ThirdField => then.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
AirTree::Int { .. }
| AirTree::String { .. }
| AirTree::ByteArray { .. }
| AirTree::CurvePoint { .. }
| AirTree::Bool { .. }
| AirTree::Void
| AirTree::Var { .. }
| AirTree::ErrorTerm { .. } => {
panic!("A tree node with no children was encountered with a longer tree path.")
}
AirTree::MultiValidator {
two_arg_name: _,
two_arg,
three_arg_name: _,
three_arg,
} => match field {
Fields::SecondField => two_arg.as_mut().do_find_air_tree_node(tree_path_iter),
Fields::FourthField => three_arg.as_mut().do_find_air_tree_node(tree_path_iter),
_ => panic!("Tree Path index outside tree children nodes"),
},
}
} else {
self
}
}
}