harn-vm 0.7.29

Async bytecode virtual machine for the Harn programming language
Documentation
use crate::chunk::{Constant, Op};
use crate::value::{VmError, VmValue};

use super::super::ExceptionHandler;

impl super::super::Vm {
    pub(super) fn try_execute_exception_op(&mut self, op: u8) -> Result<bool, VmError> {
        if op == Op::Throw as u8 {
            let val = self.pop()?;
            return Err(VmError::Thrown(val));
        } else if op == Op::TryCatchSetup as u8 {
            let frame = self.frames.last_mut().unwrap();
            let catch_offset = frame.chunk.read_u16(frame.ip) as usize;
            frame.ip += 2;
            let type_idx = frame.chunk.read_u16(frame.ip) as usize;
            frame.ip += 2;
            let error_type = match &frame.chunk.constants[type_idx] {
                Constant::String(s) => s.clone(),
                _ => String::new(),
            };
            self.exception_handlers.push(ExceptionHandler {
                catch_ip: catch_offset,
                stack_depth: self.stack.len(),
                frame_depth: self.frames.len(),
                env_scope_depth: self.env.scope_depth(),
                error_type,
            });
        } else if op == Op::PopHandler as u8 {
            self.exception_handlers.pop();
        } else if op == Op::TryUnwrap as u8 {
            let val = self.pop()?;
            match &val {
                VmValue::EnumVariant {
                    enum_name,
                    variant,
                    fields,
                } if enum_name == "Result" => {
                    if variant == "Ok" {
                        self.stack
                            .push(fields.first().cloned().unwrap_or(VmValue::Nil));
                    } else {
                        return Err(VmError::Return(val));
                    }
                }
                other => {
                    return Err(VmError::TypeError(format!(
                        "? operator requires a Result value, got {}",
                        other.type_name()
                    )));
                }
            }
        } else {
            return Ok(false);
        }
        Ok(true)
    }
}