Don't use popups, use statusbar
[jpcrr.git] / mnj / lua / BaseLib.java
blob9acecd7ff1be150279a9142c303ace9c96de3d77
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).
3 * All rights reserved.
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.
25 package mnj.lua;
27 import java.io.PrintStream;
28 import java.io.Reader;
29 import java.util.Enumeration;
31 /**
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
44 // set.
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;
86 /**
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);
91 /**
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);
97 /**
98 * Which library function this object represents. This value should
99 * be one of the "enums" defined in the class.
101 private int which;
104 * For wrapped threads created by coroutine.wrap, this references the
105 * Lua thread object.
107 private Lua thread;
109 /** Constructs instance, filling in the 'which' member. */
110 private BaseLib(int which)
112 this.which = which;
115 /** Instance constructor used by coroutine.wrap. */
116 private BaseLib(Lua L)
118 this(WRAP_AUX);
119 thread = L;
123 * Implements all of the functions in the Lua base library. Do not
124 * call directly.
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)
130 switch (which)
132 case ASSERT:
133 return assertFunction(L);
134 case COLLECTGARBAGE:
135 return collectgarbage(L);
136 case DOFILE:
137 return dofile(L);
138 case ERROR:
139 return error(L);
140 case GETFENV:
141 return getfenv(L);
142 case GETMETATABLE:
143 return getmetatable(L);
144 case IPAIRS:
145 return ipairs(L);
146 case LOAD:
147 return load(L);
148 case LOADFILE:
149 return loadfile(L);
150 case LOADSTRING:
151 return loadstring(L);
152 case NEXT:
153 return next(L);
154 case PAIRS:
155 return pairs(L);
156 case PCALL:
157 return pcall(L);
158 case PRINT:
159 return print(L);
160 case RAWEQUAL:
161 return rawequal(L);
162 case RAWGET:
163 return rawget(L);
164 case RAWSET:
165 return rawset(L);
166 case SELECT:
167 return select(L);
168 case SETFENV:
169 return setfenv(L);
170 case SETMETATABLE:
171 return setmetatable(L);
172 case TONUMBER:
173 return tonumber(L);
174 case TOSTRING:
175 return tostring(L);
176 case TYPE:
177 return type(L);
178 case UNPACK:
179 return unpack(L);
180 case XPCALL:
181 return xpcall(L);
182 case IPAIRS_AUX:
183 return ipairsaux(L);
184 case PAIRS_AUX:
185 return pairsaux(L);
187 case CREATE:
188 return create(L);
189 case RESUME:
190 return resume(L);
191 case RUNNING:
192 return running(L);
193 case STATUS:
194 return status(L);
195 case WRAP:
196 return wrap(L);
197 case YIELD:
198 return yield(L);
199 case WRAP_AUX:
200 return wrapaux(L);
202 return 0;
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)
212 // set global _G
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);
224 r(L, "load", LOAD);
225 r(L, "loadstring", LOADSTRING);
226 r(L, "next", NEXT);
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);
238 r(L, "type", TYPE);
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);
248 c(L, "wrap", WRAP);
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)
271 L.checkAny(1);
272 if (!L.toBoolean(L.value(1)))
274 L.error(L.optString(2, "assertion failed!"));
276 return L.getTop();
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])
297 case Lua.GCCOUNT:
299 int b = L.gc(Lua.GCCOUNTB, 0);
300 L.pushNumber(res + ((double)b)/1024);
301 return 1;
303 case Lua.GCSTEP:
304 L.pushBoolean(res != 0);
305 return 1;
306 default:
307 L.pushNumber(res);
308 return 1;
312 /** Implements dofile. */
313 private static int dofile(Lua L)
315 String fname = L.optString(1, null);
316 int n = L.getTop();
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);
329 L.setTop(1);
330 if (Lua.isString(L.value(1)) && level > 0)
332 L.insert(L.where(level), 1);
333 L.concat(2);
335 L.error(L.value(1));
336 // NOTREACHED
337 return 0;
340 /** Helper for getfenv and setfenv. */
341 private static Object getfunc(Lua L)
343 Object o = L.value(1);
344 if (Lua.isFunction(o))
346 return o;
348 else
350 int level = L.optInt(1, 1);
351 L.argCheck(level >= 0, 1, "level must be non-negative");
352 Debug ar = L.getStack(level);
353 if (ar == null)
355 L.argRaiseError(1, "invalid level");
357 L.getInfo("f", ar);
358 o = L.value(-1);
359 if (Lua.isNil(o))
361 L.error("no function environment for tail call at level " + level);
363 L.pop(1);
364 return o;
368 /** Implements getfenv. */
369 private static int getfenv(Lua L)
371 Object o = getfunc(L);
372 if (Lua.isJavaFunction(o))
374 L.push(L.getGlobals());
376 else
378 LuaFunction f = (LuaFunction)o;
379 L.push(f.getEnv());
381 return 1;
384 /** Implements getmetatable. */
385 private static int getmetatable(Lua L)
387 L.checkAny(1);
388 Object mt = L.getMetatable(L.value(1));
389 if (mt == null)
391 L.pushNil();
392 return 1;
394 Object protectedmt = L.getMetafield(L.value(1), "__metatable");
395 if (Lua.isNil(protectedmt))
397 L.push(mt); // return metatable
399 else
401 L.push(protectedmt); // return __metatable field
403 return 1;
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));
412 int status;
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));
435 else
437 return load_aux(L, L.loadString(s, chunkname));
441 private static int load_aux(Lua L, int status)
443 if (status == 0) // OK?
445 return 1;
447 else
449 L.insert(Lua.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
459 if (L.next(1))
461 return 2;
463 L.push(Lua.NIL);
464 return 1;
467 /** Implements ipairs. */
468 private static int ipairs(Lua L)
470 L.checkType(1, Lua.TTABLE);
471 L.push(IPAIRS_AUX_FUN);
472 L.pushValue(1);
473 L.pushNumber(0);
474 return 3;
477 /** Generator for ipairs. */
478 private static int ipairsaux(Lua L)
480 int i = L.checkInt(2);
481 L.checkType(1, Lua.TTABLE);
482 ++i;
483 Object v = Lua.rawGetI(L.value(1), i);
484 if (Lua.isNil(v))
486 return 0;
488 L.pushNumber(i);
489 L.push(v);
490 return 2;
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.
506 return 3;
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())
528 return 0;
530 Object key = e.nextElement();
531 L.push(key);
532 L.push(t.getlua(key));
533 return 2;
536 /** Implements pcall. */
537 private static int pcall(Lua L)
539 L.checkAny(1);
540 int status = L.pcall(L.getTop()-1, Lua.MULTRET, null);
541 boolean b = (status == 0);
542 L.insert(Lua.valueOfBoolean(b), 1);
543 return L.getTop();
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)
556 int n = L.getTop();
557 Object tostring = L.getGlobal("tostring");
558 for(int i=1; i<=n; ++i)
560 L.push(tostring);
561 L.pushValue(i);
562 L.call(1, 1);
563 String s = L.toString(L.value(-1));
564 if (s == null)
566 return L.error("'tostring' must return a string to 'print'");
568 if (i>1)
570 OUT.print('\t');
572 OUT.print(s);
573 L.pop(1);
575 OUT.println();
576 return 0;
579 /** Implements rawequal. */
580 private static int rawequal(Lua L)
582 L.checkAny(1);
583 L.checkAny(2);
584 L.pushBoolean(Lua.rawEqual(L.value(1), L.value(2)));
585 return 1;
588 /** Implements rawget. */
589 private static int rawget(Lua L)
591 L.checkType(1, Lua.TTABLE);
592 L.checkAny(2);
593 L.push(Lua.rawGet(L.value(1), L.value(2)));
594 return 1;
597 /** Implements rawset. */
598 private static int rawset(Lua L)
600 L.checkType(1, Lua.TTABLE);
601 L.checkAny(2);
602 L.checkAny(3);
603 L.rawSet(L.value(1), L.value(2), L.value(3));
604 return 0;
607 /** Implements select. */
608 private static int select(Lua L)
610 int n = L.getTop();
611 if (L.type(1) == Lua.TSTRING && "#".equals(L.toString(L.value(1))))
613 L.pushNumber(n-1);
614 return 1;
616 int i = L.checkInt(1);
617 if (i < 0)
619 i = n + i;
621 else if (i > n)
623 i = n;
625 L.argCheck(1 <= i, 1, "index out of range");
626 return n-i;
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 (Lua.isNumber(first) && L.toNumber(first) == 0)
637 // :todo: change environment of current thread.
638 return 0;
640 else if (Lua.isJavaFunction(o) || !L.setFenv(o, L.value(2)))
642 L.error("'setfenv' cannot change environment of given object");
644 L.push(o);
645 return 1;
648 /** Implements setmetatable. */
649 private static int setmetatable(Lua L)
651 L.checkType(1, Lua.TTABLE);
652 int t = L.type(2);
653 L.argCheck(t == Lua.TNIL || t == Lua.TTABLE, 2,
654 "nil or table expected");
655 if (!Lua.isNil(L.getMetafield(L.value(1), "__metatable")))
657 L.error("cannot change a protected metatable");
659 L.setMetatable(L.value(1), L.value(2));
660 L.setTop(1);
661 return 1;
664 /** Implements tonumber. */
665 private static int tonumber(Lua L)
667 int base = L.optInt(2, 10);
668 if (base == 10) // standard conversion
670 L.checkAny(1);
671 Object o = L.value(1);
672 if (Lua.isNumber(o))
674 L.pushNumber(L.toNumber(o));
675 return 1;
678 else
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
683 // Lua.vmTostring
686 int i = Integer.parseInt(s, base);
687 L.pushNumber(i);
688 return 1;
690 catch (NumberFormatException e_)
694 L.push(Lua.NIL);
695 return 1;
698 /** Implements tostring. */
699 private static int tostring(Lua L)
701 L.checkAny(1);
702 Object o = L.value(1);
704 if (L.callMeta(1, "__tostring")) // is there a metafield?
706 return 1; // use its value
708 switch (L.type(1))
710 case Lua.TNUMBER:
711 L.push(L.toString(o));
712 break;
713 case Lua.TSTRING:
714 L.push(o);
715 break;
716 case Lua.TBOOLEAN:
717 if (L.toBoolean(o))
719 L.pushLiteral("true");
721 else
723 L.pushLiteral("false");
725 break;
726 case Lua.TNIL:
727 L.pushLiteral("nil");
728 break;
729 default:
730 L.push(o.toString());
731 break;
733 return 1;
736 /** Implements type. */
737 private static int type(Lua L)
739 L.checkAny(1);
740 L.push(L.typeNameOfIndex(1));
741 return 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
752 if (n <= 0)
754 return 0; // empty range
756 // i already initialised to start index, which isn't necessarily 1
757 for (; i<=e; ++i)
759 L.push(t.getnum(i));
761 return n;
764 /** Implements xpcall. */
765 private static int xpcall(Lua L)
767 L.checkAny(2);
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(Lua.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(Lua.isFunction(faso) && !Lua.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
784 L.push(NL);
785 return 1;
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);
794 if (r < 0)
796 L.insert(Lua.valueOfBoolean(false), -1);
797 return 2; // return false + error message
799 L.insert(Lua.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)
806 if (L.isMain())
808 return 0; // main thread is not a coroutine
810 L.push(L);
811 return 1;
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");
819 if (L == co)
821 L.pushLiteral("running");
823 else
825 switch (co.status())
827 case Lua.YIELD:
828 L.pushLiteral("suspended");
829 break;
830 case 0:
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");
841 else
843 L.pushLiteral("suspended"); // initial state
846 break;
847 default: // some error occured
848 L.pushLiteral("dead");
851 return 1;
854 /** Implements coroutine.wrap. */
855 private static int wrap(Lua L)
857 create(L);
858 L.push(wrapit(L.toThread(L.value(-1))));
859 return 1;
862 /** Helper for wrap. Returns a LuaJavaCallback that has access to the
863 * Lua thread.
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)
874 Lua co = thread;
875 int r = auxresume(L, co, L.getTop());
876 if (r < 0)
878 if (Lua.isString(L.value(-1))) // error object is a string?
880 String w = L.where(1);
881 L.insert(w, -1);
882 L.concat(2);
884 L.error(L.value(-1)); // propagate error
886 return r;
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;
897 L.xmove(co, narg);
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
904 return nres;
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());