mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-15 08:50:45 -07:00
85 lines
2.2 KiB
Ruby
85 lines
2.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Liquid
|
|
class Expression
|
|
LITERALS = {
|
|
nil => nil,
|
|
'nil' => nil,
|
|
'null' => nil,
|
|
'' => nil,
|
|
'true' => true,
|
|
'false' => false,
|
|
'blank' => MethodLiteral::BLANK,
|
|
'empty' => MethodLiteral::EMPTY,
|
|
}.freeze
|
|
|
|
DOT = ".".ord
|
|
ZERO = "0".ord
|
|
NINE = "9".ord
|
|
DASH = "-".ord
|
|
|
|
# Use an atomic group (?>...) to avoid pathological backtracing from
|
|
# malicious input as described in https://github.com/Shopify/liquid/issues/1357
|
|
RANGES_REGEX = /\A\(\s*(?>(\S+)\s*\.\.)\s*(\S+)\s*\)\z/
|
|
INTEGER_REGEX = /\A(-?\d+)\z/
|
|
FLOAT_REGEX = /\A(-?\d+)\.\d+\z/
|
|
|
|
class << self
|
|
def parse(markup, ss = StringScanner.new(""), cache = nil)
|
|
return unless markup
|
|
|
|
markup = markup.strip # markup can be a frozen string
|
|
|
|
if (markup.start_with?('"') && markup.end_with?('"')) ||
|
|
(markup.start_with?("'") && markup.end_with?("'"))
|
|
return markup[1..-2]
|
|
elsif LITERALS.key?(markup)
|
|
return LITERALS[markup]
|
|
end
|
|
|
|
# Cache only exists during parsing
|
|
if cache
|
|
return cache[markup] if cache.key?(markup)
|
|
|
|
cache[markup] = inner_parse(markup, ss, cache).freeze
|
|
else
|
|
inner_parse(markup, ss, nil).freeze
|
|
end
|
|
end
|
|
|
|
def inner_parse(markup, ss, cache)
|
|
if markup.start_with?("(") && markup.end_with?(")") && markup =~ RANGES_REGEX
|
|
start_markup = Regexp.last_match(1)
|
|
end_markup = Regexp.last_match(2)
|
|
start_obj = parse(start_markup, ss, cache)
|
|
end_obj = parse(end_markup, ss, cache)
|
|
return RangeLookup.create(
|
|
start_obj,
|
|
end_obj,
|
|
start_markup,
|
|
end_markup,
|
|
)
|
|
end
|
|
|
|
if (num = parse_number(markup))
|
|
num
|
|
else
|
|
VariableLookup.parse(markup, ss, cache)
|
|
end
|
|
end
|
|
|
|
def parse_number(markup)
|
|
# check if the markup is simple integer or float
|
|
case markup
|
|
when INTEGER_REGEX
|
|
Integer(markup, 10)
|
|
when FLOAT_REGEX
|
|
markup.to_f
|
|
else
|
|
false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|