summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTSUYUSATO Kitsune <make.just.on@gmail.com>2023-12-11 14:10:57 +0900
committergit <svn-admin@ruby-lang.org>2023-12-11 13:34:48 +0000
commita860e3605c53e708d3cb06e2080ff73b58de4b22 (patch)
tree8ac3990fe9426a295afcec47829b64879e064515
parent1ab91b12fa5f7e98bba2e59e2f40b57004d9acf1 (diff)
[ruby/prism] Fix to parse a (endless-)range with binary operators
Fix https://github.com/ruby/prism/pull/2022 Fix https://github.com/ruby/prism/pull/2030 https://github.com/ruby/prism/commit/b78d8b6525
-rw-r--r--prism/prism.c19
-rw-r--r--test/prism/errors_test.rb17
-rw-r--r--test/prism/fixtures/ranges.txt30
-rw-r--r--test/prism/snapshots/ranges.txt337
4 files changed, 386 insertions, 17 deletions
diff --git a/prism/prism.c b/prism/prism.c
index ca9430f6ca..9ca542ba30 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -10128,7 +10128,7 @@ typedef struct {
#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
-#define NON_ASSOCIATIVE(precedence) { precedence + 1, precedence + 1, true, true }
+#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = {
@@ -16967,11 +16967,18 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
current_binding_powers.binary
) {
node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call);
- if (
- current_binding_powers.nonassoc &&
- current_binding_powers.right <= pm_binding_powers[parser->current.type].left
- ) {
- break;
+ if (current_binding_powers.nonassoc) {
+ bool endless_range_p = PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL;
+ pm_binding_power_t left = endless_range_p ? PM_BINDING_POWER_TERM : current_binding_powers.left;
+ if (
+ left <= pm_binding_powers[parser->current.type].left ||
+ // Exceptionally to operator precedences, '1.. & 2' is rejected.
+ // '1.. || 2' is also an exception, but it is handled by the lexer.
+ // (Here, parser->current is PM_TOKEN_PIPE, not PM_TOKEN_PIPE_PIPE).
+ (endless_range_p && match1(parser, PM_TOKEN_AMPERSAND))
+ ) {
+ break;
+ }
}
if (accepts_command_call) {
// A command-style method call is only accepted on method chains.
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index b0e2554338..7744bd8b88 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -1971,6 +1971,23 @@ module Prism
end
end
+ def test_range_and_bin_op
+ sources = <<~RUBY.lines
+ 1..2..3
+ 1..2..
+ 1.. || 2
+ 1.. & 2
+ 1.. * 2
+ 1.. / 2
+ 1.. % 2
+ 1.. ** 2
+ RUBY
+ sources.each do |source|
+ assert_nil Ripper.sexp_raw(source)
+ assert_false(Prism.parse(source).success?)
+ end
+ end
+
def test_constant_assignment_in_method
source = 'def foo();A=1;end'
assert_errors expression(source), source, [
diff --git a/test/prism/fixtures/ranges.txt b/test/prism/fixtures/ranges.txt
index c9bfe50399..e2e4136ae9 100644
--- a/test/prism/fixtures/ranges.txt
+++ b/test/prism/fixtures/ranges.txt
@@ -17,3 +17,33 @@ foo[...2]
(1..)
1 .. ..1
+
+1.. && 2
+
+1.. == 2
+
+1.. != 2
+
+1.. === 2
+
+1.. <=> 2
+
+1.. =~ 2
+
+1.. !~ 2
+
+1.. < 2
+
+1.. > 2
+
+1.. <= 2
+
+1.. >= 2
+
+1.. << 2
+
+1.. >> 2
+
+1.. + 2
+
+1.. - 2
diff --git a/test/prism/snapshots/ranges.txt b/test/prism/snapshots/ranges.txt
index 471efc49a7..c9dbf26022 100644
--- a/test/prism/snapshots/ranges.txt
+++ b/test/prism/snapshots/ranges.txt
@@ -1,8 +1,8 @@
-@ ProgramNode (location: (1,0)-(19,8))
+@ ProgramNode (location: (1,0)-(49,7))
├── locals: []
└── statements:
- @ StatementsNode (location: (1,0)-(19,8))
- └── body: (length: 10)
+ @ StatementsNode (location: (1,0)-(49,7))
+ └── body: (length: 25)
├── @ ParenthesesNode (location: (1,0)-(1,6))
│ ├── body:
│ │ @ StatementsNode (location: (1,1)-(1,5))
@@ -161,17 +161,332 @@
│ │ └── operator_loc: (17,2)-(17,4) = ".."
│ ├── opening_loc: (17,0)-(17,1) = "("
│ └── closing_loc: (17,4)-(17,5) = ")"
- └── @ RangeNode (location: (19,0)-(19,8))
+ ├── @ RangeNode (location: (19,0)-(19,8))
+ │ ├── flags: ∅
+ │ ├── left:
+ │ │ @ IntegerNode (location: (19,0)-(19,1))
+ │ │ └── flags: decimal
+ │ ├── right:
+ │ │ @ RangeNode (location: (19,5)-(19,8))
+ │ │ ├── flags: ∅
+ │ │ ├── left: ∅
+ │ │ ├── right:
+ │ │ │ @ IntegerNode (location: (19,7)-(19,8))
+ │ │ │ └── flags: decimal
+ │ │ └── operator_loc: (19,5)-(19,7) = ".."
+ │ └── operator_loc: (19,2)-(19,4) = ".."
+ ├── @ AndNode (location: (21,0)-(21,8))
+ │ ├── left:
+ │ │ @ RangeNode (location: (21,0)-(21,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (21,0)-(21,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (21,1)-(21,3) = ".."
+ │ ├── right:
+ │ │ @ IntegerNode (location: (21,7)-(21,8))
+ │ │ └── flags: decimal
+ │ └── operator_loc: (21,4)-(21,6) = "&&"
+ ├── @ CallNode (location: (23,0)-(23,8))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (23,0)-(23,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (23,0)-(23,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (23,1)-(23,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :==
+ │ ├── message_loc: (23,4)-(23,6) = "=="
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (23,7)-(23,8))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (23,7)-(23,8))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (25,0)-(25,8))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (25,0)-(25,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (25,0)-(25,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (25,1)-(25,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :!=
+ │ ├── message_loc: (25,4)-(25,6) = "!="
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (25,7)-(25,8))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (25,7)-(25,8))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (27,0)-(27,9))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (27,0)-(27,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (27,0)-(27,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (27,1)-(27,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :===
+ │ ├── message_loc: (27,4)-(27,7) = "==="
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (27,8)-(27,9))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (27,8)-(27,9))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (29,0)-(29,9))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (29,0)-(29,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (29,0)-(29,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (29,1)-(29,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :<=>
+ │ ├── message_loc: (29,4)-(29,7) = "<=>"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (29,8)-(29,9))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (29,8)-(29,9))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (31,0)-(31,8))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (31,0)-(31,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (31,0)-(31,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (31,1)-(31,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :=~
+ │ ├── message_loc: (31,4)-(31,6) = "=~"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (31,7)-(31,8))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (31,7)-(31,8))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (33,0)-(33,8))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (33,0)-(33,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (33,0)-(33,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (33,1)-(33,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :!~
+ │ ├── message_loc: (33,4)-(33,6) = "!~"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (33,7)-(33,8))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (33,7)-(33,8))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (35,0)-(35,7))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (35,0)-(35,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (35,0)-(35,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (35,1)-(35,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :<
+ │ ├── message_loc: (35,4)-(35,5) = "<"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (35,6)-(35,7))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (35,6)-(35,7))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (37,0)-(37,7))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (37,0)-(37,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (37,0)-(37,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (37,1)-(37,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :>
+ │ ├── message_loc: (37,4)-(37,5) = ">"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (37,6)-(37,7))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (37,6)-(37,7))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (39,0)-(39,8))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (39,0)-(39,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (39,0)-(39,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (39,1)-(39,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :<=
+ │ ├── message_loc: (39,4)-(39,6) = "<="
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (39,7)-(39,8))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (39,7)-(39,8))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (41,0)-(41,8))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (41,0)-(41,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (41,0)-(41,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (41,1)-(41,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :>=
+ │ ├── message_loc: (41,4)-(41,6) = ">="
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (41,7)-(41,8))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (41,7)-(41,8))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (43,0)-(43,8))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (43,0)-(43,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (43,0)-(43,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (43,1)-(43,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :<<
+ │ ├── message_loc: (43,4)-(43,6) = "<<"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (43,7)-(43,8))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (43,7)-(43,8))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CallNode (location: (45,0)-(45,8))
+ │ ├── flags: ∅
+ │ ├── receiver:
+ │ │ @ RangeNode (location: (45,0)-(45,3))
+ │ │ ├── flags: ∅
+ │ │ ├── left:
+ │ │ │ @ IntegerNode (location: (45,0)-(45,1))
+ │ │ │ └── flags: decimal
+ │ │ ├── right: ∅
+ │ │ └── operator_loc: (45,1)-(45,3) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :>>
+ │ ├── message_loc: (45,4)-(45,6) = ">>"
+ │ ├── opening_loc: ∅
+ │ ├── arguments:
+ │ │ @ ArgumentsNode (location: (45,7)-(45,8))
+ │ │ ├── flags: ∅
+ │ │ └── arguments: (length: 1)
+ │ │ └── @ IntegerNode (location: (45,7)-(45,8))
+ │ │ └── flags: decimal
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ RangeNode (location: (47,0)-(47,7))
+ │ ├── flags: ∅
+ │ ├── left:
+ │ │ @ IntegerNode (location: (47,0)-(47,1))
+ │ │ └── flags: decimal
+ │ ├── right:
+ │ │ @ CallNode (location: (47,4)-(47,7))
+ │ │ ├── flags: ∅
+ │ │ ├── receiver:
+ │ │ │ @ IntegerNode (location: (47,6)-(47,7))
+ │ │ │ └── flags: decimal
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── name: :+@
+ │ │ ├── message_loc: (47,4)-(47,5) = "+"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ └── block: ∅
+ │ └── operator_loc: (47,1)-(47,3) = ".."
+ └── @ RangeNode (location: (49,0)-(49,7))
├── flags: ∅
├── left:
- │ @ IntegerNode (location: (19,0)-(19,1))
+ │ @ IntegerNode (location: (49,0)-(49,1))
│ └── flags: decimal
├── right:
- │ @ RangeNode (location: (19,5)-(19,8))
+ │ @ CallNode (location: (49,4)-(49,7))
│ ├── flags: ∅
- │ ├── left: ∅
- │ ├── right:
- │ │ @ IntegerNode (location: (19,7)-(19,8))
+ │ ├── receiver:
+ │ │ @ IntegerNode (location: (49,6)-(49,7))
│ │ └── flags: decimal
- │ └── operator_loc: (19,5)-(19,7) = ".."
- └── operator_loc: (19,2)-(19,4) = ".."
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :-@
+ │ ├── message_loc: (49,4)-(49,5) = "-"
+ │ ├── opening_loc: ∅
+ │ ├── arguments: ∅
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ └── operator_loc: (49,1)-(49,3) = ".."