forked from theganyo/lua2go
/
lua2go.lua
195 lines (159 loc) · 5.01 KB
/
lua2go.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
--[[
A library for calling into Go from LuaJit
--]]
local lua2go = {}
local ffi = require('ffi')
ffi.cdef[[
// standard Go definitions //
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef char GoBool;
typedef float GoFloat32;
typedef double GoFloat64;
typedef __complex float GoComplex64;
typedef __complex double GoComplex128;
// static assertion to make sure the file is being used on architecture
// at least with matching size of GoInt.
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
// change to Go struct: add 'const' declaration to char * (required by Lua FFI)
// typedef struct { char *p; GoInt n; } GoString;
typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
// C stdlib definitions //
void free(void *ptr);
]]
local makeGoString = ffi.typeof('GoString')
local makeGoSlice = ffi.typeof('GoSlice')
local makeGoStringArray = ffi.typeof('GoString[?]')
local makeGoIntArray = ffi.typeof('GoInt[?]')
local identity = function(x) return x end
-- types: "nil", "number", "string", "boolean", "table", "function", "thread", or "userdata"
local goTypes = {
number = 'GoInt',
string = 'GoString'
}
local goArrayConstructors = {
number = makeGoIntArray,
string = makeGoStringArray
}
local goConverters = {
number = identity
}
goConverters['nil'] = identity
--
-- public interface
--
-- create cdata object
lua2go.New = ffi.new
-- add cdata to garbage collector, returns GC ref
lua2go.AddToGC = function(cdata)
return ffi.gc(cdata, ffi.C.free)
end
-- returns the typeof the Go object
lua2go.GoType = ffi.typeof
-- loads and returns a Go library
lua2go.Load = ffi.load
-- defines loaded functions
lua2go.Externs = ffi.cdef
-- convert C String to Lua
lua2go.ToLuaString = function(str)
if ffi.typeof(str) == makeGoString then
return ffi.string(str.p)
else
return ffi.string(str) -- assume char *
end
end
-- convert Number to lua bool
lua2go.ToLuaBool = function(number)
if number then
return true
else
return false
end
end
-- convert Number to Lua
lua2go.ToLuaNumber = tonumber
-- converts Lua String to a Go String
function lua2go.ToGoString(str)
if str == nil then return '' end
return makeGoString({ str, #str })
end
goConverters['string'] = lua2go.ToGoString
-- returns the Go type a luaVar will map to
-- currently supports Go strings and ints
function lua2go.Type(luaVar)
local luaType = type(luaVar)
return goTypes[luaType]
end
-- retrieve a function to get the slice type for a lua table
-- note: must be an array-style table, not a map
function lua2go.SliceType(table)
return lua2go.Type(table[1])..'[?]'
end
-- will make a Go array that is either Ints or Strings based on the first element type
-- must be an array-style table, not a map
-- currently only supports string and ints
function lua2go.ToGoArray(table)
local luaType = type(table[1])
local makeGoArray = goArrayConstructors[luaType]
local goArray = makeGoArray(#table)
local toGoType = goConverters[luaType]
for index, value in next, table do
goArray[index - 1] = toGoType(value)
end
return goArray
end
goConverters['table'] = lua2go.ToGoArray
-- will make a Go slice that is either Ints or Strings based on the first element type
-- must be an array-style table, not a map
-- returns GoSlice, backing array
function lua2go.ToGoSlice(table)
local goArray = lua2go.ToGoArray(table)
return makeGoSlice({ goArray, #table, #table }), goArray
end
-- retrieve a function to convert the luaVar to a goVar based on the type of luaVar
-- currently supports Go strings and ints
function lua2go.Converter(luaVar)
return goConverters[type(luaVar)]
end
-- converts a goVar to a luaVar
-- currently supports Go strings and ints
function lua2go.ToLua(goVar)
if goVar == nil then return nil end
if ffi.istype('GoString', goVar) or ffi.istype('char *', goVar) then
return lua2go.ToLuaString(goVar)
elseif ffi.istype('GoInt', goVar) then
return lua2go.ToLuaNumber(goVar)
else
error('unknown type')
end
end
-- converts luaVar to goVar using simple type mapping
-- currently only converts strings, numbers are left alone as they are converted automatically
function lua2go.ToGo(luaVar)
local convert = lua2go.Converter(luaVar)
return convert(luaVar)
end
-- returns a pointer and a value holder variable
function lua2go.ToGoPointer(luaVar)
local luaType = type(luaVar)
local makeGoArray = goArrayConstructors[luaType]
local ptr = makeGoArray(1, luaVar)
return ptr, ptr[0]
end
local module_mt = {
__newindex = (function (table, key, val) error('Attempt to write to undeclared variable "' .. key .. '"') end)
}
setmetatable(lua2go, module_mt)
return lua2go