use std;
use std::collections::HashMap;
use std::rc::Rc;
use super::{Command, Status};
#[derive(Debug)]
struct StackFrame {
store_load: Vec<Status>, ops: *const Operation,
len: usize,
pos: usize,
}
struct FrameHolder<'a, 'b> where 'b: 'a {
frame: Option<StackFrame>,
_lt: std::marker::PhantomData<&'a [Operation]>,
state: &'b mut State,
}
impl<'a, 'b> FrameHolder<'a, 'b> where 'b: 'a {
fn new(state: &'b mut State, ops: &'a [Operation]) -> FrameHolder<'a, 'b> where 'b: 'a {
FrameHolder {
frame: Some(StackFrame { store_load: Vec::new(), ops: ops.as_ptr(), len: ops.len(), pos: 0 }),
_lt: std::marker::PhantomData,
state: state
}
}
fn with<F, R>(mut self, f: F) -> R where F: FnOnce(&mut State) -> R {
let frame = self.frame.take().unwrap();
self.state.frames.push(frame);
f(self.state)
}
}
impl<'a, 'b> Drop for FrameHolder<'a, 'b> where 'b: 'a {
fn drop(&mut self) {
self.state.frames.pop();
}
}
#[derive(Debug, Clone)]
pub struct Operation {
trigger: [bool; 2],
force: [bool; 2],
cont: [bool; 4],
op: String,
args: Vec<String>
}
impl Operation {
pub fn trigger(&self) -> [bool; 2] {
self.trigger
}
}
#[derive(Debug)]
pub struct State {
frames: Vec<StackFrame>,
commands: HashMap<&'static str, Rc<Command>>,
}
impl State {
pub fn new() -> State {
State { frames: Vec::new(), commands: HashMap::new() }
}
pub fn register_command<T: 'static + Command>(&mut self, command: T) {
self.commands.insert(command.get_name(), Rc::new(command));
}
pub fn get_store_load<F, R>(&mut self, f: F) -> R where F: FnOnce(&mut Vec<Status>) -> R {
f(&mut self.frames.last_mut().unwrap().store_load)
}
pub fn get_op<F, R>(&self, f: F) -> R where F: FnOnce(&Operation) -> R {
unsafe {
let frame = self.frames.last().unwrap();
f(&std::slice::from_raw_parts(frame.ops, frame.len)[frame.pos])
}
}
pub fn get_pos(&self) -> usize {
self.frames.last().unwrap().pos
}
pub fn call(&mut self, prog: &[Operation]) -> Status {
FrameHolder::new(self, prog).with(|x| x.run(0).no_return())
}
pub fn run(&mut self, from: usize) -> Status {
let mut status = Status::Success;
let oldpos = self.frames.last_mut().unwrap().pos;
self.frames.last_mut().unwrap().pos = from;
while self.frames.last().unwrap().pos < self.frames.last().unwrap().len {
status = if self.get_op(|op| op.trigger[*status]) {
let newstatus = {
if let Some(x) = self.get_op(|op| self.commands.get(op.op.as_str()).map(|x| x.clone())) {
let args = self.get_op(|op| op.args.clone()); x.run(self, status, &args)
} else {
Status::Failure
}
};
if newstatus.is_return() {
self.frames.last_mut().unwrap().pos = oldpos;
return newstatus;
}
if self.get_op(|op| op.cont[*status * 2 + *newstatus]) {
Status::Success
} else {
Status::Failure
}
} else if self.get_op(|op| op.force[*status]) {
status
} else {
self.frames.last_mut().unwrap().pos = oldpos;
return status;
};
self.frames.last_mut().unwrap().pos += 1;
}
self.frames.last_mut().unwrap().pos = oldpos;
status
}
pub fn parse<I>(&mut self, program: I) -> Vec<Operation> where I: Iterator<Item=char> {
program.chain("\n".chars()).scan(String::new(), |state, x| {
if x == '\r' || x == '\n' {
let s = state.clone();
state.clear();
Some(Some(s))
} else {
state.push(x);
Some(None)
}
}).flat_map(|x| x) .filter(|x| !x.is_empty())
.filter(|x| !x.starts_with("#"))
.map(|x| {
let mut itr = x.chars();
let trigger = itr.next().and_then(|c| c.to_digit(16)).unwrap();
let cont = itr.next().and_then(|c| c.to_digit(16)).unwrap();
if itr.next().unwrap() != ' ' { panic!(); }
let mut parts = itr.as_str().split(' ');
let op = parts.next().unwrap().to_owned();
let args = parts.map(|x| x.to_owned()).collect();
Operation {
trigger: [trigger & 1 != 0, trigger & 2 != 0],
force: [trigger & 4 != 0, trigger & 8 != 0],
cont: [cont & 1 != 0, cont & 2 != 0, cont & 4 != 0, cont & 8 != 0],
op: op,
args: args
}
})
.collect()
}
}