use super::instruction::{mapper, Instruction};
use super::program::Program;
use super::error::Error;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::convert::AsRef;
pub struct Parser {
code_buffer:Vec<u8>,
}
impl Parser {
pub fn new() -> Parser {
Parser {
code_buffer:Vec::<u8>::new(),
}
}
pub fn load<S: Into<String>>(&mut self, buffer:S) -> Result<(), Error> {
self.code_buffer = buffer.into().into_bytes();
match self.code_buffer.len() {
l if l > 0 => Result::Ok(()),
_ => Result::Err(Error::EmptyProgram),
}
}
pub fn load_from_file<P: AsRef<Path>>(&mut self, src:P) -> Result<(), Error> {
match File::open(src) {
Ok(mut file) => {
let mut content = String::new();
match file.read_to_string(&mut content) {
_ => self.load(content)
}
}
Err(_) => Result::Err(Error::NoSuchFile),
}
}
pub fn parse(&mut self) -> Result<Program, Error> {
let mut prog = Program::new();
let mut loop_stack = Vec::<usize>::new();
let mut code_ptr:usize = 0;
if self.code_buffer.len() != 0 {
loop {
match self.code_buffer[code_ptr] as char {
b @ '+' => { prog.push(mapper::get_instr(b).unwrap()); }
b @ '-' => { prog.push(mapper::get_instr(b).unwrap()); }
b @ '>' => { prog.push(mapper::get_instr(b).unwrap()); }
b @ '<' => { prog.push(mapper::get_instr(b).unwrap()); }
b @ ',' => { prog.push(mapper::get_instr(b).unwrap()); }
b @ '.' => { prog.push(mapper::get_instr(b).unwrap()); }
b @ '[' => {
prog.push(mapper::get_instr(b).unwrap());
loop_stack.push(prog.get_size() - 1);
}
']' => {
if loop_stack.is_empty() {
return Result::Err(Error::MissingOpenBracket);
}
let curr_ptr = prog.get_size();
let last_open_bracket_ptr = loop_stack.pop().unwrap();
prog.update_instr(last_open_bracket_ptr, Instruction::OpenBracket(curr_ptr));
prog.push(Instruction::CloseBracket(last_open_bracket_ptr));
}
_ => { }
};
code_ptr += 1;
if code_ptr >= self.code_buffer.len() {
break;
}
}
if !loop_stack.is_empty() {
return Result::Err(Error::MissingCloseBracket);
}
} else {
return Result::Err(Error::EmptyProgram);
}
if prog.get_size() == 0 {
return Result::Err(Error::EmptyProgram);
}
return Result::Ok(prog);
}
}