Wednesday, June 14, 2017

SWIG for Lua: Reflection

For this blog entry, we show that it is possible for Lua to know about the fields and methods of a C++ struct. This ability for inspection is known as reflection in the programming world. Only basic reflection is demonstrated here; that is, only basic information is extracted from the C++ struct.

First, we define the C++ struct in the header file, example.hpp:

struct Point
{
int x;
int y;
void greet();
};
view raw example.hpp hosted with ❤ by GitHub
The struct implementation is defined in example.cpp:

#include "example.hpp"
#include <cstdio>
void Point::greet()
{
printf("x=%d, y=%d\n", x, y);
}
view raw example.cpp hosted with ❤ by GitHub
We then define the interface file, example.i, to be used by SWIG:

%module example
%{
/* Includes the header in the wrapper code */
#include "example.hpp"
%}
/* Parse the header file to generate wrappers */
%include "example.hpp"
view raw example.i hosted with ❤ by GitHub
After which, we use SWIG to generate the wrapper file:

% swig -lua -c++ example.i

We then compile the C++ source files and create the shared object to be used by our Lua script:

% g++ -fPIC -I/usr/include/lua5.2 -c example_wrap.cxx -o example_wrap.o
% g++ -fPIC -c example.cpp -o example.o
% g++ -shared -I/usr/include/lua5.2 example.o example_wrap.o -o example.so

We then write a Lua script, test.lua, for testing:

#!/usr/bin/lua
package.loadlib('./example.so', 'luaopen_example')()
A = example.Point()
A.x = 101
A.y = 202
print(A.x)
print(A.y)
A:greet()
print(swig_type(A.x))
print(swig_type(A.y))
print(swig_type(A.greet))
m = getmetatable(A)
print('/***** struct metatable *****/')
for k, v in pairs(m) do
print(k, v)
end
g = m['.get']
print('/***** struct fields *****/')
for k, v in pairs(g) do
print(k, v)
end
fn = m['.fn']
print('/***** struct methods *****/')
for k, v in pairs(fn) do
print(k, v)
end
view raw test.lua hosted with ❤ by GitHub
When run:

% ./test.lua
101
202
x=101, y=202
number
number
function
/***** struct metatable *****/
.type Point
__gc function: 0x7fced2eaf0a1
.get table: 0xf14c60
__tostring function: 0x7fced2eaf140
__newindex function: 0x7fced2eaef9f
.static table: 0xf15010
__eq function: 0x7fced2eaf29b
__index function: 0x7fced2eaeb93
.set table: 0xf15060
.fn table: 0xf150a0
.bases table: 0xf14c20
/***** struct fields *****/
y function: 0x7fced2eb1f9b
x function: 0x7fced2eb1b2f
/***** struct methods *****/
__disown function: 0x7fced2eaf234
greet function: 0x7fced2eb219a
view raw output.txt hosted with ❤ by GitHub
Lines 20-24 of test.lua print the names of the fields of the struct. Note that the order of the printing of the field names (lines 21-22 of output.txt) may not be the same as the order of declaration of the fields in the C++ struct definition in example.hpp (lines 3-4).

Lines 26-30 print the names of the methods of the struct.

Hope this helps the world.

No comments:

Post a Comment