From f94c8213b64b1add180157a324ae09a980a15f72 Mon Sep 17 00:00:00 2001 From: microproofs Date: Sat, 1 Jul 2023 01:09:26 -0400 Subject: [PATCH] checkpoint --- crates/aiken-lang/src/gen_uplc/builder.rs | 5 +- crates/aiken-lang/src/gen_uplc2.rs | 447 ++++++++++++++++++--- crates/aiken-lang/src/gen_uplc2/air.rs | 6 +- crates/aiken-lang/src/gen_uplc2/builder.rs | 66 ++- crates/aiken-lang/src/gen_uplc2/tree.rs | 379 ++++++++++++++++- crates/aiken-lang/src/tipo.rs | 15 + 6 files changed, 848 insertions(+), 70 deletions(-) diff --git a/crates/aiken-lang/src/gen_uplc/builder.rs b/crates/aiken-lang/src/gen_uplc/builder.rs index c9256fd9..4198b6d8 100644 --- a/crates/aiken-lang/src/gen_uplc/builder.rs +++ b/crates/aiken-lang/src/gen_uplc/builder.rs @@ -95,7 +95,10 @@ impl ClauseProperties { original_subject_name: subject_name, final_clause: false, needs_constr_var: false, - specific_clause: SpecificClause::ConstrClause, + specific_clause: SpecificClause::ListClause { + current_index: 0, + defined_tails: vec![], + }, } } else if t.is_tuple() { ClauseProperties { diff --git a/crates/aiken-lang/src/gen_uplc2.rs b/crates/aiken-lang/src/gen_uplc2.rs index 185ccea1..0778ab8e 100644 --- a/crates/aiken-lang/src/gen_uplc2.rs +++ b/crates/aiken-lang/src/gen_uplc2.rs @@ -21,8 +21,8 @@ use crate::{ gen_uplc::{ air::Air, builder::{ - self as build, AssignmentProperties, ClauseProperties, DataTypeKey, FunctionAccessKey, - SpecificClause, + self as build, lookup_data_type_by_tipo, AssignmentProperties, ClauseProperties, + DataTypeKey, FunctionAccessKey, SpecificClause, }, }, tipo::{ @@ -91,8 +91,10 @@ impl<'a> CodeGenerator<'a> { pub fn generate_test(&mut self, test_body: &TypedExpr) -> Program { let mut air_tree = self.build(test_body); - air_tree = AirTree::hoist_over(AirTree::no_op(), air_tree); + + air_tree = AirTree::no_op().hoist_over(air_tree); println!("{:#?}", air_tree); + println!("{:#?}", air_tree.to_vec()); todo!() } @@ -116,7 +118,7 @@ impl<'a> CodeGenerator<'a> { while let Some(expression) = expressions.pop() { let exp_tree = self.build(&expression); - last_exp = AirTree::hoist_over(exp_tree, last_exp); + last_exp = exp_tree.hoist_over(last_exp); } last_exp } @@ -309,7 +311,7 @@ impl<'a> CodeGenerator<'a> { }, ); - AirTree::hoist_over(assignment, clause_then) + assignment.hoist_over(clause_then) } else { clauses = if subject.tipo().is_list() { build::rearrange_clauses(clauses) @@ -343,9 +345,14 @@ impl<'a> CodeGenerator<'a> { ); let constr_assign = AirTree::let_assignment(&constr_var, self.build(subject)); - let when_assign = AirTree::when(subject_name, subject.tipo(), clauses); + let when_assign = AirTree::when( + subject_name, + subject.tipo(), + AirTree::local_var(constr_var, tipo.clone()), + clauses, + ); - AirTree::hoist_over(constr_assign, when_assign) + constr_assign.hoist_over(when_assign) } } @@ -511,7 +518,7 @@ impl<'a> CodeGenerator<'a> { AirTree::int(expected_int), AirTree::local_var(name, int()), ); - AirTree::assert_bool(true, AirTree::hoist_over(assignment, expect)) + AirTree::assert_bool(true, assignment.hoist_over(expect)) } else { unreachable!("Code Gen should never reach here") } @@ -524,13 +531,12 @@ impl<'a> CodeGenerator<'a> { let val = AirTree::local_var(name, tipo.clone()); if tipo.is_primitive() { - AirTree::let_assignment(name, AirTree::hoist_over(assignment, val)) + AirTree::let_assignment(name, assignment.hoist_over(val)) } else { let expect = self.expect_type(tipo, val.clone(), &mut index_map, pattern.location()); - let assign = - AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect)); - AirTree::let_assignment(name, AirTree::hoist_over(assign, val)) + let assign = AirTree::let_assignment("_", assignment.hoist_over(expect)); + AirTree::let_assignment(name, assign.hoist_over(val)) } } else { AirTree::let_assignment(name, value) @@ -551,13 +557,12 @@ impl<'a> CodeGenerator<'a> { let assignment = AirTree::let_assignment(name, value); let val = AirTree::local_var(name, tipo.clone()); if tipo.is_primitive() { - AirTree::let_assignment(name, AirTree::hoist_over(assignment, val)) + AirTree::let_assignment(name, assignment.hoist_over(val)) } else { let expect = self.expect_type(tipo, val.clone(), &mut index_map, pattern.location()); - let assign = - AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect)); - AirTree::let_assignment(name, AirTree::hoist_over(assign, val)) + let assign = AirTree::let_assignment("_", assignment.hoist_over(expect)); + AirTree::let_assignment(name, assign.hoist_over(val)) } } else if !props.remove_unused { AirTree::let_assignment(name, value) @@ -653,7 +658,6 @@ impl<'a> CodeGenerator<'a> { }, ), )); - println!("ELEMS IS {:#?}", elems); }); let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec(); @@ -801,7 +805,7 @@ impl<'a> CodeGenerator<'a> { // This `value` is either value param that was passed in or // local var - sequence.push(AirTree::fields_expose(indices, false, value)); + sequence.push(AirTree::fields_expose(indices, props.full_check, value)); sequence.append( &mut fields @@ -877,7 +881,12 @@ impl<'a> CodeGenerator<'a> { // This `value` is either value param that was passed in or // local var - sequence.push(AirTree::tuple_access(indices, tipo.clone(), false, value)); + sequence.push(AirTree::tuple_access( + indices, + tipo.clone(), + props.full_check, + value, + )); sequence.append(&mut elems.into_iter().map(|(_, field)| field).collect_vec()); @@ -930,14 +939,12 @@ impl<'a> CodeGenerator<'a> { location, ); - let anon_func_body = AirTree::hoist_over( - AirTree::UnhoistedSequence(vec![ - tuple_access, - AirTree::let_assignment("_", expect_fst), - AirTree::let_assignment("_", expect_snd), - ]), - AirTree::void(), - ); + let anon_func_body = AirTree::UnhoistedSequence(vec![ + tuple_access, + AirTree::let_assignment("_", expect_fst), + AirTree::let_assignment("_", expect_snd), + ]) + .hoist_over(AirTree::void()); let unwrap_function = AirTree::anon_func(vec![pair_name], anon_func_body); @@ -963,7 +970,7 @@ impl<'a> CodeGenerator<'a> { vec![AirTree::local_var(map_name, tipo.clone()), unwrap_function], ); - AirTree::hoist_over(assign, func_call) + assign.hoist_over(func_call) } else if tipo.is_list() { assert!(!tipo.get_inner_types().is_empty()); let inner_list_type = &tipo.get_inner_types()[0]; @@ -981,7 +988,7 @@ impl<'a> CodeGenerator<'a> { ); let anon_func_body = - AirTree::hoist_over(AirTree::let_assignment("_", expect_item), AirTree::void()); + AirTree::let_assignment("_", expect_item).hoist_over(AirTree::void()); let unwrap_function = AirTree::anon_func(vec![item_name], anon_func_body); @@ -1007,9 +1014,86 @@ impl<'a> CodeGenerator<'a> { vec![AirTree::local_var(list_name, tipo.clone()), unwrap_function], ); - AirTree::hoist_over(assign, func_call) - } else { + assign.hoist_over(func_call) + } else if tipo.is_2_tuple() { + let tuple_inner_types = tipo.get_inner_types(); + + let pair_name = format!("__pair_span_{}_{}", location.start, location.end); + let fst_name = format!("__pair_fst_span_{}_{}", location.start, location.end); + let snd_name = format!("__pair_snd_span_{}_{}", location.start, location.end); + + let tuple_assign = AirTree::let_assignment(&pair_name, value); + + let tuple_access = AirTree::tuple_access( + vec![fst_name.clone(), snd_name.clone()], + tipo.clone(), + false, + AirTree::local_var(pair_name, tipo.clone()), + ); + + let expect_fst = self.expect_type( + &tuple_inner_types[0], + AirTree::local_var(fst_name, tuple_inner_types[0].clone()), + defined_data_types, + location, + ); + + let expect_snd = self.expect_type( + &tuple_inner_types[1], + AirTree::local_var(snd_name, tuple_inner_types[1].clone()), + defined_data_types, + location, + ); + + AirTree::UnhoistedSequence(vec![ + tuple_assign, + tuple_access, + AirTree::let_assignment("_", expect_fst), + AirTree::let_assignment("_", expect_snd), + ]) + .hoist_over(AirTree::void()) + } else if tipo.is_tuple() { todo!() + } else { + let data_type = + build::lookup_data_type_by_tipo(&self.data_types, tipo).unwrap_or_else(|| { + unreachable!("We need a data type definition fot type {:#?}", tipo) + }); + + // for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { + // let field_type = arg.clone(); + // type_map.insert(index, field_type); + // } + + // TODO calculate the variant name. + let data_type_name = format!("__expect_{}{}", data_type.name, ""); + let function = self.code_gen_functions.get(&data_type_name); + + if function.is_none() && defined_data_types.get(&data_type_name).is_none() { + todo!() + } else if let Some(counter) = defined_data_types.get_mut(&data_type_name) { + *counter += 1; + } else { + defined_data_types.insert(data_type_name.to_string(), 0); + } + + let func_var = AirTree::var( + ValueConstructor::public( + tipo.clone(), + ValueConstructorVariant::ModuleFn { + name: data_type_name.to_string(), + field_map: None, + module: "".to_string(), + arity: 1, + location: Span::empty(), + builtin: None, + }, + ), + data_type_name, + "", + ); + + AirTree::call(func_var, void(), vec![value]) } } @@ -1020,19 +1104,177 @@ impl<'a> CodeGenerator<'a> { subject_tipo: &Arc, props: &mut ClauseProperties, ) -> AirTree { - assert!(!clauses.is_empty()); + assert!( + !subject_tipo.is_void(), + "WHY ARE YOU PATTERN MATCHING VOID???" + ); props.complex_clause = false; if let Some((clause, rest_clauses)) = clauses.split_first() { - todo!() + let mut clause_then = self.build(&clause.then); + + if let Some(guard) = &clause.guard { + props.complex_clause = true; + let clause_guard_name = format!( + "__clause_guard_span_{}_{}", + clause.location.start, clause.location.end + ); + + let clause_guard_assign = + AirTree::let_assignment(clause_guard_name, builder::handle_clause_guard(guard)); + + clause_then = clause_guard_assign.hoist_over(clause_then); + } + + match &mut props.specific_clause { + SpecificClause::ConstrClause => { + let data_type = build::lookup_data_type_by_tipo(&self.data_types, subject_tipo); + + let (clause_cond, clause_assign) = + self.clause_pattern(&clause.pattern, subject_tipo, props); + + let clause_assign_hoisted = clause_assign.hoist_over(clause_then); + + let complex_clause = props.complex_clause; + + let mut next_clause_props = ClauseProperties { + clause_var_name: props.clause_var_name.clone(), + complex_clause: false, + needs_constr_var: false, + original_subject_name: props.original_subject_name.clone(), + final_clause: false, + specific_clause: props.specific_clause.clone(), + }; + + if let Some(data_type) = data_type { + if data_type.constructors.len() > 1 { + AirTree::clause( + &props.original_subject_name, + clause_cond, + subject_tipo.clone(), + clause_assign_hoisted, + self.handle_each_clause( + rest_clauses, + final_clause, + subject_tipo, + &mut next_clause_props, + ), + complex_clause, + ) + } else { + AirTree::wrap_clause( + clause_assign_hoisted, + self.handle_each_clause( + rest_clauses, + final_clause, + subject_tipo, + &mut next_clause_props, + ), + ) + } + } else { + AirTree::clause( + &props.original_subject_name, + clause_cond, + subject_tipo.clone(), + clause_assign_hoisted, + self.handle_each_clause( + rest_clauses, + final_clause, + subject_tipo, + &mut next_clause_props, + ), + complex_clause, + ) + } + } + SpecificClause::ListClause { + current_index, + defined_tails, + } => { + let Pattern::List { elements, .. } = &clause.pattern + else { unreachable!() }; + + let tail_name = if *current_index == 0 { + props.original_subject_name.clone() + } else { + format!( + "tail_index_{}_span_{}_{}", + *current_index, + clause.pattern.location().start, + clause.pattern.location().end + ) + }; + + let next_tail_name = { + let next_elements_len = match &rest_clauses[0].pattern { + Pattern::List { elements, .. } => elements.len(), + _ => 0, + }; + + if (*current_index as usize) < next_elements_len { + Some(format!( + "tail_index_{}_span_{}_{}", + *current_index, + rest_clauses[0].pattern.location().start, + rest_clauses[0].pattern.location().end + )) + } else { + None + } + }; + + if elements.len() > *current_index as usize { + *current_index += 1; + defined_tails.push(tail_name.clone()); + } + + let mut next_clause_props = ClauseProperties { + clause_var_name: props.clause_var_name.clone(), + complex_clause: false, + needs_constr_var: false, + original_subject_name: props.original_subject_name.clone(), + final_clause: false, + specific_clause: SpecificClause::ListClause { + current_index: *current_index, + defined_tails: defined_tails.clone(), + }, + }; + + let (_, clause_assign) = + self.clause_pattern(&clause.pattern, subject_tipo, props); + + let clause_assign_hoisted = clause_assign.hoist_over(clause_then); + + let complex_clause = props.complex_clause; + + AirTree::list_clause( + tail_name, + subject_tipo.clone(), + clause_assign_hoisted, + self.handle_each_clause( + clauses, + final_clause, + subject_tipo, + &mut next_clause_props, + ), + next_tail_name, + complex_clause, + ); + + todo!(); + } + SpecificClause::TupleClause { .. } => todo!(), + } } else { // handle final_clause props.final_clause = true; assert!(final_clause.guard.is_none()); let clause_then = self.build(&final_clause.then); - let (_, assignments) = self.clause_pattern(&final_clause.pattern, subject_tipo, props); + let (condition, assignments) = + self.clause_pattern(&final_clause.pattern, subject_tipo, props); - AirTree::hoist_over(assignments, clause_then) + AirTree::finally(condition, assignments.hoist_over(clause_then)) } } @@ -1072,18 +1314,13 @@ impl<'a> CodeGenerator<'a> { Pattern::Discard { .. } => (AirTree::void(), AirTree::no_op()), Pattern::List { elements, tail, .. } => { let ClauseProperties { - specific_clause: - SpecificClause::ListClause { - current_index: _, - defined_tails, - }, - clause_var_name: _, - complex_clause: _, - needs_constr_var: _, + specific_clause: SpecificClause::ListClause { defined_tails, .. }, + complex_clause, original_subject_name: _, final_clause: _, + .. } = props - else { unreachable!()}; + else { unreachable!() }; let list_elem_types = subject_tipo.get_inner_types(); @@ -1116,7 +1353,7 @@ impl<'a> CodeGenerator<'a> { let statement = self.nested_clause_condition(elem, list_elem_type, &mut elem_props); - props.complex_clause = props.complex_clause || elem_props.complex_clause; + *complex_clause = *complex_clause || elem_props.complex_clause; (tail, elem_name, statement) }) @@ -1164,7 +1401,7 @@ impl<'a> CodeGenerator<'a> { let statement = self.nested_clause_condition(elem, subject_tipo, &mut elem_props); - props.complex_clause = props.complex_clause || elem_props.complex_clause; + *complex_clause = *complex_clause || elem_props.complex_clause; air_elems.push(statement); list_tail = Some((tail.to_string(), elem_name)); @@ -1183,7 +1420,123 @@ impl<'a> CodeGenerator<'a> { (AirTree::void(), AirTree::UnhoistedSequence(sequence)) } - Pattern::Constructor { .. } => todo!(), + Pattern::Constructor { + name, + arguments, + constructor, + .. + } => { + if subject_tipo.is_bool() { + (AirTree::bool(name == "True"), AirTree::no_op()) + } else { + let data_type = build::lookup_data_type_by_tipo(&self.data_types, subject_tipo) + .unwrap_or_else(|| { + unreachable!( + "Code Gen should have the definition for this constructor {}", + name + ) + }); + + assert!(!data_type.constructors.is_empty()); + + let (constr_index, _) = data_type + .constructors + .iter() + .enumerate() + .find(|(_, dt)| &dt.name == name) + .unwrap(); + + let field_map = match constructor { + PatternConstructor::Record { field_map, .. } => field_map.clone(), + }; + + let mut type_map: IndexMap> = IndexMap::new(); + + println!("tipo is {subject_tipo:#?}"); + + for (index, arg) in subject_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 mut field_props = ClauseProperties { + clause_var_name: field_name.clone(), + complex_clause: false, + needs_constr_var: false, + original_subject_name: field_name.clone(), + final_clause: props.final_clause, + specific_clause: props.specific_clause.clone(), + }; + + let statement = self.nested_clause_condition( + &arg.value, + arg_type, + &mut field_props, + ); + + props.complex_clause = + props.complex_clause || field_props.complex_clause; + + (field_index, field_name, arg_type, statement) + }) + .collect_vec(); + + let indices = fields + .iter() + .map(|(constr_index, name, tipo, _)| { + (*constr_index, name.to_string(), (*tipo).clone()) + }) + .collect_vec(); + + let mut air_fields = fields.into_iter().map(|(_, _, _, val)| val).collect_vec(); + + let field_assign = AirTree::fields_expose( + indices, + false, + AirTree::local_var(props.clause_var_name.clone(), subject_tipo.clone()), + ); + + let mut sequence = vec![field_assign]; + + sequence.append(&mut air_fields); + + ( + AirTree::int(constr_index), + AirTree::UnhoistedSequence(sequence), + ) + } + } Pattern::Tuple { .. } => todo!(), } } diff --git a/crates/aiken-lang/src/gen_uplc2/air.rs b/crates/aiken-lang/src/gen_uplc2/air.rs index e278791e..55de83ea 100644 --- a/crates/aiken-lang/src/gen_uplc2/air.rs +++ b/crates/aiken-lang/src/gen_uplc2/air.rs @@ -97,7 +97,7 @@ pub enum Air { next_tail_name: Option, complex_clause: bool, }, - WrapClause {}, + WrapClause, TupleClause { tipo: Arc, indices: IndexSet<(usize, String)>, @@ -122,7 +122,7 @@ pub enum Air { tipo: Arc, }, // Record Creation - Record { + Constr { tag: usize, tipo: Arc, count: usize, @@ -246,7 +246,7 @@ impl Air { | Air::ClauseGuard { tipo, .. } | Air::If { tipo, .. } | Air::ListClauseGuard { tipo, .. } - | Air::Record { tipo, .. } + | Air::Constr { tipo, .. } | Air::RecordUpdate { tipo, .. } | Air::RecordAccess { tipo, .. } | Air::ListAccessor { tipo, .. } diff --git a/crates/aiken-lang/src/gen_uplc2/builder.rs b/crates/aiken-lang/src/gen_uplc2/builder.rs index 22d3e832..d33166bc 100644 --- a/crates/aiken-lang/src/gen_uplc2/builder.rs +++ b/crates/aiken-lang/src/gen_uplc2/builder.rs @@ -1,6 +1,10 @@ +use crate::builtins::bool; use std::sync::Arc; -use crate::{ast::Constant, tipo::Type}; +use crate::{ + ast::{BinOp, ClauseGuard, Constant, UnOp}, + tipo::Type, +}; use super::tree::AirTree; @@ -15,3 +19,63 @@ pub fn constants_ir(literal: &Constant) -> AirTree { Constant::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()), } } + +pub fn handle_clause_guard(clause_guard: &ClauseGuard>) -> AirTree { + match clause_guard { + ClauseGuard::Not { value, .. } => { + let val = handle_clause_guard(value); + + AirTree::unop(UnOp::Not, val) + } + ClauseGuard::Equals { left, right, .. } => { + let left = handle_clause_guard(left); + let right = handle_clause_guard(right); + + AirTree::binop(BinOp::Eq, bool(), left, right) + } + ClauseGuard::NotEquals { left, right, .. } => { + let left = handle_clause_guard(left); + let right = handle_clause_guard(right); + + AirTree::binop(BinOp::NotEq, bool(), left, right) + } + ClauseGuard::GtInt { left, right, .. } => { + let left = handle_clause_guard(left); + let right = handle_clause_guard(right); + + AirTree::binop(BinOp::GtInt, bool(), left, right) + } + ClauseGuard::GtEqInt { left, right, .. } => { + let left = handle_clause_guard(left); + let right = handle_clause_guard(right); + + AirTree::binop(BinOp::GtEqInt, bool(), left, right) + } + ClauseGuard::LtInt { left, right, .. } => { + let left = handle_clause_guard(left); + let right = handle_clause_guard(right); + + AirTree::binop(BinOp::LtInt, bool(), left, right) + } + ClauseGuard::LtEqInt { left, right, .. } => { + let left = handle_clause_guard(left); + let right = handle_clause_guard(right); + + AirTree::binop(BinOp::LtEqInt, bool(), left, right) + } + ClauseGuard::Or { left, right, .. } => { + let left = handle_clause_guard(left); + let right = handle_clause_guard(right); + + AirTree::binop(BinOp::Or, bool(), left, right) + } + ClauseGuard::And { left, right, .. } => { + let left = handle_clause_guard(left); + let right = handle_clause_guard(right); + + AirTree::binop(BinOp::And, bool(), left, right) + } + ClauseGuard::Var { tipo, name, .. } => AirTree::local_var(name, tipo.clone()), + ClauseGuard::Constant(constant) => constants_ir(constant), + } +} diff --git a/crates/aiken-lang/src/gen_uplc2/tree.rs b/crates/aiken-lang/src/gen_uplc2/tree.rs index 2689540b..2c28bb06 100644 --- a/crates/aiken-lang/src/gen_uplc2/tree.rs +++ b/crates/aiken-lang/src/gen_uplc2/tree.rs @@ -5,6 +5,7 @@ use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction}; use crate::{ ast::{BinOp, Span, UnOp}, builtins::{data, list, void}, + gen_uplc::air, tipo::{Type, ValueConstructor, ValueConstructorVariant}, }; @@ -146,6 +147,7 @@ pub enum AirExpression { When { tipo: Arc, subject_name: String, + subject: Box, clauses: Box, }, Clause { @@ -396,10 +398,16 @@ impl AirTree { hoisted_over: None, } } - pub fn when(subject_name: impl ToString, tipo: Arc, clauses: AirTree) -> AirTree { + pub fn when( + subject_name: impl ToString, + tipo: Arc, + subject: AirTree, + clauses: AirTree, + ) -> AirTree { AirTree::Expression(AirExpression::When { tipo, subject_name: subject_name.to_string(), + subject: subject.into(), clauses: clauses.into(), }) } @@ -647,12 +655,12 @@ impl AirTree { pub fn list_empty(list: AirTree) -> AirTree { AirTree::Expression(AirExpression::ListEmpty { list: list.into() }) } - pub fn hoist_over(mut assignment: AirTree, next_exp: AirTree) -> AirTree { - match &mut assignment { + pub fn hoist_over(mut self, next_exp: AirTree) -> AirTree { + match &mut self { AirTree::Statement { hoisted_over, .. } => { assert!(hoisted_over.is_none()); *hoisted_over = Some(next_exp.into()); - assignment + self } AirTree::Expression(_) => { @@ -661,7 +669,7 @@ impl AirTree { AirTree::UnhoistedSequence(seq) => { let mut final_exp = next_exp; while let Some(assign) = seq.pop() { - final_exp = Self::hoist_over(assign, final_exp); + final_exp = assign.hoist_over(final_exp); } final_exp } @@ -698,7 +706,7 @@ impl AirTree { "__list_to_check", void(), AirTree::void(), - AirTree::hoist_over(assign, next_call), + assign.hoist_over(next_call), None, false, ); @@ -713,7 +721,13 @@ impl AirTree { ) } - fn to_vec(&self, air_vec: &mut Vec) { + pub fn to_vec(&self) -> Vec { + let mut air_vec = vec![]; + self.create_air_vec(&mut air_vec); + air_vec + } + + fn create_air_vec(&self, air_vec: &mut Vec) { match self { AirTree::Statement { statement, @@ -722,7 +736,7 @@ impl AirTree { match statement { AirStatement::Let { value, name } => { air_vec.push(Air::Let { name: name.clone() }); - value.to_vec(air_vec); + value.create_air_vec(air_vec); } AirStatement::DefineFunc { func_name, @@ -739,7 +753,7 @@ impl AirTree { recursive: *recursive, variant_name: variant_name.clone(), }); - func_body.to_vec(air_vec); + func_body.create_air_vec(air_vec); } AirStatement::AssertConstr { constr, @@ -748,18 +762,347 @@ impl AirTree { air_vec.push(Air::AssertConstr { constr_index: *constr_index, }); - constr.to_vec(air_vec); + constr.create_air_vec(air_vec); + } + AirStatement::AssertBool { is_true, value } => { + air_vec.push(Air::AssertBool { is_true: *is_true }); + value.create_air_vec(air_vec); + } + AirStatement::FieldsExpose { + indices, + check_last_item, + record, + } => { + air_vec.push(Air::FieldsExpose { + indices: indices.clone(), + check_last_item: *check_last_item, + }); + record.create_air_vec(air_vec); + } + AirStatement::ListAccessor { + tipo, + names, + tail, + check_last_item, + list, + } => { + air_vec.push(Air::ListAccessor { + tipo: tipo.clone(), + names: names.clone(), + tail: *tail, + check_last_item: *check_last_item, + }); + list.create_air_vec(air_vec); + } + AirStatement::ListExpose { + tipo, + tail_head_names, + tail, + list, + } => { + air_vec.push(Air::ListExpose { + tipo: tipo.clone(), + tail_head_names: tail_head_names.clone(), + tail: tail.clone(), + }); + list.create_air_vec(air_vec); + } + AirStatement::TupleAccessor { + names, + tipo, + check_last_item, + tuple, + } => { + air_vec.push(Air::TupleAccessor { + names: names.clone(), + tipo: tipo.clone(), + check_last_item: *check_last_item, + }); + tuple.create_air_vec(air_vec); + } + AirStatement::NoOp => { + air_vec.push(Air::NoOp); } - AirStatement::AssertBool { .. } => todo!(), - AirStatement::FieldsExpose { .. } => todo!(), - AirStatement::ListAccessor { .. } => todo!(), - AirStatement::ListExpose { .. } => todo!(), - AirStatement::TupleAccessor { .. } => todo!(), - AirStatement::NoOp { .. } => todo!(), }; - exp.to_vec(air_vec); + exp.create_air_vec(air_vec); } - AirTree::Expression(_) => todo!(), + AirTree::Expression(exp) => match exp { + AirExpression::Int { value } => air_vec.push(Air::Int { + value: value.clone(), + }), + AirExpression::String { value } => air_vec.push(Air::String { + value: value.clone(), + }), + AirExpression::ByteArray { bytes } => air_vec.push(Air::ByteArray { + bytes: bytes.clone(), + }), + AirExpression::Bool { value } => air_vec.push(Air::Bool { value: *value }), + AirExpression::List { tipo, tail, items } => { + air_vec.push(Air::List { + count: items.len(), + tipo: tipo.clone(), + tail: *tail, + }); + for item in items { + item.create_air_vec(air_vec); + } + } + AirExpression::Tuple { tipo, items } => { + air_vec.push(Air::Tuple { + tipo: tipo.clone(), + count: items.len(), + }); + for item in items { + item.create_air_vec(air_vec); + } + } + AirExpression::Void => air_vec.push(Air::Void), + AirExpression::Var { + constructor, + name, + variant_name, + } => air_vec.push(Air::Var { + constructor: constructor.clone(), + name: name.clone(), + variant_name: variant_name.clone(), + }), + AirExpression::Call { tipo, func, args } => { + air_vec.push(Air::Call { + count: args.len(), + tipo: tipo.clone(), + }); + func.create_air_vec(air_vec); + for arg in args { + arg.create_air_vec(air_vec); + } + } + AirExpression::Fn { params, func_body } => { + air_vec.push(Air::Fn { + params: params.clone(), + }); + func_body.create_air_vec(air_vec); + } + AirExpression::Builtin { func, tipo, args } => { + air_vec.push(Air::Builtin { + count: args.len(), + func: *func, + tipo: tipo.clone(), + }); + + for arg in args { + arg.create_air_vec(air_vec); + } + } + AirExpression::BinOp { + name, + tipo, + left, + right, + } => { + air_vec.push(Air::BinOp { + name: name.clone(), + tipo: tipo.clone(), + }); + left.create_air_vec(air_vec); + right.create_air_vec(air_vec); + } + AirExpression::UnOp { op, arg } => { + air_vec.push(Air::UnOp { op: *op }); + arg.create_air_vec(air_vec); + } + AirExpression::UnWrapData { tipo, value } => { + air_vec.push(Air::UnWrapData { tipo: tipo.clone() }); + value.create_air_vec(air_vec); + } + AirExpression::WrapData { tipo, value } => { + air_vec.push(Air::WrapData { tipo: tipo.clone() }); + value.create_air_vec(air_vec); + } + AirExpression::When { + tipo, + subject_name, + subject, + clauses, + } => { + air_vec.push(Air::When { + tipo: tipo.clone(), + subject_name: subject_name.clone(), + }); + subject.create_air_vec(air_vec); + clauses.create_air_vec(air_vec); + } + AirExpression::Clause { + tipo, + subject_name, + complex_clause, + pattern, + then, + otherwise, + } => { + air_vec.push(Air::Clause { + tipo: tipo.clone(), + subject_name: subject_name.clone(), + complex_clause: *complex_clause, + }); + pattern.create_air_vec(air_vec); + then.create_air_vec(air_vec); + otherwise.create_air_vec(air_vec); + } + AirExpression::ListClause { + tipo, + tail_name, + next_tail_name, + complex_clause, + then, + otherwise, + } => { + air_vec.push(Air::ListClause { + tipo: tipo.clone(), + tail_name: tail_name.clone(), + next_tail_name: next_tail_name.clone(), + complex_clause: *complex_clause, + }); + then.create_air_vec(air_vec); + otherwise.create_air_vec(air_vec); + } + AirExpression::WrapClause { then, otherwise } => { + air_vec.push(Air::WrapClause); + then.create_air_vec(air_vec); + otherwise.create_air_vec(air_vec); + } + AirExpression::TupleClause { + tipo, + indices, + predefined_indices, + subject_name, + type_count, + complex_clause, + then, + otherwise, + } => { + air_vec.push(Air::TupleClause { + tipo: tipo.clone(), + indices: indices.clone(), + predefined_indices: predefined_indices.clone(), + subject_name: subject_name.clone(), + count: *type_count, + complex_clause: *complex_clause, + }); + then.create_air_vec(air_vec); + otherwise.create_air_vec(air_vec); + } + AirExpression::ClauseGuard { + subject_name, + tipo, + pattern, + then, + } => { + air_vec.push(Air::ClauseGuard { + subject_name: subject_name.clone(), + tipo: tipo.clone(), + }); + + pattern.create_air_vec(air_vec); + then.create_air_vec(air_vec); + } + AirExpression::ListClauseGuard { + tipo, + tail_name, + next_tail_name, + inverse, + then, + } => { + air_vec.push(Air::ListClauseGuard { + tipo: tipo.clone(), + tail_name: tail_name.clone(), + next_tail_name: next_tail_name.clone(), + inverse: *inverse, + }); + + then.create_air_vec(air_vec); + } + AirExpression::Finally { pattern, then } => { + air_vec.push(Air::Finally); + pattern.create_air_vec(air_vec); + then.create_air_vec(air_vec); + } + AirExpression::If { + tipo, + pattern, + then, + otherwise, + } => { + air_vec.push(Air::If { tipo: tipo.clone() }); + pattern.create_air_vec(air_vec); + then.create_air_vec(air_vec); + otherwise.create_air_vec(air_vec); + } + AirExpression::Constr { tag, tipo, args } => { + air_vec.push(Air::Constr { + tag: *tag, + tipo: tipo.clone(), + count: args.len(), + }); + for arg in args { + arg.create_air_vec(air_vec); + } + } + AirExpression::RecordUpdate { + highest_index, + indices, + tipo, + record, + args, + } => { + air_vec.push(Air::RecordUpdate { + highest_index: *highest_index, + indices: indices.clone(), + tipo: tipo.clone(), + }); + record.create_air_vec(air_vec); + for arg in args { + arg.create_air_vec(air_vec); + } + } + AirExpression::RecordAccess { + field_index, + tipo, + record, + } => { + air_vec.push(Air::RecordAccess { + record_index: *field_index, + tipo: tipo.clone(), + }); + record.create_air_vec(air_vec); + } + AirExpression::TupleIndex { + tipo, + tuple_index, + tuple, + } => { + air_vec.push(Air::TupleIndex { + tipo: tipo.clone(), + tuple_index: *tuple_index, + }); + tuple.create_air_vec(air_vec); + } + AirExpression::ErrorTerm { tipo } => { + air_vec.push(Air::ErrorTerm { tipo: tipo.clone() }) + } + AirExpression::Trace { tipo, msg, then } => { + air_vec.push(Air::Trace { tipo: tipo.clone() }); + msg.create_air_vec(air_vec); + then.create_air_vec(air_vec); + } + AirExpression::FieldsEmpty { constr } => { + air_vec.push(Air::FieldsEmpty); + constr.create_air_vec(air_vec); + } + AirExpression::ListEmpty { list } => { + air_vec.push(Air::ListEmpty); + list.create_air_vec(air_vec); + } + }, AirTree::UnhoistedSequence(_) => { unreachable!("FIRST RESOLVE ALL UNHOISTED SEQUENCES") } diff --git a/crates/aiken-lang/src/tipo.rs b/crates/aiken-lang/src/tipo.rs index da34b7d8..1334e79e 100644 --- a/crates/aiken-lang/src/tipo.rs +++ b/crates/aiken-lang/src/tipo.rs @@ -180,6 +180,14 @@ impl Type { } } + pub fn is_2_tuple(&self) -> bool { + match self { + Type::Var { tipo } => tipo.borrow().is_2_tuple(), + Type::Tuple { elems } => elems.len() == 2, + _ => false, + } + } + pub fn is_data(&self) -> bool { match self { Self::App { module, name, .. } => "Data" == name && module.is_empty(), @@ -483,6 +491,13 @@ impl TypeVar { } } + pub fn is_2_tuple(&self) -> bool { + match self { + Self::Link { tipo } => tipo.is_2_tuple(), + _ => false, + } + } + pub fn is_data(&self) -> bool { match self { Self::Link { tipo } => tipo.is_data(),