1 /* lua/util.i: custom lua typemaps for xapian-bindings
2 *
3 * Copyright (C) 2011 Xiaona Han
4 * Copyright (C) 2012 Olly Betts
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 // "end" is a keyword in Lua, so we rename it to "_end"
23 %rename("_end") end;
24
25 %rename("__tostring") get_description;
26
27 %{
28 #if LUA_VERSION_NUM-0 >= 502
29 // luaL_typerror was removed in Lua 5.2.
luaL_typerror(lua_State * L,int narg,const char * tname)30 int luaL_typerror (lua_State *L, int narg, const char *tname) {
31 const char *msg = lua_pushfstring(L, "%s expected, got %s",
32 tname, luaL_typename(L, narg));
33 return luaL_argerror(L, narg, msg);
34 }
35 #endif
36
37 // Define lua_rawlen for Lua 5.1 (Lua 5.2 already has it).
38 //
39 // Newer SWIG already does this, hence the check for !defined lua_rawlen.
40 #if !defined lua_rawlen && LUA_VERSION_NUM == 501
41 # define lua_rawlen lua_objlen
42 #endif
43
44 // LUA_RIDX_GLOBALS is new in Lua 5.2.
45 #ifdef LUA_RIDX_GLOBALS
46 # ifndef LUA_GLOBALSINDEX
47 # define LUA_GLOBALSINDEX (-10002)
48 # endif
49 #define lua_pushvalue(L,P) do { if ((P) == LUA_GLOBALSINDEX) { lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); } else { lua_pushvalue(L,P); } } while (0)
50 #endif
51 %}
52
53 %define SUB_CLASS(NS, CLASS)
54 %{
55 class lua##CLASS : public NS::CLASS {
56 int r;
57 lua_State* L;
58
59 public:
CLASS(lua_State * S)60 lua##CLASS(lua_State* S) {
61 L = S;
62 if (!lua_isfunction(L, -1)) {
63 luaL_typerror(L, -1, "function");
64 }
65 r = luaL_ref(L, LUA_REGISTRYINDEX);
66 }
67
CLASS()68 ~lua##CLASS() {
69 luaL_unref(L, LUA_REGISTRYINDEX, r);
70 }
71
operator()72 bool operator()(const std::string &term) const {
73 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
74 if (!lua_isfunction(L, -1)) {
75 luaL_typerror(L, -1, "function");
76 }
77
78 lua_pushlstring(L, (char *)term.c_str(), term.length());
79 if (lua_pcall(L, 1, 1, 0) != 0){
80 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
81 }
82 if (!lua_isboolean(L, -1)) {
83 luaL_error(L, "function must return a boolean");
84 }
85 bool result = lua_toboolean(L, -1);
86 lua_pop(L, 1);
87 return result;
88 }
89 };
90 %}
91
92 %enddef
93
94 SUB_CLASS(Xapian, ExpandDecider)
95 SUB_CLASS(Xapian, Stopper)
96
97 %{
98 class luaMatchDecider : public Xapian::MatchDecider {
99 int r;
100 lua_State* L;
101
102 public:
luaMatchDecider(lua_State * S)103 luaMatchDecider(lua_State* S) {
104 L = S;
105 if (!lua_isfunction(L, -1)) {
106 luaL_typerror(L, -1, "function");
107 }
108 r = luaL_ref(L, LUA_REGISTRYINDEX);
109 }
110
~luaMatchDecider()111 ~luaMatchDecider() {
112 luaL_unref(L, LUA_REGISTRYINDEX, r);
113 }
114
operator()115 bool operator()(const Xapian::Document &doc) const {
116 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
117 if (!lua_isfunction(L, -1)) {
118 luaL_typerror(L, -1, "function");
119 }
120
121 SWIG_NewPointerObj(L, &doc, SWIGTYPE_p_Xapian__Document, 0);
122 if (lua_pcall(L, 1, 1, 0) != 0){
123 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
124 }
125 if (!lua_isboolean(L, -1)) {
126 luaL_error(L, "function must return a boolean");
127 }
128 bool result = lua_toboolean(L, -1);
129 lua_pop(L, 1);
130 return result;
131 }
132 };
133 %}
134
135 %{
136 class luaStemImplementation : public Xapian::StemImplementation {
137 int r;
138 lua_State* L;
139
140 public:
luaStemImplementation(lua_State * S)141 luaStemImplementation(lua_State* S) {
142 L = S;
143 if (!lua_isfunction(L, -1)) {
144 luaL_typerror(L, -1, "function");
145 }
146 r = luaL_ref(L, LUA_REGISTRYINDEX);
147 }
148
~luaStemImplementation()149 ~luaStemImplementation() {
150 luaL_unref(L, LUA_REGISTRYINDEX, r);
151 }
152
operator()153 std::string operator()(const std::string &word) {
154 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
155 if (!lua_isfunction(L, -1)) {
156 luaL_typerror(L, -1, "function");
157 }
158
159 lua_pushlstring(L, (char *)word.c_str(), word.length());
160 if (lua_pcall(L, 1, 1, 0) != 0){
161 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
162 }
163 if (!lua_isstring(L, -1)) {
164 luaL_error(L, "function must return a string");
165 }
166 size_t len;
167 const char * p = lua_tolstring(L, -1, &len);
168 std::string result(p, len);
169 lua_pop(L, 1);
170 return result;
171 }
get_description()172 std::string get_description() const {
173 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
174 if (!lua_isfunction(L, -1)) {
175 luaL_typerror(L, -1, "function");
176 }
177
178 if (lua_pcall(L, 0, 1, 0) != 0){
179 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
180 }
181 if (!lua_isstring(L, -1)) {
182 luaL_error(L, "function must return a string");
183 }
184
185 size_t len;
186 const char * p = lua_tolstring(L, -1, &len);
187 std::string result(p, len);
188 lua_pop(L, 1);
189 return result;
190 }
191 };
192 %}
193
194 %{
195 class luaKeyMaker : public Xapian::KeyMaker {
196 int r;
197 lua_State* L;
198
199 public:
luaKeyMaker(lua_State * S)200 luaKeyMaker(lua_State* S) {
201 L = S;
202 if (!lua_isfunction(L, -1)) {
203 luaL_typerror(L, -1, "function");
204 }
205 r = luaL_ref(L, LUA_REGISTRYINDEX);
206 }
207
~luaKeyMaker()208 ~luaKeyMaker() {
209 luaL_unref(L, LUA_REGISTRYINDEX, r);
210 }
211
operator()212 std::string operator()(const Xapian::Document &doc) const {
213 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
214 if (!lua_isfunction(L, -1)) {
215 luaL_typerror(L, -1, "function");
216 }
217
218 SWIG_NewPointerObj(L, &doc, SWIGTYPE_p_Xapian__Document, 0);
219 if (lua_pcall(L, 1, 1, 0) != 0){
220 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
221 }
222 if (!lua_isstring(L, -1)) {
223 luaL_error(L, "function must return a string");
224 }
225 size_t len;
226 const char * p = lua_tolstring(L, -1, &len);
227 std::string result(p, len);
228 lua_pop(L, 1);
229 return result;
230 }
231 };
232 %}
233
234 %{
235 class luaValueRangeProcessor : public Xapian::ValueRangeProcessor {
236 int r;
237 lua_State* L;
238
239 public:
luaValueRangeProcessor(lua_State * S)240 luaValueRangeProcessor(lua_State* S) {
241 L = S;
242 if (!lua_isfunction(L, -1)) {
243 luaL_typerror(L, -1, "function");
244 }
245 r = luaL_ref(L, LUA_REGISTRYINDEX);
246 }
247
~luaValueRangeProcessor()248 ~luaValueRangeProcessor() {
249 luaL_unref(L, LUA_REGISTRYINDEX, r);
250 }
251
operator()252 Xapian::valueno operator()(std::string &begin, std::string &end) {
253 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
254 if (!lua_isfunction(L, -1)) {
255 luaL_typerror(L, -1, "function");
256 }
257
258 lua_pushlstring(L, (char *)begin.c_str(), begin.length());
259 lua_pushlstring(L, (char *)end.c_str(), end.length());
260
261 if (lua_pcall(L, 2, 1, 0) != 0){
262 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
263 }
264 if (!lua_isnumber(L, -1)) {
265 luaL_error(L, "function must return a nubmer");
266 }
267 Xapian::valueno result(lua_tonumber(L, -1));
268 lua_pop(L, 1);
269 return result;
270 }
271 };
272 %}
273
274 %{
275 class luaMatchSpy : public Xapian::MatchSpy {
276 int r;
277 lua_State* L;
278
279 public:
luaMatchSpy(lua_State * S)280 luaMatchSpy(lua_State* S) {
281 L = S;
282 if (!lua_isfunction(L, -1)) {
283 luaL_typerror(L, -1, "function");
284 }
285 r = luaL_ref(L, LUA_REGISTRYINDEX);
286 }
287
~luaMatchSpy()288 ~luaMatchSpy() {
289 luaL_unref(L, LUA_REGISTRYINDEX, r);
290 }
291
operator()292 void operator()(const Xapian::Document &doc, Xapian::weight wt) {
293 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
294 if (!lua_isfunction(L, -1)) {
295 luaL_typerror(L, -1, "function");
296 }
297
298 SWIG_NewPointerObj(L, &doc, SWIGTYPE_p_Xapian__Document, 0);
299 SWIG_NewPointerObj(L, &wt, SWIGTYPE_p_Xapian__Weight, 0);
300 if (lua_pcall(L, 2, 1, 0) != 0){
301 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
302 }
303 return;
304 }
305 };
306 %}
307
308 %define SUB_CLASS_TYPEMAPS(NS, CLASS)
309
310 %typemap(typecheck, precedence=100) NS::CLASS * {
311 void *ptr;
312 if (lua_isfunction(L, $input) || (SWIG_isptrtype(L, $input) && !SWIG_ConvertPtr(L, $input, (void **) &ptr, $descriptor(NS::CLASS *), 0))) {
313 $1 = 1;
314 }
315 else {
316 $1 = 0;
317 }
318 }
319 %typemap(in) NS::CLASS * {
320 if (lua_isfunction(L, $input)) {
321 $1 = new lua##CLASS(L);
322 }
323 else {
324 if (!SWIG_IsOK(SWIG_ConvertPtr(L, $input, (void**)&$1, $descriptor(NS::CLASS *), 0))){
325 SWIG_fail;
326 }
327 }
328 }
329
330 %enddef
331 SUB_CLASS_TYPEMAPS(Xapian, MatchDecider)
332 SUB_CLASS_TYPEMAPS(Xapian, ExpandDecider)
333 SUB_CLASS_TYPEMAPS(Xapian, Stopper)
334 SUB_CLASS_TYPEMAPS(Xapian, StemImplementation)
335 SUB_CLASS_TYPEMAPS(Xapian, KeyMaker)
336 SUB_CLASS_TYPEMAPS(Xapian, ValueRangeProcessor)
337
338 %luacode {
339 function xapian.Iterator(begin, _end)
340 local iter = begin;
341 local isFirst = 1
342 return function()
343 if iter:equals(_end) then
344 return nil
345 else
346 if isFirst == 1 then
347 isFirst = 0;
348 return iter
349 else
350 iter:next()
351 if iter:equals(_end) then
352 return nil
353 end
354 return iter
355 end
356 end
357 end
358 end
359 }
360
361 #define XAPIAN_MIXED_VECTOR_QUERY_INPUT_TYPEMAP
362
363 %typemap(typecheck, precedence=500) const vector<Xapian::Query> & {
364 $1 = lua_istable(L, $input);
365 /* FIXME: if we add more array typemaps, we'll need to check the elements
366 * of the array here to disambiguate. */
367 }
368
369
370 %typemap(in) const vector<Xapian::Query> & (vector<Xapian::Query> v) {
371 int numitems = lua_rawlen(L, $input);;
372 v.reserve(numitems);
373 for (int i = 0; i < numitems; ++i) {
374 lua_rawgeti(L, $input, i+1);
375 if (lua_isstring(L, -1)) {
376 size_t len = 0;
377 const char *p = lua_tolstring(L, -1, &len);
378 v.push_back(Xapian::Query(string(p, len)));
379 } else {
380 Xapian::Query *subq = 0;
381 if(!lua_isuserdata(L, -1) || SWIG_ConvertPtr(L, -1, (void **)&subq, SWIGTYPE_p_Xapian__Query, 0) == -1){
382 lua_pop(L, 1);
383 luaL_argerror(L, $input, "elements of Tables passed to Query must be either Strings or other Queries");
384 }
385
386 v.push_back(*subq);
387 }
388 lua_pop(L, 1);
389 }
390 $1 = &v;
391 }
392
393 %define OUTPUT_ITERATOR_METHODS(NS, CLASS, ITERATOR_CLASS, ITERATOR_BEGIN, ITERATOR_END, DEREF_METHOD, PARAMETER_NAME, PARAMETER_VALUE)
394
395 %extend NS::CLASS {
396 std::pair<NS::ITERATOR_CLASS , NS::ITERATOR_CLASS> DEREF_METHOD(PARAMETER_NAME) {
397 return std::make_pair($self->ITERATOR_BEGIN(PARAMETER_VALUE), $self->ITERATOR_END(PARAMETER_VALUE));
398 }
399 }
400
401 %typemap(out) std::pair<NS::ITERATOR_CLASS, NS::ITERATOR_CLASS> {
402 lua_getglobal(L, "xapian");
403 lua_pushstring(L, "Iterator");
404 lua_gettable(L, -2);
405 lua_remove(L, -2);
406
407 if (!lua_isfunction(L, -1)) {
408 luaL_typerror(L, -1, "function");
409 }
410
411 NS::ITERATOR_CLASS * begin = new NS::ITERATOR_CLASS((const NS::ITERATOR_CLASS &)$1.first);
412 SWIG_NewPointerObj(L, (void *) begin, $descriptor(NS::ITERATOR_CLASS *), 1);
413
414 NS::ITERATOR_CLASS * end = new NS::ITERATOR_CLASS((const NS::ITERATOR_CLASS &)$1.second);
415 SWIG_NewPointerObj(L, (void *) end, $descriptor(NS::ITERATOR_CLASS *), 1);
416
417 if (lua_pcall(L, 2, 1, 0) != 0) {
418 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
419 }
420
421 SWIG_arg++;
422 }
423
424 %enddef
425
426 OUTPUT_ITERATOR_METHODS(Xapian, Query, TermIterator, get_terms_begin, get_terms_end, get_terms, void, )
427
428 OUTPUT_ITERATOR_METHODS(Xapian, QueryParser, TermIterator, stoplist_begin, stoplist_end, stoplist, void, )
429
430 OUTPUT_ITERATOR_METHODS(Xapian, ESet, ESetIterator, begin, end, terms, void, )
431
432 OUTPUT_ITERATOR_METHODS(Xapian, MSet, MSetIterator, begin, end, items, void, )
433
434 OUTPUT_ITERATOR_METHODS(Xapian, Document, TermIterator, termlist_begin, termlist_end, termlist, void, )
435 OUTPUT_ITERATOR_METHODS(Xapian, Document, ValueIterator, values_begin, values_end, values, void, )
436
437 OUTPUT_ITERATOR_METHODS(Xapian, Enquire, TermIterator, get_matching_terms_begin, get_matching_terms_end, get_matching_terms, Xapian::docid did, did)
438 OUTPUT_ITERATOR_METHODS(Xapian, Enquire, TermIterator, get_matching_terms_begin, get_matching_terms_end, get_matching_terms, const MSetIterator &it, it)
439
440 OUTPUT_ITERATOR_METHODS(Xapian, ValueCountMatchSpy, TermIterator, values_begin, values_end, values, void, )
441 OUTPUT_ITERATOR_METHODS(Xapian, ValueCountMatchSpy, TermIterator, top_values_begin, top_values_end, top_values, size_t maxvalues, maxvalues)
442
443 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, allterms_begin, allterms_end, allterms, void, )
444 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, spellings_begin, spellings_end, spellings, void, )
445 OUTPUT_ITERATOR_METHODS(Xapian, Database, PostingIterator, postlist_begin, postlist_end, postlist, const std::string &tname, tname)
446 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, termlist_begin, termlist_end, termlist, Xapian::docid did, did)
447 OUTPUT_ITERATOR_METHODS(Xapian, Database, ValueIterator, valuestream_begin, valuestream_end, valuestream, Xapian::valueno slot, slot)
448 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, allterms_begin, allterms_end, allterms, const std::string &prefix, prefix)
449 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, synonyms_begin, synonyms_end, synonyms, const std::string &term, term)
450 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, synonym_keys_begin, synonym_keys_end, synonym_keys, const std::string &prefix, prefix)
451 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, metadata_keys_begin, metadata_keys_end, metadata_keys, const std::string &prefix, prefix)
452
453 %extend Xapian::Database {
454 std::pair<Xapian::PositionIterator , Xapian::PositionIterator> positionlist(Xapian::docid did, const std::string &tname) {
455 return std::make_pair($self->positionlist_begin(did, tname), $self->positionlist_end(did, tname));
456 }
457 }
458
459 %typemap(out) std::pair<Xapian::PositionIterator, Xapian::PositionIterator> {
460 lua_getglobal(L, "xapian");
461 lua_pushstring(L, "Iterator");
462 lua_gettable(L, -2);
463 lua_remove(L, -2);
464
465 if (!lua_isfunction(L, -1)) {
466 luaL_typerror(L, -1, "function");
467 }
468
469 Xapian::PositionIterator * begin = new Xapian::PositionIterator((const Xapian::PositionIterator &)$1.first);
470 SWIG_NewPointerObj(L, (void *) begin, SWIGTYPE_p_Xapian__PositionIterator, 1);
471
472 Xapian::PositionIterator * end = new Xapian::PositionIterator((const Xapian::PositionIterator &)$1.second);
473 SWIG_NewPointerObj(L, (void *) end, SWIGTYPE_p_Xapian__PositionIterator, 1);
474
475 if (lua_pcall(L, 2, 1, 0) != 0) {
476 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
477 }
478
479 SWIG_arg++;
480 }
481