Archived
feat: engram-lang — new programming language, quantum-sealed prod target, spreading activation types
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
//! Bytecode instruction set for the Engram virtual machine.
|
||||
//!
|
||||
//! The VM is a simple stack machine. Every instruction pops its operands
|
||||
//! from the stack and pushes its result. Control flow uses relative signed
|
||||
//! offsets from the instruction *after* the jump.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A runtime value on the VM stack.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Value {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Str(String),
|
||||
Bool(bool),
|
||||
Nil,
|
||||
/// A list of values (used for `activate` results and array literals).
|
||||
List(Vec<Value>),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Value {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Value::Int(n) => write!(f, "{n}"),
|
||||
Value::Float(n) => write!(f, "{n}"),
|
||||
Value::Str(s) => write!(f, "{s}"),
|
||||
Value::Bool(b) => write!(f, "{b}"),
|
||||
Value::Nil => write!(f, "nil"),
|
||||
Value::List(vs) => {
|
||||
let items: Vec<_> = vs.iter().map(|v| v.to_string()).collect();
|
||||
write!(f, "[{}]", items.join(", "))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single VM instruction.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Bytecode {
|
||||
// ── Stack ─────────────────────────────────────────────────────────────────
|
||||
/// Push a constant value onto the stack.
|
||||
Push(Value),
|
||||
/// Discard the top of stack.
|
||||
Pop,
|
||||
/// Duplicate the top of stack.
|
||||
Dup,
|
||||
|
||||
// ── Arithmetic ────────────────────────────────────────────────────────────
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
|
||||
// ── Comparison ────────────────────────────────────────────────────────────
|
||||
Eq,
|
||||
NotEq,
|
||||
Lt,
|
||||
Gt,
|
||||
LtEq,
|
||||
GtEq,
|
||||
|
||||
// ── Logical ───────────────────────────────────────────────────────────────
|
||||
And,
|
||||
Or,
|
||||
Not,
|
||||
|
||||
// ── Locals ───────────────────────────────────────────────────────────────
|
||||
/// Load a local variable by name.
|
||||
LoadLocal(String),
|
||||
/// Store the top of stack into a local variable.
|
||||
StoreLocal(String),
|
||||
|
||||
// ── Functions ─────────────────────────────────────────────────────────────
|
||||
/// Call a function by name with `arity` arguments.
|
||||
Call { name: String, arity: u32 },
|
||||
/// Return from the current function (leaves return value on stack).
|
||||
Return,
|
||||
|
||||
// ── Control flow ──────────────────────────────────────────────────────────
|
||||
/// Unconditional jump: `ip += offset` (offset is from the *next* instruction).
|
||||
Jump(i32),
|
||||
/// Jump if the top of stack is truthy; pops the value.
|
||||
JumpIf(i32),
|
||||
/// Jump if the top of stack is falsy; pops the value.
|
||||
JumpIfNot(i32),
|
||||
|
||||
// ── Fields & Indexing ─────────────────────────────────────────────────────
|
||||
/// Load a named field from the struct on top of stack.
|
||||
GetField(String),
|
||||
/// Index into an array: pops index then array.
|
||||
GetIndex,
|
||||
|
||||
// ── Special ───────────────────────────────────────────────────────────────
|
||||
/// `activate TypeName "query"` — emit a semantic query stub.
|
||||
/// In a full implementation this would call into the Engram runtime.
|
||||
Activate { type_name: String, query: String },
|
||||
/// Mark the start of a sealed section (the runtime enforces protection).
|
||||
SealedBegin,
|
||||
/// Mark the end of a sealed section.
|
||||
SealedEnd,
|
||||
/// No-op — used as a placeholder for forward jumps.
|
||||
Nop,
|
||||
/// Halt the VM.
|
||||
Halt,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Bytecode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Bytecode::Push(v) => write!(f, "PUSH {v}"),
|
||||
Bytecode::Pop => write!(f, "POP"),
|
||||
Bytecode::Dup => write!(f, "DUP"),
|
||||
Bytecode::Add => write!(f, "ADD"),
|
||||
Bytecode::Sub => write!(f, "SUB"),
|
||||
Bytecode::Mul => write!(f, "MUL"),
|
||||
Bytecode::Div => write!(f, "DIV"),
|
||||
Bytecode::Eq => write!(f, "EQ"),
|
||||
Bytecode::NotEq => write!(f, "NEQ"),
|
||||
Bytecode::Lt => write!(f, "LT"),
|
||||
Bytecode::Gt => write!(f, "GT"),
|
||||
Bytecode::LtEq => write!(f, "LTE"),
|
||||
Bytecode::GtEq => write!(f, "GTE"),
|
||||
Bytecode::And => write!(f, "AND"),
|
||||
Bytecode::Or => write!(f, "OR"),
|
||||
Bytecode::Not => write!(f, "NOT"),
|
||||
Bytecode::LoadLocal(n) => write!(f, "LOAD {n}"),
|
||||
Bytecode::StoreLocal(n) => write!(f, "STORE {n}"),
|
||||
Bytecode::Call { name, arity } => write!(f, "CALL {name}/{arity}"),
|
||||
Bytecode::Return => write!(f, "RETURN"),
|
||||
Bytecode::Jump(off) => write!(f, "JUMP {off:+}"),
|
||||
Bytecode::JumpIf(off) => write!(f, "JUMPIF {off:+}"),
|
||||
Bytecode::JumpIfNot(off) => write!(f, "JUMPIFNOT {off:+}"),
|
||||
Bytecode::GetField(n) => write!(f, "GETFIELD {n}"),
|
||||
Bytecode::GetIndex => write!(f, "GETINDEX"),
|
||||
Bytecode::Activate { type_name, query } => {
|
||||
write!(f, "ACTIVATE {type_name} \"{query}\"")
|
||||
}
|
||||
Bytecode::SealedBegin => write!(f, "SEALED_BEGIN"),
|
||||
Bytecode::SealedEnd => write!(f, "SEALED_END"),
|
||||
Bytecode::Nop => write!(f, "NOP"),
|
||||
Bytecode::Halt => write!(f, "HALT"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize bytecode instructions to bytes for storage/sealing.
|
||||
pub fn serialize_bytecode(instructions: &[Bytecode]) -> Result<Vec<u8>, String> {
|
||||
serde_json::to_vec(instructions).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Deserialize bytecode instructions from bytes.
|
||||
pub fn deserialize_bytecode(bytes: &[u8]) -> Result<Vec<Bytecode>, String> {
|
||||
serde_json::from_slice(bytes).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
impl Bytecode {
|
||||
/// Deserialize a bytecode slice from JSON bytes (convenience wrapper).
|
||||
pub fn deserialize_all(bytes: &[u8]) -> Result<Vec<Bytecode>, String> {
|
||||
deserialize_bytecode(bytes)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user