[ruby/prism] Handle a non-interpolated dsym spanning a heredoc

https://github.com/ruby/prism/commit/b23136ebfd
This commit is contained in:
Kevin Newton 2023-12-11 09:12:54 -05:00 committed by git
parent 261e8f28a0
commit c65de63913
3 changed files with 124 additions and 44 deletions

View File

@ -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; content = parser->current;
unescaped = parser->current_string; unescaped = parser->current_string;
parser_lex(parser); 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:
//
// <<A; :'a
// A
// b'
//
// In this case, the best way we have to represent this is as an
// interpolated string node, so that's what we'll do here.
if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
pm_node_list_t parts = { 0 };
pm_token_t bounds = not_provided(parser);
pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
pm_node_list_append(&parts, part);
part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &parser->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 { } else {
content = (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.end, .end = parser->previous.end }; 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); pm_string_shared_init(&unescaped, content.start, content.end);

View File

@ -53,3 +53,11 @@ p]
<<A; /\ <<A; /\
A A
(?<a>)/ =~ '' (?<a>)/ =~ ''
<<A; :'a
A
b'
<<A; :"a
A
b"

View File

@ -1,8 +1,8 @@
@ ProgramNode (location: (4,0)-(55,13)) @ ProgramNode (location: (4,0)-(63,2))
├── locals: [:a] ├── locals: [:a]
└── statements: └── statements:
@ StatementsNode (location: (4,0)-(55,13)) @ StatementsNode (location: (4,0)-(63,2))
└── body: (length: 10) └── body: (length: 14)
├── @ CallNode (location: (4,0)-(7,7)) ├── @ CallNode (location: (4,0)-(7,7))
│ ├── flags: ∅ │ ├── flags: ∅
│ ├── receiver: ∅ │ ├── receiver: ∅
@ -321,45 +321,89 @@
│ ├── content_loc: (54,0)-(54,0) = "" │ ├── content_loc: (54,0)-(54,0) = ""
│ ├── closing_loc: (54,0)-(55,0) = "A\n" │ ├── closing_loc: (54,0)-(55,0) = "A\n"
│ └── unescaped: "" │ └── unescaped: ""
└── @ MatchWriteNode (location: (53,5)-(55,13)) ├── @ MatchWriteNode (location: (53,5)-(55,13))
├── call: │ ├── call:
│ @ CallNode (location: (53,5)-(55,13)) │ │ @ CallNode (location: (53,5)-(55,13))
│ ├── flags: ∅
│ ├── receiver:
│ │ @ InterpolatedRegularExpressionNode (location: (53,5)-(55,7))
│ │ ├── flags: ∅ │ │ ├── flags: ∅
│ │ ├── opening_loc: (53,5)-(53,6) = "/" │ │ ├── receiver:
│ │ ├── parts: (length: 2) │ │ │ @ InterpolatedRegularExpressionNode (location: (53,5)-(55,7))
│ │ │ ├── @ StringNode (location: (53,6)-(53,7)) │ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: (53,5)-(53,6) = "/"
│ │ │ ├── parts: (length: 2)
│ │ │ │ ├── @ StringNode (location: (53,6)-(53,7))
│ │ │ │ │ ├── flags: ∅
│ │ │ │ │ ├── opening_loc: ∅
│ │ │ │ │ ├── content_loc: (53,6)-(53,7) = "\\"
│ │ │ │ │ ├── closing_loc: ∅
│ │ │ │ │ └── unescaped: ""
│ │ │ │ └── @ StringNode (location: (55,0)-(55,6))
│ │ │ │ ├── flags: ∅ │ │ │ │ ├── flags: ∅
│ │ │ │ ├── opening_loc: ∅ │ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── content_loc: (53,6)-(53,7) = "\\" │ │ │ │ ├── content_loc: (55,0)-(55,6) = "(?<a>)"
│ │ │ │ ├── closing_loc: ∅ │ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── unescaped: "" │ │ │ │ └── unescaped: "(?<a>)"
│ │ │ └── @ StringNode (location: (55,0)-(55,6)) │ │ │ └── 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) = "<<A"
│ ├── content_loc: (58,0)-(58,0) = ""
│ ├── closing_loc: (58,0)-(59,0) = "A\n"
│ └── unescaped: ""
├── @ InterpolatedSymbolNode (location: (57,5)-(59,2))
│ ├── opening_loc: (57,5)-(57,7) = ":'"
│ ├── parts: (length: 2)
│ │ ├── @ StringNode (location: (57,7)-(58,0))
│ │ │ ├── flags: ∅ │ │ │ ├── flags: ∅
│ │ │ ├── opening_loc: ∅ │ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (55,0)-(55,6) = "(?<a>)" │ │ │ ├── content_loc: (57,7)-(58,0) = "a\n"
│ │ │ ├── closing_loc: ∅ │ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: "(?<a>)" │ │ │ └── unescaped: "a\n"
│ │ └── closing_loc: (55,6)-(55,7) = "/" │ │ └── @ StringNode (location: (59,0)-(59,1))
│ ├── call_operator_loc: ∅ │ │ ├── flags: ∅
│ ├── name: :=~ │ │ ├── opening_loc: ∅
│ ├── message_loc: (55,8)-(55,10) = "=~" │ │ ├── content_loc: (59,0)-(59,1) = "b"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "b"
│ └── closing_loc: (59,1)-(59,2) = "'"
├── @ StringNode (location: (61,0)-(61,3))
│ ├── flags: ∅
│ ├── opening_loc: (61,0)-(61,3) = "<<A"
│ ├── content_loc: (62,0)-(62,0) = ""
│ ├── closing_loc: (62,0)-(63,0) = "A\n"
│ └── unescaped: ""
└── @ InterpolatedSymbolNode (location: (61,5)-(63,2))
├── opening_loc: (61,5)-(61,7) = ":\""
├── parts: (length: 2)
│ ├── @ StringNode (location: (61,7)-(62,0))
│ │ ├── flags: ∅
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (61,7)-(62,0) = "a\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "a\n"
│ └── @ StringNode (location: (63,0)-(63,1))
│ ├── flags: ∅
│ ├── opening_loc: ∅ │ ├── opening_loc: ∅
│ ├── arguments: │ ├── content_loc: (63,0)-(63,1) = "b"
│ │ @ 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: ∅ │ ├── closing_loc: ∅
│ └── block: ∅ │ └── unescaped: "b"
└── targets: (length: 1) └── closing_loc: (63,1)-(63,2) = "\""
└── @ LocalVariableTargetNode (location: (53,5)-(55,7))
├── name: :a
└── depth: 0