Skip to content

Commit 5cffe44

Browse files
committed
fix(parse): Error on empty expressions
Initially, I planned for `{{}}` to evaluate to `""`. I asked myself: when would people ever do `{{}}` intentionally? How often might it be unintentional? So I decided to make it an error for now. Fixes #139
1 parent bd45c14 commit 5cffe44

File tree

1 file changed

+22
-10
lines changed

1 file changed

+22
-10
lines changed

src/compiler/parser.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,29 +42,32 @@ pub fn parse(elements: &[Element], options: &LiquidOptions) -> Result<Vec<Box<Re
4242
let mut iter = elements.iter();
4343
let mut token = iter.next();
4444
while token.is_some() {
45-
match *token.unwrap() {
46-
Element::Expression(ref tokens, _) => ret.push(try!(parse_expression(tokens, options))),
47-
Element::Tag(ref tokens, _) => ret.push(try!(parse_tag(&mut iter, tokens, options))),
48-
Element::Raw(ref x) => ret.push(Box::new(Text::new(x))),
49-
}
45+
let render = match *token.unwrap() {
46+
Element::Expression(ref tokens, _) => parse_expression(tokens, options)?,
47+
Element::Tag(ref tokens, _) => parse_tag(&mut iter, tokens, options)?,
48+
Element::Raw(ref x) => Box::new(Text::new(x)),
49+
};
50+
ret.push(render);
5051
token = iter.next();
5152
}
5253
Ok(ret)
5354
}
5455

5556
// creates an expression, which wraps everything that gets rendered
5657
fn parse_expression(tokens: &[Token], options: &LiquidOptions) -> Result<Box<Renderable>> {
57-
match tokens[0] {
58-
Token::Identifier(ref x) if tokens.len() > 1 &&
59-
(tokens[1] == Token::Dot || tokens[1] == Token::OpenSquare) => {
58+
match tokens.get(0) {
59+
Some(&Token::Identifier(ref x)) if tokens.len() > 1 &&
60+
(tokens[1] == Token::Dot ||
61+
tokens[1] == Token::OpenSquare) => {
6062
let indexes = parse_indexes(&tokens[1..])?;
6163
let mut result = Variable::new(x.clone());
6264
result.extend(indexes);
6365
Ok(Box::new(result))
6466
}
65-
Token::Identifier(ref x) if options.tags.contains_key(x) => {
67+
Some(&Token::Identifier(ref x)) if options.tags.contains_key(x) => {
6668
options.tags[x].parse(x, &tokens[1..], options)
6769
}
70+
None => Error::parser("expression", None),
6871
_ => {
6972
let output = parse_output(tokens)?;
7073
Ok(Box::new(output))
@@ -381,6 +384,7 @@ mod test_split_block {
381384
use super::super::FnParseBlock;
382385
use interpreter::Renderable;
383386
use interpreter::Context;
387+
use interpreter;
384388

385389
#[derive(Debug)]
386390
struct NullBlock;
@@ -409,6 +413,15 @@ mod test_split_block {
409413
options
410414
}
411415

416+
#[test]
417+
fn parse_empty_expression() {
418+
let text = "{{}}";
419+
420+
let tokens = tokenize(&text).unwrap();
421+
let template = parse(&tokens, &options()).map(interpreter::Template::new);
422+
assert!(template.is_err());
423+
}
424+
412425
#[test]
413426
fn handles_nonmatching_stream() {
414427
// A stream of tokens with lots of `else`s in it, but only one at the
@@ -425,7 +438,6 @@ mod test_split_block {
425438
assert!(trailing.is_none());
426439
}
427440

428-
429441
#[test]
430442
fn honours_nesting() {
431443
// A stream of tokens with lots of `else`s in it, but only one at the

0 commit comments

Comments
 (0)