Skip to content

Commit

Permalink
Fix code name collision for enums
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Feb 7, 2020
1 parent 176a209 commit 43285cb
Show file tree
Hide file tree
Showing 7 changed files with 25 additions and 18 deletions.
12 changes: 9 additions & 3 deletions nelua/analyzer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local tabler = require 'nelua.utils.tabler'
local pegger = require 'nelua.utils.pegger'
local typedefs = require 'nelua.typedefs'
local AnalyzerContext = require 'nelua.analyzercontext'
local Attr = require 'nelua.attr'
local Symbol = require 'nelua.symbol'
local types = require 'nelua.types'
local bn = require 'nelua.utils.bn'
Expand Down Expand Up @@ -447,12 +448,12 @@ end

function visitors.EnumFieldType(context, node)
local name, numnode = node[1], node[2]
local field = {name = name}
local field = Attr{name = name}
if numnode then
local desiredtype = node.desiredtype
context:traverse_node(numnode)
local numattr = numnode.attr
local value, numtype = numattr.value, numattr.type
local numtype = numattr.type
if not numattr.comptime then
numnode:raisef("in enum field '%s': enum fields can only be assigned to compile time values", name)
elseif not numtype:is_integral() then
Expand All @@ -463,7 +464,9 @@ function visitors.EnumFieldType(context, node)
if not ok then
numnode:raisef("in enum field '%s': %s", name, err)
end
field.value = value
field.value = numnode.attr.value
field.comptime = true
field.type = desiredtype
end
return field
end
Expand All @@ -486,12 +489,15 @@ function visitors.EnumType(context, node)
fnode:raisef("first enum field requires an initial value", field.name)
else
field.value = fields[i-1].value:add(1)
field.comptime = true
field.type = subtype
end
end
if not subtype:is_inrange(field.value) then
fnode:raisef("in enum field '%s': value %s is out of range for type '%s'",
field.name, field.value:todec(), subtype:prettyname())
end
assert(field.name)
fields[i] = field
end
attr.type = primtypes.type
Expand Down
2 changes: 1 addition & 1 deletion nelua/analyzercontext.lua
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ function AnalyzerContext:choose_codename(name)
if count then
count = count + 1
self.usedcodenames[name] = count
name = string.format('%s__%d', name, count)
name = string.format('%s__%d', name, count - 1)
end
self.usedcodenames[name] = 1
return name
Expand Down
5 changes: 1 addition & 4 deletions nelua/ccontext.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ function CContext:declname(attr)
end

function CContext:genuniquename(kind, fmt)
local count = self.uniquecounters[kind]
if not count then
count = 0
end
local count = self.uniquecounters[kind] or 0
count = count + 1
self.uniquecounters[kind] = count
if not fmt then
Expand Down
8 changes: 2 additions & 6 deletions nelua/cgenerator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,6 @@ typevisitors[types.EnumType] = function(context, type)
if type.nodecl or context:is_declared(type.codename) then return end
local decemitter = CEmitter(context, 0)
decemitter:add_ln('typedef ', type.subtype, ' ', type.codename, ';')
decemitter:add_ln('enum {')
for _,field in ipairs(type.fields) do
decemitter:add_ln(' ', field.name, ' = ', field.value, ',')
end
decemitter:add_ln('};')
context:add_declaration(decemitter:generate(), type.codename)
end

Expand Down Expand Up @@ -423,7 +418,8 @@ function visitors.DotIndex(context, node, emitter)
if objtype:is_type() then
objtype = attr.indextype
if objtype:is_enum() then
emitter:add(objtype:get_field(name).value)
local field = objtype:get_field(name)
emitter:add_numeric_literal(field)
elseif objtype:is_record() then
if attr.comptime then
emitter:add_literal(attr)
Expand Down
4 changes: 1 addition & 3 deletions nelua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -971,16 +971,14 @@ end
local EnumType = typeclass(IntegralType)
types.EnumType = EnumType
EnumType.enum = true
EnumType.primitive = false

function EnumType:_init(node, subtype, fields)
IntegralType._init(self, 'enum', subtype.size, subtype.unsigned)
self.node = node
self.subtype = subtype
self.fields = fields
self.codename = gencodename(self)
for _,field in ipairs(fields) do
field.codename = self.codename .. '_' .. field.name
end
end

function EnumType:get_field(name)
Expand Down
4 changes: 4 additions & 0 deletions spec/03-typechecker_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,10 @@ it("enums", function()
assert.analyze_ast([[
local Enum = @enum(byte){A=255}
]])
assert.analyze_error([[
local e: enum(byte){A=255}
e = 257
]], "is out of range")
assert.analyze_error([[
local Enum = @enum(byte){A=256}
]], "is out of range")
Expand Down
8 changes: 7 additions & 1 deletion spec/05-cgenerator_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1275,7 +1275,13 @@ end)
it("enums", function()
assert.generate_c(
"local e: enum{A=0}",
[[enum {]])
[[typedef int64_t enum_]])
assert.generate_c([[
local E = @enum{A=1, B=2}
local i: E = 1
local E = @enum{A=1, B=2}
local i: E = 1
]], {"typedef int64_t E", "typedef int64_t E__1"})
assert.run_c([[
local Enum = @enum{A=0,B=1,C}
local e: Enum; assert(e == 0)
Expand Down

0 comments on commit 43285cb

Please sign in to comment.