implement chapter 11 in rust
This commit is contained in:
parent
8860a1c639
commit
a25b6d1e92
16 changed files with 470 additions and 32 deletions
|
@ -8,6 +8,8 @@ use crate::{token::Token, value::Value};
|
|||
pub enum EnvironmentError {
|
||||
#[error("line {0}: undefined variable: {1}")]
|
||||
UndefinedVariable(usize, String),
|
||||
#[error("invalid environment distance")]
|
||||
InvalidDistance,
|
||||
}
|
||||
|
||||
/// Environment mapping variable names to their respective values. Can have an optional enclosing
|
||||
|
@ -50,6 +52,18 @@ impl Environment {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn assign_at(
|
||||
&mut self,
|
||||
distance: usize,
|
||||
token: &Token,
|
||||
value: Value,
|
||||
) -> Result<(), EnvironmentError> {
|
||||
self.ancestor(distance)?
|
||||
.values
|
||||
.insert(token.lexeme.clone(), value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the value of an existing (defined) variable. Error if there is no such variable in
|
||||
/// this environment or any of the enclosing ones.
|
||||
pub fn get(&self, token: &Token) -> Result<Value, EnvironmentError> {
|
||||
|
@ -64,4 +78,29 @@ impl Environment {
|
|||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_at(&self, distance: usize, token: &Token) -> Result<Value, EnvironmentError> {
|
||||
if let Some(v) = self.ancestor(distance)?.values.get(token.lexeme.as_str()) {
|
||||
Ok(v.clone())
|
||||
} else {
|
||||
Err(EnvironmentError::UndefinedVariable(
|
||||
token.line,
|
||||
token.lexeme.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn ancestor(&self, distance: usize) -> Result<Environment, EnvironmentError> {
|
||||
let mut environment = self.clone();
|
||||
|
||||
for _ in 0..distance {
|
||||
let enclosing = match &environment.enclosing {
|
||||
Some(enc) => enc.borrow().clone(),
|
||||
None => return Err(EnvironmentError::InvalidDistance),
|
||||
};
|
||||
environment = enclosing;
|
||||
}
|
||||
|
||||
Ok(environment)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue