fix(parser): implement RTL associativity for boolean expressions

- Use right-recursive descent for proper RTL precedence
- Add bin/liquid-spec-all-adapters for CI workflow
- Update CI to use dedicated script

Fixes 128 precedence test failures from original implementation.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
Charles-P. Clermont
2026-01-28 09:09:19 -05:00
co-authored by Claude Opus 4.5
parent 3b13ee0ff3
commit 26cb29487b
3 changed files with 16 additions and 15 deletions
+1 -5
View File
@@ -56,11 +56,7 @@ jobs:
bundler-cache: true
bundler: latest
- name: Run liquid-spec for all adapters
run: |
for adapter in spec/*.rb; do
echo "=== Running $adapter ==="
bundle exec liquid-spec run "$adapter" --no-max-failures
done
run: bin/liquid-spec-all-adapters
memory_profile:
runs-on: ubuntu-latest
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
for adapter in spec/*.rb; do
echo "=== Running $adapter ==="
bundle exec liquid-spec run "$adapter" --no-max-failures
done
+10 -10
View File
@@ -59,18 +59,18 @@ module Liquid
logical
end
# Logical relations in Liquid, unlike other languages, are right-to-left
# associative. This creates a right-leaning tree and is why the method
# looks a bit more complicated
#
# Logical relations use right-to-left associativity.
# `a and b or c` is evaluated like (a and (b or c))
# logical := equality (("and" | "or") equality)*
# This enables short-circuit: if `a` is false, entire expression short-circuits.
# logical := equality (("and" | "or") logical)?
def logical
operator = nil
expr = equality
expr = BinaryExpression.new(expr, operator, equality) if (operator = consume?(:logical))
expr.right_node = BinaryExpression.new(expr.right_node, operator, equality) while (operator = consume?(:logical))
expr
left = equality
if (operator = consume?(:logical))
right = logical # recursive call builds proper RTL tree
BinaryExpression.new(left, operator, right)
else
left
end
end
# equality := comparison (("==" | "!=" | "<>") comparison)*