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, then: Box, }, DefineFunc { func_name: String, module_name: String, params: Vec, recursive: bool, recursive_nonstatic_params: Vec, variant_name: String, func_body: Box, then: Box, }, DefineCyclicFuncs { func_name: String, module_name: String, variant_name: String, // params and body contained_functions: Vec<(Vec, AirTree)>, then: Box, }, // Assertions AssertConstr { constr_index: usize, constr: Box, then: Box, otherwise: Box, }, AssertBool { is_true: bool, value: Box, then: Box, otherwise: Box, }, // Clause Guards ClauseGuard { subject_name: String, subject_tipo: Rc, pattern: Box, then: Box, }, ListClauseGuard { subject_tipo: Rc, tail_name: String, next_tail_name: Option, inverse: bool, then: Box, }, TupleGuard { subject_tipo: Rc, indices: IndexSet<(usize, String)>, subject_name: String, then: Box, }, PairGuard { subject_tipo: Rc, subject_name: String, fst_name: Option, snd_name: Option, then: Box, }, // Field Access FieldsExpose { indices: Vec<(usize, String, Rc)>, record: Box, is_expect: bool, then: Box, otherwise: Box, }, // List Access ListAccessor { tipo: Rc, names: Vec, tail: bool, list: Box, expect_level: ExpectLevel, then: Box, otherwise: Box, }, ListExpose { tipo: Rc, tail_head_names: Vec<(String, String)>, tail: Option<(String, String)>, then: Box, }, // Tuple Access TupleAccessor { names: Vec, tipo: Rc, tuple: Box, is_expect: bool, then: Box, otherwise: Box, }, // Pair Access PairAccessor { fst: Option, snd: Option, tipo: Rc, is_expect: bool, pair: Box, then: Box, otherwise: Box, }, // Misc. FieldsEmpty { constr: Box, then: Box, otherwise: Box, }, ListEmpty { list: Box, then: Box, otherwise: Box, }, NoOp { then: Box, }, // End Statements // Expressions // Primitives Int { value: String, }, String { value: String, }, ByteArray { bytes: Vec, }, CurvePoint { point: Curve, }, Bool { value: bool, }, List { tipo: Rc, tail: bool, items: Vec, }, Tuple { tipo: Rc, items: Vec, }, Pair { tipo: Rc, fst: Box, snd: Box, }, Void, Var { constructor: ValueConstructor, name: String, variant_name: String, }, // Functions Call { tipo: Rc, func: Box, args: Vec, }, Fn { params: Vec, func_body: Box, allow_inline: bool, }, Builtin { func: DefaultFunction, tipo: Rc, args: Vec, }, // Operators BinOp { name: BinOp, tipo: Rc, left: Box, right: Box, argument_tipo: Rc, }, UnOp { op: UnOp, arg: Box, }, CastFromData { tipo: Rc, value: Box, otherwise: Box, full_cast: bool, }, CastToData { tipo: Rc, value: Box, }, // When When { tipo: Rc, subject_name: String, subject: Box, subject_tipo: Rc, clauses: Box, }, Clause { subject_tipo: Rc, subject_name: String, complex_clause: bool, pattern: Box, then: Box, otherwise: Box, }, ListClause { subject_tipo: Rc, tail_name: String, next_tail_name: Option<(String, String)>, complex_clause: bool, then: Box, otherwise: Box, }, WrapClause { then: Box, otherwise: Box, }, TupleClause { subject_tipo: Rc, indices: IndexSet<(usize, String)>, predefined_indices: IndexSet<(usize, String)>, subject_name: String, complex_clause: bool, then: Box, otherwise: Box, }, PairClause { subject_tipo: Rc, subject_name: String, fst_name: Option, snd_name: Option, complex_clause: bool, then: Box, otherwise: Box, }, Finally { pattern: Box, then: Box, }, // If If { tipo: Rc, condition: Box, then: Box, otherwise: Box, }, // Record Creation Constr { tag: usize, tipo: Rc, args: Vec, }, RecordUpdate { highest_index: usize, indices: Vec<(usize, Rc)>, tipo: Rc, record: Box, args: Vec, }, // Misc. ErrorTerm { tipo: Rc, validator: bool, }, Trace { tipo: Rc, msg: Box, then: Box, }, // End Expressions MultiValidator { two_arg_name: String, two_arg: Box, three_arg_name: String, three_arg: Box, }, } 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) -> 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, tipo: Rc, tail: Option) -> 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, tipo: Rc) -> AirTree { AirTree::Tuple { tipo, items } } pub fn pair(fst: AirTree, snd: AirTree, tipo: Rc) -> 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) -> 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, args: Vec) -> 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, recursive: bool, recursive_nonstatic_params: Vec, 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, 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, func_body: AirTree, allow_inline: bool) -> AirTree { AirTree::Fn { params, func_body: func_body.into(), allow_inline, } } pub fn builtin(func: DefaultFunction, tipo: Rc, args: Vec) -> AirTree { AirTree::Builtin { func, tipo, args } } pub fn binop( op: BinOp, tipo: Rc, left: AirTree, right: AirTree, argument_tipo: Rc, ) -> 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, 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) -> 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, subject_tipo: Rc, 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, 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, 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, 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, fst_name: Option, snd_name: Option, 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, 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, inverse: bool, next_tail_name: Option, 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, 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, fst_name: Option, snd_name: Option, 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, 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, args: Vec) -> AirTree { AirTree::Constr { tag, tipo, args } } pub fn record_update( indices: Vec<(usize, Rc)>, highest_index: usize, tipo: Rc, record: AirTree, args: Vec, ) -> AirTree { AirTree::RecordUpdate { highest_index, indices, tipo, record: record.into(), args, } } pub fn index_access(function_name: String, tipo: Rc, 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)>, 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, tipo: Rc, 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, then: AirTree, ) -> AirTree { AirTree::ListExpose { tipo, tail_head_names, tail, then: then.into(), } } pub fn tuple_access( names: Vec, tipo: Rc, 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, snd: Option, tipo: Rc, 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, 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, validator: bool) -> AirTree { AirTree::ErrorTerm { tipo, validator } } pub fn trace(msg: AirTree, tipo: Rc, 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 { let mut air_vec = vec![]; self.create_air_vec(&mut air_vec); air_vec } fn create_air_vec(&self, air_vec: &mut Vec) { 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 { 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> { 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 } } }