-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This implements [chapter 12](http://craftinginterpreters.com/classes.html) to support classes. In this implementation classes do not just extend `LoxFunction`. That's why the call logic is duplicated. Mutable state such as the environments and class instances are passed around in an `Object` that holds an `Rc<RefCell<...>>` to the actual state. It is not easy to track but it works. When an `Object` is cloned the reference is cloned. This mirrors somewhat how the Java implementation works but is not really "rusty". There are a lot of clone calls but it should not cost too much overhead since we mostly clone references and vectors.
- Loading branch information
Showing
11 changed files
with
425 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
class DevonshireCream { | ||
serveOn() { | ||
return "Scones"; | ||
} | ||
} | ||
|
||
print DevonshireCream; | ||
|
||
class Bagel { | ||
init() { | ||
this.topping = "cream"; | ||
} | ||
} | ||
var bagel = Bagel(); | ||
print bagel; | ||
print "Topping: " + bagel.topping; | ||
|
||
bagel.topping = "whipped cream"; | ||
print "Topping: " + bagel.topping; | ||
|
||
class Bacon { | ||
eat() { | ||
print "Crunch crunch crunch!"; | ||
} | ||
} | ||
|
||
Bacon().eat(); | ||
|
||
class Cake { | ||
taste() { | ||
var adjective = "delicious"; | ||
print "The " + this.flavor + " cake is " + adjective + "!"; | ||
} | ||
} | ||
|
||
var cake = Cake(); | ||
cake.flavor = "German chocolate"; | ||
cake.taste(); | ||
|
||
class Thing { | ||
getCallback() { | ||
fun localFunction() { | ||
print this; | ||
} | ||
|
||
return localFunction; | ||
} | ||
} | ||
|
||
var callback = Thing().getCallback(); | ||
callback(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
use crate::error::Error; | ||
use crate::function::Function; | ||
use crate::object::Object; | ||
use crate::token::Token; | ||
|
||
use std::cell::RefCell; | ||
use std::collections::HashMap; | ||
use std::rc::Rc; | ||
|
||
#[derive(Debug)] | ||
pub struct LoxClass { | ||
pub name: String, | ||
pub methods: HashMap<String, Function>, | ||
} | ||
|
||
impl LoxClass { | ||
pub fn find_method(&self, name: &str) -> Option<&Function> { | ||
self.methods.get(name) | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct LoxInstance { | ||
pub class: Rc<RefCell<LoxClass>>, | ||
fields: HashMap<String, Object>, | ||
} | ||
|
||
impl LoxInstance { | ||
/// Returns a new `LoxInstance` wrapped in an `Object::Instance`. | ||
pub fn new(class: &Rc<RefCell<LoxClass>>) -> Object { | ||
let instance = LoxInstance { | ||
class: Rc::clone(class), | ||
fields: HashMap::new(), | ||
}; | ||
Object::Instance(Rc::new(RefCell::new(instance))) | ||
} | ||
|
||
/// Returns a member field of this instance. | ||
/// | ||
/// # Args | ||
/// * name - The name of the member. | ||
/// * instance - A reference to this instance as an object. | ||
pub fn get(&self, name: &Token, instance: &Object) -> Result<Object, Error> { | ||
if let Some(field) = self.fields.get(&name.lexeme) { | ||
Ok(field.clone()) | ||
} else if let Some(method) = self.class.borrow().find_method(&name.lexeme) { | ||
Ok(Object::Callable(method.bind(instance.clone()))) | ||
} else { | ||
Err(Error::Runtime { | ||
token: name.clone(), | ||
message: format!("Undefined property '{}'.", name.lexeme), | ||
}) | ||
} | ||
} | ||
|
||
pub fn set(&mut self, name: &Token, value: Object) { | ||
self.fields.insert(name.lexeme.clone(), value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
mod class; | ||
mod env; | ||
mod error; | ||
mod function; | ||
|
Oops, something went wrong.