mod binary;
mod unary;
pub use binary::{Binary, BinaryOperation};
use log::{log, Level};
pub use unary::{Unary, UnaryOperation};
use crate::vm::VMState;
use crate::{Register, RigzType, VMError, Value, VM};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Clear {
One(Register),
Two(Register, Register),
Three(Register, Register, Register),
Many(Vec<Register>),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Instruction<'vm> {
Halt(Register),
Unary(Unary),
Binary(Binary),
UnaryAssign(Unary),
BinaryAssign(Binary),
Load(Register, Value<'vm>),
Copy(Register, Register),
Call(usize, Register),
Log(Level, &'vm str, Vec<Register>),
Puts(Vec<Register>),
CallEq(Register, Register, usize, Register),
CallNeq(Register, Register, usize, Register),
IfElse {
truthy: Register,
if_scope: usize,
else_scope: usize,
output: Register,
},
Cast {
from: Register,
to: Register,
rigz_type: RigzType,
},
Ret(Register),
GetVariable(&'vm str, Register),
LoadLetRegister(&'vm str, Register),
LoadMutRegister(&'vm str, Register),
CallModule {
module: &'vm str,
func: &'vm str,
args: Vec<usize>,
output: usize,
},
CallExtension {
module: &'vm str,
this: usize,
func: &'vm str,
args: Vec<usize>,
output: usize,
},
CallVMExtension {
module: &'vm str,
func: &'vm str,
args: Vec<usize>,
output: usize,
},
UnaryClear(Unary, Clear),
BinaryClear(Binary, Clear),
Clear(Clear),
Goto(usize, usize),
AddInstruction(usize, Box<Instruction<'vm>>),
InsertAtInstruction(usize, usize, Box<Instruction<'vm>>),
UpdateInstruction(usize, usize, Box<Instruction<'vm>>),
RemoveInstruction(usize, usize),
Push(Value<'vm>),
Pop(Register),
}
impl<'vm> VM<'vm> {
pub fn handle_clear(&mut self, clear: Clear) -> Result<(), VMError> {
match clear {
Clear::One(r) => {
self.remove_register(r)?;
}
Clear::Two(r1, r2) => {
self.remove_register(r1)?;
self.remove_register(r2)?;
}
Clear::Three(r1, r2, r3) => {
self.remove_register(r1)?;
self.remove_register(r2)?;
self.remove_register(r3)?;
}
Clear::Many(reg) => {
for r in reg {
self.remove_register(r)?;
}
}
}
Ok(())
}
pub fn process_core_instruction(
&mut self,
instruction: Instruction<'vm>,
) -> Result<VMState<'vm>, VMError> {
match instruction {
Instruction::Halt(r) => return Ok(VMState::Done(self.remove_register_eval_scope(r)?)),
Instruction::Clear(clear) => self.handle_clear(clear)?,
Instruction::Unary(u) => self.handle_unary(u)?,
Instruction::Binary(b) => self.handle_binary(b)?,
Instruction::UnaryAssign(u) => self.handle_unary_assign(u)?,
Instruction::BinaryAssign(b) => self.handle_binary_assign(b)?,
Instruction::UnaryClear(u, clear) => self.handle_unary_clear(u, clear)?,
Instruction::BinaryClear(b, clear) => self.handle_binary_clear(b, clear)?,
Instruction::Push(v) => self.stack.push(v),
Instruction::Pop(r) => match self.stack.pop() {
None => {
return Err(VMError::RuntimeError(format!(
"Pop called on empty registers with {}",
r
)))
}
Some(v) => self.insert_register(r, v),
},
Instruction::Load(r, v) => self.insert_register(r, v),
Instruction::LoadLetRegister(name, register) => self.load_let(name, register)?,
Instruction::LoadMutRegister(name, register) => self.load_mut(name, register)?,
Instruction::Call(scope_index, register) => self.call_frame(scope_index, register)?,
Instruction::CallModule {
module,
func,
args,
output,
} => {
let module = self.get_module_clone(module)?;
let args = self.resolve_registers(args)?;
let v = module.call(func, args).unwrap_or_else(|e| e.to_value());
self.insert_register(output, v);
}
Instruction::CallExtension {
module,
this,
func,
args,
output,
} => {
let module = self.get_module_clone(module)?;
let this = self.resolve_register(this)?;
let args = self.resolve_registers(args)?;
let v = module
.call_extension(this, func, args)
.unwrap_or_else(|e| e.to_value());
self.insert_register(output, v);
}
Instruction::CallVMExtension {
module,
func,
args,
output,
} => {
let module = self.get_module_clone(module)?;
let args = self.resolve_registers(args)?;
let value = module
.vm_extension(self, func, args)
.unwrap_or_else(|e| e.to_value());
self.insert_register(output, value)
}
Instruction::Copy(from, to) => {
let copy = self.resolve_register(from)?;
self.insert_register(to, copy);
}
Instruction::Cast {
from,
rigz_type,
to,
} => {
let value = self.resolve_register(from)?;
self.insert_register(to, value.cast(rigz_type)?);
}
Instruction::CallEq(a, b, scope_index, output) => {
let a = self.resolve_register(a)?;
let b = self.resolve_register(b)?;
if a == b {
self.call_frame(scope_index, output)?;
}
}
Instruction::CallNeq(a, b, scope_index, output) => {
let a = self.resolve_register(a)?;
let b = self.resolve_register(b)?;
if a != b {
self.call_frame(scope_index, output)?;
}
}
Instruction::IfElse {
truthy,
if_scope,
else_scope,
output,
} => {
if self.resolve_register(truthy)?.to_bool() {
self.call_frame(if_scope, output)?;
} else {
self.call_frame(else_scope, output)?;
}
}
Instruction::GetVariable(name, reg) => match self.current.get_variable(name, self) {
None => {
return Err(VMError::VariableDoesNotExist(format!(
"Variable {} does not exist",
name
)))
}
Some(s) => match self.registers.get(&s) {
None => {
return Err(VMError::EmptyRegister(format!(
"Register {} does not exist",
s
)))
}
Some(v) => self.insert_register(reg, v.clone()),
},
},
Instruction::Log(level, tmpl, args) => {
if !self.options.enable_logging {
return Ok(VMState::Running);
}
let mut res = (*tmpl).to_string();
for arg in args {
let l = self.resolve_register(arg)?.to_string();
res = res.replacen("{}", l.as_str(), 1);
}
log!(level, "{}", res)
}
Instruction::Puts(args) => {
let mut puts = String::new();
for r in args {
let arg = self.resolve_register(r)?;
puts.push_str(", ");
puts.push_str(arg.to_string().as_str());
}
println!("{}", puts)
}
Instruction::Ret(r) => {
return Err(VMError::UnsupportedOperation(format!(
"Ret not handled by parent function: R{}",
r
)))
}
Instruction::Goto(scope_id, index) => {
self.sp = scope_id;
self.current.pc = index;
}
Instruction::AddInstruction(scope, instruction) => match self.scopes.get_mut(scope) {
None => {
return Err(VMError::ScopeDoesNotExist(format!(
"Scope does not exist: {}",
scope
)))
}
Some(s) => {
s.instructions.push(*instruction);
}
},
Instruction::InsertAtInstruction(scope, index, new_instruction) => {
match self.scopes.get_mut(scope) {
None => {
return Err(VMError::ScopeDoesNotExist(format!(
"Scope does not exist: {}",
scope
)))
}
Some(s) => s.instructions.insert(index, *new_instruction),
}
}
Instruction::UpdateInstruction(scope, index, new_instruction) => {
match self.scopes.get_mut(scope) {
None => {
return Err(VMError::ScopeDoesNotExist(format!(
"Scope does not exist: {}",
scope
)))
}
Some(s) => match s.instructions.get_mut(index) {
None => {
return Err(VMError::ScopeDoesNotExist(format!(
"Scope does not exist: {}",
scope
)))
}
Some(i) => {
*i = *new_instruction;
}
},
}
}
Instruction::RemoveInstruction(scope, index) => match self.scopes.get_mut(scope) {
None => {
return Err(VMError::ScopeDoesNotExist(format!(
"Scope does not exist: {}",
scope
)))
}
Some(s) => {
if index >= s.instructions.len() {
return Err(VMError::UnsupportedOperation(format!(
"Instruction does not exist: {}#{}",
scope, index
)));
}
s.instructions.remove(index);
}
},
};
Ok(VMState::Running)
}
}