Restructure to library / binary combo
This commit is contained in:
290
src/ops.rs
Normal file
290
src/ops.rs
Normal file
@@ -0,0 +1,290 @@
|
||||
use binread::BinRead;
|
||||
use machine::Machine;
|
||||
use frame::Frame;
|
||||
use Result;
|
||||
use std::io::Write;
|
||||
use std::io::Read;
|
||||
|
||||
pub type OpFunc = fn(&mut Machine) -> Result<()>;
|
||||
|
||||
pub enum Operation {
|
||||
Op(&'static str, OpFunc),
|
||||
Invalid(u8)
|
||||
}
|
||||
|
||||
const JUMP_OFFSET: i32 = 3;
|
||||
|
||||
pub fn num_to_op(op: u8) -> Operation {
|
||||
match op {
|
||||
0x00 => Operation::Op("NOP", nop),
|
||||
0x10 => Operation::Op("BIPUSH", bipush),
|
||||
0x13 => Operation::Op("LDC_W", ldc_w),
|
||||
0x15 => Operation::Op("ILOAD", iload),
|
||||
0x36 => Operation::Op("ISTORE", istore),
|
||||
0x57 => Operation::Op("POP", pop),
|
||||
0x59 => Operation::Op("DUP", dup),
|
||||
0x5F => Operation::Op("SWAP", swap),
|
||||
0x60 => Operation::Op("IADD", iadd),
|
||||
0x64 => Operation::Op("ISUB", isub),
|
||||
0x7E => Operation::Op("IAND", iand),
|
||||
0xB0 => Operation::Op("IOR", ior),
|
||||
0x84 => Operation::Op("IINC", iinc),
|
||||
0x99 => Operation::Op("IFEQ", ifeq),
|
||||
0x9b => Operation::Op("IFLT", iflt),
|
||||
0x9F => Operation::Op("IF_ICMPEQ", if_icmpeq),
|
||||
0xA7 => Operation::Op("GOTO", goto),
|
||||
0xAC => Operation::Op("IRETURN", ireturn),
|
||||
0xB6 => Operation::Op("INVOKEVIRTUAL", invokevirtual),
|
||||
0xC4 => Operation::Op("WIDE", wide),
|
||||
0xFC => Operation::Op("IN", _in),
|
||||
0xFD => Operation::Op("OUT", out),
|
||||
0xFF => Operation::Op("HALT", halt),
|
||||
|
||||
#[cfg(feature = "extra:sleep")]
|
||||
0xF0 => Operation::Op("SLP", slp),
|
||||
|
||||
#[cfg(feature = "bonus:network")]
|
||||
0xE1 => Operation::Op("NETBIND", netbind),
|
||||
#[cfg(feature = "bonus:network")]
|
||||
0xE2 => Operation::Op("NETCONNECT", netconnect),
|
||||
#[cfg(feature = "bonus:network")]
|
||||
0xE3 => Operation::Op("NETIN", netin),
|
||||
#[cfg(feature = "bonus:network")]
|
||||
0xE4 => Operation::Op("NETOUT", netout),
|
||||
#[cfg(feature = "bonus:network")]
|
||||
0xE5 => Operation::Op("NETCLOSE", netclose),
|
||||
|
||||
x => Operation::Invalid(x)
|
||||
}
|
||||
}
|
||||
|
||||
fn nop(_: &mut Machine) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bipush(machine: &mut Machine) -> Result<()> {
|
||||
let val = match machine.block.read_i8() {
|
||||
Ok(a) => i32::from(a),
|
||||
Err(_) => return Err("Expected argument"),
|
||||
};
|
||||
machine.cur_stack().push(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dup(machine: &mut Machine) -> Result<()> {
|
||||
let val = machine.cur_stack().top()?;
|
||||
machine.cur_stack().push(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn out(machine: &mut Machine) -> Result<()> {
|
||||
let val = machine.cur_stack().pop()?;
|
||||
print!("{}", val as u8 as char);
|
||||
::std::io::stdout().flush().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop(machine: &mut Machine) -> Result<()> {
|
||||
machine.cur_stack().pop()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn iadd(machine: &mut Machine) -> Result<()> {
|
||||
let a = machine.cur_stack().pop()?;
|
||||
let b = machine.cur_stack().pop()?;
|
||||
machine.cur_stack().push(a + b);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn isub(machine: &mut Machine) -> Result<()> {
|
||||
let a = machine.cur_stack().pop()?;
|
||||
let b = machine.cur_stack().pop()?;
|
||||
machine.cur_stack().push(b - a);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _in(machine: &mut Machine) -> Result<()> {
|
||||
let char: Option<u8> =
|
||||
::std::io::stdin()
|
||||
.bytes()
|
||||
.next()
|
||||
.and_then(|r| r.ok());
|
||||
let val = match char {
|
||||
None => 0i32,
|
||||
Some(i) => i32::from(i)
|
||||
};
|
||||
machine.cur_stack().push(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn goto(machine: &mut Machine) -> Result<()> {
|
||||
let offset = i32::from(machine.block.read_i16()?) - JUMP_OFFSET;
|
||||
machine.block.jump(offset)
|
||||
}
|
||||
|
||||
fn halt(_: &mut Machine) -> Result<()> {
|
||||
Err("Halt")
|
||||
}
|
||||
|
||||
fn ifeq(machine: &mut Machine) -> Result<()> {
|
||||
let offset = i32::from(machine.block.read_i16()?) - JUMP_OFFSET;
|
||||
if machine.cur_stack().pop()? == 0 {
|
||||
return machine.block.jump(offset)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn iflt(machine: &mut Machine) -> Result<()> {
|
||||
let offset = i32::from(machine.block.read_i16()?) - JUMP_OFFSET;
|
||||
if machine.cur_stack().pop()? < 0 {
|
||||
return machine.block.jump(offset)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn if_icmpeq(machine: &mut Machine) -> Result<()> {
|
||||
let offset = i32::from(machine.block.read_i16()?) - JUMP_OFFSET;
|
||||
if machine.cur_stack().pop()? == machine.cur_stack().pop()? {
|
||||
return machine.block.jump(offset)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn iand(machine: &mut Machine) -> Result<()> {
|
||||
let a = machine.cur_stack().pop()?;
|
||||
let b = machine.cur_stack().pop()?;
|
||||
machine.cur_stack().push(a & b);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ior(machine: &mut Machine) -> Result<()> {
|
||||
let a = machine.cur_stack().pop()?;
|
||||
let b = machine.cur_stack().pop()?;
|
||||
machine.cur_stack().push(a | b);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ldc_w(machine: &mut Machine) -> Result<()> {
|
||||
let offset = machine.block.read_i16()? as usize;
|
||||
let val = machine.pool.get(offset)?;
|
||||
machine.cur_stack().push(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn swap(machine: &mut Machine) -> Result<()> {
|
||||
let a = machine.cur_stack().pop()?;
|
||||
let b = machine.cur_stack().pop()?;
|
||||
machine.cur_stack().push(a);
|
||||
machine.cur_stack().push(b);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wide(machine: &mut Machine) -> Result<()> {
|
||||
machine.wide = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn iload(machine: &mut Machine) -> Result<()> {
|
||||
let a = machine.read_index()?;
|
||||
let val = machine.cur_frame().get(a)?;
|
||||
machine.cur_stack().push(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn istore(machine: &mut Machine) -> Result<()> {
|
||||
let a = machine.read_index()?;
|
||||
let val = machine.cur_stack().pop()?;
|
||||
machine.cur_frame().set(a, val)
|
||||
}
|
||||
|
||||
fn iinc(machine: &mut Machine) -> Result<()> {
|
||||
let a = machine.read_index()?;
|
||||
let b = i32::from(machine.block.read_i8()?);
|
||||
let val = machine.cur_frame().get(a)?;
|
||||
machine.cur_frame().set(a, val + b)
|
||||
}
|
||||
|
||||
fn invokevirtual(machine: &mut Machine) -> Result<()> {
|
||||
let method_index = machine.block.read_u16()?;
|
||||
let invoke_addr = machine.pool.get(method_index as usize)?;
|
||||
let return_addr = machine.get_program_counter();
|
||||
// println!("METHOD {}", method_index);
|
||||
machine.block.seek(invoke_addr as usize)?;
|
||||
let arg_count = machine.block.read_u16()?;
|
||||
let var_count = machine.block.read_u16()?;
|
||||
let mut newframe = Frame::new((arg_count + var_count) as usize);
|
||||
|
||||
// Lifetime for cur_stack
|
||||
{
|
||||
let cur_stack = machine.cur_stack();
|
||||
for i in 1..arg_count {
|
||||
newframe.set((arg_count - i) as usize, cur_stack.pop()?)?;
|
||||
}
|
||||
|
||||
cur_stack.pop()?; // Nuke the OBJREF
|
||||
}
|
||||
|
||||
// println!("retaddr set {}" ,return_addr);
|
||||
newframe.set(0, return_addr as i32)?;
|
||||
|
||||
machine.frame.push(newframe);
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
fn ireturn(machine: &mut Machine) -> Result<()> {
|
||||
let mut prev_frame: Frame = match machine.frame.pop() {
|
||||
Some(a) => a,
|
||||
None => return Err("Got no frame... somehow...")
|
||||
};
|
||||
// println!("stack: {:?}", prev_frame.stack);
|
||||
let result = prev_frame.stack.pop()?;
|
||||
let return_addr = prev_frame.get(0)?;
|
||||
// println!("result: {}\nretaddr: {}", result, return_addr);
|
||||
machine.cur_stack().push(result);
|
||||
machine.block.seek(return_addr as usize)
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra:sleep")]
|
||||
fn slp(machine: &mut Machine) -> Result<()> {
|
||||
use std::time;
|
||||
use std::thread;
|
||||
let val = match machine.block.read_u8() {
|
||||
Ok(a) => u64::from(a),
|
||||
Err(_) => return Err("Expected argument"),
|
||||
};
|
||||
let slpdur = time::Duration::from_millis(val*100);
|
||||
thread::sleep(slpdur);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "bonus:network")]
|
||||
fn netbind(machine: &mut Machine) -> Result<()> {
|
||||
let port = machine.cur_stack().pop()? as u16;
|
||||
machine.net.bind(port)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bonus:network")]
|
||||
fn netconnect(machine: &mut Machine) -> Result<()> {
|
||||
let port = machine.cur_stack().pop()? as u16;
|
||||
let host = machine.cur_stack().pop()? as u32;
|
||||
machine.net.connect(host, port)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bonus:network")]
|
||||
fn netin(machine: &mut Machine) -> Result<()> {
|
||||
let byte = i32::from(machine.net.read_byte()?);
|
||||
machine.cur_stack().push(byte);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "bonus:network")]
|
||||
fn netout(machine: &mut Machine) -> Result<()> {
|
||||
let val = machine.cur_stack().pop()? as u8;
|
||||
machine.net.write_byte(val)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bonus:network")]
|
||||
fn netclose(machine: &mut Machine) -> Result<()> {
|
||||
machine.net.close()
|
||||
}
|
||||
Reference in New Issue
Block a user