use std::{error, fmt, time, path::PathBuf};
#[derive(Debug)]
pub enum Error {
Compile(String),
Runtime(RuntimeError),
Subprocess(subprocess::PopenError),
Syntax(usize),
Timeout,
}
impl error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let pre = "Error, I didn't quite get that.\n";
match self {
Error::Compile(s) => write!(f, "{}rustc error: {}", pre, s),
Error::Runtime(e) => write!(f, "{}Runtime error: {}", pre, e),
Error::Subprocess(e) => write!(f, "{}rustc error: {}", pre, e),
Error::Syntax(p) => write!(f, "{}Unmatched bracket at {}.", pre, p),
Error::Timeout => write!(f, "{}Executable timed out.", pre),
}
}
}
#[derive(Debug, PartialEq)]
pub enum RuntimeError {
OutOfMemoryBounds,
InputTooShort,
Signal,
}
impl fmt::Display for RuntimeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RuntimeError::OutOfMemoryBounds => write!(f, "access memory out of bounds"),
RuntimeError::InputTooShort => write!(f, "input was not long enough"),
RuntimeError::Signal => write!(f, "executable was probably killed by a signal"),
}
}
}
pub struct Exec {
program: String,
input: Option<String>,
time: Option<time::Duration>,
tmp_path: Option<PathBuf>,
}
impl Exec {
pub fn prog(prog: &str) -> Exec {
Exec {
program: String::from(prog),
input: None,
time: None,
tmp_path: None,
}
}
pub fn input(self, input: Option<String>) -> Exec {
Exec {
input,
..self
}
}
pub fn timeout(self, time: Option<time::Duration>) -> Exec {
Exec {
time,
..self
}
}
pub fn tmpdir(self, tmp_path: Option<PathBuf>) -> Exec {
Exec {
tmp_path,
..self
}
}
pub fn run(self) -> Result<String, Error> {
bf::run(&self.program, self.input, self.time, self.tmp_path)
}
pub fn interpret(self) -> Result<String, Error> {
bf::interpreter::run(&self.program, self.input, self.time)
}
pub fn transpile(self) -> Result<String, Error> {
bf::transpiler::run(&self.program, self.input, self.time, self.tmp_path)
}
pub fn translate(&self) -> Result<String, Error> {
bf::transpiler::translate(&self.program, self.input.clone())
}
}
pub fn check_brackets(prog: &str) -> Result<(), Error> {
let mut open: Vec<usize> = Vec::new();
for (i, b) in prog.as_bytes().iter().enumerate() {
match b {
b'[' => open.push(i),
b']' => {
if let None = open.pop() {
return Err(Error::Syntax(i));
};
}
_ => (),
}
}
if open.len() != 0 {
Err(Error::Syntax(open.pop().unwrap()))
} else {
Ok(())
}
}
pub fn wants_input(program: &str) -> bool {
program.contains(",")
}
mod bf;
#[cfg(test)]
mod tests;