1use std::{
2 fmt::{self, Display, Write},
3 rc::Rc,
4};
5
6use gc::{Finalize, Gc, GcCell};
7
8use crate::{ast::Lambda, util::ShowSlice, vm::Env};
9
10#[derive(Clone, PartialEq)]
15pub enum Value {
16 Fixnum(isize),
17 String(Box<String>),
18 Bool(bool),
19 Null,
20 Unspecified,
21 Cons(Gc<[Value; 2]>),
22 Symbol(Box<String>), PrimOp(&'static PrimOp),
24 Closure(Box<Closure>),
25 Exception(Box<Exception>),
26}
27
28#[derive(Debug, Clone, PartialEq)]
29pub struct Exception {
30 pub message: String,
31 pub irritants: Vec<Value>,
32}
33
34impl Display for Exception {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 f.write_str(&self.message)?;
37 if !self.irritants.is_empty() {
38 f.write_char(' ')?;
39 for (i, irritant) in self.irritants.iter().enumerate() {
40 if i + 1 == self.irritants.len() {
41 write!(f, "{}", irritant)?;
42 } else {
43 write!(f, "{} ", irritant)?;
44 }
45 }
46 }
47 Ok(())
48 }
49}
50
51#[derive(Clone)]
52pub struct PrimOp {
53 pub name: &'static str,
54 pub func: fn(&[Value]) -> Value,
55}
56
57impl PartialEq<PrimOp> for PrimOp {
58 fn eq(&self, other: &PrimOp) -> bool {
59 self as *const _ == other as *const _
60 }
61}
62
63impl PartialEq<Closure> for Closure {
64 fn eq(&self, _: &Closure) -> bool {
65 false
66 }
67}
68
69#[derive(Clone, Debug)]
70pub struct Closure {
71 pub lambda: Rc<Lambda>,
72 pub env: Gc<GcCell<Env>>,
73}
74
75impl Value {
76 pub fn into_result(self) -> Result<Value, Box<Exception>> {
77 match self {
78 Value::Exception(e) => Err(e),
79 _ => Ok(self),
80 }
81 }
82
83 pub fn list<I>(_elts: I) -> Self
84 where
85 I: IntoIterator,
86 I::Item: Into<Value>,
87 {
88 unimplemented!()
89 }
90
91 pub fn number<T>(n: T) -> Self
92 where
93 T: Into<isize>,
94 {
95 Value::Fixnum(n.into())
96 }
97
98 pub fn as_fixnum(&self) -> Option<isize> {
99 match self {
100 Value::Fixnum(n) => Some(*n),
101 _ => None,
102 }
103 }
104
105 pub fn is_true(&self) -> bool {
106 if let Value::Bool(v) = self {
107 *v
108 } else {
109 true
110 }
111 }
112 pub fn to_datum(&self) -> Option<lexpr::Value> {
113 use Value::*;
114 match self {
115 Null => Some(lexpr::Value::Null),
116 Unspecified => Some(lexpr::Value::Nil),
117 Bool(b) => Some((*b).into()),
118 Fixnum(n) => Some((*n as i64).into()),
119 String(s) => Some(s.as_str().into()),
120 Symbol(s) => Some(lexpr::Value::symbol(s.as_str())),
121 Cons(cell) => {
122 let cell = &*cell;
123 match (cell[0].to_datum(), cell[1].to_datum()) {
124 (Some(car), Some(cdr)) => Some((car, cdr).into()),
125 _ => None,
126 }
127 }
128 PrimOp(_) | Closure(_) | Exception(_) => None,
129 }
130 }
131}
132
133impl From<bool> for Value {
134 fn from(b: bool) -> Self {
135 Value::Bool(b)
136 }
137}
138
139impl<'a> From<&'a str> for Value {
140 fn from(s: &'a str) -> Self {
141 Value::String(Box::new(s.into()))
142 }
143}
144
145impl From<Box<Exception>> for Value {
146 fn from(e: Box<Exception>) -> Self {
147 Value::Exception(e)
148 }
149}
150
151impl From<&lexpr::Value> for Value {
152 fn from(v: &lexpr::Value) -> Self {
153 use lexpr::Value::*;
154 match v {
155 Bool(b) => Value::Bool(*b),
156 Number(n) => {
157 if let Some(n) = n.as_i64() {
158 if n <= isize::max_value() as i64 {
159 Value::Fixnum(n as isize)
160 } else {
161 unimplemented!()
162 }
163 } else {
164 unimplemented!()
165 }
166 }
167 String(s) => s.as_ref().into(),
168 Symbol(s) => Value::Symbol(Box::new(s.as_ref().to_owned())),
169 Cons(cell) => {
170 let (car, cdr) = cell.as_pair();
171 Value::Cons(Gc::new([car.into(), cdr.into()]))
172 }
173 Null => Value::Null,
174 Nil => Value::Unspecified,
175 _ => unimplemented!(),
176 }
177 }
178}
179
180impl fmt::Debug for Value {
181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 fmt::Display::fmt(self, f)
184 }
185}
186
187impl fmt::Display for Value {
188 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189 match self {
190 Value::Fixnum(n) => write!(f, "{}", n),
191 Value::Symbol(s) => write!(f, "{}", s),
192 Value::Bool(b) => f.write_str(if *b { "#t" } else { "#f" }),
193 Value::PrimOp(op) => write!(f, "#<prim-op {}>", op.name),
194 Value::Closure { .. } => write!(f, "#<closure>"),
195 Value::Null => write!(f, "()"),
196 Value::Unspecified => write!(f, "#<unspecified>"),
197 Value::Cons(cell) => write_cons(f, cell),
198 Value::String(s) => lexpr::Value::string(s.as_str()).fmt(f),
199 Value::Exception(e) => write!(
200 f,
201 "#<exception {} ({})>",
202 e.message,
203 ShowSlice(&e.irritants)
204 ),
205 }
206 }
207}
208
209fn write_cons(f: &mut fmt::Formatter, cell: &[Value; 2]) -> fmt::Result {
210 f.write_char('(')?;
211 cell[0].fmt(f)?;
212 let mut next = &cell[1];
213 loop {
214 match next {
215 Value::Null => break,
216 Value::Cons(cell) => {
217 f.write_char(' ')?;
218 cell[0].fmt(f)?;
219 next = &cell[1];
220 }
221 value => {
222 f.write_str(" . ")?;
223 value.fmt(f)?;
224 break;
225 }
226 }
227 }
228 f.write_char(')')?;
229 Ok(())
230}
231
232impl gc::Finalize for Value {
233 fn finalize(&self) {}
234}
235
236macro_rules! impl_value_trace_body {
237 ($this:ident, $method:ident) => {
238 match $this {
239 Value::Cons(cell) => {
240 cell[0].$method();
241 cell[1].$method();
242 }
243 Value::Closure(boxed) => {
244 let Closure { env, .. } = boxed.as_ref();
245 env.$method();
246 }
247 _ => {}
248 }
249 };
250}
251
252unsafe impl gc::Trace for Value {
253 unsafe fn trace(&self) {
254 impl_value_trace_body!(self, trace);
255 }
256 unsafe fn root(&self) {
257 impl_value_trace_body!(self, root);
258 }
259 unsafe fn unroot(&self) {
260 impl_value_trace_body!(self, unroot);
261 }
262 fn finalize_glue(&self) {
263 self.finalize();
264 impl_value_trace_body!(self, finalize_glue);
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use super::Value;
271 use std::mem;
272
273 #[test]
274 fn test_value_size() {
275 assert!(mem::size_of::<Value>() <= 2 * mem::size_of::<usize>());
276 }
277}