summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--prism/config.yml11
-rw-r--r--prism/prism.c56
-rw-r--r--test/prism/location_test.rb5
-rw-r--r--test/prism/snapshots/dos_endings.txt31
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_evstr_after_break.txt59
-rw-r--r--test/prism/snapshots/seattlerb/str_lit_concat_bad_encodings.txt31
-rw-r--r--test/prism/snapshots/strings.txt31
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/literal.txt31
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/dstr.txt269
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11990.txt31
-rw-r--r--test/prism/snapshots/whitequark/string_concat.txt49
11 files changed, 293 insertions, 311 deletions
diff --git a/prism/config.yml b/prism/config.yml
index ef12f7a730..6cd98b52a3 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -2370,17 +2370,6 @@ nodes:
foo; bar; baz
^^^^^^^^^^^^^
- - name: StringConcatNode
- fields:
- - name: left
- type: node
- - name: right
- type: node
- comment: |
- Represents the use of compile-time string concatenation.
-
- "foo" "bar"
- ^^^^^^^^^^^
- name: StringNode
fields:
- name: flags
diff --git a/prism/prism.c b/prism/prism.c
index 09ccaf70cf..21eb8f07fd 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -5128,28 +5128,6 @@ pm_statements_node_body_append(pm_statements_node_t *node, pm_node_t *statement)
}
/**
- * Allocate a new StringConcatNode node.
- */
-static pm_string_concat_node_t *
-pm_string_concat_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right) {
- pm_string_concat_node_t *node = PM_ALLOC_NODE(parser, pm_string_concat_node_t);
-
- *node = (pm_string_concat_node_t) {
- {
- .type = PM_STRING_CONCAT_NODE,
- .location = {
- .start = left->location.start,
- .end = right->location.end
- }
- },
- .left = left,
- .right = right
- };
-
- return node;
-}
-
-/**
* Allocate a new StringNode node with the current string on the parser.
*/
static inline pm_string_node_t *
@@ -13470,9 +13448,10 @@ parse_strings_empty_content(const uint8_t *location) {
* Parse a set of strings that could be concatenated together.
*/
static inline pm_node_t *
-parse_strings(pm_parser_t *parser) {
+parse_strings(pm_parser_t *parser, pm_node_t *current) {
assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
- pm_node_t *result = NULL;
+
+ bool concating = false;
bool state_is_arg_labeled = lex_state_p(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
@@ -13608,7 +13587,7 @@ parse_strings(pm_parser_t *parser) {
}
}
- if (result == NULL) {
+ if (current == NULL) {
// If the node we just parsed is a symbol node, then we can't
// concatenate it with anything else, so we can now return that
// node.
@@ -13618,7 +13597,7 @@ parse_strings(pm_parser_t *parser) {
// If we don't already have a node, then it's fine and we can just
// set the result to be the node we just parsed.
- result = node;
+ current = node;
} else {
// Otherwise we need to check the type of the node we just parsed.
// If it cannot be concatenated with the previous node, then we'll
@@ -13627,13 +13606,22 @@ parse_strings(pm_parser_t *parser) {
pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
}
- // Either way we will create a concat node to hold the strings
- // together.
- result = (pm_node_t *) pm_string_concat_node_create(parser, result, node);
+ // If we haven't already created our container for concatenation,
+ // we'll do that now.
+ if (!concating) {
+ concating = true;
+ pm_token_t bounds = not_provided(parser);
+
+ pm_interpolated_string_node_t *container = pm_interpolated_string_node_create(parser, &bounds, NULL, &bounds);
+ pm_interpolated_string_node_append(container, current);
+ current = (pm_node_t *) container;
+ }
+
+ pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node);
}
}
- return result;
+ return current;
}
/**
@@ -13894,8 +13882,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
// Characters can be followed by strings in which case they are
// automatically concatenated.
if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- pm_node_t *concat = parse_strings(parser);
- return (pm_node_t *) pm_string_concat_node_create(parser, node, concat);
+ return parse_strings(parser, node);
}
return node;
@@ -14169,8 +14156,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
}
if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- pm_node_t *concat = parse_strings(parser);
- return (pm_node_t *) pm_string_concat_node_create(parser, node, concat);
+ return parse_strings(parser, node);
}
return node;
@@ -15773,7 +15759,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
return (pm_node_t *) node;
}
case PM_TOKEN_STRING_BEGIN:
- return parse_strings(parser);
+ return parse_strings(parser, NULL);
case PM_TOKEN_SYMBOL_BEGIN: {
pm_lex_mode_t lex_mode = *parser->lex_modes.current;
parser_lex(parser);
diff --git a/test/prism/location_test.rb b/test/prism/location_test.rb
index 02a577a73c..302e6bd139 100644
--- a/test/prism/location_test.rb
+++ b/test/prism/location_test.rb
@@ -495,6 +495,7 @@ module Prism
def test_InterpolatedStringNode
assert_location(InterpolatedStringNode, "\"foo \#@bar baz\"")
assert_location(InterpolatedStringNode, "<<~A\nhello \#{1} world\nA", 0...4)
+ assert_location(InterpolatedStringNode, '"foo" "bar"')
end
def test_InterpolatedSymbolNode
@@ -789,10 +790,6 @@ module Prism
assert_location(StatementsNode, "\"\#{foo}\"", 3...6) { |node| node.parts.first.statements }
end
- def test_StringConcatNode
- assert_location(StringConcatNode, '"foo" "bar"')
- end
-
def test_StringNode
assert_location(StringNode, '"foo"')
assert_location(StringNode, '%q[foo]')
diff --git a/test/prism/snapshots/dos_endings.txt b/test/prism/snapshots/dos_endings.txt
index 758334138c..3097a36164 100644
--- a/test/prism/snapshots/dos_endings.txt
+++ b/test/prism/snapshots/dos_endings.txt
@@ -11,21 +11,22 @@
│ ├── arguments:
│ │ @ ArgumentsNode (location: (1,5)-(2,12))
│ │ ├── arguments: (length: 1)
- │ │ │ └── @ StringConcatNode (location: (1,5)-(2,12))
- │ │ │ ├── left:
- │ │ │ │ @ StringNode (location: (1,5)-(1,9))
- │ │ │ │ ├── flags: ∅
- │ │ │ │ ├── opening_loc: (1,5)-(1,6) = "\""
- │ │ │ │ ├── content_loc: (1,6)-(1,8) = "hi"
- │ │ │ │ ├── closing_loc: (1,8)-(1,9) = "\""
- │ │ │ │ └── unescaped: "hi"
- │ │ │ └── right:
- │ │ │ @ StringNode (location: (2,5)-(2,12))
- │ │ │ ├── flags: ∅
- │ │ │ ├── opening_loc: (2,5)-(2,6) = "\""
- │ │ │ ├── content_loc: (2,6)-(2,11) = "there"
- │ │ │ ├── closing_loc: (2,11)-(2,12) = "\""
- │ │ │ └── unescaped: "there"
+ │ │ │ └── @ InterpolatedStringNode (location: (1,5)-(2,12))
+ │ │ │ ├── opening_loc: ∅
+ │ │ │ ├── parts: (length: 2)
+ │ │ │ │ ├── @ StringNode (location: (1,5)-(1,9))
+ │ │ │ │ │ ├── flags: ∅
+ │ │ │ │ │ ├── opening_loc: (1,5)-(1,6) = "\""
+ │ │ │ │ │ ├── content_loc: (1,6)-(1,8) = "hi"
+ │ │ │ │ │ ├── closing_loc: (1,8)-(1,9) = "\""
+ │ │ │ │ │ └── unescaped: "hi"
+ │ │ │ │ └── @ StringNode (location: (2,5)-(2,12))
+ │ │ │ │ ├── flags: ∅
+ │ │ │ │ ├── opening_loc: (2,5)-(2,6) = "\""
+ │ │ │ │ ├── content_loc: (2,6)-(2,11) = "there"
+ │ │ │ │ ├── closing_loc: (2,11)-(2,12) = "\""
+ │ │ │ │ └── unescaped: "there"
+ │ │ │ └── closing_loc: ∅
│ │ └── flags: ∅
│ ├── closing_loc: ∅
│ ├── block: ∅
diff --git a/test/prism/snapshots/seattlerb/parse_line_evstr_after_break.txt b/test/prism/snapshots/seattlerb/parse_line_evstr_after_break.txt
index 662bd86c05..145da454dc 100644
--- a/test/prism/snapshots/seattlerb/parse_line_evstr_after_break.txt
+++ b/test/prism/snapshots/seattlerb/parse_line_evstr_after_break.txt
@@ -3,32 +3,33 @@
└── statements:
@ StatementsNode (location: (1,0)-(2,6))
└── body: (length: 1)
- └── @ StringConcatNode (location: (1,0)-(2,6))
- ├── left:
- │ @ StringNode (location: (1,0)-(1,3))
- │ ├── flags: ∅
- │ ├── opening_loc: (1,0)-(1,1) = "\""
- │ ├── content_loc: (1,1)-(1,2) = "a"
- │ ├── closing_loc: (1,2)-(1,3) = "\""
- │ └── unescaped: "a"
- └── right:
- @ InterpolatedStringNode (location: (2,0)-(2,6))
- ├── opening_loc: (2,0)-(2,1) = "\""
- ├── parts: (length: 1)
- │ └── @ EmbeddedStatementsNode (location: (2,1)-(2,5))
- │ ├── opening_loc: (2,1)-(2,3) = "\#{"
- │ ├── statements:
- │ │ @ StatementsNode (location: (2,3)-(2,4))
- │ │ └── body: (length: 1)
- │ │ └── @ CallNode (location: (2,3)-(2,4))
- │ │ ├── receiver: ∅
- │ │ ├── call_operator_loc: ∅
- │ │ ├── message_loc: (2,3)-(2,4) = "b"
- │ │ ├── opening_loc: ∅
- │ │ ├── arguments: ∅
- │ │ ├── closing_loc: ∅
- │ │ ├── block: ∅
- │ │ ├── flags: variable_call
- │ │ └── name: :b
- │ └── closing_loc: (2,4)-(2,5) = "}"
- └── closing_loc: (2,5)-(2,6) = "\""
+ └── @ InterpolatedStringNode (location: (1,0)-(2,6))
+ ├── opening_loc: ∅
+ ├── parts: (length: 2)
+ │ ├── @ StringNode (location: (1,0)-(1,3))
+ │ │ ├── flags: ∅
+ │ │ ├── opening_loc: (1,0)-(1,1) = "\""
+ │ │ ├── content_loc: (1,1)-(1,2) = "a"
+ │ │ ├── closing_loc: (1,2)-(1,3) = "\""
+ │ │ └── unescaped: "a"
+ │ └── @ InterpolatedStringNode (location: (2,0)-(2,6))
+ │ ├── opening_loc: (2,0)-(2,1) = "\""
+ │ ├── parts: (length: 1)
+ │ │ └── @ EmbeddedStatementsNode (location: (2,1)-(2,5))
+ │ │ ├── opening_loc: (2,1)-(2,3) = "\#{"
+ │ │ ├── statements:
+ │ │ │ @ StatementsNode (location: (2,3)-(2,4))
+ │ │ │ └── body: (length: 1)
+ │ │ │ └── @ CallNode (location: (2,3)-(2,4))
+ │ │ │ ├── receiver: ∅
+ │ │ │ ├── call_operator_loc: ∅
+ │ │ │ ├── message_loc: (2,3)-(2,4) = "b"
+ │ │ │ ├── opening_loc: ∅
+ │ │ │ ├── arguments: ∅
+ │ │ │ ├── closing_loc: ∅
+ │ │ │ ├── block: ∅
+ │ │ │ ├── flags: variable_call
+ │ │ │ └── name: :b
+ │ │ └── closing_loc: (2,4)-(2,5) = "}"
+ │ └── closing_loc: (2,5)-(2,6) = "\""
+ └── closing_loc: ∅
diff --git a/test/prism/snapshots/seattlerb/str_lit_concat_bad_encodings.txt b/test/prism/snapshots/seattlerb/str_lit_concat_bad_encodings.txt
index 7bf71b7858..f1226f34e2 100644
--- a/test/prism/snapshots/seattlerb/str_lit_concat_bad_encodings.txt
+++ b/test/prism/snapshots/seattlerb/str_lit_concat_bad_encodings.txt
@@ -3,18 +3,19 @@
└── statements:
@ StatementsNode (location: (1,0)-(2,66))
└── body: (length: 1)
- └── @ StringConcatNode (location: (1,0)-(2,66))
- ├── left:
- │ @ StringNode (location: (1,0)-(1,62))
- │ ├── flags: ∅
- │ ├── opening_loc: (1,0)-(1,1) = "\""
- │ ├── content_loc: (1,1)-(1,61) = "\\xE3\\xD3\\x8B\\xE3\\x83\\xBC\\x83\\xE3\\x83\\xE3\\x82\\xB3\\xA3\\x82\\x99"
- │ ├── closing_loc: (1,61)-(1,62) = "\""
- │ └── unescaped: "\xE3Ӌー\x83\xE3\x83コ\xA3\x82\x99"
- └── right:
- @ StringNode (location: (2,8)-(2,66))
- ├── flags: ∅
- ├── opening_loc: (2,8)-(2,9) = "\""
- ├── content_loc: (2,9)-(2,65) = "\\xE3\\x83\\xB3\\xE3\\x83\\x8F\\xE3\\x82\\x9A\\xC3\\xBD;foo@bar.com"
- ├── closing_loc: (2,65)-(2,66) = "\""
- └── unescaped: "ンパý;foo@bar.com"
+ └── @ InterpolatedStringNode (location: (1,0)-(2,66))
+ ├── opening_loc: ∅
+ ├── parts: (length: 2)
+ │ ├── @ StringNode (location: (1,0)-(1,62))
+ │ │ ├── flags: ∅
+ │ │ ├── opening_loc: (1,0)-(1,1) = "\""
+ │ │ ├── content_loc: (1,1)-(1,61) = "\\xE3\\xD3\\x8B\\xE3\\x83\\xBC\\x83\\xE3\\x83\\xE3\\x82\\xB3\\xA3\\x82\\x99"
+ │ │ ├── closing_loc: (1,61)-(1,62) = "\""
+ │ │ └── unescaped: "\xE3Ӌー\x83\xE3\x83コ\xA3\x82\x99"
+ │ └── @ StringNode (location: (2,8)-(2,66))
+ │ ├── flags: ∅
+ │ ├── opening_loc: (2,8)-(2,9) = "\""
+ │ ├── content_loc: (2,9)-(2,65) = "\\xE3\\x83\\xB3\\xE3\\x83\\x8F\\xE3\\x82\\x9A\\xC3\\xBD;foo@bar.com"
+ │ ├── closing_loc: (2,65)-(2,66) = "\""
+ │ └── unescaped: "ンパý;foo@bar.com"
+ └── closing_loc: ∅
diff --git a/test/prism/snapshots/strings.txt b/test/prism/snapshots/strings.txt
index c70e6472ee..5a03170585 100644
--- a/test/prism/snapshots/strings.txt
+++ b/test/prism/snapshots/strings.txt
@@ -482,21 +482,22 @@
│ ├── content_loc: (97,1)-(97,2) = "a"
│ ├── closing_loc: ∅
│ └── unescaped: "a"
- ├── @ StringConcatNode (location: (99,0)-(99,6))
- │ ├── left:
- │ │ @ StringNode (location: (99,0)-(99,2))
- │ │ ├── flags: ∅
- │ │ ├── opening_loc: (99,0)-(99,1) = "?"
- │ │ ├── content_loc: (99,1)-(99,2) = "a"
- │ │ ├── closing_loc: ∅
- │ │ └── unescaped: "a"
- │ └── right:
- │ @ StringNode (location: (99,3)-(99,6))
- │ ├── flags: ∅
- │ ├── opening_loc: (99,3)-(99,4) = "\""
- │ ├── content_loc: (99,4)-(99,5) = "a"
- │ ├── closing_loc: (99,5)-(99,6) = "\""
- │ └── unescaped: "a"
+ ├── @ InterpolatedStringNode (location: (99,0)-(99,6))
+ │ ├── opening_loc: ∅
+ │ ├── parts: (length: 2)
+ │ │ ├── @ StringNode (location: (99,0)-(99,2))
+ │ │ │ ├── flags: ∅
+ │ │ │ ├── opening_loc: (99,0)-(99,1) = "?"
+ │ │ │ ├── content_loc: (99,1)-(99,2) = "a"
+ │ │ │ ├── closing_loc: ∅
+ │ │ │ └── unescaped: "a"
+ │ │ └── @ StringNode (location: (99,3)-(99,6))
+ │ │ ├── flags: ∅
+ │ │ ├── opening_loc: (99,3)-(99,4) = "\""
+ │ │ ├── content_loc: (99,4)-(99,5) = "a"
+ │ │ ├── closing_loc: (99,5)-(99,6) = "\""
+ │ │ └── unescaped: "a"
+ │ └── closing_loc: ∅
├── @ StringNode (location: (101,0)-(101,7))
│ ├── flags: ∅
│ ├── opening_loc: (101,0)-(101,3) = "%Q{"
diff --git a/test/prism/snapshots/unparser/corpus/literal/literal.txt b/test/prism/snapshots/unparser/corpus/literal/literal.txt
index abf552b518..3a54d4f971 100644
--- a/test/prism/snapshots/unparser/corpus/literal/literal.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/literal.txt
@@ -338,21 +338,22 @@
│ └── numeric:
│ @ IntegerNode (location: (27,0)-(27,1))
│ └── flags: decimal
- ├── @ StringConcatNode (location: (28,0)-(28,11))
- │ ├── left:
- │ │ @ StringNode (location: (28,0)-(28,5))
- │ │ ├── flags: ∅
- │ │ ├── opening_loc: (28,0)-(28,1) = "\""
- │ │ ├── content_loc: (28,1)-(28,4) = "foo"
- │ │ ├── closing_loc: (28,4)-(28,5) = "\""
- │ │ └── unescaped: "foo"
- │ └── right:
- │ @ StringNode (location: (28,6)-(28,11))
- │ ├── flags: ∅
- │ ├── opening_loc: (28,6)-(28,7) = "\""
- │ ├── content_loc: (28,7)-(28,10) = "bar"
- │ ├── closing_loc: (28,10)-(28,11) = "\""
- │ └── unescaped: "bar"
+ ├── @ InterpolatedStringNode (location: (28,0)-(28,11))
+ │ ├── opening_loc: ∅
+ │ ├── parts: (length: 2)
+ │ │ ├── @ StringNode (location: (28,0)-(28,5))
+ │ │ │ ├── flags: ∅
+ │ │ │ ├── opening_loc: (28,0)-(28,1) = "\""
+ │ │ │ ├── content_loc: (28,1)-(28,4) = "foo"
+ │ │ │ ├── closing_loc: (28,4)-(28,5) = "\""
+ │ │ │ └── unescaped: "foo"
+ │ │ └── @ StringNode (location: (28,6)-(28,11))
+ │ │ ├── flags: ∅
+ │ │ ├── opening_loc: (28,6)-(28,7) = "\""
+ │ │ ├── content_loc: (28,7)-(28,10) = "bar"
+ │ │ ├── closing_loc: (28,10)-(28,11) = "\""
+ │ │ └── unescaped: "bar"
+ │ └── closing_loc: ∅
├── @ InterpolatedStringNode (location: (29,0)-(29,15))
│ ├── opening_loc: (29,0)-(29,1) = "\""
│ ├── parts: (length: 2)
diff --git a/test/prism/snapshots/unparser/corpus/semantic/dstr.txt b/test/prism/snapshots/unparser/corpus/semantic/dstr.txt
index bc675a56dc..5ab954b6d4 100644
--- a/test/prism/snapshots/unparser/corpus/semantic/dstr.txt
+++ b/test/prism/snapshots/unparser/corpus/semantic/dstr.txt
@@ -425,143 +425,146 @@
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "\nb"
│ └── closing_loc: (117,6)-(117,7) = "\""
- ├── @ StringConcatNode (location: (119,0)-(120,5))
- │ ├── left:
- │ │ @ StringNode (location: (119,0)-(119,3))
- │ │ ├── flags: ∅
- │ │ ├── opening_loc: (119,0)-(119,1) = "'"
- │ │ ├── content_loc: (119,1)-(119,2) = "a"
- │ │ ├── closing_loc: (119,2)-(119,3) = "'"
- │ │ └── unescaped: "a"
- │ └── right:
- │ @ InterpolatedStringNode (location: (120,0)-(120,5))
- │ ├── opening_loc: (120,0)-(120,1) = "\""
- │ ├── parts: (length: 1)
- │ │ └── @ EmbeddedStatementsNode (location: (120,1)-(120,4))
- │ │ ├── opening_loc: (120,1)-(120,3) = "\#{"
- │ │ ├── statements: ∅
- │ │ └── closing_loc: (120,3)-(120,4) = "}"
- │ └── closing_loc: (120,4)-(120,5) = "\""
- ├── @ StringConcatNode (location: (122,0)-(122,8))
- │ ├── left:
- │ │ @ StringConcatNode (location: (122,0)-(122,5))
- │ │ ├── left:
- │ │ │ @ StringNode (location: (122,0)-(122,2))
+ ├── @ InterpolatedStringNode (location: (119,0)-(120,5))
+ │ ├── opening_loc: ∅
+ │ ├── parts: (length: 2)
+ │ │ ├── @ StringNode (location: (119,0)-(119,3))
+ │ │ │ ├── flags: ∅
+ │ │ │ ├── opening_loc: (119,0)-(119,1) = "'"
+ │ │ │ ├── content_loc: (119,1)-(119,2) = "a"
+ │ │ │ ├── closing_loc: (119,2)-(119,3) = "'"
+ │ │ │ └── unescaped: "a"
+ │ │ └── @ InterpolatedStringNode (location: (120,0)-(120,5))
+ │ │ ├── opening_loc: (120,0)-(120,1) = "\""
+ │ │ ├── parts: (length: 1)
+ │ │ │ └── @ EmbeddedStatementsNode (location: (120,1)-(120,4))
+ │ │ │ ├── opening_loc: (120,1)-(120,3) = "\#{"
+ │ │ │ ├── statements: ∅
+ │ │ │ └── closing_loc: (120,3)-(120,4) = "}"
+ │ │ └── closing_loc: (120,4)-(120,5) = "\""
+ │ └── closing_loc: ∅
+ ├── @ InterpolatedStringNode (location: (122,0)-(122,8))
+ │ ├── opening_loc: ∅
+ │ ├── parts: (length: 3)
+ │ │ ├── @ StringNode (location: (122,0)-(122,2))
│ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (122,0)-(122,1) = "\""
│ │ │ ├── content_loc: (122,1)-(122,1) = ""
│ │ │ ├── closing_loc: (122,1)-(122,2) = "\""
│ │ │ └── unescaped: ""
- │ │ └── right:
- │ │ @ StringNode (location: (122,3)-(122,5))
+ │ │ ├── @ StringNode (location: (122,3)-(122,5))
+ │ │ │ ├── flags: ∅
+ │ │ │ ├── opening_loc: (122,3)-(122,4) = "\""
+ │ │ │ ├── content_loc: (122,4)-(122,4) = ""
+ │ │ │ ├── closing_loc: (122,4)-(122,5) = "\""
+ │ │ │ └── unescaped: ""
+ │ │ └── @ StringNode (location: (122,6)-(122,8))
│ │ ├── flags: ∅
- │ │ ├── opening_loc: (122,3)-(122,4) = "\""
- │ │ ├── content_loc: (122,4)-(122,4) = ""
- │ │ ├── closing_loc: (122,4)-(122,5) = "\""
+ │ │ ├── opening_loc: (122,6)-(122,7) = "\""
+ │ │ ├── content_loc: (122,7)-(122,7) = ""
+ │ │ ├── closing_loc: (122,7)-(122,8) = "\""
│ │ └── unescaped: ""
- │ └── right:
- │ @ StringNode (location: (122,6)-(122,8))
- │ ├── flags: ∅
- │ ├── opening_loc: (122,6)-(122,7) = "\""
- │ ├── content_loc: (122,7)-(122,7) = ""
- │ ├── closing_loc: (122,7)-(122,8) = "\""
- │ └── unescaped: ""
- ├── @ StringConcatNode (location: (124,0)-(124,12))
- │ ├── left:
- │ │ @ InterpolatedStringNode (location: (124,0)-(124,8))
- │ │ ├── opening_loc: (124,0)-(124,1) = "\""
- │ │ ├── parts: (length: 2)
- │ │ │ ├── @ StringNode (location: (124,1)-(124,2))
- │ │ │ │ ├── flags: ∅
- │ │ │ │ ├── opening_loc: ∅
- │ │ │ │ ├── content_loc: (124,1)-(124,2) = "a"
- │ │ │ │ ├── closing_loc: ∅
- │ │ │ │ └── unescaped: "a"
- │ │ │ └── @ EmbeddedStatementsNode (location: (124,2)-(124,7))
- │ │ │ ├── opening_loc: (124,2)-(124,4) = "\#{"
- │ │ │ ├── statements:
- │ │ │ │ @ StatementsNode (location: (124,4)-(124,6))
- │ │ │ │ └── body: (length: 1)
- │ │ │ │ └── @ InstanceVariableReadNode (location: (124,4)-(124,6))
- │ │ │ │ └── name: :@a
- │ │ │ └── closing_loc: (124,6)-(124,7) = "}"
- │ │ └── closing_loc: (124,7)-(124,8) = "\""
- │ └── right:
- │ @ StringNode (location: (124,9)-(124,12))
- │ ├── flags: ∅
- │ ├── opening_loc: (124,9)-(124,10) = "\""
- │ ├── content_loc: (124,10)-(124,11) = "b"
- │ ├── closing_loc: (124,11)-(124,12) = "\""
- │ └── unescaped: "b"
- ├── @ StringConcatNode (location: (125,0)-(125,10))
- │ ├── left:
- │ │ @ InterpolatedStringNode (location: (125,0)-(125,6))
- │ │ ├── opening_loc: (125,0)-(125,1) = "\""
- │ │ ├── parts: (length: 2)
- │ │ │ ├── @ StringNode (location: (125,1)-(125,2))
- │ │ │ │ ├── flags: ∅
- │ │ │ │ ├── opening_loc: ∅
- │ │ │ │ ├── content_loc: (125,1)-(125,2) = "a"
- │ │ │ │ ├── closing_loc: ∅
- │ │ │ │ └── unescaped: "a"
- │ │ │ └── @ EmbeddedVariableNode (location: (125,2)-(125,5))
- │ │ │ ├── operator_loc: (125,2)-(125,3) = "#"
- │ │ │ └── variable:
- │ │ │ @ InstanceVariableReadNode (location: (125,3)-(125,5))
- │ │ │ └── name: :@a
- │ │ └── closing_loc: (125,5)-(125,6) = "\""
- │ └── right:
- │ @ StringNode (location: (125,7)-(125,10))
- │ ├── flags: ∅
- │ ├── opening_loc: (125,7)-(125,8) = "\""
- │ ├── content_loc: (125,8)-(125,9) = "b"
- │ ├── closing_loc: (125,9)-(125,10) = "\""
- │ └── unescaped: "b"
- ├── @ StringConcatNode (location: (126,0)-(126,10))
- │ ├── left:
- │ │ @ InterpolatedStringNode (location: (126,0)-(126,6))
- │ │ ├── opening_loc: (126,0)-(126,1) = "\""
- │ │ ├── parts: (length: 2)
- │ │ │ ├── @ StringNode (location: (126,1)-(126,2))
- │ │ │ │ ├── flags: ∅
- │ │ │ │ ├── opening_loc: ∅
- │ │ │ │ ├── content_loc: (126,1)-(126,2) = "a"
- │ │ │ │ ├── closing_loc: ∅
- │ │ │ │ └── unescaped: "a"
- │ │ │ └── @ EmbeddedVariableNode (location: (126,2)-(126,5))
- │ │ │ ├── operator_loc: (126,2)-(126,3) = "#"
- │ │ │ └── variable:
- │ │ │ @ GlobalVariableReadNode (location: (126,3)-(126,5))
- │ │ │ └── name: :$a
- │ │ └── closing_loc: (126,5)-(126,6) = "\""
- │ └── right:
- │ @ StringNode (location: (126,7)-(126,10))
- │ ├── flags: ∅
- │ ├── opening_loc: (126,7)-(126,8) = "\""
- │ ├── content_loc: (126,8)-(126,9) = "b"
- │ ├── closing_loc: (126,9)-(126,10) = "\""
- │ └── unescaped: "b"
- └── @ StringConcatNode (location: (127,0)-(127,11))
- ├── left:
- │ @ InterpolatedStringNode (location: (127,0)-(127,7))
- │ ├── opening_loc: (127,0)-(127,1) = "\""
- │ ├── parts: (length: 2)
- │ │ ├── @ StringNode (location: (127,1)-(127,2))
- │ │ │ ├── flags: ∅
- │ │ │ ├── opening_loc: ∅
- │ │ │ ├── content_loc: (127,1)-(127,2) = "a"
- │ │ │ ├── closing_loc: ∅
- │ │ │ └── unescaped: "a"
- │ │ └── @ EmbeddedVariableNode (location: (127,2)-(127,6))
- │ │ ├── operator_loc: (127,2)-(127,3) = "#"
- │ │ └── variable:
- │ │ @ ClassVariableReadNode (location: (127,3)-(127,6))
- │ │ └── name: :@@a
- │ └── closing_loc: (127,6)-(127,7) = "\""
- └── right:
- @ StringNode (location: (127,8)-(127,11))
- ├── flags: ∅
- ├── opening_loc: (127,8)-(127,9) = "\""
- ├── content_loc: (127,9)-(127,10) = "b"
- ├── closing_loc: (127,10)-(127,11) = "\""
- └── unescaped: "b"
+ │ └── closing_loc: ∅
+ ├── @ InterpolatedStringNode (location: (124,0)-(124,12))
+ │ ├── opening_loc: ∅
+ │ ├── parts: (length: 2)
+ │ │ ├── @ InterpolatedStringNode (location: (124,0)-(124,8))
+ │ │ │ ├── opening_loc: (124,0)-(124,1) = "\""
+ │ │ │ ├── parts: (length: 2)
+ │ │ │ │ ├── @ StringNode (location: (124,1)-(124,2))
+ │ │ │ │ │ ├── flags: ∅
+ │ │ │ │ │ ├── opening_loc: ∅
+ │ │ │ │ │ ├── content_loc: (124,1)-(124,2) = "a"
+ │ │ │ │ │ ├── closing_loc: ∅
+ │ │ │ │ │ └── unescaped: "a"
+ │ │ │ │ └── @ EmbeddedStatementsNode (location: (124,2)-(124,7))
+ │ │ │ │ ├── opening_loc: (124,2)-(124,4) = "\#{"
+ │ │ │ │ ├── statements:
+ │ │ │ │ │ @ StatementsNode (location: (124,4)-(124,6))
+ │ │ │ │ │ └── body: (length: 1)
+ │ │ │ │ │ └── @ InstanceVariableReadNode (location: (124,4)-(124,6))
+ │ │ │ │ │ └── name: :@a
+ │ │ │ │ └── closing_loc: (124,6)-(124,7) = "}"
+ │ │ │ └── closing_loc: (124,7)-(124,8) = "\""
+ │ │ └── @ StringNode (location: (124,9)-(124,12))
+ │ │ ├── flags: ∅
+ │ │ ├── opening_loc: (124,9)-(124,10) = "\""
+ │ │ ├── content_loc: (124,10)-(124,11) = "b"
+ │ │ ├── closing_loc: (124,11)-(124,12) = "\""
+ │ │ └── unescaped: "b"
+ │ └── closing_loc: ∅
+ ├── @ InterpolatedStringNode (location: (125,0)-(125,10))
+ │ ├── opening_loc: ∅
+ │ ├── parts: (length: 2)
+ │ │ ├── @ InterpolatedStringNode (location: (125,0)-(125,6))
+ │ │ │ ├── opening_loc: (125,0)-(125,1) = "\""
+ │ │ │ ├── parts: (length: 2)
+ │ │ │ │ ├── @ StringNode (location: (125,1)-(125,2))
+ │ │ │ │ │ ├── flags: ∅
+ │ │ │ │ │ ├── opening_loc: ∅
+ │ │ │ │ │ ├── content_loc: (125,1)-(125,2) = "a"
+ │ │ │ │ │ ├── closing_loc: ∅
+ │ │ │ │ │ └── unescaped: "a"
+ │ │ │ │ └── @ EmbeddedVariableNode (location: (125,2)-(125,5))
+ │ │ │ │ ├── operator_loc: (125,2)-(125,3) = "#"
+ │ │ │ │ └── variable:
+ │ │ │ │ @ InstanceVariableReadNode (location: (125,3)-(125,5))
+ │ │ │ │ └── name: :@a
+ │ │ │ └── closing_loc: (125,5)-(125,6) = "\""
+ │ │ └── @ StringNode (location: (125,7)-(125,10))
+ │ │ ├── flags: ∅
+ │ │ ├── opening_loc: (125,7)-(125,8) = "\""
+ │ │ ├── content_loc: (125,8)-(125,9) = "b"
+ │ │ ├── closing_loc: (125,9)-(125,10) = "\""
+ │ │ └── unescaped: "b"
+ │ └── closing_loc: ∅
+ ├── @ InterpolatedStringNode (location: (126,0)-(126,10))
+ │ ├── opening_loc: ∅
+ │ ├── parts: (length: 2)
+ │ │ ├── @ InterpolatedStringNode (location: (126,0)-(126,6))
+ │ │ │ ├── opening_loc: (126,0)-(126,1) = "\""
+ │ │ │ ├── parts: (length: 2)
+ │ │ │ │ ├── @ StringNode (location: (126,1)-(126,2))
+ │ │ │ │ │ ├── flags: ∅
+ │ │ │ │ │ ├── opening_loc: ∅
+ │ │ │ │ │ ├── content_loc: (126,1)-(126,2) = "a"
+ │ │ │ │ │ ├── closing_loc: ∅
+ │ │ │ │ │ └── unescaped: "a"
+ │ │ │ │ └── @ EmbeddedVariableNode (location: (126,2)-(126,5))
+ │ │ │ │ ├── operator_loc: (126,2)-(126,3) = "#"
+ │ │ │ │ └── variable:
+ │ │ │ │ @ GlobalVariableReadNode (location: (126,3)-(126,5))
+ │ │ │ │ └── name: :$a
+ │ │ │ └── closing_loc: (126,5)-(126,6) = "\""
+ │ │ └── @ StringNode (location: (126,7)-(126,10))
+ │ │ ├── flags: ∅
+ │ │ ├── opening_loc: (126,7)-(126,8) = "\""
+ │ │ ├── content_loc: (126,8)-(126,9) = "b"
+ │ │ ├── closing_loc: (126,9)-(126,10) = "\""
+ │ │ └── unescaped: "b"
+ │ └── closing_loc: ∅
+ └── @ InterpolatedStringNode (location: (127,0)-(127,11))
+ ├── opening_loc: ∅
+ ├── parts: (length: 2)
+ │ ├── @ InterpolatedStringNode (location: (127,0)-(127,7))
+ │ │ ├── opening_loc: (127,0)-(127,1) = "\""
+ │ │ ├── parts: (length: 2)
+ │ │ │ ├── @ StringNode (location: (127,1)-(127,2))
+ │ │ │ │ ├── flags: ∅
+ │ │ │ │ ├── opening_loc: ∅
+ │ │ │ │ ├── content_loc: (127,1)-(127,2) = "a"
+ │ │ │ │ ├── closing_loc: ∅
+ │ │ │ │ └── unescaped: "a"
+ │ │ │ └── @ EmbeddedVariableNode (location: (127,2)-(127,6))
+ │ │ │ ├── operator_loc: (127,2)-(127,3) = "#"
+ │ │ │ └── variable:
+ │ │ │ @ ClassVariableReadNode (location: (127,3)-(127,6))
+ │ │ │ └── name: :@@a
+ │ │ └── closing_loc: (127,6)-(127,7) = "\""
+ │ └── @ StringNode (location: (127,8)-(127,11))
+ │ ├── flags: ∅
+ │ ├── opening_loc: (127,8)-(127,9) = "\""
+ │ ├── content_loc: (127,9)-(127,10) = "b"
+ │ ├── closing_loc: (127,10)-(127,11) = "\""
+ │ └── unescaped: "b"
+ └── closing_loc: ∅
diff --git a/test/prism/snapshots/whitequark/ruby_bug_11990.txt b/test/prism/snapshots/whitequark/ruby_bug_11990.txt
index 54532e329c..1e35d5434b 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_11990.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_11990.txt
@@ -11,21 +11,22 @@
├── arguments:
│ @ ArgumentsNode (location: (1,2)-(1,12))
│ ├── arguments: (length: 1)
- │ │ └── @ StringConcatNode (location: (1,2)-(1,12))
- │ │ ├── left:
- │ │ │ @ StringNode (location: (1,2)-(1,6))
- │ │ │ ├── flags: ∅
- │ │ │ ├── opening_loc: (1,2)-(1,6) = "<<~E"
- │ │ │ ├── content_loc: (2,0)-(3,0) = " x\n"
- │ │ │ ├── closing_loc: (3,0)-(4,0) = "E\n"
- │ │ │ └── unescaped: "x\n"
- │ │ └── right:
- │ │ @ StringNode (location: (1,7)-(1,12))
- │ │ ├── flags: ∅
- │ │ ├── opening_loc: (1,7)-(1,8) = "\""
- │ │ ├── content_loc: (1,8)-(1,11) = " y"
- │ │ ├── closing_loc: (1,11)-(1,12) = "\""
- │ │ └── unescaped: " y"
+ │ │ └── @ InterpolatedStringNode (location: (1,2)-(1,12))
+ │ │ ├── opening_loc: ∅
+ │ │ ├── parts: (length: 2)
+ │ │ │ ├── @ StringNode (location: (1,2)-(1,6))
+ │ │ │ │ ├── flags: ∅
+ │ │ │ │ ├── opening_loc: (1,2)-(1,6) = "<<~E"
+ │ │ │ │ ├── content_loc: (2,0)-(3,0) = " x\n"
+ │ │ │ │ ├── closing_loc: (3,0)-(4,0) = "E\n"
+ │ │ │ │ └── unescaped: "x\n"
+ │ │ │ └── @ StringNode (location: (1,7)-(1,12))
+ │ │ │ ├── flags: ∅
+ │ │ │ ├── opening_loc: (1,7)-(1,8) = "\""
+ │ │ │ ├── content_loc: (1,8)-(1,11) = " y"
+ │ │ │ ├── closing_loc: (1,11)-(1,12) = "\""
+ │ │ │ └── unescaped: " y"
+ │ │ └── closing_loc: ∅
│ └── flags: ∅
├── closing_loc: ∅
├── block: ∅
diff --git a/test/prism/snapshots/whitequark/string_concat.txt b/test/prism/snapshots/whitequark/string_concat.txt
index 2c15895d7e..38ea0c745d 100644
--- a/test/prism/snapshots/whitequark/string_concat.txt
+++ b/test/prism/snapshots/whitequark/string_concat.txt
@@ -3,27 +3,28 @@
└── statements:
@ StatementsNode (location: (1,0)-(1,14))
└── body: (length: 1)
- └── @ StringConcatNode (location: (1,0)-(1,14))
- ├── left:
- │ @ InterpolatedStringNode (location: (1,0)-(1,8))
- │ ├── opening_loc: (1,0)-(1,1) = "\""
- │ ├── parts: (length: 2)
- │ │ ├── @ StringNode (location: (1,1)-(1,4))
- │ │ │ ├── flags: ∅
- │ │ │ ├── opening_loc: ∅
- │ │ │ ├── content_loc: (1,1)-(1,4) = "foo"
- │ │ │ ├── closing_loc: ∅
- │ │ │ └── unescaped: "foo"
- │ │ └── @ EmbeddedVariableNode (location: (1,4)-(1,7))
- │ │ ├── operator_loc: (1,4)-(1,5) = "#"
- │ │ └── variable:
- │ │ @ InstanceVariableReadNode (location: (1,5)-(1,7))
- │ │ └── name: :@a
- │ └── closing_loc: (1,7)-(1,8) = "\""
- └── right:
- @ StringNode (location: (1,9)-(1,14))
- ├── flags: ∅
- ├── opening_loc: (1,9)-(1,10) = "\""
- ├── content_loc: (1,10)-(1,13) = "bar"
- ├── closing_loc: (1,13)-(1,14) = "\""
- └── unescaped: "bar"
+ └── @ InterpolatedStringNode (location: (1,0)-(1,14))
+ ├── opening_loc: ∅
+ ├── parts: (length: 2)
+ │ ├── @ InterpolatedStringNode (location: (1,0)-(1,8))
+ │ │ ├── opening_loc: (1,0)-(1,1) = "\""
+ │ │ ├── parts: (length: 2)
+ │ │ │ ├── @ StringNode (location: (1,1)-(1,4))
+ │ │ │ │ ├── flags: ∅
+ │ │ │ │ ├── opening_loc: ∅
+ │ │ │ │ ├── content_loc: (1,1)-(1,4) = "foo"
+ │ │ │ │ ├── closing_loc: ∅
+ │ │ │ │ └── unescaped: "foo"
+ │ │ │ └── @ EmbeddedVariableNode (location: (1,4)-(1,7))
+ │ │ │ ├── operator_loc: (1,4)-(1,5) = "#"
+ │ │ │ └── variable:
+ │ │ │ @ InstanceVariableReadNode (location: (1,5)-(1,7))
+ │ │ │ └── name: :@a
+ │ │ └── closing_loc: (1,7)-(1,8) = "\""
+ │ └── @ StringNode (location: (1,9)-(1,14))
+ │ ├── flags: ∅
+ │ ├── opening_loc: (1,9)-(1,10) = "\""
+ │ ├── content_loc: (1,10)-(1,13) = "bar"
+ │ ├── closing_loc: (1,13)-(1,14) = "\""
+ │ └── unescaped: "bar"
+ └── closing_loc: ∅