summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTSUYUSATO Kitsune <make.just.on@gmail.com>2023-11-11 14:44:47 +0900
committergit <svn-admin@ruby-lang.org>2023-11-11 20:37:28 +0000
commitcd91e8e73afa36961674ac55960bb45d53052607 (patch)
tree1ecb79f42be2d7ce2d8319fd1ecb2b5752db1601
parent64f03460bae489b94684c6b0aa16e5a19e06f836 (diff)
[ruby/prism] Introduce non-associativility to `in` and `=>`
Fix https://github.com/ruby/prism/pull/1596 Fix https://github.com/ruby/prism/pull/1771 Close https://github.com/ruby/prism/pull/1773 https://github.com/ruby/prism/commit/a3413e5605
-rw-r--r--prism/prism.c40
-rw-r--r--test/prism/fixtures/patterns.txt3
-rw-r--r--test/prism/fixtures/until.txt2
-rw-r--r--test/prism/fixtures/while.txt2
-rw-r--r--test/prism/snapshots/patterns.txt136
-rw-r--r--test/prism/snapshots/until.txt103
-rw-r--r--test/prism/snapshots/while.txt113
7 files changed, 270 insertions, 129 deletions
diff --git a/prism/prism.c b/prism/prism.c
index cbf0d19356..f0a4df7e6b 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -9719,7 +9719,7 @@ parser_lex(pm_parser_t *parser) {
typedef enum {
PM_BINDING_POWER_UNSET = 0, // used to indicate this token cannot be used as an infix operator
PM_BINDING_POWER_STATEMENT = 2,
- PM_BINDING_POWER_MODIFIER = 4, // if unless until while in
+ PM_BINDING_POWER_MODIFIER = 4, // if unless until while
PM_BINDING_POWER_MODIFIER_RESCUE = 6, // rescue
PM_BINDING_POWER_COMPOSITION = 8, // and or
PM_BINDING_POWER_NOT = 10, // not
@@ -9758,34 +9758,44 @@ typedef struct {
/** Whether or not this token can be used as a binary operator. */
bool binary;
+
+ /**
+ * Whether or not this token can be used as non associative binary operator.
+ * Usually, non associative operator can be handled by using the above left
+ * and right binding powers, but some operators (e.g. in and =>) need special
+ * treatment since they do not call parse_expression recursively.
+ */
+ bool nonassoc;
} pm_binding_powers_t;
-#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true }
-#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true }
-#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true }
-#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false }
+#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 RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = {
- // if unless until while in rescue
+ // if unless until while
[PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
[PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
[PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
[PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
- [PM_TOKEN_KEYWORD_IN] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
- // rescue modifier
+ // rescue
[PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = {
PM_BINDING_POWER_ASSIGNMENT,
PM_BINDING_POWER_MODIFIER_RESCUE + 1,
- true
+ true,
+ false
},
// and or
[PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
[PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
- // =>
- [PM_TOKEN_EQUAL_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
+ // => in
+ [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
+ [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
// &&= &= ^= = >>= <<= -= %= |= += /= *= **=
[PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
@@ -9853,7 +9863,7 @@ pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = {
// -@
[PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
- [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX, false },
+ [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX, false, false },
// **
[PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
@@ -16212,6 +16222,12 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, pm_diagn
current_binding_powers.binary
) {
node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right);
+ if (
+ current_binding_powers.nonassoc &&
+ current_binding_powers.right <= pm_binding_powers[parser->current.type].left
+ ) {
+ break;
+ }
}
return node;
diff --git a/test/prism/fixtures/patterns.txt b/test/prism/fixtures/patterns.txt
index e0c5f303cb..9f73e6ecc5 100644
--- a/test/prism/fixtures/patterns.txt
+++ b/test/prism/fixtures/patterns.txt
@@ -190,3 +190,6 @@ foo in A[
value: a
]
]
+
+foo in bar => baz
+foo => bar => baz
diff --git a/test/prism/fixtures/until.txt b/test/prism/fixtures/until.txt
index fa93819e25..7dcb5d495d 100644
--- a/test/prism/fixtures/until.txt
+++ b/test/prism/fixtures/until.txt
@@ -9,3 +9,5 @@ next until true
return until true
foo :a, :b until bar?
+
+foo while bar in baz
diff --git a/test/prism/fixtures/while.txt b/test/prism/fixtures/while.txt
index 66321b5368..eecfbfdddd 100644
--- a/test/prism/fixtures/while.txt
+++ b/test/prism/fixtures/while.txt
@@ -19,3 +19,5 @@ while class << self; tap do end; end; break; end
while class << self; a = tap do end; end; break; end
while def foo = bar do end; end
+
+foo while bar in baz
diff --git a/test/prism/snapshots/patterns.txt b/test/prism/snapshots/patterns.txt
index 0994330e45..d8f4935b96 100644
--- a/test/prism/snapshots/patterns.txt
+++ b/test/prism/snapshots/patterns.txt
@@ -1,8 +1,8 @@
-@ ProgramNode (location: (1,0)-(192,1))
+@ ProgramNode (location: (1,0)-(195,17))
├── locals: [:bar, :baz, :qux, :b, :a]
└── statements:
- @ StatementsNode (location: (1,0)-(192,1))
- └── body: (length: 170)
+ @ StatementsNode (location: (1,0)-(195,17))
+ └── body: (length: 172)
├── @ MatchRequiredNode (location: (1,0)-(1,10))
│ ├── value:
│ │ @ CallNode (location: (1,0)-(1,3))
@@ -4449,12 +4449,87 @@
│ │ ├── opening_loc: (184,5)-(184,6) = "["
│ │ └── closing_loc: (186,0)-(186,1) = "]"
│ └── operator_loc: (184,2)-(184,4) = "=>"
- └── @ MatchPredicateNode (location: (188,0)-(192,1))
+ ├── @ MatchPredicateNode (location: (188,0)-(192,1))
+ │ ├── value:
+ │ │ @ CallNode (location: (188,0)-(188,3))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── message_loc: (188,0)-(188,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ ├── flags: variable_call
+ │ │ └── name: :foo
+ │ ├── pattern:
+ │ │ @ HashPatternNode (location: (188,7)-(192,1))
+ │ │ ├── constant:
+ │ │ │ @ ConstantReadNode (location: (188,7)-(188,8))
+ │ │ │ └── name: :A
+ │ │ ├── elements: (length: 1)
+ │ │ │ └── @ AssocNode (location: (189,2)-(191,3))
+ │ │ │ ├── key:
+ │ │ │ │ @ SymbolNode (location: (189,2)-(189,6))
+ │ │ │ │ ├── opening_loc: ∅
+ │ │ │ │ ├── value_loc: (189,2)-(189,5) = "bar"
+ │ │ │ │ ├── closing_loc: (189,5)-(189,6) = ":"
+ │ │ │ │ └── unescaped: "bar"
+ │ │ │ ├── value:
+ │ │ │ │ @ HashPatternNode (location: (189,7)-(191,3))
+ │ │ │ │ ├── constant:
+ │ │ │ │ │ @ ConstantReadNode (location: (189,7)-(189,8))
+ │ │ │ │ │ └── name: :B
+ │ │ │ │ ├── elements: (length: 1)
+ │ │ │ │ │ └── @ AssocNode (location: (190,4)-(190,12))
+ │ │ │ │ │ ├── key:
+ │ │ │ │ │ │ @ SymbolNode (location: (190,4)-(190,10))
+ │ │ │ │ │ │ ├── opening_loc: ∅
+ │ │ │ │ │ │ ├── value_loc: (190,4)-(190,9) = "value"
+ │ │ │ │ │ │ ├── closing_loc: (190,9)-(190,10) = ":"
+ │ │ │ │ │ │ └── unescaped: "value"
+ │ │ │ │ │ ├── value:
+ │ │ │ │ │ │ @ LocalVariableTargetNode (location: (190,11)-(190,12))
+ │ │ │ │ │ │ ├── name: :a
+ │ │ │ │ │ │ └── depth: 0
+ │ │ │ │ │ └── operator_loc: ∅
+ │ │ │ │ ├── rest: ∅
+ │ │ │ │ ├── opening_loc: (189,8)-(189,9) = "["
+ │ │ │ │ └── closing_loc: (191,2)-(191,3) = "]"
+ │ │ │ └── operator_loc: ∅
+ │ │ ├── rest: ∅
+ │ │ ├── opening_loc: (188,8)-(188,9) = "["
+ │ │ └── closing_loc: (192,0)-(192,1) = "]"
+ │ └── operator_loc: (188,4)-(188,6) = "in"
+ ├── @ MatchPredicateNode (location: (194,0)-(194,17))
+ │ ├── value:
+ │ │ @ CallNode (location: (194,0)-(194,3))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── message_loc: (194,0)-(194,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ ├── flags: variable_call
+ │ │ └── name: :foo
+ │ ├── pattern:
+ │ │ @ CapturePatternNode (location: (194,7)-(194,17))
+ │ │ ├── value:
+ │ │ │ @ LocalVariableTargetNode (location: (194,7)-(194,10))
+ │ │ │ ├── name: :bar
+ │ │ │ └── depth: 0
+ │ │ ├── target:
+ │ │ │ @ LocalVariableTargetNode (location: (194,14)-(194,17))
+ │ │ │ ├── name: :baz
+ │ │ │ └── depth: 0
+ │ │ └── operator_loc: (194,11)-(194,13) = "=>"
+ │ └── operator_loc: (194,4)-(194,6) = "in"
+ └── @ MatchRequiredNode (location: (195,0)-(195,17))
├── value:
- │ @ CallNode (location: (188,0)-(188,3))
+ │ @ CallNode (location: (195,0)-(195,3))
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
- │ ├── message_loc: (188,0)-(188,3) = "foo"
+ │ ├── message_loc: (195,0)-(195,3) = "foo"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
@@ -4462,41 +4537,14 @@
│ ├── flags: variable_call
│ └── name: :foo
├── pattern:
- │ @ HashPatternNode (location: (188,7)-(192,1))
- │ ├── constant:
- │ │ @ ConstantReadNode (location: (188,7)-(188,8))
- │ │ └── name: :A
- │ ├── elements: (length: 1)
- │ │ └── @ AssocNode (location: (189,2)-(191,3))
- │ │ ├── key:
- │ │ │ @ SymbolNode (location: (189,2)-(189,6))
- │ │ │ ├── opening_loc: ∅
- │ │ │ ├── value_loc: (189,2)-(189,5) = "bar"
- │ │ │ ├── closing_loc: (189,5)-(189,6) = ":"
- │ │ │ └── unescaped: "bar"
- │ │ ├── value:
- │ │ │ @ HashPatternNode (location: (189,7)-(191,3))
- │ │ │ ├── constant:
- │ │ │ │ @ ConstantReadNode (location: (189,7)-(189,8))
- │ │ │ │ └── name: :B
- │ │ │ ├── elements: (length: 1)
- │ │ │ │ └── @ AssocNode (location: (190,4)-(190,12))
- │ │ │ │ ├── key:
- │ │ │ │ │ @ SymbolNode (location: (190,4)-(190,10))
- │ │ │ │ │ ├── opening_loc: ∅
- │ │ │ │ │ ├── value_loc: (190,4)-(190,9) = "value"
- │ │ │ │ │ ├── closing_loc: (190,9)-(190,10) = ":"
- │ │ │ │ │ └── unescaped: "value"
- │ │ │ │ ├── value:
- │ │ │ │ │ @ LocalVariableTargetNode (location: (190,11)-(190,12))
- │ │ │ │ │ ├── name: :a
- │ │ │ │ │ └── depth: 0
- │ │ │ │ └── operator_loc: ∅
- │ │ │ ├── rest: ∅
- │ │ │ ├── opening_loc: (189,8)-(189,9) = "["
- │ │ │ └── closing_loc: (191,2)-(191,3) = "]"
- │ │ └── operator_loc: ∅
- │ ├── rest: ∅
- │ ├── opening_loc: (188,8)-(188,9) = "["
- │ └── closing_loc: (192,0)-(192,1) = "]"
- └── operator_loc: (188,4)-(188,6) = "in"
+ │ @ CapturePatternNode (location: (195,7)-(195,17))
+ │ ├── value:
+ │ │ @ LocalVariableTargetNode (location: (195,7)-(195,10))
+ │ │ ├── name: :bar
+ │ │ └── depth: 0
+ │ ├── target:
+ │ │ @ LocalVariableTargetNode (location: (195,14)-(195,17))
+ │ │ ├── name: :baz
+ │ │ └── depth: 0
+ │ └── operator_loc: (195,11)-(195,13) = "=>"
+ └── operator_loc: (195,4)-(195,6) = "=>"
diff --git a/test/prism/snapshots/until.txt b/test/prism/snapshots/until.txt
index d2fa6b7a52..7e741603db 100644
--- a/test/prism/snapshots/until.txt
+++ b/test/prism/snapshots/until.txt
@@ -1,8 +1,8 @@
-@ ProgramNode (location: (1,0)-(11,21))
-├── locals: []
+@ ProgramNode (location: (1,0)-(13,20))
+├── locals: [:baz]
└── statements:
- @ StatementsNode (location: (1,0)-(11,21))
- └── body: (length: 6)
+ @ StatementsNode (location: (1,0)-(13,20))
+ └── body: (length: 7)
├── @ UntilNode (location: (1,0)-(1,18))
│ ├── keyword_loc: (1,0)-(1,5) = "until"
│ ├── closing_loc: (1,15)-(1,18) = "end"
@@ -61,44 +61,79 @@
│ │ ├── keyword_loc: (9,0)-(9,6) = "return"
│ │ └── arguments: ∅
│ └── flags: ∅
- └── @ UntilNode (location: (11,0)-(11,21))
- ├── keyword_loc: (11,11)-(11,16) = "until"
+ ├── @ UntilNode (location: (11,0)-(11,21))
+ │ ├── keyword_loc: (11,11)-(11,16) = "until"
+ │ ├── closing_loc: ∅
+ │ ├── predicate:
+ │ │ @ CallNode (location: (11,17)-(11,21))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── message_loc: (11,17)-(11,21) = "bar?"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ ├── flags: ∅
+ │ │ └── name: :bar?
+ │ ├── statements:
+ │ │ @ StatementsNode (location: (11,0)-(11,10))
+ │ │ └── body: (length: 1)
+ │ │ └── @ CallNode (location: (11,0)-(11,10))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── message_loc: (11,0)-(11,3) = "foo"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments:
+ │ │ │ @ ArgumentsNode (location: (11,4)-(11,10))
+ │ │ │ ├── arguments: (length: 2)
+ │ │ │ │ ├── @ SymbolNode (location: (11,4)-(11,6))
+ │ │ │ │ │ ├── opening_loc: (11,4)-(11,5) = ":"
+ │ │ │ │ │ ├── value_loc: (11,5)-(11,6) = "a"
+ │ │ │ │ │ ├── closing_loc: ∅
+ │ │ │ │ │ └── unescaped: "a"
+ │ │ │ │ └── @ SymbolNode (location: (11,8)-(11,10))
+ │ │ │ │ ├── opening_loc: (11,8)-(11,9) = ":"
+ │ │ │ │ ├── value_loc: (11,9)-(11,10) = "b"
+ │ │ │ │ ├── closing_loc: ∅
+ │ │ │ │ └── unescaped: "b"
+ │ │ │ └── flags: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ ├── flags: ∅
+ │ │ └── name: :foo
+ │ └── flags: ∅
+ └── @ WhileNode (location: (13,0)-(13,20))
+ ├── keyword_loc: (13,4)-(13,9) = "while"
├── closing_loc: ∅
├── predicate:
- │ @ CallNode (location: (11,17)-(11,21))
- │ ├── receiver: ∅
- │ ├── call_operator_loc: ∅
- │ ├── message_loc: (11,17)-(11,21) = "bar?"
- │ ├── opening_loc: ∅
- │ ├── arguments: ∅
- │ ├── closing_loc: ∅
- │ ├── block: ∅
- │ ├── flags: ∅
- │ └── name: :bar?
+ │ @ MatchPredicateNode (location: (13,10)-(13,20))
+ │ ├── value:
+ │ │ @ CallNode (location: (13,10)-(13,13))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── message_loc: (13,10)-(13,13) = "bar"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ ├── flags: variable_call
+ │ │ └── name: :bar
+ │ ├── pattern:
+ │ │ @ LocalVariableTargetNode (location: (13,17)-(13,20))
+ │ │ ├── name: :baz
+ │ │ └── depth: 0
+ │ └── operator_loc: (13,14)-(13,16) = "in"
├── statements:
- │ @ StatementsNode (location: (11,0)-(11,10))
+ │ @ StatementsNode (location: (13,0)-(13,3))
│ └── body: (length: 1)
- │ └── @ CallNode (location: (11,0)-(11,10))
+ │ └── @ CallNode (location: (13,0)-(13,3))
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
- │ ├── message_loc: (11,0)-(11,3) = "foo"
+ │ ├── message_loc: (13,0)-(13,3) = "foo"
│ ├── opening_loc: ∅
- │ ├── arguments:
- │ │ @ ArgumentsNode (location: (11,4)-(11,10))
- │ │ ├── arguments: (length: 2)
- │ │ │ ├── @ SymbolNode (location: (11,4)-(11,6))
- │ │ │ │ ├── opening_loc: (11,4)-(11,5) = ":"
- │ │ │ │ ├── value_loc: (11,5)-(11,6) = "a"
- │ │ │ │ ├── closing_loc: ∅
- │ │ │ │ └── unescaped: "a"
- │ │ │ └── @ SymbolNode (location: (11,8)-(11,10))
- │ │ │ ├── opening_loc: (11,8)-(11,9) = ":"
- │ │ │ ├── value_loc: (11,9)-(11,10) = "b"
- │ │ │ ├── closing_loc: ∅
- │ │ │ └── unescaped: "b"
- │ │ └── flags: ∅
+ │ ├── arguments: ∅
│ ├── closing_loc: ∅
│ ├── block: ∅
- │ ├── flags: ∅
+ │ ├── flags: variable_call
│ └── name: :foo
└── flags: ∅
diff --git a/test/prism/snapshots/while.txt b/test/prism/snapshots/while.txt
index 0fdcfe10c1..58cbac8ba5 100644
--- a/test/prism/snapshots/while.txt
+++ b/test/prism/snapshots/while.txt
@@ -1,8 +1,8 @@
-@ ProgramNode (location: (1,0)-(21,31))
-├── locals: []
+@ ProgramNode (location: (1,0)-(23,20))
+├── locals: [:baz]
└── statements:
- @ StatementsNode (location: (1,0)-(21,31))
- └── body: (length: 11)
+ @ StatementsNode (location: (1,0)-(23,20))
+ └── body: (length: 12)
├── @ WhileNode (location: (1,0)-(1,18))
│ ├── keyword_loc: (1,0)-(1,5) = "while"
│ ├── closing_loc: (1,15)-(1,18) = "end"
@@ -282,40 +282,75 @@
│ │ ├── arguments: ∅
│ │ └── keyword_loc: (19,42)-(19,47) = "break"
│ └── flags: ∅
- └── @ WhileNode (location: (21,0)-(21,31))
- ├── keyword_loc: (21,0)-(21,5) = "while"
- ├── closing_loc: (21,28)-(21,31) = "end"
+ ├── @ WhileNode (location: (21,0)-(21,31))
+ │ ├── keyword_loc: (21,0)-(21,5) = "while"
+ │ ├── closing_loc: (21,28)-(21,31) = "end"
+ │ ├── predicate:
+ │ │ @ DefNode (location: (21,6)-(21,26))
+ │ │ ├── name: :foo
+ │ │ ├── name_loc: (21,10)-(21,13) = "foo"
+ │ │ ├── receiver: ∅
+ │ │ ├── parameters: ∅
+ │ │ ├── body:
+ │ │ │ @ StatementsNode (location: (21,16)-(21,26))
+ │ │ │ └── body: (length: 1)
+ │ │ │ └── @ CallNode (location: (21,16)-(21,26))
+ │ │ │ ├── receiver: ∅
+ │ │ │ ├── call_operator_loc: ∅
+ │ │ │ ├── message_loc: (21,16)-(21,19) = "bar"
+ │ │ │ ├── opening_loc: ∅
+ │ │ │ ├── arguments: ∅
+ │ │ │ ├── closing_loc: ∅
+ │ │ │ ├── block:
+ │ │ │ │ @ BlockNode (location: (21,20)-(21,26))
+ │ │ │ │ ├── locals: []
+ │ │ │ │ ├── parameters: ∅
+ │ │ │ │ ├── body: ∅
+ │ │ │ │ ├── opening_loc: (21,20)-(21,22) = "do"
+ │ │ │ │ └── closing_loc: (21,23)-(21,26) = "end"
+ │ │ │ ├── flags: ∅
+ │ │ │ └── name: :bar
+ │ │ ├── locals: []
+ │ │ ├── def_keyword_loc: (21,6)-(21,9) = "def"
+ │ │ ├── operator_loc: ∅
+ │ │ ├── lparen_loc: ∅
+ │ │ ├── rparen_loc: ∅
+ │ │ ├── equal_loc: (21,14)-(21,15) = "="
+ │ │ └── end_keyword_loc: ∅
+ │ ├── statements: ∅
+ │ └── flags: ∅
+ └── @ WhileNode (location: (23,0)-(23,20))
+ ├── keyword_loc: (23,4)-(23,9) = "while"
+ ├── closing_loc: ∅
├── predicate:
- │ @ DefNode (location: (21,6)-(21,26))
- │ ├── name: :foo
- │ ├── name_loc: (21,10)-(21,13) = "foo"
- │ ├── receiver: ∅
- │ ├── parameters: ∅
- │ ├── body:
- │ │ @ StatementsNode (location: (21,16)-(21,26))
- │ │ └── body: (length: 1)
- │ │ └── @ CallNode (location: (21,16)-(21,26))
- │ │ ├── receiver: ∅
- │ │ ├── call_operator_loc: ∅
- │ │ ├── message_loc: (21,16)-(21,19) = "bar"
- │ │ ├── opening_loc: ∅
- │ │ ├── arguments: ∅
- │ │ ├── closing_loc: ∅
- │ │ ├── block:
- │ │ │ @ BlockNode (location: (21,20)-(21,26))
- │ │ │ ├── locals: []
- │ │ │ ├── parameters: ∅
- │ │ │ ├── body: ∅
- │ │ │ ├── opening_loc: (21,20)-(21,22) = "do"
- │ │ │ └── closing_loc: (21,23)-(21,26) = "end"
- │ │ ├── flags: ∅
- │ │ └── name: :bar
- │ ├── locals: []
- │ ├── def_keyword_loc: (21,6)-(21,9) = "def"
- │ ├── operator_loc: ∅
- │ ├── lparen_loc: ∅
- │ ├── rparen_loc: ∅
- │ ├── equal_loc: (21,14)-(21,15) = "="
- │ └── end_keyword_loc: ∅
- ├── statements: ∅
+ │ @ MatchPredicateNode (location: (23,10)-(23,20))
+ │ ├── value:
+ │ │ @ CallNode (location: (23,10)-(23,13))
+ │ │ ├── receiver: ∅
+ │ │ ├── call_operator_loc: ∅
+ │ │ ├── message_loc: (23,10)-(23,13) = "bar"
+ │ │ ├── opening_loc: ∅
+ │ │ ├── arguments: ∅
+ │ │ ├── closing_loc: ∅
+ │ │ ├── block: ∅
+ │ │ ├── flags: variable_call
+ │ │ └── name: :bar
+ │ ├── pattern:
+ │ │ @ LocalVariableTargetNode (location: (23,17)-(23,20))
+ │ │ ├── name: :baz
+ │ │ └── depth: 0
+ │ └── operator_loc: (23,14)-(23,16) = "in"
+ ├── statements:
+ │ @ StatementsNode (location: (23,0)-(23,3))
+ │ └── body: (length: 1)
+ │ └── @ CallNode (location: (23,0)-(23,3))
+ │ ├── receiver: ∅
+ │ ├── call_operator_loc: ∅
+ │ ├── message_loc: (23,0)-(23,3) = "foo"
+ │ ├── opening_loc: ∅
+ │ ├── arguments: ∅
+ │ ├── closing_loc: ∅
+ │ ├── block: ∅
+ │ ├── flags: variable_call
+ │ └── name: :foo
└── flags: ∅