mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-15 08:50:45 -07:00
Make Parser.expression parse comparisons
This commit is contained in:
@@ -62,6 +62,7 @@ require 'liquid/interrupts'
|
||||
require 'liquid/tags'
|
||||
require "liquid/environment"
|
||||
require 'liquid/lexer'
|
||||
require 'liquid/binary_expression'
|
||||
require 'liquid/parser'
|
||||
require 'liquid/i18n'
|
||||
require 'liquid/drop'
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Liquid
|
||||
class BinaryExpression
|
||||
attr_reader :left, :operator, :right
|
||||
|
||||
def initialize(left, operator, right)
|
||||
@left = left
|
||||
@operator = operator
|
||||
@right = right
|
||||
end
|
||||
|
||||
def evaluate(context)
|
||||
left_value = value(left, context)
|
||||
right_value = value(@right, context)
|
||||
|
||||
case operator
|
||||
when '>'
|
||||
left_value > right_value
|
||||
when '>='
|
||||
left_value >= right_value
|
||||
when '<'
|
||||
left_value < right_value
|
||||
when '<='
|
||||
left_value <= right_value
|
||||
when '=='
|
||||
left_value == right_value
|
||||
when '!=', '<>'
|
||||
left_value != right_value
|
||||
when 'contains'
|
||||
if left_value && right_value && left_value.respond_to?(:include?)
|
||||
right_value = right_value.to_s if left_value.is_a?(String)
|
||||
left_value.include?(right_value)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def value(expr, context)
|
||||
Utils.to_liquid_value(context.evaluate(expr))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -47,7 +47,24 @@ module Liquid
|
||||
tok[0] == type
|
||||
end
|
||||
|
||||
# expression := comparison
|
||||
# comparison := primary ((">=" | ">" | "<" | "<=" | ... ) primary)*
|
||||
# primary := string | number | variable_lookup | range | boolean
|
||||
def expression
|
||||
comparison
|
||||
end
|
||||
|
||||
# comparison := primary ((">=" | ">" | "<" | "<=" | ... ) primary)*
|
||||
def comparison
|
||||
expr = primary
|
||||
while look(:comparison)
|
||||
operator = consume
|
||||
expr = BinaryExpression.new(expr, operator, primary)
|
||||
end
|
||||
expr
|
||||
end
|
||||
|
||||
def primary
|
||||
token = @tokens[@p]
|
||||
case token[0]
|
||||
when :id
|
||||
|
||||
@@ -77,6 +77,30 @@ class ParserUnitTest < Minitest::Test
|
||||
assert_equal(0..5, p.expression)
|
||||
end
|
||||
|
||||
def test_comparison
|
||||
p = new_parser("a > b")
|
||||
expr = p.expression
|
||||
assert(expr.is_a?(BinaryExpression))
|
||||
assert_equal('>', expr.operator)
|
||||
assert(expr.left.is_a?(VariableLookup))
|
||||
assert_equal('a', expr.left.name)
|
||||
assert(expr.right.is_a?(VariableLookup))
|
||||
assert_equal('b', expr.right.name)
|
||||
|
||||
# BinaryExpression(>=)
|
||||
# left: BinaryExpression(>)
|
||||
# left: 10
|
||||
# right: 5
|
||||
# right: 4
|
||||
p = new_parser("10 > 5 >= 4")
|
||||
expr = p.expression
|
||||
assert(expr.is_a?(BinaryExpression))
|
||||
assert_equal('>=', expr.operator)
|
||||
assert_equal(10, expr.left.left)
|
||||
assert_equal(5, expr.left.right)
|
||||
assert_equal(4, expr.right)
|
||||
end
|
||||
|
||||
def test_number
|
||||
p = new_parser('-1 0 1 2.0')
|
||||
assert_equal(-1, p.number)
|
||||
|
||||
Reference in New Issue
Block a user