diff --git a/config.yml b/config.yml index ef12f7a7303..6cd98b52a3c 100644 --- a/config.yml +++ b/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/src/prism.c b/src/prism.c index 09ccaf70cf3..21eb8f07fd5 100644 --- a/src/prism.c +++ b/src/prism.c @@ -5127,28 +5127,6 @@ pm_statements_node_body_append(pm_statements_node_t *node, pm_node_t *statement) statement->flags |= PM_NODE_FLAG_NEWLINE; } -/** - * 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. */ @@ -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 02a577a73c5..302e6bd1397 100644 --- a/test/prism/location_test.rb +++ b/test/prism/location_test.rb @@ -495,6 +495,7 @@ def test_InterpolatedRegularExpressionNode 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 @@ def test_StatementsNode 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 758334138cc..3097a361643 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 662bd86c055..145da454dcd 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 7bf71b7858b..f1226f34e2c 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 c70e6472ee9..5a031705859 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 abf552b518f..3a54d4f971b 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 bc675a56dc5..5ab954b6d41 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 54532e329c0..1e35d5434bf 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 2c15895d7ea..38ea0c745dd 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: ∅