Repository: ruby/prism
Pull request #2592 (2024-03-13 04:32:55)

Fix an AST incompatibility for `Prism::Translation::Parser`
Fixes ruby/prism#2480.

This PR fixes an AST incompatibility between Parser gem and `Prism::Translation::Parser` for xstring literal with line breaks.

The following case in ruby/prism#2480 has already been addressed in ruby/prism#2576:

```ruby
"foo
bar"
```


Patch:
diff --git a/lib/prism/translation/parser/compiler.rb b/lib/prism/translation/parser/compiler.rb
index bf5b8544..cf628cdd 100644
--- a/lib/prism/translation/parser/compiler.rb
+++ b/lib/prism/translation/parser/compiler.rb
@@ -1678,9 +1678,23 @@ module Prism
             children, closing = visit_heredoc(node.to_interpolated)
             builder.xstring_compose(token(node.opening_loc), children, closing)
           else
+            parts = if node.unescaped.lines.count <= 1
+              [builder.string_internal([node.unescaped, srange(node.content_loc)])]
+            else
+              start_offset = node.content_loc.start_offset
+
+              node.unescaped.lines.map do |line|
+                end_offset = start_offset + line.length
+                offsets = srange_offsets(start_offset, end_offset)
+                start_offset = end_offset
+
+                builder.string_internal([line, offsets])
+              end
+            end
+
             builder.xstring_compose(
               token(node.opening_loc),
-              [builder.string_internal([node.unescaped, srange(node.content_loc)])],
+              parts,
               token(node.closing_loc)
             )
           end


Test patch:
diff --git a/test/prism/fixtures/xstring.txt b/test/prism/fixtures/xstring.txt
index 623afd97..fcbaad91 100644
--- a/test/prism/fixtures/xstring.txt
+++ b/test/prism/fixtures/xstring.txt
@@ -3,3 +3,7 @@
 `foo #{bar} baz`
 
 `foo`
+
+%x{
+  foo
+}
diff --git a/test/prism/snapshots/xstring.txt b/test/prism/snapshots/xstring.txt
index 0a9d0758..56ba77a8 100644
--- a/test/prism/snapshots/xstring.txt
+++ b/test/prism/snapshots/xstring.txt
@@ -1,8 +1,8 @@
-@ ProgramNode (location: (1,0)-(5,5))
+@ ProgramNode (location: (1,0)-(9,1))
 ├── locals: []
 └── statements:
-    @ StatementsNode (location: (1,0)-(5,5))
-    └── body: (length: 3)
+    @ StatementsNode (location: (1,0)-(9,1))
+    └── body: (length: 4)
         ├── @ XStringNode (location: (1,0)-(1,7))
         │   ├── flags: ∅
         │   ├── opening_loc: (1,0)-(1,3) = "%x["
@@ -41,9 +41,15 @@
         │   │       ├── closing_loc: ∅
         │   │       └── unescaped: " baz"
         │   └── closing_loc: (3,15)-(3,16) = "`"
-        └── @ XStringNode (location: (5,0)-(5,5))
+        ├── @ XStringNode (location: (5,0)-(5,5))
+        │   ├── flags: ∅
+        │   ├── opening_loc: (5,0)-(5,1) = "`"
+        │   ├── content_loc: (5,1)-(5,4) = "foo"
+        │   ├── closing_loc: (5,4)-(5,5) = "`"
+        │   └── unescaped: "foo"
+        └── @ XStringNode (location: (7,0)-(9,1))
             ├── flags: ∅
-            ├── opening_loc: (5,0)-(5,1) = "`"
-            ├── content_loc: (5,1)-(5,4) = "foo"
-            ├── closing_loc: (5,4)-(5,5) = "`"
-            └── unescaped: "foo"
+            ├── opening_loc: (7,0)-(7,3) = "%x{"
+            ├── content_loc: (7,3)-(9,0) = "\n  foo\n"
+            ├── closing_loc: (9,0)-(9,1) = "}"
+            └── unescaped: "\n  foo\n"