@@ -7,7 +7,7 @@ module BitFlags
77import Core. Intrinsics. bitcast
88import Base. Meta. isexpr
99
10- export BitFlag, @bitflag
10+ export BitFlag, @bitflag , @bitflagx
1111
1212function namemap end
1313function haszero end
@@ -78,9 +78,30 @@ function Base.show(io::IO, x::BitFlag)
7878 print (io, x)
7979 else
8080 print (io, x, " ::" )
81- # explicitly setting :compact => false prints the type with its
82- # "contextual path", i.e. MyFlag (for Main.MyFlag) or Main.SubModule.OtherFlags
83- show (IOContext (io, :compact => false ), typeof (x))
81+
82+ T = typeof (x)
83+ Tdef = parentmodule (T)
84+ from = get (io, :module , @static isdefined (Base, :active_module ) ? Base. active_module () : Main)
85+
86+ # Detect a scoped BitFlag inside a baremodule by looking for the implicit import
87+ # of Base bindings. For scoped bitflags, we actually care about whether the
88+ # module itself is visible instead of the type.
89+ isscoped = ! isdefined (Tdef, :Base )
90+ sym = nameof (! isscoped ? T : Tdef)
91+ refmod = ! isscoped ? Tdef : parentmodule (Tdef)
92+ if from === nothing || ! Base. isvisible (sym, refmod, from)
93+ if ! isscoped
94+ print (io, refmod, " ." , sym)
95+ else
96+ print (io, Tdef, " ." , nameof (T))
97+ end
98+ else
99+ if ! isscoped
100+ print (io, sym)
101+ else
102+ print (io, nameof (Tdef), " ." , nameof (T))
103+ end
104+ end
84105 print (io, " = " )
85106 show (io, Integer (x))
86107 end
103124 throw (ArgumentError (" invalid value for BitFlag $typename : $x " ))
104125end
105126
106- @noinline function _throw_error (typename, s, msg = nothing )
127+ @noinline function _throw_macro_error (macroname, args)
128+ errmsg = " bad macro call: $(Expr (:macrocall , Symbol (macroname), nothing , args... )) "
129+ throw (ArgumentError (errmsg))
130+ end
131+
132+ @noinline function _throw_named_error (typename, s, msg = nothing )
107133 errmsg = " invalid argument for BitFlag $typename : $s "
108134 if msg != = nothing
109135 errmsg *= " ; " * msg
@@ -122,14 +148,14 @@ Create a `BitFlag{BaseType}` subtype with name `BitFlagName` and flag member val
122148```jldoctest itemflags
123149julia> @bitflag Items apple=1 fork=2 napkin=4
124150
125- julia> f(x::Items) = "I'm an Item with value: \$ x"
151+ julia> f(x::Items) = "I'm a flag with value: \$ x"
126152f (generic function with 1 method)
127153
128154julia> f(apple)
129- "I'm an Item with value: apple"
155+ "I'm a flag with value: apple"
130156
131157julia> f(apple | fork)
132- "I'm an Item with value: apple | fork"
158+ "I'm a flag with value: ( apple | fork) "
133159```
134160
135161Values can also be specified inside a `begin` block, e.g.
@@ -154,34 +180,78 @@ julia> instances(Items)
154180```
155181"""
156182macro bitflag (T:: Union{Symbol, Expr} , x:: Union{Symbol, Expr} ...)
157- return _bitflag (__module__, T, Any[x... ])
183+ flagname, basetype = _parse_name (__module__, T)
184+ return _bitflag (__module__, nothing , flagname, basetype, Any[x... ])
185+ end
186+
187+ """
188+ @bitflagx [T=FlagTypeName] BitFlagName[::BaseType] value1[=x] value2[=y]
189+
190+ Like [`@bitflag`](@ref) but instead scopes the new type `FlagTypeName` (named `T` if not
191+ overridden via the first optional argument) and member constants within a module named
192+ `BitFlagName`.
193+
194+ # Examples
195+ ```jldoctest scopedflags
196+ julia> @bitflagx ScopedItems apple=1 fork=2 napkin=4
197+
198+ julia> f(x::ScopedItems.T) = "I'm a scoped flag with value: \$ x"
199+ f (generic function with 1 method
200+
201+ julia> f(ScopedItems.apple | ScopedItems.fork)
202+ "I'm a scoped flag with value: (fork | apple)"
203+ """
204+ macro bitflagx (arg1:: Union{Symbol, Expr} , args:: Union{Symbol, Expr} ...)
205+ self = Symbol (" @bitflagx" )
206+ x = Any[args... ]
207+ if isexpr (arg1, :(= ), 2 ) && (e = arg1:: Expr ; (e. args[1 ] === :T && e. args[2 ] isa Symbol))
208+ # For this case, we need to decompose and swap symbols:
209+ # - `FlagTypeName` in `T = FlagTypeName` needs to get moved to the flagexpr argument
210+ # - `BitFlagName` in `BitFlagName[::BaseType]` becomes the scope name
211+ length (x) < 1 && _throw_macro_error (self, (arg1, args... ))
212+ arg2 = popfirst! (x)
213+ flagname = arg1. args[2 ]
214+ scope, basetype = _parse_name (__module__, arg2)
215+ return _bitflag (__module__, scope, flagname, basetype, x)
216+ elseif isexpr (arg1, :(:: ), 2 ) && (e = arg1:: Expr ; e. args[1 ] isa Symbol)
217+ scope, basetype = _parse_name (__module__, arg1)
218+ return _bitflag (__module__, scope, :T , basetype, x)
219+ elseif arg1 isa Symbol
220+ return _bitflag (__module__, arg1, :T , UInt32, x)
221+ else
222+ _throw_macro_error (self, (arg1, args... ))
223+ end
158224end
159225
160- function _bitflag (__module__:: Module , T :: Union{Symbol, Expr} , x :: Vector{Any } )
161- if T isa Symbol
162- typename = T
226+ function _parse_name (__module__:: Module , flagexpr :: Union{Symbol, Expr} )
227+ if flagexpr isa Symbol
228+ flagname = flagexpr
163229 basetype = UInt32
164- elseif isexpr (T , :(:: ), 2 ) && (e = T :: Expr ; e. args[1 ] isa Symbol)
165- typename = e. args[1 ]:: Symbol
230+ elseif isexpr (flagexpr , :(:: ), 2 ) && (e = flagexpr :: Expr ; e. args[1 ] isa Symbol)
231+ flagname = e. args[1 ]:: Symbol
166232 baseexpr = Core. eval (__module__, e. args[2 ])
167233 if ! (baseexpr isa DataType) || ! (baseexpr <: Unsigned ) || ! isbitstype (baseexpr)
168- _throw_error (typename, T , " base type must be a bitstype unsigned integer" )
234+ _throw_named_error (flagname, flagexpr , " base type must be a bitstype unsigned integer" )
169235 end
170236 basetype = baseexpr:: Type{<:Unsigned}
171237 else
172- _throw_error (T , " bad expression head" )
238+ _throw_named_error (flagexpr , " bad expression head" )
173239 end
174- if isempty (x)
175- throw (ArgumentError (" no arguments given for BitFlag $typename " ))
176- elseif length (x) == 1 && isexpr (x[1 ], :block )
240+ return (flagname, basetype)
241+ end
242+
243+ function _bitflag (__module__:: Module , scope:: Union{Symbol, Nothing} , flagname:: Symbol , basetype:: Type{<:Unsigned} , x:: Vector{Any} )
244+ isempty (x) && throw (ArgumentError (" no arguments given for BitFlag $flagname " ))
245+ if length (x) == 1 && isexpr (x[1 ], :block )
177246 syms = (x[1 ]:: Expr ). args
178247 else
179248 syms = x
180249 end
181- return _bitflag_impl (__module__, typename , basetype, syms)
250+ return _bitflag_impl (__module__, scope, flagname , basetype, syms)
182251end
183252
184- function _bitflag_impl (__module__:: Module , typename:: Symbol , basetype:: Type{<:Unsigned} , syms:: Vector{Any} )
253+ function _bitflag_impl (__module__:: Module , scope:: Union{Symbol, Nothing} , typename:: Symbol , basetype:: Type{<:Unsigned} ,
254+ syms:: Vector{Any} )
185255 names = Vector {Symbol} ()
186256 values = Vector {basetype} ()
187257 seen = Set {Symbol} ()
@@ -201,23 +271,23 @@ function _bitflag_impl(__module__::Module, typename::Symbol, basetype::Type{<:Un
201271 sym = e. args[1 ]:: Symbol
202272 ei = Core. eval (__module__, e. args[2 ]) # allow exprs, e.g. uint128"1"
203273 if ! (ei isa Integer)
204- _throw_error (typename, s, " values must be unsigned integers" )
274+ _throw_named_error (typename, s, " values must be unsigned integers" )
205275 end
206276 i = convert (basetype, ei):: basetype
207277 if ! iszero (i) && ! ispow2 (i)
208- _throw_error (typename, s, " values must be a positive power of 2" )
278+ _throw_named_error (typename, s, " values must be a positive power of 2" )
209279 end
210280 else
211- _throw_error (typename, s)
281+ _throw_named_error (typename, s)
212282 end
213283 if ! Base. isidentifier (sym)
214- _throw_error (typename, s, " not a valid identifier" )
284+ _throw_named_error (typename, s, " not a valid identifier" )
215285 end
216286 if (iszero (i) && maskzero) || (i & maskother) != 0
217- _throw_error (typename, s, " value is not unique" )
287+ _throw_named_error (typename, s, " value is not unique" )
218288 end
219289 if sym in seen
220- _throw_error (typename, s, " name is not unique" )
290+ _throw_named_error (typename, s, " name is not unique" )
221291 end
222292 push! (seen, sym)
223293 push! (names, sym)
@@ -245,7 +315,6 @@ function _bitflag_impl(__module__::Module, typename::Symbol, basetype::Type{<:Un
245315 permute! (values, order)
246316
247317 etypename = esc (typename)
248- ebasetype = esc (basetype)
249318
250319 n = length (names)
251320 instances = Vector {Expr} (undef, n)
@@ -259,9 +328,9 @@ function _bitflag_impl(__module__::Module, typename::Symbol, basetype::Type{<:Un
259328
260329 blk = quote
261330 # bitflag definition
262- Base . @__doc__ ( primitive type $ etypename <: BitFlag{$ebasetype } $ (8 sizeof (basetype)) end )
331+ primitive type $ etypename <: BitFlag{$basetype } $ (8 sizeof (basetype)) end
263332 function $etypename (x:: Integer )
264- z = convert ($ ebasetype , x)
333+ z = convert ($ basetype , x)
265334 $ membershiptest || _argument_error ($ (Expr (:quote , typename)), x)
266335 return bitcast ($ etypename, z)
267336 end
@@ -274,9 +343,26 @@ function _bitflag_impl(__module__::Module, typename::Symbol, basetype::Type{<:Un
274343 end
275344 Base. instances (:: Type{$etypename} ) = ($ (instances... ),)
276345 $ (flagconsts... )
277- nothing
346+ end
347+
348+ if scope isa Symbol
349+ escope = esc (scope)
350+ blk = quote
351+ baremodule $ escope
352+ $ (blk. args... )
353+ end
354+ Base. @__doc__ $ escope
355+ nothing
356+ end
357+ else
358+ blk = quote
359+ $ (blk. args... )
360+ Base. @__doc__ $ etypename
361+ nothing
362+ end
278363 end
279364 blk. head = :toplevel
365+
280366 return blk
281367end
282368
0 commit comments