use crate::tokenizer::Tokenizer;
pub struct EvalPtr<'a> {
tok: Tokenizer<'a>,
bracket_term: bool,
term_char: Option<char>,
no_eval: bool,
}
impl<'a> EvalPtr<'a> {
pub fn new(input: &'a str) -> Self {
Self {
tok: Tokenizer::new(input),
bracket_term: false,
term_char: None,
no_eval: false,
}
}
pub fn tok(&mut self) -> &mut Tokenizer<'a> {
&mut self.tok
}
pub fn from_tokenizer(ptr: &Tokenizer<'a>) -> Self {
Self {
tok: ptr.clone(),
bracket_term: false,
term_char: None,
no_eval: false,
}
}
pub fn to_tokenizer(&self) -> Tokenizer<'a> {
self.tok.clone()
}
pub fn set_bracket_term(&mut self, flag: bool) {
self.bracket_term = flag;
self.term_char = if flag { Some(']') } else { None };
}
pub fn is_bracket_term(&self) -> bool {
self.bracket_term
}
pub fn set_no_eval(&mut self, flag: bool) {
self.no_eval = flag;
}
pub fn is_no_eval(&self) -> bool {
self.no_eval
}
pub fn next(&mut self) -> Option<char> {
self.tok.next()
}
pub fn next_is(&mut self, ch: char) -> bool {
self.tok.is(ch)
}
pub fn at_end(&mut self) -> bool {
self.tok.at_end()
}
pub fn skip(&mut self) {
self.tok.skip();
}
pub fn skip_char(&mut self, ch: char) {
self.tok.skip_char(ch);
}
pub fn skip_while<P>(&mut self, predicate: P)
where
P: Fn(&char) -> bool,
{
self.tok.skip_while(predicate);
}
pub fn mark(&mut self) -> usize {
self.tok.mark()
}
pub fn token(&self, mark: usize) -> &str {
self.tok.token(mark)
}
pub fn backslash_subst(&mut self) -> char {
self.tok.backslash_subst()
}
pub fn at_end_of_script(&mut self) -> bool {
self.tok.at_end() || self.tok.peek() == self.term_char
}
pub fn at_end_of_command(&mut self) -> bool {
self.next_is('\n') || self.next_is(';') || self.at_end_of_script()
}
pub fn next_is_block_white(&mut self) -> bool {
match self.tok.peek() {
Some(c) => c.is_whitespace(),
None => false,
}
}
pub fn next_is_line_white(&mut self) -> bool {
match self.tok.peek() {
Some(c) => c.is_whitespace() && c != '\n',
None => false,
}
}
pub fn next_is_varname_char(&mut self) -> bool {
match self.tok.peek() {
Some(c) => c.is_alphanumeric() || c == '_',
None => false,
}
}
pub fn skip_block_white(&mut self) {
while !self.at_end() && self.next_is_block_white() {
self.tok.next();
}
}
pub fn skip_line_white(&mut self) {
while !self.at_end() && self.next_is_line_white() {
self.tok.next();
}
}
pub fn skip_comment(&mut self) -> bool {
if self.next_is('#') {
while !self.at_end() {
let c = self.tok.next();
if c == Some('\n') {
break;
} else if c == Some('\\') {
self.tok.next();
}
}
true
} else {
false
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bracket_term() {
let mut ctx = EvalPtr::new("123");
assert!(!ctx.is_bracket_term());
ctx.set_bracket_term(true);
assert!(ctx.is_bracket_term());
}
#[test]
fn test_next_is() {
let mut ctx = EvalPtr::new("123");
assert!(ctx.next_is('1'));
assert!(!ctx.next_is('2'));
let mut ctx = EvalPtr::new("");
assert!(!ctx.next_is('1'));
}
#[test]
fn test_at_end() {
let mut ctx = EvalPtr::new("123");
assert!(!ctx.at_end());
let mut ctx = EvalPtr::new("");
assert!(ctx.at_end());
}
#[test]
fn test_at_end_of_script() {
let mut ctx = EvalPtr::new("123");
assert!(!ctx.at_end_of_script());
let mut ctx = EvalPtr::new("");
assert!(ctx.at_end_of_script());
let mut ctx = EvalPtr::new("]");
assert!(!ctx.at_end_of_script());
ctx.set_bracket_term(true);
assert!(ctx.at_end_of_script());
}
#[test]
fn test_at_end_of_command() {
let mut ctx = EvalPtr::new("123");
assert!(!ctx.at_end_of_command());
let mut ctx = EvalPtr::new(";123");
assert!(ctx.at_end_of_command());
let mut ctx = EvalPtr::new("\n123");
assert!(ctx.at_end_of_command());
let mut ctx = EvalPtr::new("]123");
assert!(!ctx.at_end_of_command());
let mut ctx = EvalPtr::new("]123");
ctx.set_bracket_term(true);
assert!(ctx.at_end_of_command());
}
#[test]
fn test_next_is_block_white() {
let mut ctx = EvalPtr::new("123");
assert!(!ctx.next_is_block_white());
let mut ctx = EvalPtr::new(" 123");
assert!(ctx.next_is_block_white());
let mut ctx = EvalPtr::new("\n123");
assert!(ctx.next_is_block_white());
}
#[test]
fn test_skip_block_white() {
let mut ctx = EvalPtr::new("123");
ctx.skip_block_white();
assert!(ctx.next_is('1'));
let mut ctx = EvalPtr::new(" 123");
ctx.skip_block_white();
assert!(ctx.next_is('1'));
let mut ctx = EvalPtr::new(" \n 123");
ctx.skip_block_white();
assert!(ctx.next_is('1'));
}
#[test]
fn test_next_is_line_white() {
let mut ctx = EvalPtr::new("123");
assert!(!ctx.next_is_line_white());
let mut ctx = EvalPtr::new(" 123");
assert!(ctx.next_is_line_white());
let mut ctx = EvalPtr::new("\n123");
assert!(!ctx.next_is_line_white());
}
#[test]
fn test_skip_line_white() {
let mut ctx = EvalPtr::new("123");
ctx.skip_line_white();
assert!(ctx.next_is('1'));
let mut ctx = EvalPtr::new(" 123");
ctx.skip_line_white();
assert!(ctx.next_is('1'));
let mut ctx = EvalPtr::new(" \n 123");
ctx.skip_line_white();
assert!(ctx.next_is('\n'));
}
#[test]
fn test_skip_comment() {
let mut ctx = EvalPtr::new("123");
assert!(!ctx.skip_comment());
assert!(ctx.next_is('1'));
let mut ctx = EvalPtr::new(" #123");
assert!(!ctx.skip_comment());
assert!(ctx.next_is(' '));
let mut ctx = EvalPtr::new("#123");
assert!(ctx.skip_comment());
assert!(ctx.at_end());
let mut ctx = EvalPtr::new("#1 2 3 \na");
assert!(ctx.skip_comment());
assert!(ctx.next_is('a'));
let mut ctx = EvalPtr::new("#1 \\na\nb");
assert!(ctx.skip_comment());
assert!(ctx.next_is('b'));
let mut ctx = EvalPtr::new("#1 2] 3 \na");
ctx.set_bracket_term(true);
assert!(ctx.skip_comment());
assert!(ctx.next_is('a'));
}
}