diff --git a/crates/aiken-lang/src/air.rs b/crates/aiken-lang/src/air.rs index ef60e3d9..c80829c7 100644 --- a/crates/aiken-lang/src/air.rs +++ b/crates/aiken-lang/src/air.rs @@ -96,12 +96,6 @@ pub enum Air { }, // Assignment - Assert { - scope: Vec, - tipo: Arc, - value_is_data: bool, - }, - Let { scope: Vec, name: String, @@ -112,14 +106,6 @@ pub enum Air { tipo: Arc, }, - ListAssert { - scope: Vec, - tipo: Arc, - names: Vec, - tail: bool, - value_is_data: bool, - }, - // When When { scope: Vec, @@ -275,8 +261,6 @@ impl Air { | Air::Builtin { scope, .. } | Air::BinOp { scope, .. } | Air::UnOp { scope, .. } - | Air::Assert { scope, .. } - | Air::ListAssert { scope, .. } | Air::Let { scope, .. } | Air::UnWrapData { scope, .. } | Air::When { scope, .. } @@ -356,8 +340,6 @@ impl Air { | Air::Call { tipo, .. } | Air::Builtin { tipo, .. } | Air::BinOp { tipo, .. } - | Air::Assert { tipo, .. } - | Air::ListAssert { tipo, .. } | Air::UnWrapData { tipo, .. } | Air::When { tipo, .. } | Air::Clause { tipo, .. } diff --git a/crates/aiken-lang/src/builder.rs b/crates/aiken-lang/src/builder.rs index 6f02152d..d50e7f08 100644 --- a/crates/aiken-lang/src/builder.rs +++ b/crates/aiken-lang/src/builder.rs @@ -4,7 +4,7 @@ use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; use uplc::{ ast::{ - builder::{apply_wrap, choose_list, delayed_choose_list, if_else}, + builder::{apply_wrap, delayed_choose_list, if_else}, Constant as UplcConstant, Name, Term, Type as UplcType, }, builtins::DefaultFunction, @@ -484,83 +484,50 @@ pub fn list_access_to_uplc( tipos: Vec>, check_last_item: bool, ) -> Term { - let (first, names) = names.split_first().unwrap(); - let (current_tipo, tipos) = tipos.split_first().unwrap(); + if let Some((first, names)) = names.split_first() { + let (current_tipo, tipos) = tipos.split_first().unwrap(); - let head_list = if current_tipo.is_map() { - apply_wrap( - Term::Builtin(DefaultFunction::HeadList).force_wrap(), - Term::Var(Name { - text: format!("tail_index_{}_{}", current_index, id_list[current_index]), - unique: 0.into(), - }), - ) - } else { - convert_data_to_type( + let head_list = if current_tipo.is_map() { apply_wrap( Term::Builtin(DefaultFunction::HeadList).force_wrap(), Term::Var(Name { text: format!("tail_index_{}_{}", current_index, id_list[current_index]), unique: 0.into(), }), - ), - ¤t_tipo.to_owned(), - ) - }; - - if names.len() == 1 && tail { - Term::Lambda { - parameter_name: Name { - text: format!("tail_index_{}_{}", current_index, id_list[current_index]), - unique: 0.into(), - }, - body: apply_wrap( - Term::Lambda { - parameter_name: Name { - text: first.clone(), - unique: 0.into(), - }, - body: apply_wrap( - Term::Lambda { - parameter_name: Name { - text: names[0].clone(), - unique: 0.into(), - }, - body: term.into(), - }, - apply_wrap( - Term::Builtin(DefaultFunction::TailList).force_wrap(), - Term::Var(Name { - text: format!( - "tail_index_{}_{}", - current_index, id_list[current_index] - ), - unique: 0.into(), - }), - ), - ) - .into(), - }, - head_list, ) - .into(), - } - } else if names.is_empty() { - // Maybe check list is actually empty or should we leave that to when .. is only - // this would replace term.into() if we decide to - Term::Lambda { - parameter_name: Name { - text: format!("tail_index_{}_{}", current_index, id_list[current_index]), - unique: 0.into(), - }, - body: apply_wrap( - Term::Lambda { - parameter_name: Name { - text: first.clone(), + } else { + convert_data_to_type( + apply_wrap( + Term::Builtin(DefaultFunction::HeadList).force_wrap(), + Term::Var(Name { + text: format!("tail_index_{}_{}", current_index, id_list[current_index]), unique: 0.into(), - }, - body: if check_last_item { - delayed_choose_list( + }), + ), + ¤t_tipo.to_owned(), + ) + }; + + if names.len() == 1 && tail { + Term::Lambda { + parameter_name: Name { + text: format!("tail_index_{}_{}", current_index, id_list[current_index]), + unique: 0.into(), + }, + body: apply_wrap( + Term::Lambda { + parameter_name: Name { + text: first.clone(), + unique: 0.into(), + }, + body: apply_wrap( + Term::Lambda { + parameter_name: Name { + text: names[0].clone(), + unique: 0.into(), + }, + body: term.into(), + }, apply_wrap( Term::Builtin(DefaultFunction::TailList).force_wrap(), Term::Var(Name { @@ -571,66 +538,101 @@ pub fn list_access_to_uplc( unique: 0.into(), }), ), - term, - apply_wrap( - apply_wrap( - Term::Builtin(DefaultFunction::Trace).force_wrap(), - Term::Constant(UplcConstant::String( - "List/Tuple contains more items than it should".to_string(), - )), - ), - Term::Delay(Term::Error.into()), - ) - .force_wrap(), ) - .into() - } else { - term.into() + .into(), }, + head_list, + ) + .into(), + } + } else if names.is_empty() { + Term::Lambda { + parameter_name: Name { + text: format!("tail_index_{}_{}", current_index, id_list[current_index]), + unique: 0.into(), }, - head_list, - ) - .into(), + body: apply_wrap( + Term::Lambda { + parameter_name: Name { + text: first.clone(), + unique: 0.into(), + }, + body: if check_last_item { + delayed_choose_list( + apply_wrap( + Term::Builtin(DefaultFunction::TailList).force_wrap(), + Term::Var(Name { + text: format!( + "tail_index_{}_{}", + current_index, id_list[current_index] + ), + unique: 0.into(), + }), + ), + term, + apply_wrap( + apply_wrap( + Term::Builtin(DefaultFunction::Trace).force_wrap(), + Term::Constant(UplcConstant::String( + "List/Tuple contains more items than it should" + .to_string(), + )), + ), + Term::Delay(Term::Error.into()), + ) + .force_wrap(), + ) + .into() + } else { + term.into() + }, + }, + head_list, + ) + .into(), + } + } else { + Term::Lambda { + parameter_name: Name { + text: format!("tail_index_{}_{}", current_index, id_list[current_index]), + unique: 0.into(), + }, + body: apply_wrap( + Term::Lambda { + parameter_name: Name { + text: first.clone(), + unique: 0.into(), + }, + body: apply_wrap( + list_access_to_uplc( + names, + id_list, + tail, + current_index + 1, + term, + tipos.to_owned(), + check_last_item, + ), + apply_wrap( + Term::Builtin(DefaultFunction::TailList).force_wrap(), + Term::Var(Name { + text: format!( + "tail_index_{}_{}", + current_index, id_list[current_index] + ), + unique: 0.into(), + }), + ), + ) + .into(), + }, + head_list, + ) + .into(), + } } } else { - Term::Lambda { - parameter_name: Name { - text: format!("tail_index_{}_{}", current_index, id_list[current_index]), - unique: 0.into(), - }, - body: apply_wrap( - Term::Lambda { - parameter_name: Name { - text: first.clone(), - unique: 0.into(), - }, - body: apply_wrap( - list_access_to_uplc( - names, - id_list, - tail, - current_index + 1, - term, - tipos.to_owned(), - check_last_item, - ), - apply_wrap( - Term::Builtin(DefaultFunction::TailList).force_wrap(), - Term::Var(Name { - text: format!( - "tail_index_{}_{}", - current_index, id_list[current_index] - ), - unique: 0.into(), - }), - ), - ) - .into(), - }, - head_list, - ) - .into(), - } + term } } diff --git a/crates/aiken-lang/src/tipo.rs b/crates/aiken-lang/src/tipo.rs index 541a4db4..fa8f31e3 100644 --- a/crates/aiken-lang/src/tipo.rs +++ b/crates/aiken-lang/src/tipo.rs @@ -213,6 +213,7 @@ impl Type { match self { Self::Fn { args, .. } => Some(args.clone()), Self::App { args, .. } => Some(args.clone()), + Self::Var { tipo } => tipo.borrow().arg_types(), _ => None, } } @@ -498,6 +499,13 @@ impl TypeVar { } } + pub fn arg_types(&self) -> Option>> { + match self { + Self::Link { tipo } => tipo.arg_types(), + _ => None, + } + } + pub fn get_inner_type(&self) -> Vec> { match self { Self::Link { tipo } => tipo.get_inner_types(), diff --git a/crates/aiken-lang/src/uplc.rs b/crates/aiken-lang/src/uplc.rs index 89d37b71..343dc3a7 100644 --- a/crates/aiken-lang/src/uplc.rs +++ b/crates/aiken-lang/src/uplc.rs @@ -1,4 +1,4 @@ -use std::{clone, sync::Arc, vec}; +use std::sync::Arc; use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; @@ -19,7 +19,7 @@ use uplc::{ use crate::{ air::Air, ast::{ - ArgName, AssignmentKind, BinOp, CallArg, Clause, Pattern, Span, TypedArg, TypedDataType, + ArgName, AssignmentKind, BinOp, Clause, Pattern, Span, TypedArg, TypedDataType, TypedFunction, UnOp, }, builder::{ @@ -32,8 +32,8 @@ use crate::{ }, expr::TypedExpr, tipo::{ - fields::FieldMap, ModuleValueConstructor, PatternConstructor, Type, TypeInfo, TypeVar, - ValueConstructor, ValueConstructorVariant, + ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor, + ValueConstructorVariant, }, IdGenerator, }; @@ -80,13 +80,10 @@ impl<'a> CodeGenerator<'a> { let scope = vec![self.id_gen.next()]; self.build_ir(&body, &mut ir_stack, scope); - println!("{:#?}", ir_stack); self.define_ir(&mut ir_stack); - println!("{:#?}", ir_stack); self.convert_opaque_type_to_inner_ir(&mut ir_stack); - println!("{:#?}", ir_stack); let mut term = self.uplc_code_gen(&mut ir_stack); @@ -115,7 +112,6 @@ impl<'a> CodeGenerator<'a> { version: (1, 0, 0), term, }; - println!("{}", program.to_pretty()); let mut interner = Interner::new(); @@ -324,104 +320,124 @@ impl<'a> CodeGenerator<'a> { // assuming one subject at the moment let subject = subjects[0].clone(); - if clauses.len() <= 1 { - todo!("Single clause cases not implemented") - } + let mut value_vec: Vec = vec![]; + let mut pattern_vec: Vec = vec![]; + let mut subject_vec: Vec = vec![]; - let clauses = if matches!(clauses[0].pattern[0], Pattern::List { .. }) { - rearrange_clauses(clauses.clone()) - } else { - clauses.clone() - }; + self.build_ir(&clauses[0].then, &mut value_vec, scope.clone()); - if let Some((last_clause, clauses)) = clauses.split_last() { - let mut pattern_vec = vec![]; + self.build_ir(&subject, &mut value_vec, scope.clone()); - let mut clause_properties = ClauseProperties::init( - &subject.tipo(), - constr_var.clone(), - subject_name.clone(), - ); - - self.handle_each_clause( + self.assignment_ir( + &clauses[0].pattern[0], &mut pattern_vec, - &mut clause_properties, - clauses, + &mut subject_vec, &subject.tipo(), - scope.clone(), + AssignmentProperties { + value_is_data: false, + kind: AssignmentKind::Let, + }, + scope, ); - let last_pattern = &last_clause.pattern[0]; - - let mut final_scope = scope.clone(); - - final_scope.push(self.id_gen.next()); - - pattern_vec.push(Air::Finally { - scope: final_scope.clone(), - }); - - let mut final_clause_vec = vec![]; - - self.build_ir( - &last_clause.then, - &mut final_clause_vec, - final_scope.clone(), - ); - - self.when_ir( - last_pattern, - &mut pattern_vec, - &mut final_clause_vec, - &subject.tipo(), - &mut clause_properties, - final_scope, - ); - - if *clause_properties.needs_constr_var() { - ir_stack.push(Air::Let { - scope: scope.clone(), - name: constr_var.clone(), - }); - - self.build_ir(&subject, ir_stack, scope.clone()); - - ir_stack.push(Air::When { - scope: scope.clone(), - subject_name, - tipo: subject.tipo(), - }); - - let mut scope = scope; - scope.push(self.id_gen.next()); - - ir_stack.push(Air::Var { - scope, - constructor: ValueConstructor::public( - subject.tipo(), - ValueConstructorVariant::LocalVariable { - location: Span::empty(), - }, - ), - name: constr_var, - variant_name: String::new(), - }) - } else { - ir_stack.push(Air::When { - scope: scope.clone(), - subject_name, - tipo: subject.tipo(), - }); - - let mut scope = scope; - scope.push(self.id_gen.next()); - - self.build_ir(&subject, ir_stack, scope); - } - ir_stack.append(&mut pattern_vec); - }; + ir_stack.append(&mut value_vec); + } else { + let clauses = if matches!(clauses[0].pattern[0], Pattern::List { .. }) { + rearrange_clauses(clauses.clone()) + } else { + clauses.clone() + }; + + if let Some((last_clause, clauses)) = clauses.split_last() { + let mut pattern_vec = vec![]; + + let mut clause_properties = ClauseProperties::init( + &subject.tipo(), + constr_var.clone(), + subject_name.clone(), + ); + + self.handle_each_clause( + &mut pattern_vec, + &mut clause_properties, + clauses, + &subject.tipo(), + scope.clone(), + ); + + let last_pattern = &last_clause.pattern[0]; + + let mut final_scope = scope.clone(); + + final_scope.push(self.id_gen.next()); + + pattern_vec.push(Air::Finally { + scope: final_scope.clone(), + }); + + let mut final_clause_vec = vec![]; + + self.build_ir( + &last_clause.then, + &mut final_clause_vec, + final_scope.clone(), + ); + + self.when_ir( + last_pattern, + &mut pattern_vec, + &mut final_clause_vec, + &subject.tipo(), + &mut clause_properties, + final_scope, + ); + + if *clause_properties.needs_constr_var() { + ir_stack.push(Air::Let { + scope: scope.clone(), + name: constr_var.clone(), + }); + + self.build_ir(&subject, ir_stack, scope.clone()); + + ir_stack.push(Air::When { + scope: scope.clone(), + subject_name, + tipo: subject.tipo(), + }); + + let mut scope = scope; + scope.push(self.id_gen.next()); + + ir_stack.push(Air::Var { + scope, + constructor: ValueConstructor::public( + subject.tipo(), + ValueConstructorVariant::LocalVariable { + location: Span::empty(), + }, + ), + name: constr_var, + variant_name: String::new(), + }) + } else { + ir_stack.push(Air::When { + scope: scope.clone(), + subject_name, + tipo: subject.tipo(), + }); + + let mut scope = scope; + scope.push(self.id_gen.next()); + + self.build_ir(&subject, ir_stack, scope); + } + + ir_stack.append(&mut pattern_vec); + } + } } TypedExpr::If { branches, @@ -479,7 +495,9 @@ impl<'a> CodeGenerator<'a> { tipo, .. } => match constructor { - ModuleValueConstructor::Record { .. } => todo!(), + ModuleValueConstructor::Record { .. } => { + todo!("Records from modules not yet implemented.") + } ModuleValueConstructor::Fn { name, module, .. } => { let func = self.functions.get(&FunctionAccessKey { module_name: module_name.clone(), @@ -798,7 +816,7 @@ impl<'a> CodeGenerator<'a> { pattern_vec.append(values); } - Pattern::String { .. } => todo!(), + Pattern::String { .. } => todo!("String matching in whens not yet implemented"), Pattern::Var { name, .. } => { pattern_vec.push(Air::Void { scope: scope.clone(), @@ -821,7 +839,7 @@ impl<'a> CodeGenerator<'a> { }); pattern_vec.append(values); } - Pattern::VarUsage { .. } => todo!(), + Pattern::VarUsage { .. } => unreachable!(), Pattern::Assign { name, pattern, .. } => { let mut new_vec = vec![]; new_vec.push(Air::Let { @@ -988,11 +1006,11 @@ impl<'a> CodeGenerator<'a> { scope: Vec, ) { match pattern { - Pattern::Int { .. } => todo!(), - Pattern::String { .. } => todo!(), - Pattern::Var { .. } => todo!(), - Pattern::VarUsage { .. } => todo!(), - Pattern::Assign { .. } => todo!(), + Pattern::Int { .. } => unreachable!(), + Pattern::String { .. } => unreachable!(), + Pattern::Var { .. } => unreachable!(), + Pattern::VarUsage { .. } => unreachable!(), + Pattern::Assign { .. } => todo!("Nested assign not yet implemented"), Pattern::Discard { .. } => { pattern_vec.push(Air::Void { scope }); @@ -1022,7 +1040,7 @@ impl<'a> CodeGenerator<'a> { tail_name = name.clone(); } Pattern::Discard { .. } => {} - _ => todo!(), + _ => unreachable!("Patterns in tail of list should not allow this"), } } @@ -1458,7 +1476,10 @@ impl<'a> CodeGenerator<'a> { Some(item_name) } - _ => todo!(), + Pattern::Assign { .. } => todo!("Nested assign is not yet done"), + Pattern::Int { .. } => unimplemented!(), + Pattern::String { .. } => unimplemented!(), + Pattern::VarUsage { .. } => unreachable!(), } } @@ -1506,8 +1527,8 @@ impl<'a> CodeGenerator<'a> { pattern_vec.append(&mut assert_vec); } } - Pattern::VarUsage { .. } => todo!(), - Pattern::Assign { .. } => todo!(), + Pattern::VarUsage { .. } => unreachable!(), + Pattern::Assign { .. } => todo!("Assign not yet implemented yet"), Pattern::Discard { .. } => { pattern_vec.push(Air::Let { name: "_".to_string(), @@ -1616,7 +1637,9 @@ impl<'a> CodeGenerator<'a> { Pattern::Var { name, .. } => { names.push(name.clone()); } - a @ Pattern::List { .. } => { + a @ (Pattern::List { .. } + | Pattern::Constructor { .. } + | Pattern::Tuple { .. }) => { let mut var_vec = vec![]; let item_name = format!("list_item_id_{}", self.id_gen.next()); names.push(item_name.clone()); @@ -1646,7 +1669,13 @@ impl<'a> CodeGenerator<'a> { scope.clone(), ); } - _ => todo!(), + Pattern::Int { .. } => todo!(), + Pattern::String { .. } => todo!(), + Pattern::VarUsage { .. } => todo!(), + Pattern::Assign { .. } => todo!(), + Pattern::Discard { .. } => { + names.push("_".to_string()); + } } } @@ -1700,9 +1729,9 @@ impl<'a> CodeGenerator<'a> { &item.value, *field_index, &mut nested_pattern, + type_map.get(field_index).unwrap(), &assignment_properties, &scope, - false, ) }) .sorted_by(|item1, item2| item1.1.cmp(&item2.1)) @@ -1726,59 +1755,45 @@ impl<'a> CodeGenerator<'a> { pattern_vec.append(&mut nested_pattern); } Pattern::Tuple { elems, .. } => { - let mut elements_vec = vec![]; + let mut nested_pattern = vec![]; + let mut type_map: IndexMap> = IndexMap::new(); - let mut names = vec![]; - for element in elems { - match element { - Pattern::Var { name, .. } => { - names.push(name.clone()); - } - Pattern::Discard { .. } => { - names.push("_".to_string()); - } - a @ Pattern::List { .. } => { - let mut var_vec = vec![]; - let item_name = format!("list_item_id_{}", self.id_gen.next()); - names.push(item_name.clone()); - var_vec.push(Air::Var { - constructor: ValueConstructor::public( - Type::App { - public: true, - module: String::new(), - name: String::new(), - args: vec![], - } - .into(), - ValueConstructorVariant::LocalVariable { - location: Span::empty(), - }, - ), - name: item_name, - scope: scope.clone(), - variant_name: String::new(), - }); - self.pattern_ir( - a, - &mut elements_vec, - &mut var_vec, - &tipo.get_inner_types()[0], - assignment_properties.clone(), - scope.clone(), - ); - } - _ => todo!(), - } + 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 + .iter() + .enumerate() + .filter_map(|(tuple_index, item)| { + self.extract_arg_and_index( + item, + tuple_index, + &mut nested_pattern, + type_map.get(&tuple_index).unwrap(), + &assignment_properties, + &scope, + ) + }) + .sorted_by(|item1, item2| item1.1.cmp(&item2.1)) + .collect::>(); + + if !arguments_index.is_empty() { + pattern_vec.push(Air::TupleAccessor { + scope, + names: arguments_index + .into_iter() + .map(|(item, _)| item) + .collect_vec(), + tipo: tipo.clone().into(), + check_last_item: true, + }); } - pattern_vec.push(Air::TupleAccessor { - names, - scope, - tipo: tipo.clone().into(), - check_last_item: false, - }); pattern_vec.append(values); - pattern_vec.append(&mut elements_vec); + + pattern_vec.append(&mut nested_pattern); } } } @@ -1819,7 +1834,9 @@ impl<'a> CodeGenerator<'a> { } Pattern::VarUsage { .. } => todo!(), Pattern::Assign { .. } => todo!(), - l @ Pattern::List { .. } => { + l @ (Pattern::List { .. } + | Pattern::Constructor { .. } + | Pattern::Tuple { .. }) => { let name = format!("list_item_id_{}", self.id_gen.next()); names.push(name.clone()); @@ -1842,8 +1859,6 @@ impl<'a> CodeGenerator<'a> { scope.clone(), ); } - Pattern::Constructor { .. } => todo!(), - Pattern::Tuple { elems, .. } => todo!(), _ => {} } } @@ -1899,8 +1914,6 @@ impl<'a> CodeGenerator<'a> { type_map.insert(index, field_type); } - println!("TYPE IS {:#?}", type_map); - let arguments_index = arguments .iter() .filter_map(|item| { @@ -1910,9 +1923,9 @@ impl<'a> CodeGenerator<'a> { &item.value, *field_index, &mut nested_pattern, + type_map.get(field_index).unwrap(), &assignment_properties, &scope, - true, ) }) .sorted_by(|item1, item2| item1.1.cmp(&item2.1)) @@ -1974,9 +1987,9 @@ impl<'a> CodeGenerator<'a> { item, field_index, &mut nested_pattern, + type_map.get(&field_index).unwrap(), &assignment_properties, &scope, - true, ) }) .sorted_by(|item1, item2| item1.1.cmp(&item2.1)) @@ -2003,7 +2016,7 @@ impl<'a> CodeGenerator<'a> { } } - if !arguments_index.is_empty() { + if !final_args.is_empty() { pattern_vec.push(Air::TupleAccessor { scope, names: final_args.into_iter().map(|(item, _)| item).collect_vec(), @@ -2336,7 +2349,7 @@ impl<'a> CodeGenerator<'a> { assert_vec.push(Air::ErrorTerm { scope, tipo: tipo.clone().into(), - label: None, + label: Some("Constr index did not match any type variant".to_string()), }); } } @@ -2346,15 +2359,63 @@ impl<'a> CodeGenerator<'a> { item: &Pattern>, field_index: usize, nested_pattern: &mut Vec, + tipo: &Type, assignment_properties: &AssignmentProperties, scope: &[u64], - assert: bool, ) -> Option<(String, usize)> { { let (discard, var_name) = match item { Pattern::Var { name, .. } => (false, name.clone()), Pattern::Discard { .. } => (true, "".to_string()), - Pattern::List { .. } => todo!(), + a @ Pattern::List { .. } => { + let id = self.id_gen.next(); + let list_name = format!("__list_{id}"); + + if matches!(assignment_properties.kind, AssignmentKind::Assert) + && assignment_properties.value_is_data + && !tipo.is_data() + { + self.recursive_assert_pattern( + a, + nested_pattern, + &mut vec![Air::Var { + scope: scope.to_owned(), + constructor: ValueConstructor::public( + tipo.clone().into(), + ValueConstructorVariant::LocalVariable { + location: Span::empty(), + }, + ), + name: list_name.clone(), + variant_name: String::new(), + }], + tipo, + assignment_properties.clone(), + scope.to_owned(), + ); + } else { + self.pattern_ir( + a, + nested_pattern, + &mut vec![Air::Var { + scope: scope.to_owned(), + constructor: ValueConstructor::public( + tipo.clone().into(), + ValueConstructorVariant::LocalVariable { + location: Span::empty(), + }, + ), + name: list_name.clone(), + variant_name: String::new(), + }], + tipo, + assignment_properties.clone(), + scope.to_owned(), + ); + } + + (false, list_name) + } a @ Pattern::Constructor { tipo, name: constr_name, @@ -2363,7 +2424,10 @@ impl<'a> CodeGenerator<'a> { let id = self.id_gen.next(); let constr_name = format!("{constr_name}_{id}"); - if assert { + if matches!(assignment_properties.kind, AssignmentKind::Assert) + && assignment_properties.value_is_data + && !tipo.is_data() + { self.recursive_assert_pattern( a, nested_pattern, @@ -2405,7 +2469,59 @@ impl<'a> CodeGenerator<'a> { (false, constr_name) } - _ => todo!(), + a @ Pattern::Tuple { .. } => { + let id = self.id_gen.next(); + let tuple_name = format!("__tuple_name_{id}"); + + if matches!(assignment_properties.kind, AssignmentKind::Assert) + && assignment_properties.value_is_data + && !tipo.is_data() + { + self.recursive_assert_pattern( + a, + nested_pattern, + &mut vec![Air::Var { + scope: scope.to_owned(), + constructor: ValueConstructor::public( + tipo.clone().into(), + ValueConstructorVariant::LocalVariable { + location: Span::empty(), + }, + ), + name: tuple_name.clone(), + variant_name: String::new(), + }], + tipo, + assignment_properties.clone(), + scope.to_owned(), + ); + } else { + self.pattern_ir( + a, + nested_pattern, + &mut vec![Air::Var { + scope: scope.to_owned(), + constructor: ValueConstructor::public( + tipo.clone().into(), + ValueConstructorVariant::LocalVariable { + location: Span::empty(), + }, + ), + name: tuple_name.clone(), + variant_name: String::new(), + }], + tipo, + assignment_properties.clone(), + scope.to_owned(), + ); + } + + (false, tuple_name) + } + Pattern::Int { .. } => todo!(), + Pattern::String { .. } => todo!(), + Pattern::VarUsage { .. } => todo!(), + Pattern::Assign { .. } => todo!(), }; if discard { @@ -3367,10 +3483,7 @@ impl<'a> CodeGenerator<'a> { })); } ValueConstructorVariant::Record { - name: constr_name, - field_map, - arity, - .. + name: constr_name, .. } => { if constructor.tipo.is_bool() { arg_stack @@ -3391,59 +3504,10 @@ impl<'a> CodeGenerator<'a> { .find(|(_, x)| x.name == *constr_name) .unwrap(); - let mut fields = + let fields = Term::Constant(UplcConstant::ProtoList(UplcType::Data, vec![])); - let tipo = constructor.tipo; - - let args_type = tipo.arg_types().unwrap(); - - if let Some(field_map) = field_map.clone() { - for field in field_map - .fields - .iter() - .sorted_by(|item1, item2| { - let (a, _) = item1.1; - let (b, _) = item2.1; - a.cmp(b) - }) - .zip(&args_type) - .rev() - { - // TODO revisit - fields = apply_wrap( - apply_wrap( - Term::Builtin(DefaultFunction::MkCons).force_wrap(), - convert_type_to_data( - Term::Var(Name { - text: field.0 .0.clone(), - unique: 0.into(), - }), - field.1, - ), - ), - fields, - ); - } - } else { - for (index, arg) in args_type.iter().enumerate().take(*arity) { - fields = apply_wrap( - apply_wrap( - Term::Builtin(DefaultFunction::MkCons).force_wrap(), - convert_type_to_data( - Term::Var(Name { - text: format!("__arg_{}", index), - unique: 0.into(), - }), - arg, - ), - ), - fields, - ); - } - } - - let mut term = apply_wrap( + let term = apply_wrap( apply_wrap( Term::Builtin(DefaultFunction::ConstrData), Term::Constant(UplcConstant::Integer( @@ -3453,37 +3517,6 @@ impl<'a> CodeGenerator<'a> { fields, ); - if let Some(field_map) = field_map { - for field in field_map - .fields - .iter() - .sorted_by(|item1, item2| { - let (a, _) = item1.1; - let (b, _) = item2.1; - a.cmp(b) - }) - .rev() - { - term = Term::Lambda { - parameter_name: Name { - text: field.0.clone(), - unique: 0.into(), - }, - body: term.into(), - }; - } - } else { - for (index, _) in args_type.iter().enumerate().take(*arity) { - term = Term::Lambda { - parameter_name: Name { - text: format!("__arg_{}", index), - unique: 0.into(), - }, - body: term.into(), - }; - } - } - arg_stack.push(term); } } @@ -4094,46 +4127,6 @@ impl<'a> CodeGenerator<'a> { }; arg_stack.push(term); } - Air::Assert { - tipo, - value_is_data, - .. - } => { - let constr = arg_stack.pop().unwrap(); - - let mut term = arg_stack.pop().unwrap(); - - let trace_error = apply_wrap( - apply_wrap( - Term::Builtin(DefaultFunction::Trace).force_wrap(), - Term::Constant(UplcConstant::String("Assert Failed".to_string())), - ), - Term::Delay(Term::Error.into()), - ) - .force_wrap(); - todo!(); - - // let condition = apply_wrap( - // apply_wrap( - // DefaultFunction::EqualsInteger.into(), - // Term::Constant(UplcConstant::Integer(constr_index as i128)), - // ), - // constr_index_exposer(constr), - // ); - - // term = delayed_if_else(condition, term, trace_error); - - arg_stack.push(term); - } - Air::ListAssert { - scope, - tipo, - names, - tail, - value_is_data, - } => { - todo!(); - } Air::DefineFunc { func_name, params, @@ -4735,6 +4728,29 @@ impl<'a> CodeGenerator<'a> { let names = indices.iter().cloned().map(|item| item.1).collect_vec(); let inner_types = indices.iter().cloned().map(|item| item.2).collect_vec(); + let tail_list = if !indices.is_empty() { + apply_wrap( + list_access_to_uplc( + &names, + &id_list, + false, + current_index, + term, + inner_types, + check_last_item, + ), + apply_wrap( + Term::Builtin(DefaultFunction::TailList).force_wrap(), + Term::Var(Name { + text: format!("__constr_fields_{}", list_id), + unique: 0.into(), + }), + ), + ) + } else { + term + }; + term = apply_wrap( Term::Lambda { parameter_name: Name { @@ -4747,25 +4763,7 @@ impl<'a> CodeGenerator<'a> { text: first_name.1.clone(), unique: 0.into(), }, - body: apply_wrap( - list_access_to_uplc( - &names, - &id_list, - false, - current_index, - term, - inner_types, - check_last_item, - ), - apply_wrap( - Term::Builtin(DefaultFunction::TailList).force_wrap(), - Term::Var(Name { - text: format!("__constr_fields_{}", list_id), - unique: 0.into(), - }), - ), - ) - .into(), + body: tail_list.into(), }, head_list, ) diff --git a/crates/uplc/src/machine.rs b/crates/uplc/src/machine.rs index 196fdb25..89262cbe 100644 --- a/crates/uplc/src/machine.rs +++ b/crates/uplc/src/machine.rs @@ -343,7 +343,7 @@ impl Machine { Err(Error::UnexpectedBuiltinTermArgument(t.as_ref().clone())) } } - rest => Err(Error::NonFunctionalApplication(rest)), + rest => Err(Error::NonFunctionalApplication(rest, argument)), } } diff --git a/crates/uplc/src/machine/error.rs b/crates/uplc/src/machine/error.rs index 7132db2c..5749a38f 100644 --- a/crates/uplc/src/machine/error.rs +++ b/crates/uplc/src/machine/error.rs @@ -16,8 +16,8 @@ pub enum Error { EvaluationFailure, #[error("Attempted to instantiate a non-polymorphic term:\n\n{0:#?}")] NonPolymorphicInstantiation(Value), - #[error("Attempted to apply a non-function:\n\n{0:#?}")] - NonFunctionalApplication(Value), + #[error("Attempted to apply a non-function:\n\n{0:#?} to argument:\n\n{1:#?}")] + NonFunctionalApplication(Value, Value), #[error("Type mismatch expected '{0}' got '{1}'")] TypeMismatch(Type, Type), #[error("Type mismatch expected '(list a)' got '{0}'")]