diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index 283f6347..f830c848 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -501,6 +501,7 @@ impl<'a> CodeGenerator<'a> { AssignmentProperties { value_type: value.tipo(), kind: *kind, + remove_unused: true, }, ); @@ -531,6 +532,7 @@ impl<'a> CodeGenerator<'a> { AssignmentProperties { value_type: clauses[0].then.tipo(), kind: AssignmentKind::Let, + remove_unused: false, }, ); @@ -5182,6 +5184,7 @@ impl<'a> CodeGenerator<'a> { AssignmentProperties { value_type: data(), kind: AssignmentKind::Expect, + remove_unused: true, }, ); value_stack.local_var(actual_type, &arg_name); diff --git a/crates/aiken-lang/src/gen_uplc/builder.rs b/crates/aiken-lang/src/gen_uplc/builder.rs index 246a94b3..226deca8 100644 --- a/crates/aiken-lang/src/gen_uplc/builder.rs +++ b/crates/aiken-lang/src/gen_uplc/builder.rs @@ -60,6 +60,7 @@ pub struct FunctionAccessKey { pub struct AssignmentProperties { pub value_type: Arc, pub kind: AssignmentKind, + pub remove_unused: bool, } #[derive(Clone, Debug)] diff --git a/crates/aiken-lang/src/gen_uplc/tree.rs b/crates/aiken-lang/src/gen_uplc/tree.rs index f6cc5fc2..a360d758 100644 --- a/crates/aiken-lang/src/gen_uplc/tree.rs +++ b/crates/aiken-lang/src/gen_uplc/tree.rs @@ -11,6 +11,78 @@ use super::air::Air; #[derive(Debug, Clone, PartialEq)] pub enum AirTree { + Statement(AirStatement), + Expression(AirExpression), + IncompleteSequence(Vec), +} + +#[derive(Debug, Clone, PartialEq)] +pub enum AirStatement { + // Assignment + Let { + name: String, + value: Box, + hoisted_over: Box>, + }, + DefineFunc { + func_name: String, + module_name: String, + params: Vec, + recursive: bool, + variant_name: String, + func_body: Box, + hoisted_over: Box, + }, + // Assertions + AssertConstr { + constr_index: usize, + constr: Box, + hoisted_over: Box>, + }, + AssertBool { + is_true: bool, + value: Box, + hoisted_over: Box>, + }, + // Field Access + FieldsExpose { + indices: Vec<(usize, String, Arc)>, + check_last_item: bool, + record: Box, + hoisted_over: Box>, + }, + // List Access + ListAccessor { + tipo: Arc, + names: Vec, + tail: bool, + check_last_item: bool, + list: Box, + hoisted_over: Box>, + }, + ListExpose { + tipo: Arc, + tail_head_names: Vec<(String, String)>, + tail: Option<(String, String)>, + list: Box, + hoisted_over: Box>, + }, + // Tuple Access + TupleAccessor { + names: Vec, + tipo: Arc, + check_last_item: bool, + tuple: Box, + hoisted_over: Box>, + }, + // Misc. + NoOp { + hoisted_over: Box>, + }, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum AirExpression { // Primitives Int { value: String, @@ -45,15 +117,7 @@ pub enum AirTree { func: Box, args: Vec, }, - DefineFunc { - func_name: String, - module_name: String, - params: Vec, - recursive: bool, - variant_name: String, - func_body: Box, - hoisted_over: Box, - }, + Fn { params: Vec, func_body: Box, @@ -74,12 +138,7 @@ pub enum AirTree { op: UnOp, arg: Box, }, - // Assignment - Let { - name: String, - value: Box, - hoisted_over: Box>, - }, + UnWrapData { tipo: Arc, value: Box, @@ -88,16 +147,7 @@ pub enum AirTree { tipo: Arc, value: Box, }, - AssertConstr { - constr_index: usize, - constr: Box, - hoisted_over: Box>, - }, - AssertBool { - is_true: bool, - value: Box, - hoisted_over: Box>, - }, + // When When { tipo: Arc, @@ -178,32 +228,7 @@ pub enum AirTree { tipo: Arc, record: Box, }, - FieldsExpose { - indices: Vec<(usize, String, Arc)>, - check_last_item: bool, - record: Box, - }, - // ListAccess - ListAccessor { - tipo: Arc, - names: Vec, - tail: bool, - check_last_item: bool, - list: Box, - }, - ListExpose { - tipo: Arc, - tail_head_names: Vec<(String, String)>, - tail: Option<(String, String)>, - list: Box, - }, // Tuple Access - TupleAccessor { - names: Vec, - tipo: Arc, - check_last_item: bool, - tuple: Box, - }, TupleIndex { tipo: Arc, tuple_index: usize, @@ -218,9 +243,6 @@ pub enum AirTree { msg: Box, then: Box, }, - NoOp { - hoisted_over: Box>, - }, FieldsEmpty { constr: Box, }, @@ -231,57 +253,57 @@ pub enum AirTree { impl AirTree { pub fn int(value: impl ToString) -> AirTree { - AirTree::Int { + AirTree::Expression(AirExpression::Int { value: value.to_string(), - } + }) } pub fn string(value: impl ToString) -> AirTree { - AirTree::String { + AirTree::Expression(AirExpression::String { value: value.to_string(), - } + }) } pub fn byte_array(bytes: Vec) -> AirTree { - AirTree::ByteArray { bytes } + AirTree::Expression(AirExpression::ByteArray { bytes }) } pub fn bool(value: bool) -> AirTree { - AirTree::Bool { value } + AirTree::Expression(AirExpression::Bool { value }) } pub fn list(mut items: Vec, tipo: Arc, tail: Option) -> AirTree { if let Some(tail) = tail { items.push(tail); - AirTree::List { + AirTree::Expression(AirExpression::List { tipo, tail: true, items, - } + }) } else { - AirTree::List { + AirTree::Expression(AirExpression::List { tipo, tail: false, items, - } + }) } } pub fn tuple(items: Vec, tipo: Arc) -> AirTree { - AirTree::Tuple { tipo, items } + AirTree::Expression(AirExpression::Tuple { tipo, items }) } pub fn void() -> AirTree { - AirTree::Void + AirTree::Expression(AirExpression::Void) } pub fn var( constructor: ValueConstructor, name: impl ToString, variant_name: impl ToString, ) -> AirTree { - AirTree::Var { + AirTree::Expression(AirExpression::Var { constructor, name: name.to_string(), variant_name: variant_name.to_string(), - } + }) } pub fn local_var(name: impl ToString, tipo: Arc) -> AirTree { - AirTree::Var { + AirTree::Expression(AirExpression::Var { constructor: ValueConstructor::public( tipo, ValueConstructorVariant::LocalVariable { @@ -290,14 +312,14 @@ impl AirTree { ), name: name.to_string(), variant_name: "".to_string(), - } + }) } pub fn call(func: AirTree, tipo: Arc, args: Vec) -> AirTree { - AirTree::Call { + AirTree::Expression(AirExpression::Call { tipo, func: func.into(), args, - } + }) } pub fn define_func( func_name: impl ToString, @@ -308,7 +330,7 @@ impl AirTree { func_body: AirTree, hoisting_over: AirTree, ) -> AirTree { - AirTree::DefineFunc { + AirTree::Statement(AirStatement::DefineFunc { func_name: func_name.to_string(), module_name: module_name.to_string(), params, @@ -316,63 +338,63 @@ impl AirTree { variant_name: variant_name.to_string(), func_body: func_body.into(), hoisted_over: hoisting_over.into(), - } + }) } pub fn anon_func(params: Vec, func_body: AirTree) -> AirTree { - AirTree::Fn { + AirTree::Expression(AirExpression::Fn { params, func_body: func_body.into(), - } + }) } pub fn builtin(func: DefaultFunction, tipo: Arc, args: Vec) -> AirTree { - AirTree::Builtin { func, tipo, args } + AirTree::Expression(AirExpression::Builtin { func, tipo, args }) } pub fn binop(op: BinOp, tipo: Arc, left: AirTree, right: AirTree) -> AirTree { - AirTree::BinOp { + AirTree::Expression(AirExpression::BinOp { name: op, tipo, left: left.into(), right: right.into(), - } + }) } pub fn unop(op: UnOp, arg: AirTree) -> AirTree { - AirTree::UnOp { + AirTree::Expression(AirExpression::UnOp { op, arg: arg.into(), - } + }) } pub fn let_assignment(name: impl ToString, value: AirTree) -> AirTree { - AirTree::Let { + AirTree::Statement(AirStatement::Let { name: name.to_string(), value: value.into(), hoisted_over: None.into(), - } + }) } pub fn unwrap_data(value: AirTree, tipo: Arc) -> AirTree { - AirTree::UnWrapData { + AirTree::Expression(AirExpression::UnWrapData { tipo, value: value.into(), - } + }) } pub fn wrap_data(value: AirTree, tipo: Arc) -> AirTree { - AirTree::WrapData { + AirTree::Expression(AirExpression::WrapData { tipo, value: value.into(), - } + }) } pub fn assert_constr_index(constr_index: usize, constr: AirTree) -> AirTree { - AirTree::AssertConstr { + AirTree::Statement(AirStatement::AssertConstr { constr_index, constr: constr.into(), hoisted_over: None.into(), - } + }) } pub fn assert_bool(is_true: bool, value: AirTree) -> AirTree { - AirTree::AssertBool { + AirTree::Statement(AirStatement::AssertBool { is_true, value: value.into(), hoisted_over: None.into(), - } + }) } pub fn when( subject_name: impl ToString, @@ -380,12 +402,12 @@ impl AirTree { clauses: Vec, final_clause: AirTree, ) -> AirTree { - AirTree::When { + AirTree::Expression(AirExpression::When { tipo, subject_name: subject_name.to_string(), clauses, final_clause: final_clause.into(), - } + }) } pub fn clause( subject_name: impl ToString, @@ -395,14 +417,14 @@ impl AirTree { otherwise: AirTree, complex_clause: bool, ) -> AirTree { - AirTree::Clause { + AirTree::Expression(AirExpression::Clause { tipo, subject_name: subject_name.to_string(), complex_clause, pattern: pattern.into(), then: then.into(), otherwise: otherwise.into(), - } + }) } pub fn list_clause( tail_name: impl ToString, @@ -412,14 +434,14 @@ impl AirTree { next_tail_name: Option, complex_clause: bool, ) -> AirTree { - AirTree::ListClause { + AirTree::Expression(AirExpression::ListClause { tipo, tail_name: tail_name.to_string(), next_tail_name, complex_clause, then: then.into(), otherwise: otherwise.into(), - } + }) } pub fn tuple_clause( subject_name: impl ToString, @@ -432,7 +454,7 @@ impl AirTree { ) -> AirTree { let type_count = tipo.get_inner_types().len(); - AirTree::TupleClause { + AirTree::Expression(AirExpression::TupleClause { tipo, indices, predefined_indices, @@ -441,13 +463,13 @@ impl AirTree { complex_clause, then: then.into(), otherwise: otherwise.into(), - } + }) } pub fn wrap_clause(then: AirTree, otherwise: AirTree) -> AirTree { - AirTree::WrapClause { + AirTree::Expression(AirExpression::WrapClause { then: then.into(), otherwise: otherwise.into(), - } + }) } pub fn clause_guard( subject_name: impl ToString, @@ -455,12 +477,12 @@ impl AirTree { tipo: Arc, then: AirTree, ) -> AirTree { - AirTree::ClauseGuard { + AirTree::Expression(AirExpression::ClauseGuard { subject_name: subject_name.to_string(), tipo, pattern: pattern.into(), then: then.into(), - } + }) } pub fn list_clause_guard( tail_name: impl ToString, @@ -469,19 +491,19 @@ impl AirTree { then: AirTree, next_tail_name: Option, ) -> AirTree { - AirTree::ListClauseGuard { + AirTree::Expression(AirExpression::ListClauseGuard { tipo, tail_name: tail_name.to_string(), next_tail_name, inverse, then: then.into(), - } + }) } pub fn finally(pattern: AirTree, then: AirTree) -> AirTree { - AirTree::Finally { + AirTree::Expression(AirExpression::Finally { pattern: pattern.into(), then: then.into(), - } + }) } pub fn if_branches( mut branches: Vec<(AirTree, AirTree)>, @@ -491,26 +513,26 @@ impl AirTree { assert!(!branches.is_empty()); let last_if = branches.pop().unwrap(); - let mut final_if = AirTree::If { + let mut final_if = AirTree::Expression(AirExpression::If { tipo: tipo.clone(), pattern: last_if.0.into(), then: last_if.1.into(), otherwise: otherwise.into(), - }; + }); while let Some(branch) = branches.pop() { - final_if = AirTree::If { + final_if = AirTree::Expression(AirExpression::If { tipo: tipo.clone(), pattern: branch.0.into(), then: branch.1.into(), otherwise: final_if.into(), - }; + }); } final_if } pub fn create_constr(tag: usize, tipo: Arc, args: Vec) -> AirTree { - AirTree::Constr { tag, tipo, args } + AirTree::Expression(AirExpression::Constr { tag, tipo, args }) } pub fn record_update( @@ -520,20 +542,20 @@ impl AirTree { record: AirTree, args: Vec, ) -> AirTree { - AirTree::RecordUpdate { + AirTree::Expression(AirExpression::RecordUpdate { highest_index, indices, tipo, record: record.into(), args, - } + }) } pub fn record_access(field_index: u64, tipo: Arc, record: AirTree) -> AirTree { - AirTree::RecordAccess { + AirTree::Expression(AirExpression::RecordAccess { field_index, tipo, record: record.into(), - } + }) } pub fn fields_expose( @@ -541,11 +563,12 @@ impl AirTree { check_last_item: bool, record: AirTree, ) -> AirTree { - AirTree::FieldsExpose { + AirTree::Statement(AirStatement::FieldsExpose { indices, check_last_item, record: record.into(), - } + hoisted_over: None.into(), + }) } pub fn list_access( names: Vec, @@ -554,13 +577,14 @@ impl AirTree { check_last_item: bool, list: AirTree, ) -> AirTree { - AirTree::ListAccessor { + AirTree::Statement(AirStatement::ListAccessor { tipo, names, tail, check_last_item, list: list.into(), - } + hoisted_over: None.into(), + }) } pub fn list_expose( tail_head_names: Vec<(String, String)>, @@ -568,12 +592,13 @@ impl AirTree { tipo: Arc, list: AirTree, ) -> AirTree { - AirTree::ListExpose { + AirTree::Statement(AirStatement::ListExpose { tipo, tail_head_names, tail, list: list.into(), - } + hoisted_over: None.into(), + }) } pub fn tuple_access( names: Vec, @@ -581,213 +606,80 @@ impl AirTree { check_last_item: bool, tuple: AirTree, ) -> AirTree { - AirTree::TupleAccessor { + AirTree::Statement(AirStatement::TupleAccessor { names, tipo, check_last_item, tuple: tuple.into(), - } + hoisted_over: None.into(), + }) } pub fn tuple_index(tuple_index: usize, tipo: Arc, tuple: AirTree) -> AirTree { - AirTree::TupleIndex { + AirTree::Expression(AirExpression::TupleIndex { tipo, tuple_index, tuple: tuple.into(), - } + }) } pub fn error(tipo: Arc) -> AirTree { - AirTree::ErrorTerm { tipo } + AirTree::Expression(AirExpression::ErrorTerm { tipo }) } pub fn trace(msg: AirTree, tipo: Arc, then: AirTree) -> AirTree { - AirTree::Trace { + AirTree::Expression(AirExpression::Trace { tipo, msg: msg.into(), then: then.into(), - } + }) } pub fn no_op() -> AirTree { - AirTree::NoOp { + AirTree::Statement(AirStatement::NoOp { hoisted_over: None.into(), - } + }) } pub fn fields_empty(constr: AirTree) -> AirTree { - AirTree::FieldsEmpty { + AirTree::Expression(AirExpression::FieldsEmpty { constr: constr.into(), - } + }) } pub fn list_empty(list: AirTree) -> AirTree { - AirTree::ListEmpty { list: list.into() } + AirTree::Expression(AirExpression::ListEmpty { list: list.into() }) } - 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(), + 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.") + } }, - 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?"), + AirTree::Expression(_) => { + unreachable!("Trying to hoist an expression onto an expression.") + } + AirTree::IncompleteSequence(seq) => { + let mut final_exp = next_exp; + while let Some(assign) = seq.pop() { + final_exp = Self::hoist_over(assign, final_exp); + } + final_exp + } } } - pub fn to_air_vec(air_vec: &mut Vec, tree: AirTree) { + pub fn to_air_vec(_air_vec: &mut Vec, tree: AirTree) { match tree { - AirTree::Int { value } => air_vec.push(todo!()), - AirTree::String { value } => todo!(), - AirTree::ByteArray { bytes } => 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!(), + AirTree::Statement(_) => todo!(), + AirTree::Expression(_) => todo!(), + AirTree::IncompleteSequence(_) => todo!(), } } } diff --git a/crates/aiken-lang/src/gen_uplc2.rs b/crates/aiken-lang/src/gen_uplc2.rs index 8c099e91..abdddadf 100644 --- a/crates/aiken-lang/src/gen_uplc2.rs +++ b/crates/aiken-lang/src/gen_uplc2.rs @@ -1,8 +1,6 @@ mod builder; -use std::{rc::Rc, sync::Arc}; - -use indexmap::{IndexMap, IndexSet}; +use indexmap::IndexMap; use itertools::Itertools; use uplc::ast::{Name, Program, Term}; @@ -84,12 +82,16 @@ impl<'a> CodeGenerator<'a> { TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => { 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() { 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 } @@ -243,6 +245,7 @@ impl<'a> CodeGenerator<'a> { AssignmentProperties { value_type: value.tipo(), kind: *kind, + remove_unused: true, }, ) } @@ -260,7 +263,7 @@ impl<'a> CodeGenerator<'a> { let mut clauses = clauses.clone(); 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 { let last_clause = clauses.pop().unwrap(); @@ -275,10 +278,11 @@ impl<'a> CodeGenerator<'a> { AssignmentProperties { value_type: subject.tipo(), kind: AssignmentKind::Let, + remove_unused: false, }, ); - AirTree::hoist_let(assignment, clause_then) + AirTree::hoist_over(assignment, clause_then) } else { clauses = if subject.tipo().is_list() { build::rearrange_clauses(clauses.clone()) @@ -336,7 +340,12 @@ impl<'a> CodeGenerator<'a> { field_map: field_map.clone(), location: Span::empty(), 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, }, ); diff --git a/crates/aiken-lang/src/gen_uplc2/builder.rs b/crates/aiken-lang/src/gen_uplc2/builder.rs index 2b652bb3..16ab1c25 100644 --- a/crates/aiken-lang/src/gen_uplc2/builder.rs +++ b/crates/aiken-lang/src/gen_uplc2/builder.rs @@ -1,12 +1,14 @@ use std::sync::Arc; +use indexmap::IndexMap; +use itertools::Itertools; + use crate::{ - ast::{AssignmentKind, BinOp, Constant, Pattern}, + ast::{BinOp, Constant, Pattern}, builtins::int, gen_uplc::{ - air::{self, Air}, builder::AssignmentProperties, - tree::AirTree, + tree::{AirStatement, AirTree}, }, tipo::{PatternConstructor, Type}, }; @@ -26,10 +28,14 @@ pub fn assignment_air_tree( match pattern { Pattern::Int { value: expected_int, + location, .. } => { 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 expect = AirTree::binop( @@ -38,19 +44,20 @@ pub fn assignment_air_tree( AirTree::int(expected_int), AirTree::local_var(name, int()), ); - - AirTree::assert_bool(true, AirTree::hoist_let(assignment, expect)) + AirTree::assert_bool(true, AirTree::hoist_over(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 mut index_map = IndexMap::new(); + let tipo = convert_opaque_type(); 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)) + 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 { AirTree::let_assignment(name, value) } @@ -58,35 +65,190 @@ pub fn assignment_air_tree( 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() { + if props.kind.is_expect() || !props.remove_unused { AirTree::let_assignment(name, value) } else { AirTree::no_op() } } Pattern::List { - location, elements, tail, - } => todo!(), - Pattern::Constructor { - is_record, location, - name, + .. + } => { + let list_name = format!("__expect_list_span_{}_{}", location.start, location.end); + assert!(tipo.is_list()); + assert!(props.kind.is_expect()); + let list_elem_types = tipo.get_inner_types(); + + 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, - module, constructor, - with_spread, - tipo, - } => todo!(), - Pattern::Tuple { location, elems } => todo!(), + 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> = 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, + value: AirTree, + defined_data_types: &mut IndexMap, +) -> AirTree { + todo!() +} + +pub fn convert_opaque_type() -> Arc { + todo!() +} + pub fn handle_each_clause( pattern: &Pattern>, value: AirTree,