Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

String interpolation: combine contiguous string literals #8581

Merged
merged 1 commit into from Dec 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions spec/compiler/normalize/string_interpolation_spec.cr
Expand Up @@ -5,6 +5,10 @@ describe "Normalize: string interpolation" do
assert_expand %("foo\#{bar}baz"), %(::String.interpolation("foo", bar, "baz"))
end

it "normalizes string interpolation with multiple lines" do
assert_expand %("foo\n\#{bar}\nbaz\nqux\nfox"), %(::String.interpolation("foo\\n", bar, "\\nbaz\\nqux\\nfox"))
end

it "normalizes heredoc" do
assert_normalize "<<-FOO\nhello\nFOO", %("hello")
end
Expand Down
28 changes: 27 additions & 1 deletion src/compiler/crystal/semantic/literal_expander.cr
Expand Up @@ -293,7 +293,33 @@ module Crystal
#
# String.interpolation("foo", bar, "baz", qux)
def expand(node : StringInterpolation)
Call.new(Path.global("String").at(node), "interpolation", node.expressions).at(node)
# We could do `node.expressions.dup` for more purity,
# but the string interpolation isn't used later on so this is fine,
# and having pieces in a different representation but same end
# result is just fine.
pieces = node.expressions
asterite marked this conversation as resolved.
Show resolved Hide resolved
combine_contiguous_string_literals(pieces)
Call.new(Path.global("String").at(node), "interpolation", pieces).at(node)
end

private def combine_contiguous_string_literals(pieces)
i = 0
pieces.reject! do |piece|
delete =
if i < pieces.size - 1
next_piece = pieces[i + 1]
if piece.is_a?(StringLiteral) && next_piece.is_a?(StringLiteral)
pieces[i + 1] = StringLiteral.new(piece.value + next_piece.value)
true
else
false
end
else
false
end
i += 1
delete
end
end

# Convert a Case into a series of if ... elseif ... end:
Expand Down