Skip to content

Add support for sigils containing integers #13448

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

Merged
merged 10 commits into from
May 17, 2024
Merged
2 changes: 1 addition & 1 deletion lib/elixir/src/elixir_import.erl
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ is_sigil({Name, 2}) ->
case Letters of
[L] when L >= $a, L =< $z -> true;
[] -> false;
Letters -> lists:all(fun(L) -> L >= $A andalso L =< $Z end, Letters)
Letters -> lists:all(fun(L) -> L >= 0 andalso L =< $Z end, Letters)
end;
_ ->
false
Expand Down
7 changes: 6 additions & 1 deletion lib/elixir/src/elixir_tokenizer.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1564,10 +1564,15 @@ tokenize_sigil_name([S | T], [], Line, Column, Scope, Tokens) when ?is_upcase(S)
% If we have an uppercase letter, we keep tokenizing the name.
tokenize_sigil_name([S | T], NameAcc, Line, Column, Scope, Tokens) when ?is_upcase(S) ->
tokenize_sigil_name(T, [S | NameAcc], Line, Column + 1, Scope, Tokens);
% A digit is allowed but an upcase or digit must proceed it.
tokenize_sigil_name([S | T], [P | _] = NameAcc, Line, Column, Scope, Tokens) when ?is_digit(S) andalso (?is_upcase(P)
orelse
?is_digit(P)) ->
tokenize_sigil_name(T, [S | NameAcc], Line, Column + 1, Scope, Tokens);
% With a lowercase letter and a non-empty NameAcc we return an error.
tokenize_sigil_name([S | _T] = Original, [_ | _] = NameAcc, _Line, _Column, _Scope, _Tokens) when ?is_downcase(S) ->
Message = "invalid sigil name, it should be either a one-letter lowercase letter or a" ++
" sequence of uppercase letters only, got: ",
" sequence of uppercase letters and digits, starting with uppercase letters only, got: ",
{error, Message, [$~] ++ lists:reverse(NameAcc) ++ Original};
% We finished the letters, so the name is over.
tokenize_sigil_name(T, NameAcc, Line, Column, Scope, Tokens) ->
Expand Down
8 changes: 8 additions & 0 deletions lib/elixir/test/elixir/kernel/parser_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,21 @@ defmodule Kernel.ParserTest do
meta = [delimiter: "\"\"\"", line: 1]
args = {:sigil_MAT, meta, [{:<<>>, [indentation: 0, line: 1], ["1,2,3\n"]}, []]}
assert string_to_quoted.("~MAT\"\"\"\n1,2,3\n\"\"\"") == args

args = {:sigil_FOO1, meta, [{:<<>>, [indentation: 0, line: 1], ["1,2,3\n"]}, []]}
assert string_to_quoted.("~FOO1\"\"\"\n1,2,3\n\"\"\"") == args

args = {:sigil_I18N, meta, [{:<<>>, [indentation: 0, line: 1], ["1,2,3\n"]}, []]}
assert string_to_quoted.("~I18N\"\"\"\n1,2,3\n\"\"\"") == args
end

test "invalid multi-letter sigils" do
msg =
~r/invalid sigil name, it should be either a one-letter lowercase letter or a sequence of uppercase letters only/

assert_syntax_error(["nofile:1:1:", msg], "~Regex/foo/")

assert_syntax_error(["nofile:1:1:", msg], "~FOo1/bar/")
end

test "sigil newlines" do
Expand Down