Skip to content

Commit

Permalink
Implemented support for class methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
jens-siebert committed Feb 4, 2024
1 parent 9719bc8 commit 8dbe59f
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 11 deletions.
11 changes: 9 additions & 2 deletions rlox-lib/src/base/expr_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,16 @@ impl Callable for LoxFunction {
#[derive(Clone, Debug, PartialEq)]
pub struct LoxClass {
name: Token,
methods: HashMap<String, LoxFunction>,
}

impl LoxClass {
pub fn new(name: Token) -> Self {
Self { name }
pub fn new(name: Token, methods: HashMap<String, LoxFunction>) -> Self {
Self { name, methods }
}

pub fn find_method(&self, name: &Token) -> Option<&LoxFunction> {
self.methods.get(&name.lexeme)
}
}

Expand Down Expand Up @@ -175,6 +180,8 @@ impl LoxInstance {
pub fn get(&self, name: &Token) -> Result<ExprResult, RuntimeError> {
if let Some(value) = self.fields.borrow().get(&name.lexeme) {
Ok(value.to_owned())
} else if let Some(method) = self.class.find_method(name) {
Ok(ExprResult::function(method.to_owned()))
} else {
Err(RuntimeError::UndefinedProperty { line: name.line })
}
Expand Down
21 changes: 16 additions & 5 deletions rlox-lib/src/interpreter/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,15 +312,26 @@ impl Visitor<Stmt, (), RuntimeError> for Interpreter<'_> {
self.fork(Environment::new_enclosing(Rc::clone(&self.environment)));
scoped_interpreter.execute_block(statements)?;
}
Stmt::Class {
name,
methods: _methods,
} => {
Stmt::Class { name, methods } => {
self.environment
.borrow_mut()
.define(name, ExprResult::none());

let class = LoxClass::new(*name.to_owned());
let mut functions = HashMap::new();
for method in methods {
if let Stmt::Function { name, params, body } = method {
let function = LoxFunction::new(
*name.to_owned(),
params.to_owned(),
body.to_owned(),
Rc::clone(&self.environment),
);

functions.insert(name.lexeme.to_owned(), function);
}
}

let class = LoxClass::new(*name.to_owned(), functions);

self.environment
.borrow_mut()
Expand Down
10 changes: 6 additions & 4 deletions rlox-lib/src/interpreter/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::rc::Rc;
enum FunctionType {
None,
Function,
Method,
}

pub struct Resolver<'a> {
Expand Down Expand Up @@ -126,12 +127,13 @@ impl Visitor<Stmt, (), RuntimeError> for Resolver<'_> {
self.resolve_stmts(statements)?;
self.end_scope()
}
Stmt::Class {
name,
methods: _methods,
} => {
Stmt::Class { name, methods } => {
self.declare(name)?;
self.define(name);

for method in methods {
self.resolve_function(method, FunctionType::Method)?;
}
}
Stmt::Expression { expression } => {
self.resolve_expr(expression)?;
Expand Down
23 changes: 23 additions & 0 deletions rlox-lib/tests/class_methods.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
mod common;

const INPUT: &str = r###"
class Bacon {
eat() {
print "Crunch crunch crunch!";
}
}
Bacon().eat();
"###;

const RESULT: &str = r###"
Crunch crunch crunch!
"###;

#[test]
fn test_class_declaration() {
assert_eq!(
common::interpret(INPUT).unwrap(),
RESULT.strip_prefix('\n').unwrap()
)
}

0 comments on commit 8dbe59f

Please sign in to comment.