use crate::const_getter::ConstGetters;
use crate::extractor::parse_extractor;
use crate::extractor::root;
use crate::functions_definitions::FunctionDefinitionsError;
use crate::functions_definitions::find_function;
use crate::input_context_extractor::InputContextExtractorParseError;
use crate::input_context_extractor::parse_input_context;
use crate::json_parser::JsonParserError;
use crate::json_value::JsonValue;
use crate::processor::Context;
use crate::processor::Process;
use crate::processor::ProcessDecision;
use crate::processor::Result as ProcessResult;
use crate::processor::Titles;
use crate::reader::Location;
use crate::reader::Reader;
use crate::reader::from_string;
use crate::selection_extractor::parse_get_selection;
use crate::variables_extractor::parse_get_variable;
use std::io::Error as IoError;
use std::io::Read;
use std::num::ParseIntError;
use std::rc::Rc;
use std::str::FromStr;
use std::string::FromUtf8Error;
use std::vec;
use thiserror::Error;
pub trait Get {
fn get(&self, value: &Context) -> Option<JsonValue>;
}
#[derive(Clone)]
pub struct Selection {
getter: Rc<dyn Get>,
name: Rc<String>,
}
pub type Result<T> = std::result::Result<T, SelectionParseError>;
#[derive(Debug, Error)]
pub enum SelectionParseError {
#[error("{0}")]
IoError(#[from] IoError),
#[error("{0}")]
JsonError(#[from] JsonParserError),
#[error("{0}")]
StringUtfError(#[from] FromUtf8Error),
#[error("{0}")]
NumberParseError(#[from] ParseIntError),
#[error("{0}")]
Function(#[from] FunctionDefinitionsError),
#[error("{0}")]
InputContext(#[from] InputContextExtractorParseError),
#[error("{0}, Missing key name")]
MissingKey(Location),
#[error("{0}: Expecting equals, got {1}")]
ExpectingEquals(Location, char),
#[error("{0}: Expecting EOF, got {1}")]
ExpectingEof(Location, char),
#[error("Unexpected end of string")]
UnexpectedEof,
}
impl FromStr for Selection {
type Err = SelectionParseError;
fn from_str(s: &str) -> Result<Self> {
let source = s.to_string();
let mut reader = from_string(&source);
reader.eat_whitespace()?;
let extractors = read_getter(&mut reader)?;
reader.eat_whitespace()?;
let name = match reader.peek()? {
Some(b'=') => {
reader.next()?;
reader.eat_whitespace()?;
let mut buf = vec![];
while let Some(ch) = reader.peek()? {
buf.push(ch);
reader.next()?;
}
String::from_utf8(buf)?
}
Some(ch) => {
return Err(SelectionParseError::ExpectingEquals(
reader.where_am_i(),
ch as char,
));
}
None => source.clone(),
};
let getter = extractors;
let name = Rc::new(name);
Ok(Selection { getter, name })
}
}
struct SelectionProcess {
name: Rc<String>,
getter: Rc<dyn Get>,
next: Box<dyn Process>,
}
impl Process for SelectionProcess {
fn start(&mut self, titles_so_far: Titles) -> ProcessResult<()> {
let next_titles = titles_so_far.with_title(&self.name);
self.next.start(next_titles)
}
fn complete(&mut self) -> ProcessResult<()> {
self.next.complete()
}
fn process(&mut self, context: Context) -> ProcessResult<ProcessDecision> {
let result = self.getter.get(&context);
let new_context = context.with_result(&self.name, result);
self.next.process(new_context)?;
Ok(ProcessDecision::Continue)
}
}
pub fn read_getter<R: Read>(reader: &mut Reader<R>) -> Result<Rc<dyn Get>> {
reader.eat_whitespace()?;
match reader.peek()? {
None => Err(SelectionParseError::UnexpectedEof),
Some(b'.' | b'#' | b'^') => parse_extractor(reader),
Some(b'(') => parse_function(reader),
Some(b':' | b'@') => parse_get_variable(reader),
Some(b'&') => parse_input_context(reader),
Some(b'/') => parse_get_selection(reader),
_ => match ConstGetters::parse(reader)? {
None => Err(SelectionParseError::UnexpectedEof),
Some(getter) => Ok(Rc::new(getter)),
},
}
}
fn parse_function<R: Read>(reader: &mut Reader<R>) -> Result<Rc<dyn Get>> {
let mut name = read_function_name(reader)?;
let mut args: Vec<Rc<dyn Get>> = Vec::new();
if name.starts_with('.') {
args.push(root());
name = name[1..].to_string();
}
let function = find_function(&name)?;
loop {
reader.eat_whitespace()?;
match reader.peek()? {
Some(b',') => {
reader.next()?;
}
Some(b')') => {
break;
}
None => {
return Err(SelectionParseError::UnexpectedEof);
}
_ => {
let arg = read_getter(reader)?;
args.push(arg);
}
}
}
reader.next()?;
let fun = function.create(args)?;
Ok(fun)
}
fn read_function_name<R: Read>(reader: &mut Reader<R>) -> Result<String> {
reader.eat_whitespace()?;
let mut buf = Vec::new();
loop {
match reader.next()? {
None => {
break;
}
Some(ch) => {
if ch.is_ascii_whitespace()
|| ch == b','
|| ch == b'('
|| ch == b')'
|| ch.is_ascii_control()
{
break;
}
buf.push(ch);
}
}
}
let str = String::from_utf8(buf)?;
Ok(str)
}
impl Selection {
pub fn create_process(&self, next: Box<dyn Process>) -> Box<dyn Process> {
let process = SelectionProcess {
name: self.name.clone(),
getter: self.getter.clone(),
next,
};
Box::new(process)
}
}
impl Get for Selection {
fn get(&self, context: &Context) -> Option<JsonValue> {
self.getter.get(context)
}
}