From 0b890904f052ac11cdd53423f35dc87a34c71af8 Mon Sep 17 00:00:00 2001 From: "Charles-P. Clermont" Date: Wed, 3 Dec 2025 15:03:42 -0500 Subject: [PATCH] Make Parser.expression parse equality expressions --- lib/liquid/lexer.rb | 6 +++--- lib/liquid/parser.rb | 14 ++++++++++++-- lib/liquid/tags/if.rb | 2 +- test/unit/lexer_unit_test.rb | 13 ++++++++++--- test/unit/parser_unit_test.rb | 25 +++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 9 deletions(-) diff --git a/lib/liquid/lexer.rb b/lib/liquid/lexer.rb index f1740dba..c0a6463b 100644 --- a/lib/liquid/lexer.rb +++ b/lib/liquid/lexer.rb @@ -6,14 +6,14 @@ module Liquid CLOSE_SQUARE = [:close_square, "]"].freeze COLON = [:colon, ":"].freeze COMMA = [:comma, ","].freeze - COMPARISION_NOT_EQUAL = [:comparison, "!="].freeze + COMPARISION_NOT_EQUAL = [:equality, "!="].freeze COMPARISON_CONTAINS = [:comparison, "contains"].freeze - COMPARISON_EQUAL = [:comparison, "=="].freeze + COMPARISON_EQUAL = [:equality, "=="].freeze COMPARISON_GREATER_THAN = [:comparison, ">"].freeze COMPARISON_GREATER_THAN_OR_EQUAL = [:comparison, ">="].freeze COMPARISON_LESS_THAN = [:comparison, "<"].freeze COMPARISON_LESS_THAN_OR_EQUAL = [:comparison, "<="].freeze - COMPARISON_NOT_EQUAL_ALT = [:comparison, "<>"].freeze + COMPARISON_NOT_EQUAL_ALT = [:equality, "<>"].freeze DASH = [:dash, "-"].freeze DOT = [:dot, "."].freeze DOTDOT = [:dotdot, ".."].freeze diff --git a/lib/liquid/parser.rb b/lib/liquid/parser.rb index 66d7c423..8d5151e7 100644 --- a/lib/liquid/parser.rb +++ b/lib/liquid/parser.rb @@ -47,11 +47,21 @@ module Liquid tok[0] == type end - # expression := comparison + # expression := equality + # equality := comparison (("==" | "!=" | "<>") comparison)* # comparison := primary ((">=" | ">" | "<" | "<=" | ... ) primary)* # primary := string | number | variable_lookup | range | boolean def expression - comparison + equality + end + + def equality + expr = comparison + while look(:equality) + operator = consume + expr = BinaryExpression.new(expr, operator, comparison) + end + expr end # comparison := primary ((">=" | ">" | "<" | "<=" | ... ) primary)* diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb index 2081c788..3471f677 100644 --- a/lib/liquid/tags/if.rb +++ b/lib/liquid/tags/if.rb @@ -97,7 +97,7 @@ module Liquid def parse_comparison(p) a = parse_expression(p) - if (op = p.consume?(:comparison)) + if (op = p.consume?(:comparison) || p.consume?(:equality)) b = parse_expression(p) Condition.new(a, op, b) else diff --git a/test/unit/lexer_unit_test.rb b/test/unit/lexer_unit_test.rb index 73eeb739..494769b8 100644 --- a/test/unit/lexer_unit_test.rb +++ b/test/unit/lexer_unit_test.rb @@ -26,10 +26,17 @@ class LexerUnitTest < Minitest::Test ) end + def test_equality + assert_equal( + [[:equality, '=='], [:equality, '<>'], [:equality, '!='], [:end_of_string]], + tokenize('== <> != '), + ) + end + def test_comparison assert_equal( - [[:comparison, '=='], [:comparison, '<>'], [:comparison, 'contains'], [:end_of_string]], - tokenize('== <> contains '), + [[:comparison, '>'], [:comparison, '>='], [:comparison, '<'], [:comparison, '<='], [:comparison, 'contains'], [:end_of_string]], + tokenize('> >= < <= contains'), ) end @@ -81,7 +88,7 @@ class LexerUnitTest < Minitest::Test def test_whitespace assert_equal( - [[:id, 'five'], [:pipe, '|'], [:comparison, '=='], [:end_of_string]], + [[:id, 'five'], [:pipe, '|'], [:equality, '=='], [:end_of_string]], tokenize("five|\n\t =="), ) end diff --git a/test/unit/parser_unit_test.rb b/test/unit/parser_unit_test.rb index a4d52d65..dccee43f 100644 --- a/test/unit/parser_unit_test.rb +++ b/test/unit/parser_unit_test.rb @@ -77,6 +77,31 @@ class ParserUnitTest < Minitest::Test assert_equal(0..5, p.expression) end + def test_equality + p = new_parser("a == b") + expr = p.expression + assert(expr.is_a?(BinaryExpression)) + assert_equal('==', expr.operator) + assert_equal('a', expr.left.name) + assert_equal('b', expr.right.name) + + # BinaryExpression(==) + # left: BinaryExpression(<) + # left: 0 + # right: 5 + # right: BinaryExpression(>) + # left: 6 + # right: 1 + p = new_parser("0 < 5 == 6 > 1") + expr = p.expression + assert(expr.is_a?(BinaryExpression)) + assert_equal('==', expr.operator) + assert_equal(0, expr.left.left) + assert_equal(5, expr.left.right) + assert_equal(6, expr.right.left) + assert_equal(1, expr.right.right) + end + def test_comparison p = new_parser("a > b") expr = p.expression