mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-12 23:40:45 -07:00
Parsing for if statements
This commit is contained in:
+13
-7
@@ -29,11 +29,12 @@ module Liquid
|
||||
'[' => :open_square,
|
||||
']' => :close_square
|
||||
}
|
||||
IDENTIFIER = /[\w\-]+/
|
||||
IDENTIFIER = /[\w\-?]+/
|
||||
SINGLE_STRING_LITERAL = /'[^\']*'/
|
||||
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
||||
INTEGER_LITERAL = /-?\d+/
|
||||
FLOAT_LITERAL = /-?\d+(?:\.\d+)?/
|
||||
COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains/
|
||||
|
||||
def initialize(input)
|
||||
@ss = StringScanner.new(input)
|
||||
@@ -57,21 +58,26 @@ module Liquid
|
||||
return if @ss.eos?
|
||||
|
||||
case
|
||||
when t = @ss.scan(COMPARISON_OPERATOR) then Token[:comparison, t]
|
||||
when t = @ss.scan(IDENTIFIER) then Token[:id, t]
|
||||
when t = @ss.scan(SINGLE_STRING_LITERAL) then Token[:string, t]
|
||||
when t = @ss.scan(DOUBLE_STRING_LITERAL) then Token[:string, t]
|
||||
when t = @ss.scan(INTEGER_LITERAL) then Token[:integer, t]
|
||||
when t = @ss.scan(FLOAT_LITERAL) then Token[:float, t]
|
||||
else
|
||||
c = @ss.getch
|
||||
if s = SPECIALS[c]
|
||||
return Token[s,c]
|
||||
end
|
||||
|
||||
raise SyntaxError, "Unexpected character #{c}."
|
||||
lex_specials
|
||||
end
|
||||
end
|
||||
|
||||
def lex_specials
|
||||
c = @ss.getch
|
||||
if s = SPECIALS[c]
|
||||
return Token[s,c]
|
||||
end
|
||||
|
||||
raise SyntaxError, "Unexpected character #{c}."
|
||||
end
|
||||
|
||||
def consume_whitespace
|
||||
@ss.skip(/\s*/)
|
||||
end
|
||||
|
||||
@@ -45,7 +45,7 @@ module Liquid
|
||||
block = if tag == 'else'
|
||||
ElseCondition.new
|
||||
else
|
||||
old_parse(markup)
|
||||
parse_condition(markup)
|
||||
end
|
||||
|
||||
@blocks.push(block)
|
||||
@@ -81,12 +81,19 @@ module Liquid
|
||||
new_cond.send(op.to_sym, condition)
|
||||
condition = new_cond
|
||||
end
|
||||
p.consume(:end_of_string)
|
||||
|
||||
condition
|
||||
end
|
||||
|
||||
def parse_comparison(p)
|
||||
|
||||
a = p.expression
|
||||
if op = p.consume?(:comparison)
|
||||
b = p.expression
|
||||
Condition.new(a, op, b)
|
||||
else
|
||||
Condition.new(a)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -63,11 +63,8 @@ class ErrorHandlingTest < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_unrecognized_operator
|
||||
assert_nothing_raised do
|
||||
template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ')
|
||||
assert_equal ' Liquid error: Unknown operator =! ', template.render
|
||||
assert_equal 1, template.errors.size
|
||||
assert_equal Liquid::ArgumentError, template.errors.first.class
|
||||
assert_raise(SyntaxError) do
|
||||
Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -40,15 +40,20 @@ class ParsingQuirksTest < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_meaningless_parens
|
||||
assigns = {'b' => 'bar', 'c' => 'baz'}
|
||||
markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
|
||||
assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}", assigns)
|
||||
assert_raise(SyntaxError) do
|
||||
markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
|
||||
Template.parse("{% if #{markup} %} YES {% endif %}")
|
||||
end
|
||||
end
|
||||
|
||||
def test_unexpected_characters_silently_eat_logic
|
||||
markup = "true && false"
|
||||
assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}")
|
||||
markup = "false || true"
|
||||
assert_template_result('',"{% if #{markup} %} YES {% endif %}")
|
||||
assert_raise(SyntaxError) do
|
||||
markup = "true && false"
|
||||
Template.parse("{% if #{markup} %} YES {% endif %}")
|
||||
end
|
||||
assert_raise(SyntaxError) do
|
||||
markup = "false || true"
|
||||
Template.parse("{% if #{markup} %} YES {% endif %}")
|
||||
end
|
||||
end
|
||||
end # ParsingQuirksTest
|
||||
|
||||
Reference in New Issue
Block a user