glyph-runtime 0.0.1

Runtime execution engine for the Glyph programming language
Documentation
//! VM instruction set for Glyph runtime

use glyph_types::Value;
use serde::{Deserialize, Serialize};

/// Bytecode instructions for the Glyph VM
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Instruction {
    // Stack operations
    Push(Value),
    Pop,
    Dup,
    Swap,
    Rot3, // Rotate top 3 stack items

    // Arithmetic (all immutable operations)
    Add,
    Sub,
    Mul,
    Div,
    Mod,
    Neg,
    Pow,

    // Comparison
    Eq,
    Ne,
    Lt,
    Le,
    Gt,
    Ge,

    // Logical
    And,
    Or,
    Not,

    // Control flow
    Jump(usize),
    JumpIf(usize),
    JumpIfNot(usize),
    Call(usize),        // function index
    CallNative(String), // native function name
    Return,

    // Immutable bindings (no mutation allowed)
    BindLocal(String),  // Create new immutable binding
    LoadLocal(String),  // Load from local binding
    LoadGlobal(String), // Load from global binding

    // Collections (all operations create new collections)
    MakeList(usize),                 // number of elements
    MakeDict(usize),                 // number of key-value pairs
    MakeTuple(usize),                // immutable tuple
    GetIndex,                        // Push collection[index]
    GetAttr(String),                 // Push object.attr
    Slice(Option<i64>, Option<i64>), // collection[start:end]

    // Collection builders (create new collections)
    ListAppend, // [list, item] -> new_list
    ListConcat, // [list1, list2] -> new_list
    DictInsert, // [dict, key, value] -> new_dict
    DictMerge,  // [dict1, dict2] -> new_dict

    // Pattern matching support
    MatchValue,         // Compare with pattern
    MatchType(String),  // Check type
    Destructure(usize), // Destructure tuple/list

    // Promise/async operations
    MakePromise,
    AwaitPromise,
    ResolvePromise,
    RejectPromise,

    // Result operations
    MakeOk,
    MakeErr,
    UnwrapResult,
    MapResult,

    // Capability checks
    RequireCapability(String),
    CheckCapability(String),

    // Intrinsics with capability requirements
    CallIntrinsic {
        name: String,
        capability: Option<String>,
    },

    // Debug/telemetry
    TraceValue(String),      // Debug trace with label
    RecordTelemetry(String), // Record telemetry event

    // Other
    Nop,
    Halt,
}

impl Instruction {
    /// Returns the size of this instruction in bytes (for jump calculations)
    pub fn size(&self) -> usize {
        use std::mem;
        // Real size calculation based on instruction type
        match self {
            // Fixed size instructions
            Instruction::Add
            | Instruction::Sub
            | Instruction::Mul
            | Instruction::Div
            | Instruction::Mod
            | Instruction::Neg
            | Instruction::Pow
            | Instruction::Eq
            | Instruction::Ne
            | Instruction::Lt
            | Instruction::Le
            | Instruction::Gt
            | Instruction::Ge
            | Instruction::And
            | Instruction::Or
            | Instruction::Not
            | Instruction::Pop
            | Instruction::Dup
            | Instruction::Swap
            | Instruction::Rot3
            | Instruction::GetIndex
            | Instruction::ListAppend
            | Instruction::ListConcat
            | Instruction::DictInsert
            | Instruction::DictMerge
            | Instruction::MatchValue
            | Instruction::MakePromise
            | Instruction::AwaitPromise
            | Instruction::ResolvePromise
            | Instruction::RejectPromise
            | Instruction::MakeOk
            | Instruction::MakeErr
            | Instruction::UnwrapResult
            | Instruction::MapResult
            | Instruction::Return
            | Instruction::Nop
            | Instruction::Halt => 1,

            // Variable size instructions
            Instruction::Push(value) => 1 + mem::size_of_val(value),
            Instruction::Jump(_)
            | Instruction::JumpIf(_)
            | Instruction::JumpIfNot(_)
            | Instruction::Call(_) => 1 + mem::size_of::<usize>(),
            Instruction::MakeList(n)
            | Instruction::MakeDict(n)
            | Instruction::MakeTuple(n)
            | Instruction::Destructure(n) => 1 + mem::size_of_val(n),
            Instruction::BindLocal(s)
            | Instruction::LoadLocal(s)
            | Instruction::LoadGlobal(s)
            | Instruction::CallNative(s)
            | Instruction::GetAttr(s)
            | Instruction::MatchType(s)
            | Instruction::RequireCapability(s)
            | Instruction::CheckCapability(s)
            | Instruction::TraceValue(s)
            | Instruction::RecordTelemetry(s) => 1 + s.len(),
            Instruction::CallIntrinsic { name, capability } => {
                1 + name.len() + capability.as_ref().map_or(0, |c| c.len())
            }
            Instruction::Slice(start, end) => 1 + mem::size_of_val(start) + mem::size_of_val(end),
        }
    }

    /// Check if this instruction requires a specific capability
    pub fn required_capability(&self) -> Option<&str> {
        match self {
            Instruction::RequireCapability(cap) => Some(cap),
            Instruction::CallIntrinsic {
                capability: Some(cap),
                ..
            } => Some(cap),
            _ => None,
        }
    }

    /// Check if this instruction modifies state (all should be immutable)
    pub fn is_pure(&self) -> bool {
        match self {
            // Only intrinsics and I/O operations are impure
            Instruction::CallIntrinsic { .. }
            | Instruction::TraceValue(_)
            | Instruction::RecordTelemetry(_) => false,
            _ => true,
        }
    }
}