From 22f90bf07f1154123bb8d9d953efc001663609de Mon Sep 17 00:00:00 2001 From: rvcas Date: Fri, 15 Jul 2022 19:40:56 -0400 Subject: [PATCH] feat: impl ifThenElse kinda Co-authored-by: Kasey White --- add_integers.uplc | 2 +- crates/cli/src/main.rs | 15 ++++++++--- crates/uplc/src/ast.rs | 14 +++++++--- crates/uplc/src/machine.rs | 26 +++++++++++-------- crates/uplc/src/machine/cost_model.rs | 13 +++++++++- crates/uplc/src/machine/runtime.rs | 37 +++++++++++++++++++++++---- 6 files changed, 82 insertions(+), 25 deletions(-) diff --git a/add_integers.uplc b/add_integers.uplc index dfca93b9..2d2d3aa9 100644 --- a/add_integers.uplc +++ b/add_integers.uplc @@ -1,4 +1,4 @@ (program 1.0.0 - [ (force (builtin ifThenElse)) (con bool True) (con integer 1) (con string "yo") ] + [ (builtin ifThenElse) (con bool True) (con integer 1) (con string "yo") ] ) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 261871ad..2756d2bd 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -92,11 +92,20 @@ fn main() -> anyhow::Result<()> { Program::::try_from(prog)? }; - let term = program.eval()?; + let (term, cost, _logs) = program.eval(); - let term: Term = term.try_into()?; + match term { + Ok(term) => { + let term: Term = term.try_into()?; - println!("{}", term.to_pretty()); + println!("{}", term.to_pretty()); + } + Err(err) => { + eprintln!("{}", err); + } + } + + println!("Costs - memory: {} & cpu: {}", cost.mem, cost.cpu); } }, } diff --git a/crates/uplc/src/ast.rs b/crates/uplc/src/ast.rs index 48177a28..58c20adb 100644 --- a/crates/uplc/src/ast.rs +++ b/crates/uplc/src/ast.rs @@ -4,7 +4,7 @@ use crate::{ builtins::DefaultFunction, debruijn::{self, Converter}, machine::{ - cost_model::{ExBudget, CostModel}, + cost_model::{CostModel, ExBudget}, Machine, }, }; @@ -406,11 +406,17 @@ impl From> for Term { } impl Program { - pub fn eval(&self) -> Result, crate::machine::Error> { + pub fn eval( + &self, + ) -> ( + Result, crate::machine::Error>, + ExBudget, + Vec, + ) { let mut machine = Machine::new(CostModel::default(), ExBudget::default(), 200); - let (term, _, _) = machine.run(&self.term)?; + let term = machine.run(&self.term); - Ok(term) + (term, machine.ex_budget, machine.logs) } } diff --git a/crates/uplc/src/machine.rs b/crates/uplc/src/machine.rs index f8357310..20e6b908 100644 --- a/crates/uplc/src/machine.rs +++ b/crates/uplc/src/machine.rs @@ -14,11 +14,12 @@ use self::{cost_model::CostModel, runtime::BuiltinRuntime}; pub struct Machine { costs: CostModel, - ex_budget: ExBudget, + pub ex_budget: ExBudget, frames: Vec, slippage: u32, env: Vec, unbudgeted_steps: [u32; 8], + pub logs: Vec, } impl Machine { @@ -30,20 +31,16 @@ impl Machine { frames: vec![Context::NoFrame], env: vec![], unbudgeted_steps: [0; 8], + logs: vec![], } } - pub fn run( - &mut self, - term: &Term, - ) -> Result<(Term, usize, Vec), Error> { + pub fn run(&mut self, term: &Term) -> Result, Error> { let startup_budget = self.costs.machine_costs.get(StepKind::StartUp); self.spend_budget(startup_budget)?; - let res = self.compute(term)?; - - Ok((res, 0, vec![])) + self.compute(term) } fn compute(&mut self, term: &Term) -> Result, Error> { @@ -106,7 +103,7 @@ impl Machine { } fn return_compute(&mut self, value: Value) -> Result, Error> { - // TODO: avoid unwrap if possible and just return an err when None + // avoid unwrap if possible and just return an err when None // but honestly it should never be empty anyways because Machine // is initialized with `Context::NoFrame`. let frame = self.frames.last().cloned().unwrap(); @@ -197,7 +194,9 @@ impl Machine { match value { Value::Delay(body) => self.compute(&body), Value::Builtin { fun, term, runtime } => { - let force_term = Term::Force(Box::new(term)); + let force_term = Term::Force(Box::new(dbg!(term))); + + if runtime.is_all() {} println!("{:#?}", runtime); todo!() } @@ -342,9 +341,14 @@ impl Value { matches!(self, Value::Con(Constant::Integer(_))) } + pub fn is_bool(&self) -> bool { + matches!(self, Value::Con(Constant::Bool(_))) + } + pub fn to_ex_mem(&self) -> i64 { match self { - Value::Con(_) => todo!(), + // TODO: this is not 1 + Value::Con(_) => 1, Value::Delay(_) => 1, Value::Lambda { .. } => 1, Value::Builtin { .. } => 1, diff --git a/crates/uplc/src/machine/cost_model.rs b/crates/uplc/src/machine/cost_model.rs index 160a44aa..0fb59694 100644 --- a/crates/uplc/src/machine/cost_model.rs +++ b/crates/uplc/src/machine/cost_model.rs @@ -569,7 +569,18 @@ impl BuiltinCosts { DefaultFunction::EqualsString => todo!(), DefaultFunction::EncodeUtf8 => todo!(), DefaultFunction::DecodeUtf8 => todo!(), - DefaultFunction::IfThenElse => todo!(), + DefaultFunction::IfThenElse => ExBudget { + mem: self.if_then_else.mem.cost( + args[0].to_ex_mem(), + args[1].to_ex_mem(), + args[2].to_ex_mem(), + ), + cpu: self.if_then_else.cpu.cost( + args[0].to_ex_mem(), + args[1].to_ex_mem(), + args[2].to_ex_mem(), + ), + }, DefaultFunction::ChooseUnit => todo!(), DefaultFunction::Trace => todo!(), DefaultFunction::FstPair => todo!(), diff --git a/crates/uplc/src/machine/runtime.rs b/crates/uplc/src/machine/runtime.rs index 464585d7..93b70628 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -48,12 +48,16 @@ impl BuiltinRuntime { self.args.len() == self.fun.arity() } + pub fn is_all(&self) -> bool { + self.args.is_empty() + } + pub fn call(&self) -> Result { self.fun.call(&self.args) } pub fn push(&mut self, arg: Value) -> Result<(), Error> { - self.fun.check_type(&arg)?; + self.fun.check_type(&arg, &self.args)?; self.args.push(arg); @@ -102,7 +106,7 @@ impl DefaultFunction { DefaultFunction::EqualsString => todo!(), DefaultFunction::EncodeUtf8 => todo!(), DefaultFunction::DecodeUtf8 => todo!(), - DefaultFunction::IfThenElse => todo!(), + DefaultFunction::IfThenElse => 3, DefaultFunction::ChooseUnit => todo!(), DefaultFunction::Trace => todo!(), DefaultFunction::FstPair => todo!(), @@ -131,7 +135,11 @@ impl DefaultFunction { } } - pub fn check_type(&self, arg: &Value) -> Result<(), Error> { + pub fn force_count() -> i32 { + 3 + } + + pub fn check_type(&self, arg: &Value, args: &[Value]) -> Result<(), Error> { match self { DefaultFunction::AddInteger => { if arg.is_integer() { @@ -167,7 +175,17 @@ impl DefaultFunction { DefaultFunction::EqualsString => todo!(), DefaultFunction::EncodeUtf8 => todo!(), DefaultFunction::DecodeUtf8 => todo!(), - DefaultFunction::IfThenElse => todo!(), + DefaultFunction::IfThenElse => { + if args.is_empty() { + if arg.is_bool() { + return Ok(()); + } else { + todo!("type error") + } + } + + Ok(()) + } DefaultFunction::ChooseUnit => todo!(), DefaultFunction::Trace => todo!(), DefaultFunction::FstPair => todo!(), @@ -237,7 +255,16 @@ impl DefaultFunction { DefaultFunction::EqualsString => todo!(), DefaultFunction::EncodeUtf8 => todo!(), DefaultFunction::DecodeUtf8 => todo!(), - DefaultFunction::IfThenElse => todo!(), + DefaultFunction::IfThenElse => match args[0] { + Value::Con(Constant::Bool(condition)) => { + if condition { + Ok(args[1].clone()) + } else { + Ok(args[2].clone()) + } + } + _ => todo!("handle error"), + }, DefaultFunction::ChooseUnit => todo!(), DefaultFunction::Trace => todo!(), DefaultFunction::FstPair => todo!(),