Skip to content

Commit dab3d22

Browse files
committed
Deprecate escaping closing delimiter in uppercase sigils
This aligns our uppercase sigils with Erlang/OTP 27.
1 parent 4ec15f3 commit dab3d22

File tree

4 files changed

+21
-23
lines changed

4 files changed

+21
-23
lines changed

lib/elixir/lib/kernel.ex

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6054,8 +6054,7 @@ defmodule Kernel do
60546054
Handles the sigil `~S` for strings.
60556055
60566056
It returns a string without interpolations and without escape
6057-
characters, except for the escaping of the closing sigil character
6058-
itself.
6057+
characters.
60596058
60606059
## Examples
60616060
@@ -6066,12 +6065,6 @@ defmodule Kernel do
60666065
iex> ~S(\o/)
60676066
"\\o/"
60686067
6069-
However, if you want to reuse the sigil character itself on
6070-
the string, you need to escape it:
6071-
6072-
iex> ~S((\))
6073-
"()"
6074-
60756068
"""
60766069
defmacro sigil_S(term, modifiers)
60776070
defmacro sigil_S({:<<>>, _, [binary]}, []) when is_binary(binary), do: binary
@@ -6108,8 +6101,7 @@ defmodule Kernel do
61086101
Handles the sigil `~C` for charlists.
61096102
61106103
It returns a charlist without interpolations and without escape
6111-
characters, except for the escaping of the closing sigil character
6112-
itself.
6104+
characters.
61136105
61146106
A charlist is a list of integers where all the integers are valid code points.
61156107
The three expressions below are equivalent:
@@ -6519,8 +6511,7 @@ defmodule Kernel do
65196511
Handles the sigil `~W` for list of words.
65206512
65216513
It returns a list of "words" split by whitespace without interpolations
6522-
and without escape characters, except for the escaping of the closing
6523-
sigil character itself.
6514+
and without escape characters.
65246515
65256516
## Modifiers
65266517

lib/elixir/src/elixir_interpolation.erl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,17 @@ extract([$\n | Rest], Buffer, Output, Line, _Column, Scope, Interpol, Last) ->
3333
extract_nl(Rest, [$\n | Buffer], Output, Line, Scope, Interpol, Last);
3434

3535
extract([$\\, Last | Rest], Buffer, Output, Line, Column, Scope, Interpol, Last) ->
36-
extract(Rest, [Last | Buffer], Output, Line, Column+2, Scope, Interpol, Last);
36+
NewScope =
37+
%% TODO: Remove this on Elixir v2.0
38+
case Interpol of
39+
true ->
40+
Scope;
41+
false ->
42+
Msg = "using \\~ts to escape the closing of an uppercase sigil is deprecated, please use another delimiter or a lowercase sigil instead",
43+
prepend_warning(Line, Column, io_lib:format(Msg, [[Last]]), Scope)
44+
end,
45+
46+
extract(Rest, [Last | Buffer], Output, Line, Column+2, NewScope, Interpol, Last);
3747

3848
extract([$\\, Last, Last, Last | Rest], Buffer, Output, Line, Column, Scope, Interpol, [Last, Last, Last] = All) ->
3949
extract(Rest, [Last, Last, Last | Buffer], Output, Line, Column+4, Scope, Interpol, All);
@@ -279,3 +289,6 @@ build_string(Buffer, Output) -> [lists:reverse(Buffer) | Output].
279289

280290
build_interpol(Line, Column, EndLine, EndColumn, Buffer, Output) ->
281291
[{{Line, Column, nil}, {EndLine, EndColumn, nil}, Buffer} | Output].
292+
293+
prepend_warning(Line, Column, Msg, #elixir_tokenizer{warnings=Warnings} = Scope) ->
294+
Scope#elixir_tokenizer{warnings = [{{Line, Column}, Msg} | Warnings]}.

lib/elixir/test/elixir/kernel/sigils_test.exs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ defmodule Kernel.SigilsTest do
2727
assert ~S(f#{o}o) == "f\#{o}o"
2828
assert ~S(f\#{o}o) == "f\\\#{o}o"
2929
assert ~S(f\no) == "f\\no"
30-
assert ~S(foo\)) == "foo)"
31-
assert ~S[foo\]] == "foo]"
3230
end
3331

3432
test "sigil S newline" do
@@ -42,14 +40,6 @@ bar) in ["foo\\\nbar", "foo\\\r\nbar"]
4240
"""
4341
end
4442

45-
test "sigil S with escaping" do
46-
assert "\"" == ~S"\""
47-
48-
assert "\"\"\"\n" == ~S"""
49-
\"""
50-
"""
51-
end
52-
5343
test "sigil s/S expand to binary when possible" do
5444
assert Macro.expand(quote(do: ~s(foo)), __ENV__) == "foo"
5545
assert Macro.expand(quote(do: ~S(foo)), __ENV__) == "foo"

lib/elixir/test/elixir/kernel/warning_test.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,10 @@ defmodule Kernel.WarningTest do
10991099
purge(UseSample)
11001100
end
11011101

1102+
test "deprecated closing sigil delimiter" do
1103+
assert_warn_eval(["nofile:1:7", "deprecated"], "~S(foo\\))")
1104+
end
1105+
11021106
test "deprecated not left in right" do
11031107
assert_warn_eval(["nofile:1:7", "deprecated"], "not 1 in [1, 2, 3]")
11041108
end

0 commit comments

Comments
 (0)