chore: step and maybe spend

Co-authored-by: Kasey White <kwhitemsg@gmail.com>
This commit is contained in:
rvcas 2022-07-06 22:33:00 -04:00 committed by Kasey White
parent 0bf93e59b5
commit 650a789194
1 changed files with 74 additions and 63 deletions

View File

@ -22,7 +22,7 @@ impl Machine {
costs, costs,
ex_budget: initial_budget, ex_budget: initial_budget,
slippage, slippage,
frames: vec![], frames: vec![Context::NoFrame],
env: vec![], env: vec![],
unbudgeted_steps: vec![0; 8], unbudgeted_steps: vec![0; 8],
} }
@ -36,70 +36,54 @@ impl Machine {
self.spend_budget(startup_budget)?; self.spend_budget(startup_budget)?;
self.push_frame(Context::NoFrame); let res = self.compute(term)?;
self.enter_compute(term)?; Ok((res, 0, vec![]))
todo!()
} }
fn enter_compute(&mut self, term: &Term<NamedDeBruijn>) -> Result<Term<NamedDeBruijn>, Error> { fn compute(&mut self, term: &Term<NamedDeBruijn>) -> Result<Term<NamedDeBruijn>, Error> {
match term { match term {
Term::Var(name) => { Term::Var(name) => {
self.unbudgeted_steps[1] += 1; self.step_and_maybe_spend(StepKind::Var)?;
self.unbudgeted_steps[7] += 1;
if self.unbudgeted_steps[7] >= self.slippage {
self.spend_unbudgeted_steps()?;
}
let val = self.lookup_var(name.clone())?; let val = self.lookup_var(name.clone())?;
self.return_compute(val) self.return_compute(val)
} }
Term::Delay(body) => { Term::Delay(body) => {
self.unbudgeted_steps[4] += 1; self.step_and_maybe_spend(StepKind::Delay)?;
self.unbudgeted_steps[7] += 1;
if self.unbudgeted_steps[7] >= self.slippage {
self.spend_unbudgeted_steps()?;
}
self.return_compute(Value::Delay(*body.clone())) self.return_compute(Value::Delay(*body.clone()))
} }
Term::Lambda { Term::Lambda {
parameter_name, parameter_name,
body, body,
} => { } => {
self.unbudgeted_steps[2] += 1; self.step_and_maybe_spend(StepKind::Lambda)?;
self.unbudgeted_steps[7] += 1;
if self.unbudgeted_steps[7] >= self.slippage {
self.spend_unbudgeted_steps()?;
}
self.return_compute(Value::Lambda { self.return_compute(Value::Lambda {
parameter_name: parameter_name.clone(), parameter_name: parameter_name.clone(),
body: *body.clone(), body: *body.clone(),
}) })
} }
Term::Apply { function, argument } => { Term::Apply { function, argument } => {
self.unbudgeted_steps[3] += 1; self.step_and_maybe_spend(StepKind::Apply)?;
self.unbudgeted_steps[7] += 1;
if self.unbudgeted_steps[7] >= self.slippage {
self.spend_unbudgeted_steps()?;
}
self.push_frame(Context::FrameApplyArg(*argument.clone())); self.push_frame(Context::FrameApplyArg(*argument.clone()));
self.enter_compute(function)
self.compute(function)
} }
Term::Constant(x) => { Term::Constant(x) => {
self.unbudgeted_steps[0] += 1; self.step_and_maybe_spend(StepKind::Constant)?;
self.unbudgeted_steps[7] += 1;
if self.unbudgeted_steps[7] >= self.slippage {
self.spend_unbudgeted_steps()?;
}
self.return_compute(Value::Con(x.clone())) self.return_compute(Value::Con(x.clone()))
} }
Term::Force(body) => { Term::Force(body) => {
self.unbudgeted_steps[5] += 1; self.step_and_maybe_spend(StepKind::Force)?;
self.unbudgeted_steps[7] += 1;
if self.unbudgeted_steps[7] >= self.slippage {
self.spend_unbudgeted_steps()?;
}
self.push_frame(Context::FrameForce); self.push_frame(Context::FrameForce);
self.enter_compute(body)
self.compute(body)
} }
Term::Error => Err(Error::EvaluationFailure), Term::Error => Err(Error::EvaluationFailure),
Term::Builtin(_) => todo!(), Term::Builtin(_) => todo!(),
@ -107,19 +91,27 @@ impl Machine {
} }
fn return_compute(&mut self, value: Value) -> Result<Term<NamedDeBruijn>, Error> { fn return_compute(&mut self, value: Value) -> Result<Term<NamedDeBruijn>, 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(); let frame = self.frames.last().cloned().unwrap();
match frame { match frame {
Context::FrameApplyFun(function) => { Context::FrameApplyFun(function) => {
self.pop_frame(); self.pop_frame();
self.apply_evaluate(function, value) self.apply_evaluate(function, value)
} }
Context::FrameApplyArg(arg) => { Context::FrameApplyArg(arg) => {
self.pop_frame(); self.pop_frame();
self.push_frame(Context::FrameApplyFun(value)); self.push_frame(Context::FrameApplyFun(value));
self.enter_compute(&arg)
self.compute(&arg)
} }
Context::FrameForce => { Context::FrameForce => {
self.pop_frame(); self.pop_frame();
self.force_evaluate(value) self.force_evaluate(value)
} }
Context::NoFrame => { Context::NoFrame => {
@ -128,6 +120,7 @@ impl Machine {
} }
let term = self.discharge_value(value); let term = self.discharge_value(value);
Ok(term) Ok(term)
} }
} }
@ -154,7 +147,7 @@ impl Machine {
fn discharge_value_env(&mut self, term: Term<NamedDeBruijn>) -> Term<NamedDeBruijn> { fn discharge_value_env(&mut self, term: Term<NamedDeBruijn>) -> Term<NamedDeBruijn> {
fn rec(i: u32, t: Term<NamedDeBruijn>) -> Term<NamedDeBruijn> { fn rec(i: u32, t: Term<NamedDeBruijn>) -> Term<NamedDeBruijn> {
match t { match t {
Term::Var(x) => todo!(), Term::Var(_x) => todo!(),
Term::Lambda { Term::Lambda {
parameter_name, parameter_name,
body, body,
@ -177,7 +170,7 @@ impl Machine {
fn force_evaluate(&mut self, value: Value) -> Result<Term<NamedDeBruijn>, Error> { fn force_evaluate(&mut self, value: Value) -> Result<Term<NamedDeBruijn>, Error> {
match value { match value {
Value::Delay(body) => self.enter_compute(&body), Value::Delay(body) => self.compute(&body),
Value::Builtin(_, _) => todo!(), Value::Builtin(_, _) => todo!(),
rest => Err(Error::NonPolymorphicInstantiation(rest)), rest => Err(Error::NonPolymorphicInstantiation(rest)),
} }
@ -185,23 +178,12 @@ impl Machine {
fn apply_evaluate( fn apply_evaluate(
&mut self, &mut self,
function: Value, _function: Value,
argument: Value, _argument: Value,
) -> Result<Term<NamedDeBruijn>, Error> { ) -> Result<Term<NamedDeBruijn>, Error> {
todo!() 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) { fn push_frame(&mut self, frame: Context) {
self.frames.push(frame); self.frames.push(frame);
} }
@ -217,15 +199,42 @@ impl Machine {
.ok_or(Error::OpenTermEvaluated(Term::Var(name))) .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> { fn spend_unbudgeted_steps(&mut self) -> Result<(), Error> {
for i in 0..self.unbudgeted_steps.len() - 1 { for i in 0..self.unbudgeted_steps.len() - 1 {
let mut unspent_step_budget = self.costs.get(StepKind::try_from(i as u8)?); 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.spend_budget(unspent_step_budget)?;
} }
self.unbudgeted_steps = vec![0; 8]; self.unbudgeted_steps = vec![0; 8];
Ok(()) 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)] #[derive(Clone)]
@ -260,21 +269,23 @@ pub struct ExBudget {
} }
impl ExBudget { impl ExBudget {
pub fn occurence(&mut self, n: i32) { pub fn occurences(&mut self, n: i32) {
self.mem *= n; self.mem *= n;
self.cpu *= n; self.cpu *= n;
} }
} }
#[repr(u8)]
pub enum StepKind { pub enum StepKind {
Constant, Constant = 0,
Var, Var = 1,
Lambda, Lambda = 2,
Apply, Apply = 3,
Delay, Delay = 4,
Force, Force = 5,
Builtin, Builtin = 6,
StartUp, // DO NOT USE THIS IN `step_and_maybe_spend`
StartUp = 7,
} }
impl TryFrom<u8> for StepKind { impl TryFrom<u8> for StepKind {