diff --git a/.gitignore b/.gitignore index fd71a9bc..826412aa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target .idea -_site/ \ No newline at end of file +_site/ +temp \ No newline at end of file diff --git a/crates/lang/src/ir.rs b/crates/lang/src/ir.rs index 447282fc..2c6c9cae 100644 --- a/crates/lang/src/ir.rs +++ b/crates/lang/src/ir.rs @@ -104,15 +104,18 @@ pub enum IR { // }, When { count: usize, + subject_name: String, }, Clause { count: usize, + tipo: Arc, + subject_name: String, }, - Finally { - count: usize, - }, + Discard, + + Finally, If { count: usize, diff --git a/crates/lang/src/uplc_two.rs b/crates/lang/src/uplc_two.rs index e002ef9c..afcd86e9 100644 --- a/crates/lang/src/uplc_two.rs +++ b/crates/lang/src/uplc_two.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, ops::Deref, sync::Arc}; +use std::{collections::HashMap, fmt::format, ops::Deref, sync::Arc}; use uplc::{ ast::{ @@ -193,23 +193,38 @@ impl<'a> CodeGenerator<'a> { TypedExpr::When { subjects, clauses, .. } => { + let subject_name = format!("__subject_name_{}", self.id_gen.next()); + // assuming one subject at the moment ir_stack.push(IR::When { count: clauses.len() + 1, + subject_name: subject_name.clone(), }); + let subject = subjects[0].clone(); self.build_ir(&subject, ir_stack); if let Some((last_clause, clauses)) = clauses.split_last() { let mut clauses_vec = vec![]; + let mut pattern_vec = vec![]; + for clause in clauses { - ir_stack.push(IR::Clause { count: 2 }); self.build_ir(&clause.then, &mut clauses_vec); - self.pattern_ir(&clause.pattern[0], ir_stack, &mut clauses_vec); + + self.when_ir( + &clause.pattern[0], + &mut pattern_vec, + &mut clauses_vec, + &subject.tipo(), + subject_name.clone(), + ) } + + ir_stack.append(&mut pattern_vec); + let last_pattern = &last_clause.pattern[0]; - ir_stack.push(IR::Finally { count: 2 }); + ir_stack.push(IR::Finally); self.build_ir(&last_clause.then, &mut clauses_vec); self.pattern_ir(last_pattern, ir_stack, &mut clauses_vec); @@ -326,6 +341,38 @@ impl<'a> CodeGenerator<'a> { } } + fn when_ir( + &self, + pattern: &Pattern>, + pattern_vec: &mut Vec, + values: &mut Vec, + tipo: &Type, + subject_name: String, + ) { + match pattern { + Pattern::Int { value, .. } => { + pattern_vec.push(IR::Clause { + count: 2, + tipo: tipo.clone().into(), + subject_name, + }); + + pattern_vec.push(IR::Int { + value: value.clone(), + }); + + pattern_vec.append(values); + } + Pattern::String { .. } => todo!(), + Pattern::Var { .. } => todo!(), + Pattern::VarUsage { .. } => todo!(), + Pattern::Assign { .. } => todo!(), + Pattern::Discard { .. } => unreachable!(), + Pattern::List { .. } => todo!(), + Pattern::Constructor { .. } => todo!(), + } + } + fn pattern_ir( &self, pattern: &Pattern>, @@ -338,7 +385,11 @@ impl<'a> CodeGenerator<'a> { Pattern::Var { .. } => todo!(), Pattern::VarUsage { .. } => todo!(), Pattern::Assign { .. } => todo!(), - Pattern::Discard { .. } => todo!(), + Pattern::Discard { .. } => { + pattern_vec.push(IR::Discard); + + pattern_vec.append(values); + } Pattern::List { elements, tail, .. } => { let mut elements_vec = vec![]; @@ -478,6 +529,9 @@ impl<'a> CodeGenerator<'a> { } } }, + IR::Discard => { + arg_stack.push(Term::Constant(Constant::Unit)); + } IR::List { count, tipo, tail } => { let mut args = vec![]; @@ -754,7 +808,7 @@ impl<'a> CodeGenerator<'a> { arg_stack.push(term); } IR::DefineFunc { func_name, .. } => { - let body = arg_stack.pop().unwrap(); + let _body = arg_stack.pop().unwrap(); todo!() } @@ -762,8 +816,70 @@ impl<'a> CodeGenerator<'a> { IR::DefineConstrFields { .. } => todo!(), IR::DefineConstrFieldAccess { .. } => todo!(), IR::When { .. } => todo!(), - IR::Clause { .. } => todo!(), - IR::Finally { .. } => todo!(), + IR::Clause { + count, + tipo, + subject_name, + } => { + // clause to compare + let clause = arg_stack.pop().unwrap(); + + // the body to be run if the clause matches + let body = arg_stack.pop().unwrap(); + + // the final branch in the when expression + let mut term = arg_stack.pop().unwrap(); + + let checker = if tipo.is_int() { + DefaultFunction::EqualsInteger.into() + } else if tipo.is_bytearray() { + DefaultFunction::EqualsByteString.into() + } else if tipo.is_bool() { + todo!() + } else if tipo.is_string() { + DefaultFunction::EqualsString.into() + } else if tipo.is_list() { + todo!() + } else { + DefaultFunction::EqualsData.into() + }; + + term = Term::Apply { + function: Term::Apply { + function: Term::Apply { + function: Term::Force(DefaultFunction::IfThenElse.into()).into(), + argument: Term::Apply { + function: Term::Apply { + function: checker, + argument: Term::Var(Name { + text: subject_name, + unique: 0.into(), + }) + .into(), + } + .into(), + argument: clause.into(), + } + .into(), + } + .into(), + argument: body.into(), + } + .into(), + argument: term.into(), + } + .force_wrap(); + + arg_stack.push(term); + } + IR::Finally => { + let clause = arg_stack.pop().unwrap(); + + if !clause.is_unit() { + let _body = arg_stack.pop().unwrap(); + todo!(); + } + } IR::If { .. } => todo!(), IR::Constr { .. } => todo!(), IR::Fields { .. } => todo!(), diff --git a/crates/uplc/src/ast.rs b/crates/uplc/src/ast.rs index cd35ee3b..d8019604 100644 --- a/crates/uplc/src/ast.rs +++ b/crates/uplc/src/ast.rs @@ -110,6 +110,16 @@ pub enum Term { Builtin(DefaultFunction), } +impl Term { + pub fn is_unit(&self) -> bool { + matches!(self, Term::Constant(Constant::Unit)) + } + + pub fn force_wrap(self) -> Self { + Term::Force(self.into()) + } +} + impl<'a, T> Display for Term where T: Binder<'a>, diff --git a/crates/uplc/src/builtins.rs b/crates/uplc/src/builtins.rs index 71b7f5ca..f2d8a790 100644 --- a/crates/uplc/src/builtins.rs +++ b/crates/uplc/src/builtins.rs @@ -1,9 +1,11 @@ -use std::{fmt::Display, str::FromStr}; +use std::{fmt::Display, rc::Rc, str::FromStr}; use strum_macros::EnumIter; use flat_rs::de; +use crate::ast::Term; + /// All the possible builtin functions in Untyped Plutus Core. #[repr(u8)] #[allow(non_camel_case_types)] @@ -389,3 +391,15 @@ impl DefaultFunction { .to_string() } } + +impl From for Term { + fn from(builtin: DefaultFunction) -> Self { + Term::Builtin(builtin) + } +} + +impl From for Rc> { + fn from(builtin: DefaultFunction) -> Self { + Term::Builtin(builtin).into() + } +}