runmat-vm 0.5.0

RunMat virtual machine and bytecode interpreter
Documentation
use crate::object::resolve as obj_resolve;
use runmat_builtins::Value;
use runmat_gc::gc_record_write;
use runmat_runtime::RuntimeError;

pub async fn dispatch_object(
    instr: &crate::bytecode::Instr,
    stack: &mut Vec<Value>,
    current_function_name: &str,
) -> Result<bool, RuntimeError> {
    let caller_function_name = if current_function_name.is_empty() {
        None
    } else {
        Some(current_function_name)
    };
    match instr {
        crate::bytecode::Instr::LoadMember(field) => {
            let base = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let value =
                obj_resolve::load_member(base, field.clone(), false, caller_function_name).await?;
            stack.push(value);
            Ok(true)
        }
        crate::bytecode::Instr::LoadMemberOrInit(field) => {
            let base = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let value =
                obj_resolve::load_member(base, field.clone(), true, caller_function_name).await?;
            stack.push(value);
            Ok(true)
        }
        crate::bytecode::Instr::LoadMemberDynamic => {
            let name_val = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let base = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let name: String = (&name_val).try_into()?;
            let value =
                obj_resolve::load_member_dynamic(base, name, false, caller_function_name).await?;
            stack.push(value);
            Ok(true)
        }
        crate::bytecode::Instr::LoadMemberDynamicOrInit => {
            let name_val = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let base = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let name: String = (&name_val).try_into()?;
            let value =
                obj_resolve::load_member_dynamic(base, name, true, caller_function_name).await?;
            stack.push(value);
            Ok(true)
        }
        crate::bytecode::Instr::StoreMember(field) => {
            let rhs = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let base = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let value = obj_resolve::store_member(
                base,
                field.clone(),
                rhs,
                false,
                caller_function_name,
                |oldv, newv| {
                    gc_record_write(oldv, newv);
                },
            )
            .await?;
            stack.push(value);
            Ok(true)
        }
        crate::bytecode::Instr::StoreMemberOrInit(field) => {
            let rhs = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let base = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let value = obj_resolve::store_member(
                base,
                field.clone(),
                rhs,
                true,
                caller_function_name,
                |oldv, newv| {
                    gc_record_write(oldv, newv);
                },
            )
            .await?;
            stack.push(value);
            Ok(true)
        }
        crate::bytecode::Instr::StoreMemberDynamic => {
            let rhs = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let name_val = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let base = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let name: String = (&name_val).try_into()?;
            let value = obj_resolve::store_member_dynamic(
                base,
                name,
                rhs,
                false,
                caller_function_name,
                |oldv, newv| {
                    gc_record_write(oldv, newv);
                },
            )
            .await?;
            stack.push(value);
            Ok(true)
        }
        crate::bytecode::Instr::StoreMemberDynamicOrInit => {
            let rhs = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let name_val = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let base = stack.pop().ok_or(crate::interpreter::errors::mex(
                "StackUnderflow",
                "stack underflow",
            ))?;
            let name: String = (&name_val).try_into()?;
            let value = obj_resolve::store_member_dynamic(
                base,
                name,
                rhs,
                true,
                caller_function_name,
                |oldv, newv| {
                    gc_record_write(oldv, newv);
                },
            )
            .await?;
            stack.push(value);
            Ok(true)
        }
        _ => Ok(false),
    }
}