dark-vm 0.4.3

A new VM called the DarkVM, which focuses on speed and simplicity.
Documentation
//! The VM struct represents the VM state after any given changes.
//! This struct maintains the code that is given and the stack.
//! This struct also should not change that much. The only changes would be additions to value enum and evaluate_value function.
//!
//! The VM can be invoked after the lexer has been run.
//!
//! # Example
//! ```
//! # fn run() -> Result<(), Error> {
//! let contents = "push 1";
//! let tokens = Lexer::new().lex(contents)?;
//! let result = VM::new(tokens).run()?;
//! # Ok(())
//! # }
//! ```

use crate::{
    code::Code,
    errors::{error::Error, error_kind::ErrorKind},
    tokens::token::Token,
    utils::{frames::Frame, stack::Stack},
    values::{value::Value, value_kinds::ValueKind},
};

use std::{collections::VecDeque, rc::Rc};

#[derive(Debug)]
pub struct VM {
    code: Code,
    pub operand_stack: Stack<Rc<Value>>,
    call_stack: Stack<Frame>,
}

impl VM {
    /// Constructs a new VM with the specified tokens.
    /// The tokens are usually generated through the lexer.
    /// Internally, the tokens are converted to different values by the code object.
    ///
    /// # Arguments
    /// `tokens` - The tokens produced by the lexer.
    pub fn new(tokens: VecDeque<Token>) -> Result<VM, Error> {
        let code = Code::new(tokens)?;
        let main_frame = Frame::new(0, "main", None);
        let mut call_stack = Stack::new();
        call_stack.push(main_frame);
        Ok(VM {
            code,
            operand_stack: Stack::new(),
            call_stack,
        })
    }

    /// Creates a VM in REPL mode.
    pub fn repl() -> Result<VM, Error> {
        let main_frame = Frame::new(0, "main", None);
        let mut call_stack = Stack::new();
        call_stack.push(main_frame);
        Ok(
            VM {
                code: Code::repl(VecDeque::new())?,
                operand_stack: Stack::new(),
                call_stack
            }
        )
    }

    /// Loads the given tokens into the VM.
    /// This function does not change the operand stack or the call stack.
    /// This function can be used with the REPL mode to help facilitate a proper REPL experience.
    ///
    /// # Arguments
    /// `tokens` - The tokens to load.
    pub fn load_tokens(&mut self, tokens: VecDeque<Token>) -> Result<(), Error> {
        self.code = Code::repl(tokens)?;
        Ok(())
    }

    /// Runs the VM until the end of the code.
    /// This function may return an optionally value, representing the value of the last expression.
    /// It may also prematurely return an error. This may be updated to return a vector of errors.
    pub fn run(&mut self) -> Result<Option<Rc<Value>>, Error> {
        loop {
            // A seperate function must be called here.
            // Otherwise, Rust's borrow checker will complain with the error that self.code is mutabley borrowed more than once.
            if self.is_finished() {
                return Ok(None);
            }

            let next = self.next().unwrap();
            let result = self.evaluate_value(next)?;
            if self.is_finished() && result.is_some() {
                return Ok(result);
            }
        }
    }

