Skip to main content

gc/
value.rs

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/// Runtime value stored in the GC heap. Mirrors `object::Object` but uses `GcRef` edges.
10#[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}