use std::fs::File; use std::io::prelude::*; use std::io::BufReader; use std::path::Path; use super::errors::GenericError; use super::vm::VariableType; use super::vm::{Command, CompiledReid}; #[cfg(feature = "compiler")] pub fn open_source(path: &Path) -> Result { let file = File::open(path)?; let mut reader = BufReader::new(file); let mut text = String::new(); reader.read_to_string(&mut text)?; Ok(text) } #[cfg(feature = "compiler")] pub fn into_bytecode(compiled: &CompiledReid) -> Vec { let mut list = Vec::new(); let cloned = compiled.list.clone().into_iter(); for item in cloned { list.append(&mut item.into_u8()); } list } #[cfg(feature = "compiler")] pub fn write_bytecode(bytecode: Vec, path: &Path) -> Result<(), GenericError> { let mut file = File::create(path)?; file.write_all(&bytecode)?; Ok(()) } pub fn open_bytecode(path: &Path) -> Result { let file = File::open(path)?; let mut reader = BufReader::new(file); let mut commands = Vec::new(); let mut iter = reader.fill_buf()?.iter().peekable(); while iter.peek().is_some() { if let Some(command) = Command::from_u8(&mut iter) { commands.push(command); } else { return Err(GenericError::CorruptedBytecode); } } Ok(CompiledReid { list: commands }) } impl VariableType { #[cfg(feature = "compiler")] fn into_u8(self) -> u8 { match self { VariableType::TypeString => 0, VariableType::TypeI32 => 1, } } fn from_u8(num: u8) -> Option { match num { 0 => Some(VariableType::TypeString), 1 => Some(VariableType::TypeI32), _ => None, } } } impl Command { #[cfg(feature = "compiler")] fn id(&self) -> u8 { match *self { Command::InitializeVariable(..) => 0, Command::BeginScope => 1, Command::EndScope => 2, Command::Pop(..) => 3, Command::Push(..) => 4, Command::AssignVariable(..) => 5, Command::VarToReg(..) => 6, Command::StringLit(..) => 7, Command::I32Lit(..) => 8, Command::FunctionCall(..) => 9, Command::Add => 10, Command::Subtract => 11, Command::Mult => 12, Command::Pow => 13, Command::Div => 14, Command::Mod => 15, } } fn from_u8<'a, T: Iterator>(iter: &mut T) -> Option { let id = iter.next()?; match id { 0 => { let heapid = u16::from_be_bytes([*iter.next()?, *iter.next()?]); Some(Command::InitializeVariable( heapid, VariableType::from_u8(*iter.next()?)?, )) } 1 => Some(Command::BeginScope), 2 => Some(Command::EndScope), 3 => Some(Command::Pop(*iter.next()?)), 4 => Some(Command::Push(*iter.next()?)), 5 => { let heapid = u16::from_be_bytes([*iter.next()?, *iter.next()?]); Some(Command::AssignVariable(heapid, *iter.next()?)) } 6 => { let heapid = u16::from_be_bytes([*iter.next()?, *iter.next()?]); Some(Command::VarToReg(heapid, *iter.next()?)) } 7 => { let len = u32::from_be_bytes([ *iter.next()?, *iter.next()?, *iter.next()?, *iter.next()?, ]); let string = String::from_utf8(iter.take(len as usize).cloned().collect()).ok()?; Some(Command::StringLit(string)) } 8 => { let num = i32::from_be_bytes([ *iter.next()?, *iter.next()?, *iter.next()?, *iter.next()?, ]); Some(Command::I32Lit(num)) } 9 => { let funcid = u16::from_be_bytes([*iter.next()?, *iter.next()?]); Some(Command::FunctionCall(funcid)) } 10 => Some(Command::Add), 11 => Some(Command::Subtract), 12 => Some(Command::Mult), 13 => Some(Command::Pow), 14 => Some(Command::Div), 15 => Some(Command::Mod), _ => None, } } #[cfg(feature = "compiler")] fn into_u8(self) -> Vec { let mut list = Vec::new(); list.push(self.id()); match &self { Command::InitializeVariable(heapid, variabletype) => { let heapid = heapid.to_be_bytes(); list.append(&mut vec![heapid[0], heapid[1], variabletype.into_u8()]) } Command::BeginScope => (), Command::EndScope => (), Command::Pop(regid) => list.push(*regid), Command::Push(regid) => list.push(*regid), Command::AssignVariable(heapid, regid) => { let heapid = heapid.to_be_bytes(); list.append(&mut vec![heapid[0], heapid[1], *regid]); } Command::VarToReg(heapid, regid) => { let heapid = heapid.to_be_bytes(); list.append(&mut vec![heapid[0], heapid[1], *regid]); } Command::StringLit(string) => { let string = string.as_bytes(); let len = (string.len() as u32).to_be_bytes(); list.append(&mut vec![len[0], len[1], len[2], len[3]]); list.append(&mut string.to_vec()); } Command::I32Lit(num) => { let num = num.to_be_bytes(); list.append(&mut vec![num[0], num[1], num[2], num[3]]); } Command::FunctionCall(funcid) => { let funcid = funcid.to_be_bytes(); list.append(&mut vec![funcid[0], funcid[1]]); } Command::Add => (), Command::Subtract => (), Command::Mult => (), Command::Pow => (), Command::Div => (), Command::Mod => (), } list } }