Skip to content

Commit

Permalink
[ruby/yarp] Heredocs can create Interpolated(X)StringNodes or
Browse files Browse the repository at this point in the history
(X)StringNodes
(ruby/prism#1427)

Prior to this commit, heredocs were automatically InterpolatedNodes
regardless of whether there was actually interpolation. With this
commit, heredocs are only interpolate if there is actually
interpolation

ruby/prism@e9f436128b
  • Loading branch information
jemmaissroff authored and matzbot committed Sep 12, 2023
1 parent b557855 commit 39336c1
Show file tree
Hide file tree
Showing 58 changed files with 681 additions and 1,002 deletions.
8 changes: 6 additions & 2 deletions test/yarp/heredoc_dedent_test.rb
Expand Up @@ -8,8 +8,12 @@ class HeredocDedentTest < TestCase

File.read(filepath).split(/(?=\n)\n(?=<)/).each_with_index do |heredoc, index|
define_method "test_heredoc_#{index}" do
parts = YARP.parse(heredoc).value.statements.body.first.parts
actual = parts.map { |part| part.is_a?(StringNode) ? part.unescaped : "1" }.join
node = YARP.parse(heredoc).value.statements.body.first
if node.is_a? StringNode
actual = node.unescaped
else
actual = node.parts.map { |part| part.is_a?(StringNode) ? part.unescaped : "1" }.join
end

assert_equal(eval(heredoc), actual, "Expected heredocs to match.")
end
Expand Down
2 changes: 1 addition & 1 deletion test/yarp/location_test.rb
Expand Up @@ -460,7 +460,7 @@ def test_InterpolatedRegularExpressionNode

def test_InterpolatedStringNode
assert_location(InterpolatedStringNode, "\"foo \#@bar baz\"")
assert_location(InterpolatedStringNode, "<<~A\nhello world\nA", 0...4)
assert_location(InterpolatedStringNode, "<<~A\nhello \#{1} world\nA", 0...4)
end

def test_InterpolatedSymbolNode
Expand Down
6 changes: 5 additions & 1 deletion test/yarp/parse_test.rb
Expand Up @@ -186,7 +186,11 @@ def assert_non_overlapping_locations(node)
# We only want to compare parent/child location overlap in the case that
# we are not looking at a heredoc. That's because heredoc locations are
# special in that they only use the declaration of the heredoc.
compare = !(current.is_a?(InterpolatedStringNode) || current.is_a?(InterpolatedXStringNode)) || !current.opening&.start_with?("<<")
compare = !(current.is_a?(StringNode) ||
current.is_a?(XStringNode) ||
current.is_a?(InterpolatedStringNode) ||
current.is_a?(InterpolatedXStringNode)) ||
!current.opening&.start_with?("<<")

current.child_nodes.each do |child|
# child_nodes can return nil values, so we need to skip those.
Expand Down
115 changes: 40 additions & 75 deletions test/yarp/snapshots/dash_heredocs.txt
Expand Up @@ -3,41 +3,29 @@
└── statements:
@ StatementsNode (location: (0...278))
└── body: (length: 13)
├── @ InterpolatedStringNode (location: (0...6))
├── @ StringNode (location: (0...6))
│ ├── opening_loc: (0...6) = "<<-EOF"
│ ├── parts: (length: 1)
│ │ └── @ StringNode (location: (7...11))
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (7...11) = " a\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: " a\n"
│ └── closing_loc: (11...15) = "EOF\n"
│ ├── content_loc: (7...11) = " a\n"
│ ├── closing_loc: (11...15) = "EOF\n"
│ └── unescaped: " a\n"
├── @ CallNode (location: (16...36))
│ ├── receiver:
│ │ @ InterpolatedStringNode (location: (16...24))
│ │ @ StringNode (location: (16...24))
│ │ ├── opening_loc: (16...24) = "<<-FIRST"
│ │ ├── parts: (length: 1)
│ │ │ └── @ StringNode (location: (37...41))
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (37...41) = " a\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: " a\n"
│ │ └── closing_loc: (41...47) = "FIRST\n"
│ │ ├── content_loc: (37...41) = " a\n"
│ │ ├── closing_loc: (41...47) = "FIRST\n"
│ │ └── unescaped: " a\n"
│ ├── call_operator_loc: ∅
│ ├── message_loc: (25...26) = "+"
│ ├── opening_loc: ∅
│ ├── arguments:
│ │ @ ArgumentsNode (location: (27...36))
│ │ └── arguments: (length: 1)
│ │ └── @ InterpolatedStringNode (location: (27...36))
│ │ └── @ StringNode (location: (27...36))
│ │ ├── opening_loc: (27...36) = "<<-SECOND"
│ │ ├── parts: (length: 1)
│ │ │ └── @ StringNode (location: (47...51))
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (47...51) = " b\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: " b\n"
│ │ └── closing_loc: (51...58) = "SECOND\n"
│ │ ├── content_loc: (47...51) = " b\n"
│ │ ├── closing_loc: (51...58) = "SECOND\n"
│ │ └── unescaped: " b\n"
│ ├── closing_loc: ∅
│ ├── block: ∅
│ ├── flags:
Expand Down Expand Up @@ -72,24 +60,16 @@
│ │ ├── closing_loc: ∅
│ │ └── unescaped: "\n"
│ └── closing_loc: (77...81) = "EOF\n"
├── @ InterpolatedStringNode (location: (82...88))
├── @ StringNode (location: (82...88))
│ ├── opening_loc: (82...88) = "<<-EOF"
│ ├── parts: (length: 1)
│ │ └── @ StringNode (location: (98...102))
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (98...102) = " a\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: " a\n"
│ └── closing_loc: (102...106) = "EOF\n"
├── @ InterpolatedStringNode (location: (107...113))
│ ├── content_loc: (98...102) = " a\n"
│ ├── closing_loc: (102...106) = "EOF\n"
│ └── unescaped: " a\n"
├── @ StringNode (location: (107...113))
│ ├── opening_loc: (107...113) = "<<-EOF"
│ ├── parts: (length: 1)
│ │ └── @ StringNode (location: (114...122))
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (114...122) = " a\n b\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: " a\n b\n"
│ └── closing_loc: (122...128) = " EOF\n"
│ ├── content_loc: (114...122) = " a\n b\n"
│ ├── closing_loc: (122...128) = " EOF\n"
│ └── unescaped: " a\n b\n"
├── @ InterpolatedStringNode (location: (129...137))
│ ├── opening_loc: (129...137) = "<<-\"EOF\""
│ ├── parts: (length: 3)
Expand Down Expand Up @@ -155,39 +135,28 @@
│ ├── content_loc: (175...178) = "abc"
│ ├── closing_loc: (178...179) = "#"
│ └── unescaped: "abc"
├── @ InterpolatedStringNode (location: (181...187))
├── @ StringNode (location: (181...187))
│ ├── opening_loc: (181...187) = "<<-EOF"
│ ├── parts: (length: 1)
│ │ └── @ StringNode (location: (188...196))
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (188...196) = " a\n b\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: " a\n b\n"
│ └── closing_loc: (196...200) = "EOF\n"
├── @ InterpolatedStringNode (location: (201...206))
│ ├── content_loc: (188...196) = " a\n b\n"
│ ├── closing_loc: (196...200) = "EOF\n"
│ └── unescaped: " a\n b\n"
├── @ StringNode (location: (201...206))
│ ├── opening_loc: (201...206) = "<<-''"
│ ├── parts: (length: 0)
│ └── closing_loc: (207...208) = "\n"
├── @ InterpolatedStringNode (location: (209...217))
│ ├── content_loc: (206...207) = "\n"
│ ├── closing_loc: (207...208) = "\n"
│ └── unescaped: ""
├── @ StringNode (location: (209...217))
│ ├── opening_loc: (209...217) = "<<-'EOF'"
│ ├── parts: (length: 1)
│ │ └── @ StringNode (location: (218...227))
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (218...227) = " a \#{1}\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: " a \#{1}\n"
│ └── closing_loc: (227...231) = "EOF\n"
│ ├── content_loc: (218...227) = " a \#{1}\n"
│ ├── closing_loc: (227...231) = "EOF\n"
│ └── unescaped: " a \#{1}\n"
├── @ CallNode (location: (232...243))
│ ├── receiver:
│ │ @ InterpolatedStringNode (location: (232...236))
│ │ @ StringNode (location: (232...236))
│ │ ├── opening_loc: (232...236) = "<<-A"
│ │ ├── parts: (length: 1)
│ │ │ └── @ StringNode (location: (244...248))
│ │ │ ├── opening_loc: ∅
│ │ │ ├── content_loc: (244...248) = " a\n"
│ │ │ ├── closing_loc: ∅
│ │ │ └── unescaped: " a\n"
│ │ └── closing_loc: (248...250) = "A\n"
│ │ ├── content_loc: (244...248) = " a\n"
│ │ ├── closing_loc: (248...250) = "A\n"
│ │ └── unescaped: " a\n"
│ ├── call_operator_loc: ∅
│ ├── message_loc: (237...238) = "+"
│ ├── opening_loc: ∅
Expand Down Expand Up @@ -222,15 +191,11 @@
│ └── name: "+"
└── @ CallNode (location: (267...278))
├── receiver:
│ @ InterpolatedStringNode (location: (267...271))
│ @ StringNode (location: (267...271))
│ ├── opening_loc: (267...271) = "<<-A"
│ ├── parts: (length: 1)
│ │ └── @ StringNode (location: (279...283))
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (279...283) = " a\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: " a\n"
│ └── closing_loc: (283...285) = "A\n"
│ ├── content_loc: (279...283) = " a\n"
│ ├── closing_loc: (283...285) = "A\n"
│ └── unescaped: " a\n"
├── call_operator_loc: ∅
├── message_loc: (272...273) = "+"
├── opening_loc: ∅
Expand Down
24 changes: 8 additions & 16 deletions test/yarp/snapshots/dos_endings.txt
Expand Up @@ -37,15 +37,11 @@
│ │ └── unescaped: "ab"
│ ├── opening_loc: (28...31) = "%I{"
│ └── closing_loc: (36...37) = "}"
├── @ InterpolatedStringNode (location: (41...45))
├── @ StringNode (location: (41...45))
│ ├── opening_loc: (41...45) = "<<-E"
│ ├── parts: (length: 1)
│ │ └── @ StringNode (location: (47...70))
│ │ ├── opening_loc: ∅
│ │ ├── content_loc: (47...70) = " 1 \\\r\n 2\r\n 3\r\n"
│ │ ├── closing_loc: ∅
│ │ └── unescaped: " 1 2\r\n 3\r\n"
│ └── closing_loc: (70...73) = "E\r\n"
│ ├── content_loc: (47...70) = " 1 \\\r\n 2\r\n 3\r\n"
│ ├── closing_loc: (70...73) = "E\r\n"
│ └── unescaped: " 1 2\r\n 3\r\n"
├── @ LocalVariableWriteNode (location: (75...84))
│ ├── name: :x
│ ├── depth: 0
Expand All @@ -72,15 +68,11 @@
│ │ └── arguments: (length: 1)
│ │ └── @ CallNode (location: (96...107))
│ │ ├── receiver:
│ │ │ @ InterpolatedStringNode (location: (96...102))
│ │ │ @ StringNode (location: (96...102))
│ │ │ ├── opening_loc: (96...102) = "<<~EOF"
│ │ │ ├── parts: (length: 1)
│ │ │ │ └── @ StringNode (location: (110...121))
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── content_loc: (110...121) = "\r\n baz\r\n"
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── unescaped: "\nbaz\r\n"
│ │ │ └── closing_loc: (121...128) = " EOF\r\n"
│ │ │ ├── content_loc: (110...121) = "\r\n baz\r\n"
│ │ │ ├── closing_loc: (121...128) = " EOF\r\n"
│ │ │ └── unescaped: "\nbaz\r\n"
│ │ ├── call_operator_loc: (102...103) = "."
│ │ ├── message_loc: (103...107) = "chop"
│ │ ├── opening_loc: ∅
Expand Down
14 changes: 8 additions & 6 deletions test/yarp/snapshots/heredoc_with_escaped_newline_at_start.txt
Expand Up @@ -5,10 +5,11 @@
└── body: (length: 2)
├── @ CallNode (location: (0...25))
│ ├── receiver:
│ │ @ InterpolatedStringNode (location: (0...9))
│ │ @ StringNode (location: (0...9))
│ │ ├── opening_loc: (0...9) = "<<-TARGET"
│ │ ├── parts: (length: 0)
│ │ └── closing_loc: (27...34) = "TARGET\n"
│ │ ├── content_loc: (9...27) = ".gsub /^\\s{/, ''\\\n"
│ │ ├── closing_loc: (27...34) = "TARGET\n"
│ │ └── unescaped: ""
│ ├── call_operator_loc: (9...10) = "."
│ ├── message_loc: (10...14) = "gsub"
│ ├── opening_loc: ∅
Expand All @@ -32,10 +33,11 @@
│ └── name: "gsub"
└── @ CallNode (location: (37...62))
├── receiver:
│ @ InterpolatedStringNode (location: (37...46))
│ @ StringNode (location: (37...46))
│ ├── opening_loc: (37...46) = "<<-TARGET"
│ ├── parts: (length: 0)
│ └── closing_loc: (65...73) = "TARGET\r\n"
│ ├── content_loc: (46...65) = ".gsub /^\\s{/, ''\\\r\n"
│ ├── closing_loc: (65...73) = "TARGET\r\n"
│ └── unescaped: ""
├── call_operator_loc: (46...47) = "."
├── message_loc: (47...51) = "gsub"
├── opening_loc: ∅
Expand Down
7 changes: 4 additions & 3 deletions test/yarp/snapshots/heredoc_with_trailing_newline.txt
Expand Up @@ -3,7 +3,8 @@
└── statements:
@ StatementsNode (location: (0...6))
└── body: (length: 1)
└── @ InterpolatedStringNode (location: (0...6))
└── @ StringNode (location: (0...6))
├── opening_loc: (0...6) = "<<-END"
├── parts: (length: 0)
└── closing_loc: (7...10) = "END"
├── content_loc: (6...7) = "\n"
├── closing_loc: (7...10) = "END"
└── unescaped: ""
12 changes: 4 additions & 8 deletions test/yarp/snapshots/heredocs_nested.txt
Expand Up @@ -16,15 +16,11 @@
│ │ ├── statements:
│ │ │ @ StatementsNode (location: (15...21))
│ │ │ └── body: (length: 1)
│ │ │ └── @ InterpolatedStringNode (location: (15...21))
│ │ │ └── @ StringNode (location: (15...21))
│ │ │ ├── opening_loc: (15...21) = "<<RUBY"
│ │ │ ├── parts: (length: 1)
│ │ │ │ └── @ StringNode (location: (22...30))
│ │ │ │ ├── opening_loc: ∅
│ │ │ │ ├── content_loc: (22...30) = " hello\n"
│ │ │ │ ├── closing_loc: ∅
│ │ │ │ └── unescaped: " hello\n"
│ │ │ └── closing_loc: (30...35) = "RUBY\n"
│ │ │ ├── content_loc: (22...30) = " hello\n"
│ │ │ ├── closing_loc: (30...35) = "RUBY\n"
│ │ │ └── unescaped: " hello\n"
│ │ └── closing_loc: (35...36) = "}"
│ └── @ StringNode (location: (36...42))
│ ├── opening_loc: ∅
Expand Down
19 changes: 8 additions & 11 deletions test/yarp/snapshots/heredocs_with_ignored_newlines.txt
Expand Up @@ -3,16 +3,13 @@
└── statements:
@ StatementsNode (location: (0...23))
└── body: (length: 2)
├── @ InterpolatedStringNode (location: (0...7))
├── @ StringNode (location: (0...7))
│ ├── opening_loc: (0...7) = "<<-HERE"
│ ├── parts: (length: 0)
│ └── closing_loc: (9...14) = "HERE\n"
└── @ InterpolatedStringNode (location: (15...23))
│ ├── content_loc: (7...9) = "\\\n"
│ ├── closing_loc: (9...14) = "HERE\n"
│ └── unescaped: ""
└── @ StringNode (location: (15...23))
├── opening_loc: (15...23) = "<<~THERE"
├── parts: (length: 1)
│ └── @ StringNode (location: (25...100))
│ ├── opening_loc: ∅
│ ├── content_loc: (25...100) = " way over\n <<HERE\n not here\n HERE\n\n <<~BUT\\\n but\n BUT\n there\n"
│ ├── closing_loc: ∅
│ └── unescaped: "way over\n<<HERE\n not here\nHERE\n\n<<~BUT but\nBUT\n there\n"
└── closing_loc: (100...106) = "THERE\n"
├── content_loc: (25...100) = " way over\n <<HERE\n not here\n HERE\n\n <<~BUT\\\n but\n BUT\n there\n"
├── closing_loc: (100...106) = "THERE\n"
└── unescaped: "way over\n<<HERE\n not here\nHERE\n\n<<~BUT but\nBUT\n there\n"
Expand Up @@ -3,12 +3,8 @@
└── statements:
@ StatementsNode (location: (0...6))
└── body: (length: 1)
└── @ InterpolatedStringNode (location: (0...6))
└── @ StringNode (location: (0...6))
├── opening_loc: (0...6) = "<<-EOE"
├── parts: (length: 1)
│ └── @ StringNode (location: (7...23))
│ ├── opening_loc: ∅
│ ├── content_loc: (7...23) = " some\n heredocs\n"
│ ├── closing_loc: ∅
│ └── unescaped: " some\n heredocs\n"
└── closing_loc: (23...26) = "EOE"
├── content_loc: (7...23) = " some\n heredocs\n"
├── closing_loc: (23...26) = "EOE"
└── unescaped: " some\n heredocs\n"

0 comments on commit 39336c1

Please sign in to comment.