Skip to main content

object/
object.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::fmt;
4use std::fmt::Formatter;
5use std::hash::{Hash, Hasher};
6use std::rc::Rc;
7
8use parser::ast::{BlockStatement, IDENTIFIER};
9
10#[macro_use]
11extern crate lazy_static;
12
13use crate::environment::Env;
14
15pub mod builtins;
16pub mod environment;
17
18pub type EvalError = String;
19pub type BuiltinFunc = fn(Vec<Rc<Object>>) -> Rc<Object>;
20
21pub type ClassRef = Rc<RefCell<ClassObject>>;
22pub type InstanceRef = Rc<RefCell<InstanceObject>>;
23
24#[derive(Clone)]
25pub enum Object {
26    Integer(i64),
27    Boolean(bool),
28    String(String),
29    Array(Vec<Rc<Object>>),
30    Hash(HashMap<Rc<Object>, Rc<Object>>),
31    Null,
32    ReturnValue(Rc<Object>),
33    Function(Vec<IDENTIFIER>, BlockStatement, Env),
34    Builtin(BuiltinFunc),
35    Error(String),
36    CompiledFunction(Rc<CompiledFunction>),
37    ClosureObj(Closure),
38    Class(ClassRef),
39    Instance(InstanceRef),
40    BoundMethod(Rc<BoundMethodObject>),
41}
42
43#[derive(Clone)]
44pub struct ClassObject {
45    pub name: String,
46    pub constructor: Option<Rc<Object>>,
47    pub methods: HashMap<String, Rc<Object>>,
48}
49
50#[derive(Clone)]
51pub struct InstanceObject {
52    pub class: ClassRef,
53    pub fields: HashMap<String, Rc<Object>>,
54}
55
56#[derive(Clone)]
57pub struct BoundMethodObject {
58    pub receiver: InstanceRef,
59    pub method: Rc<Object>,
60    pub name: String,
61}
62
63impl fmt::Display for Object {
64    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
65        match self {
66            Object::Integer(i) => write!(f, "{}", i),
67            Object::Boolean(b) => write!(f, "{}", b),
68            Object::String(s) => write!(f, "{}", s),
69            Object::Null => write!(f, "null"),
70            Object::ReturnValue(expr) => write!(f, "{}", expr),
71            Object::Function(params, body, _env) => {
72                let func_params = params
73                    .iter()
74                    .map(|stmt| stmt.to_string())
75                    .collect::<Vec<String>>()
76                    .join(", ");
77                write!(f, "fn({}) {{ {} }}", func_params, body)
78            }
79            Object::Builtin(_) => write!(f, "[builtin function]"),
80            Object::Error(e) => write!(f, "{}", e),
81            Object::Array(e) => write!(
82                f,
83                "[{}]",
84                e.iter()
85                    .map(|o| o.to_string())
86                    .collect::<Vec<String>>()
87                    .join(", ")
88            ),
89            Object::Hash(map) => write!(
90                f,
91                "[{}]",
92                map.iter()
93                    .map(|(k, v)| format!("{}: {}", k, v))
94                    .collect::<Vec<String>>()
95                    .join(", ")
96            ),
97            Object::CompiledFunction(_) => {
98                write!(f, "[compiled function]")
99            }
100            Object::ClosureObj(_) => {
101                write!(f, "[closure function]")
102            }
103            Object::Class(class) => write!(f, "[class {}]", class.borrow().name),
104            Object::Instance(instance) => {
105                write!(f, "[object {}]", instance.borrow().class.borrow().name)
106            }
107            Object::BoundMethod(method) => {
108                let class_name = method.receiver.borrow().class.borrow().name.clone();
109                write!(f, "[bound method {}.{}]", class_name, method.name)
110            }
111        }
112    }
113}
114
115impl fmt::Debug for Object {
116    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117        match self {
118            Object::Integer(value) => f.debug_tuple("Integer").field(value).finish(),
119            Object::Boolean(value) => f.debug_tuple("Boolean").field(value).finish(),
120            Object::String(value) => f.debug_tuple("String").field(value).finish(),
121            Object::Array(value) => f.debug_tuple("Array").field(value).finish(),
122            Object::Hash(value) => f.debug_tuple("Hash").field(value).finish(),
123            Object::Null => write!(f, "Null"),
124            Object::ReturnValue(value) => f.debug_tuple("ReturnValue").field(value).finish(),
125            Object::Function(params, body, _) => f
126                .debug_struct("Function")
127                .field("params", params)
128                .field("body", body)
129                .finish_non_exhaustive(),
130            Object::Builtin(_) => write!(f, "Builtin([function])"),
131            Object::Error(value) => f.debug_tuple("Error").field(value).finish(),
132            Object::CompiledFunction(value) => {
133                f.debug_tuple("CompiledFunction").field(value).finish()
134            }
135            Object::ClosureObj(value) => f.debug_tuple("ClosureObj").field(value).finish(),
136            Object::Class(_) | Object::Instance(_) | Object::BoundMethod(_) => {
137                write!(f, "{}", self)
138            }
139        }
140    }
141}
142
143impl PartialEq for Object {
144    fn eq(&self, other: &Self) -> bool {
145        match (self, other) {
146            (Object::Integer(left), Object::Integer(right)) => left == right,
147            (Object::Boolean(left), Object::Boolean(right)) => left == right,
148            (Object::String(left), Object::String(right)) => left == right,
149            (Object::Array(left), Object::Array(right)) => left == right,
150            (Object::Hash(left), Object::Hash(right)) => left == right,
151            (Object::Null, Object::Null) => true,
152            (Object::ReturnValue(left), Object::ReturnValue(right)) => left == right,
153            (
154                Object::Function(left_params, left_body, left_env),
155                Object::Function(right_params, right_body, right_env),
156            ) => {
157                left_params == right_params
158                    && left_body == right_body
159                    && Rc::ptr_eq(left_env, right_env)
160            }
161            (Object::Builtin(left), Object::Builtin(right)) => std::ptr::fn_addr_eq(*left, *right),
162            (Object::Error(left), Object::Error(right)) => left == right,
163            (Object::CompiledFunction(left), Object::CompiledFunction(right)) => left == right,
164            (Object::ClosureObj(left), Object::ClosureObj(right)) => left == right,
165            (Object::Class(left), Object::Class(right)) => Rc::ptr_eq(left, right),
166            (Object::Instance(left), Object::Instance(right)) => Rc::ptr_eq(left, right),
167            (Object::BoundMethod(left), Object::BoundMethod(right)) => Rc::ptr_eq(left, right),
168            _ => false,
169        }
170    }
171}
172
173impl Eq for Object {}
174
175impl Object {
176    pub fn is_hashable(&self) -> bool {
177        match self {
178            Object::Integer(_) | Object::Boolean(_) | Object::String(_) => return true,
179            _ => return false,
180        }
181    }
182}
183
184impl Hash for Object {
185    fn hash<H: Hasher>(&self, state: &mut H) {
186        match self {
187            Object::Integer(i) => i.hash(state),
188            Object::Boolean(b) => b.hash(state),
189            Object::String(s) => s.hash(state),
190            t => panic!("can't hashable for {}", t),
191        }
192    }
193}
194
195#[derive(Debug, Clone, Eq, PartialEq)]
196pub struct CompiledFunction {
197    pub name: String,
198    pub instructions: Vec<u8>,
199    pub num_locals: usize,
200    pub num_parameters: usize,
201}
202
203#[derive(Debug, Clone, Eq, PartialEq)]
204pub struct Closure {
205    pub func: Rc<CompiledFunction>,
206    pub free: Vec<Rc<Object>>,
207}