From 55dd1a1a562bd93d7c69d7c9db2d857e70c10114 Mon Sep 17 00:00:00 2001 From: microproofs Date: Tue, 25 Jul 2023 12:13:32 -0400 Subject: [PATCH] out with the old code and in with the air tree --- crates/aiken-lang/src/gen_uplc.rs | 5748 +++++++---------- crates/aiken-lang/src/gen_uplc/air.rs | 284 +- crates/aiken-lang/src/gen_uplc/builder.rs | 1917 ++---- .../src/{gen_uplc2 => gen_uplc}/tree.rs | 0 crates/aiken-lang/src/gen_uplc2.rs | 2781 -------- crates/aiken-lang/src/gen_uplc2/air.rs | 184 - crates/aiken-lang/src/gen_uplc2/builder.rs | 366 -- crates/aiken-lang/src/gen_uplc_old/air.rs | 430 ++ crates/aiken-lang/src/gen_uplc_old/builder.rs | 1 + .../src/{gen_uplc => gen_uplc_old}/scope.rs | 0 .../src/{gen_uplc => gen_uplc_old}/stack.rs | 0 crates/aiken-lang/src/lib.rs | 1 - crates/aiken-project/src/module.rs | 1 - 13 files changed, 3395 insertions(+), 8318 deletions(-) rename crates/aiken-lang/src/{gen_uplc2 => gen_uplc}/tree.rs (100%) delete mode 100644 crates/aiken-lang/src/gen_uplc2.rs delete mode 100644 crates/aiken-lang/src/gen_uplc2/air.rs delete mode 100644 crates/aiken-lang/src/gen_uplc2/builder.rs create mode 100644 crates/aiken-lang/src/gen_uplc_old/air.rs create mode 100644 crates/aiken-lang/src/gen_uplc_old/builder.rs rename crates/aiken-lang/src/{gen_uplc => gen_uplc_old}/scope.rs (100%) rename crates/aiken-lang/src/{gen_uplc => gen_uplc_old}/stack.rs (100%) diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index 948173a1..8f5c959d 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -1,4 +1,8 @@ -use std::{rc::Rc, sync::Arc}; +pub mod air; +pub mod builder; +pub mod tree; + +use std::sync::Arc; use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; @@ -7,20 +11,20 @@ use uplc::{ builder::{CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD, CONSTR_INDEX_EXPOSER, EXPECT_ON_LIST}, builtins::DefaultFunction, machine::cost_model::ExBudget, - optimize::aiken_optimize_and_intern, parser::interner::Interner, }; use crate::{ ast::{ - ArgName, AssignmentKind, BinOp, Pattern, Span, TypedArg, TypedClause, TypedDataType, - TypedFunction, TypedValidator, UnOp, + AssignmentKind, BinOp, Pattern, Span, TypedArg, TypedClause, TypedDataType, TypedFunction, + TypedValidator, UnOp, }, - builtins::{bool, data, void}, + builtins::{bool, data, int, void}, expr::TypedExpr, gen_uplc::builder::{ - find_and_replace_generics, get_arg_type_name, get_generic_id_and_type, get_variant_name, - lookup_data_type_by_tipo, + convert_opaque_type, erase_opaque_type_operations, find_and_replace_generics, + get_arg_type_name, get_generic_id_and_type, get_variant_name, monomorphize, + CodeGenFunction, SpecificClause, }, tipo::{ ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor, @@ -29,39 +33,26 @@ use crate::{ IdGenerator, }; -pub mod air; -pub mod builder; -pub mod scope; -pub mod stack; - -use air::Air; -use builder::{ - AssignmentProperties, ClauseProperties, DataTypeKey, FuncComponents, FunctionAccessKey, -}; - use self::{ - builder::{replace_opaque_type, SpecificClause}, - scope::Scope, - stack::AirStack, + air::Air, + builder::{ + convert_type_to_data, lookup_data_type_by_tipo, modify_self_calls, rearrange_clauses, + AssignmentProperties, ClauseProperties, DataTypeKey, FunctionAccessKey, UserFunction, + }, + tree::{AirExpression, AirTree, TreePath}, }; -#[derive(Clone, Debug)] -pub enum CodeGenFunction { - Function(Vec, Vec), - Link(String), -} - #[derive(Clone)] pub struct CodeGenerator<'a> { defined_functions: IndexMap, functions: IndexMap, data_types: IndexMap, module_types: IndexMap<&'a String, &'a TypeInfo>, - id_gen: Rc, needs_field_access: bool, code_gen_functions: IndexMap, zero_arg_functions: IndexMap>, tracing: bool, + id_gen: IdGenerator, } impl<'a> CodeGenerator<'a> { @@ -77,26 +68,26 @@ impl<'a> CodeGenerator<'a> { data_types, module_types, needs_field_access: false, - id_gen: IdGenerator::new().into(), code_gen_functions: IndexMap::new(), zero_arg_functions: IndexMap::new(), tracing, + id_gen: IdGenerator::new(), } } pub fn reset(&mut self) { self.code_gen_functions = IndexMap::new(); self.zero_arg_functions = IndexMap::new(); - self.id_gen = IdGenerator::new().into(); self.needs_field_access = false; self.defined_functions = IndexMap::new(); + self.id_gen = IdGenerator::new(); } pub fn insert_function( &mut self, module_name: String, function_name: String, - variant_name: String, + _variant_name: String, value: &'a TypedFunction, ) -> Option<&'a TypedFunction> { self.functions.insert( @@ -117,560 +108,344 @@ impl<'a> CodeGenerator<'a> { .. }: &TypedValidator, ) -> Program { - let mut ir_stack = AirStack::new(self.id_gen.clone()); + let air_tree_fun = self.build(&fun.body); + let mut validator_args_tree = self.check_validator_args(&fun.arguments, true, air_tree_fun); - ir_stack.noop(); + validator_args_tree = AirTree::no_op().hoist_over(validator_args_tree); + println!("{:#?}", validator_args_tree.to_vec()); - let mut args_stack = ir_stack.empty_with_scope(); - let mut body_stack = ir_stack.empty_with_scope(); - let mut unit_stack = ir_stack.empty_with_scope(); - let mut error_stack = ir_stack.empty_with_scope(); + let full_tree = self.hoist_functions_to_validator(validator_args_tree); - self.wrap_validator_args(&mut args_stack, &fun.arguments, true); + // optimizations on air tree - self.build(&fun.body, &mut body_stack); + let full_vec = full_tree.to_vec(); - unit_stack.void(); - error_stack.error(void()); + println!("FULL VEC {:#?}", full_vec); - ir_stack.merge_child(args_stack); - ir_stack.if_branch(bool(), body_stack, unit_stack); - ir_stack.merge_child(error_stack); - - let mut ir_stack = ir_stack.complete(); - - self.define_ir(&mut ir_stack); - - self.convert_opaque_type_to_inner_ir(&mut ir_stack); - - let mut term = self.uplc_code_gen(&mut ir_stack); - - if let Some(other) = other_fun { - self.reset(); - - let mut other_ir_stack = AirStack::new(self.id_gen.clone()); - - other_ir_stack.noop(); - - let mut args_stack = other_ir_stack.empty_with_scope(); - let mut body_stack = other_ir_stack.empty_with_scope(); - let mut unit_stack = other_ir_stack.empty_with_scope(); - let mut error_stack = other_ir_stack.empty_with_scope(); - - self.wrap_validator_args(&mut args_stack, &other.arguments, true); - - self.build(&other.body, &mut body_stack); - - unit_stack.void(); - error_stack.error(void()); - - other_ir_stack.merge_child(args_stack); - other_ir_stack.if_branch(bool(), body_stack, unit_stack); - other_ir_stack.merge_child(error_stack); - - let mut other_ir_stack = other_ir_stack.complete(); - - self.define_ir(&mut other_ir_stack); - - self.convert_opaque_type_to_inner_ir(&mut other_ir_stack); - - let other_term = self.uplc_code_gen(&mut other_ir_stack); - - let (spend, mint) = if other.arguments.len() > fun.arguments.len() { - (other_term, term) - } else { - (term, other_term) - }; - - term = builder::wrap_as_multi_validator(spend, mint); - - self.needs_field_access = true; - } - - term = builder::wrap_validator_args(term, params); - - self.finalize(term) + todo!() } pub fn generate_test(&mut self, test_body: &TypedExpr) -> Program { - let mut ir_stack = AirStack::new(self.id_gen.clone()); + let mut air_tree = self.build(test_body); - ir_stack.noop(); + air_tree = AirTree::no_op().hoist_over(air_tree); + println!("{:#?}", air_tree.to_vec()); - self.build(test_body, &mut ir_stack); + let full_tree = self.hoist_functions_to_validator(air_tree); - let mut ir_stack = ir_stack.complete(); + // optimizations on air tree - self.define_ir(&mut ir_stack); + let full_vec = full_tree.to_vec(); - self.convert_opaque_type_to_inner_ir(&mut ir_stack); + println!("FULL VEC {:#?}", full_vec); - let term = self.uplc_code_gen(&mut ir_stack); - - self.finalize(term) + todo!() } - fn finalize(&mut self, term: Term) -> Program { - let mut term = term; - - if self.needs_field_access { - term = term - .constr_get_field() - .constr_fields_exposer() - .constr_index_exposer(); - } - - let mut program = Program { - version: (1, 0, 0), - term, - }; - - program = aiken_optimize_and_intern(program); - - // This is very important to call here. - // If this isn't done, re-using the same instance - // of the generator will result in free unique errors - // among other unpredictable things. In fact, - // switching to a shared code generator caused some - // instability issues and we fixed it by placing this - // method here. - self.reset(); - - program + fn finalize(&mut self, _term: Term) -> Program { + todo!() } - pub(crate) fn build(&mut self, body: &TypedExpr, ir_stack: &mut AirStack) { + fn build(&mut self, body: &TypedExpr) -> AirTree { match body { - TypedExpr::UInt { value, .. } => ir_stack.integer(value.to_string()), - 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 mut stacks = Vec::new(); + TypedExpr::UInt { value, .. } => AirTree::int(value), + TypedExpr::String { value, .. } => AirTree::string(value), + TypedExpr::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()), + TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => { + let mut expressions = expressions.clone(); - for expr in expressions.iter() { - let mut stack = ir_stack.empty_with_scope(); - self.build(expr, &mut stack); - stacks.push(stack); + let mut last_exp = self.build(&expressions.pop().unwrap_or_else(|| { + unreachable!("Sequence or Pipeline should have at least one expression") + })); + + while let Some(expression) = expressions.pop() { + let exp_tree = self.build(&expression); + + last_exp = exp_tree.hoist_over(last_exp); } - - ir_stack.sequence(stacks); + last_exp } + TypedExpr::Var { constructor, name, .. - } => match &constructor.variant { - ValueConstructorVariant::ModuleConstant { literal, .. } => { - builder::constants_ir(literal, ir_stack); - } - ValueConstructorVariant::ModuleFn { - builtin: Some(builtin), - .. - } => { - ir_stack.builtin(*builtin, constructor.tipo.clone(), vec![]); - } - _ => { - ir_stack.var(constructor.clone(), name, ""); - } - }, - TypedExpr::Fn { args, body, .. } => { - let mut body_stack = ir_stack.empty_with_scope(); + } => AirTree::var(constructor.clone(), name, ""), - self.build(body, &mut body_stack); - - let params = args - .iter() + TypedExpr::Fn { args, body, .. } => AirTree::anon_func( + args.iter() .map(|arg| arg.arg_name.get_variable_name().unwrap_or("_").to_string()) - .collect(); + .collect_vec(), + self.build(body), + ), - ir_stack.anonymous_function(params, body_stack); - } TypedExpr::List { + tipo, elements, tail, + .. + } => AirTree::list( + elements.iter().map(|elem| self.build(elem)).collect_vec(), + tipo.clone(), + tail.as_ref().map(|tail| self.build(tail)), + ), + + TypedExpr::Call { + tipo, fun, args, .. + } => match fun.as_ref() { + TypedExpr::Var { + constructor: + ValueConstructor { + variant: + ValueConstructorVariant::Record { + name: constr_name, .. + }, + .. + }, + .. + } + | TypedExpr::ModuleSelect { + constructor: + ModuleValueConstructor::Record { + name: constr_name, .. + }, + .. + } => { + let Some(data_type) = lookup_data_type_by_tipo(&self.data_types, tipo) + else {unreachable!("Creating a record with no record definition.")}; + + let (constr_index, _) = data_type + .constructors + .iter() + .enumerate() + .find(|(_, dt)| &dt.name == constr_name) + .unwrap(); + + let constr_args = args.iter().map(|arg| self.build(&arg.value)).collect_vec(); + + AirTree::create_constr(constr_index, tipo.clone(), constr_args) + } + + TypedExpr::Var { + constructor: + ValueConstructor { + variant: ValueConstructorVariant::ModuleFn { builtin, .. }, + .. + }, + .. + } => { + let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")}; + + let func_args = args + .iter() + .zip(fun_arg_types) + .map(|(arg, arg_tipo)| { + let mut arg_val = self.build(&arg.value); + + if arg_tipo.is_data() && !arg.value.tipo().is_data() { + arg_val = AirTree::wrap_data(arg_val, arg.value.tipo()) + } + arg_val + }) + .collect_vec(); + + if let Some(func) = builtin { + AirTree::builtin(*func, tipo.clone(), func_args) + } else { + AirTree::call(self.build(fun.as_ref()), tipo.clone(), func_args) + } + } + + TypedExpr::ModuleSelect { + module_name, + constructor: ModuleValueConstructor::Fn { name, .. }, + .. + } => { + let type_info = self.module_types.get(module_name).unwrap(); + let value = type_info.values.get(name).unwrap(); + + let ValueConstructorVariant::ModuleFn { builtin, .. } = &value.variant else {unreachable!("Missing module function definition")}; + + let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")}; + + let func_args = args + .iter() + .zip(fun_arg_types) + .map(|(arg, arg_tipo)| { + let mut arg_val = self.build(&arg.value); + + if arg_tipo.is_data() && !arg.value.tipo().is_data() { + arg_val = AirTree::wrap_data(arg_val, arg.value.tipo()) + } + arg_val + }) + .collect_vec(); + + if let Some(func) = builtin { + AirTree::builtin(*func, tipo.clone(), func_args) + } else { + AirTree::call(self.build(fun.as_ref()), tipo.clone(), func_args) + } + } + _ => { + let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")}; + + let func_args = args + .iter() + .zip(fun_arg_types) + .map(|(arg, arg_tipo)| { + let mut arg_val = self.build(&arg.value); + + if arg_tipo.is_data() && !arg.value.tipo().is_data() { + arg_val = AirTree::wrap_data(arg_val, arg.value.tipo()) + } + arg_val + }) + .collect_vec(); + + AirTree::call(self.build(fun.as_ref()), tipo.clone(), func_args) + } + }, + TypedExpr::BinOp { + name, + left, + right, tipo, .. - } => { - let mut stacks = Vec::new(); - for element in elements { - let mut stack = ir_stack.empty_with_scope(); + } => AirTree::binop( + *name, + tipo.clone(), + self.build(left), + self.build(right), + left.tipo(), + ), - self.build(element, &mut stack); - - stacks.push(stack); - } - - let tail = tail.as_ref().map(|tail| { - let mut tail_stack = ir_stack.empty_with_scope(); - - self.build(tail, &mut tail_stack); - - tail_stack - }); - - ir_stack.list(tipo.clone(), stacks, tail); - } - TypedExpr::Call { - fun, args, tipo, .. - } => { - match &**fun { - TypedExpr::Var { constructor, .. } => match &constructor.variant { - ValueConstructorVariant::Record { - name: constr_name, .. - } => { - if let Some(data_type) = - builder::lookup_data_type_by_tipo(&self.data_types, tipo) - { - let (constr_index, _) = data_type - .constructors - .iter() - .enumerate() - .find(|(_, dt)| &dt.name == constr_name) - .unwrap(); - - let Some(fun_arg_types) = fun.tipo().arg_types() else { - unreachable!() - }; - - let mut stacks = Vec::new(); - - for (arg, func_type) in args.iter().zip(fun_arg_types) { - let mut stack = ir_stack.empty_with_scope(); - - if func_type.is_data() && !arg.value.tipo().is_data() { - stack.wrap_data(arg.value.tipo()); - } - - self.build(&arg.value, &mut stack); - - stacks.push(stack); - } - - ir_stack.record(constructor.tipo.clone(), constr_index, stacks); - - return; - } - } - ValueConstructorVariant::ModuleFn { - builtin: Some(func), - .. - } => { - let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!()}; - - let mut stacks = Vec::new(); - - for (arg, func_type) in args.iter().zip(fun_arg_types) { - let mut stack = ir_stack.empty_with_scope(); - - if func_type.is_data() && !arg.value.tipo().is_data() { - stack.wrap_data(arg.value.tipo()); - } - - self.build(&arg.value, &mut stack); - - stacks.push(stack); - } - - ir_stack.builtin(*func, tipo.clone(), stacks); - - return; - } - _ => {} - }, - TypedExpr::ModuleSelect { - constructor, - module_name, - .. - } => match constructor { - ModuleValueConstructor::Record { - name: constr_name, - tipo, - .. - } => { - if let Some(data_type) = - builder::lookup_data_type_by_tipo(&self.data_types, tipo) - { - let (constr_index, _) = data_type - .constructors - .iter() - .enumerate() - .find(|(_, dt)| &dt.name == constr_name) - .unwrap(); - - let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!()}; - - let mut stacks = Vec::new(); - - for (arg, func_type) in args.iter().zip(fun_arg_types) { - let mut stack = ir_stack.empty_with_scope(); - - if func_type.is_data() && !arg.value.tipo().is_data() { - stack.wrap_data(arg.value.tipo()); - } - - self.build(&arg.value, &mut stack); - - stacks.push(stack); - } - - ir_stack.record(tipo.clone(), constr_index, stacks); - - return; - } - } - ModuleValueConstructor::Fn { name, .. } => { - let type_info = self.module_types.get(module_name).unwrap(); - let value = type_info.values.get(name).unwrap(); - - let ValueConstructorVariant::ModuleFn { builtin, .. } = &value.variant else {unreachable!()}; - - if let Some(func) = builtin { - let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!()}; - - let mut stacks = Vec::new(); - for (arg, func_type) in args.iter().zip(fun_arg_types) { - let mut stack = ir_stack.empty_with_scope(); - - if func_type.is_data() && !arg.value.tipo().is_data() { - stack.wrap_data(arg.value.tipo()); - } - - self.build(&arg.value, &mut stack); - - stacks.push(stack); - } - - ir_stack.builtin(*func, tipo.clone(), stacks); - - return; - } - } - _ => {} - }, - _ => {} - } - - let mut fun_stack = ir_stack.empty_with_scope(); - - self.build(fun, &mut fun_stack); - - let fun_arg_types = fun.tipo().arg_types().unwrap_or_default(); - - let mut stacks = Vec::new(); - for (arg, func_type) in args.iter().zip(fun_arg_types) { - let mut stack = ir_stack.empty_with_scope(); - - if func_type.is_data() && !arg.value.tipo().is_data() { - stack.wrap_data(arg.value.tipo()); - } - - self.build(&arg.value, &mut stack); - - stacks.push(stack); - } - - ir_stack.call(tipo.clone(), fun_stack, stacks); - } - TypedExpr::BinOp { - name, left, right, .. - } => { - let mut left_stack = ir_stack.empty_with_scope(); - let mut right_stack = ir_stack.empty_with_scope(); - - self.build(left, &mut left_stack); - self.build(right, &mut right_stack); - - ir_stack.binop(*name, left.tipo(), left_stack, right_stack); - } TypedExpr::Assignment { + tipo, value, pattern, kind, - tipo, .. } => { - let mut value_stack = ir_stack.empty_with_scope(); - let mut pattern_stack = ir_stack.empty_with_scope(); + let replaced_type = convert_opaque_type(tipo, &self.data_types); - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - self.build(value, &mut value_stack); + let air_value = self.build(value); self.assignment( pattern, - &mut pattern_stack, - value_stack, + air_value, &replaced_type, AssignmentProperties { value_type: value.tipo(), kind: *kind, - remove_unused: true, - full_check: false, + remove_unused: kind.is_let(), + full_check: !tipo.is_data() && value.tipo().is_data() && kind.is_expect(), }, - ); - - ir_stack.merge(pattern_stack); + ) } + + TypedExpr::Trace { + tipo, then, text, .. + } => AirTree::trace(self.build(text), tipo.clone(), self.build(then)), + TypedExpr::When { - subject, clauses, .. + tipo, + subject, + clauses, + .. } => { - let subject_name = format!("__subject_name_{}", self.id_gen.next()); - let constr_var = format!("__constr_name_{}", self.id_gen.next()); + let mut clauses = clauses.clone(); - let subject_tipo = subject.tipo(); + if clauses.is_empty() { + unreachable!("We should have one clause at least") + } else if clauses.len() == 1 { + let last_clause = clauses.pop().unwrap(); - if clauses.len() <= 1 { - let mut value_stack = ir_stack.empty_with_scope(); - let mut pattern_stack = ir_stack.empty_with_scope(); - let mut subject_stack = ir_stack.empty_with_scope(); + let clause_then = self.build(&last_clause.then); - self.build(&clauses[0].then, &mut value_stack); + let subject_val = self.build(subject); - self.build(subject, &mut subject_stack); - - self.assignment( - &clauses[0].pattern, - &mut pattern_stack, - subject_stack, - &subject_tipo, + let assignment = self.assignment( + &last_clause.pattern, + subject_val, + tipo, AssignmentProperties { - value_type: clauses[0].then.tipo(), + value_type: subject.tipo(), kind: AssignmentKind::Let, remove_unused: false, full_check: false, }, ); - pattern_stack.merge_child(value_stack); - ir_stack.merge(pattern_stack); + assignment.hoist_over(clause_then) } else { - // TODO: go over rearrange clauses - let clauses = if subject_tipo.is_list() { - builder::rearrange_clauses(clauses.clone()) + clauses = if subject.tipo().is_list() { + rearrange_clauses(clauses) } else { - clauses.clone() + clauses }; - if let Some((last_clause, clauses)) = clauses.split_last() { - let mut pattern_stack = ir_stack.empty_with_scope(); + let last_clause = clauses.pop().unwrap(); - let mut clause_properties = ClauseProperties::init( - &subject_tipo, + let constr_var = format!( + "__when_var_span_{}_{}", + subject.location().start, + subject.location().end + ); + + let subject_name = format!( + "__subject_var_span_{}_{}", + subject.location().start, + subject.location().end + ); + + let clauses = self.handle_each_clause( + &clauses, + last_clause, + &subject.tipo(), + &mut ClauseProperties::init( + &subject.tipo(), constr_var.clone(), subject_name.clone(), - ); + ), + ); - self.handle_each_clause( - &mut pattern_stack, - &mut clause_properties, - clauses, - &subject_tipo, - ); + let constr_assign = AirTree::let_assignment(&constr_var, self.build(subject)); + let when_assign = AirTree::when( + subject_name, + tipo.clone(), + subject.tipo(), + AirTree::local_var(constr_var, subject.tipo()), + clauses, + ); - let last_pattern = &last_clause.pattern; - - let mut final_pattern_stack = ir_stack.empty_with_scope(); - let mut final_clause_stack = ir_stack.empty_with_scope(); - let mut finally_stack = ir_stack.empty_with_scope(); - - self.build(&last_clause.then, &mut final_clause_stack); - - clause_properties.final_clause = true; - - self.when_pattern( - last_pattern, - &mut final_pattern_stack, - final_clause_stack, - &subject_tipo, - &mut clause_properties, - ); - - if !matches!(last_pattern, Pattern::Tuple { .. }) { - finally_stack.finally(final_pattern_stack); - } else { - finally_stack.merge(final_pattern_stack); - } - - if clause_properties.needs_constr_var { - let mut subject_stack = ir_stack.empty_with_scope(); - - self.build(subject, &mut subject_stack); - - let mut let_stack = ir_stack.empty_with_scope(); - - let_stack.let_assignment(constr_var.clone(), subject_stack); - - ir_stack.merge(let_stack); - - let mut var_stack = ir_stack.empty_with_scope(); - let mut when_stack = ir_stack.empty_with_scope(); - - var_stack.local_var(subject_tipo.clone(), constr_var); - - when_stack.when( - subject_tipo, - subject_name, - var_stack, - pattern_stack, - finally_stack, - ); - ir_stack.merge(when_stack); - } else { - let mut subject_stack = ir_stack.empty_with_scope(); - let mut when_stack = ir_stack.empty_with_scope(); - - self.build(subject, &mut subject_stack); - - when_stack.when( - subject_tipo, - subject_name, - subject_stack, - pattern_stack, - finally_stack, - ); - ir_stack.merge(when_stack); - } - } + constr_assign.hoist_over(when_assign) } } + TypedExpr::If { branches, final_else, tipo, .. - } => { - for branch in branches.iter() { - let mut condition_stack = ir_stack.empty_with_scope(); - let mut branch_body_stack = ir_stack.empty_with_scope(); + } => AirTree::if_branches( + branches + .iter() + .map(|branch| (self.build(&branch.condition), self.build(&branch.body))) + .collect_vec(), + tipo.clone(), + self.build(final_else), + ), - self.build(&branch.condition, &mut condition_stack); - - self.build(&branch.body, &mut branch_body_stack); - - ir_stack.if_branch(tipo.clone(), condition_stack, branch_body_stack); - } - - let mut else_stack = ir_stack.empty_with_scope(); - - self.build(final_else, &mut else_stack); - - ir_stack.merge_child(else_stack); - } TypedExpr::RecordAccess { - record, + tipo, index, - tipo, + record, .. - } => { - let mut record_access_stack = ir_stack.empty_with_scope(); + } => AirTree::record_access(*index, tipo.clone(), self.build(record)), - self.build(record, &mut record_access_stack); - - ir_stack.record_access(tipo.clone(), *index, record_access_stack); - } TypedExpr::ModuleSelect { - constructor, - module_name, tipo, + module_name, + constructor, .. } => match constructor { ModuleValueConstructor::Record { @@ -680,7 +455,6 @@ impl<'a> CodeGenerator<'a> { field_map, .. } => { - assert!(arity == &0, "Wait how did you get here?"); let data_type = lookup_data_type_by_tipo(&self.data_types, tipo); let val_constructor = ValueConstructor::public( @@ -691,11 +465,16 @@ impl<'a> CodeGenerator<'a> { field_map: field_map.clone(), location: Span::empty(), module: module_name.clone(), - constructors_count: data_type.unwrap().constructors.len() as u16, + constructors_count: data_type + .unwrap_or_else(|| { + unreachable!("Created a module type without a definition?") + }) + .constructors + .len() as u16, }, ); - ir_stack.var(val_constructor, name, ""); + AirTree::var(val_constructor, name, "") } ModuleValueConstructor::Fn { name, module, .. } => { let func = self.functions.get(&FunctionAccessKey { @@ -707,1771 +486,558 @@ impl<'a> CodeGenerator<'a> { let value = type_info.values.get(name).unwrap(); if let Some(_func) = func { - ir_stack.var( + AirTree::var( ValueConstructor::public(tipo.clone(), value.variant.clone()), format!("{module}_{name}"), "", - ); + ) } else { let ValueConstructorVariant::ModuleFn { builtin: Some(builtin), .. } = &value.variant else { - unreachable!() + unreachable!("Didn't find the function definition.") }; - ir_stack.builtin(*builtin, tipo.clone(), vec![]); + AirTree::builtin(*builtin, tipo.clone(), vec![]) } } - ModuleValueConstructor::Constant { literal, .. } => { - builder::constants_ir(literal, ir_stack); - } + ModuleValueConstructor::Constant { literal, .. } => builder::constants_ir(literal), }, + + TypedExpr::Tuple { tipo, elems, .. } => AirTree::tuple( + elems.iter().map(|elem| self.build(elem)).collect_vec(), + tipo.clone(), + ), + + TypedExpr::TupleIndex { + tipo, index, tuple, .. + } => AirTree::tuple_index(*index, tipo.clone(), self.build(tuple)), + + TypedExpr::ErrorTerm { tipo, .. } => AirTree::error(tipo.clone()), + TypedExpr::RecordUpdate { - spread, args, tipo, .. + tipo, spread, args, .. } => { let mut index_types = vec![]; + let mut update_args = vec![]; + let mut highest_index = 0; - let mut update_stack = ir_stack.empty_with_scope(); - - self.build(spread, &mut update_stack); - for arg in args .iter() .sorted_by(|arg1, arg2| arg1.index.cmp(&arg2.index)) { - let mut arg_stack = update_stack.empty_with_scope(); - - self.build(&arg.value, &mut arg_stack); - - update_stack.merge(arg_stack); + let arg_val = self.build(&arg.value); if arg.index > highest_index { highest_index = arg.index; } index_types.push((arg.index, arg.value.tipo())); + update_args.push(arg_val); } - ir_stack.record_update(tipo.clone(), highest_index, index_types, update_stack); - } - TypedExpr::UnOp { value, op, .. } => { - let mut value_stack = ir_stack.empty_with_scope(); - - self.build(value, &mut value_stack); - - ir_stack.unop(*op, value_stack); - } - TypedExpr::Tuple { elems, tipo, .. } => { - let mut stacks = vec![]; - - for elem in elems { - let mut elem_stack = ir_stack.empty_with_scope(); - self.build(elem, &mut elem_stack); - stacks.push(elem_stack); - } - - ir_stack.tuple(tipo.clone(), stacks); + AirTree::record_update( + index_types, + highest_index, + tipo.clone(), + self.build(spread), + update_args, + ) } - TypedExpr::Trace { - tipo, then, text, .. - } => { - let mut text_stack = ir_stack.empty_with_scope(); - let mut then_stack = ir_stack.empty_with_scope(); - - self.build(text, &mut text_stack); - self.build(then, &mut then_stack); - - ir_stack.trace(tipo.clone()); - ir_stack.merge_child(text_stack); - ir_stack.merge_child(then_stack); - } - - TypedExpr::TupleIndex { index, tuple, .. } => { - let mut tuple_stack = ir_stack.empty_with_scope(); - - self.build(tuple, &mut tuple_stack); - - ir_stack.tuple_index(tuple.tipo(), *index, tuple_stack); - } - - TypedExpr::ErrorTerm { tipo, .. } => { - ir_stack.error(tipo.clone()); - } + TypedExpr::UnOp { value, op, .. } => AirTree::unop(*op, self.build(value)), } } - fn handle_each_clause( - &mut self, - ir_stack: &mut AirStack, - clause_properties: &mut ClauseProperties, - clauses: &[TypedClause], - subject_type: &Arc, - ) { - for (index, clause) in clauses.iter().enumerate() { - // holds when clause pattern Air - let mut clause_pattern_stack = ir_stack.empty_with_scope(); - let mut clause_then_stack = ir_stack.empty_with_scope(); - - // reset complex clause setting per clause back to default - clause_properties.complex_clause = false; - - self.build(&clause.then, &mut clause_then_stack); - - if let Some(clause_guard) = &clause.guard { - let mut clause_guard_stack = ir_stack.empty_with_scope(); - let mut clause_guard_condition = ir_stack.empty_with_scope(); - - clause_properties.complex_clause = true; - - let clause_guard_name = format!("__clause_guard_{}", self.id_gen.next()); - - builder::handle_clause_guard(clause_guard, &mut clause_guard_condition); - - clause_guard_stack - .let_assignment(clause_guard_name.clone(), clause_guard_condition); - - let mut condition_stack = ir_stack.empty_with_scope(); - - condition_stack.bool(true); - - clause_guard_stack.clause_guard( - clause_guard_name, - bool(), - condition_stack, - clause_then_stack, - ); - - clause_then_stack = clause_guard_stack; - } - - let prev_clause_properties = clause_properties.clone(); - - // deal with clause pattern and then itself - self.when_pattern( - &clause.pattern, - &mut clause_pattern_stack, - clause_then_stack, - subject_type, - clause_properties, - ); - - match clause_properties { - ClauseProperties { - original_subject_name, - specific_clause: SpecificClause::ConstrClause, - .. - } => { - let subject_name = original_subject_name.clone(); - - if clause.pattern.is_var() || clause.pattern.is_discard() { - ir_stack.wrap_clause(clause_pattern_stack); - } else { - let data_type = - builder::lookup_data_type_by_tipo(&self.data_types, subject_type); - - if let Some(data_type) = data_type { - if data_type.constructors.len() > 1 { - ir_stack.clause( - subject_type.clone(), - subject_name, - clause_properties.complex_clause, - clause_pattern_stack, - ); - } else { - let mut condition_stack = ir_stack.empty_with_scope(); - - condition_stack.integer(0.to_string()); - - condition_stack.merge_child(clause_pattern_stack); - - ir_stack.clause( - subject_type.clone(), - subject_name, - clause_properties.complex_clause, - condition_stack, - ); - } - } else { - ir_stack.clause( - subject_type.clone(), - subject_name, - clause_properties.complex_clause, - clause_pattern_stack, - ); - } - } - } - ClauseProperties { - original_subject_name, - specific_clause: SpecificClause::ListClause { current_index, .. }, - .. - } => { - let original_subject_name = original_subject_name.clone(); - - let prev_index = *current_index; - - let elements_count_and_has_tail = - builder::get_list_elements_len_and_tail(&clause.pattern); - - if let Some((current_clause_index, has_tail)) = elements_count_and_has_tail { - let subject_name = if current_clause_index == 0 { - original_subject_name.clone() - } else { - format!("__tail_{}", current_clause_index - 1) - }; - - // If current clause has already exposed all needed list items then no need to expose the - // same items again. - if current_clause_index as i64 - i64::from(has_tail) == prev_index { - ir_stack.wrap_clause(clause_pattern_stack); - } else { - let next_elements_count_and_has_tail = if index == clauses.len() - 1 { - None - } else { - builder::get_list_elements_len_and_tail( - &clauses - .get(index + 1) - .unwrap_or_else(|| { - unreachable!( - "We checked length how are we out of bounds" - ) - }) - .pattern, - ) - }; - - let next_tail = if let Some((next_elements_len, _)) = - next_elements_count_and_has_tail - { - if next_elements_len == current_clause_index { - None - } else { - Some(format!("__tail_{current_clause_index}")) - } - } else { - None - }; - - //mutate current index if we use list clause - *current_index = current_clause_index as i64; - - ir_stack.list_clause( - subject_type.clone(), - subject_name, - next_tail, - clause_properties.complex_clause, - clause_pattern_stack, - ); - } - } else { - ir_stack.wrap_clause(clause_pattern_stack); - } - } - ClauseProperties { - original_subject_name, - specific_clause: - SpecificClause::TupleClause { - defined_tuple_indices, - }, - .. - } => { - let ClauseProperties { specific_clause: SpecificClause::TupleClause { defined_tuple_indices: prev_defined_tuple_indices}, ..} = prev_clause_properties - else { - unreachable!() - }; - - let subject_name = original_subject_name.clone(); - - let indices_to_define = defined_tuple_indices - .difference(&prev_defined_tuple_indices) - .cloned() - .collect(); - - ir_stack.tuple_clause( - subject_type.clone(), - subject_name, - indices_to_define, - prev_defined_tuple_indices, - clause_properties.complex_clause || (!clause_properties.final_clause), - clause_pattern_stack, - ); - } - } - } - } - - fn when_pattern( + pub fn assignment( &mut self, pattern: &Pattern>, - pattern_stack: &mut AirStack, - value_stack: AirStack, - tipo: &Type, - clause_properties: &mut ClauseProperties, - ) { - match pattern { - Pattern::Int { value, .. } => { - pattern_stack.integer(value.clone()); + mut value: AirTree, + tipo: &Arc, + props: AssignmentProperties, + ) -> AirTree { + if props.value_type.is_data() && props.kind.is_expect() && !tipo.is_data() { + value = AirTree::unwrap_data(value, tipo.clone()); + } else if !props.value_type.is_data() && tipo.is_data() { + value = AirTree::wrap_data(value, tipo.clone()); + } - pattern_stack.merge_child(value_stack); + match pattern { + Pattern::Int { + value: expected_int, + location, + .. + } => { + if props.kind.is_expect() { + let name = format!( + "__expected_by_{}_span_{}_{}", + expected_int, location.start, location.end + ); + let assignment = AirTree::let_assignment(&name, value); + + let expect = AirTree::binop( + BinOp::Eq, + bool(), + AirTree::int(expected_int), + AirTree::local_var(name, int()), + int(), + ); + AirTree::assert_bool(true, assignment.hoist_over(expect)) + } else { + unreachable!("Code Gen should never reach here") + } } Pattern::Var { name, .. } => { - pattern_stack.void(); + if props.full_check { + let mut index_map = IndexMap::new(); + let non_opaque_tipo = convert_opaque_type(tipo, &self.data_types); - let mut var_stack = pattern_stack.empty_with_scope(); + let assignment = AirTree::let_assignment(name, value); + let val = AirTree::local_var(name, tipo.clone()); - var_stack.local_var( - tipo.clone().into(), - match clause_properties { - ClauseProperties { - clause_var_name, - needs_constr_var, - specific_clause: SpecificClause::ConstrClause, - .. - } => { - *needs_constr_var = true; - clause_var_name - } - ClauseProperties { - original_subject_name, - .. - } => original_subject_name, - }, - ); + if tipo.is_primitive() { + AirTree::let_assignment(name, assignment.hoist_over(val)) + } else { + let expect = self.expect_type_assign( + &non_opaque_tipo, + val.clone(), + &mut index_map, + pattern.location(), + ); - pattern_stack.let_assignment(name, var_stack); - - pattern_stack.merge_child(value_stack); + let assign_expect = AirTree::let_assignment("_", expect); + AirTree::let_assignment( + name, + assignment.hoist_over(assign_expect.hoist_over(val)), + ) + } + } else { + AirTree::let_assignment(name, value) + } } Pattern::Assign { name, pattern, .. } => { - let mut new_stack = pattern_stack.empty_with_scope(); + let inner_pattern = + self.assignment(pattern, AirTree::local_var(name, tipo.clone()), tipo, props); + let assign = AirTree::let_assignment(name, value); - new_stack.local_var( - tipo.clone().into(), - match clause_properties { - ClauseProperties { - clause_var_name, - needs_constr_var, - specific_clause: SpecificClause::ConstrClause, - .. - } => { - *needs_constr_var = true; - clause_var_name - } - ClauseProperties { - original_subject_name, - .. - } => original_subject_name, - }, - ); - - let mut let_stack = pattern_stack.empty_with_scope(); - - let_stack.let_assignment(name.clone(), new_stack); - - let_stack.merge_child(value_stack); - - self.when_pattern(pattern, pattern_stack, let_stack, tipo, clause_properties); + AirTree::UnhoistedSequence(vec![assign, inner_pattern]) } - Pattern::Discard { .. } => { - pattern_stack.void(); - pattern_stack.merge_child(value_stack); + Pattern::Discard { name, .. } => { + if props.full_check { + let name = &format!("__discard_expect_{}", name); + let mut index_map = IndexMap::new(); + let tipo = convert_opaque_type(tipo, &self.data_types); + let assignment = AirTree::let_assignment(name, value); + let val = AirTree::local_var(name, tipo.clone()); + if tipo.is_primitive() { + AirTree::let_assignment(name, assignment.hoist_over(val)) + } else { + let expect = self.expect_type_assign( + &tipo, + val.clone(), + &mut index_map, + pattern.location(), + ); + + let assign_expect = AirTree::let_assignment("_", expect); + AirTree::let_assignment( + name, + assignment.hoist_over(assign_expect.hoist_over(val)), + ) + } + } else if !props.remove_unused { + AirTree::let_assignment(name, value) + } else { + AirTree::no_op() + } } Pattern::List { elements, tail, .. } => { - for element in elements { - builder::check_when_pattern_needs(element, clause_properties); - } + assert!(tipo.is_list()); + assert!(props.kind.is_expect()); + let list_elem_types = tipo.get_inner_types(); - if let Some(tail) = tail { - builder::check_when_pattern_needs(tail, clause_properties); - } + let list_elem_type = list_elem_types + .get(0) + .unwrap_or_else(|| unreachable!("No list element type?")); - clause_properties.needs_constr_var = false; + let mut elems = elements + .iter() + .enumerate() + .map(|(index, elem)| { + let elem_name = match elem { + Pattern::Var { name, .. } => name.to_string(), + Pattern::Assign { name, .. } => name.to_string(), + Pattern::Discard { name, .. } => { + if props.full_check { + format!("__discard_{}", name) + } else { + "_".to_string() + } + } + _ => format!( + "elem_{}_span_{}_{}", + index, + elem.location().start, + elem.location().end + ), + }; - let mut void_stack = pattern_stack.empty_with_scope(); + let val = AirTree::local_var(&elem_name, list_elem_type.clone()); - void_stack.void(); + ( + elem_name, + self.assignment( + elem, + val, + list_elem_type, + AssignmentProperties { + value_type: list_elem_type.clone(), + kind: props.kind, + remove_unused: true, + full_check: props.full_check, + }, + ), + ) + }) + .collect_vec(); - pattern_stack.merge(void_stack); + // If Some then push tail onto elems + tail.iter().for_each(|tail| { + let tail_name = match tail.as_ref() { + Pattern::Var { name, .. } => name.to_string(), + Pattern::Assign { name, .. } => name.to_string(), + Pattern::Discard { name, .. } => { + if props.kind.is_expect() + && props.value_type.is_data() + && !tipo.is_data() + { + format!("__discard_{}", name) + } else { + "_".to_string() + } + } + _ => format!( + "tail_span_{}_{}", + tail.location().start, + tail.location().end + ), + }; - self.expose_elements(pattern, pattern_stack, value_stack, clause_properties, tipo); + let val = AirTree::local_var(&tail_name, tipo.clone()); + + elems.push(( + tail_name, + self.assignment( + tail, + val, + tipo, + AssignmentProperties { + value_type: tipo.clone(), + kind: props.kind, + remove_unused: true, + full_check: props.full_check, + }, + ), + )); + }); + + let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec(); + + let list_access = if elements.is_empty() { + AirTree::let_assignment("_", AirTree::list_empty(value)) + } else { + AirTree::list_access(names, tipo.clone(), tail.is_some(), tail.is_none(), value) + }; + + let mut sequence = vec![list_access]; + + sequence.append(&mut elems.into_iter().map(|(_, elem)| elem).collect_vec()); + + AirTree::UnhoistedSequence(sequence) } Pattern::Constructor { arguments, - name: constr_name, + constructor, + name, .. } => { - let mut temp_clause_properties = clause_properties.clone(); - temp_clause_properties.needs_constr_var = false; + let mut sequence = vec![]; if tipo.is_bool() { - pattern_stack.bool(constr_name == "True"); + assert!(props.kind.is_expect()); + + AirTree::assert_bool(name == "True", value) + } else if tipo.is_void() { + AirTree::let_assignment("_", value) } else { - for arg in arguments { - builder::check_when_pattern_needs(&arg.value, &mut temp_clause_properties); - } - - // find data type definition - let data_type = - builder::lookup_data_type_by_tipo(&self.data_types, tipo).unwrap(); - - let (index, _) = data_type - .constructors - .iter() - .enumerate() - .find(|(_, dt)| &dt.name == constr_name) - .unwrap(); - - let mut new_stack = pattern_stack.empty_with_scope(); - - new_stack - .local_var(tipo.clone().into(), temp_clause_properties.clause_var_name); - - // if only one constructor, no need to check - if data_type.constructors.len() > 1 || clause_properties.final_clause { - // push constructor Index - let mut tag_stack = pattern_stack.empty_with_scope(); - tag_stack.integer(index.to_string()); - pattern_stack.merge_child(tag_stack); - } - - if temp_clause_properties.needs_constr_var { - self.expose_elements( - pattern, - pattern_stack, - new_stack, - clause_properties, - tipo, - ); - } else { - let empty_stack = pattern_stack.empty_with_scope(); - - self.expose_elements( - pattern, - pattern_stack, - empty_stack, - clause_properties, - tipo, - ); - } - } - - pattern_stack.merge_child(value_stack); - - // unify clause properties - clause_properties.complex_clause = - clause_properties.complex_clause || temp_clause_properties.complex_clause; - - clause_properties.needs_constr_var = - clause_properties.needs_constr_var || temp_clause_properties.needs_constr_var; - } - Pattern::Tuple { elems, .. } => { - for elem in elems { - builder::check_when_pattern_needs(elem, clause_properties); - } - - clause_properties.needs_constr_var = false; - - let temp = pattern_stack.empty_with_scope(); - - self.expose_elements(pattern, pattern_stack, temp, clause_properties, tipo); - - pattern_stack.merge_child(value_stack); - } - } - - // final clause can not be complex - if clause_properties.final_clause { - clause_properties.complex_clause = false; - } - } - - fn expose_elements( - &mut self, - pattern: &Pattern>, - pattern_stack: &mut AirStack, - value_stack: AirStack, - clause_properties: &mut ClauseProperties, - tipo: &Type, - ) { - match pattern { - Pattern::Int { .. } => unreachable!(), - Pattern::Var { .. } => unreachable!(), - Pattern::Assign { .. } => todo!("Nested assign not yet implemented"), - Pattern::Discard { .. } => { - pattern_stack.void(); - - pattern_stack.merge_child(value_stack); - } - Pattern::List { elements, tail, .. } => { - let mut names = vec![]; - let mut nested_pattern = pattern_stack.empty_with_scope(); - let items_type = &tipo.get_inner_types()[0]; - - for element in elements { - let name = self.nested_pattern_ir_and_label( - element, - &mut nested_pattern, - items_type, - clause_properties.final_clause, - ); - - names.push(name.unwrap_or_else(|| "_".to_string())) - } - - let mut tail_name = String::new(); - - if let Some(tail) = tail { - match &**tail { - Pattern::Var { name, .. } => { - tail_name = name.clone(); - } - Pattern::Discard { .. } => { - tail_name = "_".to_string(); - } - _ => unreachable!("Patterns in tail of list should not allow this"), - } - } - - let tail_head_names = names - .iter() - .enumerate() - .filter(|(_, name)| *name != &"_".to_string()) - .map(|(index, name)| { - if index == 0 { - ( - clause_properties.original_subject_name.clone(), - name.clone(), - ) - } else { - (format!("__tail_{}", index - 1), name.clone()) - } - }) - .collect_vec(); - - let tail_var = if elements.len() == 1 || elements.is_empty() { - clause_properties.original_subject_name.clone() - } else { - format!("__tail_{}", elements.len() - 2) - }; - - let tail = if &tail_name == "_" || tail_name.is_empty() { - None - } else { - Some((tail_var, tail_name)) - }; - - if tail.is_some() || !tail_head_names.is_empty() { - pattern_stack.list_expose( - tipo.clone().into(), - tail_head_names, - tail, - nested_pattern, - ); - } - - pattern_stack.merge_child(value_stack); - } - Pattern::Constructor { - is_record, - name: constr_name, - arguments, - constructor, - tipo, - .. - } => { - let data_type = builder::lookup_data_type_by_tipo(&self.data_types, tipo).unwrap(); - - let constructor_type = data_type - .constructors - .iter() - .find(|dt| &dt.name == constr_name) - .unwrap(); - let mut nested_pattern = pattern_stack.empty_with_scope(); - - if *is_record { - let field_map = match constructor { - PatternConstructor::Record { field_map, .. } => field_map.clone().unwrap(), - }; - - let mut type_map: IndexMap> = IndexMap::new(); - - for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { - let label = constructor_type.arguments[index].label.clone().unwrap(); - let field_type = arg.clone(); - - type_map.insert(label, field_type); - } - - let arguments_index = arguments - .iter() - .enumerate() - .map(|(index, item)| { - let label = item.label.clone().unwrap_or_default(); - - let field_index = field_map - .fields - .get(&label) - .map(|(index, _)| index) - .unwrap_or(&index); - - let var_name = self.nested_pattern_ir_and_label( - &item.value, - &mut nested_pattern, - type_map.get(&label).unwrap_or( - &Type::App { - public: true, - module: "".to_string(), - name: "Discard".to_string(), - args: vec![], - } - .into(), - ), - clause_properties.final_clause, - ); - - var_name.map_or( - (label.clone(), "_".to_string(), *field_index), - |var_name| (label, var_name, *field_index), - ) - }) - .sorted_by(|item1, item2| item1.2.cmp(&item2.2)) - .collect::>(); - - let indices = arguments_index - .iter() - .map(|(label, var_name, index)| { - let field_type = type_map - .get(label) - .unwrap_or_else(|| type_map.get_index(*index).unwrap().1); - (*index, var_name.clone(), field_type.clone()) - }) - .collect_vec(); - - if indices.is_empty() { - pattern_stack.merge_child(value_stack); - } else { - pattern_stack.fields_expose(indices, false, value_stack); - } - } else { - let mut type_map: IndexMap> = IndexMap::new(); - - for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { - let field_type = arg.clone(); - - type_map.insert(index, field_type); - } - - let arguments_index = arguments - .iter() - .enumerate() - .map(|(index, item)| { - let var_name = self.nested_pattern_ir_and_label( - &item.value, - &mut nested_pattern, - type_map.get(&index).unwrap(), - clause_properties.final_clause, - ); - - var_name.map_or(("_".to_string(), index), |var_name| (var_name, index)) - }) - .collect::>(); - - let indices = arguments_index - .iter() - .map(|(name, index)| { - let field_type = type_map.get(index).unwrap(); - - (*index, name.clone(), field_type.clone()) - }) - .collect_vec(); - - if indices.is_empty() { - pattern_stack.merge_child(value_stack); - } else { - pattern_stack.fields_expose(indices, false, value_stack); - } - } - - pattern_stack.merge_child(nested_pattern); - } - Pattern::Tuple { elems, .. } => { - let mut nested_pattern = pattern_stack.empty_with_scope(); - let items_type = &tipo.get_inner_types(); - - let names = elems - .iter() - .enumerate() - .filter_map(|(index, element)| { - let name = self.nested_pattern_ir_and_label( - element, - &mut nested_pattern, - &items_type[index], - clause_properties.final_clause, - ); - - name.map(|name| (name, index)) - }) - .collect_vec(); - - let mut defined_indices = match clause_properties.clone() { - ClauseProperties { - specific_clause: - SpecificClause::TupleClause { - defined_tuple_indices, - }, - .. - } => defined_tuple_indices, - _ => unreachable!(), - }; - - let mut previous_defined_names = vec![]; - for (name, index) in names.clone() { - if let Some(defined_index) = defined_indices - .iter() - .find(|(defined_index, _)| *defined_index == index) - { - previous_defined_names.push(defined_index.clone()); - } else { - defined_indices.insert((index, name)); - } - } - - for (index, name) in previous_defined_names { - let mut var_stack = pattern_stack.empty_with_scope(); - - let new_name = names - .iter() - .find(|(_, current_index)| *current_index == index) - .map(|(new_name, _)| new_name) - .unwrap(); - - let pattern_type = &tipo.get_inner_types()[index]; - - var_stack.local_var(pattern_type.clone(), name); - - pattern_stack.let_assignment(new_name, var_stack); - } - - match clause_properties { - ClauseProperties { - specific_clause: - SpecificClause::TupleClause { - defined_tuple_indices, - }, - .. - } => { - *defined_tuple_indices = defined_indices; - } - _ => unreachable!(), - } - - pattern_stack.merge_child(nested_pattern); - pattern_stack.merge_child(value_stack); - } - } - } - - fn nested_pattern_ir_and_label( - &mut self, - pattern: &Pattern>, - pattern_stack: &mut AirStack, - pattern_type: &Type, - final_clause: bool, - ) -> Option { - match pattern { - Pattern::Var { name, .. } => Some(name.clone()), - Pattern::Discard { .. } => None, - pattern @ Pattern::List { elements, tail, .. } => { - let item_name = format!("__list_item_id_{}", self.id_gen.next()); - let new_tail_name = "__tail".to_string(); - - if elements.is_empty() { - assert!( - !final_clause, - "Why do you have a last clause with [] in it?" - ); - - let mut void_stack = pattern_stack.empty_with_scope(); - - void_stack.void(); - - pattern_stack.list_clause_guard( - pattern_type.clone().into(), - item_name.clone(), - None, - false, - void_stack, - ); - } else { - for (index, _) in elements.iter().enumerate() { - let prev_tail_name = if index == 0 { - item_name.clone() - } else { - format!("{}_{}", new_tail_name, index - 1) - }; - - let mut clause_properties = ClauseProperties { - clause_var_name: item_name.clone(), - needs_constr_var: false, - complex_clause: false, - original_subject_name: item_name.clone(), - specific_clause: SpecificClause::ListClause { - current_index: index as i64, - defined_tails: vec![], - }, - final_clause, - }; - - let tail_name = format!("{new_tail_name}_{index}"); - - if elements.len() - 1 == index { - if tail.is_some() { - let mut elements_stack = pattern_stack.empty_with_scope(); - - self.when_pattern( - pattern, - &mut elements_stack, - pattern_stack.empty_with_scope(), - pattern_type, - &mut clause_properties, - ); - - if !final_clause { - pattern_stack.list_clause_guard( - pattern_type.clone().into(), - prev_tail_name, - None, - true, - elements_stack, - ); - } else { - pattern_stack.finally(elements_stack) - } - } else { - let mut elements_stack = pattern_stack.empty_with_scope(); - - let mut void_stack = pattern_stack.empty_with_scope(); - - void_stack.void(); - - self.when_pattern( - pattern, - &mut elements_stack, - pattern_stack.empty_with_scope(), - pattern_type, - &mut clause_properties, - ); - - if !final_clause { - void_stack.list_clause_guard( - pattern_type.clone().into(), - &tail_name, - None, - false, - elements_stack, - ); - - pattern_stack.list_clause_guard( - pattern_type.clone().into(), - prev_tail_name, - Some(tail_name), - true, - void_stack, - ); - } else { - pattern_stack.finally(elements_stack); - } - } - } else if !final_clause { - let mut void_stack = pattern_stack.empty_with_scope(); - - void_stack.void(); - - pattern_stack.list_clause_guard( - pattern_type.clone().into(), - prev_tail_name, - Some(tail_name), - true, - void_stack, - ); - }; - } - } - - Some(item_name) - } - pattern @ Pattern::Constructor { - tipo, - name: constr_name, - .. - } => { - let id = self.id_gen.next(); - let constr_var_name = format!("{constr_name}_{id}"); - - let mut when_stack = pattern_stack.empty_with_scope(); - - let mut clause_properties = ClauseProperties { - clause_var_name: constr_var_name.clone(), - needs_constr_var: false, - complex_clause: false, - original_subject_name: constr_var_name.clone(), - final_clause, - specific_clause: SpecificClause::ConstrClause, - }; - - self.when_pattern( - pattern, - &mut when_stack, - pattern_stack.empty_with_scope(), - tipo, - &mut clause_properties, - ); - - let data_type = builder::lookup_data_type_by_tipo(&self.data_types, tipo); - if final_clause { - pattern_stack.finally(when_stack); - } else if let Some(data_type) = data_type { - if data_type.constructors.len() > 1 { - let empty_stack = pattern_stack.empty_with_scope(); - pattern_stack.clause_guard( - constr_var_name.clone(), - tipo.clone(), - when_stack, - empty_stack, - ); - } else { - pattern_stack.merge_child(when_stack); - } - } else { - let empty_stack = pattern_stack.empty_with_scope(); - pattern_stack.clause_guard( - constr_var_name.clone(), - tipo.clone(), - when_stack, - empty_stack, - ) - } - - Some(constr_var_name) - } - a @ Pattern::Tuple { .. } => { - let item_name = format!("__tuple_item_id_{}", self.id_gen.next()); - - let mut clause_properties = ClauseProperties { - clause_var_name: item_name.clone(), - needs_constr_var: false, - complex_clause: false, - original_subject_name: item_name.clone(), - specific_clause: SpecificClause::TupleClause { - defined_tuple_indices: IndexSet::new(), - }, - final_clause, - }; - - let mut inner_pattern_stack = pattern_stack.empty_with_scope(); - - self.when_pattern( - a, - &mut inner_pattern_stack, - pattern_stack.empty_with_scope(), - pattern_type, - &mut clause_properties, - ); - - let defined_indices = match clause_properties.clone() { - ClauseProperties { - specific_clause: - SpecificClause::TupleClause { - defined_tuple_indices, - .. - }, - .. - } => defined_tuple_indices, - _ => unreachable!(), - }; - - pattern_stack.tuple_clause( - pattern_type.clone().into(), - clause_properties.original_subject_name, - defined_indices, - IndexSet::new(), - false, - inner_pattern_stack, - ); - - Some(item_name) - } - Pattern::Assign { name, pattern, .. } => { - let inner_name = self.nested_pattern_ir_and_label( - pattern, - pattern_stack, - pattern_type, - final_clause, - ); - - let mut var_stack = pattern_stack.empty_with_scope(); - var_stack.local_var(pattern_type.clone().into(), inner_name.clone().unwrap()); - - pattern_stack.let_assignment(name, var_stack); - - inner_name - } - Pattern::Int { .. } => { - let error_message = "Nested pattern-match on integers isn't implemented yet. Use when clause-guard as an alternative, or break down the pattern."; - todo!("{}", error_message) - } - } - } - - fn assignment( - &mut self, - pattern: &Pattern>, - pattern_stack: &mut AirStack, - value_stack: AirStack, - tipo: &Type, - assignment_properties: AssignmentProperties, - ) { - let mut value_stack = if assignment_properties.value_type.is_data() - && !tipo.is_data() - && matches!(assignment_properties.kind, AssignmentKind::Expect) - { - let mut wrap_stack = pattern_stack.empty_with_scope(); - wrap_stack.un_wrap_data(tipo.clone().into()); - 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.empty_with_scope(); - wrap_stack.wrap_data(assignment_properties.value_type.clone()); - wrap_stack.merge_child(value_stack); - wrap_stack - } else { - value_stack - }; - - match pattern { - Pattern::Int { .. } => todo!("Pattern match with integer assignment not supported"), - Pattern::Var { name, .. } => { - 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 expect_stack = pattern_stack.empty_with_scope(); - - self.expect_pattern( - pattern, - &mut expect_stack, - expect_value_stack, - tipo, - assignment_properties, - ); - - pattern_stack.merge(expect_stack); - } - } - Pattern::Assign { name, pattern, .. } => { - let mut inner_value_stack = pattern_stack.empty_with_scope(); - inner_value_stack.var( - ValueConstructor::public( - tipo.clone().into(), - ValueConstructorVariant::LocalVariable { - location: Span::empty(), - }, - ), - name, - "", - ); - pattern_stack.let_assignment(name, value_stack); - - self.assignment( - pattern, - pattern_stack, - inner_value_stack, - tipo, - assignment_properties, - ); - } - Pattern::Discard { .. } => { - if matches!(assignment_properties.kind, AssignmentKind::Expect) - && assignment_properties.value_type.is_data() - && !tipo.is_data() - { - self.expect_pattern( - pattern, - pattern_stack, - value_stack, - tipo, - assignment_properties, - ); - } else { - pattern_stack.let_assignment("_", value_stack); - } - } - list @ Pattern::List { .. } => { - if matches!(assignment_properties.kind, AssignmentKind::Expect) - && assignment_properties.value_type.is_data() - && !tipo.is_data() - { - self.expect_pattern( - list, - pattern_stack, - value_stack, - tipo, - assignment_properties, - ); - } else { - self.pattern_ir( - list, - pattern_stack, - value_stack, - tipo, - assignment_properties, - ); - } - } - constr @ Pattern::Constructor { .. } => { - if matches!(assignment_properties.kind, AssignmentKind::Expect) - && assignment_properties.value_type.is_data() - && !tipo.is_data() - { - self.expect_pattern( - constr, - pattern_stack, - value_stack, - tipo, - assignment_properties, - ); - } else { - self.pattern_ir( - constr, - pattern_stack, - value_stack, - tipo, - assignment_properties, - ); - } - } - tuple @ Pattern::Tuple { .. } => { - if matches!(assignment_properties.kind, AssignmentKind::Expect) - && assignment_properties.value_type.is_data() - && !tipo.is_data() - { - self.expect_pattern( - tuple, - pattern_stack, - value_stack, - tipo, - assignment_properties, - ); - } else { - self.pattern_ir( - tuple, - pattern_stack, - value_stack, - tipo, - assignment_properties, - ); - } - } - } - } - - fn pattern_ir( - &mut self, - pattern: &Pattern>, - pattern_stack: &mut AirStack, - value_stack: AirStack, - tipo: &Type, - assignment_properties: AssignmentProperties, - ) { - match pattern { - Pattern::Int { .. } => unreachable!("Pattern Integer"), - Pattern::Var { .. } => unreachable!("Pattern Var"), - Pattern::Assign { .. } => unreachable!("Pattern Assign"), - Pattern::Discard { .. } => unreachable!("Pattern Discard"), - Pattern::List { elements, tail, .. } => { - let inner_list_type = &tipo.get_inner_types()[0]; - let mut elements_stack = pattern_stack.empty_with_scope(); - let mut names = vec![]; - - for element in elements { - match element { - Pattern::Var { name, .. } => { - names.push(name.clone()); - } - pattern @ (Pattern::List { .. } - | Pattern::Constructor { .. } - | Pattern::Tuple { .. }) => { - let mut var_stack = pattern_stack.empty_with_scope(); - - let item_name = format!("list_item_id_{}", self.id_gen.next()); - - names.push(item_name.clone()); - - let mut element_stack = pattern_stack.empty_with_scope(); - - var_stack.local_var(inner_list_type.clone(), item_name); - - self.pattern_ir( - pattern, - &mut element_stack, - var_stack, - &tipo.get_inner_types()[0], - assignment_properties.clone(), - ); - - elements_stack.merge(element_stack); - } - Pattern::Int { .. } => unreachable!("Inner List: Pattern Integer"), - Pattern::Assign { .. } => todo!("Assign in lists not supported yet"), - Pattern::Discard { .. } => { - names.push("_".to_string()); - } - } - } - - if let Some(tail) = tail { - match &**tail { - Pattern::Var { name, .. } => names.push(name.clone()), - Pattern::Discard { .. } => {} - _ => unreachable!(), - } - } - - if !names.is_empty() { - pattern_stack.list_accessor( - tipo.clone().into(), - names, - tail.is_some(), - !tail.is_some(), - value_stack, - ); - } else { - pattern_stack.list_empty(value_stack); - } - - pattern_stack.merge_child(elements_stack); - } - Pattern::Constructor { - arguments, - constructor, - tipo: constr_tipo, - name: constructor_name, - .. - } => { - let mut stacks = pattern_stack.empty_with_scope(); - - let field_map = match constructor { - PatternConstructor::Record { field_map, .. } => field_map.clone(), - }; - - let mut type_map: IndexMap> = IndexMap::new(); - - for (index, arg) in constr_tipo.arg_types().unwrap().iter().enumerate() { - let field_type = arg.clone(); - type_map.insert(index, field_type); - } - - let arguments_index = arguments - .iter() - .enumerate() - .map(|(index, item)| { - let label = item.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 mut nested_pattern = pattern_stack.empty_with_scope(); - - let name = self.extract_arg_name( - &item.value, - &mut nested_pattern, - type_map.get(&field_index).unwrap(), - &assignment_properties, - ); - - // Note the stacks mutation here - stacks.merge(nested_pattern); - - name.map_or(("_".to_string(), field_index), |name| (name, field_index)) - }) - .sorted_by(|item1, item2| item1.1.cmp(&item2.1)) - .collect::>(); - - let constr_name = format!("__{}_{}", constructor_name, self.id_gen.next()); - - let mut expect_stack = pattern_stack.empty_with_scope(); - - match assignment_properties.kind { - AssignmentKind::Let => { - expect_stack.merge_child(value_stack); - } - AssignmentKind::Expect => { - if tipo.is_bool() { - expect_stack.expect_bool(constructor_name == "True", value_stack); - } else if tipo.is_void() { - expect_stack.choose_unit(value_stack); - } else if tipo.is_data() { - unimplemented!("What are you doing with Data type?") - } else { - let data_type = - builder::lookup_data_type_by_tipo(&self.data_types, tipo).unwrap(); + if props.kind.is_expect() { + let data_type = lookup_data_type_by_tipo(&self.data_types, tipo) + .unwrap_or_else(|| panic!("Failed to find definition for {}", name)); + if data_type.constructors.len() > 1 || props.full_check { let (index, _) = data_type .constructors .iter() .enumerate() - .find(|(_, constr)| constr.name == *constructor_name) - .unwrap(); + .find(|(_, constr)| constr.name == *name) + .unwrap_or_else(|| { + panic!("Found constructor type {} with 0 constructors", name) + }); - let constr_name = format!("__{}_{}", constr_name, self.id_gen.next()); - let mut var_stack = expect_stack.empty_with_scope(); + let constructor_name = format!( + "__constructor_{}_span_{}_{}", + name, + pattern.location().start, + pattern.location().end + ); - var_stack.local_var(tipo.clone().into(), constr_name.clone()); + // I'm consuming `value` here + let constructor_val = AirTree::let_assignment(&constructor_name, value); - expect_stack.let_assignment(constr_name.clone(), value_stack); + sequence.push(constructor_val); - expect_stack.expect_constr(index, var_stack); + let assert_constr = AirTree::assert_constr_index( + index, + AirTree::local_var(&constructor_name, tipo.clone()), + ); - expect_stack.local_var(tipo.clone().into(), constr_name); + sequence.push(assert_constr); + + //I'm reusing the `value` pointer + value = AirTree::local_var(constructor_name, tipo.clone()); } } - } - if !arguments_index.is_empty() { - let indices = arguments_index + + let field_map = match constructor { + PatternConstructor::Record { field_map, .. } => field_map.clone(), + }; + + let mut type_map: IndexMap> = IndexMap::new(); + + for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { + let field_type = arg.clone(); + type_map.insert(index, field_type); + } + + let fields = arguments .iter() - .map(|(var_name, index)| { - let field_type = type_map.get(index).unwrap(); - (*index, var_name.clone(), field_type.clone()) + .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 { name, .. } => { + if props.full_check { + format!("__discard_{}", name) + } else { + "_".to_string() + } + } + _ => format!( + "field_{}_span_{}_{}", + field_index, + arg.value.location().start, + arg.value.location().end + ), + }; + + let arg_type = type_map.get(&field_index).unwrap_or_else(|| { + unreachable!( + "Missing type for field {} of constr {}", + field_index, name + ) + }); + + let val = AirTree::local_var(field_name.to_string(), arg_type.clone()); + + ( + field_index, + field_name, + arg_type.clone(), + self.assignment( + &arg.value, + val, + arg_type, + AssignmentProperties { + value_type: props.value_type.clone(), + kind: props.kind, + remove_unused: true, + full_check: props.full_check, + }, + ), + ) }) .collect_vec(); - pattern_stack.fields_expose(indices, false, expect_stack); - } else if (tipo.is_bool() || tipo.is_void()) - && assignment_properties.kind.is_expect() - { - pattern_stack.merge_child(expect_stack); - } else { - pattern_stack.let_assignment("_", expect_stack); - } + let indices = fields + .iter() + .map(|(index, name, tipo, _)| (*index, name.to_string(), tipo.clone())) + .collect_vec(); - pattern_stack.merge_child(stacks); + // This `value` is either value param that was passed in or + // local var + sequence.push(AirTree::fields_expose(indices, props.full_check, value)); + + sequence.append( + &mut fields + .into_iter() + .map(|(_, _, _, field)| field) + .collect_vec(), + ); + + AirTree::UnhoistedSequence(sequence) + } } - Pattern::Tuple { elems, .. } => { - let mut stacks = pattern_stack.empty_with_scope(); + Pattern::Tuple { + elems, location, .. + } => { let mut type_map: IndexMap> = IndexMap::new(); + let mut sequence = vec![]; + for (index, arg) in tipo.get_inner_types().iter().enumerate() { let field_type = arg.clone(); type_map.insert(index, field_type); } - let arguments_index = elems + let elems = elems .iter() .enumerate() - .filter_map(|(tuple_index, item)| { - let mut nested_stack = pattern_stack.empty_with_scope(); + .map(|(index, arg)| { + let tuple_name = match &arg { + Pattern::Var { name, .. } => name.to_string(), + Pattern::Assign { name, .. } => name.to_string(), + Pattern::Discard { name, .. } => { + if props.full_check { + format!("__discard_{}", name) + } else { + "_".to_string() + } + } + _ => format!( + "tuple_{}_span_{}_{}", + index, + arg.location().start, + arg.location().end + ), + }; - let name = self - .extract_arg_name( - item, - &mut nested_stack, - type_map.get(&tuple_index).unwrap(), - &assignment_properties, + let arg_type = type_map.get(&index).unwrap_or_else(|| { + unreachable!( + "Missing type for tuple index {} of tuple_span_{}_{}", + index, location.start, location.end ) - .map(|name| (name, tuple_index)); + }); - stacks.merge(nested_stack); + let val = AirTree::local_var(tuple_name.to_string(), arg_type.clone()); - name - }) - .sorted_by(|item1, item2| item1.1.cmp(&item2.1)) - .collect::>(); - - if !arguments_index.is_empty() { - let mut current_index = 0; - let mut final_args = vec![]; - - for index in 0..elems.len() { - if arguments_index.get(current_index).is_some() - && arguments_index[current_index].1 == index - { - final_args.push(arguments_index.get(current_index).unwrap().clone()); - current_index += 1; - } else { - final_args.push(("_".to_string(), index)); - } - } - - pattern_stack.tuple_accessor( - tipo.clone().into(), - final_args.into_iter().map(|(item, _)| item).collect_vec(), - false, - value_stack, - ); - } else { - pattern_stack.let_assignment("_", value_stack); - } - - pattern_stack.merge_child(stacks); - } - } - } - - pub fn expect_pattern( - &mut self, - pattern: &Pattern>, - expect_stack: &mut AirStack, - value_stack: AirStack, - tipo: &Type, - assignment_properties: AssignmentProperties, - ) { - match pattern { - Pattern::Int { .. } => unreachable!("Expect Integer"), - Pattern::Var { name, .. } => { - expect_stack.merge(value_stack); - - self.expect_type(tipo, expect_stack, name, &mut IndexMap::new()); - } - Pattern::Assign { .. } => todo!("Expect Assign not supported yet"), - Pattern::Discard { .. } => { - let name = "__expect_discard"; - - expect_stack.let_assignment(name, value_stack); - self.expect_type(tipo, expect_stack, name, &mut IndexMap::new()); - } - Pattern::List { elements, tail, .. } => { - 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!("Inner List: Expect Assign not supported yet") - } - element_pattern @ (Pattern::List { .. } - | Pattern::Constructor { .. } - | Pattern::Tuple { .. }) => { - let name = format!("list_item_id_{}", self.id_gen.next()); - - names.push(name.clone()); - - let mut element_stack = expect_stack.empty_with_scope(); - let mut value_stack = element_stack.empty_with_scope(); - - value_stack.local_var(inner_list_type.clone(), name); - - self.expect_pattern( - element_pattern, - &mut element_stack, - value_stack, - inner_list_type, - assignment_properties.clone(), - ); - - expect_list_stacks.push(element_stack); - } - Pattern::Int { .. } => unreachable!("Inner List: Expect Integer"), - _ => {} - } - } - - let mut tail_stack = expect_stack.empty_with_scope(); - - let name = if let Some(tail) = tail { - match &**tail { - Pattern::Var { name, .. } => name.clone(), - _ => format!("__tail_{}", self.id_gen.next()), - } - } else { - format!("__tail_{}", self.id_gen.next()) - }; - - if tail.is_some() { - self.expect_type(tipo, &mut tail_stack, &name, &mut IndexMap::new()); - - expect_list_stacks.push(tail_stack); - names.push(name); - } - - expect_stack.list_accessor( - tipo.clone().into(), - names, - tail.is_some(), - !tail.is_some(), - value_stack, - ); - - expect_stack.merge_children(expect_list_stacks); - } - Pattern::Constructor { - arguments, - constructor, - name: constr_name, - tipo, - .. - } => { - if tipo.is_bool() { - let PatternConstructor::Record { name, .. } = constructor; - - expect_stack.expect_bool(name == "True", value_stack); - } else if tipo.is_void() { - expect_stack.choose_unit(value_stack); - } else { - let field_map = match constructor { - PatternConstructor::Record { field_map, .. } => field_map, - }; - - let data_type = - builder::lookup_data_type_by_tipo(&self.data_types, tipo).unwrap(); - - let (index, data_type_constr) = data_type - .constructors - .iter() - .enumerate() - .find(|(_, constr)| &constr.name == constr_name) - .unwrap(); - - let mut type_map: IndexMap> = IndexMap::new(); - - let arg_types = tipo.arg_types().unwrap(); - - for (index, arg) in arg_types.iter().enumerate() { - let field_type = arg.clone(); - type_map.insert(index, field_type); - } - - let mut stacks = expect_stack.empty_with_scope(); - - let arguments_index = arguments - .iter() - .enumerate() - .filter_map(|(index, item)| { - let label = item.label.clone().unwrap_or_default(); - - let field_index = field_map - .as_ref() - .map(|field_map| { - field_map.fields.get(&label).map(|x| &x.0).unwrap_or(&index) - }) - .unwrap_or(&index); - - let mut inner_stack = expect_stack.empty_with_scope(); - - let name = self.extract_arg_name( - &item.value, - &mut inner_stack, - type_map.get(field_index).unwrap(), - &assignment_properties, - ); - - stacks.merge(inner_stack); - - name.map(|name| (name, *field_index)) - }) - .sorted_by(|item1, item2| item1.1.cmp(&item2.1)) - .collect::>(); - - let total_fields = data_type_constr.arguments.len(); - let mut final_args = vec![]; - let mut current_index = 0; - - for index in 0..total_fields { - if arguments_index.get(current_index).is_some() - && arguments_index[current_index].1 == index - { - final_args.push(arguments_index.get(current_index).unwrap().clone()); - current_index += 1; - } else { - let id_next = self.id_gen.next(); - - final_args.push((format!("__field_{index}_{id_next}"), index)); - - self.expect_type( - type_map.get(&index).unwrap(), - &mut stacks, - &format!("__field_{index}_{id_next}"), - &mut IndexMap::new(), - ) - } - } - - let constr_var = format!("__constr_{}", self.id_gen.next()); - - expect_stack.let_assignment(constr_var.clone(), value_stack); - - let mut var_stack = expect_stack.empty_with_scope(); - var_stack.local_var(tipo.clone(), constr_var.clone()); - expect_stack.expect_constr(index, var_stack); - - if !final_args.is_empty() { - let mut fields_stack = expect_stack.empty_with_scope(); - fields_stack.local_var(tipo.clone(), constr_var); - - let indices = final_args - .iter() - .map(|(var_name, index)| { - let field_type = type_map.get(index).unwrap(); - (*index, var_name.clone(), field_type.clone()) - }) - .collect_vec(); - - expect_stack.fields_expose(indices, true, fields_stack); - } - - expect_stack.merge_child(stacks); - } - } - Pattern::Tuple { elems, .. } => { - let mut type_map: IndexMap> = IndexMap::new(); - - for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { - let field_type = arg.clone(); - type_map.insert(index, field_type); - } - - let mut stacks = expect_stack.empty_with_scope(); - - let arguments_index = elems - .iter() - .enumerate() - .filter_map(|(index, item)| { - let field_index = index; - - let mut inner_stack = expect_stack.empty_with_scope(); - - let name = self.extract_arg_name( - item, - &mut inner_stack, - type_map.get(&field_index).unwrap(), - &assignment_properties, - ); - - stacks.merge(inner_stack); - - name.map(|name| (name, field_index)) - }) - .sorted_by(|item1, item2| item1.1.cmp(&item2.1)) - .collect::>(); - - let total_fields = type_map.len(); - let mut final_args = vec![]; - let mut current_index = 0; - - for index in 0..total_fields { - if arguments_index.get(current_index).is_some() - && arguments_index[current_index].1 == index - { - final_args.push(arguments_index.get(current_index).unwrap().clone()); - - current_index += 1; - } else { - let id_next = self.id_gen.next(); - - final_args.push((format!("__tuple_{index}_{id_next}"), index)); - - self.expect_type( - type_map.get(&index).unwrap(), - &mut stacks, - &format!("__tuple_{index}_{id_next}"), - &mut IndexMap::new(), + ( + tuple_name, + self.assignment( + arg, + val, + arg_type, + AssignmentProperties { + value_type: props.value_type.clone(), + kind: props.kind, + remove_unused: true, + full_check: props.full_check, + }, + ), ) - } - } + }) + .collect_vec(); - expect_stack.tuple_accessor( - tipo.clone().into(), - final_args.into_iter().map(|(item, _)| item).collect_vec(), - true, - value_stack, - ); + let indices = elems.iter().map(|(name, _)| name.to_string()).collect_vec(); - expect_stack.merge_child(stacks); + // This `value` is either value param that was passed in or + // local var + sequence.push(AirTree::tuple_access( + indices, + tipo.clone(), + props.full_check, + value, + )); + + sequence.append(&mut elems.into_iter().map(|(_, field)| field).collect_vec()); + + AirTree::UnhoistedSequence(sequence) } } } - fn expect_type( + pub fn expect_type_assign( &mut self, - tipo: &Type, - expect_stack: &mut AirStack, - name: &str, + tipo: &Arc, + value: AirTree, defined_data_types: &mut IndexMap, - ) { - let mut tipo = tipo.clone().into(); - builder::replace_opaque_type(&mut tipo, &self.data_types); - - if tipo.is_bool() - || tipo.is_bytearray() - || tipo.is_int() - || tipo.is_string() - || tipo.is_void() - || tipo.get_generic().is_some() - || tipo.is_data() - { + location: Span, + ) -> AirTree { + assert!(tipo.get_generic().is_none()); + if tipo.is_primitive() { + AirTree::void() } else if tipo.is_map() { - let new_id = self.id_gen.next(); - let id_pair = (self.id_gen.next(), self.id_gen.next()); + assert!(!tipo.get_inner_types().is_empty()); let inner_list_type = &tipo.get_inner_types()[0]; let inner_pair_types = inner_list_type.get_inner_types(); + assert!(inner_pair_types.len() == 2); - 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(); + let map_name = format!("__map_span_{}_{}", location.start, location.end); + 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); - local_var_stack.local_var(inner_list_type.clone(), format!("__pair_{new_id}")); + let assign = AirTree::let_assignment(&map_name, value); - pair_access_stack.tuple_accessor( + let tuple_access = AirTree::tuple_access( + vec![fst_name.clone(), snd_name.clone()], inner_list_type.clone(), - vec![ - format!("__pair_fst_{}", id_pair.0), - format!("__pair_snd_{}", id_pair.1), - ], false, - local_var_stack, + AirTree::local_var(&pair_name, inner_list_type.clone()), ); - self.expect_type( + let expect_fst = self.expect_type_assign( &inner_pair_types[0], - &mut pair_access_stack, - &format!("__pair_fst_{}", id_pair.0), + AirTree::local_var(fst_name, inner_pair_types[0].clone()), defined_data_types, + location, ); - self.expect_type( + let expect_snd = self.expect_type_assign( &inner_pair_types[1], - &mut pair_access_stack, - &format!("__pair_snd_{}", id_pair.1), + AirTree::local_var(snd_name, inner_pair_types[1].clone()), defined_data_types, + location, ); - unwrap_function_stack - .anonymous_function(vec![format!("__pair_{new_id}")], pair_access_stack); + 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); let function = self.code_gen_functions.get(EXPECT_ON_LIST); if function.is_none() { - let mut expect_list_stack = expect_stack.empty_with_scope(); - - expect_list_stack.expect_on_list(); + let expect_list_func = AirTree::expect_on_list(); self.code_gen_functions.insert( EXPECT_ON_LIST.to_string(), - CodeGenFunction::Function(expect_list_stack.complete(), vec![]), + CodeGenFunction::Function { + body: expect_list_func, + params: vec!["__list_to_check".to_string(), "__check_with".to_string()], + }, ); } @@ -2481,41 +1047,58 @@ impl<'a> CodeGenerator<'a> { defined_data_types.insert(EXPECT_ON_LIST.to_string(), 1); } - expect_stack.expect_list_from_data(tipo.clone(), name, unwrap_function_stack); + let func_call = AirTree::call( + AirTree::var( + ValueConstructor::public( + void(), + ValueConstructorVariant::ModuleFn { + name: EXPECT_ON_LIST.to_string(), + field_map: None, + module: "".to_string(), + arity: 1, + location, + builtin: None, + }, + ), + EXPECT_ON_LIST, + "", + ), + void(), + vec![AirTree::local_var(map_name, tipo.clone()), unwrap_function], + ); - expect_stack.void(); + assign.hoist_over(func_call) } else if tipo.is_list() { - let new_id = self.id_gen.next(); + assert!(!tipo.get_inner_types().is_empty()); let inner_list_type = &tipo.get_inner_types()[0]; - 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(); + let list_name = format!("__list_span_{}_{}", location.start, location.end); + let item_name = format!("__item_span_{}_{}", location.start, location.end); - local_var_stack.un_wrap_data(inner_list_type.clone()); - local_var_stack.local_var(inner_list_type.clone(), format!("__list_item_{new_id}")); + let assign = AirTree::let_assignment(&list_name, value); - list_access_stack.let_assignment(format!("__list_item_{new_id}"), local_var_stack); - - self.expect_type( + let expect_item = self.expect_type_assign( inner_list_type, - &mut list_access_stack, - &format!("__list_item_{new_id}"), + AirTree::local_var(&item_name, inner_list_type.clone()), defined_data_types, + location, ); - unwrap_function_stack - .anonymous_function(vec![format!("__list_item_{new_id}")], list_access_stack); + let anon_func_body = + AirTree::let_assignment("_", expect_item).hoist_over(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 mut expect_list_stack = expect_stack.empty_with_scope(); - - expect_list_stack.expect_on_list(); + let expect_list_func = AirTree::expect_on_list(); self.code_gen_functions.insert( EXPECT_ON_LIST.to_string(), - CodeGenFunction::Function(expect_list_stack.complete(), vec![]), + CodeGenFunction::Function { + body: expect_list_func, + params: vec!["__list_to_check".to_string(), "__check_with".to_string()], + }, ); } @@ -2525,206 +1108,271 @@ impl<'a> CodeGenerator<'a> { defined_data_types.insert(EXPECT_ON_LIST.to_string(), 1); } - expect_stack.expect_list_from_data(tipo.clone(), name, unwrap_function_stack); + let func_call = AirTree::call( + AirTree::var( + ValueConstructor::public( + void(), + ValueConstructorVariant::ModuleFn { + name: EXPECT_ON_LIST.to_string(), + field_map: None, + module: "".to_string(), + arity: 1, + location, + builtin: None, + }, + ), + EXPECT_ON_LIST, + "", + ), + void(), + vec![AirTree::local_var(list_name, tipo.clone()), unwrap_function], + ); - expect_stack.void(); + 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_assign( + &tuple_inner_types[0], + AirTree::local_var(fst_name, tuple_inner_types[0].clone()), + defined_data_types, + location, + ); + + let expect_snd = self.expect_type_assign( + &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() { 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())); - } + let tuple_name = format!("__tuple_span_{}_{}", location.start, location.end); + let tuple_assign = AirTree::let_assignment(&tuple_name, value); - let mut local_var_stack = expect_stack.empty_with_scope(); - - local_var_stack.local_var(tipo.clone(), name); - - let names = new_id_list + let tuple_expect_items = tuple_inner_types .iter() - .map(|(index, id)| format!("__tuple_index_{index}_{id}")) - .collect(); + .enumerate() + .map(|(index, arg)| { + let tuple_index_name = format!( + "__tuple_index_{}_span_{}_{}", + index, location.start, location.end + ); - expect_stack.tuple_accessor(tipo.clone(), names, true, local_var_stack); + let expect_tuple_item = self.expect_type_assign( + tipo, + AirTree::local_var(&tuple_index_name, arg.clone()), + defined_data_types, + location, + ); - for (index, name) in new_id_list + (tuple_index_name, expect_tuple_item) + }) + .collect_vec(); + + let tuple_index_names = tuple_expect_items + .iter() + .map(|(name, _)| name.clone()) + .collect_vec(); + + let tuple_access = AirTree::tuple_access( + tuple_index_names, + tipo.clone(), + false, + AirTree::local_var(tuple_name, tipo.clone()), + ); + + let mut tuple_expects = tuple_expect_items .into_iter() - .map(|(index, id)| (index, format!("__tuple_index_{index}_{id}"))) - { - self.expect_type( - &tuple_inner_types[index], - expect_stack, - &name, - defined_data_types, - ); - } + .map(|(_, item)| item) + .collect_vec(); + + let mut sequence = vec![tuple_assign, tuple_access]; + + sequence.append(&mut tuple_expects); + + AirTree::UnhoistedSequence(sequence).hoist_over(AirTree::void()) } else { - let data_type = builder::lookup_data_type_by_tipo(&self.data_types, &tipo).unwrap(); + let data_type = lookup_data_type_by_tipo(&self.data_types, tipo).unwrap_or_else(|| { + unreachable!("We need a data type definition fot type {:#?}", tipo) + }); - let new_id = self.id_gen.next(); - - let mut var_stack = expect_stack.empty_with_scope(); - let mut func_stack = expect_stack.empty_with_scope(); - let mut call_stack = expect_stack.empty_with_scope(); - - let mut data_type_variant = tipo + let data_type_variant = tipo .get_inner_types() .iter() .map(|arg| get_arg_type_name(arg)) .join("_"); - if let Some(types) = tipo.arg_types() { - for mut tipo in types { - replace_opaque_type(&mut tipo, &self.data_types); - get_variant_name(&mut data_type_variant, &tipo); - } - } - - let data_type_name = format!("__expect_{}{}", data_type.name, data_type_variant); + let mono_types: IndexMap> = if !data_type.typed_parameters.is_empty() { + data_type + .typed_parameters + .iter() + .zip(tipo.arg_types().unwrap()) + .flat_map(|item| get_generic_id_and_type(item.0, &item.1)) + .collect() + } else { + IndexMap::new() + }; + let data_type_name = format!("__expect_{}_{}", data_type.name, data_type_variant); let function = self.code_gen_functions.get(&data_type_name); + let error_term = if self.tracing { + AirTree::trace( + AirTree::string("Constr index did not match any type variant"), + tipo.clone(), + AirTree::error(tipo.clone()), + ) + } else { + AirTree::error(tipo.clone()) + }; + if function.is_none() && defined_data_types.get(&data_type_name).is_none() { defined_data_types.insert(data_type_name.clone(), 1); - let mono_types: IndexMap> = if !data_type.typed_parameters.is_empty() - { - data_type - .typed_parameters - .iter() - .zip(tipo.arg_types().unwrap()) - .flat_map(|item| get_generic_id_and_type(item.0, &item.1)) - .collect() - } else { - vec![].into_iter().collect() + let current_defined = defined_data_types.clone(); + let mut diff_defined_types = vec![]; + + let constr_clauses = data_type.constructors.iter().enumerate().rfold( + error_term, + |acc, (index, constr)| { + let constr_args = constr + .arguments + .iter() + .enumerate() + .map(|(index, arg)| { + let arg_name = + arg.label.clone().unwrap_or(format!("__field_{index}")); + + let arg_tipo = find_and_replace_generics(&arg.tipo, &mono_types); + + let assign = AirTree::let_assignment( + "_", + self.expect_type_assign( + &arg_tipo, + AirTree::local_var(&arg_name, arg_tipo.clone()), + defined_data_types, + location, + ), + ); + + (index, arg_name, arg_tipo, assign) + }) + .collect_vec(); + + let indices = constr_args + .iter() + .map(|(index, arg_name, arg_tipo, _)| { + (*index, arg_name.clone(), (*arg_tipo).clone()) + }) + .collect_vec(); + + let mut assigns = constr_args + .into_iter() + .map(|(_, _, _, assign)| assign) + .collect_vec(); + + if assigns.is_empty() { + let empty = AirTree::fields_empty(AirTree::local_var( + format!("__constr_var_span_{}_{}", location.start, location.end), + tipo.clone(), + )); + + assigns.insert(0, AirTree::let_assignment("_", empty)); + } else { + let expose = AirTree::fields_expose( + indices, + true, + AirTree::local_var( + format!( + "__constr_var_span_{}_{}", + location.start, location.end + ), + tipo.clone(), + ), + ); + + assigns.insert(0, expose); + }; + + let then = AirTree::UnhoistedSequence(assigns).hoist_over(AirTree::void()); + + AirTree::clause( + format!("__subject_span_{}_{}", location.start, location.end), + AirTree::int(index), + tipo.clone(), + then, + acc, + false, + ) + }, + ); + + let overhead_assign = AirTree::let_assignment( + format!("__constr_var_span_{}_{}", location.start, location.end), + AirTree::local_var("__param_0", tipo.clone()), + ); + + let when_expr = AirTree::when( + format!("__subject_span_{}_{}", location.start, location.end), + void(), + tipo.clone(), + AirTree::local_var( + format!("__constr_var_span_{}_{}", location.start, location.end), + tipo.clone(), + ), + constr_clauses, + ); + + let func_body = overhead_assign.hoist_over(when_expr); + + for (inner_data_type, inner_count) in defined_data_types.iter() { + if let Some(prev_count) = current_defined.get(inner_data_type) { + if inner_count - prev_count > 0 { + diff_defined_types.push(inner_data_type.to_string()); + } + } else { + diff_defined_types.push(inner_data_type.to_string()); + } + } + + let code_gen_func = CodeGenFunction::Function { + body: func_body, + params: vec!["__param_0".to_string()], }; - let current_defined_state = defined_data_types.clone(); - let mut diff_defined_types = IndexMap::new(); - - 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(); - let mut data_type_stack = expect_stack.empty_with_scope(); - - for (index, constr) in data_type.constructors.iter().enumerate() { - let arg_indices = constr - .arguments - .iter() - .enumerate() - .map(|(index, arg)| { - let arg_name = arg - .label - .clone() - .unwrap_or(format!("__field_{index}_{new_id}")); - - let mut arg_tipo = arg.tipo.clone(); - - find_and_replace_generics(&mut arg_tipo, &mono_types); - - (index, arg_name, arg_tipo) - }) - .collect_vec(); - - let mut arg_stack = expect_stack.empty_with_scope(); - - let mut arg_stack = if !arg_indices.is_empty() { - let mut field_expose_stack = expect_stack.empty_with_scope(); - - field_expose_stack.integer(index.to_string()); - - arg_stack.local_var(tipo.clone(), name); - - field_expose_stack.fields_expose(arg_indices.clone(), true, arg_stack); - - field_expose_stack - } else { - let mut var_stack = expect_stack.empty_with_scope(); - - var_stack.local_var(tipo.clone(), name); - - arg_stack.integer(index.to_string()); - - arg_stack.fields_empty(var_stack); - - arg_stack - }; - - for (_index, name, tipo) in arg_indices.clone() { - let mut call_stack = arg_stack.empty_with_scope(); - - self.expect_type(&tipo, &mut call_stack, &name, defined_data_types); - - arg_stack.merge_child(call_stack); - } - - for (inner_data_type, inner_count) in defined_data_types.iter() { - if let Some(prev_count) = current_defined_state.get(inner_data_type) { - diff_defined_types - .insert(inner_data_type.to_string(), *inner_count - *prev_count); - } else { - diff_defined_types.insert(inner_data_type.to_string(), *inner_count); - } - } - - arg_stack.void(); - - clause_stack.clause( - tipo.clone(), - format!("__subject_{new_id}"), - false, - arg_stack, - ); - } - - if self.tracing { - trace_stack.trace(tipo.clone()); - - trace_stack.string("Constr index did not match any type variant"); - } - - trace_stack.error(tipo.clone()); - - subject_stack.local_var(tipo.clone(), name); - - when_stack.when( - tipo.clone(), - format!("__subject_{new_id}"), - subject_stack, - clause_stack, - trace_stack, - ); - - let recursive = *diff_defined_types.get(&data_type_name).unwrap() > 0; - - data_type_stack.define_func( - &data_type_name, - "", - "", - vec![name.to_string()], - recursive, - when_stack, - ); - - self.code_gen_functions.insert( - data_type_name.clone(), - CodeGenFunction::Function( - data_type_stack.complete(), - diff_defined_types - .into_iter() - .filter(|(dt, counter)| dt != &data_type_name && *counter > 0) - .map(|(x, _)| x) - .collect_vec(), - ), - ); + self.code_gen_functions + .insert(data_type_name.clone(), code_gen_func); } else if let Some(counter) = defined_data_types.get_mut(&data_type_name) { *counter += 1; } else { - defined_data_types.insert(data_type_name.clone(), 1); + defined_data_types.insert(data_type_name.to_string(), 1); } - func_stack.var( + let func_var = AirTree::var( ValueConstructor::public( tipo.clone(), ValueConstructorVariant::ModuleFn { @@ -2740,1122 +1388,1427 @@ impl<'a> CodeGenerator<'a> { "", ); - var_stack.local_var(tipo.clone(), name); - - call_stack.call(tipo.clone(), func_stack, vec![var_stack]); - - expect_stack.expect_constr_from_data(tipo, call_stack); + AirTree::call(func_var, void(), vec![value]) } } - fn extract_arg_name( + pub fn handle_each_clause( &mut self, - item: &Pattern>, - nested_pattern_stack: &mut AirStack, - tipo: &Type, - assignment_properties: &AssignmentProperties, - ) -> Option { - match item { - Pattern::Var { name, .. } => Some(name.clone()), - Pattern::Discard { .. } => None, - a @ Pattern::List { .. } => { - let id = self.id_gen.next(); - let list_name = format!("__list_{id}"); + clauses: &[TypedClause], + final_clause: TypedClause, + subject_tipo: &Arc, + props: &mut ClauseProperties, + ) -> AirTree { + assert!( + !subject_tipo.is_void(), + "WHY ARE YOU PATTERN MATCHING VOID???" + ); + props.complex_clause = false; - let mut value_stack = nested_pattern_stack.empty_with_scope(); + if let Some((clause, rest_clauses)) = clauses.split_first() { + let mut clause_then = self.build(&clause.then); - value_stack.local_var(tipo.clone().into(), list_name.clone()); + if let Some(guard) = &clause.guard { + props.complex_clause = true; + let clause_guard_name = format!( + "__clause_guard_span_{}_{}", + clause.location.start, clause.location.end + ); - if matches!(assignment_properties.kind, AssignmentKind::Expect) - && assignment_properties.value_type.is_data() - && !tipo.is_data() - { - self.expect_pattern( - a, - nested_pattern_stack, - value_stack, - tipo, - assignment_properties.clone(), - ); - } else { - self.pattern_ir( - a, - nested_pattern_stack, - value_stack, - tipo, - assignment_properties.clone(), - ); - } + let clause_guard_assign = AirTree::let_assignment( + &clause_guard_name, + builder::handle_clause_guard(guard), + ); - Some(list_name) + clause_then = clause_guard_assign.hoist_over( + AirTree::clause_guard(clause_guard_name, AirTree::bool(true), bool()) + .hoist_over(clause_then), + ); } - a @ Pattern::Constructor { - tipo, - name: constr_name, - .. - } => { - let id = self.id_gen.next(); - let constr_name = format!("{constr_name}_{id}"); - let mut local_var_stack = nested_pattern_stack.empty_with_scope(); + match &mut props.specific_clause { + SpecificClause::ConstrClause => { + let data_type = lookup_data_type_by_tipo(&self.data_types, subject_tipo); - local_var_stack.local_var(tipo.clone(), constr_name.clone()); + let (clause_cond, clause_assign) = + self.clause_pattern(&clause.pattern, subject_tipo, props); - if matches!(assignment_properties.kind, AssignmentKind::Expect) - && assignment_properties.value_type.is_data() - && !tipo.is_data() - { - self.expect_pattern( - a, - nested_pattern_stack, - local_var_stack, - tipo, - assignment_properties.clone(), - ); - } else { - self.pattern_ir( - a, - nested_pattern_stack, - local_var_stack, - tipo, - assignment_properties.clone(), + let clause_assign_hoisted = clause_assign.hoist_over(clause_then); + + let complex_clause = props.complex_clause; + + let mut next_clause_props = ClauseProperties::init( + subject_tipo, + props.clause_var_name.clone(), + props.original_subject_name.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, tail, .. } = &clause.pattern + else { + 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(), + }, + }; - Some(constr_name) - } - a @ Pattern::Tuple { .. } => { - let id = self.id_gen.next(); - let tuple_name = format!("__tuple_name_{id}"); + let (_, clause_assign) = + self.clause_pattern(&clause.pattern, subject_tipo, props); - let mut local_var_stack = nested_pattern_stack.empty_with_scope(); + let clause_assign_hoisted = clause_assign.hoist_over(clause_then); - local_var_stack.local_var(tipo.clone().into(), tuple_name.clone()); + return AirTree::wrap_clause( + clause_assign_hoisted, + self.handle_each_clause( + rest_clauses, + final_clause, + subject_tipo, + &mut next_clause_props, + ), + ); + }; - if matches!(assignment_properties.kind, AssignmentKind::Expect) - && assignment_properties.value_type.is_data() - && !tipo.is_data() - { - self.expect_pattern( - a, - nested_pattern_stack, - local_var_stack, - tipo, - assignment_properties.clone(), - ); - } else { - self.pattern_ir( - a, - nested_pattern_stack, - local_var_stack, - tipo, - assignment_properties.clone(), - ); + 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 = { + if rest_clauses.is_empty() { + None + } else { + let next_clause = &rest_clauses[0]; + let next_elements_len = match &next_clause.pattern { + Pattern::List { elements, .. } => elements.len(), + _ => 0, + }; + + if (*current_index as usize) < next_elements_len { + Some(format!( + "tail_index_{}_span_{}_{}", + *current_index + 1, + next_clause.pattern.location().start, + next_clause.pattern.location().end + )) + } else { + None + } + } + }; + + let mut use_wrap_clause = false; + + if elements.len() - usize::from(tail.is_some() && !elements.is_empty()) + >= *current_index as usize + { + *current_index += 1; + defined_tails.push(tail_name.clone()); + } else if next_tail_name.is_none() { + use_wrap_clause = true; + } + + 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; + + if use_wrap_clause { + AirTree::wrap_clause( + clause_assign_hoisted, + self.handle_each_clause( + rest_clauses, + final_clause, + subject_tipo, + &mut next_clause_props, + ), + ) + } else { + AirTree::list_clause( + tail_name, + subject_tipo.clone(), + clause_assign_hoisted, + self.handle_each_clause( + rest_clauses, + final_clause, + subject_tipo, + &mut next_clause_props, + ), + next_tail_name, + complex_clause, + ) + } } + SpecificClause::TupleClause { + defined_tuple_indices, + } => { + let current_defined_indices = defined_tuple_indices.clone(); - Some(tuple_name) + let (_, pattern_assigns) = + self.clause_pattern(&clause.pattern, subject_tipo, props); + + let ClauseProperties{ specific_clause: SpecificClause::TupleClause { defined_tuple_indices }, ..} = props + else { + unreachable!() + }; + + let new_defined_indices: IndexSet<(usize, String)> = defined_tuple_indices + .difference(¤t_defined_indices) + .cloned() + .collect(); + + 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::TupleClause { + defined_tuple_indices: defined_tuple_indices.clone(), + }, + }; + + if new_defined_indices.is_empty() { + AirTree::wrap_clause( + pattern_assigns.hoist_over(clause_then), + self.handle_each_clause( + rest_clauses, + final_clause, + subject_tipo, + &mut next_clause_props, + ), + ) + } else { + AirTree::tuple_clause( + &props.original_subject_name, + subject_tipo.clone(), + new_defined_indices, + current_defined_indices, + pattern_assigns.hoist_over(clause_then), + self.handle_each_clause( + rest_clauses, + final_clause, + subject_tipo, + &mut next_clause_props, + ), + props.complex_clause, + ) + } + } } - Pattern::Int { .. } => todo!("Extract Arg Name: Int"), - Pattern::Assign { .. } => todo!("Extract Arg Name: Assign"), + } else { + // handle final_clause + props.final_clause = true; + assert!(final_clause.guard.is_none()); + let clause_then = self.build(&final_clause.then); + let (condition, assignments) = + self.clause_pattern(&final_clause.pattern, subject_tipo, props); + + AirTree::finally(condition, assignments.hoist_over(clause_then)) } } - fn define_ir(&mut self, ir_stack: &mut Vec) { - let mut function_definitions = IndexMap::new(); - let mut func_index_map = IndexMap::new(); - - let recursion_func_map = IndexMap::new(); - - self.define_ir_recurse( - ir_stack, - &mut function_definitions, - &mut func_index_map, - recursion_func_map, - false, - ); - - let mut final_func_dep_ir = IndexMap::new(); - let mut to_be_defined = IndexMap::new(); - - let mut dependency_map = IndexMap::new(); - let mut dependency_vec = vec![]; - - let mut func_keys = function_definitions - .clone() - .into_iter() - .filter(|(_, val)| !val.defined_by_zero_arg) - .map(|(key, val)| (key, val.defined_by_zero_arg)) - .collect_vec(); - - // deal with function dependencies by sorting order in which we iter over them. - while let Some(function) = func_keys.pop() { - let funct_comp = function_definitions.get(&function.0).unwrap(); - if dependency_map.contains_key(&function.0) { - dependency_map.shift_remove(&function.0); + pub fn clause_pattern( + &mut self, + pattern: &Pattern>, + subject_tipo: &Arc, + props: &mut ClauseProperties, + // We return condition and then assignments sequence + ) -> (AirTree, AirTree) { + match pattern { + Pattern::Int { value, .. } => { + assert!(!props.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); - func_keys.extend( - funct_comp - .dependencies + 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 { elements, tail, .. } => { + let ClauseProperties { + specific_clause: SpecificClause::ListClause { defined_tails, .. }, + complex_clause, + .. + } = props + else { unreachable!() }; + + let list_elem_types = subject_tipo.get_inner_types(); + + let list_elem_type = list_elem_types + .get(0) + .unwrap_or_else(|| unreachable!("No list element type?")); + + let defined_tails = defined_tails.clone(); + + let elems = elements .iter() - .map(|key| { - ( - key.clone(), - function_definitions.get(key).unwrap().defined_by_zero_arg, - ) - }) - .collect_vec(), - ); + .enumerate() + .map(|(index, elem)| { + let elem_name = match elem { + Pattern::Var { name, .. } => name.to_string(), + Pattern::Assign { name, .. } => name.to_string(), + Pattern::Discard { .. } => "_".to_string(), + _ => format!( + "elem_{}_span_{}_{}", + index, + elem.location().start, + elem.location().end + ), + }; - let func_scope = func_index_map.get(&function.0).unwrap().clone(); + let mut elem_props = ClauseProperties::init_inner( + list_elem_type, + elem_name.clone(), + elem_name.clone(), + props.final_clause, + ); - for dep in funct_comp.dependencies.iter() { - let Some(dep_scope) = func_index_map.get_mut(dep) else { unreachable!("Missing dependency scope.")}; + let statement = + self.nested_clause_condition(elem, list_elem_type, &mut elem_props); - *dep_scope = dep_scope.common_ancestor(&func_scope); - } + *complex_clause = *complex_clause || elem_props.complex_clause; - dependency_map.insert(function.0, function.1); - } - - dependency_vec.extend( - dependency_map - .iter() - .filter(|(_, defined_in_zero_arg)| !**defined_in_zero_arg) - .map(|(key, _)| key.clone()) - .unique() - .collect_vec(), - ); - - for func in dependency_vec { - if self.defined_functions.contains_key(&func) { - continue; - } - - let func_scope = func_index_map.get(&func).unwrap(); - - let function_component = function_definitions.get(&func).unwrap(); - - let mut dep_ir = vec![]; - - if !function_component.args.is_empty() { - // deal with function dependencies - builder::handle_func_dependencies( - &mut dep_ir, - function_component, - &function_definitions, - &mut self.defined_functions, - &func_index_map, - func_scope, - &mut to_be_defined, - self.id_gen.clone(), - ); - final_func_dep_ir.insert(func, dep_ir); - } else { - // since zero arg functions are run at compile time we need to pull all deps - // note anon functions are not included in the above. They exist in a function anyway - let mut defined_functions = IndexMap::new(); - - // deal with function dependencies in zero arg functions - builder::handle_func_dependencies( - &mut dep_ir, - function_component, - &function_definitions, - &mut defined_functions, - &func_index_map, - func_scope, - &mut to_be_defined, - self.id_gen.clone(), - ); - - let mut final_zero_arg_ir = dep_ir; - final_zero_arg_ir.extend(function_component.ir.clone()); - - self.convert_opaque_type_to_inner_ir(&mut final_zero_arg_ir); - - self.zero_arg_functions.insert(func, final_zero_arg_ir); - // zero arg functions don't contain the dependencies since they are pre-evaluated - // As such we add functions to defined only after dependencies for all other functions are calculated - } - } - - while let Some(func) = to_be_defined.pop() { - let mut dep_ir = vec![]; - let mut defined_functions = IndexMap::new(); - - // deal with function dependencies in zero arg functions - let funt_comp = function_definitions.get(&func.0).unwrap(); - let func_scope = func_index_map.get(&func.0).unwrap(); - - builder::handle_func_dependencies( - &mut dep_ir, - funt_comp, - &function_definitions, - &mut defined_functions, - &func_index_map, - func_scope, - &mut to_be_defined, - self.id_gen.clone(), - ); - - let mut final_zero_arg_ir = dep_ir; - final_zero_arg_ir.extend(funt_comp.ir.clone()); - - self.convert_opaque_type_to_inner_ir(&mut final_zero_arg_ir); - - self.zero_arg_functions.insert(func.0, final_zero_arg_ir); - } - - for (index, ir) in ir_stack.clone().into_iter().enumerate().rev() { - { - let temp_func_index_map = func_index_map.clone(); - let to_insert = final_func_dep_ir - .iter() - .filter_map(|(func_key, _)| { - temp_func_index_map - .get(func_key) - .map(|scope| (func_key.clone(), scope.clone())) - }) - .filter(|func| { - (func.1.common_ancestor(&ir.scope()) == ir.scope() - || (index == 0 && func.1.is_empty())) - && !self.defined_functions.contains_key(&func.0) - && !self.zero_arg_functions.contains_key(&func.0) - && !(*dependency_map.get(&func.0).unwrap()) + (elem_name, statement) }) .collect_vec(); - for (function_access_key, scopes) in to_insert.into_iter().rev() { - func_index_map.remove(&function_access_key); + let mut defined_heads = + elems.iter().map(|(head, _)| head.to_string()).collect_vec(); - self.defined_functions - .insert(function_access_key.clone(), ()); + let mut air_elems = elems + .into_iter() + .map(|(_, statement)| statement) + .collect_vec(); - let mut full_func_ir = - final_func_dep_ir.get(&function_access_key).unwrap().clone(); + let mut list_tail = None; - let func_comp = function_definitions - .get(&function_access_key) - .unwrap() - .clone(); + tail.iter().for_each(|elem| { + let tail = defined_tails.last().cloned().unwrap_or_default(); + let elem_name = match elem.as_ref() { + Pattern::Var { name, .. } => name.to_string(), + Pattern::Assign { name, .. } => name.to_string(), + Pattern::Discard { .. } => "_".to_string(), + _ => format!( + "tail_span_{}_{}", + elem.location().start, + elem.location().end + ), + }; - // zero arg functions are not recursive - if !func_comp.args.is_empty() { - let mut recursion_ir = vec![]; - builder::handle_recursion_ir( - &function_access_key, - &func_comp, - &mut recursion_ir, + let mut elem_props = ClauseProperties::init_inner( + subject_tipo, + elem_name.clone(), + elem_name.clone(), + props.final_clause, + ); + + let statement = + self.nested_clause_condition(elem, subject_tipo, &mut elem_props); + *complex_clause = *complex_clause || elem_props.complex_clause; + + air_elems.push(statement); + list_tail = Some((tail, elem_name.to_string())); + defined_heads.push(elem_name) + }); + + let list_assign = if props.final_clause { + AirTree::list_access( + defined_heads, + subject_tipo.clone(), + tail.is_some(), + false, + AirTree::local_var(&props.original_subject_name, subject_tipo.clone()), + ) + } else { + AirTree::list_expose( + defined_heads + .into_iter() + .zip(defined_tails.into_iter()) + .collect_vec(), + list_tail, + subject_tipo.clone(), + ) + }; + + let mut sequence = vec![list_assign]; + + sequence.append(&mut air_elems); + + (AirTree::void(), AirTree::UnhoistedSequence(sequence)) + } + Pattern::Constructor { + name, + arguments, + constructor, + tipo: function_tipo, + .. + } => { + if subject_tipo.is_bool() { + (AirTree::bool(name == "True"), AirTree::no_op()) + } else { + assert!( + matches!(function_tipo.as_ref().clone(), Type::Fn { .. }) + || matches!(function_tipo.as_ref().clone(), Type::App { .. }) + ); + let data_type = 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(); + + for (index, arg) in function_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::init_inner( + arg_type, + field_name.clone(), + field_name.clone(), + props.final_clause, + ); + + 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 { elems, .. } => { + let items_type = subject_tipo.get_inner_types(); + + let name_index_assigns = elems + .iter() + .enumerate() + .map(|(index, element)| { + let elem_name = match element { + Pattern::Var { name, .. } => name.to_string(), + Pattern::Assign { name, .. } => name.to_string(), + Pattern::Discard { .. } => "_".to_string(), + _ => format!( + "tuple_index_{}_span_{}_{}", + index, + element.location().start, + element.location().end + ), + }; + + let mut tuple_props = ClauseProperties::init_inner( + &items_type[index], + elem_name.clone(), + elem_name.clone(), + props.final_clause, ); - let recursion_stack = AirStack { - id_gen: self.id_gen.clone(), - scope: scopes.clone(), - air: recursion_ir, - }; + let elem = self.nested_clause_condition( + element, + &items_type[index], + &mut tuple_props, + ); - let mut func_stack = AirStack { - id_gen: self.id_gen.clone(), - scope: scopes.clone(), - air: vec![], - }; + props.complex_clause = props.complex_clause || tuple_props.complex_clause; - if func_comp.is_code_gen_func { - func_stack = recursion_stack - } else { - func_stack.define_func( - function_access_key.function_name.clone(), - function_access_key.module_name.clone(), - "", - func_comp.args.clone(), - func_comp.recursive, - recursion_stack, - ); - } + (elem_name, index, elem) + }) + .collect_vec(); - full_func_ir.extend(func_stack.complete()); + let mut defined_indices = match props.clone() { + ClauseProperties { + specific_clause: + SpecificClause::TupleClause { + defined_tuple_indices, + }, + .. + } => defined_tuple_indices, + _ => unreachable!(), + }; - for ir in full_func_ir.into_iter().rev() { - ir_stack.insert(index, ir); - } - } else { - full_func_ir.extend(func_comp.ir.clone()); - - self.zero_arg_functions - .insert(function_access_key, full_func_ir); + let mut previous_defined_names = vec![]; + name_index_assigns.iter().for_each(|(name, index, _)| { + if let Some((index, prev_name)) = defined_indices + .iter() + .find(|(defined_index, _nm)| defined_index == index) + { + previous_defined_names.push((*index, prev_name.clone(), name.clone())); + } else if name != "_" { + assert!(defined_indices.insert((*index, name.clone()))); } + }); + + let tuple_name_assigns = previous_defined_names + .into_iter() + .map(|(index, prev_name, name)| { + AirTree::let_assignment( + name, + AirTree::local_var(prev_name, items_type[index].clone()), + ) + }) + .collect_vec(); + + let mut tuple_item_assigns = name_index_assigns + .into_iter() + .map(|(_, _, item)| item) + .collect_vec(); + + match props { + ClauseProperties { + specific_clause: + SpecificClause::TupleClause { + defined_tuple_indices, + }, + .. + } => { + *defined_tuple_indices = defined_indices; + } + _ => unreachable!(), } + + let mut sequence = tuple_name_assigns; + sequence.append(&mut tuple_item_assigns); + + (AirTree::void(), AirTree::UnhoistedSequence(sequence)) } } } - fn define_ir_recurse( + fn nested_clause_condition( &mut self, - ir_stack: &mut [Air], - func_components: &mut IndexMap, - func_index_map: &mut IndexMap, - mut recursion_func_map: IndexMap, - in_zero_arg_func: bool, - ) { - self.define_ir_processor(ir_stack, func_components, func_index_map, in_zero_arg_func); - - let mut recursion_func_map_to_add = recursion_func_map.clone(); - - for func_index in func_index_map.clone().iter() { - let func = func_index.0; - - let function_components = func_components.get_mut(func).unwrap(); - let mut function_ir = function_components.ir.clone(); - let in_zero_arg = function_components.args.is_empty() || in_zero_arg_func; - let mut skip = false; - - for ir in function_ir.clone() { - let Air::Var { constructor, .. } = ir - else { - continue; - }; - - let ValueConstructorVariant::ModuleFn { name: func_name, module, builtin: None, .. } = constructor.variant - else { - continue; - }; - - let ir_function_key = FunctionAccessKey { - module_name: module.clone(), - function_name: func_name.clone(), - }; - - if recursion_func_map.contains_key(&ir_function_key) && func == &ir_function_key { - skip = true; - } else if func == &ir_function_key { - recursion_func_map_to_add.insert(ir_function_key, ()); + pattern: &Pattern>, + subject_tipo: &Arc, + props: &mut ClauseProperties, + ) -> AirTree { + if props.final_clause { + props.complex_clause = false; + let (_, assign) = self.clause_pattern(pattern, subject_tipo, props); + assign + } else { + assert!( + !subject_tipo.is_void(), + "WHY ARE YOU PATTERN MATCHING ON A NESTED VOID???" + ); + match pattern { + Pattern::Int { value, .. } => { + props.complex_clause = true; + AirTree::clause_guard(&props.original_subject_name, AirTree::int(value), int()) } - } + Pattern::Var { name, .. } => AirTree::let_assignment( + name, + AirTree::local_var(&props.clause_var_name, subject_tipo.clone()), + ), + Pattern::Assign { name, pattern, .. } => AirTree::UnhoistedSequence(vec![ + AirTree::let_assignment( + name, + AirTree::local_var(&props.clause_var_name, subject_tipo.clone()), + ), + self.nested_clause_condition(pattern, subject_tipo, props), + ]), + Pattern::Discard { .. } => AirTree::no_op(), + Pattern::List { elements, tail, .. } => { + props.complex_clause = true; + let tail_name_base = "__tail".to_string(); - recursion_func_map = recursion_func_map_to_add.clone(); - if !skip { - let mut inner_func_components = IndexMap::new(); + if elements.is_empty() { + assert!( + tail.is_none(), + "Why do you have a [..] in a clause? Use a var." + ); - let mut inner_func_index_map = IndexMap::new(); - - self.define_ir_recurse( - &mut function_ir, - &mut inner_func_components, - &mut inner_func_index_map, - recursion_func_map.clone(), - in_zero_arg, - ); - - function_components.ir = function_ir; - - //now unify - for item in inner_func_components { - if let Some(entry) = func_components.get_mut(&item.0) { - entry.defined_by_zero_arg = - entry.defined_by_zero_arg && item.1.defined_by_zero_arg + AirTree::list_clause_guard( + &props.original_subject_name, + subject_tipo.clone(), + false, + None, + ) } else { - func_components.insert(item.0, item.1); - } - } + let mut clause_assigns = vec![]; - for item in inner_func_index_map { - if let Some(entry) = func_index_map.get_mut(&item.0) { - *entry = entry.common_ancestor(&item.1); - } else { - func_index_map.insert(item.0, item.1); - } - } - } - } - } - - fn define_ir_processor( - &mut self, - ir_stack: &mut [Air], - func_components: &mut IndexMap, - func_index_map: &mut IndexMap, - in_zero_arg_func: bool, - ) { - let mut to_be_defined_map: IndexMap = IndexMap::new(); - for (index, ir) in ir_stack.to_vec().iter().enumerate().rev() { - // I tried putting the 2 let else together, but then formatting stopped working - #[rustfmt::skip] - let Air::Var { - scope, constructor, .. - } = ir else { - let scope = ir.scope(); - - process_scope_updates(&mut to_be_defined_map, &scope, func_index_map); - continue; - }; - - #[rustfmt::skip] - let ValueConstructorVariant::ModuleFn {name, module, builtin: None, ..} = &constructor.variant else { - let scope = ir.scope(); - - process_scope_updates(&mut to_be_defined_map, &scope, func_index_map); - continue; - }; - - let non_variant_function_key = FunctionAccessKey { - module_name: module.clone(), - function_name: name.clone(), - }; - - if let Some(function) = self.functions.get(&non_variant_function_key).cloned() { - let mut func_stack = AirStack::with_scope(self.id_gen.clone(), scope.clone()); - - self.build(&function.body, &mut func_stack); - - let func_ir = func_stack.complete(); - - let param_types = constructor.tipo.arg_types().unwrap(); - - let mut mono_types: IndexMap> = IndexMap::new(); - let mut map = mono_types.into_iter().collect_vec(); - - for (index, arg) in function.arguments.iter().enumerate() { - if arg.tipo.is_generic() { - let param_type = ¶m_types[index]; - - map.append(&mut builder::get_generic_id_and_type(&arg.tipo, param_type)); - } - } - - if function.return_type.is_generic() { - if let Type::Fn { ret, .. } = &*constructor.tipo { - map.append(&mut builder::get_generic_id_and_type( - &function.return_type, - ret, - )) - } - } - - mono_types = map.into_iter().collect(); - - let (variant_name, func_ir) = - builder::monomorphize(func_ir, mono_types, &constructor.tipo, &self.data_types); - - let function_key = FunctionAccessKey { - module_name: module.clone(), - function_name: non_variant_function_key.function_name, - }; - - ir_stack[index] = Air::Var { - scope: scope.clone(), - constructor: constructor.clone(), - name: name.clone(), - variant_name: variant_name.clone(), - }; - - if let Some(scope_prev) = to_be_defined_map.get(&function_key) { - let new_scope = scope.common_ancestor(scope_prev); - - to_be_defined_map.insert(function_key, new_scope); - } else if func_components.get(&function_key).is_some() { - to_be_defined_map.insert(function_key.clone(), scope.clone()); - } else { - to_be_defined_map.insert(function_key.clone(), scope.clone()); - let mut func_calls = IndexMap::new(); - - for ir in func_ir.clone().into_iter() { - let Air::Var { constructor, ..} = ir else { - continue; - }; - - let ValueConstructorVariant::ModuleFn { - name : func_name, module, builtin: None, .. - } = &constructor.variant - else { - continue; - }; - - let current_func = FunctionAccessKey { - module_name: module.clone(), - function_name: func_name.clone(), - }; - - let current_func_as_variant = FunctionAccessKey { - module_name: module.clone(), - function_name: func_name.clone(), - }; - - let function = self.functions.get(¤t_func); - if function_key.clone() == current_func_as_variant { - func_calls.insert(current_func_as_variant, ()); - } else if let (Some(function), Type::Fn { .. }) = - (function, &*constructor.tipo) - { - let param_types = constructor.tipo.arg_types().unwrap(); - - let mut map = vec![]; - - for (index, arg) in function.arguments.iter().enumerate() { - if arg.tipo.is_generic() { - let param_type = ¶m_types[index]; - - map.append(&mut builder::get_generic_id_and_type( - &arg.tipo, param_type, - )); - } - } - - if function.return_type.is_generic() { - if let Type::Fn { ret, .. } = &*constructor.tipo { - map.append(&mut builder::get_generic_id_and_type( - &function.return_type, - ret, - )) - } - } - - let mono_types: IndexMap> = map.into_iter().collect(); - let mut func_stack = - AirStack::with_scope(self.id_gen.clone(), scope.clone()); - - self.build(&function.body, &mut func_stack); - - let temp_ir = func_stack.complete(); - - let (variant_name, _) = builder::monomorphize( - temp_ir, - mono_types, - &constructor.tipo, - &self.data_types, - ); - - func_calls.insert( - FunctionAccessKey { - module_name: current_func.module_name, - function_name: current_func.function_name, + let ClauseProperties { + specific_clause: + SpecificClause::ListClause { + current_index, + defined_tails, }, - (), - ); - } else { - func_calls.insert(current_func, ()); + .. + } = props + else { unreachable!() }; + + for (index, _) in elements.iter().enumerate() { + let prev_tail_name = if index == 0 { + props.original_subject_name.clone() + } else { + format!("{}_{}", tail_name_base, index - 1) + }; + + let tail_name = format!("{tail_name_base}_{index}"); + + if elements.len() - 1 == index { + if tail.is_some() { + clause_assigns.push(AirTree::list_clause_guard( + prev_tail_name, + subject_tipo.clone(), + true, + None, + )); + } else { + clause_assigns.push(AirTree::list_clause_guard( + prev_tail_name, + subject_tipo.clone(), + true, + Some(tail_name.to_string()), + )); + + clause_assigns.push(AirTree::list_clause_guard( + tail_name.to_string(), + subject_tipo.clone(), + false, + None, + )); + *current_index += 1; + defined_tails.push(tail_name); + } + } else { + clause_assigns.push(AirTree::list_clause_guard( + prev_tail_name, + subject_tipo.clone(), + true, + Some(tail_name.to_string()), + )); + + *current_index += 1; + defined_tails.push(tail_name); + }; } + let (_, assigns) = self.clause_pattern(pattern, subject_tipo, props); + clause_assigns.push(assigns); + AirTree::UnhoistedSequence(clause_assigns) } - - let mut args = vec![]; - - for arg in function.arguments.iter() { - match &arg.arg_name { - ArgName::Named { name, .. } => { - args.push(name.clone()); - } - _ => { - args.push("_".to_string()); - } - } - } - - let recursive = if func_calls.get(&function_key).is_some() { - func_calls.remove(&function_key); - true + } + Pattern::Constructor { + name: constr_name, + is_record, + .. + } => { + props.complex_clause = true; + if subject_tipo.is_bool() { + AirTree::clause_guard( + &props.original_subject_name, + AirTree::bool(constr_name == "True"), + bool(), + ) } else { - false + let (cond, assign) = self.clause_pattern(pattern, subject_tipo, props); + + if *is_record { + assign + } else { + AirTree::UnhoistedSequence(vec![ + AirTree::clause_guard( + &props.original_subject_name, + cond, + subject_tipo.clone(), + ), + assign, + ]) + } + } + } + Pattern::Tuple { .. } => { + props.complex_clause = true; + let (_, assign) = self.clause_pattern(pattern, subject_tipo, props); + + let defined_indices = match &props.specific_clause { + SpecificClause::TupleClause { + defined_tuple_indices, + } => defined_tuple_indices.clone(), + _ => unreachable!(), }; - func_components.insert( - function_key, - FuncComponents { - ir: func_ir, - dependencies: func_calls.keys().cloned().collect_vec(), - recursive, - args, - defined_by_zero_arg: in_zero_arg_func, - is_code_gen_func: false, + let tuple_access = AirTree::tuple_clause_guard( + &props.original_subject_name, + subject_tipo.clone(), + defined_indices, + ); + + AirTree::UnhoistedSequence(vec![tuple_access, assign]) + } + } + } + } + + pub fn check_validator_args( + &mut self, + arguments: &[TypedArg], + has_context: bool, + body: AirTree, + ) -> AirTree { + let checked_args = arguments + .iter() + .enumerate() + .map(|(index, arg)| { + let arg_name = arg.arg_name.get_variable_name().unwrap_or("_").to_string(); + if !(has_context && index == arguments.len() - 1) && &arg_name != "_" { + let param = AirTree::local_var(&arg_name, data()); + + let actual_type = convert_opaque_type(&arg.tipo, &self.data_types); + + let assign = self.assignment( + &Pattern::Var { + location: Span::empty(), + name: arg_name.to_string(), + }, + param, + &actual_type, + AssignmentProperties { + value_type: data(), + kind: AssignmentKind::Expect, + remove_unused: false, + full_check: true, }, ); + + (arg_name, assign) + } else { + (arg_name, AirTree::no_op()) } - } else if let Some(code_gen_func) = self.code_gen_functions.get(name).cloned() { - // Get actual code gen func if link - let (func_ir, dependencies) = match code_gen_func { - CodeGenFunction::Function(func_ir, dependencies) => (func_ir, dependencies), - CodeGenFunction::Link(func) => { - if let Some(CodeGenFunction::Function(func_ir, dependencies)) = - self.code_gen_functions.get(&func).cloned() - { - (func_ir, dependencies) - } else { - unreachable!("Link must resolve to a code gen function."); - } - } - }; + }) + .collect_vec(); - let function_key = FunctionAccessKey { - module_name: "".to_string(), - function_name: name.to_string(), - }; + let arg_names = checked_args + .iter() + .map(|(name, _)| name.to_string()) + .collect_vec(); - let function_stack = AirStack { - id_gen: self.id_gen.clone(), - scope: scope.clone(), - air: func_ir, - }; + let arg_assigns = + AirTree::UnhoistedSequence(checked_args.into_iter().map(|(_, arg)| arg).collect_vec()); - let mut new_stack = AirStack::with_scope(self.id_gen.clone(), scope.clone()); + AirTree::anon_func(arg_names, arg_assigns.hoist_over(body)) + } - new_stack.merge_child(function_stack); + fn hoist_functions_to_validator(&mut self, mut air_tree: AirTree) -> AirTree { + let mut functions_to_hoist = IndexMap::new(); + let mut used_functions = vec![]; + let mut defined_functions = vec![]; + let mut hoisted_functions = vec![]; + let mut validator_hoistable; - func_components.insert( - function_key.clone(), - FuncComponents { - ir: new_stack.complete(), - dependencies: dependencies - .into_iter() - .map(|item| FunctionAccessKey { - module_name: "".to_string(), - function_name: item, - }) - .collect_vec(), - recursive: false, - args: vec!["__one".to_string()], - defined_by_zero_arg: in_zero_arg_func, - is_code_gen_func: true, - }, + // TODO change subsequent tree traversals to be more like a stream. + air_tree.traverse_tree_with(&mut |air_tree: &mut AirTree, _| { + erase_opaque_type_operations(air_tree, &self.data_types); + }); + + self.find_function_vars_and_depth( + &mut air_tree, + &mut functions_to_hoist, + &mut used_functions, + &mut TreePath::new(), + 0, + 0, + ); + + validator_hoistable = used_functions.clone(); + + while let Some((key, variant_name)) = used_functions.pop() { + defined_functions.push((key.clone(), variant_name.clone())); + let function_variants = functions_to_hoist + .get(&key) + .unwrap_or_else(|| panic!("Missing Function Definition")); + + let (tree_path, function) = function_variants + .get(&variant_name) + .unwrap_or_else(|| panic!("Missing Function Variant Definition")); + + if let UserFunction::Function(body, deps) = function { + let mut hoist_body = body.clone(); + let mut hoist_deps = deps.clone(); + + let mut tree_path = tree_path.clone(); + + self.define_dependent_functions( + &mut hoist_body, + &mut functions_to_hoist, + &mut used_functions, + &defined_functions, + &mut hoist_deps, + &mut tree_path, ); - to_be_defined_map.insert(function_key, scope.clone()); + let function_variants = functions_to_hoist + .get_mut(&key) + .unwrap_or_else(|| panic!("Missing Function Definition")); + + let (_, function) = function_variants + .get_mut(&variant_name) + .unwrap_or_else(|| panic!("Missing Function Variant Definition")); + + *function = UserFunction::Function(hoist_body, hoist_deps); } else { - unreachable!("We found a function with no definitions"); + todo!("Deal with Link later") } - process_scope_updates(&mut to_be_defined_map, scope, func_index_map); } - // Still to be defined - for func in to_be_defined_map.clone().iter() { - let index_scope = func_index_map.get(func.0).unwrap(); - func_index_map.insert(func.0.clone(), func.1.common_ancestor(index_scope)); + // First we need to sort functions by dependencies + // here's also where we deal with mutual recursion + let mut sorted_function_vec = vec![]; + + while let Some((generic_func, variant)) = validator_hoistable.pop() { + let function_variants = functions_to_hoist + .get(&generic_func) + .unwrap_or_else(|| panic!("Missing Function Definition")); + + let function_has_params = self + .functions + .get(&generic_func) + .map(|func| !func.arguments.is_empty()) + .unwrap_or_else(|| true); + + let (_, function) = function_variants + .get(&variant) + .unwrap_or_else(|| panic!("Missing Function Variant Definition")); + + // TODO: change this part to handle mutual recursion + if let UserFunction::Function(_, deps) = function { + if function_has_params { + for (dep_generic_func, dep_variant) in deps.iter() { + if !(dep_generic_func == &generic_func && dep_variant == &variant) { + validator_hoistable + .push((dep_generic_func.clone(), dep_variant.clone())); + let remove_index = + sorted_function_vec + .iter() + .position(|(generic_func, variant)| { + generic_func == dep_generic_func && variant == dep_variant + }); + if let Some(index) = remove_index { + sorted_function_vec.remove(index); + } + } + } + } + } else { + todo!("Deal with Link later") + } + + sorted_function_vec.push((generic_func, variant)); + } + sorted_function_vec.dedup(); + + // Now we need to hoist the functions to the top of the validator + for (key, variant) in sorted_function_vec { + if hoisted_functions + .iter() + .any(|(func_key, func_variant)| func_key == &key && func_variant == &variant) + { + continue; + } + + let function_variants = functions_to_hoist + .get(&key) + .unwrap_or_else(|| panic!("Missing Function Definition")); + + let (tree_path, function) = function_variants + .get(&variant) + .unwrap_or_else(|| panic!("Missing Function Variant Definition")); + + self.hoist_function( + &mut air_tree, + tree_path, + function, + (&key, &variant), + &functions_to_hoist, + &mut hoisted_functions, + ); + } + + air_tree + } + + fn hoist_function( + &mut self, + air_tree: &mut AirTree, + tree_path: &TreePath, + function: &UserFunction, + key_var: (&FunctionAccessKey, &String), + functions_to_hoist: &IndexMap< + FunctionAccessKey, + IndexMap, + >, + hoisted_functions: &mut Vec<(FunctionAccessKey, String)>, + ) { + if let UserFunction::Function(body, func_deps) = function { + let mut body = body.clone(); + let node_to_edit = air_tree.find_air_tree_node(tree_path); + + let (key, variant) = key_var; + + // check for recursiveness + let is_recursive = func_deps + .iter() + .any(|(dep_key, dep_variant)| dep_key == key && dep_variant == variant); + + // first grab dependencies + let func_params = self + .functions + .get(key) + .map(|func| { + func.arguments + .iter() + .map(|func_arg| { + func_arg + .arg_name + .get_variable_name() + .unwrap_or("_") + .to_string() + }) + .collect_vec() + }) + .unwrap_or_else(|| { + let Some(CodeGenFunction::Function { params, .. }) = + self.code_gen_functions.get(&key.function_name) + else { unreachable!() }; + + params.clone() + }); + + let params_empty = func_params.is_empty(); + + let deps = (tree_path, func_deps.clone()); + + if !params_empty { + body = AirTree::define_func( + &key.function_name, + &key.module_name, + variant, + func_params, + is_recursive, + body, + ); + + let function_deps = self.hoist_dependent_functions( + deps, + params_empty, + key, + variant, + hoisted_functions, + functions_to_hoist, + ); + + // now hoist full function onto validator tree + *node_to_edit = function_deps.hoist_over(body.hoist_over(node_to_edit.clone())); + + hoisted_functions.push((key.clone(), variant.clone())); + } else { + body = self + .hoist_dependent_functions( + deps, + params_empty, + key, + variant, + hoisted_functions, + functions_to_hoist, + ) + .hoist_over(body); + + self.zero_arg_functions.insert(key.clone(), body.to_vec()); + } + } else { + todo!() } } - fn convert_opaque_type_to_inner_ir(&mut self, ir_stack: &mut Vec) { - let mut indices_to_remove = vec![]; - for (index, ir) in ir_stack.clone().into_iter().enumerate() { - match ir { - Air::Var { - scope, - constructor, - name, - variant_name, - } => { - let mut replaced_type = constructor.tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); + fn hoist_dependent_functions( + &mut self, + deps: (&TreePath, Vec<(FunctionAccessKey, String)>), + params_empty: bool, + key: &FunctionAccessKey, + variant: &String, + hoisted_functions: &mut Vec<(FunctionAccessKey, String)>, + functions_to_hoist: &IndexMap< + FunctionAccessKey, + IndexMap, + >, + ) -> AirTree { + let (func_path, func_deps) = deps; - ir_stack[index] = Air::Var { - scope, - constructor: ValueConstructor { - public: constructor.public, - variant: constructor.variant, - tipo: replaced_type, - }, - name, - variant_name, - }; + let mut deps_vec = func_deps; + + let mut dep_insertions = vec![]; + + // This part handles hoisting dependencies + while let Some((dep_key, dep_variant)) = deps_vec.pop() { + if (!params_empty + // if the dependency is the same as the function we're hoisting + // or we hoisted it, then skip it + && hoisted_functions.iter().any(|(generic, variant)| { + generic == &dep_key && variant == &dep_variant + })) + || (&dep_key == key && &dep_variant == variant) + { + continue; + } + + let dependency = functions_to_hoist + .get(&dep_key) + .unwrap_or_else(|| panic!("Missing Function Definition")); + + let (dep_path, dep_function) = dependency + .get(&dep_variant) + .unwrap_or_else(|| panic!("Missing Function Variant Definition")); + + // In the case of zero args, we need to hoist the dependency function to the top of the zero arg function + if &dep_path.common_ancestor(func_path) == func_path || params_empty { + let dependent_params = self + .functions + .get(&dep_key) + .map(|dep_func| { + dep_func + .arguments + .iter() + .map(|func_arg| { + func_arg + .arg_name + .get_variable_name() + .unwrap_or("_") + .to_string() + }) + .collect_vec() + }) + .unwrap_or_else(|| { + let Some(CodeGenFunction::Function { params, .. }) = + self.code_gen_functions.get(&key.function_name) + else { unreachable!() }; + + params.clone() + }); + + let UserFunction::Function(dep_air_tree, dependency_deps) = + dep_function.clone() + else { unreachable!() }; + + let is_dependent_recursive = dependency_deps + .iter() + .any(|(key, variant)| &dep_key == key && &dep_variant == variant); + + let dependency_deps_to_add = dependency_deps + .iter() + .filter(|(dep_k, dep_v)| !(dep_k == &dep_key && dep_v == &dep_variant)) + .filter(|(dep_k, dep_v)| { + !params_empty + && !hoisted_functions + .iter() + .any(|(generic, variant)| generic == dep_k && variant == dep_v) + }) + .cloned() + .collect_vec(); + + dep_insertions.push(AirTree::define_func( + &dep_key.function_name, + &dep_key.module_name, + &dep_variant, + dependent_params, + is_dependent_recursive, + dep_air_tree, + )); + + deps_vec.extend(dependency_deps_to_add); + + if !params_empty { + hoisted_functions.push((dep_key.clone(), dep_variant.clone())); } - Air::List { - tipo, - scope, - count, - tail, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::List { - scope, - tipo: replaced_type, - count, - tail, - }; - } - Air::ListAccessor { - tipo, - scope, - names, - tail, - check_last_item, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::ListAccessor { - scope, - tipo: replaced_type, - names, - tail, - check_last_item, - }; - } - Air::ListExpose { - tipo, - scope, - tail_head_names, - tail, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::ListExpose { - scope, - tipo: replaced_type, - tail_head_names, - tail, - }; - } - Air::Builtin { - tipo, - scope, - func, - count, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::Builtin { - scope, - func, - count, - tipo: replaced_type, - }; - } - Air::BinOp { tipo, scope, name } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::BinOp { - scope, - name, - tipo: replaced_type, - }; - } - Air::When { - tipo, - scope, - subject_name, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::When { - scope, - tipo: replaced_type, - subject_name, - }; - } - Air::Clause { - tipo, - scope, - subject_name, - complex_clause, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::Clause { - scope, - tipo: replaced_type, - subject_name, - complex_clause, - }; - } - Air::ListClause { - tipo, - scope, - tail_name, - next_tail_name, - complex_clause, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::ListClause { - scope, - tipo: replaced_type, - tail_name, - next_tail_name, - complex_clause, - }; - } - Air::TupleClause { - tipo, - scope, - indices, - predefined_indices, - subject_name, - count, - complex_clause, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::TupleClause { - scope, - tipo: replaced_type, - indices, - predefined_indices, - subject_name, - count, - complex_clause, - }; - } - Air::ClauseGuard { - tipo, - scope, - subject_name, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::ClauseGuard { - scope, - subject_name, - tipo: replaced_type, - }; - } - Air::ListClauseGuard { - tipo, - scope, - tail_name, - next_tail_name, - inverse, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::ListClauseGuard { - scope, - tipo: replaced_type, - tail_name, - next_tail_name, - inverse, - }; - } - Air::Tuple { tipo, scope, count } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::Tuple { - scope, - tipo: replaced_type, - count, - }; - } - Air::TupleIndex { - tipo, - scope, - tuple_index, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::TupleIndex { - scope, - tipo: replaced_type, - tuple_index, - }; - } - Air::ErrorTerm { tipo, scope } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::ErrorTerm { - scope, - tipo: replaced_type, - }; - } - Air::Trace { tipo, scope } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::Trace { - scope, - tipo: replaced_type, - }; - } - Air::TupleAccessor { - tipo, - scope, - names, - check_last_item, - } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::TupleAccessor { - scope, - names, - tipo: replaced_type, - check_last_item, - }; - } - Air::RecordUpdate { - highest_index, - indices, - scope, - tipo, - } => { - let mut new_indices = vec![]; - for (ind, tipo) in indices { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - new_indices.push((ind, replaced_type)); - } - - ir_stack[index] = Air::RecordUpdate { - scope, - indices: new_indices, - highest_index, - tipo, - }; - } - Air::Record { - tag: constr_index, - tipo, - count, - scope, - } => { - if builder::check_replaceable_opaque_type(&tipo, &self.data_types) { - indices_to_remove.push(index); - } else { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::Record { - scope, - tag: constr_index, - tipo: replaced_type, - count, - }; - } - } - Air::RecordAccess { - record_index, - tipo, - scope, - } => { - let record = ir_stack[index + 1].clone(); - let record_type = record.tipo(); - if let Some(record_type) = record_type { - if builder::check_replaceable_opaque_type(&record_type, &self.data_types) { - indices_to_remove.push(index); - } else { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::RecordAccess { - scope, - record_index, - tipo: replaced_type, - }; - } - } else { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::RecordAccess { - scope, - record_index, - tipo: replaced_type, - }; - } - } - Air::FieldsExpose { - indices, - scope, - check_last_item, - } => { - let record = ir_stack[index + 1].clone(); - let record_type = record.tipo(); - if let Some(record_type) = record_type { - if builder::check_replaceable_opaque_type(&record_type, &self.data_types) { - ir_stack[index] = Air::Let { - scope, - name: indices[0].1.clone(), - }; - } else { - let mut new_indices = vec![]; - for (ind, name, tipo) in indices { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - new_indices.push((ind, name, replaced_type)); - } - - ir_stack[index] = Air::FieldsExpose { - scope, - indices: new_indices, - check_last_item, - }; - } - } else { - let mut new_indices = vec![]; - for (ind, name, tipo) in indices { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - new_indices.push((ind, name, replaced_type)); - } - - ir_stack[index] = Air::FieldsExpose { - scope, - indices: new_indices, - check_last_item, - }; - } - } - Air::Call { scope, count, tipo } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::Call { - scope, - tipo: replaced_type, - count, - }; - } - Air::If { scope, tipo } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::If { - scope, - tipo: replaced_type, - }; - } - Air::UnWrapData { scope, tipo } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::UnWrapData { - scope, - tipo: replaced_type, - }; - } - Air::WrapData { scope, tipo } => { - let mut replaced_type = tipo.clone(); - builder::replace_opaque_type(&mut replaced_type, &self.data_types); - - ir_stack[index] = Air::WrapData { - scope, - tipo: replaced_type, - }; - } - _ => {} } } - for index in indices_to_remove.into_iter().rev() { - ir_stack.remove(index); + dep_insertions.reverse(); + + AirTree::UnhoistedSequence(dep_insertions) + } + + fn define_dependent_functions( + &mut self, + air_tree: &mut AirTree, + function_usage: &mut IndexMap< + FunctionAccessKey, + IndexMap, + >, + used_functions: &mut Vec<(FunctionAccessKey, String)>, + defined_functions: &[(FunctionAccessKey, String)], + current_function_deps: &mut Vec<(FunctionAccessKey, String)>, + validator_tree_path: &mut TreePath, + ) { + let Some((depth, index)) = validator_tree_path.pop() + else { return }; + + validator_tree_path.push(depth, index); + + self.find_function_vars_and_depth( + air_tree, + function_usage, + current_function_deps, + validator_tree_path, + depth + 1, + 0, + ); + + for (generic_function_key, variant_name) in current_function_deps.iter() { + if !used_functions + .iter() + .any(|(key, name)| key == generic_function_key && name == variant_name) + && !defined_functions + .iter() + .any(|(key, name)| key == generic_function_key && name == variant_name) + { + used_functions.push((generic_function_key.clone(), variant_name.clone())); + } } } + fn find_function_vars_and_depth( + &mut self, + air_tree: &mut AirTree, + function_usage: &mut IndexMap< + FunctionAccessKey, + IndexMap, + >, + dependency_functions: &mut Vec<(FunctionAccessKey, String)>, + path: &mut TreePath, + current_depth: usize, + depth_index: usize, + ) { + air_tree.traverse_tree_with_path( + path, + current_depth, + depth_index, + &mut |air_tree, tree_path| { + if let AirTree::Expression(AirExpression::Var { + constructor, + variant_name, + .. + }) = air_tree + { + let ValueConstructorVariant::ModuleFn { + name: func_name, + module, + builtin: None, + .. + } = &constructor.variant + else { return }; + + let function_var_tipo = &constructor.tipo; + + let generic_function_key = FunctionAccessKey { + module_name: module.clone(), + function_name: func_name.clone(), + }; + + let function_def = self.functions.get(&generic_function_key); + + let Some(function_def) = function_def + else { + let code_gen_func = self + .code_gen_functions + .get(&generic_function_key.function_name) + .unwrap_or_else(|| panic!("Missing Code Gen Function Definition")); + + if let Some(func_variants) = function_usage.get_mut(&generic_function_key) { + let (path, _) = func_variants.get_mut("").unwrap(); + + *path = path.common_ancestor(tree_path); + } else { + let CodeGenFunction::Function{ body, .. } = code_gen_func + else { unreachable!() }; + + let mut function_variant_path = IndexMap::new(); + + function_variant_path.insert( + "".to_string(), + ( + tree_path.clone(), + UserFunction::Function(body.clone(), vec![]), + ), + ); + + dependency_functions.push((generic_function_key.clone(), "".to_string())); + function_usage.insert(generic_function_key, function_variant_path); + } + return; + }; + + let mut function_var_types = function_var_tipo + .arg_types() + .unwrap_or_else(|| panic!("Expected a function tipo with arg types")); + + function_var_types.push( + function_var_tipo + .return_type() + .unwrap_or_else(|| panic!("Should have return type")), + ); + + let mut function_def_types = function_def + .arguments + .iter() + .map(|arg| &arg.tipo) + .collect_vec(); + + function_def_types.push(&function_def.return_type); + + let mono_types: IndexMap> = if !function_def_types.is_empty() { + function_def_types + .into_iter() + .zip(function_var_types.into_iter()) + .flat_map(|(func_tipo, var_tipo)| { + get_generic_id_and_type(func_tipo, &var_tipo) + }) + .collect() + } else { + IndexMap::new() + }; + + let variant = mono_types + .iter() + .sorted_by(|(id, _), (id2, _)| id.cmp(id2)) + .map(|(_, tipo)| get_variant_name(tipo)) + .join(""); + + *variant_name = variant.clone(); + let mut is_recursive = false; + + if !dependency_functions + .iter() + .any(|(key, name)| key == &generic_function_key && name == &variant) + { + dependency_functions.push((generic_function_key.clone(), variant.clone())); + } else { + is_recursive = true; + } + + if let Some(func_variants) = function_usage.get_mut(&generic_function_key) { + if let Some((path, _)) = func_variants.get_mut(&variant) { + *path = path.common_ancestor(tree_path); + } else { + let mut function_air_tree_body = self.build(&function_def.body); + + function_air_tree_body.traverse_tree_with(&mut |air_tree, _| { + monomorphize(air_tree, &mono_types); + + erase_opaque_type_operations(air_tree, &self.data_types); + + if is_recursive{ + modify_self_calls(air_tree, &generic_function_key, &variant); + } + }); + + func_variants.insert( + variant, + ( + tree_path.clone(), + UserFunction::Function(function_air_tree_body, vec![]), + ), + ); + } + } else { + let mut function_air_tree_body = self.build(&function_def.body); + + function_air_tree_body.traverse_tree_with(&mut |air_tree, _| { + monomorphize(air_tree, &mono_types); + + erase_opaque_type_operations(air_tree, &self.data_types); + + if is_recursive{ + modify_self_calls(air_tree, &generic_function_key, &variant); + } + }); + + let mut function_variant_path = IndexMap::new(); + + function_variant_path.insert( + variant, + ( + tree_path.clone(), + UserFunction::Function(function_air_tree_body, vec![]), + ), + ); + + function_usage.insert(generic_function_key, function_variant_path); + } + } + }, + ); + } + fn uplc_code_gen(&mut self, ir_stack: &mut Vec) -> Term { let mut arg_stack: Vec> = vec![]; while let Some(ir_element) = ir_stack.pop() { self.gen_uplc(ir_element, &mut arg_stack); } - arg_stack[0].clone() + arg_stack.pop().unwrap() } fn gen_uplc(&mut self, ir: Air, arg_stack: &mut Vec>) { @@ -3957,7 +2910,7 @@ impl<'a> CodeGenerator<'a> { } else { for (index, arg) in constr_type.arguments.iter().enumerate().rev() { term = Term::mk_cons() - .apply(builder::convert_type_to_data( + .apply(convert_type_to_data( Term::var( arg.label .clone() @@ -4513,7 +3466,7 @@ impl<'a> CodeGenerator<'a> { arg_stack.push(term); } Air::Clause { - tipo, + subject_tipo: tipo, subject_name, complex_clause, .. @@ -4626,7 +3579,9 @@ impl<'a> CodeGenerator<'a> { arg_stack.push(term); } Air::ClauseGuard { - subject_name, tipo, .. + subject_name, + subject_tipo: tipo, + .. } => { let checker = arg_stack.pop().unwrap(); @@ -4713,7 +3668,7 @@ impl<'a> CodeGenerator<'a> { arg_stack.push(term); } - Air::Record { + Air::Constr { tag: constr_index, tipo, count, @@ -5109,7 +4064,7 @@ impl<'a> CodeGenerator<'a> { } Air::ErrorTerm { .. } => arg_stack.push(Term::Error), Air::TupleClause { - tipo, + subject_tipo: tipo, indices, subject_name, complex_clause, @@ -5155,77 +4110,12 @@ impl<'a> CodeGenerator<'a> { arg_stack.push(term); } Air::NoOp { .. } => {} - } - } - - pub fn wrap_validator_args( - &mut self, - validator_stack: &mut AirStack, - arguments: &[TypedArg], - has_context: bool, - ) { - let mut arg_stack = validator_stack.empty_with_scope(); - for (index, arg) in arguments.iter().enumerate().rev() { - let arg_name = arg.arg_name.get_variable_name().unwrap_or("_").to_string(); - if !(has_context && index == arguments.len() - 1) && &arg_name != "_" { - let mut param_stack = validator_stack.empty_with_scope(); - let mut value_stack = validator_stack.empty_with_scope(); - - param_stack.local_var(data(), arg.arg_name.get_variable_name().unwrap_or("_")); - - let mut actual_type = arg.tipo.clone(); - - replace_opaque_type(&mut actual_type, &self.data_types); - - self.assignment( - &Pattern::Var { - location: Span::empty(), - name: arg_name.to_string(), - }, - &mut value_stack, - param_stack, - &actual_type, - AssignmentProperties { - value_type: data(), - kind: AssignmentKind::Expect, - remove_unused: true, - full_check: false, - }, - ); - value_stack.local_var(actual_type, &arg_name); - - arg_stack.let_assignment(arg_name, value_stack); - } - } - - validator_stack.anonymous_function( - arguments - .iter() - .map(|arg| arg.arg_name.get_variable_name().unwrap_or("_").to_string()) - .collect_vec(), - arg_stack, - ) - } -} - -fn process_scope_updates( - to_be_defined_map: &mut IndexMap, - scope: &Scope, - func_index_map: &mut IndexMap, -) { - for func in to_be_defined_map.clone().iter() { - if &scope.common_ancestor(func.1) == scope { - if let Some(index_scope) = func_index_map.get(func.0) { - if &index_scope.common_ancestor(func.1) == scope { - func_index_map.insert(func.0.clone(), scope.clone()); - to_be_defined_map.shift_remove(func.0); - } else { - to_be_defined_map.insert(func.0.clone(), index_scope.common_ancestor(func.1)); - } - } else { - func_index_map.insert(func.0.clone(), scope.clone()); - to_be_defined_map.shift_remove(func.0); - } + Air::TupleGuard { + subject_tipo, + indices, + subject_name, + type_count, + } => todo!(), } } } diff --git a/crates/aiken-lang/src/gen_uplc/air.rs b/crates/aiken-lang/src/gen_uplc/air.rs index 190432a4..a832f70e 100644 --- a/crates/aiken-lang/src/gen_uplc/air.rs +++ b/crates/aiken-lang/src/gen_uplc/air.rs @@ -7,55 +7,42 @@ use crate::{ tipo::{Type, ValueConstructor}, }; -use super::scope::Scope; - #[derive(Debug, Clone, PartialEq)] pub enum Air { // Primitives Int { - scope: Scope, value: String, }, String { - scope: Scope, value: String, }, ByteArray { - scope: Scope, bytes: Vec, }, Bool { - scope: Scope, value: bool, }, List { - scope: Scope, count: usize, tipo: Arc, tail: bool, }, Tuple { - scope: Scope, tipo: Arc, count: usize, }, - Void { - scope: Scope, - }, + Void, Var { - scope: Scope, constructor: ValueConstructor, name: String, variant_name: String, }, // Functions Call { - scope: Scope, count: usize, tipo: Arc, }, DefineFunc { - scope: Scope, func_name: String, module_name: String, params: Vec, @@ -63,71 +50,58 @@ pub enum Air { variant_name: String, }, Fn { - scope: Scope, params: Vec, }, Builtin { - scope: Scope, count: usize, func: DefaultFunction, tipo: Arc, }, // Operators BinOp { - scope: Scope, name: BinOp, tipo: Arc, + argument_tipo: Arc, }, UnOp { - scope: Scope, op: UnOp, }, // Assignment Let { - scope: Scope, name: String, }, UnWrapData { - scope: Scope, tipo: Arc, }, WrapData { - scope: Scope, tipo: Arc, }, AssertConstr { - scope: Scope, constr_index: usize, }, AssertBool { - scope: Scope, is_true: bool, }, // When When { - scope: Scope, tipo: Arc, subject_name: String, + subject_tipo: Arc, }, Clause { - scope: Scope, - tipo: Arc, + subject_tipo: Arc, subject_name: String, complex_clause: bool, }, ListClause { - scope: Scope, - tipo: Arc, + subject_tipo: Arc, tail_name: String, next_tail_name: Option, complex_clause: bool, }, - WrapClause { - scope: Scope, - }, + WrapClause, TupleClause { - scope: Scope, - tipo: Arc, + subject_tipo: Arc, indices: IndexSet<(usize, String)>, predefined_indices: IndexSet<(usize, String)>, subject_name: String, @@ -135,296 +109,76 @@ pub enum Air { complex_clause: bool, }, ClauseGuard { - scope: Scope, subject_name: String, - tipo: Arc, + subject_tipo: Arc, }, ListClauseGuard { - scope: Scope, - tipo: Arc, + subject_tipo: Arc, tail_name: String, next_tail_name: Option, inverse: bool, }, - Finally { - scope: Scope, + TupleGuard { + subject_tipo: Arc, + indices: IndexSet<(usize, String)>, + subject_name: String, + type_count: usize, }, + Finally, // If If { - scope: Scope, tipo: Arc, }, // Record Creation - Record { - scope: Scope, + Constr { tag: usize, tipo: Arc, count: usize, }, RecordUpdate { - scope: Scope, highest_index: usize, indices: Vec<(usize, Arc)>, tipo: Arc, }, // Field Access RecordAccess { - scope: Scope, record_index: u64, tipo: Arc, }, FieldsExpose { - scope: Scope, indices: Vec<(usize, String, Arc)>, check_last_item: bool, }, // ListAccess ListAccessor { - scope: Scope, tipo: Arc, names: Vec, tail: bool, check_last_item: bool, }, ListExpose { - scope: Scope, tipo: Arc, tail_head_names: Vec<(String, String)>, tail: Option<(String, String)>, }, // Tuple Access TupleAccessor { - scope: Scope, names: Vec, tipo: Arc, check_last_item: bool, }, TupleIndex { - scope: Scope, tipo: Arc, tuple_index: usize, }, // Misc. ErrorTerm { - scope: Scope, tipo: Arc, }, Trace { - scope: Scope, tipo: Arc, }, - NoOp { - scope: Scope, - }, - FieldsEmpty { - scope: Scope, - }, - ListEmpty { - scope: Scope, - }, -} - -impl Air { - pub fn scope(&self) -> Scope { - match self { - Air::Int { scope, .. } - | Air::String { scope, .. } - | Air::ByteArray { scope, .. } - | Air::Bool { scope, .. } - | Air::List { scope, .. } - | Air::Tuple { scope, .. } - | Air::Void { scope } - | Air::Var { scope, .. } - | Air::Call { scope, .. } - | Air::DefineFunc { scope, .. } - | Air::Fn { scope, .. } - | Air::Builtin { scope, .. } - | Air::BinOp { scope, .. } - | Air::UnOp { scope, .. } - | Air::Let { scope, .. } - | Air::UnWrapData { scope, .. } - | Air::WrapData { scope, .. } - | Air::AssertConstr { scope, .. } - | Air::AssertBool { scope, .. } - | Air::When { scope, .. } - | Air::Clause { scope, .. } - | Air::ListClause { scope, .. } - | Air::WrapClause { scope } - | Air::TupleClause { scope, .. } - | Air::ClauseGuard { scope, .. } - | Air::ListClauseGuard { scope, .. } - | Air::Finally { scope } - | Air::If { scope, .. } - | Air::Record { scope, .. } - | Air::RecordUpdate { scope, .. } - | Air::RecordAccess { scope, .. } - | Air::FieldsExpose { scope, .. } - | Air::FieldsEmpty { scope } - | Air::ListEmpty { scope } - | Air::ListAccessor { scope, .. } - | Air::ListExpose { scope, .. } - | Air::TupleAccessor { scope, .. } - | Air::TupleIndex { scope, .. } - | Air::ErrorTerm { scope, .. } - | Air::Trace { scope, .. } - | Air::NoOp { scope, .. } => scope.clone(), - } - } - pub fn scope_mut(&mut self) -> &mut Scope { - match self { - Air::Int { scope, .. } - | Air::String { scope, .. } - | Air::ByteArray { scope, .. } - | Air::Bool { scope, .. } - | Air::List { scope, .. } - | Air::Tuple { scope, .. } - | Air::Void { scope } - | Air::Var { scope, .. } - | Air::Call { scope, .. } - | Air::DefineFunc { scope, .. } - | Air::Fn { scope, .. } - | Air::Builtin { scope, .. } - | Air::BinOp { scope, .. } - | Air::UnOp { scope, .. } - | Air::Let { scope, .. } - | Air::UnWrapData { scope, .. } - | Air::WrapData { scope, .. } - | Air::AssertConstr { scope, .. } - | Air::AssertBool { scope, .. } - | Air::When { scope, .. } - | Air::Clause { scope, .. } - | Air::ListClause { scope, .. } - | Air::WrapClause { scope } - | Air::TupleClause { scope, .. } - | Air::ClauseGuard { scope, .. } - | Air::ListClauseGuard { scope, .. } - | Air::Finally { scope } - | Air::If { scope, .. } - | Air::Record { scope, .. } - | Air::RecordUpdate { scope, .. } - | Air::RecordAccess { scope, .. } - | Air::FieldsExpose { scope, .. } - | Air::FieldsEmpty { scope } - | Air::ListEmpty { scope } - | Air::ListAccessor { scope, .. } - | Air::ListExpose { scope, .. } - | Air::TupleAccessor { scope, .. } - | Air::TupleIndex { scope, .. } - | Air::ErrorTerm { scope, .. } - | Air::Trace { scope, .. } - | Air::NoOp { scope, .. } => scope, - } - } - pub fn tipo(&self) -> Option> { - match self { - Air::Int { .. } => Some( - Type::App { - public: true, - module: String::new(), - name: "Int".to_string(), - args: vec![], - } - .into(), - ), - Air::String { .. } => Some( - Type::App { - public: true, - module: String::new(), - name: "String".to_string(), - args: vec![], - } - .into(), - ), - Air::ByteArray { .. } => Some( - Type::App { - public: true, - module: String::new(), - name: "ByteArray".to_string(), - args: vec![], - } - .into(), - ), - Air::Bool { .. } => Some( - Type::App { - public: true, - module: String::new(), - name: "Bool".to_string(), - args: vec![], - } - .into(), - ), - Air::Void { .. } => Some( - Type::App { - public: true, - module: String::new(), - name: "Void".to_string(), - args: vec![], - } - .into(), - ), - Air::WrapData { .. } => Some( - Type::App { - public: true, - module: String::new(), - name: "Data".to_string(), - args: vec![], - } - .into(), - ), - Air::Var { constructor, .. } => Some(constructor.tipo.clone()), - Air::List { tipo, .. } - | Air::Tuple { tipo, .. } - | Air::Call { tipo, .. } - | Air::Builtin { tipo, .. } - | Air::BinOp { tipo, .. } - | Air::UnWrapData { tipo, .. } - | Air::When { tipo, .. } - | Air::Clause { tipo, .. } - | Air::ListClause { tipo, .. } - | Air::TupleClause { tipo, .. } - | Air::ClauseGuard { tipo, .. } - | Air::If { tipo, .. } - | Air::ListClauseGuard { tipo, .. } - | Air::Record { tipo, .. } - | Air::RecordUpdate { tipo, .. } - | Air::RecordAccess { tipo, .. } - | Air::ListAccessor { tipo, .. } - | Air::ListExpose { tipo, .. } - | Air::TupleAccessor { tipo, .. } - | Air::TupleIndex { tipo, .. } - | Air::ErrorTerm { tipo, .. } - | Air::Trace { tipo, .. } => Some(tipo.clone()), - Air::DefineFunc { .. } - | Air::Fn { .. } - | Air::Let { .. } - | Air::WrapClause { .. } - | Air::AssertConstr { .. } - | Air::AssertBool { .. } - | Air::Finally { .. } - | Air::FieldsExpose { .. } - | Air::FieldsEmpty { .. } - | Air::ListEmpty { .. } - | Air::NoOp { .. } => None, - Air::UnOp { op, .. } => match op { - UnOp::Not => Some( - Type::App { - public: true, - module: String::new(), - name: "Bool".to_string(), - args: vec![], - } - .into(), - ), - UnOp::Negate => Some( - Type::App { - public: true, - module: String::new(), - name: "Int".to_string(), - args: vec![], - } - .into(), - ), - }, - } - } + NoOp, + FieldsEmpty, + ListEmpty, } diff --git a/crates/aiken-lang/src/gen_uplc/builder.rs b/crates/aiken-lang/src/gen_uplc/builder.rs index 33d3b4e3..c60afc25 100644 --- a/crates/aiken-lang/src/gen_uplc/builder.rs +++ b/crates/aiken-lang/src/gen_uplc/builder.rs @@ -14,16 +14,33 @@ use uplc::{ }; use crate::{ - ast::{ - AssignmentKind, BinOp, ClauseGuard, Constant, DataType, Pattern, Span, TypedArg, - TypedClause, TypedDataType, UnOp, - }, + ast::{AssignmentKind, DataType, Pattern, Span, TypedClause, TypedDataType}, + builtins::bool, expr::TypedExpr, - tipo::{PatternConstructor, Type, TypeVar, ValueConstructorVariant}, - IdGenerator, + tipo::{PatternConstructor, TypeVar, ValueConstructor, ValueConstructorVariant}, }; -use super::{air::Air, scope::Scope, stack::AirStack}; +use crate::{ + ast::{BinOp, ClauseGuard, Constant, UnOp}, + tipo::Type, +}; + +use super::{ + air::Air, + tree::{AirExpression, AirStatement, AirTree}, +}; + +#[derive(Clone, Debug)] +pub enum CodeGenFunction { + Function { body: AirTree, params: Vec }, + Link(String), +} + +#[derive(Clone, Debug)] +pub enum UserFunction { + Function(AirTree, Vec<(FunctionAccessKey, String)>), + Link(String), +} #[derive(Clone, Debug)] pub struct FuncComponents { @@ -164,93 +181,416 @@ impl ClauseProperties { } } -pub fn convert_type_to_data(term: Term, field_type: &Arc) -> Term { - if field_type.is_bytearray() { - Term::b_data().apply(term) - } else if field_type.is_int() { - Term::i_data().apply(term) - } else if field_type.is_void() { - term.choose_unit(Term::Constant( - UplcConstant::Data(PlutusData::Constr(Constr { - tag: convert_constr_to_tag(0).unwrap(), - any_constructor: None, - fields: vec![], - })) - .into(), - )) - } else if field_type.is_map() { - Term::map_data().apply(term) - } else if field_type.is_string() { - Term::b_data().apply(Term::Builtin(DefaultFunction::EncodeUtf8).apply(term)) - } else if field_type.is_tuple() && matches!(field_type.get_uplc_type(), UplcType::Pair(_, _)) { - Term::list_data() - .apply( - Term::mk_cons() - .apply(Term::fst_pair().apply(Term::var("__pair"))) - .apply( - Term::mk_cons() - .apply(Term::snd_pair().apply(Term::var("__pair"))) - .apply(Term::empty_list()), - ), - ) - .lambda("__pair") - .apply(term) - } else if field_type.is_list() || field_type.is_tuple() { - Term::list_data().apply(term) - } else if field_type.is_bool() { - term.if_else( - Term::Constant( - UplcConstant::Data(PlutusData::Constr(Constr { - tag: convert_constr_to_tag(1).unwrap(), - any_constructor: None, - fields: vec![], - })) - .into(), - ), - Term::Constant( - UplcConstant::Data(PlutusData::Constr(Constr { - tag: convert_constr_to_tag(0).unwrap(), - any_constructor: None, - fields: vec![], - })) - .into(), - ), - ) - } else { - term +pub fn get_generic_id_and_type(tipo: &Type, param: &Type) -> Vec<(u64, Arc)> { + let mut generics_ids = vec![]; + + if let Some(id) = tipo.get_generic() { + generics_ids.push((id, param.clone().into())); + return generics_ids; + } + + for (tipo, param_type) in tipo + .get_inner_types() + .iter() + .zip(param.get_inner_types().iter()) + { + generics_ids.append(&mut get_generic_id_and_type(tipo, param_type)); + } + generics_ids +} + +pub fn lookup_data_type_by_tipo( + data_types: &IndexMap, + tipo: &Type, +) -> Option>> { + match tipo { + Type::Fn { ret, .. } => match ret.as_ref() { + Type::App { module, name, .. } => { + let data_type_key = DataTypeKey { + module_name: module.clone(), + defined_type: name.clone(), + }; + data_types.get(&data_type_key).map(|item| (*item).clone()) + } + _ => None, + }, + Type::App { module, name, .. } => { + let data_type_key = DataTypeKey { + module_name: module.clone(), + defined_type: name.clone(), + }; + + data_types.get(&data_type_key).map(|item| (*item).clone()) + } + Type::Var { tipo } => { + if let TypeVar::Link { tipo } = &*tipo.borrow() { + lookup_data_type_by_tipo(data_types, tipo) + } else { + None + } + } + _ => None, } } -pub fn convert_data_to_type(term: Term, field_type: &Arc) -> Term { - if field_type.is_int() { - Term::un_i_data().apply(term) - } else if field_type.is_bytearray() { - Term::un_b_data().apply(term) - } else if field_type.is_void() { - Term::equals_integer() - .apply(Term::integer(0.into())) - .apply(Term::fst_pair().apply(Term::unconstr_data().apply(term))) - .delayed_if_else(Term::unit(), Term::Error) - } else if field_type.is_map() { - Term::unmap_data().apply(term) - } else if field_type.is_string() { - Term::Builtin(DefaultFunction::DecodeUtf8).apply(Term::un_b_data().apply(term)) - } else if field_type.is_tuple() && matches!(field_type.get_uplc_type(), UplcType::Pair(_, _)) { - Term::mk_pair_data() - .apply(Term::head_list().apply(Term::var("__list_data"))) - .apply(Term::head_list().apply(Term::var("__tail"))) - .lambda("__tail") - .apply(Term::tail_list().apply(Term::var("__list_data"))) - .lambda("__list_data") - .apply(Term::unlist_data().apply(term)) - } else if field_type.is_list() || field_type.is_tuple() { - Term::unlist_data().apply(term) - } else if field_type.is_bool() { - Term::equals_integer() - .apply(Term::integer(1.into())) - .apply(Term::fst_pair().apply(Term::unconstr_data().apply(term))) +pub fn get_arg_type_name(tipo: &Type) -> String { + match tipo { + Type::App { name, args, .. } => { + let inner_args = args.iter().map(|arg| get_arg_type_name(arg)).collect_vec(); + format!("{}_{}", name, inner_args.join("_")) + } + Type::Var { tipo } => match tipo.borrow().clone() { + TypeVar::Link { tipo } => get_arg_type_name(tipo.as_ref()), + _ => unreachable!(), + }, + Type::Tuple { elems } => { + let inner_args = elems.iter().map(|arg| get_arg_type_name(arg)).collect_vec(); + inner_args.join("_") + } + _ => unreachable!(), + } +} + +pub fn convert_opaque_type( + t: &Arc, + data_types: &IndexMap, +) -> Arc { + if check_replaceable_opaque_type(t, data_types) && matches!(t.as_ref(), Type::App { .. }) { + let data_type = lookup_data_type_by_tipo(data_types, t).unwrap(); + let new_type_fields = data_type.typed_parameters; + + let mono_types: IndexMap>; + let mut mono_type_vec = vec![]; + + for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) { + mono_type_vec.append(&mut get_generic_id_and_type(tipo, ¶m)); + } + mono_types = mono_type_vec.into_iter().collect(); + + let generic_type = &data_type.constructors[0].arguments[0].tipo; + + let mono_type = find_and_replace_generics(generic_type, &mono_types); + + convert_opaque_type(&mono_type, data_types) } else { - term + match t.as_ref() { + Type::App { + public, + module, + name, + args, + } => { + let mut new_args = vec![]; + for arg in args { + let arg = convert_opaque_type(arg, data_types); + new_args.push(arg); + } + Type::App { + public: *public, + module: module.clone(), + name: name.clone(), + args: new_args, + } + .into() + } + Type::Fn { args, ret } => { + let mut new_args = vec![]; + for arg in args { + let arg = convert_opaque_type(arg, data_types); + new_args.push(arg); + } + + let ret = convert_opaque_type(ret, data_types); + + Type::Fn { + args: new_args, + ret, + } + .into() + } + Type::Var { tipo: var_tipo } => { + if let TypeVar::Link { tipo } = &var_tipo.borrow().clone() { + convert_opaque_type(tipo, data_types) + } else { + t.clone() + } + } + Type::Tuple { elems } => { + let mut new_elems = vec![]; + for arg in elems { + let arg = convert_opaque_type(arg, data_types); + new_elems.push(arg); + } + Type::Tuple { elems: new_elems }.into() + } + } + } +} + +pub fn check_replaceable_opaque_type( + t: &Arc, + data_types: &IndexMap, +) -> bool { + let data_type = lookup_data_type_by_tipo(data_types, t); + + if let Some(data_type) = data_type { + let data_type_args = &data_type.constructors[0].arguments; + data_type_args.len() == 1 && data_type.opaque && data_type.constructors.len() == 1 + } else { + false + } +} + +pub fn find_and_replace_generics( + tipo: &Arc, + mono_types: &IndexMap>, +) -> Arc { + if let Some(id) = tipo.get_generic() { + // If a generic does not have a type we know of + // like a None in option then just use same type + mono_types.get(&id).unwrap_or(tipo).clone() + } else if tipo.is_generic() { + match &**tipo { + Type::App { + args, + public, + module, + name, + } => { + let mut new_args = vec![]; + for arg in args { + let arg = find_and_replace_generics(arg, mono_types); + new_args.push(arg); + } + let t = Type::App { + args: new_args, + public: *public, + module: module.clone(), + name: name.clone(), + }; + t.into() + } + Type::Fn { args, ret } => { + let mut new_args = vec![]; + for arg in args { + let arg = find_and_replace_generics(arg, mono_types); + new_args.push(arg); + } + + let ret = find_and_replace_generics(ret, mono_types); + + let t = Type::Fn { + args: new_args, + ret, + }; + + t.into() + } + Type::Tuple { elems } => { + let mut new_elems = vec![]; + for elem in elems { + let elem = find_and_replace_generics(elem, mono_types); + new_elems.push(elem); + } + let t = Type::Tuple { elems: new_elems }; + t.into() + } + Type::Var { tipo: var_tipo } => { + let var_type = var_tipo.as_ref().borrow().clone(); + + match var_type { + TypeVar::Link { tipo } => find_and_replace_generics(&tipo, mono_types), + TypeVar::Generic { .. } | TypeVar::Unbound { .. } => unreachable!(), + } + } + } + } else { + tipo.clone() + } +} + +pub fn constants_ir(literal: &Constant) -> AirTree { + match literal { + Constant::Int { value, .. } => AirTree::int(value), + Constant::String { value, .. } => AirTree::string(value), + 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_child = handle_clause_guard(left); + let right_child = handle_clause_guard(right); + + AirTree::binop(BinOp::Eq, bool(), left_child, right_child, left.tipo()) + } + ClauseGuard::NotEquals { left, right, .. } => { + let left_child = handle_clause_guard(left); + let right_child = handle_clause_guard(right); + + AirTree::binop(BinOp::NotEq, bool(), left_child, right_child, left.tipo()) + } + ClauseGuard::GtInt { left, right, .. } => { + let left_child = handle_clause_guard(left); + let right_child = handle_clause_guard(right); + + AirTree::binop(BinOp::GtInt, bool(), left_child, right_child, left.tipo()) + } + ClauseGuard::GtEqInt { left, right, .. } => { + let left_child = handle_clause_guard(left); + let right_child = handle_clause_guard(right); + + AirTree::binop(BinOp::GtEqInt, bool(), left_child, right_child, left.tipo()) + } + ClauseGuard::LtInt { left, right, .. } => { + let left_child = handle_clause_guard(left); + let right_child = handle_clause_guard(right); + + AirTree::binop(BinOp::LtInt, bool(), left_child, right_child, left.tipo()) + } + ClauseGuard::LtEqInt { left, right, .. } => { + let left_child = handle_clause_guard(left); + let right_child = handle_clause_guard(right); + + AirTree::binop(BinOp::LtEqInt, bool(), left_child, right_child, left.tipo()) + } + ClauseGuard::Or { left, right, .. } => { + let left_child = handle_clause_guard(left); + let right_child = handle_clause_guard(right); + + AirTree::binop(BinOp::Or, bool(), left_child, right_child, left.tipo()) + } + ClauseGuard::And { left, right, .. } => { + let left_child = handle_clause_guard(left); + let right_child = handle_clause_guard(right); + + AirTree::binop(BinOp::And, bool(), left_child, right_child, left.tipo()) + } + ClauseGuard::Var { tipo, name, .. } => AirTree::local_var(name, tipo.clone()), + ClauseGuard::Constant(constant) => constants_ir(constant), + } +} + +pub fn get_variant_name(t: &Arc) -> String { + if t.is_string() { + "_string".to_string() + } else if t.is_int() { + "_int".to_string() + } else if t.is_bool() { + "_bool".to_string() + } else if t.is_bytearray() { + "_bytearray".to_string() + } else if t.is_map() { + let mut full_type = vec!["_map".to_string()]; + let pair_type = &t.get_inner_types()[0]; + let fst_type = &pair_type.get_inner_types()[0]; + let snd_type = &pair_type.get_inner_types()[1]; + full_type.push(get_variant_name(fst_type)); + full_type.push(get_variant_name(snd_type)); + full_type.join("") + } else if t.is_list() { + let full_type = "_list".to_string(); + let list_type = &t.get_inner_types()[0]; + + format!("{}{}", full_type, get_variant_name(list_type)) + } else if t.is_tuple() { + let mut full_type = vec!["_tuple".to_string()]; + + let inner_types = t.get_inner_types(); + + for arg_type in inner_types { + full_type.push(get_variant_name(&arg_type)); + } + full_type.join("") + } else if t.is_unbound() { + "_unbound".to_string() + } else { + let full_type = "_data".to_string(); + + if t.is_generic() { + println!("FULL TYPE: {:#?}", t); + panic!("FOUND A POLYMORPHIC TYPE. EXPECTED MONOMORPHIC TYPE"); + } + + full_type + } +} + +pub fn monomorphize(air_tree: &mut AirTree, mono_types: &IndexMap>) { + let mut held_types = air_tree.mut_held_types(); + + while let Some(tipo) = held_types.pop() { + *tipo = find_and_replace_generics(tipo, mono_types); + } +} + +pub fn erase_opaque_type_operations( + air_tree: &mut AirTree, + data_types: &IndexMap, +) { + if let AirTree::Expression(e) = air_tree { + match e { + AirExpression::Constr { tipo, args, .. } => { + if check_replaceable_opaque_type(tipo, data_types) { + *air_tree = args.pop().unwrap(); + } + } + AirExpression::RecordAccess { tipo, record, .. } => { + if check_replaceable_opaque_type(tipo, data_types) { + *air_tree = (**record).clone(); + } + } + + _ => {} + } + } else if let AirTree::Statement { + statement: AirStatement::FieldsExpose { + record, indices, .. + }, + hoisted_over: Some(hoisted_over), + } = air_tree + { + if check_replaceable_opaque_type(&record.return_type(), data_types) { + let name = indices[0].1.clone(); + *air_tree = AirTree::let_assignment(name, (**record).clone()) + .hoist_over((**hoisted_over).clone()) + } + } + + let mut held_types = air_tree.mut_held_types(); + + while let Some(tipo) = held_types.pop() { + *tipo = convert_opaque_type(tipo, data_types); + } +} + +pub fn modify_self_calls(air_tree: &mut AirTree, func_key: &FunctionAccessKey, variant: &String) { + if let AirTree::Expression(AirExpression::Call { func, args, .. }) = air_tree { + if let AirTree::Expression(AirExpression::Var { + constructor: + ValueConstructor { + variant: ValueConstructorVariant::ModuleFn { name, module, .. }, + .. + }, + variant_name, + .. + }) = func.as_ref() + { + if name == &func_key.function_name + && module == &func_key.module_name + && variant == variant_name + { + let mut new_args = vec![func.as_ref().clone()]; + new_args.append(args); + *args = new_args; + } + } } } @@ -457,21 +797,173 @@ pub fn rearrange_clauses(clauses: Vec) -> Vec { final_clauses } -/// If the pattern is a list the return the number of elements and if it has a tail -/// Otherwise return None -pub fn get_list_elements_len_and_tail( - pattern: &Pattern>, -) -> Option<(usize, bool)> { - if let Pattern::List { elements, tail, .. } = &pattern { - Some((elements.len(), tail.is_some())) - } else if let Pattern::Assign { pattern, .. } = &pattern { - if let Pattern::List { elements, tail, .. } = pattern.as_ref() { - Some((elements.len(), tail.is_some())) - } else { - None - } +pub fn convert_data_to_type(term: Term, field_type: &Arc) -> Term { + if field_type.is_int() { + Term::un_i_data().apply(term) + } else if field_type.is_bytearray() { + Term::un_b_data().apply(term) + } else if field_type.is_void() { + Term::equals_integer() + .apply(Term::integer(0.into())) + .apply(Term::fst_pair().apply(Term::unconstr_data().apply(term))) + .delayed_if_else(Term::unit(), Term::Error) + } else if field_type.is_map() { + Term::unmap_data().apply(term) + } else if field_type.is_string() { + Term::Builtin(DefaultFunction::DecodeUtf8).apply(Term::un_b_data().apply(term)) + } else if field_type.is_tuple() && matches!(field_type.get_uplc_type(), UplcType::Pair(_, _)) { + Term::mk_pair_data() + .apply(Term::head_list().apply(Term::var("__list_data"))) + .apply(Term::head_list().apply(Term::var("__tail"))) + .lambda("__tail") + .apply(Term::tail_list().apply(Term::var("__list_data"))) + .lambda("__list_data") + .apply(Term::unlist_data().apply(term)) + } else if field_type.is_list() || field_type.is_tuple() { + Term::unlist_data().apply(term) + } else if field_type.is_bool() { + Term::equals_integer() + .apply(Term::integer(1.into())) + .apply(Term::fst_pair().apply(Term::unconstr_data().apply(term))) } else { - None + term + } +} + +pub fn convert_constants_to_data(constants: Vec>) -> Vec { + let mut new_constants = vec![]; + for constant in constants { + let constant = match constant.as_ref() { + UplcConstant::Integer(i) => UplcConstant::Data(PlutusData::BigInt(to_pallas_bigint(i))), + UplcConstant::ByteString(b) => { + UplcConstant::Data(PlutusData::BoundedBytes(b.clone().try_into().unwrap())) + } + UplcConstant::String(s) => UplcConstant::Data(PlutusData::BoundedBytes( + s.as_bytes().to_vec().try_into().unwrap(), + )), + + UplcConstant::Bool(b) => UplcConstant::Data(PlutusData::Constr(Constr { + tag: convert_constr_to_tag((*b).into()).unwrap_or(ANY_TAG), + any_constructor: convert_constr_to_tag((*b).into()) + .map_or(Some((*b).into()), |_| None), + fields: vec![], + })), + UplcConstant::ProtoList(list_type, constants) => { + if matches!(list_type, UplcType::Pair(_, _)) { + let inner_constants = constants + .iter() + .cloned() + .map(|pair| match pair { + UplcConstant::ProtoPair(_, _, left, right) => { + let inner_constants = vec![left, right]; + let inner_constants = convert_constants_to_data(inner_constants) + .into_iter() + .map(|constant| match constant { + UplcConstant::Data(d) => d, + _ => todo!(), + }) + .collect_vec(); + (inner_constants[0].clone(), inner_constants[1].clone()) + } + _ => unreachable!(), + }) + .collect_vec(); + + UplcConstant::Data(PlutusData::Map(KeyValuePairs::Def(inner_constants))) + } else { + let inner_constants = + convert_constants_to_data(constants.iter().cloned().map(Rc::new).collect()) + .into_iter() + .map(|constant| match constant { + UplcConstant::Data(d) => d, + _ => todo!(), + }) + .collect_vec(); + + UplcConstant::Data(PlutusData::Array(inner_constants)) + } + } + UplcConstant::ProtoPair(_, _, left, right) => { + let inner_constants = vec![left.clone(), right.clone()]; + let inner_constants = convert_constants_to_data(inner_constants) + .into_iter() + .map(|constant| match constant { + UplcConstant::Data(d) => d, + _ => todo!(), + }) + .collect_vec(); + + UplcConstant::Data(PlutusData::Array(vec![ + inner_constants[0].clone(), + inner_constants[1].clone(), + ])) + } + d @ UplcConstant::Data(_) => d.clone(), + UplcConstant::Unit => UplcConstant::Data(PlutusData::Constr(Constr { + tag: convert_constr_to_tag(0).unwrap(), + any_constructor: None, + fields: vec![], + })), + }; + new_constants.push(constant); + } + new_constants +} + +pub fn convert_type_to_data(term: Term, field_type: &Arc) -> Term { + if field_type.is_bytearray() { + Term::b_data().apply(term) + } else if field_type.is_int() { + Term::i_data().apply(term) + } else if field_type.is_void() { + term.choose_unit(Term::Constant( + UplcConstant::Data(PlutusData::Constr(Constr { + tag: convert_constr_to_tag(0).unwrap(), + any_constructor: None, + fields: vec![], + })) + .into(), + )) + } else if field_type.is_map() { + Term::map_data().apply(term) + } else if field_type.is_string() { + Term::b_data().apply(Term::Builtin(DefaultFunction::EncodeUtf8).apply(term)) + } else if field_type.is_tuple() && matches!(field_type.get_uplc_type(), UplcType::Pair(_, _)) { + Term::list_data() + .apply( + Term::mk_cons() + .apply(Term::fst_pair().apply(Term::var("__pair"))) + .apply( + Term::mk_cons() + .apply(Term::snd_pair().apply(Term::var("__pair"))) + .apply(Term::empty_list()), + ), + ) + .lambda("__pair") + .apply(term) + } else if field_type.is_list() || field_type.is_tuple() { + Term::list_data().apply(term) + } else if field_type.is_bool() { + term.if_else( + Term::Constant( + UplcConstant::Data(PlutusData::Constr(Constr { + tag: convert_constr_to_tag(1).unwrap(), + any_constructor: None, + fields: vec![], + })) + .into(), + ), + Term::Constant( + UplcConstant::Data(PlutusData::Constr(Constr { + tag: convert_constr_to_tag(0).unwrap(), + any_constructor: None, + fields: vec![], + })) + .into(), + ), + ) + } else { + term } } @@ -675,1179 +1167,6 @@ pub fn list_access_to_uplc( } } -pub fn check_when_pattern_needs( - pattern: &Pattern>, - clause_properties: &mut ClauseProperties, -) { - match pattern { - Pattern::Var { .. } => { - clause_properties.needs_constr_var = true; - } - Pattern::List { elements, tail, .. } => { - clause_properties.needs_constr_var = true; - - clause_properties.complex_clause = true; - - for element in elements { - check_when_pattern_needs(element, clause_properties); - } - if let Some(tail) = tail { - check_when_pattern_needs(tail, clause_properties); - } - } - Pattern::Tuple { elems, .. } => { - clause_properties.needs_constr_var = true; - - clause_properties.complex_clause = true; - - for element in elems { - check_when_pattern_needs(element, clause_properties); - } - } - Pattern::Int { .. } => { - clause_properties.needs_constr_var = true; - - clause_properties.complex_clause = true; - } - Pattern::Constructor { arguments, .. } => { - clause_properties.needs_constr_var = true; - - clause_properties.complex_clause = true; - - for argument in arguments { - check_when_pattern_needs(&argument.value, clause_properties); - } - } - Pattern::Discard { .. } => { - clause_properties.needs_constr_var = true; - } - Pattern::Assign { pattern, .. } => { - clause_properties.needs_constr_var = true; - - check_when_pattern_needs(pattern, clause_properties) - } - } -} - -pub fn constants_ir(literal: &Constant, ir_stack: &mut AirStack) { - match literal { - Constant::Int { value, .. } => { - ir_stack.integer(value.clone()); - } - Constant::String { value, .. } => { - ir_stack.string(value.clone()); - } - Constant::ByteArray { bytes, .. } => { - ir_stack.byte_array(bytes.clone()); - } - }; -} - -pub fn match_ir_for_recursion( - ir: Air, - insert_var_vec: &mut Vec<(usize, Air)>, - function_access_key: &FunctionAccessKey, - index: usize, -) { - if let Air::Var { - scope, - constructor, - variant_name, - .. - } = ir - { - if let ValueConstructorVariant::ModuleFn { - name: func_name, - module, - .. - } = constructor.clone().variant - { - let var_func_access = FunctionAccessKey { - module_name: module, - function_name: func_name.clone(), - }; - - if function_access_key.clone() == var_func_access { - insert_var_vec.push(( - index, - Air::Var { - scope, - constructor, - name: func_name, - variant_name, - }, - )); - } - } - } -} - -pub fn find_and_replace_generics(tipo: &mut Arc, mono_types: &IndexMap>) { - if let Some(id) = tipo.get_generic() { - // If a generic does not have a type we know of - // like a None in option then just use same type - *tipo = mono_types.get(&id).unwrap_or(tipo).clone(); - } else if tipo.is_generic() { - match &**tipo { - Type::App { - args, - public, - module, - name, - } => { - let mut new_args = vec![]; - for arg in args { - let mut arg = arg.clone(); - find_and_replace_generics(&mut arg, mono_types); - new_args.push(arg); - } - let t = Type::App { - args: new_args, - public: *public, - module: module.clone(), - name: name.clone(), - }; - *tipo = t.into(); - } - Type::Fn { args, ret } => { - let mut new_args = vec![]; - for arg in args { - let mut arg = arg.clone(); - find_and_replace_generics(&mut arg, mono_types); - new_args.push(arg); - } - - let mut ret = ret.clone(); - find_and_replace_generics(&mut ret, mono_types); - - let t = Type::Fn { - args: new_args, - ret, - }; - *tipo = t.into(); - } - Type::Tuple { elems } => { - let mut new_elems = vec![]; - for elem in elems { - let mut elem = elem.clone(); - find_and_replace_generics(&mut elem, mono_types); - new_elems.push(elem); - } - let t = Type::Tuple { elems: new_elems }; - *tipo = t.into(); - } - Type::Var { tipo: var_tipo } => { - let var_type = var_tipo.as_ref().borrow().clone(); - let var_tipo = match var_type { - TypeVar::Link { tipo } => { - let mut tipo = tipo; - find_and_replace_generics(&mut tipo, mono_types); - tipo - } - TypeVar::Generic { .. } | TypeVar::Unbound { .. } => unreachable!(), - }; - - *tipo = var_tipo; - } - }; - } -} - -pub fn get_generic_id_and_type(tipo: &Type, param: &Type) -> Vec<(u64, Arc)> { - let mut generics_ids = vec![]; - - if let Some(id) = tipo.get_generic() { - generics_ids.push((id, param.clone().into())); - return generics_ids; - } - - for (tipo, param_type) in tipo - .get_inner_types() - .iter() - .zip(param.get_inner_types().iter()) - { - generics_ids.append(&mut get_generic_id_and_type(tipo, param_type)); - } - generics_ids -} - -pub fn get_variant_name(new_name: &mut String, t: &Arc) { - new_name.push_str(&if t.is_string() { - "_string".to_string() - } else if t.is_int() { - "_int".to_string() - } else if t.is_bool() { - "_bool".to_string() - } else if t.is_bytearray() { - "_bytearray".to_string() - } else if t.is_map() { - let mut full_type = "_map".to_string(); - let pair_type = &t.get_inner_types()[0]; - let fst_type = &pair_type.get_inner_types()[0]; - let snd_type = &pair_type.get_inner_types()[1]; - - get_variant_name(&mut full_type, fst_type); - get_variant_name(&mut full_type, snd_type); - full_type - } else if t.is_list() { - let mut full_type = "_list".to_string(); - let list_type = &t.get_inner_types()[0]; - get_variant_name(&mut full_type, list_type); - full_type - } else if t.is_tuple() { - let mut full_type = "_tuple".to_string(); - - let inner_types = t.get_inner_types(); - - for arg_type in inner_types { - get_variant_name(&mut full_type, &arg_type); - } - full_type - } else if t.is_unbound() { - "_unbound".to_string() - } else { - let full_type = "_data".to_string(); - - if t.is_generic() { - panic!("FOUND A POLYMORPHIC TYPE. EXPECTED MONOMORPHIC TYPE"); - } - - full_type - }); -} - -pub fn convert_constants_to_data(constants: Vec>) -> Vec { - let mut new_constants = vec![]; - for constant in constants { - let constant = match constant.as_ref() { - UplcConstant::Integer(i) => UplcConstant::Data(PlutusData::BigInt(to_pallas_bigint(i))), - UplcConstant::ByteString(b) => { - UplcConstant::Data(PlutusData::BoundedBytes(b.clone().try_into().unwrap())) - } - UplcConstant::String(s) => UplcConstant::Data(PlutusData::BoundedBytes( - s.as_bytes().to_vec().try_into().unwrap(), - )), - - UplcConstant::Bool(b) => UplcConstant::Data(PlutusData::Constr(Constr { - tag: convert_constr_to_tag((*b).into()).unwrap_or(ANY_TAG), - any_constructor: convert_constr_to_tag((*b).into()) - .map_or(Some((*b).into()), |_| None), - fields: vec![], - })), - UplcConstant::ProtoList(list_type, constants) => { - if matches!(list_type, UplcType::Pair(_, _)) { - let inner_constants = constants - .iter() - .cloned() - .map(|pair| match pair { - UplcConstant::ProtoPair(_, _, left, right) => { - let inner_constants = vec![left, right]; - let inner_constants = convert_constants_to_data(inner_constants) - .into_iter() - .map(|constant| match constant { - UplcConstant::Data(d) => d, - _ => todo!(), - }) - .collect_vec(); - (inner_constants[0].clone(), inner_constants[1].clone()) - } - _ => unreachable!(), - }) - .collect_vec(); - - UplcConstant::Data(PlutusData::Map(KeyValuePairs::Def(inner_constants))) - } else { - let inner_constants = - convert_constants_to_data(constants.iter().cloned().map(Rc::new).collect()) - .into_iter() - .map(|constant| match constant { - UplcConstant::Data(d) => d, - _ => todo!(), - }) - .collect_vec(); - - UplcConstant::Data(PlutusData::Array(inner_constants)) - } - } - UplcConstant::ProtoPair(_, _, left, right) => { - let inner_constants = vec![left.clone(), right.clone()]; - let inner_constants = convert_constants_to_data(inner_constants) - .into_iter() - .map(|constant| match constant { - UplcConstant::Data(d) => d, - _ => todo!(), - }) - .collect_vec(); - - UplcConstant::Data(PlutusData::Array(vec![ - inner_constants[0].clone(), - inner_constants[1].clone(), - ])) - } - d @ UplcConstant::Data(_) => d.clone(), - UplcConstant::Unit => UplcConstant::Data(PlutusData::Constr(Constr { - tag: convert_constr_to_tag(0).unwrap(), - any_constructor: None, - fields: vec![], - })), - }; - new_constants.push(constant); - } - new_constants -} - -pub fn wrap_validator_args(term: Term, arguments: &[TypedArg]) -> Term { - let mut term = term; - for arg in arguments.iter().rev() { - if !matches!(arg.tipo.get_uplc_type(), UplcType::Data) { - term = term - .lambda(arg.arg_name.get_variable_name().unwrap_or("_")) - .apply(convert_data_to_type( - Term::var(arg.arg_name.get_variable_name().unwrap_or("_")), - &arg.tipo, - )); - } - - term = term.lambda(arg.arg_name.get_variable_name().unwrap_or("_")) - } - term -} - -pub fn wrap_as_multi_validator(spend: Term, mint: Term) -> Term { - Term::equals_integer() - .apply(Term::integer(0.into())) - .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("__second_arg"))) - .delayed_if_else( - mint.apply(Term::var("__first_arg")) - .apply(Term::var("__second_arg")), - spend.apply(Term::var("__first_arg")).apply( - Term::head_list() - .apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("__second_arg"))), - ), - ) - .lambda("__second_arg") - .lambda("__first_arg") -} - -pub fn monomorphize( - ir: Vec, - mono_types: IndexMap>, - full_type: &Arc, - data_types: &IndexMap, -) -> (String, Vec) { - let mut new_air = ir.clone(); - let mut new_name = String::new(); - let mut needs_variant = false; - - for (index, ir) in ir.into_iter().enumerate() { - match ir { - Air::Var { - constructor, - scope, - name, - .. - } => { - if constructor.tipo.is_generic() { - let mut tipo = constructor.tipo.clone(); - - find_and_replace_generics(&mut tipo, &mono_types); - - let mut variant = String::new(); - - let mut constructor = constructor.clone(); - constructor.tipo = tipo; - - if let Type::Fn { args, ret } = &*constructor.tipo { - if matches!( - constructor.variant, - ValueConstructorVariant::ModuleFn { .. } - ) { - for arg in args { - let mut arg = arg.clone(); - replace_opaque_type(&mut arg, data_types); - get_variant_name(&mut variant, &arg); - } - let mut ret = ret.clone(); - replace_opaque_type(&mut ret, data_types); - get_variant_name(&mut variant, &ret); - } - } - new_air[index] = Air::Var { - scope, - constructor, - name, - variant_name: variant, - }; - needs_variant = true; - } - } - Air::List { - tipo, - scope, - count, - tail, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::List { - scope, - count, - tipo, - tail, - }; - needs_variant = true; - } - } - Air::ListAccessor { - scope, - tipo, - names, - tail, - check_last_item, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::ListAccessor { - scope, - names, - tipo, - tail, - check_last_item, - }; - needs_variant = true; - } - } - Air::ListExpose { - scope, - tipo, - tail_head_names, - tail, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::ListExpose { - scope, - tail_head_names, - tipo, - tail, - }; - needs_variant = true; - } - } - Air::BinOp { scope, name, tipo } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::BinOp { scope, name, tipo }; - needs_variant = true; - } - } - Air::Builtin { - scope, - func, - tipo, - count, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::Builtin { - scope, - func, - tipo, - count, - }; - needs_variant = true; - } - } - Air::UnWrapData { scope, tipo } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::UnWrapData { scope, tipo }; - needs_variant = true; - } - } - Air::WrapData { scope, tipo } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::WrapData { scope, tipo }; - needs_variant = true; - } - } - Air::When { - scope, - tipo, - subject_name, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::When { - scope, - subject_name, - tipo, - }; - needs_variant = true; - } - } - Air::Clause { - scope, - tipo, - subject_name, - complex_clause, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::Clause { - scope, - tipo, - subject_name, - complex_clause, - }; - needs_variant = true; - } - } - Air::ListClause { - scope, - tipo, - tail_name, - complex_clause, - next_tail_name, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::ListClause { - scope, - tipo, - tail_name, - complex_clause, - next_tail_name, - }; - needs_variant = true; - } - } - Air::TupleClause { - scope, - tipo, - indices, - predefined_indices, - subject_name, - count, - complex_clause, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::TupleClause { - scope, - tipo, - indices, - predefined_indices, - subject_name, - count, - complex_clause, - }; - needs_variant = true; - } - } - Air::ClauseGuard { - tipo, - scope, - subject_name, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::ClauseGuard { - scope, - subject_name, - tipo, - }; - needs_variant = true; - } - } - Air::ListClauseGuard { - scope, - tipo, - tail_name, - next_tail_name, - inverse, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::ListClauseGuard { - scope, - tipo, - tail_name, - next_tail_name, - inverse, - }; - needs_variant = true; - } - } - Air::Tuple { scope, tipo, count } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::Tuple { scope, tipo, count }; - needs_variant = true; - } - } - Air::TupleIndex { - scope, - tipo, - tuple_index, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::TupleIndex { - scope, - tipo, - tuple_index, - }; - needs_variant = true; - } - } - Air::ErrorTerm { scope, tipo } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::ErrorTerm { scope, tipo }; - needs_variant = true; - } - } - Air::Trace { scope, tipo } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::Trace { scope, tipo }; - needs_variant = true; - } - } - Air::Record { - scope, - tag: constr_index, - tipo, - count, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::Record { - scope, - tipo, - tag: constr_index, - count, - }; - needs_variant = true; - } - } - Air::RecordAccess { - scope, - record_index, - tipo, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::RecordAccess { - scope, - record_index, - tipo, - }; - needs_variant = true; - } - } - Air::FieldsExpose { - scope, - indices, - check_last_item, - } => { - let mut new_indices = vec![]; - for (ind, name, tipo) in indices { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - needs_variant = true; - new_indices.push((ind, name, tipo)); - } else { - new_indices.push((ind, name, tipo)); - } - } - new_air[index] = Air::FieldsExpose { - scope, - indices: new_indices, - check_last_item, - }; - } - Air::RecordUpdate { - scope, - highest_index, - indices, - tipo, - } => { - let mut new_indices = vec![]; - let mut tipo = tipo.clone(); - for (ind, tipo) in indices { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - needs_variant = true; - new_indices.push((ind, tipo)); - } else { - new_indices.push((ind, tipo)); - } - } - if tipo.is_generic() { - find_and_replace_generics(&mut tipo, &mono_types); - } - new_air[index] = Air::RecordUpdate { - scope, - highest_index, - indices: new_indices, - tipo, - }; - } - Air::TupleAccessor { - scope, - names, - tipo, - check_last_item, - } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::TupleAccessor { - scope, - names, - tipo, - check_last_item, - }; - needs_variant = true; - } - } - - Air::Call { scope, count, tipo } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::Call { scope, count, tipo }; - needs_variant = true; - } - } - Air::If { scope, tipo } => { - if tipo.is_generic() { - let mut tipo = tipo.clone(); - find_and_replace_generics(&mut tipo, &mono_types); - - new_air[index] = Air::If { scope, tipo }; - needs_variant = true; - } - } - _ => {} - } - } - - if let Type::Fn { args, ret } = &**full_type { - if needs_variant { - for arg in args { - let mut arg = arg.clone(); - replace_opaque_type(&mut arg, data_types); - get_variant_name(&mut new_name, &arg); - } - let mut ret = ret.clone(); - replace_opaque_type(&mut ret, data_types); - get_variant_name(&mut new_name, &ret) - } - } - - (new_name, new_air) -} - -#[allow(clippy::too_many_arguments)] -pub fn handle_func_dependencies( - dependencies_ir: &mut Vec, - function_component: &FuncComponents, - func_components: &IndexMap, - defined_functions: &mut IndexMap, - func_index_map: &IndexMap, - func_scope: &Scope, - to_be_defined: &mut IndexMap, - id_gen: Rc, -) { - let function_component = function_component.clone(); - - let mut function_dependency_order = function_component - .dependencies - .iter() - .unique() - .cloned() - .collect_vec(); - let mut dependency_map = IndexMap::new(); - let mut dependency_vec = vec![]; - - // deal with function dependencies by sorting order in which we pop them. - while let Some(dependency) = function_dependency_order.pop() { - let depend_comp = func_components.get(&dependency).unwrap(); - - if dependency_map.contains_key(&dependency) { - dependency_map.shift_remove(&dependency); - } - - function_dependency_order.extend(depend_comp.dependencies.clone()); - - dependency_map.insert(dependency, ()); - } - - dependency_vec.extend(dependency_map.keys().cloned()); - dependency_vec.reverse(); - - while let Some(dependency) = dependency_vec.pop() { - let func_component_dep = func_components.get(&dependency); - - if defined_functions.contains_key(&dependency) { - continue; - } - - let Some(depend_comp) = func_component_dep else {continue}; - - let dep_scope = func_index_map - .get(&dependency) - .unwrap_or_else(|| unreachable!()); - - if (dep_scope.common_ancestor(func_scope) == *func_scope && !depend_comp.args.is_empty()) - || (function_component.args.is_empty() && !depend_comp.args.is_empty()) - { - let mut recursion_ir = vec![]; - handle_recursion_ir(&dependency, depend_comp, &mut recursion_ir); - - let mut temp_stack = AirStack { - id_gen: id_gen.clone(), - scope: func_scope.clone(), - air: vec![], - }; - - let recursion_stack = AirStack { - id_gen: id_gen.clone(), - scope: func_scope.clone(), - air: recursion_ir, - }; - - if depend_comp.is_code_gen_func { - temp_stack = recursion_stack; - } else { - temp_stack.define_func( - dependency.function_name.clone(), - dependency.module_name.clone(), - "", - depend_comp.args.clone(), - depend_comp.recursive, - recursion_stack, - ); - } - - let mut temp_ir = temp_stack.complete(); - - temp_ir.append(dependencies_ir); - - *dependencies_ir = temp_ir; - - if dep_scope.common_ancestor(func_scope) == *func_scope { - defined_functions.insert(dependency, ()); - } - } else if depend_comp.args.is_empty() { - to_be_defined.insert(dependency, ()); - } - } -} - -pub fn handle_recursion_ir( - func_key: &FunctionAccessKey, - func_comp: &FuncComponents, - recursion_ir: &mut Vec, -) { - let mut insert_var_vec = vec![]; - - for (index, ir) in func_comp.ir.iter().enumerate().rev() { - match_ir_for_recursion( - ir.clone(), - &mut insert_var_vec, - &FunctionAccessKey { - function_name: func_key.function_name.clone(), - module_name: func_key.module_name.clone(), - }, - index, - ); - } - *recursion_ir = func_comp.ir.clone(); - // Deals with self recursive function - for (index, ir) in insert_var_vec.clone() { - recursion_ir.insert(index, ir); - - let current_call = recursion_ir[index - 1].clone(); - - match current_call { - Air::Call { scope, count, tipo } => { - recursion_ir[index - 1] = Air::Call { - scope, - count: count + 1, - tipo, - } - } - _ => unreachable!("Will support not using call right away later."), - } - } -} - -pub fn lookup_data_type_by_tipo( - data_types: &IndexMap, - tipo: &Type, -) -> Option>> { - match tipo { - Type::Fn { ret, .. } => match ret.as_ref() { - Type::App { module, name, .. } => { - let data_type_key = DataTypeKey { - module_name: module.clone(), - defined_type: name.clone(), - }; - data_types.get(&data_type_key).map(|item| (*item).clone()) - } - _ => None, - }, - Type::App { module, name, .. } => { - let data_type_key = DataTypeKey { - module_name: module.clone(), - defined_type: name.clone(), - }; - - data_types.get(&data_type_key).map(|item| (*item).clone()) - } - Type::Var { tipo } => { - if let TypeVar::Link { tipo } = &*tipo.borrow() { - lookup_data_type_by_tipo(data_types, tipo) - } else { - None - } - } - _ => None, - } -} - -pub fn check_replaceable_opaque_type( - t: &Arc, - data_types: &IndexMap, -) -> bool { - let data_type = lookup_data_type_by_tipo(data_types, t); - - if let Some(data_type) = data_type { - let data_type_args = data_type.constructors[0].arguments.clone(); - data_type_args.len() == 1 && data_type.opaque && data_type.constructors.len() == 1 - } else { - false - } -} - -pub fn replace_opaque_type(t: &mut Arc, data_types: &IndexMap) { - if check_replaceable_opaque_type(t, data_types) && matches!(&**t, Type::App { .. }) { - let data_type = lookup_data_type_by_tipo(data_types, t).unwrap(); - let new_type_fields = data_type.typed_parameters; - - let mut mono_types: IndexMap> = IndexMap::new(); - - for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) { - let mut map = mono_types.into_iter().collect_vec(); - map.append(&mut get_generic_id_and_type(tipo, ¶m)); - mono_types = map.into_iter().collect(); - } - - let mut generic_type = data_type.constructors[0].arguments[0].tipo.clone(); - - find_and_replace_generics(&mut generic_type, &mono_types); - - replace_opaque_type(&mut generic_type, data_types); - *t = generic_type; - } else { - match (**t).clone() { - Type::App { - public, - module, - name, - args, - } => { - let mut new_args = vec![]; - for arg in args { - let mut new_arg_type = arg.clone(); - replace_opaque_type(&mut new_arg_type, data_types); - new_args.push(new_arg_type); - } - *t = Type::App { - public, - module, - name, - args: new_args, - } - .into(); - } - Type::Fn { args, ret } => { - let mut new_args = vec![]; - for arg in args { - let mut new_arg_type = arg.clone(); - replace_opaque_type(&mut new_arg_type, data_types); - new_args.push(new_arg_type); - } - - let mut new_ret = ret; - replace_opaque_type(&mut new_ret, data_types); - - *t = Type::Fn { - args: new_args, - ret: new_ret, - } - .into(); - } - Type::Var { tipo } => { - if let TypeVar::Link { tipo } = &*tipo.borrow() { - let mut new_type = tipo.clone(); - replace_opaque_type(&mut new_type, data_types); - *t = new_type; - } - } - Type::Tuple { elems } => { - let mut new_elems = vec![]; - for arg in elems { - let mut new_arg_type = arg.clone(); - replace_opaque_type(&mut new_arg_type, data_types); - new_elems.push(new_arg_type); - } - *t = Type::Tuple { elems: new_elems }.into(); - } - } - } -} - -pub fn handle_clause_guard( - clause_guard: &ClauseGuard>, - clause_guard_stack: &mut AirStack, -) { - match clause_guard { - ClauseGuard::Not { value, .. } => { - let mut value_stack = clause_guard_stack.empty_with_scope(); - - handle_clause_guard(value, &mut value_stack); - - clause_guard_stack.unop(UnOp::Not, value_stack); - } - ClauseGuard::Equals { left, right, .. } => { - let mut left_stack = clause_guard_stack.empty_with_scope(); - let mut right_stack = clause_guard_stack.empty_with_scope(); - - handle_clause_guard(left, &mut left_stack); - handle_clause_guard(right, &mut right_stack); - - clause_guard_stack.binop(BinOp::Eq, left.tipo(), left_stack, right_stack); - } - ClauseGuard::NotEquals { left, right, .. } => { - let mut left_stack = clause_guard_stack.empty_with_scope(); - let mut right_stack = clause_guard_stack.empty_with_scope(); - - handle_clause_guard(left, &mut left_stack); - handle_clause_guard(right, &mut right_stack); - - clause_guard_stack.binop(BinOp::NotEq, left.tipo(), left_stack, right_stack); - } - ClauseGuard::GtInt { left, right, .. } => { - let mut left_stack = clause_guard_stack.empty_with_scope(); - let mut right_stack = clause_guard_stack.empty_with_scope(); - - handle_clause_guard(left, &mut left_stack); - handle_clause_guard(right, &mut right_stack); - - clause_guard_stack.binop(BinOp::GtInt, left.tipo(), left_stack, right_stack); - } - ClauseGuard::GtEqInt { left, right, .. } => { - let mut left_stack = clause_guard_stack.empty_with_scope(); - let mut right_stack = clause_guard_stack.empty_with_scope(); - - handle_clause_guard(left, &mut left_stack); - handle_clause_guard(right, &mut right_stack); - - clause_guard_stack.binop(BinOp::GtEqInt, left.tipo(), left_stack, right_stack); - } - ClauseGuard::LtInt { left, right, .. } => { - let mut left_stack = clause_guard_stack.empty_with_scope(); - let mut right_stack = clause_guard_stack.empty_with_scope(); - - handle_clause_guard(left, &mut left_stack); - handle_clause_guard(right, &mut right_stack); - - clause_guard_stack.binop(BinOp::LtInt, left.tipo(), left_stack, right_stack); - } - ClauseGuard::LtEqInt { left, right, .. } => { - let mut left_stack = clause_guard_stack.empty_with_scope(); - let mut right_stack = clause_guard_stack.empty_with_scope(); - - handle_clause_guard(left, &mut left_stack); - handle_clause_guard(right, &mut right_stack); - - clause_guard_stack.binop(BinOp::LtEqInt, left.tipo(), left_stack, right_stack); - } - ClauseGuard::Or { left, right, .. } => { - let mut left_stack = clause_guard_stack.empty_with_scope(); - let mut right_stack = clause_guard_stack.empty_with_scope(); - - handle_clause_guard(left, &mut left_stack); - handle_clause_guard(right, &mut right_stack); - - clause_guard_stack.binop(BinOp::Or, left.tipo(), left_stack, right_stack); - } - ClauseGuard::And { left, right, .. } => { - let mut left_stack = clause_guard_stack.empty_with_scope(); - let mut right_stack = clause_guard_stack.empty_with_scope(); - - handle_clause_guard(left, &mut left_stack); - handle_clause_guard(right, &mut right_stack); - - clause_guard_stack.binop(BinOp::And, left.tipo(), left_stack, right_stack); - } - ClauseGuard::Var { tipo, name, .. } => { - clause_guard_stack.local_var(tipo.clone(), name); - } - ClauseGuard::Constant(constant) => { - constants_ir(constant, clause_guard_stack); - } - } -} - pub fn apply_builtin_forces(mut term: Term, force_count: u32) -> Term { for _ in 0..force_count { term = term.force(); @@ -2005,20 +1324,36 @@ pub fn special_case_builtin( } } -pub fn get_arg_type_name(tipo: &Type) -> String { - match tipo { - Type::App { name, args, .. } => { - let inner_args = args.iter().map(|arg| get_arg_type_name(arg)).collect_vec(); - format!("{}_{}", name, inner_args.join("_")) +pub fn wrap_as_multi_validator(spend: Term, mint: Term) -> Term { + Term::equals_integer() + .apply(Term::integer(0.into())) + .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("__second_arg"))) + .delayed_if_else( + mint.apply(Term::var("__first_arg")) + .apply(Term::var("__second_arg")), + spend.apply(Term::var("__first_arg")).apply( + Term::head_list() + .apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("__second_arg"))), + ), + ) + .lambda("__second_arg") + .lambda("__first_arg") +} + +/// If the pattern is a list the return the number of elements and if it has a tail +/// Otherwise return None +pub fn get_list_elements_len_and_tail( + pattern: &Pattern>, +) -> Option<(usize, bool)> { + if let Pattern::List { elements, tail, .. } = &pattern { + Some((elements.len(), tail.is_some())) + } else if let Pattern::Assign { pattern, .. } = &pattern { + if let Pattern::List { elements, tail, .. } = pattern.as_ref() { + Some((elements.len(), tail.is_some())) + } else { + None } - Type::Var { tipo } => match tipo.borrow().clone() { - TypeVar::Link { tipo } => get_arg_type_name(tipo.as_ref()), - _ => unreachable!(), - }, - Type::Tuple { elems } => { - let inner_args = elems.iter().map(|arg| get_arg_type_name(arg)).collect_vec(); - inner_args.join("_") - } - _ => unreachable!(), + } else { + None } } diff --git a/crates/aiken-lang/src/gen_uplc2/tree.rs b/crates/aiken-lang/src/gen_uplc/tree.rs similarity index 100% rename from crates/aiken-lang/src/gen_uplc2/tree.rs rename to crates/aiken-lang/src/gen_uplc/tree.rs diff --git a/crates/aiken-lang/src/gen_uplc2.rs b/crates/aiken-lang/src/gen_uplc2.rs deleted file mode 100644 index f325aadd..00000000 --- a/crates/aiken-lang/src/gen_uplc2.rs +++ /dev/null @@ -1,2781 +0,0 @@ -pub mod air; -mod builder; -pub mod tree; - -use std::sync::Arc; - -use indexmap::{IndexMap, IndexSet}; -use itertools::Itertools; -use uplc::{ - ast::{Name, Program, Term}, - builder::EXPECT_ON_LIST, -}; - -use crate::{ - ast::{ - AssignmentKind, BinOp, Pattern, Span, TypedArg, TypedClause, TypedDataType, TypedFunction, - TypedValidator, - }, - builtins::{bool, data, int, void}, - expr::TypedExpr, - gen_uplc::builder::{ - self as build, get_arg_type_name, AssignmentProperties, ClauseProperties, DataTypeKey, - FunctionAccessKey, SpecificClause, - }, - gen_uplc2::builder::{ - convert_opaque_type, erase_opaque_type_operations, find_and_replace_generics, - get_generic_id_and_type, get_variant_name, monomorphize, CodeGenFunction, - }, - tipo::{ - ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor, - ValueConstructorVariant, - }, -}; - -use self::{ - air::Air, - builder::UserFunction, - tree::{AirExpression, AirStatement, AirTree, TreePath}, -}; - -#[derive(Clone)] -pub struct CodeGenerator<'a> { - defined_functions: IndexMap, - functions: IndexMap, - data_types: IndexMap, - module_types: IndexMap<&'a String, &'a TypeInfo>, - needs_field_access: bool, - code_gen_functions: IndexMap, - zero_arg_functions: IndexMap>, - tracing: bool, -} - -impl<'a> CodeGenerator<'a> { - pub fn new( - functions: IndexMap, - data_types: IndexMap, - module_types: IndexMap<&'a String, &'a TypeInfo>, - tracing: bool, - ) -> Self { - CodeGenerator { - defined_functions: IndexMap::new(), - functions, - data_types, - module_types, - needs_field_access: false, - code_gen_functions: IndexMap::new(), - zero_arg_functions: IndexMap::new(), - tracing, - } - } - - pub fn reset(&mut self) { - self.code_gen_functions = IndexMap::new(); - self.zero_arg_functions = IndexMap::new(); - self.needs_field_access = false; - self.defined_functions = IndexMap::new(); - } - - pub fn generate( - &mut self, - TypedValidator { - fun, - other_fun, - params, - .. - }: &TypedValidator, - ) -> Program { - let air_tree_fun = self.build(&fun.body); - let mut validator_args_tree = self.check_validator_args(&fun.arguments, true, air_tree_fun); - - validator_args_tree = AirTree::no_op().hoist_over(validator_args_tree); - println!("{:#?}", validator_args_tree.to_vec()); - - let full_tree = self.hoist_functions_to_validator(validator_args_tree); - - // optimizations on air tree - - let full_vec = full_tree.to_vec(); - - println!("FULL VEC {:#?}", full_vec); - - todo!() - } - - pub fn generate_test(&mut self, test_body: &TypedExpr) -> Program { - let mut air_tree = self.build(test_body); - - air_tree = AirTree::no_op().hoist_over(air_tree); - println!("{:#?}", air_tree.to_vec()); - - let full_tree = self.hoist_functions_to_validator(air_tree); - - // optimizations on air tree - - let full_vec = full_tree.to_vec(); - - println!("FULL VEC {:#?}", full_vec); - - todo!() - } - - fn finalize(&mut self, _term: Term) -> Program { - todo!() - } - - fn build(&mut self, body: &TypedExpr) -> AirTree { - match body { - TypedExpr::UInt { value, .. } => AirTree::int(value), - TypedExpr::String { value, .. } => AirTree::string(value), - TypedExpr::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()), - TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => { - let mut expressions = expressions.clone(); - - let mut last_exp = self.build(&expressions.pop().unwrap_or_else(|| { - unreachable!("Sequence or Pipeline should have at least one expression") - })); - - while let Some(expression) = expressions.pop() { - let exp_tree = self.build(&expression); - - last_exp = exp_tree.hoist_over(last_exp); - } - last_exp - } - - TypedExpr::Var { - constructor, name, .. - } => AirTree::var(constructor.clone(), name, ""), - - TypedExpr::Fn { args, body, .. } => AirTree::anon_func( - args.iter() - .map(|arg| arg.arg_name.get_variable_name().unwrap_or("_").to_string()) - .collect_vec(), - self.build(body), - ), - - TypedExpr::List { - tipo, - elements, - tail, - .. - } => AirTree::list( - elements.iter().map(|elem| self.build(elem)).collect_vec(), - tipo.clone(), - tail.as_ref().map(|tail| self.build(tail)), - ), - - TypedExpr::Call { - tipo, fun, args, .. - } => match fun.as_ref() { - TypedExpr::Var { - constructor: - ValueConstructor { - variant: - ValueConstructorVariant::Record { - name: constr_name, .. - }, - .. - }, - .. - } - | TypedExpr::ModuleSelect { - constructor: - ModuleValueConstructor::Record { - name: constr_name, .. - }, - .. - } => { - let Some(data_type) = build::lookup_data_type_by_tipo(&self.data_types, tipo) - else {unreachable!("Creating a record with no record definition.")}; - - let (constr_index, _) = data_type - .constructors - .iter() - .enumerate() - .find(|(_, dt)| &dt.name == constr_name) - .unwrap(); - - let constr_args = args.iter().map(|arg| self.build(&arg.value)).collect_vec(); - - AirTree::create_constr(constr_index, tipo.clone(), constr_args) - } - - TypedExpr::Var { - constructor: - ValueConstructor { - variant: ValueConstructorVariant::ModuleFn { builtin, .. }, - .. - }, - .. - } => { - let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")}; - - let func_args = args - .iter() - .zip(fun_arg_types) - .map(|(arg, arg_tipo)| { - let mut arg_val = self.build(&arg.value); - - if arg_tipo.is_data() && !arg.value.tipo().is_data() { - arg_val = AirTree::wrap_data(arg_val, arg.value.tipo()) - } - arg_val - }) - .collect_vec(); - - if let Some(func) = builtin { - AirTree::builtin(*func, tipo.clone(), func_args) - } else { - AirTree::call(self.build(fun.as_ref()), tipo.clone(), func_args) - } - } - - TypedExpr::ModuleSelect { - module_name, - constructor: ModuleValueConstructor::Fn { name, .. }, - .. - } => { - let type_info = self.module_types.get(module_name).unwrap(); - let value = type_info.values.get(name).unwrap(); - - let ValueConstructorVariant::ModuleFn { builtin, .. } = &value.variant else {unreachable!("Missing module function definition")}; - - let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")}; - - let func_args = args - .iter() - .zip(fun_arg_types) - .map(|(arg, arg_tipo)| { - let mut arg_val = self.build(&arg.value); - - if arg_tipo.is_data() && !arg.value.tipo().is_data() { - arg_val = AirTree::wrap_data(arg_val, arg.value.tipo()) - } - arg_val - }) - .collect_vec(); - - if let Some(func) = builtin { - AirTree::builtin(*func, tipo.clone(), func_args) - } else { - AirTree::call(self.build(fun.as_ref()), tipo.clone(), func_args) - } - } - _ => { - let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")}; - - let func_args = args - .iter() - .zip(fun_arg_types) - .map(|(arg, arg_tipo)| { - let mut arg_val = self.build(&arg.value); - - if arg_tipo.is_data() && !arg.value.tipo().is_data() { - arg_val = AirTree::wrap_data(arg_val, arg.value.tipo()) - } - arg_val - }) - .collect_vec(); - - AirTree::call(self.build(fun.as_ref()), tipo.clone(), func_args) - } - }, - TypedExpr::BinOp { - name, - left, - right, - tipo, - .. - } => AirTree::binop( - *name, - tipo.clone(), - self.build(left), - self.build(right), - left.tipo(), - ), - - TypedExpr::Assignment { - tipo, - value, - pattern, - kind, - .. - } => { - let mut replaced_type = tipo.clone(); - build::replace_opaque_type(&mut replaced_type, &self.data_types); - - let air_value = self.build(value); - - self.assignment( - pattern, - air_value, - tipo, - AssignmentProperties { - value_type: value.tipo(), - kind: *kind, - remove_unused: kind.is_let(), - full_check: !tipo.is_data() && value.tipo().is_data() && kind.is_expect(), - }, - ) - } - - TypedExpr::Trace { - tipo, then, text, .. - } => AirTree::trace(self.build(text), tipo.clone(), self.build(then)), - - TypedExpr::When { - tipo, - subject, - clauses, - .. - } => { - let mut clauses = clauses.clone(); - - if clauses.is_empty() { - unreachable!("We should have one clause at least") - } else if clauses.len() == 1 { - let last_clause = clauses.pop().unwrap(); - - let clause_then = self.build(&last_clause.then); - - let subject_val = self.build(subject); - - let assignment = self.assignment( - &last_clause.pattern, - subject_val, - tipo, - AssignmentProperties { - value_type: subject.tipo(), - kind: AssignmentKind::Let, - remove_unused: false, - full_check: false, - }, - ); - - assignment.hoist_over(clause_then) - } else { - clauses = if subject.tipo().is_list() { - build::rearrange_clauses(clauses) - } else { - clauses - }; - - let last_clause = clauses.pop().unwrap(); - - let constr_var = format!( - "__when_var_span_{}_{}", - subject.location().start, - subject.location().end - ); - - let subject_name = format!( - "__subject_var_span_{}_{}", - subject.location().start, - subject.location().end - ); - - let clauses = self.handle_each_clause( - &clauses, - last_clause, - &subject.tipo(), - &mut ClauseProperties::init( - &subject.tipo(), - constr_var.clone(), - subject_name.clone(), - ), - ); - - let constr_assign = AirTree::let_assignment(&constr_var, self.build(subject)); - let when_assign = AirTree::when( - subject_name, - tipo.clone(), - subject.tipo(), - AirTree::local_var(constr_var, subject.tipo()), - clauses, - ); - - constr_assign.hoist_over(when_assign) - } - } - - TypedExpr::If { - branches, - final_else, - tipo, - .. - } => AirTree::if_branches( - branches - .iter() - .map(|branch| (self.build(&branch.condition), self.build(&branch.body))) - .collect_vec(), - tipo.clone(), - self.build(final_else), - ), - - TypedExpr::RecordAccess { - tipo, - index, - record, - .. - } => AirTree::record_access(*index, tipo.clone(), self.build(record)), - - TypedExpr::ModuleSelect { - tipo, - module_name, - constructor, - .. - } => match constructor { - ModuleValueConstructor::Record { - name, - arity, - tipo, - field_map, - .. - } => { - let data_type = build::lookup_data_type_by_tipo(&self.data_types, tipo); - - let val_constructor = ValueConstructor::public( - tipo.clone(), - ValueConstructorVariant::Record { - name: name.clone(), - arity: *arity, - field_map: field_map.clone(), - location: Span::empty(), - module: module_name.clone(), - constructors_count: data_type - .unwrap_or_else(|| { - unreachable!("Created a module type without a definition?") - }) - .constructors - .len() as u16, - }, - ); - - AirTree::var(val_constructor, name, "") - } - ModuleValueConstructor::Fn { name, module, .. } => { - let func = self.functions.get(&FunctionAccessKey { - module_name: module_name.clone(), - function_name: name.clone(), - }); - - let type_info = self.module_types.get(module_name).unwrap(); - let value = type_info.values.get(name).unwrap(); - - if let Some(_func) = func { - AirTree::var( - ValueConstructor::public(tipo.clone(), value.variant.clone()), - format!("{module}_{name}"), - "", - ) - } else { - let ValueConstructorVariant::ModuleFn { - builtin: Some(builtin), .. - } = &value.variant else { - unreachable!("Didn't find the function definition.") - }; - - AirTree::builtin(*builtin, tipo.clone(), vec![]) - } - } - ModuleValueConstructor::Constant { literal, .. } => builder::constants_ir(literal), - }, - - TypedExpr::Tuple { tipo, elems, .. } => AirTree::tuple( - elems.iter().map(|elem| self.build(elem)).collect_vec(), - tipo.clone(), - ), - - TypedExpr::TupleIndex { - tipo, index, tuple, .. - } => AirTree::tuple_index(*index, tipo.clone(), self.build(tuple)), - - TypedExpr::ErrorTerm { tipo, .. } => AirTree::error(tipo.clone()), - - TypedExpr::RecordUpdate { - tipo, spread, args, .. - } => { - let mut index_types = vec![]; - let mut update_args = vec![]; - - let mut highest_index = 0; - - for arg in args - .iter() - .sorted_by(|arg1, arg2| arg1.index.cmp(&arg2.index)) - { - let arg_val = self.build(&arg.value); - - if arg.index > highest_index { - highest_index = arg.index; - } - - index_types.push((arg.index, arg.value.tipo())); - update_args.push(arg_val); - } - - AirTree::record_update( - index_types, - highest_index, - tipo.clone(), - self.build(spread), - update_args, - ) - } - - TypedExpr::UnOp { value, op, .. } => AirTree::unop(*op, self.build(value)), - } - } - - pub fn assignment( - &mut self, - pattern: &Pattern>, - mut value: AirTree, - tipo: &Arc, - props: AssignmentProperties, - ) -> AirTree { - if props.value_type.is_data() && props.kind.is_expect() && !tipo.is_data() { - value = AirTree::unwrap_data(value, tipo.clone()); - } else if !props.value_type.is_data() && tipo.is_data() { - value = AirTree::wrap_data(value, tipo.clone()); - } - - match pattern { - Pattern::Int { - value: expected_int, - location, - .. - } => { - if props.kind.is_expect() { - let name = format!( - "__expected_by_{}_span_{}_{}", - expected_int, location.start, location.end - ); - let assignment = AirTree::let_assignment(&name, value); - - let expect = AirTree::binop( - BinOp::Eq, - bool(), - AirTree::int(expected_int), - AirTree::local_var(name, int()), - int(), - ); - AirTree::assert_bool(true, assignment.hoist_over(expect)) - } else { - unreachable!("Code Gen should never reach here") - } - } - Pattern::Var { name, .. } => { - if props.full_check { - let mut index_map = IndexMap::new(); - let non_opaque_tipo = convert_opaque_type(tipo, &self.data_types); - - let assignment = AirTree::let_assignment(name, value); - let val = AirTree::local_var(name, tipo.clone()); - - if tipo.is_primitive() { - AirTree::let_assignment(name, assignment.hoist_over(val)) - } else { - let expect = self.expect_type_assign( - &non_opaque_tipo, - val.clone(), - &mut index_map, - pattern.location(), - ); - - let assign_expect = AirTree::let_assignment("_", expect); - AirTree::let_assignment( - name, - assignment.hoist_over(assign_expect.hoist_over(val)), - ) - } - } else { - AirTree::let_assignment(name, value) - } - } - Pattern::Assign { name, pattern, .. } => { - 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]) - } - Pattern::Discard { name, .. } => { - if props.full_check { - let name = &format!("__discard_expect_{}", name); - let mut index_map = IndexMap::new(); - let tipo = convert_opaque_type(tipo, &self.data_types); - let assignment = AirTree::let_assignment(name, value); - let val = AirTree::local_var(name, tipo.clone()); - if tipo.is_primitive() { - AirTree::let_assignment(name, assignment.hoist_over(val)) - } else { - let expect = self.expect_type_assign( - &tipo, - val.clone(), - &mut index_map, - pattern.location(), - ); - - let assign_expect = AirTree::let_assignment("_", expect); - AirTree::let_assignment( - name, - assignment.hoist_over(assign_expect.hoist_over(val)), - ) - } - } else if !props.remove_unused { - AirTree::let_assignment(name, value) - } else { - AirTree::no_op() - } - } - Pattern::List { elements, tail, .. } => { - assert!(tipo.is_list()); - assert!(props.kind.is_expect()); - let list_elem_types = tipo.get_inner_types(); - - let list_elem_type = list_elem_types - .get(0) - .unwrap_or_else(|| unreachable!("No list element type?")); - - let mut elems = elements - .iter() - .enumerate() - .map(|(index, elem)| { - let elem_name = match elem { - Pattern::Var { name, .. } => name.to_string(), - Pattern::Assign { name, .. } => name.to_string(), - Pattern::Discard { name, .. } => { - if props.full_check { - format!("__discard_{}", name) - } else { - "_".to_string() - } - } - _ => format!( - "elem_{}_span_{}_{}", - index, - elem.location().start, - elem.location().end - ), - }; - - let val = AirTree::local_var(&elem_name, list_elem_type.clone()); - - ( - elem_name, - self.assignment( - elem, - val, - list_elem_type, - AssignmentProperties { - value_type: list_elem_type.clone(), - kind: props.kind, - remove_unused: true, - full_check: props.full_check, - }, - ), - ) - }) - .collect_vec(); - - // If Some then push tail onto elems - tail.iter().for_each(|tail| { - let tail_name = match tail.as_ref() { - Pattern::Var { name, .. } => name.to_string(), - Pattern::Assign { name, .. } => name.to_string(), - Pattern::Discard { name, .. } => { - if props.kind.is_expect() - && props.value_type.is_data() - && !tipo.is_data() - { - format!("__discard_{}", name) - } else { - "_".to_string() - } - } - _ => format!( - "tail_span_{}_{}", - tail.location().start, - tail.location().end - ), - }; - - let val = AirTree::local_var(&tail_name, tipo.clone()); - - elems.push(( - tail_name, - self.assignment( - tail, - val, - tipo, - AssignmentProperties { - value_type: tipo.clone(), - kind: props.kind, - remove_unused: true, - full_check: props.full_check, - }, - ), - )); - }); - - let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec(); - - let list_access = if elements.is_empty() { - AirTree::let_assignment("_", AirTree::list_empty(value)) - } else { - AirTree::list_access(names, tipo.clone(), tail.is_some(), tail.is_none(), value) - }; - - let mut sequence = vec![list_access]; - - sequence.append(&mut elems.into_iter().map(|(_, elem)| elem).collect_vec()); - - AirTree::UnhoistedSequence(sequence) - } - Pattern::Constructor { - arguments, - constructor, - name, - .. - } => { - let mut sequence = vec![]; - - if tipo.is_bool() { - assert!(props.kind.is_expect()); - - AirTree::assert_bool(name == "True", value) - } else if tipo.is_void() { - AirTree::let_assignment("_", value) - } else { - if props.kind.is_expect() { - let data_type = build::lookup_data_type_by_tipo(&self.data_types, tipo) - .unwrap_or_else(|| panic!("Failed to find definition for {}", name)); - - if data_type.constructors.len() > 1 || props.full_check { - let (index, _) = data_type - .constructors - .iter() - .enumerate() - .find(|(_, constr)| constr.name == *name) - .unwrap_or_else(|| { - panic!("Found constructor type {} with 0 constructors", name) - }); - - let constructor_name = format!( - "__constructor_{}_span_{}_{}", - name, - pattern.location().start, - pattern.location().end - ); - - // I'm consuming `value` here - let constructor_val = AirTree::let_assignment(&constructor_name, value); - - sequence.push(constructor_val); - - let assert_constr = AirTree::assert_constr_index( - index, - AirTree::local_var(&constructor_name, tipo.clone()), - ); - - sequence.push(assert_constr); - - //I'm reusing the `value` pointer - value = AirTree::local_var(constructor_name, tipo.clone()); - } - } - - let field_map = match constructor { - PatternConstructor::Record { field_map, .. } => field_map.clone(), - }; - - let mut type_map: IndexMap> = IndexMap::new(); - - for (index, arg) in tipo.arg_types().unwrap().iter().enumerate() { - let field_type = arg.clone(); - type_map.insert(index, field_type); - } - - let fields = arguments - .iter() - .enumerate() - .map(|(index, arg)| { - let label = arg.label.clone().unwrap_or_default(); - - let field_index = if let Some(field_map) = &field_map { - *field_map.fields.get(&label).map(|x| &x.0).unwrap_or(&index) - } else { - index - }; - - let field_name = match &arg.value { - Pattern::Var { name, .. } => name.to_string(), - Pattern::Assign { name, .. } => name.to_string(), - Pattern::Discard { name, .. } => { - if props.full_check { - format!("__discard_{}", name) - } else { - "_".to_string() - } - } - _ => format!( - "field_{}_span_{}_{}", - field_index, - arg.value.location().start, - arg.value.location().end - ), - }; - - let arg_type = type_map.get(&field_index).unwrap_or_else(|| { - unreachable!( - "Missing type for field {} of constr {}", - field_index, name - ) - }); - - let val = AirTree::local_var(field_name.to_string(), arg_type.clone()); - - ( - field_index, - field_name, - arg_type.clone(), - self.assignment( - &arg.value, - val, - arg_type, - AssignmentProperties { - value_type: props.value_type.clone(), - kind: props.kind, - remove_unused: true, - full_check: props.full_check, - }, - ), - ) - }) - .collect_vec(); - - let indices = fields - .iter() - .map(|(index, name, tipo, _)| (*index, name.to_string(), tipo.clone())) - .collect_vec(); - - // This `value` is either value param that was passed in or - // local var - sequence.push(AirTree::fields_expose(indices, props.full_check, value)); - - sequence.append( - &mut fields - .into_iter() - .map(|(_, _, _, field)| field) - .collect_vec(), - ); - - AirTree::UnhoistedSequence(sequence) - } - } - Pattern::Tuple { - elems, location, .. - } => { - let mut type_map: IndexMap> = IndexMap::new(); - - let mut sequence = vec![]; - - for (index, arg) in tipo.get_inner_types().iter().enumerate() { - let field_type = arg.clone(); - type_map.insert(index, field_type); - } - - let elems = elems - .iter() - .enumerate() - .map(|(index, arg)| { - let tuple_name = match &arg { - Pattern::Var { name, .. } => name.to_string(), - Pattern::Assign { name, .. } => name.to_string(), - Pattern::Discard { name, .. } => { - if props.full_check { - format!("__discard_{}", name) - } else { - "_".to_string() - } - } - _ => format!( - "tuple_{}_span_{}_{}", - index, - arg.location().start, - arg.location().end - ), - }; - - let arg_type = type_map.get(&index).unwrap_or_else(|| { - unreachable!( - "Missing type for tuple index {} of tuple_span_{}_{}", - index, location.start, location.end - ) - }); - - let val = AirTree::local_var(tuple_name.to_string(), arg_type.clone()); - - ( - tuple_name, - self.assignment( - arg, - val, - arg_type, - AssignmentProperties { - value_type: props.value_type.clone(), - kind: props.kind, - remove_unused: true, - full_check: props.full_check, - }, - ), - ) - }) - .collect_vec(); - - let indices = elems.iter().map(|(name, _)| name.to_string()).collect_vec(); - - // This `value` is either value param that was passed in or - // local var - sequence.push(AirTree::tuple_access( - indices, - tipo.clone(), - props.full_check, - value, - )); - - sequence.append(&mut elems.into_iter().map(|(_, field)| field).collect_vec()); - - AirTree::UnhoistedSequence(sequence) - } - } - } - - pub fn expect_type_assign( - &mut self, - tipo: &Arc, - value: AirTree, - defined_data_types: &mut IndexMap, - location: Span, - ) -> AirTree { - assert!(tipo.get_generic().is_none()); - if tipo.is_primitive() { - AirTree::void() - } else if tipo.is_map() { - assert!(!tipo.get_inner_types().is_empty()); - let inner_list_type = &tipo.get_inner_types()[0]; - let inner_pair_types = inner_list_type.get_inner_types(); - assert!(inner_pair_types.len() == 2); - - let map_name = format!("__map_span_{}_{}", location.start, location.end); - 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 assign = AirTree::let_assignment(&map_name, value); - - let tuple_access = AirTree::tuple_access( - vec![fst_name.clone(), snd_name.clone()], - inner_list_type.clone(), - false, - AirTree::local_var(&pair_name, inner_list_type.clone()), - ); - - let expect_fst = self.expect_type_assign( - &inner_pair_types[0], - AirTree::local_var(fst_name, inner_pair_types[0].clone()), - defined_data_types, - location, - ); - - let expect_snd = self.expect_type_assign( - &inner_pair_types[1], - AirTree::local_var(snd_name, inner_pair_types[1].clone()), - defined_data_types, - location, - ); - - 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); - - 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 { - body: expect_list_func, - params: vec!["__list_to_check".to_string(), "__check_with".to_string()], - }, - ); - } - - 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::var( - ValueConstructor::public( - void(), - ValueConstructorVariant::ModuleFn { - name: EXPECT_ON_LIST.to_string(), - field_map: None, - module: "".to_string(), - arity: 1, - location, - builtin: None, - }, - ), - EXPECT_ON_LIST, - "", - ), - void(), - vec![AirTree::local_var(map_name, tipo.clone()), unwrap_function], - ); - - 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]; - - 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_assign( - inner_list_type, - AirTree::local_var(&item_name, inner_list_type.clone()), - defined_data_types, - location, - ); - - let anon_func_body = - AirTree::let_assignment("_", expect_item).hoist_over(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 { - body: expect_list_func, - params: vec!["__list_to_check".to_string(), "__check_with".to_string()], - }, - ); - } - - 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::var( - ValueConstructor::public( - void(), - ValueConstructorVariant::ModuleFn { - name: EXPECT_ON_LIST.to_string(), - field_map: None, - module: "".to_string(), - arity: 1, - location, - builtin: None, - }, - ), - EXPECT_ON_LIST, - "", - ), - void(), - vec![AirTree::local_var(list_name, tipo.clone()), unwrap_function], - ); - - 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_assign( - &tuple_inner_types[0], - AirTree::local_var(fst_name, tuple_inner_types[0].clone()), - defined_data_types, - location, - ); - - let expect_snd = self.expect_type_assign( - &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() { - let tuple_inner_types = tipo.get_inner_types(); - - let tuple_name = format!("__tuple_span_{}_{}", location.start, location.end); - let tuple_assign = AirTree::let_assignment(&tuple_name, value); - - let tuple_expect_items = tuple_inner_types - .iter() - .enumerate() - .map(|(index, arg)| { - let tuple_index_name = format!( - "__tuple_index_{}_span_{}_{}", - index, location.start, location.end - ); - - let expect_tuple_item = self.expect_type_assign( - tipo, - AirTree::local_var(&tuple_index_name, arg.clone()), - defined_data_types, - location, - ); - - (tuple_index_name, expect_tuple_item) - }) - .collect_vec(); - - let tuple_index_names = tuple_expect_items - .iter() - .map(|(name, _)| name.clone()) - .collect_vec(); - - let tuple_access = AirTree::tuple_access( - tuple_index_names, - tipo.clone(), - false, - AirTree::local_var(tuple_name, tipo.clone()), - ); - - let mut tuple_expects = tuple_expect_items - .into_iter() - .map(|(_, item)| item) - .collect_vec(); - - let mut sequence = vec![tuple_assign, tuple_access]; - - sequence.append(&mut tuple_expects); - - AirTree::UnhoistedSequence(sequence).hoist_over(AirTree::void()) - } 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) - }); - - let data_type_variant = tipo - .get_inner_types() - .iter() - .map(|arg| get_arg_type_name(arg)) - .join("_"); - - let mono_types: IndexMap> = if !data_type.typed_parameters.is_empty() { - data_type - .typed_parameters - .iter() - .zip(tipo.arg_types().unwrap()) - .flat_map(|item| get_generic_id_and_type(item.0, &item.1)) - .collect() - } else { - IndexMap::new() - }; - - let data_type_name = format!("__expect_{}_{}", data_type.name, data_type_variant); - let function = self.code_gen_functions.get(&data_type_name); - - let error_term = if self.tracing { - AirTree::trace( - AirTree::string("Constr index did not match any type variant"), - tipo.clone(), - AirTree::error(tipo.clone()), - ) - } else { - AirTree::error(tipo.clone()) - }; - - if function.is_none() && defined_data_types.get(&data_type_name).is_none() { - defined_data_types.insert(data_type_name.clone(), 1); - - let current_defined = defined_data_types.clone(); - let mut diff_defined_types = vec![]; - - let constr_clauses = data_type.constructors.iter().enumerate().rfold( - error_term, - |acc, (index, constr)| { - let constr_args = constr - .arguments - .iter() - .enumerate() - .map(|(index, arg)| { - let arg_name = - arg.label.clone().unwrap_or(format!("__field_{index}")); - - let arg_tipo = find_and_replace_generics(&arg.tipo, &mono_types); - - let assign = AirTree::let_assignment( - "_", - self.expect_type_assign( - &arg_tipo, - AirTree::local_var(&arg_name, arg_tipo.clone()), - defined_data_types, - location, - ), - ); - - (index, arg_name, arg_tipo, assign) - }) - .collect_vec(); - - let indices = constr_args - .iter() - .map(|(index, arg_name, arg_tipo, _)| { - (*index, arg_name.clone(), (*arg_tipo).clone()) - }) - .collect_vec(); - - let mut assigns = constr_args - .into_iter() - .map(|(_, _, _, assign)| assign) - .collect_vec(); - - if assigns.is_empty() { - let empty = AirTree::fields_empty(AirTree::local_var( - format!("__constr_var_span_{}_{}", location.start, location.end), - tipo.clone(), - )); - - assigns.insert(0, AirTree::let_assignment("_", empty)); - } else { - let expose = AirTree::fields_expose( - indices, - true, - AirTree::local_var( - format!( - "__constr_var_span_{}_{}", - location.start, location.end - ), - tipo.clone(), - ), - ); - - assigns.insert(0, expose); - }; - - let then = AirTree::UnhoistedSequence(assigns).hoist_over(AirTree::void()); - - AirTree::clause( - format!("__subject_span_{}_{}", location.start, location.end), - AirTree::int(index), - tipo.clone(), - then, - acc, - false, - ) - }, - ); - - let overhead_assign = AirTree::let_assignment( - format!("__constr_var_span_{}_{}", location.start, location.end), - AirTree::local_var("__param_0", tipo.clone()), - ); - - let when_expr = AirTree::when( - format!("__subject_span_{}_{}", location.start, location.end), - void(), - tipo.clone(), - AirTree::local_var( - format!("__constr_var_span_{}_{}", location.start, location.end), - tipo.clone(), - ), - constr_clauses, - ); - - let func_body = overhead_assign.hoist_over(when_expr); - - for (inner_data_type, inner_count) in defined_data_types.iter() { - if let Some(prev_count) = current_defined.get(inner_data_type) { - if inner_count - prev_count > 0 { - diff_defined_types.push(inner_data_type.to_string()); - } - } else { - diff_defined_types.push(inner_data_type.to_string()); - } - } - - let code_gen_func = CodeGenFunction::Function { - body: func_body, - params: vec!["__param_0".to_string()], - }; - - self.code_gen_functions - .insert(data_type_name.clone(), code_gen_func); - } 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(), 1); - } - - 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]) - } - } - - pub fn handle_each_clause( - &mut self, - clauses: &[TypedClause], - final_clause: TypedClause, - subject_tipo: &Arc, - props: &mut ClauseProperties, - ) -> AirTree { - assert!( - !subject_tipo.is_void(), - "WHY ARE YOU PATTERN MATCHING VOID???" - ); - props.complex_clause = false; - - if let Some((clause, rest_clauses)) = clauses.split_first() { - 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( - AirTree::clause_guard(clause_guard_name, AirTree::bool(true), bool()) - .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::init( - subject_tipo, - props.clause_var_name.clone(), - props.original_subject_name.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, tail, .. } = &clause.pattern - else { - 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); - - return AirTree::wrap_clause( - clause_assign_hoisted, - self.handle_each_clause( - rest_clauses, - final_clause, - subject_tipo, - &mut next_clause_props, - ), - ); - }; - - 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 = { - if rest_clauses.is_empty() { - None - } else { - let next_clause = &rest_clauses[0]; - let next_elements_len = match &next_clause.pattern { - Pattern::List { elements, .. } => elements.len(), - _ => 0, - }; - - if (*current_index as usize) < next_elements_len { - Some(format!( - "tail_index_{}_span_{}_{}", - *current_index + 1, - next_clause.pattern.location().start, - next_clause.pattern.location().end - )) - } else { - None - } - } - }; - - let mut use_wrap_clause = false; - - if elements.len() - usize::from(tail.is_some() && !elements.is_empty()) - >= *current_index as usize - { - *current_index += 1; - defined_tails.push(tail_name.clone()); - } else if next_tail_name.is_none() { - use_wrap_clause = true; - } - - 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; - - if use_wrap_clause { - AirTree::wrap_clause( - clause_assign_hoisted, - self.handle_each_clause( - rest_clauses, - final_clause, - subject_tipo, - &mut next_clause_props, - ), - ) - } else { - AirTree::list_clause( - tail_name, - subject_tipo.clone(), - clause_assign_hoisted, - self.handle_each_clause( - rest_clauses, - final_clause, - subject_tipo, - &mut next_clause_props, - ), - next_tail_name, - complex_clause, - ) - } - } - SpecificClause::TupleClause { - defined_tuple_indices, - } => { - let current_defined_indices = defined_tuple_indices.clone(); - - let (_, pattern_assigns) = - self.clause_pattern(&clause.pattern, subject_tipo, props); - - let ClauseProperties{ specific_clause: SpecificClause::TupleClause { defined_tuple_indices }, ..} = props - else { - unreachable!() - }; - - let new_defined_indices: IndexSet<(usize, String)> = defined_tuple_indices - .difference(¤t_defined_indices) - .cloned() - .collect(); - - 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::TupleClause { - defined_tuple_indices: defined_tuple_indices.clone(), - }, - }; - - if new_defined_indices.is_empty() { - AirTree::wrap_clause( - pattern_assigns.hoist_over(clause_then), - self.handle_each_clause( - rest_clauses, - final_clause, - subject_tipo, - &mut next_clause_props, - ), - ) - } else { - AirTree::tuple_clause( - &props.original_subject_name, - subject_tipo.clone(), - new_defined_indices, - current_defined_indices, - pattern_assigns.hoist_over(clause_then), - self.handle_each_clause( - rest_clauses, - final_clause, - subject_tipo, - &mut next_clause_props, - ), - props.complex_clause, - ) - } - } - } - } else { - // handle final_clause - props.final_clause = true; - assert!(final_clause.guard.is_none()); - let clause_then = self.build(&final_clause.then); - let (condition, assignments) = - self.clause_pattern(&final_clause.pattern, subject_tipo, props); - - AirTree::finally(condition, assignments.hoist_over(clause_then)) - } - } - - pub fn clause_pattern( - &mut self, - pattern: &Pattern>, - subject_tipo: &Arc, - props: &mut ClauseProperties, - // We return condition and then assignments sequence - ) -> (AirTree, AirTree) { - match pattern { - Pattern::Int { value, .. } => { - assert!(!props.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 { elements, tail, .. } => { - let ClauseProperties { - specific_clause: SpecificClause::ListClause { defined_tails, .. }, - complex_clause, - .. - } = props - else { unreachable!() }; - - let list_elem_types = subject_tipo.get_inner_types(); - - let list_elem_type = list_elem_types - .get(0) - .unwrap_or_else(|| unreachable!("No list element type?")); - - let defined_tails = defined_tails.clone(); - - let elems = elements - .iter() - .enumerate() - .map(|(index, elem)| { - let elem_name = match elem { - Pattern::Var { name, .. } => name.to_string(), - Pattern::Assign { name, .. } => name.to_string(), - Pattern::Discard { .. } => "_".to_string(), - _ => format!( - "elem_{}_span_{}_{}", - index, - elem.location().start, - elem.location().end - ), - }; - - let mut elem_props = ClauseProperties::init_inner( - list_elem_type, - elem_name.clone(), - elem_name.clone(), - props.final_clause, - ); - - let statement = - self.nested_clause_condition(elem, list_elem_type, &mut elem_props); - - *complex_clause = *complex_clause || elem_props.complex_clause; - - (elem_name, statement) - }) - .collect_vec(); - - let mut defined_heads = - elems.iter().map(|(head, _)| head.to_string()).collect_vec(); - - let mut air_elems = elems - .into_iter() - .map(|(_, statement)| statement) - .collect_vec(); - - let mut list_tail = None; - - tail.iter().for_each(|elem| { - let tail = defined_tails.last().cloned().unwrap_or_default(); - let elem_name = match elem.as_ref() { - Pattern::Var { name, .. } => name.to_string(), - Pattern::Assign { name, .. } => name.to_string(), - Pattern::Discard { .. } => "_".to_string(), - _ => format!( - "tail_span_{}_{}", - elem.location().start, - elem.location().end - ), - }; - - let mut elem_props = ClauseProperties::init_inner( - subject_tipo, - elem_name.clone(), - elem_name.clone(), - props.final_clause, - ); - - let statement = - self.nested_clause_condition(elem, subject_tipo, &mut elem_props); - *complex_clause = *complex_clause || elem_props.complex_clause; - - air_elems.push(statement); - list_tail = Some((tail, elem_name.to_string())); - defined_heads.push(elem_name) - }); - - let list_assign = if props.final_clause { - AirTree::list_access( - defined_heads, - subject_tipo.clone(), - tail.is_some(), - false, - AirTree::local_var(&props.original_subject_name, subject_tipo.clone()), - ) - } else { - AirTree::list_expose( - defined_heads - .into_iter() - .zip(defined_tails.into_iter()) - .collect_vec(), - list_tail, - subject_tipo.clone(), - ) - }; - - let mut sequence = vec![list_assign]; - - sequence.append(&mut air_elems); - - (AirTree::void(), AirTree::UnhoistedSequence(sequence)) - } - Pattern::Constructor { - name, - arguments, - constructor, - tipo: function_tipo, - .. - } => { - if subject_tipo.is_bool() { - (AirTree::bool(name == "True"), AirTree::no_op()) - } else { - assert!( - matches!(function_tipo.as_ref().clone(), Type::Fn { .. }) - || matches!(function_tipo.as_ref().clone(), Type::App { .. }) - ); - 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(); - - for (index, arg) in function_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::init_inner( - arg_type, - field_name.clone(), - field_name.clone(), - props.final_clause, - ); - - 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 { elems, .. } => { - let items_type = subject_tipo.get_inner_types(); - - let name_index_assigns = elems - .iter() - .enumerate() - .map(|(index, element)| { - let elem_name = match element { - Pattern::Var { name, .. } => name.to_string(), - Pattern::Assign { name, .. } => name.to_string(), - Pattern::Discard { .. } => "_".to_string(), - _ => format!( - "tuple_index_{}_span_{}_{}", - index, - element.location().start, - element.location().end - ), - }; - - let mut tuple_props = ClauseProperties::init_inner( - &items_type[index], - elem_name.clone(), - elem_name.clone(), - props.final_clause, - ); - - let elem = self.nested_clause_condition( - element, - &items_type[index], - &mut tuple_props, - ); - - props.complex_clause = props.complex_clause || tuple_props.complex_clause; - - (elem_name, index, elem) - }) - .collect_vec(); - - let mut defined_indices = match props.clone() { - ClauseProperties { - specific_clause: - SpecificClause::TupleClause { - defined_tuple_indices, - }, - .. - } => defined_tuple_indices, - _ => unreachable!(), - }; - - let mut previous_defined_names = vec![]; - name_index_assigns.iter().for_each(|(name, index, _)| { - if let Some((index, prev_name)) = defined_indices - .iter() - .find(|(defined_index, _nm)| defined_index == index) - { - previous_defined_names.push((*index, prev_name.clone(), name.clone())); - } else if name != "_" { - assert!(defined_indices.insert((*index, name.clone()))); - } - }); - - let tuple_name_assigns = previous_defined_names - .into_iter() - .map(|(index, prev_name, name)| { - AirTree::let_assignment( - name, - AirTree::local_var(prev_name, items_type[index].clone()), - ) - }) - .collect_vec(); - - let mut tuple_item_assigns = name_index_assigns - .into_iter() - .map(|(_, _, item)| item) - .collect_vec(); - - match props { - ClauseProperties { - specific_clause: - SpecificClause::TupleClause { - defined_tuple_indices, - }, - .. - } => { - *defined_tuple_indices = defined_indices; - } - _ => unreachable!(), - } - - let mut sequence = tuple_name_assigns; - sequence.append(&mut tuple_item_assigns); - - (AirTree::void(), AirTree::UnhoistedSequence(sequence)) - } - } - } - - fn nested_clause_condition( - &mut self, - pattern: &Pattern>, - subject_tipo: &Arc, - props: &mut ClauseProperties, - ) -> AirTree { - if props.final_clause { - props.complex_clause = false; - let (_, assign) = self.clause_pattern(pattern, subject_tipo, props); - assign - } else { - assert!( - !subject_tipo.is_void(), - "WHY ARE YOU PATTERN MATCHING ON A NESTED VOID???" - ); - match pattern { - Pattern::Int { value, .. } => { - props.complex_clause = true; - AirTree::clause_guard(&props.original_subject_name, AirTree::int(value), int()) - } - Pattern::Var { name, .. } => AirTree::let_assignment( - name, - AirTree::local_var(&props.clause_var_name, subject_tipo.clone()), - ), - Pattern::Assign { name, pattern, .. } => AirTree::UnhoistedSequence(vec![ - AirTree::let_assignment( - name, - AirTree::local_var(&props.clause_var_name, subject_tipo.clone()), - ), - self.nested_clause_condition(pattern, subject_tipo, props), - ]), - Pattern::Discard { .. } => AirTree::no_op(), - Pattern::List { elements, tail, .. } => { - props.complex_clause = true; - let tail_name_base = "__tail".to_string(); - - if elements.is_empty() { - assert!( - tail.is_none(), - "Why do you have a [..] in a clause? Use a var." - ); - - AirTree::list_clause_guard( - &props.original_subject_name, - subject_tipo.clone(), - false, - None, - ) - } else { - let mut clause_assigns = vec![]; - - let ClauseProperties { - specific_clause: - SpecificClause::ListClause { - current_index, - defined_tails, - }, - .. - } = props - else { unreachable!() }; - - for (index, _) in elements.iter().enumerate() { - let prev_tail_name = if index == 0 { - props.original_subject_name.clone() - } else { - format!("{}_{}", tail_name_base, index - 1) - }; - - let tail_name = format!("{tail_name_base}_{index}"); - - if elements.len() - 1 == index { - if tail.is_some() { - clause_assigns.push(AirTree::list_clause_guard( - prev_tail_name, - subject_tipo.clone(), - true, - None, - )); - } else { - clause_assigns.push(AirTree::list_clause_guard( - prev_tail_name, - subject_tipo.clone(), - true, - Some(tail_name.to_string()), - )); - - clause_assigns.push(AirTree::list_clause_guard( - tail_name.to_string(), - subject_tipo.clone(), - false, - None, - )); - *current_index += 1; - defined_tails.push(tail_name); - } - } else { - clause_assigns.push(AirTree::list_clause_guard( - prev_tail_name, - subject_tipo.clone(), - true, - Some(tail_name.to_string()), - )); - - *current_index += 1; - defined_tails.push(tail_name); - }; - } - let (_, assigns) = self.clause_pattern(pattern, subject_tipo, props); - clause_assigns.push(assigns); - AirTree::UnhoistedSequence(clause_assigns) - } - } - Pattern::Constructor { - name: constr_name, - is_record, - .. - } => { - props.complex_clause = true; - if subject_tipo.is_bool() { - AirTree::clause_guard( - &props.original_subject_name, - AirTree::bool(constr_name == "True"), - bool(), - ) - } else { - let (cond, assign) = self.clause_pattern(pattern, subject_tipo, props); - - if *is_record { - assign - } else { - AirTree::UnhoistedSequence(vec![ - AirTree::clause_guard( - &props.original_subject_name, - cond, - subject_tipo.clone(), - ), - assign, - ]) - } - } - } - Pattern::Tuple { .. } => { - props.complex_clause = true; - let (_, assign) = self.clause_pattern(pattern, subject_tipo, props); - - let defined_indices = match &props.specific_clause { - SpecificClause::TupleClause { - defined_tuple_indices, - } => defined_tuple_indices.clone(), - _ => unreachable!(), - }; - - let tuple_access = AirTree::tuple_clause_guard( - &props.original_subject_name, - subject_tipo.clone(), - defined_indices, - ); - - AirTree::UnhoistedSequence(vec![tuple_access, assign]) - } - } - } - } - - pub fn check_validator_args( - &mut self, - arguments: &[TypedArg], - has_context: bool, - body: AirTree, - ) -> AirTree { - let checked_args = arguments - .iter() - .enumerate() - .map(|(index, arg)| { - let arg_name = arg.arg_name.get_variable_name().unwrap_or("_").to_string(); - if !(has_context && index == arguments.len() - 1) && &arg_name != "_" { - let param = AirTree::local_var(&arg_name, data()); - - let actual_type = convert_opaque_type(&arg.tipo, &self.data_types); - - let assign = self.assignment( - &Pattern::Var { - location: Span::empty(), - name: arg_name.to_string(), - }, - param, - &actual_type, - AssignmentProperties { - value_type: data(), - kind: AssignmentKind::Expect, - remove_unused: false, - full_check: true, - }, - ); - - (arg_name, assign) - } else { - (arg_name, AirTree::no_op()) - } - }) - .collect_vec(); - - let arg_names = checked_args - .iter() - .map(|(name, _)| name.to_string()) - .collect_vec(); - - let arg_assigns = - AirTree::UnhoistedSequence(checked_args.into_iter().map(|(_, arg)| arg).collect_vec()); - - AirTree::anon_func(arg_names, arg_assigns.hoist_over(body)) - } - - fn hoist_functions_to_validator(&mut self, mut air_tree: AirTree) -> AirTree { - let mut functions_to_hoist = IndexMap::new(); - let mut used_functions = vec![]; - let mut defined_functions = vec![]; - let mut hoisted_functions = vec![]; - let mut validator_hoistable; - - // TODO change subsequent tree traversals to be more like a stream. - air_tree.traverse_tree_with(&mut |air_tree: &mut AirTree, _| { - erase_opaque_type_operations(air_tree, &self.data_types); - }); - - self.find_function_vars_and_depth( - &mut air_tree, - &mut functions_to_hoist, - &mut used_functions, - &mut TreePath::new(), - 0, - 0, - ); - - validator_hoistable = used_functions.clone(); - - while let Some((key, variant_name)) = used_functions.pop() { - defined_functions.push((key.clone(), variant_name.clone())); - let function_variants = functions_to_hoist - .get(&key) - .unwrap_or_else(|| panic!("Missing Function Definition")); - - let (tree_path, function) = function_variants - .get(&variant_name) - .unwrap_or_else(|| panic!("Missing Function Variant Definition")); - - if let UserFunction::Function(body, deps) = function { - let mut hoist_body = body.clone(); - let mut hoist_deps = deps.clone(); - - let mut tree_path = tree_path.clone(); - - self.define_dependent_functions( - &mut hoist_body, - &mut functions_to_hoist, - &mut used_functions, - &defined_functions, - &mut hoist_deps, - &mut tree_path, - ); - - let function_variants = functions_to_hoist - .get_mut(&key) - .unwrap_or_else(|| panic!("Missing Function Definition")); - - let (_, function) = function_variants - .get_mut(&variant_name) - .unwrap_or_else(|| panic!("Missing Function Variant Definition")); - - *function = UserFunction::Function(hoist_body, hoist_deps); - } else { - todo!("Deal with Link later") - } - } - - // First we need to sort functions by dependencies - // here's also where we deal with mutual recursion - let mut sorted_function_vec = vec![]; - - while let Some((generic_func, variant)) = validator_hoistable.pop() { - let function_variants = functions_to_hoist - .get(&generic_func) - .unwrap_or_else(|| panic!("Missing Function Definition")); - - let function_has_params = self - .functions - .get(&generic_func) - .map(|func| !func.arguments.is_empty()) - .unwrap_or_else(|| true); - - let (_, function) = function_variants - .get(&variant) - .unwrap_or_else(|| panic!("Missing Function Variant Definition")); - - // TODO: change this part to handle mutual recursion - if let UserFunction::Function(_, deps) = function { - if function_has_params { - for (dep_generic_func, dep_variant) in deps.iter() { - if !(dep_generic_func == &generic_func && dep_variant == &variant) { - validator_hoistable - .push((dep_generic_func.clone(), dep_variant.clone())); - let remove_index = - sorted_function_vec - .iter() - .position(|(generic_func, variant)| { - generic_func == dep_generic_func && variant == dep_variant - }); - if let Some(index) = remove_index { - sorted_function_vec.remove(index); - } - } - } - } - } else { - todo!("Deal with Link later") - } - - sorted_function_vec.push((generic_func, variant)); - } - sorted_function_vec.dedup(); - - // Now we need to hoist the functions to the top of the validator - for (key, variant) in sorted_function_vec { - if hoisted_functions - .iter() - .any(|(func_key, func_variant)| func_key == &key && func_variant == &variant) - { - continue; - } - - let function_variants = functions_to_hoist - .get(&key) - .unwrap_or_else(|| panic!("Missing Function Definition")); - - let (tree_path, function) = function_variants - .get(&variant) - .unwrap_or_else(|| panic!("Missing Function Variant Definition")); - - self.hoist_function( - &mut air_tree, - tree_path, - function, - (&key, &variant), - &functions_to_hoist, - &mut hoisted_functions, - ); - } - - air_tree - } - - fn hoist_function( - &mut self, - air_tree: &mut AirTree, - tree_path: &TreePath, - function: &UserFunction, - key_var: (&FunctionAccessKey, &String), - functions_to_hoist: &IndexMap< - FunctionAccessKey, - IndexMap, - >, - hoisted_functions: &mut Vec<(FunctionAccessKey, String)>, - ) { - if let UserFunction::Function(body, func_deps) = function { - let mut body = body.clone(); - let node_to_edit = air_tree.find_air_tree_node(tree_path); - - let (key, variant) = key_var; - - // check for recursiveness - let is_recursive = func_deps - .iter() - .any(|(dep_key, dep_variant)| dep_key == key && dep_variant == variant); - - // first grab dependencies - let func_params = self - .functions - .get(key) - .map(|func| { - func.arguments - .iter() - .map(|func_arg| { - func_arg - .arg_name - .get_variable_name() - .unwrap_or("_") - .to_string() - }) - .collect_vec() - }) - .unwrap_or_else(|| { - let Some(CodeGenFunction::Function { params, .. }) = - self.code_gen_functions.get(&key.function_name) - else { unreachable!() }; - - params.clone() - }); - - let params_empty = func_params.is_empty(); - - let deps = (tree_path, func_deps.clone()); - - if !params_empty { - body = AirTree::define_func( - &key.function_name, - &key.module_name, - variant, - func_params, - is_recursive, - body, - ); - - let function_deps = self.hoist_dependent_functions( - deps, - params_empty, - key, - variant, - hoisted_functions, - functions_to_hoist, - ); - - // now hoist full function onto validator tree - *node_to_edit = function_deps.hoist_over(body.hoist_over(node_to_edit.clone())); - - hoisted_functions.push((key.clone(), variant.clone())); - } else { - body = self - .hoist_dependent_functions( - deps, - params_empty, - key, - variant, - hoisted_functions, - functions_to_hoist, - ) - .hoist_over(body); - - self.zero_arg_functions.insert(key.clone(), body.to_vec()); - } - } else { - todo!() - } - } - - fn hoist_dependent_functions( - &mut self, - deps: (&TreePath, Vec<(FunctionAccessKey, String)>), - params_empty: bool, - key: &FunctionAccessKey, - variant: &String, - hoisted_functions: &mut Vec<(FunctionAccessKey, String)>, - functions_to_hoist: &IndexMap< - FunctionAccessKey, - IndexMap, - >, - ) -> AirTree { - let (func_path, func_deps) = deps; - - let mut deps_vec = func_deps; - - let mut dep_insertions = vec![]; - - // This part handles hoisting dependencies - while let Some((dep_key, dep_variant)) = deps_vec.pop() { - if (!params_empty - // if the dependency is the same as the function we're hoisting - // or we hoisted it, then skip it - && hoisted_functions.iter().any(|(generic, variant)| { - generic == &dep_key && variant == &dep_variant - })) - || (&dep_key == key && &dep_variant == variant) - { - continue; - } - - let dependency = functions_to_hoist - .get(&dep_key) - .unwrap_or_else(|| panic!("Missing Function Definition")); - - let (dep_path, dep_function) = dependency - .get(&dep_variant) - .unwrap_or_else(|| panic!("Missing Function Variant Definition")); - - // In the case of zero args, we need to hoist the dependency function to the top of the zero arg function - if &dep_path.common_ancestor(func_path) == func_path || params_empty { - let dependent_params = self - .functions - .get(&dep_key) - .map(|dep_func| { - dep_func - .arguments - .iter() - .map(|func_arg| { - func_arg - .arg_name - .get_variable_name() - .unwrap_or("_") - .to_string() - }) - .collect_vec() - }) - .unwrap_or_else(|| { - let Some(CodeGenFunction::Function { params, .. }) = - self.code_gen_functions.get(&key.function_name) - else { unreachable!() }; - - params.clone() - }); - - let UserFunction::Function(dep_air_tree, dependency_deps) = - dep_function.clone() - else { unreachable!() }; - - let is_dependent_recursive = dependency_deps - .iter() - .any(|(key, variant)| &dep_key == key && &dep_variant == variant); - - let dependency_deps_to_add = dependency_deps - .iter() - .filter(|(dep_k, dep_v)| !(dep_k == &dep_key && dep_v == &dep_variant)) - .filter(|(dep_k, dep_v)| { - !params_empty - && !hoisted_functions - .iter() - .any(|(generic, variant)| generic == dep_k && variant == dep_v) - }) - .cloned() - .collect_vec(); - - dep_insertions.push(AirTree::define_func( - &dep_key.function_name, - &dep_key.module_name, - &dep_variant, - dependent_params, - is_dependent_recursive, - dep_air_tree, - )); - - deps_vec.extend(dependency_deps_to_add); - - if !params_empty { - hoisted_functions.push((dep_key.clone(), dep_variant.clone())); - } - } - } - - dep_insertions.reverse(); - - AirTree::UnhoistedSequence(dep_insertions) - } - - fn define_dependent_functions( - &mut self, - air_tree: &mut AirTree, - function_usage: &mut IndexMap< - FunctionAccessKey, - IndexMap, - >, - used_functions: &mut Vec<(FunctionAccessKey, String)>, - defined_functions: &[(FunctionAccessKey, String)], - current_function_deps: &mut Vec<(FunctionAccessKey, String)>, - validator_tree_path: &mut TreePath, - ) { - let Some((depth, index)) = validator_tree_path.pop() - else { return }; - - validator_tree_path.push(depth, index); - - self.find_function_vars_and_depth( - air_tree, - function_usage, - current_function_deps, - validator_tree_path, - depth + 1, - 0, - ); - - for (generic_function_key, variant_name) in current_function_deps.iter() { - if !used_functions - .iter() - .any(|(key, name)| key == generic_function_key && name == variant_name) - && !defined_functions - .iter() - .any(|(key, name)| key == generic_function_key && name == variant_name) - { - used_functions.push((generic_function_key.clone(), variant_name.clone())); - } - } - } - - fn find_function_vars_and_depth( - &mut self, - air_tree: &mut AirTree, - function_usage: &mut IndexMap< - FunctionAccessKey, - IndexMap, - >, - dependency_functions: &mut Vec<(FunctionAccessKey, String)>, - path: &mut TreePath, - current_depth: usize, - depth_index: usize, - ) { - air_tree.traverse_tree_with_path( - path, - current_depth, - depth_index, - &mut |air_tree, tree_path| { - if let AirTree::Expression(AirExpression::Var { - constructor, - variant_name, - .. - }) = air_tree - { - let ValueConstructorVariant::ModuleFn { - name: func_name, - module, - builtin: None, - .. - } = &constructor.variant - else { return }; - - let function_var_tipo = &constructor.tipo; - - let generic_function_key = FunctionAccessKey { - module_name: module.clone(), - function_name: func_name.clone(), - }; - - let function_def = self.functions.get(&generic_function_key); - - let Some(function_def) = function_def - else { - let code_gen_func = self - .code_gen_functions - .get(&generic_function_key.function_name) - .unwrap_or_else(|| panic!("Missing Code Gen Function Definition")); - - if let Some(func_variants) = function_usage.get_mut(&generic_function_key) { - let (path, _) = func_variants.get_mut("").unwrap(); - - *path = path.common_ancestor(tree_path); - } else { - let CodeGenFunction::Function{ body, .. } = code_gen_func - else { unreachable!() }; - - let mut function_variant_path = IndexMap::new(); - - function_variant_path.insert( - "".to_string(), - ( - tree_path.clone(), - UserFunction::Function(body.clone(), vec![]), - ), - ); - - dependency_functions.push((generic_function_key.clone(), "".to_string())); - function_usage.insert(generic_function_key, function_variant_path); - } - return; - }; - - let mut function_var_types = function_var_tipo - .arg_types() - .unwrap_or_else(|| panic!("Expected a function tipo with arg types")); - - function_var_types.push( - function_var_tipo - .return_type() - .unwrap_or_else(|| panic!("Should have return type")), - ); - - let mut function_def_types = function_def - .arguments - .iter() - .map(|arg| &arg.tipo) - .collect_vec(); - - function_def_types.push(&function_def.return_type); - - let mono_types: IndexMap> = if !function_def_types.is_empty() { - function_def_types - .into_iter() - .zip(function_var_types.into_iter()) - .flat_map(|(func_tipo, var_tipo)| { - get_generic_id_and_type(func_tipo, &var_tipo) - }) - .collect() - } else { - IndexMap::new() - }; - - let variant = mono_types - .iter() - .sorted_by(|(id, _), (id2, _)| id.cmp(id2)) - .map(|(_, tipo)| get_variant_name(tipo)) - .join(""); - - *variant_name = variant.clone(); - - if !dependency_functions - .iter() - .any(|(key, name)| key == &generic_function_key && name == &variant) - { - dependency_functions.push((generic_function_key.clone(), variant.clone())); - } - - if let Some(func_variants) = function_usage.get_mut(&generic_function_key) { - if let Some((path, _)) = func_variants.get_mut(&variant) { - *path = path.common_ancestor(tree_path); - } else { - let mut function_air_tree_body = self.build(&function_def.body); - - function_air_tree_body.traverse_tree_with(&mut |air_tree, _| { - monomorphize(air_tree, &mono_types); - - erase_opaque_type_operations(air_tree, &self.data_types); - }); - - func_variants.insert( - variant, - ( - tree_path.clone(), - UserFunction::Function(function_air_tree_body, vec![]), - ), - ); - } - } else { - let mut function_air_tree_body = self.build(&function_def.body); - - function_air_tree_body.traverse_tree_with(&mut |air_tree, _| { - monomorphize(air_tree, &mono_types); - - erase_opaque_type_operations(air_tree, &self.data_types); - }); - - let mut function_variant_path = IndexMap::new(); - - function_variant_path.insert( - variant, - ( - tree_path.clone(), - UserFunction::Function(function_air_tree_body, vec![]), - ), - ); - - function_usage.insert(generic_function_key, function_variant_path); - } - } - }, - ); - } - - fn uplc_code_gen(&mut self, ir_stack: &mut Vec) -> Term { - let mut arg_stack: Vec> = vec![]; - - while let Some(ir_element) = ir_stack.pop() { - todo!() - } - arg_stack[0].clone() - } -} diff --git a/crates/aiken-lang/src/gen_uplc2/air.rs b/crates/aiken-lang/src/gen_uplc2/air.rs deleted file mode 100644 index a832f70e..00000000 --- a/crates/aiken-lang/src/gen_uplc2/air.rs +++ /dev/null @@ -1,184 +0,0 @@ -use indexmap::IndexSet; -use std::sync::Arc; -use uplc::builtins::DefaultFunction; - -use crate::{ - ast::{BinOp, UnOp}, - tipo::{Type, ValueConstructor}, -}; - -#[derive(Debug, Clone, PartialEq)] -pub enum Air { - // Primitives - Int { - value: String, - }, - String { - value: String, - }, - ByteArray { - bytes: Vec, - }, - Bool { - value: bool, - }, - List { - count: usize, - tipo: Arc, - tail: bool, - }, - Tuple { - tipo: Arc, - count: usize, - }, - Void, - Var { - constructor: ValueConstructor, - name: String, - variant_name: String, - }, - // Functions - Call { - count: usize, - tipo: Arc, - }, - DefineFunc { - func_name: String, - module_name: String, - params: Vec, - recursive: bool, - variant_name: String, - }, - Fn { - params: Vec, - }, - Builtin { - count: usize, - func: DefaultFunction, - tipo: Arc, - }, - // Operators - BinOp { - name: BinOp, - tipo: Arc, - argument_tipo: Arc, - }, - UnOp { - op: UnOp, - }, - // Assignment - Let { - name: String, - }, - UnWrapData { - tipo: Arc, - }, - WrapData { - tipo: Arc, - }, - AssertConstr { - constr_index: usize, - }, - AssertBool { - is_true: bool, - }, - // When - When { - tipo: Arc, - subject_name: String, - subject_tipo: Arc, - }, - Clause { - subject_tipo: Arc, - subject_name: String, - complex_clause: bool, - }, - ListClause { - subject_tipo: Arc, - tail_name: String, - next_tail_name: Option, - complex_clause: bool, - }, - WrapClause, - TupleClause { - subject_tipo: Arc, - indices: IndexSet<(usize, String)>, - predefined_indices: IndexSet<(usize, String)>, - subject_name: String, - count: usize, - complex_clause: bool, - }, - ClauseGuard { - subject_name: String, - subject_tipo: Arc, - }, - ListClauseGuard { - subject_tipo: Arc, - tail_name: String, - next_tail_name: Option, - inverse: bool, - }, - TupleGuard { - subject_tipo: Arc, - indices: IndexSet<(usize, String)>, - subject_name: String, - type_count: usize, - }, - Finally, - // If - If { - tipo: Arc, - }, - // Record Creation - Constr { - tag: usize, - tipo: Arc, - count: usize, - }, - RecordUpdate { - highest_index: usize, - indices: Vec<(usize, Arc)>, - tipo: Arc, - }, - // Field Access - RecordAccess { - record_index: u64, - tipo: Arc, - }, - FieldsExpose { - indices: Vec<(usize, String, Arc)>, - check_last_item: bool, - }, - // ListAccess - ListAccessor { - tipo: Arc, - names: Vec, - tail: bool, - check_last_item: bool, - }, - ListExpose { - tipo: Arc, - tail_head_names: Vec<(String, String)>, - tail: Option<(String, String)>, - }, - // Tuple Access - TupleAccessor { - names: Vec, - tipo: Arc, - check_last_item: bool, - }, - TupleIndex { - tipo: Arc, - tuple_index: usize, - }, - // Misc. - ErrorTerm { - tipo: Arc, - }, - Trace { - tipo: Arc, - }, - NoOp, - FieldsEmpty, - ListEmpty, -} diff --git a/crates/aiken-lang/src/gen_uplc2/builder.rs b/crates/aiken-lang/src/gen_uplc2/builder.rs deleted file mode 100644 index 657c8d4f..00000000 --- a/crates/aiken-lang/src/gen_uplc2/builder.rs +++ /dev/null @@ -1,366 +0,0 @@ -use std::sync::Arc; - -use indexmap::IndexMap; - -use crate::{ - ast::TypedDataType, - builtins::bool, - gen_uplc::builder::{lookup_data_type_by_tipo, DataTypeKey, FunctionAccessKey}, - tipo::TypeVar, -}; - -use crate::{ - ast::{BinOp, ClauseGuard, Constant, UnOp}, - tipo::Type, -}; - -use super::tree::{AirExpression, AirStatement, AirTree}; - -#[derive(Clone, Debug)] -pub enum CodeGenFunction { - Function { body: AirTree, params: Vec }, - Link(String), -} - -#[derive(Clone, Debug)] -pub enum UserFunction { - Function(AirTree, Vec<(FunctionAccessKey, String)>), - Link(String), -} - -pub fn get_generic_id_and_type(tipo: &Type, param: &Type) -> Vec<(u64, Arc)> { - let mut generics_ids = vec![]; - - if let Some(id) = tipo.get_generic() { - generics_ids.push((id, param.clone().into())); - return generics_ids; - } - - for (tipo, param_type) in tipo - .get_inner_types() - .iter() - .zip(param.get_inner_types().iter()) - { - generics_ids.append(&mut get_generic_id_and_type(tipo, param_type)); - } - generics_ids -} - -pub fn convert_opaque_type( - t: &Arc, - data_types: &IndexMap, -) -> Arc { - if check_replaceable_opaque_type(t, data_types) && matches!(t.as_ref(), Type::App { .. }) { - let data_type = lookup_data_type_by_tipo(data_types, t).unwrap(); - let new_type_fields = data_type.typed_parameters; - - let mono_types: IndexMap>; - let mut mono_type_vec = vec![]; - - for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) { - mono_type_vec.append(&mut get_generic_id_and_type(tipo, ¶m)); - } - mono_types = mono_type_vec.into_iter().collect(); - - let generic_type = &data_type.constructors[0].arguments[0].tipo; - - let mono_type = find_and_replace_generics(generic_type, &mono_types); - - convert_opaque_type(&mono_type, data_types) - } else { - match t.as_ref() { - Type::App { - public, - module, - name, - args, - } => { - let mut new_args = vec![]; - for arg in args { - let arg = convert_opaque_type(arg, data_types); - new_args.push(arg); - } - Type::App { - public: *public, - module: module.clone(), - name: name.clone(), - args: new_args, - } - .into() - } - Type::Fn { args, ret } => { - let mut new_args = vec![]; - for arg in args { - let arg = convert_opaque_type(arg, data_types); - new_args.push(arg); - } - - let ret = convert_opaque_type(ret, data_types); - - Type::Fn { - args: new_args, - ret, - } - .into() - } - Type::Var { tipo: var_tipo } => { - if let TypeVar::Link { tipo } = &var_tipo.borrow().clone() { - convert_opaque_type(tipo, data_types) - } else { - t.clone() - } - } - Type::Tuple { elems } => { - let mut new_elems = vec![]; - for arg in elems { - let arg = convert_opaque_type(arg, data_types); - new_elems.push(arg); - } - Type::Tuple { elems: new_elems }.into() - } - } - } -} - -pub fn check_replaceable_opaque_type( - t: &Arc, - data_types: &IndexMap, -) -> bool { - let data_type = lookup_data_type_by_tipo(data_types, t); - - if let Some(data_type) = data_type { - let data_type_args = &data_type.constructors[0].arguments; - data_type_args.len() == 1 && data_type.opaque && data_type.constructors.len() == 1 - } else { - false - } -} - -pub fn find_and_replace_generics( - tipo: &Arc, - mono_types: &IndexMap>, -) -> Arc { - if let Some(id) = tipo.get_generic() { - // If a generic does not have a type we know of - // like a None in option then just use same type - mono_types.get(&id).unwrap_or(tipo).clone() - } else if tipo.is_generic() { - match &**tipo { - Type::App { - args, - public, - module, - name, - } => { - let mut new_args = vec![]; - for arg in args { - let arg = find_and_replace_generics(arg, mono_types); - new_args.push(arg); - } - let t = Type::App { - args: new_args, - public: *public, - module: module.clone(), - name: name.clone(), - }; - t.into() - } - Type::Fn { args, ret } => { - let mut new_args = vec![]; - for arg in args { - let arg = find_and_replace_generics(arg, mono_types); - new_args.push(arg); - } - - let ret = find_and_replace_generics(ret, mono_types); - - let t = Type::Fn { - args: new_args, - ret, - }; - - t.into() - } - Type::Tuple { elems } => { - let mut new_elems = vec![]; - for elem in elems { - let elem = find_and_replace_generics(elem, mono_types); - new_elems.push(elem); - } - let t = Type::Tuple { elems: new_elems }; - t.into() - } - Type::Var { tipo: var_tipo } => { - let var_type = var_tipo.as_ref().borrow().clone(); - - match var_type { - TypeVar::Link { tipo } => find_and_replace_generics(&tipo, mono_types), - TypeVar::Generic { .. } | TypeVar::Unbound { .. } => unreachable!(), - } - } - } - } else { - tipo.clone() - } -} - -pub fn constants_ir(literal: &Constant) -> AirTree { - match literal { - Constant::Int { value, .. } => AirTree::int(value), - Constant::String { value, .. } => AirTree::string(value), - 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_child = handle_clause_guard(left); - let right_child = handle_clause_guard(right); - - AirTree::binop(BinOp::Eq, bool(), left_child, right_child, left.tipo()) - } - ClauseGuard::NotEquals { left, right, .. } => { - let left_child = handle_clause_guard(left); - let right_child = handle_clause_guard(right); - - AirTree::binop(BinOp::NotEq, bool(), left_child, right_child, left.tipo()) - } - ClauseGuard::GtInt { left, right, .. } => { - let left_child = handle_clause_guard(left); - let right_child = handle_clause_guard(right); - - AirTree::binop(BinOp::GtInt, bool(), left_child, right_child, left.tipo()) - } - ClauseGuard::GtEqInt { left, right, .. } => { - let left_child = handle_clause_guard(left); - let right_child = handle_clause_guard(right); - - AirTree::binop(BinOp::GtEqInt, bool(), left_child, right_child, left.tipo()) - } - ClauseGuard::LtInt { left, right, .. } => { - let left_child = handle_clause_guard(left); - let right_child = handle_clause_guard(right); - - AirTree::binop(BinOp::LtInt, bool(), left_child, right_child, left.tipo()) - } - ClauseGuard::LtEqInt { left, right, .. } => { - let left_child = handle_clause_guard(left); - let right_child = handle_clause_guard(right); - - AirTree::binop(BinOp::LtEqInt, bool(), left_child, right_child, left.tipo()) - } - ClauseGuard::Or { left, right, .. } => { - let left_child = handle_clause_guard(left); - let right_child = handle_clause_guard(right); - - AirTree::binop(BinOp::Or, bool(), left_child, right_child, left.tipo()) - } - ClauseGuard::And { left, right, .. } => { - let left_child = handle_clause_guard(left); - let right_child = handle_clause_guard(right); - - AirTree::binop(BinOp::And, bool(), left_child, right_child, left.tipo()) - } - ClauseGuard::Var { tipo, name, .. } => AirTree::local_var(name, tipo.clone()), - ClauseGuard::Constant(constant) => constants_ir(constant), - } -} - -pub fn get_variant_name(t: &Arc) -> String { - if t.is_string() { - "_string".to_string() - } else if t.is_int() { - "_int".to_string() - } else if t.is_bool() { - "_bool".to_string() - } else if t.is_bytearray() { - "_bytearray".to_string() - } else if t.is_map() { - let mut full_type = vec!["_map".to_string()]; - let pair_type = &t.get_inner_types()[0]; - let fst_type = &pair_type.get_inner_types()[0]; - let snd_type = &pair_type.get_inner_types()[1]; - full_type.push(get_variant_name(fst_type)); - full_type.push(get_variant_name(snd_type)); - full_type.join("") - } else if t.is_list() { - let full_type = "_list".to_string(); - let list_type = &t.get_inner_types()[0]; - - format!("{}{}", full_type, get_variant_name(list_type)) - } else if t.is_tuple() { - let mut full_type = vec!["_tuple".to_string()]; - - let inner_types = t.get_inner_types(); - - for arg_type in inner_types { - full_type.push(get_variant_name(&arg_type)); - } - full_type.join("") - } else if t.is_unbound() { - "_unbound".to_string() - } else { - let full_type = "_data".to_string(); - - if t.is_generic() { - println!("FULL TYPE: {:#?}", t); - panic!("FOUND A POLYMORPHIC TYPE. EXPECTED MONOMORPHIC TYPE"); - } - - full_type - } -} - -pub fn monomorphize(air_tree: &mut AirTree, mono_types: &IndexMap>) { - let mut held_types = air_tree.mut_held_types(); - - while let Some(tipo) = held_types.pop() { - *tipo = find_and_replace_generics(tipo, mono_types); - } -} - -pub fn erase_opaque_type_operations( - air_tree: &mut AirTree, - data_types: &IndexMap, -) { - if let AirTree::Expression(e) = air_tree { - match e { - AirExpression::Constr { tipo, args, .. } => { - if check_replaceable_opaque_type(tipo, data_types) { - *air_tree = args.pop().unwrap(); - } - } - AirExpression::RecordAccess { tipo, record, .. } => { - if check_replaceable_opaque_type(tipo, data_types) { - *air_tree = (**record).clone(); - } - } - - _ => {} - } - } else if let AirTree::Statement { - statement: AirStatement::FieldsExpose { - record, indices, .. - }, - hoisted_over: Some(hoisted_over), - } = air_tree - { - if check_replaceable_opaque_type(&record.return_type(), data_types) { - let name = indices[0].1.clone(); - *air_tree = AirTree::let_assignment(name, (**record).clone()) - .hoist_over((**hoisted_over).clone()) - } - } - - let mut held_types = air_tree.mut_held_types(); - - while let Some(tipo) = held_types.pop() { - *tipo = convert_opaque_type(tipo, data_types); - } -} diff --git a/crates/aiken-lang/src/gen_uplc_old/air.rs b/crates/aiken-lang/src/gen_uplc_old/air.rs new file mode 100644 index 00000000..190432a4 --- /dev/null +++ b/crates/aiken-lang/src/gen_uplc_old/air.rs @@ -0,0 +1,430 @@ +use indexmap::IndexSet; +use std::sync::Arc; +use uplc::builtins::DefaultFunction; + +use crate::{ + ast::{BinOp, UnOp}, + tipo::{Type, ValueConstructor}, +}; + +use super::scope::Scope; + +#[derive(Debug, Clone, PartialEq)] +pub enum Air { + // Primitives + Int { + scope: Scope, + value: String, + }, + String { + scope: Scope, + value: String, + }, + ByteArray { + scope: Scope, + bytes: Vec, + }, + Bool { + scope: Scope, + value: bool, + }, + List { + scope: Scope, + count: usize, + tipo: Arc, + tail: bool, + }, + Tuple { + scope: Scope, + tipo: Arc, + count: usize, + }, + Void { + scope: Scope, + }, + Var { + scope: Scope, + constructor: ValueConstructor, + name: String, + variant_name: String, + }, + // Functions + Call { + scope: Scope, + count: usize, + tipo: Arc, + }, + DefineFunc { + scope: Scope, + func_name: String, + module_name: String, + params: Vec, + recursive: bool, + variant_name: String, + }, + Fn { + scope: Scope, + params: Vec, + }, + Builtin { + scope: Scope, + count: usize, + func: DefaultFunction, + tipo: Arc, + }, + // Operators + BinOp { + scope: Scope, + name: BinOp, + tipo: Arc, + }, + UnOp { + scope: Scope, + op: UnOp, + }, + // Assignment + Let { + scope: Scope, + name: String, + }, + UnWrapData { + scope: Scope, + tipo: Arc, + }, + WrapData { + scope: Scope, + tipo: Arc, + }, + AssertConstr { + scope: Scope, + constr_index: usize, + }, + AssertBool { + scope: Scope, + is_true: bool, + }, + // When + When { + scope: Scope, + tipo: Arc, + subject_name: String, + }, + Clause { + scope: Scope, + tipo: Arc, + subject_name: String, + complex_clause: bool, + }, + ListClause { + scope: Scope, + tipo: Arc, + tail_name: String, + next_tail_name: Option, + complex_clause: bool, + }, + WrapClause { + scope: Scope, + }, + TupleClause { + scope: Scope, + tipo: Arc, + indices: IndexSet<(usize, String)>, + predefined_indices: IndexSet<(usize, String)>, + subject_name: String, + count: usize, + complex_clause: bool, + }, + ClauseGuard { + scope: Scope, + subject_name: String, + tipo: Arc, + }, + ListClauseGuard { + scope: Scope, + tipo: Arc, + tail_name: String, + next_tail_name: Option, + inverse: bool, + }, + Finally { + scope: Scope, + }, + // If + If { + scope: Scope, + tipo: Arc, + }, + // Record Creation + Record { + scope: Scope, + tag: usize, + tipo: Arc, + count: usize, + }, + RecordUpdate { + scope: Scope, + highest_index: usize, + indices: Vec<(usize, Arc)>, + tipo: Arc, + }, + // Field Access + RecordAccess { + scope: Scope, + record_index: u64, + tipo: Arc, + }, + FieldsExpose { + scope: Scope, + indices: Vec<(usize, String, Arc)>, + check_last_item: bool, + }, + // ListAccess + ListAccessor { + scope: Scope, + tipo: Arc, + names: Vec, + tail: bool, + check_last_item: bool, + }, + ListExpose { + scope: Scope, + tipo: Arc, + tail_head_names: Vec<(String, String)>, + tail: Option<(String, String)>, + }, + // Tuple Access + TupleAccessor { + scope: Scope, + names: Vec, + tipo: Arc, + check_last_item: bool, + }, + TupleIndex { + scope: Scope, + tipo: Arc, + tuple_index: usize, + }, + // Misc. + ErrorTerm { + scope: Scope, + tipo: Arc, + }, + Trace { + scope: Scope, + tipo: Arc, + }, + NoOp { + scope: Scope, + }, + FieldsEmpty { + scope: Scope, + }, + ListEmpty { + scope: Scope, + }, +} + +impl Air { + pub fn scope(&self) -> Scope { + match self { + Air::Int { scope, .. } + | Air::String { scope, .. } + | Air::ByteArray { scope, .. } + | Air::Bool { scope, .. } + | Air::List { scope, .. } + | Air::Tuple { scope, .. } + | Air::Void { scope } + | Air::Var { scope, .. } + | Air::Call { scope, .. } + | Air::DefineFunc { scope, .. } + | Air::Fn { scope, .. } + | Air::Builtin { scope, .. } + | Air::BinOp { scope, .. } + | Air::UnOp { scope, .. } + | Air::Let { scope, .. } + | Air::UnWrapData { scope, .. } + | Air::WrapData { scope, .. } + | Air::AssertConstr { scope, .. } + | Air::AssertBool { scope, .. } + | Air::When { scope, .. } + | Air::Clause { scope, .. } + | Air::ListClause { scope, .. } + | Air::WrapClause { scope } + | Air::TupleClause { scope, .. } + | Air::ClauseGuard { scope, .. } + | Air::ListClauseGuard { scope, .. } + | Air::Finally { scope } + | Air::If { scope, .. } + | Air::Record { scope, .. } + | Air::RecordUpdate { scope, .. } + | Air::RecordAccess { scope, .. } + | Air::FieldsExpose { scope, .. } + | Air::FieldsEmpty { scope } + | Air::ListEmpty { scope } + | Air::ListAccessor { scope, .. } + | Air::ListExpose { scope, .. } + | Air::TupleAccessor { scope, .. } + | Air::TupleIndex { scope, .. } + | Air::ErrorTerm { scope, .. } + | Air::Trace { scope, .. } + | Air::NoOp { scope, .. } => scope.clone(), + } + } + pub fn scope_mut(&mut self) -> &mut Scope { + match self { + Air::Int { scope, .. } + | Air::String { scope, .. } + | Air::ByteArray { scope, .. } + | Air::Bool { scope, .. } + | Air::List { scope, .. } + | Air::Tuple { scope, .. } + | Air::Void { scope } + | Air::Var { scope, .. } + | Air::Call { scope, .. } + | Air::DefineFunc { scope, .. } + | Air::Fn { scope, .. } + | Air::Builtin { scope, .. } + | Air::BinOp { scope, .. } + | Air::UnOp { scope, .. } + | Air::Let { scope, .. } + | Air::UnWrapData { scope, .. } + | Air::WrapData { scope, .. } + | Air::AssertConstr { scope, .. } + | Air::AssertBool { scope, .. } + | Air::When { scope, .. } + | Air::Clause { scope, .. } + | Air::ListClause { scope, .. } + | Air::WrapClause { scope } + | Air::TupleClause { scope, .. } + | Air::ClauseGuard { scope, .. } + | Air::ListClauseGuard { scope, .. } + | Air::Finally { scope } + | Air::If { scope, .. } + | Air::Record { scope, .. } + | Air::RecordUpdate { scope, .. } + | Air::RecordAccess { scope, .. } + | Air::FieldsExpose { scope, .. } + | Air::FieldsEmpty { scope } + | Air::ListEmpty { scope } + | Air::ListAccessor { scope, .. } + | Air::ListExpose { scope, .. } + | Air::TupleAccessor { scope, .. } + | Air::TupleIndex { scope, .. } + | Air::ErrorTerm { scope, .. } + | Air::Trace { scope, .. } + | Air::NoOp { scope, .. } => scope, + } + } + pub fn tipo(&self) -> Option> { + match self { + Air::Int { .. } => Some( + Type::App { + public: true, + module: String::new(), + name: "Int".to_string(), + args: vec![], + } + .into(), + ), + Air::String { .. } => Some( + Type::App { + public: true, + module: String::new(), + name: "String".to_string(), + args: vec![], + } + .into(), + ), + Air::ByteArray { .. } => Some( + Type::App { + public: true, + module: String::new(), + name: "ByteArray".to_string(), + args: vec![], + } + .into(), + ), + Air::Bool { .. } => Some( + Type::App { + public: true, + module: String::new(), + name: "Bool".to_string(), + args: vec![], + } + .into(), + ), + Air::Void { .. } => Some( + Type::App { + public: true, + module: String::new(), + name: "Void".to_string(), + args: vec![], + } + .into(), + ), + Air::WrapData { .. } => Some( + Type::App { + public: true, + module: String::new(), + name: "Data".to_string(), + args: vec![], + } + .into(), + ), + Air::Var { constructor, .. } => Some(constructor.tipo.clone()), + Air::List { tipo, .. } + | Air::Tuple { tipo, .. } + | Air::Call { tipo, .. } + | Air::Builtin { tipo, .. } + | Air::BinOp { tipo, .. } + | Air::UnWrapData { tipo, .. } + | Air::When { tipo, .. } + | Air::Clause { tipo, .. } + | Air::ListClause { tipo, .. } + | Air::TupleClause { tipo, .. } + | Air::ClauseGuard { tipo, .. } + | Air::If { tipo, .. } + | Air::ListClauseGuard { tipo, .. } + | Air::Record { tipo, .. } + | Air::RecordUpdate { tipo, .. } + | Air::RecordAccess { tipo, .. } + | Air::ListAccessor { tipo, .. } + | Air::ListExpose { tipo, .. } + | Air::TupleAccessor { tipo, .. } + | Air::TupleIndex { tipo, .. } + | Air::ErrorTerm { tipo, .. } + | Air::Trace { tipo, .. } => Some(tipo.clone()), + Air::DefineFunc { .. } + | Air::Fn { .. } + | Air::Let { .. } + | Air::WrapClause { .. } + | Air::AssertConstr { .. } + | Air::AssertBool { .. } + | Air::Finally { .. } + | Air::FieldsExpose { .. } + | Air::FieldsEmpty { .. } + | Air::ListEmpty { .. } + | Air::NoOp { .. } => None, + Air::UnOp { op, .. } => match op { + UnOp::Not => Some( + Type::App { + public: true, + module: String::new(), + name: "Bool".to_string(), + args: vec![], + } + .into(), + ), + UnOp::Negate => Some( + Type::App { + public: true, + module: String::new(), + name: "Int".to_string(), + args: vec![], + } + .into(), + ), + }, + } + } +} diff --git a/crates/aiken-lang/src/gen_uplc_old/builder.rs b/crates/aiken-lang/src/gen_uplc_old/builder.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/crates/aiken-lang/src/gen_uplc_old/builder.rs @@ -0,0 +1 @@ + diff --git a/crates/aiken-lang/src/gen_uplc/scope.rs b/crates/aiken-lang/src/gen_uplc_old/scope.rs similarity index 100% rename from crates/aiken-lang/src/gen_uplc/scope.rs rename to crates/aiken-lang/src/gen_uplc_old/scope.rs diff --git a/crates/aiken-lang/src/gen_uplc/stack.rs b/crates/aiken-lang/src/gen_uplc_old/stack.rs similarity index 100% rename from crates/aiken-lang/src/gen_uplc/stack.rs rename to crates/aiken-lang/src/gen_uplc_old/stack.rs diff --git a/crates/aiken-lang/src/lib.rs b/crates/aiken-lang/src/lib.rs index 1b4b598e..3b4eb8de 100644 --- a/crates/aiken-lang/src/lib.rs +++ b/crates/aiken-lang/src/lib.rs @@ -8,7 +8,6 @@ pub mod builtins; pub mod expr; pub mod format; pub mod gen_uplc; -pub mod gen_uplc2; pub mod levenshtein; pub mod parser; pub mod pretty; diff --git a/crates/aiken-project/src/module.rs b/crates/aiken-project/src/module.rs index a1e0915a..a8c3bef9 100644 --- a/crates/aiken-project/src/module.rs +++ b/crates/aiken-project/src/module.rs @@ -317,7 +317,6 @@ impl CheckedModules { FunctionAccessKey { module_name: module.name.clone(), function_name: func.name.clone(), - variant_name: String::new(), }, func, );