1 /* $Header: //info.ravenbrook.com/project/jili/version/1.1/code/mnj/lua/BaseLib.java#1 $
2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject
11 * to the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 import java
.io
.PrintStream
;
28 import java
.io
.Reader
;
29 import java
.util
.Enumeration
;
32 * Contains Lua's base library. The base library is generally
33 * considered essential for running any Lua program. The base library
34 * can be opened using the {@link #open} method.
36 public final class BaseLib
extends LuaJavaCallback
38 // :todo: consider making the enums contiguous so that the compiler
39 // uses the compact and faster form of switch.
41 // Each function in the base library corresponds to an instance of
42 // this class which is associated (the 'which' member) with an integer
43 // which is unique within this class. They are taken from the following
45 private static final int ASSERT
= 1;
46 private static final int COLLECTGARBAGE
= 2;
47 private static final int DOFILE
= 3;
48 private static final int ERROR
= 4;
49 // private static final int GCINFO = 5;
50 private static final int GETFENV
= 6;
51 private static final int GETMETATABLE
= 7;
52 private static final int LOADFILE
= 8;
53 private static final int LOAD
= 9;
54 private static final int LOADSTRING
= 10;
55 private static final int NEXT
= 11;
56 private static final int PCALL
= 12;
57 private static final int PRINT
= 13;
58 private static final int RAWEQUAL
= 14;
59 private static final int RAWGET
= 15;
60 private static final int RAWSET
= 16;
61 private static final int SELECT
= 17;
62 private static final int SETFENV
= 18;
63 private static final int SETMETATABLE
= 19;
64 private static final int TONUMBER
= 20;
65 private static final int TOSTRING
= 21;
66 private static final int TYPE
= 22;
67 private static final int UNPACK
= 23;
68 private static final int XPCALL
= 24;
70 private static final int IPAIRS
= 25;
71 private static final int PAIRS
= 26;
72 private static final int IPAIRS_AUX
= 27;
73 private static final int PAIRS_AUX
= 28;
75 // The coroutine functions (which reside in the table "coroutine") are also
76 // part of the base library.
77 private static final int CREATE
= 50;
78 private static final int RESUME
= 51;
79 private static final int RUNNING
= 52;
80 private static final int STATUS
= 53;
81 private static final int WRAP
= 54;
82 private static final int YIELD
= 55;
84 private static final int WRAP_AUX
= 56;
87 * Lua value that represents the generator function for ipairs. In
88 * PUC-Rio this is implemented as an upvalue of ipairs.
90 private static final Object IPAIRS_AUX_FUN
= new BaseLib(IPAIRS_AUX
);
92 * Lua value that represents the generator function for pairs. In
93 * PUC-Rio this is implemented as an upvalue of pairs.
95 private static final Object PAIRS_AUX_FUN
= new BaseLib(PAIRS_AUX
);
98 * Which library function this object represents. This value should
99 * be one of the "enums" defined in the class.
104 * For wrapped threads created by coroutine.wrap, this references the
109 /** Constructs instance, filling in the 'which' member. */
110 private BaseLib(int which
)
115 /** Instance constructor used by coroutine.wrap. */
116 private BaseLib(Lua L
)
123 * Implements all of the functions in the Lua base library. Do not
125 * @param L the Lua state in which to execute.
126 * @return number of returned parameters, as per convention.
128 public int luaFunction(Lua L
)
133 return assertFunction(L
);
135 return collectgarbage(L
);
143 return getmetatable(L
);
151 return loadstring(L
);
171 return setmetatable(L
);
206 * Opens the base library into the given Lua state. This registers
207 * the symbols of the base library in the global table.
208 * @param L The Lua state into which to open.
210 public static void open(Lua L
)
213 L
.setGlobal("_G", L
.getGlobals());
214 // set global _VERSION
215 L
.setGlobal("_VERSION", Lua
.VERSION
);
216 r(L
, "assert", ASSERT
);
217 r(L
, "collectgarbage", COLLECTGARBAGE
);
218 r(L
, "dofile", DOFILE
);
219 r(L
, "error", ERROR
);
220 r(L
, "getfenv", GETFENV
);
221 r(L
, "getmetatable", GETMETATABLE
);
222 r(L
, "ipairs", IPAIRS
);
223 r(L
, "loadfile", LOADFILE
);
225 r(L
, "loadstring", LOADSTRING
);
227 r(L
, "pairs", PAIRS
);
228 r(L
, "pcall", PCALL
);
229 r(L
, "print", PRINT
);
230 r(L
, "rawequal", RAWEQUAL
);
231 r(L
, "rawget", RAWGET
);
232 r(L
, "rawset", RAWSET
);
233 r(L
, "select", SELECT
);
234 r(L
, "setfenv", SETFENV
);
235 r(L
, "setmetatable", SETMETATABLE
);
236 r(L
, "tonumber", TONUMBER
);
237 r(L
, "tostring", TOSTRING
);
239 r(L
, "unpack", UNPACK
);
240 r(L
, "xpcall", XPCALL
);
242 L
.register("coroutine");
244 c(L
, "create", CREATE
);
245 c(L
, "resume", RESUME
);
246 c(L
, "running", RUNNING
);
247 c(L
, "status", STATUS
);
249 c(L
, "yield", YIELD
);
252 /** Register a function. */
253 private static void r(Lua L
, String name
, int which
)
255 BaseLib f
= new BaseLib(which
);
256 L
.setGlobal(name
, f
);
259 /** Register a function in the coroutine table. */
260 private static void c(Lua L
, String name
, int which
)
262 BaseLib f
= new BaseLib(which
);
263 L
.setField(L
.getGlobal("coroutine"), name
, f
);
266 /** Implements assert. <code>assert</code> is a keyword in some
267 * versions of Java, so this function has a mangled name.
269 private static int assertFunction(Lua L
)
272 if (!L
.toBoolean(L
.value(1)))
274 L
.error(L
.optString(2, "assertion failed!"));
279 /** Used by {@link #collectgarbage}. */
280 private static final String
[] CGOPTS
= new String
[]
282 "stop", "restart", "collect",
283 "count", "step", "setpause", "setstepmul"};
284 /** Used by {@link #collectgarbage}. */
285 private static final int[] CGOPTSNUM
= new int[]
287 Lua
.GCSTOP
, Lua
.GCRESTART
, Lua
.GCCOLLECT
,
288 Lua
.GCCOUNT
, Lua
.GCSTEP
, Lua
.GCSETPAUSE
, Lua
.GCSETSTEPMUL
};
289 /** Implements collectgarbage. */
290 private static int collectgarbage(Lua L
)
292 int o
= L
.checkOption(1, "collect", CGOPTS
);
293 int ex
= L
.optInt(2, 0);
294 int res
= L
.gc(CGOPTSNUM
[o
], ex
);
295 switch (CGOPTSNUM
[o
])
299 int b
= L
.gc(Lua
.GCCOUNTB
, 0);
300 L
.pushNumber(res
+ ((double)b
)/1024);
304 L
.pushBoolean(res
!= 0);
312 /** Implements dofile. */
313 private static int dofile(Lua L
)
315 String fname
= L
.optString(1, null);
317 if (L
.loadFile(fname
) != 0)
319 L
.error(L
.value(-1));
321 L
.call(0, Lua
.MULTRET
);
322 return L
.getTop() - n
;
325 /** Implements error. */
326 private static int error(Lua L
)
328 int level
= L
.optInt(2, 1);
330 if (L
.isString(L
.value(1)) && level
> 0)
332 L
.insert(L
.where(level
), 1);
340 /** Helper for getfenv and setfenv. */
341 private static Object
getfunc(Lua L
)
343 Object o
= L
.value(1);
350 int level
= L
.optInt(1, 1);
351 L
.argCheck(level
>= 0, 1, "level must be non-negative");
352 Debug ar
= L
.getStack(level
);
355 L
.argError(1, "invalid level");
361 L
.error("no function environment for tail call at level " + level
);
368 /** Implements getfenv. */
369 private static int getfenv(Lua L
)
371 Object o
= getfunc(L
);
372 if (L
.isJavaFunction(o
))
374 L
.push(L
.getGlobals());
378 LuaFunction f
= (LuaFunction
)o
;
384 /** Implements getmetatable. */
385 private static int getmetatable(Lua L
)
388 Object mt
= L
.getMetatable(L
.value(1));
394 Object protectedmt
= L
.getMetafield(L
.value(1), "__metatable");
395 if (L
.isNil(protectedmt
))
397 L
.push(mt
); // return metatable
401 L
.push(protectedmt
); // return __metatable field
406 /** Implements load. */
407 private static int load(Lua L
)
409 String cname
= L
.optString(2, "=(load)");
410 L
.checkType(1, Lua
.TFUNCTION
);
411 Reader r
= new BaseLibReader(L
, L
.value(1));
414 status
= L
.load(r
, cname
);
415 return load_aux(L
, status
);
418 /** Implements loadfile. */
419 private static int loadfile(Lua L
)
421 String fname
= L
.optString(1, null);
422 return load_aux(L
, L
.loadFile(fname
));
425 /** Implements loadstring. */
426 private static int loadstring(Lua L
)
428 String s
= L
.checkString(1);
429 String chunkname
= L
.optString(2, s
);
430 if (s
.startsWith("\033"))
432 // "binary" dumped into string using string.dump.
433 return load_aux(L
, L
.load(new DumpedInput(s
), chunkname
));
437 return load_aux(L
, L
.loadString(s
, chunkname
));
441 private static int load_aux(Lua L
, int status
)
443 if (status
== 0) // OK?
449 L
.insert(L
.NIL
, -1); // put before error message
450 return 2; // return nil plus error message
454 /** Implements next. */
455 private static int next(Lua L
)
457 L
.checkType(1, Lua
.TTABLE
);
458 L
.setTop(2); // Create a 2nd argument is there isn't one
467 /** Implements ipairs. */
468 private static int ipairs(Lua L
)
470 L
.checkType(1, Lua
.TTABLE
);
471 L
.push(IPAIRS_AUX_FUN
);
477 /** Generator for ipairs. */
478 private static int ipairsaux(Lua L
)
480 int i
= L
.checkInt(2);
481 L
.checkType(1, Lua
.TTABLE
);
483 Object v
= L
.rawGetI(L
.value(1), i
);
493 /** Implements pairs. PUC-Rio uses "next" as the generator for pairs.
494 * Jill doesn't do that because it would be way too slow. We use the
495 * {@link java.util.Enumeration} returned from
496 * {@link java.util.Hashtable#keys}. The {@link #pairsaux} method
497 * implements the step-by-step iteration.
499 private static int pairs(Lua L
)
501 L
.checkType(1, Lua
.TTABLE
);
502 L
.push(PAIRS_AUX_FUN
); // return generator,
503 LuaTable t
= (LuaTable
)L
.value(1);
504 L
.push(new Object
[] { t
, t
.keys() }); // state,
505 L
.push(Lua
.NIL
); // and initial value.
509 /** Generator for pairs. This expects a <var>state</var> and
510 * <var>var</var> as (Lua) arguments.
511 * The state is setup by {@link #pairs} and is a
512 * pair of {LuaTable, Enumeration} stored in a 2-element array. The
513 * <var>var</var> is not used. This is in contrast to the PUC-Rio
514 * implementation, where the state is the table, and the var is used
515 * to generated the next key in sequence. The implementation, of
516 * pairs and pairsaux, has no control over <var>var</var>, Lua's
517 * semantics of <code>for</code> force it to be the previous result
518 * returned by this function. In Jill this value is not suitable to
519 * use for enumeration, which is why it isn't used.
521 private static int pairsaux(Lua L
)
523 Object
[] a
= (Object
[])L
.value(1);
524 LuaTable t
= (LuaTable
)a
[0];
525 Enumeration e
= (Enumeration
)a
[1];
526 if (!e
.hasMoreElements())
530 Object key
= e
.nextElement();
532 L
.push(t
.getlua(key
));
536 /** Implements pcall. */
537 private static int pcall(Lua L
)
540 int status
= L
.pcall(L
.getTop()-1, Lua
.MULTRET
, null);
541 boolean b
= (status
== 0);
542 L
.insert(L
.valueOfBoolean(b
), 1);
547 * The {@link PrintStream} used by print. Makes it more convenient if
548 * redirection is desired. For example, client code could implement
549 * their own instance which sent output to the screen of a JME device.
551 static final PrintStream OUT
= System
.out
;
553 /** Implements print. */
554 private static int print(Lua L
)
557 Object tostring
= L
.getGlobal("tostring");
558 for(int i
=1; i
<=n
; ++i
)
563 String s
= L
.toString(L
.value(-1));
566 return L
.error("'tostring' must return a string to 'print'");
579 /** Implements rawequal. */
580 private static int rawequal(Lua L
)
584 L
.pushBoolean(L
.rawEqual(L
.value(1), L
.value(2)));
588 /** Implements rawget. */
589 private static int rawget(Lua L
)
591 L
.checkType(1, Lua
.TTABLE
);
593 L
.push(L
.rawGet(L
.value(1), L
.value(2)));
597 /** Implements rawset. */
598 private static int rawset(Lua L
)
600 L
.checkType(1, Lua
.TTABLE
);
603 L
.rawSet(L
.value(1), L
.value(2), L
.value(3));
607 /** Implements select. */
608 private static int select(Lua L
)
611 if (L
.type(1) == Lua
.TSTRING
&& "#".equals(L
.toString(L
.value(1))))
616 int i
= L
.checkInt(1);
625 L
.argCheck(1 <= i
, 1, "index out of range");
629 /** Implements setfenv. */
630 private static int setfenv(Lua L
)
632 L
.checkType(2, Lua
.TTABLE
);
633 Object o
= getfunc(L
);
634 Object first
= L
.value(1);
635 if (L
.isNumber(first
) && L
.toNumber(first
) == 0)
637 // :todo: change environment of current thread.
640 else if (L
.isJavaFunction(o
) || !L
.setFenv(o
, L
.value(2)))
642 L
.error("'setfenv' cannot change environment of given object");
648 /** Implements setmetatable. */
649 private static int setmetatable(Lua L
)
651 L
.checkType(1, Lua
.TTABLE
);
653 L
.argCheck(t
== Lua
.TNIL
|| t
== Lua
.TTABLE
, 2,
654 "nil or table expected");
655 if (!L
.isNil(L
.getMetafield(L
.value(1), "__metatable")))
657 L
.error("cannot change a protected metatable");
659 L
.setMetatable(L
.value(1), L
.value(2));
664 /** Implements tonumber. */
665 private static int tonumber(Lua L
)
667 int base
= L
.optInt(2, 10);
668 if (base
== 10) // standard conversion
671 Object o
= L
.value(1);
674 L
.pushNumber(L
.toNumber(o
));
680 String s
= L
.checkString(1);
681 L
.argCheck(2 <= base
&& base
<= 36, 2, "base out of range");
682 // :todo: consider stripping space and sharing some code with
686 int i
= Integer
.parseInt(s
, base
);
690 catch (NumberFormatException e_
)
698 /** Implements tostring. */
699 private static int tostring(Lua L
)
702 Object o
= L
.value(1);
704 if (L
.callMeta(1, "__tostring")) // is there a metafield?
706 return 1; // use its value
711 L
.push(L
.toString(o
));
719 L
.pushLiteral("true");
723 L
.pushLiteral("false");
727 L
.pushLiteral("nil");
730 L
.push(o
.toString());
736 /** Implements type. */
737 private static int type(Lua L
)
740 L
.push(L
.typeNameOfIndex(1));
744 /** Implements unpack. */
745 private static int unpack(Lua L
)
747 L
.checkType(1, Lua
.TTABLE
);
748 LuaTable t
= (LuaTable
)L
.value(1);
749 int i
= L
.optInt(2, 1);
750 int e
= L
.optInt(3, t
.getn());
751 int n
= e
- i
+ 1; // number of elements
754 return 0; // empty range
756 // i already initialised to start index, which isn't necessarily 1
764 /** Implements xpcall. */
765 private static int xpcall(Lua L
)
768 Object errfunc
= L
.value(2);
769 L
.setTop(1); // remove error function from stack
770 int status
= L
.pcall(0, Lua
.MULTRET
, errfunc
);
771 L
.insert(L
.valueOfBoolean(status
== 0), 1);
772 return L
.getTop(); // return status + all results
775 /** Implements coroutine.create. */
776 private static int create(Lua L
)
778 Lua NL
= L
.newThread();
779 Object faso
= L
.value(1);
780 L
.argCheck(L
.isFunction(faso
) && !L
.isJavaFunction(faso
), 1,
781 "Lua function expected");
782 L
.setTop(1); // function is at top
783 L
.xmove(NL
, 1); // move function from L to NL
788 /** Implements coroutine.resume. */
789 private static int resume(Lua L
)
791 Lua co
= L
.toThread(L
.value(1));
792 L
.argCheck(co
!= null, 1, "coroutine expected");
793 int r
= auxresume(L
, co
, L
.getTop() - 1);
796 L
.insert(L
.valueOfBoolean(false), -1);
797 return 2; // return false + error message
799 L
.insert(L
.valueOfBoolean(true), L
.getTop()-(r
-1));
800 return r
+ 1; // return true + 'resume' returns
803 /** Implements coroutine.running. */
804 private static int running(Lua L
)
808 return 0; // main thread is not a coroutine
814 /** Implements coroutine.status. */
815 private static int status(Lua L
)
817 Lua co
= L
.toThread(L
.value(1));
818 L
.argCheck(co
!= null, 1, "coroutine expected");
821 L
.pushLiteral("running");
828 L
.pushLiteral("suspended");
832 Debug ar
= co
.getStack(0);
833 if (ar
!= null) // does it have frames?
835 L
.pushLiteral("normal"); // it is running
837 else if (co
.getTop() == 0)
839 L
.pushLiteral("dead");
843 L
.pushLiteral("suspended"); // initial state
847 default: // some error occured
848 L
.pushLiteral("dead");
854 /** Implements coroutine.wrap. */
855 private static int wrap(Lua L
)
858 L
.push(wrapit(L
.toThread(L
.value(-1))));
862 /** Helper for wrap. Returns a LuaJavaCallback that has access to the
864 * @param L the Lua thread to be wrapped.
866 private static LuaJavaCallback
wrapit(Lua L
)
868 return new BaseLib(L
);
871 /** Helper for wrap. This implements the function returned by wrap. */
872 private int wrapaux(Lua L
)
875 int r
= auxresume(L
, co
, L
.getTop());
878 if (L
.isString(L
.value(-1))) // error object is a string?
880 String w
= L
.where(1);
884 L
.error(L
.value(-1)); // propagate error
889 private static int auxresume(Lua L
, Lua co
, int narg
)
891 // if (!co.checkStack...
892 if (co
.status() == 0 && co
.getTop() == 0)
894 L
.pushLiteral("cannot resume dead coroutine");
895 return -1; // error flag;
898 int status
= co
.resume(narg
);
899 if (status
== 0 || status
== Lua
.YIELD
)
901 int nres
= co
.getTop();
902 // if (!L.checkStack...
903 co
.xmove(L
, nres
); // move yielded values
906 co
.xmove(L
, 1); // move error message
907 return -1; // error flag;
910 /** Implements coroutine.yield. */
911 private static int yield(Lua L
)
913 return L
.yield(L
.getTop());