Skip to content

Commit 9f9e8f0

Browse files
committed
Extract Parser#variable_lookup out of Expression.parse
1 parent 54e97ed commit 9f9e8f0

3 files changed

Lines changed: 103 additions & 29 deletions

File tree

lib/liquid/parser.rb

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ def look(type, ahead = 0)
5050
def expression
5151
token = @tokens[@p]
5252
case token[0]
53+
when :id
54+
variable_lookup
55+
when :open_square
56+
unnamed_variable_lookup
5357
when :string
5458
string
5559
when :number
@@ -68,45 +72,33 @@ def string
6872
consume(:string)[1..-2]
6973
end
7074

71-
def argument_string
72-
str = +""
73-
# might be a keyword argument (identifier: expression)
74-
if look(:id) && look(:colon, 1)
75-
str << consume << consume << ' '
75+
def variable_lookup
76+
name = consume(:id)
77+
lookups, command_flags = variable_lookups
78+
if Expression::LITERALS.key?(name) && lookups.empty?
79+
Expression::LITERALS[name]
80+
else
81+
VariableLookup.new(name, lookups, command_flags)
7682
end
77-
78-
str << expression_string
79-
str
8083
end
8184

82-
def variable_lookups
83-
str = +""
84-
loop do
85-
if look(:open_square)
86-
str << consume
87-
str << expression_string
88-
str << consume(:close_square)
89-
elsif look(:dot)
90-
str << consume
91-
str << consume(:id)
92-
else
93-
break
94-
end
95-
end
96-
str
85+
def unnamed_variable_lookup
86+
name = indexed_lookup
87+
lookups, command_flags = variable_lookups
88+
VariableLookup.new(name, lookups, command_flags)
9789
end
9890

9991
def expression_string
10092
token = @tokens[@p]
10193
case token[0]
10294
when :id
10395
str = consume
104-
str << variable_lookups
96+
str << variable_lookups_string
10597
when :open_square
10698
str = consume.dup
10799
str << expression_string
108100
str << consume(:close_square)
109-
str << variable_lookups
101+
str << variable_lookups_string
110102
when :string, :number
111103
consume
112104
when :open_round
@@ -121,6 +113,34 @@ def expression_string
121113
end
122114
end
123115

116+
def argument_string
117+
str = +""
118+
# might be a keyword argument (identifier: expression)
119+
if look(:id) && look(:colon, 1)
120+
str << consume << consume << ' '
121+
end
122+
123+
str << expression_string
124+
str
125+
end
126+
127+
def variable_lookups_string
128+
str = +""
129+
loop do
130+
if look(:open_square)
131+
str << consume
132+
str << expression_string
133+
str << consume(:close_square)
134+
elsif look(:dot)
135+
str << consume
136+
str << consume(:id)
137+
else
138+
break
139+
end
140+
end
141+
str
142+
end
143+
124144
# Assumes safe input. For cases where you need the string.
125145
# Don't use this unless you're sure about what you're doing.
126146
def unsafe_parse_expression(markup)
@@ -132,5 +152,31 @@ def unsafe_parse_expression(markup)
132152
def parse_expression(markup)
133153
Expression.parse(markup, @ss, @cache)
134154
end
155+
156+
def variable_lookups
157+
lookups = []
158+
command_flags = 0
159+
i = -1
160+
loop do
161+
i += 1
162+
if look(:open_square)
163+
lookups << indexed_lookup
164+
elsif consume?(:dot)
165+
lookup = consume(:id)
166+
lookups << lookup
167+
command_flags |= 1 << i if VariableLookup::COMMAND_METHODS.include?(lookup)
168+
else
169+
break
170+
end
171+
end
172+
[lookups, command_flags]
173+
end
174+
175+
def indexed_lookup
176+
consume(:open_square)
177+
expr = expression
178+
consume(:close_square)
179+
expr
180+
end
135181
end
136182
end

test/integration/expression_test.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def test_expression_cache
6767
Liquid::Template.parse(template, expression_cache: cache).render
6868

6969
assert_equal(
70-
["x", "y"],
70+
[],
7171
cache.to_a.map { _1[0] }.sort,
7272
)
7373
end
@@ -91,7 +91,7 @@ def test_expression_cache_with_true_boolean
9191
cache = parse_context.instance_variable_get(:@expression_cache)
9292

9393
assert_equal(
94-
["x", "y"],
94+
[],
9595
cache.to_a.map { _1[0] }.sort,
9696
)
9797
end
@@ -112,7 +112,7 @@ def test_expression_cache_with_lru_redux
112112
Liquid::Template.parse(template, expression_cache: cache).render
113113

114114
assert_equal(
115-
["x", "y"],
115+
[],
116116
cache.to_a.map { _1[0] }.sort,
117117
)
118118
end

test/unit/parser_unit_test.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def test_look
4545
assert_equal(false, p.look(:number, 1))
4646
end
4747

48-
def test_expressions
48+
def test_expression_string
4949
p = new_parser("hi.there hi?[5].there? hi.there.bob")
5050
assert_equal('hi.there', p.expression_string)
5151
assert_equal('hi?[5].there?', p.expression_string)
@@ -58,6 +58,25 @@ def test_expressions
5858
assert_equal('"wut"', p.expression_string)
5959
end
6060

61+
def test_expression
62+
p = new_parser("hi.there hi?[5].there? hi.there.bob")
63+
v1 = p.expression
64+
v2 = p.expression
65+
v3 = p.expression
66+
assert(v1.is_a?(VariableLookup) && v1.name == 'hi' && v1.lookups[0] == 'there')
67+
assert(v2.is_a?(VariableLookup) && v2.name == 'hi?' && v2.lookups[0] == 5)
68+
assert(v3.is_a?(VariableLookup) && v3.name == 'hi' && v3.lookups[0] == 'there')
69+
70+
p = new_parser("567 6.0 'lol' \"wut\" true false (0..5)")
71+
assert_equal(567, p.expression)
72+
assert_equal(6.0, p.expression)
73+
assert_equal('lol', p.expression)
74+
assert_equal('wut', p.expression)
75+
assert_equal(true, p.expression)
76+
assert_equal(false, p.expression)
77+
assert_equal((0..5), p.expression)
78+
end
79+
6180
def test_number
6281
p = new_parser('-1 0 1 2.0')
6382
assert_equal(-1, p.number)
@@ -74,6 +93,15 @@ def test_string
7493
assert_equal("that 's4'", p.string)
7594
end
7695

96+
def test_unnamed_variable_lookup
97+
p = new_parser('[key].title')
98+
v = p.expression
99+
assert(v.is_a?(VariableLookup))
100+
assert(v.name.is_a?(VariableLookup))
101+
assert_equal('key', v.name.name)
102+
assert_equal('title', v.lookups[0])
103+
end
104+
77105
def test_ranges
78106
p = new_parser("(5..7) (1.5..9.6) (young..old) (hi[5].wat..old)")
79107
assert_equal('(5..7)', p.expression_string)

0 commit comments

Comments
 (0)