diff --git a/crates/lang/src/builtins.rs b/crates/lang/src/builtins.rs index 198b46fc..fa6c652d 100644 --- a/crates/lang/src/builtins.rs +++ b/crates/lang/src/builtins.rs @@ -7,7 +7,7 @@ use uplc::builtins::DefaultFunction; use crate::{ ast::{ModuleKind, Span}, tipo::{ - fields::FieldMap, Type, TypeConstructor, TypeInfo, TypeVar, ValueConstructor, + self, fields::FieldMap, Type, TypeConstructor, TypeInfo, TypeVar, ValueConstructor, ValueConstructorVariant, }, IdGenerator, @@ -336,7 +336,13 @@ pub fn from_default_function( Some((tipo, 1)) } - DefaultFunction::IfThenElse => None, + DefaultFunction::IfThenElse => { + let ret = generic_var(id_gen.next()); + + let tipo = function(vec![bool(), ret.clone(), ret.clone()], ret); + + Some((tipo, 3)) + } DefaultFunction::ChooseUnit => None, DefaultFunction::Trace => { let ret = generic_var(id_gen.next()); diff --git a/crates/lang/src/ir.rs b/crates/lang/src/ir.rs index 58c043fd..ec2ae412 100644 --- a/crates/lang/src/ir.rs +++ b/crates/lang/src/ir.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use vec1::Vec1; +use uplc::builtins::DefaultFunction; use crate::{ ast::{ @@ -40,12 +40,19 @@ pub enum IR { // }, List { count: usize, + tipo: Arc, + tail: bool, }, Tail { count: usize, }, + ListAccessor { + names: Vec, + tail: bool, + }, + // func(x, other(y)) //[ Define(3) x definition *lam_body* -> [ (x [ (func [ func x [ (y [ other y ]) *definition* ] ]) *definition* ]) *definition* ], Define func -> [ (func [ func x [ (y [ other y ]) *definition* ] ]) *definition* ] , Call func -> [ func x [ (y [ other y ]) *definition* ] ], Var x -> x, Define y -> [ (y [ other y ]) *definition* ], Call other -> [ other y ], Var y -> y] @@ -54,13 +61,18 @@ pub enum IR { count: usize, }, + Builtin { + func: DefaultFunction, + }, + BinOp { name: BinOp, count: usize, + tipo: Arc, }, Assignment { - count: usize, + name: String, kind: AssignmentKind, }, diff --git a/crates/lang/src/tipo.rs b/crates/lang/src/tipo.rs index 1d04da41..89529cc4 100644 --- a/crates/lang/src/tipo.rs +++ b/crates/lang/src/tipo.rs @@ -1,6 +1,6 @@ use std::{cell::RefCell, collections::HashMap, ops::Deref, sync::Arc}; -use uplc::builtins::DefaultFunction; +use uplc::{ast::Type as UplcType, builtins::DefaultFunction}; use crate::{ ast::{Constant, DefinitionLocation, ModuleKind, Span, TypedConstant}, @@ -127,6 +127,43 @@ impl Type { } } + pub fn is_list(&self) -> bool { + match self { + Self::App { module, name, .. } if "List" == name && module.is_empty() => true, + Self::Var { tipo } => tipo.borrow().is_list(), + _ => false, + } + } + + pub fn get_uplc_type(&self) -> UplcType { + if self.is_int() { + UplcType::Integer + } else if self.is_bytearray() { + UplcType::ByteString + } else if self.is_string() { + UplcType::String + } else if self.is_bool() { + UplcType::Bool + } else if self.is_list() { + let args_type = match self { + Self::App { + module, name, args, .. + } if "List" == name && module.is_empty() => args[0].clone(), + Self::Var { tipo } => { + if let TypeVar::Link { tipo } = tipo.borrow().clone() { + tipo + } else { + todo!() + } + } + _ => todo!(), + }; + UplcType::List(Box::new(args_type.get_uplc_type())) + } else { + UplcType::Data + } + } + /// Get the args for the type if the type is a specific `Type::App`. /// Returns None if the type is not a `Type::App` or is an incorrect `Type:App` /// @@ -290,6 +327,13 @@ impl TypeVar { _ => false, } } + + pub fn is_list(&self) -> bool { + match self { + Self::Link { tipo } => tipo.is_list(), + _ => false, + } + } } #[derive(Debug, Clone, PartialEq)] diff --git a/crates/lang/src/uplc_two.rs b/crates/lang/src/uplc_two.rs index b0630dd9..ee623099 100644 --- a/crates/lang/src/uplc_two.rs +++ b/crates/lang/src/uplc_two.rs @@ -1,19 +1,20 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, ops::Deref, sync::Arc}; use indexmap::IndexMap; use uplc::{ - ast::{Name, Program, Term}, + ast::{Constant, Name, Program, Term, Type as UplcType}, + builtins::DefaultFunction, parser::interner::Interner, + BigInt, PlutusData, }; use crate::{ - ast::{DataType, Function, TypedArg}, + ast::{AssignmentKind, BinOp, DataType, Function, Pattern, Span, TypedArg}, expr::TypedExpr, ir::IR, - tipo, - uplc::{ - ConstrFieldKey, ConstrUsageKey, DataTypeKey, FunctionAccessKey, ScopeLevels, ScopedExpr, - }, + tipo::{self, Type, TypeInfo, ValueConstructor, ValueConstructorVariant}, + uplc::{DataTypeKey, FunctionAccessKey}, + IdGenerator, }; pub struct CodeGenerator<'a> { @@ -28,6 +29,8 @@ pub struct CodeGenerator<'a> { data_types: &'a HashMap>>, // imports: &'a HashMap<(String, String), &'a Use>, // constants: &'a HashMap<(String, String), &'a ModuleConstant, String>>, + module_types: &'a HashMap, + id_gen: IdGenerator, } impl<'a> CodeGenerator<'a> { @@ -37,6 +40,7 @@ impl<'a> CodeGenerator<'a> { data_types: &'a HashMap>>, // imports: &'a HashMap<(String, String), &'a Use>, // constants: &'a HashMap<(String, String), &'a ModuleConstant, String>>, + module_types: &'a HashMap, ) -> Self { CodeGenerator { // uplc_function_holder: Vec::new(), @@ -50,6 +54,8 @@ impl<'a> CodeGenerator<'a> { data_types, // imports, // constants, + module_types, + id_gen: IdGenerator::new(), } } @@ -58,108 +64,90 @@ impl<'a> CodeGenerator<'a> { self.build_ir(&body, &mut ir_stack); - todo!(); + println!("{ir_stack:#?}"); - // self.uplc_function_holder_lookup - // .sort_by(|_key1, value1, _key2, value2| { - // if value1.is_less_than(value2, true) { - // Ordering::Less - // } else if value2.is_less_than(value1, true) { - // Ordering::Greater - // } else { - // Ordering::Equal - // } - // }); + let mut term = self.uplc_code_gen(&mut ir_stack); - // println!("DATA HOLDER LOOKUP{:#?}", self.uplc_data_holder_lookup); + // Apply constr exposer to top level. + term = Term::Apply { + function: Term::Lambda { + parameter_name: Name { + text: "constr_fields_exposer".to_string(), + unique: 0.into(), + }, + body: term.into(), + } + .into(), + argument: Term::Lambda { + parameter_name: Name { + text: "constr_var".to_string(), + unique: 0.into(), + }, + body: Term::Apply { + function: Term::Force( + Term::Force(Term::Builtin(DefaultFunction::SndPair).into()).into(), + ) + .into(), + argument: Term::Apply { + function: Term::Builtin(DefaultFunction::UnConstrData).into(), + argument: Term::Var(Name { + text: "constr_var".to_string(), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + } + .into(), + }; - // println!( - // "DATA USAGE HOLDER {:#?}", - // self.uplc_data_usage_holder_lookup - // ); + term = self.add_arg_getter(term); - // let mut term = self.recurse_code_gen(&body, ScopeLevels::new()); + term = Term::Force( + Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Force(Term::Builtin(DefaultFunction::IfThenElse).into()) + .into(), + argument: term.into(), + } + .into(), + argument: Term::Delay(Term::Constant(Constant::Unit).into()).into(), + } + .into(), + argument: Term::Delay(Term::Error.into()).into(), + } + .into(), + ); - // // Apply constr exposer to top level. - // term = Term::Apply { - // function: Term::Lambda { - // parameter_name: Name { - // text: "constr_fields_exposer".to_string(), - // unique: 0.into(), - // }, - // body: term.into(), - // } - // .into(), - // argument: Term::Lambda { - // parameter_name: Name { - // text: "constr_var".to_string(), - // unique: 0.into(), - // }, - // body: Term::Apply { - // function: Term::Force( - // Term::Force(Term::Builtin(DefaultFunction::SndPair).into()).into(), - // ) - // .into(), - // argument: Term::Apply { - // function: Term::Builtin(DefaultFunction::UnConstrData).into(), - // argument: Term::Var(Name { - // text: "constr_var".to_string(), - // unique: 0.into(), - // }) - // .into(), - // } - // .into(), - // } - // .into(), - // } - // .into(), - // }; + for arg in arguments.iter().rev() { + term = Term::Lambda { + parameter_name: uplc::ast::Name { + text: arg.arg_name.get_variable_name().unwrap_or("_").to_string(), + unique: 0.into(), + }, + body: term.into(), + } + } - // term = self.add_arg_getter(term); + let mut program = Program { + version: (1, 0, 0), + term, + }; - // term = Term::Force( - // Term::Apply { - // function: Term::Apply { - // function: Term::Apply { - // function: Term::Force(Term::Builtin(DefaultFunction::IfThenElse).into()) - // .into(), - // argument: term.into(), - // } - // .into(), - // argument: Term::Delay(Term::Constant(Constant::Unit).into()).into(), - // } - // .into(), - // argument: Term::Delay(Term::Error.into()).into(), - // } - // .into(), - // ); + let mut interner = Interner::new(); - // for arg in arguments.iter().rev() { - // term = Term::Lambda { - // parameter_name: uplc::ast::Name { - // text: arg.arg_name.get_variable_name().unwrap_or("_").to_string(), - // unique: Unique::new(0), - // }, - // body: Rc::new(term), - // } - // } + println!("{}", program.to_pretty()); - // let mut program = Program { - // version: (1, 0, 0), - // term, - // }; + interner.program(&mut program); - // let mut interner = Interner::new(); - - // println!("{}", program.to_pretty()); - - // interner.program(&mut program); - - // program + program } pub(crate) fn build_ir(&mut self, body: &TypedExpr, ir_stack: &mut Vec) { - match body { + match dbg!(body) { TypedExpr::Int { value, .. } => ir_stack.push(IR::Int { value: value.to_string(), }), @@ -190,13 +178,20 @@ impl<'a> CodeGenerator<'a> { // Add constructor information here? } TypedExpr::Fn { .. } => todo!(), - TypedExpr::List { elements, tail, .. } => { + TypedExpr::List { + elements, + tail, + tipo, + .. + } => { ir_stack.push(IR::List { count: if tail.is_some() { elements.len() + 1 } else { elements.len() }, + tipo: tipo.clone(), + tail: tail.is_some(), }); for element in elements { self.build_ir(element, ir_stack) @@ -217,11 +212,16 @@ impl<'a> CodeGenerator<'a> { } } TypedExpr::BinOp { - name, left, right, .. + name, + left, + right, + tipo, + .. } => { ir_stack.push(IR::BinOp { name: *name, count: 2, + tipo: tipo.clone(), }); self.build_ir(left, ir_stack); self.build_ir(right, ir_stack); @@ -230,34 +230,26 @@ impl<'a> CodeGenerator<'a> { value, pattern, kind, + tipo, .. } => { let mut define_vec: Vec = vec![]; let mut value_vec: Vec = vec![]; let mut pattern_vec: Vec = vec![]; - pattern_vec.push(IR::Assignment { - count: 3, - kind: *kind, - }); - self.build_ir(value, &mut value_vec); self.define_ir(&value_vec, &mut define_vec); - self.pattern_ir(pattern, &mut pattern_vec); + self.assignment_ir(pattern, &mut pattern_vec, &mut value_vec, tipo, *kind); - for define in define_vec { - ir_stack.push(define); - } - for pattern in pattern_vec { - ir_stack.push(pattern); - } - for value in value_vec { - ir_stack.push(value); - } + ir_stack.append(&mut define_vec); + ir_stack.append(&mut pattern_vec); } TypedExpr::Try { .. } => todo!(), TypedExpr::When { - subjects, clauses, .. + subjects, + clauses, + tipo, + .. } => { // assuming one subject at the moment ir_stack.push(IR::When { @@ -268,98 +260,949 @@ impl<'a> CodeGenerator<'a> { self.build_ir(&subject, ir_stack); if let Some((last_clause, clauses)) = clauses.split_last() { + let mut clauses_vec = vec![]; for clause in clauses { ir_stack.push(IR::Clause { count: 2 }); - self.pattern_ir(&clause.pattern[0], ir_stack); - self.build_ir(&clause.then, ir_stack); + self.build_ir(&clause.then, &mut clauses_vec); + self.pattern_ir(&clause.pattern[0], ir_stack, &mut clauses_vec); } let last_pattern = &last_clause.pattern[0]; + ir_stack.push(IR::Finally { count: 2 }); - let mut pattern_vec = vec![]; - let mut value_vec = vec![]; - - self.pattern_ir(last_pattern, &mut pattern_vec); - self.build_ir(&last_clause.then, &mut value_vec); - - let mut final_vec = vec![]; - - final_vec.push(IR::Finally { count: 1 }); - - let pattern_field_map = match last_pattern { - crate::ast::Pattern::Int { .. } => todo!(), - crate::ast::Pattern::String { .. } => todo!(), - crate::ast::Pattern::Var { .. } => todo!(), - crate::ast::Pattern::VarUsage { .. } => todo!(), - crate::ast::Pattern::Assign { .. } => todo!(), - crate::ast::Pattern::Discard { name, location } => todo!(), - crate::ast::Pattern::List { .. } => todo!(), - crate::ast::Pattern::Constructor { - is_record, - location, - name, - arguments, - module, - constructor, - with_spread, - tipo, - } => { - let data_type_key = DataTypeKey { - module_name: module.clone().unwrap_or_default(), - defined_type: name.to_string(), - }; - } - }; - - // ir_stack.push(IR::Finally { - // count: , - // }); + self.build_ir(&last_clause.then, &mut clauses_vec); + self.pattern_ir(last_pattern, ir_stack, &mut clauses_vec); }; } - TypedExpr::If { - location, - branches, - final_else, - tipo, - } => todo!(), - TypedExpr::RecordAccess { - location, - tipo, - label, - index, - record, - } => todo!(), + TypedExpr::If { .. } => todo!(), + TypedExpr::RecordAccess { .. } => todo!(), TypedExpr::ModuleSelect { - location, tipo, - label, - module_name, - module_alias, constructor, - } => todo!(), - TypedExpr::Todo { - location, - label, - tipo, - } => todo!(), - TypedExpr::RecordUpdate { - location, - tipo, - spread, - args, - } => todo!(), - TypedExpr::Negate { location, value } => todo!(), + module_name, + .. + } => match constructor { + tipo::ModuleValueConstructor::Record { .. } => todo!(), + tipo::ModuleValueConstructor::Fn { + location, + module, + name, + } => { + let func = self.functions.get(&FunctionAccessKey { + module_name: module_name.clone(), + function_name: name.clone(), + }); + + if let Some(_func) = func { + todo!() + } else { + let type_info = self.module_types.get(module_name).unwrap(); + let value = type_info.values.get(name).unwrap(); + match &value.variant { + ValueConstructorVariant::ModuleFn { builtin, .. } => { + let builtin = builtin.unwrap(); + + ir_stack.push(IR::Builtin { func: builtin }); + } + _ => unreachable!(), + } + } + } + tipo::ModuleValueConstructor::Constant { .. } => todo!(), + }, + TypedExpr::Todo { .. } => todo!(), + TypedExpr::RecordUpdate { .. } => todo!(), + TypedExpr::Negate { .. } => todo!(), } } - fn define_ir(&self, value_vec: &Vec, define_vec: &mut Vec) { - todo!() + fn define_ir(&self, value_vec: &Vec, _define_vec: &mut Vec) { + // get value item + for value in value_vec { + match dbg!(value) { + IR::Int { .. } => {} + IR::Var { constructor, .. } => match constructor.variant { + ValueConstructorVariant::LocalVariable { .. } => {} + ValueConstructorVariant::ModuleConstant { .. } => todo!(), + ValueConstructorVariant::ModuleFn { .. } => todo!(), + ValueConstructorVariant::Record { .. } => {} + }, + IR::Call { .. } => {} + IR::BinOp { .. } => {} + IR::When { .. } => todo!(), + IR::Clause { .. } => todo!(), + IR::Finally { .. } => todo!(), + IR::If { .. } => todo!(), + IR::Constr { .. } => todo!(), + IR::Fields { .. } => todo!(), + IR::RecordAccess { .. } => todo!(), + IR::FieldsExpose { .. } => todo!(), + IR::Todo { .. } => todo!(), + IR::RecordUpdate { .. } => todo!(), + IR::Negate { .. } => todo!(), + IR::Builtin { .. } => {} + IR::List { .. } => {} + _ => todo!(), + } + } + } + + fn assignment_ir( + &self, + pattern: &Pattern>, + pattern_vec: &mut Vec, + value_vec: &mut Vec, + _tipo: &Type, + kind: AssignmentKind, + ) { + match pattern { + Pattern::Int { .. } => todo!(), + Pattern::String { .. } => todo!(), + Pattern::Var { name, .. } => { + pattern_vec.push(IR::Assignment { + name: name.clone(), + kind, + }); + + pattern_vec.append(value_vec); + } + Pattern::VarUsage { .. } => todo!(), + Pattern::Assign { .. } => todo!(), + Pattern::Discard { .. } => todo!(), + list @ Pattern::List { .. } => { + self.pattern_ir(list, pattern_vec, value_vec); + } + Pattern::Constructor { .. } => todo!(), + } } fn pattern_ir( &self, - pattern: &crate::ast::Pattern>, + pattern: &Pattern>, pattern_vec: &mut Vec, + values: &mut Vec, ) { - todo!() + match pattern { + Pattern::Int { .. } => todo!(), + Pattern::String { .. } => todo!(), + Pattern::Var { .. } => todo!(), + Pattern::VarUsage { .. } => todo!(), + Pattern::Assign { .. } => todo!(), + Pattern::Discard { .. } => todo!(), + Pattern::List { elements, tail, .. } => { + let mut elements_vec = vec![]; + let mut var_vec = vec![]; + + let mut names = vec![]; + for element in elements { + match dbg!(element) { + Pattern::Var { name, .. } => { + names.push(name.clone()); + } + a @ Pattern::List { .. } => { + self.pattern_ir(a, &mut elements_vec, &mut vec![]); + + let item_name = format!("list_item_id_{}", self.id_gen.next()); + names.push(item_name.clone()); + var_vec.push(IR::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, + }); + var_vec.append(&mut elements_vec); + } + _ => todo!(), + } + } + + if let Some(tail) = tail { + match &**tail { + Pattern::Var { name, .. } => names.push(name.clone()), + Pattern::Discard { .. } => {} + _ => unreachable!(), + } + } + + pattern_vec.push(IR::ListAccessor { + names, + tail: tail.is_some(), + }); + + pattern_vec.append(values); + + pattern_vec.append(&mut var_vec); + } + Pattern::Constructor { .. } => todo!(), + } + } + + fn uplc_code_gen(&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() + } + + fn gen_uplc(&self, ir: IR, arg_stack: &mut Vec>) { + match ir { + IR::Int { value } => { + let integer = value.parse().unwrap(); + + let term = Term::Constant(Constant::Integer(integer)); + + arg_stack.push(term); + } + IR::String { value } => { + let term = Term::Constant(Constant::String(value)); + + arg_stack.push(term); + } + IR::ByteArray { bytes } => { + let term = Term::Constant(Constant::ByteString(bytes)); + arg_stack.push(term); + } + IR::Var { name, constructor } => match constructor.variant { + ValueConstructorVariant::LocalVariable { .. } => arg_stack.push(Term::Var(Name { + text: name, + unique: 0.into(), + })), + ValueConstructorVariant::ModuleConstant { .. } => todo!(), + ValueConstructorVariant::ModuleFn { .. } => todo!(), + ValueConstructorVariant::Record { + name: constr_name, .. + } => { + let data_type_key = match &*constructor.tipo { + Type::App { module, name, .. } => DataTypeKey { + module_name: module.to_string(), + defined_type: name.to_string(), + }, + Type::Fn { .. } => todo!(), + Type::Var { .. } => todo!(), + }; + + if data_type_key.defined_type == "Bool" { + arg_stack.push(Term::Constant(Constant::Bool(constr_name == "True"))); + } else { + let data_type = self.data_types.get(&data_type_key).unwrap(); + let (constr_index, _constr) = data_type + .constructors + .iter() + .enumerate() + .find(|(_, x)| x.name == *constr_name) + .unwrap(); + + let term = Term::Apply { + function: Term::Builtin(DefaultFunction::ConstrData).into(), + argument: Term::Apply { + function: Term::Apply { + function: Term::Builtin(DefaultFunction::MkPairData).into(), + argument: Term::Constant(Constant::Data(PlutusData::BigInt( + BigInt::Int((constr_index as i128).try_into().unwrap()), + ))) + .into(), + } + .into(), + argument: Term::Constant(Constant::Data(PlutusData::Array(vec![]))) + .into(), + } + .into(), + }; + + arg_stack.push(term); + } + } + }, + IR::List { count, tipo, tail } => { + let mut args = vec![]; + + for _ in 0..count { + let arg = arg_stack.pop().unwrap(); + args.push(arg); + } + let mut constants = vec![]; + for arg in &args { + if let Term::Constant(c) = arg { + constants.push(c.clone()) + } + } + + println!("TIPO IS {tipo:#?}"); + + let list_type = match tipo.deref() { + Type::App { args, .. } => &args[0], + _ => unreachable!(), + }; + + println!("ARGS IS {:#?}", args); + println!("GET UPLC TYPE IS {:#?}", list_type.get_uplc_type()); + + if constants.len() == args.len() && !tail { + let list = + Term::Constant(Constant::ProtoList(list_type.get_uplc_type(), constants)); + println!("LIST TERM IS {:#?}", list); + + arg_stack.push(list); + } else { + let mut term = if tail { + arg_stack.pop().unwrap() + } else { + Term::Constant(Constant::ProtoList(list_type.get_uplc_type(), vec![])) + }; + + for arg in args { + term = Term::Apply { + function: Term::Apply { + function: Term::Force( + Term::Builtin(DefaultFunction::MkCons).into(), + ) + .into(), + argument: arg.into(), + } + .into(), + argument: term.into(), + }; + } + arg_stack.push(term); + } + } + + IR::Tail { .. } => todo!(), + IR::ListAccessor { mut names, tail } => { + let value = arg_stack.pop().unwrap(); + let mut term = arg_stack.pop().unwrap(); + + let mut id_list = vec![]; + + for _ in 0..names.len() { + id_list.push(self.id_gen.next()); + } + + // if tail { + // let last = names.pop().unwrap(); + // let id = id_list[names.len() - 1]; + // term = Term::Apply { + // function: Term::Lambda { + // parameter_name: Name { + // text: last, + // unique: 0.into(), + // }, + // body: term.into(), + // } + // .into(), + // argument: Term::Apply { + // function: Term::Force(Term::Builtin(DefaultFunction::TailList).into()) + // .into(), + // argument: Term::Var(Name { + // text: format!("tail_item_{}_{}", names.len() - 1, id), + // unique: 0.into(), + // }) + // .into(), + // } + // .into(), + // }; + // } + + let current_index = 0; + let (first_name, names) = names.split_first().unwrap(); + + term = Term::Apply { + function: Term::Lambda { + parameter_name: Name { + text: first_name.clone(), + unique: 0.into(), + }, + body: Term::Apply { + function: self + .list_access_to_uplc(names, &id_list, tail, current_index, term) + .into(), + argument: Term::Apply { + function: Term::Force( + Term::Builtin(DefaultFunction::TailList).into(), + ) + .into(), + argument: value.clone().into(), + } + .into(), + } + .into(), + } + .into(), + argument: Term::Apply { + function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into()) + .into(), + argument: value.into(), + } + .into(), + }; + + for (index, name) in names.iter().enumerate().rev() { + // let var_argument = if index == 0 { + // value.clone() + // } else { + // Term::Var(Name { + // text: format!("tail_item_{}", index - 1), + // unique: 0.into(), + // }) + // }; + } + + arg_stack.push(term); + } + IR::Call { count } => { + if count >= 2 { + let mut term = arg_stack.pop().unwrap(); + + for _ in 0..count - 1 { + let arg = arg_stack.pop().unwrap(); + + term = Term::Apply { + function: term.into(), + argument: arg.into(), + }; + } + arg_stack.push(term); + } else { + todo!() + } + } + IR::Builtin { func } => { + let mut term = Term::Builtin(func); + for _ in 0..func.force_count() { + term = Term::Force(term.into()); + } + arg_stack.push(term); + } + IR::BinOp { name, tipo, .. } => { + let left = arg_stack.pop().unwrap(); + let right = arg_stack.pop().unwrap(); + + let term = match name { + BinOp::And => todo!(), + BinOp::Or => todo!(), + BinOp::Eq => { + let default_builtin = match tipo.deref() { + Type::App { name, .. } => { + if name == "Int" { + Term::Builtin(DefaultFunction::EqualsInteger) + } else if name == "String" { + Term::Builtin(DefaultFunction::EqualsString) + } else if name == "ByteArray" { + Term::Builtin(DefaultFunction::EqualsByteString) + } else if name == "Bool" { + let term = Term::Force( + Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Force( + Term::Builtin(DefaultFunction::IfThenElse) + .into(), + ) + .into(), + argument: left.into(), + } + .into(), + argument: Term::Delay( + Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Force( + Term::Builtin( + DefaultFunction::IfThenElse, + ) + .into(), + ) + .into(), + argument: right.clone().into(), + } + .into(), + argument: Term::Constant( + Constant::Bool(true), + ) + .into(), + } + .into(), + argument: Term::Constant(Constant::Bool( + false, + )) + .into(), + } + .into(), + ) + .into(), + } + .into(), + argument: Term::Delay( + Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Force( + Term::Builtin( + DefaultFunction::IfThenElse, + ) + .into(), + ) + .into(), + argument: right.into(), + } + .into(), + argument: Term::Constant(Constant::Bool( + false, + )) + .into(), + } + .into(), + argument: Term::Constant(Constant::Bool(true)) + .into(), + } + .into(), + ) + .into(), + } + .into(), + ); + + arg_stack.push(term); + return; + } else { + Term::Builtin(DefaultFunction::EqualsData) + } + } + _ => unreachable!(), + }; + + Term::Apply { + function: Term::Apply { + function: default_builtin.into(), + argument: left.into(), + } + .into(), + argument: right.into(), + } + } + BinOp::NotEq => todo!(), + BinOp::LtInt => todo!(), + BinOp::LtEqInt => todo!(), + BinOp::GtEqInt => todo!(), + BinOp::GtInt => Term::Apply { + function: Term::Apply { + function: Term::Builtin(DefaultFunction::LessThanInteger).into(), + argument: right.into(), + } + .into(), + argument: left.into(), + }, + BinOp::AddInt => Term::Apply { + function: Term::Apply { + function: Term::Builtin(DefaultFunction::AddInteger).into(), + argument: left.into(), + } + .into(), + argument: right.into(), + }, + BinOp::SubInt => todo!(), + BinOp::MultInt => todo!(), + BinOp::DivInt => todo!(), + BinOp::ModInt => todo!(), + }; + arg_stack.push(term); + } + IR::Assignment { name, .. } => { + let right_hand = arg_stack.pop().unwrap(); + let lam_body = arg_stack.pop().unwrap(); + + let term = Term::Apply { + function: Term::Lambda { + parameter_name: Name { + text: name, + unique: 0.into(), + }, + body: lam_body.into(), + } + .into(), + argument: right_hand.into(), + }; + + arg_stack.push(term); + } + IR::DefineFunc { .. } => todo!(), + IR::DefineConst { .. } => todo!(), + IR::DefineConstrFields { .. } => todo!(), + IR::DefineConstrFieldAccess { .. } => todo!(), + IR::When { .. } => todo!(), + IR::Clause { .. } => todo!(), + IR::Finally { .. } => todo!(), + IR::If { .. } => todo!(), + IR::Constr { .. } => todo!(), + IR::Fields { .. } => todo!(), + IR::RecordAccess { .. } => todo!(), + IR::FieldsExpose { .. } => todo!(), + IR::Todo { .. } => todo!(), + IR::RecordUpdate { .. } => todo!(), + IR::Negate { .. } => todo!(), + } + } + + fn add_arg_getter(&self, term: Term) -> Term { + // Apply constr arg getter to top level. + Term::Apply { + function: Term::Lambda { + parameter_name: Name { + text: "constr_field_get_arg".to_string(), + unique: 0.into(), + }, + body: term.into(), + } + .into(), + argument: Term::Lambda { + parameter_name: Name { + text: "constr_list".to_string(), + unique: 0.into(), + }, + body: Term::Lambda { + parameter_name: Name { + text: "arg_number".to_string(), + unique: 0.into(), + }, + body: Term::Apply { + function: Term::Lambda { + parameter_name: Name { + text: "recurse".to_string(), + unique: 0.into(), + }, + body: Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Var(Name { + text: "recurse".to_string(), + unique: 0.into(), + }) + .into(), + argument: Term::Var(Name { + text: "recurse".to_string(), + unique: 0.into(), + }) + .into(), + } + .into(), + + // Start recursive with index 0 of list + argument: Term::Constant(Constant::Integer(0.into())).into(), + } + .into(), + argument: Term::Var(Name { + text: "constr_list".to_string(), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + + argument: Term::Lambda { + parameter_name: Name { + text: "self_recursor".to_string(), + unique: 0.into(), + }, + body: Term::Lambda { + parameter_name: Name { + text: "current_arg_number".to_string(), + unique: 0.into(), + }, + body: Term::Lambda { + parameter_name: Name { + text: "list_of_constr_args".to_string(), + unique: 0.into(), + }, + body: Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Force( + Term::Builtin(DefaultFunction::IfThenElse) + .into(), + ) + .into(), + argument: Term::Apply { + function: Term::Apply { + function: Term::Builtin( + DefaultFunction::EqualsInteger, + ) + .into(), + argument: Term::Var(Name { + text: "arg_number".to_string(), + unique: 0.into(), + }) + .into(), + } + .into(), + argument: Term::Var(Name { + text: "current_arg_number".to_string(), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + argument: Term::Force( + Term::Builtin(DefaultFunction::HeadList).into(), + ) + .into(), + } + .into(), + argument: Term::Lambda { + parameter_name: Name { + text: "current_list_of_constr_args".to_string(), + unique: 0.into(), + }, + body: Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Var(Name { + text: "self_recursor".to_string(), + unique: 0.into(), + }) + .into(), + argument: Term::Var(Name { + text: "self_recursor".to_string(), + unique: 0.into(), + }) + .into(), + } + .into(), + + argument: Term::Apply { + function: Term::Apply { + function: Term::Builtin( + DefaultFunction::AddInteger, + ) + .into(), + argument: Term::Var(Name { + text: "current_arg_number" + .to_string(), + unique: 0.into(), + }) + .into(), + } + .into(), + argument: Term::Constant( + Constant::Integer(1.into()), + ) + .into(), + } + .into(), + } + .into(), + + argument: Term::Apply { + function: Term::Force( + Term::Builtin( + DefaultFunction::TailList, + ) + .into(), + ) + .into(), + + argument: Term::Var(Name { + text: "current_list_of_constr_args" + .to_string(), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + } + .into(), + } + .into(), + argument: Term::Var(Name { + text: "list_of_constr_args".to_string(), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + } + .into(), + } + .into(), + } + .into(), + } + .into(), + } + .into(), + } + } + + fn list_access_to_uplc( + &self, + names: &[String], + id_list: &[u64], + tail: bool, + current_index: usize, + term: Term, + ) -> Term { + let (first, names) = names.split_first().unwrap(); + + if names.len() == 1 && tail { + let term = Term::Lambda { + parameter_name: Name { + text: format!("tail_index_{}_{}", current_index, id_list[current_index]), + unique: 0.into(), + }, + body: Term::Apply { + function: Term::Lambda { + parameter_name: Name { + text: first.clone(), + unique: 0.into(), + }, + body: Term::Apply { + function: Term::Lambda { + parameter_name: Name { + text: names[0].clone(), + unique: 0.into(), + }, + body: term.into(), + } + .into(), + argument: Term::Apply { + function: Term::Force( + Term::Builtin(DefaultFunction::TailList).into(), + ) + .into(), + argument: Term::Var(Name { + text: format!( + "tail_index_{}_{}", + current_index, id_list[current_index] + ), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + } + .into(), + argument: Term::Apply { + function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into()) + .into(), + argument: Term::Var(Name { + text: format!( + "tail_index_{}_{}", + current_index, id_list[current_index] + ), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + }; + term + } else if names.len() == 0 { + let term = Term::Lambda { + parameter_name: Name { + text: format!("tail_index_{}_{}", current_index, id_list[current_index]), + unique: 0.into(), + }, + body: Term::Apply { + function: Term::Lambda { + parameter_name: Name { + text: first.clone(), + unique: 0.into(), + }, + body: term.into(), + } + .into(), + argument: Term::Apply { + function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into()) + .into(), + argument: Term::Var(Name { + text: format!( + "tail_index_{}_{}", + current_index, id_list[current_index] + ), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + }; + term + } else { + let term = Term::Lambda { + parameter_name: Name { + text: format!("tail_index_{}_{}", current_index, id_list[current_index]), + unique: 0.into(), + }, + body: Term::Apply { + function: Term::Lambda { + parameter_name: Name { + text: first.clone(), + unique: 0.into(), + }, + body: Term::Apply { + function: self + .list_access_to_uplc(names, id_list, tail, current_index + 1, term) + .into(), + argument: Term::Apply { + function: Term::Force( + Term::Builtin(DefaultFunction::TailList).into(), + ) + .into(), + argument: Term::Var(Name { + text: format!( + "tail_index_{}_{}", + current_index, id_list[current_index] + ), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + } + .into(), + argument: Term::Apply { + function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into()) + .into(), + argument: Term::Var(Name { + text: format!( + "tail_index_{}_{}", + current_index, id_list[current_index] + ), + unique: 0.into(), + }) + .into(), + } + .into(), + } + .into(), + }; + term + } } } diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index 1f4c4435..c41637c5 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -14,7 +14,8 @@ use aiken_lang::{ ast::{Definition, Function, ModuleKind, TypedFunction}, builtins, tipo::TypeInfo, - uplc::{CodeGenerator, DataTypeKey, FunctionAccessKey}, + uplc::{DataTypeKey, FunctionAccessKey}, + uplc_two::CodeGenerator, IdGenerator, }; use miette::NamedSource; @@ -372,6 +373,7 @@ impl Project { &data_types, // &imports, // &constants, + &self.module_types, ); let program = generator.generate(body, arguments); diff --git a/examples/sample/validators/swap.ak b/examples/sample/validators/swap.ak index 457aee44..908cfb63 100644 --- a/examples/sample/validators/swap.ak +++ b/examples/sample/validators/swap.ak @@ -49,8 +49,9 @@ pub type Datum { } pub fn spend(datum: Datum, _rdmr: Nil, _ctx: Nil) -> Bool { - when datum is { - Sell -> True - Buy -> False - } + let x = [[[2, 9], [7]], [[4]], [[6]]] + + let [[[a, g], d], b, ..] = x + + True }