1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
//! Evaluation abstract syntax tree visitor.
//!
//! This module contains the trait and implementation for walking an annotated abstract syntax tree
//! and evaluating it. This implementation expects that the symbol table and type computation
//! annotations already exist on the tree.

use std::rc::Rc;

use sindra::Node;
use sindra::Typed;
use sindra::scope::{SymbolStore, MemoryStore, Scoped};
use sindra::operator::{UnaryOperator, BinaryOperator};
use sindra::value::Coerce;

use ast::*;
use Symbol;
use symbol::FunctionBody;
use value::{Value, ValueSet, SetInterval};
use visitor::State;

type Result = ::std::result::Result<Value, String>;

/// Trait for evaluation visitor; implemented for all abstract syntax tree nodes.
pub trait EvaluateVisitor {
    /// Walk the tree, evaluating and producing a result from the program.
    fn visit(&self, &mut State) -> Result;
}

impl EvaluateVisitor for Node<Program> {
    fn visit(&self, state: &mut State) -> Result {
        self.item.0.visit(state)
    }
}

impl EvaluateVisitor for Node<Block> {
    fn visit(&self, state: &mut State) -> Result {
        let mut last_result: Value = Value::Empty;
        for statement in self.item.0.iter() {
            last_result = statement.visit(state)?;
            // if we have a return / break value, short-circuit this block and return it
            match last_result {
                Value::Return(_) | Value::Break(_) => { return Ok(last_result); }
                _ => {}
            }
        }
        Ok(last_result)
    }
}

impl EvaluateVisitor for Node<Statement> {
    fn visit(&self, state: &mut State) -> Result {
        match (&self.item, &self.annotation) {
            (&Statement::Declare(ref ident, ref expr), &ref annotation) => {
                match annotation.borrow().scope() {
                    Some(ref scope) => {
                        let value = expr.visit(state)?;
                        scope.borrow_mut().set(ident.item.clone(), value.clone())?;
                        Ok(value)
                    },
                   None => Err("no associated scope in declaration statement".to_string())
                }
            },
            (&Statement::Assign(ref ident, ref expr), &ref annotation) => {
                match annotation.borrow().scope() {
                    Some(ref scope) => {
                        let value = expr.visit(state)?;
                        scope.borrow_mut().set(ident.item.clone(), value.clone())?;
                        Ok(value)
                    },
                    None => Err("no associated scope in assignment statement".to_string())
                }
            },
            (&Statement::Expression(ref expr), _) => {
                expr.visit(state)
            },
            (&Statement::FnDefine { .. }, _) => {
                // nothing to evaluate for function definitions
                Ok(Value::Empty)
            },
            (&Statement::Return(ref expr), _) => {
                Ok(Value::Return(Box::new(expr.visit(state)?)))
            },
            (&Statement::Break(ref expr), _) => {
                Ok(Value::Break(Box::new(expr.visit(state)?)))
            },
            (&Statement::Print(ref exprs), _) => {
                for expr in exprs {
                    let value = expr.visit(state)?;
                    write!(&mut state.io.stdout(), "{}", value).unwrap();
                }
                writeln!(&mut state.io.stdout(), "").unwrap();
                Ok(Value::Empty)
            }
        }
    }
}

