From fc6e56548bdffdb9053d0d37af21f9f7cde9a90b Mon Sep 17 00:00:00 2001 From: Alex van de Sandt Date: Fri, 12 Jul 2024 00:59:49 -0400 Subject: [PATCH] Implement class instatiation --- src/ast/stmt.rs | 10 +++++----- src/class.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++ src/interpreter.rs | 27 ++++++++++--------------- src/lib.rs | 1 + src/resolver.rs | 5 ++++- src/value.rs | 7 +++++-- 6 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 src/class.rs diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index 01527c2..0c434b5 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -28,7 +28,7 @@ pub enum Stmt { }, Return(#[allow(dead_code)] Option>), Class { - _name: String, + name: String, _methods: Vec>, }, } @@ -216,7 +216,7 @@ impl Stmt { let span = class_token.span.join(&close_brace.span); Spanned::new( Self::Class { - _name: name, + name, _methods: methods, }, span, @@ -328,9 +328,9 @@ impl Stmt { pub fn unwrap_class_decl(&self) -> (&str, &[Spanned]) { match self { Self::Class { - _name: name, - _methods: functions, - } => (name.as_ref(), functions.as_slice()), + name, + _methods: methods, + } => (name.as_ref(), methods.as_slice()), other => panic!("expected class, found {:?}", other.as_str()), } } diff --git a/src/class.rs b/src/class.rs new file mode 100644 index 0000000..0475593 --- /dev/null +++ b/src/class.rs @@ -0,0 +1,50 @@ +use std::rc::Rc; + +use crate::{ + callable::Callable, + interpreter::{Interpreter, RuntimeError}, + value::Value, +}; + +#[derive(Clone, Debug)] +pub struct Class { + name: String, +} + +impl Class { + pub fn new(name: String) -> Rc { + Rc::new(Self { name }) + } + + pub fn name(&self) -> &str { + &self.name + } + + fn instantiate(&self) -> Rc { + Rc::new(ClassInstance { + class: self.clone(), + }) + } +} + +/// Calling a class invokes its constructor +impl Callable for Class { + fn arity(&self) -> usize { + 0 + } + + fn call(&self, _: &mut Interpreter, _: Vec) -> Result { + Ok(Value::ClassInstance(self.instantiate())) + } +} + +#[derive(Clone, Debug)] +pub struct ClassInstance { + class: Class, +} + +impl ClassInstance { + pub fn class(&self) -> Class { + self.class.clone() + } +} diff --git a/src/interpreter.rs b/src/interpreter.rs index 05c65c9..9d9c236 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -6,6 +6,7 @@ use crate::{ ast::{Ast, BinaryOp, Expr, Function, LogicalOp, Lval, Stmt, UnaryOp}, callable::Callable, callable::LoxFunction, + class::Class, environment::Env, span::{Span, Spanned}, value::Value, @@ -122,7 +123,11 @@ impl<'a> Interpreter<'a> { .unwrap_or(Value::Nil); return Ok(Some(value)); } - Stmt::Class { .. } => todo!("class declaration execution"), + Stmt::Class { name, .. } => { + env.define(name.clone(), Value::Nil); + let class = Value::Callable(Class::new(name.clone())); + assert!(env.assign_at_depth(name, class, 0)); + } } Ok(None) @@ -138,21 +143,11 @@ impl<'a> Interpreter<'a> { Ok(Value::from(lit.as_ref())) } Expr::Unary { op, expr } => self.interpret_unary(op, expr, env), - Expr::Var { name } => { - name.depth() - .and_then(|depth| env.get_at_depth(name.as_ref().as_ref(), depth)) - .or_else(|| env.get_global(name.as_ref().as_ref())) - .ok_or_else(|| RuntimeError::undefined_var(name.as_ref())) - /* - let state = name.state(); - let name = name.as_ref(); - match state { - ResolutionState::Global => env.get_global(name.as_ref()), - ResolutionState::Resolved(depth) => env.get_at_depth(name.as_ref(), depth), - } - .ok_or_else(|| RuntimeError::undefined_var(name)) - */ - } + Expr::Var { name } => name + .depth() + .and_then(|depth| env.get_at_depth(name.as_ref().as_ref(), depth)) + .or_else(|| env.get_global(name.as_ref().as_ref())) + .ok_or_else(|| RuntimeError::undefined_var(name.as_ref())), Expr::Assignment { target, value } => { let name = match target.as_ref() { Lval::Ident { name } => name, diff --git a/src/lib.rs b/src/lib.rs index 2dfff0f..8989cc6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ mod ast; mod callable; +mod class; mod environment; mod interpreter; mod logging; diff --git a/src/resolver.rs b/src/resolver.rs index 51e5f5f..4b0c00e 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -112,7 +112,10 @@ impl Resolver { } self.define(name.clone()); } - Stmt::Class { .. } => todo!("class declaration resolution"), + Stmt::Class { name, .. } => { + self.declare(name.clone()); + self.define(name.clone()); + } Stmt::Expr(expr) => self.resolve_expr(expr)?, Stmt::Print(expr) => self.resolve_expr(expr)?, diff --git a/src/value.rs b/src/value.rs index 6f31b5e..133650f 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,6 +1,6 @@ -use std::fmt; -use std::rc::Rc; +use std::{fmt, rc::Rc}; +use crate::class::ClassInstance; use crate::{ast::Literal, callable::Callable}; #[derive(Clone, Debug)] @@ -10,6 +10,7 @@ pub enum Value { Bool(bool), Nil, Callable(Rc), + ClassInstance(Rc), } impl Value { @@ -32,6 +33,7 @@ impl Value { Value::Bool(_) => "bool", Value::Nil => "nil", Value::Callable(_) => "callable", + Value::ClassInstance(_) => "instance", } } @@ -81,6 +83,7 @@ impl fmt::Display for Value { Value::Bool(b) => b.fmt(f), Value::Nil => "nil".fmt(f), Value::Callable(_) => "".fmt(f), + Value::ClassInstance(i) => write!(f, "", i.class().name()), } } } -- 2.51.2