use std::io::{Read, Write}; use std::sync::Mutex; use std::rc::Rc; use Result; use block::Block; use ops::Operation; use ijvmreader::IJVMReader; use binread::{BinRead, BinReadable}; use frame::Frame; use stack::Stack; use pool::Pool; #[cfg(feature = "bonus:network")] use netstack::NetStack; #[cfg(feature = "bonus:heap")] use heap::Heap; const MAGIC_HEADER:u32 = 0x1DEA_DFAD; const ANTI_BS_SIZE:usize = 0xFFFF; pub struct Machine { pub wide: bool, pub halted: bool, pub pool: Pool, pub block: Block, pub frame: Vec, #[cfg(feature = "bonus:network")] pub net: NetStack, #[cfg(feature = "bonus:heap")] pub heap: Heap, pub stream_in: Box, pub stream_out: Rc>, } impl Machine { pub fn new(pool: Pool, block: Block) -> Machine{ Machine { wide: false, halted: false, pool, block, frame: vec![Frame::new(ANTI_BS_SIZE)], stream_in: Box::new(::std::io::stdin()), stream_out: Rc::new(Mutex::new(::std::io::stdout())), #[cfg(feature = "bonus:network")] net: NetStack::new(), #[cfg(feature = "bonus:heap")] heap: Heap::new(), } } pub fn new_from_reader(mut reader: IJVMReader) -> Result { let magic = reader.read_u32()?; if magic != MAGIC_HEADER { return Err("Invalid magic header"); } let constants = match reader.read_block() { Ok(a) => a, Err(_) => return Err("Failed to read constants block") }; let text = match reader.read_block() { Ok(block) => block, Err(_) => return Err("Failed to read text block") }; let pool = Pool::new(constants)?; Ok(Machine::new(pool, text)) } pub fn new_from_file(file: &str) -> Result { let reader = IJVMReader::new(file).unwrap(); Machine::new_from_reader(reader) } pub fn new_from_slice(source: &[u8]) -> Result { let reader = IJVMReader::new_from_slice(source); Machine::new_from_reader(reader) } pub fn step(&mut self) -> Result<()> { match self.block.read_op() { Ok(Operation::Op(a, func)) => { if cfg!(feature = "debug:instr") { println!("{}", a); println!("Stack: {:?}", self.cur_frame().stack.data); let x = func(self); println!("Stack: {:?}", self.cur_frame().stack.data); x } else { func(self) } }, Ok(Operation::Invalid(a)) => { println!("UNDEFINED OP: 0x{:X}", a); Err("Invalid op") }, Err(str) => Err(str) } } pub fn run(&mut self) -> Result<()> { while self.has_step() { self.step()?; } Ok(()) } pub fn has_step(&self) -> bool { !self.halted && self.block.has_i8() } pub fn get_program_counter(&self) -> usize { self.block.cur() } pub fn get_tos(&mut self) -> Result { self.cur_stack().top() } pub fn cur_frame(&mut self) -> &mut Frame { self.frame.last_mut().unwrap() } pub fn cur_stack(&mut self) -> &mut Stack { &mut self.cur_frame().stack } pub fn cur_instruction(&mut self) -> u8 { self.block[self.get_program_counter()] } // pub fn get_stack_pointer(&self) -> usize { // return self.frame.last().unwrap().stack.len(); // } pub fn read_index(&mut self) -> Result { if self.wide { self.wide = false; return Ok(self.block.read_u16()? as usize) } Ok(self.block.read_u8()? as usize) } pub fn set_input(&mut self, instream: Box) { self.stream_in = instream; } pub fn set_output(&mut self, outstream: Rc>) { self.stream_out = outstream; } }