@@ -6,6 +6,7 @@ import Core.Intrinsics.bitcast
66export Enum, @enum
77
88function basetype end
9+ function namemap end
910
1011"""
1112 Enum{T<:Integer}
@@ -19,6 +20,42 @@ Base.cconvert(::Type{T}, x::Enum{T2}) where {T<:Integer,T2<:Integer} = T(x)
1920Base. write (io:: IO , x:: Enum{T} ) where {T<: Integer } = write (io, T (x))
2021Base. read (io:: IO , :: Type{T} ) where {T<: Enum } = T (read (io, Enums. basetype (T)))
2122
23+ Base. isless (x:: T , y:: T ) where {T<: Enum } = isless (basetype (T)(x), basetype (T)(y))
24+
25+ Base. Symbol (x:: Enum ) = namemap (typeof (x))[Integer (x)]:: Symbol
26+
27+ Base. print (io:: IO , x:: Enum ) = print (io, Symbol (x))
28+
29+ function Base. show (io:: IO , x:: Enum )
30+ sym = Symbol (x)
31+ if ! get (io, :compact , false )
32+ from = get (io, :module , Main)
33+ def = typeof (x). name. module
34+ if from === nothing || ! Base. isvisible (sym, def, from)
35+ show (io, def)
36+ print (io, " ." )
37+ end
38+ end
39+ print (io, sym)
40+ end
41+
42+ function Base. show (io:: IO , :: MIME"text/plain" , x:: Enum )
43+ print (io, x, " ::" )
44+ show (IOContext (io, :compact => true ), typeof (x))
45+ print (io, " = " )
46+ show (io, Integer (x))
47+ end
48+
49+ function Base. show (io:: IO , :: MIME"text/plain" , t:: Type{<:Enum} )
50+ print (io, " Enum " )
51+ Base. show_datatype (io, t)
52+ print (io, " :" )
53+ for x in instances (t)
54+ print (io, " \n " , Symbol (x), " = " )
55+ show (io, Integer (x))
56+ end
57+ end
58+
2259# generate code to test whether expr is in the given set of values
2360function membershiptest (expr, values)
2461 lo, hi = extrema (values)
@@ -74,7 +111,7 @@ To list all the instances of an enum use `instances`, e.g.
74111
75112```jldoctest fruitenum
76113julia> instances(Fruit)
77- (apple::Fruit = 1 , orange::Fruit = 2 , kiwi::Fruit = 3 )
114+ (apple, orange, kiwi)
78115```
79116"""
80117macro enum (T, syms... )
@@ -92,7 +129,9 @@ macro enum(T, syms...)
92129 elseif ! isa (T, Symbol)
93130 throw (ArgumentError (" invalid type expression for enum $T " ))
94131 end
95- vals = Vector {Tuple{Symbol,Integer}} ()
132+ values = basetype[]
133+ seen = Set {Symbol} ()
134+ namemap = Dict {basetype,Symbol} ()
96135 lo = hi = 0
97136 i = zero (basetype)
98137 hasexpr = false
@@ -103,7 +142,7 @@ macro enum(T, syms...)
103142 for s in syms
104143 s isa LineNumberNode && continue
105144 if isa (s, Symbol)
106- if i == typemin (basetype) && ! isempty (vals )
145+ if i == typemin (basetype) && ! isempty (values )
107146 throw (ArgumentError (" overflow in value \" $s \" of Enum $typename " ))
108147 end
109148 elseif isa (s, Expr) &&
@@ -122,19 +161,23 @@ macro enum(T, syms...)
122161 if ! Base. isidentifier (s)
123162 throw (ArgumentError (" invalid name for Enum $typename ; \" $s \" is not a valid identifier." ))
124163 end
125- push! (vals, (s,i))
126- if length (vals) == 1
164+ if hasexpr && haskey (namemap, i)
165+ throw (ArgumentError (" values for Enum $typename are not unique" ))
166+ end
167+ namemap[i] = s
168+ push! (values, i)
169+ if s in seen
170+ throw (ArgumentError (" names for Enum $typename are not unique" ))
171+ end
172+ push! (seen, s)
173+ if length (values) == 1
127174 lo = hi = i
128175 else
129176 lo = min (lo, i)
130177 hi = max (hi, i)
131178 end
132179 i += oneunit (i)
133180 end
134- values = basetype[i[2 ] for i in vals]
135- if hasexpr && values != unique (values)
136- throw (ArgumentError (" values for Enum $typename are not unique" ))
137- end
138181 blk = quote
139182 # enum definition
140183 Base. @__doc__ (primitive type $ (esc (typename)) <: Enum{$(basetype)} $ (sizeof (basetype) * 8 ) end )
@@ -143,41 +186,15 @@ macro enum(T, syms...)
143186 return bitcast ($ (esc (typename)), convert ($ (basetype), x))
144187 end
145188 Enums. basetype (:: Type{$(esc(typename))} ) = $ (esc (basetype))
189+ Enums. namemap (:: Type{$(esc(typename))} ) = $ (esc (namemap))
146190 Base. typemin (x:: Type{$(esc(typename))} ) = $ (esc (typename))($ lo)
147191 Base. typemax (x:: Type{$(esc(typename))} ) = $ (esc (typename))($ hi)
148- Base. isless (x:: $ (esc (typename)), y:: $ (esc (typename))) = isless ($ basetype (x), $ basetype (y))
149- let insts = ntuple (i-> $ (esc (typename))($ values[i]), $ (length (vals)))
192+ let insts = ntuple (i-> $ (esc (typename))($ values[i]), $ (length (values)))
150193 Base. instances (:: Type{$(esc(typename))} ) = insts
151194 end
152- function Base. print (io:: IO , x:: $ (esc (typename)))
153- for (sym, i) in $ vals
154- if i == $ (basetype)(x)
155- print (io, sym); break
156- end
157- end
158- end
159- function Base. show (io:: IO , x:: $ (esc (typename)))
160- if get (io, :compact , false )
161- print (io, x)
162- else
163- print (io, x, " ::" )
164- show (IOContext (io, :compact => true ), typeof (x))
165- print (io, " = " )
166- show (io, $ basetype (x))
167- end
168- end
169- function Base. show (io:: IO , :: MIME"text/plain" , t:: Type{$(esc(typename))} )
170- print (io, " Enum " )
171- Base. show_datatype (io, t)
172- print (io, " :" )
173- for (sym, i) in $ vals
174- print (io, " \n " , sym, " = " )
175- show (io, i)
176- end
177- end
178195 end
179196 if isa (typename, Symbol)
180- for (sym,i ) in vals
197+ for (i, sym ) in namemap
181198 push! (blk. args, :(const $ (esc (sym)) = $ (esc (typename))($ i)))
182199 end
183200 end
0 commit comments