chore: step and maybe spend
Co-authored-by: Kasey White <kwhitemsg@gmail.com>
This commit is contained in:
parent
0bf93e59b5
commit
650a789194
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue