turtle/interpreter/
expression.rs

1use std::fmt;
2use std::sync::mpsc;
3
4use crate::Locker;
5use std::thread;
6
7use crate::{
8    exp, exp_assert, CallSnapshot, Environment, Exception, ExceptionValue as EV, SourcePosition,
9    Value,
10};
11
12#[derive(Debug, Clone)]
13pub struct Expression {
14    value: Value,
15    source: Option<SourcePosition>,
16}
17
18impl PartialEq for Expression {
19    fn eq(&self, other: &Self) -> bool {
20        // TODO: do we need to check whether the environments are the same?
21        self.value == other.value
22    }
23}
24
25impl Expression {
26    pub fn new(value: Value) -> Self {
27        Self {
28            value,
29            source: None,
30        }
31    }
32
33    pub fn with_source(mut self, source_position: SourcePosition) -> Self {
34        self.source = Some(source_position);
35        self
36    }
37
38    pub fn nil() -> Self {
39        Self {
40            value: Value::List(vec![]),
41            source: None,
42        }
43    }
44
45    pub fn t() -> Self {
46        Self {
47            value: Value::True,
48            source: None,
49        }
50    }
51
52    pub fn get_value(&self) -> &Value {
53        &self.value
54    }
55
56    pub fn into_value(self) -> Value {
57        self.value
58    }
59
60    pub fn source(&self) -> &'_ Option<SourcePosition> {
61        &self.source
62    }
63
64    pub fn eval_async(
65        self,
66        parent_snapshot: Locker<CallSnapshot>,
67        env: Locker<Environment>,
68    ) -> Result<mpsc::Receiver<Result<Self, Exception>>, Exception> {
69        let exp = self;
70        let snap = parent_snapshot.clone();
71        // TODO: do this without clone
72        let (sender, receiver) = mpsc::channel::<Result<Self, Exception>>();
73        if let Ok(th) = thread::Builder::new()
74            .stack_size(64 * 1024 * 1024)
75            .spawn(move || {
76                sender.send(exp.eval(snap, env)).unwrap();
77            })
78        {
79            match th.join() {
80                Ok(_) => {}
81                Err(_) => {
82                    return Err(Exception::new(
83                        EV::Concurrency,
84                        Some(parent_snapshot),
85                        Some("could not wait for thread to finish executing".to_string()),
86                    ))
87                }
88            }
89        };
90        Ok(receiver)
91    }
92
93    pub fn eval(
94        &self,
95        parent_snapshot: Locker<CallSnapshot>,
96        env: Locker<Environment>,
97    ) -> Result<Self, Exception> {
98        use Value::*;
99
100        let snapshot = CallSnapshot::new(&self, &parent_snapshot)?;
101
102        let snap = || snapshot.clone();
103
104        match &self.value {
105            List(vals) => {
106                if !vals.is_empty() {
107                    let operator = vals.get(0).unwrap();
108                    let arguments: Vec<&Expression> = vals.iter().skip(1).collect();
109                    match &operator.value {
110                        Operator(operand) => operand.apply(snapshot, arguments, self, env),
111                        List(_) | Symbol(_) => {
112                            let evaled_operator = operator.eval(snap(), env.clone())?;
113                            let mut new_list = vec![evaled_operator];
114                            for arg in arguments {
115                                new_list.push(arg.clone());
116                            }
117                            Expression::new(Value::List(new_list)).eval(snap(), env)
118                        }
119                        Lambda(function) | Macro(function) => {
120                            let mut scoped_env = match &operator.value {
121                                Lambda(_) => Environment::root()
122                                    .with_parent(function.lexical_scope.clone(), None),
123                                Macro(_) => {
124                                    let mut env =
125                                        Environment::root().with_parent(env.clone(), None);
126                                    env.add_parent(function.lexical_scope.clone(), None);
127                                    env
128                                }
129                                _ => unreachable!(),
130                            };
131
132                            if function.collapse_input {
133                                let sym = function.params.get(0).unwrap(); // this unwrap will always be ok; it is enforced by the parser
134                                let args_evaled = {
135                                    let mut list = Vec::new();
136                                    for arg_expr in arguments {
137                                        list.push(match &operator.value {
138                                            Lambda { .. } => arg_expr.eval(snap(), env.clone())?,
139                                            Macro { .. } => arg_expr.clone(),
140                                            _ => unreachable!(),
141                                        });
142                                    }
143                                    list
144                                };
145                                let arg = Expression::new(Value::List(args_evaled));
146                                scoped_env.assign(sym.clone(), arg, true, snap())?;
147                            } else {
148                                exp_assert!(
149                                    function.params.len() == arguments.len(),
150                                    EV::ArgumentMismatch(
151                                        arguments.len(),
152                                        format!("{}", function.params.len())
153                                    ),
154                                    snap()
155                                );
156                                for (symbol, arg_expr) in
157                                    function.params.iter().zip(arguments.into_iter())
158                                {
159                                    let arg_evaled = match &operator.value {
160                                        Lambda { .. } => arg_expr.eval(snap(), env.clone())?,
161                                        Macro { .. } => arg_expr.clone(),
162                                        _ => unreachable!(),
163                                    };
164                                    scoped_env.assign(symbol.clone(), arg_evaled, true, snap())?;
165                                }
166                            }
167                            if let Macro { .. } = &operator.value {
168                                scoped_env = scoped_env.shadow();
169                            };
170                            let mut result = Expression::nil();
171                            let scoped_env_lock = Locker::new(scoped_env);
172                            for exp in &function.expressions {
173                                result = exp.eval(snap(), scoped_env_lock.clone())?;
174                            }
175                            Ok(result)
176                        }
177                        val => exp!(EV::InvalidOperator(val.clone()), snapshot),
178                    }
179                } else {
180                    Ok(self.clone())
181                }
182            }
183            Symbol(sym) => match env
184                .read()
185                .expect("unable to access environment (are threads locked?)")
186                .lookup(&sym)
187            {
188                Some(exp) => Ok(exp.read().unwrap().clone()), // TODO: make this not need a clone (allow returning pointers)
189                None => exp!(EV::UndefinedSymbol(sym.clone()), snapshot),
190            },
191            _ => Ok(self.clone()),
192        }
193    }
194}
195
196impl fmt::Display for Expression {
197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        write!(f, "{}", self.value)
199    }
200}
201
202impl PartialOrd for Expression {
203    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
204        self.value.partial_cmp(&other.value)
205    }
206}