From 044d609a24603cd4cc1069fc7135ef7c1f470891 Mon Sep 17 00:00:00 2001 From: Kasey White Date: Thu, 1 Dec 2022 00:46:48 -0500 Subject: [PATCH] feat: nested constr access and module funcs now work --- crates/lang/src/uplc_two.rs | 224 ++++++++++++++++++++++++----- examples/sample/lib/sample.ak | 14 +- examples/sample/validators/swap.ak | 32 ++++- 3 files changed, 229 insertions(+), 41 deletions(-) diff --git a/crates/lang/src/uplc_two.rs b/crates/lang/src/uplc_two.rs index 61f0dff1..67ce5129 100644 --- a/crates/lang/src/uplc_two.rs +++ b/crates/lang/src/uplc_two.rs @@ -16,7 +16,7 @@ use crate::{ ast::{ArgName, AssignmentKind, BinOp, DataType, Function, Pattern, Span, TypedArg}, expr::TypedExpr, ir::IR, - tipo::{self, Type, TypeInfo, ValueConstructor, ValueConstructorVariant}, + tipo::{self, fields::FieldMap, Type, TypeInfo, ValueConstructor, ValueConstructorVariant}, uplc::{DataTypeKey, FunctionAccessKey}, IdGenerator, }; @@ -352,8 +352,38 @@ impl<'a> CodeGenerator<'a> { ir_stack.append(&mut pattern_vec); }; } - TypedExpr::If { .. } => { - todo!() + TypedExpr::If { + branches, + final_else, + .. + } => { + let mut if_ir = vec![]; + + for (index, branch) in branches.iter().enumerate() { + let mut branch_scope = scope.clone(); + branch_scope.push(self.id_gen.next()); + + if index == 0 { + if_ir.push(IR::If { + scope: scope.clone(), + count: 3, + }); + } else { + if_ir.push(IR::If { + scope: branch_scope.clone(), + count: 3, + }); + } + self.build_ir(&branch.condition, &mut if_ir, branch_scope.clone()); + self.build_ir(&branch.body, &mut if_ir, branch_scope); + } + + let mut branch_scope = scope.clone(); + branch_scope.push(self.id_gen.next()); + + self.build_ir(&final_else, &mut if_ir, branch_scope); + + ir_stack.append(&mut if_ir); } TypedExpr::RecordAccess { record, @@ -377,14 +407,28 @@ impl<'a> CodeGenerator<'a> { .. } => match constructor { tipo::ModuleValueConstructor::Record { .. } => todo!(), - tipo::ModuleValueConstructor::Fn { name, .. } => { + tipo::ModuleValueConstructor::Fn { name, module, .. } => { let func = self.functions.get(&FunctionAccessKey { module_name: module_name.clone(), function_name: name.clone(), }); - if let Some(_func) = func { - todo!() + if let Some(func) = func { + ir_stack.push(IR::Var { + scope, + constructor: ValueConstructor::public( + func.return_type.clone(), + ValueConstructorVariant::ModuleFn { + name: name.clone(), + field_map: None, + module: module.clone(), + arity: func.arguments.len(), + location: Span::empty(), + builtin: None, + }, + ), + name: format!("{module}_{name}"), + }); } else { let type_info = self.module_types.get(module_name).unwrap(); let value = type_info.values.get(name).unwrap(); @@ -437,7 +481,9 @@ impl<'a> CodeGenerator<'a> { list @ Pattern::List { .. } => { self.pattern_ir(list, pattern_vec, value_vec, scope); } - Pattern::Constructor { .. } => todo!(), + Pattern::Constructor { .. } => { + self.pattern_ir(pattern, pattern_vec, value_vec, scope); + } Pattern::Tuple { .. } => todo!(), } } @@ -482,7 +528,11 @@ impl<'a> CodeGenerator<'a> { pattern_vec.append(values); } Pattern::List { .. } => todo!(), - Pattern::Constructor { arguments, .. } => { + Pattern::Constructor { + arguments, + name: constr_name, + .. + } => { let mut needs_access_to_constr_var = false; for arg in arguments { match arg.value { @@ -506,13 +556,44 @@ impl<'a> CodeGenerator<'a> { scope: scope.clone(), }]; + let data_type_key = match tipo { + Type::Fn { ret, .. } => match ret.as_ref() { + Type::App { module, name, .. } => DataTypeKey { + module_name: module.clone(), + defined_type: name.clone(), + }, + _ => unreachable!(), + }, + Type::App { module, name, .. } => DataTypeKey { + module_name: module.clone(), + defined_type: name.clone(), + }, + _ => unreachable!(), + }; + + let data_type = self.data_types.get(&data_type_key).unwrap(); + let (index, _) = data_type + .constructors + .iter() + .enumerate() + .find(|(_, dt)| &dt.name == constr_name) + .unwrap(); + + // push constructor Index + pattern_vec.push(IR::Int { + value: index.to_string(), + scope: scope.clone(), + }); + if needs_access_to_constr_var { *needs_constr_var = true; - new_vec.append(values); + // new_vec.append(values); self.pattern_ir(pattern, pattern_vec, &mut new_vec, scope); + pattern_vec.append(values); } else { - self.pattern_ir(pattern, pattern_vec, values, scope); + self.pattern_ir(pattern, pattern_vec, &mut vec![], scope); + pattern_vec.append(values); } } Pattern::Tuple { .. } => todo!(), @@ -613,19 +694,13 @@ impl<'a> CodeGenerator<'a> { }; let data_type = self.data_types.get(&data_type_key).unwrap(); - let (index, constructor_type) = data_type + let (_, constructor_type) = data_type .constructors .iter() .enumerate() .find(|(_, dt)| &dt.name == constr_name) .unwrap(); - - // push constructor Index - pattern_vec.push(IR::Int { - value: index.to_string(), - scope: scope.clone(), - }); - + let mut nested_pattern = vec![]; if *is_record { let field_map = match constructor { tipo::PatternConstructor::Record { field_map, .. } => { @@ -651,7 +726,31 @@ impl<'a> CodeGenerator<'a> { Pattern::Var { name, .. } => (false, name.clone()), Pattern::Discard { .. } => (true, "".to_string()), Pattern::List { .. } => todo!(), - Pattern::Constructor { .. } => todo!(), + a @ Pattern::Constructor { + tipo, + name: constr_name, + .. + } => { + let id = self.id_gen.next(); + let constr_name = format!("{constr_name}_{id}"); + self.pattern_ir( + a, + &mut nested_pattern, + &mut vec![IR::Var { + scope: scope.clone(), + constructor: ValueConstructor::public( + tipo.clone(), + ValueConstructorVariant::LocalVariable { + location: Span::empty(), + }, + ), + name: constr_name.clone(), + }], + scope.clone(), + ); + + (false, constr_name) + } _ => todo!(), }; @@ -691,7 +790,31 @@ impl<'a> CodeGenerator<'a> { Pattern::Var { name, .. } => (false, name.clone()), Pattern::Discard { .. } => (true, "".to_string()), Pattern::List { .. } => todo!(), - Pattern::Constructor { .. } => todo!(), + a @ Pattern::Constructor { + tipo, + name: constr_name, + .. + } => { + let id = self.id_gen.next(); + let constr_name = format!("{constr_name}_{id}"); + self.pattern_ir( + a, + &mut nested_pattern, + &mut vec![IR::Var { + scope: scope.clone(), + constructor: ValueConstructor::public( + tipo.clone(), + ValueConstructorVariant::LocalVariable { + location: Span::empty(), + }, + ), + name: constr_name.clone(), + }], + scope.clone(), + ); + + (false, constr_name) + } _ => todo!(), }; @@ -715,7 +838,9 @@ impl<'a> CodeGenerator<'a> { }); } } + pattern_vec.append(values); + pattern_vec.append(&mut nested_pattern); } Pattern::Tuple { .. } => todo!(), } @@ -757,10 +882,21 @@ impl<'a> CodeGenerator<'a> { unique: 0.into(), })), ValueConstructorVariant::ModuleConstant { .. } => todo!(), - ValueConstructorVariant::ModuleFn { .. } => arg_stack.push(Term::Var(Name { - text: name, - unique: 0.into(), - })), + ValueConstructorVariant::ModuleFn { + name: func_name, + module, + .. + } => { + let name = if func_name == name { + format!("{module}_{func_name}") + } else { + name + }; + arg_stack.push(Term::Var(Name { + text: name, + unique: 0.into(), + })); + } ValueConstructorVariant::Record { name: constr_name, .. } => { @@ -1103,8 +1239,14 @@ impl<'a> CodeGenerator<'a> { func_name, params, recursive, + module_name, .. } => { + let func_name = if module_name.is_empty() { + func_name + } else { + format!("{module_name}_{func_name}") + }; let mut func_body = arg_stack.pop().unwrap(); let mut term = arg_stack.pop().unwrap(); @@ -1336,7 +1478,31 @@ impl<'a> CodeGenerator<'a> { IR::Finally { .. } => { let _clause = arg_stack.pop().unwrap(); } - IR::If { .. } => todo!(), + IR::If { .. } => { + let condition = arg_stack.pop().unwrap(); + let then = arg_stack.pop().unwrap(); + let mut term = arg_stack.pop().unwrap(); + + term = Term::Force( + Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Builtin(DefaultFunction::IfThenElse) + .force_wrap() + .into(), + argument: condition.into(), + } + .into(), + argument: Term::Delay(then.into()).into(), + } + .into(), + argument: Term::Delay(term.into()).into(), + } + .into(), + ); + + arg_stack.push(term); + } IR::Constr { .. } => todo!(), IR::Fields { .. } => todo!(), IR::RecordAccess { index, tipo, .. } => { @@ -1382,11 +1548,7 @@ impl<'a> CodeGenerator<'a> { arg_stack.push(term); } - IR::FieldsExpose { - count: _count, - indices, - .. - } => { + IR::FieldsExpose { indices, .. } => { self.needs_field_access = true; let constr_var = arg_stack.pop().unwrap(); @@ -1645,8 +1807,6 @@ impl<'a> CodeGenerator<'a> { let mut final_func_dep_ir = IndexMap::new(); - println!("GOT HERE"); - for func in func_index_map.clone() { if self.defined_functions.contains_key(&func.0) { continue; diff --git a/examples/sample/lib/sample.ak b/examples/sample/lib/sample.ak index 567ae40d..fe6a8831 100644 --- a/examples/sample/lib/sample.ak +++ b/examples/sample/lib/sample.ak @@ -18,8 +18,8 @@ pub type Datum { rdmr: Redeem, } -pub fn eqInt(a: Int, b: Int) { - a == b +pub fn eqIntPlusOne(a: Int, b: Int) { + a + 1 == b } pub fn eqString(a: ByteArray, b: ByteArray) { @@ -35,3 +35,13 @@ pub type Other { Wow Yes } + +pub fn incrementor(counter: Int, target: Int) -> Int { + if counter == target { + counter + } else if counter > target { + counter - target + } else { + incrementor(counter + 1, target) + } +} diff --git a/examples/sample/validators/swap.ak b/examples/sample/validators/swap.ak index cae8a60a..72f1742d 100644 --- a/examples/sample/validators/swap.ak +++ b/examples/sample/validators/swap.ak @@ -8,6 +8,7 @@ const something = 5 pub type Redeemer { signer: ByteArray, amount: Int, + other_thing: Redeemer, } pub type Reen { @@ -32,9 +33,12 @@ pub fn final_check(z: Int) { } pub fn incrementor(counter: Int, target: Int) -> Int { - when counter is { - target -> target - _ -> incrementor(counter+1, target) + if counter == target { + counter + } else if counter > target { + counter - target + } else { + incrementor(counter + 1, target) } } @@ -43,15 +47,29 @@ pub fn who(a: ByteArray) -> ByteArray { } pub type Datum { - Offer { price: Int, asset_class: ByteArray, thing: Int } + Offer { + price: Int, + asset_class: ByteArray, + thing: Int, + other_thing: Redeemer, + } Sell Hold(Int) } pub fn spend(datum: Datum, _rdmr: Nil, _ctx: Nil) -> Bool { when datum is { - Offer { price, thing: t, .. } -> add_one(price) > 0 - Hold(less) -> incrementor(0, 8) == less - Sell -> add_two(1) > 1 + Sell -> sample.eqIntPlusOne(sample.incrementor(0, 8), 9) + _ -> False } + + + + + // let Redeemer{ signer, amount: amount2, other_thing: Redeemer{ signer: nested_signer, ..}} = datum + // True + // when datum is { + // Offer{ price: p, asset_class: ac, thing: thing, other_thing: Redeemer{ other_thing: Redeemer{ signer: nested_signer, amount: amount, ..}, .. } } -> True + // _ -> False + // } }