From 9b967690aa228c1f99a506b837820837d3a64b3a Mon Sep 17 00:00:00 2001 From: Guilherme Carreiro Date: Wed, 5 Mar 2025 14:49:10 +0100 Subject: [PATCH] Introduce support to boolean operators in the lexer --- lib/liquid/lexer.rb | 6 +++ test/unit/lexer_unit_test.rb | 72 ++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/lib/liquid/lexer.rb b/lib/liquid/lexer.rb index f1740dba..26b74232 100644 --- a/lib/liquid/lexer.rb +++ b/lib/liquid/lexer.rb @@ -14,6 +14,8 @@ module Liquid COMPARISON_LESS_THAN = [:comparison, "<"].freeze COMPARISON_LESS_THAN_OR_EQUAL = [:comparison, "<="].freeze COMPARISON_NOT_EQUAL_ALT = [:comparison, "<>"].freeze + BOOLEAN_AND = [:boolean_operator, "and"].freeze + BOOLEAN_OR = [:boolean_operator, "or"].freeze DASH = [:dash, "-"].freeze DOT = [:dot, "."].freeze DOTDOT = [:dotdot, ".."].freeze @@ -151,6 +153,10 @@ module Liquid # Special case for "contains" output << if type == :id && t == "contains" && output.last&.first != :dot COMPARISON_CONTAINS + elsif type == :id && t == "and" && output.last&.first != :dot + BOOLEAN_AND + elsif type == :id && t == "or" && output.last&.first != :dot + BOOLEAN_OR else [type, t] end diff --git a/test/unit/lexer_unit_test.rb b/test/unit/lexer_unit_test.rb index 73eeb739..703bc976 100644 --- a/test/unit/lexer_unit_test.rb +++ b/test/unit/lexer_unit_test.rb @@ -141,6 +141,78 @@ class LexerUnitTest < Minitest::Test ) end + def test_boolean_and_operator + exp = [ + [:id, "true"], + [:boolean_operator, "and"], + [:id, "false"], + [:end_of_string], + ] + act = tokenize("true and false") + assert_equal(exp, act) + end + + def test_boolean_or_operator + exp = [ + [:id, "false"], + [:boolean_operator, "or"], + [:id, "true"], + [:end_of_string], + ] + act = tokenize("false or true") + assert_equal(exp, act) + end + + def test_boolean_operators_in_complex_expressions + exp = [ + [:id, "a"], + [:boolean_operator, "and"], + [:id, "b"], + [:boolean_operator, "or"], + [:id, "c"], + [:end_of_string], + ] + act = tokenize("a and b or c") + assert_equal(exp, act) + end + + def test_boolean_operators_with_comparisons + exp = [ + [:id, "a"], + [:comparison, ">"], + [:number, "5"], + [:boolean_operator, "and"], + [:id, "b"], + [:comparison, "<"], + [:number, "10"], + [:end_of_string], + ] + act = tokenize("a > 5 and b < 10") + assert_equal(exp, act) + end + + def test_boolean_operators_as_property_names + exp = [ + [:id, "obj"], + [:dot, "."], + [:id, "and"], + [:dot, "."], + [:id, "property"], + [:end_of_string], + ] + act = tokenize("obj.and.property") + assert_equal(exp, act) + + exp = [ + [:id, "obj"], + [:dot, "."], + [:id, "or"], + [:end_of_string], + ] + act = tokenize("obj.or") + assert_equal(exp, act) + end + private def tokenize(input)