diff --git a/crates/aiken-lang/src/uplc.rs b/crates/aiken-lang/src/uplc.rs index 4ecda5fa..a0b9fcfb 100644 --- a/crates/aiken-lang/src/uplc.rs +++ b/crates/aiken-lang/src/uplc.rs @@ -483,7 +483,6 @@ impl<'a> CodeGenerator<'a> { let mut index_types = vec![]; let mut highest_index = 0; spread_scope.push(self.id_gen.next()); - println!("{:#?}", args); self.build_ir(spread, &mut update_ir, spread_scope); @@ -3719,7 +3718,7 @@ impl<'a> CodeGenerator<'a> { } => { let tail_name_prefix = "__tail_index".to_string(); - let mut record = arg_stack.pop().unwrap(); + let record = arg_stack.pop().unwrap(); let mut args = HashMap::new(); let mut unchanged_field_indices = vec![]; @@ -3727,6 +3726,7 @@ impl<'a> CodeGenerator<'a> { for (index, tipo) in indices .iter() .sorted_by(|(index1, _), (index2, _)| index1.cmp(index2)) + .rev() { let arg = arg_stack.pop().unwrap(); args.insert(*index, (tipo.clone(), arg)); @@ -3753,15 +3753,114 @@ impl<'a> CodeGenerator<'a> { if let Some((tipo, arg)) = args.get(¤t_index) { term = apply_wrap( apply_wrap( - Term::Builtin(DefaultFunction::MkCons), + Term::Builtin(DefaultFunction::MkCons).force_wrap(), convert_type_to_data(arg.clone(), tipo), ), term, ); } else { + term = apply_wrap( + apply_wrap( + Term::Builtin(DefaultFunction::MkCons).force_wrap(), + apply_wrap( + Term::Builtin(DefaultFunction::HeadList).force_wrap(), + Term::Var(Name { + text: tail_name, + unique: 0.into(), + }), + ), + ), + term, + ) } } - todo!() + + term = apply_wrap( + apply_wrap( + Term::Builtin(DefaultFunction::ConstrData), + Term::Constant(UplcConstant::Integer(0)), + ), + term, + ); + + if !unchanged_field_indices.is_empty() { + prev_index = highest_index; + for index in unchanged_field_indices.into_iter() { + let tail_name = format!("{tail_name_prefix}_{}", prev_index); + let prev_tail_name = format!("{tail_name_prefix}_{index}"); + + let mut tail_list = Term::Var(Name { + text: prev_tail_name, + unique: 0.into(), + }); + + if index < prev_index { + for _ in index..prev_index { + tail_list = apply_wrap( + Term::Builtin(DefaultFunction::TailList).force_wrap(), + tail_list, + ); + } + + term = apply_wrap( + Term::Lambda { + parameter_name: Name { + text: tail_name, + unique: 0.into(), + }, + body: term.into(), + }, + tail_list, + ); + } + prev_index = index; + } + } + let tail_name = format!("{tail_name_prefix}_{prev_index}"); + let prev_tail_name = format!("{tail_name_prefix}_0"); + + let mut tail_list = Term::Var(Name { + text: prev_tail_name.clone(), + unique: 0.into(), + }); + + for _ in 0..prev_index { + tail_list = apply_wrap( + Term::Builtin(DefaultFunction::TailList).force_wrap(), + tail_list, + ); + } + if prev_index != 0 { + term = apply_wrap( + Term::Lambda { + parameter_name: Name { + text: tail_name, + unique: 0.into(), + }, + body: term.into(), + }, + tail_list, + ); + } + + self.needs_field_access = true; + term = apply_wrap( + Term::Lambda { + parameter_name: Name { + text: prev_tail_name, + unique: 0.into(), + }, + body: term.into(), + }, + apply_wrap( + Term::Var(Name { + text: CONSTR_FIELDS_EXPOSER.to_string(), + unique: 0.into(), + }), + record, + ), + ); + arg_stack.push(term); } Air::UnOp { op, .. } => { let value = arg_stack.pop().unwrap(); diff --git a/examples/acceptance_tests/039/aiken.lock b/examples/acceptance_tests/039/aiken.lock new file mode 100644 index 00000000..3a78b1e7 --- /dev/null +++ b/examples/acceptance_tests/039/aiken.lock @@ -0,0 +1,5 @@ +# This file was generated by Aiken +# You typically do not need to edit this file + +requirements = [] +packages = [] diff --git a/examples/acceptance_tests/039/aiken.toml b/examples/acceptance_tests/039/aiken.toml new file mode 100644 index 00000000..dbb3240d --- /dev/null +++ b/examples/acceptance_tests/039/aiken.toml @@ -0,0 +1,2 @@ +name = "aiken-lang/acceptance_test_039" +version = "0.0.0" diff --git a/examples/acceptance_tests/039/lib/tests.ak b/examples/acceptance_tests/039/lib/tests.ak new file mode 100644 index 00000000..2888def8 --- /dev/null +++ b/examples/acceptance_tests/039/lib/tests.ak @@ -0,0 +1,60 @@ + + + +pub type Door{ + locked: Bool, + hinge_angle: Int +} + + + +pub type Car{ + owner: ByteArray, + wheels: Int, + door: Door, + vin: ByteArray, +} + + +pub fn update_owner(new_owner: ByteArray, car: Car){ + Car{..car, owner: new_owner} + +} + +pub fn update_vin(new_vin: ByteArray, car: Car){ + Car{..car, vin: new_vin} +} + + +pub fn update_door_angle(new_hinge_angle: Int, car: Car){ + Car{..car, door: Door{..car.door, hinge_angle: new_hinge_angle}} +} + +pub fn update_door_locked_and_wheels(new_locked: Bool, new_wheels: Int, car: Car){ + Car{..car, door: Door{..car.door, locked: new_locked}, wheels: new_wheels} + +} + +test update_owner1(){ + let initial_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} + let final_car = Car{owner: #[244, 244, 244, 244], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} + update_owner(#[244, 244, 244, 244], initial_car) == final_car +} + +test update_vin1(){ + let initial_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} + let final_car = Car{owner: #[], wheels: 4, vin: #[2,2,2,2,2,2,2,2,2], door: Door{locked: False, hinge_angle: 45}} + update_vin(#[2,2,2,2,2,2,2,2,2], initial_car) == final_car +} + +test update_door_angle1(){ + let initial_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} + let final_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 90}} + update_door_angle(90, initial_car) == final_car +} + +test update_door_locked_and_wheels1(){ + let initial_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} + let final_car = Car{owner: #[], wheels: 5, vin: #[1,1,1,1,1,1,1], door: Door{locked: True, hinge_angle: 45}} + update_door_locked_and_wheels(True, 5, initial_car) == final_car +}