From 2ee3c722f59fafa23abc159540d1ec562ead1003 Mon Sep 17 00:00:00 2001 From: "Guillem L. Jara" <4lon3ly0@tutanota.com> Date: Tue, 26 May 2026 20:39:28 +0200 Subject: [PATCH] interpreter: refactor IR to use native enums That was huge lol. --- interpreter/src/ir.rs | 378 +++++++++++------------------------- interpreter/src/ir/lower.rs | 131 ++++++------- interpreter/src/vm.rs | 155 ++++++++------- 3 files changed, 262 insertions(+), 402 deletions(-) diff --git a/interpreter/src/ir.rs b/interpreter/src/ir.rs index b520f34..5f583f3 100644 --- a/interpreter/src/ir.rs +++ b/interpreter/src/ir.rs @@ -32,71 +32,51 @@ pub struct Label(pub u16); #[repr(transparent)] pub struct ArgCount(u16); -#[repr(u8, align(1))] +#[repr(u8, C, align(8))] #[derive(Clone, Copy, Debug)] -pub enum OpCode { +pub enum Instruction { // Unary operations - Record, - Negation, - ToInt, - Negative, + Record(UnaryArg), + Negation(UnaryArg), + ToInt(UnaryArg), + Negative(UnaryArg), + Copy(UnaryArg), // Binary operations - Eq, - NEq, - Gt, - Lt, - LtE, - GtE, - And, - Or, - Matches, - MatchesNot, - Add, - Subtract, - Multiply, - Divide, - Raise, - Modulo, - Concat, + Eq(BinaryArg), + NEq(BinaryArg), + Gt(BinaryArg), + Lt(BinaryArg), + LtE(BinaryArg), + GtE(BinaryArg), + And(BinaryArg), + Or(BinaryArg), + Matches(BinaryArg), + MatchesNot(BinaryArg), + Add(BinaryArg), + Subtract(BinaryArg), + Multiply(BinaryArg), + Divide(BinaryArg), + Raise(BinaryArg), + Modulo(BinaryArg), + Concat(BinaryArg), // Intrinsic operations - LoadUser, - LoadBultin, - LoadConst, - Copy, - StoreUser, - StoreBuiltin, - IntrinsicCall, - UserCall, - IndirectCall, - Jump, - Return, - Branch, + LoadUser(LoadStoreArg), + LoadBultin(LoadStoreArg), + LoadConst(LoadStoreArg), + StoreUser(LoadStoreArg), + StoreBuiltin(LoadStoreArg), + IntrinsicCall(CallArgs), + UserCall(IndCallArgs), + IndirectCall(CallArgs), + Jump(JumpArg), + Return(RetArg), + Branch(BranchArg), } const _: () = const { assert!(size_of::() <= 8) }; -#[derive(Clone, Copy)] -#[repr(C, align(8))] -pub struct Instruction { - pub opcode: OpCode, - pub args: Arguments, -} - -#[derive(Clone, Copy)] -#[repr(C, align(2))] -pub union Arguments { - unary_local: UnaryArg, - binary_local: BinaryArg, - load_store: LoadStoreArg, - jump: JumpArg, - ret: RetArg, - branch: BranchArg, - call: CallArgs, - ind_call: IndCallArgs, -} - pub type UnaryArg = (Reg, Reg); pub type BinaryArg = (Reg, Reg, Reg); pub type LoadStoreArg = (Reg, NonLocal); @@ -107,202 +87,65 @@ pub type CallArgs = (Reg, NonLocal, ArgCount); pub type IndCallArgs = (Reg, Reg, ArgCount); impl Instruction { - fn unary(opcode: impl Into, dest: Reg, src: Reg) -> Self { - let opcode = opcode.into(); - debug_assert!(opcode.is_unary()); - Self { - opcode, - args: Arguments { unary_local: (dest, src) }, + fn set_label(&mut self, label: Label) { + match self { + Self::Jump(lx) | Self::Branch((_, _, lx)) => *lx = label, + _ => debug_assert!(false, "Incorrect label set!"), } } - fn binary(opcode: impl Into, dest: Reg, lhs: Reg, rhs: Reg) -> Self { - let opcode = opcode.into(); - debug_assert!(opcode.is_binary()); - Self { - opcode, - args: Arguments { binary_local: (dest, lhs, rhs) }, - } - } - - fn load_store(opcode: impl Into, dest: Reg, src: NonLocal) -> Self { - let opcode = opcode.into(); - debug_assert!(opcode.is_load_store()); - Self { - opcode, - args: Arguments { load_store: (dest, src) }, - } - } - - fn jump(to: Label) -> Self { - Self { opcode: OpCode::Jump, args: Arguments { jump: to } } - } - - fn branch(cond: Reg, true_to: Label, false_to: Label) -> Self { - Self { - opcode: OpCode::Branch, - args: Arguments { branch: (cond, true_to, false_to) }, - } - } - - pub fn get_unary(&self) -> Option<&UnaryArg> { - self.opcode - .is_unary() - .then_some(unsafe { &self.args.unary_local }) - } - - pub fn get_binary(&self) -> Option<&BinaryArg> { - self.opcode - .is_binary() - .then_some(unsafe { &self.args.binary_local }) - } - - pub fn get_load_store(&self) -> Option<&LoadStoreArg> { - self.opcode - .is_load_store() - .then_some(unsafe { &self.args.load_store }) - } - - pub fn get_branch(&self) -> Option<&BranchArg> { - self.opcode - .is_branch() - .then_some(unsafe { &self.args.branch }) - } - - pub fn get_jump(&self) -> Option<&JumpArg> { - self.opcode.is_jump().then_some(unsafe { &self.args.jump }) - } -} - -impl OpCode { - fn is_unary(self) -> bool { - matches!( - self, - Self::Record | Self::Negation | Self::ToInt | Self::Negative - ) - } - - fn is_binary(self) -> bool { - matches!( - self, - Self::Eq - | Self::NEq - | Self::Gt - | Self::Lt - | Self::LtE - | Self::GtE - | Self::And - | Self::Or - | Self::Matches - | Self::MatchesNot - | Self::Add - | Self::Subtract - | Self::Multiply - | Self::Divide - | Self::Raise - | Self::Modulo - | Self::Concat - ) - } - - fn is_load_store(self) -> bool { - matches!( - self, - Self::LoadUser - | Self::LoadBultin - | Self::LoadConst - | Self::StoreUser - | Self::StoreBuiltin - ) - } - - fn is_jump(self) -> bool { - matches!(self, Self::Jump) - } - - fn is_branch(self) -> bool { - matches!(self, Self::Branch) - } -} - -impl Debug for Instruction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Instruction::{:?}", self.opcode)?; - match self.opcode { - op if op.is_unary() => { - let (dest, data) = unsafe { &self.args.unary_local }; - write!(f, "({dest:?}, {data:?})") - } - op if op.is_binary() => { - let (dest, lhs, rhs) = unsafe { &self.args.binary_local }; - write!(f, "({dest:?}, {lhs:?}, {rhs:?})") - } - op if op.is_load_store() => { - let (dest, src) = unsafe { &self.args.load_store }; - write!(f, "({dest:?}, {src:?})") - } - OpCode::Branch => { - let (cond, label_then, label_else) = unsafe { self.args.branch }; - write!(f, "({cond:?}, {label_then:?}, {label_else:?})") - } - OpCode::Jump => { - let label = unsafe { self.args.jump }; - write!(f, "({label:?})") - } - _ => todo!(), + fn push_start_label(&mut self) { + if let Self::Branch((_, label, _)) = self { + label.0 += 1; + } else { + debug_assert!(false, "Incorrect label set!"); } } } impl Display for Instruction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.opcode { - op @ (OpCode::Record - | OpCode::Negation - | OpCode::ToInt - | OpCode::Negative - | OpCode::Copy) => { - let (dest, data) = unsafe { &self.args.unary_local }; + let op = self.display_name(); + match self { + Self::Record((dest, data)) + | Self::Negation((dest, data)) + | Self::ToInt((dest, data)) + | Self::Negative((dest, data)) + | Self::Copy((dest, data)) => { write!(f, "{dest} <- {op} {data}") } - op @ (OpCode::Eq - | OpCode::NEq - | OpCode::Gt - | OpCode::Lt - | OpCode::LtE - | OpCode::GtE - | OpCode::And - | OpCode::Or - | OpCode::Matches - | OpCode::MatchesNot - | OpCode::Add - | OpCode::Subtract - | OpCode::Multiply - | OpCode::Divide - | OpCode::Raise - | OpCode::Concat - | OpCode::Modulo) => { - let (dest, lhs, rhs) = unsafe { &self.args.binary_local }; + Self::Eq((dest, lhs, rhs)) + | Self::NEq((dest, lhs, rhs)) + | Self::Gt((dest, lhs, rhs)) + | Self::Lt((dest, lhs, rhs)) + | Self::LtE((dest, lhs, rhs)) + | Self::GtE((dest, lhs, rhs)) + | Self::And((dest, lhs, rhs)) + | Self::Or((dest, lhs, rhs)) + | Self::Matches((dest, lhs, rhs)) + | Self::MatchesNot((dest, lhs, rhs)) + | Self::Add((dest, lhs, rhs)) + | Self::Subtract((dest, lhs, rhs)) + | Self::Multiply((dest, lhs, rhs)) + | Self::Divide((dest, lhs, rhs)) + | Self::Raise((dest, lhs, rhs)) + | Self::Concat((dest, lhs, rhs)) + | Self::Modulo((dest, lhs, rhs)) => { write!(f, "{dest} <- {op} {lhs}, {rhs}") } - op @ (OpCode::LoadUser | OpCode::StoreUser) => { - let (dest, src) = unsafe { &self.args.load_store }; + Self::LoadUser((dest, src)) | Self::StoreUser((dest, src)) => { write!(f, "{dest} <- {op} user[{src}]") } - op @ OpCode::LoadConst => { - let (dest, src) = unsafe { &self.args.load_store }; + Self::LoadConst((dest, src)) => { write!(f, "{dest} <- {op} mem[{src}]") } - op @ (OpCode::StoreBuiltin | OpCode::LoadBultin) => { - let (dest, src) = unsafe { &self.args.load_store }; + Self::StoreBuiltin((dest, src)) | Self::LoadBultin((dest, src)) => { write!(f, "{dest} <- {op} intrinsic[{src}]") } - op @ OpCode::Branch => { - let (cond, label_then, label_else) = unsafe { self.args.branch }; + Self::Branch((cond, label_then, label_else)) => { write!(f, "{op} {cond}, {label_then}, {label_else}") } - op @ OpCode::Jump => { - let label = unsafe { self.args.jump }; + Self::Jump(label) => { write!(f, "{op} {label}") } _ => todo!(), @@ -310,44 +153,43 @@ impl Display for Instruction { } } -impl Display for OpCode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let str = match self { - Self::Record => "rec", - Self::Negation => "not", - Self::ToInt => "int", - Self::Negative => "neg", - Self::Concat => "cat", - Self::Eq => "eq", - Self::NEq => "neq", - Self::Gt => "gt", - Self::Lt => "lt", - Self::LtE => "le", - Self::GtE => "ge", - Self::And => "and", - Self::Or => "or", - Self::Matches => "mtch", - Self::MatchesNot => "nmtch", - Self::Add => "add", - Self::Subtract => "sub", - Self::Multiply => "mul", - Self::Divide => "div", - Self::Raise => "pow", - Self::Modulo => "mod", - Self::LoadUser => "vload", - Self::LoadBultin => "iload", - Self::LoadConst => "cload", - Self::StoreUser => "vstore", - Self::StoreBuiltin => "istore", - Self::Copy => "cpy", - Self::IntrinsicCall => "icall", - Self::UserCall => "ucall", - Self::IndirectCall => "vcall", - Self::Jump => "jmp", - Self::Return => "ret", - Self::Branch => "brif", - }; - <_ as Display>::fmt(str, f) +impl Instruction { + fn display_name(self) -> &'static str { + match self { + Self::Record(_) => "rec", + Self::Negation(_) => "not", + Self::ToInt(_) => "int", + Self::Negative(_) => "neg", + Self::Concat(_) => "cat", + Self::Eq(_) => "eq", + Self::NEq(_) => "neq", + Self::Gt(_) => "gt", + Self::Lt(_) => "lt", + Self::LtE(_) => "le", + Self::GtE(_) => "ge", + Self::And(_) => "and", + Self::Or(_) => "or", + Self::Matches(_) => "mtch", + Self::MatchesNot(_) => "nmtch", + Self::Add(_) => "add", + Self::Subtract(_) => "sub", + Self::Multiply(_) => "mul", + Self::Divide(_) => "div", + Self::Raise(_) => "pow", + Self::Modulo(_) => "mod", + Self::LoadUser(_) => "vload", + Self::LoadBultin(_) => "iload", + Self::LoadConst(_) => "cload", + Self::StoreUser(_) => "vstore", + Self::StoreBuiltin(_) => "istore", + Self::Copy(_) => "cpy", + Self::IntrinsicCall(_) => "icall", + Self::UserCall(_) => "ucall", + Self::IndirectCall(_) => "vcall", + Self::Jump(_) => "jmp", + Self::Return(_) => "ret", + Self::Branch(_) => "brif", + } } } diff --git a/interpreter/src/ir/lower.rs b/interpreter/src/ir/lower.rs index 77ad0be..42e5d2c 100644 --- a/interpreter/src/ir/lower.rs +++ b/interpreter/src/ir/lower.rs @@ -12,7 +12,7 @@ use parser::{ }; use crate::{ - ir::{Instruction, Label, NonLocal, OpCode, Reg}, + ir::{BinaryArg, Instruction, Label, NonLocal, Reg, UnaryArg}, types::Value, vm::{Consts, ExecMode, Interpreter, SymbolTable}, }; @@ -45,43 +45,46 @@ impl<'a> Code<'a> { let mut state = RegsState::new(self); let condition = self.lower_expr(condition); let label_then = self.following_instr(1); - let if_label = self - .bc - .emit(Instruction::branch(*condition, label_then, Label(0))); + let if_label = + self.bc + .emit(Instruction::Branch((*condition, label_then, Label(0)))); self.free_reg(condition); self.lower_body(then_body); - self.bc.nth(if_label).args.branch.2 = self.following_instr(0); + let next = self.following_instr(0); + self.bc.nth(if_label).set_label(next); if let Some(else_body) = else_body { state.reg_pointer += 1; - unsafe { self.bc.nth(if_label).args.branch.2.0 += 1 }; - let end_label = self.bc.emit(Instruction::jump(Label(0))); + self.bc.nth(if_label).push_start_label(); + let end_label = self.bc.emit(Instruction::Jump(Label(0))); state.scope_hwm(self, |c| c.lower_body(else_body)); - self.bc.nth(end_label).args.jump = self.following_instr(0); + let next = self.following_instr(0); + self.bc.nth(end_label).set_label(next); } } Statement::While { condition, then_body } => { let cond_label = self.following_instr(0); let condition = self.lower_expr(condition); - let while_label = self.bc.emit(Instruction::branch( + let while_label = self.bc.emit(Instruction::Branch(( *condition, self.following_instr(1), Label(0), - )); + ))); self.free_reg(condition); self.lower_body(then_body); - self.bc.emit(Instruction::jump(cond_label)); - self.bc.nth(while_label).args.branch.2 = self.following_instr(0); + self.bc.emit(Instruction::Jump(cond_label)); + let next = self.following_instr(0); + self.bc.nth(while_label).set_label(next); } Statement::DoWhile { then_body, condition } => { let do_label = self.following_instr(0); self.lower_body(then_body); let condition = self.lower_expr(condition); - self.bc.emit(Instruction::branch( + self.bc.emit(Instruction::Branch(( *condition, do_label, self.following_instr(1), - )); + ))); self.free_reg(condition); } Statement::For { init, condition, update, body } => { @@ -95,22 +98,23 @@ impl<'a> Code<'a> { let body_label = self.following_instr(1); let while_label = self.bc - .emit(Instruction::branch(*condition, body_label, Label(0))); + .emit(Instruction::Branch((*condition, body_label, Label(0)))); self.free_reg(condition); self.lower_body(body); if let Some(SimpleStatement::Expression(expr)) = update { let reg = self.lower_expr(expr); self.free_reg(reg); } - self.bc.emit(Instruction::jump(cond_label)); - self.bc.nth(while_label).args.branch.2 = self.following_instr(0); + self.bc.emit(Instruction::Jump(cond_label)); + let next = self.following_instr(0); + self.bc.nth(while_label).set_label(next); } else { self.lower_body(body); if let Some(SimpleStatement::Expression(expr)) = update { let reg = self.lower_expr(expr); self.free_reg(reg); } - self.bc.emit(Instruction::jump(cond_label)); + self.bc.emit(Instruction::Jump(cond_label)); } } Statement::Simple(SimpleStatement::Expression(expr)) => { @@ -132,13 +136,11 @@ impl<'a> Code<'a> { Expr::Leaf(atom) => match atom { Atom::Variable(Variable::User(ident)) => { let src = self.symbols.register_user_var(ident, self.arena); - self.bc - .emit(Instruction::load_store(OpCode::LoadUser, dest, src)); + self.bc.emit(Instruction::LoadUser((dest, src))); } &Atom::Number(n) => { let src = self.register_const(Value::Float(n)); - self.bc - .emit(Instruction::load_store(OpCode::LoadConst, dest, src)); + self.bc.emit(Instruction::LoadConst((dest, src))); } atom @ (Atom::String(s) | Atom::TypedRegex(s)) => { let val = if matches!(atom, Atom::String(_)) { @@ -149,18 +151,15 @@ impl<'a> Code<'a> { let src = self.register_const(val(Cow::Borrowed( self.arena.alloc_slice_copy(s.as_ref()), ))); - self.bc - .emit(Instruction::load_store(OpCode::LoadConst, dest, src)); + self.bc.emit(Instruction::LoadConst((dest, src))); } Atom::Regex(r) => { let src = self.register_const(Value::Regex(Cow::Borrowed( self.arena.alloc_slice_copy(r.as_ref()), ))); - self.bc - .emit(Instruction::load_store(OpCode::LoadConst, dest, src)); + self.bc.emit(Instruction::LoadConst((dest, src))); let rec = self.lower_expr(&Expr::Leaf(Atom::Number(0.))); - self.bc - .emit(Instruction::binary(OpCode::Matches, dest, *rec, dest)); + self.bc.emit(Instruction::Matches((dest, *rec, dest))); self.free_reg(rec); } _ => todo!(), @@ -168,13 +167,13 @@ impl<'a> Code<'a> { Expr::Node(node) => match node.as_ref() { ExprNode::UnaryOperation(op, expr) => { let src = self.lower_expr(expr); - self.bc.emit(Instruction::unary(*op, dest, *src)); + self.bc.emit(Instruction::from((*op, (dest, *src)))); self.free_reg(src); } ExprNode::BinaryOperation(op, lhs, rhs) => { let lhs = self.lower_expr(lhs); let rhs = self.lower_expr(rhs); - self.bc.emit(Instruction::binary(*op, dest, *lhs, *rhs)); + self.bc.emit(Instruction::from((*op, (dest, *lhs, *rhs)))); self.free_reg(lhs); self.free_reg(rhs); } @@ -182,23 +181,26 @@ impl<'a> Code<'a> { self.lower_expr_into(cond, dest); let mut state = RegsState::new(self); - let branch = - self.bc - .emit(Instruction::branch(dest, self.following_instr(1), Label(0))); + let branch = self.bc.emit(Instruction::Branch(( + dest, + self.following_instr(1), + Label(0), + ))); state = state.scope(self, |c| { c.lower_expr_into(true_then, dest); }); - let jump = self.bc.emit(Instruction::jump(Label(0))); + let jump = self.bc.emit(Instruction::Jump(Label(0))); let label = self.following_instr(0); state.scope_hwm(self, |c| { c.lower_expr_into(false_then, dest); }); - self.bc.nth(branch).args.branch.2 = label; - self.bc.nth(jump).args.jump = self.following_instr(0); + self.bc.nth(branch).set_label(label); + let next = self.following_instr(0); + self.bc.nth(jump).set_label(next); } ExprNode::BinaryPlaceOperation(BinaryPlaceOperator::Assignment, place, expr) => { self.lower_expr_into(expr, dest); @@ -206,8 +208,7 @@ impl<'a> Code<'a> { todo!() }; let var = self.symbols.register_user_var(var, self.arena); - self.bc - .emit(Instruction::load_store(OpCode::StoreUser, dest, var)); + self.bc.emit(Instruction::StoreUser((dest, var))); } _ => todo!(), }, @@ -303,37 +304,37 @@ pub fn test_interpreter(stmnt: &Body<'_>) -> String { vm.to_string() } -impl From for OpCode { - fn from(value: UnaryOperator) -> Self { - match value { - UnaryOperator::Record => Self::Record, - UnaryOperator::Negation => Self::Negation, - UnaryOperator::ToInt => Self::ToInt, - UnaryOperator::Negative => Self::Negative, +impl From<(UnaryOperator, UnaryArg)> for Instruction { + fn from((op, args): (UnaryOperator, UnaryArg)) -> Self { + match op { + UnaryOperator::Record => Self::Record(args), + UnaryOperator::Negation => Self::Negation(args), + UnaryOperator::ToInt => Self::ToInt(args), + UnaryOperator::Negative => Self::Negative(args), } } } -impl From for OpCode { - fn from(value: BinaryOperator) -> Self { - match value { - BinaryOperator::Concat => Self::Concat, - BinaryOperator::Eq => Self::Eq, - BinaryOperator::NEq => Self::NEq, - BinaryOperator::Gt => Self::Gt, - BinaryOperator::Lt => Self::Lt, - BinaryOperator::LtE => Self::LtE, - BinaryOperator::GtE => Self::GtE, - BinaryOperator::And => Self::And, - BinaryOperator::Or => Self::Or, - BinaryOperator::Matches => Self::Matches, - BinaryOperator::MatchesNot => Self::MatchesNot, - BinaryOperator::Add => Self::Add, - BinaryOperator::Subtract => Self::Subtract, - BinaryOperator::Multiply => Self::Multiply, - BinaryOperator::Divide => Self::Divide, - BinaryOperator::Raise => Self::Raise, - BinaryOperator::Modulo => Self::Modulo, +impl From<(BinaryOperator, BinaryArg)> for Instruction { + fn from((op, args): (BinaryOperator, BinaryArg)) -> Self { + match op { + BinaryOperator::Concat => Self::Concat(args), + BinaryOperator::Eq => Self::Eq(args), + BinaryOperator::NEq => Self::NEq(args), + BinaryOperator::Gt => Self::Gt(args), + BinaryOperator::Lt => Self::Lt(args), + BinaryOperator::LtE => Self::LtE(args), + BinaryOperator::GtE => Self::GtE(args), + BinaryOperator::And => Self::And(args), + BinaryOperator::Or => Self::Or(args), + BinaryOperator::Matches => Self::Matches(args), + BinaryOperator::MatchesNot => Self::MatchesNot(args), + BinaryOperator::Add => Self::Add(args), + BinaryOperator::Subtract => Self::Subtract(args), + BinaryOperator::Multiply => Self::Multiply(args), + BinaryOperator::Divide => Self::Divide(args), + BinaryOperator::Raise => Self::Raise(args), + BinaryOperator::Modulo => Self::Modulo(args), } } } diff --git a/interpreter/src/vm.rs b/interpreter/src/vm.rs index 61ecb80..0ff8f44 100644 --- a/interpreter/src/vm.rs +++ b/interpreter/src/vm.rs @@ -17,7 +17,7 @@ use parser::Identifier; use crate::{ ir::{ - Label, NonLocal, OpCode, Reg, + Instruction, Label, NonLocal, Reg, lower::{Bytecode, Code}, }, types::Value, @@ -107,81 +107,98 @@ impl<'a> Consts<'a> { impl Interpreter<'_> { pub fn run(&mut self) { - while let Some(instr) = self.bc.code.get(self.program_counter) { + macro_rules! rx { + (self, $dest:expr, $src:ident, $e:expr) => {{ + let $src = self.registers.get($src); + self.registers.write($dest, $e); + }}; + (self, $lhs:ident, $rhs:ident) => { + let ($lhs, $rhs) = (self.registers.get($lhs), self.registers.get($rhs)); + }; + (self, $dest:expr, $lhs:ident, $rhs:ident, $e:expr) => {{ + rx!(self, $lhs, $rhs); + self.registers.write($dest, $e); + }}; + } + while let Some(&instr) = self.bc.code.get(self.program_counter) { match instr { - ix if let Some(&(dest, src)) = ix.get_unary() => { - let src = self.registers.get(src); - let val = match ix.opcode { - OpCode::Record => todo!(), - OpCode::Negation => Value::b2f(!src.to_bool()), - OpCode::ToInt => Value::Float(src.to_num()), - OpCode::Negative => Value::Float(-src.to_num()), - _ => unreachable!(), - }; + Instruction::Record(_) => todo!(), + Instruction::Negation((dest, src)) => { + rx!(self, dest, src, Value::b2f(src.to_bool())); + } + Instruction::ToInt((dest, src)) => { + rx!(self, dest, src, Value::Float(src.to_num())); + } + Instruction::Negative((dest, src)) => { + rx!(self, dest, src, Value::Float(src.to_num())); + } + Instruction::Copy((dest, src)) => rx!(self, dest, src, src.clone()), + Instruction::Eq((dest, lhs, rhs)) => { + rx!(self, dest, lhs, rhs, Value::b2f(lhs == rhs)); + } + Instruction::NEq((dest, lhs, rhs)) => { + rx!(self, dest, lhs, rhs, Value::b2f(lhs != rhs)); + } + Instruction::Gt((dest, lhs, rhs)) => { + rx!(self, dest, lhs, rhs, Value::b2f(lhs > rhs)); + } + Instruction::Lt((dest, lhs, rhs)) => { + rx!(self, dest, lhs, rhs, Value::b2f(lhs < rhs)); + } + Instruction::LtE((dest, lhs, rhs)) => { + rx!(self, dest, lhs, rhs, Value::b2f(lhs <= rhs)); + } + Instruction::GtE((dest, lhs, rhs)) => { + rx!(self, dest, lhs, rhs, Value::b2f(lhs >= rhs)); + } + Instruction::And((_dest, _lhs, _rhs)) => todo!(), + Instruction::Or((_dest, _lhs, _rhs)) => todo!(), + Instruction::Matches((_dest, _lhs, _rhs)) => todo!(), + Instruction::MatchesNot((_dest, _lhs, _rhs)) => todo!(), + Instruction::Add((dest, lhs, rhs)) => rx!(self, dest, lhs, rhs, lhs + rhs), + Instruction::Subtract((dest, lhs, rhs)) => rx!(self, dest, lhs, rhs, lhs - rhs), + Instruction::Multiply((dest, lhs, rhs)) => rx!(self, dest, lhs, rhs, lhs * rhs), + Instruction::Divide((dest, lhs, rhs)) => rx!(self, dest, lhs, rhs, lhs / rhs), + Instruction::Raise((dest, lhs, rhs)) => rx!(self, dest, lhs, rhs, lhs ^ rhs), + Instruction::Modulo((dest, lhs, rhs)) => rx!(self, dest, lhs, rhs, lhs % rhs), + Instruction::Concat((dest, lhs, rhs)) => { + rx!(self, lhs, rhs); + let mut buf = + StdVec::with_capacity(lhs.string_size_hint() + rhs.string_size_hint()); + lhs.write_string(&mut buf); + rhs.write_string(&mut buf); + self.registers.write(dest, Value::String(buf.into())); + } + Instruction::LoadUser((dest, src)) => { + let val = self.symbols.lookup_user_scalar(src); + self.registers.write(dest, val.clone()); + } + Instruction::LoadBultin((_dest, _src)) => todo!(), + Instruction::LoadConst((dest, src)) => { + let val = self.consts.0.get_index(src.0 as _).unwrap().clone(); self.registers.write(dest, val); } - ix if let Some(&(dest, lhs, rhs)) = ix.get_binary() => { - let lhs = self.registers.get(lhs); - let rhs = self.registers.get(rhs); - let val = match ix.opcode { - OpCode::Add => lhs + rhs, - OpCode::Subtract => lhs - rhs, - OpCode::Multiply => lhs * rhs, - OpCode::Divide => lhs / rhs, - OpCode::Raise => lhs ^ rhs, - OpCode::Modulo => lhs % rhs, - // Float values on boolean cmps are intentional. - OpCode::Eq => Value::b2f(lhs == rhs), - OpCode::NEq => Value::b2f(lhs != rhs), - OpCode::Gt => Value::b2f(lhs > rhs), - OpCode::Lt => Value::b2f(lhs < rhs), - OpCode::GtE => Value::b2f(lhs >= rhs), - OpCode::LtE => Value::b2f(lhs <= rhs), - OpCode::And => todo!(), - OpCode::Or => todo!(), - OpCode::Matches => todo!(), - OpCode::MatchesNot => todo!(), - OpCode::Concat => { - let mut buf = StdVec::with_capacity( - lhs.string_size_hint() + rhs.string_size_hint(), - ); - lhs.write_string(&mut buf); - rhs.write_string(&mut buf); - Value::String(buf.into()) - } - _ => unreachable!(), - }; - self.registers.write(dest, val); + Instruction::StoreUser((dest, src)) => { + let val = self.registers.get(dest).clone(); + self.symbols.write_user_val(src, val); } - ix if let Some(&(dest, src)) = ix.get_load_store() => match ix.opcode { - OpCode::LoadConst => { - let val = self.consts.0.get_index(src.0 as _).unwrap().clone(); - self.registers.write(dest, val); - } - OpCode::LoadUser => { - let val = self.symbols.lookup_user_scalar(src).clone(); - self.registers.write(dest, val); - } - OpCode::StoreUser => { - let val = self.registers.get(dest).clone(); - self.symbols.write_user_val(src, val); - } - _ => todo!(), - }, - ix if let Some((cond, Label(true_to), Label(false_to))) = ix.get_branch() => { - let label = if self.registers.get(*cond).to_bool() { - *true_to + Instruction::StoreBuiltin((_dest, _src)) => todo!(), + Instruction::IntrinsicCall((_dest, _code, _args)) => todo!(), + Instruction::UserCall((_dest, _code, _args)) => todo!(), + Instruction::IndirectCall((_dest, _code, _args)) => todo!(), + Instruction::Jump(Label(label)) => { + self.program_counter = label as _; + continue; + } + Instruction::Return(_src) => todo!(), + Instruction::Branch((src, Label(true_to), Label(false_to))) => { + if self.registers.get(src).to_bool() { + self.program_counter = true_to as _; } else { - *false_to - }; - self.program_counter = label as _; + self.program_counter = false_to as _; + } continue; } - ix if let Some(&Label(label)) = ix.get_jump() => { - self.program_counter = label as _; - continue; - } - ix => todo!("{ix:?}"), } self.program_counter += 1; }