mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-12 23:40:45 -07:00
replace INTEGER_REGEX/FLOAT_REGEX with byte-level parse_number
This commit is contained in:
+58
-45
@@ -78,61 +78,74 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_number(markup, ss)
|
def parse_number(markup, _ss = nil)
|
||||||
|
len = markup.bytesize
|
||||||
|
return false if len == 0
|
||||||
|
|
||||||
# Quick reject: first byte must be digit or dash
|
# Quick reject: first byte must be digit or dash
|
||||||
first = markup.getbyte(0)
|
pos = 0
|
||||||
return false if first != DASH && (first < ZERO || first > NINE)
|
first = markup.getbyte(pos)
|
||||||
|
if first == DASH
|
||||||
|
pos += 1
|
||||||
|
return false if pos >= len
|
||||||
|
b = markup.getbyte(pos)
|
||||||
|
return false if b < ZERO || b > NINE
|
||||||
|
pos += 1
|
||||||
|
elsif first >= ZERO && first <= NINE
|
||||||
|
pos += 1
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
# check if the markup is simple integer or float
|
# Scan digits
|
||||||
case markup
|
while pos < len
|
||||||
when INTEGER_REGEX
|
b = markup.getbyte(pos)
|
||||||
|
break unless b >= ZERO && b <= NINE
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we consumed everything, it's a simple integer
|
||||||
|
if pos == len
|
||||||
return Integer(markup, 10)
|
return Integer(markup, 10)
|
||||||
when FLOAT_REGEX
|
|
||||||
return markup.to_f
|
|
||||||
end
|
end
|
||||||
|
|
||||||
ss.string = markup
|
# Check for dot (float)
|
||||||
# the first byte must be a digit or a dash
|
if markup.getbyte(pos) == DOT
|
||||||
byte = ss.scan_byte
|
dot_pos = pos
|
||||||
|
pos += 1
|
||||||
|
# Must have at least one digit after dot
|
||||||
|
digit_after_dot = pos
|
||||||
|
while pos < len
|
||||||
|
b = markup.getbyte(pos)
|
||||||
|
break unless b >= ZERO && b <= NINE
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
|
||||||
return false if byte != DASH && (byte < ZERO || byte > NINE)
|
if pos > digit_after_dot && pos == len
|
||||||
|
# Simple float like "123.456"
|
||||||
if byte == DASH
|
return markup.to_f
|
||||||
peek_byte = ss.peek_byte
|
elsif pos > digit_after_dot
|
||||||
|
# Float followed by more dots or other chars: "1.2.3.4"
|
||||||
# if it starts with a dash, the next byte must be a digit
|
# Return the float portion up to second dot
|
||||||
return false if peek_byte.nil? || !(peek_byte >= ZERO && peek_byte <= NINE)
|
first_dot_pos = dot_pos + 1
|
||||||
end
|
while pos < len
|
||||||
|
b = markup.getbyte(pos)
|
||||||
# The markup could be a float with multiple dots
|
if b == DOT
|
||||||
first_dot_pos = nil
|
return markup.byteslice(0, pos).to_f
|
||||||
num_end_pos = nil
|
elsif b < ZERO || b > NINE
|
||||||
|
return false
|
||||||
while (byte = ss.scan_byte)
|
end
|
||||||
return false if byte != DOT && (byte < ZERO || byte > NINE)
|
pos += 1
|
||||||
|
|
||||||
# we found our number and now we are just scanning the rest of the string
|
|
||||||
next if num_end_pos
|
|
||||||
|
|
||||||
if byte == DOT
|
|
||||||
if first_dot_pos.nil?
|
|
||||||
first_dot_pos = ss.pos
|
|
||||||
else
|
|
||||||
# we found another dot, so we know that the number ends here
|
|
||||||
num_end_pos = ss.pos - 1
|
|
||||||
end
|
end
|
||||||
|
return markup.byteslice(0, pos).to_f
|
||||||
|
else
|
||||||
|
# dot at end: "123."
|
||||||
|
return markup.byteslice(0, dot_pos).to_f
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
num_end_pos = markup.length if ss.eos?
|
# Not a number (has non-digit, non-dot characters)
|
||||||
|
false
|
||||||
if num_end_pos
|
|
||||||
# number ends with a number "123.123"
|
|
||||||
markup.byteslice(0, num_end_pos).to_f
|
|
||||||
else
|
|
||||||
# number ends with a dot "123."
|
|
||||||
markup.byteslice(0, first_dot_pos).to_f
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user