Compare commits
144 Commits
v3.0.1
...
yut23/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42364df8be | ||
|
|
8a05f69f50 | ||
|
|
daf3da94e3 | ||
|
|
30e60a883e | ||
|
|
27edcc9a92 | ||
|
|
d6737c0bb3 | ||
|
|
d201bc3012 | ||
|
|
ca64666242 | ||
|
|
725cf89b6f | ||
|
|
da0b06555a | ||
|
|
ee2d5284e7 | ||
|
|
0f0ec4bf7b | ||
|
|
5813d56f89 | ||
|
|
8c42c4712b | ||
|
|
6bc8fd6b1b | ||
|
|
bf663878cb | ||
|
|
e120008f9b | ||
|
|
9a20aa8077 | ||
|
|
99f21b6277 | ||
|
|
53bd4bf71f | ||
|
|
b57eb247ba | ||
|
|
05e82f1c3f | ||
|
|
9b2f0a2805 | ||
|
|
ef8175050b | ||
|
|
0d2aa6cc54 | ||
|
|
fe7bd07450 | ||
|
|
f0e9348ae2 | ||
|
|
22e7a8c620 | ||
|
|
c8461b8128 | ||
|
|
3a6c382570 | ||
|
|
4db34780b7 | ||
|
|
ac3475deee | ||
|
|
af35c4d89e | ||
|
|
c71f277697 | ||
|
|
5fe0a3950d | ||
|
|
169202362e | ||
|
|
5609d8c92b | ||
|
|
dbab0aed01 | ||
|
|
f8d7731b56 | ||
|
|
2f5aa594bd | ||
|
|
edfe1a5fde | ||
|
|
6efb6f000e | ||
|
|
f3b8a1eddc | ||
|
|
20eca5760d | ||
|
|
3613bc0862 | ||
|
|
6985980572 | ||
|
|
60d130cecc | ||
|
|
b705eb05f4 | ||
|
|
d0bb0409a3 | ||
|
|
db58e1808b | ||
|
|
e2ede7f91c | ||
|
|
a50deaa75c | ||
|
|
f9f78b81da | ||
|
|
984fa30bf6 | ||
|
|
65beda4c2b | ||
|
|
934a8fc57b | ||
|
|
832ec739ea | ||
|
|
8345bee6b4 | ||
|
|
83f2e1d96a | ||
|
|
14745ba76a | ||
|
|
c62ba1f22e | ||
|
|
868928779f | ||
|
|
f383c27728 | ||
|
|
e7b11110a3 | ||
|
|
0fa27c3783 | ||
|
|
72a71e5a65 | ||
|
|
6031d6b479 | ||
|
|
c1834733c1 | ||
|
|
10f88d2c31 | ||
|
|
6d2deb4cb6 | ||
|
|
5f52729fc9 | ||
|
|
e6736857b6 | ||
|
|
5c5176727a | ||
|
|
7721380e20 | ||
|
|
16aa199d40 | ||
|
|
177fe4e09f | ||
|
|
a7c8a408ce | ||
|
|
84b0dd171e | ||
|
|
898208365d | ||
|
|
ffb686556f | ||
|
|
6694c375c9 | ||
|
|
e70eb5edc2 | ||
|
|
9688d3c5fc | ||
|
|
6f5af581e8 | ||
|
|
870aee2cae | ||
|
|
c2ec9edf39 | ||
|
|
cfb3aaca61 | ||
|
|
4105cebf1e | ||
|
|
339f004eb7 | ||
|
|
05a604645d | ||
|
|
63ead7aac7 | ||
|
|
c9ba2d4bb1 | ||
|
|
92cee0812d | ||
|
|
e61e5694fa | ||
|
|
47f8d6e6fc | ||
|
|
14ac4bb7f9 | ||
|
|
b8aaaafb68 | ||
|
|
88a557033b | ||
|
|
24a8559ceb | ||
|
|
028e03e4bc | ||
|
|
5c1f7d2ab2 | ||
|
|
9db1254160 | ||
|
|
f899c709ff | ||
|
|
9c9e193cc4 | ||
|
|
e9db487d97 | ||
|
|
c6fe5d3ed3 | ||
|
|
52ab872d08 | ||
|
|
5d3041c6be | ||
|
|
8d544729a8 | ||
|
|
bd57dddef0 | ||
|
|
d509e21cc6 | ||
|
|
5b67841232 | ||
|
|
bd4dac18ff | ||
|
|
e02a82ef8d | ||
|
|
70a5086097 | ||
|
|
ad20f939b1 | ||
|
|
e7058bcd6a | ||
|
|
00c7e266ba | ||
|
|
e75c5e2fca | ||
|
|
ed46675a25 | ||
|
|
8fbca25dce | ||
|
|
d0ed5b80e5 | ||
|
|
9b77084109 | ||
|
|
4f410fba6e | ||
|
|
f164c1cd28 | ||
|
|
63ca0f94af | ||
|
|
5bd9827af1 | ||
|
|
0a5cccc50f | ||
|
|
12aded74ca | ||
|
|
48dd90f6d7 | ||
|
|
6333d9acf7 | ||
|
|
d61ed707ef | ||
|
|
1e521d8900 | ||
|
|
bf8ef8d1a9 | ||
|
|
69498dbb7c | ||
|
|
4cc5f4270d | ||
|
|
75fa98d13f | ||
|
|
a627a868d5 | ||
|
|
f073919f64 | ||
|
|
27a1dcdd11 | ||
|
|
b459724103 | ||
|
|
3d22990e3c | ||
|
|
194b776317 | ||
|
|
828e4be019 |
10
.cvsignore → .gitignore
vendored
10
.cvsignore → .gitignore
vendored
@@ -1,8 +1,8 @@
|
||||
bin
|
||||
target
|
||||
build
|
||||
lib
|
||||
jit
|
||||
bin/
|
||||
target/
|
||||
build/
|
||||
lib/
|
||||
jit/
|
||||
*.ser
|
||||
*.gz
|
||||
*.jar
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2007 LuaJ. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,27 +1,24 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
# This is a fork!
|
||||
<div style="border: 1px dotted red; margin: 1.em 0.5em; font-weight: bold; color: red;">
|
||||
This repository has been forked from the original CVS sources of Luaj.
|
||||
The commit history has been converted to make sure that the original work of
|
||||
James Roseborough and Ian Farmer is not lost.
|
||||
Unfortunately, I was not able to contact either James or Ian to hand over
|
||||
ownership of the Github organization/repo as I have originally intended to.
|
||||
The community however seems interested enough to continue work on the original
|
||||
sources and therefore I have decided to make sure that any useful pull requests
|
||||
that may add some value to the original code base shall be merged in from now
|
||||
on.<br>
|
||||
-- Benjamin P. Jung, Jan. 26th 2018
|
||||
</div>
|
||||
|
||||
<head>
|
||||
<title>Getting Started with LuaJ</title>
|
||||
<link rel="stylesheet" type="text/css" href="http://www.lua.org/lua.css">
|
||||
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<hr>
|
||||
<h1>
|
||||
<a href="README.html"><img src="http://sourceforge.net/dbimage.php?id=196139" alt="" border="0"></a>
|
||||
|
||||
Getting Started with LuaJ
|
||||
|
||||
</h1>
|
||||
James Roseborough, Ian Farmer, Version 3.0.1
|
||||
<h1>Getting Started with LuaJ</h1>
|
||||
James Roseborough, Ian Farmer, Version 3.0.2
|
||||
<p>
|
||||
<small>
|
||||
Copyright © 2009-2014 Luaj.org.
|
||||
Freely available under the terms of the
|
||||
<a href="http://sourceforge.net/dbimage.php?id=196142">Luaj license</a>.
|
||||
<a href="LICENSE">Luaj license</a>.
|
||||
</small>
|
||||
<hr>
|
||||
<p>
|
||||
@@ -120,7 +117,7 @@ in comparison with the standard C distribution.
|
||||
<td>16.794</td>
|
||||
<td>11.274</td>
|
||||
<td>Java</td>
|
||||
<td>java -cp luaj-jse-3.0.1.jar;bcel-5.2.jar lua <b>-b</b> fannkuch.lua 10</td></tr>
|
||||
<td>java -cp luaj-jse-3.0.2.jar;bcel-5.2.jar lua <b>-b</b> fannkuch.lua 10</td></tr>
|
||||
<tr valign="top">
|
||||
<td></td>
|
||||
<td></td>
|
||||
@@ -130,7 +127,7 @@ in comparison with the standard C distribution.
|
||||
<td>36.894</td>
|
||||
<td>15.163</td>
|
||||
<td></td>
|
||||
<td>java -cp luaj-jse-3.0.1.jar lua -n fannkuch.lua 10</td></tr>
|
||||
<td>java -cp luaj-jse-3.0.2.jar lua -n fannkuch.lua 10</td></tr>
|
||||
<tr valign="top">
|
||||
<td>lua</td>
|
||||
<td>5.1.4</td>
|
||||
@@ -186,7 +183,7 @@ It is also faster than Java-lua implementations Jill, Kahlua, and Mochalua for a
|
||||
From the main distribution directory line type:
|
||||
|
||||
<pre>
|
||||
java -cp lib/luaj-jse-3.0.1.jar lua examples/lua/hello.lua
|
||||
java -cp luaj-jse-3.0.2.jar lua examples/lua/hello.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -198,7 +195,7 @@ You should see the following output:
|
||||
To see how luaj can be used to acccess most Java API's including swing, try:
|
||||
|
||||
<pre>
|
||||
java -cp lib/luaj-jse-3.0.1.jar lua examples/lua/swingapp.lua
|
||||
java -cp luaj-jse-3.0.2.jar lua examples/lua/swingapp.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -213,8 +210,8 @@ Links to sources:<pre>
|
||||
From the main distribution directory line type:
|
||||
|
||||
<pre>
|
||||
java -cp lib/luaj-jse-3.0.1.jar luac examples/lua/hello.lua
|
||||
java -cp lib/luaj-jse-3.0.1.jar lua luac.out
|
||||
java -cp luaj-jse-3.0.2.jar luac examples/lua/hello.lua
|
||||
java -cp luaj-jse-3.0.2.jar lua luac.out
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -228,8 +225,8 @@ Luaj can compile lua sources or binaries directly to java bytecode if the bcel l
|
||||
|
||||
<pre>
|
||||
ant bcel-lib
|
||||
java -cp "lib/luaj-jse-3.0.1.jar;lib/bcel-5.2.jar" luajc -s examples/lua -d . hello.lua
|
||||
java -cp "lib/luaj-jse-3.0.1.jar;." lua -l hello
|
||||
java -cp "luaj-jse-3.0.2.jar;lib/bcel-5.2.jar" luajc -s examples/lua -d . hello.lua
|
||||
java -cp "luaj-jse-3.0.2.jar;." lua -l hello
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -240,7 +237,7 @@ but the compiled classes must be in the class path at runtime, unless runtime ji
|
||||
<p>
|
||||
Lua scripts can also be run directly in this mode without precompiling using the <em>lua</em> command with the <b><em>-b</em></b> option and providing the <em>bcel</em> library in the class path:
|
||||
<pre>
|
||||
java -cp "lib/luaj-jse-3.0.1.jar;lib/bcel-5.2.jar" lua -b examples/lua/hello.lua
|
||||
java -cp "luaj-jse-3.0.2.jar;lib/bcel-5.2.jar" lua -b examples/lua/hello.lua
|
||||
</pre>
|
||||
|
||||
|
||||
@@ -284,7 +281,7 @@ A simple example may be found in
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You must include the library <b>lib/luaj-jse-3.0.1.jar</b> in your class path.
|
||||
You must include the library <b>luaj-jse-3.0.2.jar</b> in your class path.
|
||||
|
||||
<h2>Run a script in a MIDlet</h2>
|
||||
|
||||
@@ -311,7 +308,7 @@ A simple example may be found in
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You must include the library <b>lib/luaj-jme-3.0.1.jar</b> in your midlet jar.
|
||||
You must include the library <b>luaj-jme-3.0.2.jar</b> in your midlet jar.
|
||||
|
||||
<p>
|
||||
An ant script to build and run the midlet is in
|
||||
@@ -341,7 +338,7 @@ You can also look up the engine by language "lua" or mimetypes "text/lua" or "ap
|
||||
All standard aspects of script engines including compiled statements are supported.
|
||||
|
||||
<p>
|
||||
You must include the library <b>lib/luaj-jse-3.0.1.jar</b> in your class path.
|
||||
You must include the library <b>luaj-jse-3.0.2.jar</b> in your class path.
|
||||
|
||||
<p>
|
||||
A working example may be found in
|
||||
@@ -352,8 +349,8 @@ A working example may be found in
|
||||
To compile and run it using Java 1.6 or higher:
|
||||
|
||||
<pre>
|
||||
javac -cp lib/luaj-jse-3.0.1.jar examples/jse/ScriptEngineSample.java
|
||||
java -cp "lib/luaj-jse-3.0.1.jar;examples/jse" ScriptEngineSample
|
||||
javac -cp luaj-jse-3.0.2.jar examples/jse/ScriptEngineSample.java
|
||||
java -cp "luaj-jse-3.0.2.jar;examples/jse" ScriptEngineSample
|
||||
</pre>
|
||||
|
||||
<h2>Excluding the lua bytecode compiler</h2>
|
||||
@@ -415,7 +412,7 @@ and the math operations include all those supported by Java SE.
|
||||
Android applications should use the JsePlatform, and can include the <a href="#luajava">Luajava</a> library
|
||||
to simplify access to underlying Android APIs.
|
||||
A specialized Globals.finder should be provided to find scripts and data for loading.
|
||||
See <a href="examples/android/src/android/LuajView">examples/android/src/android/LuajView</a>
|
||||
See <a href="examples/android/src/android/LuajView.java">examples/android/src/android/LuajView.java</a>
|
||||
for an example that loads from the "res" Android project directory.
|
||||
The ant build script is <a href="examples/android/build.xml">examples/android/build.xml</a>.
|
||||
|
||||
@@ -593,7 +590,7 @@ The following lua script will open a swing frame on Java SE:
|
||||
See a longer sample in <em>examples/lua/swingapp.lua</em> for details, including a simple animation loop, rendering graphics, mouse and key handling, and image loading.
|
||||
Or try running it using:
|
||||
<pre>
|
||||
java -cp lib/luaj-jse-3.0.1.jar lua examples/lua/swingapp.lua
|
||||
java -cp luaj-jse-3.0.2.jar lua examples/lua/swingapp.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -842,7 +839,7 @@ For JSE projects, add this dependency for the luaj-jse jar:
|
||||
<dependency>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-jse</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
</pre>
|
||||
while for JME projects, use the luaj-jme jar:
|
||||
@@ -850,7 +847,7 @@ while for JME projects, use the luaj-jme jar:
|
||||
<dependency>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-jme</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
</pre>
|
||||
|
||||
@@ -880,7 +877,7 @@ Unit test scripts can be found in these locations
|
||||
test/lua/*.lua
|
||||
test/lua/errors/*.lua
|
||||
test/lua/perf/*.lua
|
||||
test/lua/luaj3.0.1-tests.zip
|
||||
test/lua/luaj3.0.2-tests.zip
|
||||
</pre>
|
||||
|
||||
<h2>Code coverage</h2>
|
||||
@@ -930,7 +927,7 @@ Files are no longer hosted at LuaForge.
|
||||
<li>Enhance javadoc, put it <a href="docs/api/index.html">in distribution</a>
|
||||
and at <a href="http://luaj.sourceforge.net/api/2.0/index.html">http://luaj.sourceforge.net/api/2.0/</a></li>
|
||||
<li>Major refactor of luajava type coercion logic, improve method selection.</li>
|
||||
<li>Add lib/luaj-sources-2.0.2.jar for easier integration into an IDE such as Netbeans </li>
|
||||
<li>Add luaj-sources-2.0.2.jar for easier integration into an IDE such as Netbeans </li>
|
||||
|
||||
<tr valign="top"><td> <b>2.0.3</b></td><td><ul>
|
||||
<li>Improve coroutine state logic including let unreferenced coroutines be garbage collected </li>
|
||||
@@ -1017,6 +1014,11 @@ and at <a href="http://luaj.sourceforge.net/api/2.0/index.html">http://luaj.sour
|
||||
<li>Move online docs to <a href="http://luaj.org/luaj/3.0/api/index.html">http://luaj.org/luaj/3.0/api/</a></li>
|
||||
<li>Fix os.time() conversions for pm times.</li>
|
||||
|
||||
<tr valign="top"><td> <b>3.0.2</b></td><td><ul>
|
||||
<li>Fix JsePlatform.luaMain() to provide an "arg" table in the chunk's environment.</li>
|
||||
<li>Let JsePlatform.luaMain() return values returned by the main chunk.</li>
|
||||
<li>Add synchronization to CoerceJavaToLua.COERCIONS map.</li>
|
||||
|
||||
</ul></td></tr>
|
||||
</table></td></tr></table>
|
||||
|
||||
@@ -82,17 +82,21 @@
|
||||
<pathelement path="lib/mmapi.jar"/>
|
||||
</path>
|
||||
<javac destdir="build/jme/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs"
|
||||
debug="on"
|
||||
srcdir="build/jme/src"/>
|
||||
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
|
||||
classpath="lib/bcel-5.2.jar"
|
||||
debug="on"
|
||||
srcdir="build/jse/src"
|
||||
excludes="**/script/*,**/Lua2Java*,**/server/*,lua*"/>
|
||||
<javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5"
|
||||
classpath="build/jse/classes"
|
||||
debug="on"
|
||||
srcdir="build/jse/src"
|
||||
includes="**/script/*,**/Lua2Java*,**/server/*"/>
|
||||
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
|
||||
classpath="build/jse/classes"
|
||||
debug="on"
|
||||
srcdir="build/jse/src"
|
||||
includes="lua*"/>
|
||||
</target>
|
||||
|
||||
@@ -11,13 +11,13 @@ import org.luaj.vm2.lib.Bit32Lib;
|
||||
import org.luaj.vm2.lib.CoroutineLib;
|
||||
import org.luaj.vm2.lib.PackageLib;
|
||||
import org.luaj.vm2.lib.ResourceFinder;
|
||||
import org.luaj.vm2.lib.StringLib;
|
||||
import org.luaj.vm2.lib.TableLib;
|
||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||
import org.luaj.vm2.lib.jse.JseBaseLib;
|
||||
import org.luaj.vm2.lib.jse.JseIoLib;
|
||||
import org.luaj.vm2.lib.jse.JseMathLib;
|
||||
import org.luaj.vm2.lib.jse.JseOsLib;
|
||||
import org.luaj.vm2.lib.jse.JseStringLib;
|
||||
import org.luaj.vm2.lib.jse.LuajavaLib;
|
||||
|
||||
/**
|
||||
@@ -76,7 +76,7 @@ public class SampleApplet extends Applet implements ResourceFinder {
|
||||
globals.load(new PackageLib());
|
||||
globals.load(new Bit32Lib());
|
||||
globals.load(new TableLib());
|
||||
globals.load(new StringLib());
|
||||
globals.load(new JseStringLib());
|
||||
globals.load(new CoroutineLib());
|
||||
globals.load(new JseMathLib());
|
||||
globals.load(new JseIoLib());
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
import org.luaj.vm2.*;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LuaBoolean;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.*;
|
||||
import org.luaj.vm2.lib.jse.*;
|
||||
import org.luaj.vm2.lib.Bit32Lib;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
import org.luaj.vm2.lib.PackageLib;
|
||||
import org.luaj.vm2.lib.TableLib;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
import org.luaj.vm2.lib.jse.JseBaseLib;
|
||||
import org.luaj.vm2.lib.jse.JseMathLib;
|
||||
import org.luaj.vm2.lib.jse.JseStringLib;
|
||||
|
||||
/** Simple program that illustrates basic sand-boxing of client scripts
|
||||
* in a server environment.
|
||||
*
|
||||
* <p>Although this sandboxing is done primarily in Java here, these
|
||||
* <p>Although this sandboxing is done primarily in Java here, these
|
||||
* same techniques should all be possible directly from lua using metatables,
|
||||
* and examples are shown in examples/lua/samplesandboxed.lua.
|
||||
*
|
||||
@@ -29,7 +43,7 @@ public class SampleSandboxed {
|
||||
server_globals = new Globals();
|
||||
server_globals.load(new JseBaseLib());
|
||||
server_globals.load(new PackageLib());
|
||||
server_globals.load(new StringLib());
|
||||
server_globals.load(new JseStringLib());
|
||||
|
||||
// To load scripts, we occasionally need a math library in addition to compiler support.
|
||||
// To limit scripts using the debug library, they must be closures, so we only install LuaC.
|
||||
@@ -47,7 +61,7 @@ public class SampleSandboxed {
|
||||
runScriptInSandbox( "return getmetatable('abc').len" );
|
||||
runScriptInSandbox( "return getmetatable('abc').__index" );
|
||||
|
||||
// Example user scripts that attempt rogue operations, and will fail.
|
||||
// Example user scripts that attempt rogue operations, and will fail.
|
||||
runScriptInSandbox( "return setmetatable('abc', {})" );
|
||||
runScriptInSandbox( "getmetatable('abc').len = function() end" );
|
||||
runScriptInSandbox( "getmetatable('abc').__index = {}" );
|
||||
@@ -61,9 +75,9 @@ public class SampleSandboxed {
|
||||
LuaValue.ADD, new TwoArgFunction() {
|
||||
public LuaValue call(LuaValue x, LuaValue y) {
|
||||
return LuaValue.valueOf(
|
||||
(x == TRUE ? 1.0 : x.todouble()) +
|
||||
(x == TRUE ? 1.0 : x.todouble()) +
|
||||
(y == TRUE ? 1.0 : y.todouble()) );
|
||||
}
|
||||
}
|
||||
},
|
||||
}));
|
||||
runScriptInSandbox( "return 5 + 6, 5 + true, false + 6" );
|
||||
@@ -75,21 +89,21 @@ public class SampleSandboxed {
|
||||
// that contain functions that can be abused.
|
||||
static void runScriptInSandbox(String script) {
|
||||
|
||||
// Each script will have it's own set of globals, which should
|
||||
// Each script will have it's own set of globals, which should
|
||||
// prevent leakage between scripts running on the same server.
|
||||
Globals user_globals = new Globals();
|
||||
user_globals.load(new JseBaseLib());
|
||||
user_globals.load(new PackageLib());
|
||||
user_globals.load(new Bit32Lib());
|
||||
user_globals.load(new TableLib());
|
||||
user_globals.load(new StringLib());
|
||||
user_globals.load(new JseStringLib());
|
||||
user_globals.load(new JseMathLib());
|
||||
|
||||
// This library is dangerous as it gives unfettered access to the
|
||||
// entire Java VM, so it's not suitable within this lightweight sandbox.
|
||||
// entire Java VM, so it's not suitable within this lightweight sandbox.
|
||||
// user_globals.load(new LuajavaLib());
|
||||
|
||||
// Starting coroutines in scripts will result in threads that are
|
||||
// Starting coroutines in scripts will result in threads that are
|
||||
// not under the server control, so this libary should probably remain out.
|
||||
// user_globals.load(new CoroutineLib());
|
||||
|
||||
@@ -98,12 +112,12 @@ public class SampleSandboxed {
|
||||
// user_globals.load(new JseIoLib());
|
||||
// user_globals.load(new JseOsLib());
|
||||
|
||||
// Loading and compiling scripts from within scripts may also be
|
||||
// Loading and compiling scripts from within scripts may also be
|
||||
// prohibited, though in theory it should be fairly safe.
|
||||
// LoadState.install(user_globals);
|
||||
// LuaC.install(user_globals);
|
||||
|
||||
// The debug library must be loaded for hook functions to work, which
|
||||
// The debug library must be loaded for hook functions to work, which
|
||||
// allow us to limit scripts to run a certain number of instructions at a time.
|
||||
// However we don't wish to expose the library in the user globals,
|
||||
// so it is immediately removed from the user globals once created.
|
||||
@@ -111,18 +125,18 @@ public class SampleSandboxed {
|
||||
LuaValue sethook = user_globals.get("debug").get("sethook");
|
||||
user_globals.set("debug", LuaValue.NIL);
|
||||
|
||||
// Set up the script to run in its own lua thread, which allows us
|
||||
// Set up the script to run in its own lua thread, which allows us
|
||||
// to set a hook function that limits the script to a specific number of cycles.
|
||||
// Note that the environment is set to the user globals, even though the
|
||||
// Note that the environment is set to the user globals, even though the
|
||||
// compiling is done with the server globals.
|
||||
LuaValue chunk = server_globals.load(script, "main", user_globals);
|
||||
LuaThread thread = new LuaThread(user_globals, chunk);
|
||||
|
||||
// Set the hook function to immediately throw an Error, which will not be
|
||||
// Set the hook function to immediately throw an Error, which will not be
|
||||
// handled by any Lua code other than the coroutine.
|
||||
LuaValue hookfunc = new ZeroArgFunction() {
|
||||
public LuaValue call() {
|
||||
// A simple lua error may be caught by the script, but a
|
||||
// A simple lua error may be caught by the script, but a
|
||||
// Java Error will pass through to top and stop the script.
|
||||
throw new Error("Script overran resource limits.");
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ import java.io.InputStream;
|
||||
* <p>
|
||||
* The {@link LoadState} class provides the default {@link Globals.Undumper}
|
||||
* which is used to undump a string of bytes that represent a lua binary file
|
||||
* using either the C-based lua compiler, or luaj's
|
||||
* using either the C-based lua compiler, or luaj's
|
||||
* {@link org.luaj.vm2.compiler.LuaC} compiler.
|
||||
* <p>
|
||||
* The canonical method to load and execute code is done
|
||||
* The canonical method to load and execute code is done
|
||||
* indirectly using the Globals:
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
@@ -44,10 +44,10 @@ import java.io.InputStream;
|
||||
* This should work regardless of which {@link Globals.Compiler} or {@link Globals.Undumper}
|
||||
* have been installed.
|
||||
* <p>
|
||||
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
|
||||
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
|
||||
* {@link org.luaj.vm2.lib.jme.JmePlatform}
|
||||
* to construct globals, the {@link LoadState} default undumper is installed
|
||||
* as the default {@link Globals.Undumper}.
|
||||
* as the default {@link Globals.Undumper}.
|
||||
* <p>
|
||||
*
|
||||
* A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState} class
|
||||
@@ -60,7 +60,7 @@ import java.io.InputStream;
|
||||
* byte[] lua_binary_file_bytes = o.toByteArray();
|
||||
* } </pre>
|
||||
*
|
||||
* The {@link LoadState}'s default undumper {@link #instance}
|
||||
* The {@link LoadState}'s default undumper {@link #instance}
|
||||
* may be used directly to undump these bytes:
|
||||
* <pre> {@code
|
||||
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
|
||||
@@ -99,7 +99,7 @@ public class LoadState {
|
||||
/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
|
||||
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
|
||||
|
||||
// type constants
|
||||
// type constants
|
||||
public static final int LUA_TINT = (-2);
|
||||
public static final int LUA_TNONE = (-1);
|
||||
public static final int LUA_TNIL = 0;
|
||||
@@ -155,7 +155,6 @@ public class LoadState {
|
||||
private static final LuaValue[] NOVALUES = {};
|
||||
private static final Prototype[] NOPROTOS = {};
|
||||
private static final LocVars[] NOLOCVARS = {};
|
||||
private static final LuaString[] NOSTRVALUES = {};
|
||||
private static final Upvaldesc[] NOUPVALDESCS = {};
|
||||
private static final int[] NOINTS = {};
|
||||
|
||||
@@ -168,17 +167,17 @@ public class LoadState {
|
||||
}
|
||||
|
||||
/** Load a 4-byte int value from the input stream
|
||||
* @return the int value laoded.
|
||||
* @return the int value laoded.
|
||||
**/
|
||||
int loadInt() throws IOException {
|
||||
is.readFully(buf,0,4);
|
||||
return luacLittleEndian?
|
||||
return luacLittleEndian?
|
||||
(buf[3] << 24) | ((0xff & buf[2]) << 16) | ((0xff & buf[1]) << 8) | (0xff & buf[0]):
|
||||
(buf[0] << 24) | ((0xff & buf[1]) << 16) | ((0xff & buf[2]) << 8) | (0xff & buf[3]);
|
||||
}
|
||||
|
||||
/** Load an array of int values from the input stream
|
||||
* @return the array of int values laoded.
|
||||
* @return the array of int values laoded.
|
||||
**/
|
||||
int[] loadIntArray() throws IOException {
|
||||
int n = loadInt();
|
||||
@@ -192,7 +191,7 @@ public class LoadState {
|
||||
is.readFully(buf,0,m);
|
||||
int[] array = new int[n];
|
||||
for ( int i=0, j=0; i<n; ++i, j+=4 )
|
||||
array[i] = luacLittleEndian?
|
||||
array[i] = luacLittleEndian?
|
||||
(buf[j+3] << 24) | ((0xff & buf[j+2]) << 16) | ((0xff & buf[j+1]) << 8) | (0xff & buf[j+0]):
|
||||
(buf[j+0] << 24) | ((0xff & buf[j+1]) << 16) | ((0xff & buf[j+2]) << 8) | (0xff & buf[j+3]);
|
||||
|
||||
@@ -200,7 +199,7 @@ public class LoadState {
|
||||
}
|
||||
|
||||
/** Load a long value from the input stream
|
||||
* @return the long value laoded.
|
||||
* @return the long value laoded.
|
||||
**/
|
||||
long loadInt64() throws IOException {
|
||||
int a,b;
|
||||
@@ -215,7 +214,7 @@ public class LoadState {
|
||||
}
|
||||
|
||||
/** Load a lua strin gvalue from the input stream
|
||||
* @return the {@link LuaString} value laoded.
|
||||
* @return the {@link LuaString} value laoded.
|
||||
**/
|
||||
LuaString loadString() throws IOException {
|
||||
int size = this.luacSizeofSizeT == 8? (int) loadInt64(): loadInt();
|
||||
@@ -227,7 +226,7 @@ public class LoadState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert bits in a long value to a {@link LuaValue}.
|
||||
* Convert bits in a long value to a {@link LuaValue}.
|
||||
* @param bits long value containing the bits
|
||||
* @return {@link LuaInteger} or {@link LuaDouble} whose value corresponds to the bits provided.
|
||||
*/
|
||||
@@ -251,7 +250,7 @@ public class LoadState {
|
||||
return LuaValue.valueOf( Double.longBitsToDouble(bits) );
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Load a number from a binary chunk
|
||||
* @return the {@link LuaValue} loaded
|
||||
* @throws IOException if an i/o exception occurs
|
||||
@@ -335,7 +334,7 @@ public class LoadState {
|
||||
f.upvalues[i].name = loadString();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Load a function prototype from the input stream
|
||||
* @param p name of the source
|
||||
* @return {@link Prototype} instance that was loaded
|
||||
@@ -366,8 +365,8 @@ public class LoadState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the lua chunk header values.
|
||||
* @throws IOException if an i/o exception occurs.
|
||||
* Load the lua chunk header values.
|
||||
* @throws IOException if an i/o exception occurs.
|
||||
*/
|
||||
public void loadHeader() throws IOException {
|
||||
luacVersion = is.readByte();
|
||||
@@ -392,7 +391,7 @@ public class LoadState {
|
||||
*/
|
||||
public static Prototype undump(InputStream stream, String chunkname) throws IOException {
|
||||
// check rest of signature
|
||||
if ( stream.read() != LUA_SIGNATURE[0]
|
||||
if ( stream.read() != LUA_SIGNATURE[0]
|
||||
|| stream.read() != LUA_SIGNATURE[1]
|
||||
|| stream.read() != LUA_SIGNATURE[2]
|
||||
|| stream.read() != LUA_SIGNATURE[3] )
|
||||
|
||||
@@ -23,10 +23,10 @@ package org.luaj.vm2;
|
||||
|
||||
|
||||
/**
|
||||
* Constants for lua limits and opcodes.
|
||||
* Constants for lua limits and opcodes.
|
||||
* <p>
|
||||
* This is a direct translation of C lua distribution header file constants
|
||||
* for bytecode creation and processing.
|
||||
* for bytecode creation and processing.
|
||||
*/
|
||||
public class Lua {
|
||||
/** version is supplied by ant build task */
|
||||
@@ -80,7 +80,6 @@ public class Lua {
|
||||
public static final int POS_Bx = POS_C;
|
||||
public static final int POS_Ax = POS_A;
|
||||
|
||||
|
||||
public static final int MAX_OP = ((1<<SIZE_OP)-1);
|
||||
public static final int MAXARG_A = ((1<<SIZE_A)-1);
|
||||
public static final int MAXARG_B = ((1<<SIZE_B)-1);
|
||||
@@ -89,17 +88,18 @@ public class Lua {
|
||||
public static final int MAXARG_sBx = (MAXARG_Bx>>1); /* `sBx' is signed */
|
||||
public static final int MAXARG_Ax = ((1<<SIZE_Ax)-1);
|
||||
|
||||
public static final int MASK_OP = ((1<<SIZE_OP)-1)<<POS_OP;
|
||||
public static final int MASK_A = ((1<<SIZE_A)-1)<<POS_A;
|
||||
public static final int MASK_B = ((1<<SIZE_B)-1)<<POS_B;
|
||||
public static final int MASK_C = ((1<<SIZE_C)-1)<<POS_C;
|
||||
public static final int MASK_Bx = ((1<<SIZE_Bx)-1)<<POS_Bx;
|
||||
public static final int MASK_OP = ((1<<SIZE_OP)-1)<<POS_OP;
|
||||
public static final int MASK_A = ((1<<SIZE_A)-1)<<POS_A;
|
||||
public static final int MASK_B = ((1<<SIZE_B)-1)<<POS_B;
|
||||
public static final int MASK_C = ((1<<SIZE_C)-1)<<POS_C;
|
||||
public static final int MASK_Bx = ((1<<SIZE_Bx)-1)<<POS_Bx;
|
||||
public static final int MASK_Ax = ((1<<SIZE_Ax)-1)<<POS_Ax;
|
||||
|
||||
public static final int MASK_NOT_OP = ~MASK_OP;
|
||||
public static final int MASK_NOT_A = ~MASK_A;
|
||||
public static final int MASK_NOT_B = ~MASK_B;
|
||||
public static final int MASK_NOT_C = ~MASK_C;
|
||||
public static final int MASK_NOT_Bx = ~MASK_Bx;
|
||||
public static final int MASK_NOT_OP = ~MASK_OP;
|
||||
public static final int MASK_NOT_A = ~MASK_A;
|
||||
public static final int MASK_NOT_B = ~MASK_B;
|
||||
public static final int MASK_NOT_C = ~MASK_C;
|
||||
public static final int MASK_NOT_Bx = ~MASK_Bx;
|
||||
|
||||
/*
|
||||
** the following macros help to manipulate instructions
|
||||
@@ -208,13 +208,13 @@ public class Lua {
|
||||
|
||||
public static final int OP_CONCAT = 22; /* A B C R(A) := R(B).. ... ..R(C) */
|
||||
|
||||
public static final int OP_JMP = 23; /* sBx pc+=sBx */
|
||||
public static final int OP_JMP = 23; /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
|
||||
public static final int OP_EQ = 24; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
public static final int OP_LT = 25; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
public static final int OP_LE = 26; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
|
||||
public static final int OP_TEST = 27; /* A C if not (R(A) <=> C) then pc++ */
|
||||
public static final int OP_TESTSET = 28; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
|
||||
public static final int OP_TEST = 27; /* A C if not (R(A) <=> C) then pc++ */
|
||||
public static final int OP_TESTSET = 28; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
|
||||
|
||||
public static final int OP_CALL = 29; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
public static final int OP_TAILCALL = 30; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
@@ -225,7 +225,7 @@ public class Lua {
|
||||
public static final int OP_FORPREP = 33; /* A sBx R(A)-=R(A+2); pc+=sBx */
|
||||
|
||||
public static final int OP_TFORCALL = 34; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
|
||||
public static final int OP_TFORLOOP = 35; /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */
|
||||
public static final int OP_TFORLOOP = 35; /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */
|
||||
public static final int OP_SETLIST = 36; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
|
||||
|
||||
public static final int OP_CLOSURE = 37; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
@@ -237,11 +237,11 @@ public class Lua {
|
||||
public static final int NUM_OPCODES = OP_EXTRAARG + 1;
|
||||
|
||||
/* pseudo-opcodes used in parsing only. */
|
||||
public static final int OP_GT = 63; // >
|
||||
public static final int OP_GT = 63; // >
|
||||
public static final int OP_GE = 62; // >=
|
||||
public static final int OP_NEQ = 61; // ~=
|
||||
public static final int OP_AND = 60; // and
|
||||
public static final int OP_OR = 59; // or
|
||||
public static final int OP_NEQ = 61; // ~=
|
||||
public static final int OP_AND = 60; // and
|
||||
public static final int OP_OR = 59; // or
|
||||
|
||||
/*===========================================================================
|
||||
Notes:
|
||||
@@ -271,7 +271,7 @@ public class Lua {
|
||||
** bits 4-5: B arg mode
|
||||
** bit 6: instruction set register A
|
||||
** bit 7: operator is a test
|
||||
*/
|
||||
*/
|
||||
|
||||
public static final int OpArgN = 0; /* argument is not used */
|
||||
public static final int OpArgU = 1; /* argument is used */
|
||||
@@ -353,7 +353,7 @@ public class Lua {
|
||||
source = "[string \""+source;
|
||||
end = "\"]";
|
||||
}
|
||||
int n = source.length() + end.length();
|
||||
int n = source.length() + end.length();
|
||||
if ( n > MAXSRC )
|
||||
source = source.substring(0,MAXSRC-end.length()-3) + "...";
|
||||
return source + end;
|
||||
|
||||
@@ -21,23 +21,25 @@
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import org.luaj.vm2.lib.DebugLib.CallFrame;
|
||||
|
||||
/**
|
||||
* Extension of {@link LuaFunction} which executes lua bytecode.
|
||||
* Extension of {@link LuaFunction} which executes lua bytecode.
|
||||
* <p>
|
||||
* A {@link LuaClosure} is a combination of a {@link Prototype}
|
||||
* A {@link LuaClosure} is a combination of a {@link Prototype}
|
||||
* and a {@link LuaValue} to use as an environment for execution.
|
||||
* Normally the {@link LuaValue} is a {@link Globals} in which case the environment
|
||||
* will contain standard lua libraries.
|
||||
* will contain standard lua libraries.
|
||||
*
|
||||
* <p>
|
||||
* There are three main ways {@link LuaClosure} instances are created:
|
||||
* <ul>
|
||||
* <ul>
|
||||
* <li>Construct an instance using {@link #LuaClosure(Prototype, LuaValue)}</li>
|
||||
* <li>Construct it indirectly by loading a chunk via {@link Globals#load(java.io.Reader, String)}
|
||||
* <li>Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode processing
|
||||
* </ul>
|
||||
* <p>
|
||||
* To construct it directly, the {@link Prototype} is typically created via a compiler such as
|
||||
* To construct it directly, the {@link Prototype} is typically created via a compiler such as
|
||||
* {@link org.luaj.vm2.compiler.LuaC}:
|
||||
* <pre> {@code
|
||||
* String script = "print( 'hello, world' )";
|
||||
@@ -46,9 +48,9 @@ package org.luaj.vm2;
|
||||
* LuaValue globals = JsePlatform.standardGlobals();
|
||||
* LuaClosure f = new LuaClosure(p, globals);
|
||||
* f.call();
|
||||
* }</pre>
|
||||
* }</pre>
|
||||
* <p>
|
||||
* To construct it indirectly, the {@link Globals#load(java.io.Reader, String)} method may be used:
|
||||
* To construct it indirectly, the {@link Globals#load(java.io.Reader, String)} method may be used:
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* LuaFunction f = globals.load(new StringReader(script), "script");
|
||||
@@ -56,11 +58,11 @@ package org.luaj.vm2;
|
||||
* c.call();
|
||||
* }</pre>
|
||||
* <p>
|
||||
* In this example, the "checkclosure()" may fail if direct lua-to-java-bytecode
|
||||
* In this example, the "checkclosure()" may fail if direct lua-to-java-bytecode
|
||||
* compiling using LuaJC is installed, because no LuaClosure is created in that case
|
||||
* and the value returned is a {@link LuaFunction} but not a {@link LuaClosure}.
|
||||
* <p>
|
||||
* Since a {@link LuaClosure} is a {@link LuaFunction} which is a {@link LuaValue},
|
||||
* <p>
|
||||
* Since a {@link LuaClosure} is a {@link LuaFunction} which is a {@link LuaValue},
|
||||
* all the value operations can be used directly such as:
|
||||
* <ul>
|
||||
* <li>{@link LuaValue#call()}</li>
|
||||
@@ -71,7 +73,7 @@ package org.luaj.vm2;
|
||||
* <li>{@link LuaValue#method(String,LuaValue)}</li>
|
||||
* <li>{@link LuaValue#invokemethod(String)}</li>
|
||||
* <li>{@link LuaValue#invokemethod(String,Varargs)}</li>
|
||||
* <li> ...</li>
|
||||
* <li> ...</li>
|
||||
* </ul>
|
||||
* @see LuaValue
|
||||
* @see LuaFunction
|
||||
@@ -92,19 +94,24 @@ public class LuaClosure extends LuaFunction {
|
||||
|
||||
/** Create a closure around a Prototype with a specific environment.
|
||||
* If the prototype has upvalues, the environment will be written into the first upvalue.
|
||||
* @param p the Prototype to construct this Closure for.
|
||||
* @param p the Prototype to construct this Closure for.
|
||||
* @param env the environment to associate with the closure.
|
||||
*/
|
||||
public LuaClosure(Prototype p, LuaValue env) {
|
||||
this.p = p;
|
||||
this.initupvalue1(env);
|
||||
globals = env instanceof Globals? (Globals) env: null;
|
||||
}
|
||||
|
||||
public void initupvalue1(LuaValue env) {
|
||||
if (p.upvalues == null || p.upvalues.length == 0)
|
||||
this.upValues = NOUPVALUES;
|
||||
else {
|
||||
this.upValues = new UpValue[p.upvalues.length];
|
||||
this.upValues[0] = new UpValue(new LuaValue[] {env}, 0);
|
||||
}
|
||||
globals = env instanceof Globals? (Globals) env: null;
|
||||
}
|
||||
|
||||
|
||||
public boolean isclosure() {
|
||||
return true;
|
||||
@@ -118,26 +125,24 @@ public class LuaClosure extends LuaFunction {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return "function: " + p.toString();
|
||||
}
|
||||
|
||||
private LuaValue[] getNewStack() {
|
||||
int max = p.maxstacksize;
|
||||
LuaValue[] stack = new LuaValue[max];
|
||||
System.arraycopy(NILS, 0, stack, 0, max);
|
||||
return stack;
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
for (int i = 0; i < p.numparams; ++i )
|
||||
stack[i] = NIL;
|
||||
LuaValue[] stack = getNewStack();
|
||||
return execute(stack,NONE).arg1();
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
for (int i = 1; i < p.numparams; ++i )
|
||||
stack[i] = NIL;
|
||||
LuaValue[] stack = getNewStack();
|
||||
switch ( p.numparams ) {
|
||||
default: stack[0]=arg; return execute(stack,NONE).arg1();
|
||||
case 0: return execute(stack,arg).arg1();
|
||||
@@ -145,9 +150,7 @@ public class LuaClosure extends LuaFunction {
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
for (int i = 2; i < p.numparams; ++i )
|
||||
stack[i] = NIL;
|
||||
LuaValue[] stack = getNewStack();
|
||||
switch ( p.numparams ) {
|
||||
default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1();
|
||||
case 1: stack[0]=arg1; return execute(stack,arg2).arg1();
|
||||
@@ -156,9 +159,7 @@ public class LuaClosure extends LuaFunction {
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
for (int i = 3; i < p.numparams; ++i )
|
||||
stack[i] = NIL;
|
||||
LuaValue[] stack = getNewStack();
|
||||
switch ( p.numparams ) {
|
||||
default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1();
|
||||
case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1();
|
||||
@@ -172,9 +173,9 @@ public class LuaClosure extends LuaFunction {
|
||||
}
|
||||
|
||||
public final Varargs onInvoke(Varargs varargs) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
LuaValue[] stack = getNewStack();
|
||||
for ( int i=0; i<p.numparams; i++ )
|
||||
stack[i] = varargs.arg(i+1);
|
||||
stack[i] = varargs.arg(i+1);
|
||||
return execute(stack,p.is_vararg!=0? varargs.subargs(p.numparams+1): NONE);
|
||||
}
|
||||
|
||||
@@ -192,13 +193,13 @@ public class LuaClosure extends LuaFunction {
|
||||
|
||||
// allow for debug hooks
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onCall( this, varargs, stack );
|
||||
globals.debuglib.onCall( this, varargs, stack );
|
||||
|
||||
// process instructions
|
||||
try {
|
||||
for (; true; ++pc) {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onInstruction( pc, v, top );
|
||||
globals.debuglib.onInstruction( pc, v, top );
|
||||
|
||||
// pull out instruction
|
||||
i = code[pc];
|
||||
@@ -215,6 +216,17 @@ public class LuaClosure extends LuaFunction {
|
||||
stack[a] = k[i>>>14];
|
||||
continue;
|
||||
|
||||
case Lua.OP_LOADKX:/* A R(A) := Kst(extra arg) */
|
||||
++pc;
|
||||
i = code[pc];
|
||||
if ((i & 0x3f) != Lua.OP_EXTRAARG) {
|
||||
int op = i & 0x3f;
|
||||
throw new LuaError("OP_EXTRAARG expected after OP_LOADKX, got " +
|
||||
(op < Print.OPNAMES.length - 1 ? Print.OPNAMES[op] : "UNKNOWN_OP_" + op));
|
||||
}
|
||||
stack[a] = k[i>>>6];
|
||||
continue;
|
||||
|
||||
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
|
||||
stack[a] = (i>>>23!=0)? LuaValue.TRUE: LuaValue.FALSE;
|
||||
if ((i&(0x1ff<<14)) != 0)
|
||||
@@ -301,8 +313,8 @@ public class LuaClosure extends LuaFunction {
|
||||
{
|
||||
if ( c > b+1 ) {
|
||||
Buffer sb = stack[c].buffer();
|
||||
while ( --c>=b )
|
||||
sb = stack[c].concat(sb);
|
||||
while ( --c>=b )
|
||||
sb.concatTo(stack[c]);
|
||||
stack[a] = sb.value();
|
||||
} else {
|
||||
stack[a] = stack[c-1].concat(stack[c]);
|
||||
@@ -310,7 +322,7 @@ public class LuaClosure extends LuaFunction {
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_JMP: /* sBx pc+=sBx */
|
||||
case Lua.OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
|
||||
pc += (i>>>14)-0x1ffff;
|
||||
if (a > 0) {
|
||||
for (--a, b = openups.length; --b>=0; )
|
||||
@@ -322,31 +334,31 @@ public class LuaClosure extends LuaFunction {
|
||||
continue;
|
||||
|
||||
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).eq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
|
||||
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).eq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
|
||||
++pc;
|
||||
continue;
|
||||
|
||||
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lt_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
|
||||
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lt_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
|
||||
++pc;
|
||||
continue;
|
||||
|
||||
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lteq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
|
||||
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lteq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
|
||||
++pc;
|
||||
continue;
|
||||
|
||||
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||
if ( stack[a].toboolean() != ((i&(0x1ff<<14))!=0) )
|
||||
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||
if ( stack[a].toboolean() != ((i&(0x1ff<<14))!=0) )
|
||||
++pc;
|
||||
continue;
|
||||
|
||||
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
|
||||
/* note: doc appears to be reversed */
|
||||
if ( (o=stack[i>>>23]).toboolean() != ((i&(0x1ff<<14))!=0) )
|
||||
if ( (o=stack[i>>>23]).toboolean() != ((i&(0x1ff<<14))!=0) )
|
||||
++pc;
|
||||
else
|
||||
stack[a] = o; // TODO: should be sBx?
|
||||
stack[a] = o; // TODO: should be sBx?
|
||||
continue;
|
||||
|
||||
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
@@ -364,9 +376,9 @@ public class LuaClosure extends LuaFunction {
|
||||
default:
|
||||
b = i>>>23;
|
||||
c = (i>>14)&0x1ff;
|
||||
v = stack[a].invoke(b>0?
|
||||
v = stack[a].invoke(b>0?
|
||||
varargsOf(stack, a+1, b-1): // exact arg count
|
||||
varargsOf(stack, a+1, top-v.narg()-(a+1), v)); // from prev top
|
||||
varargsOf(stack, a+1, top-v.narg()-(a+1), v)); // from prev top
|
||||
if ( c > 0 ) {
|
||||
v.copyto(stack, a, c-1);
|
||||
v = NONE;
|
||||
@@ -385,18 +397,18 @@ public class LuaClosure extends LuaFunction {
|
||||
case (4<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2],stack[a+3]));
|
||||
default:
|
||||
b = i>>>23;
|
||||
v = b>0?
|
||||
v = b>0?
|
||||
varargsOf(stack,a+1,b-1): // exact arg count
|
||||
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
|
||||
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
|
||||
return new TailcallVarargs( stack[a], v );
|
||||
}
|
||||
|
||||
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
b = i>>>23;
|
||||
switch ( b ) {
|
||||
case 0: return varargsOf(stack, a, top-v.narg()-a, v);
|
||||
case 0: return varargsOf(stack, a, top-v.narg()-a, v);
|
||||
case 1: return NONE;
|
||||
case 2: return stack[a];
|
||||
case 2: return stack[a];
|
||||
default:
|
||||
return varargsOf(stack, a, b-1);
|
||||
}
|
||||
@@ -405,7 +417,7 @@ public class LuaClosure extends LuaFunction {
|
||||
{
|
||||
LuaValue limit = stack[a + 1];
|
||||
LuaValue step = stack[a + 2];
|
||||
LuaValue idx = step.add(stack[a]);
|
||||
LuaValue idx = stack[a].add(step);
|
||||
if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) {
|
||||
stack[a] = idx;
|
||||
stack[a + 3] = idx;
|
||||
@@ -449,7 +461,7 @@ public class LuaClosure extends LuaFunction {
|
||||
o = stack[a];
|
||||
if ( (b=i>>>23) == 0 ) {
|
||||
b = top - a - 1;
|
||||
int m = b - v.narg();
|
||||
int m = b - v.narg();
|
||||
int j=1;
|
||||
for ( ;j<=m; j++ )
|
||||
o.set(offset+j, stack[a + j]);
|
||||
@@ -483,11 +495,11 @@ public class LuaClosure extends LuaFunction {
|
||||
if ( b == 0 ) {
|
||||
top = a + (b = varargs.narg());
|
||||
v = varargs;
|
||||
} else {
|
||||
} else {
|
||||
for ( int j=1; j<b; ++j )
|
||||
stack[a+j-1] = varargs.arg(j);
|
||||
}
|
||||
continue;
|
||||
continue;
|
||||
|
||||
case Lua.OP_EXTRAARG:
|
||||
throw new java.lang.IllegalArgumentException("Uexecutable opcode: OP_EXTRAARG");
|
||||
@@ -516,7 +528,7 @@ public class LuaClosure extends LuaFunction {
|
||||
|
||||
/**
|
||||
* Run the error hook if there is one
|
||||
* @param msg the message to use in error hook processing.
|
||||
* @param msg the message to use in error hook processing.
|
||||
* */
|
||||
String errorHook(String msg, int level) {
|
||||
if (globals == null ) return msg;
|
||||
@@ -537,8 +549,24 @@ public class LuaClosure extends LuaFunction {
|
||||
}
|
||||
|
||||
private void processErrorHooks(LuaError le, Prototype p, int pc) {
|
||||
le.fileline = (p.source != null? p.source.tojstring(): "?") + ":"
|
||||
+ (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?");
|
||||
String file = "?";
|
||||
int line = -1;
|
||||
{
|
||||
CallFrame frame = null;
|
||||
if (globals != null && globals.debuglib != null) {
|
||||
frame = globals.debuglib.getCallFrame(le.level);
|
||||
if (frame != null) {
|
||||
String src = frame.shortsource();
|
||||
file = src != null ? src : "?";
|
||||
line = frame.currentline();
|
||||
}
|
||||
}
|
||||
if (frame == null) {
|
||||
file = p.source != null? p.source.tojstring(): "?";
|
||||
line = p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length ? p.lineinfo[pc] : -1;
|
||||
}
|
||||
}
|
||||
le.fileline = file + ":" + line;
|
||||
le.traceback = errorHook(le.getMessage(), le.level);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,18 +24,18 @@ package org.luaj.vm2;
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
|
||||
/**
|
||||
* Extension of {@link LuaNumber} which can hold a Java double as its value.
|
||||
* Extension of {@link LuaNumber} which can hold a Java double as its value.
|
||||
* <p>
|
||||
* These instance are not instantiated directly by clients, but indirectly
|
||||
* These instance are not instantiated directly by clients, but indirectly
|
||||
* via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)}
|
||||
* functions. This ensures that values which can be represented as int
|
||||
* are wrapped in {@link LuaInteger} instead of {@link LuaDouble}.
|
||||
* functions. This ensures that values which can be represented as int
|
||||
* are wrapped in {@link LuaInteger} instead of {@link LuaDouble}.
|
||||
* <p>
|
||||
* Almost all API's implemented in LuaDouble are defined and documented in {@link LuaValue}.
|
||||
* <p>
|
||||
* However the constants {@link #NAN}, {@link #POSINF}, {@link #NEGINF},
|
||||
* {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful
|
||||
* when dealing with Nan or Infinite values.
|
||||
* {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful
|
||||
* when dealing with Nan or Infinite values.
|
||||
* <p>
|
||||
* LuaDouble also defines functions for handling the unique math rules of lua devision and modulo in
|
||||
* <ul>
|
||||
@@ -43,7 +43,7 @@ import org.luaj.vm2.lib.MathLib;
|
||||
* <li>{@link #ddiv_d(double, double)}</li>
|
||||
* <li>{@link #dmod(double, double)}</li>
|
||||
* <li>{@link #dmod_d(double, double)}</li>
|
||||
* </ul>
|
||||
* </ul>
|
||||
* <p>
|
||||
* @see LuaValue
|
||||
* @see LuaNumber
|
||||
@@ -90,7 +90,7 @@ public class LuaDouble extends LuaNumber {
|
||||
}
|
||||
|
||||
public boolean islong() {
|
||||
return v == (long) v;
|
||||
return v == (long) v;
|
||||
}
|
||||
|
||||
public byte tobyte() { return (byte) (long) v; }
|
||||
@@ -151,12 +151,12 @@ public class LuaDouble extends LuaNumber {
|
||||
/** Divide two double numbers according to lua math, and return a {@link LuaValue} result.
|
||||
* @param lhs Left-hand-side of the division.
|
||||
* @param rhs Right-hand-side of the division.
|
||||
* @return {@link LuaValue} for the result of the division,
|
||||
* @return {@link LuaValue} for the result of the division,
|
||||
* taking into account positive and negiative infinity, and Nan
|
||||
* @see #ddiv_d(double, double)
|
||||
* @see #ddiv_d(double, double)
|
||||
*/
|
||||
public static LuaValue ddiv(double lhs, double rhs) {
|
||||
return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF;
|
||||
return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF;
|
||||
}
|
||||
|
||||
/** Divide two double numbers according to lua math, and return a double result.
|
||||
@@ -166,54 +166,68 @@ public class LuaDouble extends LuaNumber {
|
||||
* @see #ddiv(double, double)
|
||||
*/
|
||||
public static double ddiv_d(double lhs, double rhs) {
|
||||
return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY;
|
||||
return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY;
|
||||
}
|
||||
|
||||
/** Take modulo double numbers according to lua math, and return a {@link LuaValue} result.
|
||||
* @param lhs Left-hand-side of the modulo.
|
||||
* @param rhs Right-hand-side of the modulo.
|
||||
* @return {@link LuaValue} for the result of the modulo,
|
||||
* @return {@link LuaValue} for the result of the modulo,
|
||||
* using lua's rules for modulo
|
||||
* @see #dmod_d(double, double)
|
||||
* @see #dmod_d(double, double)
|
||||
*/
|
||||
public static LuaValue dmod(double lhs, double rhs) {
|
||||
return rhs!=0? valueOf( lhs-rhs*Math.floor(lhs/rhs) ): NAN;
|
||||
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return NAN;
|
||||
if (rhs == Double.POSITIVE_INFINITY) {
|
||||
return lhs < 0 ? POSINF : valueOf(lhs);
|
||||
}
|
||||
if (rhs == Double.NEGATIVE_INFINITY) {
|
||||
return lhs > 0 ? NEGINF : valueOf(lhs);
|
||||
}
|
||||
return valueOf( lhs-rhs*Math.floor(lhs/rhs) );
|
||||
}
|
||||
|
||||
/** Take modulo for double numbers according to lua math, and return a double result.
|
||||
* @param lhs Left-hand-side of the modulo.
|
||||
* @param rhs Right-hand-side of the modulo.
|
||||
* @return double value for the result of the modulo,
|
||||
* @return double value for the result of the modulo,
|
||||
* using lua's rules for modulo
|
||||
* @see #dmod(double, double)
|
||||
*/
|
||||
public static double dmod_d(double lhs, double rhs) {
|
||||
return rhs!=0? lhs-rhs*Math.floor(lhs/rhs): Double.NaN;
|
||||
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return Double.NaN;
|
||||
if (rhs == Double.POSITIVE_INFINITY) {
|
||||
return lhs < 0 ? Double.POSITIVE_INFINITY : lhs;
|
||||
}
|
||||
if (rhs == Double.NEGATIVE_INFINITY) {
|
||||
return lhs > 0 ? Double.NEGATIVE_INFINITY : lhs;
|
||||
}
|
||||
return lhs-rhs*Math.floor(lhs/rhs);
|
||||
}
|
||||
|
||||
// relational operators
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
|
||||
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
|
||||
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
|
||||
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); }
|
||||
public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
|
||||
public boolean lt_b( int rhs ) { return v < rhs; }
|
||||
public boolean lt_b( double rhs ) { return v < rhs; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
|
||||
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
|
||||
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
|
||||
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); }
|
||||
public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
|
||||
public boolean lteq_b( int rhs ) { return v <= rhs; }
|
||||
public boolean lteq_b( double rhs ) { return v <= rhs; }
|
||||
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
|
||||
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
|
||||
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
|
||||
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); }
|
||||
public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
|
||||
public boolean gt_b( int rhs ) { return v > rhs; }
|
||||
public boolean gt_b( double rhs ) { return v > rhs; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? LuaValue.TRUE: FALSE; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
|
||||
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
|
||||
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
|
||||
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); }
|
||||
public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
|
||||
public boolean gteq_b( int rhs ) { return v >= rhs; }
|
||||
public boolean gteq_b( double rhs ) { return v >= rhs; }
|
||||
|
||||
@@ -222,17 +236,17 @@ public class LuaDouble extends LuaNumber {
|
||||
|
||||
public String tojstring() {
|
||||
/*
|
||||
if ( v == 0.0 ) { // never occurs in J2me
|
||||
if ( v == 0.0 ) { // never occurs in J2me
|
||||
long bits = Double.doubleToLongBits( v );
|
||||
return ( bits >> 63 == 0 ) ? "0" : "-0";
|
||||
}
|
||||
*/
|
||||
long l = (long) v;
|
||||
if ( l == v )
|
||||
if ( l == v )
|
||||
return Long.toString(l);
|
||||
if ( Double.isNaN(v) )
|
||||
return JSTR_NAN;
|
||||
if ( Double.isInfinite(v) )
|
||||
if ( Double.isInfinite(v) )
|
||||
return (v<0? JSTR_NEGINF: JSTR_POSINF);
|
||||
return Float.toString((float)v);
|
||||
}
|
||||
@@ -254,11 +268,11 @@ public class LuaDouble extends LuaNumber {
|
||||
}
|
||||
|
||||
public LuaNumber optnumber(LuaNumber defval) {
|
||||
return this;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isnumber() {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
@@ -273,14 +287,14 @@ public class LuaDouble extends LuaNumber {
|
||||
public LuaNumber checknumber() { return this; }
|
||||
public double checkdouble() { return v; }
|
||||
|
||||
public String checkjstring() {
|
||||
public String checkjstring() {
|
||||
return tojstring();
|
||||
}
|
||||
public LuaString checkstring() {
|
||||
public LuaString checkstring() {
|
||||
return LuaString.valueOf(tojstring());
|
||||
}
|
||||
|
||||
public boolean isvalidkey() {
|
||||
return !Double.isNaN(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
package org.luaj.vm2;
|
||||
|
||||
|
||||
/**
|
||||
* Base class for functions implemented in Java.
|
||||
/**
|
||||
* Base class for functions implemented in Java.
|
||||
* <p>
|
||||
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction}
|
||||
* which is the base class for
|
||||
* all built-in library functions coded in Java,
|
||||
* and {@link LuaClosure}, which represents a lua closure
|
||||
* whose bytecode is interpreted when the function is invoked.
|
||||
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction}
|
||||
* which is the base class for
|
||||
* all built-in library functions coded in Java,
|
||||
* and {@link LuaClosure}, which represents a lua closure
|
||||
* whose bytecode is interpreted when the function is invoked.
|
||||
* @see LuaValue
|
||||
* @see LuaClosure
|
||||
* @see org.luaj.vm2.lib.LibFunction
|
||||
@@ -57,11 +57,11 @@ public class LuaFunction extends LuaValue {
|
||||
}
|
||||
|
||||
public LuaFunction optfunction(LuaFunction defval) {
|
||||
return this;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
@@ -72,12 +72,15 @@ public class LuaFunction extends LuaValue {
|
||||
return valueOf(tojstring());
|
||||
}
|
||||
|
||||
/** Return the last part of the class name, to be used as a function name in tojstring and elsewhere.
|
||||
/** Return the last part of the class name, to be used as a function name in tojstring and elsewhere.
|
||||
* @return String naming the last part of the class name after the last dot (.) or dollar sign ($).
|
||||
* If the first character is '_', it is skipped.
|
||||
*/
|
||||
public String classnamestub() {
|
||||
String s = getClass().getName();
|
||||
return s.substring(Math.max(s.lastIndexOf('.'),s.lastIndexOf('$'))+1);
|
||||
int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$')) + 1;
|
||||
if (s.charAt(offset) == '_') offset++;
|
||||
return s.substring(offset);
|
||||
}
|
||||
|
||||
/** Return a human-readable name for this function. Returns the last part of the class name by default.
|
||||
|
||||
@@ -24,14 +24,14 @@ package org.luaj.vm2;
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
|
||||
/**
|
||||
* Extension of {@link LuaNumber} which can hold a Java int as its value.
|
||||
* Extension of {@link LuaNumber} which can hold a Java int as its value.
|
||||
* <p>
|
||||
* These instance are not instantiated directly by clients, but indirectly
|
||||
* These instance are not instantiated directly by clients, but indirectly
|
||||
* via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)}
|
||||
* functions. This ensures that policies regarding pooling of instances are
|
||||
* encapsulated.
|
||||
* functions. This ensures that policies regarding pooling of instances are
|
||||
* encapsulated.
|
||||
* <p>
|
||||
* There are no API's specific to LuaInteger that are useful beyond what is already
|
||||
* There are no API's specific to LuaInteger that are useful beyond what is already
|
||||
* exposed in {@link LuaValue}.
|
||||
*
|
||||
* @see LuaValue
|
||||
@@ -61,16 +61,16 @@ public class LuaInteger extends LuaNumber {
|
||||
*/
|
||||
public static LuaNumber valueOf(long l) {
|
||||
int i = (int) l;
|
||||
return l==i? (i<=255 && i>=-256? intValues[i+256]:
|
||||
(LuaNumber) new LuaInteger(i)):
|
||||
return l==i? (i<=255 && i>=-256? intValues[i+256]:
|
||||
(LuaNumber) new LuaInteger(i)):
|
||||
(LuaNumber) LuaDouble.valueOf(l);
|
||||
}
|
||||
|
||||
/** The value being held by this instance. */
|
||||
public final int v;
|
||||
|
||||
/**
|
||||
* Package protected constructor.
|
||||
/**
|
||||
* Package protected constructor.
|
||||
* @see LuaValue#valueOf(int)
|
||||
**/
|
||||
LuaInteger(int i) {
|
||||
@@ -103,15 +103,15 @@ public class LuaInteger extends LuaNumber {
|
||||
}
|
||||
|
||||
public LuaString optstring(LuaString defval) {
|
||||
return LuaString.valueOf(Integer.toString(v));
|
||||
return LuaString.valueOf(Integer.toString(v));
|
||||
}
|
||||
|
||||
public LuaValue tostring() {
|
||||
return LuaString.valueOf(Integer.toString(v));
|
||||
return LuaString.valueOf(Integer.toString(v));
|
||||
}
|
||||
|
||||
public String optjstring(String defval) {
|
||||
return Integer.toString(v);
|
||||
public String optjstring(String defval) {
|
||||
return Integer.toString(v);
|
||||
}
|
||||
|
||||
public LuaInteger checkinteger() {
|
||||
@@ -172,48 +172,48 @@ public class LuaInteger extends LuaNumber {
|
||||
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
|
||||
|
||||
// relational operators
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? TRUE: FALSE; }
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
|
||||
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
|
||||
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
|
||||
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); }
|
||||
public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
|
||||
public boolean lt_b( int rhs ) { return v < rhs; }
|
||||
public boolean lt_b( double rhs ) { return v < rhs; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? TRUE: FALSE; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
|
||||
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
|
||||
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
|
||||
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); }
|
||||
public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
|
||||
public boolean lteq_b( int rhs ) { return v <= rhs; }
|
||||
public boolean lteq_b( double rhs ) { return v <= rhs; }
|
||||
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? TRUE: FALSE; }
|
||||
public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
|
||||
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
|
||||
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
|
||||
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); }
|
||||
public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
|
||||
public boolean gt_b( int rhs ) { return v > rhs; }
|
||||
public boolean gt_b( double rhs ) { return v > rhs; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? TRUE: FALSE; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
|
||||
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
|
||||
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
|
||||
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); }
|
||||
public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
|
||||
public boolean gteq_b( int rhs ) { return v >= rhs; }
|
||||
public boolean gteq_b( double rhs ) { return v >= rhs; }
|
||||
|
||||
// string comparison
|
||||
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
|
||||
|
||||
public int checkint() {
|
||||
return v;
|
||||
public int checkint() {
|
||||
return v;
|
||||
}
|
||||
public long checklong() {
|
||||
return v;
|
||||
return v;
|
||||
}
|
||||
public double checkdouble() {
|
||||
return v;
|
||||
}
|
||||
public String checkjstring() {
|
||||
return String.valueOf(v);
|
||||
public String checkjstring() {
|
||||
return String.valueOf(v);
|
||||
}
|
||||
public LuaString checkstring() {
|
||||
return valueOf( String.valueOf(v) );
|
||||
public LuaString checkstring() {
|
||||
return valueOf( String.valueOf(v) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,28 +31,28 @@ import java.io.PrintStream;
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LuaValue} for representing lua strings.
|
||||
* Subclass of {@link LuaValue} for representing lua strings.
|
||||
* <p>
|
||||
* Because lua string values are more nearly sequences of bytes than
|
||||
* Because lua string values are more nearly sequences of bytes than
|
||||
* sequences of characters or unicode code points, the {@link LuaString}
|
||||
* implementation holds the string value in an internal byte array.
|
||||
* implementation holds the string value in an internal byte array.
|
||||
* <p>
|
||||
* {@link LuaString} values are not considered mutable once constructed,
|
||||
* {@link LuaString} values are not considered mutable once constructed,
|
||||
* so multiple {@link LuaString} values can chare a single byte array.
|
||||
* <p>
|
||||
* Currently {@link LuaString}s are pooled via a centrally managed weak table.
|
||||
* To ensure that as many string values as possible take advantage of this,
|
||||
* Constructors are not exposed directly. As with number, booleans, and nil,
|
||||
* To ensure that as many string values as possible take advantage of this,
|
||||
* Constructors are not exposed directly. As with number, booleans, and nil,
|
||||
* instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API.
|
||||
* <p>
|
||||
* Because of this pooling, users of LuaString <em>must not directly alter the
|
||||
* bytes in a LuaString</em>, or undefined behavior will result.
|
||||
* <p>
|
||||
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
|
||||
* The functions
|
||||
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
|
||||
* The functions
|
||||
* {@link #lengthAsUtf8(char[])},
|
||||
* {@link #encodeToUtf8(char[], int, byte[], int)}, and
|
||||
* {@link #decodeAsUtf8(byte[], int, int)}
|
||||
* {@link #encodeToUtf8(char[], int, byte[], int)}, and
|
||||
* {@link #decodeAsUtf8(byte[], int, int)}
|
||||
* are used to convert back and forth between UTF8 byte arrays and character arrays.
|
||||
*
|
||||
* @see LuaValue
|
||||
@@ -63,15 +63,15 @@ public class LuaString extends LuaValue {
|
||||
|
||||
/** The singleton instance for string metatables that forwards to the string functions.
|
||||
* Typically, this is set to the string metatable as a side effect of loading the string
|
||||
* library, and is read-write to provide flexible behavior by default. When used in a
|
||||
* library, and is read-write to provide flexible behavior by default. When used in a
|
||||
* server environment where there may be roge scripts, this should be replaced with a
|
||||
* read-only table since it is shared across all lua code in this Java VM.
|
||||
*/
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
/** The bytes for the string. These <em><b>must not be mutated directly</b></em> because
|
||||
* the backing may be shared by multiple LuaStrings, and the hash code is
|
||||
* computed only at construction time.
|
||||
* the backing may be shared by multiple LuaStrings, and the hash code is
|
||||
* computed only at construction time.
|
||||
* It is exposed only for performance and legacy reasons. */
|
||||
public final byte[] m_bytes;
|
||||
|
||||
@@ -84,29 +84,29 @@ public class LuaString extends LuaValue {
|
||||
/** The hashcode for this string. Computed at construct time. */
|
||||
private final int m_hashcode;
|
||||
|
||||
/** Size of cache of recent short strings. This is the maximum number of LuaStrings that
|
||||
/** Size of cache of recent short strings. This is the maximum number of LuaStrings that
|
||||
* will be retained in the cache of recent short strings. Exposed to package for testing. */
|
||||
static final int RECENT_STRINGS_CACHE_SIZE = 128;
|
||||
|
||||
/** Maximum length of a string to be considered for recent short strings caching.
|
||||
/** Maximum length of a string to be considered for recent short strings caching.
|
||||
* This effectively limits the total memory that can be spent on the recent strings cache,
|
||||
* because no LuaString whose backing exceeds this length will be put into the cache.
|
||||
* because no LuaString whose backing exceeds this length will be put into the cache.
|
||||
* Exposed to package for testing. */
|
||||
static final int RECENT_STRINGS_MAX_LENGTH = 32;
|
||||
|
||||
/** Simple cache of recently created strings that are short.
|
||||
* This is simply a list of strings, indexed by their hash codes modulo the cache size
|
||||
* that have been recently constructed. If a string is being constructed frequently
|
||||
* from different contexts, it will generally show up as a cache hit and resolve
|
||||
/** Simple cache of recently created strings that are short.
|
||||
* This is simply a list of strings, indexed by their hash codes modulo the cache size
|
||||
* that have been recently constructed. If a string is being constructed frequently
|
||||
* from different contexts, it will generally show up as a cache hit and resolve
|
||||
* to the same value. */
|
||||
private static final class RecentShortStrings {
|
||||
private static final LuaString recent_short_strings[] =
|
||||
private static final LuaString recent_short_strings[] =
|
||||
new LuaString[RECENT_STRINGS_CACHE_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link LuaString} instance whose bytes match
|
||||
* the supplied Java String using the UTF8 encoding.
|
||||
* Get a {@link LuaString} instance whose bytes match
|
||||
* the supplied Java String using the UTF8 encoding.
|
||||
* @param string Java String containing characters to encode as UTF8
|
||||
* @return {@link LuaString} with UTF8 bytes corresponding to the supplied String
|
||||
*/
|
||||
@@ -120,7 +120,7 @@ public class LuaString extends LuaValue {
|
||||
/** Construct a {@link LuaString} for a portion of a byte array.
|
||||
* <p>
|
||||
* The array is first be used as the backing for this object, so clients must not change contents.
|
||||
* If the supplied value for 'len' is more than half the length of the container, the
|
||||
* If the supplied value for 'len' is more than half the length of the container, the
|
||||
* supplied byte array will be used as the backing, otherwise the bytes will be copied to a
|
||||
* new byte array, and cache lookup may be performed.
|
||||
* <p>
|
||||
@@ -144,7 +144,7 @@ public class LuaString extends LuaValue {
|
||||
/** Construct a new LuaString using a copy of the bytes array supplied */
|
||||
private static LuaString valueFromCopy(byte[] bytes, int off, int len) {
|
||||
final byte[] copy = new byte[len];
|
||||
for (int i=0; i<len; ++i) copy[i] = bytes[off+i];
|
||||
System.arraycopy(bytes, off, copy, 0, len);
|
||||
return new LuaString(copy, 0, len);
|
||||
}
|
||||
|
||||
@@ -172,11 +172,11 @@ public class LuaString extends LuaValue {
|
||||
|
||||
/** Construct a {@link LuaString} using the supplied characters as byte values.
|
||||
* <p>
|
||||
* Only the low-order 8-bits of each character are used, the remainder is ignored.
|
||||
* Only the low-order 8-bits of each character are used, the remainder is ignored.
|
||||
* <p>
|
||||
* This is most useful for constructing byte sequences that do not conform to UTF8.
|
||||
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
|
||||
* @return {@link LuaString} wrapping a copy of the byte buffer
|
||||
* This is most useful for constructing byte sequences that do not conform to UTF8.
|
||||
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
|
||||
* @return {@link LuaString} wrapping a copy of the byte buffer
|
||||
*/
|
||||
public static LuaString valueOf(char[] bytes) {
|
||||
return valueOf(bytes, 0, bytes.length);
|
||||
@@ -184,11 +184,11 @@ public class LuaString extends LuaValue {
|
||||
|
||||
/** Construct a {@link LuaString} using the supplied characters as byte values.
|
||||
* <p>
|
||||
* Only the low-order 8-bits of each character are used, the remainder is ignored.
|
||||
* Only the low-order 8-bits of each character are used, the remainder is ignored.
|
||||
* <p>
|
||||
* This is most useful for constructing byte sequences that do not conform to UTF8.
|
||||
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
|
||||
* @return {@link LuaString} wrapping a copy of the byte buffer
|
||||
* This is most useful for constructing byte sequences that do not conform to UTF8.
|
||||
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
|
||||
* @return {@link LuaString} wrapping a copy of the byte buffer
|
||||
*/
|
||||
public static LuaString valueOf(char[] bytes, int off, int len) {
|
||||
byte[] b = new byte[len];
|
||||
@@ -215,7 +215,7 @@ public class LuaString extends LuaValue {
|
||||
* The LuaString returned will either be a new LuaString containing the byte array,
|
||||
* or be an existing LuaString used already having the same value.
|
||||
* <p>
|
||||
* The caller must not mutate the contents of the byte array after this call, as
|
||||
* The caller must not mutate the contents of the byte array after this call, as
|
||||
* it may be used elsewhere due to recent short string caching.
|
||||
* @param bytes byte buffer
|
||||
* @return {@link LuaString} wrapping the byte buffer
|
||||
@@ -241,11 +241,11 @@ public class LuaString extends LuaValue {
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
@@ -289,20 +289,20 @@ public class LuaString extends LuaValue {
|
||||
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); }
|
||||
|
||||
// relational operators, these only work with other strings
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.strcmp(this)>0? LuaValue.TRUE: FALSE; }
|
||||
public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; }
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>0? LuaValue.TRUE: FALSE) : super.lt(rhs); }
|
||||
public boolean lt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>0 : super.lt_b(rhs); }
|
||||
public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE; }
|
||||
public boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE) : super.lteq(rhs); }
|
||||
public boolean lteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>=0 : super.lteq_b(rhs); }
|
||||
public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public LuaValue gt( LuaValue rhs ) { return rhs.strcmp(this)<0? LuaValue.TRUE: FALSE; }
|
||||
public boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; }
|
||||
public LuaValue gt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<0? LuaValue.TRUE: FALSE) : super.gt(rhs); }
|
||||
public boolean gt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<0 : super.gt_b(rhs); }
|
||||
public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE; }
|
||||
public boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE) : super.gteq(rhs); }
|
||||
public boolean gteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<=0 : super.gteq_b(rhs); }
|
||||
public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
|
||||
|
||||
@@ -310,14 +310,14 @@ public class LuaString extends LuaValue {
|
||||
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
|
||||
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
|
||||
public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); }
|
||||
public LuaValue concatTo(LuaString lhs) {
|
||||
public LuaValue concatTo(LuaString lhs) {
|
||||
byte[] b = new byte[lhs.m_length+this.m_length];
|
||||
System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length);
|
||||
System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length);
|
||||
return valueUsing(b, 0, b.length);
|
||||
}
|
||||
|
||||
// string comparison
|
||||
// string comparison
|
||||
public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }
|
||||
public int strcmp(LuaString rhs) {
|
||||
for ( int i=0, j=0; i<m_length && j<rhs.m_length; ++i, ++j ) {
|
||||
@@ -329,9 +329,9 @@ public class LuaString extends LuaValue {
|
||||
}
|
||||
|
||||
/** Check for number in arithmetic, or throw aritherror */
|
||||
private double checkarith() {
|
||||
private double checkarith() {
|
||||
double d = scannumber();
|
||||
if ( Double.isNaN(d) )
|
||||
if ( Double.isNaN(d) )
|
||||
aritherror();
|
||||
return d;
|
||||
}
|
||||
@@ -368,15 +368,15 @@ public class LuaString extends LuaValue {
|
||||
|
||||
public boolean isint() {
|
||||
double d = scannumber();
|
||||
if ( Double.isNaN(d) )
|
||||
if ( Double.isNaN(d) )
|
||||
return false;
|
||||
int i = (int) d;
|
||||
return i == d;
|
||||
}
|
||||
|
||||
public boolean islong() {
|
||||
public boolean islong() {
|
||||
double d = scannumber();
|
||||
if ( Double.isNaN(d) )
|
||||
if ( Double.isNaN(d) )
|
||||
return false;
|
||||
long l = (long) d;
|
||||
return l == d;
|
||||
@@ -391,35 +391,35 @@ public class LuaString extends LuaValue {
|
||||
public short toshort() { return (short) toint(); }
|
||||
|
||||
public double optdouble(double defval) {
|
||||
return checknumber().checkdouble();
|
||||
return checkdouble();
|
||||
}
|
||||
|
||||
public int optint(int defval) {
|
||||
return checknumber().checkint();
|
||||
return checkint();
|
||||
}
|
||||
|
||||
public LuaInteger optinteger(LuaInteger defval) {
|
||||
return checknumber().checkinteger();
|
||||
public LuaInteger optinteger(LuaInteger defval) {
|
||||
return checkinteger();
|
||||
}
|
||||
|
||||
public long optlong(long defval) {
|
||||
return checknumber().checklong();
|
||||
return checklong();
|
||||
}
|
||||
|
||||
public LuaNumber optnumber(LuaNumber defval) {
|
||||
return checknumber().checknumber();
|
||||
return checknumber();
|
||||
}
|
||||
|
||||
public LuaString optstring(LuaString defval) {
|
||||
return this;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue tostring() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String optjstring(String defval) {
|
||||
return tojstring();
|
||||
public String optjstring(String defval) {
|
||||
return tojstring();
|
||||
}
|
||||
|
||||
public LuaString strvalue() {
|
||||
@@ -429,7 +429,7 @@ public class LuaString extends LuaValue {
|
||||
/** Take a substring using Java zero-based indexes for begin and end or range.
|
||||
* @param beginIndex The zero-based index of the first character to include.
|
||||
* @param endIndex The zero-based index of position after the last character.
|
||||
* @return LuaString which is a substring whose first character is at offset
|
||||
* @return LuaString which is a substring whose first character is at offset
|
||||
* beginIndex and extending for (endIndex - beginIndex ) characters.
|
||||
*/
|
||||
public LuaString substring( int beginIndex, int endIndex ) {
|
||||
@@ -476,7 +476,7 @@ public class LuaString extends LuaValue {
|
||||
return val.raweq(this);
|
||||
}
|
||||
|
||||
public boolean raweq( LuaString s ) {
|
||||
public boolean raweq( LuaString s ) {
|
||||
if ( this == s )
|
||||
return true;
|
||||
if ( s.m_length != m_length )
|
||||
@@ -503,7 +503,7 @@ public class LuaString extends LuaValue {
|
||||
public static boolean equals( byte[] a, int i, byte[] b, int j, int n ) {
|
||||
if ( a.length < i + n || b.length < j + n )
|
||||
return false;
|
||||
while ( --n>=0 )
|
||||
while ( --n>=0 )
|
||||
if ( a[i++]!=b[j++] )
|
||||
return false;
|
||||
return true;
|
||||
@@ -535,8 +535,8 @@ public class LuaString extends LuaValue {
|
||||
return luaByte( index );
|
||||
}
|
||||
|
||||
public String checkjstring() {
|
||||
return tojstring();
|
||||
public String checkjstring() {
|
||||
return tojstring();
|
||||
}
|
||||
|
||||
public LuaString checkstring() {
|
||||
@@ -552,7 +552,7 @@ public class LuaString extends LuaValue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the bytes of the string into the given byte array.
|
||||
* Copy the bytes of the string into the given byte array.
|
||||
* @param strOffset offset from which to copy
|
||||
* @param bytes destination byte array
|
||||
* @param arrayOffset offset in destination
|
||||
@@ -626,12 +626,12 @@ public class LuaString extends LuaValue {
|
||||
|
||||
|
||||
/**
|
||||
* Convert to Java String interpreting as utf8 characters.
|
||||
* Convert to Java String interpreting as utf8 characters.
|
||||
*
|
||||
* @param bytes byte array in UTF8 encoding to convert
|
||||
* @param offset starting index in byte array
|
||||
* @param length number of bytes to convert
|
||||
* @return Java String corresponding to the value of bytes interpreted using UTF8
|
||||
* @return Java String corresponding to the value of bytes interpreted using UTF8
|
||||
* @see #lengthAsUtf8(char[])
|
||||
* @see #encodeToUtf8(char[], int, byte[], int)
|
||||
* @see #isValidUtf8()
|
||||
@@ -662,7 +662,7 @@ public class LuaString extends LuaValue {
|
||||
* @see #decodeAsUtf8(byte[], int, int)
|
||||
* @see #isValidUtf8()
|
||||
*/
|
||||
public static int lengthAsUtf8(char[] chars) {
|
||||
public static int lengthAsUtf8(char[] chars) {
|
||||
int i,b;
|
||||
char c;
|
||||
for ( i=b=chars.length; --i>=0; )
|
||||
@@ -673,7 +673,7 @@ public class LuaString extends LuaValue {
|
||||
|
||||
/**
|
||||
* Encode the given Java string as UTF-8 bytes, writing the result to bytes
|
||||
* starting at offset.
|
||||
* starting at offset.
|
||||
* <p>
|
||||
* The string should be measured first with lengthAsUtf8
|
||||
* to make sure the given byte array is large enough.
|
||||
@@ -694,11 +694,11 @@ public class LuaString extends LuaValue {
|
||||
bytes[j++] = (byte) c;
|
||||
} else if ( c < 0x800 ) {
|
||||
bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f));
|
||||
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
|
||||
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
|
||||
} else {
|
||||
bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f));
|
||||
bytes[j++] = (byte) (0x80 | ((c>>6) & 0x3f));
|
||||
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
|
||||
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
|
||||
}
|
||||
}
|
||||
return j - off;
|
||||
@@ -714,12 +714,12 @@ public class LuaString extends LuaValue {
|
||||
for (int i=m_offset,j=m_offset+m_length; i<j;) {
|
||||
int c = m_bytes[i++];
|
||||
if ( c >= 0 ) continue;
|
||||
if ( ((c & 0xE0) == 0xC0)
|
||||
&& i<j
|
||||
if ( ((c & 0xE0) == 0xC0)
|
||||
&& i<j
|
||||
&& (m_bytes[i++] & 0xC0) == 0x80) continue;
|
||||
if ( ((c & 0xF0) == 0xE0)
|
||||
&& i+1<j
|
||||
&& (m_bytes[i++] & 0xC0) == 0x80
|
||||
if ( ((c & 0xF0) == 0xE0)
|
||||
&& i+1<j
|
||||
&& (m_bytes[i++] & 0xC0) == 0x80
|
||||
&& (m_bytes[i++] & 0xC0) == 0x80) continue;
|
||||
return false;
|
||||
}
|
||||
@@ -728,32 +728,32 @@ public class LuaString extends LuaValue {
|
||||
|
||||
// --------------------- number conversion -----------------------
|
||||
|
||||
/**
|
||||
* convert to a number using baee 10 or base 16 if it starts with '0x',
|
||||
/**
|
||||
* convert to a number using baee 10 or base 16 if it starts with '0x',
|
||||
* or NIL if it can't be converted
|
||||
* @return IntValue, DoubleValue, or NIL depending on the content of the string.
|
||||
* @see LuaValue#tonumber()
|
||||
* @see LuaValue#tonumber()
|
||||
*/
|
||||
public LuaValue tonumber() {
|
||||
double d = scannumber();
|
||||
return Double.isNaN(d)? NIL: valueOf(d);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* convert to a number using a supplied base, or NIL if it can't be converted
|
||||
* @param base the base to use, such as 10
|
||||
* @return IntValue, DoubleValue, or NIL depending on the content of the string.
|
||||
* @see LuaValue#tonumber()
|
||||
* @see LuaValue#tonumber()
|
||||
*/
|
||||
public LuaValue tonumber( int base ) {
|
||||
double d = scannumber( base );
|
||||
return Double.isNaN(d)? NIL: valueOf(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a number in base 10, or base 16 if the string starts with '0x',
|
||||
/**
|
||||
* Convert to a number in base 10, or base 16 if the string starts with '0x',
|
||||
* or return Double.NaN if it cannot be converted to a number.
|
||||
* @return double value if conversion is valid, or Double.NaN if not
|
||||
* @return double value if conversion is valid, or Double.NaN if not
|
||||
*/
|
||||
public double scannumber() {
|
||||
int i=m_offset,j=m_offset+m_length;
|
||||
@@ -767,10 +767,10 @@ public class LuaString extends LuaValue {
|
||||
return Double.isNaN(l)? scandouble(i,j): l;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Convert to a number in a base, or return Double.NaN if not a number.
|
||||
* @param base the base to use between 2 and 36
|
||||
* @return double value if conversion is valid, or Double.NaN if not
|
||||
* @return double value if conversion is valid, or Double.NaN if not
|
||||
*/
|
||||
public double scannumber(int base) {
|
||||
if ( base < 2 || base > 36 )
|
||||
@@ -788,7 +788,7 @@ public class LuaString extends LuaValue {
|
||||
* @param base the base to use, such as 10
|
||||
* @param start the index to start searching from
|
||||
* @param end the first index beyond the search range
|
||||
* @return double value if conversion is valid,
|
||||
* @return double value if conversion is valid,
|
||||
* or Double.NaN if not
|
||||
*/
|
||||
private double scanlong( int base, int start, int end ) {
|
||||
@@ -798,7 +798,7 @@ public class LuaString extends LuaValue {
|
||||
int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0':
|
||||
m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
|
||||
if ( digit < 0 || digit >= base )
|
||||
return Double.NaN;
|
||||
return Double.NaN;
|
||||
x = x * base + digit;
|
||||
if ( x < 0 )
|
||||
return Double.NaN; // overflow
|
||||
@@ -810,7 +810,7 @@ public class LuaString extends LuaValue {
|
||||
* Scan and convert a double value, or return Double.NaN if not a double.
|
||||
* @param start the index to start searching from
|
||||
* @param end the first index beyond the search range
|
||||
* @return double value if conversion is valid,
|
||||
* @return double value if conversion is valid,
|
||||
* or Double.NaN if not
|
||||
*/
|
||||
private double scandouble(int start, int end) {
|
||||
@@ -833,7 +833,7 @@ public class LuaString extends LuaValue {
|
||||
c[i-start] = (char) m_bytes[i];
|
||||
try {
|
||||
return Double.parseDouble(new String(c));
|
||||
} catch ( Exception e ) {
|
||||
} catch ( Exception e ) {
|
||||
return Double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,23 +25,23 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LuaValue} for representing lua tables.
|
||||
* Subclass of {@link LuaValue} for representing lua tables.
|
||||
* <p>
|
||||
* Almost all API's implemented in {@link LuaTable} are defined and documented in {@link LuaValue}.
|
||||
* <p>
|
||||
* If a table is needed, the one of the type-checking functions can be used such as
|
||||
* {@link #istable()},
|
||||
* {@link #istable()},
|
||||
* {@link #checktable()}, or
|
||||
* {@link #opttable(LuaTable)}
|
||||
* {@link #opttable(LuaTable)}
|
||||
* <p>
|
||||
* The main table operations are defined on {@link LuaValue}
|
||||
* The main table operations are defined on {@link LuaValue}
|
||||
* for getting and setting values with and without metatag processing:
|
||||
* <ul>
|
||||
* <li>{@link #get(LuaValue)}</li>
|
||||
* <li>{@link #set(LuaValue,LuaValue)}</li>
|
||||
* <li>{@link #rawget(LuaValue)}</li>
|
||||
* <li>{@link #get(LuaValue)}</li>
|
||||
* <li>{@link #set(LuaValue,LuaValue)}</li>
|
||||
* <li>{@link #rawget(LuaValue)}</li>
|
||||
* <li>{@link #rawset(LuaValue,LuaValue)}</li>
|
||||
* <li>plus overloads such as {@link #get(String)}, {@link #get(int)}, and so on</li>
|
||||
* <li>plus overloads such as {@link #get(String)}, {@link #get(int)}, and so on</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* To iterate over key-value pairs from Java, use
|
||||
@@ -56,7 +56,7 @@ import java.util.Vector;
|
||||
* }}</pre>
|
||||
*
|
||||
* <p>
|
||||
* As with other types, {@link LuaTable} instances should be constructed via one of the table constructor
|
||||
* As with other types, {@link LuaTable} instances should be constructed via one of the table constructor
|
||||
* methods on {@link LuaValue}:
|
||||
* <ul>
|
||||
* <li>{@link LuaValue#tableOf()} empty table</li>
|
||||
@@ -92,7 +92,7 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
hash = NOBUCKETS;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Construct table with preset capacity.
|
||||
* @param narray capacity of array part
|
||||
* @param nhash capacity of hash part
|
||||
@@ -102,9 +102,9 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct table with named and unnamed parts.
|
||||
* Construct table with named and unnamed parts.
|
||||
* @param named Named elements in order {@code key-a, value-a, key-b, value-b, ... }
|
||||
* @param unnamed Unnamed elements in order {@code value-1, value-2, ... }
|
||||
* @param unnamed Unnamed elements in order {@code value-1, value-2, ... }
|
||||
* @param lastarg Additional unnamed values beyond {@code unnamed.length}
|
||||
*/
|
||||
public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) {
|
||||
@@ -123,17 +123,17 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct table of unnamed elements.
|
||||
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
|
||||
* Construct table of unnamed elements.
|
||||
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
|
||||
*/
|
||||
public LuaTable(Varargs varargs) {
|
||||
this(varargs,1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct table of unnamed elements.
|
||||
* Construct table of unnamed elements.
|
||||
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
|
||||
* @param firstarg the index in varargs of the first argument to include in the table
|
||||
* @param firstarg the index in varargs of the first argument to include in the table
|
||||
*/
|
||||
public LuaTable(Varargs varargs, int firstarg) {
|
||||
int nskip = firstarg-1;
|
||||
@@ -152,8 +152,8 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
return "table";
|
||||
}
|
||||
|
||||
public boolean istable() {
|
||||
return true;
|
||||
public boolean istable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaTable checktable() {
|
||||
@@ -185,17 +185,17 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of the array part of the table.
|
||||
* @return length of the array part, does not relate to count of objects in the table.
|
||||
/**
|
||||
* Get the length of the array part of the table.
|
||||
* @return length of the array part, does not relate to count of objects in the table.
|
||||
*/
|
||||
protected int getArrayLength() {
|
||||
return array.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of the hash part of the table.
|
||||
* @return length of the hash part, does not relate to count of objects in the table.
|
||||
/**
|
||||
* Get the length of the hash part of the table.
|
||||
* @return length of the hash part, does not relate to count of objects in the table.
|
||||
*/
|
||||
protected int getHashLength() {
|
||||
return hash.length;
|
||||
@@ -266,8 +266,8 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
|
||||
/** caller must ensure key is not nil */
|
||||
public void set( LuaValue key, LuaValue value ) {
|
||||
if (!key.isvalidkey() && !metatag(NEWINDEX).isfunction())
|
||||
typerror("table index");
|
||||
if (key == null || !key.isvalidkey() && !metatag(NEWINDEX).isfunction())
|
||||
throw new LuaError("value ('" + key + "') can not be used as a table index");
|
||||
if ( m_metatable==null || ! rawget(key).isnil() || ! settable(this,key,value) )
|
||||
rawset(key, value);
|
||||
}
|
||||
@@ -294,35 +294,35 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
|
||||
/** Remove the element at a position in a list-table
|
||||
*
|
||||
*
|
||||
* @param pos the position to remove
|
||||
* @return The removed item, or {@link #NONE} if not removed
|
||||
*/
|
||||
public LuaValue remove(int pos) {
|
||||
int n = rawlen();
|
||||
int n = length();
|
||||
if ( pos == 0 )
|
||||
pos = n;
|
||||
else if (pos > n)
|
||||
return NONE;
|
||||
LuaValue v = rawget(pos);
|
||||
LuaValue v = get(pos);
|
||||
for ( LuaValue r=v; !r.isnil(); ) {
|
||||
r = rawget(pos+1);
|
||||
rawset(pos++, r);
|
||||
r = get(pos+1);
|
||||
set(pos++, r);
|
||||
}
|
||||
return v.isnil()? NONE: v;
|
||||
}
|
||||
|
||||
/** Insert an element at a position in a list-table
|
||||
*
|
||||
*
|
||||
* @param pos the position to remove
|
||||
* @param value The value to insert
|
||||
*/
|
||||
public void insert(int pos, LuaValue value) {
|
||||
if ( pos == 0 )
|
||||
pos = rawlen()+1;
|
||||
pos = length()+1;
|
||||
while ( ! value.isnil() ) {
|
||||
LuaValue v = rawget( pos );
|
||||
rawset(pos++, value);
|
||||
LuaValue v = get( pos );
|
||||
set(pos++, value);
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
@@ -347,17 +347,22 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return m_metatable != null? len().toint(): rawlen();
|
||||
if (m_metatable != null) {
|
||||
LuaValue len = len();
|
||||
if (!len.isint()) throw new LuaError("table length is not an integer: " + len);
|
||||
return len.toint();
|
||||
}
|
||||
return rawlen();
|
||||
}
|
||||
|
||||
public LuaValue len() {
|
||||
public LuaValue len() {
|
||||
final LuaValue h = metatag(LEN);
|
||||
if (h.toboolean())
|
||||
return h.call(this);
|
||||
return LuaInteger.valueOf(rawlen());
|
||||
}
|
||||
|
||||
public int rawlen() {
|
||||
public int rawlen() {
|
||||
int a = getArrayLength();
|
||||
int n = a+1,m=0;
|
||||
while ( !rawget(n).isnil() ) {
|
||||
@@ -375,7 +380,7 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next element after a particular key in the table
|
||||
* Get the next element after a particular key in the table
|
||||
* @return key,value or nil
|
||||
*/
|
||||
public Varargs next( LuaValue key ) {
|
||||
@@ -390,7 +395,7 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
}
|
||||
if ( hash.length == 0 )
|
||||
error( "invalid key to 'next'" );
|
||||
error( "invalid key to 'next' 1: " + key );
|
||||
i = hashSlot( key );
|
||||
boolean found = false;
|
||||
for ( Slot slot = hash[i]; slot != null; slot = slot.rest() ) {
|
||||
@@ -404,7 +409,7 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
}
|
||||
if ( !found ) {
|
||||
error( "invalid key to 'next'" );
|
||||
error( "invalid key to 'next' 2: " + key );
|
||||
}
|
||||
i += 1+array.length;
|
||||
}
|
||||
@@ -436,8 +441,8 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next element after a particular key in the
|
||||
* contiguous array part of a table
|
||||
* Get the next element after a particular key in the
|
||||
* contiguous array part of a table
|
||||
* @return key,value or none
|
||||
*/
|
||||
public Varargs inext(LuaValue key) {
|
||||
@@ -467,7 +472,8 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
}
|
||||
if ( checkLoadFactor() ) {
|
||||
if ( key.isinttype() && key.toint() > 0 ) {
|
||||
if ( (m_metatable == null || !m_metatable.useWeakValues())
|
||||
&& key.isinttype() && key.toint() > 0 ) {
|
||||
// a rehash might make room in the array portion for this key.
|
||||
rehash( key.toint() );
|
||||
if ( arrayset(key.toint(), value) )
|
||||
@@ -512,7 +518,7 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Find the hashtable slot to use
|
||||
* @param key key to look for
|
||||
* @return slot to use
|
||||
@@ -714,7 +720,7 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
StrongSlot entry = slot.first();
|
||||
if (entry != null)
|
||||
newArray[ k - 1 ] = entry.value();
|
||||
} else {
|
||||
} else if ( !(slot instanceof DeadSlot) ) {
|
||||
int j = slot.keyindex( newHashMask );
|
||||
newHash[j] = slot.relink( newHash[j] );
|
||||
}
|
||||
@@ -774,42 +780,45 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
//
|
||||
// implemented heap sort from wikipedia
|
||||
//
|
||||
// Only sorts the contiguous array part.
|
||||
// Only sorts the contiguous array part.
|
||||
//
|
||||
/** Sort the table using a comparator.
|
||||
* @param comparator {@link LuaValue} to be called to compare elements.
|
||||
*/
|
||||
public void sort(LuaValue comparator) {
|
||||
if (len().tolong() >= (long)Integer.MAX_VALUE) throw new LuaError("array too big: " + len().tolong());
|
||||
if (m_metatable != null && m_metatable.useWeakValues()) {
|
||||
dropWeakArrayValues();
|
||||
}
|
||||
int n = array.length;
|
||||
while ( n > 0 && array[n-1] == null )
|
||||
--n;
|
||||
if ( n > 1 )
|
||||
heapSort(n, comparator);
|
||||
int n = length();
|
||||
if ( n > 1 )
|
||||
heapSort(n, comparator.isnil() ? null : comparator);
|
||||
}
|
||||
|
||||
private void heapSort(int count, LuaValue cmpfunc) {
|
||||
heapify(count, cmpfunc);
|
||||
for ( int end=count-1; end>0; ) {
|
||||
swap(end, 0);
|
||||
siftDown(0, --end, cmpfunc);
|
||||
for ( int end=count; end>1; ) {
|
||||
LuaValue a = get(end); // swap(end, 1)
|
||||
set(end, get(1));
|
||||
set(1, a);
|
||||
siftDown(1, --end, cmpfunc);
|
||||
}
|
||||
}
|
||||
|
||||
private void heapify(int count, LuaValue cmpfunc) {
|
||||
for ( int start=count/2-1; start>=0; --start )
|
||||
siftDown(start, count - 1, cmpfunc);
|
||||
for ( int start=count/2; start>0; --start )
|
||||
siftDown(start, count, cmpfunc);
|
||||
}
|
||||
|
||||
private void siftDown(int start, int end, LuaValue cmpfunc) {
|
||||
for ( int root=start; root*2+1 <= end; ) {
|
||||
int child = root*2+1;
|
||||
for ( int root=start; root*2 <= end; ) {
|
||||
int child = root*2;
|
||||
if (child < end && compare(child, child + 1, cmpfunc))
|
||||
++child;
|
||||
++child;
|
||||
if (compare(root, child, cmpfunc)) {
|
||||
swap(root, child);
|
||||
LuaValue a = get(root); // swap(root, child)
|
||||
set(root, get(child));
|
||||
set(child, a);
|
||||
root = child;
|
||||
} else
|
||||
return;
|
||||
@@ -817,32 +826,19 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
|
||||
private boolean compare(int i, int j, LuaValue cmpfunc) {
|
||||
LuaValue a, b;
|
||||
if (m_metatable == null) {
|
||||
a = array[i];
|
||||
b = array[j];
|
||||
} else {
|
||||
a = m_metatable.arrayget(array, i);
|
||||
b = m_metatable.arrayget(array, j);
|
||||
}
|
||||
LuaValue a = get(i), b = get(j);
|
||||
if ( a == null || b == null )
|
||||
return false;
|
||||
if ( ! cmpfunc.isnil() ) {
|
||||
if ( cmpfunc != null ) {
|
||||
return cmpfunc.call(a,b).toboolean();
|
||||
} else {
|
||||
return a.lt_b(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void swap(int i, int j) {
|
||||
LuaValue a = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = a;
|
||||
}
|
||||
|
||||
/** This may be deprecated in a future release.
|
||||
/** This may be deprecated in a future release.
|
||||
* It is recommended to count via iteration over next() instead
|
||||
* @return count of keys in the table
|
||||
* @return count of keys in the table
|
||||
* */
|
||||
public int keyCount() {
|
||||
LuaValue k = LuaValue.NIL;
|
||||
@@ -853,9 +849,9 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
}
|
||||
|
||||
/** This may be deprecated in a future release.
|
||||
* It is recommended to use next() instead
|
||||
* @return array of keys in the table
|
||||
/** This may be deprecated in a future release.
|
||||
* It is recommended to use next() instead
|
||||
* @return array of keys in the table
|
||||
* */
|
||||
public LuaValue[] keys() {
|
||||
Vector l = new Vector();
|
||||
@@ -892,6 +888,11 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
|
||||
/** Unpack the elements from i to j inclusive */
|
||||
public Varargs unpack(int i, int j) {
|
||||
if (j < i) return NONE;
|
||||
int count = j - i;
|
||||
if (count < 0) throw new LuaError("too many results to unpack: greater " + Integer.MAX_VALUE); // integer overflow
|
||||
int max = 0x00ffffff;
|
||||
if (count >= max) throw new LuaError("too many results to unpack: " + count + " (max is " + max + ')');
|
||||
int n = j + 1 - i;
|
||||
switch (n) {
|
||||
case 0: return NONE;
|
||||
@@ -900,10 +901,14 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
default:
|
||||
if (n < 0)
|
||||
return NONE;
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
while (--n >= 0)
|
||||
v[n] = get(i+n);
|
||||
return varargsOf(v);
|
||||
try {
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
while (--n >= 0)
|
||||
v[n] = get(i+n);
|
||||
return varargsOf(v);
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw new LuaError("too many results to unpack [out of memory]: " + n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1231,13 +1236,14 @@ public class LuaTable extends LuaValue implements Metatable {
|
||||
}
|
||||
|
||||
public Entry set(LuaValue value) {
|
||||
LuaValue n = value.tonumber();
|
||||
if ( !n.isnil() ) {
|
||||
this.value = n.todouble();
|
||||
return this;
|
||||
} else {
|
||||
return new NormalEntry( this.key, value );
|
||||
if (value.type() == TNUMBER) {
|
||||
LuaValue n = value.tonumber();
|
||||
if (!n.isnil()) {
|
||||
this.value = n.todouble();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
return new NormalEntry( this.key, value );
|
||||
}
|
||||
|
||||
public int keyindex( int mask ) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -128,6 +128,10 @@ public class Print extends Lua {
|
||||
}
|
||||
|
||||
static void printValue( PrintStream ps, LuaValue v ) {
|
||||
if (v == null) {
|
||||
ps.print("null");
|
||||
return;
|
||||
}
|
||||
switch ( v.type() ) {
|
||||
case LuaValue.TSTRING: printString( ps, (LuaString) v ); break;
|
||||
default: ps.print( v.tojstring() );
|
||||
@@ -136,7 +140,7 @@ public class Print extends Lua {
|
||||
}
|
||||
|
||||
static void printConstant(PrintStream ps, Prototype f, int i) {
|
||||
printValue( ps, f.k[i] );
|
||||
printValue( ps, i < f.k.length ? f.k[i] : LuaValue.valueOf("UNKNOWN_CONST_" + i) );
|
||||
}
|
||||
|
||||
static void printUpvalue(PrintStream ps, Upvaldesc u) {
|
||||
@@ -152,7 +156,7 @@ public class Print extends Lua {
|
||||
int[] code = f.code;
|
||||
int pc, n = code.length;
|
||||
for (pc = 0; pc < n; pc++) {
|
||||
printOpCode(f, pc);
|
||||
pc = printOpCode(f, pc);
|
||||
ps.println();
|
||||
}
|
||||
}
|
||||
@@ -161,9 +165,10 @@ public class Print extends Lua {
|
||||
* Print an opcode in a prototype
|
||||
* @param f the {@link Prototype}
|
||||
* @param pc the program counter to look up and print
|
||||
* @return pc same as above or changed
|
||||
*/
|
||||
public static void printOpCode(Prototype f, int pc) {
|
||||
printOpCode(ps,f,pc);
|
||||
public static int printOpCode(Prototype f, int pc) {
|
||||
return printOpCode(ps,f,pc);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,8 +176,9 @@ public class Print extends Lua {
|
||||
* @param ps the {@link PrintStream} to print to
|
||||
* @param f the {@link Prototype}
|
||||
* @param pc the program counter to look up and print
|
||||
* @return pc same as above or changed
|
||||
*/
|
||||
public static void printOpCode(PrintStream ps, Prototype f, int pc) {
|
||||
public static int printOpCode(PrintStream ps, Prototype f, int pc) {
|
||||
int[] code = f.code;
|
||||
int i = code[pc];
|
||||
int o = GET_OPCODE(i);
|
||||
@@ -187,80 +193,67 @@ public class Print extends Lua {
|
||||
ps.print("[" + line + "] ");
|
||||
else
|
||||
ps.print("[-] ");
|
||||
ps.print(OPNAMES[o] + " ");
|
||||
switch (getOpMode(o)) {
|
||||
case iABC:
|
||||
ps.print( a );
|
||||
if (getBMode(o) != OpArgN)
|
||||
ps.print(" "+(ISK(b) ? (-1 - INDEXK(b)) : b));
|
||||
if (getCMode(o) != OpArgN)
|
||||
ps.print(" "+(ISK(c) ? (-1 - INDEXK(c)) : c));
|
||||
break;
|
||||
case iABx:
|
||||
if (getBMode(o) == OpArgK) {
|
||||
ps.print(a + " " + (-1 - bx));
|
||||
} else {
|
||||
ps.print(a + " " + (bx));
|
||||
if (o >= OPNAMES.length - 1) {
|
||||
ps.print("UNKNOWN_OP_" + o + " ");
|
||||
} else {
|
||||
ps.print(OPNAMES[o] + " ");
|
||||
switch (getOpMode(o)) {
|
||||
case iABC:
|
||||
ps.print( a );
|
||||
if (getBMode(o) != OpArgN)
|
||||
ps.print(" "+(ISK(b) ? (-1 - INDEXK(b)) : b));
|
||||
if (getCMode(o) != OpArgN)
|
||||
ps.print(" "+(ISK(c) ? (-1 - INDEXK(c)) : c));
|
||||
break;
|
||||
case iABx:
|
||||
if (getBMode(o) == OpArgK) {
|
||||
ps.print(a + " " + (-1 - bx));
|
||||
} else {
|
||||
ps.print(a + " " + (bx));
|
||||
}
|
||||
break;
|
||||
case iAsBx:
|
||||
if (o == OP_JMP)
|
||||
ps.print( sbx );
|
||||
else
|
||||
ps.print(a + " " + sbx);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case iAsBx:
|
||||
if (o == OP_JMP)
|
||||
ps.print( sbx );
|
||||
else
|
||||
ps.print(a + " " + sbx);
|
||||
break;
|
||||
}
|
||||
switch (o) {
|
||||
case OP_LOADK:
|
||||
ps.print(" ; ");
|
||||
printConstant(ps, f, bx);
|
||||
break;
|
||||
case OP_GETUPVAL:
|
||||
case OP_SETUPVAL:
|
||||
ps.print(" ; ");
|
||||
printUpvalue(ps, f.upvalues[b]);
|
||||
break;
|
||||
case OP_GETTABUP:
|
||||
ps.print(" ; ");
|
||||
printUpvalue(ps, f.upvalues[b]);
|
||||
ps.print(" ");
|
||||
if (ISK(c))
|
||||
printConstant(ps, f, INDEXK(c));
|
||||
else
|
||||
ps.print("-");
|
||||
break;
|
||||
case OP_SETTABUP:
|
||||
ps.print(" ; ");
|
||||
printUpvalue(ps, f.upvalues[a]);
|
||||
ps.print(" ");
|
||||
if (ISK(b))
|
||||
printConstant(ps, f, INDEXK(b));
|
||||
else
|
||||
ps.print("-");
|
||||
ps.print(" ");
|
||||
if (ISK(c))
|
||||
printConstant(ps, f, INDEXK(c));
|
||||
else
|
||||
ps.print("-");
|
||||
break;
|
||||
case OP_GETTABLE:
|
||||
case OP_SELF:
|
||||
if (ISK(c)) {
|
||||
switch (o) {
|
||||
case OP_LOADK:
|
||||
ps.print(" ; ");
|
||||
printConstant(ps, f, INDEXK(c));
|
||||
}
|
||||
break;
|
||||
case OP_SETTABLE:
|
||||
case OP_ADD:
|
||||
case OP_SUB:
|
||||
case OP_MUL:
|
||||
case OP_DIV:
|
||||
case OP_POW:
|
||||
case OP_EQ:
|
||||
case OP_LT:
|
||||
case OP_LE:
|
||||
if (ISK(b) || ISK(c)) {
|
||||
printConstant(ps, f, bx);
|
||||
break;
|
||||
case OP_GETUPVAL:
|
||||
case OP_SETUPVAL:
|
||||
ps.print(" ; ");
|
||||
if (b < f.upvalues.length) {
|
||||
printUpvalue(ps, f.upvalues[b]);
|
||||
} else {
|
||||
ps.print("UNKNOWN_UPVALUE_" + b);
|
||||
}
|
||||
break;
|
||||
case OP_GETTABUP:
|
||||
ps.print(" ; ");
|
||||
if (b < f.upvalues.length) {
|
||||
printUpvalue(ps, f.upvalues[b]);
|
||||
} else {
|
||||
ps.print("UNKNOWN_UPVALUE_" + b);
|
||||
}
|
||||
ps.print(" ");
|
||||
if (ISK(c))
|
||||
printConstant(ps, f, INDEXK(c));
|
||||
else
|
||||
ps.print("-");
|
||||
break;
|
||||
case OP_SETTABUP:
|
||||
ps.print(" ; ");
|
||||
if (a < f.upvalues.length) {
|
||||
printUpvalue(ps, f.upvalues[a]);
|
||||
} else {
|
||||
ps.print("UNKNOWN_UPVALUE_" + a);
|
||||
}
|
||||
ps.print(" ");
|
||||
if (ISK(b))
|
||||
printConstant(ps, f, INDEXK(b));
|
||||
else
|
||||
@@ -270,28 +263,62 @@ public class Print extends Lua {
|
||||
printConstant(ps, f, INDEXK(c));
|
||||
else
|
||||
ps.print("-");
|
||||
break;
|
||||
case OP_GETTABLE:
|
||||
case OP_SELF:
|
||||
if (ISK(c)) {
|
||||
ps.print(" ; ");
|
||||
printConstant(ps, f, INDEXK(c));
|
||||
}
|
||||
break;
|
||||
case OP_SETTABLE:
|
||||
case OP_ADD:
|
||||
case OP_SUB:
|
||||
case OP_MUL:
|
||||
case OP_DIV:
|
||||
case OP_POW:
|
||||
case OP_EQ:
|
||||
case OP_LT:
|
||||
case OP_LE:
|
||||
if (ISK(b) || ISK(c)) {
|
||||
ps.print(" ; ");
|
||||
if (ISK(b))
|
||||
printConstant(ps, f, INDEXK(b));
|
||||
else
|
||||
ps.print("-");
|
||||
ps.print(" ");
|
||||
if (ISK(c))
|
||||
printConstant(ps, f, INDEXK(c));
|
||||
else
|
||||
ps.print("-");
|
||||
}
|
||||
break;
|
||||
case OP_JMP:
|
||||
case OP_FORLOOP:
|
||||
case OP_FORPREP:
|
||||
ps.print(" ; to " + (sbx + pc + 2));
|
||||
break;
|
||||
case OP_CLOSURE:
|
||||
if (bx < f.p.length) {
|
||||
ps.print(" ; " + f.p[bx].getClass().getName());
|
||||
} else {
|
||||
ps.print(" ; UNKNOWN_PROTYPE_" + bx);
|
||||
}
|
||||
break;
|
||||
case OP_SETLIST:
|
||||
if (c == 0)
|
||||
ps.print(" ; " + ((int) code[++pc]) + " (stored in the next OP)");
|
||||
else
|
||||
ps.print(" ; " + ((int) c));
|
||||
break;
|
||||
case OP_VARARG:
|
||||
ps.print( " ; is_vararg="+ f.is_vararg );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OP_JMP:
|
||||
case OP_FORLOOP:
|
||||
case OP_FORPREP:
|
||||
ps.print(" ; to " + (sbx + pc + 2));
|
||||
break;
|
||||
case OP_CLOSURE:
|
||||
ps.print(" ; " + f.p[bx].getClass().getName());
|
||||
break;
|
||||
case OP_SETLIST:
|
||||
if (c == 0)
|
||||
ps.print(" ; " + ((int) code[++pc]));
|
||||
else
|
||||
ps.print(" ; " + ((int) c));
|
||||
break;
|
||||
case OP_VARARG:
|
||||
ps.print( " ; is_vararg="+ f.is_vararg );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
|
||||
private static int getline(Prototype f, int pc) {
|
||||
|
||||
@@ -24,16 +24,16 @@ package org.luaj.vm2;
|
||||
/**
|
||||
* Class to encapsulate varargs values, either as part of a variable argument list, or multiple return values.
|
||||
* <p>
|
||||
* To construct varargs, use one of the static methods such as
|
||||
* To construct varargs, use one of the static methods such as
|
||||
* {@code LuaValue.varargsOf(LuaValue,LuaValue)}
|
||||
* <p>
|
||||
* <p>
|
||||
* Any LuaValue can be used as a stand-in for Varargs, for both calls and return values.
|
||||
* When doing so, nargs() will return 1 and arg1() or arg(1) will return this.
|
||||
* This simplifies the case when calling or implementing varargs functions with only
|
||||
* 1 argument or 1 return value.
|
||||
* Any LuaValue can be used as a stand-in for Varargs, for both calls and return values.
|
||||
* When doing so, nargs() will return 1 and arg1() or arg(1) will return this.
|
||||
* This simplifies the case when calling or implementing varargs functions with only
|
||||
* 1 argument or 1 return value.
|
||||
* <p>
|
||||
* Varargs can also be derived from other varargs by appending to the front with a call
|
||||
* Varargs can also be derived from other varargs by appending to the front with a call
|
||||
* such as {@code LuaValue.varargsOf(LuaValue,Varargs)}
|
||||
* or by taking a portion of the args using {@code Varargs.subargs(int start)}
|
||||
* <p>
|
||||
@@ -57,22 +57,22 @@ public abstract class Varargs {
|
||||
abstract public LuaValue arg( int i );
|
||||
|
||||
/**
|
||||
* Get the number of arguments, or 0 if there are none.
|
||||
* @return number of arguments.
|
||||
* Get the number of arguments, or 0 if there are none.
|
||||
* @return number of arguments.
|
||||
*/
|
||||
abstract public int narg();
|
||||
|
||||
/**
|
||||
* Get the first argument in the list.
|
||||
* Get the first argument in the list.
|
||||
* @return LuaValue which is first in the list, or LuaValue.NIL if there are no values.
|
||||
* @see Varargs#arg(int)
|
||||
* @see LuaValue#NIL
|
||||
*/
|
||||
abstract public LuaValue arg1();
|
||||
|
||||
/**
|
||||
/**
|
||||
* Evaluate any pending tail call and return result.
|
||||
* @return the evaluated tail call result
|
||||
* @return the evaluated tail call result
|
||||
*/
|
||||
public Varargs eval() { return this; }
|
||||
|
||||
@@ -88,7 +88,7 @@ public abstract class Varargs {
|
||||
// utilities to get specific arguments and type-check them.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/** Gets the type of argument {@code i}
|
||||
/** Gets the type of argument {@code i}
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return int value corresponding to one of the LuaValue integer type values
|
||||
* @see LuaValue#TNIL
|
||||
@@ -117,20 +117,20 @@ public abstract class Varargs {
|
||||
public boolean isfunction(int i) { return arg(i).isfunction(); }
|
||||
|
||||
/** Tests if argument i is a number.
|
||||
* Since anywhere a number is required, a string can be used that
|
||||
* is a number, this will return true for both numbers and
|
||||
* strings that can be interpreted as numbers.
|
||||
* Since anywhere a number is required, a string can be used that
|
||||
* is a number, this will return true for both numbers and
|
||||
* strings that can be interpreted as numbers.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if the argument exists and is a number or
|
||||
* @return true if the argument exists and is a number or
|
||||
* string that can be interpreted as a number, false otherwise
|
||||
* @see LuaValue#TNUMBER
|
||||
* @see LuaValue#TSTRING
|
||||
* */
|
||||
public boolean isnumber(int i) { return arg(i).isnumber(); }
|
||||
|
||||
/** Tests if argument i is a string.
|
||||
* Since all lua numbers can be used where strings are used,
|
||||
* this will return true for both strings and numbers.
|
||||
/** Tests if argument i is a string.
|
||||
* Since all lua numbers can be used where strings are used,
|
||||
* this will return true for both strings and numbers.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if the argument exists and is a string or number, false otherwise
|
||||
* @see LuaValue#TNUMBER
|
||||
@@ -167,7 +167,7 @@ public abstract class Varargs {
|
||||
|
||||
/** Return argument i as a boolean value, {@code defval} if nil, or throw a LuaError if any other type.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if argument i is boolean true, false if it is false, or defval if not supplied or nil
|
||||
* @return true if argument i is boolean true, false if it is false, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a lua boolean
|
||||
* */
|
||||
public boolean optboolean(int i, boolean defval) { return arg(i).optboolean(defval); }
|
||||
@@ -256,7 +256,7 @@ public abstract class Varargs {
|
||||
* */
|
||||
public Object optuserdata(int i, Object defval) { return arg(i).optuserdata(defval); }
|
||||
|
||||
/** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
|
||||
/** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
|
||||
* {@code defval} if nil, or throw a LuaError if any other type.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @param c the class to which the userdata instance must be assignable
|
||||
@@ -291,7 +291,7 @@ public abstract class Varargs {
|
||||
* @return java double value if argument i is a number or string that converts to a number
|
||||
* @exception LuaError if the argument is not a number
|
||||
* */
|
||||
public double checkdouble(int i) { return arg(i).checknumber().todouble(); }
|
||||
public double checkdouble(int i) { return arg(i).checkdouble(); }
|
||||
|
||||
/** Return argument i as a function, or throw an error if an incompatible type.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
@@ -300,12 +300,12 @@ public abstract class Varargs {
|
||||
* */
|
||||
public LuaFunction checkfunction(int i) { return arg(i).checkfunction(); }
|
||||
|
||||
/** Return argument i as a java int value, discarding any fractional part, or throw an error if not a number.
|
||||
/** Return argument i as a java int value, or throw an error if it cannot be converted to one.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return int value with fraction discarded and truncated if necessary if argument i is number
|
||||
* @exception LuaError if the argument is not a number
|
||||
* @return int value if argument i is a number or string that converts to a number
|
||||
* @exception LuaError if the argument cannot be represented by a java int value
|
||||
* */
|
||||
public int checkint(int i) { return arg(i).checknumber().toint(); }
|
||||
public int checkint(int i) { return arg(i).checkint(); }
|
||||
|
||||
/** Return argument i as a java int value, or throw an error if not a number or is not representable by a java int.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
@@ -314,12 +314,12 @@ public abstract class Varargs {
|
||||
* */
|
||||
public LuaInteger checkinteger(int i) { return arg(i).checkinteger(); }
|
||||
|
||||
/** Return argument i as a java long value, discarding any fractional part, or throw an error if not a number.
|
||||
/** Return argument i as a java long value, or throw an error if it cannot be converted to one.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return long value with fraction discarded and truncated if necessary if argument i is number
|
||||
* @exception LuaError if the argument is not a number
|
||||
* @return long value if argument i is a number or string that converts to a number
|
||||
* @exception LuaError if the argument cannot be represented by a java long value
|
||||
* */
|
||||
public long checklong(int i) { return arg(i).checknumber().tolong(); }
|
||||
public long checklong(int i) { return arg(i).checklong(); }
|
||||
|
||||
/** Return argument i as a LuaNumber, or throw an error if not a number or string that can be converted to a number.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
@@ -363,7 +363,7 @@ public abstract class Varargs {
|
||||
* */
|
||||
public Object checkuserdata(int i) { return arg(i).checkuserdata(); }
|
||||
|
||||
/** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
|
||||
/** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
|
||||
* or throw an error if any other type.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @param c the class to which the userdata instance must be assignable
|
||||
@@ -387,7 +387,7 @@ public abstract class Varargs {
|
||||
public LuaValue checknotnil(int i) { return arg(i).checknotnil(); }
|
||||
|
||||
/** Performs test on argument i as a LuaValue when a user-supplied assertion passes, or throw an error.
|
||||
* Returns normally if the value of {@code test} is {@code true}, otherwise throws and argument error with
|
||||
* Returns normally if the value of {@code test} is {@code true}, otherwise throws and argument error with
|
||||
* the supplied message, {@code msg}.
|
||||
* @param test user supplied assertion to test against
|
||||
* @param i the index to report in any error message
|
||||
@@ -404,20 +404,20 @@ public abstract class Varargs {
|
||||
return i>narg() || arg(i).isnil();
|
||||
}
|
||||
|
||||
/** Convert argument {@code i} to java boolean based on lua rules for boolean evaluation.
|
||||
/** Convert argument {@code i} to java boolean based on lua rules for boolean evaluation.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return {@code false} if argument i is nil or false, otherwise {@code true}
|
||||
* */
|
||||
public boolean toboolean(int i) { return arg(i).toboolean(); }
|
||||
|
||||
/** Return argument i as a java byte value, discarding any fractional part and truncating,
|
||||
/** Return argument i as a java byte value, discarding any fractional part and truncating,
|
||||
* or 0 if not a number.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return byte value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
|
||||
* */
|
||||
public byte tobyte(int i) { return arg(i).tobyte(); }
|
||||
|
||||
/** Return argument i as a java char value, discarding any fractional part and truncating,
|
||||
/** Return argument i as a java char value, discarding any fractional part and truncating,
|
||||
* or 0 if not a number.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return char value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
|
||||
@@ -430,21 +430,21 @@ public abstract class Varargs {
|
||||
* */
|
||||
public double todouble(int i) { return arg(i).todouble(); }
|
||||
|
||||
/** Return argument i as a java float value, discarding excess fractional part and truncating,
|
||||
/** Return argument i as a java float value, discarding excess fractional part and truncating,
|
||||
* or 0 if not a number.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return float value with excess fraction discarded and truncated if necessary if argument i is number, otherwise 0
|
||||
* */
|
||||
public float tofloat(int i) { return arg(i).tofloat(); }
|
||||
|
||||
/** Return argument i as a java int value, discarding any fractional part and truncating,
|
||||
/** Return argument i as a java int value, discarding any fractional part and truncating,
|
||||
* or 0 if not a number.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return int value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
|
||||
* */
|
||||
public int toint(int i) { return arg(i).toint(); }
|
||||
|
||||
/** Return argument i as a java long value, discarding any fractional part and truncating,
|
||||
/** Return argument i as a java long value, discarding any fractional part and truncating,
|
||||
* or 0 if not a number.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return long value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
|
||||
@@ -457,7 +457,7 @@ public abstract class Varargs {
|
||||
* */
|
||||
public String tojstring(int i) { return arg(i).tojstring(); }
|
||||
|
||||
/** Return argument i as a java short value, discarding any fractional part and truncating,
|
||||
/** Return argument i as a java short value, discarding any fractional part and truncating,
|
||||
* or 0 if not a number.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return short value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
|
||||
@@ -477,8 +477,8 @@ public abstract class Varargs {
|
||||
* */
|
||||
public Object touserdata(int i,Class c) { return arg(i).touserdata(c); }
|
||||
|
||||
/** Convert the list of varargs values to a human readable java String.
|
||||
* @return String value in human readable form such as {1,2}.
|
||||
/** Convert the list of varargs values to a human readable java String.
|
||||
* @return String value in human readable form such as {1,2}.
|
||||
*/
|
||||
public String tojstring() {
|
||||
Buffer sb = new Buffer();
|
||||
@@ -491,8 +491,8 @@ public abstract class Varargs {
|
||||
return sb.tojstring();
|
||||
}
|
||||
|
||||
/** Convert the value or values to a java String using Varargs.tojstring()
|
||||
* @return String value in human readable form.
|
||||
/** Convert the value or values to a java String using Varargs.tojstring()
|
||||
* @return String value in human readable form.
|
||||
* @see Varargs#tojstring()
|
||||
*/
|
||||
public String toString() { return tojstring(); }
|
||||
@@ -544,21 +544,21 @@ public abstract class Varargs {
|
||||
}
|
||||
}
|
||||
|
||||
/** Varargs implemenation backed by two values.
|
||||
/** Varargs implemenation backed by two values.
|
||||
* <p>
|
||||
* This is an internal class not intended to be used directly.
|
||||
* Instead use the corresponding static method on LuaValue.
|
||||
*
|
||||
* Instead use the corresponding static method on LuaValue.
|
||||
*
|
||||
* @see LuaValue#varargsOf(LuaValue, Varargs)
|
||||
*/
|
||||
static final class PairVarargs extends Varargs {
|
||||
private final LuaValue v1;
|
||||
private final Varargs v2;
|
||||
/** Construct a Varargs from an two LuaValue.
|
||||
/** Construct a Varargs from an two LuaValue.
|
||||
* <p>
|
||||
* This is an internal class not intended to be used directly.
|
||||
* Instead use the corresponding static method on LuaValue.
|
||||
*
|
||||
* Instead use the corresponding static method on LuaValue.
|
||||
*
|
||||
* @see LuaValue#varargsOf(LuaValue, Varargs)
|
||||
*/
|
||||
PairVarargs(LuaValue v1, Varargs v2) {
|
||||
@@ -571,8 +571,8 @@ public abstract class Varargs {
|
||||
public int narg() {
|
||||
return 1+v2.narg();
|
||||
}
|
||||
public LuaValue arg1() {
|
||||
return v1;
|
||||
public LuaValue arg1() {
|
||||
return v1;
|
||||
}
|
||||
public Varargs subargs(final int start) {
|
||||
if (start == 1)
|
||||
@@ -585,22 +585,22 @@ public abstract class Varargs {
|
||||
}
|
||||
}
|
||||
|
||||
/** Varargs implemenation backed by an array of LuaValues
|
||||
/** Varargs implemenation backed by an array of LuaValues
|
||||
* <p>
|
||||
* This is an internal class not intended to be used directly.
|
||||
* Instead use the corresponding static methods on LuaValue.
|
||||
*
|
||||
* Instead use the corresponding static methods on LuaValue.
|
||||
*
|
||||
* @see LuaValue#varargsOf(LuaValue[])
|
||||
* @see LuaValue#varargsOf(LuaValue[], Varargs)
|
||||
*/
|
||||
static final class ArrayVarargs extends Varargs {
|
||||
private final LuaValue[] v;
|
||||
private final Varargs r;
|
||||
/** Construct a Varargs from an array of LuaValue.
|
||||
/** Construct a Varargs from an array of LuaValue.
|
||||
* <p>
|
||||
* This is an internal class not intended to be used directly.
|
||||
* Instead use the corresponding static methods on LuaValue.
|
||||
*
|
||||
* Instead use the corresponding static methods on LuaValue.
|
||||
*
|
||||
* @see LuaValue#varargsOf(LuaValue[])
|
||||
* @see LuaValue#varargsOf(LuaValue[], Varargs)
|
||||
*/
|
||||
@@ -631,11 +631,11 @@ public abstract class Varargs {
|
||||
}
|
||||
}
|
||||
|
||||
/** Varargs implemenation backed by an array of LuaValues
|
||||
/** Varargs implemenation backed by an array of LuaValues
|
||||
* <p>
|
||||
* This is an internal class not intended to be used directly.
|
||||
* Instead use the corresponding static methods on LuaValue.
|
||||
*
|
||||
* Instead use the corresponding static methods on LuaValue.
|
||||
*
|
||||
* @see LuaValue#varargsOf(LuaValue[], int, int)
|
||||
* @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
|
||||
*/
|
||||
@@ -644,11 +644,11 @@ public abstract class Varargs {
|
||||
private final LuaValue[] v;
|
||||
private final int length;
|
||||
private final Varargs more;
|
||||
/** Construct a Varargs from an array of LuaValue.
|
||||
/** Construct a Varargs from an array of LuaValue.
|
||||
* <p>
|
||||
* This is an internal class not intended to be used directly.
|
||||
* Instead use the corresponding static methods on LuaValue.
|
||||
*
|
||||
* Instead use the corresponding static methods on LuaValue.
|
||||
*
|
||||
* @see LuaValue#varargsOf(LuaValue[], int, int)
|
||||
*/
|
||||
ArrayPartVarargs(LuaValue[] v, int offset, int length) {
|
||||
@@ -657,11 +657,11 @@ public abstract class Varargs {
|
||||
this.length = length;
|
||||
this.more = LuaValue.NONE;
|
||||
}
|
||||
/** Construct a Varargs from an array of LuaValue and additional arguments.
|
||||
/** Construct a Varargs from an array of LuaValue and additional arguments.
|
||||
* <p>
|
||||
* This is an internal class not intended to be used directly.
|
||||
* Instead use the corresponding static method on LuaValue.
|
||||
*
|
||||
* Instead use the corresponding static method on LuaValue.
|
||||
*
|
||||
* @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
|
||||
*/
|
||||
public ArrayPartVarargs(LuaValue[] v, int offset, int length, Varargs more) {
|
||||
@@ -676,8 +676,8 @@ public abstract class Varargs {
|
||||
public int narg() {
|
||||
return length + more.narg();
|
||||
}
|
||||
public LuaValue arg1() {
|
||||
return length>0? v[offset]: more.arg1();
|
||||
public LuaValue arg1() {
|
||||
return length>0? v[offset]: more.arg1();
|
||||
}
|
||||
public Varargs subargs(int start) {
|
||||
if (start <= 0)
|
||||
@@ -707,8 +707,10 @@ public abstract class Varargs {
|
||||
/** Return Varargs that cannot be using a shared array for the storage, and is flattened.
|
||||
* Internal utility method not intended to be called directly from user code.
|
||||
* @return Varargs containing same values, but flattened and with a new array if needed.
|
||||
* @exclude
|
||||
* @hide
|
||||
*/
|
||||
Varargs dealias() {
|
||||
public Varargs dealias() {
|
||||
int n = narg();
|
||||
switch (n) {
|
||||
case 0: return LuaValue.NONE;
|
||||
|
||||
@@ -46,20 +46,20 @@ public class Constants extends Lua {
|
||||
|
||||
|
||||
/* OpMode - basic instruction format */
|
||||
static final int
|
||||
static final int
|
||||
iABC = 0,
|
||||
iABx = 1,
|
||||
iAsBx = 2;
|
||||
|
||||
/* OpArgMask */
|
||||
static final int
|
||||
static final int
|
||||
OpArgN = 0, /* argument is not used */
|
||||
OpArgU = 1, /* argument is used */
|
||||
OpArgR = 2, /* argument is a register or a jump offset */
|
||||
OpArgK = 3; /* argument is a constant or register/constant */
|
||||
|
||||
|
||||
protected static void _assert(boolean b) {
|
||||
protected static void _assert(boolean b) {
|
||||
if (!b)
|
||||
throw new LuaError("compiler assert failed");
|
||||
}
|
||||
@@ -104,6 +104,11 @@ public class Constants extends Lua {
|
||||
((a << POS_A) & MASK_A) |
|
||||
((bc << POS_Bx) & MASK_Bx) ;
|
||||
}
|
||||
|
||||
static int CREATE_Ax(int o, int a) {
|
||||
return ((o << POS_OP) & MASK_OP) |
|
||||
((a << POS_Ax) & MASK_Ax) ;
|
||||
}
|
||||
|
||||
// vector reallocation
|
||||
|
||||
@@ -150,7 +155,7 @@ public class Constants extends Lua {
|
||||
}
|
||||
|
||||
static LexState.Labeldesc[] grow(LexState.Labeldesc[] v, int min_n) {
|
||||
return v == null ? new LexState.Labeldesc[2] : v.length < min_n ? realloc(v, v.length*2) : v;
|
||||
return v == null ? new LexState.Labeldesc[2] : v.length < min_n ? realloc(v, v.length*2) : v;
|
||||
}
|
||||
|
||||
static LexState.Labeldesc[] realloc(LexState.Labeldesc[] v, int n) {
|
||||
|
||||
@@ -28,14 +28,14 @@ import java.io.OutputStream;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LocVars;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
|
||||
|
||||
/** Class to dump a {@link Prototype} into an output stream, as part of compiling.
|
||||
* <p>
|
||||
* Generally, this class is not used directly, but rather indirectly via a command
|
||||
* Generally, this class is not used directly, but rather indirectly via a command
|
||||
* line interface tool such as {@link luac}.
|
||||
* <p>
|
||||
* A lua binary file is created via {@link DumpState#dump}:
|
||||
@@ -85,7 +85,7 @@ public class DumpState {
|
||||
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
|
||||
|
||||
// header fields
|
||||
private boolean IS_LITTLE_ENDIAN = false;
|
||||
private boolean IS_LITTLE_ENDIAN = true;
|
||||
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
|
||||
private int SIZEOF_LUA_NUMBER = 8;
|
||||
private static final int SIZEOF_INT = 4;
|
||||
@@ -190,7 +190,7 @@ public class DumpState {
|
||||
dumpString((LuaString)o);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("bad type for " + o);
|
||||
throw new IllegalArgumentException("bad type for " + o);
|
||||
}
|
||||
}
|
||||
n = f.p.length;
|
||||
|
||||
@@ -50,7 +50,6 @@ public class FuncState extends Constants {
|
||||
Hashtable h; /* table to find (and reuse) elements in `k' */
|
||||
FuncState prev; /* enclosing function */
|
||||
LexState ls; /* lexical state */
|
||||
LuaC.CompileState L; /* compiler being invoked */
|
||||
BlockCnt bl; /* chain of current blocks */
|
||||
int pc; /* next position to code (equivalent to `ncode') */
|
||||
int lasttarget; /* `pc' of last `jump target' */
|
||||
@@ -113,8 +112,8 @@ public class FuncState extends Constants {
|
||||
void errorlimit (int limit, String what) {
|
||||
// TODO: report message logic.
|
||||
String msg = (f.linedefined == 0) ?
|
||||
L.pushfstring("main function has more than "+limit+" "+what) :
|
||||
L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
|
||||
ls.L.pushfstring("main function has more than "+limit+" "+what) :
|
||||
ls.L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
|
||||
ls.lexerror(msg, 0);
|
||||
}
|
||||
|
||||
@@ -296,7 +295,7 @@ public class FuncState extends Constants {
|
||||
}
|
||||
} /* else go through */
|
||||
}
|
||||
this.codeABC(OP_LOADNIL, from, n - 1, 0);
|
||||
this.codeABC(OP_LOADNIL, from, n - 1, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -478,7 +477,7 @@ public class FuncState extends Constants {
|
||||
this.h = new Hashtable();
|
||||
} else if (this.h.containsKey(v)) {
|
||||
return ((Integer) h.get(v)).intValue();
|
||||
}
|
||||
}
|
||||
final int idx = this.nk;
|
||||
this.h.put(v, new Integer(idx));
|
||||
final Prototype f = this.f;
|
||||
@@ -496,7 +495,7 @@ public class FuncState extends Constants {
|
||||
if ( r instanceof LuaDouble ) {
|
||||
double d = r.todouble();
|
||||
int i = (int) d;
|
||||
if ( d == (double) i )
|
||||
if ( d == (double) i )
|
||||
r = LuaInteger.valueOf(i);
|
||||
}
|
||||
return this.addk(r);
|
||||
@@ -581,11 +580,11 @@ public class FuncState extends Constants {
|
||||
break;
|
||||
}
|
||||
case LexState.VK: {
|
||||
this.codeABx(OP_LOADK, reg, e.u.info);
|
||||
this.codeK(reg, e.u.info);
|
||||
break;
|
||||
}
|
||||
case LexState.VKNUM: {
|
||||
this.codeABx(OP_LOADK, reg, this.numberK(e.u.nval()));
|
||||
this.codeK(reg, this.numberK(e.u.nval()));
|
||||
break;
|
||||
}
|
||||
case LexState.VRELOCABLE: {
|
||||
@@ -688,7 +687,7 @@ public class FuncState extends Constants {
|
||||
case LexState.VKNUM: {
|
||||
e.u.info = this.numberK(e.u.nval());
|
||||
e.k = LexState.VK;
|
||||
/* go through */
|
||||
/* go through */
|
||||
}
|
||||
case LexState.VK: {
|
||||
if (e.u.info <= MAXINDEXRK) /* constant fit in argC? */
|
||||
@@ -1117,6 +1116,20 @@ public class FuncState extends Constants {
|
||||
return this.code(CREATE_ABx(o, a, bc), this.ls.lastline);
|
||||
}
|
||||
|
||||
int codeextraarg(int a) {
|
||||
_assert(a <= MAXARG_Ax);
|
||||
return this.code(CREATE_Ax(OP_EXTRAARG, a), this.ls.lastline);
|
||||
}
|
||||
|
||||
int codeK(int reg, int k) {
|
||||
if (k <= MAXARG_Bx)
|
||||
return codeABx(OP_LOADK, reg, k);
|
||||
else {
|
||||
int p = codeABx(OP_LOADKX, reg, 0);
|
||||
codeextraarg(k);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
void setlist(int base, int nelems, int tostore) {
|
||||
int c = (nelems - 1) / LFIELDS_PER_FLUSH + 1;
|
||||
|
||||
@@ -62,14 +62,14 @@ public class LexState extends Constants {
|
||||
|
||||
private static final int EOZ = (-1);
|
||||
private static final int MAX_INT = Integer.MAX_VALUE-2;
|
||||
private static final int UCHAR_MAX = 255; // TODO, convert to unicode CHAR_MAX?
|
||||
private static final int UCHAR_MAX = 255; // TODO, convert to unicode CHAR_MAX?
|
||||
private static final int LUAI_MAXCCALLS = 200;
|
||||
|
||||
private static final String LUA_QS(String s) { return "'"+s+"'"; }
|
||||
private static final String LUA_QL(Object o) { return LUA_QS(String.valueOf(o)); }
|
||||
|
||||
private static final int LUA_COMPAT_LSTR = 1; // 1 for compatibility, 2 for old behavior
|
||||
private static final boolean LUA_COMPAT_VARARG = true;
|
||||
private static final boolean LUA_COMPAT_VARARG = true;
|
||||
|
||||
public static boolean isReservedKeyword(String varName) {
|
||||
return RESERVED_LOCAL_VAR_KEYWORDS_TABLE.containsKey(varName);
|
||||
@@ -84,7 +84,7 @@ public class LexState extends Constants {
|
||||
/*
|
||||
** grep "ORDER OPR" if you change these enums
|
||||
*/
|
||||
static final int
|
||||
static final int
|
||||
OPR_ADD=0, OPR_SUB=1, OPR_MUL=2, OPR_DIV=3, OPR_MOD=4, OPR_POW=5,
|
||||
OPR_CONCAT=6,
|
||||
OPR_NE=7, OPR_EQ=8,
|
||||
@@ -92,11 +92,11 @@ public class LexState extends Constants {
|
||||
OPR_AND=13, OPR_OR=14,
|
||||
OPR_NOBINOPR=15;
|
||||
|
||||
static final int
|
||||
static final int
|
||||
OPR_MINUS=0, OPR_NOT=1, OPR_LEN=2, OPR_NOUNOPR=3;
|
||||
|
||||
/* exp kind */
|
||||
static final int
|
||||
static final int
|
||||
VVOID = 0, /* no value */
|
||||
VNIL = 1,
|
||||
VTRUE = 2,
|
||||
@@ -153,14 +153,14 @@ public class LexState extends Constants {
|
||||
"::", "<eos>", "<number>", "<name>", "<string>", "<eof>",
|
||||
};
|
||||
|
||||
final static int
|
||||
final static int
|
||||
/* terminal symbols denoted by reserved words */
|
||||
TK_AND=257, TK_BREAK=258, TK_DO=259, TK_ELSE=260, TK_ELSEIF=261,
|
||||
TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_GOTO=266, TK_IF=267,
|
||||
TK_AND=257, TK_BREAK=258, TK_DO=259, TK_ELSE=260, TK_ELSEIF=261,
|
||||
TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_GOTO=266, TK_IF=267,
|
||||
TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273,
|
||||
TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278,
|
||||
/* other terminal symbols */
|
||||
TK_CONCAT=279, TK_DOTS=280, TK_EQ=281, TK_GE=282, TK_LE=283, TK_NE=284,
|
||||
TK_CONCAT=279, TK_DOTS=280, TK_EQ=281, TK_GE=282, TK_LE=283, TK_NE=284,
|
||||
TK_DBCOLON=285, TK_EOS=286, TK_NUMBER=287, TK_NAME=288, TK_STRING=289;
|
||||
|
||||
final static int FIRST_RESERVED = TK_AND;
|
||||
@@ -175,7 +175,7 @@ public class LexState extends Constants {
|
||||
}
|
||||
|
||||
private boolean isalnum(int c) {
|
||||
return (c >= '0' && c <= '9')
|
||||
return (c >= '0' && c <= '9')
|
||||
|| (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (c == '_');
|
||||
@@ -188,17 +188,17 @@ public class LexState extends Constants {
|
||||
}
|
||||
|
||||
private boolean isdigit(int c) {
|
||||
return (c >= '0' && c <= '9');
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
private boolean isxdigit(int c) {
|
||||
return (c >= '0' && c <= '9')
|
||||
|| (c >= 'a' && c <= 'f')
|
||||
|| (c >= 'A' && c <= 'F');
|
||||
|| (c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
private boolean isspace(int c) {
|
||||
return (c <= ' ');
|
||||
return (c >= 0 && c <= ' ');
|
||||
}
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ public class LexState extends Constants {
|
||||
|
||||
String token2str( int token ) {
|
||||
if ( token < FIRST_RESERVED ) {
|
||||
return iscntrl(token)?
|
||||
return iscntrl(token)?
|
||||
L.pushfstring( "char("+((int)token)+")" ):
|
||||
L.pushfstring( String.valueOf( (char) token ) );
|
||||
} else {
|
||||
@@ -388,8 +388,13 @@ public class LexState extends Constants {
|
||||
seminfo.r = LuaValue.ZERO;
|
||||
else if (str.indexOf('x')>=0 || str.indexOf('X')>=0)
|
||||
seminfo.r = strx2number(str, seminfo);
|
||||
else
|
||||
seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim()));
|
||||
else {
|
||||
try {
|
||||
seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim()));
|
||||
} catch (NumberFormatException e) {
|
||||
lexerror("malformed number (" + e.getMessage() + ")", TK_NUMBER);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -408,7 +413,6 @@ public class LexState extends Constants {
|
||||
else
|
||||
break;
|
||||
}
|
||||
save('\0');
|
||||
String str = new String(buff, 0, nbuff);
|
||||
str2d(str, seminfo);
|
||||
}
|
||||
@@ -585,6 +589,13 @@ public class LexState extends Constants {
|
||||
inclinenumber();
|
||||
continue;
|
||||
}
|
||||
case ' ':
|
||||
case '\f':
|
||||
case '\t':
|
||||
case 0x0B: /* \v */ {
|
||||
nextChar();
|
||||
continue;
|
||||
}
|
||||
case '-': {
|
||||
nextChar();
|
||||
if (current != '-')
|
||||
@@ -688,19 +699,12 @@ public class LexState extends Constants {
|
||||
return TK_EOS;
|
||||
}
|
||||
default: {
|
||||
if (isspace(current)) {
|
||||
_assert (!currIsNewline());
|
||||
nextChar();
|
||||
continue;
|
||||
} else if (isdigit(current)) {
|
||||
read_numeral(seminfo);
|
||||
return TK_NUMBER;
|
||||
} else if (isalpha(current) || current == '_') {
|
||||
if (isalpha(current) || current == '_') {
|
||||
/* identifier or reserved word */
|
||||
LuaString ts;
|
||||
do {
|
||||
save_and_next();
|
||||
} while (isalnum(current) || current == '_');
|
||||
} while (isalnum(current));
|
||||
ts = newstring(buff, 0, nbuff);
|
||||
if ( RESERVED.containsKey(ts) )
|
||||
return ((Integer)RESERVED.get(ts)).intValue();
|
||||
@@ -821,7 +825,7 @@ public class LexState extends Constants {
|
||||
|
||||
/* dynamic structures used by the parser */
|
||||
static class Dyndata {
|
||||
Vardesc[] actvar; /* list of active local variables */
|
||||
Vardesc[] actvar; /* list of active local variables */
|
||||
int n_actvar = 0;
|
||||
Labeldesc[] gt; /* list of pending gotos */
|
||||
int n_gt = 0;
|
||||
@@ -1610,7 +1614,7 @@ public class LexState extends Constants {
|
||||
switch (t.token) {
|
||||
case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOS:
|
||||
return true;
|
||||
case TK_UNTIL:
|
||||
case TK_UNTIL:
|
||||
return withuntil;
|
||||
default: return false;
|
||||
}
|
||||
@@ -1634,7 +1638,7 @@ public class LexState extends Constants {
|
||||
static class LHS_assign {
|
||||
LHS_assign prev;
|
||||
/* variable (global, local, upvalue, or indexed) */
|
||||
expdesc v = new expdesc();
|
||||
expdesc v = new expdesc();
|
||||
};
|
||||
|
||||
|
||||
@@ -1744,7 +1748,7 @@ public class LexState extends Constants {
|
||||
fs.checkrepeated(dyd.label, dyd.n_label, label); /* check for repeated labels */
|
||||
checknext(TK_DBCOLON); /* skip double colon */
|
||||
/* create new entry for this label */
|
||||
l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.pc);
|
||||
l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.getlabel());
|
||||
skipnoopstat(); /* skip other no-op statements */
|
||||
if (block_follow(false)) { /* label is last no-op statement in the block? */
|
||||
/* assume that locals are already out of scope */
|
||||
@@ -1845,7 +1849,7 @@ public class LexState extends Constants {
|
||||
if (this.testnext(','))
|
||||
this.exp1(); /* optional step */
|
||||
else { /* default step = 1 */
|
||||
fs.codeABx(Lua.OP_LOADK, fs.freereg, fs.numberK(LuaInteger.valueOf(1)));
|
||||
fs.codeK(fs.freereg, fs.numberK(LuaInteger.valueOf(1)));
|
||||
fs.reserveregs(1);
|
||||
}
|
||||
this.forbody(base, line, 1, true);
|
||||
|
||||
@@ -117,7 +117,7 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
|
||||
protected CompileState() {}
|
||||
|
||||
/** Parse the input */
|
||||
private Prototype luaY_parser(InputStream z, String name) throws IOException{
|
||||
Prototype luaY_parser(InputStream z, String name) throws IOException{
|
||||
LexState lexstate = new LexState(this, z);
|
||||
FuncState funcstate = new FuncState();
|
||||
// lexstate.buff = buff;
|
||||
|
||||
@@ -1,483 +1,485 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua basic library functions.
|
||||
* <p>
|
||||
* This contains all library functions listed as "basic functions" in the lua documentation for JME.
|
||||
* The functions dofile and loadfile use the
|
||||
* {@link Globals#finder} instance to find resource files.
|
||||
* Since JME has no file system by default, {@link BaseLib} implements
|
||||
* {@link ResourceFinder} using {@link Class#getResource(String)},
|
||||
* which is the closest equivalent on JME.
|
||||
* The default loader chain in {@link PackageLib} will use these as well.
|
||||
* <p>
|
||||
* To use basic library functions that include a {@link ResourceFinder} based on
|
||||
* directory lookup, use {@link org.luaj.vm2.lib.jse.JseBaseLib} instead.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
|
||||
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* globals.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* <p>
|
||||
* This is a direct port of the corresponding library in C.
|
||||
* @see org.luaj.vm2.lib.jse.JseBaseLib
|
||||
* @see ResourceFinder
|
||||
* @see Globals#finder
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.lib.jse.JsePlatform
|
||||
* @see org.luaj.vm2.lib.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib Reference</a>
|
||||
*/
|
||||
public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
||||
|
||||
Globals globals;
|
||||
|
||||
|
||||
/** Perform one-time initialization on the library by adding base functions
|
||||
* to the supplied environment, and returning it as the return value.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, which must be a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
globals = env.checkglobals();
|
||||
globals.finder = this;
|
||||
globals.baselib = this;
|
||||
env.set( "_G", env );
|
||||
env.set( "_VERSION", Lua._VERSION );
|
||||
env.set("assert", new _assert());
|
||||
env.set("collectgarbage", new collectgarbage());
|
||||
env.set("dofile", new dofile());
|
||||
env.set("error", new error());
|
||||
env.set("getmetatable", new getmetatable());
|
||||
env.set("load", new load());
|
||||
env.set("loadfile", new loadfile());
|
||||
env.set("pcall", new pcall());
|
||||
env.set("print", new print(this));
|
||||
env.set("rawequal", new rawequal());
|
||||
env.set("rawget", new rawget());
|
||||
env.set("rawlen", new rawlen());
|
||||
env.set("rawset", new rawset());
|
||||
env.set("select", new select());
|
||||
env.set("setmetatable", new setmetatable());
|
||||
env.set("tonumber", new tonumber());
|
||||
env.set("tostring", new tostring());
|
||||
env.set("type", new type());
|
||||
env.set("xpcall", new xpcall());
|
||||
|
||||
next next;
|
||||
env.set("next", next = new next());
|
||||
env.set("pairs", new pairs(next));
|
||||
env.set("ipairs", new ipairs());
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
/** ResourceFinder implementation
|
||||
*
|
||||
* Tries to open the file as a resource, which can work for JSE and JME.
|
||||
*/
|
||||
public InputStream findResource(String filename) {
|
||||
return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
|
||||
}
|
||||
|
||||
|
||||
// "assert", // ( v [,message] ) -> v, message | ERR
|
||||
static final class _assert extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
if ( !args.arg1().toboolean() )
|
||||
error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" );
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
// "collectgarbage", // ( opt [,arg] ) -> value
|
||||
static final class collectgarbage extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
String s = args.optjstring(1, "collect");
|
||||
if ( "collect".equals(s) ) {
|
||||
System.gc();
|
||||
return ZERO;
|
||||
} else if ( "count".equals(s) ) {
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
long used = rt.totalMemory() - rt.freeMemory();
|
||||
return varargsOf(valueOf(used/1024.), valueOf(used%1024));
|
||||
} else if ( "step".equals(s) ) {
|
||||
System.gc();
|
||||
return LuaValue.TRUE;
|
||||
} else {
|
||||
this.argerror("gc op");
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
// "dofile", // ( filename ) -> result1, ...
|
||||
final class dofile extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
|
||||
String filename = args.isstring(1)? args.tojstring(1): null;
|
||||
Varargs v = filename == null?
|
||||
loadStream( globals.STDIN, "=stdin", "bt", globals ):
|
||||
loadFile( args.checkjstring(1), "bt", globals );
|
||||
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
|
||||
}
|
||||
}
|
||||
|
||||
// "error", // ( message [,level] ) -> ERR
|
||||
static final class error extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
throw arg1.isnil()? new LuaError(null, arg2.optint(1)):
|
||||
arg1.isstring()? new LuaError(arg1.tojstring(), arg2.optint(1)):
|
||||
new LuaError(arg1);
|
||||
}
|
||||
}
|
||||
|
||||
// "getmetatable", // ( object ) -> table
|
||||
static final class getmetatable extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "value");
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaValue mt = arg.getmetatable();
|
||||
return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL;
|
||||
}
|
||||
}
|
||||
// "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
|
||||
final class load extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue ld = args.arg1();
|
||||
args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function");
|
||||
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
|
||||
String mode = args.optjstring(3, "bt");
|
||||
LuaValue env = args.optvalue(4, globals);
|
||||
return loadStream(ld.isstring()? ld.strvalue().toInputStream():
|
||||
new StringInputStream(ld.checkfunction()), source, mode, env);
|
||||
}
|
||||
}
|
||||
|
||||
// "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
|
||||
final class loadfile extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
|
||||
String filename = args.isstring(1)? args.tojstring(1): null;
|
||||
String mode = args.optjstring(2, "bt");
|
||||
LuaValue env = args.optvalue(3, globals);
|
||||
return filename == null?
|
||||
loadStream( globals.STDIN, "=stdin", mode, env ):
|
||||
loadFile( filename, mode, env );
|
||||
}
|
||||
}
|
||||
|
||||
// "pcall", // (f, arg1, ...) -> status, result1, ...
|
||||
final class pcall extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue func = args.checkvalue(1);
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onCall(this);
|
||||
try {
|
||||
return varargsOf(TRUE, func.invoke(args.subargs(2)));
|
||||
} catch ( LuaError le ) {
|
||||
final LuaValue m = le.getMessageObject();
|
||||
return varargsOf(FALSE, m!=null? m: NIL);
|
||||
} catch ( Exception e ) {
|
||||
final String m = e.getMessage();
|
||||
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
|
||||
} finally {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onReturn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "print", // (...) -> void
|
||||
final class print extends VarArgFunction {
|
||||
final BaseLib baselib;
|
||||
print(BaseLib baselib) {
|
||||
this.baselib = baselib;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue tostring = globals.get("tostring");
|
||||
for ( int i=1, n=args.narg(); i<=n; i++ ) {
|
||||
if ( i>1 ) globals.STDOUT.print( '\t' );
|
||||
LuaString s = tostring.call( args.arg(i) ).strvalue();
|
||||
globals.STDOUT.print(s.tojstring());
|
||||
}
|
||||
globals.STDOUT.println();
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// "rawequal", // (v1, v2) -> boolean
|
||||
static final class rawequal extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "value");
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return argerror(2, "value");
|
||||
}
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return valueOf(arg1.raweq(arg2));
|
||||
}
|
||||
}
|
||||
|
||||
// "rawget", // (table, index) -> value
|
||||
static final class rawget extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "value");
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return argerror(2, "value");
|
||||
}
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return arg1.checktable().rawget(arg2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// "rawlen", // (v) -> value
|
||||
static final class rawlen extends LibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return valueOf(arg.rawlen());
|
||||
}
|
||||
}
|
||||
|
||||
// "rawset", // (table, index, value) -> table
|
||||
static final class rawset extends LibFunction {
|
||||
public LuaValue call(LuaValue table) {
|
||||
return argerror(2,"value");
|
||||
}
|
||||
public LuaValue call(LuaValue table, LuaValue index) {
|
||||
return argerror(3,"value");
|
||||
}
|
||||
public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
|
||||
LuaTable t = table.checktable();
|
||||
t.rawset(index.checknotnil(), value);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
// "select", // (f, ...) -> value1, ...
|
||||
static final class select extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int n = args.narg()-1;
|
||||
if ( args.arg1().equals(valueOf("#")) )
|
||||
return valueOf(n);
|
||||
int i = args.checkint(1);
|
||||
if ( i == 0 || i < -n )
|
||||
argerror(1,"index out of range");
|
||||
return args.subargs(i<0? n+i+2: i+1);
|
||||
}
|
||||
}
|
||||
|
||||
// "setmetatable", // (table, metatable) -> table
|
||||
static final class setmetatable extends LibFunction {
|
||||
public LuaValue call(LuaValue table) {
|
||||
return argerror(2,"value");
|
||||
}
|
||||
public LuaValue call(LuaValue table, LuaValue metatable) {
|
||||
final LuaValue mt0 = table.checktable().getmetatable();
|
||||
if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
|
||||
error("cannot change a protected metatable");
|
||||
return table.setmetatable(metatable.isnil()? null: metatable.checktable());
|
||||
}
|
||||
}
|
||||
|
||||
// "tonumber", // (e [,base]) -> value
|
||||
static final class tonumber extends LibFunction {
|
||||
public LuaValue call(LuaValue e) {
|
||||
return e.tonumber();
|
||||
}
|
||||
public LuaValue call(LuaValue e, LuaValue base) {
|
||||
if (base.isnil())
|
||||
return e.tonumber();
|
||||
final int b = base.checkint();
|
||||
if ( b < 2 || b > 36 )
|
||||
argerror(2, "base out of range");
|
||||
return e.checkstring().tonumber(b);
|
||||
}
|
||||
}
|
||||
|
||||
// "tostring", // (e) -> value
|
||||
static final class tostring extends LibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaValue h = arg.metatag(TOSTRING);
|
||||
if ( ! h.isnil() )
|
||||
return h.call(arg);
|
||||
LuaValue v = arg.tostring();
|
||||
if ( ! v.isnil() )
|
||||
return v;
|
||||
return valueOf(arg.tojstring());
|
||||
}
|
||||
}
|
||||
|
||||
// "type", // (v) -> value
|
||||
static final class type extends LibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return valueOf(arg.typename());
|
||||
}
|
||||
}
|
||||
|
||||
// "xpcall", // (f, err) -> result1, ...
|
||||
final class xpcall extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
final LuaThread t = globals.running;
|
||||
final LuaValue preverror = t.errorfunc;
|
||||
t.errorfunc = args.checkvalue(2);
|
||||
try {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onCall(this);
|
||||
try {
|
||||
return varargsOf(TRUE, args.arg1().invoke(args.subargs(3)));
|
||||
} catch ( LuaError le ) {
|
||||
final LuaValue m = le.getMessageObject();
|
||||
return varargsOf(FALSE, m!=null? m: NIL);
|
||||
} catch ( Exception e ) {
|
||||
final String m = e.getMessage();
|
||||
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
|
||||
} finally {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onReturn();
|
||||
}
|
||||
} finally {
|
||||
t.errorfunc = preverror;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "pairs" (t) -> iter-func, t, nil
|
||||
static final class pairs extends VarArgFunction {
|
||||
final next next;
|
||||
pairs(next next) {
|
||||
this.next = next;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
return varargsOf( next, args.checktable(1), NIL );
|
||||
}
|
||||
}
|
||||
|
||||
// // "ipairs", // (t) -> iter-func, t, 0
|
||||
static final class ipairs extends VarArgFunction {
|
||||
inext inext = new inext();
|
||||
public Varargs invoke(Varargs args) {
|
||||
return varargsOf( inext, args.checktable(1), ZERO );
|
||||
}
|
||||
}
|
||||
|
||||
// "next" ( table, [index] ) -> next-index, next-value
|
||||
static final class next extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
return args.checktable(1).next(args.arg(2));
|
||||
}
|
||||
}
|
||||
|
||||
// "inext" ( table, [int-index] ) -> next-index, next-value
|
||||
static final class inext extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
return args.checktable(1).inext(args.arg(2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a named file, returning the chunk or nil,error of can't load
|
||||
* @param env
|
||||
* @param mode
|
||||
* @return Varargs containing chunk, or NIL,error-text on error
|
||||
*/
|
||||
public Varargs loadFile(String filename, String mode, LuaValue env) {
|
||||
InputStream is = globals.finder.findResource(filename);
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory"));
|
||||
try {
|
||||
return loadStream(is, "@"+filename, mode, env);
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) {
|
||||
try {
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("not found: "+chunkname));
|
||||
return globals.load(is, chunkname, mode, env);
|
||||
} catch (Exception e) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StringInputStream extends InputStream {
|
||||
final LuaValue func;
|
||||
byte[] bytes;
|
||||
int offset, remaining = 0;
|
||||
StringInputStream(LuaValue func) {
|
||||
this.func = func;
|
||||
}
|
||||
public int read() throws IOException {
|
||||
if ( remaining <= 0 ) {
|
||||
LuaValue s = func.call();
|
||||
if ( s.isnil() )
|
||||
return -1;
|
||||
LuaString ls = s.strvalue();
|
||||
bytes = ls.m_bytes;
|
||||
offset = ls.m_offset;
|
||||
remaining = ls.m_length;
|
||||
if (remaining <= 0)
|
||||
return -1;
|
||||
}
|
||||
--remaining;
|
||||
return bytes[offset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua basic library functions.
|
||||
* <p>
|
||||
* This contains all library functions listed as "basic functions" in the lua documentation for JME.
|
||||
* The functions dofile and loadfile use the
|
||||
* {@link Globals#finder} instance to find resource files.
|
||||
* Since JME has no file system by default, {@link BaseLib} implements
|
||||
* {@link ResourceFinder} using {@link Class#getResource(String)},
|
||||
* which is the closest equivalent on JME.
|
||||
* The default loader chain in {@link PackageLib} will use these as well.
|
||||
* <p>
|
||||
* To use basic library functions that include a {@link ResourceFinder} based on
|
||||
* directory lookup, use {@link org.luaj.vm2.lib.jse.JseBaseLib} instead.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
|
||||
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* globals.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* <p>
|
||||
* This is a direct port of the corresponding library in C.
|
||||
* @see org.luaj.vm2.lib.jse.JseBaseLib
|
||||
* @see ResourceFinder
|
||||
* @see Globals#finder
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.lib.jse.JsePlatform
|
||||
* @see org.luaj.vm2.lib.jme.JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib Reference</a>
|
||||
*/
|
||||
public class BaseLib extends TwoArgFunction implements ResourceFinder {
|
||||
|
||||
Globals globals;
|
||||
|
||||
|
||||
/** Perform one-time initialization on the library by adding base functions
|
||||
* to the supplied environment, and returning it as the return value.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, which must be a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
globals = env.checkglobals();
|
||||
globals.finder = this;
|
||||
globals.baselib = this;
|
||||
env.set( "_G", env );
|
||||
env.set( "_VERSION", Lua._VERSION );
|
||||
env.set("assert", new _assert());
|
||||
env.set("collectgarbage", new collectgarbage());
|
||||
env.set("dofile", new dofile());
|
||||
env.set("error", new error());
|
||||
env.set("getmetatable", new getmetatable());
|
||||
env.set("load", new load());
|
||||
env.set("loadfile", new loadfile());
|
||||
env.set("pcall", new pcall());
|
||||
env.set("print", new print(this));
|
||||
env.set("rawequal", new rawequal());
|
||||
env.set("rawget", new rawget());
|
||||
env.set("rawlen", new rawlen());
|
||||
env.set("rawset", new rawset());
|
||||
env.set("select", new select());
|
||||
env.set("setmetatable", new setmetatable());
|
||||
env.set("tonumber", new tonumber());
|
||||
env.set("tostring", new tostring());
|
||||
env.set("type", new type());
|
||||
env.set("xpcall", new xpcall());
|
||||
|
||||
next next;
|
||||
env.set("next", next = new next());
|
||||
env.set("pairs", new pairs(next));
|
||||
env.set("ipairs", new ipairs());
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
/** ResourceFinder implementation
|
||||
*
|
||||
* Tries to open the file as a resource, which can work for JSE and JME.
|
||||
*/
|
||||
public InputStream findResource(String filename) {
|
||||
return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
|
||||
}
|
||||
|
||||
|
||||
// "assert", // ( v [,message] ) -> v, message | ERR
|
||||
static final class _assert extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
if ( !args.arg1().toboolean() )
|
||||
error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" );
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
// "collectgarbage", // ( opt [,arg] ) -> value
|
||||
static final class collectgarbage extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
String s = args.optjstring(1, "collect");
|
||||
if ( "collect".equals(s) ) {
|
||||
System.gc();
|
||||
return ZERO;
|
||||
} else if ( "count".equals(s) ) {
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
long used = rt.totalMemory() - rt.freeMemory();
|
||||
return varargsOf(valueOf(used/1024.), valueOf(used%1024));
|
||||
} else if ( "step".equals(s) ) {
|
||||
System.gc();
|
||||
return LuaValue.TRUE;
|
||||
} else {
|
||||
argerror(1, "invalid option '" + s + "'");
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
// "dofile", // ( filename ) -> result1, ...
|
||||
final class dofile extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
|
||||
String filename = args.isstring(1)? args.tojstring(1): null;
|
||||
Varargs v = filename == null?
|
||||
loadStream( globals.STDIN, "=stdin", "bt", globals ):
|
||||
loadFile( args.checkjstring(1), "bt", globals );
|
||||
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
|
||||
}
|
||||
}
|
||||
|
||||
// "error", // ( message [,level] ) -> ERR
|
||||
static final class error extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
if (arg1.isnil()) throw new LuaError(NIL);
|
||||
if (!arg1.isstring() || arg2.optint(1) == 0) throw new LuaError(arg1);
|
||||
throw new LuaError(arg1.tojstring(), arg2.optint(1));
|
||||
}
|
||||
}
|
||||
|
||||
// "getmetatable", // ( object ) -> table
|
||||
static final class getmetatable extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaValue mt = arg.getmetatable();
|
||||
return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL;
|
||||
}
|
||||
}
|
||||
// "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg
|
||||
final class load extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue ld = args.arg1();
|
||||
if (!ld.isstring() && !ld.isfunction()) {
|
||||
throw new LuaError("bad argument #1 to 'load' (string or function expected, got " + ld.typename() + ")");
|
||||
}
|
||||
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
|
||||
String mode = args.optjstring(3, "bt");
|
||||
LuaValue env = args.optvalue(4, globals);
|
||||
return loadStream(ld.isstring()? ld.strvalue().toInputStream():
|
||||
new StringInputStream(ld.checkfunction()), source, mode, env);
|
||||
}
|
||||
}
|
||||
|
||||
// "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
|
||||
final class loadfile extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
|
||||
String filename = args.isstring(1)? args.tojstring(1): null;
|
||||
String mode = args.optjstring(2, "bt");
|
||||
LuaValue env = args.optvalue(3, globals);
|
||||
return filename == null?
|
||||
loadStream( globals.STDIN, "=stdin", mode, env ):
|
||||
loadFile( filename, mode, env );
|
||||
}
|
||||
}
|
||||
|
||||
// "pcall", // (f, arg1, ...) -> status, result1, ...
|
||||
final class pcall extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue func = args.checkvalue(1);
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onCall(this);
|
||||
try {
|
||||
return varargsOf(TRUE, func.invoke(args.subargs(2)));
|
||||
} catch ( LuaError le ) {
|
||||
final LuaValue m = le.getMessageObject();
|
||||
return varargsOf(FALSE, m!=null? m: NIL);
|
||||
} catch ( Exception e ) {
|
||||
final String m = e.getMessage();
|
||||
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
|
||||
} finally {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onReturn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "print", // (...) -> void
|
||||
final class print extends VarArgFunction {
|
||||
final BaseLib baselib;
|
||||
print(BaseLib baselib) {
|
||||
this.baselib = baselib;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue tostring = globals.get("tostring");
|
||||
for ( int i=1, n=args.narg(); i<=n; i++ ) {
|
||||
if ( i>1 ) globals.STDOUT.print( '\t' );
|
||||
LuaString s = tostring.call( args.arg(i) ).strvalue();
|
||||
globals.STDOUT.print(s.tojstring());
|
||||
}
|
||||
globals.STDOUT.print('\n');
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// "rawequal", // (v1, v2) -> boolean
|
||||
static final class rawequal extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return argerror(2, "value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return valueOf(arg1.raweq(arg2));
|
||||
}
|
||||
}
|
||||
|
||||
// "rawget", // (table, index) -> value
|
||||
static final class rawget extends TableLibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return argerror(2, "value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return arg1.checktable().rawget(arg2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// "rawlen", // (v) -> value
|
||||
static final class rawlen extends LibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return valueOf(arg.rawlen());
|
||||
}
|
||||
}
|
||||
|
||||
// "rawset", // (table, index, value) -> table
|
||||
static final class rawset extends TableLibFunction {
|
||||
public LuaValue call(LuaValue table) {
|
||||
return argerror(2,"value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue table, LuaValue index) {
|
||||
return argerror(3,"value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
|
||||
LuaTable t = table.checktable();
|
||||
if (!index.isvalidkey()) argerror(2, "table index is nil");
|
||||
t.rawset(index, value);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
// "select", // (f, ...) -> value1, ...
|
||||
static final class select extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int n = args.narg()-1;
|
||||
if ( args.arg1().equals(valueOf("#")) )
|
||||
return valueOf(n);
|
||||
int i = args.checkint(1);
|
||||
if ( i == 0 || i < -n )
|
||||
argerror(1,"index out of range");
|
||||
return args.subargs(i<0? n+i+2: i+1);
|
||||
}
|
||||
}
|
||||
|
||||
// "setmetatable", // (table, metatable) -> table
|
||||
static final class setmetatable extends TableLibFunction {
|
||||
public LuaValue call(LuaValue table) {
|
||||
return argerror(2,"nil or table expected");
|
||||
}
|
||||
public LuaValue call(LuaValue table, LuaValue metatable) {
|
||||
final LuaValue mt0 = table.checktable().getmetatable();
|
||||
if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
|
||||
error("cannot change a protected metatable");
|
||||
return table.setmetatable(metatable.isnil()? null: metatable.checktable());
|
||||
}
|
||||
}
|
||||
|
||||
// "tonumber", // (e [,base]) -> value
|
||||
static final class tonumber extends LibFunction {
|
||||
public LuaValue call(LuaValue e) {
|
||||
return e.tonumber();
|
||||
}
|
||||
public LuaValue call(LuaValue e, LuaValue base) {
|
||||
if (base.isnil())
|
||||
return e.tonumber();
|
||||
final int b = base.checkint();
|
||||
if ( b < 2 || b > 36 )
|
||||
argerror(2, "base out of range");
|
||||
return e.checkstring().tonumber(b);
|
||||
}
|
||||
}
|
||||
|
||||
// "tostring", // (e) -> value
|
||||
static final class tostring extends LibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaValue h = arg.metatag(TOSTRING);
|
||||
if ( ! h.isnil() )
|
||||
return h.call(arg);
|
||||
LuaValue v = arg.tostring();
|
||||
if ( ! v.isnil() )
|
||||
return v;
|
||||
return valueOf(arg.tojstring());
|
||||
}
|
||||
}
|
||||
|
||||
// "type", // (v) -> value
|
||||
static final class type extends LibFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return valueOf(arg.typename());
|
||||
}
|
||||
}
|
||||
|
||||
// "xpcall", // (f, err) -> result1, ...
|
||||
final class xpcall extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
final LuaThread t = globals.running;
|
||||
final LuaValue preverror = t.errorfunc;
|
||||
t.errorfunc = args.checkvalue(2);
|
||||
try {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onCall(this);
|
||||
try {
|
||||
return varargsOf(TRUE, args.arg1().invoke(args.subargs(3)));
|
||||
} catch ( LuaError le ) {
|
||||
final LuaValue m = le.getMessageObject();
|
||||
return varargsOf(FALSE, m!=null? m: NIL);
|
||||
} catch ( Exception e ) {
|
||||
final String m = e.getMessage();
|
||||
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
|
||||
} finally {
|
||||
if (globals != null && globals.debuglib != null)
|
||||
globals.debuglib.onReturn();
|
||||
}
|
||||
} finally {
|
||||
t.errorfunc = preverror;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "pairs" (t) -> iter-func, t, nil
|
||||
static final class pairs extends VarArgFunction {
|
||||
final next next;
|
||||
pairs(next next) {
|
||||
this.next = next;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
return varargsOf( next, args.checktable(1), NIL );
|
||||
}
|
||||
}
|
||||
|
||||
// // "ipairs", // (t) -> iter-func, t, 0
|
||||
static final class ipairs extends VarArgFunction {
|
||||
inext inext = new inext();
|
||||
public Varargs invoke(Varargs args) {
|
||||
return varargsOf( inext, args.checktable(1), ZERO );
|
||||
}
|
||||
}
|
||||
|
||||
// "next" ( table, [index] ) -> next-index, next-value
|
||||
static final class next extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
return args.checktable(1).next(args.arg(2));
|
||||
}
|
||||
}
|
||||
|
||||
// "inext" ( table, [int-index] ) -> next-index, next-value
|
||||
static final class inext extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
return args.checktable(1).inext(args.arg(2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a named file, returning the chunk or nil,error of can't load
|
||||
* @param env
|
||||
* @param mode
|
||||
* @return Varargs containing chunk, or NIL,error-text on error
|
||||
*/
|
||||
public Varargs loadFile(String filename, String mode, LuaValue env) {
|
||||
InputStream is = globals.finder.findResource(filename);
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory"));
|
||||
try {
|
||||
return loadStream(is, "@"+filename, mode, env);
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) {
|
||||
try {
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("not found: "+chunkname));
|
||||
return globals.load(is, chunkname, mode, env);
|
||||
} catch (Exception e) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StringInputStream extends InputStream {
|
||||
final LuaValue func;
|
||||
byte[] bytes;
|
||||
int offset, remaining = 0;
|
||||
StringInputStream(LuaValue func) {
|
||||
this.func = func;
|
||||
}
|
||||
public int read() throws IOException {
|
||||
if ( remaining < 0 )
|
||||
return -1;
|
||||
if ( remaining == 0 ) {
|
||||
LuaValue s = func.call();
|
||||
if ( s.isnil() )
|
||||
return remaining = -1;
|
||||
LuaString ls = s.strvalue();
|
||||
bytes = ls.m_bytes;
|
||||
offset = ls.m_offset;
|
||||
remaining = ls.m_length;
|
||||
if (remaining <= 0)
|
||||
return -1;
|
||||
}
|
||||
--remaining;
|
||||
return 0xFF&bytes[offset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,15 +27,15 @@ import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of LibFunction that implements the Lua standard {@code bit32} library.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("bit32").get("bnot").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
@@ -71,7 +71,7 @@ public class Bit32Lib extends TwoArgFunction {
|
||||
"arshift", "lrotate", "lshift", "rrotate", "rshift"
|
||||
});
|
||||
env.set("bit32", t);
|
||||
env.get("package").get("loaded").set("bit32", t);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("bit32", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -219,6 +219,6 @@ public class Bit32Lib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
private static LuaValue bitsToValue( int x ) {
|
||||
return ( x < 0 ) ? valueOf((double) ((long) x & 0xFFFFFFFFL)) : valueOf(x);
|
||||
return ( x < 0 ) ? valueOf((double) ((long) x & 0xFFFFFFFFL)) : valueOf(x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,25 +27,25 @@ import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code coroutine}
|
||||
* library.
|
||||
* <p>
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code coroutine}
|
||||
* library.
|
||||
* <p>
|
||||
* The coroutine library in luaj has the same behavior as the
|
||||
* coroutine library in C, but is implemented using Java Threads to maintain
|
||||
* the call state between invocations. Therefore it can be yielded from anywhere,
|
||||
* coroutine library in C, but is implemented using Java Threads to maintain
|
||||
* the call state between invocations. Therefore it can be yielded from anywhere,
|
||||
* similar to the "Coco" yield-from-anywhere patch available for C-based lua.
|
||||
* However, coroutines that are yielded but never resumed to complete their execution
|
||||
* may not be collected by the garbage collector.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* may not be collected by the garbage collector.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("coroutine").get("running").call() );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
@@ -82,7 +82,7 @@ public class CoroutineLib extends TwoArgFunction {
|
||||
coroutine.set("yield", new yield());
|
||||
coroutine.set("wrap", new wrap());
|
||||
env.set("coroutine", coroutine);
|
||||
env.get("package").get("loaded").set("coroutine", coroutine);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("coroutine", coroutine);
|
||||
return coroutine;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class CoroutineLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
final class resume extends VarArgFunction {
|
||||
static final class resume extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
final LuaThread t = args.checkthread(1);
|
||||
return t.resume( args.subargs(2) );
|
||||
@@ -127,7 +127,7 @@ public class CoroutineLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
final class wrapper extends VarArgFunction {
|
||||
static final class wrapper extends VarArgFunction {
|
||||
final LuaThread luathread;
|
||||
wrapper(LuaThread luathread) {
|
||||
this.luathread = luathread;
|
||||
|
||||
@@ -38,26 +38,26 @@ import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code debug}
|
||||
* library.
|
||||
* <p>
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code debug}
|
||||
* library.
|
||||
* <p>
|
||||
* The debug library in luaj tries to emulate the behavior of the corresponding C-based lua library.
|
||||
* To do this, it must maintain a separate stack of calls to {@link LuaClosure} and {@link LibFunction}
|
||||
* instances.
|
||||
* To do this, it must maintain a separate stack of calls to {@link LuaClosure} and {@link LibFunction}
|
||||
* instances.
|
||||
* Especially when lua-to-java bytecode compiling is being used
|
||||
* via a {@link org.luaj.vm2.Globals.Compiler} such as {@link org.luaj.vm2.luajc.LuaJC},
|
||||
* this cannot be done in all cases.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#debugGlobals()} or
|
||||
* via a {@link org.luaj.vm2.Globals.Compiler} such as {@link org.luaj.vm2.luajc.LuaJC},
|
||||
* this cannot be done in all cases.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#debugGlobals()} or
|
||||
* {@link org.luaj.vm2.lib.jme.JmePlatform#debugGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.debugGlobals();
|
||||
* System.out.println( globals.get("debug").get("traceback").call() );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
@@ -84,27 +84,27 @@ public class DebugLib extends TwoArgFunction {
|
||||
try { TRACE = (null != System.getProperty("TRACE")); } catch (Exception e) {}
|
||||
}
|
||||
|
||||
private static final LuaString LUA = valueOf("Lua");
|
||||
private static final LuaString QMARK = valueOf("?");
|
||||
private static final LuaString CALL = valueOf("call");
|
||||
private static final LuaString LINE = valueOf("line");
|
||||
private static final LuaString COUNT = valueOf("count");
|
||||
static final LuaString LUA = valueOf("Lua");
|
||||
private static final LuaString QMARK = valueOf("?");
|
||||
private static final LuaString CALL = valueOf("call");
|
||||
private static final LuaString LINE = valueOf("line");
|
||||
private static final LuaString COUNT = valueOf("count");
|
||||
private static final LuaString RETURN = valueOf("return");
|
||||
|
||||
private static final LuaString FUNC = valueOf("func");
|
||||
private static final LuaString ISTAILCALL = valueOf("istailcall");
|
||||
private static final LuaString ISVARARG = valueOf("isvararg");
|
||||
private static final LuaString NUPS = valueOf("nups");
|
||||
private static final LuaString NPARAMS = valueOf("nparams");
|
||||
private static final LuaString NAME = valueOf("name");
|
||||
private static final LuaString NAMEWHAT = valueOf("namewhat");
|
||||
private static final LuaString WHAT = valueOf("what");
|
||||
private static final LuaString SOURCE = valueOf("source");
|
||||
private static final LuaString SHORT_SRC = valueOf("short_src");
|
||||
private static final LuaString LINEDEFINED = valueOf("linedefined");
|
||||
private static final LuaString LASTLINEDEFINED = valueOf("lastlinedefined");
|
||||
private static final LuaString CURRENTLINE = valueOf("currentline");
|
||||
private static final LuaString ACTIVELINES = valueOf("activelines");
|
||||
static final LuaString FUNC = valueOf("func");
|
||||
static final LuaString ISTAILCALL = valueOf("istailcall");
|
||||
static final LuaString ISVARARG = valueOf("isvararg");
|
||||
static final LuaString NUPS = valueOf("nups");
|
||||
static final LuaString NPARAMS = valueOf("nparams");
|
||||
static final LuaString NAME = valueOf("name");
|
||||
static final LuaString NAMEWHAT = valueOf("namewhat");
|
||||
static final LuaString WHAT = valueOf("what");
|
||||
static final LuaString SOURCE = valueOf("source");
|
||||
static final LuaString SHORT_SRC = valueOf("short_src");
|
||||
static final LuaString LINEDEFINED = valueOf("linedefined");
|
||||
static final LuaString LASTLINEDEFINED = valueOf("lastlinedefined");
|
||||
static final LuaString CURRENTLINE = valueOf("currentline");
|
||||
static final LuaString ACTIVELINES = valueOf("activelines");
|
||||
|
||||
Globals globals;
|
||||
|
||||
@@ -135,19 +135,19 @@ public class DebugLib extends TwoArgFunction {
|
||||
debug.set("upvalueid", new upvalueid());
|
||||
debug.set("upvaluejoin", new upvaluejoin());
|
||||
env.set("debug", debug);
|
||||
env.get("package").get("loaded").set("debug", debug);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("debug", debug);
|
||||
return debug;
|
||||
}
|
||||
|
||||
// debug.debug()
|
||||
static final class debug extends ZeroArgFunction {
|
||||
static final class debug extends ZeroArgFunction {
|
||||
public LuaValue call() {
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.gethook ([thread])
|
||||
final class gethook extends VarArgFunction {
|
||||
final class gethook extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaThread t = args.narg() > 0 ? args.checkthread(1): globals.running;
|
||||
LuaThread.State s = t.state;
|
||||
@@ -159,10 +159,10 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.getinfo ([thread,] f [, what])
|
||||
final class getinfo extends VarArgFunction {
|
||||
final class getinfo extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
LuaValue func = args.arg(a++);
|
||||
String what = args.optjstring(a++, "flnStu");
|
||||
DebugLib.CallStack callstack = callstack(thread);
|
||||
@@ -222,10 +222,10 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.getlocal ([thread,] f, local)
|
||||
final class getlocal extends VarArgFunction {
|
||||
final class getlocal extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
int level = args.checkint(a++);
|
||||
int local = args.checkint(a++);
|
||||
CallFrame f = callstack(thread).getCallFrame(level);
|
||||
@@ -234,7 +234,7 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.getmetatable (value)
|
||||
final class getmetatable extends LibFunction {
|
||||
static final class getmetatable extends LibFunction {
|
||||
public LuaValue call(LuaValue v) {
|
||||
LuaValue mt = v.getmetatable();
|
||||
return mt != null? mt: NIL;
|
||||
@@ -249,7 +249,7 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.getupvalue (f, up)
|
||||
static final class getupvalue extends VarArgFunction {
|
||||
static final class getupvalue extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
@@ -265,7 +265,7 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.getuservalue (u)
|
||||
static final class getuservalue extends LibFunction {
|
||||
static final class getuservalue extends LibFunction {
|
||||
public LuaValue call(LuaValue u) {
|
||||
return u.isuserdata()? u: NIL;
|
||||
}
|
||||
@@ -273,10 +273,10 @@ public class DebugLib extends TwoArgFunction {
|
||||
|
||||
|
||||
// debug.sethook ([thread,] hook, mask [, count])
|
||||
final class sethook extends VarArgFunction {
|
||||
final class sethook extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
LuaValue func = args.optfunction(a++, null);
|
||||
String str = args.optjstring(a++,"");
|
||||
int count = args.optint(a++,0);
|
||||
@@ -298,20 +298,20 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.setlocal ([thread,] level, local, value)
|
||||
final class setlocal extends VarArgFunction {
|
||||
final class setlocal extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
int level = args.checkint(a++);
|
||||
int local = args.checkint(a++);
|
||||
LuaValue value = args.arg(a++);
|
||||
CallFrame f = callstack(thread).getCallFrame(level);
|
||||
CallFrame f = callstack(thread).getCallFrame(level);
|
||||
return f != null? f.setLocal(local, value): NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// debug.setmetatable (value, table)
|
||||
final class setmetatable extends TwoArgFunction {
|
||||
static final class setmetatable extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue value, LuaValue table) {
|
||||
LuaValue mt = table.opttable(null);
|
||||
switch ( value.type() ) {
|
||||
@@ -328,7 +328,7 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.setupvalue (f, up, value)
|
||||
final class setupvalue extends VarArgFunction {
|
||||
static final class setupvalue extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
@@ -346,7 +346,7 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.setuservalue (udata, value)
|
||||
final class setuservalue extends VarArgFunction {
|
||||
static final class setuservalue extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
Object o = args.checkuserdata(1);
|
||||
LuaValue v = args.checkvalue(2);
|
||||
@@ -358,10 +358,10 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.traceback ([thread,] [message [, level]])
|
||||
final class traceback extends VarArgFunction {
|
||||
final class traceback extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
|
||||
String message = args.optjstring(a++, null);
|
||||
int level = args.optint(a++,1);
|
||||
String tb = callstack(thread).traceback(level);
|
||||
@@ -370,7 +370,7 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.upvalueid (f, n)
|
||||
final class upvalueid extends VarArgFunction {
|
||||
static final class upvalueid extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
@@ -385,7 +385,7 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// debug.upvaluejoin (f1, n1, f2, n2)
|
||||
final class upvaluejoin extends VarArgFunction {
|
||||
static final class upvaluejoin extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaClosure f1 = args.checkclosure(1);
|
||||
int n1 = args.checkint(2);
|
||||
@@ -442,6 +442,10 @@ public class DebugLib extends TwoArgFunction {
|
||||
return callstack().traceback(level);
|
||||
}
|
||||
|
||||
public CallFrame getCallFrame(int level) {
|
||||
return callstack().getCallFrame(level);
|
||||
}
|
||||
|
||||
void callHook(LuaThread.State s, LuaValue type, LuaValue arg) {
|
||||
if (s.inhook || s.hookfunc == null) return;
|
||||
s.inhook = true;
|
||||
@@ -565,7 +569,11 @@ public class DebugLib extends TwoArgFunction {
|
||||
sb.append( ar.name );
|
||||
sb.append( '\'' );
|
||||
} else {
|
||||
sb.append( "function <"+c.shortsource()+":"+c.linedefined()+">" );
|
||||
sb.append( "function <" );
|
||||
sb.append( c.shortsource() );
|
||||
sb.append( ':' );
|
||||
sb.append( c.linedefined() );
|
||||
sb.append( '>' );
|
||||
}
|
||||
}
|
||||
sb.append("\n\t[Java]: in ?");
|
||||
@@ -583,7 +591,7 @@ public class DebugLib extends TwoArgFunction {
|
||||
if (frame[calls-i].f == func)
|
||||
return frame[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
synchronized DebugInfo auxgetinfo(String what, LuaFunction f, CallFrame ci) {
|
||||
@@ -637,11 +645,11 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
return ar;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CallFrame {
|
||||
public static class CallFrame {
|
||||
LuaFunction f;
|
||||
int pc;
|
||||
int top;
|
||||
@@ -673,30 +681,30 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
Varargs getLocal(int i) {
|
||||
LuaString name = getlocalname(i);
|
||||
if ( name != null )
|
||||
return varargsOf( name, stack[i-1] );
|
||||
if ( i >= 1 && i <= stack.length && stack[i-1] != null )
|
||||
return varargsOf( name == null ? NIL : name, stack[i-1] );
|
||||
else
|
||||
return NIL;
|
||||
}
|
||||
Varargs setLocal(int i, LuaValue value) {
|
||||
LuaString name = getlocalname(i);
|
||||
if ( name != null ) {
|
||||
if ( i >= 1 && i <= stack.length && stack[i-1] != null ) {
|
||||
stack[i-1] = value;
|
||||
return name;
|
||||
return name == null ? NIL : name;
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
int currentline() {
|
||||
public int currentline() {
|
||||
if ( !f.isclosure() ) return -1;
|
||||
int[] li = f.checkclosure().p.lineinfo;
|
||||
return li==null || pc<0 || pc>=li.length? -1: li[pc];
|
||||
return li==null || pc<0 || pc>=li.length? -1: li[pc];
|
||||
}
|
||||
String sourceline() {
|
||||
if ( !f.isclosure() ) return f.tojstring();
|
||||
return f.checkclosure().p.shortsource() + ":" + currentline();
|
||||
}
|
||||
private int linedefined() {
|
||||
int linedefined() {
|
||||
return f.isclosure()? f.checkclosure().p.linedefined: -1;
|
||||
}
|
||||
LuaString getlocalname(int index) {
|
||||
@@ -717,7 +725,7 @@ public class DebugLib extends TwoArgFunction {
|
||||
|
||||
static void lua_assert(boolean x) {
|
||||
if (!x) throw new RuntimeException("lua_assert failed");
|
||||
}
|
||||
}
|
||||
|
||||
static class NameWhat {
|
||||
final String name;
|
||||
@@ -792,13 +800,13 @@ public class DebugLib extends TwoArgFunction {
|
||||
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */
|
||||
? p.getlocalname(t + 1, pc)
|
||||
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
|
||||
name = kname(p, k);
|
||||
return new NameWhat( name.tojstring(), vn != null && vn.eq_b(ENV)? "global": "field" );
|
||||
String jname = kname(p, pc, k);
|
||||
return new NameWhat( jname, vn != null && vn.eq_b(ENV)? "global": "field" );
|
||||
}
|
||||
case Lua.OP_GETUPVAL: {
|
||||
int u = Lua.GETARG_B(i); /* upvalue index */
|
||||
name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
|
||||
return new NameWhat( name.tojstring(), "upvalue" );
|
||||
return name == null ? null : new NameWhat( name.tojstring(), "upvalue" );
|
||||
}
|
||||
case Lua.OP_LOADK:
|
||||
case Lua.OP_LOADKX: {
|
||||
@@ -812,8 +820,8 @@ public class DebugLib extends TwoArgFunction {
|
||||
}
|
||||
case Lua.OP_SELF: {
|
||||
int k = Lua.GETARG_C(i); /* key index */
|
||||
name = kname(p, k);
|
||||
return new NameWhat( name.tojstring(), "method" );
|
||||
String jname = kname(p, pc, k);
|
||||
return new NameWhat( jname, "method" );
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@@ -822,11 +830,20 @@ public class DebugLib extends TwoArgFunction {
|
||||
return null; /* no useful name found */
|
||||
}
|
||||
|
||||
static LuaString kname(Prototype p, int c) {
|
||||
if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring())
|
||||
return p.k[Lua.INDEXK(c)].strvalue();
|
||||
else
|
||||
return QMARK;
|
||||
static String kname(Prototype p, int pc, int c) {
|
||||
if (Lua.ISK(c)) { /* is 'c' a constant? */
|
||||
LuaValue k = p.k[Lua.INDEXK(c)];
|
||||
if (k.isstring()) { /* literal constant? */
|
||||
return k.tojstring(); /* it is its own name */
|
||||
} /* else no reasonable name found */
|
||||
} else { /* 'c' is a register */
|
||||
NameWhat what = getobjname(p, pc, c); /* search for 'c' */
|
||||
if (what != null && "constant".equals(what.namewhat)) { /* found a constant name? */
|
||||
return what.name; /* 'name' already filled */
|
||||
}
|
||||
/* else no reasonable name found */
|
||||
}
|
||||
return "?"; /* no reasonable name found */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -867,6 +884,10 @@ public class DebugLib extends TwoArgFunction {
|
||||
if (reg == a) setreg = pc; /* jumped code can change 'a' */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SETLIST: { // Lua.testAMode(Lua.OP_SETLIST) == false
|
||||
if ( ((i>>14)&0x1ff) == 0 ) pc++; // if c == 0 then c stored in next op -> skip
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (Lua.testAMode(op) && reg == a) /* any instruction that set A */
|
||||
setreg = pc;
|
||||
|
||||
@@ -31,31 +31,31 @@ import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Abstract base class extending {@link LibFunction} which implements the
|
||||
* core of the lua standard {@code io} library.
|
||||
* <p>
|
||||
/**
|
||||
* Abstract base class extending {@link LibFunction} which implements the
|
||||
* core of the lua standard {@code io} library.
|
||||
* <p>
|
||||
* It contains the implementation of the io library support that is common to
|
||||
* the JSE and JME platforms.
|
||||
* In practice on of the concrete IOLib subclasses is chosen:
|
||||
* {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
|
||||
* the JSE and JME platforms.
|
||||
* In practice on of the concrete IOLib subclasses is chosen:
|
||||
* {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
|
||||
* {@link org.luaj.vm2.lib.jme.JmeIoLib} for the JME platform.
|
||||
* <p>
|
||||
* The JSE implementation conforms almost completely to the C-based lua library,
|
||||
* while the JME implementation follows closely except in the area of random-access files,
|
||||
* which are difficult to support properly on JME.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* The JSE implementation conforms almost completely to the C-based lua library,
|
||||
* while the JME implementation follows closely except in the area of random-access files,
|
||||
* which are difficult to support properly on JME.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseIoLib} library will be loaded, which will include
|
||||
* the base functionality provided by this class, whereas the {@link org.luaj.vm2.lib.jse.JsePlatform} would load the
|
||||
* the base functionality provided by this class, whereas the {@link org.luaj.vm2.lib.jse.JsePlatform} would load the
|
||||
* {@link org.luaj.vm2.lib.jse.JseIoLib}.
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
@@ -73,10 +73,10 @@ import org.luaj.vm2.Varargs;
|
||||
* @see org.luaj.vm2.lib.jme.JmeIoLib
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.7">http://www.lua.org/manual/5.1/manual.html#5.7</a>
|
||||
*/
|
||||
abstract
|
||||
abstract
|
||||
public class IoLib extends TwoArgFunction {
|
||||
|
||||
abstract
|
||||
abstract
|
||||
protected class File extends LuaValue{
|
||||
abstract public void write( LuaString string ) throws IOException;
|
||||
abstract public void flush() throws IOException;
|
||||
@@ -85,16 +85,22 @@ public class IoLib extends TwoArgFunction {
|
||||
abstract public boolean isclosed();
|
||||
// returns new position
|
||||
abstract public int seek(String option, int bytecount) throws IOException;
|
||||
abstract public void setvbuf(String mode, int size);
|
||||
abstract public void setvbuf(String mode, int size);
|
||||
// get length remaining to read
|
||||
abstract public int remaining() throws IOException;
|
||||
abstract public int remaining() throws IOException;
|
||||
// peek ahead one character
|
||||
abstract public int peek() throws IOException, EOFException;
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
abstract public int peek() throws IOException, EOFException;
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
abstract public int read() throws IOException, EOFException;
|
||||
// return number of bytes read if positive, false if eof, throw IOException on other exception
|
||||
abstract public int read(byte[] bytes, int offset, int length) throws IOException;
|
||||
|
||||
public boolean eof() throws IOException {
|
||||
try {
|
||||
return peek() < 0;
|
||||
} catch (EOFException e) { return true; }
|
||||
}
|
||||
|
||||
// delegate method access to file methods table
|
||||
public LuaValue get( LuaValue key ) {
|
||||
return filemethods.get(key);
|
||||
@@ -112,6 +118,14 @@ public class IoLib extends TwoArgFunction {
|
||||
public String tojstring() {
|
||||
return "file: " + Integer.toHexString(hashCode());
|
||||
}
|
||||
|
||||
public void finalize() {
|
||||
if (!isclosed()) {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ignore) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Enumerated value representing stdin */
|
||||
@@ -123,29 +137,29 @@ public class IoLib extends TwoArgFunction {
|
||||
/** Enumerated value representing a file type for a named file */
|
||||
protected static final int FTYPE_NAMED = 3;
|
||||
|
||||
/**
|
||||
* Wrap the standard input.
|
||||
* @return File
|
||||
/**
|
||||
* Wrap the standard input.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStdin() throws IOException;
|
||||
|
||||
/**
|
||||
* Wrap the standard output.
|
||||
* @return File
|
||||
/**
|
||||
* Wrap the standard output.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStdout() throws IOException;
|
||||
|
||||
/**
|
||||
* Wrap the standard error output.
|
||||
* @return File
|
||||
/**
|
||||
* Wrap the standard error output.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStderr() throws IOException;
|
||||
|
||||
/**
|
||||
* Open a file in a particular mode.
|
||||
* Open a file in a particular mode.
|
||||
* @param filename
|
||||
* @param readMode true if opening in read mode
|
||||
* @param appendMode true if opening in append mode
|
||||
@@ -157,7 +171,7 @@ public class IoLib extends TwoArgFunction {
|
||||
abstract protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException;
|
||||
|
||||
/**
|
||||
* Open a temporary file.
|
||||
* Open a temporary file.
|
||||
* @return File object if successful
|
||||
* @throws IOException if could not be opened
|
||||
*/
|
||||
@@ -167,7 +181,7 @@ public class IoLib extends TwoArgFunction {
|
||||
* Start a new process and return a file for input or output
|
||||
* @param prog the program to execute
|
||||
* @param mode "r" to read, "w" to write
|
||||
* @return File to read to or write from
|
||||
* @return File to read to or write from
|
||||
* @throws IOException if an i/o exception occurs
|
||||
*/
|
||||
abstract protected File openProgram(String prog, String mode) throws IOException;
|
||||
@@ -178,7 +192,7 @@ public class IoLib extends TwoArgFunction {
|
||||
|
||||
private static final LuaValue STDIN = valueOf("stdin");
|
||||
private static final LuaValue STDOUT = valueOf("stdout");
|
||||
private static final LuaValue STDERR = valueOf("stderr");
|
||||
private static final LuaValue STDERR = valueOf("stderr");
|
||||
private static final LuaValue FILE = valueOf("file");
|
||||
private static final LuaValue CLOSED_FILE = valueOf("closed file");
|
||||
|
||||
@@ -256,7 +270,7 @@ public class IoLib extends TwoArgFunction {
|
||||
|
||||
// return the table
|
||||
env.set("io", t);
|
||||
env.get("package").get("loaded").set("io", t);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("io", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -269,8 +283,15 @@ public class IoLib extends TwoArgFunction {
|
||||
static final class IoLibV extends VarArgFunction {
|
||||
private File f;
|
||||
public IoLib iolib;
|
||||
private boolean toclose;
|
||||
private Varargs args;
|
||||
public IoLibV() {
|
||||
}
|
||||
public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) {
|
||||
this(f, name, opcode, iolib);
|
||||
this.toclose = toclose;
|
||||
this.args = args.dealias();
|
||||
}
|
||||
public IoLibV(File f, String name, int opcode, IoLib iolib) {
|
||||
super();
|
||||
this.f = f;
|
||||
@@ -290,22 +311,26 @@ public class IoLib extends TwoArgFunction {
|
||||
case IO_TYPE: return iolib._io_type(args.arg1());
|
||||
case IO_POPEN: return iolib._io_popen(args.checkjstring(1),args.optjstring(2,"r"));
|
||||
case IO_OPEN: return iolib._io_open(args.checkjstring(1), args.optjstring(2,"r"));
|
||||
case IO_LINES: return iolib._io_lines(args.isvalue(1)? args.checkjstring(1): null);
|
||||
case IO_LINES: return iolib._io_lines(args);
|
||||
case IO_READ: return iolib._io_read(args);
|
||||
case IO_WRITE: return iolib._io_write(args);
|
||||
|
||||
case FILE_CLOSE: return iolib._file_close(args.arg1());
|
||||
case FILE_FLUSH: return iolib._file_flush(args.arg1());
|
||||
case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,1024));
|
||||
case FILE_LINES: return iolib._file_lines(args.arg1());
|
||||
case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,8192));
|
||||
case FILE_LINES: return iolib._file_lines(args);
|
||||
case FILE_READ: return iolib._file_read(args.arg1(),args.subargs(2));
|
||||
case FILE_SEEK: return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0));
|
||||
case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2));
|
||||
|
||||
case IO_INDEX: return iolib._io_index(args.arg(2));
|
||||
case LINES_ITER: return iolib._lines_iter(f);
|
||||
case LINES_ITER: return iolib._lines_iter(f, toclose, this.args);
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
if (opcode == LINES_ITER) {
|
||||
String s = ioe.getMessage();
|
||||
error(s != null ? s : ioe.toString());
|
||||
}
|
||||
return errorresult(ioe);
|
||||
}
|
||||
return NONE;
|
||||
@@ -316,7 +341,7 @@ public class IoLib extends TwoArgFunction {
|
||||
return infile!=null? infile: (infile=ioopenfile(FTYPE_STDIN, "-","r"));
|
||||
}
|
||||
|
||||
// io.flush() -> bool
|
||||
// io.flush() -> bool
|
||||
public Varargs _io_flush() throws IOException {
|
||||
checkopen(output());
|
||||
outfile.flush();
|
||||
@@ -337,7 +362,7 @@ public class IoLib extends TwoArgFunction {
|
||||
|
||||
// io.input([file]) -> file
|
||||
public Varargs _io_input(LuaValue file) {
|
||||
infile = file.isnil()? input():
|
||||
infile = file.isnil()? input():
|
||||
file.isstring()? ioopenfile(FTYPE_NAMED, file.checkjstring(),"r"):
|
||||
checkfile(file);
|
||||
return infile;
|
||||
@@ -345,7 +370,7 @@ public class IoLib extends TwoArgFunction {
|
||||
|
||||
// io.output(filename) -> file
|
||||
public Varargs _io_output(LuaValue filename) {
|
||||
outfile = filename.isnil()? output():
|
||||
outfile = filename.isnil()? output():
|
||||
filename.isstring()? ioopenfile(FTYPE_NAMED, filename.checkjstring(),"w"):
|
||||
checkfile(filename);
|
||||
return outfile;
|
||||
@@ -361,6 +386,7 @@ public class IoLib extends TwoArgFunction {
|
||||
|
||||
// io.popen(prog, [mode]) -> file
|
||||
public Varargs _io_popen(String prog, String mode) throws IOException {
|
||||
if (!"r".equals(mode) && !"w".equals(mode)) argerror(2, "invalid value: '" + mode + "'; must be one of 'r' or 'w'");
|
||||
return openProgram(prog, mode);
|
||||
}
|
||||
|
||||
@@ -369,11 +395,12 @@ public class IoLib extends TwoArgFunction {
|
||||
return rawopenfile(FTYPE_NAMED, filename, mode);
|
||||
}
|
||||
|
||||
// io.lines(filename) -> iterator
|
||||
public Varargs _io_lines(String filename) {
|
||||
infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
|
||||
// io.lines(filename, ...) -> iterator
|
||||
public Varargs _io_lines(Varargs args) {
|
||||
String filename = args.optjstring(1, null);
|
||||
File infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
|
||||
checkopen(infile);
|
||||
return lines(infile);
|
||||
return lines(infile, filename != null, args.subargs(2));
|
||||
}
|
||||
|
||||
// io.read(...) -> (...)
|
||||
@@ -401,13 +428,19 @@ public class IoLib extends TwoArgFunction {
|
||||
|
||||
// file:setvbuf(mode,[size]) -> void
|
||||
public Varargs _file_setvbuf(LuaValue file, String mode, int size) {
|
||||
if ("no".equals(mode)) {
|
||||
} else if ("full".equals(mode)) {
|
||||
} else if ("line".equals(mode)) {
|
||||
} else {
|
||||
argerror(1, "invalid value: '" + mode + "'; must be one of 'no', 'full' or 'line'");
|
||||
}
|
||||
checkfile(file).setvbuf(mode,size);
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
// file:lines() -> iterator
|
||||
public Varargs _file_lines(LuaValue file) {
|
||||
return lines(checkfile(file));
|
||||
// file:lines(...) -> iterator
|
||||
public Varargs _file_lines(Varargs args) {
|
||||
return lines(checkfile(args.arg1()), false, args.subargs(2));
|
||||
}
|
||||
|
||||
// file:read(...) -> (...)
|
||||
@@ -417,10 +450,16 @@ public class IoLib extends TwoArgFunction {
|
||||
|
||||
// file:seek([whence][,offset]) -> pos | nil,error
|
||||
public Varargs _file_seek(LuaValue file, String whence, int offset) throws IOException {
|
||||
if ("set".equals(whence)) {
|
||||
} else if ("end".equals(whence)) {
|
||||
} else if ("cur".equals(whence)) {
|
||||
} else {
|
||||
argerror(1, "invalid value: '" + whence + "'; must be one of 'set', 'cur' or 'end'");
|
||||
}
|
||||
return valueOf( checkfile(file).seek(whence,offset) );
|
||||
}
|
||||
|
||||
// file:write(...) -> void
|
||||
// file:write(...) -> void
|
||||
public Varargs _file_write(LuaValue file, Varargs subargs) throws IOException {
|
||||
return iowrite(checkfile(file),subargs);
|
||||
}
|
||||
@@ -433,8 +472,13 @@ public class IoLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
// lines iterator(s,var) -> var'
|
||||
public Varargs _lines_iter(LuaValue file) throws IOException {
|
||||
return freadline(checkfile(file));
|
||||
public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
|
||||
File f = optfile(file);
|
||||
if ( f == null ) argerror(1, "not a file: " + file);
|
||||
if ( f.isclosed() ) error("file is already closed");
|
||||
Varargs ret = ioread(f, args);
|
||||
if (toclose && ret.isnil(1) && f.eof()) f.close();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private File output() {
|
||||
@@ -467,8 +511,8 @@ public class IoLib extends TwoArgFunction {
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
private static Varargs errorresult(Exception ioe) {
|
||||
String s = ioe.getMessage();
|
||||
static Varargs errorresult(Exception ioe) {
|
||||
String s = ioe.getMessage();
|
||||
return errorresult("io error: "+(s!=null? s: ioe.toString()));
|
||||
}
|
||||
|
||||
@@ -476,9 +520,9 @@ public class IoLib extends TwoArgFunction {
|
||||
return varargsOf(NIL, valueOf(errortext));
|
||||
}
|
||||
|
||||
private Varargs lines(final File f) {
|
||||
private Varargs lines(final File f, boolean toclose, Varargs args) {
|
||||
try {
|
||||
return new IoLibV(f,"lnext",LINES_ITER,this);
|
||||
return new IoLibV(f,"lnext",LINES_ITER,this,toclose,args);
|
||||
} catch ( Exception e ) {
|
||||
return error("lines: "+e);
|
||||
}
|
||||
@@ -492,6 +536,7 @@ public class IoLib extends TwoArgFunction {
|
||||
|
||||
private Varargs ioread(File f, Varargs args) throws IOException {
|
||||
int i,n=args.narg();
|
||||
if (n == 0) return freadline(f,false);
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
LuaValue ai,vi;
|
||||
LuaString fmt;
|
||||
@@ -502,15 +547,16 @@ public class IoLib extends TwoArgFunction {
|
||||
break item;
|
||||
case LuaValue.TSTRING:
|
||||
fmt = ai.checkstring();
|
||||
if ( fmt.m_length == 2 && fmt.m_bytes[fmt.m_offset] == '*' ) {
|
||||
if ( fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*' ) {
|
||||
switch ( fmt.m_bytes[fmt.m_offset+1] ) {
|
||||
case 'n': vi = freadnumber(f); break item;
|
||||
case 'l': vi = freadline(f); break item;
|
||||
case 'l': vi = freadline(f,false); break item;
|
||||
case 'L': vi = freadline(f,true); break item;
|
||||
case 'a': vi = freadall(f); break item;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return argerror( i+1, "(invalid format)" );
|
||||
default:
|
||||
return argerror( i+1, "(invalid format)" );
|
||||
}
|
||||
if ( (v[i++] = vi).isnil() )
|
||||
break;
|
||||
@@ -537,6 +583,17 @@ public class IoLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
private File rawopenfile(int filetype, String filename, String mode) throws IOException {
|
||||
int len = mode.length();
|
||||
for (int i = 0; i < len; i++) { // [rwa][+]?b*
|
||||
char ch = mode.charAt(i);
|
||||
if (i == 0 && "rwa".indexOf(ch) >= 0) continue;
|
||||
if (i == 1 && ch == '+') continue;
|
||||
if (i >= 1 && ch == 'b') continue;
|
||||
len = -1;
|
||||
break;
|
||||
}
|
||||
if (len <= 0) argerror(2, "invalid mode: '" + mode + "'");
|
||||
|
||||
switch (filetype) {
|
||||
case FTYPE_STDIN: return wrapStdin();
|
||||
case FTYPE_STDOUT: return wrapStdout();
|
||||
@@ -544,7 +601,7 @@ public class IoLib extends TwoArgFunction {
|
||||
}
|
||||
boolean isreadmode = mode.startsWith("r");
|
||||
boolean isappend = mode.startsWith("a");
|
||||
boolean isupdate = mode.indexOf("+") > 0;
|
||||
boolean isupdate = mode.indexOf('+') > 0;
|
||||
boolean isbinary = mode.endsWith("b");
|
||||
return openFile( filename, isreadmode, isappend, isupdate, isbinary );
|
||||
}
|
||||
@@ -553,44 +610,45 @@ public class IoLib extends TwoArgFunction {
|
||||
// ------------- file reading utilitied ------------------
|
||||
|
||||
public static LuaValue freadbytes(File f, int count) throws IOException {
|
||||
if (count == 0) return f.eof() ? NIL : EMPTYSTRING;
|
||||
byte[] b = new byte[count];
|
||||
int r;
|
||||
if ( ( r = f.read(b,0,b.length) ) < 0 )
|
||||
return NIL;
|
||||
return LuaString.valueUsing(b, 0, r);
|
||||
}
|
||||
public static LuaValue freaduntil(File f,boolean lineonly) throws IOException {
|
||||
public static LuaValue freaduntil(File f,boolean lineonly,boolean withend) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int c;
|
||||
try {
|
||||
if ( lineonly ) {
|
||||
loop: while ( (c = f.read()) > 0 ) {
|
||||
loop: while ( (c = f.read()) >= 0 ) {
|
||||
switch ( c ) {
|
||||
case '\r': break;
|
||||
case '\n': break loop;
|
||||
case '\r': if (withend) baos.write(c); break;
|
||||
case '\n': if (withend) baos.write(c); break loop;
|
||||
default: baos.write(c); break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while ( (c = f.read()) > 0 )
|
||||
while ( (c = f.read()) >= 0 )
|
||||
baos.write(c);
|
||||
}
|
||||
} catch ( EOFException e ) {
|
||||
c = -1;
|
||||
}
|
||||
return ( c < 0 && baos.size() == 0 )?
|
||||
return ( c < 0 && baos.size() == 0 )?
|
||||
(LuaValue) NIL:
|
||||
(LuaValue) LuaString.valueUsing(baos.toByteArray());
|
||||
}
|
||||
public static LuaValue freadline(File f) throws IOException {
|
||||
return freaduntil(f,true);
|
||||
public static LuaValue freadline(File f,boolean withend) throws IOException {
|
||||
return freaduntil(f,true,withend);
|
||||
}
|
||||
public static LuaValue freadall(File f) throws IOException {
|
||||
int n = f.remaining();
|
||||
if ( n >= 0 ) {
|
||||
return freadbytes(f, n);
|
||||
return n == 0 ? EMPTYSTRING : freadbytes(f, n);
|
||||
} else {
|
||||
return freaduntil(f,false);
|
||||
return freaduntil(f,false,false);
|
||||
}
|
||||
}
|
||||
public static LuaValue freadnumber(File f) throws IOException {
|
||||
@@ -619,7 +677,7 @@ public class IoLib extends TwoArgFunction {
|
||||
if ( baos != null )
|
||||
baos.write( c );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -27,21 +27,21 @@ import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LuaFunction} common to Java functions exposed to lua.
|
||||
* Subclass of {@link LuaFunction} common to Java functions exposed to lua.
|
||||
* <p>
|
||||
* To provide for common implementations in JME and JSE,
|
||||
* To provide for common implementations in JME and JSE,
|
||||
* library functions are typically grouped on one or more library classes
|
||||
* and an opcode per library function is defined and used to key the switch
|
||||
* to the correct function within the library.
|
||||
* to the correct function within the library.
|
||||
* <p>
|
||||
* Since lua functions can be called with too few or too many arguments,
|
||||
* and there are overloaded {@link LuaValue#call()} functions with varying
|
||||
* Since lua functions can be called with too few or too many arguments,
|
||||
* and there are overloaded {@link LuaValue#call()} functions with varying
|
||||
* number of arguments, a Java function exposed in lua needs to handle the
|
||||
* argument fixup when a function is called with a number of arguments
|
||||
* differs from that expected.
|
||||
* argument fixup when a function is called with a number of arguments
|
||||
* differs from that expected.
|
||||
* <p>
|
||||
* To simplify the creation of library functions,
|
||||
* there are 5 direct subclasses to handle common cases based on number of
|
||||
* To simplify the creation of library functions,
|
||||
* there are 5 direct subclasses to handle common cases based on number of
|
||||
* argument values and number of return return values.
|
||||
* <ul>
|
||||
* <li>{@link ZeroArgFunction}</li>
|
||||
@@ -51,13 +51,13 @@ import org.luaj.vm2.Varargs;
|
||||
* <li>{@link VarArgFunction}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* To be a Java library that can be loaded via {@code require}, it should have
|
||||
* a public constructor that returns a {@link LuaValue} that, when executed,
|
||||
* initializes the library.
|
||||
* <p>
|
||||
* For example, the following code will implement a library called "hyperbolic"
|
||||
* To be a Java library that can be loaded via {@code require}, it should have
|
||||
* a public constructor that returns a {@link LuaValue} that, when executed,
|
||||
* initializes the library.
|
||||
* <p>
|
||||
* For example, the following code will implement a library called "hyperbolic"
|
||||
* with two functions, "sinh", and "cosh":
|
||||
<pre> {@code
|
||||
<pre> {@code
|
||||
* import org.luaj.vm2.LuaValue;
|
||||
* import org.luaj.vm2.lib.*;
|
||||
*
|
||||
@@ -86,13 +86,13 @@ import org.luaj.vm2.Varargs;
|
||||
* }
|
||||
*}
|
||||
*}</pre>
|
||||
* The default constructor is used to instantiate the library
|
||||
* The default constructor is used to instantiate the library
|
||||
* in response to {@code require 'hyperbolic'} statement,
|
||||
* provided it is on Java"s class path.
|
||||
* This instance is then invoked with 2 arguments: the name supplied to require(),
|
||||
* and the environment for this function. The library may ignore these, or use
|
||||
* them to leave side effects in the global environment, for example.
|
||||
* In the previous example, two functions are created, 'sinh', and 'cosh', and placed
|
||||
* provided it is on Java"s class path.
|
||||
* This instance is then invoked with 2 arguments: the name supplied to require(),
|
||||
* and the environment for this function. The library may ignore these, or use
|
||||
* them to leave side effects in the global environment, for example.
|
||||
* In the previous example, two functions are created, 'sinh', and 'cosh', and placed
|
||||
* into a global table called 'hyperbolic' using the supplied 'env' argument.
|
||||
* <p>
|
||||
* To test it, a script such as this can be used:
|
||||
@@ -105,7 +105,7 @@ import org.luaj.vm2.Varargs;
|
||||
* end
|
||||
* print( 'sinh(.5)', hyperbolic.sinh(.5) )
|
||||
* print( 'cosh(.5)', hyperbolic.cosh(.5) )
|
||||
* }</pre>
|
||||
* }</pre>
|
||||
* <p>
|
||||
* It should produce something like:
|
||||
* <pre> {@code
|
||||
@@ -115,16 +115,16 @@ import org.luaj.vm2.Varargs;
|
||||
* k,v sinh function: 3dbbd242
|
||||
* sinh(.5) 0.5210953
|
||||
* cosh(.5) 1.127626
|
||||
* }</pre>
|
||||
* <p>
|
||||
* See the source code in any of the library functions
|
||||
* such as {@link BaseLib} or {@link TableLib} for other examples.
|
||||
* }</pre>
|
||||
* <p>
|
||||
* See the source code in any of the library functions
|
||||
* such as {@link BaseLib} or {@link TableLib} for other examples.
|
||||
*/
|
||||
abstract public class LibFunction extends LuaFunction {
|
||||
|
||||
/** User-defined opcode to differentiate between instances of the library function class.
|
||||
/** User-defined opcode to differentiate between instances of the library function class.
|
||||
* <p>
|
||||
* Subclass will typicall switch on this value to provide the specific behavior for each function.
|
||||
* Subclass will typicall switch on this value to provide the specific behavior for each function.
|
||||
*/
|
||||
protected int opcode;
|
||||
|
||||
@@ -135,37 +135,37 @@ abstract public class LibFunction extends LuaFunction {
|
||||
protected String name;
|
||||
|
||||
/** Default constructor for use by subclasses */
|
||||
protected LibFunction() {
|
||||
protected LibFunction() {
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return name != null? name: super.tojstring();
|
||||
return name != null ? "function: " + name : super.tojstring();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a set of library functions.
|
||||
/**
|
||||
* Bind a set of library functions.
|
||||
* <p>
|
||||
* An array of names is provided, and the first name is bound
|
||||
* with opcode = 0, second with 1, etc.
|
||||
* @param env The environment to apply to each bound function
|
||||
* An array of names is provided, and the first name is bound
|
||||
* with opcode = 0, second with 1, etc.
|
||||
* @param env The environment to apply to each bound function
|
||||
* @param factory the Class to instantiate for each bound function
|
||||
* @param names array of String names, one for each function.
|
||||
* @see #bind(LuaValue, Class, String[], int)
|
||||
* @see #bind(LuaValue, Class, String[], int)
|
||||
*/
|
||||
protected void bind(LuaValue env, Class factory, String[] names ) {
|
||||
bind( env, factory, names, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a set of library functions, with an offset
|
||||
/**
|
||||
* Bind a set of library functions, with an offset
|
||||
* <p>
|
||||
* An array of names is provided, and the first name is bound
|
||||
* with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc.
|
||||
* @param env The environment to apply to each bound function
|
||||
* An array of names is provided, and the first name is bound
|
||||
* with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc.
|
||||
* @param env The environment to apply to each bound function
|
||||
* @param factory the Class to instantiate for each bound function
|
||||
* @param names array of String names, one for each function.
|
||||
* @param firstopcode the first opcode to use
|
||||
* @see #bind(LuaValue, Class, String[])
|
||||
* @param firstopcode the first opcode to use
|
||||
* @see #bind(LuaValue, Class, String[])
|
||||
*/
|
||||
protected void bind(LuaValue env, Class factory, String[] names, int firstopcode ) {
|
||||
try {
|
||||
@@ -178,7 +178,7 @@ abstract public class LibFunction extends LuaFunction {
|
||||
} catch ( Exception e ) {
|
||||
throw new LuaError( "bind failed: "+e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Java code generation utility to allocate storage for upvalue, leave it empty */
|
||||
protected static LuaValue[] newupe() {
|
||||
@@ -196,7 +196,7 @@ abstract public class LibFunction extends LuaFunction {
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return argerror(1,"value");
|
||||
return argerror(1,"value expected");
|
||||
}
|
||||
public LuaValue call(LuaValue a) {
|
||||
return call();
|
||||
@@ -219,4 +219,4 @@ abstract public class LibFunction extends LuaFunction {
|
||||
default: return call(args.arg1(),args.arg(2),args.arg(3),args.arg(4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
|
||||
* library.
|
||||
* <p>
|
||||
* It contains only the math library support that is possible on JME.
|
||||
* For a more complete implementation based on math functions specific to JSE
|
||||
* use {@link org.luaj.vm2.lib.jse.JseMathLib}.
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
|
||||
* library.
|
||||
* <p>
|
||||
* It contains only the math library support that is possible on JME.
|
||||
* For a more complete implementation based on math functions specific to JSE
|
||||
* use {@link org.luaj.vm2.lib.jse.JseMathLib}.
|
||||
* In Particular the following math functions are <b>not</b> implemented by this library:
|
||||
* <ul>
|
||||
* <li>acos</li>
|
||||
@@ -47,21 +47,21 @@ import org.luaj.vm2.Varargs;
|
||||
* <li>atan2</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The implementations of {@code exp()} and {@code pow()} are constructed by
|
||||
* The implementations of {@code exp()} and {@code pow()} are constructed by
|
||||
* hand for JME, so will be slower and less accurate than when executed on the JSE platform.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
|
||||
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* When using {@link org.luaj.vm2.lib.jse.JsePlatform} as in this example,
|
||||
* the subclass {@link org.luaj.vm2.lib.jse.JseMathLib} will
|
||||
* When using {@link org.luaj.vm2.lib.jse.JsePlatform} as in this example,
|
||||
* the subclass {@link org.luaj.vm2.lib.jse.JseMathLib} will
|
||||
* be included, which also includes this base functionality.
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
@@ -70,8 +70,8 @@ import org.luaj.vm2.Varargs;
|
||||
* globals.load(new MathLib());
|
||||
* System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* @see LibFunction
|
||||
@@ -87,8 +87,8 @@ public class MathLib extends TwoArgFunction {
|
||||
*/
|
||||
public static MathLib MATHLIB = null;
|
||||
|
||||
/** Construct a MathLib, which can be initialized by calling it with a
|
||||
* modname string, and a global environment table as arguments using
|
||||
/** Construct a MathLib, which can be initialized by calling it with a
|
||||
* modname string, and a global environment table as arguments using
|
||||
* {@link #call(LuaValue, LuaValue)}. */
|
||||
public MathLib() {
|
||||
MATHLIB = this;
|
||||
@@ -125,7 +125,7 @@ public class MathLib extends TwoArgFunction {
|
||||
math.set("sqrt", new sqrt());
|
||||
math.set("tan", new tan());
|
||||
env.set("math", math);
|
||||
env.get("package").get("loaded").set("math", math);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("math", math);
|
||||
return math;
|
||||
}
|
||||
|
||||
@@ -158,15 +158,17 @@ public class MathLib extends TwoArgFunction {
|
||||
exp(MathLib mathlib) {
|
||||
this.mathlib = mathlib;
|
||||
}
|
||||
protected double call(double d) {
|
||||
return mathlib.dpow_lib(Math.E,d);
|
||||
}
|
||||
protected double call(double d) {
|
||||
return mathlib.dpow_lib(Math.E,d);
|
||||
}
|
||||
}
|
||||
|
||||
static final class fmod extends BinaryOp {
|
||||
protected double call(double x, double y) {
|
||||
double q = x/y;
|
||||
return x - y * (q>=0? Math.floor(q): Math.ceil(q));
|
||||
static final class fmod extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue xv, LuaValue yv) {
|
||||
if (xv.islong() && yv.islong()) {
|
||||
return valueOf(xv.tolong() % yv.tolong());
|
||||
}
|
||||
return valueOf(xv.checkdouble() % yv.checkdouble());
|
||||
}
|
||||
}
|
||||
static final class ldexp extends BinaryOp {
|
||||
@@ -194,27 +196,36 @@ public class MathLib extends TwoArgFunction {
|
||||
|
||||
static class max extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
double m = args.checkdouble(1);
|
||||
for ( int i=2,n=args.narg(); i<=n; ++i )
|
||||
m = Math.max(m,args.checkdouble(i));
|
||||
return valueOf(m);
|
||||
LuaValue m = args.checkvalue(1);
|
||||
for ( int i=2,n=args.narg(); i<=n; ++i ) {
|
||||
LuaValue v = args.checkvalue(i);
|
||||
if (m.lt_b(v)) m = v;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
static class min extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
double m = args.checkdouble(1);
|
||||
for ( int i=2,n=args.narg(); i<=n; ++i )
|
||||
m = Math.min(m,args.checkdouble(i));
|
||||
return valueOf(m);
|
||||
LuaValue m = args.checkvalue(1);
|
||||
for ( int i=2,n=args.narg(); i<=n; ++i ) {
|
||||
LuaValue v = args.checkvalue(i);
|
||||
if (v.lt_b(m)) m = v;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
static class modf extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
double x = args.checkdouble(1);
|
||||
LuaValue n = args.arg1();
|
||||
/* number is its own integer part, no fractional part */
|
||||
if (n.islong()) return varargsOf(n, valueOf(0.0));
|
||||
double x = n.checkdouble();
|
||||
/* integer part (rounds toward zero) */
|
||||
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
|
||||
double fracPart = x - intPart;
|
||||
/* fractional part (test needed for inf/-inf) */
|
||||
double fracPart = x == intPart ? 0.0 : x - intPart;
|
||||
return varargsOf( valueOf(intPart), valueOf(fracPart) );
|
||||
}
|
||||
}
|
||||
@@ -252,26 +263,26 @@ public class MathLib extends TwoArgFunction {
|
||||
|
||||
/** compute power using installed math library, or default if there is no math library installed */
|
||||
public static LuaValue dpow(double a, double b) {
|
||||
return LuaDouble.valueOf(
|
||||
return LuaDouble.valueOf(
|
||||
MATHLIB!=null?
|
||||
MATHLIB.dpow_lib(a,b):
|
||||
dpow_default(a,b) );
|
||||
}
|
||||
public static double dpow_d(double a, double b) {
|
||||
return MATHLIB!=null?
|
||||
MATHLIB.dpow_lib(a,b):
|
||||
return MATHLIB!=null?
|
||||
MATHLIB.dpow_lib(a,b):
|
||||
dpow_default(a,b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to override default dpow behavior with faster implementation.
|
||||
/**
|
||||
* Hook to override default dpow behavior with faster implementation.
|
||||
*/
|
||||
public double dpow_lib(double a, double b) {
|
||||
return dpow_default(a,b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default JME version computes using longhand heuristics.
|
||||
/**
|
||||
* Default JME version computes using longhand heuristics.
|
||||
*/
|
||||
protected static double dpow_default(double a, double b) {
|
||||
if ( b < 0 )
|
||||
|
||||
@@ -35,17 +35,17 @@ import org.luaj.vm2.Varargs;
|
||||
* Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
|
||||
* <p>
|
||||
* It is a usable base with simplified stub functions
|
||||
* for library functions that cannot be implemented uniformly
|
||||
* on Jse and Jme.
|
||||
* for library functions that cannot be implemented uniformly
|
||||
* on Jse and Jme.
|
||||
* <p>
|
||||
* This can be installed as-is on either platform, or extended
|
||||
* This can be installed as-is on either platform, or extended
|
||||
* and refined to be used in a complete Jse implementation.
|
||||
* <p>
|
||||
* Because the nature of the {@code os} library is to encapsulate
|
||||
* os-specific features, the behavior of these functions varies considerably
|
||||
* from their counterparts in the C platform.
|
||||
* Because the nature of the {@code os} library is to encapsulate
|
||||
* os-specific features, the behavior of these functions varies considerably
|
||||
* from their counterparts in the C platform.
|
||||
* <p>
|
||||
* The following functions have limited implementations of features
|
||||
* The following functions have limited implementations of features
|
||||
* that are not supported well on Jme:
|
||||
* <ul>
|
||||
* <li>{@code execute()}</li>
|
||||
@@ -54,7 +54,7 @@ import org.luaj.vm2.Varargs;
|
||||
* <li>{@code tmpname()}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
@@ -63,7 +63,7 @@ import org.luaj.vm2.Varargs;
|
||||
* In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseOsLib} library will be loaded, which will include
|
||||
* the base functionality provided by this class.
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
@@ -80,8 +80,8 @@ import org.luaj.vm2.Varargs;
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.8">http://www.lua.org/manual/5.1/manual.html#5.8</a>
|
||||
*/
|
||||
public class OsLib extends TwoArgFunction {
|
||||
public static String TMP_PREFIX = ".luaj";
|
||||
public static String TMP_SUFFIX = "tmp";
|
||||
public static final String TMP_PREFIX = ".luaj";
|
||||
public static final String TMP_SUFFIX = "tmp";
|
||||
|
||||
private static final int CLOCK = 0;
|
||||
private static final int DATE = 1;
|
||||
@@ -114,8 +114,8 @@ public class OsLib extends TwoArgFunction {
|
||||
|
||||
protected Globals globals;
|
||||
|
||||
/**
|
||||
* Create and OsLib instance.
|
||||
/**
|
||||
* Create and OsLib instance.
|
||||
*/
|
||||
public OsLib() {
|
||||
}
|
||||
@@ -132,7 +132,7 @@ public class OsLib extends TwoArgFunction {
|
||||
for (int i = 0; i < NAMES.length; ++i)
|
||||
os.set(NAMES[i], new OsLibFunc(i, NAMES[i]));
|
||||
env.set("os", os);
|
||||
env.get("package").get("loaded").set("os", os);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("os", os);
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -200,8 +200,8 @@ public class OsLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an approximation of the amount in seconds of CPU time used by
|
||||
* the program. For luaj this simple returns the elapsed time since the
|
||||
* @return an approximation of the amount in seconds of CPU time used by
|
||||
* the program. For luaj this simple returns the elapsed time since the
|
||||
* OsLib class was loaded.
|
||||
*/
|
||||
protected double clock() {
|
||||
@@ -209,7 +209,7 @@ public class OsLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of seconds from time t1 to time t2.
|
||||
* Returns the number of seconds from time t1 to time t2.
|
||||
* In POSIX, Windows, and some other systems, this value is exactly t2-t1.
|
||||
* @param t2
|
||||
* @param t1
|
||||
@@ -220,21 +220,21 @@ public class OsLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* If the time argument is present, this is the time to be formatted
|
||||
* (see the os.time function for a description of this value).
|
||||
* If the time argument is present, this is the time to be formatted
|
||||
* (see the os.time function for a description of this value).
|
||||
* Otherwise, date formats the current time.
|
||||
*
|
||||
* Date returns the date as a string,
|
||||
* Date returns the date as a string,
|
||||
* formatted according to the same rules as ANSII strftime, but without
|
||||
* support for %g, %G, or %V.
|
||||
*
|
||||
* When called without arguments, date returns a reasonable date and
|
||||
* time representation that depends on the host system and on the
|
||||
* When called without arguments, date returns a reasonable date and
|
||||
* time representation that depends on the host system and on the
|
||||
* current locale (that is, os.date() is equivalent to os.date("%c")).
|
||||
*
|
||||
* @param format
|
||||
*
|
||||
* @param format
|
||||
* @param time time since epoch, or -1 if not supplied
|
||||
* @return a LString or a LTable containing date and time,
|
||||
* @return a LString or a LTable containing date and time,
|
||||
* formatted according to the given string format.
|
||||
*/
|
||||
public String date(String format, double time) {
|
||||
@@ -277,8 +277,8 @@ public class OsLib extends TwoArgFunction {
|
||||
break;
|
||||
case 'B':
|
||||
result.append(MonthName[d.get(Calendar.MONTH)]);
|
||||
break;
|
||||
case 'c':
|
||||
break;
|
||||
case 'c':
|
||||
result.append(date("%a %b %d %H:%M:%S %Y", time));
|
||||
break;
|
||||
case 'd':
|
||||
@@ -314,7 +314,7 @@ public class OsLib extends TwoArgFunction {
|
||||
case 'w':
|
||||
result.append(String.valueOf((d.get(Calendar.DAY_OF_WEEK)+6)%7));
|
||||
break;
|
||||
case 'W':
|
||||
case 'W':
|
||||
result.append(String.valueOf(weekNumber(d, 1)));
|
||||
break;
|
||||
case 'x':
|
||||
@@ -372,7 +372,7 @@ public class OsLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
private int timeZoneOffset(Calendar d) {
|
||||
int localStandarTimeMillis = (
|
||||
int localStandarTimeMillis = (
|
||||
d.get(Calendar.HOUR_OF_DAY) * 3600 +
|
||||
d.get(Calendar.MINUTE) * 60 +
|
||||
d.get(Calendar.SECOND)) * 1000;
|
||||
@@ -381,28 +381,28 @@ public class OsLib extends TwoArgFunction {
|
||||
d.get(Calendar.YEAR),
|
||||
d.get(Calendar.MONTH),
|
||||
d.get(Calendar.DAY_OF_MONTH),
|
||||
d.get(Calendar.DAY_OF_WEEK),
|
||||
d.get(Calendar.DAY_OF_WEEK),
|
||||
localStandarTimeMillis) / 1000;
|
||||
}
|
||||
|
||||
private boolean isDaylightSavingsTime(Calendar d) {
|
||||
return timeZoneOffset(d) != d.getTimeZone().getRawOffset() / 1000;
|
||||
return timeZoneOffset(d) != d.getTimeZone().getRawOffset() / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is equivalent to the C function system.
|
||||
* It passes command to be executed by an operating system shell.
|
||||
* It returns a status code, which is system-dependent.
|
||||
* If command is absent, then it returns nonzero if a shell
|
||||
/**
|
||||
* This function is equivalent to the C function system.
|
||||
* It passes command to be executed by an operating system shell.
|
||||
* It returns a status code, which is system-dependent.
|
||||
* If command is absent, then it returns nonzero if a shell
|
||||
* is available and zero otherwise.
|
||||
* @param command command to pass to the system
|
||||
*/
|
||||
*/
|
||||
protected Varargs execute(String command) {
|
||||
return varargsOf(NIL, valueOf("exit"), ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the C function exit, with an optional code, to terminate the host program.
|
||||
* Calls the C function exit, with an optional code, to terminate the host program.
|
||||
* @param code
|
||||
*/
|
||||
protected void exit(int code) {
|
||||
@@ -415,13 +415,13 @@ public class OsLib extends TwoArgFunction {
|
||||
* or null if the variable is not defined in either environment.
|
||||
*
|
||||
* The default implementation, which is used by the JmePlatform,
|
||||
* only queryies System.getProperty().
|
||||
* only queryies System.getProperty().
|
||||
*
|
||||
* The JsePlatform overrides this behavior and returns the
|
||||
* environment variable value using System.getenv() if it exists,
|
||||
* environment variable value using System.getenv() if it exists,
|
||||
* or the System property value if it does not.
|
||||
*
|
||||
* A SecurityException may be thrown if access is not allowed
|
||||
* A SecurityException may be thrown if access is not allowed
|
||||
* for 'varname'.
|
||||
* @param varname
|
||||
* @return String value, or null if not defined
|
||||
@@ -431,10 +431,10 @@ public class OsLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the file or directory with the given name.
|
||||
* Directories must be empty to be removed.
|
||||
* Deletes the file or directory with the given name.
|
||||
* Directories must be empty to be removed.
|
||||
* If this function fails, it throws and IOException
|
||||
*
|
||||
*
|
||||
* @param filename
|
||||
* @throws IOException if it fails
|
||||
*/
|
||||
@@ -443,9 +443,9 @@ public class OsLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames file or directory named oldname to newname.
|
||||
* Renames file or directory named oldname to newname.
|
||||
* If this function fails,it throws and IOException
|
||||
*
|
||||
*
|
||||
* @param oldname old file name
|
||||
* @param newname new file name
|
||||
* @throws IOException if it fails
|
||||
@@ -455,21 +455,21 @@ public class OsLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current locale of the program. locale is a string specifying
|
||||
* a locale; category is an optional string describing which category to change:
|
||||
* "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category
|
||||
* is "all".
|
||||
* Sets the current locale of the program. locale is a string specifying
|
||||
* a locale; category is an optional string describing which category to change:
|
||||
* "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category
|
||||
* is "all".
|
||||
*
|
||||
* If locale is the empty string, the current locale is set to an implementation-
|
||||
* defined native locale. If locale is the string "C", the current locale is set
|
||||
* defined native locale. If locale is the string "C", the current locale is set
|
||||
* to the standard C locale.
|
||||
*
|
||||
* When called with null as the first argument, this function only returns the
|
||||
* When called with null as the first argument, this function only returns the
|
||||
* name of the current locale for the given category.
|
||||
*
|
||||
*
|
||||
* @param locale
|
||||
* @param category
|
||||
* @return the name of the new locale, or null if the request
|
||||
* @return the name of the new locale, or null if the request
|
||||
* cannot be honored.
|
||||
*/
|
||||
protected String setlocale(String locale, String category) {
|
||||
@@ -477,10 +477,10 @@ public class OsLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time when called without arguments,
|
||||
* or a time representing the date and time specified by the given table.
|
||||
* This table must have fields year, month, and day,
|
||||
* and may have fields hour, min, sec, and isdst
|
||||
* Returns the current time when called without arguments,
|
||||
* or a time representing the date and time specified by the given table.
|
||||
* This table must have fields year, month, and day,
|
||||
* and may have fields hour, min, sec, and isdst
|
||||
* (for a description of these fields, see the os.date function).
|
||||
* @param table
|
||||
* @return long value for the time
|
||||
@@ -504,15 +504,15 @@ public class OsLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with a file name that can be used for a temporary file.
|
||||
* The file must be explicitly opened before its use and explicitly removed
|
||||
* Returns a string with a file name that can be used for a temporary file.
|
||||
* The file must be explicitly opened before its use and explicitly removed
|
||||
* when no longer needed.
|
||||
*
|
||||
* On some systems (POSIX), this function also creates a file with that name,
|
||||
* to avoid security risks. (Someone else might create the file with wrong
|
||||
* permissions in the time between getting the name and creating the file.)
|
||||
* You still have to open the file to use it and to remove it (even if you
|
||||
* do not use it).
|
||||
* On some systems (POSIX), this function also creates a file with that name,
|
||||
* to avoid security risks. (Someone else might create the file with wrong
|
||||
* permissions in the time between getting the name and creating the file.)
|
||||
* You still have to open the file to use it and to remove it (even if you
|
||||
* do not use it).
|
||||
*
|
||||
* @return String filename to use
|
||||
*/
|
||||
|
||||
@@ -30,9 +30,9 @@ import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard package and module
|
||||
* library functions.
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard package and module
|
||||
* library functions.
|
||||
*
|
||||
* <h3>Lua Environment Variables</h3>
|
||||
* The following variables are available to lua scrips when this library has been loaded:
|
||||
@@ -50,14 +50,14 @@ import org.luaj.vm2.Varargs;
|
||||
* </ul>
|
||||
*
|
||||
* <h3>Loading</h3>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("require").call"foo") );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
@@ -67,8 +67,8 @@ import org.luaj.vm2.Varargs;
|
||||
* } </pre>
|
||||
* <h3>Limitations</h3>
|
||||
* This library has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* However, the default filesystem search semantics are different and delegated to the bas library
|
||||
* as outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib} documentation.
|
||||
* However, the default filesystem search semantics are different and delegated to the bas library
|
||||
* as outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib} documentation.
|
||||
* <p>
|
||||
* @see LibFunction
|
||||
* @see BaseLib
|
||||
@@ -81,23 +81,26 @@ public class PackageLib extends TwoArgFunction {
|
||||
|
||||
/** The default value to use for package.path. This can be set with the system property
|
||||
* <code>"luaj.package.path"</code>, and is <code>"?.lua"</code> by default. */
|
||||
public static String DEFAULT_LUA_PATH;
|
||||
public static final String DEFAULT_LUA_PATH;
|
||||
static {
|
||||
String path = null;
|
||||
try {
|
||||
DEFAULT_LUA_PATH = System.getProperty("luaj.package.path");
|
||||
path = System.getProperty("luaj.package.path");
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.toString());
|
||||
}
|
||||
if (DEFAULT_LUA_PATH == null)
|
||||
DEFAULT_LUA_PATH = "?.lua";
|
||||
if (path == null) {
|
||||
path = "?.lua";
|
||||
}
|
||||
DEFAULT_LUA_PATH = path;
|
||||
}
|
||||
|
||||
private static final LuaString _LOADED = valueOf("loaded");
|
||||
static final LuaString _LOADED = valueOf("loaded");
|
||||
private static final LuaString _LOADLIB = valueOf("loadlib");
|
||||
private static final LuaString _PRELOAD = valueOf("preload");
|
||||
private static final LuaString _PATH = valueOf("path");
|
||||
private static final LuaString _SEARCHPATH = valueOf("searchpath");
|
||||
private static final LuaString _SEARCHERS = valueOf("searchers");
|
||||
static final LuaString _PRELOAD = valueOf("preload");
|
||||
static final LuaString _PATH = valueOf("path");
|
||||
static final LuaString _SEARCHPATH = valueOf("searchpath");
|
||||
static final LuaString _SEARCHERS = valueOf("searchers");
|
||||
|
||||
/** The globals that were used to load this library. */
|
||||
Globals globals;
|
||||
@@ -141,6 +144,7 @@ public class PackageLib extends TwoArgFunction {
|
||||
searchers.set(2, lua_searcher = new lua_searcher());
|
||||
searchers.set(3, java_searcher = new java_searcher());
|
||||
package_.set(_SEARCHERS, searchers);
|
||||
package_.set("config", FILE_SEP + "\n;\n?\n!\n-\n");
|
||||
package_.get(_LOADED).set("package", package_);
|
||||
env.set("package", package_);
|
||||
globals.package_ = this;
|
||||
@@ -153,7 +157,7 @@ public class PackageLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
|
||||
/** Set the lua path used by this library instance to a new value.
|
||||
/** Set the lua path used by this library instance to a new value.
|
||||
* Merely sets the value of {@link path} to be used in subsequent searches. */
|
||||
public void setLuaPath( String newLuaPath ) {
|
||||
package_.set(_PATH, LuaValue.valueOf(newLuaPath));
|
||||
@@ -165,33 +169,33 @@ public class PackageLib extends TwoArgFunction {
|
||||
|
||||
// ======================== Package loading =============================
|
||||
|
||||
/**
|
||||
/**
|
||||
* require (modname)
|
||||
*
|
||||
* Loads the given module. The function starts by looking into the package.loaded table
|
||||
* to determine whether modname is already loaded. If it is, then require returns the value
|
||||
* Loads the given module. The function starts by looking into the package.loaded table
|
||||
* to determine whether modname is already loaded. If it is, then require returns the value
|
||||
* stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.
|
||||
*
|
||||
* To find a loader, require is guided by the package.searchers sequence.
|
||||
* By changing this sequence, we can change how require looks for a module.
|
||||
* To find a loader, require is guided by the package.searchers sequence.
|
||||
* By changing this sequence, we can change how require looks for a module.
|
||||
* The following explanation is based on the default configuration for package.searchers.
|
||||
*
|
||||
* First require queries package.preload[modname]. If it has a value, this value
|
||||
* (which should be a function) is the loader. Otherwise require searches for a Lua loader using
|
||||
* the path stored in package.path. If that also fails, it searches for a Java loader using
|
||||
* First require queries package.preload[modname]. If it has a value, this value
|
||||
* (which should be a function) is the loader. Otherwise require searches for a Lua loader using
|
||||
* the path stored in package.path. If that also fails, it searches for a Java loader using
|
||||
* the classpath, using the public default constructor, and casting the instance to LuaFunction.
|
||||
*
|
||||
* Once a loader is found, require calls the loader with two arguments: modname and an extra value
|
||||
* Once a loader is found, require calls the loader with two arguments: modname and an extra value
|
||||
* dependent on how it got the loader. If the loader came from a file, this extra value is the file name.
|
||||
* If the loader is a Java instance of LuaFunction, this extra value is the environment.
|
||||
* If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname].
|
||||
* If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname],
|
||||
* If the loader is a Java instance of LuaFunction, this extra value is the environment.
|
||||
* If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname].
|
||||
* If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname],
|
||||
* then require assigns true to this entry.
|
||||
* In any case, require returns the final value of package.loaded[modname].
|
||||
*
|
||||
*
|
||||
* If there is any error loading or running the module, or if it cannot find any loader for the module,
|
||||
* then require raises an error.
|
||||
*/
|
||||
*/
|
||||
public class require extends OneArgFunction {
|
||||
public LuaValue call( LuaValue arg ) {
|
||||
LuaString name = arg.checkstring();
|
||||
@@ -210,7 +214,7 @@ public class PackageLib extends TwoArgFunction {
|
||||
for ( int i=1; true; i++ ) {
|
||||
LuaValue searcher = tbl.get(i);
|
||||
if ( searcher.isnil() ) {
|
||||
error( "module '"+name+"' not found: "+name+sb );
|
||||
error( "module '"+name+"' not found: "+name+sb );
|
||||
}
|
||||
|
||||
/* call loader with module name as argument */
|
||||
@@ -226,14 +230,14 @@ public class PackageLib extends TwoArgFunction {
|
||||
result = loader.arg1().call(name, loader.arg(2));
|
||||
if ( ! result.isnil() )
|
||||
loaded.set( name, result );
|
||||
else if ( (result = loaded.get(name)) == _SENTINEL )
|
||||
else if ( (result = loaded.get(name)) == _SENTINEL )
|
||||
loaded.set( name, result = LuaValue.TRUE );
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class loadlib extends VarArgFunction {
|
||||
public Varargs loadlib( Varargs args ) {
|
||||
public Varargs invoke( Varargs args ) {
|
||||
args.checkstring(1);
|
||||
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
|
||||
}
|
||||
@@ -243,7 +247,7 @@ public class PackageLib extends TwoArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaString name = args.checkstring(1);
|
||||
LuaValue val = package_.get(_PRELOAD).get(name);
|
||||
return val.isnil()?
|
||||
return val.isnil()?
|
||||
valueOf("\n\tno field package.preload['"+name+"']"):
|
||||
val;
|
||||
}
|
||||
@@ -252,11 +256,10 @@ public class PackageLib extends TwoArgFunction {
|
||||
public class lua_searcher extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaString name = args.checkstring(1);
|
||||
InputStream is = null;
|
||||
|
||||
// get package path
|
||||
LuaValue path = package_.get(_PATH);
|
||||
if ( ! path.isstring() )
|
||||
if ( ! path.isstring() )
|
||||
return valueOf("package.path is not a string");
|
||||
|
||||
// get the searchpath function.
|
||||
@@ -268,7 +271,7 @@ public class PackageLib extends TwoArgFunction {
|
||||
LuaString filename = v.arg1().strvalue();
|
||||
|
||||
// Try to load the file.
|
||||
v = globals.loadfile(filename.tojstring());
|
||||
v = globals.loadfile(filename.tojstring());
|
||||
if ( v.arg1().isfunction() )
|
||||
return LuaValue.varargsOf(v.arg1(), filename);
|
||||
|
||||
@@ -353,9 +356,9 @@ public class PackageLib extends TwoArgFunction {
|
||||
StringBuffer sb = new StringBuffer(j);
|
||||
for ( int i=0; i<j; i++ ) {
|
||||
c = filename.charAt(i);
|
||||
sb.append(
|
||||
sb.append(
|
||||
(isClassnamePart(c))? c:
|
||||
((c=='/') || (c=='\\'))? '.': '_' );
|
||||
((c=='/') || (c=='\\'))? '.': '_' );
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -374,5 +377,5 @@ public class PackageLib extends TwoArgFunction {
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,32 +24,32 @@ package org.luaj.vm2.lib;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.Buffer;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.compiler.DumpState;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code string}
|
||||
* library.
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code string}
|
||||
* library.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("string").get("upper").call( LuaValue.valueOf("abcde") ) );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new StringLib());
|
||||
* globals.load(new JseStringLib());
|
||||
* System.out.println( globals.get("string").get("upper").call( LuaValue.valueOf("abcde") ) );
|
||||
* } </pre>
|
||||
* <p>
|
||||
@@ -61,8 +61,8 @@ import org.luaj.vm2.compiler.DumpState;
|
||||
*/
|
||||
public class StringLib extends TwoArgFunction {
|
||||
|
||||
/** Construct a StringLib, which can be initialized by calling it with a
|
||||
* modname string, and a global environment table as arguments using
|
||||
/** Construct a StringLib, which can be initialized by calling it with a
|
||||
* modname string, and a global environment table as arguments using
|
||||
* {@link #call(LuaValue, LuaValue)}. */
|
||||
public StringLib() {
|
||||
}
|
||||
@@ -75,16 +75,16 @@ public class StringLib extends TwoArgFunction {
|
||||
* If the shared strings metatable instance is null, will set the metatable as
|
||||
* the global shared metatable for strings.
|
||||
* <P>
|
||||
* All tables and metatables are read-write by default so if this will be used in
|
||||
* a server environment, sandboxing should be used. In particular, the
|
||||
* All tables and metatables are read-write by default so if this will be used in
|
||||
* a server environment, sandboxing should be used. In particular, the
|
||||
* {@link LuaString#s_metatable} table should probably be made read-only.
|
||||
* @param modname the module name supplied if this is loaded via 'require'.
|
||||
* @param env the environment to load into, typically a Globals instance.
|
||||
*/
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
LuaTable string = new LuaTable();
|
||||
string.set("byte", new byte_());
|
||||
string.set("char", new char_());
|
||||
string.set("byte", new _byte());
|
||||
string.set("char", new _char());
|
||||
string.set("dump", new dump());
|
||||
string.set("find", new find());
|
||||
string.set("format", new format());
|
||||
@@ -97,17 +97,17 @@ public class StringLib extends TwoArgFunction {
|
||||
string.set("reverse", new reverse());
|
||||
string.set("sub", new sub());
|
||||
string.set("upper", new upper());
|
||||
LuaTable mt = LuaValue.tableOf(
|
||||
new LuaValue[] { INDEX, string });
|
||||
|
||||
env.set("string", string);
|
||||
env.get("package").get("loaded").set("string", string);
|
||||
if (LuaString.s_metatable == null)
|
||||
LuaString.s_metatable = mt;
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("string", string);
|
||||
if (LuaString.s_metatable == null) {
|
||||
LuaString.s_metatable = LuaValue.tableOf(new LuaValue[] { INDEX, string });
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* string.byte (s [, i [, j]])
|
||||
* string.byte (s [, i [, j]])
|
||||
*
|
||||
* Returns the internal numerical codes of the
|
||||
* characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the
|
||||
@@ -117,7 +117,7 @@ public class StringLib extends TwoArgFunction {
|
||||
*
|
||||
* @param args the calling args
|
||||
*/
|
||||
static final class byte_ extends VarArgFunction {
|
||||
static final class _byte extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaString s = args.checkstring(1);
|
||||
int l = s.m_length;
|
||||
@@ -137,45 +137,47 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* string.char (...)
|
||||
*
|
||||
* Receives zero or more integers. Returns a string with length equal
|
||||
* to the number of arguments, in which each character has the internal
|
||||
* numerical code equal to its corresponding argument.
|
||||
* Receives zero or more integers. Returns a string with length equal
|
||||
* to the number of arguments, in which each character has the internal
|
||||
* numerical code equal to its corresponding argument.
|
||||
*
|
||||
* Note that numerical codes are not necessarily portable across platforms.
|
||||
*
|
||||
* @param args the calling VM
|
||||
*/
|
||||
static final class char_ extends VarArgFunction {
|
||||
static final class _char extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int n = args.narg();
|
||||
byte[] bytes = new byte[n];
|
||||
for ( int i=0, a=1; i<n; i++, a++ ) {
|
||||
int c = args.checkint(a);
|
||||
if (c<0 || c>=256) argerror(a, "invalid value");
|
||||
if (c<0 || c>=256) argerror(a, "invalid value for string.char [0; 255]: " + c);
|
||||
bytes[i] = (byte) c;
|
||||
}
|
||||
return LuaString.valueUsing( bytes );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* string.dump (function)
|
||||
/**
|
||||
* string.dump (function[, stripDebug])
|
||||
*
|
||||
* Returns a string containing a binary representation of the given function,
|
||||
* so that a later loadstring on this string returns a copy of the function.
|
||||
* Returns a string containing a binary representation of the given function,
|
||||
* so that a later loadstring on this string returns a copy of the function.
|
||||
* function must be a Lua function without upvalues.
|
||||
*
|
||||
* Boolean param stripDebug - true to strip debugging info, false otherwise.
|
||||
* The default value for stripDebug is true.
|
||||
*
|
||||
* TODO: port dumping code as optional add-on
|
||||
*/
|
||||
static final class dump extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaValue f = arg.checkfunction();
|
||||
static final class dump extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaValue f = args.checkfunction(1);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
DumpState.dump( ((LuaClosure)f).p, baos, true );
|
||||
DumpState.dump( ((LuaClosure)f).p, baos, args.optboolean(2, true) );
|
||||
return LuaString.valueUsing(baos.toByteArray());
|
||||
} catch (IOException e) {
|
||||
return error( e.getMessage() );
|
||||
@@ -183,20 +185,20 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* string.find (s, pattern [, init [, plain]])
|
||||
*
|
||||
* Looks for the first match of pattern in the string s.
|
||||
* If it finds a match, then find returns the indices of s
|
||||
* where this occurrence starts and ends; otherwise, it returns nil.
|
||||
* A third, optional numerical argument init specifies where to start the search;
|
||||
* its default value is 1 and may be negative. A value of true as a fourth,
|
||||
* optional argument plain turns off the pattern matching facilities,
|
||||
* so the function does a plain "find substring" operation,
|
||||
* with no characters in pattern being considered "magic".
|
||||
* Looks for the first match of pattern in the string s.
|
||||
* If it finds a match, then find returns the indices of s
|
||||
* where this occurrence starts and ends; otherwise, it returns nil.
|
||||
* A third, optional numerical argument init specifies where to start the search;
|
||||
* its default value is 1 and may be negative. A value of true as a fourth,
|
||||
* optional argument plain turns off the pattern matching facilities,
|
||||
* so the function does a plain "find substring" operation,
|
||||
* with no characters in pattern being considered "magic".
|
||||
* Note that if plain is given, then init must be given as well.
|
||||
*
|
||||
* If the pattern has captures, then in a successful match the captured values
|
||||
* If the pattern has captures, then in a successful match the captured values
|
||||
* are also returned, after the two indices.
|
||||
*/
|
||||
static final class find extends VarArgFunction {
|
||||
@@ -205,30 +207,30 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* string.format (formatstring, ...)
|
||||
*
|
||||
* Returns a formatted version of its variable number of arguments following
|
||||
* the description given in its first argument (which must be a string).
|
||||
* The format string follows the same rules as the printf family of standard C functions.
|
||||
* The only differences are that the options/modifiers *, l, L, n, p, and h are not supported
|
||||
* and that there is an extra option, q. The q option formats a string in a form suitable
|
||||
* to be safely read back by the Lua interpreter: the string is written between double quotes,
|
||||
* and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly
|
||||
* Returns a formatted version of its variable number of arguments following
|
||||
* the description given in its first argument (which must be a string).
|
||||
* The format string follows the same rules as the printf family of standard C functions.
|
||||
* The only differences are that the options/modifiers *, l, L, n, p, and h are not supported
|
||||
* and that there is an extra option, q. The q option formats a string in a form suitable
|
||||
* to be safely read back by the Lua interpreter: the string is written between double quotes,
|
||||
* and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly
|
||||
* escaped when written. For instance, the call
|
||||
* string.format('%q', 'a string with "quotes" and \n new line')
|
||||
*
|
||||
* will produce the string:
|
||||
* "a string with \"quotes\" and \
|
||||
* new line"
|
||||
*
|
||||
* The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument,
|
||||
* whereas q and s expect a string.
|
||||
*
|
||||
* This function does not accept string values containing embedded zeros,
|
||||
* except as arguments to the q option.
|
||||
* The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument,
|
||||
* whereas q and s expect a string.
|
||||
*
|
||||
* This function does not accept string values containing embedded zeros,
|
||||
* except as arguments to the q option.
|
||||
*/
|
||||
static final class format extends VarArgFunction {
|
||||
final class format extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaString fmt = args.checkstring( 1 );
|
||||
final int n = fmt.length();
|
||||
@@ -259,7 +261,7 @@ public class StringLib extends TwoArgFunction {
|
||||
break;
|
||||
case 'i':
|
||||
case 'd':
|
||||
fdsc.format( result, args.checkint( arg ) );
|
||||
fdsc.format( result, args.checklong( arg ) );
|
||||
break;
|
||||
case 'o':
|
||||
case 'u':
|
||||
@@ -298,7 +300,7 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
private static void addquoted(Buffer buf, LuaString s) {
|
||||
static void addquoted(Buffer buf, LuaString s) {
|
||||
int c;
|
||||
buf.append( (byte) '"' );
|
||||
for ( int i = 0, n = s.length(); i < n; i++ ) {
|
||||
@@ -328,7 +330,7 @@ public class StringLib extends TwoArgFunction {
|
||||
|
||||
private static final String FLAGS = "-+ #0";
|
||||
|
||||
static class FormatDesc {
|
||||
class FormatDesc {
|
||||
|
||||
private boolean leftAdjust;
|
||||
private boolean zeroPad;
|
||||
@@ -338,11 +340,13 @@ public class StringLib extends TwoArgFunction {
|
||||
private static final int MAX_FLAGS = 5;
|
||||
|
||||
private int width;
|
||||
private int precision;
|
||||
int precision;
|
||||
|
||||
public final int conversion;
|
||||
public final int length;
|
||||
|
||||
public final String src;
|
||||
|
||||
public FormatDesc(Varargs args, LuaString strfrmt, final int start) {
|
||||
int p = start, n = strfrmt.length();
|
||||
int c = 0;
|
||||
@@ -390,6 +394,7 @@ public class StringLib extends TwoArgFunction {
|
||||
zeroPad &= !leftAdjust; // '-' overrides '0'
|
||||
conversion = c;
|
||||
length = p - start;
|
||||
src = strfrmt.substring(start - 1, p).tojstring();
|
||||
}
|
||||
|
||||
public void format(Buffer buf, byte c) {
|
||||
@@ -465,8 +470,7 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
public void format(Buffer buf, double x) {
|
||||
// TODO
|
||||
buf.append( String.valueOf( x ) );
|
||||
buf.append( StringLib.this.format(src, x) );
|
||||
}
|
||||
|
||||
public void format(Buffer buf, LuaString s) {
|
||||
@@ -476,27 +480,31 @@ public class StringLib extends TwoArgFunction {
|
||||
buf.append(s);
|
||||
}
|
||||
|
||||
public static final void pad(Buffer buf, char c, int n) {
|
||||
public final void pad(Buffer buf, char c, int n) {
|
||||
byte b = (byte)c;
|
||||
while ( n-- > 0 )
|
||||
buf.append(b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
protected String format(String src, double x) {
|
||||
return String.valueOf(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* string.gmatch (s, pattern)
|
||||
*
|
||||
* Returns an iterator function that, each time it is called, returns the next captures
|
||||
* from pattern over string s. If pattern specifies no captures, then the
|
||||
* whole match is produced in each call.
|
||||
* Returns an iterator function that, each time it is called, returns the next captures
|
||||
* from pattern over string s. If pattern specifies no captures, then the
|
||||
* whole match is produced in each call.
|
||||
*
|
||||
* As an example, the following loop
|
||||
* s = "hello world from Lua"
|
||||
* for w in string.gmatch(s, "%a+") do
|
||||
* print(w)
|
||||
* end
|
||||
*
|
||||
* will iterate over all the words from string s, printing one per line.
|
||||
*
|
||||
* will iterate over all the words from string s, printing one per line.
|
||||
* The next example collects all pairs key=value from the given string into a table:
|
||||
* t = {}
|
||||
* s = "from=world, to=Lua"
|
||||
@@ -504,7 +512,7 @@ public class StringLib extends TwoArgFunction {
|
||||
* t[k] = v
|
||||
* end
|
||||
*
|
||||
* For this function, a '^' at the start of a pattern does not work as an anchor,
|
||||
* For this function, a '^' at the start of a pattern does not work as an anchor,
|
||||
* as this would prevent the iteration.
|
||||
*/
|
||||
static final class gmatch extends VarArgFunction {
|
||||
@@ -519,18 +527,20 @@ public class StringLib extends TwoArgFunction {
|
||||
private final int srclen;
|
||||
private final MatchState ms;
|
||||
private int soffset;
|
||||
private int lastmatch;
|
||||
public GMatchAux(Varargs args, LuaString src, LuaString pat) {
|
||||
this.srclen = src.length();
|
||||
this.ms = new MatchState(args, src, pat);
|
||||
this.soffset = 0;
|
||||
this.lastmatch = -1;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
for ( ; soffset<srclen; soffset++ ) {
|
||||
for ( ; soffset<=srclen; soffset++ ) {
|
||||
ms.reset();
|
||||
int res = ms.match(soffset, 0);
|
||||
if ( res >=0 ) {
|
||||
if ( res >=0 && res != lastmatch ) {
|
||||
int soff = soffset;
|
||||
soffset = res;
|
||||
lastmatch = soffset = res;
|
||||
return ms.push_captures( true, soff, res );
|
||||
}
|
||||
}
|
||||
@@ -539,28 +549,28 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* string.gsub (s, pattern, repl [, n])
|
||||
* Returns a copy of s in which all (or the first n, if given) occurrences of the
|
||||
* pattern have been replaced by a replacement string specified by repl, which
|
||||
* may be a string, a table, or a function. gsub also returns, as its second value,
|
||||
* Returns a copy of s in which all (or the first n, if given) occurrences of the
|
||||
* pattern have been replaced by a replacement string specified by repl, which
|
||||
* may be a string, a table, or a function. gsub also returns, as its second value,
|
||||
* the total number of matches that occurred.
|
||||
*
|
||||
* If repl is a string, then its value is used for replacement.
|
||||
* The character % works as an escape character: any sequence in repl of the form %n,
|
||||
* with n between 1 and 9, stands for the value of the n-th captured substring (see below).
|
||||
* The sequence %0 stands for the whole match. The sequence %% stands for a single %.
|
||||
*
|
||||
* If repl is a table, then the table is queried for every match, using the first capture
|
||||
* as the key; if the pattern specifies no captures, then the whole match is used as the key.
|
||||
* If repl is a string, then its value is used for replacement.
|
||||
* The character % works as an escape character: any sequence in repl of the form %n,
|
||||
* with n between 1 and 9, stands for the value of the n-th captured substring (see below).
|
||||
* The sequence %0 stands for the whole match. The sequence %% stands for a single %.
|
||||
*
|
||||
* If repl is a function, then this function is called every time a match occurs,
|
||||
* with all captured substrings passed as arguments, in order; if the pattern specifies
|
||||
* no captures, then the whole match is passed as a sole argument.
|
||||
* If repl is a table, then the table is queried for every match, using the first capture
|
||||
* as the key; if the pattern specifies no captures, then the whole match is used as the key.
|
||||
*
|
||||
* If the value returned by the table query or by the function call is a string or a number,
|
||||
* then it is used as the replacement string; otherwise, if it is false or nil,
|
||||
* then there is no replacement (that is, the original match is kept in the string).
|
||||
* If repl is a function, then this function is called every time a match occurs,
|
||||
* with all captured substrings passed as arguments, in order; if the pattern specifies
|
||||
* no captures, then the whole match is passed as a sole argument.
|
||||
*
|
||||
* If the value returned by the table query or by the function call is a string or a number,
|
||||
* then it is used as the replacement string; otherwise, if it is false or nil,
|
||||
* then there is no replacement (that is, the original match is kept in the string).
|
||||
*
|
||||
* Here are some examples:
|
||||
* x = string.gsub("hello world", "(%w+)", "%1 %1")
|
||||
@@ -589,6 +599,7 @@ public class StringLib extends TwoArgFunction {
|
||||
LuaString src = args.checkstring( 1 );
|
||||
final int srclen = src.length();
|
||||
LuaString p = args.checkstring( 2 );
|
||||
int lastmatch = -1; /* end of last match */
|
||||
LuaValue repl = args.arg( 3 );
|
||||
int max_s = args.optint( 4, srclen + 1 );
|
||||
final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^';
|
||||
@@ -601,29 +612,26 @@ public class StringLib extends TwoArgFunction {
|
||||
while ( n < max_s ) {
|
||||
ms.reset();
|
||||
int res = ms.match( soffset, anchor ? 1 : 0 );
|
||||
if ( res != -1 ) {
|
||||
if ( res != -1 && res != lastmatch ) { /* match? */
|
||||
n++;
|
||||
ms.add_value( lbuf, soffset, res, repl );
|
||||
ms.add_value( lbuf, soffset, res, repl ); /* add replacement to buffer */
|
||||
soffset = lastmatch = res;
|
||||
}
|
||||
if ( res != -1 && res > soffset )
|
||||
soffset = res;
|
||||
else if ( soffset < srclen )
|
||||
else if ( soffset < srclen ) /* otherwise, skip one character */
|
||||
lbuf.append( (byte) src.luaByte( soffset++ ) );
|
||||
else
|
||||
break;
|
||||
if ( anchor )
|
||||
break;
|
||||
else break; /* end of subject */
|
||||
if ( anchor ) break;
|
||||
}
|
||||
lbuf.append( src.substring( soffset, srclen ) );
|
||||
return varargsOf(lbuf.tostring(), valueOf(n));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* string.len (s)
|
||||
*
|
||||
* Receives a string and returns its length. The empty string "" has length 0.
|
||||
* Embedded zeros are counted, so "a\000bc\000" has length 5.
|
||||
* Receives a string and returns its length. The empty string "" has length 0.
|
||||
* Embedded zeros are counted, so "a\000bc\000" has length 5.
|
||||
*/
|
||||
static final class len extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
@@ -631,11 +639,11 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* string.lower (s)
|
||||
*
|
||||
* Receives a string and returns a copy of this string with all uppercase letters
|
||||
* changed to lowercase. All other characters are left unchanged.
|
||||
* Receives a string and returns a copy of this string with all uppercase letters
|
||||
* changed to lowercase. All other characters are left unchanged.
|
||||
* The definition of what an uppercase letter is depends on the current locale.
|
||||
*/
|
||||
static final class lower extends OneArgFunction {
|
||||
@@ -662,7 +670,7 @@ public class StringLib extends TwoArgFunction {
|
||||
/**
|
||||
* string.rep (s, n)
|
||||
*
|
||||
* Returns a string that is the concatenation of n copies of the string s.
|
||||
* Returns a string that is the concatenation of n copies of the string s.
|
||||
*/
|
||||
static final class rep extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
@@ -677,10 +685,10 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* string.reverse (s)
|
||||
*
|
||||
* Returns a string that is the string s reversed.
|
||||
* Returns a string that is the string s reversed.
|
||||
*/
|
||||
static final class reverse extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
@@ -693,15 +701,15 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* string.sub (s, i [, j])
|
||||
*
|
||||
* Returns the substring of s that starts at i and continues until j;
|
||||
* i and j may be negative. If j is absent, then it is assumed to be equal to -1
|
||||
* (which is the same as the string length). In particular, the call
|
||||
* string.sub(s,1,j)
|
||||
* returns a prefix of s with length j, and
|
||||
* string.sub(s, -i)
|
||||
* Returns the substring of s that starts at i and continues until j;
|
||||
* i and j may be negative. If j is absent, then it is assumed to be equal to -1
|
||||
* (which is the same as the string length). In particular, the call
|
||||
* string.sub(s,1,j)
|
||||
* returns a prefix of s with length j, and
|
||||
* string.sub(s, -i)
|
||||
* returns a suffix of s with length i.
|
||||
*/
|
||||
static final class sub extends VarArgFunction {
|
||||
@@ -725,12 +733,12 @@ public class StringLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* string.upper (s)
|
||||
*
|
||||
* Receives a string and returns a copy of this string with all lowercase letters
|
||||
* changed to uppercase. All other characters are left unchanged.
|
||||
* The definition of what a lowercase letter is depends on the current locale.
|
||||
* Receives a string and returns a copy of this string with all lowercase letters
|
||||
* changed to uppercase. All other characters are left unchanged.
|
||||
* The definition of what a lowercase letter is depends on the current locale.
|
||||
*/
|
||||
static final class upper extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
@@ -764,7 +772,7 @@ public class StringLib extends TwoArgFunction {
|
||||
|
||||
boolean anchor = false;
|
||||
int poff = 0;
|
||||
if ( pat.luaByte( 0 ) == '^' ) {
|
||||
if ( pat.length() > 0 && pat.luaByte( 0 ) == '^' ) {
|
||||
anchor = true;
|
||||
poff = 1;
|
||||
}
|
||||
@@ -785,7 +793,7 @@ public class StringLib extends TwoArgFunction {
|
||||
return NIL;
|
||||
}
|
||||
|
||||
private static int posrelat( int pos, int len ) {
|
||||
static int posrelat( int pos, int len ) {
|
||||
return ( pos >= 0 ) ? pos : len + pos + 1;
|
||||
}
|
||||
|
||||
@@ -795,6 +803,8 @@ public class StringLib extends TwoArgFunction {
|
||||
private static final LuaString SPECIALS = valueOf("^$*+?.([%-");
|
||||
private static final int MAX_CAPTURES = 32;
|
||||
|
||||
private static final int MAXCCALLS = 200;
|
||||
|
||||
private static final int CAP_UNFINISHED = -1;
|
||||
private static final int CAP_POSITION = -2;
|
||||
|
||||
@@ -807,12 +817,12 @@ public class StringLib extends TwoArgFunction {
|
||||
private static final byte MASK_CONTROL = 0x40;
|
||||
private static final byte MASK_HEXDIGIT = (byte)0x80;
|
||||
|
||||
private static final byte[] CHAR_TABLE;
|
||||
static final byte[] CHAR_TABLE;
|
||||
|
||||
static {
|
||||
CHAR_TABLE = new byte[256];
|
||||
|
||||
for ( int i = 0; i < 256; ++i ) {
|
||||
for ( int i = 0; i < 128; ++i ) {
|
||||
final char c = (char) i;
|
||||
CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) |
|
||||
( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) |
|
||||
@@ -821,7 +831,7 @@ public class StringLib extends TwoArgFunction {
|
||||
if ( ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) || ( c >= '0' && c <= '9' ) ) {
|
||||
CHAR_TABLE[i] |= MASK_HEXDIGIT;
|
||||
}
|
||||
if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) ) {
|
||||
if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) || ( c >= '[' && c <= '`' ) || ( c >= '{' && c <= '~' ) ) {
|
||||
CHAR_TABLE[i] |= MASK_PUNCT;
|
||||
}
|
||||
if ( ( CHAR_TABLE[i] & ( MASK_LOWERCASE | MASK_UPPERCASE ) ) != 0 ) {
|
||||
@@ -833,11 +843,12 @@ public class StringLib extends TwoArgFunction {
|
||||
CHAR_TABLE['\r'] |= MASK_SPACE;
|
||||
CHAR_TABLE['\n'] |= MASK_SPACE;
|
||||
CHAR_TABLE['\t'] |= MASK_SPACE;
|
||||
CHAR_TABLE[0x0C /* '\v' */ ] |= MASK_SPACE;
|
||||
CHAR_TABLE[0x0B /* '\v' */ ] |= MASK_SPACE;
|
||||
CHAR_TABLE['\f'] |= MASK_SPACE;
|
||||
};
|
||||
|
||||
static class MatchState {
|
||||
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
|
||||
final LuaString s;
|
||||
final LuaString p;
|
||||
final Varargs args;
|
||||
@@ -852,10 +863,12 @@ public class StringLib extends TwoArgFunction {
|
||||
this.level = 0;
|
||||
this.cinit = new int[ MAX_CAPTURES ];
|
||||
this.clen = new int[ MAX_CAPTURES ];
|
||||
this.matchdepth = MAXCCALLS;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
level = 0;
|
||||
this.matchdepth = MAXCCALLS;
|
||||
}
|
||||
|
||||
private void add_s( Buffer lbuf, LuaString news, int soff, int e ) {
|
||||
@@ -866,8 +879,14 @@ public class StringLib extends TwoArgFunction {
|
||||
lbuf.append( (byte) b );
|
||||
} else {
|
||||
++i; // skip ESC
|
||||
b = (byte) news.luaByte( i );
|
||||
b = (byte)(i < l ? news.luaByte( i ) : 0);
|
||||
if ( !Character.isDigit( (char) b ) ) {
|
||||
if (b != L_ESC) error( "invalid use of '" + (char)L_ESC +
|
||||
"' in replacement string: after '" + (char)L_ESC +
|
||||
"' must be '0'-'9' or '" + (char)L_ESC +
|
||||
"', but found " + (i < l ? "symbol '" + (char)b + "' with code " + b +
|
||||
" at pos " + (i + 1) :
|
||||
"end of string"));
|
||||
lbuf.append( b );
|
||||
} else if ( b == '0' ) {
|
||||
lbuf.append( s.substring( soff, e ) );
|
||||
@@ -924,7 +943,7 @@ public class StringLib extends TwoArgFunction {
|
||||
if ( i == 0 ) {
|
||||
return s.substring( soff, end );
|
||||
} else {
|
||||
return error( "invalid capture index" );
|
||||
return error( "invalid capture index %" + (i + 1) );
|
||||
}
|
||||
} else {
|
||||
int l = clen[i];
|
||||
@@ -943,7 +962,7 @@ public class StringLib extends TwoArgFunction {
|
||||
private int check_capture( int l ) {
|
||||
l -= '1';
|
||||
if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) {
|
||||
error("invalid capture index");
|
||||
error("invalid capture index %" + (l + 1));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
@@ -961,19 +980,19 @@ public class StringLib extends TwoArgFunction {
|
||||
switch ( p.luaByte( poffset++ ) ) {
|
||||
case L_ESC:
|
||||
if ( poffset == p.length() ) {
|
||||
error( "malformed pattern (ends with %)" );
|
||||
error( "malformed pattern (ends with '%')" );
|
||||
}
|
||||
return poffset + 1;
|
||||
|
||||
case '[':
|
||||
if ( p.luaByte( poffset ) == '^' ) poffset++;
|
||||
if ( poffset != p.length() && p.luaByte( poffset ) == '^' ) poffset++;
|
||||
do {
|
||||
if ( poffset == p.length() ) {
|
||||
error( "malformed pattern (missing ])" );
|
||||
error( "malformed pattern (missing ']')" );
|
||||
}
|
||||
if ( p.luaByte( poffset++ ) == L_ESC && poffset != p.length() )
|
||||
poffset++;
|
||||
} while ( p.luaByte( poffset ) != ']' );
|
||||
if ( p.luaByte( poffset++ ) == L_ESC && poffset < p.length() )
|
||||
poffset++; /* skip escapes (e.g. '%]') */
|
||||
} while ( poffset == p.length() || p.luaByte( poffset ) != ']' );
|
||||
return poffset + 1;
|
||||
default:
|
||||
return poffset;
|
||||
@@ -993,9 +1012,10 @@ public class StringLib extends TwoArgFunction {
|
||||
case 'c': res = ( cdata & MASK_CONTROL ) != 0; break;
|
||||
case 'p': res = ( cdata & MASK_PUNCT ) != 0; break;
|
||||
case 's': res = ( cdata & MASK_SPACE ) != 0; break;
|
||||
case 'g': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT | MASK_PUNCT ) ) != 0; break;
|
||||
case 'w': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT ) ) != 0; break;
|
||||
case 'x': res = ( cdata & MASK_HEXDIGIT ) != 0; break;
|
||||
case 'z': res = ( c == 0 ); break;
|
||||
case 'z': res = ( c == 0 ); break; /* deprecated option */
|
||||
default: return cl == c;
|
||||
}
|
||||
return ( lcl == cl ) ? res : !res;
|
||||
@@ -1037,80 +1057,86 @@ public class StringLib extends TwoArgFunction {
|
||||
* where match ends, otherwise returns -1.
|
||||
*/
|
||||
int match( int soffset, int poffset ) {
|
||||
while ( true ) {
|
||||
// Check if we are at the end of the pattern -
|
||||
// equivalent to the '\0' case in the C version, but our pattern
|
||||
// string is not NUL-terminated.
|
||||
if ( poffset == p.length() )
|
||||
return soffset;
|
||||
switch ( p.luaByte( poffset ) ) {
|
||||
case '(':
|
||||
if ( ++poffset < p.length() && p.luaByte( poffset ) == ')' )
|
||||
return start_capture( soffset, poffset + 1, CAP_POSITION );
|
||||
else
|
||||
return start_capture( soffset, poffset, CAP_UNFINISHED );
|
||||
case ')':
|
||||
return end_capture( soffset, poffset + 1 );
|
||||
case L_ESC:
|
||||
if ( poffset + 1 == p.length() )
|
||||
error("malformed pattern (ends with '%')");
|
||||
switch ( p.luaByte( poffset + 1 ) ) {
|
||||
case 'b':
|
||||
soffset = matchbalance( soffset, poffset + 2 );
|
||||
if ( soffset == -1 ) return -1;
|
||||
poffset += 4;
|
||||
continue;
|
||||
case 'f': {
|
||||
poffset += 2;
|
||||
if ( p.luaByte( poffset ) != '[' ) {
|
||||
error("Missing [ after %f in pattern");
|
||||
if (matchdepth-- == 0) error("pattern too complex");
|
||||
try {
|
||||
while ( true ) {
|
||||
// Check if we are at the end of the pattern -
|
||||
// equivalent to the '\0' case in the C version, but our pattern
|
||||
// string is not NUL-terminated.
|
||||
if ( poffset == p.length() )
|
||||
return soffset;
|
||||
switch ( p.luaByte( poffset ) ) {
|
||||
case '(':
|
||||
if ( ++poffset < p.length() && p.luaByte( poffset ) == ')' )
|
||||
return start_capture( soffset, poffset + 1, CAP_POSITION );
|
||||
else
|
||||
return start_capture( soffset, poffset, CAP_UNFINISHED );
|
||||
case ')':
|
||||
return end_capture( soffset, poffset + 1 );
|
||||
case L_ESC:
|
||||
if ( poffset + 1 == p.length() )
|
||||
error("malformed pattern (ends with '%')");
|
||||
switch ( p.luaByte( poffset + 1 ) ) {
|
||||
case 'b':
|
||||
soffset = matchbalance( soffset, poffset + 2 );
|
||||
if ( soffset == -1 ) return -1;
|
||||
poffset += 4;
|
||||
continue;
|
||||
case 'f': {
|
||||
poffset += 2;
|
||||
if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) {
|
||||
error("missing '[' after '%f' in pattern");
|
||||
}
|
||||
int ep = classend( poffset );
|
||||
int previous = ( soffset == 0 ) ? '\0' : s.luaByte( soffset - 1 );
|
||||
int next = ( soffset == s.length() ) ? '\0' : s.luaByte( soffset );
|
||||
if ( matchbracketclass( previous, poffset, ep - 1 ) ||
|
||||
!matchbracketclass( next, poffset, ep - 1 ) )
|
||||
return -1;
|
||||
poffset = ep;
|
||||
continue;
|
||||
}
|
||||
int ep = classend( poffset );
|
||||
int previous = ( soffset == 0 ) ? -1 : s.luaByte( soffset - 1 );
|
||||
if ( matchbracketclass( previous, poffset, ep - 1 ) ||
|
||||
matchbracketclass( s.luaByte( soffset ), poffset, ep - 1 ) )
|
||||
default: {
|
||||
int c = p.luaByte( poffset + 1 );
|
||||
if ( Character.isDigit( (char) c ) ) {
|
||||
soffset = match_capture( soffset, c );
|
||||
if ( soffset == -1 )
|
||||
return -1;
|
||||
return match( soffset, poffset + 2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
case '$':
|
||||
if ( poffset + 1 == p.length() )
|
||||
return ( soffset == s.length() ) ? soffset : -1;
|
||||
}
|
||||
int ep = classend( poffset );
|
||||
boolean m = soffset < s.length() && singlematch( s.luaByte( soffset ), poffset, ep );
|
||||
int pc = ( ep < p.length() ) ? p.luaByte( ep ) : '\0';
|
||||
|
||||
switch ( pc ) {
|
||||
case '?':
|
||||
int res;
|
||||
if ( m && ( ( res = match( soffset + 1, ep + 1 ) ) != -1 ) )
|
||||
return res;
|
||||
poffset = ep + 1;
|
||||
continue;
|
||||
case '*':
|
||||
return max_expand( soffset, poffset, ep );
|
||||
case '+':
|
||||
return ( m ? max_expand( soffset + 1, poffset, ep ) : -1 );
|
||||
case '-':
|
||||
return min_expand( soffset, poffset, ep );
|
||||
default:
|
||||
if ( !m )
|
||||
return -1;
|
||||
soffset++;
|
||||
poffset = ep;
|
||||
continue;
|
||||
}
|
||||
default: {
|
||||
int c = p.luaByte( poffset + 1 );
|
||||
if ( Character.isDigit( (char) c ) ) {
|
||||
soffset = match_capture( soffset, c );
|
||||
if ( soffset == -1 )
|
||||
return -1;
|
||||
return match( soffset, poffset + 2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
case '$':
|
||||
if ( poffset + 1 == p.length() )
|
||||
return ( soffset == s.length() ) ? soffset : -1;
|
||||
}
|
||||
int ep = classend( poffset );
|
||||
boolean m = soffset < s.length() && singlematch( s.luaByte( soffset ), poffset, ep );
|
||||
int pc = ( ep < p.length() ) ? p.luaByte( ep ) : '\0';
|
||||
|
||||
switch ( pc ) {
|
||||
case '?':
|
||||
int res;
|
||||
if ( m && ( ( res = match( soffset + 1, ep + 1 ) ) != -1 ) )
|
||||
return res;
|
||||
poffset = ep + 1;
|
||||
continue;
|
||||
case '*':
|
||||
return max_expand( soffset, poffset, ep );
|
||||
case '+':
|
||||
return ( m ? max_expand( soffset + 1, poffset, ep ) : -1 );
|
||||
case '-':
|
||||
return min_expand( soffset, poffset, ep );
|
||||
default:
|
||||
if ( !m )
|
||||
return -1;
|
||||
soffset++;
|
||||
poffset = ep;
|
||||
continue;
|
||||
}
|
||||
} finally {
|
||||
matchdepth++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1175,7 +1201,7 @@ public class StringLib extends TwoArgFunction {
|
||||
int matchbalance( int soff, int poff ) {
|
||||
final int plen = p.length();
|
||||
if ( poff == plen || poff + 1 == plen ) {
|
||||
error( "unbalanced pattern" );
|
||||
error( "malformed pattern (missing arguments to '%b')" );
|
||||
}
|
||||
final int slen = s.length();
|
||||
if ( soff >= slen )
|
||||
|
||||
@@ -25,19 +25,19 @@ import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code table}
|
||||
* library.
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code table}
|
||||
* library.
|
||||
*
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("table").get("length").call( LuaValue.tableOf() ) );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
@@ -70,15 +70,9 @@ public class TableLib extends TwoArgFunction {
|
||||
table.set("sort", new sort());
|
||||
table.set("unpack", new unpack());
|
||||
env.set("table", table);
|
||||
env.get("package").get("loaded").set("table", table);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("table", table);
|
||||
return NIL;
|
||||
}
|
||||
|
||||
static class TableLibFunction extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "table expected, got no value");
|
||||
}
|
||||
}
|
||||
|
||||
// "concat" (table [, sep [, i [, j]]]) -> string
|
||||
static class concat extends TableLibFunction {
|
||||
@@ -100,18 +94,22 @@ public class TableLib extends TwoArgFunction {
|
||||
static class insert extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch (args.narg()) {
|
||||
case 0: case 1: {
|
||||
return argerror(2, "value expected");
|
||||
}
|
||||
case 2: {
|
||||
LuaTable table = args.arg1().checktable();
|
||||
LuaTable table = args.checktable(1);
|
||||
table.insert(table.length()+1,args.arg(2));
|
||||
return NONE;
|
||||
}
|
||||
default: {
|
||||
args.arg1().checktable().insert(args.checkint(2),args.arg(3));
|
||||
case 3: {
|
||||
LuaTable table = args.checktable(1);
|
||||
int pos = args.checkint(2);
|
||||
int max = table.length() + 1;
|
||||
if (pos < 1 || pos > max) argerror(2, "position out of bounds: " + pos + " not between 1 and " + max);
|
||||
table.insert(pos, args.arg(3));
|
||||
return NONE;
|
||||
}
|
||||
default: {
|
||||
return error("wrong number of arguments to 'table.insert': " + args.narg() + " (must be 2 or 3)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,15 +126,21 @@ public class TableLib extends TwoArgFunction {
|
||||
// "remove" (table [, pos]) -> removed-ele
|
||||
static class remove extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
return args.arg1().checktable().remove(args.optint(2, 0));
|
||||
LuaTable table = args.checktable(1);
|
||||
int size = table.length();
|
||||
int pos = args.optint(2, size);
|
||||
if (pos != size && (pos < 1 || pos > size + 1)) {
|
||||
argerror(2, "position out of bounds: " + pos + " not between 1 and " + (size + 1));
|
||||
}
|
||||
return table.remove(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// "sort" (table [, comp])
|
||||
static class sort extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
args.arg1().checktable().sort(
|
||||
args.arg(2).isnil()? NIL: args.arg(2).checkfunction());
|
||||
args.checktable(1).sort(
|
||||
args.isnil(2)? NIL: args.checkfunction(2));
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
@@ -146,11 +150,9 @@ public class TableLib extends TwoArgFunction {
|
||||
static class unpack extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaTable t = args.checktable(1);
|
||||
switch (args.narg()) {
|
||||
case 1: return t.unpack();
|
||||
case 2: return t.unpack(args.checkint(2));
|
||||
default: return t.unpack(args.checkint(2), args.checkint(3));
|
||||
}
|
||||
// do not waste resource for calc rawlen if arg3 is not nil
|
||||
int len = args.arg(3).isnil() ? t.length() : 0;
|
||||
return t.unpack(args.optint(2, 1), args.optint(3, len));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
9
src/core/org/luaj/vm2/lib/TableLibFunction.java
Normal file
9
src/core/org/luaj/vm2/lib/TableLibFunction.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
class TableLibFunction extends LibFunction {
|
||||
public LuaValue call() {
|
||||
return argerror(1, "table expected, got no value");
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ abstract public class Visitor {
|
||||
visitExps(args.exps);
|
||||
}
|
||||
public void visit(TableField field) {
|
||||
if ( field.name != null );
|
||||
if ( field.name != null )
|
||||
visit( field.name );
|
||||
if ( field.index != null )
|
||||
field.index.accept(this);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -133,7 +134,7 @@ public class CoerceJavaToLua {
|
||||
}
|
||||
|
||||
|
||||
static final Map COERCIONS = new HashMap();
|
||||
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static {
|
||||
Coercion boolCoercion = new BoolCoercion() ;
|
||||
|
||||
@@ -51,7 +51,7 @@ class JavaMember extends VarArgFunction {
|
||||
fixedargs = new CoerceLuaToJava.Coercion[isvarargs? params.length-1: params.length];
|
||||
for ( int i=0; i<fixedargs.length; i++ )
|
||||
fixedargs[i] = CoerceLuaToJava.getCoercion( params[i] );
|
||||
varargs = isvarargs? CoerceLuaToJava.getCoercion( params[params.length-1] ): null;
|
||||
varargs = isvarargs? CoerceLuaToJava.getCoercion( params[params.length-1].getComponentType() ): null;
|
||||
}
|
||||
|
||||
int score(Varargs args) {
|
||||
@@ -72,12 +72,15 @@ class JavaMember extends VarArgFunction {
|
||||
for ( int i=0; i<a.length; i++ )
|
||||
a[i] = fixedargs[i].coerce( args.arg(i+1) );
|
||||
} else {
|
||||
int n = Math.max(fixedargs.length,args.narg());
|
||||
a = new Object[n];
|
||||
// should be the fixed arguments, followed by an array with the varargs
|
||||
a = new Object[fixedargs.length+1];
|
||||
int nvar = Math.max(0, args.narg()-fixedargs.length);
|
||||
Object[] vararray = new Object[nvar];
|
||||
for ( int i=0; i<fixedargs.length; i++ )
|
||||
a[i] = fixedargs[i].coerce( args.arg(i+1) );
|
||||
for ( int i=fixedargs.length; i<n; i++ )
|
||||
a[i] = varargs.coerce( args.arg(i+1) );
|
||||
a[a.length-1] = vararray;
|
||||
for ( int i=0; i<nvar; i++ )
|
||||
vararray[i] = varargs.coerce( args.arg(fixedargs.length+i+1) );
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -106,9 +107,10 @@ public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
|
||||
if ( ! f.exists() )
|
||||
return super.findResource(filename);
|
||||
try {
|
||||
return new FileInputStream(f);
|
||||
return new BufferedInputStream(new FileInputStream(f));
|
||||
} catch ( IOException ioe ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,20 +36,20 @@ import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.IoLib;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
|
||||
/**
|
||||
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
|
||||
* library for the JSE platform.
|
||||
* <p>
|
||||
* It uses RandomAccessFile to implement seek on files.
|
||||
/**
|
||||
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
|
||||
* library for the JSE platform.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* It uses RandomAccessFile to implement seek on files.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
@@ -96,9 +96,9 @@ public class JseIoLib extends IoLib {
|
||||
|
||||
protected File openProgram(String prog, String mode) throws IOException {
|
||||
final Process p = Runtime.getRuntime().exec(prog);
|
||||
return "w".equals(mode)?
|
||||
new FileImpl( p.getOutputStream() ):
|
||||
new FileImpl( p.getInputStream() );
|
||||
return "w".equals(mode)?
|
||||
new FileImpl( p.getOutputStream() ):
|
||||
new FileImpl( p.getInputStream() );
|
||||
}
|
||||
|
||||
protected File tmpFile() throws IOException {
|
||||
@@ -133,7 +133,7 @@ public class JseIoLib extends IoLib {
|
||||
this( null, null, o );
|
||||
}
|
||||
public String tojstring() {
|
||||
return "file ("+this.hashCode()+")";
|
||||
return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
|
||||
}
|
||||
public boolean isstdfile() {
|
||||
return file == null;
|
||||
@@ -199,11 +199,11 @@ public class JseIoLib extends IoLib {
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
public int read() throws IOException {
|
||||
if ( is != null )
|
||||
if ( is != null )
|
||||
return is.read();
|
||||
else if ( file != null ) {
|
||||
return file.read();
|
||||
@@ -321,7 +321,7 @@ public class JseIoLib extends IoLib {
|
||||
}
|
||||
|
||||
public int remaining() throws IOException {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int peek() throws IOException, EOFException {
|
||||
|
||||
@@ -24,6 +24,7 @@ package org.luaj.vm2.lib.jse;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
|
||||
@@ -76,8 +77,9 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib {
|
||||
LuaValue math = env.get("math");
|
||||
math.set("acos", new acos());
|
||||
math.set("asin", new asin());
|
||||
math.set("atan", new atan());
|
||||
math.set("atan2", new atan2());
|
||||
LuaValue atan = new atan2();
|
||||
math.set("atan", atan);
|
||||
math.set("atan2", atan);
|
||||
math.set("cosh", new cosh());
|
||||
math.set("exp", new exp());
|
||||
math.set("log", new log());
|
||||
@@ -89,11 +91,21 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib {
|
||||
|
||||
static final class acos extends UnaryOp { protected double call(double d) { return Math.acos(d); } }
|
||||
static final class asin extends UnaryOp { protected double call(double d) { return Math.asin(d); } }
|
||||
static final class atan extends UnaryOp { protected double call(double d) { return Math.atan(d); } }
|
||||
static final class atan2 extends BinaryOp { protected double call(double y, double x) { return Math.atan2(y, x); } }
|
||||
static final class atan2 extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue x, LuaValue y) {
|
||||
return valueOf(Math.atan2(x.checkdouble(), y.optdouble(1)));
|
||||
}
|
||||
}
|
||||
static final class cosh extends UnaryOp { protected double call(double d) { return Math.cosh(d); } }
|
||||
static final class exp extends UnaryOp { protected double call(double d) { return Math.exp(d); } }
|
||||
static final class log extends UnaryOp { protected double call(double d) { return Math.log(d); } }
|
||||
static final class log extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue x, LuaValue base) {
|
||||
double nat = Math.log(x.checkdouble());
|
||||
double b = base.optdouble(Math.E);
|
||||
if (b != Math.E) nat /= Math.log(b);
|
||||
return valueOf(nat);
|
||||
}
|
||||
}
|
||||
static final class pow extends BinaryOp { protected double call(double x, double y) { return Math.pow(x, y); } }
|
||||
static final class sinh extends UnaryOp { protected double call(double d) { return Math.sinh(d); } }
|
||||
static final class tanh extends UnaryOp { protected double call(double d) { return Math.tanh(d); } }
|
||||
@@ -105,3 +117,4 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ import org.luaj.vm2.lib.OsLib;
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
|
||||
* <p>
|
||||
* This contains more complete implementations of the following functions
|
||||
* using features that are specific to JSE:
|
||||
* This contains more complete implementations of the following functions
|
||||
* using features that are specific to JSE:
|
||||
* <ul>
|
||||
* <li>{@code execute()}</li>
|
||||
* <li>{@code remove()}</li>
|
||||
@@ -42,18 +42,18 @@ import org.luaj.vm2.lib.OsLib;
|
||||
* <li>{@code tmpname()}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Because the nature of the {@code os} library is to encapsulate
|
||||
* os-specific features, the behavior of these functions varies considerably
|
||||
* from their counterparts in the C platform.
|
||||
* Because the nature of the {@code os} library is to encapsulate
|
||||
* os-specific features, the behavior of these functions varies considerably
|
||||
* from their counterparts in the C platform.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("os").get("time").call() );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* For special cases where the smallest possible footprint is desired,
|
||||
* a minimal set of libraries could be loaded
|
||||
* directly via {@link Globals#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
@@ -74,13 +74,13 @@ import org.luaj.vm2.lib.OsLib;
|
||||
public class JseOsLib extends org.luaj.vm2.lib.OsLib {
|
||||
|
||||
/** return code indicating the execute() threw an I/O exception */
|
||||
public static int EXEC_IOEXCEPTION = 1;
|
||||
public static final int EXEC_IOEXCEPTION = 1;
|
||||
|
||||
/** return code indicating the execute() was interrupted */
|
||||
public static int EXEC_INTERRUPTED = -2;
|
||||
public static final int EXEC_INTERRUPTED = -2;
|
||||
|
||||
/** return code indicating the execute() threw an unknown exception */
|
||||
public static int EXEC_ERROR = -3;
|
||||
public static final int EXEC_ERROR = -3;
|
||||
|
||||
/** public constructor */
|
||||
public JseOsLib() {
|
||||
@@ -120,13 +120,13 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
|
||||
if ( ! f.exists() )
|
||||
throw new IOException("No such file or directory");
|
||||
if ( ! f.renameTo(new File(newname)) )
|
||||
throw new IOException("Failed to delete");
|
||||
throw new IOException("Failed to rename");
|
||||
}
|
||||
|
||||
protected String tmpname() {
|
||||
try {
|
||||
java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
|
||||
return f.getName();
|
||||
return f.getAbsolutePath();
|
||||
} catch ( IOException ioe ) {
|
||||
return super.tmpname();
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ package org.luaj.vm2.lib.jse;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.Bit32Lib;
|
||||
import org.luaj.vm2.lib.CoroutineLib;
|
||||
@@ -34,10 +34,10 @@ import org.luaj.vm2.lib.ResourceFinder;
|
||||
import org.luaj.vm2.lib.StringLib;
|
||||
import org.luaj.vm2.lib.TableLib;
|
||||
|
||||
/** The {@link org.luaj.vm2.lib.jse.JsePlatform} class is a convenience class to standardize
|
||||
* how globals tables are initialized for the JSE platform.
|
||||
/** The {@link org.luaj.vm2.lib.jse.JsePlatform} class is a convenience class to standardize
|
||||
* how globals tables are initialized for the JSE platform.
|
||||
* <p>
|
||||
* It is used to allocate either a set of standard globals using
|
||||
* It is used to allocate either a set of standard globals using
|
||||
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
|
||||
* <p>
|
||||
* A simple example of initializing globals and using them from Java is:
|
||||
@@ -51,7 +51,7 @@ import org.luaj.vm2.lib.TableLib;
|
||||
* globals.load( new FileInputStream("main.lua"), "main.lua" ).call();
|
||||
* } </pre>
|
||||
* <p>
|
||||
* although {@code require} could also be used:
|
||||
* although {@code require} could also be used:
|
||||
* <pre> {@code
|
||||
* globals.get("require").call(LuaValue.valueOf("main"));
|
||||
* } </pre>
|
||||
@@ -72,8 +72,8 @@ import org.luaj.vm2.lib.TableLib;
|
||||
* <li>{@link org.luaj.vm2.lib.jse.JseOsLib}</li>
|
||||
* <li>{@link org.luaj.vm2.lib.jse.LuajavaLib}</li>
|
||||
* </ul>
|
||||
* In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
|
||||
* <p>
|
||||
* In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
|
||||
* <p>
|
||||
* The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}.
|
||||
* <p>
|
||||
* The class ensures that initialization is done in the correct order.
|
||||
@@ -97,7 +97,7 @@ public class JsePlatform {
|
||||
globals.load(new PackageLib());
|
||||
globals.load(new Bit32Lib());
|
||||
globals.load(new TableLib());
|
||||
globals.load(new StringLib());
|
||||
globals.load(new JseStringLib());
|
||||
globals.load(new CoroutineLib());
|
||||
globals.load(new JseMathLib());
|
||||
globals.load(new JseIoLib());
|
||||
@@ -105,7 +105,7 @@ public class JsePlatform {
|
||||
globals.load(new LuajavaLib());
|
||||
LoadState.install(globals);
|
||||
LuaC.install(globals);
|
||||
return globals;
|
||||
return globals;
|
||||
}
|
||||
|
||||
/** Create standard globals including the {@link DebugLib} library.
|
||||
@@ -123,11 +123,12 @@ public class JsePlatform {
|
||||
}
|
||||
|
||||
|
||||
/** Simple wrapper for invoking a lua function with command line arguments.
|
||||
* The supplied function is first given a new Globals object,
|
||||
/** Simple wrapper for invoking a lua function with command line arguments.
|
||||
* The supplied function is first given a new Globals object as its environment
|
||||
* then the program is run with arguments.
|
||||
* @return {@link Varargs} containing any values returned by mainChunk.
|
||||
*/
|
||||
public static void luaMain(LuaValue mainChunk, String[] args) {
|
||||
public static Varargs luaMain(LuaValue mainChunk, String[] args) {
|
||||
Globals g = standardGlobals();
|
||||
int n = args.length;
|
||||
LuaValue[] vargs = new LuaValue[args.length];
|
||||
@@ -137,6 +138,6 @@ public class JsePlatform {
|
||||
arg.set("n", n);
|
||||
g.set("arg", arg);
|
||||
mainChunk.initupvalue1(g);
|
||||
mainChunk.invoke(LuaValue.varargsOf(vargs));
|
||||
return mainChunk.invoke(LuaValue.varargsOf(vargs));
|
||||
}
|
||||
}
|
||||
|
||||
39
src/jse/org/luaj/vm2/lib/jse/JseStringLib.java
Normal file
39
src/jse/org/luaj/vm2/lib/jse/JseStringLib.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Luaj.org. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
public class JseStringLib extends org.luaj.vm2.lib.StringLib {
|
||||
|
||||
/** public constructor */
|
||||
public JseStringLib() {
|
||||
}
|
||||
|
||||
protected String format(String src, double x) {
|
||||
String out;
|
||||
try {
|
||||
out = String.format(src, new Object[] {Double.valueOf(x)});
|
||||
} catch (Throwable e) {
|
||||
out = super.format(src, x);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
@@ -37,38 +37,38 @@ import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the features of the luajava package.
|
||||
* <p>
|
||||
* Luajava is an approach to mixing lua and java using simple functions that bind
|
||||
* java classes and methods to lua dynamically. The API is documented on the
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the features of the luajava package.
|
||||
* <p>
|
||||
* Luajava is an approach to mixing lua and java using simple functions that bind
|
||||
* java classes and methods to lua dynamically. The API is documented on the
|
||||
* <a href="http://www.keplerproject.org/luajava/">luajava</a> documentation pages.
|
||||
*
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
|
||||
* <pre> {@code
|
||||
* Globals globals = JsePlatform.standardGlobals();
|
||||
* System.out.println( globals.get("luajava").get("bindClass").call( LuaValue.valueOf("java.lang.System") ).invokeMethod("currentTimeMillis") );
|
||||
* } </pre>
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link Globals#load} using code such as:
|
||||
* <pre> {@code
|
||||
* Globals globals = new Globals();
|
||||
* globals.load(new JseBaseLib());
|
||||
* globals.load(new PackageLib());
|
||||
* globals.load(new LuajavaLib());
|
||||
* globals.load(
|
||||
* globals.load(
|
||||
* "sys = luajava.bindClass('java.lang.System')\n"+
|
||||
* "print ( sys:currentTimeMillis() )\n", "main.lua" ).call();
|
||||
* "print ( sys:currentTimeMillis() )\n", "main.lua" ).call();
|
||||
* } </pre>
|
||||
* <p>
|
||||
*
|
||||
* The {@code luajava} library is available
|
||||
* The {@code luajava} library is available
|
||||
* on all JSE platforms via the call to {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()}
|
||||
* and the luajava api's are simply invoked from lua.
|
||||
* Because it makes extensive use of Java's reflection API, it is not available
|
||||
* and the luajava api's are simply invoked from lua.
|
||||
* Because it makes extensive use of Java's reflection API, it is not available
|
||||
* on JME, but can be used in Android applications.
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
@@ -91,10 +91,10 @@ public class LuajavaLib extends VarArgFunction {
|
||||
static final int LOADLIB = 5;
|
||||
|
||||
static final String[] NAMES = {
|
||||
"bindClass",
|
||||
"newInstance",
|
||||
"new",
|
||||
"createProxy",
|
||||
"bindClass",
|
||||
"newInstance",
|
||||
"new",
|
||||
"createProxy",
|
||||
"loadLib",
|
||||
};
|
||||
|
||||
@@ -112,7 +112,7 @@ public class LuajavaLib extends VarArgFunction {
|
||||
LuaTable t = new LuaTable();
|
||||
bind( t, this.getClass(), NAMES, BINDCLASS );
|
||||
env.set("luajava", t);
|
||||
env.get("package").get("loaded").set("luajava", t);
|
||||
if (!env.get("package").isnil()) env.get("package").get("loaded").set("luajava", t);
|
||||
return t;
|
||||
}
|
||||
case BINDCLASS: {
|
||||
@@ -122,13 +122,13 @@ public class LuajavaLib extends VarArgFunction {
|
||||
case NEWINSTANCE:
|
||||
case NEW: {
|
||||
// get constructor
|
||||
final LuaValue c = args.checkvalue(1);
|
||||
final LuaValue c = args.checkvalue(1);
|
||||
final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class));
|
||||
final Varargs consargs = args.subargs(2);
|
||||
return JavaClass.forClass(clazz).getConstructor().invoke(consargs);
|
||||
}
|
||||
|
||||
case CREATEPROXY: {
|
||||
case CREATEPROXY: {
|
||||
final int niface = args.narg()-1;
|
||||
if ( niface <= 0 )
|
||||
throw new LuaError("no interfaces");
|
||||
@@ -136,7 +136,7 @@ public class LuajavaLib extends VarArgFunction {
|
||||
|
||||
// get the interfaces
|
||||
final Class[] ifaces = new Class[niface];
|
||||
for ( int i=0; i<niface; i++ )
|
||||
for ( int i=0; i<niface; i++ )
|
||||
ifaces[i] = classForName(args.checkjstring(i+1));
|
||||
|
||||
// create the invocation handler
|
||||
@@ -191,16 +191,16 @@ public class LuajavaLib extends VarArgFunction {
|
||||
if ( func.isnil() )
|
||||
return null;
|
||||
boolean isvarargs = ((method.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0);
|
||||
int n = args!=null? args.length: 0;
|
||||
int n = args!=null? args.length: 0;
|
||||
LuaValue[] v;
|
||||
if ( isvarargs ) {
|
||||
if ( isvarargs ) {
|
||||
Object o = args[--n];
|
||||
int m = Array.getLength( o );
|
||||
v = new LuaValue[n+m];
|
||||
for ( int i=0; i<n; i++ )
|
||||
v[i] = CoerceJavaToLua.coerce(args[i]);
|
||||
for ( int i=0; i<m; i++ )
|
||||
v[i+n] = CoerceJavaToLua.coerce(Array.get(o,i));
|
||||
v[i+n] = CoerceJavaToLua.coerce(Array.get(o,i));
|
||||
} else {
|
||||
v = new LuaValue[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.luaj.vm2.compiler.DumpLoadEndianIntTest;
|
||||
import org.luaj.vm2.compiler.LuaParserTests;
|
||||
import org.luaj.vm2.compiler.RegressionTests;
|
||||
import org.luaj.vm2.compiler.SimpleTests;
|
||||
import org.luaj.vm2.lib.jse.JsePlatformTest;
|
||||
import org.luaj.vm2.lib.jse.LuaJavaCoercionTest;
|
||||
import org.luaj.vm2.lib.jse.LuajavaAccessibleMembersTest;
|
||||
import org.luaj.vm2.lib.jse.LuajavaClassMembersTest;
|
||||
@@ -85,6 +86,7 @@ public class AllTests {
|
||||
|
||||
// library tests
|
||||
TestSuite lib = new TestSuite("Library Tests");
|
||||
lib.addTestSuite(JsePlatformTest.class);
|
||||
lib.addTestSuite(LuajavaAccessibleMembersTest.class);
|
||||
lib.addTestSuite(LuajavaClassMembersTest.class);
|
||||
lib.addTestSuite(LuaJavaCoercionTest.class);
|
||||
|
||||
21
test/junit/org/luaj/vm2/lib/jse/JsePlatformTest.java
Normal file
21
test/junit/org/luaj/vm2/lib/jse/JsePlatformTest.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package org.luaj.vm2.lib.jse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
|
||||
public class JsePlatformTest extends TestCase {
|
||||
public void testLuaMainPassesArguments() {
|
||||
Globals globals = JsePlatform.standardGlobals();
|
||||
LuaValue chunk = globals.load("return #arg, arg.n, arg[2], arg[1]");
|
||||
Varargs results = JsePlatform.luaMain(chunk, new String[] { "aaa", "bbb" });
|
||||
assertEquals(results.narg(), 4);
|
||||
assertEquals(results.arg(1), LuaValue.valueOf(2));
|
||||
assertEquals(results.arg(2), LuaValue.valueOf(2));
|
||||
assertEquals(results.arg(3), LuaValue.valueOf("bbb"));
|
||||
assertEquals(results.arg(4), LuaValue.valueOf("aaa"));
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
version: 3.0.1
|
||||
version: 3.0.2
|
||||
Reference in New Issue
Block a user