Skip to content

Commit

Permalink
Add <ctypedef> annotation to import structs from C without typedef
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Nov 12, 2020
1 parent d7016f3 commit 4a85f6d
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 36 deletions.
10 changes: 2 additions & 8 deletions lib/C/locale.nelua
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
require 'C'

##[[
cinclude '<locale.h>'
## cinclude '<locale.h>'

cemitdecl([==[
typedef struct lconv lconv_t;
]==])
]]

global lconv <cimport'lconv_t',nodecl> = @record {
global lconv <cimport'lconv_t',nodecl,ctypedef> = @record {
decimal_point: cstring,
thousands_sep: cstring,
grouping: cstring,
Expand Down
10 changes: 2 additions & 8 deletions lib/C/time.nelua
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@ require 'C'

##[[
cinclude '<time.h>'
cemitdecl([==[
typedef struct tm tm_t;
typedef struct timespec timespec_t;
]==])
local neluatypes = require 'nelua.types'
]]

global clock_t <cimport'clock_t',nodecl> = #[neluatypes.IntegralType('clock_t', primtypes.clong.size)]#
global time_t <cimport'time_t',nodecl> = #[neluatypes.IntegralType('time_t', primtypes.clong.size)]#
global tm <cimport'tm_t',nodecl> = @record{
global tm <cimport'tm',nodecl,ctypedef> = @record{
tm_sec: cint,
tm_min: cint,
tm_hour: cint,
Expand All @@ -24,7 +18,7 @@ global tm <cimport'tm_t',nodecl> = @record{
tm_yday: cint,
tm_isdst: cint
}
global timespec <cimport'timespec_t',nodecl> = @record {
global timespec <cimport'timespec',nodecl,ctypedef> = @record {
tv_sec: time_t,
tv_nsec: clong
}
Expand Down
8 changes: 1 addition & 7 deletions lib/os.nelua
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,10 @@ require 'string'
--------------------------------------------------------------------------------
-- C imports

##[[
cemitdecl([==[
typedef struct tm tm_t;
]==])
]]

local clock_t <cimport,nodecl> = #[types.IntegralType('clock_t', primtypes.clong.size)]#
local time_t <cimport,nodecl> = #[types.IntegralType('time_t', primtypes.clong.size)]#

local tm <cimport'tm_t',nodecl> = @record {
local tm <cimport'tm',nodecl,ctypedef> = @record {
tm_year: cint,
tm_mon: cint,
tm_mday: cint,
Expand Down
29 changes: 21 additions & 8 deletions nelua/ccontext.lua
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,28 @@ function CContext:typename(type)
until visitor

if visitor then
if config.check_type_shape then
assert(type:shape())
end
if type.cinclude then -- include headers before declaring
self:add_include(type.cinclude)
end
if not type.nodecl and not self:is_declared(type.codename) then
if not self:is_declared(type.codename) then
self.declarations[type.codename] = true
if config.check_type_shape then
assert(type:shape())
end
if type.cinclude then -- include headers before declaring
self:add_include(type.cinclude)
end
-- only declare when needed
visitor(self, type)
if not type.nodecl then
visitor(self, type)
elseif type.ctypedef then
local kind
if type.is_record then kind = 'struct'
elseif type.is_union then kind = 'union'
elseif type.is_enum then kind = 'enum'
end
if kind then
local code = 'typedef '..kind..' '..type.codename..' '..type.codename..';\n'
table.insert(self.declarations, code)
end
end
end
end
return type.codename
Expand Down
8 changes: 3 additions & 5 deletions nelua/cgenerator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,10 @@ typevisitors[types.ArrayType] = function(context, type)
decemitter:add_ln(';')
decemitter:add_ln('nelua_static_assert(sizeof(',type.codename,') == ', type.size,
', "Nelua and C disagree on type size");')
context:add_declaration(decemitter:generate(), type.codename)
table.insert(context.declarations, decemitter:generate())
end

typevisitors[types.PointerType] = function(context, type)
context.declarations[type.codename] = true
local decemitter = CEmitter(context, 0)
local index = nil
if type.subtype.is_record and not type.subtype.nodecl and not context.declarations[type.subtype.codename] then
Expand All @@ -284,7 +283,6 @@ typevisitors[types.PointerType] = function(context, type)
end

typevisitors[types.RecordType] = function(context, type)
context.declarations[type.codename] = true
local decemitter = CEmitter(context, 0)
decemitter:add_ln('typedef struct ', type.codename, ' ', type.codename, ';')
table.insert(context.declarations, decemitter:generate())
Expand Down Expand Up @@ -317,7 +315,7 @@ end
typevisitors[types.EnumType] = function(context, type)
local decemitter = CEmitter(context, 0)
decemitter:add_ln('typedef ', type.subtype, ' ', type.codename, ';')
context:add_declaration(decemitter:generate(), type.codename)
table.insert(context.declarations, decemitter:generate())
end

typevisitors[types.FunctionType] = function(context, type)
Expand All @@ -330,7 +328,7 @@ typevisitors[types.FunctionType] = function(context, type)
decemitter:add(argtype)
end
decemitter:add_ln(');')
context:add_declaration(decemitter:generate(), type.codename)
table.insert(context.declarations, decemitter:generate())
end

typevisitors.FunctionReturnType = function(context, functype)
Expand Down
2 changes: 2 additions & 0 deletions nelua/typedefs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ typedefs.type_annots = {
-- Whether to skip declaring the type in C.
-- When using this, the type must be declared somewhere else, like in a C include.
nodecl = true,
-- Whether to emit typedef for a C imported structs.
ctypedef = true,
-- Whether the compiler should pack a record type, removing padding between fields.
-- It uses the '__attribute__((packed))' in C.
packed = true,
Expand Down
2 changes: 2 additions & 0 deletions nelua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ Type.shape = shaper.shape {
nodecl = shaper.optional_boolean,
-- Whether the code generator should import the type from C.
cimport = shaper.optional_boolean,
-- Whether to emit typedef for a C imported structs.
ctypedef = shaper.optional_boolean,
-- Marked when declaring a type without its definition.
forwarddecl = shaper.optional_boolean,
-- C header that the code generator should include when using the type.
Expand Down
4 changes: 4 additions & 0 deletions spec/05-cgenerator_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2355,6 +2355,10 @@ it("annotations", function()
assert.generate_c(
"local function puts(s: cstring): int32 <cimport'puts'> end",
"int32_t puts(char* s);")
assert.generate_c([[
global timespec <cimport'timespec',nodecl,ctypedef> = @record{tv_sec: clong, tv_nsec: clong}
local t: timespec
]], "typedef struct timespec timespec;")
assert.generate_c(
"local function cos(x: number): number <cimport'myfunc',cinclude'<myheader.h>',nodecl> end",
"#include <myheader.h>")
Expand Down

0 comments on commit 4a85f6d

Please sign in to comment.