diff --git a/prism/prism.c b/prism/prism.c index 1cc999e31e..9922f57722 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -12543,6 +12543,34 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s content = parser->current; unescaped = parser->current_string; parser_lex(parser); + + // If we have two string contents in a row, then the content of this + // symbol is split because of heredoc contents. This looks like: + // + // <current, &bounds, &parser->current_string); + pm_node_list_append(&parts, part); + + if (next_state != PM_LEX_STATE_NONE) { + lex_state_set(parser, next_state); + } + + parser_lex(parser); + expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC); + return (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); + } } else { content = (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.end, .end = parser->previous.end }; pm_string_shared_init(&unescaped, content.start, content.end); diff --git a/test/prism/fixtures/spanning_heredoc.txt b/test/prism/fixtures/spanning_heredoc.txt index c1b9ec72f4..d09cb11b1f 100644 --- a/test/prism/fixtures/spanning_heredoc.txt +++ b/test/prism/fixtures/spanning_heredoc.txt @@ -53,3 +53,11 @@ p] <)/ =~ '' + +<)" + │ │ │ └── closing_loc: (55,6)-(55,7) = "/" + │ │ ├── call_operator_loc: ∅ + │ │ ├── name: :=~ + │ │ ├── message_loc: (55,8)-(55,10) = "=~" + │ │ ├── opening_loc: ∅ + │ │ ├── arguments: + │ │ │ @ ArgumentsNode (location: (55,11)-(55,13)) + │ │ │ ├── flags: ∅ + │ │ │ └── arguments: (length: 1) + │ │ │ └── @ StringNode (location: (55,11)-(55,13)) + │ │ │ ├── flags: ∅ + │ │ │ ├── opening_loc: (55,11)-(55,12) = "'" + │ │ │ ├── content_loc: (55,12)-(55,12) = "" + │ │ │ ├── closing_loc: (55,12)-(55,13) = "'" + │ │ │ └── unescaped: "" + │ │ ├── closing_loc: ∅ + │ │ └── block: ∅ + │ └── targets: (length: 1) + │ └── @ LocalVariableTargetNode (location: (53,5)-(55,7)) + │ ├── name: :a + │ └── depth: 0 + ├── @ StringNode (location: (57,0)-(57,3)) + │ ├── flags: ∅ + │ ├── opening_loc: (57,0)-(57,3) = "<)" - │ │ └── closing_loc: (55,6)-(55,7) = "/" - │ ├── call_operator_loc: ∅ - │ ├── name: :=~ - │ ├── message_loc: (55,8)-(55,10) = "=~" - │ ├── opening_loc: ∅ - │ ├── arguments: - │ │ @ ArgumentsNode (location: (55,11)-(55,13)) - │ │ ├── flags: ∅ - │ │ └── arguments: (length: 1) - │ │ └── @ StringNode (location: (55,11)-(55,13)) - │ │ ├── flags: ∅ - │ │ ├── opening_loc: (55,11)-(55,12) = "'" - │ │ ├── content_loc: (55,12)-(55,12) = "" - │ │ ├── closing_loc: (55,12)-(55,13) = "'" - │ │ └── unescaped: "" - │ ├── closing_loc: ∅ - │ └── block: ∅ - └── targets: (length: 1) - └── @ LocalVariableTargetNode (location: (53,5)-(55,7)) - ├── name: :a - └── depth: 0 + │ │ ├── opening_loc: ∅ + │ │ ├── content_loc: (61,7)-(62,0) = "a\n" + │ │ ├── closing_loc: ∅ + │ │ └── unescaped: "a\n" + │ └── @ StringNode (location: (63,0)-(63,1)) + │ ├── flags: ∅ + │ ├── opening_loc: ∅ + │ ├── content_loc: (63,0)-(63,1) = "b" + │ ├── closing_loc: ∅ + │ └── unescaped: "b" + └── closing_loc: (63,1)-(63,2) = "\""