summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTSUYUSATO Kitsune <make.just.on@gmail.com>2023-11-29 10:32:26 +0900
committergit <svn-admin@ruby-lang.org>2023-11-29 02:03:06 +0000
commita908cef53f4c647c7fe7c9e808b501c3bb3cc70f (patch)
tree5bcade9747f23bde3587ee114c4611800f82cecc
parentfcabe2df39b892458cb1f67437852c4acbb245a6 (diff)
[ruby/prism] Reject class/module defs in method params/rescue/ensure/else
Fix https://github.com/ruby/prism/pull/1936 https://github.com/ruby/prism/commit/232e77a003
-rw-r--r--prism/diagnostic.c4
-rw-r--r--prism/parser.h9
-rw-r--r--prism/prism.c43
-rw-r--r--test/prism/errors_test.rb34
-rw-r--r--test/prism/fixtures/methods.txt2
-rw-r--r--test/prism/snapshots/methods.txt153
6 files changed, 174 insertions, 71 deletions
diff --git a/prism/diagnostic.c b/prism/diagnostic.c
index e2181151c2..443ad35c6a 100644
--- a/prism/diagnostic.c
+++ b/prism/diagnostic.c
@@ -90,7 +90,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
[PM_ERR_CASE_MATCH_MISSING_PREDICATE] = "expected a predicate for a case matching statement",
[PM_ERR_CASE_MISSING_CONDITIONS] = "expected a `when` or `in` clause after `case`",
[PM_ERR_CASE_TERM] = "expected an `end` to close the `case` statement",
- [PM_ERR_CLASS_IN_METHOD] = "unexpected class definition in a method body",
+ [PM_ERR_CLASS_IN_METHOD] = "unexpected class definition in a method definition",
[PM_ERR_CLASS_NAME] = "expected a constant name after `class`",
[PM_ERR_CLASS_SUPERCLASS] = "expected a superclass after `<`",
[PM_ERR_CLASS_TERM] = "expected an `end` to close the `class` statement",
@@ -185,7 +185,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
[PM_ERR_LIST_W_UPPER_ELEMENT] = "expected a string in a `%W` list",
[PM_ERR_LIST_W_UPPER_TERM] = "expected a closing delimiter for the `%W` list",
[PM_ERR_MALLOC_FAILED] = "failed to allocate memory",
- [PM_ERR_MODULE_IN_METHOD] = "unexpected module definition in a method body",
+ [PM_ERR_MODULE_IN_METHOD] = "unexpected module definition in a method definition",
[PM_ERR_MODULE_NAME] = "expected a constant name after `module`",
[PM_ERR_MODULE_TERM] = "expected an `end` to close the `module` statement",
[PM_ERR_MULTI_ASSIGN_MULTI_SPLATS] = "multiple splats in multiple assignment",
diff --git a/prism/parser.h b/prism/parser.h
index fec1036229..c1f9e0f663 100644
--- a/prism/parser.h
+++ b/prism/parser.h
@@ -297,6 +297,9 @@ typedef enum {
/** an ensure statement */
PM_CONTEXT_ENSURE,
+ /** an ensure statement within a method definition */
+ PM_CONTEXT_ENSURE_DEF,
+
/** a for loop */
PM_CONTEXT_FOR,
@@ -333,9 +336,15 @@ typedef enum {
/** a rescue else statement */
PM_CONTEXT_RESCUE_ELSE,
+ /** a rescue else statement within a method definition */
+ PM_CONTEXT_RESCUE_ELSE_DEF,
+
/** a rescue statement */
PM_CONTEXT_RESCUE,
+ /** a rescue statement within a method definition */
+ PM_CONTEXT_RESCUE_DEF,
+
/** a singleton class definition */
PM_CONTEXT_SCLASS,
diff --git a/prism/prism.c b/prism/prism.c
index 03b6204a78..41ed44e9c1 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -6603,6 +6603,7 @@ context_terminator(pm_context_t context, pm_token_t *token) {
case PM_CONTEXT_ELSE:
case PM_CONTEXT_FOR:
case PM_CONTEXT_ENSURE:
+ case PM_CONTEXT_ENSURE_DEF:
return token->type == PM_TOKEN_KEYWORD_END;
case PM_CONTEXT_FOR_INDEX:
return token->type == PM_TOKEN_KEYWORD_IN;
@@ -6623,8 +6624,10 @@ context_terminator(pm_context_t context, pm_token_t *token) {
return token->type == PM_TOKEN_PARENTHESIS_RIGHT;
case PM_CONTEXT_BEGIN:
case PM_CONTEXT_RESCUE:
+ case PM_CONTEXT_RESCUE_DEF:
return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END;
case PM_CONTEXT_RESCUE_ELSE:
+ case PM_CONTEXT_RESCUE_ELSE_DEF:
return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_END;
case PM_CONTEXT_LAMBDA_BRACES:
return token->type == PM_TOKEN_BRACE_RIGHT;
@@ -6690,6 +6693,10 @@ context_def_p(pm_parser_t *parser) {
while (context_node != NULL) {
switch (context_node->context) {
case PM_CONTEXT_DEF:
+ case PM_CONTEXT_DEF_PARAMS:
+ case PM_CONTEXT_ENSURE_DEF:
+ case PM_CONTEXT_RESCUE_DEF:
+ case PM_CONTEXT_RESCUE_ELSE_DEF:
return true;
case PM_CONTEXT_CLASS:
case PM_CONTEXT_MODULE:
@@ -11837,7 +11844,7 @@ parse_parameters(
* nodes pointing to each other from the top.
*/
static inline void
-parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) {
+parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) {
pm_rescue_node_t *current = NULL;
while (accept1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
@@ -11900,7 +11907,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) {
if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
pm_accepts_block_stack_push(parser, true);
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_RESCUE);
+ pm_statements_node_t *statements = parse_statements(parser, def_p ? PM_CONTEXT_RESCUE_DEF : PM_CONTEXT_RESCUE);
if (statements) {
pm_rescue_node_statements_set(rescue, statements);
}
@@ -11936,7 +11943,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) {
pm_statements_node_t *else_statements = NULL;
if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
pm_accepts_block_stack_push(parser, true);
- else_statements = parse_statements(parser, PM_CONTEXT_RESCUE_ELSE);
+ else_statements = parse_statements(parser, def_p ? PM_CONTEXT_RESCUE_ELSE_DEF : PM_CONTEXT_RESCUE_ELSE);
pm_accepts_block_stack_pop(parser);
accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
}
@@ -11952,7 +11959,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) {
pm_statements_node_t *ensure_statements = NULL;
if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
pm_accepts_block_stack_push(parser, true);
- ensure_statements = parse_statements(parser, PM_CONTEXT_ENSURE);
+ ensure_statements = parse_statements(parser, def_p ? PM_CONTEXT_ENSURE_DEF : PM_CONTEXT_ENSURE);
pm_accepts_block_stack_pop(parser);
accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
}
@@ -11970,10 +11977,10 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node) {
}
static inline pm_begin_node_t *
-parse_rescues_as_begin(pm_parser_t *parser, pm_statements_node_t *statements) {
+parse_rescues_as_begin(pm_parser_t *parser, pm_statements_node_t *statements, bool def_p) {
pm_token_t no_begin_token = not_provided(parser);
pm_begin_node_t *begin_node = pm_begin_node_create(parser, &no_begin_token, statements);
- parse_rescues(parser, begin_node);
+ parse_rescues(parser, begin_node, def_p);
// All nodes within a begin node are optional, so we look
// for the earliest possible node that we can use to set
@@ -12078,7 +12085,7 @@ parse_block(pm_parser_t *parser) {
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
}
}
@@ -14547,7 +14554,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
}
pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
- parse_rescues(parser, begin_node);
+ parse_rescues(parser, begin_node, false);
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
begin_node->base.location.end = parser->previous.end;
@@ -14665,7 +14672,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
}
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
@@ -14717,7 +14724,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
}
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
@@ -14744,6 +14751,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_token_t operator = not_provided(parser);
pm_token_t name = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = def_keyword.end, .end = def_keyword.end };
+ // This context is necessary for lexing `...` in a bare params correctly.
+ // It must be pushed before lexing the first param, so it is here.
context_push(parser, PM_CONTEXT_DEF_PARAMS);
parser_lex(parser);
pm_constant_id_t old_param_name = parser->current_param_name;
@@ -14844,7 +14853,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
break;
}
case PM_TOKEN_PARENTHESIS_LEFT: {
+ // The current context is `PM_CONTEXT_DEF_PARAMS`, however the inner expression
+ // of this parenthesis should not be processed under this context.
+ // Thus, the context is popped here.
+ context_pop(parser);
parser_lex(parser);
+
pm_token_t lparen = parser->previous;
pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, PM_ERR_DEF_RECEIVER);
@@ -14859,6 +14873,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
pm_parser_scope_push(parser, true);
parser->current_param_name = 0;
+
+ // To push `PM_CONTEXT_DEF_PARAMS` again is for the same reason as described the above.
+ context_push(parser, PM_CONTEXT_DEF_PARAMS);
name = parse_method_definition_name(parser);
break;
}
@@ -14967,7 +14984,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, true);
}
pm_accepts_block_stack_pop(parser);
@@ -15222,7 +15239,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements);
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
}
pm_constant_id_list_t locals = parser->current_scope->locals;
@@ -15893,7 +15910,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
- body = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) body);
+ body = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) body, false);
}
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index 871caa7475..4b745d31f8 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -428,7 +428,7 @@ module Prism
)
assert_errors expected, "def foo;module A;end;end", [
- ["unexpected module definition in a method body", 8..14]
+ ["unexpected module definition in a method definition", 8..14]
]
end
@@ -467,7 +467,7 @@ module Prism
Location()
)
- assert_errors expected, <<~RUBY, [["unexpected module definition in a method body", 21..27]]
+ assert_errors expected, <<~RUBY, [["unexpected module definition in a method definition", 21..27]]
def foo
bar do
module Foo;end
@@ -476,6 +476,20 @@ module Prism
RUBY
end
+ def test_module_definition_in_method_defs
+ source = <<~RUBY
+ def foo(bar = module A;end);end
+ def foo;rescue;module A;end;end
+ def foo;ensure;module A;end;end
+ RUBY
+ message = "unexpected module definition in a method definition"
+ assert_errors expression(source), source, [
+ [message, 14..20],
+ [message, 47..53],
+ [message, 79..85],
+ ]
+ end
+
def test_class_definition_in_method_body
expected = DefNode(
:foo,
@@ -504,7 +518,21 @@ module Prism
)
assert_errors expected, "def foo;class A;end;end", [
- ["unexpected class definition in a method body", 8..13]
+ ["unexpected class definition in a method definition", 8..13]
+ ]
+ end
+
+ def test_class_definition_in_method_defs
+ source = <<~RUBY
+ def foo(bar = class A;end);end
+ def foo;rescue;class A;end;end
+ def foo;ensure;class A;end;end
+ RUBY
+ message = "unexpected class definition in a method definition"
+ assert_errors expression(source), source, [
+ [message, 14..19],
+ [message, 46..51],
+ [message, 77..82],
]
end
diff --git a/test/prism/fixtures/methods.txt b/test/prism/fixtures/methods.txt
index 3c382d07f0..703527f2de 100644
--- a/test/prism/fixtures/methods.txt
+++ b/test/prism/fixtures/methods.txt
@@ -182,3 +182,5 @@ def foo(...)
end
def foo(bar = (def baz(bar) = bar; 1)) = 2
+
+def (class Foo; end).foo(bar = 1) = 2
diff --git a/test/prism/snapshots/methods.txt b/test/prism/snapshots/methods.txt
index b0981f1202..960264f6a8 100644
--- a/test/prism/snapshots/methods.txt
+++ b/test/prism/snapshots/methods.txt
@@ -1,8 +1,8 @@
-@ ProgramNode (location: (1,0)-(184,42))
+@ ProgramNode (location: (1,0)-(186,37))
├── locals: [:a, :c, :foo]
└── statements:
- @ StatementsNode (location: (1,0)-(184,42))
- └── body: (length: 69)
+ @ StatementsNode (location: (1,0)-(186,37))
+ └── body: (length: 70)
├── @ DefNode (location: (1,0)-(2,3))
│ ├── name: :foo
│ ├── name_loc: (1,4)-(1,7) = "foo"
@@ -1888,69 +1888,116 @@
│ ├── rparen_loc: (180,11)-(180,12) = ")"
│ ├── equal_loc: ∅
│ └── end_keyword_loc: (182,0)-(182,3) = "end"
- └── @ DefNode (location: (184,0)-(184,42))
+ ├── @ DefNode (location: (184,0)-(184,42))
+ │ ├── name: :foo
+ │ ├── name_loc: (184,4)-(184,7) = "foo"
+ │ ├── receiver: ∅
+ │ ├── parameters:
+ │ │ @ ParametersNode (location: (184,8)-(184,37))
+ │ │ ├── requireds: (length: 0)
+ │ │ ├── optionals: (length: 1)
+ │ │ │ └── @ OptionalParameterNode (location: (184,8)-(184,37))
+ │ │ │ ├── name: :bar
+ │ │ │ ├── name_loc: (184,8)-(184,11) = "bar"
+ │ │ │ ├── operator_loc: (184,12)-(184,13) = "="
+ │ │ │ └── value:
+ │ │ │ @ ParenthesesNode (location: (184,14)-(184,37))
+ │ │ │ ├── body:
+ │ │ │ │ @ StatementsNode (location: (184,15)-(184,36))
+ │ │ │ │ └── body: (length: 2)
+ │ │ │ │ ├── @ DefNode (location: (184,15)-(184,33))
+ │ │ │ │ │ ├── name: :baz
+ │ │ │ │ │ ├── name_loc: (184,19)-(184,22) = "baz"
+ │ │ │ │ │ ├── receiver: ∅
+ │ │ │ │ │ ├── parameters:
+ │ │ │ │ │ │ @ ParametersNode (location: (184,23)-(184,26))
+ │ │ │ │ │ │ ├── requireds: (length: 1)
+ │ │ │ │ │ │ │ └── @ RequiredParameterNode (location: (184,23)-(184,26))
+ │ │ │ │ │ │ │ └── name: :bar
+ │ │ │ │ │ │ ├── optionals: (length: 0)
+ │ │ │ │ │ │ ├── rest: ∅
+ │ │ │ │ │ │ ├── posts: (length: 0)
+ │ │ │ │ │ │ ├── keywords: (length: 0)
+ │ │ │ │ │ │ ├── keyword_rest: ∅
+ │ │ │ │ │ │ └── block: ∅
+ │ │ │ │ │ ├── body:
+ │ │ │ │ │ │ @ StatementsNode (location: (184,30)-(184,33))
+ │ │ │ │ │ │ └── body: (length: 1)
+ │ │ │ │ │ │ └── @ LocalVariableReadNode (location: (184,30)-(184,33))
+ │ │ │ │ │ │ ├── name: :bar
+ │ │ │ │ │ │ └── depth: 0
+ │ │ │ │ │ ├── locals: [:bar]
+ │ │ │ │ │ ├── def_keyword_loc: (184,15)-(184,18) = "def"
+ │ │ │ │ │ ├── operator_loc: ∅
+ │ │ │ │ │ ├── lparen_loc: (184,22)-(184,23) = "("
+ │ │ │ │ │ ├── rparen_loc: (184,26)-(184,27) = ")"
+ │ │ │ │ │ ├── equal_loc: (184,28)-(184,29) = "="
+ │ │ │ │ │ └── end_keyword_loc: ∅
+ │ │ │ │ └── @ IntegerNode (location: (184,35)-(184,36))
+ │ │ │ │ └── flags: decimal
+ │ │ │ ├── opening_loc: (184,14)-(184,15) = "("
+ │ │ │ └── closing_loc: (184,36)-(184,37) = ")"
+ │ │ ├── rest: ∅
+ │ │ ├── posts: (length: 0)
+ │ │ ├── keywords: (length: 0)
+ │ │ ├── keyword_rest: ∅
+ │ │ └── block: ∅
+ │ ├── body:
+ │ │ @ StatementsNode (location: (184,41)-(184,42))
+ │ │ └── body: (length: 1)
+ │ │ └── @ IntegerNode (location: (184,41)-(184,42))
+ │ │ └── flags: decimal
+ │ ├── locals: [:bar]
+ │ ├── def_keyword_loc: (184,0)-(184,3) = "def"
+ │ ├── operator_loc: ∅
+ │ ├── lparen_loc: (184,7)-(184,8) = "("
+ │ ├── rparen_loc: (184,37)-(184,38) = ")"
+ │ ├── equal_loc: (184,39)-(184,40) = "="
+ │ └── end_keyword_loc: ∅
+ └── @ DefNode (location: (186,0)-(186,37))
├── name: :foo
- ├── name_loc: (184,4)-(184,7) = "foo"
- ├── receiver: ∅
+ ├── name_loc: (186,21)-(186,24) = "foo"
+ ├── receiver:
+ │ @ ParenthesesNode (location: (186,4)-(186,20))
+ │ ├── body:
+ │ │ @ ClassNode (location: (186,5)-(186,19))
+ │ │ ├── locals: []
+ │ │ ├── class_keyword_loc: (186,5)-(186,10) = "class"
+ │ │ ├── constant_path:
+ │ │ │ @ ConstantReadNode (location: (186,11)-(186,14))
+ │ │ │ └── name: :Foo
+ │ │ ├── inheritance_operator_loc: ∅
+ │ │ ├── superclass: ∅
+ │ │ ├── body: ∅
+ │ │ ├── end_keyword_loc: (186,16)-(186,19) = "end"
+ │ │ └── name: :Foo
+ │ ├── opening_loc: (186,4)-(186,5) = "("
+ │ └── closing_loc: (186,19)-(186,20) = ")"
├── parameters:
- │ @ ParametersNode (location: (184,8)-(184,37))
+ │ @ ParametersNode (location: (186,25)-(186,32))
│ ├── requireds: (length: 0)
│ ├── optionals: (length: 1)
- │ │ └── @ OptionalParameterNode (location: (184,8)-(184,37))
+ │ │ └── @ OptionalParameterNode (location: (186,25)-(186,32))
│ │ ├── name: :bar
- │ │ ├── name_loc: (184,8)-(184,11) = "bar"
- │ │ ├── operator_loc: (184,12)-(184,13) = "="
+ │ │ ├── name_loc: (186,25)-(186,28) = "bar"
+ │ │ ├── operator_loc: (186,29)-(186,30) = "="
│ │ └── value:
- │ │ @ ParenthesesNode (location: (184,14)-(184,37))
- │ │ ├── body:
- │ │ │ @ StatementsNode (location: (184,15)-(184,36))
- │ │ │ └── body: (length: 2)
- │ │ │ ├── @ DefNode (location: (184,15)-(184,33))
- │ │ │ │ ├── name: :baz
- │ │ │ │ ├── name_loc: (184,19)-(184,22) = "baz"
- │ │ │ │ ├── receiver: ∅
- │ │ │ │ ├── parameters:
- │ │ │ │ │ @ ParametersNode (location: (184,23)-(184,26))
- │ │ │ │ │ ├── requireds: (length: 1)
- │ │ │ │ │ │ └── @ RequiredParameterNode (location: (184,23)-(184,26))
- │ │ │ │ │ │ └── name: :bar
- │ │ │ │ │ ├── optionals: (length: 0)
- │ │ │ │ │ ├── rest: ∅
- │ │ │ │ │ ├── posts: (length: 0)
- │ │ │ │ │ ├── keywords: (length: 0)
- │ │ │ │ │ ├── keyword_rest: ∅
- │ │ │ │ │ └── block: ∅
- │ │ │ │ ├── body:
- │ │ │ │ │ @ StatementsNode (location: (184,30)-(184,33))
- │ │ │ │ │ └── body: (length: 1)
- │ │ │ │ │ └── @ LocalVariableReadNode (location: (184,30)-(184,33))
- │ │ │ │ │ ├── name: :bar
- │ │ │ │ │ └── depth: 0
- │ │ │ │ ├── locals: [:bar]
- │ │ │ │ ├── def_keyword_loc: (184,15)-(184,18) = "def"
- │ │ │ │ ├── operator_loc: ∅
- │ │ │ │ ├── lparen_loc: (184,22)-(184,23) = "("
- │ │ │ │ ├── rparen_loc: (184,26)-(184,27) = ")"
- │ │ │ │ ├── equal_loc: (184,28)-(184,29) = "="
- │ │ │ │ └── end_keyword_loc: ∅
- │ │ │ └── @ IntegerNode (location: (184,35)-(184,36))
- │ │ │ └── flags: decimal
- │ │ ├── opening_loc: (184,14)-(184,15) = "("
- │ │ └── closing_loc: (184,36)-(184,37) = ")"
+ │ │ @ IntegerNode (location: (186,31)-(186,32))
+ │ │ └── flags: decimal
│ ├── rest: ∅
│ ├── posts: (length: 0)
│ ├── keywords: (length: 0)
│ ├── keyword_rest: ∅
│ └── block: ∅
├── body:
- │ @ StatementsNode (location: (184,41)-(184,42))
+ │ @ StatementsNode (location: (186,36)-(186,37))
│ └── body: (length: 1)
- │ └── @ IntegerNode (location: (184,41)-(184,42))
+ │ └── @ IntegerNode (location: (186,36)-(186,37))
│ └── flags: decimal
├── locals: [:bar]
- ├── def_keyword_loc: (184,0)-(184,3) = "def"
- ├── operator_loc: ∅
- ├── lparen_loc: (184,7)-(184,8) = "("
- ├── rparen_loc: (184,37)-(184,38) = ")"
- ├── equal_loc: (184,39)-(184,40) = "="
+ ├── def_keyword_loc: (186,0)-(186,3) = "def"
+ ├── operator_loc: (186,20)-(186,21) = "."
+ ├── lparen_loc: (186,24)-(186,25) = "("
+ ├── rparen_loc: (186,32)-(186,33) = ")"
+ ├── equal_loc: (186,34)-(186,35) = "="
└── end_keyword_loc: ∅