use crate::error::RadError;
use crate::consts::*;
use crate::utils::Utils;
pub struct Lexor {
previous_char : Option<char>,
pub cursor: Cursor,
pub escape_next : bool,
pub lit_count: usize,
pub paren_count : usize,
pub escape_nl : bool,
}
impl Lexor {
pub fn new() -> Self {
Lexor {
previous_char : None,
cursor: Cursor::None,
escape_next : false,
escape_nl : false,
lit_count : 0,
paren_count : 0,
}
}
pub fn reset(&mut self) {
self.previous_char = None;
self.cursor= Cursor::None;
self.escape_next = false;
self.escape_nl = false;
self.paren_count = 0;
}
pub fn lex(&mut self, ch: char) -> Result<LexResult, RadError> {
let result: LexResult;
if self.start_literal(ch) {
self.previous_char.replace('0');
return Ok(LexResult::Literal(self.cursor));
} else if self.end_literal(ch){
self.previous_char.replace('0');
return Ok(LexResult::Literal(self.cursor));
} else if self.lit_count >0 {
self.previous_char.replace(ch);
return Ok(LexResult::Literal(self.cursor));
}
match self.cursor {
Cursor::None => {
result = self.branch_none(ch);
},
Cursor::Name => {
result = self.branch_name(ch);
}
Cursor::Arg => {
result = self.branch_arg(ch);
} }
let replace = ch;
self.previous_char.replace(replace);
Ok(result)
}
fn branch_none(&mut self, ch: char) -> LexResult {
let result: LexResult;
if ch == MACRO_START_CHAR
&& self.previous_char.unwrap_or('0') != ESCAPE_CHAR
{
self.cursor = Cursor::Name;
result = LexResult::Ignore;
self.escape_nl = false;
}
else if self.escape_nl && (ch as i32 == 13 || ch as i32 == 10) {
result = LexResult::Discard;
}
else {
self.escape_nl = false;
result = LexResult::AddToRemainder;
}
result
}
fn branch_name(&mut self, ch: char) -> LexResult {
let mut result: LexResult;
if Utils::is_blank_char(ch) {
self.cursor = Cursor::None;
result = LexResult::ExitFrag;
}
else if ch == '(' {
self.cursor = Cursor::Arg;
self.paren_count = 1;
result = LexResult::StartFrag;
if self.previous_char.unwrap_or('0') == '$' {
result = LexResult::EmptyName;
}
}
else if ch == '$' {
result = LexResult::RestartName;
}
else {
result = LexResult::AddToFrag(Cursor::Name);
}
result
}
fn branch_arg(&mut self, ch: char) -> LexResult {
let mut result: LexResult = LexResult::AddToFrag(Cursor::Arg);
if ch == ')'{
self.paren_count = self.paren_count - 1;
if self.paren_count == 0 {
self.cursor = Cursor::None;
result = LexResult::EndFrag;
}
}
else if ch == '(' {
self.paren_count = self.paren_count + 1;
}
result
}
fn start_literal(&mut self, ch: char) -> bool {
if ch == LIT_CHAR && self.previous_char.unwrap_or('0') == ESCAPE_CHAR {
self.lit_count = self.lit_count + 1;
true
} else {
false
}
}
fn end_literal(&mut self, ch: char) -> bool {
if ch == ESCAPE_CHAR && self.previous_char.unwrap_or('0') == LIT_CHAR {
if self.lit_count > 0 {
self.lit_count = self.lit_count - 1;
} true
} else {
false
}
}
}
#[derive(Debug)]
pub enum LexResult {
Discard,
Ignore,
AddToRemainder,
StartFrag,
EmptyName,
RestartName,
AddToFrag(Cursor),
EndFrag,
ExitFrag,
Literal(Cursor),
}
#[derive(Clone, Copy, Debug)]
pub enum Cursor {
None,
Name,
Arg,
}