implement chapter 12 in rust
This commit is contained in:
parent
283155c38b
commit
621c97102a
10 changed files with 366 additions and 17 deletions
|
@ -6,9 +6,10 @@ use tracing::error;
|
|||
|
||||
use crate::{
|
||||
callable::CallingError,
|
||||
class::Class,
|
||||
environment::{Environment, EnvironmentError},
|
||||
expression::Expression,
|
||||
function::Function,
|
||||
function::{self, Function},
|
||||
native_functions,
|
||||
statement::Statement,
|
||||
token::{Literal, Token, TokenType},
|
||||
|
@ -33,6 +34,10 @@ pub enum InterpreterError {
|
|||
NotACallable(usize, Value),
|
||||
#[error("line {0}: {1}.")]
|
||||
FailedToCall(usize, CallingError),
|
||||
#[error("line {0}: only instances have fields.")]
|
||||
OnlyInstancesHaveFields(usize),
|
||||
#[error("{0}")]
|
||||
InstanceError(#[from] crate::instance::InstanceError),
|
||||
}
|
||||
|
||||
/// Interpreter for the Lox language.
|
||||
|
@ -106,6 +111,7 @@ impl Interpreter {
|
|||
self.function_statement(name, params, body)
|
||||
}
|
||||
Statement::Return { keyword: _, value } => self.return_statement(value),
|
||||
Statement::Class { name, methods } => self.class(name, methods),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,6 +144,39 @@ impl Interpreter {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
fn class(
|
||||
&mut self,
|
||||
name: &Token,
|
||||
methods: &[Statement],
|
||||
) -> Result<Option<Value>, InterpreterError> {
|
||||
self.environment
|
||||
.borrow_mut()
|
||||
.define(name.lexeme.clone(), Value::Nil);
|
||||
|
||||
let mut class_methods: HashMap<String, Function> = HashMap::new();
|
||||
|
||||
for method in methods {
|
||||
if let Statement::Function { name, params, body } = method {
|
||||
let function = function::Function {
|
||||
name: name.clone(),
|
||||
is_initializer: name.lexeme == "init",
|
||||
params: params.clone(),
|
||||
body: body.clone(),
|
||||
closure: self.environment.clone(),
|
||||
};
|
||||
class_methods.insert(name.lexeme.clone(), function);
|
||||
}
|
||||
}
|
||||
|
||||
let class = Class::new(name.lexeme.clone(), class_methods);
|
||||
self.environment
|
||||
.borrow_mut()
|
||||
.assign(name, Value::Callable(Rc::new(class)))
|
||||
.map_err(InterpreterError::UndefinedVariable)?;
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Evaluate an expression and return its value.
|
||||
fn evaluate(&mut self, expression: &Expression) -> Result<Value, InterpreterError> {
|
||||
match expression {
|
||||
|
@ -164,6 +203,13 @@ impl Interpreter {
|
|||
paren,
|
||||
args,
|
||||
} => self.call(callee, paren, args),
|
||||
Expression::Get { object, name } => self.get(object, name),
|
||||
Expression::Set {
|
||||
object,
|
||||
name,
|
||||
value,
|
||||
} => self.set(object, name, value),
|
||||
Expression::This { keyword } => self.lookup_var(keyword, expression),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,6 +236,29 @@ impl Interpreter {
|
|||
}
|
||||
}
|
||||
|
||||
fn get(&mut self, object: &Expression, name: &Token) -> Result<Value, InterpreterError> {
|
||||
match self.evaluate(object)? {
|
||||
Value::Instance(instance) => Ok(instance.borrow().get(name, instance.clone())?),
|
||||
_ => Err(InterpreterError::OnlyInstancesHaveFields(name.line)),
|
||||
}
|
||||
}
|
||||
fn set(
|
||||
&mut self,
|
||||
object: &Expression,
|
||||
name: &Token,
|
||||
value: &Expression,
|
||||
) -> Result<Value, InterpreterError> {
|
||||
match self.evaluate(object)? {
|
||||
Value::Instance(instance) => {
|
||||
let value = self.evaluate(value)?;
|
||||
instance.borrow_mut().set(name, value.clone());
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
_ => Err(InterpreterError::OnlyInstancesHaveFields(name.line)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Define a new function.
|
||||
fn function_statement(
|
||||
&mut self,
|
||||
|
@ -200,6 +269,7 @@ impl Interpreter {
|
|||
let fn_name = name.lexeme.clone();
|
||||
let fun = Function {
|
||||
name: name.clone(),
|
||||
is_initializer: false,
|
||||
params: params.to_vec(),
|
||||
body: body.to_vec(),
|
||||
closure: self.environment.clone(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue