feat: start on build assignment

feat: implement assignment hoisting
This commit is contained in:
microproofs 2023-06-28 01:55:16 -04:00 committed by Kasey
parent c359bd35d7
commit 65bb7e48e2
3 changed files with 123 additions and 20 deletions

View File

@ -3,8 +3,8 @@ use std::sync::Arc;
use uplc::builtins::DefaultFunction; use uplc::builtins::DefaultFunction;
use crate::{ use crate::{
ast::{BinOp, UnOp}, ast::{BinOp, Span, UnOp},
tipo::{Type, ValueConstructor}, tipo::{Type, ValueConstructor, ValueConstructorVariant},
}; };
use super::air::Air; use super::air::Air;
@ -91,10 +91,12 @@ pub enum AirTree {
AssertConstr { AssertConstr {
constr_index: usize, constr_index: usize,
constr: Box<AirTree>, constr: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
}, },
AssertBool { AssertBool {
is_true: bool, is_true: bool,
value: Box<AirTree>, value: Box<AirTree>,
hoisted_over: Box<Option<AirTree>>,
}, },
// When // When
When { When {
@ -216,7 +218,9 @@ pub enum AirTree {
msg: Box<AirTree>, msg: Box<AirTree>,
then: Box<AirTree>, then: Box<AirTree>,
}, },
NoOp, NoOp {
hoisted_over: Box<Option<AirTree>>,
},
FieldsEmpty { FieldsEmpty {
constr: Box<AirTree>, constr: Box<AirTree>,
}, },
@ -276,6 +280,18 @@ impl AirTree {
variant_name: variant_name.to_string(), variant_name: variant_name.to_string(),
} }
} }
pub fn local_var(name: impl ToString, tipo: Arc<Type>) -> AirTree {
AirTree::Var {
constructor: ValueConstructor::public(
tipo,
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: name.to_string(),
variant_name: "".to_string(),
}
}
pub fn call(func: AirTree, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree { pub fn call(func: AirTree, tipo: Arc<Type>, args: Vec<AirTree>) -> AirTree {
AirTree::Call { AirTree::Call {
tipo, tipo,
@ -348,12 +364,14 @@ impl AirTree {
AirTree::AssertConstr { AirTree::AssertConstr {
constr_index, constr_index,
constr: constr.into(), constr: constr.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::AssertBool {
is_true, is_true,
value: value.into(), value: value.into(),
hoisted_over: None.into(),
} }
} }
pub fn when( pub fn when(
@ -588,7 +606,9 @@ impl AirTree {
} }
} }
pub fn no_op() -> AirTree { pub fn no_op() -> AirTree {
AirTree::NoOp AirTree::NoOp {
hoisted_over: None.into(),
}
} }
pub fn fields_empty(constr: AirTree) -> AirTree { pub fn fields_empty(constr: AirTree) -> AirTree {
AirTree::FieldsEmpty { AirTree::FieldsEmpty {
@ -605,13 +625,30 @@ impl AirTree {
value, value,
hoisted_over: Some(next_exp).into(), hoisted_over: Some(next_exp).into(),
}, },
AirTree::AssertBool { is_true, value, .. } => AirTree::AssertBool {
is_true,
value,
hoisted_over: Some(next_exp).into(),
},
AirTree::AssertConstr {
constr_index,
constr,
..
} => 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?"), _ => unimplemented!("IS THIS REACHABLE?"),
} }
} }
pub fn to_air_vec(tree: AirTree) -> Vec<Air> { pub fn to_air_vec(air_vec: &mut Vec<Air>, tree: AirTree) {
match tree { match tree {
AirTree::Int { value } => todo!(), AirTree::Int { value } => air_vec.push(todo!()),
AirTree::String { value } => todo!(), AirTree::String { value } => todo!(),
AirTree::ByteArray { bytes } => todo!(), AirTree::ByteArray { bytes } => todo!(),
AirTree::Bool { value } => todo!(), AirTree::Bool { value } => todo!(),
@ -649,11 +686,8 @@ impl AirTree {
} => todo!(), } => todo!(),
AirTree::UnWrapData { tipo, value } => todo!(), AirTree::UnWrapData { tipo, value } => todo!(),
AirTree::WrapData { tipo, value } => todo!(), AirTree::WrapData { tipo, value } => todo!(),
AirTree::AssertConstr { AirTree::AssertConstr { .. } => todo!(),
constr_index, AirTree::AssertBool { .. } => todo!(),
constr,
} => todo!(),
AirTree::AssertBool { is_true, value } => todo!(),
AirTree::When { AirTree::When {
tipo, tipo,
subject_name, subject_name,
@ -751,7 +785,7 @@ impl AirTree {
} => todo!(), } => todo!(),
AirTree::ErrorTerm { tipo } => todo!(), AirTree::ErrorTerm { tipo } => todo!(),
AirTree::Trace { tipo, msg, then } => todo!(), AirTree::Trace { tipo, msg, then } => todo!(),
AirTree::NoOp => todo!(), AirTree::NoOp { .. } => todo!(),
AirTree::FieldsEmpty { constr } => todo!(), AirTree::FieldsEmpty { constr } => todo!(),
AirTree::ListEmpty { list } => todo!(), AirTree::ListEmpty { list } => todo!(),
} }

View File

@ -389,7 +389,6 @@ impl<'a> CodeGenerator<'a> {
let mut update_args = vec![]; let mut update_args = vec![];
let mut highest_index = 0; let mut highest_index = 0;
let record = self.build(spread);
for arg in args for arg in args
.iter() .iter()
@ -409,7 +408,7 @@ impl<'a> CodeGenerator<'a> {
index_types, index_types,
highest_index, highest_index,
tipo.clone(), tipo.clone(),
record, self.build(spread),
update_args, update_args,
) )
} }

View File

@ -1,18 +1,90 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{ use crate::{
ast::{Constant, Pattern}, ast::{AssignmentKind, BinOp, Constant, Pattern},
gen_uplc::{builder::AssignmentProperties, tree::AirTree}, builtins::int,
gen_uplc::{
air::{self, Air},
builder::AssignmentProperties,
tree::AirTree,
},
tipo::{PatternConstructor, Type}, tipo::{PatternConstructor, Type},
}; };
pub fn assignment_air_tree( pub fn assignment_air_tree(
pattern: &Pattern<PatternConstructor, Arc<Type>>, pattern: &Pattern<PatternConstructor, Arc<Type>>,
value: AirTree, mut value: AirTree,
tipo: &Arc<Type>, tipo: &Arc<Type>,
props: AssignmentProperties, props: AssignmentProperties,
) -> AirTree { ) -> AirTree {
todo!() if props.value_type.is_data() && props.kind.is_expect() && !tipo.is_data() {
value = AirTree::unwrap_data(value, tipo.clone());
} else if !props.value_type.is_data() && tipo.is_data() {
value = AirTree::wrap_data(value, tipo.clone());
}
match pattern {
Pattern::Int {
value: expected_int,
..
} => {
if props.kind.is_expect() {
let name = format!("__expected_by_{}", expected_int);
let assignment = AirTree::let_assignment(&name, value);
let expect = AirTree::binop(
BinOp::Eq,
int(),
AirTree::int(expected_int),
AirTree::local_var(name, int()),
);
AirTree::assert_bool(true, AirTree::hoist_let(assignment, expect))
} else {
unreachable!("Code Gen should never reach here")
}
}
Pattern::Var { name, .. } => {
if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() {
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());
AirTree::let_assignment(name, AirTree::hoist_let(assign, val))
} else {
AirTree::let_assignment(name, value)
}
}
Pattern::Assign { name, pattern, .. } => {
let inner_pattern =
assignment_air_tree(pattern, AirTree::local_var(name, tipo.clone()), tipo, props);
AirTree::let_assignment(name, inner_pattern)
}
Pattern::Discard { name, .. } => {
if props.kind.is_expect() {
AirTree::let_assignment(name, value)
} else {
AirTree::no_op()
}
}
Pattern::List {
location,
elements,
tail,
} => todo!(),
Pattern::Constructor {
is_record,
location,
name,
arguments,
module,
constructor,
with_spread,
tipo,
} => todo!(),
Pattern::Tuple { location, elems } => todo!(),
}
} }
pub fn handle_each_clause( pub fn handle_each_clause(
@ -31,5 +103,3 @@ pub fn constants_ir(literal: &Constant) -> AirTree {
Constant::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()), Constant::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()),
} }
} }