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