feat(gen_uplc): introduce scope new type
* new module scope which holds some ancestor logic * rework some things to truly hide scope increments Co-authored-by: Kasey White <kwhitemsg@gmail.com>
This commit is contained in:
		
							parent
							
								
									ca0d896b8d
								
							
						
					
					
						commit
						33a3c5dc13
					
				|  | @ -4,7 +4,7 @@ use indexmap::{IndexMap, IndexSet}; | |||
| use itertools::Itertools; | ||||
| use uplc::{ | ||||
|     ast::{Constant as UplcConstant, Name, NamedDeBruijn, Program, Term, Type as UplcType}, | ||||
|     builder::{ASSERT_ON_LIST, CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD, CONSTR_INDEX_EXPOSER}, | ||||
|     builder::{CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD, CONSTR_INDEX_EXPOSER, EXPECT_ON_LIST}, | ||||
|     builtins::DefaultFunction, | ||||
|     machine::cost_model::ExBudget, | ||||
|     optimize::aiken_optimize_and_intern, | ||||
|  | @ -27,6 +27,7 @@ use crate::{ | |||
| 
 | ||||
| pub mod air; | ||||
| pub mod builder; | ||||
| pub mod scope; | ||||
| pub mod stack; | ||||
| 
 | ||||
| use air::Air; | ||||
|  | @ -185,14 +186,15 @@ impl<'a> CodeGenerator<'a> { | |||
|             TypedExpr::String { value, .. } => ir_stack.string(value.to_string()), | ||||
|             TypedExpr::ByteArray { bytes, .. } => ir_stack.byte_array(bytes.to_vec()), | ||||
|             TypedExpr::Pipeline { expressions, .. } | TypedExpr::Sequence { expressions, .. } => { | ||||
|                 let stacks = Vec::new(); | ||||
|                 let mut stacks = Vec::new(); | ||||
| 
 | ||||
|                 for (index, expr) in expressions.iter().enumerate() { | ||||
|                     if index == 0 { | ||||
|                         self.build_ir(expr, ir_stack); | ||||
|                     } else { | ||||
|                         let mut stack = ir_stack.in_new_scope(); | ||||
|                         let mut stack = ir_stack.empty_with_scope(); | ||||
|                         self.build_ir(expr, &mut stack); | ||||
|                         stacks.push(stack); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|  | @ -215,7 +217,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                 } | ||||
|             }, | ||||
|             TypedExpr::Fn { args, body, .. } => { | ||||
|                 let mut body_stack = ir_stack.in_new_scope(); | ||||
|                 let mut body_stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                 self.build_ir(body, &mut body_stack); | ||||
| 
 | ||||
|  | @ -234,7 +236,7 @@ impl<'a> CodeGenerator<'a> { | |||
|             } => { | ||||
|                 let stacks = Vec::new(); | ||||
|                 for element in elements { | ||||
|                     let mut stack = ir_stack.in_new_scope(); | ||||
|                     let mut stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                     self.build_ir(element, &mut stack); | ||||
| 
 | ||||
|  | @ -242,7 +244,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                 } | ||||
| 
 | ||||
|                 let tail = tail.as_ref().map(|tail| { | ||||
|                     let mut tail_stack = ir_stack.in_new_scope(); | ||||
|                     let mut tail_stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                     self.build_ir(tail, &mut tail_stack); | ||||
| 
 | ||||
|  | @ -276,7 +278,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                                 let stacks = Vec::new(); | ||||
| 
 | ||||
|                                 for (arg, func_type) in args.iter().zip(fun_arg_types) { | ||||
|                                     let mut stack = ir_stack.in_new_scope(); | ||||
|                                     let mut stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                                     if func_type.is_data() && !arg.value.tipo().is_data() { | ||||
|                                         stack.wrap_data(arg.value.tipo()); | ||||
|  | @ -301,7 +303,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                             let stacks = Vec::new(); | ||||
| 
 | ||||
|                             for (arg, func_type) in args.iter().zip(fun_arg_types) { | ||||
|                                 let mut stack = ir_stack.in_new_scope(); | ||||
|                                 let mut stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                                 if func_type.is_data() && !arg.value.tipo().is_data() { | ||||
|                                     stack.wrap_data(arg.value.tipo()); | ||||
|  | @ -341,7 +343,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                                 let mut stacks = Vec::new(); | ||||
| 
 | ||||
|                                 for (arg, func_type) in args.iter().zip(fun_arg_types) { | ||||
|                                     let mut stack = ir_stack.in_new_scope(); | ||||
|                                     let mut stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                                     if func_type.is_data() && !arg.value.tipo().is_data() { | ||||
|                                         stack.wrap_data(arg.value.tipo()); | ||||
|  | @ -366,7 +368,7 @@ impl<'a> CodeGenerator<'a> { | |||
| 
 | ||||
|                                 let mut stacks = Vec::new(); | ||||
|                                 for (arg, func_type) in args.iter().zip(fun_arg_types) { | ||||
|                                     let mut stack = ir_stack.in_new_scope(); | ||||
|                                     let mut stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                                     if func_type.is_data() && !arg.value.tipo().is_data() { | ||||
|                                         stack.wrap_data(arg.value.tipo()); | ||||
|  | @ -385,7 +387,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                     _ => {} | ||||
|                 } | ||||
| 
 | ||||
|                 let mut fun_stack = ir_stack.in_new_scope(); | ||||
|                 let mut fun_stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                 self.build_ir(fun, &mut fun_stack); | ||||
| 
 | ||||
|  | @ -393,7 +395,7 @@ impl<'a> CodeGenerator<'a> { | |||
| 
 | ||||
|                 let mut stacks = Vec::new(); | ||||
|                 for (arg, func_type) in args.iter().zip(fun_arg_types) { | ||||
|                     let mut stack = ir_stack.in_new_scope(); | ||||
|                     let mut stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                     if func_type.is_data() && !arg.value.tipo().is_data() { | ||||
|                         stack.wrap_data(arg.value.tipo()); | ||||
|  | @ -407,8 +409,8 @@ impl<'a> CodeGenerator<'a> { | |||
|             TypedExpr::BinOp { | ||||
|                 name, left, right, .. | ||||
|             } => { | ||||
|                 let mut left_stack = ir_stack.in_new_scope(); | ||||
|                 let mut right_stack = ir_stack.in_new_scope(); | ||||
|                 let mut left_stack = ir_stack.empty_with_scope(); | ||||
|                 let mut right_stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                 self.build_ir(left, &mut left_stack); | ||||
|                 self.build_ir(right, &mut right_stack); | ||||
|  | @ -422,8 +424,8 @@ impl<'a> CodeGenerator<'a> { | |||
|                 tipo, | ||||
|                 .. | ||||
|             } => { | ||||
|                 let mut value_stack = ir_stack.in_new_scope(); | ||||
|                 let mut pattern_stack = ir_stack.in_new_scope(); | ||||
|                 let mut value_stack = ir_stack.empty_with_scope(); | ||||
|                 let mut pattern_stack = ir_stack.empty_with_scope(); | ||||
| 
 | ||||
|                 let mut replaced_type = tipo.clone(); | ||||
|                 builder::replace_opaque_type(&mut replaced_type, self.data_types.clone()); | ||||
|  | @ -1756,17 +1758,17 @@ impl<'a> CodeGenerator<'a> { | |||
|             && !tipo.is_data() | ||||
|             && !pattern.is_discard() | ||||
|         { | ||||
|             let mut wrap_stack = pattern_stack.in_new_scope(); | ||||
|             let mut wrap_stack = pattern_stack.empty_with_scope(); | ||||
|             wrap_stack.un_wrap_data(tipo.clone().into()); | ||||
|             wrap_stack.merge(value_stack); | ||||
|             wrap_stack.merge_child(value_stack); | ||||
|             wrap_stack | ||||
|         } else if !assignment_properties.value_type.is_data() | ||||
|             && tipo.is_data() | ||||
|             && !pattern.is_discard() | ||||
|         { | ||||
|             let mut wrap_stack = pattern_stack.in_new_scope(); | ||||
|             let mut wrap_stack = pattern_stack.empty_with_scope(); | ||||
|             wrap_stack.wrap_data(assignment_properties.value_type.clone()); | ||||
|             wrap_stack.merge(value_stack); | ||||
|             wrap_stack.merge_child(value_stack); | ||||
|             wrap_stack | ||||
|         } else { | ||||
|             value_stack | ||||
|  | @ -1775,24 +1777,24 @@ impl<'a> CodeGenerator<'a> { | |||
|         match pattern { | ||||
|             Pattern::Int { .. } => todo!(), | ||||
|             Pattern::Var { name, .. } => { | ||||
|                 let assert_value_stack = value_stack.in_new_scope(); | ||||
|                 let expect_value_stack = value_stack.empty_with_scope(); | ||||
|                 pattern_stack.let_assignment(name, value_stack); | ||||
| 
 | ||||
|                 if matches!(assignment_properties.kind, AssignmentKind::Expect) | ||||
|                     && assignment_properties.value_type.is_data() | ||||
|                     && !tipo.is_data() | ||||
|                 { | ||||
|                     let mut assert_stack = pattern_stack.in_new_scope(); | ||||
|                     let mut expect_stack = pattern_stack.empty_with_scope(); | ||||
| 
 | ||||
|                     self.recursive_assert_pattern( | ||||
|                     self.expect_pattern( | ||||
|                         pattern, | ||||
|                         &mut assert_stack, | ||||
|                         assert_value_stack, | ||||
|                         &mut expect_stack, | ||||
|                         expect_value_stack, | ||||
|                         tipo, | ||||
|                         assignment_properties, | ||||
|                     ); | ||||
| 
 | ||||
|                     pattern_stack.merge(assert_stack); | ||||
|                     pattern_stack.merge(expect_stack); | ||||
|                 } | ||||
|             } | ||||
|             Pattern::Assign { .. } => todo!("Assign not yet implemented"), | ||||
|  | @ -1804,7 +1806,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                     && assignment_properties.value_type.is_data() | ||||
|                     && !tipo.is_data() | ||||
|                 { | ||||
|                     self.recursive_assert_pattern( | ||||
|                     self.expect_pattern( | ||||
|                         list, | ||||
|                         pattern_vec, | ||||
|                         value_vec, | ||||
|  | @ -1828,7 +1830,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                     && assignment_properties.value_type.is_data() | ||||
|                     && !tipo.is_data() | ||||
|                 { | ||||
|                     self.recursive_assert_pattern( | ||||
|                     self.expect_pattern( | ||||
|                         constr, | ||||
|                         pattern_vec, | ||||
|                         value_vec, | ||||
|  | @ -1852,7 +1854,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                     && assignment_properties.value_type.is_data() | ||||
|                     && !tipo.is_data() | ||||
|                 { | ||||
|                     self.recursive_assert_pattern( | ||||
|                     self.expect_pattern( | ||||
|                         tuple, | ||||
|                         pattern_vec, | ||||
|                         value_vec, | ||||
|  | @ -2165,10 +2167,10 @@ impl<'a> CodeGenerator<'a> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn recursive_assert_pattern( | ||||
|     pub fn expect_pattern( | ||||
|         &mut self, | ||||
|         pattern: &Pattern<PatternConstructor, Arc<Type>>, | ||||
|         assert_stack: &mut AirStack, | ||||
|         expect_stack: &mut AirStack, | ||||
|         value_stack: AirStack, | ||||
|         tipo: &Type, | ||||
|         assignment_properties: AssignmentProperties, | ||||
|  | @ -2176,51 +2178,52 @@ impl<'a> CodeGenerator<'a> { | |||
|         match pattern { | ||||
|             Pattern::Int { .. } => unreachable!(), | ||||
|             Pattern::Var { name, .. } => { | ||||
|                 assert_stack.merge(value_stack); | ||||
|                 expect_stack.merge(value_stack); | ||||
| 
 | ||||
|                 self.recursive_assert_tipo(tipo, assert_stack, name); | ||||
|                 self.expect_type(tipo, expect_stack, name); | ||||
|             } | ||||
|             Pattern::Assign { .. } => todo!(), | ||||
|             Pattern::Discard { .. } => unreachable!(), | ||||
|             Pattern::List { elements, tail, .. } => { | ||||
|                 let mut assert_list_vec = vec![]; | ||||
|                 let inner_list_type = &tipo.get_inner_types()[0]; | ||||
|                 let mut names = vec![]; | ||||
| 
 | ||||
|                 let mut expect_list_stacks = vec![]; | ||||
| 
 | ||||
|                 for element in elements { | ||||
|                     match element { | ||||
|                         Pattern::Var { name, .. } => { | ||||
|                             names.push(name.clone()); | ||||
|                         } | ||||
|                         Pattern::Assign { .. } => todo!(), | ||||
|                         l @ (Pattern::List { .. } | ||||
|                         element_pattern @ (Pattern::List { .. } | ||||
|                         | Pattern::Constructor { .. } | ||||
|                         | Pattern::Tuple { .. }) => { | ||||
|                             let name = format!("list_item_id_{}", self.id_gen.next()); | ||||
| 
 | ||||
|                             names.push(name.clone()); | ||||
| 
 | ||||
|                             self.recursive_assert_pattern( | ||||
|                                 l, | ||||
|                                 &mut assert_list_vec, | ||||
|                                 &mut vec![Air::Var { | ||||
|                                     scope: scope.clone(), | ||||
|                                     constructor: ValueConstructor::public( | ||||
|                                         tipo.clone().into(), | ||||
|                                         ValueConstructorVariant::LocalVariable { | ||||
|                                             location: Span::empty(), | ||||
|                                         }, | ||||
|                                     ), | ||||
|                                     name, | ||||
|                                     variant_name: String::new(), | ||||
|                                 }], | ||||
|                             let mut element_stack = expect_stack.empty_with_scope(); | ||||
|                             let mut value_stack = element_stack.empty_with_scope(); | ||||
| 
 | ||||
|                             value_stack.local_var(tipo.clone().into(), name); | ||||
| 
 | ||||
|                             self.expect_pattern( | ||||
|                                 element_pattern, | ||||
|                                 &mut element_stack, | ||||
|                                 value_stack, | ||||
|                                 inner_list_type, | ||||
|                                 assignment_properties.clone(), | ||||
|                                 scope.clone(), | ||||
|                             ); | ||||
| 
 | ||||
|                             expect_list_stacks.push(element_stack); | ||||
|                         } | ||||
|                         _ => {} | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 let mut tail_stack = expect_stack.empty_with_scope(); | ||||
| 
 | ||||
|                 let name = if let Some(tail) = tail { | ||||
|                     match &**tail { | ||||
|                         Pattern::Var { name, .. } => name.clone(), | ||||
|  | @ -2230,21 +2233,13 @@ impl<'a> CodeGenerator<'a> { | |||
|                     format!("__tail_{}", self.id_gen.next()) | ||||
|                 }; | ||||
| 
 | ||||
|                 self.recursive_assert_tipo(tipo, &mut assert_list_vec, &name, scope.clone()); | ||||
|                 self.expect_type(tipo, &mut tail_stack, &name); | ||||
| 
 | ||||
|                 names.push(name); | ||||
| 
 | ||||
|                 pattern_vec.push(Air::ListAccessor { | ||||
|                     scope, | ||||
|                     tipo: tipo.clone().into(), | ||||
|                     names, | ||||
|                     tail: true, | ||||
|                     check_last_item: false, | ||||
|                 }); | ||||
|                 expect_stack.list_accessor(tipo.clone().into(), names, true, false, value_stack); | ||||
| 
 | ||||
|                 pattern_vec.append(value_vec); | ||||
| 
 | ||||
|                 pattern_vec.append(&mut assert_list_vec); | ||||
|                 expect_stack.merge_children(expect_list_stacks); | ||||
|             } | ||||
|             Pattern::Constructor { | ||||
|                 arguments, | ||||
|  | @ -2306,17 +2301,19 @@ impl<'a> CodeGenerator<'a> { | |||
|                         current_index += 1; | ||||
|                     } else { | ||||
|                         let id_next = self.id_gen.next(); | ||||
| 
 | ||||
|                         final_args.push((format!("__field_{index}_{id_next}"), index)); | ||||
|                         self.recursive_assert_tipo( | ||||
| 
 | ||||
|                         self.expect_type( | ||||
|                             type_map.get(&index).unwrap(), | ||||
|                             &mut nested_pattern, | ||||
|                             &format!("__field_{index}_{id_next}"), | ||||
|                             scope.clone(), | ||||
|                         ) | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 let constr_var = format!("__constr_{}", self.id_gen.next()); | ||||
| 
 | ||||
|                 pattern_vec.push(Air::Let { | ||||
|                     scope: scope.clone(), | ||||
|                     name: constr_var.clone(), | ||||
|  | @ -2411,11 +2408,10 @@ impl<'a> CodeGenerator<'a> { | |||
|                     } else { | ||||
|                         let id_next = self.id_gen.next(); | ||||
|                         final_args.push((format!("__tuple_{index}_{id_next}"), index)); | ||||
|                         self.recursive_assert_tipo( | ||||
|                         self.expect_type( | ||||
|                             type_map.get(&index).unwrap(), | ||||
|                             &mut nested_pattern, | ||||
|                             &format!("__tuple_{index}_{id_next}"), | ||||
|                             scope.clone(), | ||||
|                         ) | ||||
|                     } | ||||
|                 } | ||||
|  | @ -2436,7 +2432,7 @@ impl<'a> CodeGenerator<'a> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn recursive_assert_tipo(&mut self, tipo: &Type, assert_vec: &mut AirStack, name: &str) { | ||||
|     fn expect_type(&mut self, tipo: &Type, expect_stack: &mut AirStack, name: &str) { | ||||
|         let mut tipo = tipo.clone().into(); | ||||
|         builder::replace_opaque_type(&mut tipo, self.data_types.clone()); | ||||
| 
 | ||||
|  | @ -2455,231 +2451,103 @@ impl<'a> CodeGenerator<'a> { | |||
|             let inner_list_type = &tipo.get_inner_types()[0]; | ||||
|             let inner_pair_types = inner_list_type.get_inner_types(); | ||||
| 
 | ||||
|             assert_vec.push(Air::Builtin { | ||||
|                 scope: scope.clone(), | ||||
|                 func: DefaultFunction::ChooseUnit, | ||||
|                 tipo: tipo.clone(), | ||||
|                 count: DefaultFunction::ChooseUnit.arity(), | ||||
|             }); | ||||
|             let mut unwrap_function_stack = expect_stack.empty_with_scope(); | ||||
|             let mut pair_access_stack = unwrap_function_stack.empty_with_scope(); | ||||
|             let mut local_var_stack = pair_access_stack.empty_with_scope(); | ||||
| 
 | ||||
|             assert_vec.push(Air::Call { | ||||
|                 scope: scope.clone(), | ||||
|                 count: 2, | ||||
|                 tipo: tipo.clone(), | ||||
|             }); | ||||
|             local_var_stack.local_var(inner_list_type.clone(), format!("__pair_{new_id}")); | ||||
| 
 | ||||
|             assert_vec.push(Air::Var { | ||||
|                 scope: scope.clone(), | ||||
|                 constructor: ValueConstructor::public( | ||||
|                     tipo.clone(), | ||||
|                     ValueConstructorVariant::LocalVariable { | ||||
|                         location: Span::empty(), | ||||
|                     }, | ||||
|                 ), | ||||
|                 name: ASSERT_ON_LIST.to_string(), | ||||
|                 variant_name: String::new(), | ||||
|             }); | ||||
| 
 | ||||
|             assert_vec.push(Air::Var { | ||||
|                 scope: scope.clone(), | ||||
|                 constructor: ValueConstructor::public( | ||||
|                     tipo.clone(), | ||||
|                     ValueConstructorVariant::LocalVariable { | ||||
|                         location: Span::empty(), | ||||
|                     }, | ||||
|                 ), | ||||
|                 name: name.to_owned(), | ||||
|                 variant_name: String::new(), | ||||
|             }); | ||||
| 
 | ||||
|             assert_vec.push(Air::Fn { | ||||
|                 scope: scope.clone(), | ||||
|                 params: vec![format!("__pair_{new_id}")], | ||||
|             }); | ||||
| 
 | ||||
|             assert_vec.push(Air::TupleAccessor { | ||||
|                 scope: scope.clone(), | ||||
|                 names: vec![ | ||||
|             pair_access_stack.tuple_accessor( | ||||
|                 inner_list_type.clone(), | ||||
|                 vec![ | ||||
|                     format!("__pair_fst_{}", id_pair.0), | ||||
|                     format!("__pair_snd_{}", id_pair.1), | ||||
|                 ], | ||||
|                 tipo: inner_list_type.clone(), | ||||
|                 check_last_item: false, | ||||
|             }); | ||||
|                 false, | ||||
|                 local_var_stack, | ||||
|             ); | ||||
| 
 | ||||
|             assert_vec.push(Air::Var { | ||||
|                 scope: scope.clone(), | ||||
|                 constructor: ValueConstructor::public( | ||||
|                     tipo.clone(), | ||||
|                     ValueConstructorVariant::LocalVariable { | ||||
|                         location: Span::empty(), | ||||
|                     }, | ||||
|                 ), | ||||
|                 name: format!("__pair_{new_id}"), | ||||
|                 variant_name: String::new(), | ||||
|             }); | ||||
| 
 | ||||
|             self.recursive_assert_tipo( | ||||
|             self.expect_type( | ||||
|                 &inner_pair_types[0], | ||||
|                 assert_vec, | ||||
|                 &mut pair_access_stack, | ||||
|                 &format!("__pair_fst_{}", id_pair.0), | ||||
|                 scope.clone(), | ||||
|             ); | ||||
| 
 | ||||
|             self.recursive_assert_tipo( | ||||
|             self.expect_type( | ||||
|                 &inner_pair_types[1], | ||||
|                 assert_vec, | ||||
|                 &mut pair_access_stack, | ||||
|                 &format!("__pair_snd_{}", id_pair.1), | ||||
|                 scope.clone(), | ||||
|             ); | ||||
| 
 | ||||
|             assert_vec.push(Air::Void { scope }); | ||||
|             unwrap_function_stack | ||||
|                 .anonymous_function(vec![format!("__pair_{new_id}")], pair_access_stack); | ||||
| 
 | ||||
|             expect_stack.expect_list_from_data(tipo.clone(), name, unwrap_function_stack); | ||||
| 
 | ||||
|             expect_stack.void(); | ||||
|         } else if tipo.is_list() { | ||||
|             self.used_data_assert_on_list = true; | ||||
|             let new_id = self.id_gen.next(); | ||||
|             let inner_list_type = &tipo.get_inner_types()[0]; | ||||
| 
 | ||||
|             assert_vec.push(Air::Builtin { | ||||
|                 scope: scope.clone(), | ||||
|                 func: DefaultFunction::ChooseUnit, | ||||
|                 tipo: tipo.clone(), | ||||
|                 count: DefaultFunction::ChooseUnit.arity(), | ||||
|             }); | ||||
|             let mut unwrap_function_stack = expect_stack.empty_with_scope(); | ||||
|             let mut list_access_stack = unwrap_function_stack.empty_with_scope(); | ||||
|             let mut local_var_stack = list_access_stack.empty_with_scope(); | ||||
| 
 | ||||
|             assert_vec.push(Air::Call { | ||||
|                 scope: scope.clone(), | ||||
|                 count: 2, | ||||
|                 tipo: tipo.clone(), | ||||
|             }); | ||||
|             local_var_stack.un_wrap_data(inner_list_type.clone()); | ||||
|             local_var_stack.local_var(inner_list_type.clone(), format!("__list_item_{new_id}")); | ||||
| 
 | ||||
|             assert_vec.push(Air::Var { | ||||
|                 scope: scope.clone(), | ||||
|                 constructor: ValueConstructor::public( | ||||
|                     tipo.clone(), | ||||
|                     ValueConstructorVariant::LocalVariable { | ||||
|                         location: Span::empty(), | ||||
|                     }, | ||||
|                 ), | ||||
|                 name: ASSERT_ON_LIST.to_string(), | ||||
|                 variant_name: String::new(), | ||||
|             }); | ||||
|             list_access_stack.let_assignment(format!("__list_item_{new_id}"), local_var_stack); | ||||
| 
 | ||||
|             assert_vec.push(Air::Var { | ||||
|                 scope: scope.clone(), | ||||
|                 constructor: ValueConstructor::public( | ||||
|                     tipo.clone(), | ||||
|                     ValueConstructorVariant::LocalVariable { | ||||
|                         location: Span::empty(), | ||||
|                     }, | ||||
|                 ), | ||||
|                 name: name.to_owned(), | ||||
|                 variant_name: String::new(), | ||||
|             }); | ||||
| 
 | ||||
|             assert_vec.push(Air::Fn { | ||||
|                 scope: scope.clone(), | ||||
|                 params: vec![format!("__list_item_{new_id}")], | ||||
|             }); | ||||
| 
 | ||||
|             assert_vec.push(Air::Let { | ||||
|                 scope: scope.clone(), | ||||
|                 name: format!("__list_item_{new_id}"), | ||||
|             }); | ||||
| 
 | ||||
|             assert_vec.push(Air::UnWrapData { | ||||
|                 scope: scope.clone(), | ||||
|                 tipo: inner_list_type.clone(), | ||||
|             }); | ||||
| 
 | ||||
|             assert_vec.push(Air::Var { | ||||
|                 scope: scope.clone(), | ||||
|                 constructor: ValueConstructor::public( | ||||
|                     tipo.clone(), | ||||
|                     ValueConstructorVariant::LocalVariable { | ||||
|                         location: Span::empty(), | ||||
|                     }, | ||||
|                 ), | ||||
|                 name: format!("__list_item_{new_id}"), | ||||
|                 variant_name: String::new(), | ||||
|             }); | ||||
| 
 | ||||
|             self.recursive_assert_tipo( | ||||
|             self.expect_type( | ||||
|                 inner_list_type, | ||||
|                 assert_vec, | ||||
|                 &mut list_access_stack, | ||||
|                 &format!("__list_item_{new_id}"), | ||||
|                 scope.clone(), | ||||
|             ); | ||||
| 
 | ||||
|             assert_vec.push(Air::Void { scope }); | ||||
|             unwrap_function_stack | ||||
|                 .anonymous_function(vec![format!("__list_item_{new_id}")], list_access_stack); | ||||
| 
 | ||||
|             expect_stack.expect_list_from_data(tipo.clone(), name, unwrap_function_stack); | ||||
| 
 | ||||
|             expect_stack.void(); | ||||
|         } else if tipo.is_tuple() { | ||||
|             let tuple_inner_types = tipo.get_inner_types(); | ||||
|             let mut new_id_list = vec![]; | ||||
| 
 | ||||
|             for (index, _) in tuple_inner_types.iter().enumerate() { | ||||
|                 new_id_list.push((index, self.id_gen.next())); | ||||
|             } | ||||
| 
 | ||||
|             assert_vec.push(Air::TupleAccessor { | ||||
|                 scope: scope.clone(), | ||||
|                 names: new_id_list | ||||
|                     .iter() | ||||
|                     .map(|(index, id)| format!("__tuple_index_{index}_{id}")) | ||||
|                     .collect_vec(), | ||||
|                 tipo: tipo.clone(), | ||||
|                 check_last_item: true, | ||||
|             }); | ||||
|             let mut local_var_stack = expect_stack.empty_with_scope(); | ||||
| 
 | ||||
|             assert_vec.push(Air::Var { | ||||
|                 scope: scope.clone(), | ||||
|                 constructor: ValueConstructor::public( | ||||
|                     tipo.clone(), | ||||
|                     ValueConstructorVariant::LocalVariable { | ||||
|                         location: Span::empty(), | ||||
|                     }, | ||||
|                 ), | ||||
|                 name: name.to_owned(), | ||||
|                 variant_name: String::new(), | ||||
|             }); | ||||
|             local_var_stack.local_var(tipo, name); | ||||
| 
 | ||||
|             let names = new_id_list | ||||
|                 .iter() | ||||
|                 .map(|(index, id)| format!("__tuple_index_{index}_{id}")) | ||||
|                 .collect(); | ||||
| 
 | ||||
|             expect_stack.tuple_accessor(tipo, names, true, local_var_stack); | ||||
| 
 | ||||
|             for (index, name) in new_id_list | ||||
|                 .into_iter() | ||||
|                 .map(|(index, id)| (index, format!("__tuple_index_{index}_{id}"))) | ||||
|             { | ||||
|                 self.recursive_assert_tipo( | ||||
|                     &tuple_inner_types[index], | ||||
|                     assert_vec, | ||||
|                     &name, | ||||
|                     scope.clone(), | ||||
|                 ); | ||||
|                 self.expect_type(&tuple_inner_types[index], expect_stack, &name); | ||||
|             } | ||||
|         } else { | ||||
|             let data_type = | ||||
|                 builder::lookup_data_type_by_tipo(self.data_types.clone(), &tipo).unwrap(); | ||||
| 
 | ||||
|             let new_id = self.id_gen.next(); | ||||
| 
 | ||||
|             assert_vec.push(Air::Builtin { | ||||
|                 scope: scope.clone(), | ||||
|                 func: DefaultFunction::ChooseUnit, | ||||
|                 tipo: tipo.clone(), | ||||
|                 count: DefaultFunction::ChooseUnit.arity(), | ||||
|             }); | ||||
| 
 | ||||
|             assert_vec.push(Air::When { | ||||
|                 scope: scope.clone(), | ||||
|                 tipo: tipo.clone(), | ||||
|                 subject_name: format!("__subject_{new_id}"), | ||||
|             }); | ||||
| 
 | ||||
|             assert_vec.push(Air::Var { | ||||
|                 scope: scope.clone(), | ||||
|                 constructor: ValueConstructor::public( | ||||
|                     tipo.clone(), | ||||
|                     ValueConstructorVariant::LocalVariable { | ||||
|                         location: Span::empty(), | ||||
|                     }, | ||||
|                 ), | ||||
|                 name: name.to_owned(), | ||||
|                 variant_name: String::new(), | ||||
|             }); | ||||
|             // START HERE
 | ||||
|             let mut arg_stack = expect_stack.empty_with_scope(); | ||||
|             let mut clause_stack = expect_stack.empty_with_scope(); | ||||
|             let mut when_stack = expect_stack.empty_with_scope(); | ||||
|             let mut trace_stack = expect_stack.empty_with_scope(); | ||||
|             let mut subject_stack = expect_stack.empty_with_scope(); | ||||
| 
 | ||||
|             for (index, constr) in data_type.constructors.iter().enumerate() { | ||||
|                 let arg_indices = constr | ||||
|  | @ -2691,65 +2559,50 @@ impl<'a> CodeGenerator<'a> { | |||
|                             .label | ||||
|                             .clone() | ||||
|                             .unwrap_or(format!("__field_{index}_{new_id}")); | ||||
| 
 | ||||
|                         (index, arg_name, arg.tipo.clone()) | ||||
|                     }) | ||||
|                     .collect_vec(); | ||||
| 
 | ||||
|                 assert_vec.push(Air::Clause { | ||||
|                     scope: scope.clone(), | ||||
|                     tipo: tipo.clone(), | ||||
|                     subject_name: format!("__subject_{new_id}"), | ||||
|                     complex_clause: false, | ||||
|                 }); | ||||
| 
 | ||||
|                 assert_vec.push(Air::Int { | ||||
|                     scope: scope.clone(), | ||||
|                     value: index.to_string(), | ||||
|                 }); | ||||
| 
 | ||||
|                 if !arg_indices.is_empty() { | ||||
|                     assert_vec.push(Air::FieldsExpose { | ||||
|                         scope: scope.clone(), | ||||
|                         indices: arg_indices.clone(), | ||||
|                         check_last_item: true, | ||||
|                     }); | ||||
| 
 | ||||
|                     assert_vec.push(Air::Var { | ||||
|                         scope: scope.clone(), | ||||
|                         constructor: ValueConstructor::public( | ||||
|                             tipo.clone(), | ||||
|                             ValueConstructorVariant::LocalVariable { | ||||
|                                 location: Span::empty(), | ||||
|                             }, | ||||
|                         ), | ||||
|                         name: name.to_owned(), | ||||
|                         variant_name: String::new(), | ||||
|                     }); | ||||
|                 for (index, name, tipo) in arg_indices { | ||||
|                     self.expect_type(&tipo, &mut arg_stack, &name); | ||||
|                 } | ||||
| 
 | ||||
|                 for (_, name, tipo) in arg_indices { | ||||
|                     self.recursive_assert_tipo(&tipo, assert_vec, &name, scope.clone()); | ||||
|                 } | ||||
|                 arg_stack = if !arg_indices.is_empty() { | ||||
|                     arg_stack.local_var(tipo, name); | ||||
| 
 | ||||
|                 assert_vec.push(Air::Void { | ||||
|                     scope: scope.clone(), | ||||
|                 }); | ||||
|                     let field_expose_stack = expect_stack.empty_with_scope(); | ||||
| 
 | ||||
|                     field_expose_stack.fields_expose(arg_indices.clone(), true, arg_stack); | ||||
| 
 | ||||
|                     field_expose_stack | ||||
|                 } else { | ||||
|                     arg_stack | ||||
|                 }; | ||||
| 
 | ||||
|                 arg_stack.void(); | ||||
| 
 | ||||
|                 clause_stack.clause(tipo, format!("__subject_{new_id}"), index, false, arg_stack); | ||||
|             } | ||||
| 
 | ||||
|             assert_vec.push(Air::Trace { | ||||
|                 scope: scope.clone(), | ||||
|                 tipo: tipo.clone(), | ||||
|             }); | ||||
|             trace_stack.trace(tipo.clone()); | ||||
| 
 | ||||
|             assert_vec.push(Air::String { | ||||
|                 scope: scope.clone(), | ||||
|                 value: "Constr index did not match any type variant".to_string(), | ||||
|             }); | ||||
|             trace_stack.string("Constr index did not match any type variant"); | ||||
| 
 | ||||
|             assert_vec.push(Air::ErrorTerm { | ||||
|                 scope, | ||||
|                 tipo: tipo.clone(), | ||||
|             }); | ||||
|             trace_stack.error(tipo.clone()); | ||||
| 
 | ||||
|             subject_stack.local_var(tipo, name); | ||||
| 
 | ||||
|             when_stack.when( | ||||
|                 tipo, | ||||
|                 format!("__subject_{new_id}"), | ||||
|                 subject_stack, | ||||
|                 clause_stack, | ||||
|                 trace_stack, | ||||
|             ); | ||||
| 
 | ||||
|             // Only used here
 | ||||
|             expect_stack.expect_constr_from_data(tipo.clone(), when_stack); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -2774,7 +2627,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                         && assignment_properties.value_type.is_data() | ||||
|                         && !tipo.is_data() | ||||
|                     { | ||||
|                         self.recursive_assert_pattern( | ||||
|                         self.expect_pattern( | ||||
|                             a, | ||||
|                             nested_pattern, | ||||
|                             &mut vec![Air::Var { | ||||
|  | @ -2827,7 +2680,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                         && assignment_properties.value_type.is_data() | ||||
|                         && !tipo.is_data() | ||||
|                     { | ||||
|                         self.recursive_assert_pattern( | ||||
|                         self.expect_pattern( | ||||
|                             a, | ||||
|                             nested_pattern, | ||||
|                             &mut vec![Air::Var { | ||||
|  | @ -2876,7 +2729,7 @@ impl<'a> CodeGenerator<'a> { | |||
|                         && assignment_properties.value_type.is_data() | ||||
|                         && !tipo.is_data() | ||||
|                     { | ||||
|                         self.recursive_assert_pattern( | ||||
|                         self.expect_pattern( | ||||
|                             a, | ||||
|                             nested_pattern, | ||||
|                             &mut vec![Air::Var { | ||||
|  |  | |||
|  | @ -7,53 +7,55 @@ use crate::{ | |||
|     tipo::{Type, ValueConstructor}, | ||||
| }; | ||||
| 
 | ||||
| use super::scope::Scope; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Air { | ||||
|     // Primitives
 | ||||
|     Int { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         value: String, | ||||
|     }, | ||||
|     String { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         value: String, | ||||
|     }, | ||||
|     ByteArray { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         bytes: Vec<u8>, | ||||
|     }, | ||||
|     Bool { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         value: bool, | ||||
|     }, | ||||
|     List { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         count: usize, | ||||
|         tipo: Arc<Type>, | ||||
|         tail: bool, | ||||
|     }, | ||||
|     Tuple { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|         count: usize, | ||||
|     }, | ||||
|     Void { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|     }, | ||||
|     Var { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         constructor: ValueConstructor, | ||||
|         name: String, | ||||
|         variant_name: String, | ||||
|     }, | ||||
|     // Functions
 | ||||
|     Call { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         count: usize, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     DefineFunc { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         func_name: String, | ||||
|         module_name: String, | ||||
|         params: Vec<String>, | ||||
|  | @ -61,70 +63,70 @@ pub enum Air { | |||
|         variant_name: String, | ||||
|     }, | ||||
|     Fn { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         params: Vec<String>, | ||||
|     }, | ||||
|     Builtin { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         count: usize, | ||||
|         func: DefaultFunction, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     // Operators
 | ||||
|     BinOp { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         name: BinOp, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     UnOp { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         op: UnOp, | ||||
|     }, | ||||
|     // Assignment
 | ||||
|     Let { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         name: String, | ||||
|     }, | ||||
|     UnWrapData { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     WrapData { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     AssertConstr { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         constr_index: usize, | ||||
|     }, | ||||
|     AssertBool { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         is_true: bool, | ||||
|     }, | ||||
|     // When
 | ||||
|     When { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|         subject_name: String, | ||||
|     }, | ||||
|     Clause { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|         subject_name: String, | ||||
|         complex_clause: bool, | ||||
|     }, | ||||
|     ListClause { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|         tail_name: String, | ||||
|         next_tail_name: Option<String>, | ||||
|         complex_clause: bool, | ||||
|     }, | ||||
|     WrapClause { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|     }, | ||||
|     TupleClause { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|         indices: IndexSet<(usize, String)>, | ||||
|         predefined_indices: IndexSet<(usize, String)>, | ||||
|  | @ -133,88 +135,88 @@ pub enum Air { | |||
|         complex_clause: bool, | ||||
|     }, | ||||
|     ClauseGuard { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         subject_name: String, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     ListClauseGuard { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|         tail_name: String, | ||||
|         next_tail_name: Option<String>, | ||||
|         inverse: bool, | ||||
|     }, | ||||
|     Finally { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|     }, | ||||
|     // If
 | ||||
|     If { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     // Record Creation
 | ||||
|     Record { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tag: usize, | ||||
|         tipo: Arc<Type>, | ||||
|         count: usize, | ||||
|     }, | ||||
|     RecordUpdate { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         highest_index: usize, | ||||
|         indices: Vec<(usize, Arc<Type>)>, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     // Field Access
 | ||||
|     RecordAccess { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         record_index: u64, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     FieldsExpose { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         indices: Vec<(usize, String, Arc<Type>)>, | ||||
|         check_last_item: bool, | ||||
|     }, | ||||
|     // ListAccess
 | ||||
|     ListAccessor { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|         names: Vec<String>, | ||||
|         tail: bool, | ||||
|         check_last_item: bool, | ||||
|     }, | ||||
|     ListExpose { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|         tail_head_names: Vec<(String, String)>, | ||||
|         tail: Option<(String, String)>, | ||||
|     }, | ||||
|     // Tuple Access
 | ||||
|     TupleAccessor { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         names: Vec<String>, | ||||
|         tipo: Arc<Type>, | ||||
|         check_last_item: bool, | ||||
|     }, | ||||
|     TupleIndex { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|         tuple_index: usize, | ||||
|     }, | ||||
|     // Misc.
 | ||||
|     ErrorTerm { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
|     Trace { | ||||
|         scope: Vec<u64>, | ||||
|         scope: Scope, | ||||
|         tipo: Arc<Type>, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| impl Air { | ||||
|     pub fn scope(&self) -> Vec<u64> { | ||||
|     pub fn scope(&self) -> Scope { | ||||
|         match self { | ||||
|             Air::Int { scope, .. } | ||||
|             | Air::String { scope, .. } | ||||
|  | @ -256,7 +258,7 @@ impl Air { | |||
|             | Air::Trace { scope, .. } => scope.clone(), | ||||
|         } | ||||
|     } | ||||
|     pub fn scope_mut(&mut self) -> &mut Vec<u64> { | ||||
|     pub fn scope_mut(&mut self) -> &mut Scope { | ||||
|         match self { | ||||
|             Air::Int { scope, .. } | ||||
|             | Air::String { scope, .. } | ||||
|  |  | |||
|  | @ -636,29 +636,6 @@ pub fn list_access_to_uplc( | |||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn get_common_ancestor(scope: &[u64], scope_prev: &[u64]) -> Vec<u64> { | ||||
|     let longest_length = if scope.len() >= scope_prev.len() { | ||||
|         scope.len() | ||||
|     } else { | ||||
|         scope_prev.len() | ||||
|     }; | ||||
| 
 | ||||
|     if *scope == *scope_prev { | ||||
|         return scope.to_vec(); | ||||
|     } | ||||
| 
 | ||||
|     for index in 0..longest_length { | ||||
|         if scope.get(index).is_none() { | ||||
|             return scope.to_vec(); | ||||
|         } else if scope_prev.get(index).is_none() { | ||||
|             return scope_prev.to_vec(); | ||||
|         } else if scope[index] != scope_prev[index] { | ||||
|             return scope[0..index].to_vec(); | ||||
|         } | ||||
|     } | ||||
|     vec![] | ||||
| } | ||||
| 
 | ||||
| pub fn check_when_pattern_needs( | ||||
|     pattern: &Pattern<PatternConstructor, Arc<Type>>, | ||||
|     clause_properties: &mut ClauseProperties, | ||||
|  |  | |||
|  | @ -0,0 +1,65 @@ | |||
| #[derive(Debug, Clone, Default)] | ||||
| pub struct Scope(Vec<u64>); | ||||
| 
 | ||||
| impl Scope { | ||||
|     pub fn push(&mut self, value: u64) { | ||||
|         self.0.push(value); | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_empty(&self) -> bool { | ||||
|         self.0.is_empty() | ||||
|     } | ||||
| 
 | ||||
|     pub fn replace(&mut self, pattern: &Scope, replacement: Scope) { | ||||
|         let mut result = Vec::new(); | ||||
| 
 | ||||
|         let mut index = 0; | ||||
|         let mut pattern_index = 0; | ||||
| 
 | ||||
|         let mut no_matches = true; | ||||
| 
 | ||||
|         while index < self.0.len() { | ||||
|             if self.0[index] == pattern.0[pattern_index] { | ||||
|                 if pattern_index == pattern.0.len() - 1 { | ||||
|                     no_matches = false; | ||||
|                     result.extend(replacement.0.clone()); | ||||
|                     pattern_index = 0; | ||||
|                 } else { | ||||
|                     pattern_index += 1; | ||||
|                 } | ||||
|             } else { | ||||
|                 result.push(self.0[index]); | ||||
|                 pattern_index = 0; | ||||
|             } | ||||
| 
 | ||||
|             index += 1; | ||||
|         } | ||||
| 
 | ||||
|         if no_matches { | ||||
|             replacement.0.extend(self.0); | ||||
|             self.0 = replacement.0; | ||||
|         } else { | ||||
|             self.0 = result; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn common_ancestor(&self, other: &Self) -> Scope { | ||||
|         let longest_length = self.0.len().max(other.0.len()); | ||||
| 
 | ||||
|         if *self.0 == *other.0 { | ||||
|             return self.clone(); | ||||
|         } | ||||
| 
 | ||||
|         for index in 0..longest_length { | ||||
|             if self.0.get(index).is_none() { | ||||
|                 return self.clone(); | ||||
|             } else if other.0.get(index).is_none() { | ||||
|                 return other.clone(); | ||||
|             } else if self.0[index] != other.0[index] { | ||||
|                 return Scope(self.0[0..index].to_vec()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         Scope::default() | ||||
|     } | ||||
| } | ||||
|  | @ -1,30 +1,34 @@ | |||
| use std::sync::Arc; | ||||
| 
 | ||||
| use uplc::builtins::DefaultFunction; | ||||
| use uplc::{builder::EXPECT_ON_LIST, builtins::DefaultFunction}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     tipo::{Type, ValueConstructor}, | ||||
|     ast::Span, | ||||
|     tipo::{Type, ValueConstructor, ValueConstructorVariant}, | ||||
|     IdGenerator, | ||||
| }; | ||||
| 
 | ||||
| use super::air::Air; | ||||
| use super::{air::Air, scope::Scope}; | ||||
| 
 | ||||
| /// A builder for [`Air`].
 | ||||
| pub struct AirStack<'a> { | ||||
|     pub id_gen: &'a mut IdGenerator, | ||||
|     pub scope: Vec<u64>, | ||||
|     pub scope: Scope, | ||||
|     pub air: Vec<Air>, | ||||
| } | ||||
| 
 | ||||
| impl<'a> AirStack<'a> { | ||||
|     /// Create a new [`AirStack`] with an [`IdGenerator`]
 | ||||
|     pub fn new(id_gen: &'a mut IdGenerator) -> Self { | ||||
|         AirStack { | ||||
|             id_gen, | ||||
|             scope: vec![id_gen.next()], | ||||
|             scope: Scope::default(), | ||||
|             air: vec![], | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn with_scope(id_gen: &'a mut IdGenerator, scope: Vec<u64>) -> Self { | ||||
|     /// Create a new [`AirStack`] with an [`IdGenerator`] and [`Scope`].
 | ||||
|     pub fn with_scope(id_gen: &'a mut IdGenerator, scope: Scope) -> Self { | ||||
|         AirStack { | ||||
|             id_gen, | ||||
|             scope, | ||||
|  | @ -32,22 +36,37 @@ impl<'a> AirStack<'a> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn in_new_scope(&mut self) -> Self { | ||||
|         let mut new_stack = AirStack::with_scope(&mut self.id_gen, self.scope.clone()); | ||||
| 
 | ||||
|         new_stack.new_scope(); | ||||
| 
 | ||||
|         new_stack | ||||
|     /// Create a new empty [`AirStack`] with the current stack's scope.
 | ||||
|     pub fn empty_with_scope(&mut self) -> Self { | ||||
|         AirStack::with_scope(&mut self.id_gen, self.scope.clone()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn new_scope(&mut self) { | ||||
|     /// Increment the [`Scope`]
 | ||||
|     fn new_scope(&mut self) { | ||||
|         self.scope.push(self.id_gen.next()); | ||||
|     } | ||||
| 
 | ||||
|     /// Merge two [`AirStack`]'s together while maintaining the current stack's [`Scope`]
 | ||||
|     pub fn merge(&mut self, mut other: AirStack) { | ||||
|         self.air.append(&mut other.air); | ||||
|     } | ||||
| 
 | ||||
|     pub fn merge_child(&mut self, mut other: AirStack) { | ||||
|         let pattern = self.scope.common_ancestor(&other.scope); | ||||
| 
 | ||||
|         for ir in other.air.iter_mut() { | ||||
|             ir.scope_mut().replace(&pattern, self.scope.clone()); | ||||
|         } | ||||
| 
 | ||||
|         self.merge(other); | ||||
|     } | ||||
| 
 | ||||
|     pub fn merge_children(&mut self, stacks: Vec<AirStack>) { | ||||
|         for stack in stacks { | ||||
|             self.merge_child(stack) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn sequence(&mut self, stacks: Vec<AirStack>) { | ||||
|         for stack in stacks { | ||||
|             self.merge(stack) | ||||
|  | @ -55,20 +74,26 @@ impl<'a> AirStack<'a> { | |||
|     } | ||||
| 
 | ||||
|     pub fn integer(&mut self, value: String) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Int { | ||||
|             scope: self.scope.clone(), | ||||
|             value, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     pub fn string(&mut self, value: String) { | ||||
|     pub fn string(&mut self, value: impl ToString) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::String { | ||||
|             scope: self.scope.clone(), | ||||
|             value, | ||||
|             value: value.to_string(), | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     pub fn byte_array(&mut self, bytes: Vec<u8>) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::ByteArray { | ||||
|             scope: self.scope.clone(), | ||||
|             bytes, | ||||
|  | @ -76,6 +101,8 @@ impl<'a> AirStack<'a> { | |||
|     } | ||||
| 
 | ||||
|     pub fn builtin(&mut self, func: DefaultFunction, tipo: Arc<Type>, args: Vec<AirStack>) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Builtin { | ||||
|             scope: self.scope.clone(), | ||||
|             count: args.len(), | ||||
|  | @ -83,7 +110,7 @@ impl<'a> AirStack<'a> { | |||
|             tipo, | ||||
|         }); | ||||
| 
 | ||||
|         self.sequence(args); | ||||
|         self.merge_children(args); | ||||
|     } | ||||
| 
 | ||||
|     pub fn var( | ||||
|  | @ -92,6 +119,8 @@ impl<'a> AirStack<'a> { | |||
|         name: impl ToString, | ||||
|         variant_name: impl ToString, | ||||
|     ) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Var { | ||||
|             scope: self.scope.clone(), | ||||
|             constructor, | ||||
|  | @ -100,16 +129,36 @@ impl<'a> AirStack<'a> { | |||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     pub fn local_var(&mut self, tipo: Arc<Type>, name: impl ToString) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Var { | ||||
|             scope: self.scope.clone(), | ||||
|             constructor: ValueConstructor::public( | ||||
|                 tipo, | ||||
|                 ValueConstructorVariant::LocalVariable { | ||||
|                     location: Span::empty(), | ||||
|                 }, | ||||
|             ), | ||||
|             name: name.to_string(), | ||||
|             variant_name: String::new(), | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     pub fn anonymous_function(&mut self, params: Vec<String>, body: AirStack) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Fn { | ||||
|             scope: self.scope.clone(), | ||||
|             params, | ||||
|         }); | ||||
| 
 | ||||
|         self.merge(body); | ||||
|         self.merge_child(body); | ||||
|     } | ||||
| 
 | ||||
|     pub fn list(&mut self, tipo: Arc<Type>, elements: Vec<AirStack>, tail: Option<AirStack>) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::List { | ||||
|             scope: self.scope.clone(), | ||||
|             count: elements.len(), | ||||
|  | @ -117,14 +166,16 @@ impl<'a> AirStack<'a> { | |||
|             tail: tail.is_some(), | ||||
|         }); | ||||
| 
 | ||||
|         self.sequence(elements); | ||||
|         self.merge_children(elements); | ||||
| 
 | ||||
|         if let Some(tail) = tail { | ||||
|             self.merge(tail); | ||||
|             self.merge_child(tail); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn record(&mut self, tipo: Arc<Type>, tag: usize, fields: Vec<AirStack>) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Record { | ||||
|             scope: self.scope.clone(), | ||||
|             tag, | ||||
|  | @ -132,19 +183,21 @@ impl<'a> AirStack<'a> { | |||
|             count: fields.len(), | ||||
|         }); | ||||
| 
 | ||||
|         self.sequence(fields); | ||||
|         self.merge_children(fields); | ||||
|     } | ||||
| 
 | ||||
|     pub fn call(&mut self, tipo: Arc<Type>, fun: AirStack, args: Vec<AirStack>) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Call { | ||||
|             scope: self.scope.clone(), | ||||
|             count: args.len(), | ||||
|             tipo, | ||||
|         }); | ||||
| 
 | ||||
|         self.merge(fun); | ||||
|         self.merge_child(fun); | ||||
| 
 | ||||
|         self.sequence(args); | ||||
|         self.merge_children(args); | ||||
|     } | ||||
| 
 | ||||
|     pub fn binop( | ||||
|  | @ -154,26 +207,62 @@ impl<'a> AirStack<'a> { | |||
|         left: AirStack, | ||||
|         right: AirStack, | ||||
|     ) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::BinOp { | ||||
|             scope: self.scope.clone(), | ||||
|             name, | ||||
|             tipo, | ||||
|         }); | ||||
| 
 | ||||
|         self.merge(left); | ||||
|         self.merge(right); | ||||
|         self.merge_child(left); | ||||
|         self.merge_child(right); | ||||
|     } | ||||
| 
 | ||||
|     pub fn let_assignment(&mut self, name: impl ToString, value: AirStack) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Let { | ||||
|             scope: self.scope.clone(), | ||||
|             name: name.to_string(), | ||||
|         }); | ||||
| 
 | ||||
|         self.merge(value); | ||||
|         self.merge_child(value); | ||||
|     } | ||||
| 
 | ||||
|     pub fn expect_list_from_data( | ||||
|         &mut self, | ||||
|         tipo: Arc<Type>, | ||||
|         name: impl ToString, | ||||
|         unwrap_function: AirStack, | ||||
|     ) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Builtin { | ||||
|             scope: self.scope.clone(), | ||||
|             func: DefaultFunction::ChooseUnit, | ||||
|             tipo: tipo.clone(), | ||||
|             count: DefaultFunction::ChooseUnit.arity(), | ||||
|         }); | ||||
| 
 | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Call { | ||||
|             scope: self.scope.clone(), | ||||
|             count: 2, | ||||
|             tipo, | ||||
|         }); | ||||
| 
 | ||||
|         self.local_var(tipo.clone(), EXPECT_ON_LIST); | ||||
| 
 | ||||
|         self.local_var(tipo, name); | ||||
| 
 | ||||
|         self.merge_child(unwrap_function); | ||||
|     } | ||||
| 
 | ||||
|     pub fn wrap_data(&mut self, tipo: Arc<Type>) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::WrapData { | ||||
|             scope: self.scope.clone(), | ||||
|             tipo, | ||||
|  | @ -181,9 +270,150 @@ impl<'a> AirStack<'a> { | |||
|     } | ||||
| 
 | ||||
|     pub fn un_wrap_data(&mut self, tipo: Arc<Type>) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::UnWrapData { | ||||
|             scope: self.scope.clone(), | ||||
|             tipo, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn void(&mut self) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Void { | ||||
|             scope: self.scope.clone(), | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn tuple_accessor( | ||||
|         &mut self, | ||||
|         tipo: Arc<Type>, | ||||
|         names: Vec<String>, | ||||
|         check_last_item: bool, | ||||
|         value: AirStack, | ||||
|     ) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::TupleAccessor { | ||||
|             scope: self.scope.clone(), | ||||
|             names, | ||||
|             tipo, | ||||
|             check_last_item, | ||||
|         }); | ||||
| 
 | ||||
|         self.merge_child(value); | ||||
|     } | ||||
| 
 | ||||
|     pub fn fields_expose( | ||||
|         &mut self, | ||||
|         indices: Vec<(usize, String, Arc<Type>)>, | ||||
|         check_last_item: bool, | ||||
|         value: AirStack, | ||||
|     ) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::FieldsExpose { | ||||
|             scope: self.scope.clone(), | ||||
|             indices, | ||||
|             check_last_item, | ||||
|         }); | ||||
| 
 | ||||
|         self.merge_child(value); | ||||
|     } | ||||
| 
 | ||||
|     pub fn clause( | ||||
|         &mut self, | ||||
|         tipo: Arc<Type>, | ||||
|         subject_name: impl ToString, | ||||
|         tag: usize, | ||||
|         complex_clause: bool, | ||||
|         body: AirStack, | ||||
|     ) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Clause { | ||||
|             scope: self.scope.clone(), | ||||
|             subject_name: subject_name.to_string(), | ||||
|             complex_clause, | ||||
|             tipo, | ||||
|         }); | ||||
| 
 | ||||
|         self.integer(tag.to_string()); | ||||
| 
 | ||||
|         self.merge_child(body); | ||||
|     } | ||||
| 
 | ||||
|     pub fn trace(&mut self, tipo: Arc<Type>) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Trace { | ||||
|             scope: self.scope.clone(), | ||||
|             tipo, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn error(&mut self, tipo: Arc<Type>) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::ErrorTerm { | ||||
|             scope: self.scope.clone(), | ||||
|             tipo, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn expect_constr_from_data(&mut self, tipo: Arc<Type>, when_stack: AirStack) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::Builtin { | ||||
|             scope: self.scope.clone(), | ||||
|             func: DefaultFunction::ChooseUnit, | ||||
|             tipo: tipo.clone(), | ||||
|             count: DefaultFunction::ChooseUnit.arity(), | ||||
|         }); | ||||
| 
 | ||||
|         self.merge_child(when_stack); | ||||
|     } | ||||
| 
 | ||||
|     pub fn when( | ||||
|         &mut self, | ||||
|         tipo: Arc<Type>, | ||||
|         subject_name: impl ToString, | ||||
|         subject_stack: AirStack, | ||||
|         clauses_stack: AirStack, | ||||
|         else_stack: AirStack, | ||||
|     ) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::When { | ||||
|             scope: self.scope.clone(), | ||||
|             subject_name: subject_name.to_string(), | ||||
|             tipo, | ||||
|         }); | ||||
| 
 | ||||
|         self.merge_child(subject_stack); | ||||
|         self.merge_child(clauses_stack); | ||||
|         self.merge_child(else_stack); | ||||
|     } | ||||
| 
 | ||||
|     pub fn list_accessor( | ||||
|         &mut self, | ||||
|         tipo: Arc<Type>, | ||||
|         names: Vec<String>, | ||||
|         tail: bool, | ||||
|         check_last_item: bool, | ||||
|         value: AirStack, | ||||
|     ) { | ||||
|         self.new_scope(); | ||||
| 
 | ||||
|         self.air.push(Air::ListAccessor { | ||||
|             scope: self.scope.clone(), | ||||
|             names, | ||||
|             tail, | ||||
|             check_last_item, | ||||
|             tipo, | ||||
|         }); | ||||
| 
 | ||||
|         self.merge_child(value); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ use crate::{ | |||
| pub const CONSTR_FIELDS_EXPOSER: &str = "__constr_fields_exposer"; | ||||
| pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer"; | ||||
| pub const CONSTR_GET_FIELD: &str = "__constr_get_field"; | ||||
| pub const ASSERT_ON_LIST: &str = "__assert_on_list"; | ||||
| pub const EXPECT_ON_LIST: &str = "__expect_on_list"; | ||||
| 
 | ||||
| impl Term<Name> { | ||||
|     pub fn apply(self, arg: Self) -> Self { | ||||
|  | @ -213,11 +213,11 @@ impl Term<Name> { | |||
|     } | ||||
| 
 | ||||
|     pub fn assert_on_list(self) -> Term<Name> { | ||||
|         self.lambda(ASSERT_ON_LIST.to_string()) | ||||
|         self.lambda(EXPECT_ON_LIST.to_string()) | ||||
|             .apply( | ||||
|                 Term::var(ASSERT_ON_LIST.to_string()).apply(Term::var(ASSERT_ON_LIST.to_string())), | ||||
|                 Term::var(EXPECT_ON_LIST.to_string()).apply(Term::var(EXPECT_ON_LIST.to_string())), | ||||
|             ) | ||||
|             .lambda(ASSERT_ON_LIST.to_string()) | ||||
|             .lambda(EXPECT_ON_LIST.to_string()) | ||||
|             .apply( | ||||
|                 Term::var("__list_to_check".to_string()) | ||||
|                     .delayed_choose_list( | ||||
|  | @ -227,8 +227,8 @@ impl Term<Name> { | |||
|                                 Term::head_list().apply(Term::var("__list_to_check".to_string())), | ||||
|                             ) | ||||
|                             .choose_unit( | ||||
|                                 Term::var(ASSERT_ON_LIST.to_string()) | ||||
|                                     .apply(Term::var(ASSERT_ON_LIST.to_string())) | ||||
|                                 Term::var(EXPECT_ON_LIST.to_string()) | ||||
|                                     .apply(Term::var(EXPECT_ON_LIST.to_string())) | ||||
|                                     .apply( | ||||
|                                         Term::tail_list() | ||||
|                                             .apply(Term::var("__list_to_check".to_string())), | ||||
|  | @ -238,7 +238,7 @@ impl Term<Name> { | |||
|                     ) | ||||
|                     .lambda("__check_with".to_string()) | ||||
|                     .lambda("__list_to_check".to_string()) | ||||
|                     .lambda(ASSERT_ON_LIST), | ||||
|                     .lambda(EXPECT_ON_LIST), | ||||
|             ) | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 rvcas
						rvcas