[ruby/prism] Add a multiple statements flag to parentheses

This can get triggered even if the list of statements only contains
a single statement. This is necessary to properly support compiling

```ruby
defined? (;a)
defined? (a;)
```

as "expression". Previously these were parsed as statements lists
with single statements in them.

https://github.com/ruby/prism/commit/b63b5d67a9
This commit is contained in:
Kevin Newton 2025-03-13 13:59:45 -04:00
parent e3c8464630
commit dc48c1aca3
11 changed files with 40 additions and 2155 deletions

View File

@ -719,6 +719,11 @@ flags:
- name: REPEATED_PARAMETER
comment: "a parameter name that has been repeated in the method signature"
comment: Flags for parameter nodes.
- name: ParenthesesNodeFlags
values:
- name: MULTIPLE_STATEMENTS
comment: "parentheses that contain multiple potentially void statements"
comment: Flags for parentheses nodes.
- name: RangeFlags
values:
- name: EXCLUDE_END
@ -3852,6 +3857,7 @@ nodes:
^^^^^^^
end
- name: ParenthesesNode
flags: ParenthesesNodeFlags
fields:
- name: body
type: node?

View File

@ -6412,12 +6412,13 @@ pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_st
* Allocate and initialize new ParenthesesNode node.
*/
static pm_parentheses_node_t *
pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing) {
pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing, pm_node_flags_t flags) {
pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
*node = (pm_parentheses_node_t) {
{
.type = PM_PARENTHESES_NODE,
.flags = flags,
.node_id = PM_NODE_IDENTIFY(parser),
.location = {
.start = opening->start,
@ -17561,7 +17562,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
accept1(parser, PM_TOKEN_NEWLINE);
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
pm_node_t *right = (pm_node_t *) pm_parentheses_node_create(parser, &opening, body, &parser->previous);
pm_node_t *right = (pm_node_t *) pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0);
if (node == NULL) {
node = right;
@ -18184,12 +18185,19 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
case PM_TOKEN_PARENTHESIS_LEFT:
case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
pm_token_t opening = parser->current;
pm_node_flags_t flags = 0;
pm_node_list_t current_block_exits = { 0 };
pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
parser_lex(parser);
while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
while (true) {
if (accept1(parser, PM_TOKEN_SEMICOLON)) {
flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
} else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
break;
}
}
// If this is the end of the file or we match a right parenthesis, then
// we have an empty parentheses node, and we can immediately return.
@ -18199,7 +18207,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pop_block_exits(parser, previous_block_exits);
pm_node_list_free(&current_block_exits);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->previous);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, flags);
}
// Otherwise, we're going to parse the first statement in the list
@ -18212,9 +18220,23 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// Determine if this statement is followed by a terminator. In the
// case of a single statement, this is fine. But in the case of
// multiple statements it's required.
bool terminator_found = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
bool terminator_found = false;
if (accept1(parser, PM_TOKEN_SEMICOLON)) {
terminator_found = true;
flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
} else if (accept1(parser, PM_TOKEN_NEWLINE)) {
terminator_found = true;
}
if (terminator_found) {
while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
while (true) {
if (accept1(parser, PM_TOKEN_SEMICOLON)) {
flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
} else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
break;
}
}
}
// If we hit a right parenthesis, then we're done parsing the
@ -18286,13 +18308,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_statements_node_t *statements = pm_statements_node_create(parser);
pm_statements_node_body_append(parser, statements, statement, true);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous, flags);
}
// If we have more than one statement in the set of parentheses,
// then we are going to parse all of them as a list of statements.
// We'll do that here.
context_push(parser, PM_CONTEXT_PARENS);
flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
pm_statements_node_t *statements = pm_statements_node_create(parser);
pm_statements_node_body_append(parser, statements, statement, true);
@ -18369,7 +18393,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_node_list_free(&current_block_exits);
pm_void_statements_check(parser, statements, true);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous, flags);
}
case PM_TOKEN_BRACE_LEFT: {
// If we were passed a current_hash_keys via the parser, then that
@ -19415,7 +19439,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
operator = parser->previous;
receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0);
// To push `PM_CONTEXT_DEF_PARAMS` again is for the same
// reason as described the above.
@ -19748,7 +19772,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_token_t lparen = parser->previous;
if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous);
receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0);
} else {
arguments.opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));

View File

@ -29,10 +29,6 @@ foo\\\\\
"
"
<<<<<<< HEAD
<<<<<<< HEAD
=======
>>>>>>> 2637007929 (Better handle all kinds of multiline strings in the parser translator)
foo\
b\nar
#{}
@ -43,9 +39,4 @@ b\nar
a\nb\n#{}\nc\n"
"
<<<<<<< HEAD
=======
>>>>>>> a651126458 (Fix an incompatibility with the parser translator)
=======
>>>>>>> 2637007929 (Better handle all kinds of multiline strings in the parser translator)
"

View File

