|
|
|
@ -6,6 +6,8 @@ export @enumx |
|
|
|
|
|
|
|
|
|
|
|
abstract type Enum{T} <: Base.Enum{T} end |
|
|
|
abstract type Enum{T} <: Base.Enum{T} end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
panic(x) = throw(ArgumentError(x)) |
|
|
|
|
|
|
|
|
|
|
|
macro enumx(args...) |
|
|
|
macro enumx(args...) |
|
|
|
return enumx(__module__, args...) |
|
|
|
return enumx(__module__, args...) |
|
|
|
end |
|
|
|
end |
|
|
|
@ -14,11 +16,12 @@ function enumx(_module_, name, args...) |
|
|
|
if name isa Symbol |
|
|
|
if name isa Symbol |
|
|
|
modname = name |
|
|
|
modname = name |
|
|
|
baseT = Int32 |
|
|
|
baseT = Int32 |
|
|
|
elseif name isa Expr && name.head == :(::) && name.args[1] isa Symbol && length(name.args) == 2 |
|
|
|
elseif name isa Expr && name.head == :(::) && name.args[1] isa Symbol && |
|
|
|
|
|
|
|
length(name.args) == 2 |
|
|
|
modname = name.args[1] |
|
|
|
modname = name.args[1] |
|
|
|
baseT = Core.eval(_module_, name.args[2]) |
|
|
|
baseT = Core.eval(_module_, name.args[2]) |
|
|
|
else |
|
|
|
else |
|
|
|
throw(ArgumentError("invalid EnumX.@enumx type specification: $(name)")) |
|
|
|
panic("invalid EnumX.@enumx type specification: $(name).") |
|
|
|
end |
|
|
|
end |
|
|
|
name = modname |
|
|
|
name = modname |
|
|
|
if length(args) == 1 && args[1] isa Expr && args[1].head === :block |
|
|
|
if length(args) == 1 && args[1] isa Expr && args[1].head === :block |
|
|
|
@ -27,18 +30,49 @@ function enumx(_module_, name, args...) |
|
|
|
syms = args |
|
|
|
syms = args |
|
|
|
end |
|
|
|
end |
|
|
|
namemap = Dict{baseT,Symbol}() |
|
|
|
namemap = Dict{baseT,Symbol}() |
|
|
|
next = 0 |
|
|
|
next = zero(baseT) |
|
|
|
for s in syms |
|
|
|
for s in syms |
|
|
|
s isa LineNumberNode && continue |
|
|
|
s isa LineNumberNode && continue |
|
|
|
s isa Symbol || throw(ArgumentError("invalid member expression: $(s)")) |
|
|
|
local sym |
|
|
|
namemap[next] = s |
|
|
|
if s isa Symbol |
|
|
|
next += 1 |
|
|
|
if next == typemin(baseT) |
|
|
|
|
|
|
|
panic("value overflow for Enum $(modname): $(modname).$(s) = $(next).") |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
sym = s |
|
|
|
|
|
|
|
elseif s isa Expr && s.head === :(=) && s.args[1] isa Symbol && length(s.args) == 2 |
|
|
|
|
|
|
|
nx = Core.eval(_module_, s.args[2]) |
|
|
|
|
|
|
|
if !(nx isa Integer && typemin(baseT) <= nx <= typemax(baseT)) |
|
|
|
|
|
|
|
panic( |
|
|
|
|
|
|
|
"invalid value for Enum $(modname){$(baseT)}: " * |
|
|
|
|
|
|
|
"$(modname).$(s.args[1]) = $(repr(nx))." |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
next = convert(baseT, nx) |
|
|
|
|
|
|
|
sym = s.args[1] |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
panic("invalid EnumX.@enumx entry: $(s)") |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
if next in keys(namemap) |
|
|
|
|
|
|
|
panic( |
|
|
|
|
|
|
|
"duplicate value for Enum $(modname): $(modname).$(sym) = $(next)," * |
|
|
|
|
|
|
|
" value already used for $(modname).$(namemap[next]) = $(next)." |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
elseif sym in values(namemap) |
|
|
|
|
|
|
|
value = findfirst(x -> x === sym, namemap) |
|
|
|
|
|
|
|
panic( |
|
|
|
|
|
|
|
"duplicate name for Enum $(modname): $(modname).$(sym) = $(next)," * |
|
|
|
|
|
|
|
" name already used for $(modname).$(namemap[value]) = $(value)." |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
namemap[next] = sym |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
next += oneunit(baseT) |
|
|
|
end |
|
|
|
end |
|
|
|
module_block = quote |
|
|
|
module_block = quote |
|
|
|
primitive type Type <: Enum{$(baseT)} $(sizeof(baseT) * 8) end |
|
|
|
primitive type Type <: Enum{$(baseT)} $(sizeof(baseT) * 8) end |
|
|
|
let namemap = $(namemap) |
|
|
|
let namemap = $(namemap) |
|
|
|
check_valid(x) = x in keys(namemap) || |
|
|
|
check_valid(x) = x in keys(namemap) || |
|
|
|
throw(ArgumentError("invalid value $(x) for Enum $($(QuoteNode(modname)))")) |
|
|
|
throw(ArgumentError("invalid value for Enum $($(QuoteNode(modname))): $(x).")) |
|
|
|
global function $(esc(:Type))(x::Integer) |
|
|
|
global function $(esc(:Type))(x::Integer) |
|
|
|
check_valid(x) |
|
|
|
check_valid(x) |
|
|
|
return Base.bitcast($(esc(:Type)), convert($(baseT), x)) |
|
|
|
return Base.bitcast($(esc(:Type)), convert($(baseT), x)) |
|
|
|
@ -68,7 +102,10 @@ function Base.show(io::IO, ::MIME"text/plain", ::Base.Type{E}) where E <: Enum |
|
|
|
string("$(nameof(parentmodule(E))).", v) => k for (k, v) in Base.Enums.namemap(E) |
|
|
|
string("$(nameof(parentmodule(E))).", v) => k for (k, v) in Base.Enums.namemap(E) |
|
|
|
) |
|
|
|
) |
|
|
|
mx = maximum(textwidth, keys(stringmap); init = 0) |
|
|
|
mx = maximum(textwidth, keys(stringmap); init = 0) |
|
|
|
print(iob, "Enum type $(nameof(parentmodule(E))).Type <: Enum{$(Base.Enums.basetype(E))} with $(n) instance$(n == 1 ? "" : "s"):") |
|
|
|
print(iob, |
|
|
|
|
|
|
|
"Enum type $(nameof(parentmodule(E))).Type <: ", |
|
|
|
|
|
|
|
"Enum{$(Base.Enums.basetype(E))} with $(n) instance$(n == 1 ? "" : "s"):" |
|
|
|
|
|
|
|
) |
|
|
|
for (k, v) in stringmap |
|
|
|
for (k, v) in stringmap |
|
|
|
print(iob, "\n", rpad(k, mx), " = $(v)") |
|
|
|
print(iob, "\n", rpad(k, mx), " = $(v)") |
|
|
|
end |
|
|
|
end |
|
|
|
|