From 9674865846b3280e58c2aae1c1e83487b2ea9afe Mon Sep 17 00:00:00 2001 From: Chris Wong <lambda.fairy@gmail.com> Date: Sat, 7 Oct 2017 14:03:38 +1300 Subject: [PATCH] Combine `.push_str()` calls across blocks This also disallows `@let` in non-block contexts, e.g. img src=@let foo = bar; ; This yields a 20 - 50 ns speedup in benchmarks, as well as reducing code size by a slight amount. --- maud_macros/src/parse.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index b33942f..4299647 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -95,9 +95,28 @@ impl Parser { /// Parses and renders multiple blocks of markup. fn markups(&mut self, builder: &mut Builder) -> ParseResult<()> { loop { - match self.peek() { + match self.peek2() { None => return Ok(()), - Some(TokenTree { kind: TokenNode::Op(';', _), .. }) => self.advance(), + Some((TokenTree { kind: TokenNode::Op(';', _), .. }, _)) => self.advance(), + Some(( + TokenTree { kind: TokenNode::Op('@', _), .. }, + Some(TokenTree { kind: TokenNode::Term(term), span }), + )) if term.as_str() == "let" => { + // When emitting a `@let`, wrap the rest of the block in a + // new block to avoid scoping issues + let keyword = TokenTree { kind: TokenNode::Term(term), span }; + self.advance2(); + builder.push({ + let mut builder = self.builder(); + builder.push(keyword); + self.let_expr(&mut builder)?; + self.markups(&mut builder)?; + TokenTree { + kind: TokenNode::Group(Delimiter::Brace, builder.build()), + span, + } + }); + }, _ => self.markup(builder)?, } } @@ -127,7 +146,7 @@ impl Parser { "while" => self.while_expr(builder)?, "for" => self.for_expr(builder)?, "match" => self.match_expr(builder)?, - "let" => self.let_expr(builder)?, + "let" => return self.error(format!("@let only works inside a block")), other => return self.error(format!("unknown keyword `@{}`", other)), } }, @@ -145,10 +164,9 @@ impl Parser { builder.splice(expr); } // Block - TokenTree { kind: TokenNode::Group(Delimiter::Brace, block), span } => { + TokenTree { kind: TokenNode::Group(Delimiter::Brace, block), .. } => { self.advance(); - let block = self.block(block, span)?; - builder.push(block); + self.with_input(block).markups(builder)?; }, // ??? _ => return self.error("invalid syntax"),