From c7ab906ad9483a214f25317c2d369bc0e2f029ea Mon Sep 17 00:00:00 2001 From: Chris Wong <lambda.fairy@gmail.com> Date: Fri, 27 Mar 2015 09:49:23 +1300 Subject: [PATCH] Guard against trailing tokens in Rust exprs Currently, the following parses: $for x in y.iter() #$%!INVALID~SYNTAX!^&* { } This is because the Rust parser only consumes enough to parse a single expression (in this case `y.iter()`), ignoring all the nonsense after it. With this patch, we check that the parser has consumed *all* tokens before yielding a result, ensuring that invalid syntax (like the snippet above) is not ignored. --- maud_macros/src/parse.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index 4270faa..6ff0a64 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -73,8 +73,19 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { } /// Construct a Rust AST parser from the given token tree. - fn new_rust_parser(&self, tts: Vec<TokenTree>) -> RustParser<'s> { - parse::tts_to_parser(self.render.cx.parse_sess, tts, self.render.cx.cfg.clone()) + fn with_rust_parser<F, T>(&self, tts: Vec<TokenTree>, callback: F) -> T where + F: FnOnce(&mut RustParser<'s>) -> T + { + let mut parser = parse::tts_to_parser(self.render.cx.parse_sess, tts, + self.render.cx.cfg.clone()); + let result = callback(&mut parser); + // Make sure all tokens were consumed + if parser.token != token::Eof { + let token = parser.this_token_to_string(); + self.render.cx.span_err(parser.span, + &format!("unexpected token: `{}`", token)); + } + result } fn markups(&mut self) { @@ -144,7 +155,7 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { } fn literal(&mut self, tt: &TokenTree, minus: bool) { - let lit = self.new_rust_parser(vec![tt.clone()]).parse_lit(); + let lit = self.with_rust_parser(vec![tt.clone()], RustParser::parse_lit); match lit_to_string(self.render.cx, lit, minus) { Some(s) => self.render.string(&s, Escape::Escape), None => {}, @@ -210,7 +221,7 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { }, _ => self.render.cx.span_fatal(sp, "invalid $for"), }} - let pattern = self.new_rust_parser(pattern).parse_pat(); + let pattern = self.with_rust_parser(pattern, RustParser::parse_pat); let mut iterable = vec![]; let body; loop { match self.input { @@ -225,7 +236,7 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { }, _ => self.render.cx.span_fatal(sp, "invalid $for"), }} - let iterable = self.new_rust_parser(iterable).parse_expr(); + let iterable = self.with_rust_parser(iterable, RustParser::parse_expr); self.render.emit_for(pattern, iterable, body); } @@ -253,7 +264,7 @@ impl<'cx, 's, 'i> Parser<'cx, 's, 'i> { if tts.is_empty() { self.render.cx.span_fatal(sp, "expected expression for this splice"); } else { - self.new_rust_parser(tts).parse_expr() + self.with_rust_parser(tts, RustParser::parse_expr) } }