Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

Commit

Permalink
Merge pull request #2 from devsbb/enum-state
Browse files Browse the repository at this point in the history
chore: Use enum for states and results
  • Loading branch information
jaysonsantos authored Mar 31, 2020
2 parents 67f1ee7 + 22ae2ef commit 2e55647
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 40 deletions.
1 change: 0 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ fn main() -> Result<()> {
Box::new(File::create(output_file)?)
} else {
eprintln!("No output file specified, falling back to stdout");

Box::new(stdout())
};
let mut parser = Parser::new(input, output, config.fail);
Expand Down
101 changes: 62 additions & 39 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ const START: char = b'{' as char;
const END: char = b'}' as char;
const VALID_CHARS: [char; 1] = [b'_' as char];

#[derive(Debug, PartialEq)]
enum State {
TextOutput,
ParsingVariable,
OpenBraces,
}

#[derive(Debug, PartialEq)]
enum ParseCharResult {
Consumed,
Ignored,
}

pub struct Parser<R, W>
where
R: BufRead,
Expand All @@ -19,8 +32,7 @@ where
fail_when_not_found: bool,

current_variable_name: String,
parsing_variable: bool,
open_braces: bool,
state: State,
}

impl<R, W> Parser<R, W>
Expand All @@ -34,8 +46,7 @@ where
output: BufWriter::new(output),
fail_when_not_found,
current_variable_name: "".to_owned(),
parsing_variable: false,
open_braces: false,
state: State::TextOutput,
}
}

Expand All @@ -51,13 +62,13 @@ where
for current_char in line.chars() {
self.parse_char(current_char)?;
}
if self.parsing_variable && !self.open_braces {
if self.state == State::ParsingVariable {
self.write_variable()?;
}
line.clear();
}

if self.parsing_variable {
if self.state != State::TextOutput {
anyhow::bail!(
"Failed to parse a variable on line {} missing a '}}' after '{}'",
last_processed_line,
Expand All @@ -68,29 +79,29 @@ where
}

fn parse_char(&mut self, current_char: char) -> Result<()> {
if self.start_parsing_variable(current_char)? {
if self.start_parsing_variable(current_char)? == ParseCharResult::Consumed {
return Ok(());
}

if self.check_braces_opening(current_char)? {
if self.check_braces_opening(current_char)? == ParseCharResult::Consumed {
return Ok(());
}

if self.check_braces_ending(current_char)? {
if self.check_braces_ending(current_char)? == ParseCharResult::Consumed {
return Ok(());
}

if self.check_whitespace(current_char)? {
if self.check_whitespace(current_char)? == ParseCharResult::Consumed {
return Ok(());
}

if self.parsing_variable {
if self.state == State::ParsingVariable || self.state == State::OpenBraces {
if VALID_CHARS.contains(&current_char) || current_char.is_alphabetic() {
self.current_variable_name.push(current_char);
return Ok(());
}

if self.open_braces {
if self.state == State::OpenBraces {
anyhow::bail!(
"Failed to parse variable {} with extra character '{}'",
&self.current_variable_name,
Expand All @@ -106,52 +117,65 @@ where
Ok(())
}

fn start_parsing_variable(&mut self, current_char: char) -> Result<bool> {
fn start_parsing_variable(&mut self, current_char: char) -> Result<ParseCharResult> {
if current_char == VARIABLE {
if self.parsing_variable {
if self.state == State::ParsingVariable {
anyhow::bail!("Variable is already being parsed")
}
self.parsing_variable = true;
return Ok(true);
self.state = State::ParsingVariable;
return Ok(ParseCharResult::Consumed);
}

Ok(false)
Ok(ParseCharResult::Ignored)
}

fn check_braces_opening(&mut self, current_char: char) -> Result<bool> {
if current_char == START && self.parsing_variable {
if self.open_braces {
anyhow::bail!("Double open braces")
}
self.open_braces = true;
return Ok(true);
fn check_braces_opening(&mut self, current_char: char) -> Result<ParseCharResult> {
if current_char != START {
return Ok(ParseCharResult::Ignored);
}

if self.state == State::ParsingVariable {
self.state = State::OpenBraces;
return Ok(ParseCharResult::Consumed);
}

Ok(false)
if self.state == State::OpenBraces {
anyhow::bail!("Double open braces")
}

Ok(ParseCharResult::Ignored)
}

fn check_braces_ending(&mut self, current_char: char) -> Result<bool> {
if current_char == END && self.parsing_variable {
if !self.open_braces {
anyhow::bail!("Closing braces without opening");
}
fn check_braces_ending(&mut self, current_char: char) -> Result<ParseCharResult> {
if current_char != END {
return Ok(ParseCharResult::Ignored);
}

if self.state == State::OpenBraces {
self.write_variable()?;
return Ok(true);
return Ok(ParseCharResult::Consumed);
}

Ok(false)
if self.state == State::ParsingVariable {
anyhow::bail!("Closing braces without opening");
}

Ok(ParseCharResult::Ignored)
}

fn check_whitespace(&mut self, current_char: char) -> Result<bool> {
if current_char.is_ascii_whitespace() && self.parsing_variable {
if self.open_braces {
fn check_whitespace(&mut self, current_char: char) -> Result<ParseCharResult> {
if self.state != State::ParsingVariable && self.state != State::OpenBraces {
return Ok(ParseCharResult::Ignored);
}
if current_char.is_ascii_whitespace() {
if self.state == State::OpenBraces {
anyhow::bail!("Braces not closed");
}
self.write_variable()?;
self.write_char(current_char)?;
return Ok(true);
return Ok(ParseCharResult::Consumed);
}
Ok(false)
Ok(ParseCharResult::Ignored)
}

fn write_variable(&mut self) -> Result<()> {
Expand All @@ -177,8 +201,7 @@ where
}

fn reset_state(&mut self) {
self.open_braces = false;
self.parsing_variable = false;
self.state = State::TextOutput;
self.current_variable_name.clear();
}

Expand Down

0 comments on commit 2e55647

Please sign in to comment.