Improve name & documentation accuracy

Renamed ControlFlow -> HaltStatus because that's what the enum really
is -- a status on why something halted. Also reviewed `interpret.rs`'s
documentation and fixed a few things that were out of date.
This commit is contained in:
Alex Bethel 2021-05-25 21:55:02 -05:00
parent ec81ead3ea
commit c906366e3f

View file

@ -24,8 +24,8 @@ pub struct ExecEnv {
stack: Vec<Scope>, stack: Vec<Scope>,
} }
/// A set of visible variable and function definitions, which serves /// A set of visible variable and function definitions in a single
/// as a context in which expressions can be evaluated. /// stack frame.
#[derive(Default)] #[derive(Default)]
struct Scope { struct Scope {
/// The mapping from variable names to values. /// The mapping from variable names to values.
@ -34,15 +34,17 @@ struct Scope {
// other information. // other information.
} }
/// The result of successfully executing a set of statements. /// The reason a successful series of statements halted.
enum ControlFlow { enum HaltStatus {
/// The statements evaluated to this value. /// The last statement in the list evaluated to this value.
Value(Value), Value(Value),
/// A "break" statement occurred at the top level. /// A `break` statement occurred and was not caught by a `loop`
/// statement.
Break, Break,
/// A "hopback" statement occurred at the top level. /// A `hopback` statement occurred and was not caught by a `loop`
/// statement.
Hopback, Hopback,
} }
@ -57,11 +59,12 @@ impl ExecEnv {
/// Evaluate a set of Items in their own stack frame. Return the /// Evaluate a set of Items in their own stack frame. Return the
/// value of the last Item evaluated, or an error if one or more /// value of the last Item evaluated, or an error if one or more
/// of the Items failed to evaluate. /// of the Items failed to evaluate or if a `break` or `hopback`
/// statement occurred at the top level.
pub fn eval_items(&mut self, items: &[Item]) -> Result<Value, Error> { pub fn eval_items(&mut self, items: &[Item]) -> Result<Value, Error> {
match self.eval_items_cf(items)? { match self.eval_items_hs(items)? {
ControlFlow::Value(v) => Ok(v), HaltStatus::Value(v) => Ok(v),
ControlFlow::Break | ControlFlow::Hopback => Err(Error { HaltStatus::Break | HaltStatus::Hopback => Err(Error {
// It's an error to issue a `break` outside of a // It's an error to issue a `break` outside of a
// `loop` statement. // `loop` statement.
kind: ErrorKind::TopLevelBreak, kind: ErrorKind::TopLevelBreak,
@ -70,16 +73,19 @@ impl ExecEnv {
} }
} }
/// The same as `eval_items`, but reports "break" and "hopback" /// The same as `eval_items`, but report "break" and "hopback"
/// exit codes as normal conditions in a ControlFlow enum. /// exit codes as normal conditions in a HaltStatus enum.
fn eval_items_cf(&mut self, items: &[Item]) -> Result<ControlFlow, Error> { ///
/// `interpret`-internal code should typically prefer this
/// function over `eval_items`.
fn eval_items_hs(&mut self, items: &[Item]) -> Result<HaltStatus, Error> {
let init_depth = self.stack.len(); let init_depth = self.stack.len();
self.stack.push(Default::default()); self.stack.push(Default::default());
let mut final_result = Ok(ControlFlow::Value(Value::Nul)); let mut final_result = Ok(HaltStatus::Value(Value::Nul));
for item in items { for item in items {
final_result = self.eval_item(item); final_result = self.eval_item(item);
if !matches!(final_result, Ok(ControlFlow::Value(_))) { if !matches!(final_result, Ok(HaltStatus::Value(_))) {
break; break;
} }
} }
@ -91,9 +97,9 @@ impl ExecEnv {
} }
/// Evaluate a single Item, returning its value or an error. /// Evaluate a single Item, returning its value or an error.
fn eval_item(&mut self, item: &Item) -> Result<ControlFlow, Error> { fn eval_item(&mut self, item: &Item) -> Result<HaltStatus, Error> {
match item { match item {
Item::Expr(expr) => self.eval_expr(expr).map(|v| ControlFlow::Value(v)), Item::Expr(expr) => self.eval_expr(expr).map(|v| HaltStatus::Value(v)),
Item::Stmt(stmt) => self.eval_stmt(stmt), Item::Stmt(stmt) => self.eval_stmt(stmt),
} }
} }
@ -139,7 +145,7 @@ impl ExecEnv {
} }
/// Perform the action indicated by a statement. /// Perform the action indicated by a statement.
fn eval_stmt(&mut self, stmt: &Stmt) -> Result<ControlFlow, Error> { fn eval_stmt(&mut self, stmt: &Stmt) -> Result<HaltStatus, Error> {
match stmt { match stmt {
Stmt::Print(expr) => { Stmt::Print(expr) => {
println!("{}", self.eval_expr(expr)?); println!("{}", self.eval_expr(expr)?);
@ -169,33 +175,33 @@ impl ExecEnv {
Stmt::BfFDeclaration { iden: _, body: _ } => todo!(), Stmt::BfFDeclaration { iden: _, body: _ } => todo!(),
Stmt::If { cond, body } => { Stmt::If { cond, body } => {
if self.eval_expr(cond)?.into() { if self.eval_expr(cond)?.into() {
return self.eval_items_cf(body); return self.eval_items_hs(body);
} }
} }
Stmt::FunctionCall { iden: _, args: _ } => todo!(), Stmt::FunctionCall { iden: _, args: _ } => todo!(),
Stmt::Loop { body } => loop { Stmt::Loop { body } => loop {
let res = self.eval_items_cf(body)?; let res = self.eval_items_hs(body)?;
match res { match res {
ControlFlow::Value(_) => {} HaltStatus::Value(_) => {}
ControlFlow::Break => break, HaltStatus::Break => break,
ControlFlow::Hopback => continue, HaltStatus::Hopback => continue,
} }
}, },
Stmt::VarAssignment { iden, value } => { Stmt::VarAssignment { iden, value } => {
self.get_var_mut(&iden.0)?.value = self.eval_expr(value)?; self.get_var_mut(&iden.0)?.value = self.eval_expr(value)?;
} }
Stmt::Break => { Stmt::Break => {
return Ok(ControlFlow::Break); return Ok(HaltStatus::Break);
} }
Stmt::HopBack => { Stmt::HopBack => {
return Ok(ControlFlow::Hopback); return Ok(HaltStatus::Hopback);
} }
Stmt::Melo(iden) => { Stmt::Melo(iden) => {
self.get_var_mut(&iden.0)?.melo = true; self.get_var_mut(&iden.0)?.melo = true;
} }
} }
Ok(ControlFlow::Value(Value::Nul)) Ok(HaltStatus::Value(Value::Nul))
} }
/// Get a shared reference to the value of a variable. Throw an /// Get a shared reference to the value of a variable. Throw an
@ -229,7 +235,8 @@ impl ExecEnv {
/// Get a mutable reference to a variable. Throw an error if the /// Get a mutable reference to a variable. Throw an error if the
/// variable is inaccessible or banned. /// variable is inaccessible or banned.
fn get_var_mut(&mut self, name: &str) -> Result<&mut Variable, Error> { fn get_var_mut(&mut self, name: &str) -> Result<&mut Variable, Error> {
// FIXME: This function is almost exactly the same as get_var. // This function is almost exactly 22 lines of duplicated code
// from get_var, which I feel like is a bad sign...
match self match self
.stack .stack
.iter_mut() .iter_mut()