use crate::ledstrip_controller::{LedStripController, StateStripCommand}; use crate::registers::{ Rcb, Rcg, Rcr, Rcs, Register, Rgd, Rgi, Rgl, Rgo, Rgp, RCB, RCG, RCR, RGD, RGI, RGL, RGO, RGP, }; use crate::tokens::{ AddToken, AndToken, ClearToken, CmdToken, CopyToken, DebugToken, DivToken, ExitToken, FromBytecode, GotoToken, JeToken, JgToken, JlToken, LabelToken, LoadToken, LshToken, ModToken, MulToken, NopToken, NotToken, NrtToken, OrToken, PauseToken, PowToken, PrintToken, RshToken, SendToken, SetToken, SubToken, Token, WriteToken, XorToken, T_ADD, T_AND, T_CLEAR, T_CMD, T_COPY, T_DEBUG, T_DIV, T_EXIT, T_GOTO, T_JE, T_JG, T_JL, T_LABEL, T_LOAD, T_LSH, T_MOD, T_MUL, T_NOT, T_NRT, T_OR, T_PAUSE, T_POW, T_PRINT, T_RSH, T_SEND, T_SET, T_SUB, T_WRITE, T_XOR, }; use std::cell::RefCell; use std::collections::HashMap; use std::io; use std::rc::Rc; #[derive(Clone)] pub struct Runtime { pub rcs: Rcs, pub rcr: Rcr, pub rcg: Rcg, pub rcb: Rcb, pub rgd: Rgd, pub rgp: Rgp, pub rgi: Rgi, pub rgo: Rgo, pub rgl: Rgl, pub memory: HashMap, text: Rc>>>, pub labels: HashMap, pub strip_controller: Rc>, exit: Option, current_index: usize, } impl Runtime { pub fn new(ip: &str, port: usize) -> Self { let controller = LedStripController::new(ip, port) .expect("failed to establish a connection to the led strip"); let controller = Rc::new(RefCell::new(controller)); Self { rcs: Rcs::new(controller.clone()), rcr: Rcr::new(), rcg: Rcg::new(), rcb: Rcb::new(), rgd: Rgd::new(), rgp: Rgp::new(), rgi: Rgi::new(), rgo: Rgo::new(), rgl: Rgl::new(), memory: HashMap::new(), text: Rc::new(RefCell::new(Vec::new())), labels: HashMap::new(), strip_controller: controller, exit: None, current_index: 0, } } /// Parses a vector containing the bytecode into a vector of tokens /// that can be executed pub fn parse_bytecode(&mut self, bytecode: Vec) { let mut code_iter = bytecode.iter(); let mut text = self.text.borrow_mut(); let mut index = 0; while let Some(instruction) = code_iter.next() { match *instruction { T_EXIT => text.push(Box::new(ExitToken::from_bytecode(&[ instruction, code_iter.next().unwrap(), ]))), T_SET => text.push(Box::new(SetToken::from_bytecode(&[ instruction, code_iter.next().unwrap(), code_iter.next().unwrap(), ]))), T_COPY => text.push(Box::new(CopyToken::from_bytecode(&[ instruction, code_iter.next().unwrap(), code_iter.next().unwrap(), ]))), T_LOAD => text.push(Box::new(LoadToken)), T_CLEAR => text.push(Box::new(ClearToken::from_bytecode(&[ instruction, code_iter.next().unwrap(), ]))), T_WRITE => text.push(Box::new(WriteToken)), T_LABEL => { let token = LabelToken::from_bytecode(&[ instruction, code_iter.next().unwrap(), code_iter.next().unwrap(), code_iter.next().unwrap(), code_iter.next().unwrap(), ]); self.labels.insert(token.value, index); text.push(Box::new(token)); } T_GOTO => text.push(Box::new(GotoToken)), T_DEBUG => text.push(Box::new(DebugToken)), T_PRINT => text.push(Box::new(PrintToken::from_bytecode(&[ instruction, code_iter.next().unwrap(), ]))), T_ADD => text.push(Box::new(AddToken)), T_SUB => text.push(Box::new(SubToken)), T_MUL => text.push(Box::new(MulToken)), T_DIV => text.push(Box::new(DivToken)), T_MOD => text.push(Box::new(ModToken)), T_LSH => text.push(Box::new(LshToken)), T_RSH => text.push(Box::new(RshToken)), T_AND => text.push(Box::new(AndToken)), T_OR => text.push(Box::new(OrToken)), T_NOT => text.push(Box::new(NotToken)), T_XOR => text.push(Box::new(XorToken)), T_POW => text.push(Box::new(PowToken)), T_NRT => text.push(Box::new(NrtToken)), T_JG => text.push(Box::new(JgToken)), T_JL => text.push(Box::new(JlToken)), T_JE => text.push(Box::new(JeToken)), T_PAUSE => text.push(Box::new(PauseToken)), T_CMD => text.push(Box::new(CmdToken)), T_SEND => text.push(Box::new(SendToken)), _ => panic!("unknown instruction {}", instruction), }; index += 1; } } /// Executes the text stored in the runtime pub fn run(&mut self) -> io::Result { let text_ref = self.text.clone(); let text = text_ref.borrow_mut(); while self.current_index < text.len() { let token = text.get(self.current_index).unwrap(); token.invoke(self)?; if let Some(code) = self.exit { self.strip_controller .borrow_mut() .set_state(StateStripCommand::Off) .unwrap(); return Ok(code); } self.current_index += 1; } self.strip_controller .borrow_mut() .set_state(StateStripCommand::Off) .unwrap(); Ok(0) } /// Exists the program with a specified error code pub fn exit(&mut self, code: u8) { self.exit = Some(code); } /// Returns the 1byte register referenced by the code pub fn get_1byte_register(&mut self, code: u8) -> Option>> { match code { RCR => Some(Box::new(&mut self.rcr)), RCG => Some(Box::new(&mut self.rcg)), RCB => Some(Box::new(&mut self.rcb)), _ => None, } } /// Returns the 4byte register referenced by the code pub fn get_4byte_register(&mut self, code: u8) -> Option>> { match code { RGD => Some(Box::new(&mut self.rgd)), RGP => Some(Box::new(&mut self.rgp)), RGI => Some(Box::new(&mut self.rgi)), RGO => Some(Box::new(&mut self.rgo)), RGL => Some(Box::new(&mut self.rgl)), _ => None, } } /// Creates a new label at the current position pub fn create_label(&mut self, id: u32) { self.labels.insert(id, self.current_index); } /// Jumps to a specified label pub fn jump(&mut self, label: u32) -> io::Result<()> { self.current_index = *self .labels .get(&label) .expect(&format!("The label {} does not exist", label)); Ok(()) } }