rocks_lang/
object.rs

1use std::fmt::{Debug, Display};
2use std::cell::RefCell;
3use std::ops::{Mul, Div, Add, Sub, Not, Neg};
4use std::rc::Rc;
5
6use crate::class::{Class, Instance};
7use crate::error::RuntimeError;
8use crate::function::{Function, NativeFunction};
9use crate::literal::Literal;
10use crate::interpreter::Interpreter;
11
12/// Represents an object that can be stored in a variable or returned from a function.
13/// This is an enum that wraps all the possible types of values in the language.
14#[derive(Debug, Clone)]
15pub enum Object {
16    Literal(Literal),
17    Function(Function),
18    NativeFunction(NativeFunction),
19    Class(Rc<RefCell<Class>>),
20    Instance(Rc<RefCell<Instance>>),
21}
22
23impl Object {
24    /// Returns the object as a boolean if it is a literal.
25    pub fn as_bool(&self) -> Option<bool> {
26        match self {
27            Object::Literal(literal) => Some(literal.as_bool()),
28            _ => None,
29        }
30    }
31
32    pub fn type_str(&self) -> &str {
33        match self {
34            Object::Literal(literal) => literal.type_str(),
35            Object::Function(_) => "function",
36            Object::NativeFunction(_) => "native function",
37            Object::Class(_) => "class",
38            Object::Instance(_) => "instance",
39        }
40    }
41}
42
43impl PartialEq for Object {
44    fn eq(&self, other: &Self) -> bool {
45        match (self, other) {
46            (Object::Literal(left), Object::Literal(right)) => left == right,
47            (Object::Function(left), Object::Function(right)) => left == right,
48            (Object::NativeFunction(left), Object::NativeFunction(right)) => left == right,
49            (Object::Class(left), Object::Class(right)) => left == right,
50            (Object::Instance(left), Object::Instance(right)) => left == right,
51            _ => false,
52        }
53    }
54}
55
56impl PartialOrd for Object {
57    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
58        match (self, other) {
59            (Object::Literal(left), Object::Literal(right)) => left.partial_cmp(right),
60            _ => None
61        }
62    }
63}
64
65impl Add for Object {
66    type Output = Option<Self>;
67
68    fn add(self, rhs: Self) -> Self::Output {
69        match (self, rhs) {
70            (Object::Literal(left), Object::Literal(right)) => left + right,
71            _ => None,
72        }.map(|x| x.into())
73    }
74}
75
76impl Sub for Object {
77    type Output = Option<Self>;
78
79    fn sub(self, rhs: Self) -> Self::Output {
80        match (self, rhs) {
81            (Object::Literal(left), Object::Literal(right)) => left - right,
82            _ => None,
83        }.map(|x| x.into())
84    }
85}
86
87impl Mul for Object {
88    type Output = Option<Self>;
89
90    fn mul(self, rhs: Self) -> Self::Output {
91        match (self, rhs) {
92            (Object::Literal(left), Object::Literal(right)) => left * right,
93            _ => None,
94        }.map(|x| x.into())
95    }
96}
97
98impl Div for Object {
99    type Output = Option<Self>;
100
101    fn div(self, rhs: Self) -> Self::Output {
102        match (self, rhs) {
103            (Object::Literal(left), Object::Literal(right)) => left / right,
104            _ => None,
105        }.map(|x| x.into())
106    }
107}
108
109impl Not for Object {
110    type Output = Option<Self>;
111
112    fn not(self) -> Self::Output {
113        match self {
114            Object::Literal(right) => !right,
115            _ => None,
116        }.map(|x| x.into())
117    }
118}
119
120impl Neg for Object {
121    type Output = Option<Self>;
122
123    fn neg(self) -> Self::Output {
124        match self {
125            Object::Literal(right) => -right,
126            _ => None,
127        }.map(|x| x.into())
128    }
129}
130
131impl From<Literal> for Object {
132    fn from(literal: Literal) -> Self {
133        Object::Literal(literal)
134    }
135}
136
137impl From<f64> for Object {
138    fn from(number: f64) -> Self {
139        Object::Literal(Literal::Number(number))
140    }
141}
142
143impl From<bool> for Object {
144    fn from(boolean: bool) -> Self {
145        Object::Literal(Literal::Bool(boolean))
146    }
147}
148
149impl From<String> for Object {
150    fn from(string: String) -> Self {
151        Object::Literal(Literal::String(string))
152    }
153}
154
155impl From<&str> for Object {
156    fn from(string: &str) -> Self {
157        Object::Literal(Literal::String(string.to_owned()))
158    }
159}
160
161impl From<Function> for Object {
162    fn from(value: Function) -> Self {
163        Object::Function(value)
164    }
165}
166
167impl From<NativeFunction> for Object {
168    fn from(value: NativeFunction) -> Self {
169        Object::NativeFunction(value)
170    }
171}
172
173impl From<Rc<RefCell<Class>>> for Object {
174    fn from(value: Rc<RefCell<Class>>) -> Self {
175        Object::Class(value)
176    }
177}
178
179impl From<Instance> for Object {
180    fn from(value: Instance) -> Self {
181        Object::Instance(Rc::new(RefCell::new(value)))
182    }
183}
184
185impl From<Rc<RefCell<Instance>>> for Object {
186    fn from(value: Rc<RefCell<Instance>>) -> Self {
187        Object::Instance(value)
188    }
189}
190
191impl Display for Object {
192    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193        match self {
194            Object::Literal(literal) => write!(f, "{literal}"),
195            Object::Function(function) => write!(f, "{function}"),
196            Object::NativeFunction(function) => write!(f, "{function}"),
197            Object::Class(class) => write!(f, "{}", class.borrow()),
198            Object::Instance(instance) => write!(f, "{}", instance.borrow()),
199        }
200    }
201}
202
203/// Represents a callable object in the language.
204pub trait Callable: Debug {
205    /// Calls the object with the given arguments and the current state of the interpreter.
206    /// The interpreter is passed in as a mutable refernece so that the object can access
207    /// the environment and call other functions. It returns the result of the call or an
208    /// error if the call failed for some reason.
209    fn call(&self, interpreter: &mut Interpreter, arguments: Vec<Object>) -> Result<Object, RuntimeError>;
210
211    /// Returns the arity of the object.
212    fn arity(&self) -> usize;
213}