feat: start on build assignment
feat: implement assignment hoisting
This commit is contained in:
parent
c359bd35d7
commit
65bb7e48e2
|
@ -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!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue