glyph-runtime 0.0.1

Runtime execution engine for the Glyph programming language
Documentation
//! High-level compiler that orchestrates the compilation pipeline
//!
//! This module provides the main interface for compiling Glyph source code
//! into executable bytecode and running it on the VM.

use crate::{
    ast_to_ir::ast_to_ir,
    ir_to_bytecode::ir_to_bytecode,
    vm::{VMConfig, VMError, VM},
    CapabilitySet,
};
use glyph_parser::parse_glyph;
use glyph_types::Value;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum CompileError {
    #[error("Parse error: {0}")]
    ParseError(String),

    #[error("IR generation error: {0}")]
    IrError(String),

    #[error("Bytecode generation error: {0}")]
    BytecodeError(String),

    #[error("VM error: {0}")]
    VmError(#[from] VMError),
}

/// Result type for compilation operations
pub type CompileResult<T> = Result<T, CompileError>;

/// Compiled Glyph program ready for execution
#[derive(Debug)]
pub struct CompiledProgram {
    /// Program name
    pub name: String,
    /// Required capabilities
    pub requires: Vec<String>,
    /// Bytecode for all functions
    pub bytecode: Vec<Vec<crate::Instruction>>,
}

/// Compile Glyph source code to bytecode
pub fn compile(source: &str) -> CompileResult<CompiledProgram> {
    // Parse source code
    let module = parse_glyph(source).map_err(|e| CompileError::ParseError(format!("{e:?}")))?;

    // Convert AST to IR
    let ir_module = ast_to_ir(&module);

    // Compile IR to bytecode
    let bytecode = ir_to_bytecode(&ir_module);

    Ok(CompiledProgram {
        name: ir_module.program.name,
        requires: ir_module.program.requires,
        bytecode,
    })
}

/// Compile and run Glyph source code with default configuration
pub fn compile_and_run(source: &str) -> CompileResult<Value> {
    let program = compile(source)?;

    // Create VM with required capabilities
    let mut capabilities = CapabilitySet::new();
    for cap in &program.requires {
        // Map capability names to capability types
        match cap.as_str() {
            "audio.speak" => capabilities.grant(crate::Capability::AudioSpeak),
            "display.visual" => capabilities.grant(crate::Capability::DisplayChart),
            "network.fetch" => capabilities.grant(crate::Capability::NetworkFetch("*".to_string())),
            "ui.interact" => {} // No direct UI interact capability yet
            _ => {}             // Unknown capability - skip
        }
    }

    let config = VMConfig {
        capabilities,
        ..Default::default()
    };

    let mut vm = VM::new(config);
    vm.load_bytecode(program.bytecode);

    vm.execute().map_err(CompileError::from)
}

/// Compile and run with custom VM configuration
pub fn compile_and_run_with_config(source: &str, config: VMConfig) -> CompileResult<Value> {
    let program = compile(source)?;

    let mut vm = VM::new(config);
    vm.load_bytecode(program.bytecode);

    vm.execute().map_err(CompileError::from)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_compile_simple_program() {
        let source = r#"
@program(name="test")

def main():
    return 42
"#;

        let program = compile(source).unwrap();
        assert_eq!(program.name, "test");
        assert!(!program.bytecode.is_empty());
    }

    #[test]
    fn test_compile_and_run() {
        let source = r#"
@program(name="test")

def main():
    return 42
"#;

        let result = compile_and_run(source).unwrap();
        assert_eq!(result, Value::Int(42));
    }

    #[test]
    fn test_arithmetic_program() {
        let source = r#"
@program(name="calc")

def main():
    let x = 10
    let y = 5
    return x + y
"#;

        let result = compile_and_run(source).unwrap();
        assert_eq!(result, Value::Int(15));
    }

    #[test]
    fn test_function_call() {
        let source = r#"
@program(name="funcs")

def add(a: int, b: int) -> int:
    return a + b

def main():
    return add(10, 20)
"#;

        let result = compile_and_run(source).unwrap();
        assert_eq!(result, Value::Int(30));
    }
}