From 665a8dec675e123fc50b4117ee9a700e893c116a Mon Sep 17 00:00:00 2001 From: Kasey White Date: Sat, 25 Feb 2023 23:51:07 -0500 Subject: [PATCH] feat: add support for unconstr_data -Builitins IR now acts like Record IR in terms of argument consumption -UnConstrData returns as Pair(Data,Data) to conform with how pairs are treated behind the scenes. --- crates/aiken-lang/src/air.rs | 1 + crates/aiken-lang/src/builder.rs | 14 +- crates/aiken-lang/src/tipo/expr.rs | 4 +- crates/aiken-lang/src/uplc.rs | 393 ++++++++++++++++------ examples/acceptance_tests/036/plutus.json | 3 +- examples/acceptance_tests/047/plutus.json | 3 +- examples/acceptance_tests/048/plutus.json | 3 +- 7 files changed, 318 insertions(+), 103 deletions(-) diff --git a/crates/aiken-lang/src/air.rs b/crates/aiken-lang/src/air.rs index 1bd2add4..1c063406 100644 --- a/crates/aiken-lang/src/air.rs +++ b/crates/aiken-lang/src/air.rs @@ -78,6 +78,7 @@ pub enum Air { Builtin { scope: Vec, + count: usize, func: DefaultFunction, tipo: Arc, }, diff --git a/crates/aiken-lang/src/builder.rs b/crates/aiken-lang/src/builder.rs index 3d9c0a64..ade4817b 100644 --- a/crates/aiken-lang/src/builder.rs +++ b/crates/aiken-lang/src/builder.rs @@ -1485,12 +1485,22 @@ pub fn monomorphize( needs_variant = true; } } - Air::Builtin { scope, func, tipo } => { + Air::Builtin { + scope, + func, + tipo, + count, + } => { if tipo.is_generic() { let mut tipo = tipo.clone(); find_generics_to_replace(&mut tipo, &generic_types); - new_air[index] = Air::Builtin { scope, func, tipo }; + new_air[index] = Air::Builtin { + scope, + func, + tipo, + count, + }; needs_variant = true; } } diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 695ff653..0760f6ec 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -999,8 +999,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> { start: location.start, end: location.start + kind.location_offset(), }, - pattern_location: dbg!(untyped_pattern.location()), - value_location: dbg!(untyped_value.location()), + pattern_location: untyped_pattern.location(), + value_location: untyped_value.location(), sample: UntypedExpr::Assignment { location: Span::empty(), value: Box::new(untyped_value), diff --git a/crates/aiken-lang/src/uplc.rs b/crates/aiken-lang/src/uplc.rs index 269ca214..e5be0445 100644 --- a/crates/aiken-lang/src/uplc.rs +++ b/crates/aiken-lang/src/uplc.rs @@ -174,6 +174,7 @@ impl<'a> CodeGenerator<'a> { scope, func: *builtin, tipo: constructor.tipo.clone(), + count: 0, }); } _ => { @@ -233,44 +234,168 @@ impl<'a> CodeGenerator<'a> { TypedExpr::Call { fun, args, tipo, .. } => { - if let Some(data_type) = lookup_data_type_by_tipo(self.data_types.clone(), tipo) { - if let TypedExpr::Var { constructor, .. } = &**fun { - if let ValueConstructorVariant::Record { + match &**fun { + TypedExpr::Var { constructor, .. } => match &constructor.variant { + ValueConstructorVariant::Record { name: constr_name, .. - } = &constructor.variant - { - let (constr_index, _) = data_type - .constructors - .iter() - .enumerate() - .find(|(_, dt)| &dt.name == constr_name) - .unwrap(); + } => { + if let Some(data_type) = + lookup_data_type_by_tipo(self.data_types.clone(), tipo) + { + let (constr_index, _) = data_type + .constructors + .iter() + .enumerate() + .find(|(_, dt)| &dt.name == constr_name) + .unwrap(); - ir_stack.push(Air::Record { - scope: scope.clone(), - constr_index, - tipo: constructor.tipo.clone(), - count: args.len(), - }); + ir_stack.push(Air::Record { + scope: scope.clone(), + constr_index, + tipo: constructor.tipo.clone(), + count: args.len(), + }); - if let Some(fun_arg_types) = fun.tipo().arg_types() { - for (arg, func_type) in args.iter().zip(fun_arg_types) { - let mut scope = scope.clone(); - scope.push(self.id_gen.next()); + if let Some(fun_arg_types) = fun.tipo().arg_types() { + for (arg, func_type) in args.iter().zip(fun_arg_types) { + let mut scope = scope.clone(); + scope.push(self.id_gen.next()); - if func_type.is_data() && !arg.value.tipo().is_data() { - ir_stack.push(Air::WrapData { - scope: scope.clone(), - tipo: arg.value.tipo(), - }) + if func_type.is_data() && !arg.value.tipo().is_data() { + ir_stack.push(Air::WrapData { + scope: scope.clone(), + tipo: arg.value.tipo(), + }) + } + + self.build_ir(&arg.value, ir_stack, scope); } - - self.build_ir(&arg.value, ir_stack, scope); + } else { + unreachable!() } return; } } - } + ValueConstructorVariant::ModuleFn { builtin, .. } => { + if let Some(func) = builtin { + ir_stack.push(Air::Builtin { + scope: scope.clone(), + count: func.arity(), + func: func.clone(), + tipo: tipo.clone(), + }); + + if let Some(fun_arg_types) = fun.tipo().arg_types() { + for (arg, func_type) in args.iter().zip(fun_arg_types) { + let mut scope = scope.clone(); + scope.push(self.id_gen.next()); + + if func_type.is_data() && !arg.value.tipo().is_data() { + ir_stack.push(Air::WrapData { + scope: scope.clone(), + tipo: arg.value.tipo(), + }) + } + + self.build_ir(&arg.value, ir_stack, scope); + } + } else { + unreachable!() + } + return; + } + } + _ => {} + }, + TypedExpr::ModuleSelect { + constructor, + module_name, + .. + } => match constructor { + ModuleValueConstructor::Record { + name: constr_name, + tipo, + .. + } => { + if let Some(data_type) = + lookup_data_type_by_tipo(self.data_types.clone(), tipo) + { + let (constr_index, _) = data_type + .constructors + .iter() + .enumerate() + .find(|(_, dt)| &dt.name == constr_name) + .unwrap(); + + ir_stack.push(Air::Record { + scope: scope.clone(), + constr_index, + tipo: tipo.clone(), + count: args.len(), + }); + + if let Some(fun_arg_types) = fun.tipo().arg_types() { + for (arg, func_type) in args.iter().zip(fun_arg_types) { + let mut scope = scope.clone(); + scope.push(self.id_gen.next()); + + if func_type.is_data() && !arg.value.tipo().is_data() { + ir_stack.push(Air::WrapData { + scope: scope.clone(), + tipo: arg.value.tipo(), + }) + } + + self.build_ir(&arg.value, ir_stack, scope); + } + } else { + unreachable!() + } + return; + } + } + ModuleValueConstructor::Fn { name, .. } => { + let type_info = self.module_types.get(module_name).unwrap(); + let value = type_info.values.get(name).unwrap(); + + match &value.variant { + ValueConstructorVariant::ModuleFn { builtin, .. } => { + if let Some(func) = builtin { + ir_stack.push(Air::Builtin { + scope: scope.clone(), + count: func.arity(), + func: func.clone(), + tipo: tipo.clone(), + }); + + if let Some(fun_arg_types) = fun.tipo().arg_types() { + for (arg, func_type) in args.iter().zip(fun_arg_types) { + let mut scope = scope.clone(); + scope.push(self.id_gen.next()); + + if func_type.is_data() + && !arg.value.tipo().is_data() + { + ir_stack.push(Air::WrapData { + scope: scope.clone(), + tipo: arg.value.tipo(), + }) + } + + self.build_ir(&arg.value, ir_stack, scope); + } + } else { + unreachable!() + } + return; + } + } + _ => unreachable!(), + } + } + _ => {} + }, + _ => {} } ir_stack.push(Air::Call { @@ -575,13 +700,14 @@ impl<'a> CodeGenerator<'a> { let value = type_info.values.get(name).unwrap(); match &value.variant { ValueConstructorVariant::ModuleFn { builtin, .. } => { - let builtin = builtin.unwrap(); - - ir_stack.push(Air::Builtin { - func: builtin, - scope, - tipo: tipo.clone(), - }); + if let Some(builtin) = builtin { + ir_stack.push(Air::Builtin { + func: *builtin, + scope, + tipo: tipo.clone(), + count: 0, + }); + } } _ => unreachable!(), } @@ -2339,16 +2465,11 @@ impl<'a> CodeGenerator<'a> { let inner_list_type = &tipo.get_inner_types()[0]; let inner_pair_types = inner_list_type.get_inner_types(); - assert_vec.push(Air::Call { - scope: scope.clone(), - count: 2, - tipo: tipo.clone(), - }); - assert_vec.push(Air::Builtin { scope: scope.clone(), func: DefaultFunction::ChooseUnit, tipo: tipo.clone(), + count: DefaultFunction::ChooseUnit.arity(), }); assert_vec.push(Air::Call { @@ -2428,16 +2549,11 @@ impl<'a> CodeGenerator<'a> { let new_id = self.id_gen.next(); let inner_list_type = &tipo.get_inner_types()[0]; - assert_vec.push(Air::Call { - scope: scope.clone(), - count: 2, - tipo: tipo.clone(), - }); - assert_vec.push(Air::Builtin { scope: scope.clone(), func: DefaultFunction::ChooseUnit, tipo: tipo.clone(), + count: DefaultFunction::ChooseUnit.arity(), }); assert_vec.push(Air::Call { @@ -2549,16 +2665,11 @@ impl<'a> CodeGenerator<'a> { let data_type = lookup_data_type_by_tipo(self.data_types.clone(), &tipo).unwrap(); let new_id = self.id_gen.next(); - assert_vec.push(Air::Call { - scope: scope.clone(), - count: 2, - tipo: tipo.clone(), - }); - assert_vec.push(Air::Builtin { scope: scope.clone(), func: DefaultFunction::ChooseUnit, tipo: tipo.clone(), + count: DefaultFunction::ChooseUnit.arity(), }); assert_vec.push(Air::When { @@ -3409,13 +3520,19 @@ impl<'a> CodeGenerator<'a> { tail, }; } - Air::Builtin { tipo, scope, func } => { + Air::Builtin { + tipo, + scope, + func, + count, + } => { let mut replaced_type = tipo.clone(); replace_opaque_type(&mut replaced_type, self.data_types.clone()); ir_stack[index] = Air::Builtin { scope, func, + count, tipo: replaced_type, }; } @@ -4157,53 +4274,138 @@ impl<'a> CodeGenerator<'a> { } } } - Air::Builtin { func, tipo, .. } => match func { - DefaultFunction::FstPair | DefaultFunction::SndPair | DefaultFunction::HeadList => { - let id = self.id_gen.next(); - let mut term: Term = func.into(); - for _ in 0..func.force_count() { - term = term.force_wrap(); - } + Air::Builtin { + func, tipo, count, .. + } => { + let mut term: Term = Term::Builtin(func); + for _ in 0..func.force_count() { + term = term.force_wrap(); + } - term = apply_wrap( - term, - Term::Var( - Name { - text: format!("__arg_{id}"), - unique: 0.into(), - } - .into(), - ), - ); + let mut arg_vec = vec![]; + for _ in 0..count { + arg_vec.push(arg_stack.pop().unwrap()); + } - let inner_type = if matches!(func, DefaultFunction::SndPair) { - tipo.get_inner_types()[0].get_inner_types()[1].clone() - } else { - tipo.get_inner_types()[0].get_inner_types()[0].clone() - }; + for arg in arg_vec.iter() { + term = apply_wrap(term, arg.clone()); + } - term = convert_data_to_type(term, &inner_type); - term = Term::Lambda { - parameter_name: Name { - text: format!("__arg_{id}"), - unique: 0.into(), + match func { + DefaultFunction::FstPair + | DefaultFunction::SndPair + | DefaultFunction::HeadList => { + let temp_var = format!("__item_{}", self.id_gen.next()); + + if count == 0 { + term = apply_wrap( + term, + Term::Var( + Name { + text: temp_var.clone(), + unique: 0.into(), + } + .into(), + ), + ); } - .into(), - body: term.into(), - }; - arg_stack.push(term); - } - DefaultFunction::MkCons => todo!(), - DefaultFunction::MkPairData => todo!(), - _ => { - let mut term = Term::Builtin(func); - for _ in 0..func.force_count() { - term = term.force_wrap(); + term = convert_data_to_type(term, &tipo); + + if count == 0 { + term = Term::Lambda { + parameter_name: Name { + text: temp_var, + unique: 0.into(), + } + .into(), + body: term.into(), + }; + } } - arg_stack.push(term); + DefaultFunction::UnConstrData => { + let temp_tuple = format!("__unconstr_tuple_{}", self.id_gen.next()); + + let temp_var = format!("__item_{}", self.id_gen.next()); + + if count == 0 { + term = apply_wrap( + term, + Term::Var( + Name { + text: temp_var.clone(), + unique: 0.into(), + } + .into(), + ), + ); + } + + term = apply_wrap( + Term::Lambda { + parameter_name: Name { + text: temp_tuple.clone(), + unique: 0.into(), + } + .into(), + body: apply_wrap( + apply_wrap( + Term::Builtin(DefaultFunction::MkPairData), + apply_wrap( + Term::Builtin(DefaultFunction::IData), + apply_wrap( + Term::Builtin(DefaultFunction::FstPair) + .force_wrap() + .force_wrap(), + Term::Var( + Name { + text: temp_tuple.clone(), + unique: 0.into(), + } + .into(), + ), + ), + ), + ), + apply_wrap( + Term::Builtin(DefaultFunction::ListData), + apply_wrap( + Term::Builtin(DefaultFunction::SndPair) + .force_wrap() + .force_wrap(), + Term::Var( + Name { + text: temp_tuple, + unique: 0.into(), + } + .into(), + ), + ), + ), + ) + .into(), + }, + term, + ); + + if count == 0 { + term = Term::Lambda { + parameter_name: Name { + text: temp_var, + unique: 0.into(), + } + .into(), + body: term.into(), + }; + } + } + DefaultFunction::MkCons => { + unimplemented!("Use brackets instead."); + } + _ => {} } - }, + arg_stack.push(term); + } Air::BinOp { name, tipo, .. } => { let left = arg_stack.pop().unwrap(); let right = arg_stack.pop().unwrap(); @@ -4927,7 +5129,6 @@ impl<'a> CodeGenerator<'a> { arg_stack.push(term); } - Air::WrapClause { .. } => { let _ = arg_stack.pop().unwrap(); diff --git a/examples/acceptance_tests/036/plutus.json b/examples/acceptance_tests/036/plutus.json index cc40b784..49cd6e0b 100644 --- a/examples/acceptance_tests/036/plutus.json +++ b/examples/acceptance_tests/036/plutus.json @@ -1,7 +1,8 @@ { "preamble": { "title": "aiken-lang/acceptance_test_036", - "version": "0.0.0" + "version": "0.0.0", + "plutusVersion": "v2" }, "validators": [ { diff --git a/examples/acceptance_tests/047/plutus.json b/examples/acceptance_tests/047/plutus.json index 81fc4af5..53ecb938 100644 --- a/examples/acceptance_tests/047/plutus.json +++ b/examples/acceptance_tests/047/plutus.json @@ -1,7 +1,8 @@ { "preamble": { "title": "aiken-lang/acceptance_test_047", - "version": "0.0.0" + "version": "0.0.0", + "plutusVersion": "v2" }, "validators": [ { diff --git a/examples/acceptance_tests/048/plutus.json b/examples/acceptance_tests/048/plutus.json index 25d9bab1..c35490a4 100644 --- a/examples/acceptance_tests/048/plutus.json +++ b/examples/acceptance_tests/048/plutus.json @@ -1,7 +1,8 @@ { "preamble": { "title": "aiken-lang/acceptance_test_048", - "version": "0.0.0" + "version": "0.0.0", + "plutusVersion": "v2" }, "validators": [ {