mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-15 08:50:45 -07:00
replace For tag Syntax regex with manual byte-level parser
This commit is contained in:
+70
-11
@@ -72,21 +72,80 @@ module Liquid
|
|||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
# Fast byte-level parser for "var in collection [reversed] [limit:N] [offset:N]"
|
||||||
|
REVERSED_BYTES = "reversed".bytes.freeze
|
||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
if markup =~ Syntax
|
# Try fast manual parse first
|
||||||
@variable_name = Regexp.last_match(1)
|
len = markup.bytesize
|
||||||
collection_name = Regexp.last_match(2)
|
pos = 0
|
||||||
@reversed = !!Regexp.last_match(3)
|
|
||||||
@name = "#{@variable_name}-#{collection_name}"
|
# Skip whitespace
|
||||||
@collection_name = parse_expression(collection_name)
|
pos += 1 while pos < len && (b = markup.getbyte(pos)) && (b == 32 || b == 9)
|
||||||
# Only scan for limit:/offset: attributes if markup contains ':'
|
|
||||||
if markup.include?(':')
|
# Parse variable name: [\w-]+
|
||||||
markup.scan(TagAttributes) do |key, value|
|
var_start = pos
|
||||||
set_attribute(key, value)
|
while pos < len
|
||||||
|
b = markup.getbyte(pos)
|
||||||
|
break unless (b >= 97 && b <= 122) || (b >= 65 && b <= 90) || (b >= 48 && b <= 57) || b == 95 || b == 45
|
||||||
|
pos += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if pos == var_start
|
||||||
|
raise SyntaxError, options[:locale].t("errors.syntax.for")
|
||||||
|
end
|
||||||
|
|
||||||
|
@variable_name = markup.byteslice(var_start, pos - var_start)
|
||||||
|
|
||||||
|
# Expect whitespace + "in" + whitespace
|
||||||
|
pos += 1 while pos < len && markup.getbyte(pos) == 32
|
||||||
|
unless pos + 1 < len && markup.getbyte(pos) == 105 && markup.getbyte(pos + 1) == 110 # 'i', 'n'
|
||||||
|
raise SyntaxError, options[:locale].t("errors.syntax.for")
|
||||||
|
end
|
||||||
|
pos += 2
|
||||||
|
pos += 1 while pos < len && markup.getbyte(pos) == 32
|
||||||
|
|
||||||
|
# Parse collection name (QuotedFragment - take everything until whitespace)
|
||||||
|
col_start = pos
|
||||||
|
# Handle parenthesized ranges: (1..10)
|
||||||
|
if pos < len && markup.getbyte(pos) == 40 # '('
|
||||||
|
depth = 1
|
||||||
|
pos += 1
|
||||||
|
while pos < len && depth > 0
|
||||||
|
b = markup.getbyte(pos)
|
||||||
|
depth += 1 if b == 40
|
||||||
|
depth -= 1 if b == 41
|
||||||
|
pos += 1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise SyntaxError, options[:locale].t("errors.syntax.for")
|
while pos < len
|
||||||
|
b = markup.getbyte(pos)
|
||||||
|
break if b == 32 || b == 9
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
collection_name = markup.byteslice(col_start, pos - col_start)
|
||||||
|
|
||||||
|
@name = "#{@variable_name}-#{collection_name}"
|
||||||
|
@collection_name = parse_expression(collection_name)
|
||||||
|
|
||||||
|
# Skip whitespace
|
||||||
|
pos += 1 while pos < len && markup.getbyte(pos) == 32
|
||||||
|
|
||||||
|
# Check for 'reversed'
|
||||||
|
@reversed = false
|
||||||
|
if pos + 7 < len && markup.byteslice(pos, 8) == "reversed"
|
||||||
|
@reversed = true
|
||||||
|
pos += 8
|
||||||
|
pos += 1 while pos < len && markup.getbyte(pos) == 32
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse limit:/offset: if present
|
||||||
|
if pos < len && markup.include?(':')
|
||||||
|
rest = markup.byteslice(pos, len - pos)
|
||||||
|
rest.scan(TagAttributes) do |key, value|
|
||||||
|
set_attribute(key, value)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user