use crate::utils::Utils;
pub struct DefineParser {
arg_cursor: DefineCursor,
name: String,
args: String,
body: String,
bind: bool,
container: String,
}
impl DefineParser {
pub fn new() -> Self {
Self {
arg_cursor: DefineCursor::Name,
name: String::new(),
args: String::new(),
body: String::new(),
bind: false,
container: String::new(),
}
}
fn clear(&mut self) {
self.arg_cursor = DefineCursor::Name;
self.name.clear();
self.args.clear();
self.body.clear();
self.bind = false;
self.container.clear();
}
pub(crate) fn parse_define(&mut self, text: &str) -> Option<(String, String, String)> {
self.clear(); let char_iter = text.chars().peekable();
for ch in char_iter {
match self.arg_cursor {
DefineCursor::Name => {
if let ParseIgnore::Ignore = self.branch_name(ch) {
continue;
}
if !self.is_valid_char(ch) {
return None;
}
}
DefineCursor::Args => {
if let ParseIgnore::Ignore = self.branch_args(ch) {
continue;
}
if !self.is_valid_char(ch) {
return None;
}
}
DefineCursor::Body => (),
}
self.container.push(ch);
}
if self.args.is_empty() && !self.bind {
return None;
}
self.body.push_str(&self.container);
Some((self.name.clone(), self.args.clone(), self.body.clone()))
}
fn is_valid_char(&self, ch: char) -> bool {
if self.container.is_empty() {
if !ch.is_alphabetic() {
return false;
}
} else {
if !ch.is_alphanumeric() && ch != '_' {
return false;
}
}
true
}
fn branch_name(&mut self, ch: char) -> ParseIgnore {
if ch == '=' {
self.name.push_str(&self.container);
self.container.clear();
self.arg_cursor = DefineCursor::Body;
self.bind = true;
ParseIgnore::Ignore
} else if Utils::is_blank_char(ch) {
if !self.name.is_empty() {
self.container.clear();
ParseIgnore::None
} else {
ParseIgnore::Ignore
}
}
else if ch == ',' {
self.name.push_str(&self.container);
self.container.clear();
self.arg_cursor = DefineCursor::Args;
ParseIgnore::Ignore
} else {
ParseIgnore::None
}
}
fn branch_args(&mut self, ch: char) -> ParseIgnore {
if Utils::is_blank_char(ch) && !self.name.is_empty() {
if !self.container.is_empty() {
self.args.push_str(&self.container);
self.args.push(' ');
self.container.clear();
}
ParseIgnore::Ignore
}
else if ch == '=' {
self.args.push_str(&self.container);
self.container.clear();
self.arg_cursor = DefineCursor::Body;
ParseIgnore::Ignore
}
else {
ParseIgnore::None
}
}
}
pub(crate) enum DefineCursor {
Name,
Args,
Body,
}
enum ParseIgnore {
Ignore,
None,
}