1use std::{any::Any, cmp, collections::HashMap, error, fmt};
2
3mod chunk;
4mod obj;
5mod ops;
6
7pub(crate) use {chunk::Chunk, obj::Gc, ops::Op};
8
9use super::RuntimeError;
10
11#[derive(Clone)]
13#[non_exhaustive]
14pub enum Value {
15 Nil,
16 Boolean(bool),
17 Number(f64),
18 r#String(Box<str>),
19 NativeFun(Gc<NativeFun>),
20
21 #[doc(hidden)]
22 Fun(Gc<Fun>),
23 #[doc(hidden)]
24 Closure(Gc<Fun>, Box<[Gc<UpvalueRef>]>),
25 #[doc(hidden)]
26 BoundMethod {
27 recv: Gc<Instance>,
28 fun: Gc<Fun>,
29 upvalues: Box<[Gc<UpvalueRef>]>,
30 },
31 #[doc(hidden)]
32 Class(Gc<Class>),
33 #[doc(hidden)]
34 Instance(Gc<Instance>),
35}
36
37impl fmt::Display for Value {
38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39 match self {
40 Self::Nil => write!(f, "nil"),
41 Self::Boolean(b) => write!(f, "{}", b),
42 Self::Number(v) => write!(f, "{}", v),
43 Self::r#String(s) => write!(f, "{}", s),
44 Self::Fun(fun) | Self::Closure(fun, _) | Self::BoundMethod { fun, .. } => {
45 write!(f, "{}", **fun)
46 }
47 Self::Class(c) => write!(f, "{}", **c),
48 Self::Instance(i) => write!(f, "{} instance", *i.class),
49 Self::NativeFun(_) => write!(f, "#<native fun>"),
50 }
51 }
52}
53
54impl fmt::Debug for Value {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 match self {
57 Self::Nil => write!(f, "Nil"),
58 Self::Boolean(b) => write!(f, "Boolean({})", b),
59 Self::Number(v) => write!(f, "Number({})", v),
60 Self::r#String(s) => write!(f, "String({})", s),
61 Self::Fun(fun) => write!(f, "Fun({})", **fun),
62 Self::Closure(fun, upvals) => write!(f, "Closure({}, {:#?})", **fun, upvals),
63 Self::Class(c) => write!(f, "Class({})", **c),
64 Self::Instance(i) => write!(f, "Instance({:?})", i),
65 Self::BoundMethod {
66 recv,
67 fun,
68 upvalues,
69 } => write!(
70 f,
71 "BoundMethod {{ {:?}#{} {:#?} }}",
72 **recv, **fun, upvalues
73 ),
74 Self::NativeFun(ptr) => write!(f, "NativeFun({:p})", ptr),
75 }
76 }
77}
78
79impl cmp::PartialEq for Value {
80 fn eq(&self, other: &Self) -> bool {
81 match (self, other) {
82 (Self::Nil, Self::Nil) => true,
83 (Self::Boolean(a), Self::Boolean(b)) => a == b,
84 (Self::Number(a), Self::Number(b)) => a == b,
85 (Self::r#String(a), Self::r#String(b)) => a == b,
86 _ => false,
87 }
88 }
89}
90
91impl From<bool> for Value {
92 fn from(b: bool) -> Self {
93 Self::Boolean(b)
94 }
95}
96
97impl From<f64> for Value {
98 fn from(f: f64) -> Self {
99 Self::Number(f)
100 }
101}
102
103impl From<&str> for Value {
104 fn from(s: &str) -> Self {
105 s.to_string().into()
106 }
107}
108
109impl From<String> for Value {
110 fn from(s: String) -> Self {
111 Self::r#String(s.into_boxed_str())
112 }
113}
114
115impl Value {
116 pub(crate) fn is_falsey(&self) -> bool {
117 match self {
118 Self::Nil | Self::Boolean(false) => true,
119 _ => false,
120 }
121 }
122
123 pub(crate) fn negate(self) -> Result<Value, RuntimeError> {
124 if let Self::Number(a) = self {
125 Ok(Self::Number(-a))
126 } else {
127 Err(RuntimeError::ArgumentTypes)
128 }
129 }
130
131 pub(crate) fn mark(&self, grays: &mut Vec<Gc<dyn Any>>) {
132 match self {
133 Self::Fun(f) => {
134 f.mark();
135 grays.push(f.as_any());
136 }
137 Self::Closure(f, u) => {
138 f.mark();
139 grays.push(f.as_any());
140
141 for u_val in u.iter() {
142 u_val.mark();
143 grays.push(u_val.as_any());
144 }
145 }
146 Self::Class(c) => {
147 c.mark();
148 grays.push(c.as_any());
149 }
150 Self::Instance(i) => {
151 i.mark();
152 grays.push(i.as_any());
153 }
154 Self::BoundMethod {
155 recv,
156 fun,
157 upvalues,
158 } => {
159 recv.mark();
160 grays.push(recv.as_any());
161
162 fun.mark();
163 grays.push(fun.as_any());
164
165 for u_val in upvalues.iter() {
166 u_val.mark();
167 grays.push(u_val.as_any());
168 }
169 }
170 Self::NativeFun(nf) => {
171 nf.mark();
172 grays.push(nf.as_any());
173 }
174 _ => (),
175 }
176 }
177}
178
179impl Gc<dyn Any> {
180 pub(crate) fn blacken(self, gray_stack: &mut Vec<Gc<dyn Any>>) {
181 if self.is_marked() {
182 return;
183 }
184
185 #[cfg(feature = "trace-gc")]
186 log::debug!("{0:p} blacken\t{0:?}", self);
187
188 if let Some(f) = self.downcast_ref::<Fun>() {
189 for c in &f.chunk.constants {
190 c.mark(gray_stack);
191 }
192 } else if let Some(u) = self.downcast_ref::<UpvalueRef>() {
193 if let UpvalueRef::Captured(ref v) = *u {
194 v.mark(gray_stack);
195 }
196 } else if let Some(Class { methods, .. }) = self.downcast_ref::<Class>() {
197 for method in methods.values() {
198 method.mark(gray_stack);
199 }
200 } else if let Some(Instance { class, fields }) = self.downcast_ref::<Instance>() {
201 class.mark();
202 gray_stack.push(class.as_any());
203
204 for value in fields.values() {
205 value.mark(gray_stack);
206 }
207 }
208 }
209}
210
211#[derive(Clone, Debug)]
212pub struct Fun {
213 pub(crate) name: Box<str>,
214 pub(crate) arity: u8,
215 pub(crate) chunk: Chunk,
216}
217
218impl fmt::Display for Fun {
219 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220 write!(f, "#<fun {}/{}>", self.name, self.arity)
221 }
222}
223
224impl Fun {
225 pub(crate) fn new<T: ToString>(name: &T, arity: u8) -> Self {
226 Self {
227 arity,
228 name: name.to_string().into_boxed_str(),
229 chunk: Chunk::new(name),
230 }
231 }
232}
233
234#[derive(Clone, Debug)]
235pub enum UpvalueRef {
236 Live(usize),
237 Captured(Box<Value>),
238}
239
240impl UpvalueRef {
241 pub(crate) fn new(slot: usize) -> Self {
242 Self::Live(slot)
243 }
244
245 pub(crate) fn close(&mut self, ptr: Value) {
246 *self = Self::Captured(Box::new(ptr));
247 }
248}
249
250impl fmt::Display for UpvalueRef {
251 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252 match self {
253 Self::Live(idx) => write!(f, "at stack index {}", idx),
254 Self::Captured(ptr) => write!(f, "at address {:p}", ptr),
255 }
256 }
257}
258
259#[derive(Clone, Debug)]
260pub struct Class {
261 pub(crate) name: Box<str>,
262 pub(crate) methods: HashMap<Box<str>, Value>,
263}
264
265impl Class {
266 pub(crate) fn new<T: ToString>(name: &T) -> Self {
267 Self {
268 name: name.to_string().into_boxed_str(),
269 methods: HashMap::new(),
270 }
271 }
272}
273
274impl fmt::Display for Class {
275 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276 write!(f, "{}", self.name)
277 }
278}
279
280#[derive(Clone, Debug)]
281pub struct Instance {
282 pub(crate) class: Gc<Class>,
283 pub(crate) fields: HashMap<Box<str>, Value>,
284}
285
286impl Instance {
287 pub(crate) fn new(class: Gc<Class>) -> Self {
288 Self {
289 class,
290 fields: HashMap::new(),
291 }
292 }
293}
294
295pub type NativeFun = Box<dyn FnMut(&[Value]) -> Result<Value, Box<dyn error::Error>>>;