    /// Evaluates the next value.
    /// This means every value is an expression in some sense.
    ///
    /// # Arguments
    /// `value` - The value to evaluate.
    fn evaluate_value(&mut self, value: Rc<Value>) -> Result<Option<Rc<Value>>, Error> {
        match &value.kind {
            ValueKind::Void => Ok(None),
            ValueKind::Any => Ok(None),

            ValueKind::Int(_)
            | ValueKind::Float(_)
            | ValueKind::Boolean(_)
            | ValueKind::String(_) => Ok(Some(value)),

            // Cloning here is cheap because val is reference counted, so only a counter is incremented.
            ValueKind::Identifier(name) => self
                .call_stack
                .peek()
                .unwrap()
                .find(name, value.pos)
                .map(Some),
            ValueKind::Label(_) => {
                let mut found_end = false;
                while let Some(value) = self.next() {
                    if let ValueKind::End = value.kind {
                        found_end = true;
                        break;
                    }
                }

                if !found_end {
                    Err(Error::new(ErrorKind::NoEndOfLabel, value.pos))
                } else {
                    Ok(None)
                }
            }
            ValueKind::End => {
                let frame = self.call_stack.pop(value.pos)?;
                if let Some(error) = self
                    .code
                    .jump(frame.get_caller_position() as i64, value.pos)
                {
                    Err(error)
                } else {
                    Ok(None)
                }
            }

            ValueKind::Push => self.push(value.pos),
            ValueKind::Pop => self.pop(value.pos).map(|(_, value)| value),
            ValueKind::Peek => self.operand_stack.peek().map_or(
                Ok(Some(Rc::new(Value::new(value.pos, ValueKind::Void)))),
                |peeked_value| Ok(Some(peeked_value.clone())),
            ),
            ValueKind::Add => self.add(value.pos),
            ValueKind::Sub => self.sub(value.pos),
            ValueKind::Mul => self.mul(value.pos),
            ValueKind::Div => self.div(value.pos),
            ValueKind::LessThan => self.lt(value.pos),
            ValueKind::LessThanEqual => self.lte(value.pos),
            ValueKind::GreaterThan => self.gt(value.pos),
            ValueKind::GreaterThanEqual => self.gte(value.pos),
            ValueKind::Equal => self.eq(value.pos),
            ValueKind::NotEqual => self.neq(value.pos),
            ValueKind::Jump => self.jmp(value.pos),
            ValueKind::RelativeJump => self.rjmp(value.pos),
            ValueKind::JumpIfTrue => self.jmpt(value.pos),
            ValueKind::JumpIfFalse => self.jmpf(value.pos),
            ValueKind::Print => self.print(value.pos),
            ValueKind::PrintNewLine => self.printn(value.pos),
            ValueKind::Set => self.set(value.pos),
            ValueKind::Call => self.call(value.pos),
        }
    }

    /// Pushes the next value on to the stack.
    /// This will call the get_arg method, which calls the evaluate_value function again.
    /// This ensures that instructions can be followed by more instructions as arguments.
    ///
    /// # Arguments
    /// `pos` - The position where the instruction was called.
    fn push(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        // Get the next argument. The two parameters passed are useful in the case of errors.
        let (pos, arg) = self.get_arg(1, pos)?;

        // If the argument does not exist, return an error, otherwise push it on to the stack.
        match arg {
            Some(value) => self.operand_stack.push(value),
            None => {
                return Err(Error::new(
                    ErrorKind::ValueMismatch(
                        ValueKind::Any.get_value_name(),
                        ValueKind::Void.get_value_name(),
                    ),
                    pos,
                ))
            }
        }

        Ok(None)
    }

    /// Pops the top value from the stack.
    ///
    /// # Arguments
    /// `pos` - The position where the instruction was called.
    fn pop(&mut self, pos: usize) -> Result<(usize, Option<Rc<Value>>), Error> {
        // Pop the value and if there are no errors, map it to an option with the value.
        // stack.pop takes the position where the instruction was used in the case that the stack was empty.
        self.operand_stack.pop(pos).map(|val| (val.pos, Some(val)))
    }

