From 650a7891944c0ea753029818371b6ca1b42f934e Mon Sep 17 00:00:00 2001 From: rvcas Date: Wed, 6 Jul 2022 22:33:00 -0400 Subject: [PATCH] chore: step and maybe spend Co-authored-by: Kasey White --- crates/uplc/src/machine.rs | 137 ++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 63 deletions(-) diff --git a/crates/uplc/src/machine.rs b/crates/uplc/src/machine.rs index eabcda15..bc26a441 100644 --- a/crates/uplc/src/machine.rs +++ b/crates/uplc/src/machine.rs @@ -22,7 +22,7 @@ impl Machine { costs, ex_budget: initial_budget, slippage, - frames: vec![], + frames: vec![Context::NoFrame], env: vec![], unbudgeted_steps: vec![0; 8], } @@ -36,70 +36,54 @@ impl Machine { self.spend_budget(startup_budget)?; - self.push_frame(Context::NoFrame); + let res = self.compute(term)?; - self.enter_compute(term)?; - todo!() + Ok((res, 0, vec![])) } - fn enter_compute(&mut self, term: &Term) -> Result, Error> { + fn compute(&mut self, term: &Term) -> Result, Error> { match term { Term::Var(name) => { - self.unbudgeted_steps[1] += 1; - self.unbudgeted_steps[7] += 1; - if self.unbudgeted_steps[7] >= self.slippage { - self.spend_unbudgeted_steps()?; - } + self.step_and_maybe_spend(StepKind::Var)?; + let val = self.lookup_var(name.clone())?; + self.return_compute(val) } Term::Delay(body) => { - self.unbudgeted_steps[4] += 1; - self.unbudgeted_steps[7] += 1; - if self.unbudgeted_steps[7] >= self.slippage { - self.spend_unbudgeted_steps()?; - } + self.step_and_maybe_spend(StepKind::Delay)?; + self.return_compute(Value::Delay(*body.clone())) } Term::Lambda { parameter_name, body, } => { - self.unbudgeted_steps[2] += 1; - self.unbudgeted_steps[7] += 1; - if self.unbudgeted_steps[7] >= self.slippage { - self.spend_unbudgeted_steps()?; - } + self.step_and_maybe_spend(StepKind::Lambda)?; + self.return_compute(Value::Lambda { parameter_name: parameter_name.clone(), body: *body.clone(), }) } Term::Apply { function, argument } => { - self.unbudgeted_steps[3] += 1; - self.unbudgeted_steps[7] += 1; - if self.unbudgeted_steps[7] >= self.slippage { - self.spend_unbudgeted_steps()?; - } + self.step_and_maybe_spend(StepKind::Apply)?; + self.push_frame(Context::FrameApplyArg(*argument.clone())); - self.enter_compute(function) + + self.compute(function) } Term::Constant(x) => { - self.unbudgeted_steps[0] += 1; - self.unbudgeted_steps[7] += 1; - if self.unbudgeted_steps[7] >= self.slippage { - self.spend_unbudgeted_steps()?; - } + self.step_and_maybe_spend(StepKind::Constant)?; + self.return_compute(Value::Con(x.clone())) } Term::Force(body) => { - self.unbudgeted_steps[5] += 1; - self.unbudgeted_steps[7] += 1; - if self.unbudgeted_steps[7] >= self.slippage { - self.spend_unbudgeted_steps()?; - } + self.step_and_maybe_spend(StepKind::Force)?; + self.push_frame(Context::FrameForce); - self.enter_compute(body) + + self.compute(body) } Term::Error => Err(Error::EvaluationFailure), Term::Builtin(_) => todo!(), @@ -107,19 +91,27 @@ impl Machine { } fn return_compute(&mut self, value: Value) -> Result, Error> { + // TODO: avoid unwrap and possible 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(); + match frame { Context::FrameApplyFun(function) => { self.pop_frame(); + self.apply_evaluate(function, value) } Context::FrameApplyArg(arg) => { self.pop_frame(); + self.push_frame(Context::FrameApplyFun(value)); - self.enter_compute(&arg) + + self.compute(&arg) } Context::FrameForce => { self.pop_frame(); + self.force_evaluate(value) } Context::NoFrame => { @@ -128,6 +120,7 @@ impl Machine { } let term = self.discharge_value(value); + Ok(term) } } @@ -154,7 +147,7 @@ impl Machine { fn discharge_value_env(&mut self, term: Term) -> Term { fn rec(i: u32, t: Term) -> Term { match t { - Term::Var(x) => todo!(), + Term::Var(_x) => todo!(), Term::Lambda { parameter_name, body, @@ -177,7 +170,7 @@ impl Machine { fn force_evaluate(&mut self, value: Value) -> Result, Error> { match value { - Value::Delay(body) => self.enter_compute(&body), + Value::Delay(body) => self.compute(&body), Value::Builtin(_, _) => todo!(), rest => Err(Error::NonPolymorphicInstantiation(rest)), } @@ -185,23 +178,12 @@ impl Machine { fn apply_evaluate( &mut self, - function: Value, - argument: Value, + _function: Value, + _argument: Value, ) -> Result, Error> { todo!() } - fn spend_budget(&mut self, spend_budget: ExBudget) -> Result<(), Error> { - self.ex_budget.mem -= spend_budget.mem; - self.ex_budget.cpu -= spend_budget.cpu; - - if self.ex_budget.mem < 0 || self.ex_budget.cpu < 0 { - Err(Error::OutOfExError(self.ex_budget)) - } else { - Ok(()) - } - } - fn push_frame(&mut self, frame: Context) { self.frames.push(frame); } @@ -217,15 +199,42 @@ impl Machine { .ok_or(Error::OpenTermEvaluated(Term::Var(name))) } + fn step_and_maybe_spend(&mut self, step: StepKind) -> Result<(), Error> { + let index = step as u8; + self.unbudgeted_steps[index as usize] += 1; + self.unbudgeted_steps[7] += 1; + + if self.unbudgeted_steps[7] >= self.slippage { + self.spend_unbudgeted_steps()?; + } + + Ok(()) + } + fn spend_unbudgeted_steps(&mut self) -> Result<(), Error> { for i in 0..self.unbudgeted_steps.len() - 1 { let mut unspent_step_budget = self.costs.get(StepKind::try_from(i as u8)?); - unspent_step_budget.occurence(self.unbudgeted_steps[i] as i32); + + unspent_step_budget.occurences(self.unbudgeted_steps[i] as i32); + self.spend_budget(unspent_step_budget)?; } + self.unbudgeted_steps = vec![0; 8]; + Ok(()) } + + fn spend_budget(&mut self, spend_budget: ExBudget) -> Result<(), Error> { + self.ex_budget.mem -= spend_budget.mem; + self.ex_budget.cpu -= spend_budget.cpu; + + if self.ex_budget.mem < 0 || self.ex_budget.cpu < 0 { + Err(Error::OutOfExError(self.ex_budget)) + } else { + Ok(()) + } + } } #[derive(Clone)] @@ -260,21 +269,23 @@ pub struct ExBudget { } impl ExBudget { - pub fn occurence(&mut self, n: i32) { + pub fn occurences(&mut self, n: i32) { self.mem *= n; self.cpu *= n; } } +#[repr(u8)] pub enum StepKind { - Constant, - Var, - Lambda, - Apply, - Delay, - Force, - Builtin, - StartUp, + Constant = 0, + Var = 1, + Lambda = 2, + Apply = 3, + Delay = 4, + Force = 5, + Builtin = 6, + // DO NOT USE THIS IN `step_and_maybe_spend` + StartUp = 7, } impl TryFrom for StepKind {