Make Parser.expression parse comparisons

This commit is contained in:
Charles-P. Clermont
2026-01-26 16:52:31 -05:00
parent 6f03452245
commit b161dae495
4 changed files with 88 additions and 0 deletions
+1
View File
@@ -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'
+46
View File
@@ -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
+17
View File
@@ -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
+24
View File
@@ -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)