feat: almost done assignment have tuple and constr left

feat: modified the AirTree structure to have statements, sequences, and expressions
feat: changed the hoist_over function to be universal
This commit is contained in:
microproofs 2023-06-28 16:33:09 -04:00 committed by Kasey
parent 65bb7e48e2
commit 59362e3d8c
5 changed files with 394 additions and 327 deletions

View File

@ -501,6 +501,7 @@ impl<'a> CodeGenerator<'a> {
AssignmentProperties { AssignmentProperties {
value_type: value.tipo(), value_type: value.tipo(),
kind: *kind, kind: *kind,
remove_unused: true,
}, },
); );
@ -531,6 +532,7 @@ impl<'a> CodeGenerator<'a> {
AssignmentProperties { AssignmentProperties {
value_type: clauses[0].then.tipo(), value_type: clauses[0].then.tipo(),
kind: AssignmentKind::Let, kind: AssignmentKind::Let,
remove_unused: false,
}, },
); );
@ -5182,6 +5184,7 @@ impl<'a> CodeGenerator<'a> {
AssignmentProperties { AssignmentProperties {
value_type: data(), value_type: data(),
kind: AssignmentKind::Expect, kind: AssignmentKind::Expect,
remove_unused: true,
}, },
); );
value_stack.local_var(actual_type, &arg_name); value_stack.local_var(actual_type, &arg_name);

View File

