use std::collections::HashSet;
use std::fmt;
use indexmap::IndexSet;
use crate::{static_throw, SchemeInit};
use crate::lexer::lexer::LexerInfo;
use crate::common;
use crate::serializator::serializator::StructName;
use super::error::StaticSchemeRes;
use super::init::{Environment, StaticShm};
use super::scheme::VectorSerializType;
use super::scheme::{ArgDataType, ProcFlags};
pub struct CommonReader<'cr>
{
env: &'cr Environment,
li: &'cr LexerInfo,
args: &'cr [StaticShm],
counter: usize,
}
impl<'cr> CommonReader<'cr>
{
#[inline]
fn resolve_symbol(&self, name: &String, li: &LexerInfo) -> StaticSchemeRes<&StaticShm>
{
match self.env.get(name)
{
Some(r) =>
return Ok(r),
None =>
static_throw!(li, "identifier: '{}' not found", name)
}
}
pub
fn new(env: &'cr Environment, li: &'cr LexerInfo, args: &'cr [StaticShm], counter: usize) -> Self
{
return Self {env: env, li: li, args: args, counter: counter};
}
pub
fn is_eof(&self) -> bool
{
return self.counter >= self.args.len();
}
pub
fn get_counter(&self) -> usize
{
return self.counter;
}
pub
fn get_prev_lexerinfo(&self) -> LexerInfo
{
let index =
if self.counter == 0
{
self.counter
}
else
{
self.counter - 1
};
return self.args[index].extract_lexerinfo();
}
pub
fn get_lexerinfo(&self) -> LexerInfo
{
if self.counter >= self.args.len()
{
return LexerInfo::notexistent();
}
else
{
return self.args[self.counter].extract_lexerinfo();
}
}
pub
fn left(&self) -> usize
{
return self.args.len() - self.counter;
}
pub
fn now_eof(&self) -> StaticSchemeRes<()>
{
if self.counter >= self.args.len()
{
static_throw!(self.li, "unexpected EOF was reached {} < {}", self.counter, self.args.len());
}
return Ok(());
}
pub
fn eof(&self) -> StaticSchemeRes<()>
{
if self.counter < self.args.len()
{
static_throw!(self.li, "expected EOF, but was not reached {} < {}", self.counter, self.args.len());
}
return Ok(());
}
pub
fn evaluate_list<F>(&mut self, throw: bool, steps: usize, mut hndl: F) -> StaticSchemeRes<()>
where F: FnMut(&Vec<StaticShm>, &Environment, &LexerInfo) -> StaticSchemeRes<()>
{
let l_steps =
if steps == 0
{
self.args.len()
}
else
{
if (self.counter + steps) > self.args.len()
{
static_throw!(&self.args[self.counter].extract_lexerinfo(), "evaluate_list(), step too large {} len: {}, \n {:?}",
steps, self.args.len(), &self.args[self.counter..self.args.len()]);
}
else
{
self.counter + steps
}
};
let mut offset = 0;
for arg in &self.args[self.counter..l_steps]
{
match arg
{
StaticShm::List(ref list, ref li) =>
{
if list.len() > 0
{
hndl(list, &self.env, li)?;
offset += 1;
}
else
{
static_throw!(li, "empty procedure: '{}'", arg);
}
},
_ =>
{
if throw == true
{
static_throw!(&arg.extract_lexerinfo(), "expected procedure, found: '{}'", arg);
}
}
}
}
self.counter += offset;
return Ok(());
}
pub
fn evaluate_procedure(&mut self, arg_name: &'static str) -> StaticSchemeRes<StaticShm>
{
self.now_eof()?;
let ref arg = self.args[self.counter];
match arg
{
StaticShm::List(ref list, ref li) =>
{
if list.len() > 0
{
let eval = SchemeInit::evaluate_expression(list, self.env, li)?;
self.counter += 1;
return Ok(eval);
}
else
{
static_throw!(li, "arg name: '{}', empty procedure", arg_name);
}
},
_ =>
{
static_throw!(&arg.extract_lexerinfo(), "expected procedure, found: '{}'", arg);
}
}
}
pub
fn read_vectype(&mut self, arg_title: &'static str) -> StaticSchemeRes<VectorSerializType>
{
self.now_eof()?;
let ref arg = self.args[self.counter];
match arg
{
StaticShm::Symbol(ref name, ref li) =>
{
let symb = self.resolve_symbol(name, li)?;
let res =
match symb
{
StaticShm::VectorType(s) =>
{
s.clone()
}
_ =>
static_throw!(&symb.extract_lexerinfo(), "arg name: '{}', expected speficif keyword 'field_data_type' \
i.e f/list, found: '{}'", arg_title, symb
),
};
self.counter += 1;
return Ok(res);
},
_ =>
static_throw!(&arg.extract_lexerinfo(), "expected speficif keyword 'field_data_type' \
i.e f/list, found: '{}'", arg),
}
}
pub
fn read_datatype(&mut self) -> StaticSchemeRes<ArgDataType>
{
self.now_eof()?;
let ref arg = self.args[self.counter];
match arg
{
StaticShm::Symbol(ref name, ref li) =>
{
let symb = self.resolve_symbol(name, li)?;
let res =
match symb
{
StaticShm::ArgDataTypeEnum(s) =>
{
s.clone()
}
_ =>
static_throw!(&symb.extract_lexerinfo(), "expected speficic keyword 'field_data_type' \
i.e f/list, found: '{}'", symb),
};
self.counter += 1;
return Ok(res);
},
_ =>
static_throw!(&arg.extract_lexerinfo(), "expected speficic keyword 'field_data_type' \
i.e f/list, found: '{}'", arg),
}
}
fn check_string(&mut self, s: &String, li: &LexerInfo, arg_title: &str) -> StaticSchemeRes<()>
{
if common::contains_printable_all(s) == false || s.is_empty() == true
{
static_throw!(li, "arg title: '{}', string: '{}', empty string or \
string contains non printable characters which is not allowed",
arg_title, common::sanitize_str_unicode(s));
}
return Ok(());
}
pub
fn read_string(&mut self, arg_title: &'static str) -> StaticSchemeRes<String>
{
self.now_eof()?;
let ref arg = self.args[self.counter];
match arg
{
StaticShm::String(ref s, ref li) =>
{
self.check_string(s, li, arg_title)?;
self.counter += 1;
return Ok(s.clone());
},
_ =>
static_throw!(&arg.extract_lexerinfo(), "arg title: '{}', arg count: '{}', expected <string>, found: '{}'",
arg_title, self.counter, arg),
};
}
pub
fn read_int(&mut self) -> StaticSchemeRes<i64>
{
self.now_eof()?;
let ref arg = self.args[self.counter];
match arg
{
StaticShm::Int(ref i, _) =>
{
self.counter += 1;
return Ok(*i);
},
_ =>
static_throw!(&arg.extract_lexerinfo(), "arg cnt: '{}', expected <int>, found: '{}'",
self.counter, arg),
};
}
pub
fn read_uint(&mut self) -> StaticSchemeRes<u64>
{
let ref arg = self.args[self.counter];
match arg
{
StaticShm::UInt(ref u, _) =>
{
self.counter += 1;
return Ok(*u);
},
_ =>
static_throw!(&arg.extract_lexerinfo(), "arg cnt: '{}', expected <uint>, found: '{}'",
self.counter, arg),
};
}
pub
fn read_string_or_symbol(&mut self, arg_title: &'static str) -> StaticSchemeRes<&StaticShm>
{
self.now_eof()?;
let arg = &self.args[self.counter];
match arg
{
StaticShm::String(s, ref li) =>
{
self.check_string(s, li, arg_title)?;
},
StaticShm::Symbol(_name, _li) =>
{
}
_ =>
static_throw!(&arg.extract_lexerinfo(), "expected <symbol|string>, found: '{}'", arg),
}
self.counter += 1;
return Ok(arg);
}
pub
fn read_uint_or_datawidth(&mut self, arg_title: &'static str) -> StaticSchemeRes<&StaticShm>
{
self.now_eof()?;
let arg = &self.args[self.counter];
match *arg
{
StaticShm::UInt(_, _) => {},
StaticShm::Symbol(_, _) => {},
_ =>
static_throw!(&arg.extract_lexerinfo(), "argument: '{}', expected <symbol(uint)|uint>, found: '{}'", arg_title, arg),
}
self.counter += 1;
return Ok(arg);
}
pub
fn read_sibs(&mut self, arg_title: &'static str) -> StaticSchemeRes<&StaticShm>
{
self.now_eof()?;
let arg = &self.args[self.counter];
match arg
{
StaticShm::String(s, ref li) =>
{
self.check_string(s, li, arg_title)?;
},
StaticShm::Int(_, _) |
StaticShm::UInt(_, _) |
StaticShm::Boolean(_, _) |
StaticShm::Symbol(_, _) => {},
_ =>
static_throw!(&arg.extract_lexerinfo(), "expected <symbol|integer|uinteger|boolean> \
found: '{}'", arg),
}
self.counter += 1;
return Ok(arg);
}
pub
fn read_sibr(&mut self, arg_title: &'static str) -> StaticSchemeRes<&StaticShm>
{
self.now_eof()?;
let arg = &self.args[self.counter];
match arg
{
StaticShm::String(s, ref li) =>
{
self.check_string(s, li, arg_title)?;
},
StaticShm::Int(_, _) |
StaticShm::UInt(_, _) |
StaticShm::LongInt(_, _) |
StaticShm::LongUInt( .. ) |
StaticShm::Boolean(_, _) => {},
_ =>
static_throw!(&arg.extract_lexerinfo(), "arg title: '{}', arg count: '{}', expected <string>, found: '{}'",
arg_title, self.counter, arg),
}
self.counter += 1;
return Ok(arg);
}
pub
fn common_read_bool(&mut self) -> StaticSchemeRes<bool>
{
self.now_eof()?;
let ref arg = self.args[self.counter];
match arg
{
StaticShm::Boolean(ref b, _) =>
{
self.counter += 1;
return Ok(*b);
},
_ =>
static_throw!(&arg.extract_lexerinfo(), "expected <boolean>, found: '{}'", arg)
}
}
pub
fn read_struct_name(&mut self, arg_title: &'static str) -> StaticSchemeRes<StructName>
{
self.now_eof()?;
let arg = &self.args[self.counter];
match *arg
{
StaticShm::String(ref s, ref li) =>
{
self.check_string(s, li, arg_title)?;
self.counter += 1;
return Ok(StructName::Name(s.clone()));
},
StaticShm::List(ref _list, ref _li) =>
{
let names = self.read_hset_string_nodup(arg_title)?;
return Ok(StructName::Names(names));
},
StaticShm::Symbol(ref name, ref li) =>
{
let symb = self.resolve_symbol(name, li)?;
let res =
match symb
{
StaticShm::StructNameEnum(s) =>
{
s.clone()
}
_ =>
static_throw!(&symb.extract_lexerinfo(), "expected speficif keyword 'field_data_type' \
i.e f/list, found: '{}'", symb),
};
self.counter += 1;
return Ok(res);
},
_ =>
static_throw!(&arg.extract_lexerinfo(), "expected <symbol|string>, found: '{}'", arg),
}
}
pub
fn read_proc_flags(&mut self, arg_title: &'static str) -> StaticSchemeRes<ProcFlags>
{
let arg = &self.args[self.counter];
let argeval =
SchemeInit::evaluate_value(arg, self.env.clone())?;
let mut flags: ProcFlags = ProcFlags::empty();
match argeval
{
StaticShm::List(list, ref li) =>
{
for l in list
{
match l
{
StaticShm::Symbol(s, lli) =>
{
let l = self.resolve_symbol(&s, &lli)?;
match *l
{
StaticShm::ProcedureFlags(u) =>
{
if flags.intersects(u) == true
{
static_throw!(&lli, "argument: '{}' duplicate flag: '{}', started at: {}", arg_title, s, li);
}
flags.toggle(u);
},
_ =>
static_throw!(&lli, "argument: '{}' expected <ProcedureFlags>, started at: {}", arg_title, li),
}
},
_ =>
static_throw!(&l.extract_lexerinfo(), "read_proc_flags(), argument: '{}' \
expected <symbol>, found: '{}'", arg_title, l),
}
}
},
_ =>
static_throw!(&argeval.extract_lexerinfo(), "read_proc_flags(), argument: '{}' \
expected <list>, found: '{}'", arg_title, argeval),
}
self.counter += 1;
return Ok(flags);
}
pub
fn read_vec_string_nodup(&mut self, arg_title: &'static str) -> StaticSchemeRes<Vec<String>>
{
let arg = &self.args[self.counter];
let argeval =
SchemeInit::evaluate_value(arg, self.env.clone())?;
let mut retlist: Vec<String> = Vec::new();
let mut dup_list: HashSet<String> = HashSet::new();
match argeval
{
StaticShm::List(list, ref _li) =>
{
for l in list
{
match l
{
StaticShm::String(s, lli) =>
{
self.check_string(&s, &lli, arg_title)?;
if dup_list.insert(s.clone()) == false
{
static_throw!(&lli, "arg name: '{}', duplicate element '{}' in \
the list", arg_title, s);
}
retlist.push(s);
},
_ =>
static_throw!(&l.extract_lexerinfo(), "arg name: '{}', expected <string>, found: '{}'",
arg_title, l),
}
}
},
_ =>
static_throw!(&argeval.extract_lexerinfo(), "arg name: '{}', expected <string>, found: '{}'",
arg_title, argeval),
}
self.counter += 1;
return Ok(retlist);
}
pub
fn read_hset_string_nodup(&mut self, arg_title: &str) -> StaticSchemeRes<HashSet<String>>
{
let arg = &self.args[self.counter];
let argeval =
SchemeInit::evaluate_value(arg, self.env.clone())?;
let mut retlist: HashSet<String> = HashSet::new();
match argeval
{
StaticShm::List(list, ref li) =>
{
for l in list
{
match l
{
StaticShm::String(s, lli) =>
{
self.check_string(&s, &lli, arg_title)?;
retlist.insert(s);
},
_ =>
static_throw!(li, "arg title: '{}', expected <string>, found: '{}'", arg_title, l)
}
}
},
_ =>
static_throw!(&argeval.extract_lexerinfo(),
"arg title: '{}', expected <list> of <string>, found: '{}'", arg_title, argeval),
}
self.counter += 1;
return Ok(retlist);
}
pub
fn read_ordkeep_string_nodup(&mut self, arg_title: &str) -> StaticSchemeRes<IndexSet<String>>
{
let arg = &self.args[self.counter];
let argeval =
SchemeInit::evaluate_value(arg, self.env.clone())?;
let mut retlist: IndexSet<String> = IndexSet::new();
match argeval
{
StaticShm::List(list, ref li) =>
{
for l in list
{
match l
{
StaticShm::String(s, lli) =>
{
self.check_string(&s, &lli, arg_title)?;
retlist.insert(s);
},
_ =>
static_throw!(li, "arg title: '{}', expected <string>, found: '{}'", arg_title, l)
}
}
},
_ =>
static_throw!(&argeval.extract_lexerinfo(),
"arg title: '{}', expected <list> of <string>, found: '{}'", arg_title, argeval),
}
self.counter += 1;
return Ok(retlist);
}
}