impl EvaluateVisitor for Node<Expression> {
    fn visit(&self, state: &mut State) -> Result {
        match (&self.item, &self.annotation) {
            (&Expression::Literal(ref literal), _) => {
                Ok(Value::from(literal.item.clone()))
            },
            (&Expression::Identifier(ref ident), &ref annotation) => {
                let ident = &ident.item;
                match annotation.borrow().scope() {
                    Some(ref scope) => {
                        match scope.borrow().get(&ident) {
                            Some(ref value) => Ok(value.clone()),
                            None => Err(format!("uninitialized variable: {}", ident))
                        }
                    },
                    None => Err("invalid scope".to_string())
                }
            },
            (&Expression::Infix { ref op, ref left, ref right },
                    &ref annotation) => {
                let lval = left.visit(state)?;
                let rval = right.visit(state)?;

                op.op(
                    annotation.borrow().ty().unwrap(),
                    &lval.coerce(left.annotation.borrow().promote_type()),
                    &rval.coerce(right.annotation.borrow().promote_type())
                )
            },
            (&Expression::Prefix { ref op, ref right }, &ref annotation) => {
                let rval = right.visit(state)?;

                op.op(
                    annotation.borrow().ty().unwrap(),
                    &rval.coerce(right.annotation.borrow().promote_type())
                )
            },
            (&Expression::Postfix { ref op, ref left }, &ref annotation) => {
                let lval = left.visit(state)?;

                op.op(
                    annotation.borrow().ty().unwrap(),
                    &lval.coerce(left.annotation.borrow().promote_type())
                )
            },
            (&Expression::Block(ref block), _) => {
                block.visit(state)
            }
            (&Expression::FnCall { ref name, ref args, .. } , &ref annotation) => {
                let mut evaluated_args = vec![];
                for arg in args {
                    evaluated_args.push(arg.visit(state)?);
                }

                let scope = annotation.borrow().scope().ok_or(format!(
                    "invalid scope when calling function \
                    '{}'", name.item))?;

                let sym: Symbol = scope.borrow().resolve(&name.item).ok_or(format!(
                    "symbol not found: '{}'", name.item))?;

                match sym {
                    Symbol::Function { ref name, body: FunctionBody::Ast(ref body),
                            ref params, .. } => {
                        let fn_scope = body.annotation.borrow().scope().ok_or(
                            format!("missing function scope for function \
                                '{}'", name)
                        )?;

                        // establish arguments as parameters in new scope
                        for (i, arg) in evaluated_args.iter().enumerate() {
                            let param = &params[i];
                            let pname = param.item.name.item.clone();
                            fn_scope.borrow_mut().set(pname.clone(), arg.clone())?;
                        }

                        let prev_scope = Rc::clone(&state.scope);
                        state.scope = fn_scope;
                        // evaluate body, and handle possible return values (by unwrapping them)
                        let val = match body.visit(state)? {
                            Value::Return(returned_val) => {
                                *returned_val
                            },
                            val => val,
                        };

                        // reset scope
                        state.scope = Rc::clone(&prev_scope);
                        // return result
                        Ok(val)
                    },
                    Symbol::Function { body: FunctionBody::External(ext_func_id), .. } => {
                        state.std_funcs.call(&mut state.std_env, ext_func_id, evaluated_args)
                    },
                    _ => Err(format!("unable to call symbol '{}' as function", name.item))
                }
            }
            (&Expression::IfElse { ref cond, ref if_block, ref else_block }, _) => {
                match cond.visit(state)? {
                    Value::Boolean(b) => {
                        if b {
                            if_block.visit(state)
                        } else {
                            if let Some(ref eblock) = *else_block {
                                eblock.visit(state)
                            } else {
                                // only if block exists; thus no value is generated
                                Ok(Value::Empty)
                            }
                        }
                    },
                    _ => Err(format!("conditional expression expected to be boolean"))
                }
            }
            (&Expression::Loop { ref variant, ref set, ref body }, _) => {
                let value_set = match set.visit(state)? {
                    Value::Set(value_set) => value_set,
                    _ => { return Err("loop specification did not evaluate as a set".to_string()); }
                };
                let mut val = Value::Empty;
                for elem in value_set.iter()? {
                    if let Some(scope) = body.annotation.borrow().scope() {
                        match *variant {
                            Some(ref var) => {
                                scope.borrow_mut().set(var.item.clone(), elem.clone())?;
                            },
                            None => {}
                        }
                    } else {
                        return Err(
                            "missing scope when trying to evaluate loop".to_string());
                    }
                    match body.visit(state)? {
                        Value::Break(returned_val) => {
                            val = *returned_val;
                            break;
                        },
                        v => {
                            val = v;
                        }
                    }
                }
                Ok(val)
            }
        }
    }
}

impl EvaluateVisitor for Node<Set> {
    fn visit(&self, state: &mut State) -> Result {
        match self.item {
            Set::Interval { ref start, ref end, end_inclusive, ref step } => {
                Ok(Value::Set(Box::new(ValueSet::Interval(SetInterval {
                    start: start.visit(state)?,
                    end: end.visit(state)?,
                    end_inclusive: end_inclusive,
                    step: step.visit(state)?,
                }))))
            }
        }
    }
}