Skip to content

Commit

Permalink
If no enum member values are given, pick the smallest signed integer …
Browse files Browse the repository at this point in the history
…to fit all values
  • Loading branch information
quinnj committed Feb 12, 2015
1 parent 02cb520 commit f2d7f0f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 8 deletions.
9 changes: 8 additions & 1 deletion base/Enums.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Base.start{T<:Enum}(::Type{T}) = 1
Base.next{T<:Enum}(::Type{T},s) = Base.next(names(T),s)
Base.done{T<:Enum}(::Type{T},s) = Base.done(names(T),s)
# Pass Integer through to Enum constructor through Val{T}
call{T<:Enum}(::Type{T},x::Integer) = T(Val{convert(fieldtype(T,:n),x)})
call{T<:Enum}(::Type{T},x::Integer) = T(Val{convert(fieldtype(T,:val),x)})
# Catchall that errors when specific Enum(::Type{Val{n}}) hasn't been defined
call{T<:Enum,n}(::Type{T},::Type{Val{n}}) = error(string("invalid enum value for $T: ",n))

Expand All @@ -28,13 +28,15 @@ macro enum(T,syms...)
hi = typemin(Int)
i = -1
enumT = typeof(i)
hasexpr = false
for s in syms
i += one(typeof(i))
if isa(s,Symbol)
# pass
elseif isa(s,Expr) && s.head == :(=) && length(s.args) == 2 && isa(s.args[1],Symbol)
i = eval(s.args[2]) # allow exprs, e.g. uint128"1"
s = s.args[1]
hasexpr = true
else
error(string("invalid syntax in @enum: ",s))
end
Expand All @@ -44,6 +46,11 @@ macro enum(T,syms...)
i < lo && (lo = i)
i > hi && (hi = i)
end
if !hasexpr
n = length(vals)
enumT = n < 128 ? Int8 : n < 32768 ? Int16 :
n < 2147483648 ? Int32 : Int64
end
blk = quote
# enum definition
immutable $(esc(T)) <: $(esc(Enum))
Expand Down
28 changes: 21 additions & 7 deletions test/enums.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ using Base.Test
@test typeof(Fruit) == DataType
@test isbits(Fruit)
@test typeof(apple) <: Fruit <: Base.Enums.Enum
@test typeof(apple.val) <: Int
@test typeof(apple.val) <: Int8
@test int(apple) == 0
@test int(orange) == 1
@test int(kiwi) == 2
@test apple.val === Int8(0)
@test orange.val === Int8(1)
@test kiwi.val === Int8(2)
@test Fruit(0) == apple
@test Fruit(1) == orange
@test Fruit(2) == kiwi
@test_throws ErrorException Fruit(3)
@test_throws ErrorException Fruit(-1)
@test Fruit(Val{0}) == apple
@test Fruit(Val{Int8(0)}) == apple
@test_throws ErrorException Fruit(Val{3})
@test Fruit(0x00) == apple
@test Fruit(big(0)) == apple
Expand Down Expand Up @@ -81,31 +84,42 @@ end
@test ff.val === 0xff
@test overflowed.val === 0x00

@test_throws MethodError eval(macroexpand(:(@enum Test1 _zerofp=0.0)))
@test_throws MethodError eval(:(@enum Test1 _zerofp=0.0))

@test_throws InexactError eval(macroexpand(:(@enum Test11 _zerofp2=0.5)))
@test_throws InexactError eval(:(@enum Test11 _zerofp2=0.5))
# can't use non-identifiers as enum members
@test_throws ErrorException eval(macroexpand(:(@enum Test2 1=2)))
@test_throws ErrorException eval(:(@enum Test2 1=2))
# other Integer types of enum members
@enum Test3 _one_Test3=0x01 _two_Test3=0x02 _three_Test3=0x03
@test typeof(_one_Test3.val) <: UInt8
@test _one_Test3.val === 0x01
@test length(Test3) == 3

@enum Test4 _one_Test4=0x01 _two_Test4=0x0002 _three_Test4=0x03
@test _one_Test4.val === 0x0001
@test _two_Test4.val === 0x0002
@test _three_Test4.val === 0x0003
@test typeof(_one_Test4.val) <: UInt16

@enum Test5 _one_Test5=0x01 _two_Test5=0x00000002 _three_Test5=0x00000003
@test _one_Test5.val === 0x00000001
@test _two_Test5.val === 0x00000002
@test _three_Test5.val === 0x00000003
@test typeof(_one_Test5.val) <: UInt32

@enum Test6 _one_Test6=0x00000000000000000000000000000001 _two_Test6=0x00000000000000000000000000000002
@test _one_Test6.val === 0x00000000000000000000000000000001
@test _two_Test6.val === 0x00000000000000000000000000000002
@test typeof(_one_Test6.val) <: UInt128

@enum Test7 _zero_Test7=0b0 _one_Test7=0b1 _two_Test7=0b10
@test _zero_Test7.val === 0x00
@test _one_Test7.val === 0x01
@test _two_Test7.val === 0x02
@test typeof(_zero_Test7.val) <: UInt8

@test_throws MethodError eval(macroexpand(:(@enum Test8 _zero="zero")))
@test_throws MethodError eval(macroexpand(:(@enum Test9 _zero='0')))
@test_throws MethodError eval(:(@enum Test8 _zero="zero"))
@test_throws MethodError eval(:(@enum Test9 _zero='0'))

@enum Test8 _zero_Test8=zero(Int64)
@test typeof(_zero_Test8.val) <: Int64
Expand Down

0 comments on commit f2d7f0f

Please sign in to comment.