1 /* lua
/util.i
: custom lua typemaps for xapian-bindings
3 * Copyright
(C
) 2011 Xiaona Han
4 * Copyright
(C
) 2011,2012,2017,2019,2020 Olly Betts
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.
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.
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
23 // We use std
::unique_ptr
<> to avoid leaks.
27 // "end" is a keyword in Lua
, so we rename it to
"_end"
30 %rename
("__tostring") get_description
;
32 // On platforms where
(sizeof
(long
) == 4), SWIG by default wraps
33 // Xapian
::BAD_VALUENO as a negative constant in Lua
, which is then rejected by
34 // a check which disallows passing negative values for unsigned C
++ types.
35 // This
%apply wraps it as a double constant
, and also eliminates the negative
37 %apply double
{ Xapian
::valueno
};
40 #if LUA_VERSION_NUM-0
>= 502
41 // luaL_typerror was removed in Lua
5.2.
42 int luaL_typerror
(lua_State
*L
, int narg
, const char
*tname
) {
43 const char
*msg
= lua_pushfstring
(L
, "%s expected, got %s",
44 tname
, luaL_typename
(L
, narg
));
45 return luaL_argerror
(L
, narg
, msg
);
50 %define SUB_CLASS
(NS
, CLASS
)
52 class lua##CLASS
: public NS
::CLASS
{
57 lua##CLASS
(lua_State
* S
) {
59 if
(!lua_isfunction
(L
, -1)) {
60 luaL_typerror
(L
, -1, "function");
62 r
= luaL_ref
(L
, LUA_REGISTRYINDEX
);
66 luaL_unref
(L
, LUA_REGISTRYINDEX
, r
);
69 bool operator
()(const std
::string
& term) const override {
70 lua_rawgeti
(L
, LUA_REGISTRYINDEX
, r
);
71 if
(!lua_isfunction
(L
, -1)) {
72 luaL_typerror
(L
, -1, "function");
75 lua_pushlstring
(L
, term.data
(), term.length
());
76 if
(lua_pcall
(L
, 1, 1, 0) != 0) {
77 luaL_error
(L
, "error running function: %s", lua_tostring
(L
, -1));
79 if
(!lua_isboolean
(L
, -1)) {
80 luaL_error
(L
, "function must return a boolean");
82 bool result
= lua_toboolean
(L
, -1);
91 SUB_CLASS
(Xapian
, ExpandDecider
)
92 SUB_CLASS
(Xapian
, Stopper
)
95 class luaMatchDecider
: public Xapian
::MatchDecider
{
100 luaMatchDecider
(lua_State
* S
) {
102 if
(!lua_isfunction
(L
, -1)) {
103 luaL_typerror
(L
, -1, "function");
105 r
= luaL_ref
(L
, LUA_REGISTRYINDEX
);
109 luaL_unref
(L
, LUA_REGISTRYINDEX
, r
);
112 bool operator
()(const Xapian
::Document
& doc) const override {
113 lua_rawgeti
(L
, LUA_REGISTRYINDEX
, r
);
114 if
(!lua_isfunction
(L
, -1)) {
115 luaL_typerror
(L
, -1, "function");
118 SWIG_NewPointerObj
(L
, &doc, SWIGTYPE_p_Xapian__Document, 0);
119 if
(lua_pcall
(L
, 1, 1, 0) != 0) {
120 luaL_error
(L
, "error running function: %s", lua_tostring
(L
, -1));
122 if
(!lua_isboolean
(L
, -1)) {
123 luaL_error
(L
, "function must return a boolean");
125 bool result
= lua_toboolean
(L
, -1);
133 class luaStemImplementation
: public Xapian
::StemImplementation
{
138 luaStemImplementation
(lua_State
* S
) {
140 if
(!lua_isfunction
(L
, -1)) {
141 luaL_typerror
(L
, -1, "function");
143 r
= luaL_ref
(L
, LUA_REGISTRYINDEX
);
146 ~luaStemImplementation
() {
147 luaL_unref
(L
, LUA_REGISTRYINDEX
, r
);
150 std
::string operator
()(const std
::string
& word) override {
151 lua_rawgeti
(L
, LUA_REGISTRYINDEX
, r
);
152 if
(!lua_isfunction
(L
, -1)) {
153 luaL_typerror
(L
, -1, "function");
156 lua_pushlstring
(L
, word.data
(), word.length
());
157 if
(lua_pcall
(L
, 1, 1, 0) != 0) {
158 luaL_error
(L
, "error running function: %s", lua_tostring
(L
, -1));
160 if
(!lua_isstring
(L
, -1)) {
161 luaL_error
(L
, "function must return a string");
164 const char
* p
= lua_tolstring
(L
, -1, &len);
165 std
::string result
(p
, len
);
170 std
::string get_description
() const
{
171 return
"luaStemImplementation()";
177 class luaKeyMaker
: public Xapian
::KeyMaker
{
182 luaKeyMaker
(lua_State
* S
) {
184 if
(!lua_isfunction
(L
, -1)) {
185 luaL_typerror
(L
, -1, "function");
187 r
= luaL_ref
(L
, LUA_REGISTRYINDEX
);
191 luaL_unref
(L
, LUA_REGISTRYINDEX
, r
);
194 std
::string operator
()(const Xapian
::Document
& doc) const override {
195 lua_rawgeti
(L
, LUA_REGISTRYINDEX
, r
);
196 if
(!lua_isfunction
(L
, -1)) {
197 luaL_typerror
(L
, -1, "function");
200 SWIG_NewPointerObj
(L
, &doc, SWIGTYPE_p_Xapian__Document, 0);
201 if
(lua_pcall
(L
, 1, 1, 0) != 0) {
202 luaL_error
(L
, "error running function: %s", lua_tostring
(L
, -1));
204 if
(!lua_isstring
(L
, -1)) {
205 luaL_error
(L
, "function must return a string");
208 const char
* p
= lua_tolstring
(L
, -1, &len);
209 std
::string result
(p
, len
);
217 class luaRangeProcessor
: public Xapian
::RangeProcessor
{
222 luaRangeProcessor
(lua_State
* S
) {
224 if
(!lua_isfunction
(L
, -1)) {
225 luaL_typerror
(L
, -1, "function");
227 r
= luaL_ref
(L
, LUA_REGISTRYINDEX
);
230 ~luaRangeProcessor
() {
231 luaL_unref
(L
, LUA_REGISTRYINDEX
, r
);
234 Xapian
::Query operator
()(const std
::string
& begin,
235 const std
::string
& end) override {
236 lua_rawgeti
(L
, LUA_REGISTRYINDEX
, r
);
237 if
(!lua_isfunction
(L
, -1)) {
238 luaL_typerror
(L
, -1, "function");
241 lua_pushlstring
(L
, begin.data
(), begin.length
());
242 lua_pushlstring
(L
, end.data
(), end.length
());
244 if
(lua_pcall
(L
, 2, 1, 0) != 0) {
245 luaL_error
(L
, "error running function: %s", lua_tostring
(L
, -1));
248 // Allow the function to return a string or Query object.
249 if
(lua_isstring
(L
, -1)) {
251 const char
* p
= lua_tolstring
(L
, -1, &len);
252 std
::string result
(p
, len
);
254 return Xapian
::Query
(result
);
257 Xapian
::Query
*subq
= 0;
258 if
(!lua_isuserdata
(L
, -1) ||
259 SWIG_ConvertPtr
(L
, -1, (void
**)&subq,
260 SWIGTYPE_p_Xapian__Query
, 0) == -1) {
262 luaL_error
(L
, "function must return a string or Query object");
272 class luaFieldProcessor
: public Xapian
::FieldProcessor
{
277 luaFieldProcessor
(lua_State
* S
) {
279 if
(!lua_isfunction
(L
, -1)) {
280 luaL_typerror
(L
, -1, "function");
282 r
= luaL_ref
(L
, LUA_REGISTRYINDEX
);
285 ~luaFieldProcessor
() {
286 luaL_unref
(L
, LUA_REGISTRYINDEX
, r
);
289 Xapian
::Query operator
()(const std
::string
& str) override {
290 lua_rawgeti
(L
, LUA_REGISTRYINDEX
, r
);
291 if
(!lua_isfunction
(L
, -1)) {
292 luaL_typerror
(L
, -1, "function");
295 lua_pushlstring
(L
, str.data
(), str.length
());
297 if
(lua_pcall
(L
, 1, 1, 0) != 0) {
298 luaL_error
(L
, "error running function: %s", lua_tostring
(L
, -1));
301 // Allow the function to return a string or Query object.
302 if
(lua_isstring
(L
, -1)) {
304 const char
* p
= lua_tolstring
(L
, -1, &len);
305 std
::string result
(p
, len
);
307 return Xapian
::Query
(result
);
310 Xapian
::Query
*subq
= 0;
311 if
(!lua_isuserdata
(L
, -1) ||
312 SWIG_ConvertPtr
(L
, -1, (void
**)&subq,
313 SWIGTYPE_p_Xapian__Query
, 0) == -1) {
315 luaL_error
(L
, "function must return a string or Query object");
325 class luaMatchSpy
: public Xapian
::MatchSpy
{
330 luaMatchSpy
(lua_State
* S
) {
332 if
(!lua_isfunction
(L
, -1)) {
333 luaL_typerror
(L
, -1, "function");
335 r
= luaL_ref
(L
, LUA_REGISTRYINDEX
);
339 luaL_unref
(L
, LUA_REGISTRYINDEX
, r
);
342 void operator
()(const Xapian
::Document
& doc, double wt) override {
343 lua_rawgeti
(L
, LUA_REGISTRYINDEX
, r
);
344 if
(!lua_isfunction
(L
, -1)) {
345 luaL_typerror
(L
, -1, "function");
348 SWIG_NewPointerObj
(L
, &doc, SWIGTYPE_p_Xapian__Document, 0);
349 SWIG_NewPointerObj
(L
, &wt, SWIGTYPE_p_Xapian__Weight, 0);
350 if
(lua_pcall
(L
, 2, 1, 0) != 0) {
351 luaL_error
(L
, "error running function: %s", lua_tostring
(L
, -1));
358 %define SUB_CLASS_TYPEMAPS_
(NS
, CLASS
, PARAM, CODE...
)
360 %typemap
(typecheck
, precedence
=100) NS
::CLASS
* {
362 if
(lua_isfunction
(L
, $input
) ||
(SWIG_isptrtype
(L
, $input
) && !SWIG_ConvertPtr(L, $input, (void **) &ptr, $descriptor(NS::CLASS *), 0))) {
368 %typemap
(in
, noblock
=1) NS
::CLASS
* PARAM {
369 if
(lua_isfunction
(L
, $input
)) {
370 auto functor
= new lua##CLASS
(L
);
374 if
(!SWIG_IsOK
(SWIG_ConvertPtr
(L
, $input
, (void
**)&$1, $descriptor(NS::CLASS *), 0))) {
382 // Functor classes where Xapian takes ownership of the passed object.
383 #define SUB_CLASS_TYPEMAPS_DISOWNED
(NS
, CLASS
) SUB_CLASS_TYPEMAPS_
(NS
, CLASS
, , )
384 SUB_CLASS_TYPEMAPS_DISOWNED
(Xapian
, StemImplementation
)
386 // Functor classes which don't need to live on after the wrapped C
++ method returns.
387 #define SUB_CLASS_TYPEMAPS_EMPHEMERAL
(NS
, CLASS
) SUB_CLASS_TYPEMAPS_
(NS
, CLASS
, (std
::unique_ptr
<lua##CLASS
> cleanup
), cleanup.reset
(functor
);)
388 SUB_CLASS_TYPEMAPS_EMPHEMERAL
(Xapian
, MatchDecider
)
389 SUB_CLASS_TYPEMAPS_EMPHEMERAL
(Xapian
, ExpandDecider
)
391 // Functor classes which use Xapian's optional reference counting.
392 #define SUB_CLASS_TYPEMAPS_PERSISTENT
(NS
, CLASS
) SUB_CLASS_TYPEMAPS_
(NS
, CLASS
, , functor-
>release
();)
393 SUB_CLASS_TYPEMAPS_PERSISTENT
(Xapian
, Stopper
)
394 SUB_CLASS_TYPEMAPS_PERSISTENT
(Xapian
, KeyMaker
)
395 SUB_CLASS_TYPEMAPS_PERSISTENT
(Xapian
, RangeProcessor
)
396 SUB_CLASS_TYPEMAPS_PERSISTENT
(Xapian
, FieldProcessor
)
397 SUB_CLASS_TYPEMAPS_PERSISTENT
(Xapian
, MatchSpy
)
400 function xapian.Iterator
(begin
, _end
)
404 if iter
:equals
(_end
) then
412 if iter
:equals
(_end
) then
422 #define XAPIAN_MIXED_SUBQUERIES_BY_ITERATOR_TYPEMAP
424 %typemap
(typecheck
, precedence
=500) (XapianSWIGQueryItor qbegin
, XapianSWIGQueryItor qend
) {
425 $
1 = lua_istable
(L
, $input
);
426 /* FIXME
: if we add more array typemaps
, we'll need to check the elements
427 * of the array here to disambiguate.
*/
431 class XapianSWIGQueryItor
{
437 typedef std
::random_access_iterator_tag iterator_category
;
438 typedef Xapian
::Query value_type
;
439 typedef Xapian
::termcount_diff difference_type
;
440 typedef Xapian
::Query
* pointer
;
441 typedef Xapian
::Query
& reference;
443 XapianSWIGQueryItor
() { }
445 void begin
(lua_State
* S
, int index_
) {
451 void end
(lua_State
* S
, int index_
, int n
) {
461 XapianSWIGQueryItor
& operator++() {
466 Xapian
::Query operator
*() const
{
467 lua_rawgeti
(L
, index
, i
+1);
468 if
(lua_isstring
(L
, -1)) {
470 const char
*p
= lua_tolstring
(L
, -1, &len);
472 return Xapian
::Query
(string
(p
, len
));
475 Xapian
::Query
*subq
= 0;
476 if
(!lua_isuserdata
(L
, -1) ||
477 SWIG_ConvertPtr
(L
, -1, (void
**)&subq,
478 SWIGTYPE_p_Xapian__Query
, 0) == -1) {
480 luaL_argerror
(L
, index
,
481 "elements must be Query objects or strings");
488 bool operator
==(const XapianSWIGQueryItor
& o) {
492 bool operator
!=(const XapianSWIGQueryItor
& o) {
493 return
!(*this
== o
);
496 difference_type operator-
(const XapianSWIGQueryItor
&o) const {
503 %typemap
(in
) (XapianSWIGQueryItor qbegin
, XapianSWIGQueryItor qend
) {
504 if
(lua_istable
(L
, $input
)) {
506 $
2.end
(L
, $input
, lua_rawlen
(L
, $input
));
513 %define OUTPUT_ITERATOR_METHODS
(NS
, CLASS
, ITERATOR_CLASS
, ITERATOR_BEGIN
, ITERATOR_END
, DEREF_METHOD
, PARAMETER_NAME
, PARAMETER_VALUE
)
516 std
::pair
<NS
::ITERATOR_CLASS
, NS
::ITERATOR_CLASS
> DEREF_METHOD
(PARAMETER_NAME
) {
517 return std
::make_pair
($self-
>ITERATOR_BEGIN
(PARAMETER_VALUE
), $self-
>ITERATOR_END
(PARAMETER_VALUE
));
521 %typemap
(out
) std
::pair
<NS
::ITERATOR_CLASS
, NS
::ITERATOR_CLASS
> {
522 lua_getglobal
(L
, "xapian");
523 lua_pushstring
(L
, "Iterator");
527 if
(!lua_isfunction
(L
, -1)) {
528 luaL_typerror
(L
, -1, "function");
531 NS
::ITERATOR_CLASS
* begin
= new NS
::ITERATOR_CLASS
((const NS
::ITERATOR_CLASS
&)$1.first);
532 SWIG_NewPointerObj
(L
, (void
*) begin
, $descriptor
(NS
::ITERATOR_CLASS
*), 1);
534 NS
::ITERATOR_CLASS
* end
= new NS
::ITERATOR_CLASS
((const NS
::ITERATOR_CLASS
&)$1.second);
535 SWIG_NewPointerObj
(L
, (void
*) end
, $descriptor
(NS
::ITERATOR_CLASS
*), 1);
537 if
(lua_pcall
(L
, 2, 1, 0) != 0) {
538 luaL_error
(L
, "error running function: %s", lua_tostring
(L
, -1));
546 OUTPUT_ITERATOR_METHODS
(Xapian
, Query
, TermIterator
, get_terms_begin
, get_terms_end
, get_terms
, void
, )
548 OUTPUT_ITERATOR_METHODS
(Xapian
, QueryParser
, TermIterator
, stoplist_begin
, stoplist_end
, stoplist
, void
, )
550 OUTPUT_ITERATOR_METHODS
(Xapian
, ESet
, ESetIterator
, begin
, end
, terms
, void
, )
552 OUTPUT_ITERATOR_METHODS
(Xapian
, MSet
, MSetIterator
, begin
, end
, items
, void
, )
554 OUTPUT_ITERATOR_METHODS
(Xapian
, Document
, TermIterator
, termlist_begin
, termlist_end
, termlist
, void
, )
555 OUTPUT_ITERATOR_METHODS
(Xapian
, Document
, ValueIterator
, values_begin
, values_end
, values
, void
, )
557 OUTPUT_ITERATOR_METHODS
(Xapian
, Enquire
, TermIterator
, get_matching_terms_begin
, get_matching_terms_end
, get_matching_terms
, Xapian
::docid did
, did
)
558 OUTPUT_ITERATOR_METHODS
(Xapian
, Enquire
, TermIterator
, get_matching_terms_begin
, get_matching_terms_end
, get_matching_terms
, const MSetIterator
&it, it)
560 OUTPUT_ITERATOR_METHODS
(Xapian
, ValueCountMatchSpy
, TermIterator
, values_begin
, values_end
, values
, void
, )
561 OUTPUT_ITERATOR_METHODS
(Xapian
, ValueCountMatchSpy
, TermIterator
, top_values_begin
, top_values_end
, top_values
, size_t maxvalues
, maxvalues
)
563 OUTPUT_ITERATOR_METHODS
(Xapian
, Database
, TermIterator
, allterms_begin
, allterms_end
, allterms
, void
, )
564 OUTPUT_ITERATOR_METHODS
(Xapian
, Database
, TermIterator
, spellings_begin
, spellings_end
, spellings
, void
, )
565 OUTPUT_ITERATOR_METHODS
(Xapian
, Database
, PostingIterator
, postlist_begin
, postlist_end
, postlist
, const std
::string
&tname, tname)
566 OUTPUT_ITERATOR_METHODS
(Xapian
, Database
, TermIterator
, termlist_begin
, termlist_end
, termlist
, Xapian
::docid did
, did
)
567 OUTPUT_ITERATOR_METHODS
(Xapian
, Database
, ValueIterator
, valuestream_begin
, valuestream_end
, valuestream
, Xapian
::valueno slot
, slot
)
568 OUTPUT_ITERATOR_METHODS
(Xapian
, Database
, TermIterator
, allterms_begin
, allterms_end
, allterms
, const std
::string
&prefix, prefix)
569 OUTPUT_ITERATOR_METHODS
(Xapian
, Database
, TermIterator
, synonyms_begin
, synonyms_end
, synonyms
, const std
::string
&term, term)
570 OUTPUT_ITERATOR_METHODS
(Xapian
, Database
, TermIterator
, synonym_keys_begin
, synonym_keys_end
, synonym_keys
, const std
::string
&prefix, prefix)
571 OUTPUT_ITERATOR_METHODS
(Xapian
, Database
, TermIterator
, metadata_keys_begin
, metadata_keys_end
, metadata_keys
, const std
::string
&prefix, prefix)
573 %extend Xapian
::Database
{
574 std
::pair
<Xapian
::PositionIterator
, Xapian
::PositionIterator
> positionlist
(Xapian
::docid did
, const std
::string
&tname) {
575 return std
::make_pair
($self-
>positionlist_begin
(did
, tname
), $self-
>positionlist_end
(did
, tname
));
579 %typemap
(out
) std
::pair
<Xapian
::PositionIterator
, Xapian
::PositionIterator
> {
580 lua_getglobal
(L
, "xapian");
581 lua_pushstring
(L
, "Iterator");
585 if
(!lua_isfunction
(L
, -1)) {
586 luaL_typerror
(L
, -1, "function");
589 Xapian
::PositionIterator
* begin
= new Xapian
::PositionIterator
((const Xapian
::PositionIterator
&)$1.first);
590 SWIG_NewPointerObj
(L
, (void
*) begin
, SWIGTYPE_p_Xapian__PositionIterator
, 1);
592 Xapian
::PositionIterator
* end
= new Xapian
::PositionIterator
((const Xapian
::PositionIterator
&)$1.second);
593 SWIG_NewPointerObj
(L
, (void
*) end
, SWIGTYPE_p_Xapian__PositionIterator
, 1);
595 if
(lua_pcall
(L
, 2, 1, 0) != 0) {
596 luaL_error
(L
, "error running function: %s", lua_tostring
(L
, -1));