Skip to content

Commit

Permalink
Fix ignore superfluous filtered expression tokens. Closes #103.
Browse files Browse the repository at this point in the history
  • Loading branch information
jg-rp committed Jan 12, 2023
1 parent 0db8ed4 commit 87cace9
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Version 1.7.1
misinterpreting unquoted cycle group names as strings rather than variables to be
resolved, and not Liquid stringifying some cycled items before output. We've also
rolled back changes to ``CycleNode.children()`` from version 1.7.0.
- Fixed a regression bug that lead to some erroneous filtered expressions tokens to be
silently ignored. Specifically any tokens that appear after a valid left value and the
first filters, or end of expression. We now raise a ``LiquidSyntaxError`` in such
cases. See `#103 <https://github.com/jg-rp/liquid/issues/103>`_.

Version 1.7.0
-------------
Expand Down
9 changes: 3 additions & 6 deletions liquid/builtin/tags/assign_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,18 @@ def _parse_expression(self, value: str) -> Expression:

def parse(self, stream: TokenStream) -> AssignNode:
expect(stream, TOKEN_TAG, value=TAG_ASSIGN)
tok = stream.current
stream.next_token()

tok = stream.next_token()
expect(stream, TOKEN_EXPRESSION)

match = RE_ASSIGNMENT.match(stream.current.value)
if match:
name, expression = match.groups()
name, right = match.groups()
else:
raise LiquidSyntaxError(
f'invalid assignment expression "{stream.current.value}"',
linenum=stream.current.linenum,
)

return AssignNode(
tok,
AssignmentExpression(name, self._parse_expression(expression)),
tok, AssignmentExpression(name, self._parse_expression(right))
)
13 changes: 10 additions & 3 deletions liquid/expressions/filtered/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,18 @@ def _parse_filter(tokens: List[Token], linenum: int) -> Filter:
def parse_from_tokens(tokens: Iterator[Token], linenum: int = 1) -> FilteredExpression:
"""Parse an expression with zero or more filters from a token iterator."""
parts = tuple(split_at_first_pipe(tokens))
stream = TokenStream(iter(parts[0]))
left = parse_obj(stream)

if stream.peek[1] != TOKEN_EOF:
raise LiquidSyntaxError(
f"expected a filter or end of expression, found {stream.peek[2]!r}",
linenum=stream.current[0],
)

if len(parts) == 1:
stream = TokenStream(iter(parts[0]))
return FilteredExpression(parse_obj(stream))
return FilteredExpression(left)

left = parse_obj(TokenStream(iter(parts[0])))
filters = [_parse_filter(_tokens, linenum) for _tokens in split_at_pipe(parts[1])]
return FilteredExpression(left, filters)

Expand Down
16 changes: 16 additions & 0 deletions tests/test_malformed.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,22 @@ def test_liquid_syntax(self):
expect_exception=LiquidSyntaxError,
expect_msg="unexpected pipe or missing filter name, on line 1",
),
Case(
description="unexpected token between left value and filter",
template=r'{{ "hello" boo || upcase }}',
expect_exception=LiquidSyntaxError,
expect_msg=(
"expected a filter or end of expression, found 'boo', on line 1"
),
),
Case(
description="unexpected token after left value and no filters",
template=r'{{ "hello" offset:2 }}',
expect_exception=LiquidSyntaxError,
expect_msg=(
"expected a filter or end of expression, found 'offset', on line 1"
),
),
]

self._test(test_cases, mode=Mode.STRICT)
Expand Down

0 comments on commit 87cace9

Please sign in to comment.