From 65bb7e48e2a2c99f7d790a4f5d8aac407b088dcf Mon Sep 17 00:00:00 2001 From: microproofs Date: Wed, 28 Jun 2023 01:55:16 -0400 Subject: [PATCH] feat: start on build assignment feat: implement assignment hoisting --- crates/aiken-lang/src/gen_uplc/tree.rs | 58 +++++++++++---- crates/aiken-lang/src/gen_uplc2.rs | 3 +- crates/aiken-lang/src/gen_uplc2/builder.rs | 82 ++++++++++++++++++++-- 3 files changed, 123 insertions(+), 20 deletions(-) diff --git a/crates/aiken-lang/src/gen_uplc/tree.rs b/crates/aiken-lang/src/gen_uplc/tree.rs index bfcb6e41..f6cc5fc2 100644 --- a/crates/aiken-lang/src/gen_uplc/tree.rs +++ b/crates/aiken-lang/src/gen_uplc/tree.rs @@ -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, + hoisted_over: Box>, }, AssertBool { is_true: bool, value: Box, + hoisted_over: Box>, }, // When When { @@ -216,7 +218,9 @@ pub enum AirTree { msg: Box, then: Box, }, - NoOp, + NoOp { + hoisted_over: Box>, + }, FieldsEmpty { constr: Box, }, @@ -276,6 +280,18 @@ impl AirTree { variant_name: variant_name.to_string(), } } + pub fn local_var(name: impl ToString, tipo: Arc) -> 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, args: Vec) -> 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 { + pub fn to_air_vec(air_vec: &mut Vec, 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!(), } diff --git a/crates/aiken-lang/src/gen_uplc2.rs b/crates/aiken-lang/src/gen_uplc2.rs index 9a7e1f2f..8c099e91 100644 --- a/crates/aiken-lang/src/gen_uplc2.rs +++ b/crates/aiken-lang/src/gen_uplc2.rs @@ -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, ) } diff --git a/crates/aiken-lang/src/gen_uplc2/builder.rs b/crates/aiken-lang/src/gen_uplc2/builder.rs index cc86a886..2b652bb3 100644 --- a/crates/aiken-lang/src/gen_uplc2/builder.rs +++ b/crates/aiken-lang/src/gen_uplc2/builder.rs @@ -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>, - value: AirTree, + mut value: AirTree, tipo: &Arc, 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()), } } - -