use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum OpCode {
Nop = 0x00,
LoadK = 0x01, LoadNil = 0x02, LoadBool = 0x03, LoadInt = 0x04, Move = 0x05,
NewList = 0x06, NewMap = 0x07, NewRecord = 0x08, NewUnion = 0x09, NewTuple = 0x0A, NewSet = 0x0B,
GetField = 0x10, SetField = 0x11, GetIndex = 0x12, SetIndex = 0x13, GetTuple = 0x14,
Add = 0x20, Sub = 0x21, Mul = 0x22, Div = 0x23, Mod = 0x24, Pow = 0x25, Neg = 0x26, Concat = 0x27, FloorDiv = 0x2E,
BitOr = 0x28, BitAnd = 0x29, BitXor = 0x2A, BitNot = 0x2B, Shl = 0x2C, Shr = 0x2D,
Eq = 0x30, Lt = 0x31, Le = 0x32, Not = 0x33, And = 0x34, Or = 0x35, In = 0x36, Is = 0x37, NullCo = 0x38, Test = 0x39,
Jmp = 0x40, Call = 0x41, TailCall = 0x42, Return = 0x43, Halt = 0x44, Loop = 0x45, ForPrep = 0x46, ForLoop = 0x47, ForIn = 0x48, Break = 0x49, Continue = 0x4A,
Intrinsic = 0x50,
Closure = 0x51, GetUpval = 0x52, SetUpval = 0x53,
ToolCall = 0x60, Schema = 0x61, Emit = 0x62, TraceRef = 0x63, Await = 0x64, Spawn = 0x65,
Append = 0x70,
IsVariant = 0x71, Unbox = 0x72, }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum IntrinsicId {
Length = 0,
Count = 1,
Matches = 2,
Hash = 3,
Diff = 4,
Patch = 5,
Redact = 6,
Validate = 7,
TraceRef = 8,
Print = 9,
ToString = 10,
ToInt = 11,
ToFloat = 12,
TypeOf = 13,
Keys = 14,
Values = 15,
Contains = 16,
Join = 17,
Split = 18,
Trim = 19,
Upper = 20,
Lower = 21,
Replace = 22,
Slice = 23,
Append = 24,
Range = 25,
Abs = 26,
Min = 27,
Max = 28,
Sort = 29,
Reverse = 30,
Map = 31,
Filter = 32,
Reduce = 33,
FlatMap = 34,
Zip = 35,
Enumerate = 36,
Any = 37,
All = 38,
Find = 39,
Position = 40,
GroupBy = 41,
Chunk = 42,
Window = 43,
Flatten = 44,
Unique = 45,
Take = 46,
Drop = 47,
First = 48,
Last = 49,
IsEmpty = 50,
Chars = 51,
StartsWith = 52,
EndsWith = 53,
IndexOf = 54,
PadLeft = 55,
PadRight = 56,
Round = 57,
Ceil = 58,
Floor = 59,
Sqrt = 60,
Pow = 61,
Log = 62,
Sin = 63,
Cos = 64,
Clamp = 65,
Clone = 66,
Sizeof = 67,
Debug = 68,
ToSet = 69,
HasKey = 70,
Merge = 71,
Size = 72,
Add = 73,
Remove = 74,
Entries = 75,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Instruction {
pub op: OpCode,
pub a: u8,
pub b: u8,
pub c: u8,
}
impl Instruction {
pub fn abc(op: OpCode, a: u8, b: u8, c: u8) -> Self {
Self { op, a, b, c }
}
pub fn abx(op: OpCode, a: u8, bx: u16) -> Self {
Self {
op,
a,
b: (bx >> 8) as u8,
c: (bx & 0xFF) as u8,
}
}
pub fn ax(op: OpCode, ax: u32) -> Self {
Self {
op,
a: ((ax >> 16) & 0xFF) as u8,
b: ((ax >> 8) & 0xFF) as u8,
c: (ax & 0xFF) as u8,
}
}
pub fn sax(op: OpCode, offset: i32) -> Self {
let bits = (offset as u32) & 0xFFFFFF;
Self {
op,
a: ((bits >> 16) & 0xFF) as u8,
b: ((bits >> 8) & 0xFF) as u8,
c: (bits & 0xFF) as u8,
}
}
pub fn bx(&self) -> u16 {
((self.b as u16) << 8) | (self.c as u16)
}
pub fn ax_val(&self) -> u32 {
((self.a as u32) << 16) | ((self.b as u32) << 8) | (self.c as u32)
}
pub fn sax_val(&self) -> i32 {
let raw = self.ax_val();
if raw & 0x800000 != 0 {
(raw | 0xFF000000) as i32
} else {
raw as i32
}
}
pub fn sbx(&self) -> i16 {
self.bx() as i16
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Constant {
Null,
Bool(bool),
Int(i64),
Float(f64),
String(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirType {
pub kind: String,
pub name: String,
pub fields: Vec<LirField>,
pub variants: Vec<LirVariant>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirField {
pub name: String,
#[serde(rename = "type")]
pub ty: String,
pub constraints: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirVariant {
pub name: String,
pub payload: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirCell {
pub name: String,
pub params: Vec<LirParam>,
pub returns: Option<String>,
pub registers: u8,
pub constants: Vec<Constant>,
pub instructions: Vec<Instruction>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirParam {
pub name: String,
#[serde(rename = "type")]
pub ty: String,
pub register: u8,
#[serde(default)]
pub variadic: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirTool {
pub alias: String,
pub tool_id: String,
pub version: String,
pub mcp_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirPolicy {
pub tool_alias: String,
pub grants: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirAgent {
pub name: String,
pub methods: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirAddon {
pub kind: String,
pub name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirEffect {
pub name: String,
pub operations: Vec<LirEffectOp>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirEffectOp {
pub name: String,
pub params: Vec<LirParam>,
pub returns: Option<String>,
pub effects: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirEffectBind {
pub effect_path: String,
pub tool_alias: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirHandler {
pub name: String,
pub handles: Vec<LirHandle>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirHandle {
pub operation: String,
pub cell: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LirModule {
pub version: String,
pub doc_hash: String,
pub strings: Vec<String>,
pub types: Vec<LirType>,
pub cells: Vec<LirCell>,
pub tools: Vec<LirTool>,
pub policies: Vec<LirPolicy>,
pub agents: Vec<LirAgent>,
pub addons: Vec<LirAddon>,
pub effects: Vec<LirEffect>,
pub effect_binds: Vec<LirEffectBind>,
pub handlers: Vec<LirHandler>,
}
impl LirModule {
pub fn new(doc_hash: String) -> Self {
Self {
version: "1.0.0".to_string(),
doc_hash,
strings: Vec::new(),
types: Vec::new(),
cells: Vec::new(),
tools: Vec::new(),
policies: Vec::new(),
agents: Vec::new(),
addons: Vec::new(),
effects: Vec::new(),
effect_binds: Vec::new(),
handlers: Vec::new(),
}
}
pub fn merge(&mut self, other: &LirModule) {
use std::collections::HashMap;
let mut string_remap: HashMap<usize, usize> = HashMap::new();
for (old_idx, s) in other.strings.iter().enumerate() {
if let Some(existing_idx) = self.strings.iter().position(|x| x == s) {
string_remap.insert(old_idx, existing_idx);
} else {
string_remap.insert(old_idx, self.strings.len());
self.strings.push(s.clone());
}
}
for ty in &other.types {
if !self.types.iter().any(|t| t.name == ty.name) {
self.types.push(ty.clone());
}
}
for cell in &other.cells {
if !self.cells.iter().any(|c| c.name == cell.name) {
self.cells.push(cell.clone());
}
}
for tool in &other.tools {
if !self.tools.iter().any(|t| t.alias == tool.alias) {
self.tools.push(tool.clone());
}
}
for policy in &other.policies {
if !self
.policies
.iter()
.any(|p| p.tool_alias == policy.tool_alias)
{
self.policies.push(policy.clone());
}
}
for agent in &other.agents {
if !self.agents.iter().any(|a| a.name == agent.name) {
self.agents.push(agent.clone());
}
}
self.addons.extend_from_slice(&other.addons);
for effect in &other.effects {
if !self.effects.iter().any(|e| e.name == effect.name) {
self.effects.push(effect.clone());
}
}
for bind in &other.effect_binds {
if !self
.effect_binds
.iter()
.any(|b| b.effect_path == bind.effect_path && b.tool_alias == bind.tool_alias)
{
self.effect_binds.push(bind.clone());
}
}
for handler in &other.handlers {
if !self.handlers.iter().any(|h| h.name == handler.name) {
self.handlers.push(handler.clone());
}
}
}
}