@ -45,19 +45,10 @@ foo\
b\nar
"
<<<<<<< HEAD
<<<<<<< HEAD
=======
>>>>>>> 4ef093b600 (Fix parser translator edge-case when multiline string ends with \n)
"foo
\nbar\n\n
a\nb\n\nc\n"
<<<<<<< HEAD
=======
>>>>>>> 2637007929 (Better handle all kinds of multiline strings in the parser translator)
=======
>>>>>>> 4ef093b600 (Fix parser translator edge-case when multiline string ends with \n)
%q{abc}
%s[abc]
@ -85,13 +76,6 @@ a\nb\n\nc\n"
%w[foo\ bar\\ baz\\\
bat]
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
=======
>>>>>>> 4edfe9d981 (Further refine string handling in the parser translator)
=======
>>>>>>> 4edfe9d981 (Further refine string handling in the parser translator)
%W[#{foo}\
bar
baz #{bat}
@ -107,14 +91,6 @@ baz #{bat}
%W(foo\
bar)
<<<<<<< HEAD
<<<<<<< HEAD
=======
>>>>>>> bd3dd2b62a (Fix parser translator tokens for %-arrays with whitespace escapes)
=======
>>>>>>> 4edfe9d981 (Further refine string handling in the parser translator)
=======
>>>>>>> 4edfe9d981 (Further refine string handling in the parser translator)
%w[foo bar]
%w[

View File

@ -13,18 +13,9 @@
%x{}
`
<<<<<<< HEAD
<<<<<<< HEAD
=======
>>>>>>> 2637007929 (Better handle all kinds of multiline strings in the parser translator)
foo\
b\nar
`
`
<<<<<<< HEAD
=======
>>>>>>> a651126458 (Fix an incompatibility with the parser translator)
=======
>>>>>>> 2637007929 (Better handle all kinds of multiline strings in the parser translator)
`

View File

@ -92,11 +92,6 @@ module Prism
# These files are either failing to parse or failing to translate, so we'll
# skip them for now.
skip_all = skip_incorrect | [
<<<<<<< HEAD
=======
"unescaping.txt",
"seattlerb/regexp_esc_C_slash.txt",
>>>>>>> 4edfe9d981 (Further refine string handling in the parser translator)
]
# Not sure why these files are failing on JRuby, but skipping them for now.

View File

@ -1,223 +0,0 @@
@ ProgramNode (location: (1,0)-(43,8))
├── flags: ∅
├── locals: []
└── statements:
@ StatementsNode (location: (1,0)-(43,8))
├── flags: ∅
└── body: (length: 4)
├── @ StringNode (location: (1,0)-(1,7))
│ ├── flags: newline
│ ├── opening_loc: (1,0)-(1,7) = "<<-RUBY"
│ ├── content_loc: (2,0)-(13,0) = " \\n\n \\n\n exit\n \\\\n\n \\n\\n\\n\\n\n argh\n \\\\\n \\\\\\\n foo\\nbar\n \\f\n ok\n"
│ ├── closing_loc: (13,0)-(14,0) = "RUBY\n"
│ └── unescaped: " \n\n \n\n exit\n \\n\n \n\n\n\n\n argh\n \\\n \\ foo\nbar\n \f\n ok\n"
├── @ InterpolatedStringNode (location: (15,0)-(15,7))
│ ├── flags: newline, static_literal
│ ├── opening_loc: (15,0)-(15,7) = "<<~RUBY"
│ ├── parts: (length: 11)
│ │ ├── @ StringNode (location: (16,0)-(17,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (16,0)-(17,0) = " \\n\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\n\n"
│ │ ├── @ StringNode (location: (17,0)-(18,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (17,0)-(18,0) = " \\n\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\n\n"
│ │ ├── @ StringNode (location: (18,0)-(19,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (18,0)-(19,0) = " exit\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "exit\n"
│ │ ├── @ StringNode (location: (19,0)-(20,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (19,0)-(20,0) = " \\\\n\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\\n\n"
│ │ ├── @ StringNode (location: (20,0)-(21,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (20,0)-(21,0) = " \\n\\n\\n\\n\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\n\n\n\n\n"
│ │ ├── @ StringNode (location: (21,0)-(22,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (21,0)-(22,0) = " argh\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "argh\n"
│ │ ├── @ StringNode (location: (22,0)-(23,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (22,0)-(23,0) = " \\\\\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\\\n"
│ │ ├── @ StringNode (location: (23,0)-(24,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (23,0)-(24,0) = " \\\\\\\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\\"
│ │ ├── @ StringNode (location: (24,0)-(25,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (24,0)-(25,0) = " foo\\nbar\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "foo\nbar\n"
│ │ ├── @ StringNode (location: (25,0)-(26,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (25,0)-(26,0) = " \\f\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\f\n"
│ │ └── @ StringNode (location: (26,0)-(27,0))
│ │ ├── flags: static_literal, frozen
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (26,0)-(27,0) = " ok\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "ok\n"
│ └── closing_loc: (27,0)-(28,0) = "RUBY\n"
├── @ InterpolatedStringNode (location: (29,0)-(29,7))
│ ├── flags: newline
│ ├── opening_loc: (29,0)-(29,7) = "<<~RUBY"
│ ├── parts: (length: 18)
│ │ ├── @ EmbeddedStatementsNode (location: (30,2)-(30,8))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (30,2)-(30,4) = "\#{"
│ │ │ ├── statements:
│ │ │ │ @ StatementsNode (location: (30,4)-(30,7))
│ │ │ │ ├── flags: ∅
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ IntegerNode (location: (30,4)-(30,7))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 123
│ │ │ └── closing_loc: (30,7)-(30,8) = "}"
│ │ ├── @ StringNode (location: (30,8)-(31,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (30,8)-(31,0) = "\\n\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\n\n"
│ │ ├── @ StringNode (location: (31,0)-(32,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (31,0)-(32,0) = " \\n\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\n\n"
│ │ ├── @ StringNode (location: (32,0)-(33,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (32,0)-(33,0) = " exit\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "exit\n"
│ │ ├── @ StringNode (location: (33,0)-(33,4))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (33,0)-(33,4) = " \\\\"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\\"
│ │ ├── @ EmbeddedStatementsNode (location: (33,4)-(33,10))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (33,4)-(33,6) = "\#{"
│ │ │ ├── statements:
│ │ │ │ @ StatementsNode (location: (33,6)-(33,9))
│ │ │ │ ├── flags: ∅
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ IntegerNode (location: (33,6)-(33,9))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 123
│ │ │ └── closing_loc: (33,9)-(33,10) = "}"
│ │ ├── @ StringNode (location: (33,10)-(34,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (33,10)-(34,0) = "n\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "n\n"
│ │ ├── @ StringNode (location: (34,0)-(34,4))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (34,0)-(34,4) = " \\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\n"
│ │ ├── @ EmbeddedStatementsNode (location: (34,4)-(34,10))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (34,4)-(34,6) = "\#{"
│ │ │ ├── statements:
│ │ │ │ @ StatementsNode (location: (34,6)-(34,9))
│ │ │ │ ├── flags: ∅
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ IntegerNode (location: (34,6)-(34,9))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 123
│ │ │ └── closing_loc: (34,9)-(34,10) = "}"
│ │ ├── @ StringNode (location: (34,10)-(35,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (34,10)-(35,0) = "\\n\\n\\n\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\n\n\n\n"
│ │ ├── @ StringNode (location: (35,0)-(36,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (35,0)-(36,0) = " argh\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "argh\n"
│ │ ├── @ StringNode (location: (36,0)-(36,4))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (36,0)-(36,4) = " \\\\"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\\"
│ │ ├── @ EmbeddedStatementsNode (location: (36,4)-(36,10))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (36,4)-(36,6) = "\#{"
│ │ │ ├── statements:
│ │ │ │ @ StatementsNode (location: (36,6)-(36,9))
│ │ │ │ ├── flags: ∅
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ IntegerNode (location: (36,6)-(36,9))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 123
│ │ │ └── closing_loc: (36,9)-(36,10) = "}"
│ │ ├── @ StringNode (location: (36,10)-(37,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (36,10)-(37,0) = "baz\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "baz\n"
│ │ ├── @ StringNode (location: (37,0)-(38,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (37,0)-(38,0) = " \\\\\\\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\\"
│ │ ├── @ StringNode (location: (38,0)-(39,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (38,0)-(39,0) = " foo\\nbar\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "foo\nbar\n"
│ │ ├── @ StringNode (location: (39,0)-(40,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (39,0)-(40,0) = " \\f\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\f\n"
│ │ └── @ StringNode (location: (40,0)-(41,0))
│ │ ├── flags: static_literal, frozen
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (40,0)-(41,0) = " ok\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "ok\n"
│ └── closing_loc: (41,0)-(42,0) = "RUBY\n"
└── @ StringNode (location: (43,0)-(43,8))
├── flags: newline
├── opening_loc: (43,0)-(43,8) = "<<'RUBY'"
├── content_loc: (44,0)-(55,0) = " \\n\n \\n\n exit\n \\n\n \\n\\n\\n\\n\n argh\n \\\n \\\n foo\\nbar\n \\f\n ok\n"
├── closing_loc: (55,0)-(56,0) = "RUBY\n"
└── unescaped: " \\n\n \\n\n exit\n \\n\n \\n\\n\\n\\n\n argh\n \\\n \\\n foo\\nbar\n \\f\n ok\n"

View File

@ -1,800 +0,0 @@
@ ProgramNode (location: (1,0)-(147,15))
├── flags: ∅
├── locals: []
└── statements:
@ StatementsNode (location: (1,0)-(147,15))
├── flags: ∅
└── body: (length: 63)
├── @ StringNode (location: (1,0)-(1,6))
│ ├── flags: newline
│ ├── opening_loc: (1,0)-(1,2) = "%%"
│ ├── content_loc: (1,2)-(1,5) = "abc"
│ ├── closing_loc: (1,5)-(1,6) = "%"
│ └── unescaped: "abc"
├── @ StringNode (location: (3,0)-(3,6))
│ ├── flags: newline
│ ├── opening_loc: (3,0)-(3,2) = "%^"
│ ├── content_loc: (3,2)-(3,5) = "abc"
│ ├── closing_loc: (3,5)-(3,6) = "^"
│ └── unescaped: "abc"
├── @ StringNode (location: (5,0)-(5,6))
│ ├── flags: newline
│ ├── opening_loc: (5,0)-(5,2) = "%&"
│ ├── content_loc: (5,2)-(5,5) = "abc"
│ ├── closing_loc: (5,5)-(5,6) = "&"
│ └── unescaped: "abc"
├── @ StringNode (location: (7,0)-(7,6))
│ ├── flags: newline
│ ├── opening_loc: (7,0)-(7,2) = "%*"
│ ├── content_loc: (7,2)-(7,5) = "abc"
│ ├── closing_loc: (7,5)-(7,6) = "*"
│ └── unescaped: "abc"
├── @ StringNode (location: (9,0)-(9,6))
│ ├── flags: newline
│ ├── opening_loc: (9,0)-(9,2) = "%_"
│ ├── content_loc: (9,2)-(9,5) = "abc"
│ ├── closing_loc: (9,5)-(9,6) = "_"
│ └── unescaped: "abc"
├── @ StringNode (location: (11,0)-(11,6))
│ ├── flags: newline
│ ├── opening_loc: (11,0)-(11,2) = "%+"
│ ├── content_loc: (11,2)-(11,5) = "abc"
│ ├── closing_loc: (11,5)-(11,6) = "+"
│ └── unescaped: "abc"
├── @ StringNode (location: (13,0)-(13,6))
│ ├── flags: newline
│ ├── opening_loc: (13,0)-(13,2) = "%-"
│ ├── content_loc: (13,2)-(13,5) = "abc"
│ ├── closing_loc: (13,5)-(13,6) = "-"
│ └── unescaped: "abc"
├── @ StringNode (location: (15,0)-(15,6))
│ ├── flags: newline
│ ├── opening_loc: (15,0)-(15,2) = "%:"
│ ├── content_loc: (15,2)-(15,5) = "abc"
│ ├── closing_loc: (15,5)-(15,6) = ":"
│ └── unescaped: "abc"
├── @ StringNode (location: (17,0)-(17,6))
│ ├── flags: newline
│ ├── opening_loc: (17,0)-(17,2) = "%;"
│ ├── content_loc: (17,2)-(17,5) = "abc"
│ ├── closing_loc: (17,5)-(17,6) = ";"
│ └── unescaped: "abc"
├── @ StringNode (location: (19,0)-(19,6))
│ ├── flags: newline
│ ├── opening_loc: (19,0)-(19,2) = "%'"
│ ├── content_loc: (19,2)-(19,5) = "abc"
│ ├── closing_loc: (19,5)-(19,6) = "'"
│ └── unescaped: "abc"
├── @ StringNode (location: (21,0)-(21,6))
│ ├── flags: newline
│ ├── opening_loc: (21,0)-(21,2) = "%~"
│ ├── content_loc: (21,2)-(21,5) = "abc"
│ ├── closing_loc: (21,5)-(21,6) = "~"
│ └── unescaped: "abc"
├── @ StringNode (location: (23,0)-(23,6))
│ ├── flags: newline
│ ├── opening_loc: (23,0)-(23,2) = "%?"
│ ├── content_loc: (23,2)-(23,5) = "abc"
│ ├── closing_loc: (23,5)-(23,6) = "?"
│ └── unescaped: "abc"
├── @ ArrayNode (location: (25,0)-(25,8))
│ ├── flags: newline, static_literal
│ ├── elements: (length: 0)
│ ├── opening_loc: (25,0)-(25,3) = "%w{"
│ └── closing_loc: (25,7)-(25,8) = "}"
├── @ StringNode (location: (27,0)-(27,6))
│ ├── flags: newline
│ ├── opening_loc: (27,0)-(27,2) = "%/"
│ ├── content_loc: (27,2)-(27,5) = "abc"
│ ├── closing_loc: (27,5)-(27,6) = "/"
│ └── unescaped: "abc"
├── @ StringNode (location: (29,0)-(29,6))
│ ├── flags: newline
│ ├── opening_loc: (29,0)-(29,2) = "%`"
│ ├── content_loc: (29,2)-(29,5) = "abc"
│ ├── closing_loc: (29,5)-(29,6) = "`"
│ └── unescaped: "abc"
├── @ InterpolatedStringNode (location: (31,0)-(31,8))
│ ├── flags: newline
│ ├── opening_loc: (31,0)-(31,1) = "\""
│ ├── parts: (length: 1)
│ │ └── @ EmbeddedVariableNode (location: (31,1)-(31,7))
│ │ ├── flags: ∅
│ │ ├── operator_loc: (31,1)-(31,2) = "#"
│ │ └── variable:
│ │ @ ClassVariableReadNode (location: (31,2)-(31,7))
│ │ ├── flags: ∅
│ │ └── name: :@@foo
│ └── closing_loc: (31,7)-(31,8) = "\""
├── @ StringNode (location: (33,0)-(33,6))
│ ├── flags: newline
│ ├── opening_loc: (33,0)-(33,2) = "%\\"
│ ├── content_loc: (33,2)-(33,5) = "abc"
│ ├── closing_loc: (33,5)-(33,6) = "\\"
│ └── unescaped: "abc"
├── @ InterpolatedStringNode (location: (35,0)-(35,17))
│ ├── flags: newline
│ ├── opening_loc: (35,0)-(35,2) = "%{"
│ ├── parts: (length: 3)
│ │ ├── @ StringNode (location: (35,2)-(35,6))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (35,2)-(35,6) = "aaa "
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "aaa "
│ │ ├── @ EmbeddedStatementsNode (location: (35,6)-(35,12))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (35,6)-(35,8) = "\#{"
│ │ │ ├── statements:
│ │ │ │ @ StatementsNode (location: (35,8)-(35,11))
│ │ │ │ ├── flags: ∅
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ CallNode (location: (35,8)-(35,11))
│ │ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ │ ├── receiver: ∅
│ │ │ │ ├── call_operator_loc: ∅
│ │ │ │ ├── name: :bbb
│ │ │ │ ├── message_loc: (35,8)-(35,11) = "bbb"
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── arguments: ∅
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── block: ∅
│ │ │ └── closing_loc: (35,11)-(35,12) = "}"
│ │ └── @ StringNode (location: (35,12)-(35,16))
│ │ ├── flags: static_literal, frozen
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (35,12)-(35,16) = " ccc"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: " ccc"
│ └── closing_loc: (35,16)-(35,17) = "}"
├── @ StringNode (location: (37,0)-(37,8))
│ ├── flags: newline
│ ├── opening_loc: (37,0)-(37,2) = "%["
│ ├── content_loc: (37,2)-(37,7) = "foo[]"
│ ├── closing_loc: (37,7)-(37,8) = "]"
│ └── unescaped: "foo[]"
├── @ CallNode (location: (39,0)-(41,5))
│ ├── flags: newline
│ ├── receiver:
│ │ @ StringNode (location: (39,0)-(39,5))
│ │ ├── flags: ∅
│ │ ├── opening_loc: (39,0)-(39,1) = "\""
│ │ ├── content_loc: (39,1)-(39,4) = "foo"
│ │ ├── closing_loc: (39,4)-(39,5) = "\""
│ │ └── unescaped: "foo"
│ ├── call_operator_loc: ∅
│ ├── name: :+
│ ├── message_loc: (39,6)-(39,7) = "+"
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (41,0)-(41,5))
│ │ ├── flags: ∅
│ │ └── arguments: (length: 1)
│ │ └── @ StringNode (location: (41,0)-(41,5))
│ │ ├── flags: ∅
│ │ ├── opening_loc: (41,0)-(41,1) = "\""
│ │ ├── content_loc: (41,1)-(41,4) = "bar"
│ │ ├── closing_loc: (41,4)-(41,5) = "\""
│ │ └── unescaped: "bar"
│ ├── closing_loc: ∅
│ └── block: ∅
├── @ StringNode (location: (43,0)-(46,1))
│ ├── flags: newline
│ ├── opening_loc: (43,0)-(43,1) = "\""
│ ├── content_loc: (43,1)-(46,0) = "\nfoo\\\nb\\nar\n"
│ ├── closing_loc: (46,0)-(46,1) = "\""
│ └── unescaped: "\nfoob\nar\n"
├── @ StringNode (location: (48,0)-(48,7))
│ ├── flags: newline
│ ├── opening_loc: (48,0)-(48,3) = "%q{"
│ ├── content_loc: (48,3)-(48,6) = "abc"
│ ├── closing_loc: (48,6)-(48,7) = "}"
│ └── unescaped: "abc"
├── @ SymbolNode (location: (50,0)-(50,7))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (50,0)-(50,3) = "%s["
│ ├── value_loc: (50,3)-(50,6) = "abc"
│ ├── closing_loc: (50,6)-(50,7) = "]"
│ └── unescaped: "abc"
├── @ StringNode (location: (52,0)-(52,6))
│ ├── flags: newline
│ ├── opening_loc: (52,0)-(52,2) = "%{"
│ ├── content_loc: (52,2)-(52,5) = "abc"
│ ├── closing_loc: (52,5)-(52,6) = "}"
│ └── unescaped: "abc"
├── @ StringNode (location: (54,0)-(54,2))
│ ├── flags: newline
│ ├── opening_loc: (54,0)-(54,1) = "'"
│ ├── content_loc: (54,1)-(54,1) = ""
│ ├── closing_loc: (54,1)-(54,2) = "'"
│ └── unescaped: ""
├── @ StringNode (location: (56,0)-(56,5))
│ ├── flags: newline
│ ├── opening_loc: (56,0)-(56,1) = "\""
│ ├── content_loc: (56,1)-(56,4) = "abc"
│ ├── closing_loc: (56,4)-(56,5) = "\""
│ └── unescaped: "abc"
├── @ StringNode (location: (58,0)-(58,7))
│ ├── flags: newline
│ ├── opening_loc: (58,0)-(58,1) = "\""
│ ├── content_loc: (58,1)-(58,6) = "\#@---"
│ ├── closing_loc: (58,6)-(58,7) = "\""
│ └── unescaped: "\#@---"
├── @ InterpolatedStringNode (location: (60,0)-(60,16))
│ ├── flags: newline
│ ├── opening_loc: (60,0)-(60,1) = "\""
│ ├── parts: (length: 3)
│ │ ├── @ StringNode (location: (60,1)-(60,5))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (60,1)-(60,5) = "aaa "
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "aaa "
│ │ ├── @ EmbeddedStatementsNode (location: (60,5)-(60,11))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (60,5)-(60,7) = "\#{"
│ │ │ ├── statements:
│ │ │ │ @ StatementsNode (location: (60,7)-(60,10))
│ │ │ │ ├── flags: ∅
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ CallNode (location: (60,7)-(60,10))
│ │ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ │ ├── receiver: ∅
│ │ │ │ ├── call_operator_loc: ∅
│ │ │ │ ├── name: :bbb
│ │ │ │ ├── message_loc: (60,7)-(60,10) = "bbb"
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── arguments: ∅
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── block: ∅
│ │ │ └── closing_loc: (60,10)-(60,11) = "}"
│ │ └── @ StringNode (location: (60,11)-(60,15))
│ │ ├── flags: static_literal, frozen
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (60,11)-(60,15) = " ccc"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: " ccc"
│ └── closing_loc: (60,15)-(60,16) = "\""
├── @ StringNode (location: (62,0)-(62,5))
│ ├── flags: newline
│ ├── opening_loc: (62,0)-(62,1) = "'"
│ ├── content_loc: (62,1)-(62,4) = "abc"
│ ├── closing_loc: (62,4)-(62,5) = "'"
│ └── unescaped: "abc"
├── @ ArrayNode (location: (64,0)-(64,9))
│ ├── flags: newline
│ ├── elements: (length: 3)
│ │ ├── @ StringNode (location: (64,3)-(64,4))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (64,3)-(64,4) = "a"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a"
│ │ ├── @ StringNode (location: (64,5)-(64,6))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (64,5)-(64,6) = "b"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "b"
│ │ └── @ StringNode (location: (64,7)-(64,8))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (64,7)-(64,8) = "c"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "c"
│ ├── opening_loc: (64,0)-(64,3) = "%w["
│ └── closing_loc: (64,8)-(64,9) = "]"
├── @ ArrayNode (location: (66,0)-(66,17))
│ ├── flags: newline
│ ├── elements: (length: 3)
│ │ ├── @ StringNode (location: (66,3)-(66,6))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (66,3)-(66,6) = "a[]"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a[]"
│ │ ├── @ StringNode (location: (66,7)-(66,12))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (66,7)-(66,12) = "b[[]]"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "b[[]]"
│ │ └── @ StringNode (location: (66,13)-(66,16))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (66,13)-(66,16) = "c[]"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "c[]"
│ ├── opening_loc: (66,0)-(66,3) = "%w["
│ └── closing_loc: (66,16)-(66,17) = "]"
├── @ ArrayNode (location: (68,0)-(68,18))
│ ├── flags: newline
│ ├── elements: (length: 2)
│ │ ├── @ StringNode (location: (68,3)-(68,11))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (68,3)-(68,11) = "foo\\ bar"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "foo bar"
│ │ └── @ StringNode (location: (68,12)-(68,17))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (68,12)-(68,17) = "\\\#{1}"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "\\\#{1}"
│ ├── opening_loc: (68,0)-(68,3) = "%w["
│ └── closing_loc: (68,17)-(68,18) = "]"
├── @ ArrayNode (location: (70,0)-(70,16))
│ ├── flags: newline
│ ├── elements: (length: 2)
│ │ ├── @ StringNode (location: (70,3)-(70,11))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (70,3)-(70,11) = "foo\\ bar"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "foo bar"
│ │ └── @ StringNode (location: (70,12)-(70,15))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (70,12)-(70,15) = "baz"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "baz"
│ ├── opening_loc: (70,0)-(70,3) = "%w["
│ └── closing_loc: (70,15)-(70,16) = "]"
├── @ ArrayNode (location: (72,0)-(73,5))
│ ├── flags: newline
│ ├── elements: (length: 3)
│ │ ├── @ StringNode (location: (72,3)-(72,13))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (72,3)-(72,13) = "foo\\ bar\\\\"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "foo bar\\"
│ │ ├── @ StringNode (location: (72,14)-(73,0))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (72,14)-(73,0) = "baz\\\\\\\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "baz\\\n"
│ │ └── @ StringNode (location: (73,1)-(73,4))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (73,1)-(73,4) = "bat"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "bat"
│ ├── opening_loc: (72,0)-(72,3) = "%w["
│ └── closing_loc: (73,4)-(73,5) = "]"
├── @ ArrayNode (location: (75,0)-(78,1))
│ ├── flags: newline
│ ├── elements: (length: 3)
│ │ ├── @ InterpolatedStringNode (location: (75,3)-(76,3))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── parts: (length: 2)
│ │ │ │ ├── @ EmbeddedStatementsNode (location: (75,3)-(75,9))
│ │ │ │ │ ├── flags: ∅
│ │ │ │ │ ├── opening_loc: (75,3)-(75,5) = "\#{"
│ │ │ │ │ ├── statements:
│ │ │ │ │ │ @ StatementsNode (location: (75,5)-(75,8))
│ │ │ │ │ │ ├── flags: ∅
│ │ │ │ │ │ └── body: (length: 1)
│ │ │ │ │ │ └── @ CallNode (location: (75,5)-(75,8))
│ │ │ │ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ │ │ │ ├── receiver: ∅
│ │ │ │ │ │ ├── call_operator_loc: ∅
│ │ │ │ │ │ ├── name: :foo
│ │ │ │ │ │ ├── message_loc: (75,5)-(75,8) = "foo"
│ │ │ │ │ │ ├── opening_loc: ∅
│ │ │ │ │ │ ├── arguments: ∅
│ │ │ │ │ │ ├── closing_loc: ∅
│ │ │ │ │ │ └── block: ∅
│ │ │ │ │ └── closing_loc: (75,8)-(75,9) = "}"
│ │ │ │ └── @ StringNode (location: (75,9)-(76,3))
│ │ │ │ ├── flags: static_literal, frozen
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── content_loc: (75,9)-(76,3) = "\\\nbar"
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── unescaped: "\nbar"
│ │ │ └── closing_loc: ∅
│ │ ├── @ StringNode (location: (77,0)-(77,3))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (77,0)-(77,3) = "baz"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "baz"
│ │ └── @ InterpolatedStringNode (location: (77,4)-(77,10))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── parts: (length: 1)
│ │ │ └── @ EmbeddedStatementsNode (location: (77,4)-(77,10))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (77,4)-(77,6) = "\#{"
│ │ │ ├── statements:
│ │ │ │ @ StatementsNode (location: (77,6)-(77,9))
│ │ │ │ ├── flags: ∅
│ │ │ │ └── body: (length: 1)
│ │ │ │ └── @ CallNode (location: (77,6)-(77,9))
│ │ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ │ ├── receiver: ∅
│ │ │ │ ├── call_operator_loc: ∅
│ │ │ │ ├── name: :bat
│ │ │ │ ├── message_loc: (77,6)-(77,9) = "bat"
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── arguments: ∅
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── block: ∅
│ │ │ └── closing_loc: (77,9)-(77,10) = "}"
│ │ └── closing_loc: ∅
│ ├── opening_loc: (75,0)-(75,3) = "%W["
│ └── closing_loc: (78,0)-(78,1) = "]"
├── @ ArrayNode (location: (80,0)-(80,9))
│ ├── flags: newline
│ ├── elements: (length: 1)
│ │ └── @ StringNode (location: (80,3)-(80,8))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (80,3)-(80,8) = "foo\\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "foo\\n"
│ ├── opening_loc: (80,0)-(80,3) = "%w("
│ └── closing_loc: (80,8)-(80,9) = ")"
├── @ ArrayNode (location: (82,0)-(83,1))
│ ├── flags: newline
│ ├── elements: (length: 1)
│ │ └── @ StringNode (location: (82,3)-(83,0))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (82,3)-(83,0) = "foo\\\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "foo\n"
│ ├── opening_loc: (82,0)-(82,3) = "%w("
│ └── closing_loc: (83,0)-(83,1) = ")"
├── @ ArrayNode (location: (85,0)-(85,10))
│ ├── flags: newline
│ ├── elements: (length: 2)
│ │ ├── @ StringNode (location: (85,3)-(85,6))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (85,3)-(85,6) = "foo"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "foo"
│ │ └── @ StringNode (location: (85,7)-(85,9))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (85,7)-(85,9) = "\\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "\\n"
│ ├── opening_loc: (85,0)-(85,3) = "%w("
│ └── closing_loc: (85,9)-(85,10) = ")"
├── @ ArrayNode (location: (87,0)-(88,4))
│ ├── flags: newline
│ ├── elements: (length: 1)
│ │ └── @ StringNode (location: (87,3)-(88,3))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (87,3)-(88,3) = "foo\\\nbar"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "foo\nbar"
│ ├── opening_loc: (87,0)-(87,3) = "%W("
│ └── closing_loc: (88,3)-(88,4) = ")"
├── @ ArrayNode (location: (90,0)-(90,15))
│ ├── flags: newline
│ ├── elements: (length: 2)
│ │ ├── @ StringNode (location: (90,3)-(90,6))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (90,3)-(90,6) = "foo"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "foo"
│ │ └── @ StringNode (location: (90,11)-(90,14))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (90,11)-(90,14) = "bar"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "bar"
│ ├── opening_loc: (90,0)-(90,3) = "%w["
│ └── closing_loc: (90,14)-(90,15) = "]"
├── @ ArrayNode (location: (92,0)-(96,1))
│ ├── flags: newline
│ ├── elements: (length: 4)
│ │ ├── @ StringNode (location: (93,2)-(93,3))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (93,2)-(93,3) = "a"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a"
│ │ ├── @ StringNode (location: (94,2)-(94,3))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (94,2)-(94,3) = "b"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "b"
│ │ ├── @ StringNode (location: (94,6)-(94,7))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (94,6)-(94,7) = "c"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "c"
│ │ └── @ StringNode (location: (95,1)-(95,2))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (95,1)-(95,2) = "d"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "d"
│ ├── opening_loc: (92,0)-(92,3) = "%w["
│ └── closing_loc: (96,0)-(96,1) = "]"
├── @ ArrayNode (location: (98,0)-(98,18))
│ ├── flags: newline
│ ├── elements: (length: 1)
│ │ └── @ StringNode (location: (98,3)-(98,17))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (98,3)-(98,17) = "f\\u{006f 006f}"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "foo"
│ ├── opening_loc: (98,0)-(98,3) = "%W["
│ └── closing_loc: (98,17)-(98,18) = "]"
├── @ ArrayNode (location: (100,0)-(100,14))
│ ├── flags: newline
│ ├── elements: (length: 3)
│ │ ├── @ StringNode (location: (100,3)-(100,4))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (100,3)-(100,4) = "a"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a"
│ │ ├── @ InterpolatedStringNode (location: (100,5)-(100,11))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── parts: (length: 3)
│ │ │ │ ├── @ StringNode (location: (100,5)-(100,6))
│ │ │ │ │ ├── flags: static_literal, frozen
│ │ │ │ │ ├── opening_loc: ∅
│ │ │ │ │ ├── content_loc: (100,5)-(100,6) = "b"
│ │ │ │ │ ├── closing_loc: ∅
│ │ │ │ │ └── unescaped: "b"
│ │ │ │ ├── @ EmbeddedStatementsNode (location: (100,6)-(100,10))
│ │ │ │ │ ├── flags: ∅
│ │ │ │ │ ├── opening_loc: (100,6)-(100,8) = "\#{"
│ │ │ │ │ ├── statements:
│ │ │ │ │ │ @ StatementsNode (location: (100,8)-(100,9))
│ │ │ │ │ │ ├── flags: ∅
│ │ │ │ │ │ └── body: (length: 1)
│ │ │ │ │ │ └── @ CallNode (location: (100,8)-(100,9))
│ │ │ │ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ │ │ │ ├── receiver: ∅
│ │ │ │ │ │ ├── call_operator_loc: ∅
│ │ │ │ │ │ ├── name: :c
│ │ │ │ │ │ ├── message_loc: (100,8)-(100,9) = "c"
│ │ │ │ │ │ ├── opening_loc: ∅
│ │ │ │ │ │ ├── arguments: ∅
│ │ │ │ │ │ ├── closing_loc: ∅
│ │ │ │ │ │ └── block: ∅
│ │ │ │ │ └── closing_loc: (100,9)-(100,10) = "}"
│ │ │ │ └── @ StringNode (location: (100,10)-(100,11))
│ │ │ │ ├── flags: static_literal, frozen
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── content_loc: (100,10)-(100,11) = "d"
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── unescaped: "d"
│ │ │ └── closing_loc: ∅
│ │ └── @ StringNode (location: (100,12)-(100,13))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (100,12)-(100,13) = "e"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "e"
│ ├── opening_loc: (100,0)-(100,3) = "%W["
│ └── closing_loc: (100,13)-(100,14) = "]"
├── @ ArrayNode (location: (102,0)-(102,9))
│ ├── flags: newline
│ ├── elements: (length: 3)
│ │ ├── @ StringNode (location: (102,3)-(102,4))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (102,3)-(102,4) = "a"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a"
│ │ ├── @ StringNode (location: (102,5)-(102,6))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (102,5)-(102,6) = "b"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "b"
│ │ └── @ StringNode (location: (102,7)-(102,8))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (102,7)-(102,8) = "c"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "c"
│ ├── opening_loc: (102,0)-(102,3) = "%W["
│ └── closing_loc: (102,8)-(102,9) = "]"
├── @ ArrayNode (location: (104,0)-(108,1))
│ ├── flags: newline
│ ├── elements: (length: 3)
│ │ ├── @ StringNode (location: (105,2)-(105,3))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (105,2)-(105,3) = "a"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a"
│ │ ├── @ StringNode (location: (106,2)-(106,3))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (106,2)-(106,3) = "b"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "b"
│ │ └── @ StringNode (location: (107,2)-(107,3))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (107,2)-(107,3) = "c"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "c"
│ ├── opening_loc: (104,0)-(104,3) = "%w["
│ └── closing_loc: (108,0)-(108,1) = "]"
├── @ StringNode (location: (110,0)-(110,15))
│ ├── flags: newline
│ ├── opening_loc: (110,0)-(110,1) = "'"
│ ├── content_loc: (110,1)-(110,14) = "\\' foo \\' bar"
│ ├── closing_loc: (110,14)-(110,15) = "'"
│ └── unescaped: "' foo ' bar"
├── @ StringNode (location: (112,0)-(112,15))
│ ├── flags: newline
│ ├── opening_loc: (112,0)-(112,1) = "'"
│ ├── content_loc: (112,1)-(112,14) = "\\\\ foo \\\\ bar"
│ ├── closing_loc: (112,14)-(112,15) = "'"
│ └── unescaped: "\\ foo \\ bar"
├── @ StringNode (location: (114,0)-(117,1))
│ ├── flags: newline
│ ├── opening_loc: (114,0)-(114,1) = "'"
│ ├── content_loc: (114,1)-(117,0) = "foo\\\nbar\\\\\nbaz\n"
│ ├── closing_loc: (117,0)-(117,1) = "'"
│ └── unescaped: "foo\\\nbar\\\nbaz\n"
├── @ InterpolatedStringNode (location: (119,0)-(119,7))
│ ├── flags: newline
│ ├── opening_loc: (119,0)-(119,1) = "\""
│ ├── parts: (length: 1)
│ │ └── @ EmbeddedVariableNode (location: (119,1)-(119,6))
│ │ ├── flags: ∅
│ │ ├── operator_loc: (119,1)-(119,2) = "#"
│ │ └── variable:
│ │ @ GlobalVariableReadNode (location: (119,2)-(119,6))
│ │ ├── flags: ∅
│ │ └── name: :$foo
│ └── closing_loc: (119,6)-(119,7) = "\""
├── @ InterpolatedStringNode (location: (121,0)-(121,7))
│ ├── flags: newline
│ ├── opening_loc: (121,0)-(121,1) = "\""
│ ├── parts: (length: 1)
│ │ └── @ EmbeddedVariableNode (location: (121,1)-(121,6))
│ │ ├── flags: ∅
│ │ ├── operator_loc: (121,1)-(121,2) = "#"
│ │ └── variable:
│ │ @ InstanceVariableReadNode (location: (121,2)-(121,6))
│ │ ├── flags: ∅
│ │ └── name: :@foo
│ └── closing_loc: (121,6)-(121,7) = "\""
├── @ StringNode (location: (123,0)-(123,15))
│ ├── flags: newline
│ ├── opening_loc: (123,0)-(123,1) = "\""
│ ├── content_loc: (123,1)-(123,14) = "\\x7 \\x23 \\x61"
│ ├── closing_loc: (123,14)-(123,15) = "\""
│ └── unescaped: "\a # a"
├── @ StringNode (location: (125,0)-(125,13))
│ ├── flags: newline
│ ├── opening_loc: (125,0)-(125,1) = "\""
│ ├── content_loc: (125,1)-(125,12) = "\\7 \\43 \\141"
│ ├── closing_loc: (125,12)-(125,13) = "\""
│ └── unescaped: "\a # a"
├── @ StringNode (location: (127,0)-(127,17))
│ ├── flags: newline, forced_utf8_encoding
│ ├── opening_loc: (127,0)-(127,1) = "\""
│ ├── content_loc: (127,1)-(127,16) = "ち\\xE3\\x81\\xFF"
│ ├── closing_loc: (127,16)-(127,17) = "\""
│ └── unescaped: "ち\xE3\x81\xFF"
├── @ StringNode (location: (129,0)-(129,6))
│ ├── flags: newline
│ ├── opening_loc: (129,0)-(129,2) = "%["
│ ├── content_loc: (129,2)-(129,5) = "abc"
│ ├── closing_loc: (129,5)-(129,6) = "]"
│ └── unescaped: "abc"
├── @ StringNode (location: (131,0)-(131,6))
│ ├── flags: newline
│ ├── opening_loc: (131,0)-(131,2) = "%("
│ ├── content_loc: (131,2)-(131,5) = "abc"
│ ├── closing_loc: (131,5)-(131,6) = ")"
│ └── unescaped: "abc"
├── @ StringNode (location: (133,0)-(133,6))
│ ├── flags: newline
│ ├── opening_loc: (133,0)-(133,2) = "%@"
│ ├── content_loc: (133,2)-(133,5) = "abc"
│ ├── closing_loc: (133,5)-(133,6) = "@"
│ └── unescaped: "abc"
├── @ StringNode (location: (135,0)-(135,6))
│ ├── flags: newline
│ ├── opening_loc: (135,0)-(135,2) = "%$"
│ ├── content_loc: (135,2)-(135,5) = "abc"
│ ├── closing_loc: (135,5)-(135,6) = "$"
│ └── unescaped: "abc"
├── @ StringNode (location: (137,0)-(137,2))
│ ├── flags: newline
│ ├── opening_loc: (137,0)-(137,1) = "?"
│ ├── content_loc: (137,1)-(137,2) = "a"
│ ├── closing_loc: ∅
│ └── unescaped: "a"
├── @ InterpolatedStringNode (location: (139,0)-(139,6))
│ ├── flags: newline, static_literal
│ ├── opening_loc: ∅
│ ├── parts: (length: 2)
│ │ ├── @ StringNode (location: (139,0)-(139,2))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: (139,0)-(139,1) = "?"
│ │ │ ├── content_loc: (139,1)-(139,2) = "a"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a"
│ │ └── @ StringNode (location: (139,3)-(139,6))
│ │ ├── flags: static_literal, frozen
│ │ ├── opening_loc: (139,3)-(139,4) = "\""
│ │ ├── content_loc: (139,4)-(139,5) = "a"
│ │ ├── closing_loc: (139,5)-(139,6) = "\""
│ │ └── unescaped: "a"
│ └── closing_loc: ∅
├── @ StringNode (location: (141,0)-(141,7))
│ ├── flags: newline
│ ├── opening_loc: (141,0)-(141,3) = "%Q{"
│ ├── content_loc: (141,3)-(141,6) = "abc"
│ ├── closing_loc: (141,6)-(141,7) = "}"
│ └── unescaped: "abc"
├── @ StringNode (location: (143,0)-(143,5))
│ ├── flags: newline
│ ├── opening_loc: (143,0)-(143,2) = "%^"
│ ├── content_loc: (143,2)-(143,4) = "\#$"
│ ├── closing_loc: (143,4)-(143,5) = "^"
│ └── unescaped: "\#$"
├── @ StringNode (location: (145,0)-(145,4))
│ ├── flags: newline
│ ├── opening_loc: (145,0)-(145,2) = "%@"
│ ├── content_loc: (145,2)-(145,3) = "#"
│ ├── closing_loc: (145,3)-(145,4) = "@"
│ └── unescaped: "#"
└── @ InterpolatedStringNode (location: (147,0)-(147,15))
├── flags: newline
├── opening_loc: (147,0)-(147,1) = "\""
├── parts: (length: 2)
│ ├── @ EmbeddedStatementsNode (location: (147,1)-(147,12))
│ │ ├── flags: ∅
│ │ ├── opening_loc: (147,1)-(147,3) = "\#{"
│ │ ├── statements:
│ │ │ @ StatementsNode (location: (147,3)-(147,11))
│ │ │ ├── flags: ∅
│ │ │ └── body: (length: 1)
│ │ │ └── @ InterpolatedStringNode (location: (147,3)-(147,11))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (147,3)-(147,4) = "\""
│ │ │ ├── parts: (length: 2)
│ │ │ │ ├── @ EmbeddedStatementsNode (location: (147,4)-(147,8))
│ │ │ │ │ ├── flags: ∅
│ │ │ │ │ ├── opening_loc: (147,4)-(147,6) = "\#{"
│ │ │ │ │ ├── statements:
│ │ │ │ │ │ @ StatementsNode (location: (147,6)-(147,7))
│ │ │ │ │ │ ├── flags: ∅
│ │ │ │ │ │ └── body: (length: 1)
│ │ │ │ │ │ └── @ ConstantReadNode (location: (147,6)-(147,7))
│ │ │ │ │ │ ├── flags: ∅
│ │ │ │ │ │ └── name: :B
│ │ │ │ │ └── closing_loc: (147,7)-(147,8) = "}"
│ │ │ │ └── @ StringNode (location: (147,8)-(147,10))
│ │ │ │ ├── flags: static_literal, frozen
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── content_loc: (147,8)-(147,10) = " C"
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── unescaped: " C"
│ │ │ └── closing_loc: (147,10)-(147,11) = "\""
│ │ └── closing_loc: (147,11)-(147,12) = "}"
│ └── @ StringNode (location: (147,12)-(147,14))
│ ├── flags: static_literal, frozen
│ ├── opening_loc: ∅
│ ├── content_loc: (147,12)-(147,14) = " D"
│ ├── closing_loc: ∅
│ └── unescaped: " D"
└── closing_loc: (147,14)-(147,15) = "\""

View File

@ -1,510 +0,0 @@
@ ProgramNode (location: (1,0)-(104,13))
├── flags: ∅
├── locals: []
└── statements:
@ StatementsNode (location: (1,0)-(104,13))
├── flags: ∅
└── body: (length: 49)
├── @ SymbolNode (location: (1,0)-(1,6))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (1,0)-(1,2) = ":'"
│ ├── value_loc: (1,2)-(1,5) = "abc"
│ ├── closing_loc: (1,5)-(1,6) = "'"
│ └── unescaped: "abc"
├── @ InterpolatedSymbolNode (location: (3,0)-(3,9))
│ ├── flags: newline
│ ├── opening_loc: (3,0)-(3,2) = ":\""
│ ├── parts: (length: 1)
│ │ └── @ EmbeddedStatementsNode (location: (3,2)-(3,8))
│ │ ├── flags: ∅
│ │ ├── opening_loc: (3,2)-(3,4) = "\#{"
│ │ ├── statements:
│ │ │ @ StatementsNode (location: (3,4)-(3,7))
│ │ │ ├── flags: ∅
│ │ │ └── body: (length: 1)
│ │ │ └── @ CallNode (location: (3,4)-(3,7))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :var
│ │ │ ├── message_loc: (3,4)-(3,7) = "var"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ └── closing_loc: (3,7)-(3,8) = "}"
│ └── closing_loc: (3,8)-(3,9) = "\""
├── @ InterpolatedSymbolNode (location: (5,0)-(5,10))
│ ├── flags: newline
│ ├── opening_loc: (5,0)-(5,2) = ":\""
│ ├── parts: (length: 2)
│ │ ├── @ StringNode (location: (5,2)-(5,5))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (5,2)-(5,5) = "abc"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "abc"
│ │ └── @ EmbeddedStatementsNode (location: (5,5)-(5,9))
│ │ ├── flags: ∅
│ │ ├── opening_loc: (5,5)-(5,7) = "\#{"
│ │ ├── statements:
│ │ │ @ StatementsNode (location: (5,7)-(5,8))
│ │ │ ├── flags: ∅
│ │ │ └── body: (length: 1)
│ │ │ └── @ IntegerNode (location: (5,7)-(5,8))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ └── closing_loc: (5,8)-(5,9) = "}"
│ └── closing_loc: (5,9)-(5,10) = "\""
├── @ SymbolNode (location: (7,0)-(10,1))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (7,0)-(7,2) = ":\""
│ ├── value_loc: (7,2)-(10,0) = "\nfoo\\\nb\\nar\n"
│ ├── closing_loc: (10,0)-(10,1) = "\""
│ └── unescaped: "\nfoob\nar\n"
├── @ InterpolatedSymbolNode (location: (12,0)-(16,1))
│ ├── flags: newline
│ ├── opening_loc: (12,0)-(12,2) = ":\""
│ ├── parts: (length: 3)
│ │ ├── @ StringNode (location: (12,2)-(15,0))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (12,2)-(15,0) = "\nfoo\\\nb\\nar\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\nfoob\nar\n"
│ │ ├── @ EmbeddedStatementsNode (location: (15,0)-(15,3))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (15,0)-(15,2) = "\#{"
│ │ │ ├── statements: ∅
│ │ │ └── closing_loc: (15,2)-(15,3) = "}"
│ │ └── @ StringNode (location: (15,3)-(16,0))
│ │ ├── flags: static_literal, frozen
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (15,3)-(16,0) = "\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "\n"
│ └── closing_loc: (16,0)-(16,1) = "\""
├── @ ArrayNode (location: (18,0)-(18,20))
│ ├── flags: newline, static_literal
│ ├── elements: (length: 4)
│ │ ├── @ SymbolNode (location: (18,1)-(18,4))
│ │ │ ├── flags: static_literal
│ │ │ ├── opening_loc: (18,1)-(18,2) = ":"
│ │ │ ├── value_loc: (18,2)-(18,4) = "Υ"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "Υ"
│ │ ├── @ SymbolNode (location: (18,6)-(18,9))
│ │ │ ├── flags: static_literal
│ │ │ ├── opening_loc: (18,6)-(18,7) = ":"
│ │ │ ├── value_loc: (18,7)-(18,9) = "ά"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "ά"
│ │ ├── @ SymbolNode (location: (18,11)-(18,14))
│ │ │ ├── flags: static_literal
│ │ │ ├── opening_loc: (18,11)-(18,12) = ":"
│ │ │ ├── value_loc: (18,12)-(18,14) = "ŗ"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "ŗ"
│ │ └── @ SymbolNode (location: (18,16)-(18,19))
│ │ ├── flags: static_literal
│ │ ├── opening_loc: (18,16)-(18,17) = ":"
│ │ ├── value_loc: (18,17)-(18,19) = "ρ"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "ρ"
│ ├── opening_loc: (18,0)-(18,1) = "["
│ └── closing_loc: (18,19)-(18,20) = "]"
├── @ SymbolNode (location: (20,0)-(20,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (20,0)-(20,1) = ":"
│ ├── value_loc: (20,1)-(20,3) = "-@"
│ ├── closing_loc: ∅
│ └── unescaped: "-@"
├── @ SymbolNode (location: (22,0)-(22,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (22,0)-(22,1) = ":"
│ ├── value_loc: (22,1)-(22,2) = "-"
│ ├── closing_loc: ∅
│ └── unescaped: "-"
├── @ SymbolNode (location: (24,0)-(24,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (24,0)-(24,1) = ":"
│ ├── value_loc: (24,1)-(24,2) = "%"
│ ├── closing_loc: ∅
│ └── unescaped: "%"
├── @ SymbolNode (location: (26,0)-(26,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (26,0)-(26,1) = ":"
│ ├── value_loc: (26,1)-(26,2) = "|"
│ ├── closing_loc: ∅
│ └── unescaped: "|"
├── @ SymbolNode (location: (28,0)-(28,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (28,0)-(28,1) = ":"
│ ├── value_loc: (28,1)-(28,3) = "+@"
│ ├── closing_loc: ∅
│ └── unescaped: "+@"
├── @ SymbolNode (location: (30,0)-(30,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (30,0)-(30,1) = ":"
│ ├── value_loc: (30,1)-(30,2) = "+"
│ ├── closing_loc: ∅
│ └── unescaped: "+"
├── @ SymbolNode (location: (32,0)-(32,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (32,0)-(32,1) = ":"
│ ├── value_loc: (32,1)-(32,2) = "/"
│ ├── closing_loc: ∅
│ └── unescaped: "/"
├── @ SymbolNode (location: (34,0)-(34,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (34,0)-(34,1) = ":"
│ ├── value_loc: (34,1)-(34,3) = "**"
│ ├── closing_loc: ∅
│ └── unescaped: "**"
├── @ SymbolNode (location: (36,0)-(36,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (36,0)-(36,1) = ":"
│ ├── value_loc: (36,1)-(36,2) = "*"
│ ├── closing_loc: ∅
│ └── unescaped: "*"
├── @ SymbolNode (location: (38,0)-(38,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (38,0)-(38,1) = ":"
│ ├── value_loc: (38,1)-(38,3) = "~@"
│ ├── closing_loc: ∅
│ └── unescaped: "~"
├── @ ArrayNode (location: (40,0)-(40,16))
│ ├── flags: newline, static_literal
│ ├── elements: (length: 4)
│ │ ├── @ IntegerNode (location: (40,1)-(40,2))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ ├── @ FloatNode (location: (40,4)-(40,7))
│ │ │ ├── flags: static_literal
│ │ │ └── value: 1.0
│ │ ├── @ RationalNode (location: (40,9)-(40,11))
│ │ │ ├── flags: static_literal, decimal
│ │ │ ├── numerator: 1
│ │ │ └── denominator: 1
│ │ └── @ ImaginaryNode (location: (40,13)-(40,15))
│ │ ├── flags: static_literal
│ │ └── numeric:
│ │ @ IntegerNode (location: (40,13)-(40,14))
│ │ ├── flags: static_literal, decimal
│ │ └── value: 1
│ ├── opening_loc: (40,0)-(40,1) = "["
│ └── closing_loc: (40,15)-(40,16) = "]"
├── @ SymbolNode (location: (42,0)-(42,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (42,0)-(42,1) = ":"
│ ├── value_loc: (42,1)-(42,2) = "~"
│ ├── closing_loc: ∅
│ └── unescaped: "~"
├── @ SymbolNode (location: (44,0)-(44,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (44,0)-(44,1) = ":"
│ ├── value_loc: (44,1)-(44,2) = "a"
│ ├── closing_loc: ∅
│ └── unescaped: "a"
├── @ ArrayNode (location: (46,0)-(46,9))
│ ├── flags: newline, static_literal
│ ├── elements: (length: 3)
│ │ ├── @ SymbolNode (location: (46,3)-(46,4))
│ │ │ ├── flags: static_literal, forced_us_ascii_encoding
│ │ │ ├── opening_loc: ∅
│ │ │ ├── value_loc: (46,3)-(46,4) = "a"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a"
│ │ ├── @ SymbolNode (location: (46,5)-(46,6))
│ │ │ ├── flags: static_literal, forced_us_ascii_encoding
│ │ │ ├── opening_loc: ∅
│ │ │ ├── value_loc: (46,5)-(46,6) = "b"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "b"
│ │ └── @ SymbolNode (location: (46,7)-(46,8))
│ │ ├── flags: static_literal, forced_us_ascii_encoding
│ │ ├── opening_loc: ∅
│ │ ├── value_loc: (46,7)-(46,8) = "c"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "c"
│ ├── opening_loc: (46,0)-(46,3) = "%i["
│ └── closing_loc: (46,8)-(46,9) = "]"
├── @ ArrayNode (location: (48,0)-(48,24))
│ ├── flags: newline, static_literal
│ ├── elements: (length: 4)
│ │ ├── @ SymbolNode (location: (48,3)-(48,4))
│ │ │ ├── flags: static_literal, forced_us_ascii_encoding
│ │ │ ├── opening_loc: ∅
│ │ │ ├── value_loc: (48,3)-(48,4) = "a"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a"
│ │ ├── @ SymbolNode (location: (48,5)-(48,10))
│ │ │ ├── flags: static_literal, forced_us_ascii_encoding
│ │ │ ├── opening_loc: ∅
│ │ │ ├── value_loc: (48,5)-(48,10) = "b\#{1}"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "b\#{1}"
│ │ ├── @ SymbolNode (location: (48,11)-(48,16))
│ │ │ ├── flags: static_literal, forced_us_ascii_encoding
│ │ │ ├── opening_loc: ∅
│ │ │ ├── value_loc: (48,11)-(48,16) = "\#{2}c"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "\#{2}c"
│ │ └── @ SymbolNode (location: (48,17)-(48,23))
│ │ ├── flags: static_literal, forced_us_ascii_encoding
│ │ ├── opening_loc: ∅
│ │ ├── value_loc: (48,17)-(48,23) = "d\#{3}f"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "d\#{3}f"
│ ├── opening_loc: (48,0)-(48,3) = "%i["
│ └── closing_loc: (48,23)-(48,24) = "]"
├── @ ArrayNode (location: (50,0)-(50,24))
│ ├── flags: newline
│ ├── elements: (length: 4)
│ │ ├── @ SymbolNode (location: (50,3)-(50,4))
│ │ │ ├── flags: static_literal, forced_us_ascii_encoding
│ │ │ ├── opening_loc: ∅
│ │ │ ├── value_loc: (50,3)-(50,4) = "a"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "a"
│ │ ├── @ InterpolatedSymbolNode (location: (50,5)-(50,10))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── parts: (length: 2)
│ │ │ │ ├── @ StringNode (location: (50,5)-(50,6))
│ │ │ │ │ ├── flags: static_literal, frozen
│ │ │ │ │ ├── opening_loc: ∅
│ │ │ │ │ ├── content_loc: (50,5)-(50,6) = "b"
│ │ │ │ │ ├── closing_loc: ∅
│ │ │ │ │ └── unescaped: "b"
│ │ │ │ └── @ EmbeddedStatementsNode (location: (50,6)-(50,10))
│ │ │ │ ├── flags: ∅
│ │ │ │ ├── opening_loc: (50,6)-(50,8) = "\#{"
│ │ │ │ ├── statements:
│ │ │ │ │ @ StatementsNode (location: (50,8)-(50,9))
│ │ │ │ │ ├── flags: ∅
│ │ │ │ │ └── body: (length: 1)
│ │ │ │ │ └── @ IntegerNode (location: (50,8)-(50,9))
│ │ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ │ └── value: 1
│ │ │ │ └── closing_loc: (50,9)-(50,10) = "}"
│ │ │ └── closing_loc: ∅
│ │ ├── @ InterpolatedSymbolNode (location: (50,11)-(50,16))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅
│ │ │ ├── parts: (length: 2)
│ │ │ │ ├── @ EmbeddedStatementsNode (location: (50,11)-(50,15))
│ │ │ │ │ ├── flags: ∅
│ │ │ │ │ ├── opening_loc: (50,11)-(50,13) = "\#{"
│ │ │ │ │ ├── statements:
│ │ │ │ │ │ @ StatementsNode (location: (50,13)-(50,14))
│ │ │ │ │ │ ├── flags: ∅
│ │ │ │ │ │ └── body: (length: 1)
│ │ │ │ │ │ └── @ IntegerNode (location: (50,13)-(50,14))
│ │ │ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ │ │ └── value: 2
│ │ │ │ │ └── closing_loc: (50,14)-(50,15) = "}"
│ │ │ │ └── @ StringNode (location: (50,15)-(50,16))
│ │ │ │ ├── flags: static_literal, frozen
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── content_loc: (50,15)-(50,16) = "c"
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── unescaped: "c"
│ │ │ └── closing_loc: ∅
│ │ └── @ InterpolatedSymbolNode (location: (50,17)-(50,23))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── parts: (length: 3)
│ │ │ ├── @ StringNode (location: (50,17)-(50,18))
│ │ │ │ ├── flags: static_literal, frozen
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── content_loc: (50,17)-(50,18) = "d"
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── unescaped: "d"
│ │ │ ├── @ EmbeddedStatementsNode (location: (50,18)-(50,22))
│ │ │ │ ├── flags: ∅
│ │ │ │ ├── opening_loc: (50,18)-(50,20) = "\#{"
│ │ │ │ ├── statements:
│ │ │ │ │ @ StatementsNode (location: (50,20)-(50,21))
│ │ │ │ │ ├── flags: ∅
│ │ │ │ │ └── body: (length: 1)
│ │ │ │ │ └── @ IntegerNode (location: (50,20)-(50,21))
│ │ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ │ └── value: 3
│ │ │ │ └── closing_loc: (50,21)-(50,22) = "}"
│ │ │ └── @ StringNode (location: (50,22)-(50,23))
│ │ │ ├── flags: static_literal, frozen
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (50,22)-(50,23) = "f"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "f"
│ │ └── closing_loc: ∅
│ ├── opening_loc: (50,0)-(50,3) = "%I["
│ └── closing_loc: (50,23)-(50,24) = "]"
├── @ SymbolNode (location: (52,0)-(52,4))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (52,0)-(52,1) = ":"
│ ├── value_loc: (52,1)-(52,4) = "@@a"
│ ├── closing_loc: ∅
│ └── unescaped: "@@a"
├── @ SymbolNode (location: (54,0)-(54,5))
│ ├── flags: newline, static_literal
│ ├── opening_loc: (54,0)-(54,1) = ":"
│ ├── value_loc: (54,1)-(54,5) = "👍"
│ ├── closing_loc: ∅
│ └── unescaped: "👍"
├── @ ArrayNode (location: (56,0)-(56,7))
│ ├── flags: newline, static_literal
│ ├── elements: (length: 1)
│ │ └── @ SymbolNode (location: (56,3)-(56,6))
│ │ ├── flags: static_literal, forced_us_ascii_encoding
│ │ ├── opening_loc: ∅
│ │ ├── value_loc: (56,3)-(56,6) = "a\\b"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "a\\b"
│ ├── opening_loc: (56,0)-(56,3) = "%i["
│ └── closing_loc: (56,6)-(56,7) = "]"
├── @ SymbolNode (location: (58,0)-(58,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (58,0)-(58,1) = ":"
│ ├── value_loc: (58,1)-(58,3) = "$a"
│ ├── closing_loc: ∅
│ └── unescaped: "$a"
├── @ SymbolNode (location: (60,0)-(60,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (60,0)-(60,1) = ":"
│ ├── value_loc: (60,1)-(60,3) = "@a"
│ ├── closing_loc: ∅
│ └── unescaped: "@a"
├── @ SymbolNode (location: (62,0)-(62,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (62,0)-(62,1) = ":"
│ ├── value_loc: (62,1)-(62,3) = "do"
│ ├── closing_loc: ∅
│ └── unescaped: "do"
├── @ SymbolNode (location: (64,0)-(64,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (64,0)-(64,1) = ":"
│ ├── value_loc: (64,1)-(64,2) = "&"
│ ├── closing_loc: ∅
│ └── unescaped: "&"
├── @ SymbolNode (location: (66,0)-(66,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (66,0)-(66,1) = ":"
│ ├── value_loc: (66,1)-(66,2) = "`"
│ ├── closing_loc: ∅
│ └── unescaped: "`"
├── @ SymbolNode (location: (68,0)-(68,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (68,0)-(68,1) = ":"
│ ├── value_loc: (68,1)-(68,3) = "!@"
│ ├── closing_loc: ∅
│ └── unescaped: "!"
├── @ SymbolNode (location: (70,0)-(70,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (70,0)-(70,1) = ":"
│ ├── value_loc: (70,1)-(70,3) = "!~"
│ ├── closing_loc: ∅
│ └── unescaped: "!~"
├── @ SymbolNode (location: (72,0)-(72,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (72,0)-(72,1) = ":"
│ ├── value_loc: (72,1)-(72,2) = "!"
│ ├── closing_loc: ∅
│ └── unescaped: "!"
├── @ SymbolNode (location: (74,0)-(74,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (74,0)-(74,1) = ":"
│ ├── value_loc: (74,1)-(74,3) = "[]"
│ ├── closing_loc: ∅
│ └── unescaped: "[]"
├── @ SymbolNode (location: (76,0)-(76,4))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (76,0)-(76,1) = ":"
│ ├── value_loc: (76,1)-(76,4) = "[]="
│ ├── closing_loc: ∅
│ └── unescaped: "[]="
├── @ SymbolNode (location: (78,0)-(78,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (78,0)-(78,1) = ":"
│ ├── value_loc: (78,1)-(78,2) = "^"
│ ├── closing_loc: ∅
│ └── unescaped: "^"
├── @ SymbolNode (location: (80,0)-(80,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (80,0)-(80,1) = ":"
│ ├── value_loc: (80,1)-(80,3) = "=="
│ ├── closing_loc: ∅
│ └── unescaped: "=="
├── @ SymbolNode (location: (82,0)-(82,4))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (82,0)-(82,1) = ":"
│ ├── value_loc: (82,1)-(82,4) = "==="
│ ├── closing_loc: ∅
│ └── unescaped: "==="
├── @ SymbolNode (location: (84,0)-(84,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (84,0)-(84,1) = ":"
│ ├── value_loc: (84,1)-(84,3) = "=~"
│ ├── closing_loc: ∅
│ └── unescaped: "=~"
├── @ SymbolNode (location: (86,0)-(86,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (86,0)-(86,1) = ":"
│ ├── value_loc: (86,1)-(86,3) = ">="
│ ├── closing_loc: ∅
│ └── unescaped: ">="
├── @ SymbolNode (location: (88,0)-(88,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (88,0)-(88,1) = ":"
│ ├── value_loc: (88,1)-(88,3) = ">>"
│ ├── closing_loc: ∅
│ └── unescaped: ">>"
├── @ SymbolNode (location: (90,0)-(90,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (90,0)-(90,1) = ":"
│ ├── value_loc: (90,1)-(90,2) = ">"
│ ├── closing_loc: ∅
│ └── unescaped: ">"
├── @ SymbolNode (location: (92,0)-(92,4))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (92,0)-(92,1) = ":"
│ ├── value_loc: (92,1)-(92,4) = "<=>"
│ ├── closing_loc: ∅
│ └── unescaped: "<=>"
├── @ SymbolNode (location: (94,0)-(94,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (94,0)-(94,1) = ":"
│ ├── value_loc: (94,1)-(94,3) = "<="
│ ├── closing_loc: ∅
│ └── unescaped: "<="
├── @ SymbolNode (location: (96,0)-(96,3))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (96,0)-(96,1) = ":"
│ ├── value_loc: (96,1)-(96,3) = "<<"
│ ├── closing_loc: ∅
│ └── unescaped: "<<"
├── @ SymbolNode (location: (98,0)-(98,2))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (98,0)-(98,1) = ":"
│ ├── value_loc: (98,1)-(98,2) = "<"
│ ├── closing_loc: ∅
│ └── unescaped: "<"
├── @ SymbolNode (location: (100,0)-(100,9))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (100,0)-(100,1) = ":"
│ ├── value_loc: (100,1)-(100,9) = "__LINE__"
│ ├── closing_loc: ∅
│ └── unescaped: "__LINE__"
├── @ SymbolNode (location: (102,0)-(102,9))
│ ├── flags: newline, static_literal, forced_us_ascii_encoding
│ ├── opening_loc: (102,0)-(102,1) = ":"
│ ├── value_loc: (102,1)-(102,9) = "__FILE__"
│ ├── closing_loc: ∅
│ └── unescaped: "__FILE__"
└── @ SymbolNode (location: (104,0)-(104,13))
├── flags: newline, static_literal, forced_us_ascii_encoding
├── opening_loc: (104,0)-(104,1) = ":"
├── value_loc: (104,1)-(104,13) = "__ENCODING__"
├── closing_loc: ∅
└── unescaped: "__ENCODING__"

View File

@ -1,488 +0,0 @@
@ ProgramNode (location: (1,0)-(49,10))
├── flags: ∅
├── locals: [:abc, :foo, :bar, :baz, :a, :b, :c, :d]
└── statements:
@ StatementsNode (location: (1,0)-(49,10))
├── flags: ∅
└── body: (length: 26)
├── @ ClassVariableReadNode (location: (1,0)-(1,5))
│ ├── flags: newline
│ └── name: :@@abc
├── @ ClassVariableWriteNode (location: (3,0)-(3,9))
│ ├── flags: newline
│ ├── name: :@@abc
│ ├── name_loc: (3,0)-(3,5) = "@@abc"
│ ├── value:
│ │ @ IntegerNode (location: (3,8)-(3,9))
│ │ ├── flags: static_literal, decimal
│ │ └── value: 1
│ └── operator_loc: (3,6)-(3,7) = "="
├── @ MultiWriteNode (location: (5,0)-(5,16))
│ ├── flags: newline
│ ├── lefts: (length: 2)
│ │ ├── @ ClassVariableTargetNode (location: (5,0)-(5,5))
│ │ │ ├── flags: ∅
│ │ │ └── name: :@@foo
│ │ └── @ ClassVariableTargetNode (location: (5,7)-(5,12))
│ │ ├── flags: ∅
│ │ └── name: :@@bar
│ ├── rest: ∅
│ ├── rights: (length: 0)
│ ├── lparen_loc: ∅
│ ├── rparen_loc: ∅
│ ├── operator_loc: (5,13)-(5,14) = "="
│ └── value:
│ @ IntegerNode (location: (5,15)-(5,16))
│ ├── flags: static_literal, decimal
│ └── value: 1
├── @ ClassVariableWriteNode (location: (7,0)-(7,12))
│ ├── flags: newline
│ ├── name: :@@foo
│ ├── name_loc: (7,0)-(7,5) = "@@foo"
│ ├── value:
│ │ @ ArrayNode (location: (7,8)-(7,12))
│ │ ├── flags: static_literal
│ │ ├── elements: (length: 2)
│ │ │ ├── @ IntegerNode (location: (7,8)-(7,9))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ └── @ IntegerNode (location: (7,11)-(7,12))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 2
│ │ ├── opening_loc: ∅
│ │ └── closing_loc: ∅
│ └── operator_loc: (7,6)-(7,7) = "="
├── @ GlobalVariableWriteNode (location: (9,0)-(9,8))
│ ├── flags: newline
│ ├── name: :$abc
│ ├── name_loc: (9,0)-(9,4) = "$abc"
│ ├── value:
│ │ @ IntegerNode (location: (9,7)-(9,8))
│ │ ├── flags: static_literal, decimal
│ │ └── value: 1
│ └── operator_loc: (9,5)-(9,6) = "="
├── @ GlobalVariableReadNode (location: (11,0)-(11,4))
│ ├── flags: newline
│ └── name: :$abc
├── @ InstanceVariableReadNode (location: (13,0)-(13,4))
│ ├── flags: newline
│ └── name: :@abc
├── @ InstanceVariableWriteNode (location: (15,0)-(15,8))
│ ├── flags: newline
│ ├── name: :@abc
│ ├── name_loc: (15,0)-(15,4) = "@abc"
│ ├── value:
│ │ @ IntegerNode (location: (15,7)-(15,8))
│ │ ├── flags: static_literal, decimal
│ │ └── value: 1
│ └── operator_loc: (15,5)-(15,6) = "="
├── @ CallNode (location: (17,0)-(17,1))
│ ├── flags: newline, variable_call, ignore_visibility
│ ├── receiver: ∅
│ ├── call_operator_loc: ∅
│ ├── name: :a
│ ├── message_loc: (17,0)-(17,1) = "a"
│ ├── opening_loc: ∅
│ ├── arguments: ∅
│ ├── closing_loc: ∅
│ └── block: ∅
├── @ LocalVariableWriteNode (location: (19,0)-(19,7))
│ ├── flags: newline
│ ├── name: :abc
│ ├── depth: 0
│ ├── name_loc: (19,0)-(19,3) = "abc"
│ ├── value:
│ │ @ IntegerNode (location: (19,6)-(19,7))
│ │ ├── flags: static_literal, decimal
│ │ └── value: 1
│ └── operator_loc: (19,4)-(19,5) = "="
├── @ MultiWriteNode (location: (21,0)-(21,14))
│ ├── flags: newline
│ ├── lefts: (length: 2)
│ │ ├── @ GlobalVariableTargetNode (location: (21,0)-(21,4))
│ │ │ ├── flags: ∅
│ │ │ └── name: :$foo
│ │ └── @ GlobalVariableTargetNode (location: (21,6)-(21,10))
│ │ ├── flags: ∅
│ │ └── name: :$bar
│ ├── rest: ∅
│ ├── rights: (length: 0)
│ ├── lparen_loc: ∅
│ ├── rparen_loc: ∅
│ ├── operator_loc: (21,11)-(21,12) = "="
│ └── value:
│ @ IntegerNode (location: (21,13)-(21,14))
│ ├── flags: static_literal, decimal
│ └── value: 1
├── @ GlobalVariableWriteNode (location: (23,0)-(23,11))
│ ├── flags: newline
│ ├── name: :$foo
│ ├── name_loc: (23,0)-(23,4) = "$foo"
│ ├── value:
│ │ @ ArrayNode (location: (23,7)-(23,11))
│ │ ├── flags: static_literal
│ │ ├── elements: (length: 2)
│ │ │ ├── @ IntegerNode (location: (23,7)-(23,8))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ └── @ IntegerNode (location: (23,10)-(23,11))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 2
│ │ ├── opening_loc: ∅
│ │ └── closing_loc: ∅
│ └── operator_loc: (23,5)-(23,6) = "="
├── @ MultiWriteNode (location: (25,0)-(25,14))
│ ├── flags: newline
│ ├── lefts: (length: 2)
│ │ ├── @ InstanceVariableTargetNode (location: (25,0)-(25,4))
│ │ │ ├── flags: ∅
│ │ │ └── name: :@foo
│ │ └── @ InstanceVariableTargetNode (location: (25,6)-(25,10))
│ │ ├── flags: ∅
│ │ └── name: :@bar
│ ├── rest: ∅
│ ├── rights: (length: 0)
│ ├── lparen_loc: ∅
│ ├── rparen_loc: ∅
│ ├── operator_loc: (25,11)-(25,12) = "="
│ └── value:
│ @ IntegerNode (location: (25,13)-(25,14))
│ ├── flags: static_literal, decimal
│ └── value: 1
├── @ InstanceVariableWriteNode (location: (27,0)-(27,11))
│ ├── flags: newline
│ ├── name: :@foo
│ ├── name_loc: (27,0)-(27,4) = "@foo"
│ ├── value:
│ │ @ ArrayNode (location: (27,7)-(27,11))
│ │ ├── flags: static_literal
│ │ ├── elements: (length: 2)
│ │ │ ├── @ IntegerNode (location: (27,7)-(27,8))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ └── @ IntegerNode (location: (27,10)-(27,11))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 2
│ │ ├── opening_loc: ∅
│ │ └── closing_loc: ∅
│ └── operator_loc: (27,5)-(27,6) = "="
├── @ LocalVariableWriteNode (location: (29,0)-(29,7))
│ ├── flags: newline
│ ├── name: :foo
│ ├── depth: 0
│ ├── name_loc: (29,0)-(29,3) = "foo"
│ ├── value:
│ │ @ IntegerNode (location: (29,6)-(29,7))
│ │ ├── flags: static_literal, decimal
│ │ └── value: 1
│ └── operator_loc: (29,4)-(29,5) = "="
├── @ LocalVariableWriteNode (location: (29,9)-(29,19))
│ ├── flags: newline
│ ├── name: :foo
│ ├── depth: 0
│ ├── name_loc: (29,9)-(29,12) = "foo"
│ ├── value:
│ │ @ ArrayNode (location: (29,15)-(29,19))
│ │ ├── flags: static_literal
│ │ ├── elements: (length: 2)
│ │ │ ├── @ IntegerNode (location: (29,15)-(29,16))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ └── @ IntegerNode (location: (29,18)-(29,19))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 2
│ │ ├── opening_loc: ∅
│ │ └── closing_loc: ∅
│ └── operator_loc: (29,13)-(29,14) = "="
├── @ LocalVariableWriteNode (location: (31,0)-(31,10))
│ ├── flags: newline
│ ├── name: :foo
│ ├── depth: 0
│ ├── name_loc: (31,0)-(31,3) = "foo"
│ ├── value:
│ │ @ ArrayNode (location: (31,6)-(31,10))
│ │ ├── flags: static_literal
│ │ ├── elements: (length: 2)
│ │ │ ├── @ IntegerNode (location: (31,6)-(31,7))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ └── @ IntegerNode (location: (31,9)-(31,10))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 2
│ │ ├── opening_loc: ∅
│ │ └── closing_loc: ∅
│ └── operator_loc: (31,4)-(31,5) = "="
├── @ MultiWriteNode (location: (33,0)-(33,13))
│ ├── flags: newline
│ ├── lefts: (length: 1)
│ │ └── @ LocalVariableTargetNode (location: (33,0)-(33,3))
│ │ ├── flags: ∅
│ │ ├── name: :foo
│ │ └── depth: 0
│ ├── rest:
│ │ @ SplatNode (location: (33,5)-(33,6))
│ │ ├── flags: ∅
│ │ ├── operator_loc: (33,5)-(33,6) = "*"
│ │ └── expression: ∅
│ ├── rights: (length: 0)
│ ├── lparen_loc: ∅
│ ├── rparen_loc: ∅
│ ├── operator_loc: (33,7)-(33,8) = "="
│ └── value:
│ @ ArrayNode (location: (33,9)-(33,13))
│ ├── flags: static_literal
│ ├── elements: (length: 2)
│ │ ├── @ IntegerNode (location: (33,9)-(33,10))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ └── @ IntegerNode (location: (33,12)-(33,13))
│ │ ├── flags: static_literal, decimal
│ │ └── value: 2
│ ├── opening_loc: ∅
│ └── closing_loc: ∅
├── @ MultiWriteNode (location: (35,0)-(35,11))
│ ├── flags: newline
│ ├── lefts: (length: 1)
│ │ └── @ LocalVariableTargetNode (location: (35,0)-(35,3))
│ │ ├── flags: ∅
│ │ ├── name: :foo
│ │ └── depth: 0
│ ├── rest:
│ │ @ ImplicitRestNode (location: (35,3)-(35,4))
│ │ └── flags: ∅
│ ├── rights: (length: 0)
│ ├── lparen_loc: ∅
│ ├── rparen_loc: ∅
│ ├── operator_loc: (35,5)-(35,6) = "="
│ └── value:
│ @ ArrayNode (location: (35,7)-(35,11))
│ ├── flags: static_literal
│ ├── elements: (length: 2)
│ │ ├── @ IntegerNode (location: (35,7)-(35,8))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ └── @ IntegerNode (location: (35,10)-(35,11))
│ │ ├── flags: static_literal, decimal
│ │ └── value: 2
│ ├── opening_loc: ∅
│ └── closing_loc: ∅
├── @ MultiWriteNode (location: (37,0)-(37,16))
│ ├── flags: newline
│ ├── lefts: (length: 1)
│ │ └── @ LocalVariableTargetNode (location: (37,0)-(37,3))
│ │ ├── flags: ∅
│ │ ├── name: :foo
│ │ └── depth: 0
│ ├── rest:
│ │ @ SplatNode (location: (37,5)-(37,9))
│ │ ├── flags: ∅
│ │ ├── operator_loc: (37,5)-(37,6) = "*"
│ │ └── expression:
│ │ @ LocalVariableTargetNode (location: (37,6)-(37,9))
│ │ ├── flags: ∅
│ │ ├── name: :bar
│ │ └── depth: 0
│ ├── rights: (length: 0)
│ ├── lparen_loc: ∅
│ ├── rparen_loc: ∅
│ ├── operator_loc: (37,10)-(37,11) = "="
│ └── value:
│ @ ArrayNode (location: (37,12)-(37,16))
│ ├── flags: static_literal
│ ├── elements: (length: 2)
│ │ ├── @ IntegerNode (location: (37,12)-(37,13))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ └── @ IntegerNode (location: (37,15)-(37,16))
│ │ ├── flags: static_literal, decimal
│ │ └── value: 2
│ ├── opening_loc: ∅
│ └── closing_loc: ∅
├── @ MultiWriteNode (location: (39,0)-(39,27))
│ ├── flags: newline
│ ├── lefts: (length: 2)
│ │ ├── @ LocalVariableTargetNode (location: (39,0)-(39,3))
│ │ │ ├── flags: ∅
│ │ │ ├── name: :foo
│ │ │ └── depth: 0
│ │ └── @ MultiTargetNode (location: (39,5)-(39,15))
│ │ ├── flags: ∅
│ │ ├── lefts: (length: 2)
│ │ │ ├── @ LocalVariableTargetNode (location: (39,6)-(39,9))
│ │ │ │ ├── flags: ∅
│ │ │ │ ├── name: :bar
│ │ │ │ └── depth: 0
│ │ │ └── @ LocalVariableTargetNode (location: (39,11)-(39,14))
│ │ │ ├── flags: ∅
│ │ │ ├── name: :baz
│ │ │ └── depth: 0
│ │ ├── rest: ∅
│ │ ├── rights: (length: 0)
│ │ ├── lparen_loc: (39,5)-(39,6) = "("
│ │ └── rparen_loc: (39,14)-(39,15) = ")"
│ ├── rest: ∅
│ ├── rights: (length: 0)
│ ├── lparen_loc: ∅
│ ├── rparen_loc: ∅
│ ├── operator_loc: (39,16)-(39,17) = "="
│ └── value:
│ @ ArrayNode (location: (39,18)-(39,27))
│ ├── flags: ∅
│ ├── elements: (length: 2)
│ │ ├── @ IntegerNode (location: (39,18)-(39,19))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 1
│ │ └── @ ArrayNode (location: (39,21)-(39,27))
│ │ ├── flags: static_literal
│ │ ├── elements: (length: 2)
│ │ │ ├── @ IntegerNode (location: (39,22)-(39,23))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 2
│ │ │ └── @ IntegerNode (location: (39,25)-(39,26))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 3
│ │ ├── opening_loc: (39,21)-(39,22) = "["
│ │ └── closing_loc: (39,26)-(39,27) = "]"
│ ├── opening_loc: ∅
│ └── closing_loc: ∅
├── @ LocalVariableWriteNode (location: (41,0)-(41,10))
│ ├── flags: newline
│ ├── name: :foo
│ ├── depth: 0
│ ├── name_loc: (41,0)-(41,3) = "foo"
│ ├── value:
│ │ @ ArrayNode (location: (41,6)-(41,10))
│ │ ├── flags: contains_splat
│ │ ├── elements: (length: 1)
│ │ │ └── @ SplatNode (location: (41,6)-(41,10))
│ │ │ ├── flags: ∅
│ │ │ ├── operator_loc: (41,6)-(41,7) = "*"
│ │ │ └── expression:
│ │ │ @ LocalVariableReadNode (location: (41,7)-(41,10))
│ │ │ ├── flags: ∅
│ │ │ ├── name: :bar
│ │ │ └── depth: 0
│ │ ├── opening_loc: ∅
│ │ └── closing_loc: ∅
│ └── operator_loc: (41,4)-(41,5) = "="
├── @ ConstantWriteNode (location: (43,0)-(43,10))
│ ├── flags: newline
│ ├── name: :Foo
│ ├── name_loc: (43,0)-(43,3) = "Foo"
│ ├── value:
│ │ @ ArrayNode (location: (43,6)-(43,10))
│ │ ├── flags: static_literal
│ │ ├── elements: (length: 2)
│ │ │ ├── @ IntegerNode (location: (43,6)-(43,7))
│ │ │ │ ├── flags: static_literal, decimal
│ │ │ │ └── value: 1
│ │ │ └── @ IntegerNode (location: (43,9)-(43,10))
│ │ │ ├── flags: static_literal, decimal
│ │ │ └── value: 2
│ │ ├── opening_loc: ∅
│ │ └── closing_loc: ∅
│ └── operator_loc: (43,4)-(43,5) = "="
├── @ ParenthesesNode (location: (45,0)-(45,9))
│ ├── flags: newline
│ ├── body:
│ │ @ StatementsNode (location: (45,1)-(45,8))
│ │ ├── flags: ∅
│ │ └── body: (length: 3)
│ │ ├── @ CallNode (location: (45,1)-(45,2))
│ │ │ ├── flags: newline, variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :a
│ │ │ ├── message_loc: (45,1)-(45,2) = "a"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ ├── @ CallNode (location: (45,4)-(45,5))
│ │ │ ├── flags: newline, variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :b
│ │ │ ├── message_loc: (45,4)-(45,5) = "b"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ └── @ CallNode (location: (45,7)-(45,8))
│ │ ├── flags: newline, variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :c
│ │ ├── message_loc: (45,7)-(45,8) = "c"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── opening_loc: (45,0)-(45,1) = "("
│ └── closing_loc: (45,8)-(45,9) = ")"
├── @ MultiWriteNode (location: (47,0)-(47,17))
│ ├── flags: newline
│ ├── lefts: (length: 3)
│ │ ├── @ LocalVariableTargetNode (location: (47,0)-(47,1))
│ │ │ ├── flags: ∅
│ │ │ ├── name: :a
│ │ │ └── depth: 0
│ │ ├── @ MultiTargetNode (location: (47,3)-(47,9))
│ │ │ ├── flags: ∅
│ │ │ ├── lefts: (length: 2)
│ │ │ │ ├── @ LocalVariableTargetNode (location: (47,4)-(47,5))
│ │ │ │ │ ├── flags: ∅
│ │ │ │ │ ├── name: :b
│ │ │ │ │ └── depth: 0
│ │ │ │ └── @ LocalVariableTargetNode (location: (47,7)-(47,8))
│ │ │ │ ├── flags: ∅
│ │ │ │ ├── name: :c
│ │ │ │ └── depth: 0
│ │ │ ├── rest: ∅
│ │ │ ├── rights: (length: 0)
│ │ │ ├── lparen_loc: (47,3)-(47,4) = "("
│ │ │ └── rparen_loc: (47,8)-(47,9) = ")"
│ │ └── @ LocalVariableTargetNode (location: (47,11)-(47,12))
│ │ ├── flags: ∅
│ │ ├── name: :d
│ │ └── depth: 0
│ ├── rest: ∅
│ ├── rights: (length: 0)
│ ├── lparen_loc: ∅
│ ├── rparen_loc: ∅
│ ├── operator_loc: (47,13)-(47,14) = "="
│ └── value:
│ @ ArrayNode (location: (47,15)-(47,17))
│ ├── flags: static_literal
│ ├── elements: (length: 0)
│ ├── opening_loc: (47,15)-(47,16) = "["
│ └── closing_loc: (47,16)-(47,17) = "]"
└── @ MultiWriteNode (location: (49,0)-(49,10))
├── flags: newline
├── lefts: (length: 1)
│ └── @ MultiTargetNode (location: (49,0)-(49,4))
│ ├── flags: ∅
│ ├── lefts: (length: 1)
│ │ └── @ LocalVariableTargetNode (location: (49,1)-(49,2))
│ │ ├── flags: ∅
│ │ ├── name: :a
│ │ └── depth: 0
│ ├── rest:
│ │ @ ImplicitRestNode (location: (49,2)-(49,3))
│ │ └── flags: ∅
│ ├── rights: (length: 0)
│ ├── lparen_loc: (49,0)-(49,1) = "("
│ └── rparen_loc: (49,3)-(49,4) = ")"
├── rest:
│ @ ImplicitRestNode (location: (49,4)-(49,5))
│ └── flags: ∅
├── rights: (length: 0)
├── lparen_loc: ∅
├── rparen_loc: ∅
├── operator_loc: (49,6)-(49,7) = "="
└── value:
@ ArrayNode (location: (49,8)-(49,10))
├── flags: static_literal
├── elements: (length: 0)
├── opening_loc: (49,8)-(49,9) = "["
└── closing_loc: (49,9)-(49,10) = "]"

View File

@ -1,77 +0,0 @@
# frozen_string_literal: true
require_relative "test_helper"
# We don't want to generate snapshots when running
# against files outside of the project folder.
return if Prism::TestCase::Fixture.custom_base_path?
module Prism
class SnapshotsTest < TestCase
# When we pretty-print the trees to compare against the snapshots, we want
# to be certain that we print with the same external encoding. This is
# because methods like Symbol#inspect take into account external encoding
# and it could change how the snapshot is generated. On machines with
# certain settings (like LANG=C or -Eascii-8bit) this could have been
# changed. So here we're going to force it to be UTF-8 to keep the snapshots
# consistent.
def setup
@previous_default_external = Encoding.default_external
ignore_warnings { Encoding.default_external = Encoding::UTF_8 }
end
def teardown
ignore_warnings { Encoding.default_external = @previous_default_external }
end
except = []
# These fail on TruffleRuby due to a difference in Symbol#inspect:
# :测试 vs :"测试"
if RUBY_ENGINE == "truffleruby"
except.push(
"emoji_method_calls.txt",
"seattlerb/bug202.txt",
"seattlerb/magic_encoding_comment.txt"
)
end
Fixture.each(except: except) do |fixture|
define_method(fixture.test_name) { assert_snapshot(fixture) }
end
private
def assert_snapshot(fixture)
source = fixture.read
result = Prism.parse(source, filepath: fixture.path)
assert result.success?
printed = PP.pp(result.value, +"", 79)
snapshot = fixture.snapshot_path
if File.exist?(snapshot)
saved = File.read(snapshot)
# If the snapshot file exists, but the printed value does not match the
# snapshot, then update the snapshot file.
if printed != saved
File.write(snapshot, printed)
warn("Updated snapshot at #{snapshot}.")
end
# If the snapshot file exists, then assert that the printed value
# matches the snapshot.
assert_equal(saved, printed)
else
# If the snapshot file does not yet exist, then write it out now.
directory = File.dirname(snapshot)
FileUtils.mkdir_p(directory) unless File.directory?(directory)
File.write(snapshot, printed)
warn("Created snapshot at #{snapshot}.")
end
end
end
end