1139 lines
35 KiB
Rust
1139 lines
35 KiB
Rust
use indexmap::IndexSet;
|
|
use std::sync::Arc;
|
|
use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction};
|
|
|
|
use crate::{
|
|
ast::{BinOp, Span, UnOp},
|
|
builtins::{data, list, void},
|
|
tipo::{Type, ValueConstructor, ValueConstructorVariant},
|
|
};
|
|
|
|
use super::air::Air;
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum AirTree {
|
|
Statement {
|
|
statement: AirStatement,
|
|
hoisted_over: Option<Box<AirTree>>,
|
|
},
|
|
Expression(AirExpression),
|
|
UnhoistedSequence(Vec<AirTree>),
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum AirStatement {
|
|
// Assignment
|
|
Let {
|
|
name: String,
|
|
value: Box<AirTree>,
|
|
},
|
|
DefineFunc {
|
|
func_name: String,
|
|
module_name: String,
|
|
params: Vec<String>,
|
|
recursive: bool,
|
|
variant_name: String,
|
|
func_body: Box<AirTree>,
|
|
},
|
|
// Assertions
|
|
AssertConstr {
|
|
constr_index: usize,
|
|
constr: Box<AirTree>,
|
|
},
|
|
AssertBool {
|
|
is_true: bool,
|
|
value: Box<AirTree>,
|
|
},
|
|
// Clause Guards
|
|
ClauseGuard {
|
|
subject_name: String,
|
|
tipo: Arc<Type>,
|
|
pattern: Box<AirTree>,
|
|
},
|
|
ListClauseGuard {
|
|
tipo: Arc<Type>,
|
|
tail_name: String,
|
|
next_tail_name: Option<String>,
|
|
inverse: bool,
|
|
},
|
|
TupleGuard {
|
|
tipo: Arc<Type>,
|
|
indices: IndexSet<(usize, String)>,
|
|
subject_name: String,
|
|
type_count: usize,
|
|
},
|
|
// Field Access
|
|
FieldsExpose {
|
|
indices: Vec<(usize, String, Arc<Type>)>,
|
|
check_last_item: bool,
|
|
record: Box<AirTree>,
|
|
},
|
|
// List Access
|
|
ListAccessor {
|
|
tipo: Arc<Type>,
|
|
names: Vec<String>,
|
|
tail: bool,
|
|
check_last_item: bool,
|
|
list: Box<AirTree>,
|
|
},
|
|
ListExpose {
|
|
tipo: Arc<Type>,
|
|
tail_head_names: Vec<(String, String)>,
|
|
tail: Option<(String, String)>,
|
|
list: Box<AirTree>,
|
|
},
|
|
// Tuple Access
|
|
TupleAccessor {
|
|
names: Vec<String>,
|
|
tipo: Arc<Type>,
|
|
check_last_item: bool,
|
|
tuple: Box<AirTree>,
|
|
},
|
|
// Misc.
|
|
NoOp,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum AirExpression {
|
|
// Primitives
|
|
Int {
|
|
value: String,
|
|
},
|
|
String {
|
|
value: String,
|
|
},
|
|
ByteArray {
|
|
bytes: Vec<u8>,
|
|
},
|
|
Bool {
|
|
value: bool,
|
|
},
|
|
List {
|
|
tipo: Arc<Type>,
|
|
tail: bool,
|
|
items: Vec<AirTree>,
|
|
},
|
|
Tuple {
|
|
tipo: Arc<Type>,
|
|
items: Vec<AirTree>,
|
|
},
|
|
Void,
|
|
Var {
|
|
constructor: ValueConstructor,
|
|
name: String,
|
|
variant_name: String,
|
|
},
|
|
// Functions
|
|
Call {
|
|
tipo: Arc<Type>,
|
|
func: Box<AirTree>,
|
|
args: Vec<AirTree>,
|
|
},
|
|
|
|
Fn {
|
|
params: Vec<String>,
|
|
func_body: Box<AirTree>,
|
|
},
|
|
Builtin {
|
|
func: DefaultFunction,
|
|
tipo: Arc<Type>,
|
|
args: Vec<AirTree>,
|
|
},
|
|
// Operators
|
|
BinOp {
|
|
name: BinOp,
|
|
tipo: Arc<Type>,
|
|
left: Box<AirTree>,
|
|
right: Box<AirTree>,
|
|
},
|
|
UnOp {
|
|
op: UnOp,
|
|
arg: Box<AirTree>,
|
|
},
|
|
|
|
UnWrapData {
|
|
tipo: Arc<Type>,
|
|
value: Box<AirTree>,
|
|
},
|
|
WrapData {
|
|
tipo: Arc<Type>,
|
|
value: Box<AirTree>,
|
|
},
|
|
|
|
// When
|
|
When {
|
|
tipo: Arc<Type>,
|
|
subject_name: String,
|
|
subject: Box<AirTree>,
|
|
clauses: Box<AirTree>,
|
|
},
|
|
Clause {
|
|
tipo: Arc<Type>,
|
|
subject_name: String,
|
|
complex_clause: bool,
|
|
pattern: Box<AirTree>,
|
|
then: Box<AirTree>,
|
|
otherwise: Box<AirTree>,
|
|
},
|
|
ListClause {
|
|
tipo: Arc<Type>,
|
|
tail_name: String,
|
|
next_tail_name: Option<String>,
|
|
complex_clause: bool,
|
|
then: Box<AirTree>,
|
|
otherwise: Box<AirTree>,
|
|
},
|
|
WrapClause {
|
|
then: Box<AirTree>,
|
|
otherwise: Box<AirTree>,
|
|
},
|
|
TupleClause {
|
|
tipo: Arc<Type>,
|
|
indices: IndexSet<(usize, String)>,
|
|
predefined_indices: IndexSet<(usize, String)>,
|
|
subject_name: String,
|
|
type_count: usize,
|
|
complex_clause: bool,
|
|
then: Box<AirTree>,
|
|
otherwise: Box<AirTree>,
|
|
},
|
|
|
|
Finally {
|
|
pattern: Box<AirTree>,
|
|
then: Box<AirTree>,
|
|
},
|
|
// If
|
|
If {
|
|
tipo: Arc<Type>,
|
|
pattern: Box<AirTree>,
|
|
then: Box<AirTree>,
|
|
otherwise: Box<AirTree>,
|
|
},
|
|
// Record Creation
|
|
Constr {
|
|
tag: usize,
|
|
tipo: Arc<Type>,
|
|
args: Vec<AirTree>,
|
|
},
|
|
RecordUpdate {
|
|
highest_index: usize,
|
|
indices: Vec<(usize, Arc<Type>)>,
|
|
tipo: Arc<Type>,
|
|
record: Box<AirTree>,
|
|
args: Vec<AirTree>,
|
|
},
|
|
// Field Access
|
|
RecordAccess {
|
|
field_index: u64,
|
|
tipo: Arc<Type>,
|
|
record: Box<AirTree>,
|
|
},
|
|
// Tuple Access
|
|
TupleIndex {
|
|
tipo: Arc<Type>,
|
|
tuple_index: usize,
|
|
tuple: Box<AirTree>,
|
|
},
|
|
// Misc.
|
|
ErrorTerm {
|
|
tipo: Arc<Type>,
|
|
},
|
|
Trace {
|
|
tipo: Arc<Type>,
|
|
msg: Box<AirTree>,
|
|
then: Box<AirTree>,
|
|
},
|
|
FieldsEmpty {
|
|
constr: Box<AirTree>,
|
|
},
|
|
ListEmpty {
|
|
list: Box<AirTree>,
|
|
},
|
|
}
|
|
|
|
impl AirTree {
|
|
pub fn int(value: impl ToString) -> AirTree {
|
|
AirTree::Expression(AirExpression::Int {
|
|
value: value.to_string(),
|
|
})
|
|
}
|
|
pub fn string(value: impl ToString) -> AirTree {
|
|
AirTree::Expression(AirExpression::String {
|
|
value: value.to_string(),
|
|
})
|
|
}
|
|
pub fn byte_array(bytes: Vec<u8>) -> AirTree {
|
|
AirTree::Expression(AirExpression::ByteArray { bytes })
|
|
}
|
|
pub fn bool(value: bool) -> AirTree {
|
|
AirTree::Expression(AirExpression::Bool { value })
|
|
}
|
|
pub fn list(mut items: Vec<AirTree>, tipo: Arc<Type>, tail: Option<AirTree>) -> AirTree {
|
|
if let Some(tail) = tail {
|
|
items.push(tail);
|
|
|
|
AirTree::Expression(AirExpression::List {
|
|
tipo,
|
|
tail: true,
|
|
items,
|
|
})
|
|
} else {
|
|
AirTree::Expression(AirExpression::List {
|
|
tipo,
|
|
tail: false,
|
|
items,
|
|
})
|
|
}
|
|
}
|
|
pub fn tuple(items: Vec<AirTree>, tipo: Arc<Type>) -> AirTree {
|
|
AirTree::Expression(AirExpression::Tuple { tipo, items })
|
|
}
|
|
pub fn void() -> AirTree {
|
|
AirTree::Expression(AirExpression::Void)
|
|
}
|
|
pub fn var(
|
|
constructor: ValueConstructor,
|
|
name: impl ToString,
|
|
variant_name: impl ToString,
|
|
) -> AirTree {
|
|
AirTree::Expression(AirExpression::Var {
|
|
constructor,
|
|
name: name.to_string(),
|
|
variant_name: variant_name.to_string(),
|
|
})
|
|
}
|
|
pub fn local_var(name: impl ToString, tipo: Arc<Type>) -> AirTree {
|
|
AirTree::Expression(AirExpression::Var {
|
|
constructor: ValueConstructor::public(
|
|
tipo,
|
|
ValueConstructorVariant::LocalVariable {
|
|
location: Span::empty(),
|
|
},
|
|
),
|
|
name: name.to_string(),
|
|
variant_name: "".to_string(),
|
|
})
|
|
}
|
|
pub fn call(func: AirTree, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree {
|
|
AirTree::Expression(AirExpression::Call {
|
|
tipo,
|
|
func: func.into(),
|
|
args,
|
|
})
|
|
}
|
|
pub fn define_func(
|
|
func_name: impl ToString,
|
|
module_name: impl ToString,
|
|
variant_name: impl ToString,
|
|
params: Vec<String>,
|
|
recursive: bool,
|
|
func_body: AirTree,
|
|
) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::DefineFunc {
|
|
func_name: func_name.to_string(),
|
|
module_name: module_name.to_string(),
|
|
params,
|
|
recursive,
|
|
variant_name: variant_name.to_string(),
|
|
func_body: func_body.into(),
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn anon_func(params: Vec<String>, func_body: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::Fn {
|
|
params,
|
|
func_body: func_body.into(),
|
|
})
|
|
}
|
|
pub fn builtin(func: DefaultFunction, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree {
|
|
AirTree::Expression(AirExpression::Builtin { func, tipo, args })
|
|
}
|
|
pub fn binop(op: BinOp, tipo: Arc<Type>, left: AirTree, right: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::BinOp {
|
|
name: op,
|
|
tipo,
|
|
left: left.into(),
|
|
right: right.into(),
|
|
})
|
|
}
|
|
pub fn unop(op: UnOp, arg: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::UnOp {
|
|
op,
|
|
arg: arg.into(),
|
|
})
|
|
}
|
|
pub fn let_assignment(name: impl ToString, value: AirTree) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::Let {
|
|
name: name.to_string(),
|
|
value: value.into(),
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn unwrap_data(value: AirTree, tipo: Arc<Type>) -> AirTree {
|
|
AirTree::Expression(AirExpression::UnWrapData {
|
|
tipo,
|
|
value: value.into(),
|
|
})
|
|
}
|
|
pub fn wrap_data(value: AirTree, tipo: Arc<Type>) -> AirTree {
|
|
AirTree::Expression(AirExpression::WrapData {
|
|
tipo,
|
|
value: value.into(),
|
|
})
|
|
}
|
|
pub fn assert_constr_index(constr_index: usize, constr: AirTree) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::AssertConstr {
|
|
constr_index,
|
|
constr: constr.into(),
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn assert_bool(is_true: bool, value: AirTree) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::AssertBool {
|
|
is_true,
|
|
value: value.into(),
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn when(
|
|
subject_name: impl ToString,
|
|
tipo: Arc<Type>,
|
|
subject: AirTree,
|
|
clauses: AirTree,
|
|
) -> AirTree {
|
|
AirTree::Expression(AirExpression::When {
|
|
tipo,
|
|
subject_name: subject_name.to_string(),
|
|
subject: subject.into(),
|
|
clauses: clauses.into(),
|
|
})
|
|
}
|
|
pub fn clause(
|
|
subject_name: impl ToString,
|
|
pattern: AirTree,
|
|
tipo: Arc<Type>,
|
|
then: AirTree,
|
|
otherwise: AirTree,
|
|
complex_clause: bool,
|
|
) -> AirTree {
|
|
AirTree::Expression(AirExpression::Clause {
|
|
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,
|
|
tipo: Arc<Type>,
|
|
then: AirTree,
|
|
otherwise: AirTree,
|
|
next_tail_name: Option<String>,
|
|
complex_clause: bool,
|
|
) -> AirTree {
|
|
AirTree::Expression(AirExpression::ListClause {
|
|
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,
|
|
tipo: Arc<Type>,
|
|
indices: IndexSet<(usize, String)>,
|
|
predefined_indices: IndexSet<(usize, String)>,
|
|
then: AirTree,
|
|
otherwise: AirTree,
|
|
complex_clause: bool,
|
|
) -> AirTree {
|
|
let type_count = tipo.get_inner_types().len();
|
|
|
|
AirTree::Expression(AirExpression::TupleClause {
|
|
tipo,
|
|
indices,
|
|
predefined_indices,
|
|
subject_name: subject_name.to_string(),
|
|
type_count,
|
|
complex_clause,
|
|
then: then.into(),
|
|
otherwise: otherwise.into(),
|
|
})
|
|
}
|
|
pub fn wrap_clause(then: AirTree, otherwise: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::WrapClause {
|
|
then: then.into(),
|
|
otherwise: otherwise.into(),
|
|
})
|
|
}
|
|
pub fn clause_guard(subject_name: impl ToString, pattern: AirTree, tipo: Arc<Type>) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::ClauseGuard {
|
|
subject_name: subject_name.to_string(),
|
|
tipo,
|
|
pattern: pattern.into(),
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn list_clause_guard(
|
|
tail_name: impl ToString,
|
|
tipo: Arc<Type>,
|
|
inverse: bool,
|
|
next_tail_name: Option<String>,
|
|
) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::ListClauseGuard {
|
|
tipo,
|
|
tail_name: tail_name.to_string(),
|
|
next_tail_name,
|
|
inverse,
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn tuple_clause_guard(
|
|
subject_name: impl ToString,
|
|
tipo: Arc<Type>,
|
|
indices: IndexSet<(usize, String)>,
|
|
) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::TupleGuard {
|
|
indices,
|
|
subject_name: subject_name.to_string(),
|
|
type_count: tipo.get_inner_types().len(),
|
|
tipo,
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn finally(pattern: AirTree, then: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::Finally {
|
|
pattern: pattern.into(),
|
|
then: then.into(),
|
|
})
|
|
}
|
|
pub fn if_branches(
|
|
mut branches: Vec<(AirTree, AirTree)>,
|
|
tipo: Arc<Type>,
|
|
otherwise: AirTree,
|
|
) -> AirTree {
|
|
assert!(!branches.is_empty());
|
|
let last_if = branches.pop().unwrap();
|
|
|
|
let mut final_if = AirTree::Expression(AirExpression::If {
|
|
tipo: tipo.clone(),
|
|
pattern: last_if.0.into(),
|
|
then: last_if.1.into(),
|
|
otherwise: otherwise.into(),
|
|
});
|
|
|
|
while let Some(branch) = branches.pop() {
|
|
final_if = AirTree::Expression(AirExpression::If {
|
|
tipo: tipo.clone(),
|
|
pattern: branch.0.into(),
|
|
then: branch.1.into(),
|
|
otherwise: final_if.into(),
|
|
});
|
|
}
|
|
|
|
final_if
|
|
}
|
|
pub fn create_constr(tag: usize, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree {
|
|
AirTree::Expression(AirExpression::Constr { tag, tipo, args })
|
|
}
|
|
|
|
pub fn record_update(
|
|
indices: Vec<(usize, Arc<Type>)>,
|
|
highest_index: usize,
|
|
tipo: Arc<Type>,
|
|
record: AirTree,
|
|
args: Vec<AirTree>,
|
|
) -> AirTree {
|
|
AirTree::Expression(AirExpression::RecordUpdate {
|
|
highest_index,
|
|
indices,
|
|
tipo,
|
|
record: record.into(),
|
|
args,
|
|
})
|
|
}
|
|
pub fn record_access(field_index: u64, tipo: Arc<Type>, record: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::RecordAccess {
|
|
field_index,
|
|
tipo,
|
|
record: record.into(),
|
|
})
|
|
}
|
|
|
|
pub fn fields_expose(
|
|
indices: Vec<(usize, String, Arc<Type>)>,
|
|
check_last_item: bool,
|
|
record: AirTree,
|
|
) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::FieldsExpose {
|
|
indices,
|
|
check_last_item,
|
|
record: record.into(),
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn list_access(
|
|
names: Vec<String>,
|
|
tipo: Arc<Type>,
|
|
tail: bool,
|
|
check_last_item: bool,
|
|
list: AirTree,
|
|
) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::ListAccessor {
|
|
tipo,
|
|
names,
|
|
tail,
|
|
check_last_item,
|
|
list: list.into(),
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn list_expose(
|
|
tail_head_names: Vec<(String, String)>,
|
|
tail: Option<(String, String)>,
|
|
tipo: Arc<Type>,
|
|
list: AirTree,
|
|
) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::ListExpose {
|
|
tipo,
|
|
tail_head_names,
|
|
tail,
|
|
list: list.into(),
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn tuple_access(
|
|
names: Vec<String>,
|
|
tipo: Arc<Type>,
|
|
check_last_item: bool,
|
|
tuple: AirTree,
|
|
) -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::TupleAccessor {
|
|
names,
|
|
tipo,
|
|
check_last_item,
|
|
tuple: tuple.into(),
|
|
},
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn tuple_index(tuple_index: usize, tipo: Arc<Type>, tuple: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::TupleIndex {
|
|
tipo,
|
|
tuple_index,
|
|
tuple: tuple.into(),
|
|
})
|
|
}
|
|
pub fn error(tipo: Arc<Type>) -> AirTree {
|
|
AirTree::Expression(AirExpression::ErrorTerm { tipo })
|
|
}
|
|
pub fn trace(msg: AirTree, tipo: Arc<Type>, then: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::Trace {
|
|
tipo,
|
|
msg: msg.into(),
|
|
then: then.into(),
|
|
})
|
|
}
|
|
pub fn no_op() -> AirTree {
|
|
AirTree::Statement {
|
|
statement: AirStatement::NoOp,
|
|
hoisted_over: None,
|
|
}
|
|
}
|
|
pub fn fields_empty(constr: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::FieldsEmpty {
|
|
constr: constr.into(),
|
|
})
|
|
}
|
|
pub fn list_empty(list: AirTree) -> AirTree {
|
|
AirTree::Expression(AirExpression::ListEmpty { list: list.into() })
|
|
}
|
|
pub fn hoist_over(mut self, next_exp: AirTree) -> AirTree {
|
|
match &mut self {
|
|
AirTree::Statement { hoisted_over, .. } => {
|
|
assert!(hoisted_over.is_none());
|
|
*hoisted_over = Some(next_exp.into());
|
|
self
|
|
}
|
|
|
|
AirTree::Expression(_) => {
|
|
unreachable!("Trying to hoist an expression onto an expression.")
|
|
}
|
|
AirTree::UnhoistedSequence(seq) => {
|
|
let mut final_exp = next_exp;
|
|
while let Some(assign) = seq.pop() {
|
|
final_exp = assign.hoist_over(final_exp);
|
|
}
|
|
final_exp
|
|
}
|
|
}
|
|
}
|
|
|
|
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 assign = AirTree::let_assignment("_", expect_on_head);
|
|
|
|
let next_call = AirTree::call(
|
|
AirTree::local_var(EXPECT_ON_LIST, void()),
|
|
void(),
|
|
vec![
|
|
AirTree::builtin(
|
|
DefaultFunction::TailList,
|
|
list(data()),
|
|
vec![AirTree::local_var("__list_to_check", list(data()))],
|
|
),
|
|
AirTree::local_var("__check_with", void()),
|
|
],
|
|
);
|
|
|
|
let list_clause = AirTree::list_clause(
|
|
"__list_to_check",
|
|
void(),
|
|
AirTree::void(),
|
|
assign.hoist_over(next_call),
|
|
None,
|
|
false,
|
|
);
|
|
|
|
AirTree::define_func(
|
|
EXPECT_ON_LIST,
|
|
"",
|
|
"",
|
|
vec!["__list_to_check".to_string(), "__check_with".to_string()],
|
|
true,
|
|
list_clause,
|
|
)
|
|
}
|
|
|
|
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::Statement {
|
|
statement,
|
|
hoisted_over: Some(exp),
|
|
} => {
|
|
match statement {
|
|
AirStatement::Let { value, name } => {
|
|
air_vec.push(Air::Let { name: name.clone() });
|
|
value.create_air_vec(air_vec);
|
|
}
|
|
AirStatement::DefineFunc {
|
|
func_name,
|
|
module_name,
|
|
params,
|
|
recursive,
|
|
variant_name,
|
|
func_body,
|
|
} => {
|
|
air_vec.push(Air::DefineFunc {
|
|
func_name: func_name.clone(),
|
|
module_name: module_name.clone(),
|
|
params: params.clone(),
|
|
recursive: *recursive,
|
|
variant_name: variant_name.clone(),
|
|
});
|
|
func_body.create_air_vec(air_vec);
|
|
}
|
|
AirStatement::AssertConstr {
|
|
constr,
|
|
constr_index,
|
|
} => {
|
|
air_vec.push(Air::AssertConstr {
|
|
constr_index: *constr_index,
|
|
});
|
|
constr.create_air_vec(air_vec);
|
|
}
|
|
AirStatement::AssertBool { is_true, value } => {
|
|
air_vec.push(Air::AssertBool { is_true: *is_true });
|
|
value.create_air_vec(air_vec);
|
|
}
|
|
AirStatement::ClauseGuard {
|
|
subject_name,
|
|
tipo,
|
|
pattern,
|
|
} => {
|
|
air_vec.push(Air::ClauseGuard {
|
|
subject_name: subject_name.clone(),
|
|
tipo: tipo.clone(),
|
|
});
|
|
|
|
pattern.create_air_vec(air_vec);
|
|
}
|
|
AirStatement::ListClauseGuard {
|
|
tipo,
|
|
tail_name,
|
|
next_tail_name,
|
|
inverse,
|
|
} => {
|
|
air_vec.push(Air::ListClauseGuard {
|
|
tipo: tipo.clone(),
|
|
tail_name: tail_name.clone(),
|
|
next_tail_name: next_tail_name.clone(),
|
|
inverse: *inverse,
|
|
});
|
|
}
|
|
AirStatement::TupleGuard {
|
|
tipo,
|
|
indices,
|
|
subject_name,
|
|
type_count,
|
|
} => {
|
|
air_vec.push(Air::TupleGuard {
|
|
tipo: tipo.clone(),
|
|
indices: indices.clone(),
|
|
subject_name: subject_name.clone(),
|
|
type_count: *type_count,
|
|
});
|
|
}
|
|
AirStatement::FieldsExpose {
|
|
indices,
|
|
check_last_item,
|
|
record,
|
|
} => {
|
|
air_vec.push(Air::FieldsExpose {
|
|
indices: indices.clone(),
|
|
check_last_item: *check_last_item,
|
|
});
|
|
record.create_air_vec(air_vec);
|
|
}
|
|
AirStatement::ListAccessor {
|
|
tipo,
|
|
names,
|
|
tail,
|
|
check_last_item,
|
|
list,
|
|
} => {
|
|
air_vec.push(Air::ListAccessor {
|
|
tipo: tipo.clone(),
|
|
names: names.clone(),
|
|
tail: *tail,
|
|
check_last_item: *check_last_item,
|
|
});
|
|
list.create_air_vec(air_vec);
|
|
}
|
|
AirStatement::ListExpose {
|
|
tipo,
|
|
tail_head_names,
|
|
tail,
|
|
list,
|
|
} => {
|
|
air_vec.push(Air::ListExpose {
|
|
tipo: tipo.clone(),
|
|
tail_head_names: tail_head_names.clone(),
|
|
tail: tail.clone(),
|
|
});
|
|
list.create_air_vec(air_vec);
|
|
}
|
|
AirStatement::TupleAccessor {
|
|
names,
|
|
tipo,
|
|
check_last_item,
|
|
tuple,
|
|
} => {
|
|
air_vec.push(Air::TupleAccessor {
|
|
names: names.clone(),
|
|
tipo: tipo.clone(),
|
|
check_last_item: *check_last_item,
|
|
});
|
|
tuple.create_air_vec(air_vec);
|
|
}
|
|
AirStatement::NoOp => {
|
|
air_vec.push(Air::NoOp);
|
|
}
|
|
};
|
|
exp.create_air_vec(air_vec);
|
|
}
|
|
AirTree::Expression(exp) => match exp {
|
|
AirExpression::Int { value } => air_vec.push(Air::Int {
|
|
value: value.clone(),
|
|
}),
|
|
AirExpression::String { value } => air_vec.push(Air::String {
|
|
value: value.clone(),
|
|
}),
|
|
AirExpression::ByteArray { bytes } => air_vec.push(Air::ByteArray {
|
|
bytes: bytes.clone(),
|
|
}),
|
|
AirExpression::Bool { value } => air_vec.push(Air::Bool { value: *value }),
|
|
AirExpression::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);
|
|
}
|
|
}
|
|
AirExpression::Tuple { tipo, items } => {
|
|
air_vec.push(Air::Tuple {
|
|
tipo: tipo.clone(),
|
|
count: items.len(),
|
|
});
|
|
for item in items {
|
|
item.create_air_vec(air_vec);
|
|
}
|
|
}
|
|
AirExpression::Void => air_vec.push(Air::Void),
|
|
AirExpression::Var {
|
|
constructor,
|
|
name,
|
|
variant_name,
|
|
} => air_vec.push(Air::Var {
|
|
constructor: constructor.clone(),
|
|
name: name.clone(),
|
|
variant_name: variant_name.clone(),
|
|
}),
|
|
AirExpression::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);
|
|
}
|
|
}
|
|
AirExpression::Fn { params, func_body } => {
|
|
air_vec.push(Air::Fn {
|
|
params: params.clone(),
|
|
});
|
|
func_body.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::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);
|
|
}
|
|
}
|
|
AirExpression::BinOp {
|
|
name,
|
|
tipo,
|
|
left,
|
|
right,
|
|
} => {
|
|
air_vec.push(Air::BinOp {
|
|
name: *name,
|
|
tipo: tipo.clone(),
|
|
});
|
|
left.create_air_vec(air_vec);
|
|
right.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::UnOp { op, arg } => {
|
|
air_vec.push(Air::UnOp { op: *op });
|
|
arg.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::UnWrapData { tipo, value } => {
|
|
air_vec.push(Air::UnWrapData { tipo: tipo.clone() });
|
|
value.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::WrapData { tipo, value } => {
|
|
air_vec.push(Air::WrapData { tipo: tipo.clone() });
|
|
value.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::When {
|
|
tipo,
|
|
subject_name,
|
|
subject,
|
|
clauses,
|
|
} => {
|
|
air_vec.push(Air::When {
|
|
tipo: tipo.clone(),
|
|
subject_name: subject_name.clone(),
|
|
});
|
|
subject.create_air_vec(air_vec);
|
|
clauses.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::Clause {
|
|
tipo,
|
|
subject_name,
|
|
complex_clause,
|
|
pattern,
|
|
then,
|
|
otherwise,
|
|
} => {
|
|
air_vec.push(Air::Clause {
|
|
tipo: 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);
|
|
}
|
|
AirExpression::ListClause {
|
|
tipo,
|
|
tail_name,
|
|
next_tail_name,
|
|
complex_clause,
|
|
then,
|
|
otherwise,
|
|
} => {
|
|
air_vec.push(Air::ListClause {
|
|
tipo: 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);
|
|
}
|
|
AirExpression::WrapClause { then, otherwise } => {
|
|
air_vec.push(Air::WrapClause);
|
|
then.create_air_vec(air_vec);
|
|
otherwise.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::TupleClause {
|
|
tipo,
|
|
indices,
|
|
predefined_indices,
|
|
subject_name,
|
|
type_count,
|
|
complex_clause,
|
|
then,
|
|
otherwise,
|
|
} => {
|
|
air_vec.push(Air::TupleClause {
|
|
tipo: tipo.clone(),
|
|
indices: indices.clone(),
|
|
predefined_indices: predefined_indices.clone(),
|
|
subject_name: subject_name.clone(),
|
|
count: *type_count,
|
|
complex_clause: *complex_clause,
|
|
});
|
|
then.create_air_vec(air_vec);
|
|
otherwise.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::Finally { pattern, then } => {
|
|
air_vec.push(Air::Finally);
|
|
pattern.create_air_vec(air_vec);
|
|
then.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::If {
|
|
tipo,
|
|
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);
|
|
}
|
|
AirExpression::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);
|
|
}
|
|
}
|
|
AirExpression::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);
|
|
}
|
|
}
|
|
AirExpression::RecordAccess {
|
|
field_index,
|
|
tipo,
|
|
record,
|
|
} => {
|
|
air_vec.push(Air::RecordAccess {
|
|
record_index: *field_index,
|
|
tipo: tipo.clone(),
|
|
});
|
|
record.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::TupleIndex {
|
|
tipo,
|
|
tuple_index,
|
|
tuple,
|
|
} => {
|
|
air_vec.push(Air::TupleIndex {
|
|
tipo: tipo.clone(),
|
|
tuple_index: *tuple_index,
|
|
});
|
|
tuple.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::ErrorTerm { tipo } => {
|
|
air_vec.push(Air::ErrorTerm { tipo: tipo.clone() })
|
|
}
|
|
AirExpression::Trace { tipo, msg, then } => {
|
|
air_vec.push(Air::Trace { tipo: tipo.clone() });
|
|
msg.create_air_vec(air_vec);
|
|
then.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::FieldsEmpty { constr } => {
|
|
air_vec.push(Air::FieldsEmpty);
|
|
constr.create_air_vec(air_vec);
|
|
}
|
|
AirExpression::ListEmpty { list } => {
|
|
air_vec.push(Air::ListEmpty);
|
|
list.create_air_vec(air_vec);
|
|
}
|
|
},
|
|
AirTree::UnhoistedSequence(_) => {
|
|
unreachable!("FIRST RESOLVE ALL UNHOISTED SEQUENCES")
|
|
}
|
|
_ => unreachable!("FOUND UNHOISTED STATEMENT"),
|
|
}
|
|
}
|
|
}
|