    /// Pops the top two values from the stack and adds them together.
    /// This internally calls both the pop instruction and the add method on the Value struct.
    ///
    /// # Arguments
    /// `pos` - The position where the instruction was called.
    fn add(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.pop(pos)?;
        let (arg_pos_2, arg2) = self.pop(pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => operand1
                .add(operand2.as_ref(), pos)
                .map(|val| Some(Rc::new(val))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Pops the top two values from the stack and subtracts them.
    /// This internally calls both the pop instruction and the sub method on the Value struct.
    ///
    /// # Arguments
    /// `pos` - The position where the instruction was called.
    fn sub(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.pop(pos)?;
        let (arg_pos_2, arg2) = self.pop(pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => operand1
                .sub(operand2.as_ref(), pos)
                .map(|val| Some(Rc::new(val))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Pops the top two values from the stack and multiplies them.
    /// This internally calls both the pop instruction and the mul method on the Value struct.
    ///
    /// # Arguments
    /// `pos` - The position where the instruction was called.
    fn mul(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.pop(pos)?;
        let (arg_pos_2, arg2) = self.pop(pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => operand1
                .mul(operand2.as_ref(), pos)
                .map(|val| Some(Rc::new(val))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Pops the top two values from the stack and divides them.
    /// This internally calls both the pop instruction and the div method on the Value struct.
    ///
    /// # Arguments
    /// `pos` - The position where the instruction was called.
    fn div(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.pop(pos)?;
        let (arg_pos_2, arg2) = self.pop(pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => operand1
                .div(operand2.as_ref(), pos)
                .map(|val| Some(Rc::new(val))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Compares the two arguments and returns if the first argument is less than the second argument.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn lt(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(2, pos)?;
        let (arg_pos_2, arg2) = self.get_arg(1, pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => operand1
                .lt(operand2.as_ref(), pos)
                .map(|val| Some(Rc::new(val))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Compares the two arguments and returns if the first argument is less than the second argument.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn lte(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(2, pos)?;
        let (arg_pos_2, arg2) = self.get_arg(1, pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => operand1
                .lte(operand2.as_ref(), pos)
                .map(|val| Some(Rc::new(val))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Compares the two arguments and returns if the first argument is less than the second argument.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn gt(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(2, pos)?;
        let (arg_pos_2, arg2) = self.get_arg(1, pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => operand1
                .gt(operand2.as_ref(), pos)
                .map(|val| Some(Rc::new(val))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Compares the two arguments and returns if the first argument is less than the second argument.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn gte(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(2, pos)?;
        let (arg_pos_2, arg2) = self.get_arg(1, pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => operand1
                .gte(operand2.as_ref(), pos)
                .map(|val| Some(Rc::new(val))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Compares the two arguments and returns if the first argument is less than the second argument.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn eq(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(2, pos)?;
        let (arg_pos_2, arg2) = self.get_arg(1, pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => Ok(Some(Rc::new(operand1.equal(operand2.as_ref(), pos)))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Compares the two arguments and returns if the first argument is less than the second argument.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn neq(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(2, pos)?;
        let (arg_pos_2, arg2) = self.get_arg(1, pos)?;

        match (arg1, arg2) {
            (Some(operand1), Some(operand2)) => Ok(Some(Rc::new(operand1.not_equal(operand2.as_ref(), pos)))),
            (None, _) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
            (_, None) => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_2,
            )),
        }
    }

    /// Changes the instruction pointer in the Code struct to the argument passed in.
    /// However, there are restrictions on the argument:
    /// - First, the argument must be an int.
    /// - Second, the argument must fit in the range 0 and values.len() inclusive.
    /// If either of these constraints are broken, an error is returned.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn jmp(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(1, pos)?;
        match arg1 {
            Some(value) => {
                if let ValueKind::Int(jump_location) = value.kind {
                    if let Some(error) = self.code.jump(jump_location, pos) {
                        Err(error)
                    } else {
                        Ok(None)
                    }
                } else {
                    Err(Error::new(
                        ErrorKind::ValueMismatch(
                            ValueKind::Int(0).get_value_name(),
                            value.kind.get_value_name(),
                        ),
                        arg_pos_1,
                    ))
                }
            }
            None => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Int(0).get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
        }
    }

    /// Changes the instruction pointer in the Code struct by the argument passed in.
    /// This argument can be positive or negative. However, it must meet the same bound requirements
    /// as the jmp instruction.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn rjmp(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(1, pos)?;
        match arg1 {
            Some(value) => {
                if let ValueKind::Int(jump_location) = value.kind {
                    if let Some(error) = self.code.relative_jump(jump_location, pos) {
                        Err(error)
                    } else {
                        Ok(None)
                    }
                } else {
                    Err(Error::new(
                        ErrorKind::ValueMismatch(
                            ValueKind::Int(0).get_value_name(),
                            value.kind.get_value_name(),
                        ),
                        arg_pos_1,
                    ))
                }
            }
            None => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Int(0).get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
        }
    }

    /// Changes the instruction pointer in the Code struct to the argument passed in
    /// if the top value on the stack is true.
    /// However, there are restrictions on the argument:
    /// - First, the argument must be an int.
    /// - Second, the argument must fit in the range 0 and values.len() inclusive.
    /// If either of these constraints are broken, an error is returned.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn jmpt(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        match self.operand_stack.peek() {
            Some(value) if value.is_truthy() => self.jmp(pos),
            None => Err(Error::new(ErrorKind::EmptyStack, pos)),
            _ => Ok(None),
        }
    }

    /// Changes the instruction pointer in the Code struct to the argument passed in
    /// if the top value on the stack is false.
    /// However, there are restrictions on the argument:
    /// - First, the argument must be an int.
    /// - Second, the argument must fit in the range 0 and values.len() inclusive.
    /// If either of these constraints are broken, an error is returned.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn jmpf(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        match self.operand_stack.peek() {
            Some(value) if !value.is_truthy() => self.jmp(pos),
            None => Err(Error::new(ErrorKind::EmptyStack, pos)),
            _ => Ok(None),
        }
    }

    /// Prints the argument passed in.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn print(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(1, pos)?;
        match arg1 {
            Some(value) => {
                print!("{:#?}", value);
                Ok(None)
            }
            None => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
        }
    }

    /// Prints the argument passed in with a new line after it.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn printn(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg(1, pos)?;
        match arg1 {
            Some(value) => {
                println!("{:#?}", value);
                Ok(None)
            }
            None => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Any.get_value_name(),
                    ValueKind::Void.get_value_name(),
                ),
                arg_pos_1,
            )),
        }
    }

    /// Sets the identifier passed in to the value passed in.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn set(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg_unevaluated(2, pos)?;
        let (arg_pos_2, arg2) = self.get_arg(1, pos)?;

        match &arg1.kind {
            ValueKind::Identifier(name) => {
                if let Some(value) = arg2 {
                    self.call_stack.peek_mut().unwrap().define(name, value);
                    Ok(None)
                } else {
                    Err(Error::new(
                        ErrorKind::ValueMismatch(
                            ValueKind::Any.get_value_name(),
                            ValueKind::Void.get_value_name(),
                        ),
                        arg_pos_2,
                    ))
                }
            }
            kind => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Identifier("".to_owned()).get_value_name(),
                    kind.get_value_name(),
                ),
                arg_pos_1,
            )),
        }
    }

    /// Calls the label passed in. In other words, it changes the instruction pointer.
    /// In the future, this would be changed to include the number of parameters on the stack.
    ///
    /// # Arguments
    /// `pos` - The position where this instruction was called.
    fn call(&mut self, pos: usize) -> Result<Option<Rc<Value>>, Error> {
        let (arg_pos_1, arg1) = self.get_arg_unevaluated(1, pos)?;
        match &arg1.kind {
            ValueKind::Identifier(label_name) => {
                let caller_pos = self.code.get_current_pos();
                let (start, end) = self.code.set_label_location(label_name, arg_pos_1)?;
                let store = self.call_stack.peek().filter(|frame| {
                    if let Some((cur_start, cur_end)) = self.code.get_label_start_end(&frame.name) {
                        cur_start < start && end < cur_end
                    } else {
                        false
                    }
                }).map(|frame| &frame.current_store);

                let new_frame = Frame::new(caller_pos, label_name, store);
                self.call_stack.push(new_frame);

                Ok(None)
            },
            kind => Err(Error::new(
                ErrorKind::ValueMismatch(
                    ValueKind::Label("".to_owned()).get_value_name(),
                    kind.get_value_name(),
                ),
                arg_pos_1,
            )),
        }
    }

    /// Gets the next argument.
    /// This funtion is usually called by instructions.
    ///
    /// # Arguments
    /// * `expected_args` - The number of arguments remaining for the instruction.
    /// * `pos` - The position where the instrution was called.
    fn get_arg(
        &mut self,
        expected_args: usize,
        pos: usize,
    ) -> Result<(usize, Option<Rc<Value>>), Error> {
        let arg = self
            .next()
            .ok_or_else(|| Error::new(ErrorKind::ExpectedArgs(expected_args), pos))?;
        Ok((arg.pos, self.evaluate_value(arg)?))
    }

    /// Gets the next argument.
    /// This funtion is usually called by instructions.
    ///
    /// # Arguments
    /// * `expected_args` - The number of arguments remaining for the instruction.
    /// * `pos` - The position where the instrution was called.
    fn get_arg_unevaluated(
        &mut self,
        expected_args: usize,
        pos: usize,
    ) -> Result<(usize, Rc<Value>), Error> {
        let arg = self
            .next()
            .ok_or_else(|| Error::new(ErrorKind::ExpectedArgs(expected_args), pos))?;
        Ok((arg.pos, arg))
    }

    /// Gets the next value.
    /// This method needs to be abstracted away because Rust will complain with the message that self.code was mutabley borrowed more than once.
    fn next(&mut self) -> Option<Rc<Value>> {
        self.code.next()
    }

    /// Checks if there are any more values left.
    /// This method needs to be abstracted away because Rust will complain with the message that self.code was mutabley borrowed more than once.
    fn is_finished(&self) -> bool {
        self.code.is_finished() || self.call_stack.is_empty()
    }
}