TSUYUSATO Kitsune 2023-11-11 14:44:47 +09:00 committed by git
parent 64f03460ba
commit cd91e8e73a
7 changed files with 270 additions and 129 deletions

View File

@ -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;

View File

@ -190,3 +190,6 @@ foo in A[
value: a
]
]
foo in bar => baz
foo => bar => baz

View File

@ -9,3 +9,5 @@ next until true
return until true
foo :a, :b until bar?
foo while bar in baz

View File

@ -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

View File

@ -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) = "=>"

View File

@ -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: ∅

View File

@ -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: ∅