@@ -5,7 +5,7 @@ module Enums
55import Core. Intrinsics. bitcast
66export Enum, @enum
77
8- function basetype end
8+ function namemap end
99
1010"""
1111 Enum{T<:Integer}
@@ -14,10 +14,48 @@ The abstract supertype of all enumerated types defined with [`@enum`](@ref).
1414"""
1515abstract type Enum{T<: Integer } end
1616
17+ basetype (:: Type{<:Enum{T}} ) where {T<: Integer } = T
18+
1719(:: Type{T} )(x:: Enum{T2} ) where {T<: Integer ,T2<: Integer } = T (bitcast (T2, x)):: T
1820Base. cconvert (:: Type{T} , x:: Enum{T2} ) where {T<: Integer ,T2<: Integer } = T (x)
1921Base. write (io:: IO , x:: Enum{T} ) where {T<: Integer } = write (io, T (x))
20- Base. read (io:: IO , :: Type{T} ) where {T<: Enum } = T (read (io, Enums. basetype (T)))
22+ Base. read (io:: IO , :: Type{T} ) where {T<: Enum } = T (read (io, basetype (T)))
23+
24+ Base. isless (x:: T , y:: T ) where {T<: Enum } = isless (basetype (T)(x), basetype (T)(y))
25+
26+ Base. Symbol (x:: Enum ) = namemap (typeof (x))[Integer (x)]:: Symbol
27+
28+ Base. print (io:: IO , x:: Enum ) = print (io, Symbol (x))
29+
30+ function Base. show (io:: IO , x:: Enum )
31+ sym = Symbol (x)
32+ if ! get (io, :compact , false )
33+ from = get (io, :module , Main)
34+ def = typeof (x). name. module
35+ if from === nothing || ! Base. isvisible (sym, def, from)
36+ show (io, def)
37+ print (io, " ." )
38+ end
39+ end
40+ print (io, sym)
41+ end
42+
43+ function Base. show (io:: IO , :: MIME"text/plain" , x:: Enum )
44+ print (io, x, " ::" )
45+ show (IOContext (io, :compact => true ), typeof (x))
46+ print (io, " = " )
47+ show (io, Integer (x))
48+ end
49+
50+ function Base. show (io:: IO , :: MIME"text/plain" , t:: Type{<:Enum} )
51+ print (io, " Enum " )
52+ Base. show_datatype (io, t)
53+ print (io, " :" )
54+ for x in instances (t)
55+ print (io, " \n " , Symbol (x), " = " )
56+ show (io, Integer (x))
57+ end
58+ end
2159
2260# generate code to test whether expr is in the given set of values
2361function membershiptest (expr, values)
@@ -74,7 +112,7 @@ To list all the instances of an enum use `instances`, e.g.
74112
75113```jldoctest fruitenum
76114julia> instances(Fruit)
77- (apple::Fruit = 1 , orange::Fruit = 2 , kiwi::Fruit = 3 )
115+ (apple, orange, kiwi)
78116```
79117"""
80118macro enum (T, syms... )
@@ -92,7 +130,9 @@ macro enum(T, syms...)
92130 elseif ! isa (T, Symbol)
93131 throw (ArgumentError (" invalid type expression for enum $T " ))
94132 end
95- vals = Vector {Tuple{Symbol,Integer}} ()
133+ values = basetype[]
134+ seen = Set {Symbol} ()
135+ namemap = Dict {basetype,Symbol} ()
96136 lo = hi = 0
97137 i = zero (basetype)
98138 hasexpr = false
@@ -103,7 +143,7 @@ macro enum(T, syms...)
103143 for s in syms
104144 s isa LineNumberNode && continue
105145 if isa (s, Symbol)
106- if i == typemin (basetype) && ! isempty (vals )
146+ if i == typemin (basetype) && ! isempty (values )
107147 throw (ArgumentError (" overflow in value \" $s \" of Enum $typename " ))
108148 end
109149 elseif isa (s, Expr) &&
@@ -120,64 +160,41 @@ macro enum(T, syms...)
120160 throw (ArgumentError (string (" invalid argument for Enum " , typename, " : " , s)))
121161 end
122162 if ! Base. isidentifier (s)
123- throw (ArgumentError (" invalid name for Enum $typename ; \" $s \" is not a valid identifier." ))
163+ throw (ArgumentError (" invalid name for Enum $typename ; \" $s \" is not a valid identifier" ))
164+ end
165+ if hasexpr && haskey (namemap, i)
166+ throw (ArgumentError (" both $s and $(namemap[i]) have value $i in Enum $typename ; values must be unique" ))
124167 end
125- push! (vals, (s,i))
126- if length (vals) == 1
168+ namemap[i] = s
169+ push! (values, i)
170+ if s in seen
171+ throw (ArgumentError (" name \" $s \" in Enum $typename is not unique" ))
172+ end
173+ push! (seen, s)
174+ if length (values) == 1
127175 lo = hi = i
128176 else
129177 lo = min (lo, i)
130178 hi = max (hi, i)
131179 end
132180 i += oneunit (i)
133181 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
138182 blk = quote
139183 # enum definition
140184 Base. @__doc__ (primitive type $ (esc (typename)) <: Enum{$(basetype)} $ (sizeof (basetype) * 8 ) end )
141185 function $ (esc (typename))(x:: Integer )
142186 $ (membershiptest (:x , values)) || enum_argument_error ($ (Expr (:quote , typename)), x)
143187 return bitcast ($ (esc (typename)), convert ($ (basetype), x))
144188 end
145- 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