use std::cell::RefCell;
use std::io::Write;
use std::rc::Rc;
use crate::context::Context;
use crate::error::{EngineError, MyError, MyResult};
use crate::interface::{Directive, Interface, Operation};
use crate::value::Value;
pub enum Action<W: Write> {
Operation(Rc<Operation<W>>),
Directive(Rc<Directive<W>>, Vec<String>),
Definition(Vec<Action<W>>),
Value(Value),
}
impl<W: Write> Clone for Action<W> {
fn clone(&self) -> Self {
match self {
Action::Operation(operation) => Action::Operation(operation.clone()),
Action::Directive(directive, tokens) => Action::Directive(directive.clone(), tokens.clone()),
Action::Definition(actions) => Action::Definition(actions.clone()),
Action::Value(value) => Action::Value(value.clone()),
}
}
}
pub struct Actions<'a, W: Write, I: Iterator<Item = &'a str>> {
interface: Rc<RefCell<Interface<W>>>,
context: Rc<RefCell<Context>>,
tokens: I,
}
impl<'a, W: Write, I: Iterator<Item = &'a str>> Actions<'a, W, I> {
pub fn new(
interface: &Rc<RefCell<Interface<W>>>,
context: &Rc<RefCell<Context>>,
tokens: I,
) -> Actions<'a, W, I> {
let interface = Rc::clone(interface);
let context = Rc::clone(context);
return Actions { interface, context, tokens };
}
}
impl<'a, W: Write, I: Iterator<Item = &'a str>> Iterator for Actions<'a, W, I> {
type Item = MyResult<(Action<W>, &'a str)>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(token) = self.tokens.next() {
let interface = self.interface.borrow();
if let Some(operation) = interface.get_operation(token) {
let action = Action::Operation(operation);
return Some(Ok((action, token)));
} else if let Some(directive) = interface.get_directive(token) {
let mut tokens = Vec::new();
while let Some(token) = self.tokens.next() {
tokens.push(String::from(token));
}
let action = Action::Directive(directive, tokens);
return Some(Ok((action, token)));
} else if let Some(actions) = interface.get_definition(token) {
let action = Action::Definition(actions);
return Some(Ok((action, token)));
} else {
match Value::from_string(&self.context.borrow(), token) {
Ok(value) => {
let action = Action::Value(value);
return Some(Ok((action, token)));
}
Err(_) => {
let error = EngineError::ParseError(String::from(token));
return Some(Err(MyError::from(error)));
}
}
}
}
return None;
}
}