1use std::collections::HashMap;
2use std::fmt;
3use std::rc::Rc;
4
5use crate::header::GcObjectType;
6use crate::{GcHeap, GcObject, GcRef};
7use object::{BuiltinFunc, Closure, CompiledFunction, Object};
8
9#[derive(Debug, Clone, PartialEq)]
11pub enum Value {
12 Integer(i64),
13 Boolean(bool),
14 String(String),
15 Array(Vec<GcRef>),
16 Hash(HashMap<HashKey, GcRef>),
17 Null,
18 Error(String),
19 CompiledFunction(CompiledFunction),
20 Closure(GcClosure),
21 Builtin(BuiltinFunc),
22}
23
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct GcClosure {
26 pub func: GcRef,
27 pub free: Vec<GcRef>,
28}
29
30#[derive(Clone, Debug, PartialEq, Eq, Hash)]
31pub enum HashKey {
32 Integer(i64),
33 Boolean(bool),
34 String(String),
35}
36
37pub struct ValueCell {
38 pub value: Value,
39}
40
41impl GcObject for ValueCell {
42 fn trace(&self, visit: &mut dyn FnMut(crate::GcId)) {
43 self.value.trace(&mut |reference| visit(reference.0));
44 }
45}
46
47impl Value {
48 pub fn trace(&self, visit: &mut dyn FnMut(GcRef)) {
49 match self {
50 Value::Array(items) => {
51 for item in items {
52 visit(*item);
53 }
54 }
55 Value::Hash(map) => {
56 for value in map.values() {
57 visit(*value);
58 }
59 }
60 Value::Closure(closure) => {
61 visit(closure.func);
62 for free in &closure.free {
63 visit(*free);
64 }
65 }
66 _ => {}
67 }
68 }
69
70 pub fn with_owned_edges(self, heap: &mut GcHeap) -> Self {
71 match self {
72 Value::Array(items) => Value::Array(items.into_iter().map(|r| heap.dup(r)).collect()),
73 Value::Hash(map) => {
74 Value::Hash(map.into_iter().map(|(k, v)| (k, heap.dup(v))).collect())
75 }
76 Value::Closure(mut closure) => {
77 closure.func = heap.dup(closure.func);
78 closure.free = closure.free.into_iter().map(|r| heap.dup(r)).collect();
79 Value::Closure(closure)
80 }
81 other => other,
82 }
83 }
84
85 pub fn edge_refs(&self) -> Vec<GcRef> {
86 let mut refs = Vec::new();
87 self.trace(&mut |reference| refs.push(reference));
88 refs
89 }
90}
91
92impl HashKey {
93 pub fn from_object(object: &Object) -> Option<HashKey> {
94 match object {
95 Object::Integer(i) => Some(HashKey::Integer(*i)),
96 Object::Boolean(b) => Some(HashKey::Boolean(*b)),
97 Object::String(s) => Some(HashKey::String(s.clone())),
98 _ => None,
99 }
100 }
101
102 pub fn from_value(value: &Value) -> Option<HashKey> {
103 match value {
104 Value::Integer(i) => Some(HashKey::Integer(*i)),
105 Value::Boolean(b) => Some(HashKey::Boolean(*b)),
106 Value::String(s) => Some(HashKey::String(s.clone())),
107 _ => None,
108 }
109 }
110
111 pub fn to_object(&self) -> Object {
112 match self {
113 HashKey::Integer(i) => Object::Integer(*i),
114 HashKey::Boolean(b) => Object::Boolean(*b),
115 HashKey::String(s) => Object::String(s.clone()),
116 }
117 }
118}
119
120pub fn alloc_value(heap: &mut GcHeap, value: Value) -> GcRef {
121 let value = value.with_owned_edges(heap);
122 heap.alloc(
123 ValueCell {
124 value,
125 },
126 GcObjectType::MonkeyObject,
127 )
128}
129
130pub fn get_value<'a>(heap: &'a GcHeap, reference: GcRef) -> &'a Value {
131 &heap
132 .runtime()
133 .object_downcast::<ValueCell>(reference.0)
134 .expect("invalid value reference")
135 .value
136}
137
138pub fn value_to_string(heap: &GcHeap, reference: GcRef) -> String {
139 format_value(heap, get_value(heap, reference))
140}
141
142fn format_value(heap: &GcHeap, value: &Value) -> String {
143 match value {
144 Value::Integer(i) => i.to_string(),
145 Value::Boolean(b) => b.to_string(),
146 Value::String(s) => s.clone(),
147 Value::Null => "null".to_string(),
148 Value::Error(e) => e.clone(),
149 Value::Array(items) => {
150 let parts = items
151 .iter()
152 .map(|item| value_to_string(heap, *item))
153 .collect::<Vec<_>>()
154 .join(", ");
155 format!("[{}]", parts)
156 }
157 Value::Hash(map) => {
158 let parts = map
159 .iter()
160 .map(|(k, v)| format!("{}: {}", format_hash_key(k), value_to_string(heap, *v)))
161 .collect::<Vec<_>>()
162 .join(", ");
163 format!("{{{}}}", parts)
164 }
165 Value::CompiledFunction(_) => "[compiled function]".to_string(),
166 Value::Closure(_) => "[closure function]".to_string(),
167 Value::Builtin(_) => "[builtin function]".to_string(),
168 }
169}
170
171fn format_hash_key(key: &HashKey) -> String {
172 match key {
173 HashKey::Integer(i) => i.to_string(),
174 HashKey::Boolean(b) => b.to_string(),
175 HashKey::String(s) => s.clone(),
176 }
177}
178
179pub fn import_object(heap: &mut GcHeap, object: &Object) -> GcRef {
180 let value = match object {
181 Object::Integer(i) => Value::Integer(*i),
182 Object::Boolean(b) => Value::Boolean(*b),
183 Object::String(s) => Value::String(s.clone()),
184 Object::Null => Value::Null,
185 Object::Error(e) => Value::Error(e.clone()),
186 Object::Array(items) => {
187 Value::Array(items.iter().map(|item| import_object(heap, item)).collect())
188 }
189 Object::Hash(map) => Value::Hash(
190 map.iter()
191 .map(|(k, v)| {
192 (
193 HashKey::from_object(k).expect("hash key must be hashable"),
194 import_object(heap, v),
195 )
196 })
197 .collect(),
198 ),
199 Object::CompiledFunction(f) => Value::CompiledFunction(CompiledFunction {
200 instructions: f.instructions.clone(),
201 num_locals: f.num_locals,
202 num_parameters: f.num_parameters,
203 }),
204 Object::ClosureObj(closure) => Value::Closure(GcClosure {
205 func: import_object(heap, &Object::CompiledFunction(Rc::clone(&closure.func))),
206 free: closure
207 .free
208 .iter()
209 .map(|item| import_object(heap, item))
210 .collect(),
211 }),
212 Object::Builtin(b) => Value::Builtin(*b),
213 Object::ReturnValue(inner) => return import_object(heap, inner),
214 Object::Function(_, _, _) => {
215 panic!("interpreter functions cannot be imported into the GC VM")
216 }
217 };
218 let edge_refs = value.edge_refs();
219 let reference = alloc_value(heap, value);
220 for edge in edge_refs {
221 heap.free(edge);
222 }
223 reference
224}
225
226pub fn export_object(heap: &GcHeap, reference: GcRef) -> Object {
227 match get_value(heap, reference) {
228 Value::Integer(i) => Object::Integer(*i),
229 Value::Boolean(b) => Object::Boolean(*b),
230 Value::String(s) => Object::String(s.clone()),
231 Value::Null => Object::Null,
232 Value::Error(e) => Object::Error(e.clone()),
233 Value::Array(items) => Object::Array(
234 items
235 .iter()
236 .map(|item| Rc::new(export_object(heap, *item)))
237 .collect(),
238 ),
239 Value::Hash(map) => Object::Hash(
240 map.iter()
241 .map(|(k, v)| (Rc::new(k.to_object()), Rc::new(export_object(heap, *v))))
242 .collect(),
243 ),
244 Value::CompiledFunction(f) => Object::CompiledFunction(Rc::new(f.clone())),
245 Value::Closure(closure) => {
246 let func = match get_value(heap, closure.func) {
247 Value::CompiledFunction(f) => Rc::new(f.clone()),
248 _ => panic!("closure func must be compiled function"),
249 };
250 Object::ClosureObj(Closure {
251 func,
252 free: closure
253 .free
254 .iter()
255 .map(|item| Rc::new(export_object(heap, *item)))
256 .collect(),
257 })
258 }
259 Value::Builtin(b) => Object::Builtin(*b),
260 }
261}
262
263pub fn call_builtin(heap: &mut GcHeap, builtin: BuiltinFunc, args: Vec<GcRef>) -> GcRef {
264 let rc_args = args
265 .iter()
266 .map(|reference| Rc::new(export_object(heap, *reference)))
267 .collect();
268 let result = builtin(rc_args);
269 import_object(heap, &result)
270}
271
272impl fmt::Display for Value {
273 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274 write!(f, "{:?}", self)
275 }
276}