@ -60,6 +60,7 @@ pub struct FunctionAccessKey {
pub struct AssignmentProperties { pub struct AssignmentProperties {
pub value_type: Arc<Type>, pub value_type: Arc<Type>,
pub kind: AssignmentKind, pub kind: AssignmentKind,
pub remove_unused: bool,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View File

@ -11,6 +11,78 @@ use super::air::Air;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum AirTree { pub enum AirTree {
Statement(AirStatement),
Expression(AirExpression),
IncompleteSequence(Vec<AirTree>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum AirStatement {
// Assignment
Let {
name: String,
value: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
DefineFunc {
func_name: String,
module_name: String,
params: Vec<String>,
recursive: bool,
variant_name: String,
func_body: Box<AirTree>,
hoisted_over: Box<AirTree>,
},
// Assertions
AssertConstr {
constr_index: usize,
constr: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
AssertBool {
is_true: bool,
value: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
// Field Access
FieldsExpose {
indices: Vec<(usize, String, Arc<Type>)>,
check_last_item: bool,
record: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
// List Access
ListAccessor {
tipo: Arc<Type>,
names: Vec<String>,
tail: bool,
check_last_item: bool,
list: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
ListExpose {
tipo: Arc<Type>,
tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>,
list: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
// Tuple Access
TupleAccessor {
names: Vec<String>,
tipo: Arc<Type>,
check_last_item: bool,
tuple: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
// Misc.
NoOp {
hoisted_over: Box<Option<AirTree>>,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum AirExpression {
// Primitives // Primitives
Int { Int {
value: String, value: String,
@ -45,15 +117,7 @@ pub enum AirTree {
func: Box<AirTree>, func: Box<AirTree>,
args: Vec<AirTree>, args: Vec<AirTree>,
}, },
DefineFunc {
func_name: String,
module_name: String,
params: Vec<String>,
recursive: bool,
variant_name: String,
func_body: Box<AirTree>,
hoisted_over: Box<AirTree>,
},
Fn { Fn {
params: Vec<String>, params: Vec<String>,
func_body: Box<AirTree>, func_body: Box<AirTree>,
@ -74,12 +138,7 @@ pub enum AirTree {
op: UnOp, op: UnOp,
arg: Box<AirTree>, arg: Box<AirTree>,
}, },
// Assignment
Let {
name: String,
value: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
UnWrapData { UnWrapData {
tipo: Arc<Type>, tipo: Arc<Type>,
value: Box<AirTree>, value: Box<AirTree>,
@ -88,16 +147,7 @@ pub enum AirTree {
tipo: Arc<Type>, tipo: Arc<Type>,
value: Box<AirTree>, value: Box<AirTree>,
}, },
AssertConstr {
constr_index: usize,
constr: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
AssertBool {
is_true: bool,
value: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
},
// When // When
When { When {
tipo: Arc<Type>, tipo: Arc<Type>,
@ -178,32 +228,7 @@ pub enum AirTree {
tipo: Arc<Type>, tipo: Arc<Type>,
record: Box<AirTree>, record: Box<AirTree>,
}, },
FieldsExpose {
indices: Vec<(usize, String, Arc<Type>)>,
check_last_item: bool,
record: Box<AirTree>,
},
// ListAccess
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 // Tuple Access
TupleAccessor {
names: Vec<String>,
tipo: Arc<Type>,
check_last_item: bool,
tuple: Box<AirTree>,
},
TupleIndex { TupleIndex {
tipo: Arc<Type>, tipo: Arc<Type>,
tuple_index: usize, tuple_index: usize,
@ -218,9 +243,6 @@ pub enum AirTree {
msg: Box<AirTree>, msg: Box<AirTree>,
then: Box<AirTree>, then: Box<AirTree>,
}, },
NoOp {
hoisted_over: Box<Option<AirTree>>,
},
FieldsEmpty { FieldsEmpty {
constr: Box<AirTree>, constr: Box<AirTree>,
}, },
@ -231,57 +253,57 @@ pub enum AirTree {
impl AirTree { impl AirTree {
pub fn int(value: impl ToString) -> AirTree { pub fn int(value: impl ToString) -> AirTree {
AirTree::Int { AirTree::Expression(AirExpression::Int {
value: value.to_string(), value: value.to_string(),
} })
} }
pub fn string(value: impl ToString) -> AirTree { pub fn string(value: impl ToString) -> AirTree {
AirTree::String { AirTree::Expression(AirExpression::String {
value: value.to_string(), value: value.to_string(),
} })
} }
pub fn byte_array(bytes: Vec<u8>) -> AirTree { pub fn byte_array(bytes: Vec<u8>) -> AirTree {
AirTree::ByteArray { bytes } AirTree::Expression(AirExpression::ByteArray { bytes })
} }
pub fn bool(value: bool) -> AirTree { pub fn bool(value: bool) -> AirTree {
AirTree::Bool { value } AirTree::Expression(AirExpression::Bool { value })
} }
pub fn list(mut items: Vec<AirTree>, tipo: Arc<Type>, tail: Option<AirTree>) -> AirTree { pub fn list(mut items: Vec<AirTree>, tipo: Arc<Type>, tail: Option<AirTree>) -> AirTree {
if let Some(tail) = tail { if let Some(tail) = tail {
items.push(tail); items.push(tail);
AirTree::List { AirTree::Expression(AirExpression::List {
tipo, tipo,
tail: true, tail: true,
items, items,
} })
} else { } else {
AirTree::List { AirTree::Expression(AirExpression::List {
tipo, tipo,
tail: false, tail: false,
items, items,
} })
} }
} }
pub fn tuple(items: Vec<AirTree>, tipo: Arc<Type>) -> AirTree { pub fn tuple(items: Vec<AirTree>, tipo: Arc<Type>) -> AirTree {
AirTree::Tuple { tipo, items } AirTree::Expression(AirExpression::Tuple { tipo, items })
} }
pub fn void() -> AirTree { pub fn void() -> AirTree {
AirTree::Void AirTree::Expression(AirExpression::Void)
} }
pub fn var( pub fn var(
constructor: ValueConstructor, constructor: ValueConstructor,
name: impl ToString, name: impl ToString,
variant_name: impl ToString, variant_name: impl ToString,
) -> AirTree { ) -> AirTree {
AirTree::Var { AirTree::Expression(AirExpression::Var {
constructor, constructor,
name: name.to_string(), name: name.to_string(),
variant_name: variant_name.to_string(), variant_name: variant_name.to_string(),
} })
} }
pub fn local_var(name: impl ToString, tipo: Arc<Type>) -> AirTree { pub fn local_var(name: impl ToString, tipo: Arc<Type>) -> AirTree {
AirTree::Var { AirTree::Expression(AirExpression::Var {
constructor: ValueConstructor::public( constructor: ValueConstructor::public(
tipo, tipo,
ValueConstructorVariant::LocalVariable { ValueConstructorVariant::LocalVariable {
@ -290,14 +312,14 @@ impl AirTree {
), ),
name: name.to_string(), name: name.to_string(),
variant_name: "".to_string(), variant_name: "".to_string(),
} })
} }
pub fn call(func: AirTree, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree { pub fn call(func: AirTree, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Call { AirTree::Expression(AirExpression::Call {
tipo, tipo,
func: func.into(), func: func.into(),
args, args,
} })
} }
pub fn define_func( pub fn define_func(
func_name: impl ToString, func_name: impl ToString,
@ -308,7 +330,7 @@ impl AirTree {
func_body: AirTree, func_body: AirTree,
hoisting_over: AirTree, hoisting_over: AirTree,
) -> AirTree { ) -> AirTree {
AirTree::DefineFunc { AirTree::Statement(AirStatement::DefineFunc {
func_name: func_name.to_string(), func_name: func_name.to_string(),
module_name: module_name.to_string(), module_name: module_name.to_string(),
params, params,
@ -316,63 +338,63 @@ impl AirTree {
variant_name: variant_name.to_string(), variant_name: variant_name.to_string(),
func_body: func_body.into(), func_body: func_body.into(),
hoisted_over: hoisting_over.into(), hoisted_over: hoisting_over.into(),
} })
} }
pub fn anon_func(params: Vec<String>, func_body: AirTree) -> AirTree { pub fn anon_func(params: Vec<String>, func_body: AirTree) -> AirTree {
AirTree::Fn { AirTree::Expression(AirExpression::Fn {
params, params,
func_body: func_body.into(), func_body: func_body.into(),
} })
} }
pub fn builtin(func: DefaultFunction, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree { pub fn builtin(func: DefaultFunction, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Builtin { func, tipo, args } AirTree::Expression(AirExpression::Builtin { func, tipo, args })
} }
pub fn binop(op: BinOp, tipo: Arc<Type>, left: AirTree, right: AirTree) -> AirTree { pub fn binop(op: BinOp, tipo: Arc<Type>, left: AirTree, right: AirTree) -> AirTree {
AirTree::BinOp { AirTree::Expression(AirExpression::BinOp {
name: op, name: op,
tipo, tipo,
left: left.into(), left: left.into(),
right: right.into(), right: right.into(),
} })
} }
pub fn unop(op: UnOp, arg: AirTree) -> AirTree { pub fn unop(op: UnOp, arg: AirTree) -> AirTree {
AirTree::UnOp { AirTree::Expression(AirExpression::UnOp {
op, op,
arg: arg.into(), arg: arg.into(),
} })
} }
pub fn let_assignment(name: impl ToString, value: AirTree) -> AirTree { pub fn let_assignment(name: impl ToString, value: AirTree) -> AirTree {
AirTree::Let { AirTree::Statement(AirStatement::Let {
name: name.to_string(), name: name.to_string(),
value: value.into(), value: value.into(),
hoisted_over: None.into(), hoisted_over: None.into(),
} })
} }
pub fn unwrap_data(value: AirTree, tipo: Arc<Type>) -> AirTree { pub fn unwrap_data(value: AirTree, tipo: Arc<Type>) -> AirTree {
AirTree::UnWrapData { AirTree::Expression(AirExpression::UnWrapData {
tipo, tipo,
value: value.into(), value: value.into(),
} })
} }
pub fn wrap_data(value: AirTree, tipo: Arc<Type>) -> AirTree { pub fn wrap_data(value: AirTree, tipo: Arc<Type>) -> AirTree {
AirTree::WrapData { AirTree::Expression(AirExpression::WrapData {
tipo, tipo,
value: value.into(), value: value.into(),
} })
} }
pub fn assert_constr_index(constr_index: usize, constr: AirTree) -> AirTree { pub fn assert_constr_index(constr_index: usize, constr: AirTree) -> AirTree {
AirTree::AssertConstr { AirTree::Statement(AirStatement::AssertConstr {
constr_index, constr_index,
constr: constr.into(), constr: constr.into(),
hoisted_over: None.into(), hoisted_over: None.into(),
} })
} }
pub fn assert_bool(is_true: bool, value: AirTree) -> AirTree { pub fn assert_bool(is_true: bool, value: AirTree) -> AirTree {
AirTree::AssertBool { AirTree::Statement(AirStatement::AssertBool {
is_true, is_true,
value: value.into(), value: value.into(),
hoisted_over: None.into(), hoisted_over: None.into(),
} })
} }
pub fn when( pub fn when(
subject_name: impl ToString, subject_name: impl ToString,
@ -380,12 +402,12 @@ impl AirTree {
clauses: Vec<AirTree>, clauses: Vec<AirTree>,
final_clause: AirTree, final_clause: AirTree,
) -> AirTree { ) -> AirTree {
AirTree::When { AirTree::Expression(AirExpression::When {
tipo, tipo,
subject_name: subject_name.to_string(), subject_name: subject_name.to_string(),
clauses, clauses,
final_clause: final_clause.into(), final_clause: final_clause.into(),
} })
} }
pub fn clause( pub fn clause(
subject_name: impl ToString, subject_name: impl ToString,
@ -395,14 +417,14 @@ impl AirTree {
otherwise: AirTree, otherwise: AirTree,
complex_clause: bool, complex_clause: bool,
) -> AirTree { ) -> AirTree {
AirTree::Clause { AirTree::Expression(AirExpression::Clause {
tipo, tipo,
subject_name: subject_name.to_string(), subject_name: subject_name.to_string(),
complex_clause, complex_clause,
pattern: pattern.into(), pattern: pattern.into(),
then: then.into(), then: then.into(),
otherwise: otherwise.into(), otherwise: otherwise.into(),
} })
} }
pub fn list_clause( pub fn list_clause(
tail_name: impl ToString, tail_name: impl ToString,
@ -412,14 +434,14 @@ impl AirTree {
next_tail_name: Option<String>, next_tail_name: Option<String>,
complex_clause: bool, complex_clause: bool,
) -> AirTree { ) -> AirTree {
AirTree::ListClause { AirTree::Expression(AirExpression::ListClause {
tipo, tipo,
tail_name: tail_name.to_string(), tail_name: tail_name.to_string(),
next_tail_name, next_tail_name,
complex_clause, complex_clause,
then: then.into(), then: then.into(),
otherwise: otherwise.into(), otherwise: otherwise.into(),
} })
} }
pub fn tuple_clause( pub fn tuple_clause(
subject_name: impl ToString, subject_name: impl ToString,
@ -432,7 +454,7 @@ impl AirTree {
) -> AirTree { ) -> AirTree {
let type_count = tipo.get_inner_types().len(); let type_count = tipo.get_inner_types().len();
AirTree::TupleClause { AirTree::Expression(AirExpression::TupleClause {
tipo, tipo,
indices, indices,
predefined_indices, predefined_indices,
@ -441,13 +463,13 @@ impl AirTree {
complex_clause, complex_clause,
then: then.into(), then: then.into(),
otherwise: otherwise.into(), otherwise: otherwise.into(),
} })
} }
pub fn wrap_clause(then: AirTree, otherwise: AirTree) -> AirTree { pub fn wrap_clause(then: AirTree, otherwise: AirTree) -> AirTree {
AirTree::WrapClause { AirTree::Expression(AirExpression::WrapClause {
then: then.into(), then: then.into(),
otherwise: otherwise.into(), otherwise: otherwise.into(),
} })
} }
pub fn clause_guard( pub fn clause_guard(
subject_name: impl ToString, subject_name: impl ToString,
@ -455,12 +477,12 @@ impl AirTree {
tipo: Arc<Type>, tipo: Arc<Type>,
then: AirTree, then: AirTree,
) -> AirTree { ) -> AirTree {
AirTree::ClauseGuard { AirTree::Expression(AirExpression::ClauseGuard {
subject_name: subject_name.to_string(), subject_name: subject_name.to_string(),
tipo, tipo,
pattern: pattern.into(), pattern: pattern.into(),
then: then.into(), then: then.into(),
} })
} }
pub fn list_clause_guard( pub fn list_clause_guard(
tail_name: impl ToString, tail_name: impl ToString,
@ -469,19 +491,19 @@ impl AirTree {
then: AirTree, then: AirTree,
next_tail_name: Option<String>, next_tail_name: Option<String>,
) -> AirTree { ) -> AirTree {
AirTree::ListClauseGuard { AirTree::Expression(AirExpression::ListClauseGuard {
tipo, tipo,
tail_name: tail_name.to_string(), tail_name: tail_name.to_string(),
next_tail_name, next_tail_name,
inverse, inverse,
then: then.into(), then: then.into(),
} })
} }
pub fn finally(pattern: AirTree, then: AirTree) -> AirTree { pub fn finally(pattern: AirTree, then: AirTree) -> AirTree {
AirTree::Finally { AirTree::Expression(AirExpression::Finally {
pattern: pattern.into(), pattern: pattern.into(),
then: then.into(), then: then.into(),
} })
} }
pub fn if_branches( pub fn if_branches(
mut branches: Vec<(AirTree, AirTree)>, mut branches: Vec<(AirTree, AirTree)>,
@ -491,26 +513,26 @@ impl AirTree {
assert!(!branches.is_empty()); assert!(!branches.is_empty());
let last_if = branches.pop().unwrap(); let last_if = branches.pop().unwrap();
let mut final_if = AirTree::If { let mut final_if = AirTree::Expression(AirExpression::If {
tipo: tipo.clone(), tipo: tipo.clone(),
pattern: last_if.0.into(), pattern: last_if.0.into(),
then: last_if.1.into(), then: last_if.1.into(),
otherwise: otherwise.into(), otherwise: otherwise.into(),
}; });
while let Some(branch) = branches.pop() { while let Some(branch) = branches.pop() {
final_if = AirTree::If { final_if = AirTree::Expression(AirExpression::If {
tipo: tipo.clone(), tipo: tipo.clone(),
pattern: branch.0.into(), pattern: branch.0.into(),
then: branch.1.into(), then: branch.1.into(),
otherwise: final_if.into(), otherwise: final_if.into(),
}; });
} }
final_if final_if
} }
pub fn create_constr(tag: usize, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree { pub fn create_constr(tag: usize, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Constr { tag, tipo, args } AirTree::Expression(AirExpression::Constr { tag, tipo, args })
} }
pub fn record_update( pub fn record_update(
@ -520,20 +542,20 @@ impl AirTree {
record: AirTree, record: AirTree,
args: Vec<AirTree>, args: Vec<AirTree>,
) -> AirTree { ) -> AirTree {
AirTree::RecordUpdate { AirTree::Expression(AirExpression::RecordUpdate {
highest_index, highest_index,
indices, indices,
tipo, tipo,
record: record.into(), record: record.into(),
args, args,
} })
} }
pub fn record_access(field_index: u64, tipo: Arc<Type>, record: AirTree) -> AirTree { pub fn record_access(field_index: u64, tipo: Arc<Type>, record: AirTree) -> AirTree {
AirTree::RecordAccess { AirTree::Expression(AirExpression::RecordAccess {
field_index, field_index,
tipo, tipo,
record: record.into(), record: record.into(),
} })
} }
pub fn fields_expose( pub fn fields_expose(
@ -541,11 +563,12 @@ impl AirTree {
check_last_item: bool, check_last_item: bool,
record: AirTree, record: AirTree,
) -> AirTree { ) -> AirTree {
AirTree::FieldsExpose { AirTree::Statement(AirStatement::FieldsExpose {
indices, indices,
check_last_item, check_last_item,
record: record.into(), record: record.into(),
} hoisted_over: None.into(),
})
} }
pub fn list_access( pub fn list_access(
names: Vec<String>, names: Vec<String>,
@ -554,13 +577,14 @@ impl AirTree {
check_last_item: bool, check_last_item: bool,
list: AirTree, list: AirTree,
) -> AirTree { ) -> AirTree {
AirTree::ListAccessor { AirTree::Statement(AirStatement::ListAccessor {
tipo, tipo,
names, names,
tail, tail,
check_last_item, check_last_item,
list: list.into(), list: list.into(),
} hoisted_over: None.into(),
})
} }
pub fn list_expose( pub fn list_expose(
tail_head_names: Vec<(String, String)>, tail_head_names: Vec<(String, String)>,
@ -568,12 +592,13 @@ impl AirTree {
tipo: Arc<Type>, tipo: Arc<Type>,
list: AirTree, list: AirTree,
) -> AirTree { ) -> AirTree {
AirTree::ListExpose { AirTree::Statement(AirStatement::ListExpose {
tipo, tipo,
tail_head_names, tail_head_names,
tail, tail,
list: list.into(), list: list.into(),
} hoisted_over: None.into(),
})
} }
pub fn tuple_access( pub fn tuple_access(
names: Vec<String>, names: Vec<String>,
@ -581,213 +606,80 @@ impl AirTree {
check_last_item: bool, check_last_item: bool,
tuple: AirTree, tuple: AirTree,
) -> AirTree { ) -> AirTree {
AirTree::TupleAccessor { AirTree::Statement(AirStatement::TupleAccessor {
names, names,
tipo, tipo,
check_last_item, check_last_item,
tuple: tuple.into(), tuple: tuple.into(),
} hoisted_over: None.into(),
})
} }
pub fn tuple_index(tuple_index: usize, tipo: Arc<Type>, tuple: AirTree) -> AirTree { pub fn tuple_index(tuple_index: usize, tipo: Arc<Type>, tuple: AirTree) -> AirTree {
AirTree::TupleIndex { AirTree::Expression(AirExpression::TupleIndex {
tipo, tipo,
tuple_index, tuple_index,
tuple: tuple.into(), tuple: tuple.into(),
} })
} }
pub fn error(tipo: Arc<Type>) -> AirTree { pub fn error(tipo: Arc<Type>) -> AirTree {
AirTree::ErrorTerm { tipo } AirTree::Expression(AirExpression::ErrorTerm { tipo })
} }
pub fn trace(msg: AirTree, tipo: Arc<Type>, then: AirTree) -> AirTree { pub fn trace(msg: AirTree, tipo: Arc<Type>, then: AirTree) -> AirTree {
AirTree::Trace { AirTree::Expression(AirExpression::Trace {
tipo, tipo,
msg: msg.into(), msg: msg.into(),
then: then.into(), then: then.into(),
} })
} }
pub fn no_op() -> AirTree { pub fn no_op() -> AirTree {
AirTree::NoOp { AirTree::Statement(AirStatement::NoOp {
hoisted_over: None.into(), hoisted_over: None.into(),
} })
} }
pub fn fields_empty(constr: AirTree) -> AirTree { pub fn fields_empty(constr: AirTree) -> AirTree {
AirTree::FieldsEmpty { AirTree::Expression(AirExpression::FieldsEmpty {
constr: constr.into(), constr: constr.into(),
} })
} }
pub fn list_empty(list: AirTree) -> AirTree { pub fn list_empty(list: AirTree) -> AirTree {
AirTree::ListEmpty { list: list.into() } AirTree::Expression(AirExpression::ListEmpty { list: list.into() })
}
pub fn hoist_over(mut assignment: AirTree, next_exp: AirTree) -> AirTree {
match &mut assignment {
AirTree::Statement(st) => match st {
AirStatement::Let { hoisted_over, .. }
| AirStatement::AssertConstr { hoisted_over, .. }
| AirStatement::AssertBool { hoisted_over, .. }
| AirStatement::FieldsExpose { hoisted_over, .. }
| AirStatement::ListAccessor { hoisted_over, .. }
| AirStatement::NoOp { hoisted_over }
| AirStatement::ListExpose { hoisted_over, .. }
| AirStatement::TupleAccessor { hoisted_over, .. } => {
*hoisted_over = Some(next_exp).into();
assignment
}
AirStatement::DefineFunc { .. } => {
unreachable!("Should not use this function to hoist defined functions.")
} }
pub fn hoist_let(assignment: AirTree, next_exp: AirTree) -> AirTree {
match assignment {
AirTree::Let { name, value, .. } => AirTree::Let {
name,
value,
hoisted_over: Some(next_exp).into(),
}, },
AirTree::AssertBool { is_true, value, .. } => AirTree::AssertBool { AirTree::Expression(_) => {
is_true, unreachable!("Trying to hoist an expression onto an expression.")
value, }
hoisted_over: Some(next_exp).into(), AirTree::IncompleteSequence(seq) => {
}, let mut final_exp = next_exp;
AirTree::AssertConstr { while let Some(assign) = seq.pop() {
constr_index, final_exp = Self::hoist_over(assign, final_exp);
constr, }
.. final_exp
} => AirTree::AssertConstr { }
constr_index,
constr,
hoisted_over: Some(next_exp).into(),
},
AirTree::NoOp { .. } => AirTree::NoOp {
hoisted_over: Some(next_exp).into(),
},
_ => unimplemented!("IS THIS REACHABLE?"),
} }
} }
pub fn to_air_vec(air_vec: &mut Vec<Air>, tree: AirTree) { pub fn to_air_vec(_air_vec: &mut Vec<Air>, tree: AirTree) {
match tree { match tree {
AirTree::Int { value } => air_vec.push(todo!()), AirTree::Statement(_) => todo!(),
AirTree::String { value } => todo!(), AirTree::Expression(_) => todo!(),
AirTree::ByteArray { bytes } => todo!(), AirTree::IncompleteSequence(_) => todo!(),
AirTree::Bool { value } => todo!(),
AirTree::List { tipo, tail, items } => todo!(),
AirTree::Tuple { tipo, items } => todo!(),
AirTree::Void => todo!(),
AirTree::Var {
constructor,
name,
variant_name,
} => todo!(),
AirTree::Call { tipo, func, args } => todo!(),
AirTree::DefineFunc {
func_name,
module_name,
params,
recursive,
variant_name,
func_body,
hoisted_over,
} => todo!(),
AirTree::Fn { params, func_body } => todo!(),
AirTree::Builtin { func, tipo, args } => todo!(),
AirTree::BinOp {
name,
tipo,
left,
right,
} => todo!(),
AirTree::UnOp { op, arg } => todo!(),
AirTree::Let {
name,
value,
hoisted_over,
} => todo!(),
AirTree::UnWrapData { tipo, value } => todo!(),
AirTree::WrapData { tipo, value } => todo!(),
AirTree::AssertConstr { .. } => todo!(),
AirTree::AssertBool { .. } => todo!(),
AirTree::When {
tipo,
subject_name,
clauses,
final_clause,
} => todo!(),
AirTree::Clause {
tipo,
subject_name,
complex_clause,
pattern,
then,
otherwise,
} => todo!(),
AirTree::ListClause {
tipo,
tail_name,
next_tail_name,
complex_clause,
then,
otherwise,
} => todo!(),
AirTree::WrapClause { then, otherwise } => todo!(),
AirTree::TupleClause {
tipo,
indices,
predefined_indices,
subject_name,
type_count,
complex_clause,
then,
otherwise,
} => todo!(),
AirTree::ClauseGuard {
subject_name,
tipo,
pattern,
then,
} => todo!(),
AirTree::ListClauseGuard {
tipo,
tail_name,
next_tail_name,
inverse,
then,
} => todo!(),
AirTree::Finally { pattern, then } => todo!(),
AirTree::If {
tipo,
pattern,
then,
otherwise,
} => todo!(),
AirTree::Constr { tag, tipo, args } => todo!(),
AirTree::RecordUpdate {
highest_index,
indices,
tipo,
record,
args,
} => todo!(),
AirTree::RecordAccess {
field_index,
tipo,
record,
} => todo!(),
AirTree::FieldsExpose {
indices,
check_last_item,
record,
} => todo!(),
AirTree::ListAccessor {
tipo,
names,
tail,
check_last_item,
list,
} => todo!(),
AirTree::ListExpose {
tipo,
tail_head_names,
tail,
list,
} => todo!(),
AirTree::TupleAccessor {
names,
tipo,
check_last_item,
tuple,
} => todo!(),
AirTree::TupleIndex {
tipo,
tuple_index,
tuple,
} => todo!(),
AirTree::ErrorTerm { tipo } => todo!(),
AirTree::Trace { tipo, msg, then } => todo!(),
AirTree::NoOp { .. } => todo!(),
AirTree::FieldsEmpty { constr } => todo!(),
AirTree::ListEmpty { list } => todo!(),
} }
} }
} }

View File

@ -1,8 +1,6 @@
mod builder; mod builder;
use std::{rc::Rc, sync::Arc}; use indexmap::IndexMap;
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools; use itertools::Itertools;
use uplc::ast::{Name, Program, Term}; use uplc::ast::{Name, Program, Term};
@ -84,12 +82,16 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => { TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => {
let mut expressions = expressions.clone(); let mut expressions = expressions.clone();
let mut last_exp = self.build(&expressions.pop().unwrap()); let mut last_exp = self.build(&expressions.pop().unwrap_or_else(|| {
unreachable!("Sequence or Pipeline should have at least one expression")
}));
assert!(matches!(last_exp, AirTree::Expression(_)));
while let Some(expression) = expressions.pop() { while let Some(expression) = expressions.pop() {
let exp_tree = self.build(&expression); let exp_tree = self.build(&expression);
last_exp = AirTree::hoist_let(exp_tree, last_exp); last_exp = AirTree::hoist_over(exp_tree, last_exp);
} }
last_exp last_exp
} }
@ -243,6 +245,7 @@ impl<'a> CodeGenerator<'a> {
AssignmentProperties { AssignmentProperties {
value_type: value.tipo(), value_type: value.tipo(),
kind: *kind, kind: *kind,
remove_unused: true,
}, },
) )
} }
@ -260,7 +263,7 @@ impl<'a> CodeGenerator<'a> {
let mut clauses = clauses.clone(); let mut clauses = clauses.clone();
if clauses.is_empty() { if clauses.is_empty() {
panic!("We should have one clause at least") unreachable!("We should have one clause at least")
} else if clauses.len() == 1 { } else if clauses.len() == 1 {
let last_clause = clauses.pop().unwrap(); let last_clause = clauses.pop().unwrap();
@ -275,10 +278,11 @@ impl<'a> CodeGenerator<'a> {
AssignmentProperties { AssignmentProperties {
value_type: subject.tipo(), value_type: subject.tipo(),
kind: AssignmentKind::Let, kind: AssignmentKind::Let,
remove_unused: false,
}, },
); );
AirTree::hoist_let(assignment, clause_then) AirTree::hoist_over(assignment, clause_then)
} else { } else {
clauses = if subject.tipo().is_list() { clauses = if subject.tipo().is_list() {
build::rearrange_clauses(clauses.clone()) build::rearrange_clauses(clauses.clone())
@ -336,7 +340,12 @@ impl<'a> CodeGenerator<'a> {
field_map: field_map.clone(), field_map: field_map.clone(),
location: Span::empty(), location: Span::empty(),
module: module_name.clone(), module: module_name.clone(),
constructors_count: data_type.unwrap().constructors.len() as u16, constructors_count: data_type
.unwrap_or_else(|| {
unreachable!("Created a module type without a definition?")
})
.constructors
.len() as u16,
}, },
); );

View File

@ -1,12 +1,14 @@
use std::sync::Arc; use std::sync::Arc;
use indexmap::IndexMap;
use itertools::Itertools;
use crate::{ use crate::{
ast::{AssignmentKind, BinOp, Constant, Pattern}, ast::{BinOp, Constant, Pattern},
builtins::int, builtins::int,
gen_uplc::{ gen_uplc::{
air::{self, Air},
builder::AssignmentProperties, builder::AssignmentProperties,
tree::AirTree, tree::{AirStatement, AirTree},
}, },
tipo::{PatternConstructor, Type}, tipo::{PatternConstructor, Type},
}; };
@ -26,10 +28,14 @@ pub fn assignment_air_tree(
match pattern { match pattern {
Pattern::Int { Pattern::Int {
value: expected_int, value: expected_int,
location,
.. ..
} => { } => {
if props.kind.is_expect() { if props.kind.is_expect() {
let name = format!("__expected_by_{}", expected_int); let name = format!(
"__expected_by_{}_span_{}_{}",
expected_int, location.start, location.end
);
let assignment = AirTree::let_assignment(&name, value); let assignment = AirTree::let_assignment(&name, value);
let expect = AirTree::binop( let expect = AirTree::binop(
@ -38,19 +44,20 @@ pub fn assignment_air_tree(
AirTree::int(expected_int), AirTree::int(expected_int),
AirTree::local_var(name, int()), AirTree::local_var(name, int()),
); );
AirTree::assert_bool(true, AirTree::hoist_over(assignment, expect))
AirTree::assert_bool(true, AirTree::hoist_let(assignment, expect))
} else { } else {
unreachable!("Code Gen should never reach here") unreachable!("Code Gen should never reach here")
} }
} }
Pattern::Var { name, .. } => { Pattern::Var { name, .. } => {
if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() { if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() {
let mut index_map = IndexMap::new();
let tipo = convert_opaque_type();
let assignment = AirTree::let_assignment(name, value); let assignment = AirTree::let_assignment(name, value);
let expect = todo!();
let assign = AirTree::let_assignment("_", AirTree::hoist_let(assignment, expect));
let val = AirTree::local_var(name, tipo.clone()); let val = AirTree::local_var(name, tipo.clone());
AirTree::let_assignment(name, AirTree::hoist_let(assign, val)) let expect = expect_type(&tipo, val.clone(), &mut index_map);
let assign = AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect));
AirTree::let_assignment(name, AirTree::hoist_over(assign, val))
} else { } else {
AirTree::let_assignment(name, value) AirTree::let_assignment(name, value)
} }
@ -58,33 +65,188 @@ pub fn assignment_air_tree(
Pattern::Assign { name, pattern, .. } => { Pattern::Assign { name, pattern, .. } => {
let inner_pattern = let inner_pattern =
assignment_air_tree(pattern, AirTree::local_var(name, tipo.clone()), tipo, props); assignment_air_tree(pattern, AirTree::local_var(name, tipo.clone()), tipo, props);
AirTree::let_assignment(name, inner_pattern) AirTree::let_assignment(name, inner_pattern)
} }
Pattern::Discard { name, .. } => { Pattern::Discard { name, .. } => {
if props.kind.is_expect() { if props.kind.is_expect() || !props.remove_unused {
AirTree::let_assignment(name, value) AirTree::let_assignment(name, value)
} else { } else {
AirTree::no_op() AirTree::no_op()
} }
} }
Pattern::List { Pattern::List {
location,
elements, elements,
tail, tail,
} => todo!(),
Pattern::Constructor {
is_record,
location, location,
name, ..
arguments, } => {
module, let list_name = format!("__expect_list_span_{}_{}", location.start, location.end);
constructor, assert!(tipo.is_list());
with_spread, assert!(props.kind.is_expect());
tipo, let list_elem_types = tipo.get_inner_types();
} => todo!(),
Pattern::Tuple { location, elems } => todo!(), let list_elem_type = list_elem_types
.get(0)
.unwrap_or_else(|| unreachable!("No list element type?"));
let mut elems = elements
.iter()
.enumerate()
.map(|(index, elem)| {
let elem_name = match elem {
Pattern::Var { name, .. } => name.to_string(),
Pattern::Assign { name, .. } => name.to_string(),
Pattern::Discard { .. } => "_".to_string(),
_ => format!(
"elem_{}_span_{}_{}",
index,
elem.location().start,
elem.location().end
),
};
let val = AirTree::local_var(&elem_name, list_elem_type.clone());
(
elem_name,
assignment_air_tree(elem, val, list_elem_type, props.clone()),
)
})
.collect_vec();
// If Some then push tail onto elems
tail.iter().for_each(|tail| {
let tail_name = match tail.as_ref() {
Pattern::Var { name, .. } => name.to_string(),
Pattern::Assign { name, .. } => name.to_string(),
Pattern::Discard { .. } => "_".to_string(),
_ => format!(
"tail_span_{}_{}",
tail.location().start,
tail.location().end
),
};
let val = AirTree::local_var(&tail_name, tipo.clone());
elems.push((
tail_name,
assignment_air_tree(tail, val, tipo, props.clone()),
));
});
let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec();
let mut sequence = vec![AirTree::list_access(
names,
tipo.clone(),
tail.is_some(),
tail.is_none(),
value,
)];
sequence.append(&mut elems.into_iter().map(|(_, elem)| elem).collect_vec());
AirTree::IncompleteSequence(sequence)
} }
Pattern::Constructor {
arguments,
constructor,
is_record,
name,
..
} => {
if props.kind.is_expect() {
todo!()
} else {
assert!(is_record);
let field_map = match constructor {
PatternConstructor::Record { field_map, .. } => field_map.clone(),
};
let mut type_map: IndexMap<usize, Arc<Type>> = IndexMap::new();
println!("tipo is {tipo:#?}");
for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() {
let field_type = arg.clone();
type_map.insert(index, field_type);
}
let fields = arguments
.iter()
.enumerate()
.map(|(index, arg)| {
let label = arg.label.clone().unwrap_or_default();
let field_index = if let Some(field_map) = &field_map {
*field_map.fields.get(&label).map(|x| &x.0).unwrap_or(&index)
} else {
index
};
let field_name = match &arg.value {
Pattern::Var { name, .. } => name.to_string(),
Pattern::Assign { name, .. } => name.to_string(),
Pattern::Discard { .. } => "_".to_string(),
_ => format!(
"field_{}_span_{}_{}",
field_index,
arg.value.location().start,
arg.value.location().end
),
};
let arg_type = type_map.get(&field_index).unwrap_or_else(|| {
unreachable!(
"Missing type for field {} of constr {}",
field_index, name
)
});
let val = AirTree::local_var(field_name.to_string(), arg_type.clone());
(
field_index,
field_name,
arg_type.clone(),
assignment_air_tree(&arg.value, val, arg_type, props.clone()),
)
})
.collect_vec();
let indices = fields
.iter()
.map(|(index, name, tipo, _)| (*index, name.to_string(), tipo.clone()))
.collect_vec();
let mut sequence = vec![AirTree::fields_expose(indices, false, value)];
sequence.append(
&mut fields
.into_iter()
.map(|(_, _, _, field)| field)
.collect_vec(),
);
AirTree::IncompleteSequence(sequence)
}
}
Pattern::Tuple { elems, .. } => todo!(),
}
}
pub fn expect_type(
tipo: &Arc<Type>,
value: AirTree,
defined_data_types: &mut IndexMap<String, u64>,
) -> AirTree {
todo!()
}
pub fn convert_opaque_type() -> Arc<Type> {
todo!()
} }
pub fn handle_each_clause( pub fn handle_each_clause(