Skip to content

Commit

Permalink
🌟 completed classes
Browse files Browse the repository at this point in the history
  • Loading branch information
aym-n committed Jan 10, 2024
1 parent 1d47f8d commit e7cfc79
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 12 deletions.
10 changes: 6 additions & 4 deletions main.arc
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
class Bacon {
eat() {
print "Crunch crunch crunch!";
class Foo {
init() {
print this;
return 10;
}
}

Bacon().eat();
var foo = Foo();
print foo.init();
1 change: 1 addition & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::tokens::*;

#[derive(Debug, PartialEq, Clone)]
pub enum Error {
ParseError { token: Token, message: String },
RuntimeError { token: Token, message: String },
Expand Down
19 changes: 16 additions & 3 deletions src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::interpreter::Interpreter;
pub struct Function {
name : Token,
params : Rc<Vec<Token>>,
is_initializer: bool,
body : Rc<Vec<Rc<Stmt>>>,
closure: Rc<RefCell<Environment>>,
}
Expand All @@ -26,6 +27,7 @@ impl Clone for Function {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
is_initializer: self.is_initializer,
params: Rc::clone(&self.params),
body: Rc::clone(&self.body),
closure: Rc::clone(&self.closure),
Expand All @@ -40,12 +42,13 @@ impl PartialEq for Function {
}

impl Function {
pub fn new(declaration: &FunctionStmt, closure: &Rc<RefCell<Environment>>) -> Self {
pub fn new(declaration: &FunctionStmt, closure: &Rc<RefCell<Environment>>, is_initializer: bool) -> Self {
Self {
name: declaration.name.clone(),
params: Rc::clone(&declaration.params),
body: Rc::clone(&declaration.body),
closure: Rc::clone(&closure),
is_initializer: is_initializer,
}
}

Expand All @@ -54,6 +57,7 @@ impl Function {
e.borrow_mut().define("this".to_string(), instance.clone());
Object::Function(Rc::new(Self {
name: self.name.clone(),
is_initializer: self.is_initializer,
params: Rc::clone(&self.params),
body: Rc::clone(&self.body),
closure: Rc::new(e),
Expand All @@ -71,10 +75,19 @@ impl CallableTrait for Function {
}

match interpreter.execute_block(&self.body, e) {
Ok(_) => Ok(Object::Nil),
Ok(_) => {
if self.is_initializer {
return Ok(self.closure.borrow().get_at(0, "this").unwrap());
}
Ok(Object::Nil)
}
Err(e) => {
match e {
Error::Return { value } => Ok(value),
Error::Return { value } => if self.is_initializer {
Ok(self.closure.borrow().get_at(0, "this").unwrap())
} else {
Ok(value)
}
_ => Err(e),
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ impl StmtVisitor<()> for Interpreter {
let mut methods = HashMap::new();
for method in stmt.methods.deref() {
if let Stmt::Function(func) = method.deref() {
let is_initializer = func.name.lexeme == "init";
let function = Object::Function(Rc::new(
Function::new(func, self.environment.borrow().deref()),
Function::new(func, self.environment.borrow().deref(), is_initializer),
));
methods.insert(func.name.lexeme.clone(), function);
} else {
Expand Down Expand Up @@ -58,7 +59,7 @@ impl StmtVisitor<()> for Interpreter {
}
}
fn visit_function_stmt(&self, _: Rc<Stmt>, stmt: &FunctionStmt) -> Result<(), Error> {
let function = Function::new(stmt, self.environment.borrow().deref());
let function = Function::new(stmt, self.environment.borrow().deref(), false);
self.environment.borrow().borrow_mut().define(
stmt.name.lexeme.clone(),
Object::Function(Rc::new(function)),
Expand Down
27 changes: 26 additions & 1 deletion src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,50 @@ pub struct Resolver<'a>{
scopes: RefCell<Vec<RefCell<HashMap<String, bool>>>>,
had_error: RefCell<bool>,
current_function: RefCell<FunctionType>,
current_class: RefCell<ClassType>,
}

#[derive(PartialEq)]
enum FunctionType {
None,
Function,
Initializer,
Method,
}

#[derive(PartialEq)]
enum ClassType {
None,
Class,
}


impl<'a> StmtVisitor<()> for Resolver<'a>{
fn visit_class_stmt(&self , _: Rc<Stmt>, stmt: &ClassStmt) -> Result<(), Error> {

let enclosing_class = self.current_class.replace(ClassType::Class);

self.declare(&stmt.name);
self.define(&stmt.name);

self.begin_scope();
self.scopes.borrow().last().unwrap().borrow_mut().insert("this".to_string(), true);

for method in stmt.methods.deref() {
let declaration = FunctionType::Method;
if let Stmt::Function(method) = method.deref() {
let declaration = if method.name.lexeme == "init" {
FunctionType::Initializer
}else{
FunctionType::Method
};
self.resolve_function(method, declaration);
}else{
return Err(Error::runtime_error(&stmt.name, "Class method did not resolve to a function."));
}
}

self.end_scope();
self.current_class.replace(enclosing_class);

Ok(())
}
Expand All @@ -51,6 +68,9 @@ impl<'a> StmtVisitor<()> for Resolver<'a>{
}

if let Some(value) = stmt.value.clone() {
if *self.current_function.borrow() == FunctionType::Initializer {
return Err(Error::runtime_error(&stmt.keyword, "Cannot return a value from an initializer."));
}
self.resolve_expr(value);
}

Expand Down Expand Up @@ -104,6 +124,10 @@ impl<'a> StmtVisitor<()> for Resolver<'a>{

impl<'a> ExprVisitor<()> for Resolver<'a>{
fn visit_this_expr(&self, wrapper: Rc<Expr>, expr: &ThisExpr) -> Result<(), Error> {
if *self.current_class.borrow() == ClassType::None {
self.error(&expr.keyword, "Cannot use 'this' outside of a class.");
return Ok(());
}
self.resolve_local(wrapper, &expr.keyword);
Ok(())
}
Expand Down Expand Up @@ -173,6 +197,7 @@ impl<'a> Resolver<'a> {
scopes: RefCell::new(Vec::new()),
had_error: RefCell::new(false),
current_function: RefCell::new(FunctionType::None),
current_class: RefCell::new(ClassType::None),
}
}
pub fn resolve(&self, statement: &Rc<Vec<Rc<Stmt>>>){
Expand Down
13 changes: 11 additions & 2 deletions src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,14 @@ impl ClassStruct {
}
}

pub fn instantiate(&self, _interpreter: &Interpreter, _arguments: Vec<Object>, cls: Rc<ClassStruct>) -> Result<Object, Error> {
Ok(Object::Instance(Rc::new(InstanceStruct::new(cls))))
pub fn instantiate(&self, interpreter: &Interpreter, arguments: Vec<Object>, cls: Rc<ClassStruct>) -> Result<Object, Error> {
let instance = Object::Instance(Rc::new(InstanceStruct::new(cls)));
if let Some(Object::Function(initializer)) = self.find_method("init".to_string()){
if let Object::Function(initializer) = initializer.bind(&instance) {
initializer.call(interpreter, &arguments)?;
}
}
Ok(instance)
}

pub fn find_method(&self, name: String) -> Option<Object> {
Expand All @@ -128,6 +134,9 @@ impl CallableTrait for ClassStruct {
}

fn arity(&self) -> usize {
if let Some(Object::Function(initializer)) = self.find_method("init".to_string()){
return initializer.arity();
}
0
}

Expand Down

0 comments on commit e7cfc79

Please sign in to comment.