Skip to content

Commit 9376e46

Browse files
committed
Use new OTP28.1 :re.import in escaped regex AST
erlang/otp#9976
1 parent d21a13b commit 9376e46

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

lib/elixir/lib/kernel.ex

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6647,16 +6647,26 @@ defmodule Kernel do
66476647
end
66486648

66496649
defp compile_regex(binary_or_tuple, options) do
6650-
# TODO: Remove this when we require Erlang/OTP 28+
6651-
case is_binary(binary_or_tuple) and :erlang.system_info(:otp_release) < [?2, ?8] do
6650+
bin_opts = :binary.list_to_bin(options)
6651+
6652+
# TODO: Remove this when we require Erlang/OTP 28.1+
6653+
case is_binary(binary_or_tuple) and compile_time_regexes_supported?() do
66526654
true ->
6653-
Macro.escape(Regex.compile!(binary_or_tuple, :binary.list_to_bin(options)))
6655+
Macro.escape(Regex.compile!(binary_or_tuple, bin_opts))
66546656

66556657
false ->
6656-
quote(do: Regex.compile!(unquote(binary_or_tuple), unquote(:binary.list_to_bin(options))))
6658+
quote(do: Regex.compile!(unquote(binary_or_tuple), unquote(bin_opts)))
66576659
end
66586660
end
66596661

6662+
defp compile_time_regexes_supported? do
6663+
# OTP 28.0 introduced refs in patterns, which can't be used in AST anymore
6664+
# OTP 28.1 introduced :re.import/1 which allows us to fix this in Macro.escape
6665+
:erlang.system_info(:otp_release) < [?2, ?8] or
6666+
(Code.ensure_loaded?(:re) and
6667+
function_exported?(:re, :import, 1))
6668+
end
6669+
66606670
@doc ~S"""
66616671
Handles the sigil `~D` for dates.
66626672

lib/elixir/src/elixir_quote.erl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,21 @@ do_escape(BitString, _) when is_bitstring(BitString) ->
168168
{'<<>>', [], [{'::', [], [Bits, {size, [], [Size]}]}, {'::', [], [Bytes, {binary, [], nil}]}]}
169169
end;
170170

171+
do_escape(#{
172+
'__struct__' := 'Elixir.Regex',
173+
're_pattern' := {re_pattern, _, _, _, Ref},
174+
'source' := Source,
175+
'opts' := Opts
176+
}, Q) when is_reference(Ref), is_binary(Source), is_list(Opts) ->
177+
{ok, ExportedPattern} = re:compile(Source, [export | Opts]),
178+
PatternAst = {{'.', [], ['re', 'import']}, [], [do_escape(ExportedPattern, Q)]},
179+
{'%{}', [], [
180+
{'__struct__', 'Elixir.Regex'},
181+
{'re_pattern', PatternAst},
182+
{'source', Source},
183+
{'opts', do_escape(Opts, Q)}
184+
]};
185+
171186
do_escape(Map, Q) when is_map(Map) ->
172187
TT = [escape_map_key_value(K, V, Map, Q) || {K, V} <- lists:sort(maps:to_list(Map))],
173188
{'%{}', [], TT};

0 commit comments

Comments
 (0)