1 /* lua/util.i: custom lua typemaps for xapian-bindings
2  *
3  * Copyright (C) 2011 Xiaona Han
4  * Copyright (C) 2011,2012,2017,2019,2020 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 // On platforms where (sizeof(long) == 4), SWIG by default wraps
28 // Xapian::BAD_VALUENO as a negative constant in Lua, which is then rejected by
29 // a check which disallows passing negative values for unsigned C++ types.
30 // This %apply wraps it as a double constant, and also eliminates the negative
31 // value check.
32 %apply double { Xapian::valueno };
33 
34 %{
35 #if LUA_VERSION_NUM-0 >= 502
36 // luaL_typerror was removed in Lua 5.2.
luaL_typerror(lua_State * L,int narg,const char * tname)37 int luaL_typerror (lua_State *L, int narg, const char *tname) {
38   const char *msg = lua_pushfstring(L, "%s expected, got %s",
39 				    tname, luaL_typename(L, narg));
40   return luaL_argerror(L, narg, msg);
41 }
42 #endif
43 %}
44 
45 %define SUB_CLASS(NS, CLASS)
46 %{
47 class lua##CLASS : public NS::CLASS {
48     int r;
49     lua_State* L;
50 
51   public:
CLASS(lua_State * S)52     lua##CLASS(lua_State* S) {
53 	L = S;
54 	if (!lua_isfunction(L, -1)) {
55 	    luaL_typerror(L, -1, "function");
56 	}
57 	r = luaL_ref(L, LUA_REGISTRYINDEX);
58     }
59 
CLASS()60     ~lua##CLASS() {
61 	luaL_unref(L, LUA_REGISTRYINDEX, r);
62     }
63 
operator()64     bool operator()(const std::string &term) const {
65 	lua_rawgeti(L, LUA_REGISTRYINDEX, r);
66 	if (!lua_isfunction(L, -1)) {
67 	    luaL_typerror(L, -1, "function");
68 	}
69 
70 	lua_pushlstring(L, term.data(), term.length());
71 	if (lua_pcall(L, 1, 1, 0) != 0) {
72 	    luaL_error(L, "error running function: %s", lua_tostring(L, -1));
73 	}
74 	if (!lua_isboolean(L, -1)) {
75 	    luaL_error(L, "function must return a boolean");
76 	}
77 	bool result = lua_toboolean(L, -1);
78 	lua_pop(L, 1);
79 	return result;
80     }
81 };
82 %}
83 
84 %enddef
85 
86 SUB_CLASS(Xapian, ExpandDecider)
87 SUB_CLASS(Xapian, Stopper)
88 
89 %{
90 class luaMatchDecider : public Xapian::MatchDecider {
91     int r;
92     lua_State* L;
93 
94   public:
luaMatchDecider(lua_State * S)95     luaMatchDecider(lua_State* S) {
96 	L = S;
97 	if (!lua_isfunction(L, -1)) {
98 	    luaL_typerror(L, -1, "function");
99 	}
100 	r = luaL_ref(L, LUA_REGISTRYINDEX);
101     }
102 
~luaMatchDecider()103     ~luaMatchDecider() {
104 	luaL_unref(L, LUA_REGISTRYINDEX, r);
105     }
106 
operator()107     bool operator()(const Xapian::Document &doc) const {
108 	lua_rawgeti(L, LUA_REGISTRYINDEX, r);
109 	if (!lua_isfunction(L, -1)) {
110 	    luaL_typerror(L, -1, "function");
111 	}
112 
113 	SWIG_NewPointerObj(L, &doc, SWIGTYPE_p_Xapian__Document, 0);
114 	if (lua_pcall(L, 1, 1, 0) != 0) {
115 	    luaL_error(L, "error running function: %s", lua_tostring(L, -1));
116 	}
117 	if (!lua_isboolean(L, -1)) {
118 	    luaL_error(L, "function must return a boolean");
119 	}
120 	bool result = lua_toboolean(L, -1);
121 	lua_pop(L, 1);
122 	return result;
123     }
124 };
125 %}
126 
127 %{
128 class luaStemImplementation : public Xapian::StemImplementation {
129     int r;
130     lua_State* L;
131 
132   public:
luaStemImplementation(lua_State * S)133     luaStemImplementation(lua_State* S) {
134 	L = S;
135 	if (!lua_isfunction(L, -1)) {
136 	    luaL_typerror(L, -1, "function");
137 	}
138 	r = luaL_ref(L, LUA_REGISTRYINDEX);
139     }
140 
~luaStemImplementation()141     ~luaStemImplementation() {
142 	luaL_unref(L, LUA_REGISTRYINDEX, r);
143     }
144 
operator()145     std::string operator()(const std::string &word) {
146 	lua_rawgeti(L, LUA_REGISTRYINDEX, r);
147 	if (!lua_isfunction(L, -1)) {
148 	    luaL_typerror(L, -1, "function");
149 	}
150 
151 	lua_pushlstring(L, word.data(), word.length());
152 	if (lua_pcall(L, 1, 1, 0) != 0) {
153 	    luaL_error(L, "error running function: %s", lua_tostring(L, -1));
154 	}
155 	if (!lua_isstring(L, -1)) {
156 	    luaL_error(L, "function must return a string");
157 	}
158 	size_t len;
159 	const char * p = lua_tolstring(L, -1, &len);
160 	std::string result(p, len);
161 	lua_pop(L, 1);
162 	return result;
163     }
164 
get_description()165     std::string get_description() const {
166 	lua_rawgeti(L, LUA_REGISTRYINDEX, r);
167 	if (!lua_isfunction(L, -1)) {
168 	    luaL_typerror(L, -1, "function");
169 	}
170 
171 	if (lua_pcall(L, 0, 1, 0) != 0) {
172 	    luaL_error(L, "error running function: %s", lua_tostring(L, -1));
173 	}
174 	if (!lua_isstring(L, -1)) {
175 	    luaL_error(L, "function must return a string");
176 	}
177 
178 	size_t len;
179 	const char * p = lua_tolstring(L, -1, &len);
180 	std::string result(p, len);
181 	lua_pop(L, 1);
182 	return result;
183     }
184 };
185 %}
186 
187 %{
188 class luaKeyMaker : public Xapian::KeyMaker {
189     int r;
190     lua_State* L;
191 
192   public:
luaKeyMaker(lua_State * S)193     luaKeyMaker(lua_State* S) {
194 	L = S;
195 	if (!lua_isfunction(L, -1)) {
196 	    luaL_typerror(L, -1, "function");
197 	}
198 	r = luaL_ref(L, LUA_REGISTRYINDEX);
199     }
200 
~luaKeyMaker()201     ~luaKeyMaker() {
202 	luaL_unref(L, LUA_REGISTRYINDEX, r);
203     }
204 
operator()205     std::string operator()(const Xapian::Document &doc) const {
206 	lua_rawgeti(L, LUA_REGISTRYINDEX, r);
207 	if (!lua_isfunction(L, -1)) {
208 	    luaL_typerror(L, -1, "function");
209 	}
210 
211 	SWIG_NewPointerObj(L, &doc, SWIGTYPE_p_Xapian__Document, 0);
212 	if (lua_pcall(L, 1, 1, 0) != 0) {
213 	    luaL_error(L, "error running function: %s", lua_tostring(L, -1));
214 	}
215 	if (!lua_isstring(L, -1)) {
216 	    luaL_error(L, "function must return a string");
217 	}
218 	size_t len;
219 	const char * p = lua_tolstring(L, -1, &len);
220 	std::string result(p, len);
221 	lua_pop(L, 1);
222 	return result;
223     }
224 };
225 %}
226 
227 %{
228 class luaRangeProcessor : public Xapian::RangeProcessor {
229     int r;
230     lua_State* L;
231 
232   public:
luaRangeProcessor(lua_State * S)233     luaRangeProcessor(lua_State* S) {
234 	L = S;
235 	if (!lua_isfunction(L, -1)) {
236 	    luaL_typerror(L, -1, "function");
237 	}
238 	r = luaL_ref(L, LUA_REGISTRYINDEX);
239     }
240 
~luaRangeProcessor()241     ~luaRangeProcessor() {
242 	luaL_unref(L, LUA_REGISTRYINDEX, r);
243     }
244 
operator()245     Xapian::Query operator()(const std::string& begin, const std::string& end) {
246 	lua_rawgeti(L, LUA_REGISTRYINDEX, r);
247 	if (!lua_isfunction(L, -1)) {
248 	    luaL_typerror(L, -1, "function");
249 	}
250 
251 	lua_pushlstring(L, begin.data(), begin.length());
252 	lua_pushlstring(L, end.data(), end.length());
253 
254 	if (lua_pcall(L, 2, 1, 0) != 0) {
255 	    luaL_error(L, "error running function: %s", lua_tostring(L, -1));
256 	}
257 
258 	// Allow the function to return a string or Query object.
259 	if (lua_isstring(L, -1)) {
260 	    size_t len;
261 	    const char * p = lua_tolstring(L, -1, &len);
262 	    std::string result(p, len);
263 	    lua_pop(L, 1);
264 	    return Xapian::Query(result);
265 	}
266 
267 	Xapian::Query *subq = 0;
268 	if (!lua_isuserdata(L, -1) ||
269 	    SWIG_ConvertPtr(L, -1, (void **)&subq,
270 			    SWIGTYPE_p_Xapian__Query, 0) == -1) {
271 	    lua_pop(L, 1);
272 	    luaL_error(L, "function must return a string or Query object");
273 	}
274 
275 	lua_pop(L, 1);
276 	return *subq;
277     }
278 };
279 %}
280 
281 %{
282 class luaValueRangeProcessor : public Xapian::ValueRangeProcessor {
283     int r;
284     lua_State* L;
285 
286   public:
luaValueRangeProcessor(lua_State * S)287     luaValueRangeProcessor(lua_State* S) {
288 	L = S;
289 	if (!lua_isfunction(L, -1)) {
290 	    luaL_typerror(L, -1, "function");
291 	}
292 	r = luaL_ref(L, LUA_REGISTRYINDEX);
293     }
294 
~luaValueRangeProcessor()295     ~luaValueRangeProcessor() {
296 	luaL_unref(L, LUA_REGISTRYINDEX, r);
297     }
298 
operator()299     Xapian::valueno operator()(std::string &begin, std::string &end) {
300 	lua_rawgeti(L, LUA_REGISTRYINDEX, r);
301 	if (!lua_isfunction(L, -1)) {
302 	    luaL_typerror(L, -1, "function");
303 	}
304 
305 	lua_pushlstring(L, (char *)begin.c_str(), begin.length());
306 	lua_pushlstring(L, (char *)end.c_str(), end.length());
307 
308 	if (lua_pcall(L, 2, 1, 0) != 0) {
309 	    luaL_error(L, "error running function: %s", lua_tostring(L, -1));
310 	}
311 	if (!lua_isnumber(L, -1)) {
312 	    luaL_error(L, "function must return a number");
313 	}
314 	Xapian::valueno result(lua_tonumber(L, -1));
315 	lua_pop(L, 1);
316 	return result;
317     }
318 };
319 %}
320 
321 %{
322 class luaFieldProcessor : public Xapian::FieldProcessor {
323     int r;
324     lua_State* L;
325 
326   public:
luaFieldProcessor(lua_State * S)327     luaFieldProcessor(lua_State* S) {
328 	L = S;
329 	if (!lua_isfunction(L, -1)) {
330 	    luaL_typerror(L, -1, "function");
331 	}
332 	r = luaL_ref(L, LUA_REGISTRYINDEX);
333     }
334 
~luaFieldProcessor()335     ~luaFieldProcessor() {
336 	luaL_unref(L, LUA_REGISTRYINDEX, r);
337     }
338 
operator()339     Xapian::Query operator()(const std::string &str) {
340 	lua_rawgeti(L, LUA_REGISTRYINDEX, r);
341 	if (!lua_isfunction(L, -1)) {
342 	    luaL_typerror(L, -1, "function");
343 	}
344 
345 	lua_pushlstring(L, str.data(), str.length());
346 
347 	if (lua_pcall(L, 1, 1, 0) != 0) {
348 	    luaL_error(L, "error running function: %s", lua_tostring(L, -1));
349 	}
350 
351 	// Allow the function to return a string or Query object.
352 	if (lua_isstring(L, -1)) {
353 	    size_t len;
354 	    const char * p = lua_tolstring(L, -1, &len);
355 	    std::string result(p, len);
356 	    lua_pop(L, 1);
357 	    return Xapian::Query(result);
358 	}
359 
360 	Xapian::Query *subq = 0;
361 	if (!lua_isuserdata(L, -1) ||
362 	    SWIG_ConvertPtr(L, -1, (void **)&subq,
363 			    SWIGTYPE_p_Xapian__Query, 0) == -1) {
364 	    lua_pop(L, 1);
365 	    luaL_error(L, "function must return a string or Query object");
366 	}
367 
368 	lua_pop(L, 1);
369 	return *subq;
370     }
371 };
372 %}
373 
374 %{
375 class luaMatchSpy : public Xapian::MatchSpy {
376     int r;
377     lua_State* L;
378 
379   public:
luaMatchSpy(lua_State * S)380     luaMatchSpy(lua_State* S) {
381 	L = S;
382 	if (!lua_isfunction(L, -1)) {
383 	    luaL_typerror(L, -1, "function");
384 	}
385 	r = luaL_ref(L, LUA_REGISTRYINDEX);
386     }
387 
~luaMatchSpy()388     ~luaMatchSpy() {
389 	luaL_unref(L, LUA_REGISTRYINDEX, r);
390     }
391 
operator()392     void operator()(const Xapian::Document &doc, double wt) {
393 	lua_rawgeti(L, LUA_REGISTRYINDEX, r);
394 	if (!lua_isfunction(L, -1)) {
395 	    luaL_typerror(L, -1, "function");
396 	}
397 
398 	SWIG_NewPointerObj(L, &doc, SWIGTYPE_p_Xapian__Document, 0);
399 	SWIG_NewPointerObj(L, &wt, SWIGTYPE_p_Xapian__Weight, 0);
400 	if (lua_pcall(L, 2, 1, 0) != 0) {
401 	    luaL_error(L, "error running function: %s", lua_tostring(L, -1));
402 	}
403     }
404 };
405 %}
406 
407 %define SUB_CLASS_TYPEMAPS(NS, CLASS)
408 
409 %typemap(typecheck, precedence=100) NS::CLASS * {
410     void *ptr;
411     if (lua_isfunction(L, $input) || (SWIG_isptrtype(L, $input) && !SWIG_ConvertPtr(L, $input, (void **) &ptr, $descriptor(NS::CLASS *), 0))) {
412 	$1 = 1;
413     } else {
414 	$1 = 0;
415     }
416 }
417 %typemap(in) NS::CLASS * {
418     if (lua_isfunction(L, $input)) {
419 	$1 = new lua##CLASS(L);
420     } else {
421 	if (!SWIG_IsOK(SWIG_ConvertPtr(L, $input, (void**)&$1, $descriptor(NS::CLASS *), 0))) {
422 	    SWIG_fail;
423 	}
424     }
425 }
426 
427 %enddef
428 SUB_CLASS_TYPEMAPS(Xapian, MatchDecider)
429 SUB_CLASS_TYPEMAPS(Xapian, ExpandDecider)
430 SUB_CLASS_TYPEMAPS(Xapian, Stopper)
431 SUB_CLASS_TYPEMAPS(Xapian, StemImplementation)
432 SUB_CLASS_TYPEMAPS(Xapian, KeyMaker)
433 SUB_CLASS_TYPEMAPS(Xapian, RangeProcessor)
434 SUB_CLASS_TYPEMAPS(Xapian, ValueRangeProcessor)
435 SUB_CLASS_TYPEMAPS(Xapian, FieldProcessor)
436 SUB_CLASS_TYPEMAPS(Xapian, MatchSpy)
437 
438 %luacode {
439 function xapian.Iterator(begin, _end)
440 	local iter = begin;
441 	local isFirst = 1
442 	return function()
443 		if iter:equals(_end) then
444 			return nil
445 		else
446 			if isFirst == 1 then
447 				isFirst = 0;
448 				return iter
449 			else
450 				iter:next()
451 				if iter:equals(_end) then
452 					return nil
453 				end
454 				return iter
455 			end
456 		end
457 	end
458 end
459 }
460 
461 #define XAPIAN_MIXED_SUBQUERIES_BY_ITERATOR_TYPEMAP
462 
463 %typemap(typecheck, precedence=500) (XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend) {
464     $1 = lua_istable(L, $input);
465     /* FIXME: if we add more array typemaps, we'll need to check the elements
466      * of the array here to disambiguate. */
467 }
468 
469 %{
470 class XapianSWIGQueryItor {
471     lua_State* L;
472     int index;
473     int i;
474 
475   public:
476     typedef std::random_access_iterator_tag iterator_category;
477     typedef Xapian::Query value_type;
478     typedef Xapian::termcount_diff difference_type;
479     typedef Xapian::Query * pointer;
480     typedef Xapian::Query & reference;
481 
482     XapianSWIGQueryItor() { }
483 
484     void begin(lua_State * S, int index_) {
485 	L = S;
486 	index = index_;
487 	i = 0;
488     }
489 
490     void end(lua_State * S, int index_, int n) {
491 	L = S;
492 	index = index_;
493 	i = n;
494     }
495 
496     void end() {
497 	i = 0;
498     }
499 
500     XapianSWIGQueryItor & operator++() {
501 	++i;
502 	return *this;
503     }
504 
505     Xapian::Query operator*() const {
506 	lua_rawgeti(L, index, i+1);
507 	if (lua_isstring(L, -1)) {
508 	    size_t len = 0;
509 	    const char *p = lua_tolstring(L, -1, &len);
510 	    lua_pop(L,1);
511 	    return Xapian::Query(string(p, len));
512 	}
513 
514 	Xapian::Query *subq = 0;
515 	if (!lua_isuserdata(L, -1) ||
516 	    SWIG_ConvertPtr(L, -1, (void **)&subq,
517 			    SWIGTYPE_p_Xapian__Query, 0) == -1) {
518 	    lua_pop(L, 1);
519 	    luaL_argerror(L, index,
520 			  "elements must be Query objects or strings");
521 	}
522 
523 	lua_pop(L, 1);
524 	return *subq;
525     }
526 
527     bool operator==(const XapianSWIGQueryItor & o) {
528 	return i == o.i;
529     }
530 
531     bool operator!=(const XapianSWIGQueryItor & o) {
532 	return !(*this == o);
533     }
534 
535     difference_type operator-(const XapianSWIGQueryItor &o) const {
536 	return i - o.i;
537     }
538 };
539 
540 %}
541 
542 %typemap(in) (XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend) {
543     if (lua_istable(L, $input)) {
544 	$1.begin(L, $input);
545 	$2.end(L, $input, lua_rawlen(L, $input));
546     } else {
547 	$1.end();
548 	$2.end();
549     }
550 }
551 
552 %define OUTPUT_ITERATOR_METHODS(NS, CLASS, ITERATOR_CLASS, ITERATOR_BEGIN, ITERATOR_END, DEREF_METHOD, PARAMETER_NAME, PARAMETER_VALUE)
553 
554 %extend NS::CLASS {
555     std::pair<NS::ITERATOR_CLASS , NS::ITERATOR_CLASS> DEREF_METHOD(PARAMETER_NAME) {
556 	return std::make_pair($self->ITERATOR_BEGIN(PARAMETER_VALUE), $self->ITERATOR_END(PARAMETER_VALUE));
557     }
558 }
559 
560 %typemap(out) std::pair<NS::ITERATOR_CLASS, NS::ITERATOR_CLASS> {
561     lua_getglobal(L, "xapian");
562     lua_pushstring(L, "Iterator");
563     lua_gettable(L, -2);
564     lua_remove(L, -2);
565 
566     if (!lua_isfunction(L, -1)) {
567 	luaL_typerror(L, -1, "function");
568     }
569 
570     NS::ITERATOR_CLASS * begin = new NS::ITERATOR_CLASS((const NS::ITERATOR_CLASS &)$1.first);
571     SWIG_NewPointerObj(L, (void *) begin, $descriptor(NS::ITERATOR_CLASS *), 1);
572 
573     NS::ITERATOR_CLASS * end = new NS::ITERATOR_CLASS((const NS::ITERATOR_CLASS &)$1.second);
574     SWIG_NewPointerObj(L, (void *) end, $descriptor(NS::ITERATOR_CLASS *), 1);
575 
576     if (lua_pcall(L, 2, 1, 0) != 0) {
577 	luaL_error(L, "error running function: %s", lua_tostring(L, -1));
578     }
579 
580     SWIG_arg++;
581 }
582 
583 %enddef
584 
585 OUTPUT_ITERATOR_METHODS(Xapian, Query, TermIterator, get_terms_begin, get_terms_end, get_terms, void, )
586 
587 OUTPUT_ITERATOR_METHODS(Xapian, QueryParser, TermIterator, stoplist_begin, stoplist_end, stoplist, void, )
588 
589 OUTPUT_ITERATOR_METHODS(Xapian, ESet, ESetIterator, begin, end, terms, void, )
590 
591 OUTPUT_ITERATOR_METHODS(Xapian, MSet, MSetIterator, begin, end, items, void, )
592 
593 OUTPUT_ITERATOR_METHODS(Xapian, Document, TermIterator, termlist_begin, termlist_end, termlist, void, )
594 OUTPUT_ITERATOR_METHODS(Xapian, Document, ValueIterator, values_begin, values_end, values, void, )
595 
596 OUTPUT_ITERATOR_METHODS(Xapian, Enquire, TermIterator, get_matching_terms_begin, get_matching_terms_end, get_matching_terms, Xapian::docid did, did)
597 OUTPUT_ITERATOR_METHODS(Xapian, Enquire, TermIterator, get_matching_terms_begin, get_matching_terms_end, get_matching_terms, const MSetIterator &it, it)
598 
599 OUTPUT_ITERATOR_METHODS(Xapian, ValueCountMatchSpy, TermIterator, values_begin, values_end, values, void, )
600 OUTPUT_ITERATOR_METHODS(Xapian, ValueCountMatchSpy, TermIterator, top_values_begin, top_values_end, top_values, size_t maxvalues, maxvalues)
601 
602 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, allterms_begin, allterms_end, allterms, void, )
603 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, spellings_begin, spellings_end, spellings, void, )
604 OUTPUT_ITERATOR_METHODS(Xapian, Database, PostingIterator, postlist_begin, postlist_end, postlist, const std::string &tname, tname)
605 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, termlist_begin, termlist_end, termlist, Xapian::docid did, did)
606 OUTPUT_ITERATOR_METHODS(Xapian, Database, ValueIterator, valuestream_begin, valuestream_end, valuestream, Xapian::valueno slot, slot)
607 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, allterms_begin, allterms_end, allterms, const std::string &prefix, prefix)
608 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, synonyms_begin, synonyms_end, synonyms, const std::string &term, term)
609 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, synonym_keys_begin, synonym_keys_end, synonym_keys, const std::string &prefix, prefix)
610 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, metadata_keys_begin, metadata_keys_end, metadata_keys, const std::string &prefix, prefix)
611 
612 %extend Xapian::Database {
613     std::pair<Xapian::PositionIterator , Xapian::PositionIterator> positionlist(Xapian::docid did, const std::string &tname) {
614 	return std::make_pair($self->positionlist_begin(did, tname), $self->positionlist_end(did, tname));
615     }
616 }
617 
618 %typemap(out) std::pair<Xapian::PositionIterator, Xapian::PositionIterator> {
619     lua_getglobal(L, "xapian");
620     lua_pushstring(L, "Iterator");
621     lua_gettable(L, -2);
622     lua_remove(L, -2);
623 
624     if (!lua_isfunction(L, -1)) {
625 	luaL_typerror(L, -1, "function");
626     }
627 
628     Xapian::PositionIterator * begin = new Xapian::PositionIterator((const Xapian::PositionIterator &)$1.first);
629     SWIG_NewPointerObj(L, (void *) begin, SWIGTYPE_p_Xapian__PositionIterator, 1);
630 
631     Xapian::PositionIterator * end = new Xapian::PositionIterator((const Xapian::PositionIterator &)$1.second);
632     SWIG_NewPointerObj(L, (void *) end, SWIGTYPE_p_Xapian__PositionIterator, 1);
633 
634     if (lua_pcall(L, 2, 1, 0) != 0) {
635 	luaL_error(L, "error running function: %s", lua_tostring(L, -1));
636     }
637 
638     SWIG_arg++;
639 }
640