diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index ab6be1bf..40721be1 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> { value_type: value.tipo(), kind: *kind, remove_unused: true, + full_check: false, }, ); @@ -532,6 +533,7 @@ impl<'a> CodeGenerator<'a> { value_type: clauses[0].then.tipo(), kind: AssignmentKind::Let, remove_unused: false, + full_check: false, }, ); @@ -5184,6 +5186,7 @@ impl<'a> CodeGenerator<'a> { value_type: data(), kind: AssignmentKind::Expect, remove_unused: true, + full_check: false, }, ); 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 226deca8..4fc90dab 100644 --- a/crates/aiken-lang/src/gen_uplc/builder.rs +++ b/crates/aiken-lang/src/gen_uplc/builder.rs @@ -61,6 +61,7 @@ pub struct AssignmentProperties { pub value_type: Arc, pub kind: AssignmentKind, pub remove_unused: bool, + pub full_check: bool, } #[derive(Clone, Debug)] diff --git a/crates/aiken-lang/src/gen_uplc2.rs b/crates/aiken-lang/src/gen_uplc2.rs index ebd5466b..aaf599ff 100644 --- a/crates/aiken-lang/src/gen_uplc2.rs +++ b/crates/aiken-lang/src/gen_uplc2.rs @@ -91,6 +91,7 @@ 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); + println!("{:#?}", air_tree); todo!() } @@ -261,7 +262,7 @@ impl<'a> CodeGenerator<'a> { let air_value = self.build(value); - self.assignment_air_tree( + self.assignment( pattern, air_value, tipo, @@ -269,6 +270,7 @@ impl<'a> CodeGenerator<'a> { value_type: value.tipo(), kind: *kind, remove_unused: kind.is_let(), + full_check: false, }, ) } @@ -294,7 +296,7 @@ impl<'a> CodeGenerator<'a> { let subject_val = self.build(subject); - let assignment = self.assignment_air_tree( + let assignment = self.assignment( &last_clause.pattern, subject_val, tipo, @@ -302,6 +304,7 @@ impl<'a> CodeGenerator<'a> { value_type: subject.tipo(), kind: AssignmentKind::Let, remove_unused: false, + full_check: false, }, ); @@ -475,7 +478,7 @@ impl<'a> CodeGenerator<'a> { } } - pub fn assignment_air_tree( + pub fn assignment( &mut self, pattern: &Pattern>, mut value: AirTree, @@ -515,7 +518,7 @@ impl<'a> CodeGenerator<'a> { Pattern::Var { name, .. } => { if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() { let mut index_map = IndexMap::new(); - let tipo = builder::convert_opaque_type(); + // let tipo = builder::convert_opaque_type(); let assignment = AirTree::let_assignment(name, value); let val = AirTree::local_var(name, tipo.clone()); @@ -537,12 +540,8 @@ impl<'a> CodeGenerator<'a> { } } Pattern::Assign { name, pattern, .. } => { - let inner_pattern = self.assignment_air_tree( - pattern, - AirTree::local_var(name, tipo.clone()), - tipo, - props, - ); + let inner_pattern = + self.assignment(pattern, AirTree::local_var(name, tipo.clone()), tipo, props); let assign = AirTree::let_assignment(name, value); AirTree::UnhoistedSequence(vec![assign, inner_pattern]) @@ -550,18 +549,14 @@ impl<'a> CodeGenerator<'a> { Pattern::Discard { name, .. } => { if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() { let mut index_map = IndexMap::new(); - let tipo = builder::convert_opaque_type(); + // let tipo = builder::convert_opaque_type(); 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)) } else { - let expect = self.expect_type( - &tipo, - val.clone(), - &mut index_map, - pattern.location(), - ); + 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)) @@ -610,14 +605,15 @@ impl<'a> CodeGenerator<'a> { ( elem_name, - self.assignment_air_tree( + self.assignment( elem, val, list_elem_type, AssignmentProperties { - value_type: props.value_type.clone(), + value_type: list_elem_type.clone(), kind: props.kind, remove_unused: true, + full_check: false, }, ), ) @@ -650,7 +646,7 @@ impl<'a> CodeGenerator<'a> { elems.push(( tail_name, - self.assignment_air_tree( + self.assignment( tail, val, tipo, @@ -658,9 +654,11 @@ impl<'a> CodeGenerator<'a> { value_type: props.value_type.clone(), kind: props.kind, remove_unused: true, + full_check: false, }, ), )); + println!("ELEMS IS {:#?}", elems); }); let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec(); @@ -688,11 +686,9 @@ impl<'a> CodeGenerator<'a> { if tipo.is_bool() { assert!(props.kind.is_expect()); - sequence.push(AirTree::assert_bool(name == "True", value)); - - AirTree::UnhoistedSequence(sequence) + AirTree::assert_bool(name == "True", value) } else if tipo.is_void() { - todo!() + AirTree::let_assignment("_", value) } else { if props.kind.is_expect() { let data_type = build::lookup_data_type_by_tipo(&self.data_types, tipo) @@ -793,7 +789,7 @@ impl<'a> CodeGenerator<'a> { field_index, field_name, arg_type.clone(), - self.assignment_air_tree( + self.assignment( &arg.value, val, arg_type, @@ -801,6 +797,7 @@ impl<'a> CodeGenerator<'a> { value_type: props.value_type.clone(), kind: props.kind, remove_unused: true, + full_check: false, }, ), ) @@ -874,7 +871,7 @@ impl<'a> CodeGenerator<'a> { ( tuple_name, - self.assignment_air_tree( + self.assignment( arg, val, arg_type, @@ -882,6 +879,7 @@ impl<'a> CodeGenerator<'a> { value_type: props.value_type.clone(), kind: props.kind, remove_unused: true, + full_check: false, }, ), ) @@ -978,6 +976,50 @@ impl<'a> CodeGenerator<'a> { vec![AirTree::local_var(map_name, tipo.clone()), unwrap_function], ); + AirTree::hoist_over(assign, func_call) + } else if tipo.is_list() { + assert!(!tipo.get_inner_types().is_empty()); + let inner_list_type = &tipo.get_inner_types()[0]; + + let list_name = format!("__list_span_{}_{}", location.start, location.end); + let item_name = format!("__item_span_{}_{}", location.start, location.end); + + let assign = AirTree::let_assignment(&list_name, value); + + let expect_item = self.expect_type( + inner_list_type, + AirTree::local_var(&item_name, inner_list_type.clone()), + defined_data_types, + location, + ); + + let anon_func_body = + AirTree::hoist_over(AirTree::let_assignment("_", expect_item), AirTree::void()); + + let unwrap_function = AirTree::anon_func(vec![item_name], anon_func_body); + + let function = self.code_gen_functions.get(EXPECT_ON_LIST); + + if function.is_none() { + let expect_list_func = AirTree::expect_on_list(); + self.code_gen_functions.insert( + EXPECT_ON_LIST.to_string(), + CodeGenFunction::Function(expect_list_func, vec![]), + ); + } + + if let Some(counter) = defined_data_types.get_mut(EXPECT_ON_LIST) { + *counter += 1 + } else { + defined_data_types.insert(EXPECT_ON_LIST.to_string(), 1); + } + + let func_call = AirTree::call( + AirTree::local_var(EXPECT_ON_LIST, void()), + void(), + vec![AirTree::local_var(list_name, tipo.clone()), unwrap_function], + ); + AirTree::hoist_over(assign, func_call) } else { todo!() @@ -998,18 +1040,60 @@ impl<'a> CodeGenerator<'a> { todo!() } else { // handle final_clause - *props.is_final_clause() = true; assert!(final_clause.guard.is_none()); let clause_then = self.build(&final_clause.then); - self.clause_pattern(&final_clause.pattern, clause_then) + let (_, assignments) = self.clause_pattern(&final_clause.pattern, subject_tipo, props); + + AirTree::hoist_over(assignments, clause_then) } } pub fn clause_pattern( &mut self, pattern: &Pattern>, - clause_then: AirTree, + subject_tipo: &Arc, + props: &mut ClauseProperties, + // We return condition and then assignments sequence + ) -> (AirTree, AirTree) { + match pattern { + Pattern::Int { value, .. } => { + assert!(!*props.is_final_clause()); + (AirTree::int(value), AirTree::no_op()) + } + Pattern::Var { name, .. } => ( + AirTree::void(), + AirTree::let_assignment( + name, + AirTree::local_var(props.clause_var_name(), subject_tipo.clone()), + ), + ), + Pattern::Assign { name, pattern, .. } => { + let (inner_condition, inner_assignment) = + self.clause_pattern(pattern, subject_tipo, props); + + let sequence = vec![ + AirTree::let_assignment( + name, + AirTree::local_var(props.clause_var_name(), subject_tipo.clone()), + ), + inner_assignment, + ]; + + (inner_condition, AirTree::UnhoistedSequence(sequence)) + } + Pattern::Discard { .. } => (AirTree::void(), AirTree::no_op()), + Pattern::List { .. } => todo!(), + Pattern::Constructor { .. } => todo!(), + Pattern::Tuple { .. } => todo!(), + } + } + + fn nested_clause_condition( + &mut self, + pattern: &Pattern>, + subject_tipo: &Arc, + props: &mut ClauseProperties, ) -> AirTree { todo!() } diff --git a/crates/aiken-lang/src/gen_uplc2/tree.rs b/crates/aiken-lang/src/gen_uplc2/tree.rs index 4d60a740..627f5201 100644 --- a/crates/aiken-lang/src/gen_uplc2/tree.rs +++ b/crates/aiken-lang/src/gen_uplc2/tree.rs @@ -1,6 +1,6 @@ use indexmap::IndexSet; use std::{collections::VecDeque, sync::Arc}; -use uplc::builtins::DefaultFunction; +use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction}; use crate::{ ast::{BinOp, Span, UnOp}, @@ -68,7 +68,7 @@ pub enum AirStatement { recursive: bool, variant_name: String, func_body: Box, - hoisted_over: Box, + hoisted_over: Option>, }, // Assertions AssertConstr { @@ -364,7 +364,6 @@ impl AirTree { params: Vec, recursive: bool, func_body: AirTree, - hoisting_over: AirTree, ) -> AirTree { AirTree::Statement(AirStatement::DefineFunc { func_name: func_name.to_string(), @@ -373,7 +372,7 @@ impl AirTree { recursive, variant_name: variant_name.to_string(), func_body: func_body.into(), - hoisted_over: hoisting_over.into(), + hoisted_over: None, }) } pub fn anon_func(params: Vec, func_body: AirTree) -> AirTree { @@ -682,14 +681,12 @@ impl AirTree { | AirStatement::ListAccessor { hoisted_over, .. } | AirStatement::NoOp { hoisted_over } | AirStatement::ListExpose { hoisted_over, .. } - | AirStatement::TupleAccessor { hoisted_over, .. } => { + | AirStatement::TupleAccessor { hoisted_over, .. } + | AirStatement::DefineFunc { hoisted_over, .. } => { assert!(hoisted_over.is_none()); *hoisted_over = Some(next_exp.into()); assignment } - AirStatement::DefineFunc { .. } => { - unreachable!("Should not use this function to hoist defined functions.") - } }, AirTree::Expression(_) => { unreachable!("Trying to hoist an expression onto an expression.") @@ -705,6 +702,49 @@ impl AirTree { } pub fn expect_on_list() -> AirTree { + let list_var = AirTree::local_var("__list_to_check", list(data())); + + let head_list = AirTree::builtin(DefaultFunction::HeadList, data(), vec![list_var]); + + let expect_on_head = AirTree::call( + AirTree::local_var("__check_with", void()), + void(), + vec![head_list], + ); + + let assign = AirTree::let_assignment("_", expect_on_head); + + let next_call = AirTree::call( + AirTree::local_var(EXPECT_ON_LIST, void()), + void(), + vec![ + AirTree::builtin( + DefaultFunction::TailList, + list(data()), + vec![AirTree::local_var("__list_to_check", list(data()))], + ), + AirTree::local_var("__check_with", void()), + ], + ); + + let list_clause = AirTree::list_clause( + "__list_to_check", + void(), + AirTree::void(), + next_call, + None, + false, + ); + + AirTree::define_func( + EXPECT_ON_LIST, + "", + "", + vec!["__list_to_check".to_string(), "__check_with".to_string()], + true, + list_clause, + ) + // self.air.push(Air::DefineFunc { // scope: self.scope.clone(), // func_name: EXPECT_ON_LIST.to_string(), @@ -713,45 +753,6 @@ impl AirTree { // recursive: true, // variant_name: "".to_string(), // }); - - let list_var = AirTree::local_var("__list_to_check", list(data())); - - let head_list = AirTree::builtin(DefaultFunction::HeadList, data(), vec![list_var]); - - let _expect_on_head = AirTree::call( - AirTree::local_var("__check_with", void()), - void(), - vec![head_list], - ); - todo!() - - // self.list_clause(void(), "__list_to_check", None, false, void_stack); - - // self.choose_unit(check_with_stack); - - // expect_stack.var( - // ValueConstructor::public( - // void(), - // ValueConstructorVariant::ModuleFn { - // name: EXPECT_ON_LIST.to_string(), - // field_map: None, - // module: "".to_string(), - // arity: 2, - // location: Span::empty(), - // builtin: None, - // }, - // ), - // EXPECT_ON_LIST, - // "", - // ); - - // arg_stack1.local_var(list(data()), "__list_to_check"); - - // arg_stack2.local_var(void(), "__check_with"); - - // tail_stack.builtin(DefaultFunction::TailList, list(data()), vec![arg_stack1]); - - // self.call(void(), expect_stack, vec![tail_stack, arg_stack2]) } pub fn iter(&self) -> AirTreeIterator {