From 8c60657f02e81a4376a249a59f295d63003d4ceb Mon Sep 17 00:00:00 2001 From: doorgan Date: Thu, 22 Jan 2026 12:28:10 -0300 Subject: [PATCH] fix: range operator precedence and nested range with ternary step --- lib/spitfire.ex | 13 +++++++++---- test/spitfire_test.exs | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/spitfire.ex b/lib/spitfire.ex index 5f5e021..4b709bd 100644 --- a/lib/spitfire.ex +++ b/lib/spitfire.ex @@ -82,7 +82,7 @@ defmodule Spitfire do @xor_op {:left, 40} @ternary_op {:right, 42} @concat_op {:right, 44} - @range_op {:right, 46} + @range_op {:right, 44} @dual_op {:left, 48} @mult_op {:left, 50} @power_op {:left, 52} @@ -382,7 +382,8 @@ defmodule Spitfire do parse_infix_expression(next_token(parser), left) :range_op -> - parse_range_expression(next_token(parser), left) + in_range = Map.get(parser, :in_range, false) + parse_range_expression(next_token(parser), left, in_range) :stab_op when not is_stab -> parse_stab_expression(next_token(parser), left) @@ -1065,15 +1066,19 @@ defmodule Spitfire do end end - defp parse_range_expression(parser, lhs) do + defp parse_range_expression(parser, lhs, inside_range) do trace "parse_range_expression (with lhs)", trace_meta(parser) do token = current_token(parser) meta = current_meta(parser) precedence = current_precedence(parser) parser = next_token(parser) + + old_in_range = Map.get(parser, :in_range, false) + parser = Map.put(parser, :in_range, true) {rhs, parser} = parse_expression(parser, precedence, false, false, false) + parser = Map.put(parser, :in_range, old_in_range) - if peek_token(parser) == :ternary_op do + if not inside_range and peek_token(parser) == :ternary_op do parser = parser |> next_token() |> next_token() {rrhs, parser} = parse_expression(parser, precedence, false, false, false) diff --git a/test/spitfire_test.exs b/test/spitfire_test.exs index f15bbc6..11bd132 100644 --- a/test/spitfire_test.exs +++ b/test/spitfire_test.exs @@ -1694,6 +1694,22 @@ defmodule SpitfireTest do assert Spitfire.parse(code) == s2q(code) end + test "range operator precedence and nested ranges" do + codes = [ + "a..b ++ c", + "a..b -- c", + "a..b <> c", + "a..b..c//d", + "1..2..3//4", + "a..b//c", + "1..10//2" + ] + + for code <- codes do + assert Spitfire.parse(code) == s2q(code) + end + end + test "from nx repo" do code = ~S''' def a,