use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result as FmtResult, Write};
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum Instruction {
Constant(u16),
DefineGlobal(u16),
SetGlobal(u16),
GetGlobal(u16),
SetLocal(u16),
GetLocal(u16),
CloseUpvalue,
SetUpvalue(u16),
GetUpvalue(u16),
Jump(u16),
JumpIfFalse(u16),
Loop(u16),
Closure(u16),
Call(u8),
Class(u16),
Method(u16),
GetProperty(u16),
SetProperty(u16),
Invoke((u16, u8)),
GetSuper(u16),
SuperInvoke((u16, u8)),
Negate,
Add,
Subtract,
Multiply,
Divide,
Return,
Nil,
True,
False,
Not,
Equal,
NotEqual,
GreaterThan,
LessThan,
GreaterThanOrEqual,
LessThanOrEqual,
Print,
Pop,
Inherit,
}
impl Instruction {
#[named]
pub fn dump<W: Write>(
&self,
index: usize,
offset: usize,
line: usize,
same_line: bool,
out: &mut W,
) -> Result<usize, Box<dyn StdError>> {
trace_enter!();
trace_var!(index);
trace_var!(offset);
trace_var!(line);
use Instruction::*;
let result = match &self {
Constant(_) | DefineGlobal(_) | SetGlobal(_) | GetGlobal(_) => 1,
_ => 0,
};
let line_string = match same_line {
true => "|".to_string(),
false => line.to_string(),
};
#[allow(clippy::to_string_in_format_args)]
writeln!(
out,
"{:5} {:#06X} {:>6} {:>16} {:>4}",
index,
offset,
line_string,
self.to_string(),
result,
)?;
trace_var!(result);
trace_exit!();
Ok(result)
}
}
impl Display for Instruction {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{:?}", self)
}
}
#[cfg(test)]
pub mod test {
use super::*;
use crate::test::*;
#[named]
#[test]
pub fn test_fmt() {
init();
trace_enter!();
assert_eq!(Instruction::Negate.to_string(), "Negate");
assert_eq!(Instruction::Return.to_string(), "Return");
assert_eq!(Instruction::Constant(5).to_string(), "Constant(5)");
trace_exit!();
}
#[named]
#[test]
pub fn test() {
init();
trace_enter!();
let mut string = String::new();
let result = Instruction::Return.dump(0, 0, 0, false, &mut string).unwrap();
assert_eq!(result, 0);
assert_eq!(string, " 0 0x0000 0 Return 0\n");
trace_exit!();
}
#[named]
#[test]
pub fn test2() {
init();
trace_enter!();
let mut string = String::new();
let result = Instruction::Return.dump(16, 23, 72, false, &mut string).unwrap();
assert_eq!(result, 0);
assert_eq!(string, " 16 0x0017 72 Return 0\n");
trace_exit!();
}
#[named]
#[test]
pub fn test3() {
init();
trace_enter!();
let mut string = String::new();
let result = Instruction::Return.dump(16, 23, 72, true, &mut string).unwrap();
assert_eq!(result, 0);
assert_eq!(string, " 16 0x0017 | Return 0\n");
trace_exit!();
}
}