-
Notifications
You must be signed in to change notification settings - Fork 1
/
ltypelib.h
192 lines (143 loc) · 4.23 KB
/
ltypelib.h
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
struct s {
int x, y;
};
void meth(struct *s, int x, int y);
int cmeth(lua_State *L) {
struct s *_s;
luaXt_pull(L, 1, s, &_s); // safe, since typechecks were done by wrapper
int x = lua_tointeger(L, 2);
int y = lua_tointeger(L, 3);
meth(_s, x, y);
return 0;
}
luaXt_declfield(s, x, int);
luaXt_declfield(s, y, int);
luaXt_declmethod(s, void, meth, 2, int, x, int, y); // FIXME What is this supposed to produce?
luaXt_declcmethod(s, cmeth, 2, int, x, int, y);
struct s *_s;
luaXt_push(L, s, _s);
// ---
void fun(int x);
int cfun(lua_State *L) {
int x = lua_tointeger(L, 1); // safe, since typechecks were done by wrapper
fun(x);
return 0;
}
luaXt_declfunction(void, fun, 1, int, x);
luaXt_declcfunction(cfun, 1, int, x);
luaXt_pushcfunction(L, cfun);
lua_setglobal(L, "fun");
// ---
typedef struct luaXt_Type luaXt_Type;
typedef struct luaXt_Field luaXt_Field;
typedef struct luaXt_CMethod luaXt_CMethod;
typedef struct luaXt_Argument luaXt_Argument;
typedef struct luaXt_CFunction luaXt_CFunction;
struct luaXt_Type {
const char *name;
bool (*is)(lua_State*, int narg); // FIXME call it "test" instead?
void (*push)(lua_State*, void*);
void (*pull)(lua_State*, int narg, void*);
int type; // LUA_TTABLE, LUA_TLIGHTUSERDATA or LUA_TUSERDATA
union {
struct {
int nfields;
luaXt_Field fields[];
} table;
struct {
int nmethods;
luaXt_CMethod methods[];
} udata;
};
};
struct luaXt_Field {
const char *name;
luaXt_Type *type;
};
struct luaXt_CMethod {
luaXt_Type *self;
const char *name;
lua_CFunction function;
};
#ifdef 0
struct luaXt_CMethod {
luaXt_Type *self;
luaXt_CFunction f;
};
#include "macromagic.h"
#define luaXt_declcfunction(function, ...) \
luaXt_declcfunction_impl(function, STRINGIFY function, NUM_ARGS(__VA_ARGS__)/2, FOREACH(STRINGIFY, (__VA_ARGS__)))
#define luaXt_pushcfunction(L, function) \
luaXt_pushcfunction_impl(L, STRINGIFY function)
struct luaXt_Argument {
const char *name;
luaXt_Type *type;
};
struct luaXt_CFunction {
const char *name;
lua_CFunction function;
int nargs;
luaXt_Argument args[];
};
void luaXt_declcfunction_impl(lua_CFunction function, const char *fname, int nargs, ...) {
va_list ap;
luaXt_CFunction *f = malloc(sizeof(luaXt_CFunction) + nargs*sizeof(luaXt_Argument));
*f = (luaXt_CFunction){
function,
strdup(fname),
nargs
};
va_start(ap, nargs);
for (int i = 0; i < nargs; i++) {
const char *arg_tname = va_arg(ap, const char*);
const char *arg_name = va_arg(ap, const char*);
luaXt_Type *targ = find_type(arg_tname);
if (targ == NULL) {
bail();
}
f->args[i] = (luaXt_Argument){strdup(arg_name), targ};
}
va_end(ap);
insert_cfunction(f); // map[fname] = f
}
void luaXt_pushcfunction_impl(lua_State *L, const char *fname) {
luaXt_CFunction *f = find_cfunction(fname); // f = map[fname]
lua_pushlightuserdata(L, f);
lua_pushcclosure(L, wrap_cfunction, 1);
}
int wrap_cfunction(lua_State *L) {
luaXt_CFunction *f = lua_touserdata(L, lua_upvalueindex(1));
for (int i = 0; i < f->nargs; i++) {
luaXt_Argument *arg = &f->args[i];
if (!arg->type->is(L, i)) {
return typeerror(L, i, f, arg);
}
}
return f->function(L);
}
int wrap_cmethod(lua_State *L) {
luaXt_CMethod *m = lua_touserdata(L, lua_upvalueindex(1));
void *self = luaX_testclass(L, 1, m->self->name, "self"); // FIXME Why not use checkclass instead?
if (self == NULL) {
return typeerror(L, 0, &m->f, m->self); // FIXME what is this exactly?
}
for (int i = 0; i < m->f.nargs; i++) {
luaXt_Argument *arg = &m->f.args[i];
if (!arg->type->is(L, i+1)) { // FIXME Why not use check functions instead?
return typeerror(L, i, &m->f, arg);
}
}
return m->f.function(L);
}
// --
Creating a function that will call through to Lua:
luaXt_declfunction(void, fun, 1, int, x);
#define luaXt_declfunction(rtype, function, ...) \
luaXt_declfunction_impl(STRINGIFY rtype, function, STRINGIFY function, NUM_ARGS(__VA_ARGS__), FOREACH(STRINGIFY, (__VA_ARGS__)))
// FIXME: Idea using the macro technique:
FOREACH_PAIR(PUSHARG, (__VA_ARGS__));
#define PUSHARG(arg_tname, arg_name) PUSHARG_##arg_tname(arg_name)
#define PUSHARG_int(arg_name) lua_pushinteger(L, arg_name)
void luaXt_declfunction_impl(const char *rtype, lua_CFunction function, const char *fname, int nargs, ...) {
}
#endif