@@ -5,7 +5,19 @@ if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@compi
55end
66
77export is_enum,
8- pattern_uncall, pattern_unref, pattern_unmacrocall, @switch , @case , @tryswitch , @match , @trymatch , Where, gen_match, gen_switch
8+ enum_matcher,
9+ pattern_uncall,
10+ pattern_unref,
11+ pattern_unmacrocall,
12+ @switch ,
13+ @case ,
14+ @tryswitch ,
15+ @match ,
16+ @trymatch ,
17+ Where,
18+ gen_match,
19+ gen_switch
20+
921export Q
1022import MLStyle
1123using MLStyle: mlstyle_report_deprecation_msg!
@@ -17,8 +29,70 @@ using MLStyle.AbstractPatterns
1729using MLStyle. AbstractPatterns. BasicPatterns
1830OptionalLn = Union{LineNumberNode, Nothing}
1931
32+ """
33+ is_enum(EnumPattern)::Bool
34+
35+ Convert the pattern `EnumPattern` to `EnumPattern()`.
36+
37+ e.g.,
38+ ```
39+ abstract type AbsS end
40+ struct S1 <: AbsS end
41+ struct S2 <: AbsS end
42+ MLStyle.pattern_uncall(::Type{S}, self, _, _, _) where {S<:AbsS} = literal(S())
43+ MLStyle.is_enum(::Type{<:AbsS}) = true
44+
45+ x = S1()
46+ @match x begin
47+ S2 => 1
48+ S1 => 2
49+ end
50+ ```
51+
52+ """
2053is_enum (_):: Bool = false
21- function pattern_uncall end
54+
55+ """
56+ enum_matcher(Enum, value)::Expr
57+
58+ Generates the expression used to test if `value` is the case `Enum`.
59+
60+ NOTE that this only works when `is_enum(Enum)` is `true`!!!
61+
62+ @match V begin
63+ Enum => ...
64+ @end
65+
66+ Above single case matches when
67+
68+ 1. `enum_matcher(Enum, ::Any)` is not defined and `V == Enum`.
69+ 2. The expression generated from `enum_matcher(Enum, :V)`
70+ evaluates to `true` under the current module.
71+
72+ """
73+ function enum_matcher end
74+
75+ struct _EnumCase{E}
76+ pattern:: E
77+ end
78+
79+ function pattern_uncall (enumCase:: _EnumCase{E} , self, type_params, type_args, args) where E
80+ isempty (type_params) || error (" Enum type should not have type parameters!" )
81+ isempty (type_args) || error (" Enum type should not have type arguments!" )
82+ isempty (args) || error (" Enum type should not have arguments!" )
83+
84+ let enumPattern = enumCase. pattern
85+ if hasmethod (MLStyle. enum_matcher, Tuple{E, Any})
86+ function via_enum_matcher (target, _, _)
87+ return MLStyle. enum_matcher (enumPattern, target)
88+ end
89+ guard (via_enum_matcher)
90+ else
91+ pattern_uncall (enumPattern, self, type_params, type_args, args)
92+ end
93+ end
94+ end
95+
2296function pattern_unref end
2397function pattern_unmacrocall (macro_func, self:: Function , args:: AbstractArray )
2498 @sswitch args begin
@@ -85,6 +159,12 @@ function guess_type_from_expr(m::Module, ex::Any, tps::Set{Symbol})
85159 end
86160end
87161
162+ struct ModuleBoundedEx2tf <: Function
163+ m:: Module
164+ end
165+
166+ @inline (self:: ModuleBoundedEx2tf )(arg) = ex2tf (self. m, arg)
167+
88168ex2tf (m:: Module , @nospecialize (a)) = literal (a)
89169ex2tf (m:: Module , l:: LineNumberNode ) = wildcard
90170ex2tf (m:: Module , q:: QuoteNode ) = literal (q. value)
@@ -97,8 +177,8 @@ ex2tf(m::Module, n::Symbol) =
97177 else
98178 if isdefined (m, n)
99179 p = getfield (m, n)
100- rec (x) = ex2tf (m, x )
101- is_enum (p) && return pattern_uncall (p , rec, [], [], [])
180+ rec = ModuleBoundedEx2tf (m )
181+ is_enum (p) && return pattern_uncall (_EnumCase (p) , rec, [], [], [])
102182 end
103183 P_capture (n)
104184 end
@@ -112,7 +192,8 @@ function ex2tf(m::Module, s::QuotePattern)
112192end
113193
114194function ex2tf (m:: Module , w:: Where )
115- rec (x) = ex2tf (m, x)
195+ rec = ModuleBoundedEx2tf (m)
196+
116197 @sswitch w begin
117198 @case Where (; value = val, type = t, type_parameters = tps)
118199
170251
171252function ex2tf (m:: Module , ex:: Expr )
172253 eval = m. eval
173- rec (x) = ex2tf (m, x )
254+ rec = ModuleBoundedEx2tf (m )
174255
175256 @sswitch ex begin
176257 @case Expr (:|| , args)
0 commit comments