mirror of
https://github.com/uutils/awk.git
synced 2026-06-10 16:15:04 -07:00
interpreter: refactor IR to use native enums
That was huge lol.
This commit is contained in:
+110
-268
@@ -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::<Instruction>() <= 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<OpCode>, 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<OpCode>, 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<OpCode>, 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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+66
-65
@@ -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<UnaryOperator> 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<BinaryOperator> 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+86
-69
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user