From 5d5ddf30d00e96cbc3143a6bab7325cabcb52081 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Wed, 28 Dec 2016 08:35:02 -0700 Subject: [PATCH] Find escaped characters in strings --- src/lexer/char.rs | 10 ++++++++++ src/lexer/mod.rs | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/lexer/char.rs b/src/lexer/char.rs index f5ab38f..7f49f2e 100644 --- a/src/lexer/char.rs +++ b/src/lexer/char.rs @@ -10,6 +10,8 @@ pub trait Lexable { fn is_hash(&self) -> bool; fn is_dot(&self) -> bool; fn is_string_quote(&self) -> bool; + fn is_string_escape_leader(&self) -> bool; + fn is_string_escaped(&self) -> bool; fn is_newline(&self) -> bool; fn is_eof(&self) -> bool; @@ -44,6 +46,14 @@ impl Lexable for char { *self == '"' } + fn is_string_escape_leader(&self) -> bool { + *self == '\\' + } + + fn is_string_escaped(&self) -> bool { + *self == '"' || *self == '\\' + } + fn is_boolean_true(&self) -> bool { *self == 't' } diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index e1b9b7f..ffa47da 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -38,6 +38,7 @@ enum State { NumberSign, Sign, String, + StringEscape, } pub struct Lexer { @@ -357,6 +358,20 @@ impl Lexer { if c.is_string_quote() { return self.token_result(Token::String(self.value())); } + else if c.is_string_escape_leader() { + self.state = State::StringEscape; + } + Ok(None) + } + + fn state_string_escape(&mut self, c: char) -> StateResult { + if c.is_string_escaped() { + self.state = State::String; + self.advance(); + } + else { + return Err(self.error_string(format!("Invalid string escape character: {}", c))); + } Ok(None) } @@ -402,6 +417,7 @@ impl Iterator for Lexer { State::NumberSign => self.state_number_sign(c), State::Sign => self.state_sign(c), State::String => self.state_string(c), + State::StringEscape => self.state_string_escape(c), State::Comment => self.state_comment(c), }; assert!(result.has_token() || self.forward != previous_forward, "No lexing progress made!"); @@ -488,6 +504,12 @@ mod tests { check_single_token("\"abc\"", Token::String(String::from("\"abc\""))); } + #[test] + fn finds_escaped_characters_in_strings() { + check_single_token("\"\\\\\"", Token::String(String::from("\"\\\\\""))); + check_single_token("\"\\\"\"", Token::String(String::from("\"\\\"\""))); + } + #[test] fn finds_numbers() { check_single_token(".34", Token::Number(Number::new(0.34)));