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 crate::{
ast::{BinOp, UnOp},
tipo::{Type, ValueConstructor},
ast::{BinOp, Span, UnOp},
tipo::{Type, ValueConstructor, ValueConstructorVariant},
};
use super::air::Air;
@ -91,10 +91,12 @@ pub enum 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 {
@ -216,7 +218,9 @@ pub enum AirTree {
msg: Box<AirTree>,
then: Box<AirTree>,
},
NoOp,
NoOp {
hoisted_over: Box<Option<AirTree>>,
},
FieldsEmpty {
constr: Box<AirTree>,
},
@ -276,6 +280,18 @@ impl AirTree {
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 {
AirTree::Call {
tipo,
@ -348,12 +364,14 @@ impl AirTree {
AirTree::AssertConstr {
constr_index,
constr: constr.into(),
hoisted_over: None.into(),
}
}
pub fn assert_bool(is_true: bool, value: AirTree) -> AirTree {
AirTree::AssertBool {
is_true,
value: value.into(),
hoisted_over: None.into(),
}
}
pub fn when(
@ -588,7 +606,9 @@ impl AirTree {
}
}
pub fn no_op() -> AirTree {
AirTree::NoOp
AirTree::NoOp {
hoisted_over: None.into(),
}
}
pub fn fields_empty(constr: AirTree) -> AirTree {
AirTree::FieldsEmpty {
@ -605,13 +625,30 @@ impl AirTree {
value,
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?"),
}
}
pub fn to_air_vec(tree: AirTree) -> Vec<Air> {
pub fn to_air_vec(air_vec: &mut Vec<Air>, tree: AirTree) {
match tree {
AirTree::Int { value } => todo!(),
AirTree::Int { value } => air_vec.push(todo!()),
AirTree::String { value } => todo!(),
AirTree::ByteArray { bytes } => todo!(),
AirTree::Bool { value } => todo!(),
@ -649,11 +686,8 @@ impl AirTree {
} => todo!(),
AirTree::UnWrapData { tipo, value } => todo!(),
AirTree::WrapData { tipo, value } => todo!(),
AirTree::AssertConstr {
constr_index,
constr,
} => todo!(),
AirTree::AssertBool { is_true, value } => todo!(),
AirTree::AssertConstr { .. } => todo!(),
AirTree::AssertBool { .. } => todo!(),
AirTree::When {
tipo,
subject_name,
@ -751,7 +785,7 @@ impl AirTree {
} => todo!(),
AirTree::ErrorTerm { tipo } => todo!(),
AirTree::Trace { tipo, msg, then } => todo!(),
AirTree::NoOp => todo!(),
AirTree::NoOp { .. } => todo!(),
AirTree::FieldsEmpty { constr } => todo!(),
AirTree::ListEmpty { list } => todo!(),
}

View File

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

View File

@ -1,18 +1,90 @@
use std::sync::Arc;
use crate::{
ast::{Constant, Pattern},
gen_uplc::{builder::AssignmentProperties, tree::AirTree},
ast::{AssignmentKind, BinOp, Constant, Pattern},
builtins::int,
gen_uplc::{
air::{self, Air},
builder::AssignmentProperties,
tree::AirTree,
},
tipo::{PatternConstructor, Type},
};
pub fn assignment_air_tree(
pattern: &Pattern<PatternConstructor, Arc<Type>>,
value: AirTree,
mut value: AirTree,
tipo: &Arc<Type>,
props: AssignmentProperties,
) -> 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(
@ -31,5 +103,3 @@ pub fn constants_ir(literal: &Constant) -> AirTree {
Constant::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()),
}
}