From 2e6948c182636b8478113fd272fbeee9bafb94a6 Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Tue, 7 Nov 2017 03:06:12 -0800 Subject: [PATCH] Handle apostrophes in #warn correctly --- src/dreammaker/lexer.rs | 39 ++++++++++++++++++++++++++++++---- src/dreammaker/preprocessor.rs | 6 ++++-- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/dreammaker/lexer.rs b/src/dreammaker/lexer.rs index bd1b41f4..bb1af269 100644 --- a/src/dreammaker/lexer.rs +++ b/src/dreammaker/lexer.rs @@ -225,6 +225,15 @@ struct Interpolation { bracket_depth: usize, } +// Used to track specially-lexed preprocessor directives like #warn +#[derive(Debug, PartialEq, Copy, Clone)] +enum Directive { + None, + Hash, + Ordinary, + Stringy, +} + /// The lexer, which serves as a source of tokens through iteration. #[derive(Debug)] pub struct Lexer { @@ -232,6 +241,7 @@ pub struct Lexer { input: Bytes, location: Location, at_line_head: bool, + directive: Directive, interp_stack: Vec, } @@ -253,6 +263,7 @@ impl Lexer { column: 1, }, at_line_head: true, + directive: Directive::None, interp_stack: Vec::new(), } } @@ -267,6 +278,7 @@ impl Lexer { self.location.line += 1; self.location.column = 1; self.at_line_head = true; + self.directive = Directive::None; } else { if ch != b'\t' && ch != b' ' && self.at_line_head { self.at_line_head = false; @@ -379,19 +391,20 @@ impl Lexer { String::from_utf8(ident).map_err(|_| self.error("non-utf8 identifier")) // TODO } - fn next_string(&mut self) -> Result { + fn next_string(&mut self, start_loc: Location) -> Result { match self.next() { Ok(Some(ch)) => Ok(ch), - Ok(None) => Err(self.error("unterminated string")), + Ok(None) => Err(DMError::new(start_loc, "unterminated string")), Err(e) => Err(e), } } fn read_resource(&mut self) -> Result { + let start_loc = self.location(); let mut buf = Vec::new(); loop { - let ch = self.next_string()?; + let ch = self.next_string(start_loc)?; if ch == b'\'' { break; } else { @@ -403,13 +416,14 @@ impl Lexer { } fn read_string(&mut self, end: &'static [u8], interp_closed: bool) -> Result { + let start_loc = self.location(); let mut buf = Vec::new(); let mut backslash = false; let mut idx = 0; let mut interp_opened = false; loop { - let ch = self.next_string()?; + let ch = self.next_string(start_loc)?; if ch == end[idx] && !backslash { idx += 1; if idx == end.len() { @@ -538,8 +552,18 @@ impl Iterator for Lexer { let loc = self.location; let locate = |token| LocatedToken::new(loc, token); + if self.directive == Directive::Stringy { + self.directive = Directive::None; + self.put_back(Some(first)); + return Some(self.read_string(b"\n", false).map(locate)); + } + let punct = try_iter!(self.read_punct(first)); return match punct { + Some(Hash) if self.directive == Directive::None => { + self.directive = Directive::Hash; + Some(Ok(locate(Punct(Hash)))) + } Some(BlockComment) => { try_iter!(self.skip_until(b"*/")); continue; @@ -578,6 +602,13 @@ impl Iterator for Lexer { let next = try_iter!(self.next()); self.put_back(next); let ws = next == Some(b' ') || next == Some(b'\t'); + if self.directive == Directive::Hash { + if ident == "warn" || ident == "error" { + self.directive = Directive::Stringy; + } else { + self.directive = Directive::Ordinary; + } + } Some(Ok(locate(Ident(ident, ws)))) } b'\\' => { diff --git a/src/dreammaker/preprocessor.rs b/src/dreammaker/preprocessor.rs index 73715271..d3a54852 100644 --- a/src/dreammaker/preprocessor.rs +++ b/src/dreammaker/preprocessor.rs @@ -419,8 +419,10 @@ impl Preprocessor { expect_token!(() = Token::Punct(Punctuation::Newline)); self.defines.remove(&define_name); // TODO: warn if none } - "error" => { - return Err(DMError::new(self.last_input_loc, "#error")); + "warn" | "error" => { + // TODO: report warnings as warnings rather than errors + expect_token!((text) = Token::String(text)); + return Err(DMError::new(self.last_input_loc, format!("#{} {}", ident, text))); } // none of this other stuff should even exist _ => return Err(DMError::new(self.last_input_loc, format!("unknown directive: #{}", ident)))