diff --git a/crates/aiken-lang/src/gen_uplc/tree.rs b/crates/aiken-lang/src/gen_uplc/tree.rs index eb700e14..317f704e 100644 --- a/crates/aiken-lang/src/gen_uplc/tree.rs +++ b/crates/aiken-lang/src/gen_uplc/tree.rs @@ -4,6 +4,7 @@ use uplc::builtins::DefaultFunction; use crate::{ ast::{BinOp, Span, UnOp}, + builtins::{data, list, void}, tipo::{Type, ValueConstructor, ValueConstructorVariant}, }; @@ -655,6 +656,7 @@ impl AirTree { | AirStatement::NoOp { hoisted_over } | AirStatement::ListExpose { hoisted_over, .. } | AirStatement::TupleAccessor { hoisted_over, .. } => { + assert!(hoisted_over.is_none()); *hoisted_over = Some(next_exp).into(); assignment } @@ -675,6 +677,56 @@ impl AirTree { } } + pub fn expect_on_list() -> AirTree { + // self.air.push(Air::DefineFunc { + // scope: self.scope.clone(), + // func_name: EXPECT_ON_LIST.to_string(), + // module_name: "".to_string(), + // params: vec!["__list_to_check".to_string(), "__check_with".to_string()], + // recursive: true, + // variant_name: "".to_string(), + // }); + + let list_var = AirTree::local_var("__list_to_check", list(data())); + + let head_list = AirTree::builtin(DefaultFunction::HeadList, data(), vec![list_var]); + + let expect_on_head = AirTree::call( + AirTree::local_var("__check_with", void()), + void(), + vec![head_list], + ); + todo!() + + // self.list_clause(void(), "__list_to_check", None, false, void_stack); + + // self.choose_unit(check_with_stack); + + // expect_stack.var( + // ValueConstructor::public( + // void(), + // ValueConstructorVariant::ModuleFn { + // name: EXPECT_ON_LIST.to_string(), + // field_map: None, + // module: "".to_string(), + // arity: 2, + // location: Span::empty(), + // builtin: None, + // }, + // ), + // EXPECT_ON_LIST, + // "", + // ); + + // arg_stack1.local_var(list(data()), "__list_to_check"); + + // arg_stack2.local_var(void(), "__check_with"); + + // tail_stack.builtin(DefaultFunction::TailList, list(data()), vec![arg_stack1]); + + // self.call(void(), expect_stack, vec![tail_stack, arg_stack2]) + } + pub fn to_air_vec(_air_vec: &mut Vec, tree: AirTree) { match tree { AirTree::Statement(_) => todo!(), diff --git a/crates/aiken-lang/src/gen_uplc2.rs b/crates/aiken-lang/src/gen_uplc2.rs index b8b2d3ce..f7e6081f 100644 --- a/crates/aiken-lang/src/gen_uplc2.rs +++ b/crates/aiken-lang/src/gen_uplc2.rs @@ -1,21 +1,38 @@ mod builder; +use std::sync::Arc; + use indexmap::IndexMap; use itertools::Itertools; -use uplc::ast::{Name, Program, Term}; +use uplc::{ + ast::{Name, Program, Term}, + builder::EXPECT_ON_LIST, +}; use crate::{ - ast::{AssignmentKind, Span, TypedDataType, TypedFunction, TypedValidator}, + ast::{ + AssignmentKind, BinOp, DataType, Pattern, Span, TypedDataType, TypedFunction, + TypedValidator, + }, + builtins::{int, void}, expr::TypedExpr, gen_uplc::{ air::Air, builder::{self as build, AssignmentProperties, DataTypeKey, FunctionAccessKey}, tree::AirTree, - CodeGenFunction, }, - tipo::{ModuleValueConstructor, TypeInfo, ValueConstructor, ValueConstructorVariant}, + tipo::{ + ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor, + ValueConstructorVariant, + }, }; +#[derive(Clone, Debug)] +pub enum CodeGenFunction { + Function(AirTree, Vec), + Link(String), +} + #[derive(Clone)] pub struct CodeGenerator<'a> { defined_functions: IndexMap, @@ -67,6 +84,9 @@ impl<'a> CodeGenerator<'a> { } pub fn generate_test(&mut self, test_body: &TypedExpr) -> Program { + let mut air_tree = self.build(test_body); + air_tree = AirTree::hoist_over(AirTree::no_op(), air_tree); + todo!() } @@ -236,11 +256,10 @@ impl<'a> CodeGenerator<'a> { let air_value = self.build(value); - builder::assignment_air_tree( + self.assignment_air_tree( pattern, air_value, tipo, - &self.data_types, AssignmentProperties { value_type: value.tipo(), kind: *kind, @@ -270,11 +289,10 @@ impl<'a> CodeGenerator<'a> { let subject_val = self.build(subject); - let assignment = builder::assignment_air_tree( + let assignment = self.assignment_air_tree( &last_clause.pattern, subject_val, tipo, - &self.data_types, AssignmentProperties { value_type: subject.tipo(), kind: AssignmentKind::Let, @@ -425,4 +443,513 @@ impl<'a> CodeGenerator<'a> { TypedExpr::UnOp { value, op, .. } => AirTree::unop(*op, self.build(value)), } } + + pub fn assignment_air_tree( + &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, + int(), + AirTree::int(expected_int), + AirTree::local_var(name, int()), + ); + AirTree::assert_bool(true, AirTree::hoist_over(assignment, expect)) + } else { + unreachable!("Code Gen should never reach here") + } + } + Pattern::Var { name, .. } => { + if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() { + let mut index_map = IndexMap::new(); + let tipo = builder::convert_opaque_type(); + let assignment = AirTree::let_assignment(name, value); + let val = AirTree::local_var(name, tipo.clone()); + + if tipo.is_primitive() { + AirTree::let_assignment(name, AirTree::hoist_over(assignment, val)) + } else { + let expect = self.expect_type( + &tipo, + val.clone(), + &mut index_map, + pattern.location(), + ); + let assign = + AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect)); + AirTree::let_assignment(name, AirTree::hoist_over(assign, val)) + } + } else { + AirTree::let_assignment(name, value) + } + } + Pattern::Assign { name, pattern, .. } => { + let inner_pattern = self.assignment_air_tree( + 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.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() { + let mut index_map = IndexMap::new(); + let tipo = builder::convert_opaque_type(); + let assignment = AirTree::let_assignment(name, value); + let val = AirTree::local_var(name, tipo.clone()); + if tipo.is_primitive() { + AirTree::let_assignment(name, AirTree::hoist_over(assignment, val)) + } else { + let expect = self.expect_type( + &tipo, + val.clone(), + &mut index_map, + pattern.location(), + ); + let assign = + AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect)); + AirTree::let_assignment(name, AirTree::hoist_over(assign, 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.kind.is_expect() + && props.value_type.is_data() + && !tipo.is_data() + { + 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_air_tree( + elem, + val, + list_elem_type, + AssignmentProperties { + value_type: props.value_type.clone(), + kind: props.kind, + remove_unused: true, + }, + ), + ) + }) + .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_air_tree( + tail, + val, + tipo, + AssignmentProperties { + value_type: props.value_type.clone(), + kind: props.kind, + remove_unused: true, + }, + ), + )); + }); + + let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec(); + + let mut sequence = vec![AirTree::list_access( + names, + tipo.clone(), + tail.is_some(), + tail.is_none(), + value, + )]; + + 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()); + + sequence.push(AirTree::assert_bool(name == "True", value)); + + AirTree::UnhoistedSequence(sequence) + } else if tipo.is_void() { + todo!() + } 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 + || (!tipo.is_data() && props.value_type.is_data()) + { + 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(); + + println!("tipo is {tipo:#?}"); + + 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.kind.is_expect() + && props.value_type.is_data() + && !tipo.is_data() + { + 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_air_tree( + &arg.value, + val, + arg_type, + AssignmentProperties { + value_type: props.value_type.clone(), + kind: props.kind, + remove_unused: true, + }, + ), + ) + }) + .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, false, 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.kind.is_expect() + && props.value_type.is_data() + && !tipo.is_data() + { + 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_air_tree( + arg, + val, + arg_type, + AssignmentProperties { + value_type: props.value_type.clone(), + kind: props.kind, + remove_unused: true, + }, + ), + ) + }) + .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(), false, value)); + + sequence.append(&mut elems.into_iter().map(|(_, field)| field).collect_vec()); + + AirTree::UnhoistedSequence(sequence) + } + } + } + + pub fn expect_type( + &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( + &inner_pair_types[0], + AirTree::local_var(fst_name, inner_pair_types[0].clone()), + defined_data_types, + location, + ); + + let expect_snd = self.expect_type( + &inner_pair_types[1], + AirTree::local_var(snd_name, inner_pair_types[1].clone()), + defined_data_types, + location, + ); + + let anon_func_body = AirTree::hoist_over( + AirTree::UnhoistedSequence(vec![ + tuple_access, + AirTree::let_assignment("_", expect_fst), + AirTree::let_assignment("_", expect_snd), + ]), + AirTree::void(), + ); + + let 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(expect_list_func, vec![]), + ); + } + + if let Some(counter) = defined_data_types.get_mut(EXPECT_ON_LIST) { + *counter += 1 + } else { + defined_data_types.insert(EXPECT_ON_LIST.to_string(), 1); + } + + let func_call = AirTree::call( + AirTree::local_var(EXPECT_ON_LIST, void()), + void(), + vec![AirTree::local_var(map_name, tipo.clone()), unwrap_function], + ); + + AirTree::hoist_over(assign, func_call) + } else { + todo!() + } + } } diff --git a/crates/aiken-lang/src/gen_uplc2/builder.rs b/crates/aiken-lang/src/gen_uplc2/builder.rs index 014fb840..3bedc89e 100644 --- a/crates/aiken-lang/src/gen_uplc2/builder.rs +++ b/crates/aiken-lang/src/gen_uplc2/builder.rs @@ -1,363 +1,11 @@ use std::sync::Arc; -use indexmap::IndexMap; -use itertools::Itertools; - use crate::{ - ast::{BinOp, Constant, DataType, Pattern}, - builtins::int, - gen_uplc::{ - builder::{self, AssignmentProperties, DataTypeKey}, - tree::AirTree, - }, + ast::{Constant, Pattern}, + gen_uplc::{builder::AssignmentProperties, tree::AirTree}, tipo::{PatternConstructor, Type}, }; -pub fn assignment_air_tree( - pattern: &Pattern>, - mut value: AirTree, - tipo: &Arc, - data_types: &IndexMap>>, - 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, - int(), - AirTree::int(expected_int), - AirTree::local_var(name, int()), - ); - AirTree::assert_bool(true, AirTree::hoist_over(assignment, expect)) - } else { - unreachable!("Code Gen should never reach here") - } - } - Pattern::Var { name, .. } => { - if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() { - let mut index_map = IndexMap::new(); - let tipo = convert_opaque_type(); - let assignment = AirTree::let_assignment(name, value); - let val = AirTree::local_var(name, tipo.clone()); - let expect = expect_type(&tipo, val.clone(), &mut index_map); - let assign = AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect)); - AirTree::let_assignment(name, AirTree::hoist_over(assign, val)) - } else { - AirTree::let_assignment(name, value) - } - } - Pattern::Assign { name, pattern, .. } => { - let inner_pattern = assignment_air_tree( - pattern, - AirTree::local_var(name, tipo.clone()), - tipo, - data_types, - props, - ); - let assign = AirTree::let_assignment(name, value); - - AirTree::UnhoistedSequence(vec![assign, inner_pattern]) - } - Pattern::Discard { name, .. } => { - if props.kind.is_expect() && props.value_type.is_data() && !tipo.is_data() { - let mut index_map = IndexMap::new(); - let tipo = convert_opaque_type(); - let assignment = AirTree::let_assignment(name, value); - let val = AirTree::local_var(name, tipo.clone()); - let expect = expect_type(&tipo, val.clone(), &mut index_map); - let assign = AirTree::let_assignment("_", AirTree::hoist_over(assignment, expect)); - AirTree::let_assignment(name, AirTree::hoist_over(assign, 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.kind.is_expect() - && props.value_type.is_data() - && !tipo.is_data() - { - 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, - assignment_air_tree( - elem, - val, - list_elem_type, - data_types, - AssignmentProperties { - value_type: props.value_type.clone(), - kind: props.kind, - remove_unused: true, - }, - ), - ) - }) - .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, - assignment_air_tree( - tail, - val, - tipo, - data_types, - AssignmentProperties { - value_type: props.value_type.clone(), - kind: props.kind, - remove_unused: true, - }, - ), - )); - }); - - let names = elems.iter().map(|(name, _)| name.to_string()).collect_vec(); - - let mut sequence = vec![AirTree::list_access( - names, - tipo.clone(), - tail.is_some(), - tail.is_none(), - value, - )]; - - 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()); - - sequence.push(AirTree::assert_bool(name == "True", value)); - - AirTree::UnhoistedSequence(sequence) - } else if tipo.is_void() { - todo!() - } else { - if props.kind.is_expect() { - let data_type = builder::lookup_data_type_by_tipo(data_types, tipo) - .unwrap_or_else(|| panic!("Failed to find definition for {}", name)); - - if data_type.constructors.len() > 1 - || (!tipo.is_data() && props.value_type.is_data()) - { - 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 moving `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(); - - println!("tipo is {tipo:#?}"); - - 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.kind.is_expect() - && props.value_type.is_data() - && !tipo.is_data() - { - 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(), - assignment_air_tree( - &arg.value, - val, - arg_type, - data_types, - AssignmentProperties { - value_type: props.value_type.clone(), - kind: props.kind, - remove_unused: true, - }, - ), - ) - }) - .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, false, value)); - - sequence.append( - &mut fields - .into_iter() - .map(|(_, _, _, field)| field) - .collect_vec(), - ); - - AirTree::UnhoistedSequence(sequence) - } - } - Pattern::Tuple { elems, .. } => { - todo!() - } - } -} - -pub fn expect_type( - tipo: &Arc, - value: AirTree, - defined_data_types: &mut IndexMap, -) -> AirTree { - todo!() -} - pub fn convert_opaque_type() -> Arc { todo!() } diff --git a/crates/aiken-lang/src/tipo.rs b/crates/aiken-lang/src/tipo.rs index 9306e044..da34b7d8 100644 --- a/crates/aiken-lang/src/tipo.rs +++ b/crates/aiken-lang/src/tipo.rs @@ -89,6 +89,15 @@ impl Type { } } + pub fn is_primitive(&self) -> bool { + self.is_bool() + || self.is_bytearray() + || self.is_int() + || self.is_string() + || self.is_void() + || self.is_data() + } + pub fn is_void(&self) -> bool { match self { Self::App { module, name, .. } if "Void" == name && module.is_empty() => true,