interpreter/
lib.rs

1//! # Interpreter Module
2//!
3//! The Interpreter module is responsible for the execution, and runtime management of a
4//! SAP program. Through the [`eval_program()`] function, the AST is traversed, and the
5//! actual runtime logic of each node is applied. For example if a [`Binary`] node is
6//! encountered, it is converted into it's actual value (i.e. `1+2` becomes `3`).
7//!
8//! ## Values
9//!
10//! [`Value`]s a repsented as enum. The same module also contains all the logic for
11//! manipulating values, such as comparing, adding, subtracting and so on...
12//!
13//! ## Environment
14//!
15//! At runtime, values which aren't directly stored in the AST (i.e variables) are stored
16//! in an [`Environment`]. An environment is made up of 2 things: A hashmap binding the
17//! variable names to the data they store, and a reference to the outer/parent
18//! environment.
19//!
20//! ## Execution
21//!
22//! As previosuly mentioned, a SAP program is executed by traversing it's AST, and
23//! applying the runtime logic of each node. This can be evaluating numerical expression,
24//! retrieving/storing variables, repetition or displaying to the console.
25//!
26//! Before understanding traversal interrupts, it is important to note that the call stack
27//! is reflective of where in the tree the code has traversed, as each AST node has it's
28//! own dedicated function.
29//!
30//! There are two things which can interrupt the traversal of the tree:
31//! - Runtime errors
32//! - Return statements
33//!
34//! When a runtime error is encountered, traversal stops completely and
35//! the error is returned to the caller of the [`eval_program()`] function.
36//!
37//! When a return statement in encountered, the code backtracks up the tree until reaching
38//! a [`FunctionCall`] node, or the root ([`Program`]) node. If the root node is reached,
39//! this indicates the return statement was used outside of a function, which is treated
40//! as an error.
41//!
42//! If a [`FunctionCall`] node is reached, this indicates the return statement was used
43//! inside a function, which was invoked by this function call. The return value is
44//! unwrapped into a normal value, and can be used as normal in the place of the function
45//! call.
46//!
47//! For example, take the expression `set x = 1+add(1, 3)`, the function `add(1, 3)` might
48//! produce a `Return(Value(4))` which is then unwrapped into a `Value(4)`. The resulting
49//! statement now looks like `set x = 1+4`.
50use std::cell::RefCell;
51use std::ops::ControlFlow;
52use std::ops::ControlFlow::{Break, Continue};
53use std::rc::Rc;
54
55use ast::expression::{Binary, Expression, FunctionCall, Identifier, Selection, Unary};
56use ast::literal::Literal;
57use ast::statement::{
58    Display, FunctionDeclaration, RepeatForever, RepeatNTimes, RepeatUntil, Return, Set, Statement,
59};
60use ast::Program;
61use lexer::token::TokenKind;
62use shared::error::{Error, ErrorKind};
63use shared::{err, stdoutln};
64
65use crate::runtime::{EnvRef, Environment};
66use crate::value::{Function, Value};
67
68// Attempt to obtain the current version of the interpreter module.
69pub const VERSION: Option<&str> = std::option_env!("CARGO_PKG_VERSION");
70
71#[cfg(test)]
72mod test;
73
74pub mod runtime;
75pub mod value;
76
77/// Represents an interruption in traversal of the AST.
78///
79/// The reasons traversal may be interrupted are:
80/// 1. An error in encountered, in which case backtrack all the way up the call stack and
81///    return the error to the caller of the [`eval_program()`] function.
82/// 2. Or, a [`Return`] statement in encountered.
83///
84/// In the case of a [`Return`] statement, the code backtracks up the call stack to the
85/// point where the function containing the [`Return`] statement was called, and hands
86/// over the return value to the caller. If the return statement was used outside of a
87/// function, and the code reaches the end of the call stack, it is treated as an error.
88pub enum TraversalInterrupt {
89    ReturnValue(Rc<Value>),
90    Error(Error),
91}
92
93/// Type alias representing what the evaluation of a node produces.
94///
95/// It may either produce a [`Value`], indicating that the evaluation was a success and
96/// traversal may continue as normal, and it may produce a [`TraversalInterrupt`], which
97/// should be immediately returned from the current function, unless specified otherwise.
98type EvaluationOutcome = ControlFlow<TraversalInterrupt, Rc<Value>>;
99
100/// Shorthand macro for creating an [`Error`] wrapped in an [`EvaluationOutcome`].
101///
102/// # Arguments
103///
104/// Either:
105/// * `kind` - An [`ErrorKind`].
106/// * `err_msg` - The error message (Same syntax as the [`format!`] macro).
107///
108/// Or
109/// * `err` - An already constructed [`Error`].
110macro_rules! traversal_error {
111    ($kind:expr, $($arg:tt)*) => {
112        Break(TraversalInterrupt::Error(Error::new(&format!($($arg)*), $kind)))
113    };
114    ($err:ident) => {
115        Break(TraversalInterrupt::Error($err))
116    }
117}
118
119/// Shorthand function for creating a new empty [`EnvRef`]
120pub fn create_env() -> EnvRef {
121    return Rc::new(RefCell::new(Environment::new()));
122}
123
124/// Probably the most important function in the whole program, the main entry point of the
125/// SAP interpreter. It performs the actual execution of a program, returning a final
126/// result.
127///
128/// # Arguments
129///
130/// * `env` - An [`EnvRef`] representing the starting global environment. Data may be
131///   inserted ahead of time.
132/// * `ast` - An AST root ([`Program`]) node representing the program that is to be
133///   executed.
134///
135/// # Returns
136///
137/// Either an [`Ok`] containing a tuple
138pub fn eval_program(env: &EnvRef, ast: Program) -> Result<(EnvRef, Rc<Value>), Error> {
139    match eval_statements(env, &ast.statements) {
140        Break(TraversalInterrupt::ReturnValue(_)) => {
141            err!(ErrorKind::TypeError, "'return' used outside of function")
142        }
143        Break(TraversalInterrupt::Error(error)) => Err(error),
144        Continue(value) => Ok((env.clone(), value)),
145    }
146}
147
148/// Evaluates a list of [`Statement`]s, returning the result of the last statement.
149fn eval_statements(env: &EnvRef, statements: &Vec<Statement>) -> EvaluationOutcome {
150    let mut value = Rc::new(Value::Null);
151    for statement in statements {
152        value = eval_statement(env, &statement)?;
153    }
154    return Continue(value);
155}
156
157/// Evaluates a single [`Statement`], returning the result of the evaluation.
158fn eval_statement(env: &EnvRef, statement: &Statement) -> EvaluationOutcome {
159    match statement {
160        Statement::Expression(expression) => eval_expression(env, expression),
161        Statement::Return(ret) => eval_return_statement(env, ret),
162        Statement::Set(set_stmt) => eval_set_statement(env, set_stmt),
163        Statement::FunctionDeclaration(func) => eval_func_decl_statement(env, func),
164        Statement::RepeatNTimes(repeat) => eval_repeat_n_times_statement(env, repeat),
165        Statement::RepeatUntil(repeat) => eval_repeat_until_statement(env, repeat),
166        Statement::RepeatForever(repeat) => eval_repeat_forever_statement(env, repeat),
167        Statement::Display(display) => eval_display_statement(env, display),
168    }
169}
170
171/// Evaluates a [`Set`] statement, storing the result of the expression in the
172/// environment.
173fn eval_set_statement(env: &EnvRef, let_stmt: &Set) -> EvaluationOutcome {
174    let value = eval_expression(env, &let_stmt.expr)?;
175    let name = let_stmt.ident.name.clone();
176    env.borrow_mut().store(name, value);
177    return Continue(Rc::new(Value::Null));
178}
179
180/// Evaluates a [`Return`] statement, interrupting the traversal and returning the value
181/// to the caller.
182fn eval_return_statement(env: &EnvRef, ret: &Return) -> EvaluationOutcome {
183    let value = eval_expression(env, &ret.value)?;
184    return Break(TraversalInterrupt::ReturnValue(value));
185}
186
187/// Evaluates a [`FunctionDeclaration`] statement, storing the function in the
188/// environment.
189fn eval_func_decl_statement(env: &EnvRef, func: &FunctionDeclaration) -> EvaluationOutcome {
190    let parameters = func
191        .parameters
192        .iter()
193        .map(|ident| ident.name.clone())
194        .collect();
195
196    let name = func.name.name.clone();
197    let value = Rc::new(Value::Function(Function {
198        parameters,
199        body: func.body.statements.clone(),
200        env: env.clone(),
201    }));
202
203    env.borrow_mut().store(name, value);
204    return Continue(Rc::new(Value::Null));
205}
206
207/// Evaluates a [`Display`] statement, printing the result of the expressions to the
208/// console (or whatever [`stdoutln!`] outputs to).
209fn eval_display_statement(env: &EnvRef, display: &Display) -> EvaluationOutcome {
210    // Evaluate each item in the display statement, convert it to a string and print it as one
211    // string, separated by spaces.
212    let mut values = Vec::new();
213    for expression in &display.expressions {
214        match eval_expression(env, expression)?.cast_to_string() {
215            Value::String(s) => values.push(s),
216            _ => unreachable!(),
217        };
218    }
219    stdoutln!("{}", values.join(" "));
220    return Continue(Rc::new(Value::Null));
221}
222
223/// Evaluates a [`RepeatForever`] statement, repeating the body of the statement forever.
224fn eval_repeat_forever_statement(env: &EnvRef, repeat: &RepeatForever) -> EvaluationOutcome {
225    loop {
226        eval_statements(env, &repeat.body.statements)?;
227    }
228}
229
230/// Evaluates a [`RepeatNTimes`] statement, repeating the body of the statement `n` times.
231fn eval_repeat_n_times_statement(env: &EnvRef, repeat: &RepeatNTimes) -> EvaluationOutcome {
232    // From the given `repeat` arugment, determine the number of times to repeat the body.
233    let n_rc = eval_expression(env, &repeat.n)?;
234    let n = match n_rc.as_ref() {
235        Value::Integer(n) => {
236            if *n < 0 {
237                return traversal_error!(
238                    ErrorKind::TypeError,
239                    "repeat _ times expected non-negative integer, got '{}'",
240                    n
241                );
242            }
243            *n as usize
244        }
245        _ => {
246            return traversal_error!(
247                ErrorKind::TypeError,
248                "repeat _ times expected non-negative integer, got type {}",
249                n_rc.variant_name()
250            )
251        }
252    };
253
254    // Repeat the body `n` times
255    for _ in 0..n {
256        eval_statements(env, &repeat.body.statements)?;
257    }
258
259    // This statement does not produce a value, so return `null`.
260    return Continue(Rc::new(Value::Null));
261}
262
263/// Evaluates a [`RepeatUntil`] statement, repeating the body of the statement until a
264/// given condition is `true`.
265fn eval_repeat_until_statement(env: &EnvRef, repeat: &RepeatUntil) -> EvaluationOutcome {
266    loop {
267        // Determine if the condition is `true`, if so, break the loop.
268        let condition = eval_expression(env, &repeat.condition)?.cast_to_boolean();
269        let condition_value = match condition {
270            Ok(value) => value,
271            Err(e) => return traversal_error!(e),
272        };
273        if let Value::Boolean(true) = condition_value {
274            break;
275        }
276        // Otherwise, continue evaluating the body of the repeat statement.
277        eval_statements(env, &repeat.body.statements)?;
278    }
279
280    // This statement does not produce a value, so return `null`.
281    return Continue(Rc::new(Value::Null));
282}
283
284/// Evaluates an [`Expression`], returning the result of the evaluation.
285fn eval_expression(env: &EnvRef, expression: &Expression) -> EvaluationOutcome {
286    match expression {
287        Expression::Literal(literal) => eval_literal(literal),
288        Expression::Unary(unary) => eval_unary_expression(env, unary),
289        Expression::Binary(binary) => eval_binary_expression(env, binary),
290        Expression::Selection(selection) => eval_selection_expression(env, selection),
291        Expression::Identifier(ident) => eval_identifier_expression(env, ident),
292        Expression::FunctionCall(func_call) => eval_func_call_expression(env, func_call),
293        // Array related expressions have been implemented in the parser, but not in the
294        // interpreter (yet!).
295        _ => traversal_error!(
296            ErrorKind::NotImplemented,
297            "expression type '{}' has not been implemented by the interpreter",
298            expression
299        ),
300    }
301}
302
303/// Evaluates a [`Literal`], returning the result of the evaluation.
304fn eval_literal(literal: &Literal) -> EvaluationOutcome {
305    let result = match literal {
306        Literal::Integer { value, .. } => Ok(Value::Integer(*value)),
307        Literal::Float { value, .. } => Ok(Value::Float(*value)),
308        Literal::Boolean { value, .. } => Ok(Value::Boolean(*value)),
309        Literal::String { value, .. } => Ok(Value::String(value.to_owned())),
310    };
311    match result {
312        Ok(value) => Continue(Rc::new(value)),
313        Err(e) => traversal_error!(e),
314    }
315}
316
317/// Evaluates a [`Unary`] expression, returning the result of the evaluation.
318fn eval_unary_expression(env: &EnvRef, unary: &Unary) -> EvaluationOutcome {
319    // Evaluate the left hand side of the unary expression.
320    let left_rc = eval_expression(env, &unary.operand)?;
321    let left = left_rc.as_ref();
322
323    // Perform the operation on the left hand side.
324    let result = match unary.operator {
325        TokenKind::Not => left.not(),
326        TokenKind::Minus => left.neg(),
327        _ => {
328            return traversal_error!(
329                ErrorKind::TypeError,
330                "invalid operation '{}' for type {}",
331                unary.operator,
332                left.variant_name(),
333            )
334        }
335    };
336    match result {
337        Ok(value) => Continue(Rc::new(value)),
338        Err(e) => traversal_error!(e),
339    }
340}
341
342/// Evaluates a [`Binary`] expression, returning the result of the evaluation.
343fn eval_binary_expression(env: &EnvRef, binary: &Binary) -> EvaluationOutcome {
344    // Evaluate the left and right hand side of the binary expression.
345    let left_rc = eval_expression(env, &binary.left)?;
346    let right_rc = eval_expression(env, &binary.right)?;
347
348    // Borrow the values inside the Rc<Value>.
349    let left = left_rc.as_ref();
350    let right = right_rc.as_ref();
351
352    // Perform the operation on the left and right hand side.
353    let result = match binary.operator {
354        TokenKind::Plus => left.add(right),
355        TokenKind::Minus => left.sub(right),
356        TokenKind::Mult => left.mul(right),
357        TokenKind::Div => left.div(right),
358        TokenKind::Eq => left.eq(right),
359        TokenKind::NotEq => left.ne(right),
360        TokenKind::Lt => left.lt(right),
361        TokenKind::LtEq => left.le(right),
362        TokenKind::Gt => left.gt(right),
363        TokenKind::GtEq => left.ge(right),
364        TokenKind::And => left.and(right),
365        TokenKind::Or => left.or(right),
366        TokenKind::Mod => left.rem(right),
367        _ => {
368            return traversal_error!(
369                ErrorKind::TypeError,
370                "invalid operation '{}' between {} and {}",
371                binary.operator,
372                left.variant_name(),
373                right.variant_name(),
374            )
375        }
376    };
377    match result {
378        Ok(value) => Continue(Rc::new(value)),
379        Err(e) => traversal_error!(e),
380    }
381}
382
383/// Evaluates a [`Selection`] expression, returning the result of the evaluation.
384fn eval_selection_expression(env: &EnvRef, selection: &Selection) -> EvaluationOutcome {
385    // Evaluate the condition of the selection statement.
386    let result = eval_expression(env, &selection.condition)?.cast_to_boolean();
387    let condition_value = match result {
388        Ok(value) => value,
389        Err(e) => return traversal_error!(e),
390    };
391
392    // If the condition is `true`, evaluate the body of the selection statement. Otherwise,
393    // evaluate the body of the `else` statement, if it exists (otherwise, return `null`).
394    match condition_value {
395        Value::Boolean(b) => {
396            if b {
397                eval_statements(env, &selection.conditional.statements)
398            } else if let Some(else_conditional) = &selection.else_conditional {
399                eval_statements(env, &else_conditional.statements)
400            } else {
401                Continue(Rc::new(Value::Null))
402            }
403        }
404        // The `cast_to_boolean` function guarantees that the result is a boolean, so this
405        // should never be reached.
406        _ => unreachable!(),
407    }
408}
409
410/// Evaluates an [`Identifier`] expression, returning the result of the evaluation.
411fn eval_identifier_expression(env: &EnvRef, ident: &Identifier) -> EvaluationOutcome {
412    return lookup_variable_name(env, &ident.name);
413}
414
415/// Evaluates a [`FunctionCall`] expression, returning the result of the evaluation.
416fn eval_func_call_expression(env: &EnvRef, func_call: &FunctionCall) -> EvaluationOutcome {
417    // Evaluate callee
418    let callee = eval_expression(env, &func_call.callee)?;
419
420    // Evaluate each argument and store the result in the arguments vector.
421    let mut arguments = Vec::new();
422    for expression in &func_call.arguments {
423        let value = eval_expression(env, expression)?;
424        arguments.push(value);
425    }
426
427    return apply_function(&callee, &arguments);
428}
429
430/// Applies a function to a list of arguments, returning the result of the evaluation.
431///
432/// To "apply" a function means to create a new environment for the function, execute
433/// the body of the function, and return the result of the body.
434fn apply_function(callee: &Rc<Value>, arguments: &Vec<Rc<Value>>) -> EvaluationOutcome {
435    match &**callee {
436        Value::Function(function) => {
437            // Create a new environment for the function.
438            let mut env = Environment::new_enclosed_environment(&function.env);
439
440            // Transfer the arguments into the new environment.
441            for (param_name, arg_value) in function.parameters.iter().zip(arguments.iter()) {
442                env.store(param_name.clone(), arg_value.clone())
443            }
444
445            // Execute the body of the function and handle the result
446            match eval_statements(&Rc::new(RefCell::new(env)), &function.body) {
447                Break(TraversalInterrupt::ReturnValue(value)) => Continue(value),
448                Break(TraversalInterrupt::Error(err)) => traversal_error!(err),
449                _ => Continue(Rc::new(Value::Null)),
450            }
451        }
452        _ => traversal_error!(
453            ErrorKind::TypeError,
454            "'{}' is not callable",
455            callee.variant_name(),
456        ),
457    }
458}
459
460/// Attempts to lookup a variable name in the environment, returning the result of the
461/// evaluation.
462fn lookup_variable_name(env: &EnvRef, name: &str) -> EvaluationOutcome {
463    if let Some(value) = env.borrow().lookup(name) {
464        Continue(value)
465    } else {
466        traversal_error!(ErrorKind::NameError, "variable '{}' does not exist", name)
467    }
468}