From dff829ec724c38e2d9d2eb36b13e2df6e1beea02 Mon Sep 17 00:00:00 2001 From: "Charles-P. Clermont" Date: Wed, 3 Dec 2025 11:40:51 -0500 Subject: [PATCH] Extract Parser#range_lookup out of Expression.parse --- lib/liquid/parser.rb | 13 ++++++++++++- lib/liquid/range_lookup.rb | 4 +++- test/integration/expression_test.rb | 2 +- test/unit/parser_unit_test.rb | 9 +++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/liquid/parser.rb b/lib/liquid/parser.rb index 72516c26..7003af9b 100644 --- a/lib/liquid/parser.rb +++ b/lib/liquid/parser.rb @@ -58,8 +58,10 @@ module Liquid string when :number number + when :open_round + range_lookup else - parse_expression(expression_string) + raise SyntaxError, "#{token} is not a valid expression" end end @@ -88,6 +90,15 @@ module Liquid VariableLookup.new(name, lookups, command_flags) end + def range_lookup + consume(:open_round) + first = expression + consume(:dotdot) + last = expression + consume(:close_round) + RangeLookup.create(first, last) + end + def expression_string token = @tokens[@p] case token[0] diff --git a/lib/liquid/range_lookup.rb b/lib/liquid/range_lookup.rb index e4ce296c..8e617f73 100644 --- a/lib/liquid/range_lookup.rb +++ b/lib/liquid/range_lookup.rb @@ -2,13 +2,15 @@ module Liquid class RangeLookup - def self.create(start_obj, end_obj, start_markup, end_markup) + def self.create(start_obj, end_obj, start_markup = nil, end_markup = nil) if start_obj.respond_to?(:evaluate) || end_obj.respond_to?(:evaluate) new(start_obj, end_obj) else begin start_obj.to_i..end_obj.to_i rescue NoMethodError + start_markup = start_obj.to_s unless start_markup + end_markup = end_obj.to_s unless end_markup invalid_expr = start_markup unless start_obj.respond_to?(:to_i) invalid_expr ||= end_markup unless end_obj.respond_to?(:to_i) if invalid_expr diff --git a/test/integration/expression_test.rb b/test/integration/expression_test.rb index 2f53596d..89dc9ab1 100644 --- a/test/integration/expression_test.rb +++ b/test/integration/expression_test.rb @@ -46,7 +46,7 @@ class ExpressionTest < Minitest::Test "{{ (false..true) }}", ) assert_match_syntax_error( - "Liquid syntax error (line 1): Invalid expression type '(1..2)' in range expression", + "Liquid syntax error (line 1): Invalid expression type '1..2' in range expression", "{{ ((1..2)..3) }}", ) end diff --git a/test/unit/parser_unit_test.rb b/test/unit/parser_unit_test.rb index 1b3e142d..cf0d8c7b 100644 --- a/test/unit/parser_unit_test.rb +++ b/test/unit/parser_unit_test.rb @@ -102,6 +102,15 @@ class ParserUnitTest < Minitest::Test assert_equal('title', v.lookups[0]) end + def test_range_lookup + p = new_parser('(0..5) (a..b)') + assert_equal((0..5), p.expression) + + r2 = p.expression + assert(r2.is_a?(RangeLookup)) + assert_equal((1..4), r2.evaluate(Context.new({ 'a' => 1, 'b' => 4 }))) + end + def test_ranges p = new_parser("(5..7) (1.5..9.6) (young..old) (hi[5].wat..old)") assert_equal('(5..7)', p.expression_string)