mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-03-23 20:06:58 +00:00
Remove LuaJ
I feel I should write a long winded commit message about the rationale behind it, but honestly, it was just another folder in the directory root we didn't need.
This commit is contained in:
parent
86569533e9
commit
c3e4a4de5e
@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src/core"/>
|
||||
<classpathentry excluding="org/luaj/vm2/luajc/antlr/|org/luaj/vm2/luajc/lst/|org/luaj/vm2/luajc/JavaCodeGenerator.java" kind="src" path="src/jse"/>
|
||||
<classpathentry kind="src" path="src/jme"/>
|
||||
<classpathentry kind="src" path="test/java"/>
|
||||
<classpathentry kind="src" path="test/junit"/>
|
||||
<classpathentry kind="src" path="test/lua"/>
|
||||
<classpathentry kind="src" path="examples/jse"/>
|
||||
<classpathentry kind="src" path="examples/jme"/>
|
||||
<classpathentry kind="src" path="examples/lua"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
|
||||
<classpathentry kind="lib" path="lib/midpapi20.jar"/>
|
||||
<classpathentry kind="lib" path="lib/cldcapi11.jar"/>
|
||||
<classpathentry kind="lib" path="lib/bcel-5.2.jar"/>
|
||||
<classpathentry kind="var" path="JRE_LIB"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>luaj-vm</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@ -1,19 +0,0 @@
|
||||
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,780 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
|
||||
<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 2.0.3
|
||||
<p>
|
||||
<small>
|
||||
Copyright © 2009-2012 Luaj.org.
|
||||
Freely available under the terms of the
|
||||
<a href="http://sourceforge.net/dbimage.php?id=196142">Luaj license</a>.
|
||||
</small>
|
||||
<hr>
|
||||
<p>
|
||||
|
||||
<a href="#1">introduction</a>
|
||||
·
|
||||
<a href="#2">examples</a>
|
||||
·
|
||||
<a href="#3">concepts</a>
|
||||
·
|
||||
<a href="#4">libraries</a>
|
||||
·
|
||||
<a href="#5">luaj api</a>
|
||||
·
|
||||
<a href="#6">parser</a>
|
||||
·
|
||||
<a href="#7">building</a>
|
||||
·
|
||||
<a href="#8">downloads</a>
|
||||
·
|
||||
<a href="#9">release notes</a>
|
||||
|
||||
<!-- ====================================================================== -->
|
||||
<p>
|
||||
|
||||
<h1>1 - <a name="1">Introduction</a></h1>
|
||||
<h2>Goals of Luaj</h2>
|
||||
Luaj is a lua interpreter based on the 5.1.x version of lua with the following goals in mind:
|
||||
<ul>
|
||||
<li>Java-centric implementation of lua vm built to leverage standard Java features.
|
||||
<li>Lightweight, high performance execution of lua.
|
||||
<li>Multi-platform to be able to run on JME, JSE, or JEE environments.
|
||||
<li>Complete set of libraries and tools for integration into real-world projects.
|
||||
<li>Dependable due to sufficient unit testing of vm and library features.
|
||||
</ul>
|
||||
|
||||
<h2>Differences with 1.0</h2>
|
||||
In addition to the basic goals of luaj, version 2.0 is aimed
|
||||
at improving on the 1.0 vm in the following aspects.
|
||||
<ul>
|
||||
<li>Support for compiling lua source code into Java source code.
|
||||
<li>Support for compiling lua bytecode directly into Java bytecode.
|
||||
<li>Improved performance of of lua bytecode processing.
|
||||
<li>Stackless vm design centered around dynamically typed objects.
|
||||
<li>More alignment with C API (see <a href="names.csv">names.csv</a> for details)
|
||||
<li>Improved class and package naming conventions.
|
||||
<li>Improved unit tests of core classes.
|
||||
<li>Improved quality due to major redesign and rewrite of core elements.
|
||||
<li>More complete implementation including weak keys and values, and all metatags.
|
||||
</ul>
|
||||
|
||||
<h2>Performance</h2>
|
||||
Good performance is a major goal of luaj.
|
||||
The following table provides measured execution times on a subset of benchmarks from
|
||||
<a href="http://shootout.alioth.debian.org/">the computer language benchmarks game</a>
|
||||
in comparison with the standard C distribution.
|
||||
<table cellspacing="10"><tr><td><table>
|
||||
<tr valign="top">
|
||||
<td><u>Project</td>
|
||||
<td><u>Version</td>
|
||||
<td><u>Mode</td>
|
||||
<td rowspan="9"> </td>
|
||||
<td colspan="4" align="center"><u>Benchmark execution time (sec)</td>
|
||||
<td rowspan="9"> </td>
|
||||
<td><u>Language</td>
|
||||
<td><u>Sample command</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td colspan="2"></td>
|
||||
<td></td>
|
||||
<td><em>binarytrees 15</em></td>
|
||||
<td><em>fannkuch 10</em></td>
|
||||
<td><em>nbody 1e6</em></td>
|
||||
<td><em>nsieve 9</em></td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td>luaj</td>
|
||||
<td>2.0</td>
|
||||
<td>-b (luajc)</td>
|
||||
<td>2.980</td>
|
||||
<td>5.073</td>
|
||||
<td>16.794</td>
|
||||
<td>11.274</td>
|
||||
<td>Java</td>
|
||||
<td>java -cp luaj-jse-2.0.3.jar;bcel-5.2.jar lua <b>-b</b> fannkuch.lua 10</td></tr>
|
||||
<tr valign="top">
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>-j (lua2java)</td>
|
||||
<td>4.463</td>
|
||||
<td>5.884</td>
|
||||
<td>16.701</td>
|
||||
<td>13.789</td>
|
||||
<td></td>
|
||||
<td>java -cp luaj-jse-2.0.3.jar lua <b>-j</b> fannkuch.lua 10</td></tr>
|
||||
<tr valign="top">
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>-n (interpreted)</td>
|
||||
<td>12.838</td>
|
||||
<td>23.290</td>
|
||||
<td>36.894</td>
|
||||
<td>15.163</td>
|
||||
<td></td>
|
||||
<td>java -cp luaj-jse-2.0.3.jar lua -n fannkuch.lua 10</td></tr>
|
||||
<tr valign="top">
|
||||
<td>lua</td>
|
||||
<td>5.1.4</td>
|
||||
<td></td>
|
||||
<td>17.637</td>
|
||||
<td>16.044</td>
|
||||
<td>15.201</td>
|
||||
<td>5.477</td>
|
||||
<td>C</td>
|
||||
<td>lua fannkuch.lua 10</td></tr>
|
||||
<tr valign="top">
|
||||
<td>jill</td>
|
||||
<td>1.0.1</td>
|
||||
<td></td>
|
||||
<td>44.512</td>
|
||||
<td>54.630</td>
|
||||
<td>72.172</td>
|
||||
<td>20.779</td>
|
||||
<td>Java</td>
|
||||
<td></td></tr>
|
||||
<tr valign="top">
|
||||
<td>kahlua</td>
|
||||
<td>1.0</td>
|
||||
<td>jse</td>
|
||||
<td>22.963</td>
|
||||
<td>63.277</td>
|
||||
<td>68.223</td>
|
||||
<td>21.529</td>
|
||||
<td>Java</td>
|
||||
<td></td></tr>
|
||||
<tr valign="top">
|
||||
<td>mochalua</td>
|
||||
<td>1.0</td>
|
||||
<td></td>
|
||||
<td>50.457</td>
|
||||
<td>70.368</td>
|
||||
<td>82.868</td>
|
||||
<td>41.262</td>
|
||||
<td>Java</td>
|
||||
<td></td></tr>
|
||||
</table></td></tr></table>
|
||||
|
||||
Luaj in interpreted mode performs well for the benchmarks, and even better when source-to-source (lua2java)
|
||||
or bytecode-to-bytecode (luajc) compilers are used,
|
||||
and actually executes <em>faster</em> than C-based lua in some cases.
|
||||
It is also faster than Java-lua implementations Jill, Kahlua, and Mochalua for all benchmarks tested.
|
||||
|
||||
<h1>2 - <a name="2">Simple Examples</a></h1>
|
||||
|
||||
<h2>Run a lua script in Java SE</h2>
|
||||
|
||||
<p>
|
||||
From the main distribution directory line type:
|
||||
|
||||
<pre>
|
||||
java -cp lib/luaj-jse-2.0.3.jar lua examples/lua/hello.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You should see the following output:
|
||||
<pre>
|
||||
hello, world
|
||||
</pre>
|
||||
|
||||
To see how luaj can be used to acccess most Java API's including swing, try:
|
||||
|
||||
<pre>
|
||||
java -cp lib/luaj-jse-2.0.3.jar lua examples/lua/swingapp.lua
|
||||
</pre>
|
||||
|
||||
<h2>Compile lua source to lua bytecode</h2>
|
||||
|
||||
<p>
|
||||
From the main distribution directory line type:
|
||||
|
||||
<pre>
|
||||
java -cp lib/luaj-jse-2.0.3.jar luac examples/lua/hello.lua
|
||||
java -cp lib/luaj-jse-2.0.3.jar lua luac.out
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The compiled output "luac.out" is lua bytecode and should run and produce the same result.
|
||||
|
||||
<h2>Compile lua source to java source</h2>
|
||||
|
||||
<p>
|
||||
Luaj can compile to lua source code to Java source code:
|
||||
|
||||
<pre>
|
||||
java -cp lib/luaj-jse-2.0.3.jar lua2java -s examples/lua -d . hello.lua
|
||||
javac -cp lib/luaj-jse-2.0.3.jar hello.java
|
||||
java -cp "lib/luaj-jse-2.0.3.jar;." lua -l hello
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The output <em>hello.java</em> is Java source, that implements the logic in hello.lua directly.
|
||||
Once <em>hello.java</em> is compiled into <em>hello.class</em> it can be required and used in place of the original lua script, but with better performance.
|
||||
There are no additional dependencies for compiling or running source-to-source compiled lua.
|
||||
|
||||
<p>
|
||||
Lua scripts can also be run directly in this mode without precompiling using the <em>lua</em> command with the <b><em>-j</em></b> option when run in JDK 1.5 or higher:
|
||||
<pre>
|
||||
java -cp lib/luaj-jse-2.0.3.jar lua -j examples/lua/hello.lua
|
||||
</pre>
|
||||
|
||||
<h2>Compile lua bytecode to java bytecode</h2>
|
||||
|
||||
<p>
|
||||
Luaj can compile lua sources or binaries directly to java bytecode if the bcel library is on the class path. From the main distribution directory line type:
|
||||
|
||||
<pre>
|
||||
ant bcel-lib
|
||||
java -cp "lib/luaj-jse-2.0.3.jar;lib/bcel-5.2.jar" luajc -s examples/lua -d . hello.lua
|
||||
java -cp "lib/luaj-jse-2.0.3.jar;." lua -l hello
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The output <em>hello.class</em> is Java bytecode, should run and produce the same result.
|
||||
There is no runtime dependency on the bcel library,
|
||||
but the compiled classes must be in the class path at runtime, unless runtime jit-compiling via luajc and bcel are desired (see later sections).
|
||||
|
||||
<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-2.0.3.jar;lib/bcel-5.2.jar" lua -b examples/lua/hello.lua
|
||||
</pre>
|
||||
|
||||
|
||||
<h2>Run a script in a Java Application</h2>
|
||||
|
||||
<p>
|
||||
The following pattern is used within Java SE
|
||||
|
||||
<pre>
|
||||
import org.luaj.vm2.*;
|
||||
import org.luaj.vm2.lib.jse.*;
|
||||
|
||||
String script = "examples/lua/hello.lua";
|
||||
LuaValue _G = JsePlatform.standardGlobals();
|
||||
_G.get("dofile").call( LuaValue.valueOf(script) );
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A simple example may be found in
|
||||
<pre>
|
||||
examples/jse/SampleJseMain.java
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You must include the library <b>lib/luaj-jse-2.0.3.jar</b> in your class path.
|
||||
|
||||
<h2>Run a script in a MIDlet</h2>
|
||||
|
||||
<p>
|
||||
The for MIDlets the <em>JmePlatform</em> is used instead:
|
||||
|
||||
<pre>
|
||||
import org.luaj.vm2.*;
|
||||
import org.luaj.vm2.lib.jme.*;
|
||||
|
||||
String script = "examples/lua/hello.lua";
|
||||
LuaValue _G = JmePlatform.standardGlobals();
|
||||
_G.get("dofile").call( LuaValue.valueOf(script) );
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The file must be a resource within within the midlet jar for <em>dofile()</em> to find it.
|
||||
Any files included via <em>require()</em> must also be part of the midlet resources.
|
||||
|
||||
<p>
|
||||
A simple example may be found in
|
||||
<pre>
|
||||
examples/jme/SampleMIDlet.java
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You must include the library <b>lib/luaj-jme-2.0.3.jar</b> in your midlet jar.
|
||||
|
||||
<p>
|
||||
An ant script to build and run the midlet is in
|
||||
<pre>
|
||||
build-midlet.xml
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You must install the wireless toolkit and define <em>WTK_HOME</em> for this script to work.
|
||||
|
||||
<h2>Run a script using JSR-223 Dynamic Scripting</h2>
|
||||
|
||||
<p>
|
||||
The standard use of JSR-223 scripting engines may be used:
|
||||
|
||||
<pre>
|
||||
ScriptEngineManager mgr = new ScriptEngineManager();
|
||||
ScriptEngine e = mgr.getEngineByExtension(".lua");
|
||||
e.put("x", 25);
|
||||
e.eval("y = math.sqrt(x)");
|
||||
System.out.println( "y="+e.get("y") );
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
All standard aspects of script engines including compiled statements should be supported.
|
||||
|
||||
<p>
|
||||
You must include the library <b>lib/luaj-jse-2.0.3.jar</b> in your class path.
|
||||
|
||||
<p>
|
||||
A working example may be found in
|
||||
<pre>
|
||||
examples/jse/ScriptEngineSample.java
|
||||
</pre>
|
||||
|
||||
To compile and run it using Java 1.6 or higher:
|
||||
|
||||
<pre>
|
||||
javac examples/jse/ScriptEngineSample.java
|
||||
java -cp "lib/luaj-jse-2.0.3.jar;examples/jse" ScriptEngineSample
|
||||
</pre>
|
||||
|
||||
<h2>Excluding the lua bytecode compiler</h2>
|
||||
|
||||
By default, the compiler is included whenever <em>standardGlobals()</em> or <em>debugGlobals()</em> are called.
|
||||
Without a compiler, files can still be executed, but they must be compiled elsewhere beforehand.
|
||||
The "luac" utility is provided in the jse jar for this purpose, or a standard lua compiler can be used.
|
||||
|
||||
<p>
|
||||
To exclude the lua-to-lua-bytecode compiler, do not call
|
||||
<em>standardGlobals()</em> or <em>debugGlobals()</em>
|
||||
but instead initialize globals with including only those libraries
|
||||
that are needed and omitting the line:
|
||||
<pre>
|
||||
org.luaj.vm2.compiler.LuaC.install();
|
||||
</pre>
|
||||
|
||||
|
||||
<h2>Including the Lua2Java lua-source-to-Java-source compiler</h2>
|
||||
|
||||
<p>
|
||||
To compile from lua sources to Java sources for all lua loaded at runtime,
|
||||
install the Lua2Java compiler <em>after</em> globals have been created using:
|
||||
|
||||
<pre>
|
||||
org.luaj.vm2.jse.lua2java.Lua2Java.install();
|
||||
</pre>
|
||||
|
||||
This uses the system Java compiler to compile from Java source to Java bytecode,
|
||||
and cannot compile lua binary files containing lua bytecode at runtime.
|
||||
|
||||
<h2>Including the LuaJC lua-bytecode-to-Java-bytecode compiler</h2>
|
||||
|
||||
<p>
|
||||
To compile from lua to Java bytecode for all lua loaded at runtime,
|
||||
install the LuaJC compiler <em>after</em> globals have been created using:
|
||||
|
||||
<pre>
|
||||
org.luaj.vm2.jse.luajc.LuaJC.install();
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This will compile all lua bytecode into Java bytecode, regardless of if they are loaded as
|
||||
lua source or lua binary files.
|
||||
|
||||
<p>
|
||||
The requires <em>bcel</em> to be on the class path, and the ClassLoader of JSE or CDC.
|
||||
|
||||
<h1>3 - <a name="3">Concepts</a></h1>
|
||||
|
||||
<h2>Globals</h2>
|
||||
The old notion of platform has been replaced with creation of globals.
|
||||
Two classes are provided to encapsulate common combinations of libraries.
|
||||
|
||||
<h3>JsePlatform</h3>
|
||||
|
||||
This class can be used as a factory for globals in a typical Java SE application.
|
||||
All standard libraries are included, as well as the luajava library.
|
||||
The default search path is the current directory,
|
||||
and the math operations include all those supported by Java SE.
|
||||
|
||||
<h3>JmePlatform</h3>
|
||||
|
||||
This class can be used to set up the basic environment for a Java ME application.
|
||||
The default search path is limited to the jar resources,
|
||||
and the math operations are limited to those supported by Java ME.
|
||||
All libraries are included except luajava, and the os, io, and math libraries are
|
||||
limited to those functions that can be supported on that platform.
|
||||
|
||||
|
||||
<h1>4 - <a name="4">Libraries</a></h1>
|
||||
|
||||
<h2>Standard Libraries</h2>
|
||||
|
||||
Libraries are coded to closely match the behavior specified in
|
||||
See <a href="http://www.lua.org/manual/5.1/">standard lua documentation</a> for details on the library API's
|
||||
|
||||
<p>
|
||||
The following libraries are loaded by both <em>JsePlatform.standardGlobals()</em> and <em>JmePlatform.standardGlobals()</em>:
|
||||
<pre> base
|
||||
coroutine
|
||||
io
|
||||
math
|
||||
os
|
||||
package
|
||||
string
|
||||
table
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <em>JsePlatform.standardGlobals()</em> globals also include:
|
||||
<pre> luajava
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <em>JsePlatform.debugGlobals()</em> and <em>JsePlatform.debugGlobals()</em> functions produce globals that include:
|
||||
<pre> debug
|
||||
</pre>
|
||||
|
||||
<h3>I/O Library</h3>
|
||||
The implementation of the <em>io</em> library differs by platform owing to platform limitations.
|
||||
|
||||
<p>
|
||||
The <em>JmePlatform.standardGlobals()</em> instantiated the io library <em>io</em> in
|
||||
<pre>
|
||||
src/jme/org/luaj/vm2/lib/jme/JmeIoLib.java
|
||||
</pre>
|
||||
|
||||
The <em>JsePlatform.standardGlobals()</em> includes support for random access and is in
|
||||
<pre>
|
||||
src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
|
||||
</pre>
|
||||
|
||||
<h3>OS Library</h3>
|
||||
The implementation of the <em>os</em> library also differs per platform.
|
||||
|
||||
<p>
|
||||
The basic <em>os</em> library implementation us used by <em>JmePlatform</em> and is in:
|
||||
<pre>
|
||||
src/core/org/luaj/lib/OsLib.java
|
||||
</pre>
|
||||
|
||||
A richer version for use by <em>JsePlatform</em> is :
|
||||
<pre>
|
||||
src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
|
||||
</pre>
|
||||
|
||||
Time is a represented as number of milliseconds since the epoch,
|
||||
and most time and date formatting, locales, and other features
|
||||
are not implemented.
|
||||
|
||||
<h3>Coroutine Library</h3>
|
||||
The <em>coroutine</em> library is implemented using one JavaThread per coroutine.
|
||||
This allows <em>coroutine.yield()</em> can be called from anywhere,
|
||||
as with the yield-from-anywhere patch in C-based lua.
|
||||
|
||||
<p>
|
||||
Luaj uses WeakReferences and the OrphanedThread error to ensure that coroutines that are no longer referenced
|
||||
are properly garbage collected. For thread safety, OrphanedThread should not be caught by Java code.
|
||||
See <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/LuaThread.html">LuaThread</a>
|
||||
and <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/OrphanedThread.html">OrphanedThread</a>
|
||||
javadoc for details.
|
||||
|
||||
<h3>Debug Library</h3>
|
||||
The <em>debug</em> library is not included by default by
|
||||
<em>JmePlatform.standardGlobals()</em> or <em>JsePlatform.standardGlobsls()</em> .
|
||||
|
||||
The functions <em>JmePlatform.debugGlobals()</em> and <em>JsePlatform.debugGlobsls()</em>
|
||||
create globals that contain the debug library in addition to the other standard libraries.
|
||||
|
||||
To install dynamically from lua use java-class-based require:</em>:
|
||||
<pre>
|
||||
require 'org.luaj.vm2.lib.DebugLib'
|
||||
</pre>
|
||||
|
||||
The <em>lua</em> command line utility includes the <em>debug</em> library by default.
|
||||
|
||||
|
||||
<h3>The Luajava Library</h3>
|
||||
The <em>JsePlatform.standardGlobals()</em> includes the <em>luajava</em> library, which simplifies binding to Java classes and methods.
|
||||
It is patterned after the original <a href="http://www.keplerproject.org/luajava/">luajava project</a>.
|
||||
|
||||
<p>
|
||||
The following lua script will open a swing frame on Java SE:
|
||||
<pre>
|
||||
jframe = luajava.bindClass( "javax.swing.JFrame" )
|
||||
frame = luajava.newInstance( "javax.swing.JFrame", "Texts" );
|
||||
frame:setDefaultCloseOperation(jframe.EXIT_ON_CLOSE)
|
||||
frame:setSize(300,400)
|
||||
frame:setVisible(true)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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-2.0.3.jar lua examples/lua/swingapp.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The Java ME platform does not include this library, and it cannot be made to work because of the lack of a reflection API in Java ME.
|
||||
|
||||
<p>
|
||||
The <em>lua</em> connand line tool includes <em>luajava</em>.
|
||||
|
||||
<h1>5 - <a name="5">LuaJ API</a></h1>
|
||||
|
||||
<h2>API Javadoc</h2>
|
||||
The javadoc for the main classes in the LuaJ API are on line at
|
||||
<pre>
|
||||
<a href="http://luaj.sourceforge.net/api/2.0/index.html">http://luaj.sourceforge.net/api/2.0</a>
|
||||
</pre>
|
||||
|
||||
You can also build a local version from sources using
|
||||
<pre>
|
||||
ant doc
|
||||
</pre>
|
||||
|
||||
<h2>LuaValue and Varargs</h2>
|
||||
All lua value manipulation is now organized around
|
||||
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/LuaValue.html">LuaValue</a>
|
||||
which exposes the majority of interfaces used for lua computation.
|
||||
<pre>
|
||||
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/LuaValue.html">org.luaj.vm2.LuaValue</a>
|
||||
</pre>
|
||||
|
||||
<h3>Common Functions</h3>
|
||||
<em>LuaValue</em> exposes functions for each of the operations in LuaJ.
|
||||
Some commonly used functions and constants include:
|
||||
<pre>
|
||||
call(); // invoke the function with no arguments
|
||||
call(LuaValue arg1); // call the function with 1 argument
|
||||
invoke(Varargs arg); // call the function with variable arguments, variable return values
|
||||
get(int index); // get a table entry using an integer key
|
||||
get(LuaValue key); // get a table entry using an arbitrary key, may be a LuaInteger
|
||||
rawget(int index); // raw get without metatable calls
|
||||
valueOf(int i); // return LuaValue corresponding to an integer
|
||||
valueOf(String s); // return LuaValue corresponding to a String
|
||||
toint(); // return value as a Java int
|
||||
tojstring(); // return value as a Java String
|
||||
isnil(); // is the value nil
|
||||
NIL; // the value nil
|
||||
NONE; // a Varargs instance with no values
|
||||
</pre>
|
||||
|
||||
<h2>Varargs</h2>
|
||||
The interface <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/Varargs.html">Varargs</a> provides an abstraction for
|
||||
both a variable argument list and multiple return values.
|
||||
For convenience, <em>LuaValue</em> implements <em>Varargs</em> so a single value can be supplied anywhere
|
||||
variable arguments are expected.
|
||||
<pre>
|
||||
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/Varargs.html">org.luaj.vm2.Varargs</a>
|
||||
</pre>
|
||||
|
||||
<h3>Common Functions</h3>
|
||||
<em>Varargs</em> exposes functions for accessing elements, and coercing them to specific types:
|
||||
<pre>
|
||||
narg(); // return number of arguments
|
||||
arg1(); // return the first argument
|
||||
arg(int n); // return the nth argument
|
||||
isnil(int n); // true if the nth argument is nil
|
||||
checktable(int n); // return table or throw error
|
||||
optlong(int n,long d); // return n if a long, d if no argument, or error if not a long
|
||||
</pre>
|
||||
|
||||
See the <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/Varargs.html">Varargs</a> API for a complete list.
|
||||
|
||||
<h2>LibFunction</h2>
|
||||
The simplest way to implement a function is to choose a base class based on the number of arguments to the function.
|
||||
LuaJ provides 5 base classes for this purpose, depending if the function has 0, 1, 2, 3 or variable arguments,
|
||||
and if it provide multiple return values.
|
||||
<pre>
|
||||
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/ZeroArgFunction.html">org.luaj.vm2.lib.ZeroArgFunction</a>
|
||||
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/OneArgFunction.html">org.luaj.vm2.lib.OneArgFunction</a>
|
||||
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/TwoArgFunction.html">org.luaj.vm2.lib.TwoArgFunction</a>
|
||||
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/ThreeArgFunction.html">org.luaj.vm2.lib.ThreeArgFunction</a>
|
||||
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/VarArgFunction.html">org.luaj.vm2.lib.VarArgFunction</a>
|
||||
</pre>
|
||||
|
||||
Each of these functions has an abstract method that must be implemented,
|
||||
and argument fixup is done automatically by the classes as each Java function is invoked.
|
||||
|
||||
<p>
|
||||
For example, to implement a "hello, world" function, we could supply:
|
||||
<pre>
|
||||
pubic class hello extends ZeroArgFunction {
|
||||
public LuaValue call() {
|
||||
env.get("print").call(valueOf("hello, world"));
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
The value <em>env</em> is the environment of the function, and is normally supplied
|
||||
by the instantiating object whenever default loading is used.
|
||||
|
||||
<p>
|
||||
Calling this function from lua could be done by:
|
||||
<pre>
|
||||
require( 'hello' )()
|
||||
</pre>
|
||||
|
||||
while calling this function from Java would look like:
|
||||
<pre>
|
||||
new hello().call();
|
||||
</pre>
|
||||
|
||||
Note that in both the lua and Java case, extra arguments will be ignored, and the function will be called.
|
||||
Also, no virtual machine instance is necessary to call the function.
|
||||
To allow for arguments, or return multiple values, extend one of the other base classes.
|
||||
|
||||
<h2>Closures</h2>
|
||||
Closures still exist in this framework, but are optional, and are only used to implement lua bytecode execution.
|
||||
|
||||
<h1>6 - <a name="6">Parser</a></h1>
|
||||
|
||||
<h2>Javacc Grammar</h2>
|
||||
A Javacc grammarwas developed to simplify the creation of Java-based parsers for the lua language.
|
||||
The grammar is specified for <a href="https://javacc.dev.java.net/">javacc version 5.0</a> because that tool generates standalone
|
||||
parsers that do not require a separate runtime.
|
||||
|
||||
<p>
|
||||
A plain undecorated grammer that can be used for validation is available in <a href="grammar/Lua51.jj">grammar/Lua51.jj</a>
|
||||
while a grammar that generates a typed parse tree is in <a href="grammar/LuaParser.jj">grammar/LuaParser.jj</a>
|
||||
|
||||
<h2>Creating a Parse Tree from Lua Source</h2>
|
||||
The default lu compiler does a single-pass compile of lua source to lua bytecode, so no explicit parse tree is produced.
|
||||
|
||||
<p>
|
||||
To simplify the creation of abstract syntax trees from lua sources, the LuaParser class is generated as part of the JME build.
|
||||
To use it, provide an input stream, and invoke the root generator, which will return a Chunk if the file is valid,
|
||||
or throw a ParseException if there is a syntax error.
|
||||
|
||||
<p>
|
||||
For example, to parse a file and print all variable names, use code like:
|
||||
<pre>
|
||||
try {
|
||||
String file = "main.lua";
|
||||
LuaParser parser = new LuaParser(new FileInputStream(file));
|
||||
Chunk chunk = parser.Chunk();
|
||||
chunk.accept( new Visitor() {
|
||||
public void visit(Exp.NameExp exp) {
|
||||
System.out.println("Name in use: "+exp.name.name);
|
||||
}
|
||||
} );
|
||||
} catch ( ParseException e ) {
|
||||
System.out.println("parse failed: " + e.getMessage() + "\n"
|
||||
+ "Token Image: '" + e.currentToken.image + "'\n"
|
||||
+ "Location: " + e.currentToken.beginLine + ":" + e.currentToken.beginColumn
|
||||
+ "-" + e.currentToken.endLine + "," + e.currentToken.endColumn);
|
||||
}
|
||||
</pre>
|
||||
In luaj 2.0.3 error reporting was turned on in the parser so line numbers are avaiable for most parse exceptions.
|
||||
This example may be found in
|
||||
<pre>
|
||||
examples/jse/SampleParser.java
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
See the <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/ast/package-summary.html">org.luaj.vm2.ast package</a> javadoc for the API relating to the syntax tree that is produced.
|
||||
|
||||
<h1>7 - <a name="7">Building and Testing</a></h1>
|
||||
|
||||
<h2>Building the jars</h2>
|
||||
An ant file is included in the root directory which builds the libraries by default.
|
||||
|
||||
<p>
|
||||
Other targets exist for creating distribution file an measuring code coverage of unit tests.
|
||||
|
||||
<h2>Unit tests</h2>
|
||||
|
||||
<p>
|
||||
The main luaj JUnit tests are organized into a JUnit 3 suite:
|
||||
<pre>
|
||||
test/junit/org/luaj/vm2/AllTests.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Unit test scripts can be found in these locations
|
||||
<pre>
|
||||
test/lua/*.lua
|
||||
test/junit/org/luaj/vm2/compiler/lua5.1-tests.zip
|
||||
test/junit/org/luaj/vm2/compiler/regressions.zip
|
||||
test/junit/org/luaj/vm2/vm1/luajvm1-tests.zip
|
||||
</pre>
|
||||
|
||||
<h2>Code coverage</h2>
|
||||
|
||||
<p>
|
||||
A build script for running unit tests and producing code coverage statistics is in
|
||||
<pre>
|
||||
build-coverage.xml
|
||||
</pre>
|
||||
|
||||
It relies on the cobertura code coverage library.
|
||||
|
||||
<h1>8 - <a name="8">Downloads</a></h1>
|
||||
|
||||
<h2>Downloads and Project Pages</h2>
|
||||
Downloads for all version available on SourceForge or LuaForge.
|
||||
Sources are hosted on SourceForge and available via sourceforge.net
|
||||
<br/>
|
||||
<pre>
|
||||
<a href="http://luaj.sourceforge.net/">SourceForge Luaj Project Page</a>
|
||||
<a href="http://sourceforge.net/project/platformdownload.php?group_id=197627">SourceForge Luaj Download Area</a>
|
||||
</pre>
|
||||
<p/>
|
||||
and LuaForge:
|
||||
<pre>
|
||||
<a href="http://luaforge.net/projects/luaj/">LuaForge Luaj Project Page</a>
|
||||
<a href="http://luaforge.net/frs/?group_id=457">LuaForge Luaj Project Area</a>
|
||||
</pre>
|
||||
|
||||
<h1>9 - <a name="9">Release Notes</a></h1>
|
||||
|
||||
<h2>Main Changes by Version</h2>
|
||||
<table cellspacing="10"><tr><td><table cellspacing="4">
|
||||
<tr valign="top"><td> <b>2.0</b></td><td><ul>
|
||||
<li>Initial release of 2.0 version </li>
|
||||
</ul></td></tr>
|
||||
<tr valign="top"><td> <b>2.0.1</b></td><td><ul>
|
||||
<li>Improve correctness of singleton construction related to static initialization </li>
|
||||
<li>Fix nan-related error in constant folding logic that was failing on some JVMs </li>
|
||||
<li>JSR-223 fixes: add META-INF/services entry in jse jar, improve bindings implementation </li>
|
||||
</ul></td></tr>
|
||||
<tr valign="top"><td> <b>2.0.2</b></td><td><ul>
|
||||
<li>JSR-223 bindings change: non Java-primitives will now be passed as LuaValue </li>
|
||||
<li>JSR-223 enhancement: allow both ".lua" and "lua" as extensions in getScriptEngine() </li>
|
||||
<li>JSR-223 fix: use system class loader to support using luaj as JRE extension </li>
|
||||
<li>Improve selection logic when binding to overloaded functions using luajava</li>
|
||||
<li>Enhance javadoc, put it <a href="docs/api/index.html">in distribution</a> and <a href="http://luaj.sourceforge.net/api/2.0/index.html">on line</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>
|
||||
<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>
|
||||
<li>Fix lua command vararg values passed into main script to match what is in global arg table </li>
|
||||
<li>Add arithmetic metatag processing when left hand side is a number and right hand side has metatable </li>
|
||||
<li>Fix load(func) when mutiple string fragments are supplied by calls to func </li>
|
||||
<li>Allow access to public members of private inner classes where possible </li>
|
||||
<li>Turn on error reporting in LuaParser so line numbers ar available in ParseException </li>
|
||||
<li>Improve compatibility of table.remove() </li>
|
||||
<li>Disallow base library setfenv() calls on Java functions </li>
|
||||
</ul></td></tr>
|
||||
</table></td></tr></table>
|
||||
|
||||
<h2>Known Issues</h2>
|
||||
<ul>
|
||||
<li>debug code may not be completely removed by some obfuscators
|
||||
<li>tail calls are not tracked in debug information
|
||||
<li>using both version 1 and 2 libraries together in the same java vm has not been tested
|
||||
<li>module() and setfenv() only partially supported for lau2java or luajc compiled lua
|
||||
<li>values associated with weak keys may linger longer than expected
|
||||
<li>behavior of luaj when a SecurityManager is used has not been fully characterized
|
||||
</ul>
|
||||
|
@ -1,119 +0,0 @@
|
||||
<project default="all" xmlns:artifact="antlib:org.apache.maven.artifact.ant">
|
||||
<!--
|
||||
Run code coverage for unit tests on the luaj vm and libraries.
|
||||
-->
|
||||
|
||||
<property name="classes.dir" value="build/classes-debug" />
|
||||
<property name="instrumented.dir" value="build/instrumented" />
|
||||
<property name="reports.xml.dir" value="build/reports-junit-xml" />
|
||||
<property name="reports.html.dir" value="build/reports-junit-html" />
|
||||
<property name="coverage.xml.dir" value="build/reports-coverage-xml" />
|
||||
<property name="coverage.html.dir" value="build/reports-coverage-html" />
|
||||
<property name="cobertura.serfile" value="cobertura.ser" />
|
||||
<property name="cobertura.logfile" value="cobertura.log" />
|
||||
|
||||
<artifact:dependencies filesetId="cobutura.fileset">
|
||||
<dependency groupId="net.sourceforge.cobertura" artifactId="cobertura" version="1.9.4.1"/>
|
||||
<dependency groupId="junit" artifactId="junit" version="3.8.1"/>
|
||||
</artifact:dependencies>
|
||||
|
||||
<path id="cobertura.classpath">
|
||||
<fileset refid="cobutura.fileset" />
|
||||
</path>
|
||||
|
||||
<taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
|
||||
|
||||
<import file="wtk.xml"/>
|
||||
|
||||
<property environment="env"/>
|
||||
|
||||
<target name="clean" description="Remove all files created by the build/test process.">
|
||||
<delete dir="${classes.dir}" failonerror="yes"/>
|
||||
<delete dir="${instrumented.dir}" failonerror="yes"/>
|
||||
<delete file="${cobertura.logfile}" />
|
||||
<delete file="${cobertura.serfile}" />
|
||||
</target>
|
||||
|
||||
<target name="init">
|
||||
<ant antfile="build.xml" target="bcel-lib"/>
|
||||
<ant antfile="build.xml" target="luaj1-lib"/>
|
||||
<mkdir dir="${classes.dir}" />
|
||||
<mkdir dir="${instrumented.dir}" />
|
||||
<mkdir dir="${reports.xml.dir}" />
|
||||
<mkdir dir="${reports.html.dir}" />
|
||||
<mkdir dir="${coverage.xml.dir}" />
|
||||
<mkdir dir="${coverage.html.dir}" />
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="init,wtk-or-fail">
|
||||
<javac destdir="${classes.dir}" debug="yes" target="1.5">
|
||||
<classpath refid="cobertura.classpath" />
|
||||
<classpath refid="wtk-libs" />
|
||||
<classpath path="lib/bcel-5.2.jar" />
|
||||
<src path="src/core"/>
|
||||
<src path="src/jme"/>
|
||||
<src path="src/jse"/>
|
||||
<src path="test/junit"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="instrument" depends="compile">
|
||||
<delete file="${cobertura.serfile}"/>
|
||||
<delete dir="${instrumented.dir}" failonerror="no"/>
|
||||
<cobertura-instrument datafile="${cobertura.serfile}" todir="${instrumented.dir}">
|
||||
<fileset dir="${classes.dir}">
|
||||
<include name="org/luaj/vm2/*.class" />
|
||||
<include name="org/luaj/vm2/lib/*.class" />
|
||||
<include name="org/luaj/vm2/lib/jse/*.class" />
|
||||
<include name="org/luaj/vm2/lib/jme/*.class" />
|
||||
<include name="org/luaj/vm2/compiler/*.class" />
|
||||
<include name="org/luaj/vm2/luajc/*.class" />
|
||||
<include name="org/luaj/vm2/lua2java/*.class" />
|
||||
<include name="org/luaj/vm2/parser/*.class" />
|
||||
<include name="org/luaj/vm2/ast/*.class" />
|
||||
<exclude name="**/*Test*.class" />
|
||||
</fileset>
|
||||
</cobertura-instrument>
|
||||
</target>
|
||||
|
||||
<target name="test">
|
||||
<junit fork="yes" dir="${basedir}" showoutput="yes">
|
||||
<sysproperty key="net.sourceforge.cobertura.serfile"
|
||||
file="${basedir}/${cobertura.serfile}" />
|
||||
<classpath location="${instrumented.dir}" />
|
||||
<classpath location="${classes.dir}" />
|
||||
<classpath refid="cobertura.classpath" />
|
||||
<classpath location="test/lua" />
|
||||
<classpath location="test/junit/org/luaj/vm2/compiler" />
|
||||
<classpath location="test/junit/org/luaj/vm2/vm1" />
|
||||
<classpath path="lib/bcel-5.2.jar" />
|
||||
<formatter type="xml" />
|
||||
<batchtest todir="${reports.xml.dir}">
|
||||
<fileset dir="test/junit">
|
||||
<include name="org/luaj/vm2/AllTests.java" />
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
|
||||
<junitreport todir="${reports.xml.dir}">
|
||||
<fileset dir="${reports.xml.dir}">
|
||||
<include name="TEST-*.xml" />
|
||||
</fileset>
|
||||
<report format="frames" todir="${reports.html.dir}" />
|
||||
</junitreport>
|
||||
</target>
|
||||
|
||||
<target name="report">
|
||||
<cobertura-report datafile="${cobertura.serfile}" destdir="${coverage.xml.dir}" format="xml" />
|
||||
<cobertura-report datafile="${cobertura.serfile}" destdir="${coverage.html.dir}">
|
||||
<fileset dir="src/core"/>
|
||||
<fileset dir="src/jse"/>
|
||||
<fileset dir="src/jme"/>
|
||||
</cobertura-report>
|
||||
</target>
|
||||
|
||||
<target name="coverage" depends="clean,init,compile,instrument,test,report"/>
|
||||
|
||||
<target name="all" depends="coverage" />
|
||||
|
||||
</project>
|
@ -1,56 +0,0 @@
|
||||
<project default="all-libs">
|
||||
|
||||
<available file="lib/midpapi20.jar" property="midpapi.lib.exists"/>
|
||||
<available file="lib/bcel-5.2.jar" property="bcel.lib.exists"/>
|
||||
<available file="lib/javacc.jar" property="javacc.lib.exists"/>
|
||||
<available file="lib/proguard.jar" property="proguard.lib.exists"/>
|
||||
<available file="lib/antenna-bin-1.2.0-beta.jar" property="antenna.lib.exists"/>
|
||||
<available file="lib/junit.jar" property="junit.lib.exists"/>
|
||||
<available file="lib/cobertura.jar" property="cobertura.lib.exists"/>
|
||||
<available file="lib/microemulator.jar" property="microemulator.lib.exists"/>
|
||||
|
||||
<macrodef name="download">
|
||||
<attribute name="zipname"/>
|
||||
<attribute name="jars" default="**/*.jar"/>
|
||||
<sequential>
|
||||
<mkdir dir="lib"/>
|
||||
<get src="http://luaj.sourceforge.net/lib/@{zipname}.tar.gz"
|
||||
dest="lib/@{zipname}.tar.gz"/>
|
||||
<gunzip src="lib/@{zipname}.tar.gz" dest="lib/@{zipname}.tar"/>
|
||||
<untar src="lib/@{zipname}.tar" dest="lib" overwrite="true">
|
||||
<patternset>
|
||||
<include name="@{jars}"/>
|
||||
</patternset>
|
||||
<mapper type="flatten"/>
|
||||
</untar>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<target name="wtk-libs" unless="midpapi.lib.exists">
|
||||
<download zipname="wtk-2.5.2-api"/>
|
||||
</target>
|
||||
<target name="bcel-lib" unless="bcel.lib.exists">
|
||||
<download zipname="/bcel-5.2"/>
|
||||
</target>
|
||||
<target name="javacc-lib" unless="javacc.lib.exists">
|
||||
<download zipname="javacc-5.0"/>
|
||||
</target>
|
||||
<target name="proguard-lib" unless="proguard.lib.exists">
|
||||
<download zipname="proguard4.6"/>
|
||||
</target>
|
||||
<target name="antenna-lib" unless="antenna.lib.exists">
|
||||
<download zipname="antenna-bin-1.2.0-beta"/>
|
||||
</target>
|
||||
<target name="junit-lib" unless="junit.lib.exists">
|
||||
<download zipname="junit-3.8.2"/>
|
||||
</target>
|
||||
<target name="cobertura-lib" unless="cobertura.lib.exists">
|
||||
<download zipname="cobertura-1.9.4.1-bin"/>
|
||||
</target>
|
||||
<target name="microemulator-lib" unless="microemulator.lib.exists">
|
||||
<download zipname="microemulator-2.0.4" jars="**/microemulator.jar"/>
|
||||
</target>
|
||||
|
||||
<target name="all-libs" depends="wtk-libs,bcel-lib,javacc-lib,proguard-lib,antenna-lib,junit-lib,cobertura-lib"/>
|
||||
|
||||
</project>
|
@ -1,172 +0,0 @@
|
||||
<project default="all">
|
||||
<property file="version.properties"/>
|
||||
|
||||
<property name="jar.name.jme" value="luaj-jme-${version}.jar"/>
|
||||
<property name="jar.name.jse" value="luaj-jse-${version}.jar"/>
|
||||
<property name="jar.name.sources" value="luaj-sources-${version}.jar"/>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="build"/>
|
||||
<delete>
|
||||
<fileset dir="." includes="luaj-*.jar"/>
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<import file="build-libs.xml"/>
|
||||
|
||||
<target name="parser" depends="javacc-lib">
|
||||
<java classname="javacc" classpath="lib/javacc.jar">
|
||||
<arg line="grammar/LuaParser.jj"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="wtk-libs,bcel-lib">
|
||||
<delete dir="build/jme/src"/>
|
||||
<delete dir="build/jse/src"/>
|
||||
<mkdir dir="build/jme/src"/>
|
||||
<mkdir dir="build/jse/src"/>
|
||||
<mkdir dir="build/jme/classes"/>
|
||||
<mkdir dir="build/jse/classes"/>
|
||||
<copy todir="build/jme/src">
|
||||
<fileset dir="src/core"/>
|
||||
<fileset dir="src/jme"/>
|
||||
<filterchain>
|
||||
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-jme ${version}"'/></tokenfilter>
|
||||
</filterchain>
|
||||
</copy>
|
||||
<copy todir="build/jse/src">
|
||||
<fileset dir="src/core"/>
|
||||
<filterchain>
|
||||
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-jse ${version}"'/></tokenfilter>
|
||||
</filterchain>
|
||||
</copy>
|
||||
<copy todir="build/jse/src">
|
||||
<fileset dir="src/jse"/>
|
||||
<filterchain>
|
||||
<tokenfilter><replacestring from='<String>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<Stat>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<Exp>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<Name>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<Block>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<TableField>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<VarExp>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<Exp.VarExp>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<Object,String>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<Double,String>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<Integer,Integer>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<Exp,Integer>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<String,byte[]>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<String,Variable>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<LuaValue,String>' to=''/></tokenfilter>
|
||||
<tokenfilter><replacestring from='<LuaString,String>' to=''/></tokenfilter>
|
||||
</filterchain>
|
||||
</copy>
|
||||
<path id="wtk-libs">
|
||||
<pathelement path="lib/cldcapi11.jar"/>
|
||||
<pathelement path="lib/midpapi20.jar"/>
|
||||
<pathelement path="lib/mmapi.jar"/>
|
||||
</path>
|
||||
<javac destdir="build/jme/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs"
|
||||
srcdir="build/jme/src"/>
|
||||
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
|
||||
classpath="lib/bcel-5.2.jar"
|
||||
srcdir="build/jse/src"
|
||||
excludes="**/script/*,**/Lua2Java*,lua*"/>
|
||||
<javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5"
|
||||
classpath="build/jse/classes"
|
||||
srcdir="build/jse/src"
|
||||
includes="**/script/*,**/Lua2Java*"/>
|
||||
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
|
||||
classpath="build/jse/classes"
|
||||
srcdir="build/jse/src"
|
||||
includes="lua*"/>
|
||||
</target>
|
||||
|
||||
<target name="jar-jme" depends="compile">
|
||||
<jar destfile="${jar.name.jme}" basedir="build/jme/classes"/>
|
||||
</target>
|
||||
|
||||
<target name="jar-jse" depends="compile">
|
||||
<jar destfile="${jar.name.jse}">
|
||||
<fileset dir="build/jse/classes"/>
|
||||
<fileset dir="src/jse/">
|
||||
<include name="META-INF/services/**"/>
|
||||
</fileset>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="jar-jse-sources" depends="compile">
|
||||
<jar destfile="${jar.name.sources}">
|
||||
<fileset dir="build/jme/src"/>
|
||||
<fileset dir="build/jse/src"/>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="doc">
|
||||
<delete dir="docs/api"/>
|
||||
<mkdir dir="docs/api"/>
|
||||
<javadoc defaultexcludes="yes"
|
||||
destdir="docs/api"
|
||||
author="true"
|
||||
version="true"
|
||||
use="true"
|
||||
windowtitle="Luaj API">
|
||||
<fileset dir="src/core" defaultexcludes="yes" includes="org/luaj/vm2/*.java,org/luaj/vm2/compiler/LuaC.java,org/luaj/vm2/lib/*.java"/>
|
||||
<fileset dir="src/jse" defaultexcludes="yes" includes="org/luaj/vm2/lib/jse/*.java,org/luaj/vm2/luajc/LuaJC.java"/>
|
||||
<fileset dir="src/jme" defaultexcludes="yes" includes="org/luaj/vm2/lib/jme/*.java"/>
|
||||
<doctitle><![CDATA[<h1>Luaj API</h1>]]></doctitle>
|
||||
<bottom><![CDATA[<i>Copyright © 2007-2008 Luaj.org. All Rights Reserved.</i>]]></bottom>
|
||||
<tag name="todo" scope="all" description="To do:"/>
|
||||
<group title="Core VM" packages="org.luaj.vm.*"/>
|
||||
<link offline="true" href="http://sourceforge.net/projects/luaj/" packagelistLoc="C:\tmp"/>
|
||||
<link href="http://sourceforge.net/projects/luaj/"/>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
<target name="dist" depends="all,doc">
|
||||
<delete dir="build/luaj-${version}"/>
|
||||
<mkdir dir="build/luaj-${version}/src"/>
|
||||
<mkdir dir="build/luaj-${version}/lib"/>
|
||||
<copy todir="build/luaj-${version}/src">
|
||||
<fileset dir="src">
|
||||
<exclude name="src/test/**"/>
|
||||
<exclude name="**/antlr/**"/>
|
||||
<exclude name="**/lst/**"/>
|
||||
<exclude name="**/JavaCodeGenerator.java"/>
|
||||
<exclude name="**/LuaJCompiler.java"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="build/luaj-${version}/test">
|
||||
<fileset dir="test"/>
|
||||
</copy>
|
||||
<copy todir="build/luaj-${version}/examples">
|
||||
<fileset dir="examples"/>
|
||||
</copy>
|
||||
<copy todir="build/luaj-${version}/lib">
|
||||
<fileset dir=".">
|
||||
<include name="*-${version}.jar"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="build/luaj-${version}">
|
||||
<fileset dir=".">
|
||||
<include name="build.xml"/>
|
||||
<include name="build-libs.xml"/>
|
||||
<include name="build-coverage.xml"/>
|
||||
<include name="version.properties"/>
|
||||
<include name="wtk.xml"/>
|
||||
<include name="README.html"/>
|
||||
<include name="names.csv"/>
|
||||
<include name=".classpath"/>
|
||||
<include name=".project"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="build/luaj-${version}/docs">
|
||||
<fileset dir="docs"/>
|
||||
</copy>
|
||||
<zip destfile="luaj-${version}.zip"
|
||||
basedir="build" includes="luaj-${version}/**"/>
|
||||
</target>
|
||||
|
||||
<target name="all" depends="clean,jar-jme,jar-jse,jar-jse-sources"/>
|
||||
|
||||
</project>
|
@ -1,89 +0,0 @@
|
||||
LuaValue Consructors,,Return type,,,,,,,,,,
|
||||
,valueOf(boolean),LuaBoolean,,,,,,,,,,
|
||||
,valueOf(null),LuaNil,,,,,,,,,,
|
||||
,valueOf(int) ,LuaInteger,,,,,,,,,,
|
||||
,valueOf(double),LuaNumber,,,,,,,,,,
|
||||
,valueOf(long),LuaNumber,,,,,,,,,,
|
||||
,valueOf(String),LuaString,,,,,,,,,,
|
||||
,tableOf(...),LuaTable,,,,,,,,,,
|
||||
,listOf(LuaValue[]),LuaTable,,,,,,,,,,
|
||||
,userdataOf(Object),LuaUserdata,,,,,,,,,,
|
||||
,"uerdataOf(Object,Value)",LuaUserdata,,,,,,,,,,
|
||||
,,,,,,,Arugment type,,,,,
|
||||
,,,LuaBoolean,LuaClosure,LuaFunction,LuaDouble,LuaInteger,LuaNil,LuaString,LuaTable,LuaThread,LuaUserdata
|
||||
Type Check Functions,,,,,,,,,,,,
|
||||
,isboolean,boolean,TRUE,f,f,f,f,f,f,f,f,f
|
||||
,isclosure,boolean,f,TRUE,f,f,f,f,f,f,f,f
|
||||
,isfunction,boolean,f,TRUE,TRUE,f,f,f,f,f,f,f
|
||||
,isint,boolean,f,f,f,f,TRUE,f,true | f,f,f,f
|
||||
,isinttype,boolean,f,f,f,f,TRUE,f,f,f,f,f
|
||||
,isnumber,boolean,f,f,f,TRUE,TRUE,f,true | f,f,f,f
|
||||
,islong,boolean,f,f,f,true | f,TRUE,f,true | f,f,f,f
|
||||
,isnil,boolean,f,f,f,f,f,TRUE,f,f,f,f
|
||||
,isstring,boolean,f,f,f,true | f,TRUE,f,TRUE,f,f,f
|
||||
,istable,boolean,f,f,f,f,f,f,f,TRUE,f,f
|
||||
,isthread,boolean,f,f,f,f,f,f,f,f,TRUE,f
|
||||
,isuserdata,boolean,f,f,f,f,f,f,f,f,f,TRUE
|
||||
,isuserdata(Class c),boolean,f,f,f,f,f,f,f,f,f,true | f
|
||||
|
||||
|
||||
Java Type Coercion Functions,,,,,,,,,,,,
|
||||
,toboolean,boolean,this.v,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE
|
||||
,tobyte,byte,0,0,0,0,this.v | 0,0,this.v | 0,0,0,0
|
||||
,tochar,char,0,0,0,0,this.v | 0,0,this.v | 0,0,0,0
|
||||
,todouble,double,0,0,0,this.v,this.v,0,this.v | 0,0,0,0
|
||||
,tofloat,float,0,0,0,this.v | 0,this.v,0,this.v | 0,0,0,0
|
||||
,toint,int,0,0,0,0,this.v,0,this.v | 0,0,0,0
|
||||
,tolong,long,0,0,0,0,this.v,0,this.v | 0,0,0,0
|
||||
,toshort,short,0,0,0,0,this.v | 0,0,this.v | 0,0,0,0
|
||||
,tojstring,String,"""true""|""false""","""closure: x""","""name""",(str) this.v,(str) this.v,"""nil""",this.v,"""table: x""","""thread: x""","""userdata: x"""
|
||||
,touserdata,Object,null,null,null,null,null,null,null,null,this,this.instance
|
||||
|
||||
,,,LuaBoolean,LuaClosure,LuaFunction,LuaDouble,LuaInteger,LuaNil,LuaString,LuaTable,LuaThread,LuaUserdata
|
||||
Optional Argument Conversion Functions,,,,,,,,,,,,
|
||||
,optboolean,boolean,this,e,e,e,e,defval,e,e,e,e
|
||||
,optclosure,LuaClosure,n,this,e,e,e,defval,e,e,e,e
|
||||
,optdouble,double,e,e,e,this,this,defval,this | e,e,e,e
|
||||
,optfunction,LuaFunction,n,this,this,e,e,defval,e,e,e,e
|
||||
,optint,int,e,e,e,(int) this,this,defval,this | e,e,e,e
|
||||
,optinteger,LuaInteger,e,e,e,(int) this,this,defval,this | e,e,e,e
|
||||
,optlong,long,e,e,e,(long) this,this,defval,this | e,e,e,e
|
||||
,optnumber,LuaNumber,e,e,e,this,this,defval,this | e,e,e,e
|
||||
,optjstring,String,e,e,e,(str) this.v,(str) this.v,defval,this,e,e,e
|
||||
,optstring,LuaString,e,e,e,(str) this.v,(str) this.v,defval,this,e,e,e
|
||||
,opttable,LuaTable,e,e,e,e,e,defval,e,this,e,e
|
||||
,optthread,LuaThread,e,e,e,e,e,defval,e,e,this,n
|
||||
,optuserdata,Object,e,e,e,e,e,defval,e,e,e,instance
|
||||
,optuserdata(Class c),Object,e,e,e,e,e,defval,e,e,e,instance | e
|
||||
|
||||
Required Argument Conversion Functions,,,,,,,,,,,,
|
||||
,checkboolean,boolean,this,e,e,e,e,e,e,e,e,e
|
||||
,checkclosure,LuaClosure,e,this,e,e,e,e,e,e,e,e
|
||||
,checkdouble,double,e,e,e,this,this,e,e,e,e,e
|
||||
,checkfunction,LuaFunction,e,this,this,e,e,e,e,e,e,e
|
||||
,checkint,int,e,e,e,this | e,this,e,e,e,e,e
|
||||
,checkinteger,LuaInteger,e,e,e,e,this,e,e,e,e,e
|
||||
,checklong,LuaNumber,e,e,e,this | e,this,e,e,e,e,e
|
||||
,checknumber,LuaNumber,e,e,e,this,this,e,e,e,e,e
|
||||
,checkjstring,String,e,e,e,(str) this.v,(str) this.v,e,(str) this.v,e,e,e
|
||||
,checkstring,LuaString,e,e,e,(str) this.v,(str) this.v,e,this,e,e,e
|
||||
,checktable,LuaTable,e,e,e,e,e,e,e,this,e,e
|
||||
,checkthread,LuaThread,e,e,e,e,e,e,e,e,this,e
|
||||
,checkuserdata,Object,e,e,e,e,e,e,e,e,e,instance
|
||||
,checkuserdata(Class c),Object,e,e,e,e,e,e,e,e,e,instance | e
|
||||
,checkvalue,LuaValue,this,this,this,this,this,e,this,this,this,this
|
||||
|
||||
,,,LuaBoolean,LuaClosure,LuaFunction,LuaDouble,LuaInteger,LuaNil,LuaString,LuaTable,LuaThread,LuaUserdata
|
||||
Lua Language Operations,,,,,,,,,,,,
|
||||
,type,int,TBOOLEAN,TFUNCTION,TFUNCTION,TNUMBER,TNUMBER,TNIL,TSTRING,TTABLE,TTHREAD,TUSERDATA
|
||||
,typename,string,"""boolean""","""function""","""function""","""number""","""number""","""nil""","""string""","""table""","""thread""","""userdata"""
|
||||
,len,LuaInteger,e,e,e,e,e,e,#v,#v,e,e
|
||||
,length,int,e,e,e,e,e,e,#v,#v,e,e
|
||||
,getmetatable,LuaValue,static,static,static,static,static,static,static,instance,static ,instance
|
||||
,setmetatable,LuaValue,e,e,e,e,e,e,e,instance,e,instance
|
||||
,getfenv,LuaTable,e,instance,instance,e,e,e,e,e,instance,e
|
||||
,setfenv,LuaFunction,e,instance,instance,e,e,e,e,e,instance,e
|
||||
,call,LuaValue,__call,call,call,__call,__call,__call,__call,__call,__call,__call
|
||||
,invoke,Varargs,__call,call,call,__call,__call,__call,__call,__call,__call,__call
|
||||
,get,LuaValue,__index,__index,__index,__index,__index,__index,__index,get,__index,__index
|
||||
,set,LuaValue,__newindex,__newindex,__newindex,__newindex,__newindex,__newindex,__newindex,set,__newindex,__newindex
|
|
@ -1,260 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* String buffer for use in string library methods, optimized for production
|
||||
* of StrValue instances.
|
||||
* <p>
|
||||
* The buffer can begin initially as a wrapped {@link LuaValue}
|
||||
* and only when concatenation actually occurs are the bytes first copied.
|
||||
* <p>
|
||||
* To convert back to a {@link LuaValue} again,
|
||||
* the function {@link Buffer#value()} is used.
|
||||
* @see LuaValue
|
||||
* @see LuaValue#buffer()
|
||||
* @see LuaString
|
||||
*/
|
||||
public final class Buffer {
|
||||
|
||||
/** Default capacity for a buffer: 64 */
|
||||
private static final int DEFAULT_CAPACITY = 64;
|
||||
|
||||
/** Shared static array with no bytes */
|
||||
private static final byte[] NOBYTES = {};
|
||||
|
||||
/** Bytes in this buffer */
|
||||
private byte[] bytes;
|
||||
|
||||
/** Length of this buffer */
|
||||
private int length;
|
||||
|
||||
/** Offset into the byte array */
|
||||
private int offset;
|
||||
|
||||
/** Value of this buffer, when not represented in bytes */
|
||||
private LuaValue value;
|
||||
|
||||
/**
|
||||
* Create buffer with default capacity
|
||||
* @see #DEFAULT_CAPACITY
|
||||
*/
|
||||
public Buffer() {
|
||||
this(DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create buffer with specified initial capacity
|
||||
* @param initialCapacity the initial capacity
|
||||
*/
|
||||
public Buffer( int initialCapacity ) {
|
||||
bytes = new byte[ initialCapacity ];
|
||||
length = 0;
|
||||
offset = 0;
|
||||
value = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create buffer with specified initial value
|
||||
* @param value the initial value
|
||||
*/
|
||||
public Buffer(LuaValue value) {
|
||||
bytes = NOBYTES;
|
||||
length = offset = 0;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get buffer contents as a {@link LuaValue}
|
||||
* @return value as a {@link LuaValue}, converting as necessary
|
||||
*/
|
||||
public LuaValue value() {
|
||||
return value != null? value: this.tostring();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set buffer contents as a {@link LuaValue}
|
||||
* @param value value to set
|
||||
*/
|
||||
public Buffer setvalue(LuaValue value) {
|
||||
bytes = NOBYTES;
|
||||
offset = length = 0;
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the buffer to a {@link LuaString}
|
||||
* @return the value as a {@link LuaString}
|
||||
*/
|
||||
public final LuaString tostring() {
|
||||
realloc( length, 0 );
|
||||
return LuaString.valueOf( bytes, offset, length );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the buffer to a Java String
|
||||
* @return the value as a Java String
|
||||
*/
|
||||
public String tojstring() {
|
||||
return value().tojstring();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the buffer to a Java String
|
||||
* @return the value as a Java String
|
||||
*/
|
||||
public String toString() {
|
||||
return tojstring();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a single byte to the buffer.
|
||||
* @return {@code this} to allow call chaining
|
||||
*/
|
||||
public final Buffer append( byte b ) {
|
||||
makeroom( 0, 1 );
|
||||
bytes[ offset + length++ ] = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a {@link LuaValue} to the buffer.
|
||||
* @return {@code this} to allow call chaining
|
||||
*/
|
||||
public final Buffer append( LuaValue val ) {
|
||||
append( val.strvalue() );
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a {@link LuaString} to the buffer.
|
||||
* @return {@code this} to allow call chaining
|
||||
*/
|
||||
public final Buffer append( LuaString str ) {
|
||||
final int n = str.m_length;
|
||||
makeroom( 0, n );
|
||||
str.copyInto( 0, bytes, offset + length, n );
|
||||
length += n;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a Java String to the buffer.
|
||||
* The Java string will be converted to bytes using the UTF8 encoding.
|
||||
* @return {@code this} to allow call chaining
|
||||
* @see LuaString#encodeToUtf8(char[], byte[], int)
|
||||
*/
|
||||
public final Buffer append( String str ) {
|
||||
char[] chars = str.toCharArray();
|
||||
/* DAN200 START */
|
||||
/*
|
||||
final int n = LuaString.lengthAsUtf8( chars );
|
||||
makeroom( 0, n );
|
||||
LuaString.encodeToUtf8( chars, bytes, offset + length );
|
||||
length += n;
|
||||
*/
|
||||
makeroom( 0, chars.length );
|
||||
for( int i=0; i<chars.length; ++i )
|
||||
{
|
||||
char ch = chars[i];
|
||||
bytes[ offset + length + i ] = (ch < 256) ? (byte)ch : (byte)'?';
|
||||
}
|
||||
length += chars.length;
|
||||
/* DAN200 END */
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Concatenate this buffer onto a {@link LuaValue}
|
||||
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
|
||||
* @return {@link Buffer} for use in call chaining.
|
||||
*/
|
||||
public Buffer concatTo(LuaValue lhs) {
|
||||
return setvalue(lhs.concat(value()));
|
||||
}
|
||||
|
||||
/** Concatenate this buffer onto a {@link LuaString}
|
||||
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
|
||||
* @return {@link Buffer} for use in call chaining.
|
||||
*/
|
||||
public Buffer concatTo(LuaString lhs) {
|
||||
return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs);
|
||||
}
|
||||
|
||||
/** Concatenate this buffer onto a {@link LuaNumber}
|
||||
* <p>
|
||||
* The {@link LuaNumber} will be converted to a string before concatenating.
|
||||
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
|
||||
* @return {@link Buffer} for use in call chaining.
|
||||
*/
|
||||
public Buffer concatTo(LuaNumber lhs) {
|
||||
return value!=null&&!value.isstring()? setvalue(lhs.concat(value)): prepend(lhs.strvalue());
|
||||
}
|
||||
|
||||
/** Concatenate bytes from a {@link LuaString} onto the front of this buffer
|
||||
* @param s the left-hand-side value which we will concatenate onto the front of {@code this}
|
||||
* @return {@link Buffer} for use in call chaining.
|
||||
*/
|
||||
public Buffer prepend(LuaString s) {
|
||||
int n = s.m_length;
|
||||
makeroom( n, 0 );
|
||||
System.arraycopy( s.m_bytes, s.m_offset, bytes, offset-n, n );
|
||||
offset -= n;
|
||||
length += n;
|
||||
value = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Ensure there is enough room before and after the bytes.
|
||||
* @param nbefore number of unused bytes which must precede the data after this completes
|
||||
* @param nafter number of unused bytes which must follow the data after this completes
|
||||
*/
|
||||
public final void makeroom( int nbefore, int nafter ) {
|
||||
if ( value != null ) {
|
||||
LuaString s = value.strvalue();
|
||||
value = null;
|
||||
length = s.m_length;
|
||||
offset = nbefore;
|
||||
bytes = new byte[nbefore+length+nafter];
|
||||
System.arraycopy(s.m_bytes, s.m_offset, bytes, offset, length);
|
||||
} else if ( offset+length+nafter > bytes.length || offset<nbefore ) {
|
||||
int n = nbefore+length+nafter;
|
||||
int m = n<32? 32: n<length*2? length*2: n;
|
||||
realloc( m, nbefore==0? 0: m-length-nafter );
|
||||
}
|
||||
}
|
||||
|
||||
/** Reallocate the internal storage for the buffer
|
||||
* @param newSize the size of the buffer to use
|
||||
* @param newOffset the offset to use
|
||||
*/
|
||||
private final void realloc( int newSize, int newOffset ) {
|
||||
if ( newSize != bytes.length ) {
|
||||
byte[] newBytes = new byte[ newSize ];
|
||||
System.arraycopy( bytes, offset, newBytes, newOffset, length );
|
||||
bytes = newBytes;
|
||||
offset = newOffset;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,428 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* Class to manage loading of {@link Prototype} instances.
|
||||
* <p>
|
||||
* The {@link LoadState} class exposes one main function,
|
||||
* namely {@link #load(InputStream, String, LuaValue)},
|
||||
* to be used to load code from a particular input stream.
|
||||
* <p>
|
||||
* A simple pattern for loading and executing code is
|
||||
* <pre> {@code
|
||||
* LuaValue _G = JsePlatform.standardGlobals();
|
||||
* LoadState.load( new FileInputStream("main.lua"), "main.lua", _G ).call();
|
||||
* } </pre>
|
||||
* This should work regardless of which {@link LuaCompiler}
|
||||
* has been installed.
|
||||
* <p>
|
||||
*
|
||||
* Prior to loading code, a compiler should be installed.
|
||||
* <p>
|
||||
* By default, when using {@link JsePlatform} or {@JmePlatform}
|
||||
* to construct globals, the {@link LuaC} compiler is installed.
|
||||
* <p>
|
||||
* To override the default compiler with, say, the {@link LuaJC}
|
||||
* lua-to-java bytecode compiler, install it before loading,
|
||||
* for example:
|
||||
* <pre> {@code
|
||||
* LuaValue _G = JsePlatform.standardGlobals();
|
||||
* LuaJC.install();
|
||||
* LoadState.load( new FileInputStream("main.lua"), "main.lua", _G ).call();
|
||||
* } </pre>
|
||||
*
|
||||
* @see LuaCompiler
|
||||
* @see LuaClosure
|
||||
* @see LuaFunction
|
||||
* @see LoadState#compiler
|
||||
* @see LoadState#load(InputStream, String, LuaValue)
|
||||
* @see LuaC
|
||||
* @see LuaJC
|
||||
*/
|
||||
public class LoadState {
|
||||
|
||||
/** format corresponding to non-number-patched lua, all numbers are floats or doubles */
|
||||
public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
|
||||
|
||||
/** format corresponding to non-number-patched lua, all numbers are ints */
|
||||
public static final int NUMBER_FORMAT_INTS_ONLY = 1;
|
||||
|
||||
/** 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
|
||||
public static final int LUA_TINT = (-2);
|
||||
public static final int LUA_TNONE = (-1);
|
||||
public static final int LUA_TNIL = 0;
|
||||
public static final int LUA_TBOOLEAN = 1;
|
||||
public static final int LUA_TLIGHTUSERDATA = 2;
|
||||
public static final int LUA_TNUMBER = 3;
|
||||
public static final int LUA_TSTRING = 4;
|
||||
public static final int LUA_TTABLE = 5;
|
||||
public static final int LUA_TFUNCTION = 6;
|
||||
public static final int LUA_TUSERDATA = 7;
|
||||
public static final int LUA_TTHREAD = 8;
|
||||
public static final int LUA_TVALUE = 9;
|
||||
|
||||
/** Interface for the compiler, if it is installed.
|
||||
* <p>
|
||||
* See the {@link LuaClosure} documentation for examples of how to use the compiler.
|
||||
* @see LuaClosure
|
||||
* @see #load(InputStream, String, LuaValue)
|
||||
* */
|
||||
public interface LuaCompiler {
|
||||
|
||||
/** Load into a Closure or LuaFunction from a Stream and initializes the environment
|
||||
* @throws IOException */
|
||||
public LuaFunction load(InputStream stream, String filename, LuaValue env) throws IOException;
|
||||
}
|
||||
|
||||
/** Compiler instance, if installed */
|
||||
public static LuaCompiler compiler = null;
|
||||
|
||||
/** Signature byte indicating the file is a compiled binary chunk */
|
||||
private static final byte[] LUA_SIGNATURE = { '\033', 'L', 'u', 'a' };
|
||||
|
||||
/** Name for compiled chunks */
|
||||
public static final String SOURCE_BINARY_STRING = "binary string";
|
||||
|
||||
|
||||
/** for header of binary files -- this is Lua 5.1 */
|
||||
public static final int LUAC_VERSION = 0x51;
|
||||
|
||||
/** for header of binary files -- this is the official format */
|
||||
public static final int LUAC_FORMAT = 0;
|
||||
|
||||
/** size of header of binary files */
|
||||
public static final int LUAC_HEADERSIZE = 12;
|
||||
|
||||
// values read from the header
|
||||
private int luacVersion;
|
||||
private int luacFormat;
|
||||
private boolean luacLittleEndian;
|
||||
private int luacSizeofInt;
|
||||
private int luacSizeofSizeT;
|
||||
private int luacSizeofInstruction;
|
||||
private int luacSizeofLuaNumber;
|
||||
private int luacNumberFormat;
|
||||
|
||||
/** input stream from which we are loading */
|
||||
public final DataInputStream is;
|
||||
|
||||
/** Name of what is being loaded? */
|
||||
String name;
|
||||
|
||||
private static final LuaValue[] NOVALUES = {};
|
||||
private static final Prototype[] NOPROTOS = {};
|
||||
private static final LocVars[] NOLOCVARS = {};
|
||||
private static final LuaString[] NOSTRVALUES = {};
|
||||
private static final int[] NOINTS = {};
|
||||
|
||||
/** Read buffer */
|
||||
private byte[] buf = new byte[512];
|
||||
|
||||
|
||||
/** Load a 4-byte int value from the input stream
|
||||
* @return the int value laoded.
|
||||
**/
|
||||
int loadInt() throws IOException {
|
||||
is.readFully(buf,0,4);
|
||||
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.
|
||||
**/
|
||||
int[] loadIntArray() throws IOException {
|
||||
int n = loadInt();
|
||||
if ( n == 0 )
|
||||
return NOINTS;
|
||||
|
||||
// read all data at once
|
||||
int m = n << 2;
|
||||
if ( buf.length < m )
|
||||
buf = new byte[m];
|
||||
is.readFully(buf,0,m);
|
||||
int[] array = new int[n];
|
||||
for ( int i=0, j=0; i<n; ++i, j+=4 )
|
||||
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]);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/** Load a long value from the input stream
|
||||
* @return the long value laoded.
|
||||
**/
|
||||
long loadInt64() throws IOException {
|
||||
int a,b;
|
||||
if ( this.luacLittleEndian ) {
|
||||
a = loadInt();
|
||||
b = loadInt();
|
||||
} else {
|
||||
b = loadInt();
|
||||
a = loadInt();
|
||||
}
|
||||
return (((long)b)<<32) | (((long)a)&0xffffffffL);
|
||||
}
|
||||
|
||||
/** Load a lua strin gvalue from the input stream
|
||||
* @return the {@link LuaString} value laoded.
|
||||
**/
|
||||
LuaString loadString() throws IOException {
|
||||
int size = this.luacSizeofSizeT == 8? (int) loadInt64(): loadInt();
|
||||
if ( size == 0 )
|
||||
return null;
|
||||
byte[] bytes = new byte[size];
|
||||
is.readFully( bytes, 0, size );
|
||||
return LuaString.valueOf( bytes, 0, bytes.length - 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static LuaValue longBitsToLuaNumber( long bits ) {
|
||||
if ( ( bits & ( ( 1L << 63 ) - 1 ) ) == 0L ) {
|
||||
return LuaValue.ZERO;
|
||||
}
|
||||
|
||||
int e = (int)((bits >> 52) & 0x7ffL) - 1023;
|
||||
|
||||
if ( e >= 0 && e < 31 ) {
|
||||
long f = bits & 0xFFFFFFFFFFFFFL;
|
||||
int shift = 52 - e;
|
||||
long intPrecMask = ( 1L << shift ) - 1;
|
||||
if ( ( f & intPrecMask ) == 0 ) {
|
||||
int intValue = (int)( f >> shift ) | ( 1 << e );
|
||||
return LuaInteger.valueOf( ( ( bits >> 63 ) != 0 ) ? -intValue : intValue );
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
LuaValue loadNumber() throws IOException {
|
||||
if ( luacNumberFormat == NUMBER_FORMAT_INTS_ONLY ) {
|
||||
return LuaInteger.valueOf( loadInt() );
|
||||
} else {
|
||||
return longBitsToLuaNumber( loadInt64() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a list of constants from a binary chunk
|
||||
* @param f the function prototype
|
||||
* @throws IOException if an i/o exception occurs
|
||||
*/
|
||||
void loadConstants(Prototype f) throws IOException {
|
||||
int n = loadInt();
|
||||
LuaValue[] values = n>0? new LuaValue[n]: NOVALUES;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
switch ( is.readByte() ) {
|
||||
case LUA_TNIL:
|
||||
values[i] = LuaValue.NIL;
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
values[i] = (0 != is.readUnsignedByte()? LuaValue.TRUE: LuaValue.FALSE);
|
||||
break;
|
||||
case LUA_TINT:
|
||||
values[i] = LuaInteger.valueOf( loadInt() );
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
values[i] = loadNumber();
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
values[i] = loadString();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("bad constant");
|
||||
}
|
||||
}
|
||||
f.k = values;
|
||||
|
||||
n = loadInt();
|
||||
Prototype[] protos = n>0? new Prototype[n]: NOPROTOS;
|
||||
for ( int i=0; i<n; i++ )
|
||||
protos[i] = loadFunction(f.source);
|
||||
f.p = protos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the debug infor for a function prototype
|
||||
* @param f the function Prototype
|
||||
* @throws IOException if there is an i/o exception
|
||||
*/
|
||||
void loadDebug( Prototype f ) throws IOException {
|
||||
f.lineinfo = loadIntArray();
|
||||
int n = loadInt();
|
||||
f.locvars = n>0? new LocVars[n]: NOLOCVARS;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
LuaString varname = loadString();
|
||||
int startpc = loadInt();
|
||||
int endpc = loadInt();
|
||||
f.locvars[i] = new LocVars(varname, startpc, endpc);
|
||||
}
|
||||
|
||||
n = loadInt();
|
||||
f.upvalues = n>0? new LuaString[n]: NOSTRVALUES;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
f.upvalues[i] = loadString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a function prototype from the input stream
|
||||
* @param p name of the source
|
||||
* @return {@link Prototype} instance that was loaded
|
||||
* @throws IOException
|
||||
*/
|
||||
public Prototype loadFunction(LuaString p) throws IOException {
|
||||
Prototype f = new Prototype();
|
||||
// this.L.push(f);
|
||||
f.source = loadString();
|
||||
if ( f.source == null )
|
||||
f.source = p;
|
||||
f.linedefined = loadInt();
|
||||
f.lastlinedefined = loadInt();
|
||||
f.nups = is.readUnsignedByte();
|
||||
f.numparams = is.readUnsignedByte();
|
||||
f.is_vararg = is.readUnsignedByte();
|
||||
f.maxstacksize = is.readUnsignedByte();
|
||||
f.code = loadIntArray();
|
||||
loadConstants(f);
|
||||
loadDebug(f);
|
||||
|
||||
// TODO: add check here, for debugging purposes, I believe
|
||||
// see ldebug.c
|
||||
// IF (!luaG_checkcode(f), "bad code");
|
||||
|
||||
// this.L.pop();
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the lua chunk header values.
|
||||
* @throws IOException if an i/o exception occurs.
|
||||
*/
|
||||
public void loadHeader() throws IOException {
|
||||
luacVersion = is.readByte();
|
||||
luacFormat = is.readByte();
|
||||
luacLittleEndian = (0 != is.readByte());
|
||||
luacSizeofInt = is.readByte();
|
||||
luacSizeofSizeT = is.readByte();
|
||||
luacSizeofInstruction = is.readByte();
|
||||
luacSizeofLuaNumber = is.readByte();
|
||||
luacNumberFormat = is.readByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load lua in either binary or text form from an input stream.
|
||||
* @param firstByte the first byte of the input stream
|
||||
* @param stream InputStream to read, after having read the first byte already
|
||||
* @param name Name to apply to the loaded chunk
|
||||
* @return {@link Prototype} that was loaded
|
||||
* @throws IllegalArgumentException if the signature is bac
|
||||
* @throws IOException if an IOException occurs
|
||||
*/
|
||||
public static LuaFunction load( InputStream stream, String name, LuaValue env ) throws IOException {
|
||||
if ( compiler != null )
|
||||
return compiler.load(stream, name, env);
|
||||
else {
|
||||
int firstByte = stream.read();
|
||||
if ( firstByte != LUA_SIGNATURE[0] )
|
||||
throw new LuaError("no compiler");
|
||||
Prototype p = loadBinaryChunk( firstByte, stream, name );
|
||||
return new LuaClosure( p, env );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load lua thought to be a binary chunk from its first byte from an input stream.
|
||||
* @param firstByte the first byte of the input stream
|
||||
* @param stream InputStream to read, after having read the first byte already
|
||||
* @param name Name to apply to the loaded chunk
|
||||
* @return {@link Prototype} that was loaded
|
||||
* @throws IllegalArgumentException if the signature is bac
|
||||
* @throws IOException if an IOException occurs
|
||||
*/
|
||||
public static Prototype loadBinaryChunk( int firstByte, InputStream stream, String name ) throws IOException {
|
||||
|
||||
// check rest of signature
|
||||
if ( firstByte != LUA_SIGNATURE[0]
|
||||
|| stream.read() != LUA_SIGNATURE[1]
|
||||
|| stream.read() != LUA_SIGNATURE[2]
|
||||
|| stream.read() != LUA_SIGNATURE[3] )
|
||||
throw new IllegalArgumentException("bad signature");
|
||||
|
||||
// load file as a compiled chunk
|
||||
String sname = getSourceName(name);
|
||||
LoadState s = new LoadState( stream, sname );
|
||||
s.loadHeader();
|
||||
|
||||
// check format
|
||||
switch ( s.luacNumberFormat ) {
|
||||
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
|
||||
case NUMBER_FORMAT_INTS_ONLY:
|
||||
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
||||
break;
|
||||
default:
|
||||
throw new LuaError("unsupported int size");
|
||||
}
|
||||
return s.loadFunction( LuaString.valueOf(sname) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a source name from a supplied chunk name
|
||||
* @param name String name that appears in the chunk
|
||||
* @return source file name
|
||||
*/
|
||||
public static String getSourceName(String name) {
|
||||
String sname = name;
|
||||
if ( name.startsWith("@") || name.startsWith("=") )
|
||||
sname = name.substring(1);
|
||||
else if ( name.startsWith("\033") )
|
||||
sname = SOURCE_BINARY_STRING;
|
||||
return sname;
|
||||
}
|
||||
|
||||
/** Private constructor for create a load state */
|
||||
private LoadState( InputStream stream, String name ) {
|
||||
this.name = name;
|
||||
this.is = new DataInputStream( stream );
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
/**
|
||||
* Data class to hold debug information relatign to local variables for a {@link Prototype}
|
||||
*/
|
||||
public class LocVars {
|
||||
/** The local variable name */
|
||||
public LuaString varname;
|
||||
|
||||
/** The instruction offset when the variable comes into scope */
|
||||
public int startpc;
|
||||
|
||||
/** The instruction offset when the variable goes out of scope */
|
||||
public int endpc;
|
||||
|
||||
/**
|
||||
* Construct a LocVars instance.
|
||||
* @param varname The local variable name
|
||||
* @param startpc The instruction offset when the variable comes into scope
|
||||
* @param endpc The instruction offset when the variable goes out of scope
|
||||
*/
|
||||
public LocVars(LuaString varname, int startpc, int endpc) {
|
||||
this.varname = varname;
|
||||
this.startpc = startpc;
|
||||
this.endpc = endpc;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return varname+" "+startpc+"-"+endpc;
|
||||
}
|
||||
}
|
@ -1,337 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
|
||||
/**
|
||||
* Constants for lua limits and opcodes.
|
||||
* <p>
|
||||
* This is a direct translation of C lua distribution header file constants
|
||||
* for bytecode creation and processing.
|
||||
*/
|
||||
public class Lua {
|
||||
/** version is supplied by ant build task */
|
||||
public static final String _VERSION = "Luaj 0.0";
|
||||
|
||||
/** use return values from previous op */
|
||||
public static final int LUA_MULTRET = -1;
|
||||
|
||||
/** masks for new-style vararg */
|
||||
public static final int VARARG_HASARG = 1;
|
||||
public static final int VARARG_ISVARARG = 2;
|
||||
public static final int VARARG_NEEDSARG = 4;
|
||||
|
||||
// from lopcodes.h
|
||||
|
||||
/*===========================================================================
|
||||
We assume that instructions are unsigned numbers.
|
||||
All instructions have an opcode in the first 6 bits.
|
||||
Instructions can have the following fields:
|
||||
`A' : 8 bits
|
||||
`B' : 9 bits
|
||||
`C' : 9 bits
|
||||
`Bx' : 18 bits (`B' and `C' together)
|
||||
`sBx' : signed Bx
|
||||
|
||||
A signed argument is represented in excess K; that is, the number
|
||||
value is the unsigned value minus K. K is exactly the maximum value
|
||||
for that argument (so that -max is represented by 0, and +max is
|
||||
represented by 2*max), which is half the maximum for the corresponding
|
||||
unsigned argument.
|
||||
===========================================================================*/
|
||||
|
||||
|
||||
/* basic instruction format */
|
||||
public static final int iABC = 0;
|
||||
public static final int iABx = 1;
|
||||
public static final int iAsBx = 2;
|
||||
|
||||
|
||||
/*
|
||||
** size and position of opcode arguments.
|
||||
*/
|
||||
public static final int SIZE_C = 9;
|
||||
public static final int SIZE_B = 9;
|
||||
public static final int SIZE_Bx = (SIZE_C + SIZE_B);
|
||||
public static final int SIZE_A = 8;
|
||||
|
||||
public static final int SIZE_OP = 6;
|
||||
|
||||
public static final int POS_OP = 0;
|
||||
public static final int POS_A = (POS_OP + SIZE_OP);
|
||||
public static final int POS_C = (POS_A + SIZE_A);
|
||||
public static final int POS_B = (POS_C + SIZE_C);
|
||||
public static final int POS_Bx = POS_C;
|
||||
|
||||
|
||||
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);
|
||||
public static final int MAXARG_C = ((1<<SIZE_C)-1);
|
||||
public static final int MAXARG_Bx = ((1<<SIZE_Bx)-1);
|
||||
public static final int MAXARG_sBx = (MAXARG_Bx>>1); /* `sBx' is signed */
|
||||
|
||||
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_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
|
||||
*/
|
||||
public static int GET_OPCODE(int i) {
|
||||
return (i >> POS_OP) & MAX_OP;
|
||||
}
|
||||
|
||||
public static int GETARG_A(int i) {
|
||||
return (i >> POS_A) & MAXARG_A;
|
||||
}
|
||||
|
||||
public static int GETARG_B(int i) {
|
||||
return (i >> POS_B) & MAXARG_B;
|
||||
}
|
||||
|
||||
public static int GETARG_C(int i) {
|
||||
return (i >> POS_C) & MAXARG_C;
|
||||
}
|
||||
|
||||
public static int GETARG_Bx(int i) {
|
||||
return (i >> POS_Bx) & MAXARG_Bx;
|
||||
}
|
||||
|
||||
public static int GETARG_sBx(int i) {
|
||||
return ((i >> POS_Bx) & MAXARG_Bx) - MAXARG_sBx;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Macros to operate RK indices
|
||||
*/
|
||||
|
||||
/** this bit 1 means constant (0 means register) */
|
||||
public static final int BITRK = (1 << (SIZE_B - 1));
|
||||
|
||||
/** test whether value is a constant */
|
||||
public static boolean ISK(int x) {
|
||||
return 0 != ((x) & BITRK);
|
||||
}
|
||||
|
||||
/** gets the index of the constant */
|
||||
public static int INDEXK(int r) {
|
||||
return ((int)(r) & ~BITRK);
|
||||
}
|
||||
|
||||
public static final int MAXINDEXRK = (BITRK - 1);
|
||||
|
||||
/** code a constant index as a RK value */
|
||||
public static int RKASK(int x) {
|
||||
return ((x) | BITRK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** invalid register that fits in 8 bits
|
||||
*/
|
||||
public static final int NO_REG = MAXARG_A;
|
||||
|
||||
|
||||
/*
|
||||
** R(x) - register
|
||||
** Kst(x) - constant (in constant table)
|
||||
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** grep "ORDER OP" if you change these enums
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
name args description
|
||||
------------------------------------------------------------------------*/
|
||||
public static final int OP_MOVE = 0;/* A B R(A) := R(B) */
|
||||
public static final int OP_LOADK = 1;/* A Bx R(A) := Kst(Bx) */
|
||||
public static final int OP_LOADBOOL = 2;/* A B C R(A) := (Bool)B; if (C) pc++ */
|
||||
public static final int OP_LOADNIL = 3; /* A B R(A) := ... := R(B) := nil */
|
||||
public static final int OP_GETUPVAL = 4; /* A B R(A) := UpValue[B] */
|
||||
|
||||
public static final int OP_GETGLOBAL = 5; /* A Bx R(A) := Gbl[Kst(Bx)] */
|
||||
public static final int OP_GETTABLE = 6; /* A B C R(A) := R(B)[RK(C)] */
|
||||
|
||||
public static final int OP_SETGLOBAL = 7; /* A Bx Gbl[Kst(Bx)] := R(A) */
|
||||
public static final int OP_SETUPVAL = 8; /* A B UpValue[B] := R(A) */
|
||||
public static final int OP_SETTABLE = 9; /* A B C R(A)[RK(B)] := RK(C) */
|
||||
|
||||
public static final int OP_NEWTABLE = 10; /* A B C R(A) := {} (size = B,C) */
|
||||
|
||||
public static final int OP_SELF = 11; /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
|
||||
|
||||
public static final int OP_ADD = 12; /* A B C R(A) := RK(B) + RK(C) */
|
||||
public static final int OP_SUB = 13; /* A B C R(A) := RK(B) - RK(C) */
|
||||
public static final int OP_MUL = 14; /* A B C R(A) := RK(B) * RK(C) */
|
||||
public static final int OP_DIV = 15; /* A B C R(A) := RK(B) / RK(C) */
|
||||
public static final int OP_MOD = 16; /* A B C R(A) := RK(B) % RK(C) */
|
||||
public static final int OP_POW = 17; /* A B C R(A) := RK(B) ^ RK(C) */
|
||||
public static final int OP_UNM = 18; /* A B R(A) := -R(B) */
|
||||
public static final int OP_NOT = 19; /* A B R(A) := not R(B) */
|
||||
public static final int OP_LEN = 20; /* A B R(A) := length of R(B) */
|
||||
|
||||
public static final int OP_CONCAT = 21; /* A B C R(A) := R(B).. ... ..R(C) */
|
||||
|
||||
public static final int OP_JMP = 22; /* sBx pc+=sBx */
|
||||
|
||||
public static final int OP_EQ = 23; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
public static final int OP_LT = 24; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
public static final int OP_LE = 25; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
|
||||
public static final int OP_TEST = 26; /* A C if not (R(A) <=> C) then pc++ */
|
||||
public static final int OP_TESTSET = 27; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
|
||||
|
||||
public static final int OP_CALL = 28; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
public static final int OP_TAILCALL = 29; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
public static final int OP_RETURN = 30; /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
|
||||
public static final int OP_FORLOOP = 31; /* A sBx R(A)+=R(A+2);
|
||||
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
|
||||
public static final int OP_FORPREP = 32; /* A sBx R(A)-=R(A+2); pc+=sBx */
|
||||
|
||||
public static final int OP_TFORLOOP = 33; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
|
||||
if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */
|
||||
public static final int OP_SETLIST = 34; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
|
||||
|
||||
public static final int OP_CLOSE = 35; /* A close all variables in the stack up to (>=) R(A)*/
|
||||
public static final int OP_CLOSURE = 36; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
public static final int OP_VARARG = 37; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
|
||||
public static final int NUM_OPCODES = OP_VARARG + 1;
|
||||
|
||||
/* pseudo-opcodes used in parsing only. */
|
||||
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
|
||||
|
||||
/*===========================================================================
|
||||
Notes:
|
||||
(*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
|
||||
and can be 0: OP_CALL then sets `top' to last_result+1, so
|
||||
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
|
||||
|
||||
(*) In OP_VARARG, if (B == 0) then use actual number of varargs and
|
||||
set top (like in OP_CALL with C == 0).
|
||||
|
||||
(*) In OP_RETURN, if (B == 0) then return up to `top'
|
||||
|
||||
(*) In OP_SETLIST, if (B == 0) then B = `top';
|
||||
if (C == 0) then next `instruction' is real C
|
||||
|
||||
(*) For comparisons, A specifies what condition the test should accept
|
||||
(true or false).
|
||||
|
||||
(*) All `skips' (pc++) assume that next instruction is a jump
|
||||
===========================================================================*/
|
||||
|
||||
|
||||
/*
|
||||
** masks for instruction properties. The format is:
|
||||
** bits 0-1: op mode
|
||||
** bits 2-3: C arg mode
|
||||
** 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 */
|
||||
public static final int OpArgR = 2; /* argument is a register or a jump offset */
|
||||
public static final int OpArgK = 3; /* argument is a constant or register/constant */
|
||||
|
||||
public static final int[] luaP_opmodes = {
|
||||
/* T A B C mode opcode */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_MOVE */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_LOADK */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_LOADBOOL */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_LOADNIL */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_GETUPVAL */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_GETGLOBAL */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgK<<2) | (iABC), /* OP_GETTABLE */
|
||||
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_SETGLOBAL */
|
||||
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_SETUPVAL */
|
||||
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SETTABLE */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_NEWTABLE */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgK<<2) | (iABC), /* OP_SELF */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_ADD */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SUB */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MUL */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_DIV */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MOD */
|
||||
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_POW */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_UNM */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_NOT */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_LEN */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgR<<2) | (iABC), /* OP_CONCAT */
|
||||
(0<<7) | (0<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_JMP */
|
||||
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_EQ */
|
||||
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LT */
|
||||
(1<<7) | (0<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_LE */
|
||||
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgU<<2) | (iABC), /* OP_TEST */
|
||||
(1<<7) | (1<<6) | (OpArgR<<4) | (OpArgU<<2) | (iABC), /* OP_TESTSET */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_CALL */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_TAILCALL */
|
||||
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_RETURN */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORLOOP */
|
||||
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iAsBx), /* OP_FORPREP */
|
||||
(1<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TFORLOOP */
|
||||
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_SETLIST */
|
||||
(0<<7) | (0<<6) | (OpArgN<<4) | (OpArgN<<2) | (iABC), /* OP_CLOSE */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABx), /* OP_CLOSURE */
|
||||
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_VARARG */
|
||||
};
|
||||
|
||||
public static int getOpMode(int m) {
|
||||
return luaP_opmodes[m] & 3;
|
||||
}
|
||||
public static int getBMode(int m) {
|
||||
return (luaP_opmodes[m] >> 4) & 3;
|
||||
}
|
||||
public static int getCMode(int m) {
|
||||
return (luaP_opmodes[m] >> 2) & 3;
|
||||
}
|
||||
public static boolean testAMode(int m) {
|
||||
return 0 != (luaP_opmodes[m] & (1 << 6));
|
||||
}
|
||||
public static boolean testTMode(int m) {
|
||||
return 0 != (luaP_opmodes[m] & (1 << 7));
|
||||
}
|
||||
|
||||
/* number of list items to accumulate before a SETLIST instruction */
|
||||
public static final int LFIELDS_PER_FLUSH = 50;
|
||||
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
/**
|
||||
* Extension of {@link LuaValue} which can hold a Java boolean as its value.
|
||||
* <p>
|
||||
* These instance are not instantiated directly by clients.
|
||||
* Instead, there are exactly twon instances of this class,
|
||||
* {@link LuaValue#TRUE} and {@link LuaValue#FALSE}
|
||||
* representing the lua values {@code true} and {@link false}.
|
||||
* The function {@link LuaValue#valueOf(boolean)} will always
|
||||
* return one of these two values.
|
||||
* <p>
|
||||
* Any {@link LuaValue} can be converted to its equivalent
|
||||
* boolean representation using {@link LuaValue#toboolean()}
|
||||
* <p>
|
||||
* @see LuaValue
|
||||
* @see LuaValue#valueOf(boolean)
|
||||
* @see LuaValue#TRUE
|
||||
* @see LuaValue#FALSE
|
||||
*/
|
||||
public final class LuaBoolean extends LuaValue {
|
||||
|
||||
/** The singleton instance representing lua {@code true} */
|
||||
static final LuaBoolean _TRUE = new LuaBoolean(true);
|
||||
|
||||
/** The singleton instance representing lua {@code false} */
|
||||
static final LuaBoolean _FALSE = new LuaBoolean(false);
|
||||
|
||||
/** Shared static metatable for boolean values represented in lua. */
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
/** The value of the boolean */
|
||||
public final boolean v;
|
||||
|
||||
LuaBoolean(boolean b) {
|
||||
this.v = b;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TBOOLEAN;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "boolean";
|
||||
}
|
||||
|
||||
public boolean isboolean() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue not() {
|
||||
return v ? FALSE : LuaValue.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the boolean value for this boolean
|
||||
* @return value as a Java boolean
|
||||
*/
|
||||
public boolean booleanValue() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public boolean toboolean() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return v ? "true" : "false";
|
||||
}
|
||||
|
||||
public boolean optboolean(boolean defval) {
|
||||
return this.v;
|
||||
}
|
||||
|
||||
public boolean checkboolean() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
}
|
@ -1,521 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
|
||||
/**
|
||||
* Extension of {@link LuaFunction} which executes lua bytecode.
|
||||
* <p>
|
||||
* A {@link LuaClosure} is a combination of a {@link Prototype}
|
||||
* and a {@link LuaValue} to use as an environment for execution.
|
||||
* <p>
|
||||
* There are three main ways {@link LuaClosure} instances are created:
|
||||
* <ul>
|
||||
* <li>Construct an instance using {@link #LuaClosure(Prototype, LuaValue)}</li>
|
||||
* <li>Construct it indirectly by loading a chunk via {@link LuaCompiler#load(java.io.InputStream, String, LuaValue)}
|
||||
* <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 {@link LuaC}:
|
||||
* <pre> {@code
|
||||
* InputStream is = new ByteArrayInputStream("print('hello,world').getBytes());
|
||||
* Prototype p = LuaC.instance.compile(is, "script");
|
||||
* LuaValue _G = JsePlatform.standardGlobals()
|
||||
* LuaClosure f = new LuaClosure(p, _G);
|
||||
* }</pre>
|
||||
* <p>
|
||||
* To construct it indirectly, the {@link LuaC} compiler may be used,
|
||||
* which implements the {@link LuaCompiler} interface:
|
||||
* <pre> {@code
|
||||
* LuaFunction f = LuaC.instance.load(is, "script", _G);
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Typically, a closure that has just been loaded needs to be initialized by executing it,
|
||||
* and its return value can be saved if needed:
|
||||
* <pre> {@code
|
||||
* LuaValue r = f.call();
|
||||
* _G.set( "mypkg", r )
|
||||
* }</pre>
|
||||
* <p>
|
||||
* In the preceding, the loaded value is typed as {@link LuaFunction}
|
||||
* to allow for the possibility of other compilers such as {@link LuaJC}
|
||||
* producing {@link LuaFunction} directly without
|
||||
* creating a {@link Prototype} or {@link LuaClosure}.
|
||||
* <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#setfenv(LuaValue)}</li>
|
||||
* <li>{@link LuaValue#call()}</li>
|
||||
* <li>{@link LuaValue#call(LuaValue)}</li>
|
||||
* <li>{@link LuaValue#invoke()}</li>
|
||||
* <li>{@link LuaValue#invoke(Varargs)}</li>
|
||||
* <li>{@link LuaValue#method(String)}</li>
|
||||
* <li>{@link LuaValue#method(String,LuaValue)}</li>
|
||||
* <li>{@link LuaValue#invokemethod(String)}</li>
|
||||
* <li>{@link LuaValue#invokemethod(String,Varargs)}</li>
|
||||
* <li> ...</li>
|
||||
* </ul>
|
||||
* @see LuaValue
|
||||
* @see LuaFunction
|
||||
* @see LuaValue#isclosure()
|
||||
* @see LuaValue#checkclosure()
|
||||
* @see LuaValue#optclosure(LuaClosure)
|
||||
* @see LoadState
|
||||
* @see LoadState#compiler
|
||||
*/
|
||||
public class LuaClosure extends LuaFunction {
|
||||
private static final UpValue[] NOUPVALUES = new UpValue[0];
|
||||
|
||||
public final Prototype p;
|
||||
public final UpValue[] upValues;
|
||||
|
||||
LuaClosure() {
|
||||
p = null;
|
||||
upValues = null;
|
||||
}
|
||||
/** Supply the initial environment */
|
||||
public LuaClosure(Prototype p, LuaValue env) {
|
||||
super( env );
|
||||
this.p = p;
|
||||
this.upValues = p.nups>0? new UpValue[p.nups]: NOUPVALUES;
|
||||
}
|
||||
|
||||
protected LuaClosure(int nupvalues, LuaValue env) {
|
||||
super( env );
|
||||
this.p = null;
|
||||
this.upValues = nupvalues>0? new UpValue[nupvalues]: NOUPVALUES;
|
||||
}
|
||||
|
||||
public boolean isclosure() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaClosure optclosure(LuaClosure defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaClosure checkclosure() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
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);
|
||||
switch ( p.numparams ) {
|
||||
default: stack[0]=arg; return execute(stack,NONE).arg1();
|
||||
case 0: return execute(stack,arg).arg1();
|
||||
}
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
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();
|
||||
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).arg1();
|
||||
}
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
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();
|
||||
case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1();
|
||||
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1();
|
||||
}
|
||||
}
|
||||
|
||||
public final Varargs invoke(Varargs varargs) {
|
||||
return onInvoke( varargs ).eval();
|
||||
}
|
||||
|
||||
public Varargs onInvoke(Varargs varargs) {
|
||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||
for ( int i=0; i<p.numparams; i++ )
|
||||
stack[i] = varargs.arg(i+1);
|
||||
return execute(stack,p.is_vararg!=0? varargs.subargs(p.numparams+1): NONE);
|
||||
}
|
||||
|
||||
|
||||
protected Varargs execute( LuaValue[] stack, Varargs varargs ) {
|
||||
// loop through instructions
|
||||
int i,a,b,c,pc=0,top=0;
|
||||
LuaValue o;
|
||||
Varargs v = NONE;
|
||||
int[] code = p.code;
|
||||
LuaValue[] k = p.k;
|
||||
|
||||
// upvalues are only possible when closures create closures
|
||||
UpValue[] openups = p.p.length>0? new UpValue[stack.length]: null;
|
||||
|
||||
// create varargs "arg" table
|
||||
if ( p.is_vararg >= Lua.VARARG_NEEDSARG )
|
||||
stack[p.numparams] = new LuaTable(varargs);
|
||||
|
||||
// debug wants args to this function
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugSetupCall(varargs, stack);
|
||||
|
||||
// process instructions
|
||||
LuaThread.CallStack cs = LuaThread.onCall( this );
|
||||
try {
|
||||
while ( true ) {
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugBytecode(pc, v, top);
|
||||
|
||||
// pull out instruction
|
||||
i = code[pc++];
|
||||
a = ((i>>6) & 0xff);
|
||||
|
||||
// process the op code
|
||||
switch ( i & 0x3f ) {
|
||||
|
||||
case Lua.OP_MOVE:/* A B R(A):= R(B) */
|
||||
stack[a] = stack[i>>>23];
|
||||
continue;
|
||||
|
||||
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
|
||||
stack[a] = k[i>>>14];
|
||||
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)
|
||||
pc++; /* skip next instruction (if C) */
|
||||
continue;
|
||||
|
||||
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(B):= nil */
|
||||
for ( b=i>>>23; a<=b; )
|
||||
stack[a++] = LuaValue.NIL;
|
||||
continue;
|
||||
|
||||
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
|
||||
stack[a] = upValues[i>>>23].getValue();
|
||||
continue;
|
||||
|
||||
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
|
||||
stack[a] = env.get(k[i>>>14]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
|
||||
stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
|
||||
env.set(k[i>>>14], stack[a]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||
upValues[i>>>23].setValue(stack[a]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
|
||||
stack[a].set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
|
||||
stack[a] = new LuaTable(i>>>23,(i>>14)&0x1ff);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
|
||||
stack[a+1] = (o = stack[i>>>23]);
|
||||
stack[a] = o.get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).add((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).sub((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mul((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).div((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mod((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
|
||||
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).pow((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
|
||||
continue;
|
||||
|
||||
case Lua.OP_UNM: /* A B R(A):= -R(B) */
|
||||
stack[a] = stack[i>>>23].neg();
|
||||
continue;
|
||||
|
||||
case Lua.OP_NOT: /* A B R(A):= not R(B) */
|
||||
stack[a] = stack[i>>>23].not();
|
||||
continue;
|
||||
|
||||
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
|
||||
stack[a] = stack[i>>>23].len();
|
||||
continue;
|
||||
|
||||
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
|
||||
b = i>>>23;
|
||||
c = (i>>14)&0x1ff;
|
||||
{
|
||||
if ( c > b+1 ) {
|
||||
Buffer sb = stack[c].buffer();
|
||||
while ( --c>=b )
|
||||
sb = stack[c].concat(sb);
|
||||
stack[a] = sb.value();
|
||||
} else {
|
||||
stack[a] = stack[c-1].concat(stack[c]);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_JMP: /* sBx pc+=sBx */
|
||||
pc += (i>>>14)-0x1ffff;
|
||||
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) )
|
||||
++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) )
|
||||
++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) )
|
||||
++pc;
|
||||
continue;
|
||||
|
||||
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) )
|
||||
++pc;
|
||||
else
|
||||
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)) */
|
||||
switch ( i & (Lua.MASK_B | Lua.MASK_C) ) {
|
||||
case (1<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(NONE); top=a+v.narg(); continue;
|
||||
case (2<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(stack[a+1]); top=a+v.narg(); continue;
|
||||
case (1<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(); continue;
|
||||
case (2<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1]); continue;
|
||||
case (3<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2]); continue;
|
||||
case (4<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
|
||||
case (1<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(); continue;
|
||||
case (2<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1]); continue;
|
||||
case (3<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2]); continue;
|
||||
case (4<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
|
||||
default:
|
||||
b = i>>>23;
|
||||
c = (i>>14)&0x1ff;
|
||||
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
|
||||
v = stack[a].invoke(v);
|
||||
if ( c > 0 ) {
|
||||
while ( --c > 0 )
|
||||
stack[a+c-1] = v.arg(c);
|
||||
v = NONE; // TODO: necessary?
|
||||
} else {
|
||||
top = a + v.narg();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
switch ( i & Lua.MASK_B ) {
|
||||
case (1<<Lua.POS_B): return new TailcallVarargs(stack[a], NONE);
|
||||
case (2<<Lua.POS_B): return new TailcallVarargs(stack[a], stack[a+1]);
|
||||
case (3<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2]));
|
||||
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?
|
||||
varargsOf(stack,a+1,b-1): // exact arg count
|
||||
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 1: return NONE;
|
||||
case 2: return stack[a];
|
||||
default:
|
||||
return varargsOf(stack, a, b-1);
|
||||
}
|
||||
|
||||
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
|
||||
{
|
||||
LuaValue limit = stack[a + 1];
|
||||
LuaValue step = stack[a + 2];
|
||||
LuaValue idx = step.add(stack[a]);
|
||||
if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) {
|
||||
stack[a] = idx;
|
||||
stack[a + 3] = idx;
|
||||
pc += (i>>>14)-0x1ffff;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
|
||||
{
|
||||
LuaValue init = stack[a].checknumber("'for' initial value must be a number");
|
||||
LuaValue limit = stack[a + 1].checknumber("'for' limit must be a number");
|
||||
LuaValue step = stack[a + 2].checknumber("'for' step must be a number");
|
||||
stack[a] = init.sub(step);
|
||||
stack[a + 1] = limit;
|
||||
stack[a + 2] = step;
|
||||
pc += (i>>>14)-0x1ffff;
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_TFORLOOP: /*
|
||||
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
|
||||
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
|
||||
* else pc++
|
||||
*/
|
||||
// TODO: stack call on for loop body, such as: stack[a].call(ci);
|
||||
v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
|
||||
if ( (o=v.arg1()).isnil() )
|
||||
++pc;
|
||||
else {
|
||||
stack[a+2] = stack[a+3] = o;
|
||||
for ( c=(i>>14)&0x1ff; c>1; --c )
|
||||
stack[a+2+c] = v.arg(c);
|
||||
v = NONE; // todo: necessary?
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
|
||||
{
|
||||
if ( (c=(i>>14)&0x1ff) == 0 )
|
||||
c = code[pc++];
|
||||
int offset = (c-1) * Lua.LFIELDS_PER_FLUSH;
|
||||
o = stack[a];
|
||||
if ( (b=i>>>23) == 0 ) {
|
||||
b = top - a - 1;
|
||||
int m = b - v.narg();
|
||||
int j=1;
|
||||
for ( ;j<=m; j++ )
|
||||
o.set(offset+j, stack[a + j]);
|
||||
for ( ;j<=b; j++ )
|
||||
o.set(offset+j, v.arg(j-m));
|
||||
} else {
|
||||
o.presize( offset + b );
|
||||
for (int j=1; j<=b; j++)
|
||||
o.set(offset+j, stack[a + j]);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
|
||||
for ( b=openups.length; --b>=a; )
|
||||
if ( openups[b]!=null ) {
|
||||
openups[b].close();
|
||||
openups[b] = null;
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
{
|
||||
Prototype newp = p.p[i>>>14];
|
||||
LuaClosure newcl = new LuaClosure(newp, env);
|
||||
for ( int j=0, nup=newp.nups; j<nup; ++j ) {
|
||||
i = code[pc++];
|
||||
//b = B(i);
|
||||
b = i>>>23;
|
||||
newcl.upValues[j] = (i&4) != 0?
|
||||
upValues[b]:
|
||||
openups[b]!=null? openups[b]: (openups[b]=new UpValue(stack,b));
|
||||
}
|
||||
stack[a] = newcl;
|
||||
}
|
||||
continue;
|
||||
|
||||
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
b = i>>>23;
|
||||
if ( b == 0 ) {
|
||||
top = a + (b = varargs.narg());
|
||||
v = varargs;
|
||||
} else {
|
||||
for ( int j=1; j<b; ++j )
|
||||
stack[a+j-1] = varargs.arg(j);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch ( LuaError le ) {
|
||||
throw le;
|
||||
} catch ( Exception e ) {
|
||||
throw new LuaError(e);
|
||||
} finally {
|
||||
cs.onReturn();
|
||||
if ( openups != null )
|
||||
for ( int u=openups.length; --u>=0; )
|
||||
if ( openups[u] != null )
|
||||
openups[u].close();
|
||||
}
|
||||
}
|
||||
|
||||
protected LuaValue getUpvalue(int i) {
|
||||
return upValues[i].getValue();
|
||||
}
|
||||
|
||||
protected void setUpvalue(int i, LuaValue v) {
|
||||
upValues[i].setValue(v);
|
||||
}
|
||||
}
|
@ -1,288 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
|
||||
/**
|
||||
* Extension of {@link LuaNumber} which can hold a Java double as its value.
|
||||
* <p>
|
||||
* 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}.
|
||||
* <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.
|
||||
* <p>
|
||||
* LuaDouble also defines functions for handling the unique math rules of lua devision and modulo in
|
||||
* <ul>
|
||||
* <li>{@link #ddiv(double, double)}</li>
|
||||
* <li>{@link #ddiv_d(double, double)}</li>
|
||||
* <li>{@link #dmod(double, double)}</li>
|
||||
* <li>{@link #dmod_d(double, double)}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* @see LuaValue
|
||||
* @see LuaNumber
|
||||
* @see LuaInteger
|
||||
* @see LuaValue#valueOf(int)
|
||||
* @see LuaValue#valueOf(double)
|
||||
*/
|
||||
public class LuaDouble extends LuaNumber {
|
||||
|
||||
/** Constant LuaDouble representing NaN (not a number) */
|
||||
public static final LuaDouble NAN = new LuaDouble( Double.NaN );
|
||||
|
||||
/** Constant LuaDouble representing positive infinity */
|
||||
public static final LuaDouble POSINF = new LuaDouble( Double.POSITIVE_INFINITY );
|
||||
|
||||
/** Constant LuaDouble representing negative infinity */
|
||||
public static final LuaDouble NEGINF = new LuaDouble( Double.NEGATIVE_INFINITY );
|
||||
|
||||
/** Constant String representation for NaN (not a number), "nan" */
|
||||
public static final String JSTR_NAN = "nan";
|
||||
|
||||
/** Constant String representation for positive infinity, "inf" */
|
||||
public static final String JSTR_POSINF = "inf";
|
||||
|
||||
/** Constant String representation for negative infinity, "-inf" */
|
||||
public static final String JSTR_NEGINF = "-inf";
|
||||
|
||||
/** The value being held by this instance. */
|
||||
final double v;
|
||||
|
||||
public static LuaNumber valueOf(double d) {
|
||||
int id = (int) d;
|
||||
return d==id? (LuaNumber) LuaInteger.valueOf(id): (LuaNumber) new LuaDouble(d);
|
||||
}
|
||||
|
||||
/** Don't allow ints to be boxed by DoubleValues */
|
||||
private LuaDouble(double d) {
|
||||
this.v = d;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
long l = Double.doubleToLongBits(v);
|
||||
return ((int)(l>>32)) | (int) l;
|
||||
}
|
||||
|
||||
public boolean islong() {
|
||||
return v == (long) v;
|
||||
}
|
||||
|
||||
public byte tobyte() { return (byte) (long) v; }
|
||||
public char tochar() { return (char) (long) v; }
|
||||
public double todouble() { return v; }
|
||||
public float tofloat() { return (float) v; }
|
||||
public int toint() { return (int) (long) v; }
|
||||
public long tolong() { return (long) v; }
|
||||
public short toshort() { return (short) (long) v; }
|
||||
|
||||
public double optdouble(double defval) { return v; }
|
||||
public int optint(int defval) { return (int) (long) v; }
|
||||
public LuaInteger optinteger(LuaInteger defval) { return LuaInteger.valueOf((int) (long)v); }
|
||||
public long optlong(long defval) { return (long) v; }
|
||||
|
||||
public LuaInteger checkinteger() { return LuaInteger.valueOf( (int) (long) v ); }
|
||||
|
||||
// unary operators
|
||||
public LuaValue neg() { return valueOf(-v); }
|
||||
|
||||
// object equality, used for key comparison
|
||||
public boolean equals(Object o) { return o instanceof LuaDouble? ((LuaDouble)o).v == v: false; }
|
||||
|
||||
// equality w/ metatable processing
|
||||
public LuaValue eq( LuaValue val ) { return val.raweq(v)? TRUE: FALSE; }
|
||||
public boolean eq_b( LuaValue val ) { return val.raweq(v); }
|
||||
|
||||
// equality w/o metatable processing
|
||||
public boolean raweq( LuaValue val ) { return val.raweq(v); }
|
||||
public boolean raweq( double val ) { return v == val; }
|
||||
public boolean raweq( int val ) { return v == val; }
|
||||
|
||||
// basic binary arithmetic
|
||||
public LuaValue add( LuaValue rhs ) { return rhs.add(v); }
|
||||
public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); }
|
||||
public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); }
|
||||
public LuaValue sub( double rhs ) { return LuaDouble.valueOf(v - rhs); }
|
||||
public LuaValue sub( int rhs ) { return LuaDouble.valueOf(v - rhs); }
|
||||
public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); }
|
||||
public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); }
|
||||
public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); }
|
||||
public LuaValue mul( int lhs ) { return LuaDouble.valueOf(lhs * v); }
|
||||
public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); }
|
||||
public LuaValue pow( double rhs ) { return MathLib.dpow(v,rhs); }
|
||||
public LuaValue pow( int rhs ) { return MathLib.dpow(v,rhs); }
|
||||
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); }
|
||||
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); }
|
||||
public LuaValue div( LuaValue rhs ) { return rhs.divInto(v); }
|
||||
public LuaValue div( double rhs ) { return LuaDouble.ddiv(v,rhs); }
|
||||
public LuaValue div( int rhs ) { return LuaDouble.ddiv(v,rhs); }
|
||||
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
|
||||
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
|
||||
public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); }
|
||||
public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); }
|
||||
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
|
||||
|
||||
|
||||
/** 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,
|
||||
* taking into account positive and negiative infinity, and Nan
|
||||
* @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;
|
||||
}
|
||||
|
||||
/** Divide two double numbers according to lua math, and return a double result.
|
||||
* @param lhs Left-hand-side of the division.
|
||||
* @param rhs Right-hand-side of the division.
|
||||
* @return Value of the division, taking into account positive and negative infinity, and Nan
|
||||
* @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;
|
||||
}
|
||||
|
||||
/** 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,
|
||||
* using lua's rules for modulo
|
||||
* @see #dmod_d(double, double)
|
||||
*/
|
||||
public static LuaValue dmod(double lhs, double rhs) {
|
||||
return rhs!=0? valueOf( lhs-rhs*Math.floor(lhs/rhs) ): NAN;
|
||||
}
|
||||
|
||||
/** 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,
|
||||
* 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;
|
||||
}
|
||||
|
||||
// relational operators
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; }
|
||||
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( 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( 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( 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( 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( 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( 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( 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 String tojstring() {
|
||||
/*
|
||||
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 )
|
||||
return Long.toString(l);
|
||||
if ( Double.isNaN(v) )
|
||||
return JSTR_NAN;
|
||||
if ( Double.isInfinite(v) )
|
||||
return (v<0? JSTR_NEGINF: JSTR_POSINF);
|
||||
return Float.toString((float)v);
|
||||
}
|
||||
|
||||
public LuaString strvalue() {
|
||||
return LuaString.valueOf(tojstring());
|
||||
}
|
||||
|
||||
public LuaString optstring(LuaString defval) {
|
||||
return LuaString.valueOf(tojstring());
|
||||
}
|
||||
|
||||
public LuaValue tostring() {
|
||||
return LuaString.valueOf(tojstring());
|
||||
}
|
||||
|
||||
public String optjstring(String defval) {
|
||||
return tojstring();
|
||||
}
|
||||
|
||||
public LuaNumber optnumber(LuaNumber defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isnumber() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue tonumber() {
|
||||
return this;
|
||||
}
|
||||
public int checkint() { return (int) (long) v; }
|
||||
public long checklong() { return (long) v; }
|
||||
public LuaNumber checknumber() { return this; }
|
||||
public double checkdouble() { return v; }
|
||||
|
||||
public String checkjstring() {
|
||||
return tojstring();
|
||||
}
|
||||
public LuaString checkstring() {
|
||||
return LuaString.valueOf(tojstring());
|
||||
}
|
||||
|
||||
public LuaValue checkvalidkey() {
|
||||
if ( Double.isNaN(v) )
|
||||
throw new LuaError("table index expected, got nan");
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
|
||||
/**
|
||||
* RuntimeException that is thrown and caught in response to a lua error.
|
||||
* <p>
|
||||
* {@link LuaError} is used wherever a lua call to {@code error()}
|
||||
* would be used within a script.
|
||||
* <p>
|
||||
* Since it is an unchecked exception inheriting from {@link RuntimeException},
|
||||
* Java method signatures do notdeclare this exception, althoug it can
|
||||
* be thrown on almost any luaj Java operation.
|
||||
* This is analagous to the fact that any lua script can throw a lua error at any time.
|
||||
* <p>
|
||||
*/
|
||||
public class LuaError extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String traceback;
|
||||
|
||||
/**
|
||||
* Run the error hook if there is one
|
||||
* @param msg the message to use in error hook processing.
|
||||
* */
|
||||
private static String errorHook(String msg) {
|
||||
LuaThread thread = LuaThread.getRunning();
|
||||
if ( thread.err != null ) {
|
||||
LuaValue errfunc = thread.err;
|
||||
thread.err = null;
|
||||
try {
|
||||
return errfunc.call( LuaValue.valueOf(msg) ).tojstring();
|
||||
} catch ( Throwable t ) {
|
||||
return "error in error handling";
|
||||
} finally {
|
||||
thread.err = errfunc;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
private Throwable cause;
|
||||
|
||||
/** Construct LuaError when a program exception occurs.
|
||||
* <p>
|
||||
* All errors generated from lua code should throw LuaError(String) instead.
|
||||
* @param cause the Throwable that caused the error, if known.
|
||||
*/
|
||||
public LuaError(Throwable cause) {
|
||||
super( errorHook( addFileLine( "vm error: "+cause ) ) );
|
||||
this.cause = cause;
|
||||
this.traceback = DebugLib.traceback(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a LuaError with a specific message.
|
||||
*
|
||||
* @param message message to supply
|
||||
*/
|
||||
public LuaError(String message) {
|
||||
super( errorHook( addFileLine( message ) ) );
|
||||
this.traceback = DebugLib.traceback(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a LuaError with a message, and level to draw line number information from.
|
||||
* @param message message to supply
|
||||
* @param level where to supply line info from in call stack
|
||||
*/
|
||||
public LuaError(String message, int level) {
|
||||
super( errorHook( addFileLine( message, level ) ) );
|
||||
this.traceback = DebugLib.traceback(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add file and line info to a message at a particular level
|
||||
* @param message the String message to use
|
||||
* @param level where to supply line info from in call stack
|
||||
* */
|
||||
private static String addFileLine( String message, int level ) {
|
||||
if ( message == null ) return null;
|
||||
if ( level == 0 ) return message;
|
||||
String fileline = DebugLib.fileline(level-1);
|
||||
return fileline!=null? fileline+": "+message: message;
|
||||
}
|
||||
|
||||
/** Add file and line info for the nearest enclosing closure
|
||||
* @param message the String message to use
|
||||
* */
|
||||
private static String addFileLine( String message ) {
|
||||
if ( message == null ) return null;
|
||||
String fileline = DebugLib.fileline();
|
||||
return fileline!=null? fileline+": "+message: message;
|
||||
}
|
||||
|
||||
/** Print the message and stack trace */
|
||||
public void printStackTrace() {
|
||||
System.out.println( toString() );
|
||||
if ( traceback != null )
|
||||
System.out.println( traceback );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cause, if any.
|
||||
*/
|
||||
public Throwable getCause() {
|
||||
return cause;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
/**
|
||||
* Base class for functions implemented in Java.
|
||||
* <p>
|
||||
* Direct subclass include {@link 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 LibFunction
|
||||
* @see LuaClosure
|
||||
*/
|
||||
abstract
|
||||
public class LuaFunction extends LuaValue {
|
||||
|
||||
/** Shared static metatable for all functions and closures. */
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
protected LuaValue env;
|
||||
|
||||
public LuaFunction() {
|
||||
this.env = NIL;
|
||||
}
|
||||
|
||||
public LuaFunction(LuaValue env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return TFUNCTION;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "function";
|
||||
}
|
||||
|
||||
public boolean isfunction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue checkfunction() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaFunction optfunction(LuaFunction defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public LuaValue getfenv() {
|
||||
return env;
|
||||
}
|
||||
|
||||
public void setfenv(LuaValue env) {
|
||||
this.env = env!=null? env: NIL;
|
||||
}
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
|
||||
/**
|
||||
* Extension of {@link LuaNumber} which can hold a Java int as its value.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* There are no API's specific to LuaInteger that are useful beyond what is already
|
||||
* exposed in {@link LuaValue}.
|
||||
*
|
||||
* @see LuaValue
|
||||
* @see LuaNumber
|
||||
* @see LuaDouble
|
||||
* @see LuaValue#valueOf(int)
|
||||
* @see LuaValue#valueOf(double)
|
||||
*/
|
||||
public class LuaInteger extends LuaNumber {
|
||||
|
||||
private static final LuaInteger[] intValues = new LuaInteger[512];
|
||||
static {
|
||||
for ( int i=0; i<512; i++ )
|
||||
intValues[i] = new LuaInteger(i-256);
|
||||
}
|
||||
|
||||
public static LuaInteger valueOf(int i) {
|
||||
return i<=255 && i>=-256? intValues[i+256]: new LuaInteger(i);
|
||||
};
|
||||
|
||||
// TODO consider moving this to LuaValue
|
||||
/** Return a LuaNumber that represents the value provided
|
||||
* @param l long value to represent.
|
||||
* @return LuaNumber that is eithe LuaInteger or LuaDouble representing l
|
||||
* @see LuaValue#valueOf(int)
|
||||
* @see LuaValue#valueOf(double)
|
||||
*/
|
||||
public static LuaNumber valueOf(long l) {
|
||||
int i = (int) l;
|
||||
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.
|
||||
* @see LuaValue#valueOf(int)
|
||||
**/
|
||||
LuaInteger(int i) {
|
||||
this.v = i;
|
||||
}
|
||||
|
||||
public boolean isint() { return true; }
|
||||
public boolean isinttype() { return true; }
|
||||
public boolean islong() { return true; }
|
||||
|
||||
public byte tobyte() { return (byte) v; }
|
||||
public char tochar() { return (char) v; }
|
||||
public double todouble() { return v; }
|
||||
public float tofloat() { return v; }
|
||||
public int toint() { return v; }
|
||||
public long tolong() { return v; }
|
||||
public short toshort() { return (short) v; }
|
||||
|
||||
public double optdouble(double defval) { return v; }
|
||||
public int optint(int defval) { return v; }
|
||||
public LuaInteger optinteger(LuaInteger defval) { return this; }
|
||||
public long optlong(long defval) { return v; }
|
||||
|
||||
public String tojstring() {
|
||||
return Integer.toString(v);
|
||||
}
|
||||
|
||||
public LuaString strvalue() {
|
||||
return LuaString.valueOf(Integer.toString(v));
|
||||
}
|
||||
|
||||
public LuaString optstring(LuaString defval) {
|
||||
return LuaString.valueOf(Integer.toString(v));
|
||||
}
|
||||
|
||||
public LuaValue tostring() {
|
||||
return LuaString.valueOf(Integer.toString(v));
|
||||
}
|
||||
|
||||
public String optjstring(String defval) {
|
||||
return Integer.toString(v);
|
||||
}
|
||||
|
||||
public LuaInteger checkinteger() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return v;
|
||||
}
|
||||
|
||||
// unary operators
|
||||
public LuaValue neg() { return valueOf(-(long)v); }
|
||||
|
||||
// object equality, used for key comparison
|
||||
public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger)o).v == v: false; }
|
||||
|
||||
// equality w/ metatable processing
|
||||
public LuaValue eq( LuaValue val ) { return val.raweq(v)? TRUE: FALSE; }
|
||||
public boolean eq_b( LuaValue val ) { return val.raweq(v); }
|
||||
|
||||
// equality w/o metatable processing
|
||||
public boolean raweq( LuaValue val ) { return val.raweq(v); }
|
||||
public boolean raweq( double val ) { return v == val; }
|
||||
public boolean raweq( int val ) { return v == val; }
|
||||
|
||||
// arithmetic operators
|
||||
public LuaValue add( LuaValue rhs ) { return rhs.add(v); }
|
||||
public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); }
|
||||
public LuaValue add( int lhs ) { return LuaInteger.valueOf(lhs + (long)v); }
|
||||
public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); }
|
||||
public LuaValue sub( double rhs ) { return LuaDouble.valueOf(v - rhs); }
|
||||
public LuaValue sub( int rhs ) { return LuaDouble.valueOf(v - rhs); }
|
||||
public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); }
|
||||
public LuaValue subFrom( int lhs ) { return LuaInteger.valueOf(lhs - (long)v); }
|
||||
public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); }
|
||||
public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); }
|
||||
public LuaValue mul( int lhs ) { return LuaInteger.valueOf(lhs * (long)v); }
|
||||
public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); }
|
||||
public LuaValue pow( double rhs ) { return MathLib.dpow(v,rhs); }
|
||||
public LuaValue pow( int rhs ) { return MathLib.dpow(v,rhs); }
|
||||
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); }
|
||||
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); }
|
||||
public LuaValue div( LuaValue rhs ) { return rhs.divInto(v); }
|
||||
public LuaValue div( double rhs ) { return LuaDouble.ddiv(v,rhs); }
|
||||
public LuaValue div( int rhs ) { return LuaDouble.ddiv(v,rhs); }
|
||||
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
|
||||
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
|
||||
public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); }
|
||||
public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); }
|
||||
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( 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( 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( 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( 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( 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( 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( 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( 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 long checklong() {
|
||||
return v;
|
||||
}
|
||||
public double checkdouble() {
|
||||
return v;
|
||||
}
|
||||
public String checkjstring() {
|
||||
return String.valueOf(v);
|
||||
}
|
||||
public LuaString checkstring() {
|
||||
return valueOf( String.valueOf(v) );
|
||||
}
|
||||
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
/**
|
||||
* Class to encapsulate behavior of the singleton instance {@code nil}
|
||||
* <p>
|
||||
* There will be one instance of this class, {@link LuaValue#NIL},
|
||||
* per Java virtual machine.
|
||||
* However, the {@link Varargs} instance {@link LuaValue#NONE}
|
||||
* which is the empty list,
|
||||
* is also considered treated as a nil value by default.
|
||||
* <p>
|
||||
* Although it is possible to test for nil using Java == operator,
|
||||
* the recommended approach is to use the method {@link LuaValue#isnil()}
|
||||
* instead. By using that any ambiguities between
|
||||
* {@link LuaValue#NIL} and {@link LuaValue#NONE} are avoided.
|
||||
* @see LuaValue
|
||||
* @see LuaValue#NIL
|
||||
*/
|
||||
public class LuaNil extends LuaValue {
|
||||
|
||||
static final LuaNil _NIL = new LuaNil();
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
LuaNil() {}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TNIL;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "nil";
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return "nil";
|
||||
}
|
||||
|
||||
public LuaValue not() {
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
public boolean toboolean() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isnil() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof LuaNil;
|
||||
}
|
||||
|
||||
public LuaValue checknotnil() {
|
||||
return argerror("value");
|
||||
}
|
||||
|
||||
public LuaValue checkvalidkey() {
|
||||
return typerror("table index");
|
||||
}
|
||||
|
||||
// optional argument conversions - nil alwas falls badk to default value
|
||||
public boolean optboolean(boolean defval) { return defval; }
|
||||
public LuaClosure optclosure(LuaClosure defval) { return defval; }
|
||||
public double optdouble(double defval) { return defval; }
|
||||
public LuaFunction optfunction(LuaFunction defval) { return defval; }
|
||||
public int optint(int defval) { return defval; }
|
||||
public LuaInteger optinteger(LuaInteger defval) { return defval; }
|
||||
public long optlong(long defval) { return defval; }
|
||||
public LuaNumber optnumber(LuaNumber defval) { return defval; }
|
||||
public LuaTable opttable(LuaTable defval) { return defval; }
|
||||
public LuaThread optthread(LuaThread defval) { return defval; }
|
||||
public String optjstring(String defval) { return defval; }
|
||||
public LuaString optstring(LuaString defval) { return defval; }
|
||||
public Object optuserdata(Object defval) { return defval; }
|
||||
public Object optuserdata(Class c, Object defval) { return defval; }
|
||||
public LuaValue optvalue(LuaValue defval) { return defval; }
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
/**
|
||||
* Base class for representing numbers as lua values directly.
|
||||
* <p>
|
||||
* The main subclasses are {@link LuaInteger} which holds values that fit in a java int,
|
||||
* and {@link LuaDouble} which holds all other number values.
|
||||
* @see LuaInteger
|
||||
* @see LuaDouble
|
||||
* @see LuaValue
|
||||
*
|
||||
*/
|
||||
abstract
|
||||
public class LuaNumber extends LuaValue {
|
||||
|
||||
/** Shared static metatable for all number values represented in lua. */
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
public int type() {
|
||||
return TNUMBER;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "number";
|
||||
}
|
||||
|
||||
public LuaNumber checknumber() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaNumber checknumber(String errmsg) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaNumber optnumber(LuaNumber defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue tonumber() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isnumber() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
|
||||
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
|
||||
public LuaValue concatTo(LuaNumber lhs) { return strvalue().concatTo(lhs.strvalue()); }
|
||||
public LuaValue concatTo(LuaString lhs) { return strvalue().concatTo(lhs); }
|
||||
|
||||
}
|
@ -1,749 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.String;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
import org.luaj.vm2.lib.StringLib;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LuaValue} for representing lua strings.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* {@link LuaString} values are generally not 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,
|
||||
* instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API.
|
||||
* <p>
|
||||
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
|
||||
* The functions
|
||||
* {@link LuaString#lengthAsUtf8(char[]),
|
||||
* {@link LuaString#encodeToUtf8(char[], byte[], int)}, and
|
||||
* {@link LuaString#decodeAsUtf8(byte[], int, int)
|
||||
* are used to convert back and forth between UTF8 byte arrays and character arrays.
|
||||
*
|
||||
* @see LuaValue
|
||||
* @see LuaValue#valueOf(String)
|
||||
* @see LuaValue#valueOf(byte[])
|
||||
*/
|
||||
public class LuaString extends LuaValue {
|
||||
|
||||
/** The singleton instance representing lua {@code true} */
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
/** The bytes for the string */
|
||||
public final byte[] m_bytes;
|
||||
|
||||
/** The offset into the byte array, 0 means start at the first byte */
|
||||
public final int m_offset;
|
||||
|
||||
/** The number of bytes that comprise this string */
|
||||
public final int m_length;
|
||||
|
||||
private static final Hashtable index_java = new Hashtable();
|
||||
|
||||
private final static LuaString index_get(Hashtable indextable, Object key) {
|
||||
WeakReference w = (WeakReference) indextable.get(key);
|
||||
return w!=null? (LuaString) w.get(): null;
|
||||
}
|
||||
|
||||
private final static void index_set(Hashtable indextable, Object key, LuaString value) {
|
||||
indextable.put(key, new WeakReference(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static LuaString valueOf(String string) {
|
||||
LuaString s = index_get( index_java, string );
|
||||
if ( s != null ) return s;
|
||||
char[] c = string.toCharArray();
|
||||
/* DAN200 START */
|
||||
/*
|
||||
byte[] b = new byte[lengthAsUtf8(c)];
|
||||
encodeToUtf8(c, b, 0);
|
||||
*/
|
||||
byte[] b = new byte[c.length];
|
||||
for( int i=0; i<b.length; ++i )
|
||||
{
|
||||
char ch = c[i];
|
||||
b[i] = (ch < 256) ? (byte)ch : (byte)'?';
|
||||
}
|
||||
/* DAN200 END */
|
||||
s = valueOf(b, 0, b.length);
|
||||
index_set( index_java, string, s );
|
||||
return s;
|
||||
}
|
||||
|
||||
// TODO: should this be deprecated or made private?
|
||||
/** Construct a {@link LuaString} around a byte array without copying the contents.
|
||||
* <p>
|
||||
* The array is used directly after this is called, so clients must not change contents.
|
||||
* <p>
|
||||
* @param bytes byte buffer
|
||||
* @param off offset into the byte buffer
|
||||
* @param len length of the byte buffer
|
||||
* @return {@link LuaString} wrapping the byte buffer
|
||||
*/
|
||||
public static LuaString valueOf(byte[] bytes, int off, int len) {
|
||||
return new LuaString(bytes, off, len);
|
||||
}
|
||||
|
||||
/** Construct a {@link LuaString} using the supplied characters as byte values.
|
||||
* <p>
|
||||
* Only th elow-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
|
||||
*/
|
||||
public static LuaString valueOf(char[] bytes) {
|
||||
int n = bytes.length;
|
||||
byte[] b = new byte[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
b[i] = (byte) bytes[i];
|
||||
return valueOf(b, 0, n);
|
||||
}
|
||||
|
||||
|
||||
/** Construct a {@link LuaString} around a byte array without copying the contents.
|
||||
* <p>
|
||||
* The array is used directly after this is called, so clients must not change contents.
|
||||
* <p>
|
||||
* @param bytes byte buffer
|
||||
* @return {@link LuaString} wrapping the byte buffer
|
||||
*/
|
||||
public static LuaString valueOf(byte[] bytes) {
|
||||
return valueOf(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/** Construct a {@link LuaString} around a byte array without copying the contents.
|
||||
* <p>
|
||||
* The array is used directly after this is called, so clients must not change contents.
|
||||
* <p>
|
||||
* @param bytes byte buffer
|
||||
* @param offset offset into the byte buffer
|
||||
* @param length length of the byte buffer
|
||||
* @return {@link LuaString} wrapping the byte buffer
|
||||
*/
|
||||
private LuaString(byte[] bytes, int offset, int length) {
|
||||
this.m_bytes = bytes;
|
||||
this.m_offset = offset;
|
||||
this.m_length = length;
|
||||
}
|
||||
|
||||
public boolean isstring() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TSTRING;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "string";
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
/* DAN200 START */
|
||||
/*
|
||||
return decodeAsUtf8(m_bytes, m_offset, m_length);
|
||||
*/
|
||||
char[] chars = new char[ m_length ];
|
||||
for( int i=0; i<chars.length; ++i )
|
||||
{
|
||||
chars[i] = (char)(m_bytes[ m_offset + i ] & 255);
|
||||
}
|
||||
return new String( chars );
|
||||
/* DAN200 END */
|
||||
}
|
||||
|
||||
// get is delegated to the string library
|
||||
public LuaValue get(LuaValue key) {
|
||||
return s_metatable!=null? gettable(this,key): StringLib.instance.get(key);
|
||||
}
|
||||
|
||||
// unary operators
|
||||
public LuaValue neg() { double d = scannumber(10); return Double.isNaN(d)? super.neg(): valueOf(-d); }
|
||||
|
||||
// basic binary arithmetic
|
||||
public LuaValue add( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(ADD,rhs): rhs.add(d); }
|
||||
public LuaValue add( double rhs ) { return valueOf( checkarith() + rhs ); }
|
||||
public LuaValue add( int rhs ) { return valueOf( checkarith() + rhs ); }
|
||||
public LuaValue sub( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(SUB,rhs): rhs.subFrom(d); }
|
||||
public LuaValue sub( double rhs ) { return valueOf( checkarith() - rhs ); }
|
||||
public LuaValue sub( int rhs ) { return valueOf( checkarith() - rhs ); }
|
||||
public LuaValue subFrom( double lhs ) { return valueOf( lhs - checkarith() ); }
|
||||
public LuaValue mul( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(MUL,rhs): rhs.mul(d); }
|
||||
public LuaValue mul( double rhs ) { return valueOf( checkarith() * rhs ); }
|
||||
public LuaValue mul( int rhs ) { return valueOf( checkarith() * rhs ); }
|
||||
public LuaValue pow( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(POW,rhs): rhs.powWith(d); }
|
||||
public LuaValue pow( double rhs ) { return MathLib.dpow(checkarith(),rhs); }
|
||||
public LuaValue pow( int rhs ) { return MathLib.dpow(checkarith(),rhs); }
|
||||
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs, checkarith()); }
|
||||
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs, checkarith()); }
|
||||
public LuaValue div( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(DIV,rhs): rhs.divInto(d); }
|
||||
public LuaValue div( double rhs ) { return LuaDouble.ddiv(checkarith(),rhs); }
|
||||
public LuaValue div( int rhs ) { return LuaDouble.ddiv(checkarith(),rhs); }
|
||||
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs, checkarith()); }
|
||||
public LuaValue mod( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(MOD,rhs): rhs.modFrom(d); }
|
||||
public LuaValue mod( double rhs ) { return LuaDouble.dmod(checkarith(), rhs); }
|
||||
public LuaValue mod( int rhs ) { return LuaDouble.dmod(checkarith(), rhs); }
|
||||
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 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 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 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 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; }
|
||||
|
||||
// concatenation
|
||||
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) {
|
||||
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 new LuaString(b, 0, b.length);
|
||||
}
|
||||
|
||||
// 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 ) {
|
||||
if ( m_bytes[m_offset+i] != rhs.m_bytes[rhs.m_offset+j] ) {
|
||||
return ((int)m_bytes[m_offset+i]) - ((int) rhs.m_bytes[rhs.m_offset+j]);
|
||||
}
|
||||
}
|
||||
return m_length - rhs.m_length;
|
||||
}
|
||||
|
||||
/** Check for number in arithmetic, or throw aritherror */
|
||||
private double checkarith() {
|
||||
double d = scannumber(10);
|
||||
if ( Double.isNaN(d) )
|
||||
aritherror();
|
||||
return d;
|
||||
}
|
||||
|
||||
public int checkint() {
|
||||
return (int) (long) checkdouble();
|
||||
}
|
||||
public LuaInteger checkinteger() {
|
||||
return valueOf(checkint());
|
||||
}
|
||||
public long checklong() {
|
||||
return (long) checkdouble();
|
||||
}
|
||||
public double checkdouble() {
|
||||
double d = scannumber(10);
|
||||
if ( Double.isNaN(d) )
|
||||
argerror("number");
|
||||
return d;
|
||||
}
|
||||
public LuaNumber checknumber() {
|
||||
return valueOf(checkdouble());
|
||||
}
|
||||
public LuaNumber checknumber(String msg) {
|
||||
double d = scannumber(10);
|
||||
if ( Double.isNaN(d) )
|
||||
error(msg);
|
||||
return valueOf(d);
|
||||
}
|
||||
public LuaValue tonumber() {
|
||||
return tonumber(10);
|
||||
}
|
||||
|
||||
public boolean isnumber() {
|
||||
double d = scannumber(10);
|
||||
return ! Double.isNaN(d);
|
||||
}
|
||||
|
||||
public boolean isint() {
|
||||
double d = scannumber(10);
|
||||
if ( Double.isNaN(d) )
|
||||
return false;
|
||||
int i = (int) d;
|
||||
return i == d;
|
||||
}
|
||||
|
||||
public boolean islong() {
|
||||
double d = scannumber(10);
|
||||
if ( Double.isNaN(d) )
|
||||
return false;
|
||||
long l = (long) d;
|
||||
return l == d;
|
||||
}
|
||||
|
||||
public byte tobyte() { return (byte) toint(); }
|
||||
public char tochar() { return (char) toint(); }
|
||||
public double todouble() { double d=scannumber(10); return Double.isNaN(d)? 0: d; }
|
||||
public float tofloat() { return (float) todouble(); }
|
||||
public int toint() { return (int) tolong(); }
|
||||
public long tolong() { return (long) todouble(); }
|
||||
public short toshort() { return (short) toint(); }
|
||||
|
||||
public double optdouble(double defval) {
|
||||
return checknumber().checkdouble();
|
||||
}
|
||||
|
||||
public int optint(int defval) {
|
||||
return checknumber().checkint();
|
||||
}
|
||||
|
||||
public LuaInteger optinteger(LuaInteger defval) {
|
||||
return checknumber().checkinteger();
|
||||
}
|
||||
|
||||
public long optlong(long defval) {
|
||||
return checknumber().checklong();
|
||||
}
|
||||
|
||||
public LuaNumber optnumber(LuaNumber defval) {
|
||||
return checknumber().checknumber();
|
||||
}
|
||||
|
||||
public LuaString optstring(LuaString defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue tostring() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String optjstring(String defval) {
|
||||
return tojstring();
|
||||
}
|
||||
|
||||
public LuaString strvalue() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaString substring( int beginIndex, int endIndex ) {
|
||||
return new LuaString( m_bytes, m_offset + beginIndex, endIndex - beginIndex );
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int h = m_length; /* seed */
|
||||
int step = (m_length>>5)+1; /* if string is too long, don't hash all its chars */
|
||||
for (int l1=m_length; l1>=step; l1-=step) /* compute hash */
|
||||
h = h ^ ((h<<5)+(h>>2)+(((int) m_bytes[m_offset+l1-1] ) & 0x0FF ));
|
||||
return h;
|
||||
}
|
||||
|
||||
// object comparison, used in key comparison
|
||||
public boolean equals( Object o ) {
|
||||
if ( o instanceof LuaString ) {
|
||||
return raweq( (LuaString) o );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// equality w/ metatable processing
|
||||
public LuaValue eq( LuaValue val ) { return val.raweq(this)? TRUE: FALSE; }
|
||||
public boolean eq_b( LuaValue val ) { return val.raweq(this); }
|
||||
|
||||
// equality w/o metatable processing
|
||||
public boolean raweq( LuaValue val ) {
|
||||
return val.raweq(this);
|
||||
}
|
||||
|
||||
public boolean raweq( LuaString s ) {
|
||||
if ( this == s )
|
||||
return true;
|
||||
if ( s.m_length != m_length )
|
||||
return false;
|
||||
if ( s.m_bytes == m_bytes && s.m_offset == m_offset )
|
||||
return true;
|
||||
if ( s.hashCode() != hashCode() )
|
||||
return false;
|
||||
for ( int i=0; i<m_length; i++ )
|
||||
if ( s.m_bytes[s.m_offset+i] != m_bytes[m_offset+i] )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean equals( LuaString a, int i, LuaString b, int j, int n ) {
|
||||
return equals( a.m_bytes, a.m_offset + i, b.m_bytes, b.m_offset + j, n );
|
||||
}
|
||||
|
||||
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 )
|
||||
if ( a[i++]!=b[j++] )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void write(DataOutputStream writer, int i, int len) throws IOException {
|
||||
writer.write(m_bytes,m_offset+i,len);
|
||||
}
|
||||
|
||||
public LuaValue len() {
|
||||
return LuaInteger.valueOf(m_length);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return m_length;
|
||||
}
|
||||
|
||||
public int luaByte(int index) {
|
||||
return m_bytes[m_offset + index] & 0x0FF;
|
||||
}
|
||||
|
||||
public int charAt( int index ) {
|
||||
if ( index < 0 || index >= m_length )
|
||||
throw new IndexOutOfBoundsException();
|
||||
return luaByte( index );
|
||||
}
|
||||
|
||||
public String checkjstring() {
|
||||
return tojstring();
|
||||
}
|
||||
|
||||
public LuaString checkstring() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Convert value to an input stream.
|
||||
*
|
||||
* @return {@link InputStream} whose data matches the bytes in this {@link LuaString}
|
||||
*/
|
||||
public InputStream toInputStream() {
|
||||
return new ByteArrayInputStream(m_bytes, m_offset, m_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param len number of bytes to copy
|
||||
*/
|
||||
public void copyInto( int strOffset, byte[] bytes, int arrayOffset, int len ) {
|
||||
System.arraycopy( m_bytes, m_offset+strOffset, bytes, arrayOffset, len );
|
||||
}
|
||||
|
||||
/** Java version of strpbrk - find index of any byte that in an accept string.
|
||||
* @param accept {@link LuaString} containing characters to look for.
|
||||
* @return index of first match in the {@code accept} string, or -1 if not found.
|
||||
*/
|
||||
public int indexOfAny( LuaString accept ) {
|
||||
final int ilimit = m_offset + m_length;
|
||||
final int jlimit = accept.m_offset + accept.m_length;
|
||||
for ( int i = m_offset; i < ilimit; ++i ) {
|
||||
for ( int j = accept.m_offset; j < jlimit; ++j ) {
|
||||
if ( m_bytes[i] == accept.m_bytes[j] ) {
|
||||
return i - m_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of a byte starting at a point in this string
|
||||
* @param b the byte to look for
|
||||
* @param start the first index in the string
|
||||
* @return index of first match found, or -1 if not found.
|
||||
*/
|
||||
public int indexOf( byte b, int start ) {
|
||||
for ( int i=0, j=m_offset+start; i < m_length; ++i ) {
|
||||
if ( m_bytes[j++] == b )
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of a string starting at a point in this string
|
||||
* @param s the string to search for
|
||||
* @param start the first index in the string
|
||||
* @return index of first match found, or -1 if not found.
|
||||
*/
|
||||
public int indexOf( LuaString s, int start ) {
|
||||
final int slen = s.length();
|
||||
final int limit = m_offset + m_length - slen;
|
||||
for ( int i = m_offset + start; i <= limit; ++i ) {
|
||||
if ( equals( m_bytes, i, s.m_bytes, s.m_offset, slen ) ) {
|
||||
/* DAN200 START */
|
||||
//return i;
|
||||
return i - m_offset;
|
||||
/* DAN200 END */
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the last index of a string in this string
|
||||
* @param s the string to search for
|
||||
* @return index of last match found, or -1 if not found.
|
||||
*/
|
||||
public int lastIndexOf( LuaString s ) {
|
||||
final int slen = s.length();
|
||||
final int limit = m_offset + m_length - slen;
|
||||
for ( int i = limit; i >= m_offset; --i ) {
|
||||
if ( equals( m_bytes, i, s.m_bytes, s.m_offset, slen ) ) {
|
||||
/* DAN200 START */
|
||||
//return i;
|
||||
return i - m_offset;
|
||||
/* DAN200 END */
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @see #lengthAsUtf8(char[])
|
||||
* @see #encodeToUtf8(char[], byte[], int)
|
||||
* @see #isValidUtf8()
|
||||
*/
|
||||
/* DAN200 START */
|
||||
//public static String decodeAsUtf8(byte[] bytes, int offset, int length) {
|
||||
private static String decodeAsUtf8(byte[] bytes, int offset, int length) {
|
||||
/* DAN200 END */
|
||||
int i,j,n,b;
|
||||
for ( i=offset,j=offset+length,n=0; i<j; ++n ) {
|
||||
switch ( 0xE0 & bytes[i++] ) {
|
||||
case 0xE0: ++i;
|
||||
case 0xC0: ++i;
|
||||
}
|
||||
}
|
||||
char[] chars=new char[n];
|
||||
for ( i=offset,j=offset+length,n=0; i<j; ) {
|
||||
chars[n++] = (char) (
|
||||
((b=bytes[i++])>=0||i>=j)? b:
|
||||
(b<-32||i+1>=j)? (((b&0x3f) << 6) | (bytes[i++]&0x3f)):
|
||||
(((b&0xf) << 12) | ((bytes[i++]&0x3f)<<6) | (bytes[i++]&0x3f)));
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of bytes required to encode the string as UTF-8.
|
||||
* @param chars Array of unicode characters to be encoded as UTF-8
|
||||
* @return count of bytes needed to encode using UTF-8
|
||||
* @see #encodeToUtf8(char[], byte[], int)
|
||||
* @see #decodeAsUtf8(byte[], int, int)
|
||||
* @see #isValidUtf8()
|
||||
*/
|
||||
/* DAN200 START */
|
||||
//public static int lengthAsUtf8(char[] chars) {
|
||||
private static int lengthAsUtf8(char[] chars) {
|
||||
/* DAN200 END */
|
||||
int i,b;
|
||||
char c;
|
||||
for ( i=b=chars.length; --i>=0; )
|
||||
if ( (c=chars[i]) >=0x80 )
|
||||
b += (c>=0x800)? 2: 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given Java string as UTF-8 bytes, writing the result to bytes
|
||||
* starting at offset.
|
||||
* <p>
|
||||
* The string should be measured first with lengthAsUtf8
|
||||
* to make sure the given byte array is large enough.
|
||||
* @param chars Array of unicode characters to be encoded as UTF-8
|
||||
* @param bytes byte array to hold the result
|
||||
* @param off offset into the byte array to start writing
|
||||
* @see #lengthAsUtf8(char[])
|
||||
* @see #decodeAsUtf8(byte[], int, int)
|
||||
* @see #isValidUtf8()
|
||||
*/
|
||||
/* DAN200 START */
|
||||
//public static void encodeToUtf8(char[] chars, byte[] bytes, int off) {
|
||||
private static void encodeToUtf8(char[] chars, byte[] bytes, int off) {
|
||||
/* DAN200 END */
|
||||
final int n = chars.length;
|
||||
char c;
|
||||
for ( int i=0, j=off; i<n; i++ ) {
|
||||
if ( (c = chars[i]) < 0x80 ) {
|
||||
bytes[j++] = (byte) c;
|
||||
} else if ( c < 0x800 ) {
|
||||
bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Check that a byte sequence is valid UTF-8
|
||||
* @return true if it is valid UTF-8, otherwise false
|
||||
* @see #lengthAsUtf8(char[])
|
||||
* @see #encodeToUtf8(char[], byte[], int)
|
||||
* @see #decodeAsUtf8(byte[], int, int)
|
||||
*/
|
||||
public boolean isValidUtf8() {
|
||||
int i,j,n,b,e=0;
|
||||
for ( i=m_offset,j=m_offset+m_length,n=0; i<j; ++n ) {
|
||||
int c = m_bytes[i++];
|
||||
if ( c >= 0 ) continue;
|
||||
if ( ((c & 0xE0) == 0xC0)
|
||||
&& i<j
|
||||
&& (m_bytes[i++] & 0xC0) == 0x80) continue;
|
||||
if ( ((c & 0xF0) == 0xE0)
|
||||
&& i+1<j
|
||||
&& (m_bytes[i++] & 0xC0) == 0x80
|
||||
&& (m_bytes[i++] & 0xC0) == 0x80) continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------- number conversion -----------------------
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public LuaValue tonumber( int base ) {
|
||||
double d = scannumber( base );
|
||||
return Double.isNaN(d)? NIL: valueOf(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a number in a base, or return Double.NaN if not a number.
|
||||
* @param base the base to use, such as 10
|
||||
* @return double value if conversion is valid, or Double.NaN if not
|
||||
*/
|
||||
public double scannumber( int base ) {
|
||||
if ( base >= 2 && base <= 36 ) {
|
||||
int i=m_offset,j=m_offset+m_length;
|
||||
while ( i<j && m_bytes[i]==' ' ) ++i;
|
||||
while ( i<j && m_bytes[j-1]==' ' ) --j;
|
||||
if ( i>=j )
|
||||
return Double.NaN;
|
||||
if ( ( base == 10 || base == 16 ) && ( m_bytes[i]=='0' && i+1<j && (m_bytes[i+1]=='x'||m_bytes[i+1]=='X') ) ) {
|
||||
base = 16;
|
||||
i+=2;
|
||||
}
|
||||
double l = scanlong( base, i, j );
|
||||
return Double.isNaN(l) && base==10? scandouble(i,j): l;
|
||||
}
|
||||
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan and convert a long value, or return Double.NaN if not found.
|
||||
* @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,
|
||||
* or Double.NaN if not
|
||||
*/
|
||||
private double scanlong( int base, int start, int end ) {
|
||||
long x = 0;
|
||||
boolean neg = (m_bytes[start] == '-');
|
||||
for ( int i=(neg?start+1:start); i<end; i++ ) {
|
||||
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;
|
||||
x = x * base + digit;
|
||||
}
|
||||
return neg? -x: x;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* or Double.NaN if not
|
||||
*/
|
||||
private double scandouble(int start, int end) {
|
||||
if ( end>start+64 ) end=start+64;
|
||||
for ( int i=start; i<end; i++ ) {
|
||||
switch ( m_bytes[i] ) {
|
||||
case '-':
|
||||
case '+':
|
||||
case '.':
|
||||
case 'e': case 'E':
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
break;
|
||||
default:
|
||||
return Double.NaN;
|
||||
}
|
||||
}
|
||||
char [] c = new char[end-start];
|
||||
for ( int i=start; i<end; i++ )
|
||||
c[i-start] = (char) m_bytes[i];
|
||||
try {
|
||||
return Double.parseDouble(new String(c));
|
||||
} catch ( Exception e ) {
|
||||
return Double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,718 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* 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 #checktable()}, or
|
||||
* {@link #opttable(LuaTable)}
|
||||
* <p>
|
||||
* 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 #rawset(LuaValue,LuaValue)}</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
|
||||
* <pre> {@code
|
||||
* LuaValue k = LuaValue.NIL;
|
||||
* while ( true ) {
|
||||
* Varargs n = table.next(k);
|
||||
* if ( (k = n.arg1()).isnil() )
|
||||
* break;
|
||||
* LuaValue v = n.arg(2)
|
||||
* process( k, v )
|
||||
* }}</pre>
|
||||
*
|
||||
* <p>
|
||||
* 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>
|
||||
* <li>{@link LuaValue#tableOf(int, int)} table with capacity</li>
|
||||
* <li>{@link LuaValue#listOf(LuaValue[])} initialize array part</li>
|
||||
* <li>{@link LuaValue#listOf(LuaValue[], Varargs)} initialize array part</li>
|
||||
* <li>{@link LuaValue#tableOf(LuaValue[])} initialize named hash part</li>
|
||||
* <li>{@link LuaValue#tableOf(Varargs, int)} initialize named hash part</li>
|
||||
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[])} initialize array and named parts</li>
|
||||
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], Varargs)} initialize array and named parts</li>
|
||||
* </ul>
|
||||
* @see LuaValue
|
||||
*/
|
||||
public class LuaTable extends LuaValue {
|
||||
private static final int MIN_HASH_CAPACITY = 2;
|
||||
private static final LuaString N = valueOf("n");
|
||||
|
||||
/** the array values */
|
||||
protected LuaValue[] array;
|
||||
|
||||
/** the hash keys */
|
||||
protected LuaValue[] hashKeys;
|
||||
|
||||
/** the hash values */
|
||||
protected LuaValue[] hashValues;
|
||||
|
||||
/** the number of hash entries */
|
||||
protected int hashEntries;
|
||||
|
||||
/** metatable for this table, or null */
|
||||
protected LuaValue m_metatable;
|
||||
|
||||
/** Construct empty table */
|
||||
public LuaTable() {
|
||||
array = NOVALS;
|
||||
hashKeys = NOVALS;
|
||||
hashValues = NOVALS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct table with preset capacity.
|
||||
* @param narray capacity of array part
|
||||
* @param nhash capacity of hash part
|
||||
*/
|
||||
public LuaTable(int narray, int nhash) {
|
||||
presize(narray, nhash);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 lastarg Additional unnamed values beyond {@code unnamed.length}
|
||||
*/
|
||||
public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) {
|
||||
int nn = (named!=null? named.length: 0);
|
||||
int nu = (unnamed!=null? unnamed.length: 0);
|
||||
int nl = (lastarg!=null? lastarg.narg(): 0);
|
||||
presize(nu+nl, nn-(nn>>1));
|
||||
for ( int i=0; i<nu; i++ )
|
||||
rawset(i+1,unnamed[i]);
|
||||
if ( lastarg != null )
|
||||
for ( int i=1,n=lastarg.narg(); i<=n; ++i )
|
||||
rawset(nu+i,lastarg.arg(i));
|
||||
for ( int i=0; i<nn; i+=2 )
|
||||
if (!named[i+1].isnil())
|
||||
rawset(named[i], named[i+1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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
|
||||
*/
|
||||
public LuaTable(Varargs varargs, int firstarg) {
|
||||
int nskip = firstarg-1;
|
||||
int n = Math.max(varargs.narg()-nskip,0);
|
||||
presize( n, 1 );
|
||||
set(N, valueOf(n));
|
||||
for ( int i=1; i<=n; i++ )
|
||||
set(i, varargs.arg(i+nskip));
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TTABLE;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "table";
|
||||
}
|
||||
|
||||
public boolean istable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaTable checktable() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaTable opttable(LuaTable defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void presize( int narray ) {
|
||||
if ( narray > array.length )
|
||||
array = resize( array, narray );
|
||||
}
|
||||
|
||||
public void presize(int narray, int nhash) {
|
||||
if ( nhash > 0 && nhash < MIN_HASH_CAPACITY )
|
||||
nhash = MIN_HASH_CAPACITY;
|
||||
array = (narray>0? new LuaValue[narray]: NOVALS);
|
||||
hashKeys = (nhash>0? new LuaValue[nhash]: NOVALS);
|
||||
hashValues = (nhash>0? new LuaValue[nhash]: NOVALS);
|
||||
hashEntries = 0;
|
||||
}
|
||||
|
||||
/** Resize the table */
|
||||
private static LuaValue[] resize( LuaValue[] old, int n ) {
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
System.arraycopy(old, 0, v, 0, old.length);
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
protected int getHashLength() {
|
||||
return hashValues.length;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return m_metatable;
|
||||
}
|
||||
|
||||
public LuaValue setmetatable(LuaValue metatable) {
|
||||
m_metatable = metatable;
|
||||
LuaValue mode;
|
||||
if ( m_metatable!=null && (mode=m_metatable.rawget(MODE)).isstring() ) {
|
||||
String m = mode.tojstring();
|
||||
boolean k = m.indexOf('k')>=0;
|
||||
boolean v = m.indexOf('v')>=0;
|
||||
return changemode(k,v);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the mode of a table
|
||||
* @param weakkeys true to make the table have weak keys going forward
|
||||
* @param weakvalues true to make the table have weak values going forward
|
||||
* @return {@code this} or a new {@link WeakTable} if the mode change requires copying.
|
||||
*/
|
||||
protected LuaTable changemode(boolean weakkeys, boolean weakvalues) {
|
||||
if ( weakkeys || weakvalues )
|
||||
return new WeakTable(weakkeys, weakvalues, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue get( int key ) {
|
||||
LuaValue v = rawget(key);
|
||||
return v.isnil() && m_metatable!=null? gettable(this,valueOf(key)): v;
|
||||
}
|
||||
|
||||
public LuaValue get( LuaValue key ) {
|
||||
LuaValue v = rawget(key);
|
||||
return v.isnil() && m_metatable!=null? gettable(this,key): v;
|
||||
}
|
||||
|
||||
public LuaValue rawget( int key ) {
|
||||
if ( key>0 && key<=array.length )
|
||||
return array[key-1]!=null? array[key-1]: NIL;
|
||||
return hashget( LuaInteger.valueOf(key) );
|
||||
}
|
||||
|
||||
public LuaValue rawget( LuaValue key ) {
|
||||
if ( key.isinttype() ) {
|
||||
int ikey = key.toint();
|
||||
if ( ikey>0 && ikey<=array.length )
|
||||
return array[ikey-1]!=null? array[ikey-1]: NIL;
|
||||
}
|
||||
return hashget( key );
|
||||
}
|
||||
|
||||
protected LuaValue hashget(LuaValue key) {
|
||||
if ( hashEntries > 0 ) {
|
||||
LuaValue v = hashValues[hashFindSlot(key)];
|
||||
return v!=null? v: NIL;
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
public void set( int key, LuaValue value ) {
|
||||
if ( m_metatable==null || ! rawget(key).isnil() || ! settable(this,LuaInteger.valueOf(key),value) )
|
||||
rawset(key, value);
|
||||
}
|
||||
|
||||
/** caller must ensure key is not nil */
|
||||
public void set( LuaValue key, LuaValue value ) {
|
||||
key.checkvalidkey();
|
||||
if ( m_metatable==null || ! rawget(key).isnil() || ! settable(this,key,value) )
|
||||
rawset(key, value);
|
||||
}
|
||||
|
||||
public void rawset( int key, LuaValue value ) {
|
||||
if ( ! arrayset(key, value) )
|
||||
hashset( LuaInteger.valueOf(key), value );
|
||||
}
|
||||
|
||||
/** caller must ensure key is not nil */
|
||||
public void rawset( LuaValue key, LuaValue value ) {
|
||||
if ( !key.isinttype() || !arrayset(key.toint(), value) )
|
||||
hashset( key, value );
|
||||
}
|
||||
|
||||
/** Set an array element */
|
||||
private boolean arrayset( int key, LuaValue value ) {
|
||||
if ( key>0 && key<=array.length ) {
|
||||
array[key-1] = (value.isnil()? null: value);
|
||||
return true;
|
||||
} else if ( key==array.length+1 && !value.isnil() ) {
|
||||
expandarray();
|
||||
array[key-1] = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Expand the array part */
|
||||
private void expandarray() {
|
||||
int n = array.length;
|
||||
int m = Math.max(2,n*2);
|
||||
array = resize(array, m);
|
||||
for ( int i=n; i<m; i++ ) {
|
||||
LuaValue k = LuaInteger.valueOf(i+1);
|
||||
LuaValue v = hashget(k);
|
||||
if ( !v.isnil() ) {
|
||||
hashset(k, NIL);
|
||||
array[i] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 = length();
|
||||
if ( pos == 0 )
|
||||
pos = n;
|
||||
else if (pos > n)
|
||||
return NONE;
|
||||
LuaValue v = rawget(pos);
|
||||
for ( LuaValue r=v; !r.isnil(); ) {
|
||||
r = rawget(pos+1);
|
||||
rawset(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 = length()+1;
|
||||
while ( ! value.isnil() ) {
|
||||
LuaValue v = rawget( pos );
|
||||
rawset(pos++, value);
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
|
||||
/** Concatenate the contents of a table efficiently, using {@link Buffer}
|
||||
*
|
||||
* @param sep {@link LuaString} separater to apply between elements
|
||||
* @param i the first element index
|
||||
* @param j the last element index, inclusive
|
||||
* @return {@link LuaString} value of the concatenation
|
||||
*/
|
||||
public LuaValue concat(LuaString sep, int i, int j) {
|
||||
Buffer sb = new Buffer ();
|
||||
if ( i<=j ) {
|
||||
sb.append( get(i).checkstring() );
|
||||
while ( ++i<=j ) {
|
||||
sb.append( sep );
|
||||
sb.append( get(i).checkstring() );
|
||||
}
|
||||
}
|
||||
return sb.tostring();
|
||||
}
|
||||
|
||||
public LuaValue getn() {
|
||||
for ( int n=getArrayLength(); n>0; --n )
|
||||
if ( !rawget(n).isnil() )
|
||||
return LuaInteger.valueOf(n);
|
||||
return ZERO;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
int a = getArrayLength();
|
||||
int n = a+1,m=0;
|
||||
while ( !rawget(n).isnil() ) {
|
||||
m = n;
|
||||
n += a+getHashLength()+1;
|
||||
}
|
||||
while ( n > m+1 ) {
|
||||
int k = (n+m) / 2;
|
||||
if ( !rawget(k).isnil() )
|
||||
m = k;
|
||||
else
|
||||
n = k;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public LuaValue len() {
|
||||
return LuaInteger.valueOf(length());
|
||||
}
|
||||
|
||||
/** Return table.maxn() as defined by lua 5.0.
|
||||
* <p>
|
||||
* Provided for compatibility, not a scalable operation.
|
||||
* @return value for maxn
|
||||
*/
|
||||
public int maxn() {
|
||||
int n = 0;
|
||||
for ( int i=0; i<array.length; i++ )
|
||||
if ( array[i] != null )
|
||||
n = i+1;
|
||||
for ( int i=0; i<hashKeys.length; i++ ) {
|
||||
LuaValue v = hashKeys[i];
|
||||
if ( v!=null && v.isinttype() ) {
|
||||
int key = v.toint();
|
||||
if ( key > n )
|
||||
n = key;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next element after a particular key in the table
|
||||
* @return key,value or nil
|
||||
*/
|
||||
public Varargs next( LuaValue key ) {
|
||||
int i = 0;
|
||||
do {
|
||||
// find current key index
|
||||
if ( ! key.isnil() ) {
|
||||
if ( key.isinttype() ) {
|
||||
i = key.toint();
|
||||
if ( i>0 && i<=array.length ) {
|
||||
if ( array[i-1] == null )
|
||||
error( "invalid key to 'next'" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( hashKeys.length == 0 )
|
||||
error( "invalid key to 'next'" );
|
||||
i = hashFindSlot(key);
|
||||
if ( hashKeys[i] == null )
|
||||
error( "invalid key to 'next'" );
|
||||
i += 1+array.length;
|
||||
}
|
||||
} while ( false );
|
||||
|
||||
// check array part
|
||||
for ( ; i<array.length; ++i )
|
||||
if ( array[i] != null )
|
||||
return varargsOf(LuaInteger.valueOf(i+1),array[i]);
|
||||
|
||||
// check hash part
|
||||
for ( i-=array.length; i<hashKeys.length; ++i )
|
||||
if ( hashKeys[i] != null )
|
||||
return varargsOf(hashKeys[i],hashValues[i]);
|
||||
|
||||
// nothing found, push nil, return nil.
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
int k = key.checkint() + 1;
|
||||
LuaValue v = rawget(k);
|
||||
return v.isnil()? NONE: varargsOf(LuaInteger.valueOf(k),v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the supplied function once for each key-value pair
|
||||
*
|
||||
* @param func function to call
|
||||
*/
|
||||
public LuaValue foreach(LuaValue func) {
|
||||
Varargs n;
|
||||
LuaValue k = NIL;
|
||||
LuaValue v;
|
||||
while ( !(k = ((n = next(k)).arg1())).isnil() )
|
||||
if ( ! (v = func.call(k, n.arg(2))).isnil() )
|
||||
return v;
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the supplied function once for each key-value pair
|
||||
* in the contiguous array part
|
||||
*
|
||||
* @param func
|
||||
*/
|
||||
public LuaValue foreachi(LuaValue func) {
|
||||
LuaValue v,r;
|
||||
for ( int k=0; !(v = rawget(++k)).isnil(); )
|
||||
if ( ! (r = func.call(valueOf(k), v)).isnil() )
|
||||
return r;
|
||||
return NIL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a hashtable value
|
||||
* @param key key to set
|
||||
* @param value value to set
|
||||
*/
|
||||
public void hashset(LuaValue key, LuaValue value) {
|
||||
if ( value.isnil() )
|
||||
hashRemove(key);
|
||||
else {
|
||||
if ( hashKeys.length == 0 ) {
|
||||
hashKeys = new LuaValue[ MIN_HASH_CAPACITY ];
|
||||
hashValues = new LuaValue[ MIN_HASH_CAPACITY ];
|
||||
}
|
||||
int slot = hashFindSlot( key );
|
||||
if ( hashFillSlot( slot, value ) )
|
||||
return;
|
||||
hashKeys[slot] = key;
|
||||
hashValues[slot] = value;
|
||||
if ( checkLoadFactor() )
|
||||
rehash();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the hashtable slot to use
|
||||
* @param key key to look for
|
||||
* @return slot to use
|
||||
*/
|
||||
public int hashFindSlot(LuaValue key) {
|
||||
int i = ( key.hashCode() & 0x7FFFFFFF ) % hashKeys.length;
|
||||
|
||||
// This loop is guaranteed to terminate as long as we never allow the
|
||||
// table to get 100% full.
|
||||
LuaValue k;
|
||||
while ( ( k = hashKeys[i] ) != null && !k.raweq(key) ) {
|
||||
i = ( i + 1 ) % hashKeys.length;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private boolean hashFillSlot( int slot, LuaValue value ) {
|
||||
hashValues[ slot ] = value;
|
||||
if ( hashKeys[ slot ] != null ) {
|
||||
return true;
|
||||
} else {
|
||||
++hashEntries;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void hashRemove( LuaValue key ) {
|
||||
if ( hashKeys.length > 0 ) {
|
||||
int slot = hashFindSlot( key );
|
||||
hashClearSlot( slot );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a particular slot in the table
|
||||
* @param i slot to clear.
|
||||
*/
|
||||
protected void hashClearSlot( int i ) {
|
||||
if ( hashKeys[ i ] != null ) {
|
||||
|
||||
int j = i;
|
||||
int n = hashKeys.length;
|
||||
while ( hashKeys[ j = ( ( j + 1 ) % n ) ] != null ) {
|
||||
final int k = ( ( hashKeys[ j ].hashCode() )& 0x7FFFFFFF ) % n;
|
||||
if ( ( j > i && ( k <= i || k > j ) ) ||
|
||||
( j < i && ( k <= i && k > j ) ) ) {
|
||||
hashKeys[ i ] = hashKeys[ j ];
|
||||
hashValues[ i ] = hashValues[ j ];
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
--hashEntries;
|
||||
hashKeys[ i ] = null;
|
||||
hashValues[ i ] = null;
|
||||
|
||||
if ( hashEntries == 0 ) {
|
||||
hashKeys = NOVALS;
|
||||
hashValues = NOVALS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkLoadFactor() {
|
||||
// Using a load factor of (n+1) >= 7/8 because that is easy to compute without
|
||||
// overflow or division.
|
||||
final int hashCapacity = hashKeys.length;
|
||||
return hashEntries >= (hashCapacity - (hashCapacity>>3));
|
||||
}
|
||||
|
||||
private void rehash() {
|
||||
final int oldCapacity = hashKeys.length;
|
||||
final int newCapacity = oldCapacity+(oldCapacity>>2)+MIN_HASH_CAPACITY;
|
||||
|
||||
final LuaValue[] oldKeys = hashKeys;
|
||||
final LuaValue[] oldValues = hashValues;
|
||||
|
||||
hashKeys = new LuaValue[ newCapacity ];
|
||||
hashValues = new LuaValue[ newCapacity ];
|
||||
|
||||
for ( int i = 0; i < oldCapacity; ++i ) {
|
||||
final LuaValue k = oldKeys[i];
|
||||
if ( k != null ) {
|
||||
final LuaValue v = oldValues[i];
|
||||
final int slot = hashFindSlot( k );
|
||||
hashKeys[slot] = k;
|
||||
hashValues[slot] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------- sort support -----------------------------
|
||||
//
|
||||
// implemented heap sort from wikipedia
|
||||
//
|
||||
// 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) {
|
||||
int n = array.length;
|
||||
while ( n > 0 && array[n-1] == null )
|
||||
--n;
|
||||
if ( n > 1 )
|
||||
heapSort(n, 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);
|
||||
}
|
||||
}
|
||||
|
||||
private void heapify(int count, LuaValue cmpfunc) {
|
||||
for ( int start=count/2-1; start>=0; --start )
|
||||
siftDown(start, count - 1, cmpfunc);
|
||||
}
|
||||
|
||||
private void siftDown(int start, int end, LuaValue cmpfunc) {
|
||||
for ( int root=start; root*2+1 <= end; ) {
|
||||
int child = root*2+1;
|
||||
if (child < end && compare(child, child + 1, cmpfunc))
|
||||
++child;
|
||||
if (compare(root, child, cmpfunc)) {
|
||||
swap(root, child);
|
||||
root = child;
|
||||
} else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean compare(int i, int j, LuaValue cmpfunc) {
|
||||
LuaValue a = array[i];
|
||||
LuaValue b = array[j];
|
||||
if ( a == null || b == null )
|
||||
return false;
|
||||
if ( ! cmpfunc.isnil() ) {
|
||||
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.
|
||||
* It is recommended to count via iteration over next() instead
|
||||
* @return count of keys in the table
|
||||
* */
|
||||
public int keyCount() {
|
||||
LuaValue k = LuaValue.NIL;
|
||||
for ( int i=0; true; i++ ) {
|
||||
Varargs n = next(k);
|
||||
if ( (k = n.arg1()).isnil() )
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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();
|
||||
LuaValue k = LuaValue.NIL;
|
||||
while ( true ) {
|
||||
Varargs n = next(k);
|
||||
if ( (k = n.arg1()).isnil() )
|
||||
break;
|
||||
l.addElement( k );
|
||||
}
|
||||
LuaValue[] a = new LuaValue[l.size()];
|
||||
l.copyInto(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
// equality w/ metatable processing
|
||||
public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; }
|
||||
public boolean eq_b( LuaValue val ) {
|
||||
if ( this == val ) return true;
|
||||
if ( m_metatable == null || !val.istable() ) return false;
|
||||
LuaValue valmt = val.getmetatable();
|
||||
return valmt!=null && LuaValue.eqmtcall(this, m_metatable, val, valmt);
|
||||
}
|
||||
}
|
@ -1,433 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007-2012 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
|
||||
/* DAN200 START */
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
/* DAN200 END */
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LuaValue} that implements
|
||||
* a lua coroutine thread using Java Threads.
|
||||
* <p>
|
||||
* A LuaThread is typically created in response to a scripted call to
|
||||
* {@code coroutine.create()}
|
||||
* <p>
|
||||
* The threads must be initialized with the globals, so that
|
||||
* the global environment may be passed along according to rules of lua.
|
||||
* This is done via a call to {@link #setGlobals(LuaValue)}
|
||||
* at some point during globals initialization.
|
||||
* See {@link BaseLib} for additional documentation and example code.
|
||||
* <p>
|
||||
* The utility classes {@link JsePlatform} and {@link JmePlatform}
|
||||
* see to it that this initialization is done properly.
|
||||
* For this reason it is highly recommended to use one of these classes
|
||||
* when initializing globals.
|
||||
* <p>
|
||||
* The behavior of coroutine threads matches closely the behavior
|
||||
* of C coroutine library. However, because of the use of Java threads
|
||||
* to manage call state, it is possible to yield from anywhere in luaj.
|
||||
* <p>
|
||||
* Each Java thread wakes up at regular intervals and checks a weak reference
|
||||
* to determine if it can ever be resumed. If not, it throws
|
||||
* {@link OrphanedThread} which is an {@link java.lang.Error}.
|
||||
* Applications should not catch {@link OrphanedThread}, because it can break
|
||||
* the thread safety of luaj.
|
||||
*
|
||||
* @see LuaValue
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see CoroutineLib
|
||||
*/
|
||||
public class LuaThread extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
public static int coroutine_count = 0;
|
||||
|
||||
/** Interval at which to check for lua threads that are no longer referenced.
|
||||
* This can be changed by Java startup code if desired.
|
||||
*/
|
||||
static long thread_orphan_check_interval = 30000;
|
||||
|
||||
private static final int STATUS_INITIAL = 0;
|
||||
private static final int STATUS_SUSPENDED = 1;
|
||||
private static final int STATUS_RUNNING = 2;
|
||||
private static final int STATUS_NORMAL = 3;
|
||||
private static final int STATUS_DEAD = 4;
|
||||
private static final String[] STATUS_NAMES = {
|
||||
"suspended",
|
||||
"suspended",
|
||||
"running",
|
||||
"normal",
|
||||
"dead",};
|
||||
|
||||
private LuaValue env;
|
||||
private final State state;
|
||||
|
||||
/** Field to hold state of error condition during debug hook function calls. */
|
||||
public LuaValue err;
|
||||
|
||||
final CallStack callstack = new CallStack();
|
||||
|
||||
public static final int MAX_CALLSTACK = 256;
|
||||
|
||||
private static final LuaThread main_thread = new LuaThread();
|
||||
|
||||
// state of running thread including call stack
|
||||
private static LuaThread running_thread = main_thread;
|
||||
|
||||
/** Interval to check for LuaThread dereferencing. */
|
||||
public static int GC_INTERVAL = 30000;
|
||||
|
||||
/** Thread-local used by DebugLib to store debugging state. */
|
||||
public Object debugState;
|
||||
|
||||
/* DAN200 START */
|
||||
private Vector children = new Vector();
|
||||
/* DAN200 END */
|
||||
|
||||
/** Private constructor for main thread only */
|
||||
private LuaThread() {
|
||||
state = new State(this, null);
|
||||
state.status = STATUS_RUNNING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a LuaThread around a function and environment
|
||||
* @param func The function to execute
|
||||
* @param env The environment to apply to the thread
|
||||
*/
|
||||
public LuaThread(LuaValue func, LuaValue env) {
|
||||
LuaValue.assert_(func != null, "function cannot be null");
|
||||
this.env = env;
|
||||
state = new State(this, func);
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TTHREAD;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "thread";
|
||||
}
|
||||
|
||||
public boolean isthread() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public LuaThread optthread(LuaThread defval) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaThread checkthread() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
|
||||
public LuaValue getfenv() {
|
||||
return env;
|
||||
}
|
||||
|
||||
public void setfenv(LuaValue env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return STATUS_NAMES[state.status];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently running thread.
|
||||
* @return {@link LuaThread} that is currenly running
|
||||
*/
|
||||
public static LuaThread getRunning() {
|
||||
return running_thread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this is the main thread
|
||||
* @return true if this is the main thread
|
||||
*/
|
||||
public static boolean isMainThread(LuaThread r) {
|
||||
return r == main_thread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the globals of the current thread.
|
||||
* <p>
|
||||
* This must be done once before any other code executes.
|
||||
* @param globals The global variables for the main ghread.
|
||||
*/
|
||||
public static void setGlobals(LuaValue globals) {
|
||||
running_thread.env = globals;
|
||||
}
|
||||
|
||||
/** Get the current thread's environment
|
||||
* @return {@link LuaValue} containing the global variables of the current thread.
|
||||
*/
|
||||
public static LuaValue getGlobals() {
|
||||
LuaValue e = running_thread.env;
|
||||
return e!=null? e: LuaValue.error("LuaThread.setGlobals() not initialized");
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback used at the beginning of a call to prepare for possible getfenv/setfenv calls
|
||||
* @param function Function being called
|
||||
* @return CallStack which is used to signal the return or a tail-call recursion
|
||||
* @see DebugLib
|
||||
*/
|
||||
public static final CallStack onCall(LuaFunction function) {
|
||||
CallStack cs = running_thread.callstack;
|
||||
cs.onCall(function);
|
||||
return cs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the function called as a specific location on the stack.
|
||||
* @param level 1 for the function calling this one, 2 for the next one.
|
||||
* @return LuaFunction on the call stack, or null if outside of range of active stack
|
||||
*/
|
||||
public static final LuaFunction getCallstackFunction(int level) {
|
||||
return running_thread.callstack.getFunction(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the error function of the currently running thread.
|
||||
* @param errfunc the new error function to use.
|
||||
* @return the previous error function.
|
||||
*/
|
||||
public static LuaValue setErrorFunc(LuaValue errfunc) {
|
||||
LuaValue prev = running_thread.err;
|
||||
running_thread.err = errfunc;
|
||||
return prev;
|
||||
}
|
||||
|
||||
/** Yield the current thread with arguments
|
||||
*
|
||||
* @param args The arguments to send as return values to {@link #resume(Varargs)}
|
||||
* @return {@link Varargs} provided as arguments to {@link #resume(Varargs)}
|
||||
*/
|
||||
public static Varargs yield(Varargs args) {
|
||||
State s = running_thread.state;
|
||||
if (s.function == null)
|
||||
throw new LuaError("cannot yield main thread");
|
||||
return s.lua_yield(args);
|
||||
}
|
||||
|
||||
/** Start or resume this thread
|
||||
*
|
||||
* @param args The arguments to send as return values to {@link #yield(Varargs)}
|
||||
* @return {@link Varargs} provided as arguments to {@link #yield(Varargs)}
|
||||
*/
|
||||
public Varargs resume(Varargs args) {
|
||||
if (this.state.status > STATUS_SUSPENDED)
|
||||
return LuaValue.varargsOf(LuaValue.FALSE,
|
||||
LuaValue.valueOf("cannot resume "+LuaThread.STATUS_NAMES[this.state.status]+" coroutine"));
|
||||
return state.lua_resume(this, args);
|
||||
}
|
||||
|
||||
/* DAN200 START */
|
||||
public void addChild( LuaThread thread ) {
|
||||
this.children.addElement( new WeakReference( thread ) );
|
||||
}
|
||||
|
||||
public Varargs abandon() {
|
||||
if( this.state.status > STATUS_SUSPENDED ) {
|
||||
return LuaValue.varargsOf( LuaValue.FALSE, LuaValue.valueOf( "cannot abandon " + STATUS_NAMES[this.state.status] + " coroutine" ) );
|
||||
} else {
|
||||
this.state.lua_abandon( this );
|
||||
|
||||
Enumeration it = this.children.elements();
|
||||
while( it.hasMoreElements() ) {
|
||||
WeakReference ref = (WeakReference)it.nextElement();
|
||||
LuaThread thread = (LuaThread)ref.get();
|
||||
if(thread != null && !thread.getStatus().equals("dead")) {
|
||||
thread.abandon();
|
||||
}
|
||||
}
|
||||
|
||||
this.children.removeAllElements();
|
||||
return LuaValue.varargsOf( new LuaValue[] { LuaValue.TRUE } );
|
||||
}
|
||||
}
|
||||
/* DAN200 END */
|
||||
|
||||
static class State implements Runnable {
|
||||
final WeakReference lua_thread;
|
||||
final LuaValue function;
|
||||
Varargs args = LuaValue.NONE;
|
||||
Varargs result = LuaValue.NONE;
|
||||
String error = null;
|
||||
int status = LuaThread.STATUS_INITIAL;
|
||||
/* DAN200 START */
|
||||
boolean abandoned = false;
|
||||
/* DAN200 END */
|
||||
|
||||
State(LuaThread lua_thread, LuaValue function) {
|
||||
this.lua_thread = new WeakReference(lua_thread);
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
public synchronized void run() {
|
||||
try {
|
||||
Varargs a = this.args;
|
||||
this.args = LuaValue.NONE;
|
||||
this.result = function.invoke(a);
|
||||
} catch (Throwable t) {
|
||||
this.error = t.getMessage();
|
||||
} finally {
|
||||
this.status = LuaThread.STATUS_DEAD;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
synchronized Varargs lua_resume(LuaThread new_thread, Varargs args) {
|
||||
LuaThread previous_thread = LuaThread.running_thread;
|
||||
try {
|
||||
LuaThread.running_thread = new_thread;
|
||||
this.args = args;
|
||||
if (this.status == STATUS_INITIAL) {
|
||||
this.status = STATUS_RUNNING;
|
||||
new Thread(this, "Coroutine-"+(++coroutine_count)).start();
|
||||
} else {
|
||||
this.notify();
|
||||
}
|
||||
previous_thread.state.status = STATUS_NORMAL;
|
||||
this.status = STATUS_RUNNING;
|
||||
this.wait();
|
||||
return (this.error != null?
|
||||
LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(this.error)):
|
||||
LuaValue.varargsOf(LuaValue.TRUE, this.result));
|
||||
} catch (InterruptedException ie) {
|
||||
throw new OrphanedThread();
|
||||
} finally {
|
||||
running_thread = previous_thread;
|
||||
running_thread.state.status =STATUS_RUNNING;
|
||||
this.args = LuaValue.NONE;
|
||||
this.result = LuaValue.NONE;
|
||||
this.error = null;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized Varargs lua_yield(Varargs args) {
|
||||
try {
|
||||
this.result = args;
|
||||
this.status = STATUS_SUSPENDED;
|
||||
this.notify();
|
||||
do {
|
||||
this.wait(thread_orphan_check_interval);
|
||||
/* DAN200 START */
|
||||
//if (this.lua_thread.get() == null) {
|
||||
if( this.abandoned || this.lua_thread.get() == null ) {
|
||||
/* DAN200 END */
|
||||
this.status = STATUS_DEAD;
|
||||
throw new OrphanedThread();
|
||||
}
|
||||
} while (this.status == STATUS_SUSPENDED);
|
||||
return this.args;
|
||||
} catch (InterruptedException ie) {
|
||||
this.status = STATUS_DEAD;
|
||||
throw new OrphanedThread();
|
||||
} finally {
|
||||
this.args = LuaValue.NONE;
|
||||
this.result = LuaValue.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* DAN200 START */
|
||||
synchronized void lua_abandon(LuaThread thread) {
|
||||
LuaThread current = LuaThread.running_thread;
|
||||
|
||||
try {
|
||||
current.state.status = STATUS_NORMAL;
|
||||
this.abandoned = true;
|
||||
if(this.status == STATUS_INITIAL) {
|
||||
this.status = STATUS_DEAD;
|
||||
} else {
|
||||
this.notify();
|
||||
this.wait();
|
||||
}
|
||||
} catch (InterruptedException var7) {
|
||||
this.status = STATUS_DEAD;
|
||||
} finally {
|
||||
current.state.status = STATUS_RUNNING;
|
||||
this.args = LuaValue.NONE;
|
||||
this.result = LuaValue.NONE;
|
||||
this.error = null;
|
||||
}
|
||||
}
|
||||
/* DAN200 END */
|
||||
}
|
||||
|
||||
public static class CallStack {
|
||||
final LuaFunction[] functions = new LuaFunction[MAX_CALLSTACK];
|
||||
int calls = 0;
|
||||
|
||||
/**
|
||||
* Method to indicate the start of a call
|
||||
* @see DebugLib
|
||||
*/
|
||||
final void onCall(LuaFunction function) {
|
||||
functions[calls++] = function;
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugOnCall(running_thread, calls, function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to signal the end of a call
|
||||
* @see DebugLib
|
||||
*/
|
||||
public final void onReturn() {
|
||||
functions[--calls] = null;
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugOnReturn(running_thread, calls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of calls in stack
|
||||
* @return number of calls in current call stack
|
||||
* @see DebugLib
|
||||
*/
|
||||
public final int getCallstackDepth() {
|
||||
return calls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the function at a particular level of the stack.
|
||||
* @param level # of levels back from the top of the stack.
|
||||
* @return LuaFunction, or null if beyond the stack limits.
|
||||
*/
|
||||
LuaFunction getFunction(int level) {
|
||||
return level>0 && level<=calls? functions[calls-level]: null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
public class LuaUserdata extends LuaValue {
|
||||
|
||||
public final Object m_instance;
|
||||
public LuaValue m_metatable;
|
||||
|
||||
public LuaUserdata(Object obj) {
|
||||
m_instance = obj;
|
||||
}
|
||||
|
||||
public LuaUserdata(Object obj, LuaValue metatable) {
|
||||
m_instance = obj;
|
||||
m_metatable = metatable;
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return String.valueOf(m_instance);
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TUSERDATA;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "userdata";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return m_instance.hashCode();
|
||||
}
|
||||
|
||||
public Object userdata() {
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
public boolean isuserdata() { return true; }
|
||||
public boolean isuserdata(Class c) { return c.isAssignableFrom(m_instance.getClass()); }
|
||||
public Object touserdata() { return m_instance; }
|
||||
public Object touserdata(Class c) { return c.isAssignableFrom(m_instance.getClass())? m_instance: null; }
|
||||
public Object optuserdata(Object defval) { return m_instance; }
|
||||
public Object optuserdata(Class c, Object defval) {
|
||||
if (!c.isAssignableFrom(m_instance.getClass()))
|
||||
typerror(c.getName());
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return m_metatable;
|
||||
}
|
||||
|
||||
public LuaValue setmetatable(LuaValue metatable) {
|
||||
this.m_metatable = metatable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object checkuserdata() {
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
public Object checkuserdata(Class c) {
|
||||
if ( c.isAssignableFrom(m_instance.getClass()) )
|
||||
return m_instance;
|
||||
return typerror(c.getName());
|
||||
}
|
||||
|
||||
public LuaValue get( LuaValue key ) {
|
||||
return m_metatable!=null? gettable(this,key): NIL;
|
||||
}
|
||||
|
||||
public void set( LuaValue key, LuaValue value ) {
|
||||
if ( m_metatable==null || ! settable(this,key,value) )
|
||||
error( "cannot set "+key+" for userdata" );
|
||||
}
|
||||
|
||||
public boolean equals( Object val ) {
|
||||
if ( this == val )
|
||||
return true;
|
||||
if ( ! (val instanceof LuaUserdata) )
|
||||
return false;
|
||||
LuaUserdata u = (LuaUserdata) val;
|
||||
return m_instance.equals(u.m_instance);
|
||||
}
|
||||
|
||||
// equality w/ metatable processing
|
||||
public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; }
|
||||
public boolean eq_b( LuaValue val ) {
|
||||
if ( val.raweq(this) ) return true;
|
||||
if ( m_metatable == null || !val.isuserdata() ) return false;
|
||||
LuaValue valmt = val.getmetatable();
|
||||
return valmt!=null && LuaValue.eqmtcall(this, m_metatable, val, valmt);
|
||||
}
|
||||
|
||||
// equality w/o metatable processing
|
||||
public boolean raweq( LuaValue val ) { return val.raweq(this); }
|
||||
public boolean raweq( LuaUserdata val ) {
|
||||
return this == val || (m_metatable == val.m_metatable && m_instance.equals(val.m_instance));
|
||||
}
|
||||
|
||||
// __eq metatag processing
|
||||
public boolean eqmt( LuaValue val ) {
|
||||
return m_metatable!=null && val.isuserdata()? LuaValue.eqmtcall(this, m_metatable, val, val.getmetatable()): false;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,44 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012 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;
|
||||
|
||||
/**
|
||||
* {@link java.lang.Error} sublcass that indicates a lua thread that is no
|
||||
* longer referenced has been detected.
|
||||
* <p>
|
||||
* The java thread in which this is thrown should correspond to a
|
||||
* {@link LuaThread} being used as a coroutine that could not possibly be
|
||||
* resumed again because there are no more references to the LuaThread with
|
||||
* which it is associated. Rather than locking up resources forever, this error
|
||||
* is thrown, and should fall through all the way to the thread's {@link Thread.run}() method.
|
||||
* <p>
|
||||
* Java code mixed with the luaj vm should not catch this error because it may
|
||||
* occur when the coroutine is not running, so any processing done during error
|
||||
* handling could break the thread-safety of the application because other lua
|
||||
* processing could be going on in a different thread.
|
||||
*/
|
||||
public class OrphanedThread extends Error {
|
||||
|
||||
public OrphanedThread() {
|
||||
super("orphaned thread");
|
||||
}
|
||||
}
|
@ -1,417 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
/**
|
||||
* Debug helper class to pretty-print lua bytecodes.
|
||||
* @see Prototype
|
||||
* @see LuaClosure
|
||||
*/
|
||||
public class Print extends Lua {
|
||||
|
||||
/** opcode names */
|
||||
private static final String STRING_FOR_NULL = "null";
|
||||
public static PrintStream ps = System.out;
|
||||
|
||||
public static final String[] OPNAMES = {
|
||||
"MOVE",
|
||||
"LOADK",
|
||||
"LOADBOOL",
|
||||
"LOADNIL",
|
||||
"GETUPVAL",
|
||||
"GETGLOBAL",
|
||||
"GETTABLE",
|
||||
"SETGLOBAL",
|
||||
"SETUPVAL",
|
||||
"SETTABLE",
|
||||
"NEWTABLE",
|
||||
"SELF",
|
||||
"ADD",
|
||||
"SUB",
|
||||
"MUL",
|
||||
"DIV",
|
||||
"MOD",
|
||||
"POW",
|
||||
"UNM",
|
||||
"NOT",
|
||||
"LEN",
|
||||
"CONCAT",
|
||||
"JMP",
|
||||
"EQ",
|
||||
"LT",
|
||||
"LE",
|
||||
"TEST",
|
||||
"TESTSET",
|
||||
"CALL",
|
||||
"TAILCALL",
|
||||
"RETURN",
|
||||
"FORLOOP",
|
||||
"FORPREP",
|
||||
"TFORLOOP",
|
||||
"SETLIST",
|
||||
"CLOSE",
|
||||
"CLOSURE",
|
||||
"VARARG",
|
||||
null,
|
||||
};
|
||||
|
||||
|
||||
static void printString(PrintStream ps, final LuaString s) {
|
||||
|
||||
ps.print('"');
|
||||
for (int i = 0, n = s.m_length; i < n; i++) {
|
||||
int c = s.m_bytes[s.m_offset+i];
|
||||
if ( c >= ' ' && c <= '~' && c != '\"' && c != '\\' )
|
||||
ps.print((char) c);
|
||||
else {
|
||||
switch (c) {
|
||||
case '"':
|
||||
ps.print("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
ps.print("\\\\");
|
||||
break;
|
||||
case 0x0007: /* bell */
|
||||
ps.print("\\a");
|
||||
break;
|
||||
case '\b': /* backspace */
|
||||
ps.print("\\b");
|
||||
break;
|
||||
case '\f': /* form feed */
|
||||
ps.print("\\f");
|
||||
break;
|
||||
case '\t': /* tab */
|
||||
ps.print("\\t");
|
||||
break;
|
||||
case '\r': /* carriage return */
|
||||
ps.print("\\r");
|
||||
break;
|
||||
case '\n': /* newline */
|
||||
ps.print("\\n");
|
||||
break;
|
||||
case 0x000B: /* vertical tab */
|
||||
ps.print("\\v");
|
||||
break;
|
||||
default:
|
||||
ps.print('\\');
|
||||
ps.print(Integer.toString(1000 + 0xff&c).substring(1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ps.print('"');
|
||||
}
|
||||
|
||||
static void printValue( PrintStream ps, LuaValue v ) {
|
||||
switch ( v.type() ) {
|
||||
case LuaValue.TSTRING: printString( ps, (LuaString) v ); break;
|
||||
default: ps.print( v.tojstring() );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void printConstant(PrintStream ps, Prototype f, int i) {
|
||||
printValue( ps, f.k[i] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the code in a prototype
|
||||
* @param f the {@link Prototype}
|
||||
*/
|
||||
public static void printCode(Prototype f) {
|
||||
int[] code = f.code;
|
||||
int pc, n = code.length;
|
||||
for (pc = 0; pc < n; pc++) {
|
||||
printOpCode(f, pc);
|
||||
ps.println();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an opcode in a prototype
|
||||
* @param f the {@link Prototype}
|
||||
* @param pc the program counter to look up and print
|
||||
*/
|
||||
public static void printOpCode(Prototype f, int pc) {
|
||||
printOpCode(ps,f,pc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an opcode in a prototype
|
||||
* @param ps the {@link PrintStream} to print to
|
||||
* @param f the {@link Prototype}
|
||||
* @param pc the program counter to look up and print
|
||||
*/
|
||||
public static void printOpCode(PrintStream ps, Prototype f, int pc) {
|
||||
int[] code = f.code;
|
||||
int i = code[pc];
|
||||
int o = GET_OPCODE(i);
|
||||
int a = GETARG_A(i);
|
||||
int b = GETARG_B(i);
|
||||
int c = GETARG_C(i);
|
||||
int bx = GETARG_Bx(i);
|
||||
int sbx = GETARG_sBx(i);
|
||||
int line = getline(f, pc);
|
||||
ps.print(" " + (pc + 1) + " ");
|
||||
if (line > 0)
|
||||
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));
|
||||
}
|
||||
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(" ; ");
|
||||
if ( f.upvalues.length > b )
|
||||
printValue(ps, f.upvalues[b]);
|
||||
else
|
||||
ps.print( "-" );
|
||||
break;
|
||||
case OP_GETGLOBAL:
|
||||
case OP_SETGLOBAL:
|
||||
ps.print(" ; ");
|
||||
printConstant( ps, f, bx );
|
||||
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:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getline(Prototype f, int pc) {
|
||||
return pc>0 && f.lineinfo!=null && pc<f.lineinfo.length? f.lineinfo[pc]: -1;
|
||||
}
|
||||
|
||||
static void printHeader(Prototype f) {
|
||||
String s = String.valueOf(f.source);
|
||||
if (s.startsWith("@") || s.startsWith("="))
|
||||
s = s.substring(1);
|
||||
else if ("\033Lua".equals(s))
|
||||
s = "(bstring)";
|
||||
else
|
||||
s = "(string)";
|
||||
String a = (f.linedefined == 0) ? "main" : "function";
|
||||
ps.print("\n%" + a + " <" + s + ":" + f.linedefined + ","
|
||||
+ f.lastlinedefined + "> (" + f.code.length + " instructions, "
|
||||
+ f.code.length * 4 + " bytes at " + id(f) + ")\n");
|
||||
ps.print(f.numparams + " param, " + f.maxstacksize + " slot, "
|
||||
+ f.upvalues.length + " upvalue, ");
|
||||
ps.print(f.locvars.length + " local, " + f.k.length
|
||||
+ " constant, " + f.p.length + " function\n");
|
||||
}
|
||||
|
||||
static void printConstants(Prototype f) {
|
||||
int i, n = f.k.length;
|
||||
ps.print("constants (" + n + ") for " + id(f) + ":\n");
|
||||
for (i = 0; i < n; i++) {
|
||||
ps.print(" " + (i + 1) + " ");
|
||||
printValue( ps, f.k[i] );
|
||||
ps.print( "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void printLocals(Prototype f) {
|
||||
int i, n = f.locvars.length;
|
||||
ps.print("locals (" + n + ") for " + id(f) + ":\n");
|
||||
for (i = 0; i < n; i++) {
|
||||
ps.println(" "+i+" "+f.locvars[i].varname+" "+(f.locvars[i].startpc+1)+" "+(f.locvars[i].endpc+1));
|
||||
}
|
||||
}
|
||||
|
||||
static void printUpValues(Prototype f) {
|
||||
int i, n = f.upvalues.length;
|
||||
ps.print("upvalues (" + n + ") for " + id(f) + ":\n");
|
||||
for (i = 0; i < n; i++) {
|
||||
ps.print(" " + i + " " + f.upvalues[i] + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
public static void print(Prototype p) {
|
||||
printFunction(p, true);
|
||||
}
|
||||
|
||||
public static void printFunction(Prototype f, boolean full) {
|
||||
int i, n = f.p.length;
|
||||
printHeader(f);
|
||||
printCode(f);
|
||||
if (full) {
|
||||
printConstants(f);
|
||||
printLocals(f);
|
||||
printUpValues(f);
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
printFunction(f.p[i], full);
|
||||
}
|
||||
|
||||
private static void format( String s, int maxcols ) {
|
||||
int n = s.length();
|
||||
if ( n > maxcols )
|
||||
ps.print( s.substring(0,maxcols) );
|
||||
else {
|
||||
ps.print( s );
|
||||
for ( int i=maxcols-n; --i>=0; )
|
||||
ps.print( ' ' );
|
||||
}
|
||||
}
|
||||
|
||||
private static String id(Prototype f) {
|
||||
return "Proto";
|
||||
}
|
||||
private void _assert(boolean b) {
|
||||
if ( !b )
|
||||
throw new NullPointerException("_assert failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the state of a {@link LuaClosure} that is being executed
|
||||
* @param cl the {@link LuaClosure}
|
||||
* @param pc the program counter
|
||||
* @param stack the stack of {@link LuaValue}
|
||||
* @param top the top of the stack
|
||||
* @param varargs any {@link Varargs} value that may apply
|
||||
*/
|
||||
public static void printState(LuaClosure cl, int pc, LuaValue[] stack, int top, Varargs varargs) {
|
||||
// print opcode into buffer
|
||||
PrintStream previous = ps;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ps = new PrintStream( baos );
|
||||
printOpCode( cl.p, pc );
|
||||
ps.flush();
|
||||
ps.close();
|
||||
ps = previous;
|
||||
format( baos.toString(), 50 );
|
||||
|
||||
// print stack
|
||||
ps.print('[');
|
||||
for ( int i=0; i<stack.length; i++ ) {
|
||||
LuaValue v = stack[i];
|
||||
if ( v == null )
|
||||
ps.print(STRING_FOR_NULL);
|
||||
else switch ( v.type() ) {
|
||||
case LuaValue.TSTRING:
|
||||
LuaString s = v.checkstring();
|
||||
ps.print( s.length() < 48?
|
||||
s.tojstring():
|
||||
s.substring(0, 32).tojstring()+"...+"+(s.length()-32)+"b");
|
||||
break;
|
||||
case LuaValue.TFUNCTION:
|
||||
ps.print( ( v instanceof LuaClosure )?
|
||||
((LuaClosure)v).p.toString(): v.tojstring() );
|
||||
break;
|
||||
case LuaValue.TUSERDATA:
|
||||
Object o = v.touserdata();
|
||||
if ( o != null ) {
|
||||
String n = o.getClass().getName();
|
||||
n = n.substring(n.lastIndexOf('.')+1);
|
||||
ps.print( n+": "+Integer.toHexString(o.hashCode()) );
|
||||
} else {
|
||||
ps.print( v.toString() );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ps.print(v.tojstring());
|
||||
}
|
||||
if ( i+1 == top )
|
||||
ps.print(']');
|
||||
ps.print( " | " );
|
||||
}
|
||||
ps.print(varargs);
|
||||
ps.println();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
/**
|
||||
* Prototype representing compiled lua code.
|
||||
* <p>
|
||||
* This is both a straight translation of the corresponding C type,
|
||||
* and the main data structure for execution of compiled lua bytecode.
|
||||
* <p>
|
||||
* See documentatation on {@link LuaClosure} for information on how to load
|
||||
* and execute a {@link Prototype}.
|
||||
* @see LuaClosure
|
||||
*/
|
||||
|
||||
public class Prototype {
|
||||
/* constants used by the function */
|
||||
public LuaValue[] k;
|
||||
public int[] code;
|
||||
/* functions defined inside the function */
|
||||
public Prototype[] p;
|
||||
/* map from opcodes to source lines */
|
||||
public int[] lineinfo;
|
||||
/* information about local variables */
|
||||
public LocVars[] locvars;
|
||||
/* upvalue names */
|
||||
public LuaString[] upvalues;
|
||||
public LuaString source;
|
||||
public int nups;
|
||||
public int linedefined;
|
||||
public int lastlinedefined;
|
||||
public int numparams;
|
||||
public int is_vararg;
|
||||
public int maxstacksize;
|
||||
|
||||
|
||||
public String toString() {
|
||||
return source + ":" + linedefined+"-"+lastlinedefined;
|
||||
}
|
||||
|
||||
/** Get the name of a local variable.
|
||||
*
|
||||
* @param number the local variable number to look up
|
||||
* @param pc the program counter
|
||||
* @return the name, or null if not found
|
||||
*/
|
||||
public LuaString getlocalname(int number, int pc) {
|
||||
int i;
|
||||
for (i = 0; i<locvars.length && locvars[i].startpc <= pc; i++) {
|
||||
if (pc < locvars[i].endpc) { /* is variable active? */
|
||||
number--;
|
||||
if (number == 0)
|
||||
return locvars[i].varname;
|
||||
}
|
||||
}
|
||||
return null; /* not found */
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010-2011 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;
|
||||
|
||||
/**
|
||||
* Subclass of {@link Varargs} that represents a lua tail call
|
||||
* in a Java library function execution environment.
|
||||
* <p>
|
||||
* Since Java doesn't have direct support for tail calls,
|
||||
* any lua function whose {@link Prototype} contains the
|
||||
* {@link Lua#OP_TAILCALL} bytecode needs a mechanism
|
||||
* for tail calls when converting lua-bytecode to java-bytecode.
|
||||
* <p>
|
||||
* The tail call holds the next function and arguments,
|
||||
* and the client a call to {@link #eval()} executes the function
|
||||
* repeatedly until the tail calls are completed.
|
||||
* <p>
|
||||
* Normally, users of luaj need not concern themselves with the
|
||||
* details of this mechanism, as it is built into the core
|
||||
* execution framework.
|
||||
* @see Prototype
|
||||
* @see LuaJC
|
||||
*/
|
||||
public class TailcallVarargs extends Varargs {
|
||||
|
||||
private LuaValue func;
|
||||
private Varargs args;
|
||||
private Varargs result;
|
||||
|
||||
public TailcallVarargs(LuaValue f, Varargs args) {
|
||||
this.func = f;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public TailcallVarargs(LuaValue object, LuaValue methodname, Varargs args) {
|
||||
this.func = object.get(methodname);
|
||||
this.args = LuaValue.varargsOf(object, args);
|
||||
}
|
||||
|
||||
public boolean isTailcall() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Varargs eval() {
|
||||
while ( result == null ) {
|
||||
Varargs r = func.onInvoke(args);
|
||||
if (r.isTailcall()) {
|
||||
TailcallVarargs t = (TailcallVarargs) r;
|
||||
func = t.func;
|
||||
args = t.args;
|
||||
}
|
||||
else {
|
||||
result = r;
|
||||
func = null;
|
||||
args = null;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public LuaValue arg( int i ) {
|
||||
if ( result == null )
|
||||
eval();
|
||||
return result.arg(i);
|
||||
}
|
||||
|
||||
public LuaValue arg1() {
|
||||
if (result == null)
|
||||
eval();
|
||||
return result.arg1();
|
||||
}
|
||||
|
||||
public int narg() {
|
||||
if (result == null)
|
||||
eval();
|
||||
return result.narg();
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
|
||||
/** Upvalue used with Closure formulation
|
||||
* <p>
|
||||
* @see LuaClosure
|
||||
* @see Prototype
|
||||
*/
|
||||
public final class UpValue {
|
||||
|
||||
LuaValue[] array; // initially the stack, becomes a holder
|
||||
int index;
|
||||
|
||||
/**
|
||||
* Create an upvalue relative to a stack
|
||||
* @param stack the stack
|
||||
* @param index the index on the stack for the upvalue
|
||||
*/
|
||||
public UpValue( LuaValue[] stack, int index) {
|
||||
this.array = stack;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this upvalue to a Java String
|
||||
* @return the Java String for this upvalue.
|
||||
* @see LuaValue#tojstring()
|
||||
*/
|
||||
public String tojstring() {
|
||||
return array[index].tojstring();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the upvalue
|
||||
* @return the {@link LuaValue} for this upvalue
|
||||
*/
|
||||
public final LuaValue getValue() {
|
||||
return array[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the upvalue
|
||||
* @param the {@link LuaValue} to set it to
|
||||
*/
|
||||
public final void setValue( LuaValue value ) {
|
||||
array[index] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close this upvalue so it is no longer on the stack
|
||||
*/
|
||||
public final void close() {
|
||||
array = new LuaValue[] { array[index] };
|
||||
index = 0;
|
||||
}
|
||||
}
|
@ -1,537 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* {@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.
|
||||
* <p>
|
||||
* 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>
|
||||
* @see LuaValue#varargsOf(LuaValue[])
|
||||
* @see LuaValue#varargsOf(LuaValue, Varargs)
|
||||
* @see LuaValue#varargsOf(LuaValue[], Varargs)
|
||||
* @see LuaValue#varargsOf(LuaValue, LuaValue, Varargs)
|
||||
* @see LuaValue#varargsOf(LuaValue[], int, int)
|
||||
* @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
|
||||
* @see LuaValue#subargs(int)
|
||||
*/
|
||||
public abstract class Varargs {
|
||||
|
||||
/**
|
||||
* Get the n-th argument value (1-based).
|
||||
* @param i the index of the argument to get, 1 is the first argument
|
||||
* @return Value at position i, or LuaValue.NIL if there is none.
|
||||
* @see Varargs#arg1()
|
||||
* @see LuaValue#NIL
|
||||
*/
|
||||
abstract public LuaValue arg( int i );
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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
|
||||
*/
|
||||
public Varargs eval() { return this; }
|
||||
|
||||
/**
|
||||
* Return true if this is a TailcallVarargs
|
||||
* @return true if a tail call, false otherwise
|
||||
*/
|
||||
public boolean isTailcall() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// utilities to get specific arguments and type-check them.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/** 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
|
||||
* @see LuaValue.TBOOLEAN
|
||||
* @see LuaValue.TNUMBER
|
||||
* @see LuaValue.TSTRING
|
||||
* @see LuaValue.TTABLE
|
||||
* @see LuaValue.TFUNCTION
|
||||
* @see LuaValue.TUSERDATA
|
||||
* @see LuaValue.TTHREAD
|
||||
* */
|
||||
public int type(int i) { return arg(i).type(); }
|
||||
|
||||
/** Tests if argument i is nil.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if the argument is nil or does not exist, false otherwise
|
||||
* @see LuaValue.TNIL
|
||||
* */
|
||||
public boolean isnil(int i) { return arg(i).isnil(); }
|
||||
|
||||
/** Tests if argument i is a function.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if the argument exists and is a function or closure, false otherwise
|
||||
* @see LuaValue.TFUNCTION
|
||||
* */
|
||||
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.
|
||||
* @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
|
||||
* 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.
|
||||
* @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
|
||||
* @see LuaValue.TSTRING
|
||||
* */
|
||||
public boolean isstring(int i) { return arg(i).isstring(); }
|
||||
|
||||
/** Tests if argument i is a table.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if the argument exists and is a lua table, false otherwise
|
||||
* @see LuaValue.TTABLE
|
||||
* */
|
||||
public boolean istable(int i) { return arg(i).istable(); }
|
||||
|
||||
/** Tests if argument i is a thread.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if the argument exists and is a lua thread, false otherwise
|
||||
* @see LuaValue.TTHREAD
|
||||
* */
|
||||
public boolean isthread(int i) { return arg(i).isthread(); }
|
||||
|
||||
/** Tests if argument i is a userdata.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if the argument exists and is a userdata, false otherwise
|
||||
* @see LuaValue.TUSERDATA
|
||||
* */
|
||||
public boolean isuserdata(int i) { return arg(i).isuserdata(); }
|
||||
|
||||
/** Tests if a value exists at argument i.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if the argument exists, false otherwise
|
||||
* */
|
||||
public boolean isvalue(int i) { return i>0 && i<=narg(); }
|
||||
|
||||
/** 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
|
||||
* @exception LuaError if the argument is not a lua boolean
|
||||
* */
|
||||
public boolean optboolean(int i, boolean defval) { return arg(i).optboolean(defval); }
|
||||
|
||||
/** Return argument i as a closure, {@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 LuaClosure if argument i is a closure, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a lua closure
|
||||
* */
|
||||
public LuaClosure optclosure(int i, LuaClosure defval) { return arg(i).optclosure(defval); }
|
||||
|
||||
/** Return argument i as a double, {@code defval} if nil, or throw a LuaError if it cannot be converted to one.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return java double value if argument i is a number or string that converts to a number, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a number
|
||||
* */
|
||||
public double optdouble(int i, double defval) { return arg(i).optdouble(defval); }
|
||||
|
||||
/** Return argument i as a function, {@code defval} if nil, or throw a LuaError if an incompatible type.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return LuaValue that can be called if argument i is lua function or closure, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a lua function or closure
|
||||
* */
|
||||
public LuaFunction optfunction(int i, LuaFunction defval) { return arg(i).optfunction(defval); }
|
||||
|
||||
/** Return argument i as a java int value, discarding any fractional part, {@code defval} if nil, or throw a LuaError if not a number.
|
||||
* @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, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a number
|
||||
* */
|
||||
public int optint(int i, int defval) { return arg(i).optint(defval); }
|
||||
|
||||
/** Return argument i as a java int value, {@code defval} if nil, or throw a LuaError 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
|
||||
* @return LuaInteger value that fits in a java int without rounding, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument cannot be represented by a java int value
|
||||
* */
|
||||
public LuaInteger optinteger(int i, LuaInteger defval) { return arg(i).optinteger(defval); }
|
||||
|
||||
/** Return argument i as a java long value, discarding any fractional part, {@code defval} if nil, or throw a LuaError if not a number.
|
||||
* @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, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a number
|
||||
* */
|
||||
public long optlong(int i, long defval) { return arg(i).optlong(defval); }
|
||||
|
||||
/** Return argument i as a LuaNumber, {@code defval} if nil, or throw a LuaError 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, or defval if not supplied or nil
|
||||
* @return LuaNumber if argument i is number or can be converted to a number
|
||||
* @exception LuaError if the argument is not a number
|
||||
* */
|
||||
public LuaNumber optnumber(int i, LuaNumber defval) { return arg(i).optnumber(defval); }
|
||||
|
||||
/** Return argument i as a java String if a string or number, {@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 String value if argument i is a string or number, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a string or number
|
||||
* */
|
||||
public String optjstring(int i, String defval) { return arg(i).optjstring(defval); }
|
||||
|
||||
/** Return argument i as a LuaString if a string or number, {@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 LuaString value if argument i is a string or number, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a string or number
|
||||
* */
|
||||
public LuaString optstring(int i, LuaString defval) { return arg(i).optstring(defval); }
|
||||
|
||||
/** Return argument i as a LuaTable if a lua table, {@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 LuaTable value if a table, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a lua table
|
||||
* */
|
||||
public LuaTable opttable(int i, LuaTable defval) { return arg(i).opttable(defval); }
|
||||
|
||||
/** Return argument i as a LuaThread if a lua thread, {@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 LuaThread value if a thread, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a lua thread
|
||||
* */
|
||||
public LuaThread optthread(int i, LuaThread defval) { return arg(i).optthread(defval); }
|
||||
|
||||
/** Return argument i as a java Object if a userdata, {@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 java Object value if argument i is a userdata, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a userdata
|
||||
* */
|
||||
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,
|
||||
* {@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
|
||||
* @return java Object value if argument i is a userdata whose instance Class c or a subclass, or defval if not supplied or nil
|
||||
* @exception LuaError if the argument is not a userdata or from whose instance c is not assignable
|
||||
* */
|
||||
public Object optuserdata(int i, Class c, Object defval) { return arg(i).optuserdata(c,defval); }
|
||||
|
||||
/** Return argument i as a LuaValue if it exists, or {@code defval}.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return LuaValue value if the argument exists, defval if not
|
||||
* @exception LuaError if the argument does not exist.
|
||||
* */
|
||||
public LuaValue optvalue(int i, LuaValue defval) { return i>0 && i<=narg()? arg(i): defval; }
|
||||
|
||||
/** Return argument i as a boolean value, or throw an error 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
|
||||
* @exception LuaError if the argument is not a lua boolean
|
||||
* */
|
||||
public boolean checkboolean(int i) { return arg(i).checkboolean(); }
|
||||
|
||||
/** Return argument i as a closure, or throw an error if any other type.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return LuaClosure if argument i is a closure.
|
||||
* @exception LuaError if the argument is not a lua closure
|
||||
* */
|
||||
public LuaClosure checkclosure(int i) { return arg(i).checkclosure(); }
|
||||
|
||||
/** Return argument i as a double, 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 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(); }
|
||||
|
||||
/** 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
|
||||
* @return LuaValue that can be called if argument i is lua function or closure
|
||||
* @exception LuaError if the argument is not a lua function or closure
|
||||
* */
|
||||
public LuaValue 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.
|
||||
* @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
|
||||
* */
|
||||
public int checkint(int i) { return arg(i).checknumber().toint(); }
|
||||
|
||||
/** 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
|
||||
* @return LuaInteger value that fits in a java int without rounding
|
||||
* @exception LuaError if the argument cannot be represented by a java int value
|
||||
* */
|
||||
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.
|
||||
* @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
|
||||
* */
|
||||
public long checklong(int i) { return arg(i).checknumber().tolong(); }
|
||||
|
||||
/** 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
|
||||
* @return LuaNumber if argument i is number or can be converted to a number
|
||||
* @exception LuaError if the argument is not a number
|
||||
* */
|
||||
public LuaNumber checknumber(int i) { return arg(i).checknumber(); }
|
||||
|
||||
/** Return argument i as a java String if a string or number, or throw an error if any other type
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return String value if argument i is a string or number
|
||||
* @exception LuaError if the argument is not a string or number
|
||||
* */
|
||||
public String checkjstring(int i) { return arg(i).checkjstring(); }
|
||||
|
||||
/** Return argument i as a LuaString if a string or number, or throw an error if any other type
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return LuaString value if argument i is a string or number
|
||||
* @exception LuaError if the argument is not a string or number
|
||||
* */
|
||||
public LuaString checkstring(int i) { return arg(i).checkstring(); }
|
||||
|
||||
/** Return argument i as a LuaTable if a lua table, or throw an error if any other type.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return LuaTable value if a table
|
||||
* @exception LuaError if the argument is not a lua table
|
||||
* */
|
||||
public LuaTable checktable(int i) { return arg(i).checktable(); }
|
||||
|
||||
/** Return argument i as a LuaThread if a lua thread, or throw an error if any other type.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return LuaThread value if a thread
|
||||
* @exception LuaError if the argument is not a lua thread
|
||||
* */
|
||||
public LuaThread checkthread(int i) { return arg(i).checkthread(); }
|
||||
|
||||
/** Return argument i as a java Object if a userdata, or throw an error if any other type.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return java Object value if argument i is a userdata
|
||||
* @exception LuaError if the argument is not a userdata
|
||||
* */
|
||||
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,
|
||||
* 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
|
||||
* @return java Object value if argument i is a userdata whose instance Class c or a subclass
|
||||
* @exception LuaError if the argument is not a userdata or from whose instance c is not assignable
|
||||
* */
|
||||
public Object checkuserdata(int i,Class c) { return arg(i).checkuserdata(c); }
|
||||
|
||||
/** Return argument i as a LuaValue if it exists, or throw an error.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return LuaValue value if the argument exists
|
||||
* @exception LuaError if the argument does not exist.
|
||||
* */
|
||||
public LuaValue checkvalue(int i) { return i<=narg()? arg(i): LuaValue.argerror(i,"value expected"); }
|
||||
|
||||
/** Return argument i as a LuaValue if it is not nil, or throw an error if it is nil.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return LuaValue value if the argument is not nil
|
||||
* @exception LuaError if the argument doesn't exist or evaluates to nil.
|
||||
* */
|
||||
public LuaValue checknotnil(int i) { return arg(i).checknotnil(); }
|
||||
|
||||
/** Return argument i as a LuaValue when a user-supplied assertion passes, or throw an error.
|
||||
* @param test user supplied assertion to test against
|
||||
* @param i the index to report in any error message
|
||||
* @param msg the error message to use when the test fails
|
||||
* @return LuaValue value if the value of {@code test} is {@code true}
|
||||
* @exception LuaError if the the value of {@code test} is {@code false}
|
||||
* */
|
||||
public void argcheck(boolean test, int i, String msg) { if (!test) LuaValue.argerror(i,msg); }
|
||||
|
||||
/** Return true if there is no argument or nil at argument i.
|
||||
* @param i the index of the argument to test, 1 is the first argument
|
||||
* @return true if argument i contains either no argument or nil
|
||||
* */
|
||||
public boolean isnoneornil(int i) {
|
||||
return i>narg() || arg(i).isnil();
|
||||
}
|
||||
|
||||
/** 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,
|
||||
* 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,
|
||||
* 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
|
||||
* */
|
||||
public char tochar(int i) { return arg(i).tochar(); }
|
||||
|
||||
/** Return argument i as a java double value or 0 if not a number.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return double value if argument i is number, otherwise 0
|
||||
* */
|
||||
public double todouble(int i) { return arg(i).todouble(); }
|
||||
|
||||
/** 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,
|
||||
* 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,
|
||||
* 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
|
||||
* */
|
||||
public long tolong(int i) { return arg(i).tolong(); }
|
||||
|
||||
/** Return argument i as a java String based on the type of the argument.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return String value representing the type
|
||||
* */
|
||||
public String tojstring(int i) { return arg(i).tojstring(); }
|
||||
|
||||
/** 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
|
||||
* */
|
||||
public short toshort(int i) { return arg(i).toshort(); }
|
||||
|
||||
/** Return argument i as a java Object if a userdata, or null.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @return java Object value if argument i is a userdata, otherwise null
|
||||
* */
|
||||
public Object touserdata(int i) { return arg(i).touserdata(); }
|
||||
|
||||
/** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass, or null.
|
||||
* @param i the index of the argument to convert, 1 is the first argument
|
||||
* @param c the class to which the userdata instance must be assignable
|
||||
* @return java Object value if argument i is a userdata whose instance Class c or a subclass, otherwise null
|
||||
* */
|
||||
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}.
|
||||
*/
|
||||
public String tojstring() {
|
||||
Buffer sb = new Buffer();
|
||||
sb.append( "(" );
|
||||
for ( int i=1,n=narg(); i<=n; i++ ) {
|
||||
if (i>1) sb.append( "," );
|
||||
sb.append( arg(i).tojstring() );
|
||||
}
|
||||
sb.append( ")" );
|
||||
return sb.tojstring();
|
||||
}
|
||||
|
||||
/** 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(); }
|
||||
|
||||
/**
|
||||
* Create a {@code Varargs} instance containing arguments starting at index {@code start}
|
||||
* @param start the index from which to include arguments, where 1 is the first argument.
|
||||
* @return Varargs containing argument { start, start+1, ... , narg-start-1 }
|
||||
*/
|
||||
public Varargs subargs(final int start) {
|
||||
int end = narg();
|
||||
switch ( end-start ) {
|
||||
case 0: return arg(start);
|
||||
case 1: return new LuaValue.PairVarargs(arg(start),arg(end));
|
||||
}
|
||||
return end<start? (Varargs) LuaValue.NONE: new SubVarargs(this,start,end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Varargs for use in the Varargs.subargs() function.
|
||||
* @see Varargs#subargs(int)
|
||||
*/
|
||||
private static class SubVarargs extends Varargs {
|
||||
private final Varargs v;
|
||||
private final int start;
|
||||
private final int end;
|
||||
public SubVarargs(Varargs varargs, int start, int end) {
|
||||
this.v = varargs;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
public LuaValue arg(int i) {
|
||||
i += start-1;
|
||||
return i>=start && i<=end? v.arg(i): LuaValue.NIL;
|
||||
}
|
||||
public LuaValue arg1() {
|
||||
return v.arg(start);
|
||||
}
|
||||
public int narg() {
|
||||
return end+1-start;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,349 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LuaTable} that provides weak key and weak value semantics.
|
||||
* <p>
|
||||
* Normally these are not created directly, but indirectly when changing the mode
|
||||
* of a {@link LuaTable} as lua script executes.
|
||||
* <p>
|
||||
* However, calling the constructors directly when weak tables are required from
|
||||
* Java will reduce overhead.
|
||||
*/
|
||||
public class WeakTable extends LuaTable {
|
||||
private boolean weakkeys,weakvalues;
|
||||
|
||||
/**
|
||||
* Construct a table with weak keys, weak values, or both
|
||||
* @param weakkeys true to let the table have weak keys
|
||||
* @param weakvalues true to let the table have weak values
|
||||
*/
|
||||
public WeakTable(boolean weakkeys, boolean weakvalues) {
|
||||
this(weakkeys, weakvalues, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a table with weak keys, weak values, or both, and an initial capacity
|
||||
* @param weakkeys true to let the table have weak keys
|
||||
* @param weakvalues true to let the table have weak values
|
||||
* @param narray capacity of array part
|
||||
* @param nhash capacity of hash part
|
||||
*/
|
||||
protected WeakTable(boolean weakkeys, boolean weakvalues, int narray, int nhash) {
|
||||
super(narray, nhash);
|
||||
this.weakkeys = weakkeys;
|
||||
this.weakvalues = weakvalues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a table with weak keys, weak values, or both, and a source of initial data
|
||||
* @param weakkeys true to let the table have weak keys
|
||||
* @param weakvalues true to let the table have weak values
|
||||
* @param source {@link LuaTable} containing the initial elements
|
||||
*/
|
||||
protected WeakTable(boolean weakkeys, boolean weakvalues, LuaTable source) {
|
||||
this(weakkeys, weakvalues, source.getArrayLength(), source.getHashLength());
|
||||
Varargs n;
|
||||
LuaValue k = NIL;
|
||||
while ( !(k = ((n = source.next(k)).arg1())).isnil() )
|
||||
rawset(k, n.arg(2));
|
||||
m_metatable = source.m_metatable;
|
||||
}
|
||||
|
||||
public void presize( int narray ) {
|
||||
super.presize(narray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Presize capacity of both array and hash parts.
|
||||
* @param narray capacity of array part
|
||||
* @param nhash capacity of hash part
|
||||
*/
|
||||
public void presize(int narray, int nhash) {
|
||||
super.presize(narray, nhash);
|
||||
}
|
||||
|
||||
protected int getArrayLength() {
|
||||
return super.getArrayLength();
|
||||
}
|
||||
|
||||
protected int getHashLength() {
|
||||
return super.getHashLength();
|
||||
}
|
||||
|
||||
protected LuaTable changemode(boolean weakkeys, boolean weakvalues) {
|
||||
this.weakkeys = weakkeys;
|
||||
this.weakvalues = weakvalues;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Self-sent message to convert a value to its weak counterpart
|
||||
* @param value value to convert
|
||||
* @return {@link LuaValue} that is a strong or weak reference, depending on type of {@code value}
|
||||
*/
|
||||
LuaValue weaken( LuaValue value ) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TFUNCTION:
|
||||
case LuaValue.TTHREAD:
|
||||
case LuaValue.TTABLE:
|
||||
return new WeakValue(value);
|
||||
case LuaValue.TUSERDATA:
|
||||
return new WeakUserdata(value);
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public void rawset( int key, LuaValue value ) {
|
||||
if ( weakvalues )
|
||||
value = weaken( value );
|
||||
super.rawset(key, value);
|
||||
}
|
||||
|
||||
public void rawset( LuaValue key, LuaValue value ) {
|
||||
if ( weakvalues )
|
||||
value = weaken( value );
|
||||
if ( weakkeys ) {
|
||||
switch ( key.type() ) {
|
||||
case LuaValue.TFUNCTION:
|
||||
case LuaValue.TTHREAD:
|
||||
case LuaValue.TTABLE:
|
||||
case LuaValue.TUSERDATA:
|
||||
key = value = new WeakEntry(this, key, value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
super.rawset(key, value);
|
||||
}
|
||||
|
||||
|
||||
public LuaValue rawget( int key ) {
|
||||
return super.rawget(key).strongvalue();
|
||||
}
|
||||
|
||||
public LuaValue rawget( LuaValue key ) {
|
||||
return super.rawget(key).strongvalue();
|
||||
}
|
||||
|
||||
/** Get the hash value for a key
|
||||
* key the key to look up
|
||||
* */
|
||||
protected LuaValue hashget(LuaValue key) {
|
||||
if ( hashEntries > 0 ) {
|
||||
int i = hashFindSlot(key);
|
||||
if ( hashEntries == 0 )
|
||||
return NIL;
|
||||
LuaValue v = hashValues[i];
|
||||
return v!=null? v: NIL;
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
|
||||
// override to remove values for weak keys as we search
|
||||
public int hashFindSlot(LuaValue key) {
|
||||
int i = ( key.hashCode() & 0x7FFFFFFF ) % hashKeys.length;
|
||||
LuaValue k;
|
||||
while ( ( k = hashKeys[i] ) != null ) {
|
||||
if ( k.isweaknil() ) {
|
||||
hashClearSlot(i);
|
||||
if ( hashEntries == 0 )
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if ( k.raweq(key.strongkey()) )
|
||||
return i;
|
||||
i = ( i + 1 ) % hashKeys.length;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public int maxn() {
|
||||
return super.maxn();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next element after a particular key in the table
|
||||
* @return key,value or nil
|
||||
*/
|
||||
public Varargs next( LuaValue key ) {
|
||||
while ( true ) {
|
||||
Varargs n = super.next(key);
|
||||
LuaValue k = n.arg1();
|
||||
if ( k.isnil() )
|
||||
return NIL;
|
||||
LuaValue ks = k.strongkey();
|
||||
LuaValue vs = n.arg(2).strongvalue();
|
||||
if ( ks.isnil() || vs.isnil() ) {
|
||||
super.rawset(k, NIL);
|
||||
} else {
|
||||
return varargsOf(ks,vs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------- sort support -----------------------------
|
||||
public void sort(final LuaValue comparator) {
|
||||
super.sort( new TwoArgFunction() {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return comparator.call( arg1.strongvalue(), arg2.strongvalue() );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/** Internal class to implement weak values.
|
||||
* @see WeakTable
|
||||
*/
|
||||
static class WeakValue extends LuaValue {
|
||||
final WeakReference ref;
|
||||
|
||||
protected WeakValue(LuaValue value) {
|
||||
ref = new WeakReference(value);
|
||||
}
|
||||
|
||||
public int type() {
|
||||
illegal("type","weak value");
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
illegal("typename","weak value");
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "weak<"+ref.get()+">";
|
||||
}
|
||||
|
||||
public LuaValue strongvalue() {
|
||||
Object o = ref.get();
|
||||
return o!=null? (LuaValue)o: NIL;
|
||||
}
|
||||
|
||||
public boolean raweq(LuaValue rhs) {
|
||||
Object o = ref.get();
|
||||
return o!=null && rhs.raweq((LuaValue)o);
|
||||
}
|
||||
|
||||
public boolean isweaknil() {
|
||||
return ref.get() == null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Internal class to implement weak userdata values.
|
||||
* @see WeakTable
|
||||
*/
|
||||
static final class WeakUserdata extends WeakValue {
|
||||
private final WeakReference ob;
|
||||
private final LuaValue mt;
|
||||
|
||||
private WeakUserdata(LuaValue value) {
|
||||
super(value);
|
||||
ob = new WeakReference(value.touserdata());
|
||||
mt = value.getmetatable();
|
||||
}
|
||||
|
||||
public LuaValue strongvalue() {
|
||||
Object u = ref.get();
|
||||
if ( u != null )
|
||||
return (LuaValue) u;
|
||||
Object o = ob.get();
|
||||
return o!=null? userdataOf(o,mt): NIL;
|
||||
}
|
||||
|
||||
public boolean raweq(LuaValue rhs) {
|
||||
if ( ! rhs.isuserdata() )
|
||||
return false;
|
||||
LuaValue v = (LuaValue) ref.get();
|
||||
if ( v != null && v.raweq(rhs) )
|
||||
return true;
|
||||
return rhs.touserdata() == ob.get();
|
||||
}
|
||||
|
||||
public boolean isweaknil() {
|
||||
return ob.get() == null || ref.get() == null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Internal class to implement weak table entries.
|
||||
* @see WeakTable
|
||||
*/
|
||||
static final class WeakEntry extends LuaValue {
|
||||
final LuaValue weakkey;
|
||||
LuaValue weakvalue;
|
||||
final int keyhash;
|
||||
|
||||
private WeakEntry(WeakTable table, LuaValue key, LuaValue weakvalue) {
|
||||
this.weakkey = table.weaken(key);
|
||||
this.keyhash = key.hashCode();
|
||||
this.weakvalue = weakvalue;
|
||||
}
|
||||
|
||||
public LuaValue strongkey() {
|
||||
return weakkey.strongvalue();
|
||||
}
|
||||
|
||||
// when looking up the value, look in the keys metatable
|
||||
public LuaValue strongvalue() {
|
||||
LuaValue key = weakkey.strongvalue();
|
||||
if ( key.isnil() )
|
||||
return weakvalue = NIL;
|
||||
return weakvalue.strongvalue();
|
||||
}
|
||||
|
||||
public int type() {
|
||||
return TNONE;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
illegal("typename","weak entry");
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "weak<"+weakkey.strongvalue()+","+strongvalue()+">";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return keyhash;
|
||||
}
|
||||
|
||||
public boolean raweq(LuaValue rhs) {
|
||||
//return rhs.raweq(weakkey.strongvalue());
|
||||
return weakkey.raweq(rhs);
|
||||
}
|
||||
|
||||
public boolean isweaknil() {
|
||||
return weakkey.isweaknil() || weakvalue.isweaknil();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,267 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.compiler;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.luaj.vm2.LocVars;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
|
||||
public class DumpState {
|
||||
|
||||
/** mark for precompiled code (`<esc>Lua') */
|
||||
public static final String LUA_SIGNATURE = "\033Lua";
|
||||
|
||||
/** for header of binary files -- this is Lua 5.1 */
|
||||
public static final int LUAC_VERSION = 0x51;
|
||||
|
||||
/** for header of binary files -- this is the official format */
|
||||
public static final int LUAC_FORMAT = 0;
|
||||
|
||||
/** size of header of binary files */
|
||||
public static final int LUAC_HEADERSIZE = 12;
|
||||
|
||||
/** expected lua header bytes */
|
||||
private static final byte[] LUAC_HEADER_SIGNATURE = { '\033', 'L', 'u', 'a' };
|
||||
|
||||
/** set true to allow integer compilation */
|
||||
public static boolean ALLOW_INTEGER_CASTING = false;
|
||||
|
||||
/** format corresponding to non-number-patched lua, all numbers are floats or doubles */
|
||||
public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
|
||||
|
||||
/** format corresponding to non-number-patched lua, all numbers are ints */
|
||||
public static final int NUMBER_FORMAT_INTS_ONLY = 1;
|
||||
|
||||
/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
|
||||
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
|
||||
|
||||
/** default number format */
|
||||
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
|
||||
|
||||
// header fields
|
||||
private boolean IS_LITTLE_ENDIAN = false;
|
||||
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
|
||||
private int SIZEOF_LUA_NUMBER = 8;
|
||||
private static final int SIZEOF_INT = 4;
|
||||
private static final int SIZEOF_SIZET = 4;
|
||||
private static final int SIZEOF_INSTRUCTION = 4;
|
||||
|
||||
DataOutputStream writer;
|
||||
boolean strip;
|
||||
int status;
|
||||
|
||||
public DumpState(OutputStream w, boolean strip) {
|
||||
this.writer = new DataOutputStream( w );
|
||||
this.strip = strip;
|
||||
this.status = 0;
|
||||
}
|
||||
|
||||
void dumpBlock(final byte[] b, int size) throws IOException {
|
||||
writer.write(b, 0, size);
|
||||
}
|
||||
|
||||
void dumpChar(int b) throws IOException {
|
||||
writer.write( b );
|
||||
}
|
||||
|
||||
void dumpInt(int x) throws IOException {
|
||||
if ( IS_LITTLE_ENDIAN ) {
|
||||
writer.writeByte(x&0xff);
|
||||
writer.writeByte((x>>8)&0xff);
|
||||
writer.writeByte((x>>16)&0xff);
|
||||
writer.writeByte((x>>24)&0xff);
|
||||
} else {
|
||||
writer.writeInt(x);
|
||||
}
|
||||
}
|
||||
|
||||
void dumpString(LuaString s) throws IOException {
|
||||
final int len = s.len().toint();
|
||||
dumpInt( len+1 );
|
||||
s.write( writer, 0, len );
|
||||
writer.write( 0 );
|
||||
}
|
||||
|
||||
void dumpDouble(double d) throws IOException {
|
||||
long l = Double.doubleToLongBits(d);
|
||||
if ( IS_LITTLE_ENDIAN ) {
|
||||
dumpInt( (int) l );
|
||||
dumpInt( (int) (l>>32) );
|
||||
} else {
|
||||
writer.writeLong(l);
|
||||
}
|
||||
}
|
||||
|
||||
void dumpCode( final Prototype f ) throws IOException {
|
||||
final int[] code = f.code;
|
||||
int n = code.length;
|
||||
dumpInt( n );
|
||||
for ( int i=0; i<n; i++ )
|
||||
dumpInt( code[i] );
|
||||
}
|
||||
|
||||
void dumpConstants(final Prototype f) throws IOException {
|
||||
final LuaValue[] k = f.k;
|
||||
int i, n = k.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++) {
|
||||
final LuaValue o = k[i];
|
||||
switch ( o.type() ) {
|
||||
case LuaValue.TNIL:
|
||||
writer.write(LuaValue.TNIL);
|
||||
break;
|
||||
case LuaValue.TBOOLEAN:
|
||||
writer.write(LuaValue.TBOOLEAN);
|
||||
dumpChar(o.toboolean() ? 1 : 0);
|
||||
break;
|
||||
case LuaValue.TNUMBER:
|
||||
switch (NUMBER_FORMAT) {
|
||||
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
|
||||
writer.write(LuaValue.TNUMBER);
|
||||
dumpDouble(o.todouble());
|
||||
break;
|
||||
case NUMBER_FORMAT_INTS_ONLY:
|
||||
if ( ! ALLOW_INTEGER_CASTING && ! o.isint() )
|
||||
throw new java.lang.IllegalArgumentException("not an integer: "+o);
|
||||
writer.write(LuaValue.TNUMBER);
|
||||
dumpInt(o.toint());
|
||||
break;
|
||||
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
||||
if ( o.isint() ) {
|
||||
writer.write(LuaValue.TINT);
|
||||
dumpInt(o.toint());
|
||||
} else {
|
||||
writer.write(LuaValue.TNUMBER);
|
||||
dumpDouble(o.todouble());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("number format not supported: "+NUMBER_FORMAT);
|
||||
}
|
||||
break;
|
||||
case LuaValue.TSTRING:
|
||||
writer.write(LuaValue.TSTRING);
|
||||
dumpString((LuaString)o);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("bad type for " + o);
|
||||
}
|
||||
}
|
||||
n = f.p.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++)
|
||||
dumpFunction(f.p[i], f.source);
|
||||
}
|
||||
|
||||
void dumpDebug(final Prototype f) throws IOException {
|
||||
int i, n;
|
||||
n = (strip) ? 0 : f.lineinfo.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++)
|
||||
dumpInt(f.lineinfo[i]);
|
||||
n = (strip) ? 0 : f.locvars.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++) {
|
||||
LocVars lvi = f.locvars[i];
|
||||
dumpString(lvi.varname);
|
||||
dumpInt(lvi.startpc);
|
||||
dumpInt(lvi.endpc);
|
||||
}
|
||||
n = (strip) ? 0 : f.upvalues.length;
|
||||
dumpInt(n);
|
||||
for (i = 0; i < n; i++)
|
||||
dumpString(f.upvalues[i]);
|
||||
}
|
||||
|
||||
void dumpFunction(final Prototype f, final LuaString string) throws IOException {
|
||||
if ( f.source == null || f.source.equals(string) || strip )
|
||||
dumpInt(0);
|
||||
else
|
||||
dumpString(f.source);
|
||||
dumpInt(f.linedefined);
|
||||
dumpInt(f.lastlinedefined);
|
||||
dumpChar(f.nups);
|
||||
dumpChar(f.numparams);
|
||||
dumpChar(f.is_vararg);
|
||||
dumpChar(f.maxstacksize);
|
||||
dumpCode(f);
|
||||
dumpConstants(f);
|
||||
dumpDebug(f);
|
||||
}
|
||||
|
||||
void dumpHeader() throws IOException {
|
||||
writer.write( LUAC_HEADER_SIGNATURE );
|
||||
writer.write( LUAC_VERSION );
|
||||
writer.write( LUAC_FORMAT );
|
||||
writer.write( IS_LITTLE_ENDIAN? 1: 0 );
|
||||
writer.write( SIZEOF_INT );
|
||||
writer.write( SIZEOF_SIZET );
|
||||
writer.write( SIZEOF_INSTRUCTION );
|
||||
writer.write( SIZEOF_LUA_NUMBER );
|
||||
writer.write( NUMBER_FORMAT );
|
||||
}
|
||||
|
||||
/*
|
||||
** dump Lua function as precompiled chunk
|
||||
*/
|
||||
public static int dump( Prototype f, OutputStream w, boolean strip ) throws IOException {
|
||||
DumpState D = new DumpState(w,strip);
|
||||
D.dumpHeader();
|
||||
D.dumpFunction(f,null);
|
||||
return D.status;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param f the function to dump
|
||||
* @param w the output stream to dump to
|
||||
* @param stripDebug true to strip debugging info, false otherwise
|
||||
* @param numberFormat one of NUMBER_FORMAT_FLOATS_OR_DOUBLES, NUMBER_FORMAT_INTS_ONLY, NUMBER_FORMAT_NUM_PATCH_INT32
|
||||
* @param littleendian true to use little endian for numbers, false for big endian
|
||||
* @return 0 if dump succeeds
|
||||
* @throws IOException
|
||||
* @throws IllegalArgumentException if the number format it not supported
|
||||
*/
|
||||
public static int dump(Prototype f, OutputStream w, boolean stripDebug, int numberFormat, boolean littleendian) throws IOException {
|
||||
switch ( numberFormat ) {
|
||||
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
|
||||
case NUMBER_FORMAT_INTS_ONLY:
|
||||
case NUMBER_FORMAT_NUM_PATCH_INT32:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("number format not supported: "+numberFormat);
|
||||
}
|
||||
DumpState D = new DumpState(w,stripDebug);
|
||||
D.IS_LITTLE_ENDIAN = littleendian;
|
||||
D.NUMBER_FORMAT = numberFormat;
|
||||
D.SIZEOF_LUA_NUMBER = (numberFormat==NUMBER_FORMAT_INTS_ONLY? 4: 8);
|
||||
D.dumpHeader();
|
||||
D.dumpFunction(f,null);
|
||||
return D.status;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.compiler;
|
||||
|
||||
class InstructionPtr {
|
||||
final int[] code;
|
||||
final int idx;
|
||||
InstructionPtr(int[] code, int idx ) {
|
||||
this.code = code;
|
||||
this.idx = idx;
|
||||
}
|
||||
int get() {
|
||||
return code[idx];
|
||||
}
|
||||
void set(int value) {
|
||||
code[idx] = value;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.compiler;
|
||||
|
||||
public class IntPtr {
|
||||
int i;
|
||||
IntPtr() {
|
||||
}
|
||||
IntPtr(int value) {
|
||||
this.i = value;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,251 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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.compiler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LocVars;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||
|
||||
/**
|
||||
* Compiler for Lua.
|
||||
* <p>
|
||||
* Compiles lua source files into lua bytecode within a {@link Prototype},
|
||||
* loads lua binary files directly into a{@link Prototype},
|
||||
* and optionaly instantiates a {@link LuaClosure} around the result
|
||||
* using a user-supplied environment.
|
||||
* <p>
|
||||
* Implements the {@link LuaCompiler} interface for loading
|
||||
* initialized chunks, which is an interface common to
|
||||
* lua bytecode compiling and java bytecode compiling.
|
||||
* <p>
|
||||
* Teh {@link LuaC} compiler is installed by default by both the
|
||||
* {@link JsePlatform} and {@link JmePlatform} classes,
|
||||
* so in the following example, the default {@link LuaC} compiler
|
||||
* will be used:
|
||||
* <pre> {@code
|
||||
* LuaValue _G = JsePlatform.standardGlobals();
|
||||
* LoadState.load( new ByteArrayInputStream("print 'hello'".getBytes()), "main.lua", _G ).call();
|
||||
* } </pre>
|
||||
* @see LuaCompiler
|
||||
* @see LuaJC
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see BaseLib
|
||||
* @see LuaValue
|
||||
* @see LuaCompiler
|
||||
* @see Prototype
|
||||
*/
|
||||
public class LuaC extends Lua implements LuaCompiler {
|
||||
|
||||
public static final LuaC instance = new LuaC();
|
||||
|
||||
/** Install the compiler so that LoadState will first
|
||||
* try to use it when handed bytes that are
|
||||
* not already a compiled lua chunk.
|
||||
*/
|
||||
public static void install() {
|
||||
org.luaj.vm2.LoadState.compiler = instance;
|
||||
}
|
||||
|
||||
protected static void _assert(boolean b) {
|
||||
if (!b)
|
||||
throw new LuaError("compiler assert failed");
|
||||
}
|
||||
|
||||
public static final int MAXSTACK = 250;
|
||||
static final int LUAI_MAXUPVALUES = 60;
|
||||
static final int LUAI_MAXVARS = 200;
|
||||
static final int NO_REG = MAXARG_A;
|
||||
|
||||
|
||||
/* OpMode - basic instruction format */
|
||||
static final int
|
||||
iABC = 0,
|
||||
iABx = 1,
|
||||
iAsBx = 2;
|
||||
|
||||
/* OpArgMask */
|
||||
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 */
|
||||
|
||||
|
||||
static void SET_OPCODE(InstructionPtr i,int o) {
|
||||
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
|
||||
}
|
||||
|
||||
static void SETARG_A(InstructionPtr i,int u) {
|
||||
i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) );
|
||||
}
|
||||
|
||||
static void SETARG_B(InstructionPtr i,int u) {
|
||||
i.set( ( i.get() & (MASK_NOT_B)) | ((u << POS_B) & MASK_B) );
|
||||
}
|
||||
|
||||
static void SETARG_C(InstructionPtr i,int u) {
|
||||
i.set( ( i.get() & (MASK_NOT_C)) | ((u << POS_C) & MASK_C) );
|
||||
}
|
||||
|
||||
static void SETARG_Bx(InstructionPtr i,int u) {
|
||||
i.set( ( i.get() & (MASK_NOT_Bx)) | ((u << POS_Bx) & MASK_Bx) );
|
||||
}
|
||||
|
||||
static void SETARG_sBx(InstructionPtr i,int u) {
|
||||
SETARG_Bx( i, u + MAXARG_sBx );
|
||||
}
|
||||
|
||||
static int CREATE_ABC(int o, int a, int b, int c) {
|
||||
return ((o << POS_OP) & MASK_OP) |
|
||||
((a << POS_A) & MASK_A) |
|
||||
((b << POS_B) & MASK_B) |
|
||||
((c << POS_C) & MASK_C) ;
|
||||
}
|
||||
|
||||
static int CREATE_ABx(int o, int a, int bc) {
|
||||
return ((o << POS_OP) & MASK_OP) |
|
||||
((a << POS_A) & MASK_A) |
|
||||
((bc << POS_Bx) & MASK_Bx) ;
|
||||
}
|
||||
|
||||
// vector reallocation
|
||||
|
||||
static LuaValue[] realloc(LuaValue[] v, int n) {
|
||||
LuaValue[] a = new LuaValue[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static Prototype[] realloc(Prototype[] v, int n) {
|
||||
Prototype[] a = new Prototype[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static LuaString[] realloc(LuaString[] v, int n) {
|
||||
LuaString[] a = new LuaString[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static LocVars[] realloc(LocVars[] v, int n) {
|
||||
LocVars[] a = new LocVars[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static int[] realloc(int[] v, int n) {
|
||||
int[] a = new int[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
static byte[] realloc(byte[] v, int n) {
|
||||
byte[] a = new byte[n];
|
||||
if ( v != null )
|
||||
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
|
||||
return a;
|
||||
}
|
||||
|
||||
public int nCcalls;
|
||||
Hashtable strings;
|
||||
|
||||
protected LuaC() {}
|
||||
|
||||
private LuaC(Hashtable strings) {
|
||||
this.strings = strings;
|
||||
}
|
||||
|
||||
/** Load into a Closure or LuaFunction, with the supplied initial environment */
|
||||
public LuaFunction load(InputStream stream, String name, LuaValue env) throws IOException {
|
||||
Prototype p = compile( stream, name );
|
||||
return new LuaClosure( p, env );
|
||||
}
|
||||
|
||||
/** Compile a prototype or load as a binary chunk */
|
||||
public static Prototype compile(InputStream stream, String name) throws IOException {
|
||||
int firstByte = stream.read();
|
||||
return ( firstByte == '\033' )?
|
||||
LoadState.loadBinaryChunk(firstByte, stream, name):
|
||||
(new LuaC(new Hashtable())).luaY_parser(firstByte, stream, name);
|
||||
}
|
||||
|
||||
/** Parse the input */
|
||||
private Prototype luaY_parser(int firstByte, InputStream z, String name) {
|
||||
LexState lexstate = new LexState(this, z);
|
||||
FuncState funcstate = new FuncState();
|
||||
// lexstate.buff = buff;
|
||||
lexstate.setinput( this, firstByte, z, (LuaString) LuaValue.valueOf(name) );
|
||||
lexstate.open_func(funcstate);
|
||||
/* main func. is always vararg */
|
||||
funcstate.f.is_vararg = LuaC.VARARG_ISVARARG;
|
||||
funcstate.f.source = (LuaString) LuaValue.valueOf(name);
|
||||
lexstate.next(); /* read first token */
|
||||
lexstate.chunk();
|
||||
lexstate.check(LexState.TK_EOS);
|
||||
lexstate.close_func();
|
||||
LuaC._assert (funcstate.prev == null);
|
||||
LuaC._assert (funcstate.f.nups == 0);
|
||||
LuaC._assert (lexstate.fs == null);
|
||||
return funcstate.f;
|
||||
}
|
||||
|
||||
// look up and keep at most one copy of each string
|
||||
public LuaString newTString(byte[] bytes, int offset, int len) {
|
||||
LuaString tmp = LuaString.valueOf(bytes, offset, len);
|
||||
LuaString v = (LuaString) strings.get(tmp);
|
||||
if ( v == null ) {
|
||||
// must copy bytes, since bytes could be from reusable buffer
|
||||
byte[] copy = new byte[len];
|
||||
System.arraycopy(bytes, offset, copy, 0, len);
|
||||
v = LuaString.valueOf(copy);
|
||||
strings.put(v, v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public String pushfstring(String string) {
|
||||
return string;
|
||||
}
|
||||
|
||||
public LuaFunction load(Prototype p, String filename, LuaValue env) {
|
||||
return new LuaClosure( p, env );
|
||||
}
|
||||
|
||||
}
|
@ -1,430 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 java.io.PrintStream;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
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 #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 JseBaseLib} instead.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link JmePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new BaseLib());
|
||||
* _G.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 JseBaseLib
|
||||
* @see ResourceFinder
|
||||
* @see #FINDER
|
||||
* @see LibFunction
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.1">http://www.lua.org/manual/5.1/manual.html#5.1</a>
|
||||
*/
|
||||
public class BaseLib extends OneArgFunction implements ResourceFinder {
|
||||
|
||||
public static BaseLib instance;
|
||||
|
||||
public InputStream STDIN = null;
|
||||
public PrintStream STDOUT = System.out;
|
||||
public PrintStream STDERR = System.err;
|
||||
|
||||
/**
|
||||
* Singleton file opener for this Java ClassLoader realm.
|
||||
*
|
||||
* Unless set or changed elsewhere, will be set by the BaseLib that is created.
|
||||
*/
|
||||
public static ResourceFinder FINDER;
|
||||
|
||||
private LuaValue next;
|
||||
private LuaValue inext;
|
||||
|
||||
private static final String[] LIB2_KEYS = {
|
||||
"collectgarbage", // ( opt [,arg] ) -> value
|
||||
"error", // ( message [,level] ) -> ERR
|
||||
"setfenv", // (f, table) -> void
|
||||
};
|
||||
private static final String[] LIBV_KEYS = {
|
||||
"assert", // ( v [,message] ) -> v, message | ERR
|
||||
"dofile", // ( filename ) -> result1, ...
|
||||
"getfenv", // ( [f] ) -> env
|
||||
"getmetatable", // ( object ) -> table
|
||||
"load", // ( func [,chunkname] ) -> chunk | nil, msg
|
||||
"loadfile", // ( [filename] ) -> chunk | nil, msg
|
||||
"loadstring", // ( string [,chunkname] ) -> chunk | nil, msg
|
||||
"pcall", // (f, arg1, ...) -> status, result1, ...
|
||||
"xpcall", // (f, err) -> result1, ...
|
||||
"print", // (...) -> void
|
||||
"select", // (f, ...) -> value1, ...
|
||||
"unpack", // (list [,i [,j]]) -> result1, ...
|
||||
"type", // (v) -> value
|
||||
"rawequal", // (v1, v2) -> boolean
|
||||
"rawget", // (table, index) -> value
|
||||
"rawset", // (table, index, value) -> table
|
||||
"setmetatable", // (table, metatable) -> table
|
||||
"tostring", // (e) -> value
|
||||
"tonumber", // (e [,base]) -> value
|
||||
"pairs", // "pairs" (t) -> iter-func, t, nil
|
||||
"ipairs", // "ipairs", // (t) -> iter-func, t, 0
|
||||
"next", // "next" ( table, [index] ) -> next-index, next-value
|
||||
"__inext", // "inext" ( table, [int-index] ) -> next-index, next-value
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a base libarary instance.
|
||||
*/
|
||||
public BaseLib() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
env.set( "_G", env );
|
||||
env.set( "_VERSION", Lua._VERSION );
|
||||
bind( env, BaseLib2.class, LIB2_KEYS );
|
||||
bind( env, BaseLibV.class, LIBV_KEYS );
|
||||
|
||||
// remember next, and inext for use in pairs and ipairs
|
||||
next = env.get("next");
|
||||
inext = env.get("__inext");
|
||||
|
||||
// inject base lib int vararg instances
|
||||
for ( int i=0; i<LIBV_KEYS.length; i++ )
|
||||
((BaseLibV) env.get(LIBV_KEYS[i])).baselib = this;
|
||||
|
||||
// set the default resource finder if not set already
|
||||
if ( FINDER == null )
|
||||
FINDER = this;
|
||||
return env;
|
||||
}
|
||||
|
||||
/** ResourceFinder implementation
|
||||
*
|
||||
* Tries to open the file as a resource, which can work for .
|
||||
*/
|
||||
public InputStream findResource(String filename) {
|
||||
Class c = getClass();
|
||||
return c.getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
|
||||
}
|
||||
|
||||
static final class BaseLib2 extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
switch ( opcode ) {
|
||||
case 0: // "collectgarbage", // ( opt [,arg] ) -> value
|
||||
String s = arg1.checkjstring();
|
||||
int result = 0;
|
||||
if ( "collect".equals(s) ) {
|
||||
System.gc();
|
||||
return ZERO;
|
||||
} else if ( "count".equals(s) ) {
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
long used = rt.totalMemory() - rt.freeMemory();
|
||||
return valueOf(used/1024.);
|
||||
} else if ( "step".equals(s) ) {
|
||||
System.gc();
|
||||
return LuaValue.TRUE;
|
||||
} else {
|
||||
this.argerror(1, "gc op");
|
||||
}
|
||||
return NIL;
|
||||
case 1: // "error", // ( message [,level] ) -> ERR
|
||||
throw new LuaError( arg1.isnil()? null: arg1.tojstring(), arg2.optint(1) );
|
||||
case 2: { // "setfenv", // (f, table) -> void
|
||||
LuaTable t = arg2.checktable();
|
||||
LuaValue f = getfenvobj(arg1);
|
||||
if ( ! f.isthread() && ! f.isclosure() )
|
||||
error("'setfenv' cannot change environment of given object");
|
||||
f.setfenv(t);
|
||||
return f.isthread()? NONE: f;
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
private static LuaValue getfenvobj(LuaValue arg) {
|
||||
if ( arg.isfunction() )
|
||||
return arg;
|
||||
int level = arg.optint(1);
|
||||
arg.argcheck(level>=0, 1, "level must be non-negative");
|
||||
if ( level == 0 )
|
||||
return LuaThread.getRunning();
|
||||
LuaValue f = LuaThread.getCallstackFunction(level);
|
||||
arg.argcheck(f != null, 1, "invalid level");
|
||||
return f;
|
||||
}
|
||||
|
||||
static final class BaseLibV extends VarArgFunction {
|
||||
public BaseLib baselib;
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: // "assert", // ( v [,message] ) -> v, message | ERR
|
||||
if ( !args.arg1().toboolean() )
|
||||
error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" );
|
||||
return args;
|
||||
case 1: // "dofile", // ( filename ) -> result1, ...
|
||||
{
|
||||
Varargs v = args.isnil(1)?
|
||||
BaseLib.loadStream( baselib.STDIN, "=stdin" ):
|
||||
BaseLib.loadFile( args.checkjstring(1) );
|
||||
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
|
||||
}
|
||||
case 2: // "getfenv", // ( [f] ) -> env
|
||||
{
|
||||
LuaValue f = getfenvobj(args.arg1());
|
||||
LuaValue e = f.getfenv();
|
||||
return e!=null? e: NIL;
|
||||
}
|
||||
case 3: // "getmetatable", // ( object ) -> table
|
||||
{
|
||||
LuaValue mt = args.checkvalue(1).getmetatable();
|
||||
return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL;
|
||||
}
|
||||
case 4: // "load", // ( func [,chunkname] ) -> chunk | nil, msg
|
||||
{
|
||||
LuaValue func = args.checkfunction(1);
|
||||
String chunkname = args.optjstring(2, "function");
|
||||
return BaseLib.loadStream(new StringInputStream(func), chunkname);
|
||||
}
|
||||
case 5: // "loadfile", // ( [filename] ) -> chunk | nil, msg
|
||||
{
|
||||
return args.isnil(1)?
|
||||
BaseLib.loadStream( baselib.STDIN, "stdin" ):
|
||||
BaseLib.loadFile( args.checkjstring(1) );
|
||||
}
|
||||
case 6: // "loadstring", // ( string [,chunkname] ) -> chunk | nil, msg
|
||||
{
|
||||
LuaString script = args.checkstring(1);
|
||||
String chunkname = args.optjstring(2, "string");
|
||||
return BaseLib.loadStream(script.toInputStream(),chunkname);
|
||||
}
|
||||
case 7: // "pcall", // (f, arg1, ...) -> status, result1, ...
|
||||
{
|
||||
LuaValue func = args.checkvalue(1);
|
||||
LuaThread.CallStack cs = LuaThread.onCall(this);
|
||||
try {
|
||||
return pcall(func,args.subargs(2),null);
|
||||
} finally {
|
||||
cs.onReturn();
|
||||
}
|
||||
}
|
||||
case 8: // "xpcall", // (f, err) -> result1, ...
|
||||
{
|
||||
LuaThread.CallStack cs = LuaThread.onCall(this);
|
||||
try {
|
||||
return pcall(args.arg1(),NONE,args.checkvalue(2));
|
||||
} finally {
|
||||
cs.onReturn();
|
||||
}
|
||||
}
|
||||
case 9: // "print", // (...) -> void
|
||||
{
|
||||
LuaValue tostring = LuaThread.getGlobals().get("tostring");
|
||||
for ( int i=1, n=args.narg(); i<=n; i++ ) {
|
||||
if ( i>1 ) baselib.STDOUT.write( '\t' );
|
||||
LuaString s = tostring.call( args.arg(i) ).strvalue();
|
||||
int z = s.indexOf((byte)0, 0);
|
||||
baselib.STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length );
|
||||
}
|
||||
baselib.STDOUT.println();
|
||||
return NONE;
|
||||
}
|
||||
case 10: // "select", // (f, ...) -> value1, ...
|
||||
{
|
||||
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);
|
||||
}
|
||||
case 11: // "unpack", // (list [,i [,j]]) -> result1, ...
|
||||
{
|
||||
int na = args.narg();
|
||||
LuaTable t = args.checktable(1);
|
||||
int n = t.length();
|
||||
int i = na>=2? args.checkint(2): 1;
|
||||
int j = na>=3? args.checkint(3): n;
|
||||
n = j-i+1;
|
||||
if ( n<0 ) return NONE;
|
||||
if ( n==1 ) return t.get(i);
|
||||
if ( n==2 ) return varargsOf(t.get(i),t.get(j));
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
for ( int k=0; k<n; k++ )
|
||||
v[k] = t.get(i+k);
|
||||
return varargsOf(v);
|
||||
}
|
||||
case 12: // "type", // (v) -> value
|
||||
return valueOf(args.checkvalue(1).typename());
|
||||
case 13: // "rawequal", // (v1, v2) -> boolean
|
||||
return valueOf(args.checkvalue(1) == args.checkvalue(2));
|
||||
case 14: // "rawget", // (table, index) -> value
|
||||
return args.checktable(1).rawget(args.checkvalue(2));
|
||||
case 15: { // "rawset", // (table, index, value) -> table
|
||||
LuaTable t = args.checktable(1);
|
||||
t.rawset(args.checknotnil(2), args.checkvalue(3));
|
||||
return t;
|
||||
}
|
||||
case 16: { // "setmetatable", // (table, metatable) -> table
|
||||
final LuaValue t = args.arg1();
|
||||
final LuaValue mt0 = t.getmetatable();
|
||||
if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
|
||||
error("cannot change a protected metatable");
|
||||
final LuaValue mt = args.checkvalue(2);
|
||||
return t.setmetatable(mt.isnil()? null: mt.checktable());
|
||||
}
|
||||
case 17: { // "tostring", // (e) -> value
|
||||
LuaValue arg = args.checkvalue(1);
|
||||
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());
|
||||
}
|
||||
case 18: { // "tonumber", // (e [,base]) -> value
|
||||
LuaValue arg1 = args.checkvalue(1);
|
||||
final int base = args.optint(2,10);
|
||||
if (base == 10) { /* standard conversion */
|
||||
return arg1.tonumber();
|
||||
} else {
|
||||
if ( base < 2 || base > 36 )
|
||||
argerror(2, "base out of range");
|
||||
return arg1.checkstring().tonumber(base);
|
||||
}
|
||||
}
|
||||
case 19: // "pairs" (t) -> iter-func, t, nil
|
||||
return varargsOf( baselib.next, args.checktable(1), NIL );
|
||||
case 20: // "ipairs", // (t) -> iter-func, t, 0
|
||||
return varargsOf( baselib.inext, args.checktable(1), ZERO );
|
||||
case 21: // "next" ( table, [index] ) -> next-index, next-value
|
||||
return args.checktable(1).next(args.arg(2));
|
||||
case 22: // "inext" ( table, [int-index] ) -> next-index, next-value
|
||||
return args.checktable(1).inext(args.arg(2));
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public static Varargs pcall(LuaValue func, Varargs args, LuaValue errfunc) {
|
||||
LuaValue olderr = LuaThread.setErrorFunc(errfunc);
|
||||
try {
|
||||
Varargs result = varargsOf(LuaValue.TRUE, func.invoke(args));
|
||||
LuaThread.setErrorFunc(olderr);
|
||||
return result;
|
||||
} catch ( LuaError le ) {
|
||||
LuaThread.setErrorFunc(olderr);
|
||||
String m = le.getMessage();
|
||||
return varargsOf(FALSE, m!=null? valueOf(m): NIL);
|
||||
} catch ( Exception e ) {
|
||||
LuaThread.setErrorFunc(olderr);
|
||||
String m = e.getMessage();
|
||||
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a named file, returning the chunk or nil,error of can't load
|
||||
* @return Varargs containing chunk, or NIL,error-text on error
|
||||
*/
|
||||
public static Varargs loadFile(String filename) {
|
||||
InputStream is = FINDER.findResource(filename);
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory"));
|
||||
try {
|
||||
return loadStream(is, "@"+filename);
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Varargs loadStream(InputStream is, String chunkname) {
|
||||
try {
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("not found: "+chunkname));
|
||||
return LoadState.load(is, chunkname, LuaThread.getGlobals());
|
||||
} 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++];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012 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 org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Subclass of LibFunction that implements the Lua standard {@code bit32} library.
|
||||
*/
|
||||
public class Bit32Lib extends ZeroArgFunction
|
||||
{
|
||||
public LuaValue call( )
|
||||
{
|
||||
LuaTable t = new LuaTable();
|
||||
bind( t, Bit32LibV.class, new String[] {
|
||||
"band", "bnot", "bor", "btest", "bxor", "extract", "replace"
|
||||
} );
|
||||
bind( t, Bit32Lib2.class, new String[] {
|
||||
"arshift", "lrotate", "lshift", "rrotate", "rshift"
|
||||
} );
|
||||
env.set( "bit32", t );
|
||||
return t;
|
||||
}
|
||||
|
||||
public static final class Bit32LibV extends VarArgFunction
|
||||
{
|
||||
public Varargs invoke( Varargs args )
|
||||
{
|
||||
switch( opcode )
|
||||
{
|
||||
case 0: // band
|
||||
{
|
||||
int result = -1;
|
||||
for( int i = 1; i <= args.narg(); i++ )
|
||||
{
|
||||
result &= args.checkint( i );
|
||||
}
|
||||
return bitsToValue( result );
|
||||
}
|
||||
case 1: // bnot
|
||||
return bitsToValue( ~args.checkint( 1 ) );
|
||||
case 2: // bot
|
||||
{
|
||||
int result = 0;
|
||||
for( int i = 1; i <= args.narg(); i++ )
|
||||
{
|
||||
result |= args.checkint( i );
|
||||
}
|
||||
return bitsToValue( result );
|
||||
}
|
||||
case 3: // btest
|
||||
{
|
||||
int bits = -1;
|
||||
for( int i = 1; i <= args.narg(); i++ )
|
||||
{
|
||||
bits &= args.checkint( i );
|
||||
}
|
||||
return valueOf( bits != 0 );
|
||||
}
|
||||
case 4: // bxor
|
||||
{
|
||||
int result = 0;
|
||||
for( int i = 1; i <= args.narg(); i++ )
|
||||
{
|
||||
result ^= args.checkint( i );
|
||||
}
|
||||
return bitsToValue( result );
|
||||
}
|
||||
case 5: // extract
|
||||
{
|
||||
int field = args.checkint( 2 );
|
||||
int width = args.optint( 3, 1 );
|
||||
|
||||
if( field < 0 ) argerror( 2, "field cannot be negative" );
|
||||
if( width <= 0 ) argerror( 3, "width must be postive" );
|
||||
if( field + width > 32 ) error( "trying to access non-existent bits" );
|
||||
|
||||
return bitsToValue( (args.checkint( 1 ) >>> field) & (-1 >>> (32 - width)) );
|
||||
}
|
||||
case 6: // replace
|
||||
{
|
||||
int n = args.checkint( 1 );
|
||||
int v = args.checkint( 2 );
|
||||
int field = args.checkint( 3 );
|
||||
int width = args.optint( 4, 1 );
|
||||
|
||||
if( field < 0 ) argerror( 3, "field cannot be negative" );
|
||||
if( width <= 0 ) argerror( 4, "width must be postive" );
|
||||
if( field + width > 32 ) error( "trying to access non-existent bits" );
|
||||
|
||||
int mask = (-1 >>> (32 - width)) << field;
|
||||
n = (n & ~mask) | ((v << field) & mask);
|
||||
return bitsToValue( n );
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Bit32Lib2 extends TwoArgFunction
|
||||
{
|
||||
public LuaValue call( LuaValue arg1, LuaValue arg2 )
|
||||
{
|
||||
switch( opcode )
|
||||
{
|
||||
case 0: // arshift
|
||||
{
|
||||
int x = arg1.checkint();
|
||||
int disp = arg2.checkint();
|
||||
return disp >= 0 ? bitsToValue( x >> disp ) : bitsToValue( x << -disp );
|
||||
}
|
||||
case 1: // lrotate
|
||||
return rotate( arg1.checkint(), arg2.checkint() );
|
||||
case 2: // lshift
|
||||
return shift( arg1.checkint(), arg2.checkint() );
|
||||
case 3: // rrotate
|
||||
return rotate( arg1.checkint(), -arg2.checkint() );
|
||||
case 4: // rshift
|
||||
return shift( arg1.checkint(), -arg2.checkint() );
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
static LuaValue rotate( int x, int disp )
|
||||
{
|
||||
if( disp < 0 )
|
||||
{
|
||||
disp = -disp & 31;
|
||||
return bitsToValue( (x >>> disp) | (x << (32 - disp)) );
|
||||
}
|
||||
else
|
||||
{
|
||||
disp = disp & 31;
|
||||
return bitsToValue( (x << disp) | (x >>> (32 - disp)) );
|
||||
}
|
||||
}
|
||||
|
||||
static LuaValue shift( int x, int disp )
|
||||
{
|
||||
if( disp >= 32 || disp <= -32 )
|
||||
{
|
||||
return ZERO;
|
||||
}
|
||||
else if( disp >= 0 )
|
||||
{
|
||||
return bitsToValue( x << disp );
|
||||
}
|
||||
else
|
||||
{
|
||||
return bitsToValue( x >>> -disp );
|
||||
}
|
||||
}
|
||||
|
||||
private static LuaValue bitsToValue( int x )
|
||||
{
|
||||
return x < 0 ? LuaValue.valueOf( (long) x & 0xFFFFFFFFL ) : LuaInteger.valueOf( x );
|
||||
}
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007-2011 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
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 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,
|
||||
* 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
|
||||
* {@link JsePlatform#standardGlobals()} or {@link JmePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* _G.load(new CoroutineLib());
|
||||
* } </pre>
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* <p>
|
||||
* @see LibFunction
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.2">http://www.lua.org/manual/5.1/manual.html#5.2</a>
|
||||
*/
|
||||
public class CoroutineLib extends VarArgFunction {
|
||||
|
||||
private static final int INIT = 0;
|
||||
private static final int CREATE = 1;
|
||||
private static final int RESUME = 2;
|
||||
private static final int RUNNING = 3;
|
||||
private static final int STATUS = 4;
|
||||
private static final int YIELD = 5;
|
||||
private static final int WRAP = 6;
|
||||
private static final int WRAPPED = 7;
|
||||
|
||||
public CoroutineLib() {
|
||||
}
|
||||
|
||||
private LuaTable init() {
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, CoroutineLib.class, new String[] {
|
||||
"create", "resume", "running", "status", "yield", "wrap" },
|
||||
CREATE);
|
||||
env.set("coroutine", t);
|
||||
PackageLib.instance.LOADED.set("coroutine", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case INIT: {
|
||||
return init();
|
||||
}
|
||||
case CREATE: {
|
||||
final LuaValue func = args.checkfunction(1);
|
||||
/* DAN200 START */
|
||||
//return new LuaThread(func, LuaThread.getGlobals() );
|
||||
final LuaThread thread = new LuaThread( func, LuaThread.getGlobals() );
|
||||
LuaThread.getRunning().addChild( thread );
|
||||
return thread;
|
||||
/* DAN200 END */
|
||||
}
|
||||
case RESUME: {
|
||||
final LuaThread t = args.checkthread(1);
|
||||
return t.resume( args.subargs(2) );
|
||||
}
|
||||
case RUNNING: {
|
||||
final LuaThread r = LuaThread.getRunning();
|
||||
return LuaThread.isMainThread(r)? NIL: r;
|
||||
}
|
||||
case STATUS: {
|
||||
return valueOf( args.checkthread(1).getStatus() );
|
||||
}
|
||||
case YIELD: {
|
||||
return LuaThread.yield( args );
|
||||
}
|
||||
case WRAP: {
|
||||
final LuaValue func = args.checkfunction(1);
|
||||
final LuaThread thread = new LuaThread(func, func.getfenv());
|
||||
/* DAN200 START */
|
||||
LuaThread.getRunning().addChild( thread );
|
||||
/* DAN200 END */
|
||||
CoroutineLib cl = new CoroutineLib();
|
||||
cl.setfenv(thread);
|
||||
cl.name = "wrapped";
|
||||
cl.opcode = WRAPPED;
|
||||
return cl;
|
||||
}
|
||||
case WRAPPED: {
|
||||
final LuaThread t = (LuaThread) env;
|
||||
final Varargs result = t.resume( args );
|
||||
if ( result.arg1().toboolean() ) {
|
||||
return result.subargs(2);
|
||||
} else {
|
||||
error( result.arg(2).tojstring() );
|
||||
}
|
||||
}
|
||||
default:
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,977 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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.lang.ref.WeakReference;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaBoolean;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaNil;
|
||||
import org.luaj.vm2.LuaNumber;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
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>
|
||||
* 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.
|
||||
* Especially when lua-to-java bytecode compiling is being used
|
||||
* via a {@link LuaCompiler} such as {@link LuaJC},
|
||||
* this cannot be done in all cases.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link JsePlatform#debugGlobals()} or {@link JmePlatform#debugGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* _G.load(new DebugLib());
|
||||
* } </pre>
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* <p>
|
||||
* @see LibFunction
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.9">http://www.lua.org/manual/5.1/manual.html#5.9</a>
|
||||
*/
|
||||
public class DebugLib extends VarArgFunction {
|
||||
public static final boolean CALLS = (null != System.getProperty("CALLS"));
|
||||
public static final boolean TRACE = (null != System.getProperty("TRACE"));
|
||||
|
||||
// leave this unset to allow obfuscators to
|
||||
// remove it in production builds
|
||||
public static boolean DEBUG_ENABLED;
|
||||
|
||||
static final String[] NAMES = {
|
||||
"debug",
|
||||
"getfenv",
|
||||
"gethook",
|
||||
"getinfo",
|
||||
"getlocal",
|
||||
"getmetatable",
|
||||
"getregistry",
|
||||
"getupvalue",
|
||||
"setfenv",
|
||||
"sethook",
|
||||
"setlocal",
|
||||
"setmetatable",
|
||||
"setupvalue",
|
||||
"traceback",
|
||||
};
|
||||
|
||||
private static final int INIT = 0;
|
||||
private static final int DEBUG = 1;
|
||||
private static final int GETFENV = 2;
|
||||
private static final int GETHOOK = 3;
|
||||
private static final int GETINFO = 4;
|
||||
private static final int GETLOCAL = 5;
|
||||
private static final int GETMETATABLE = 6;
|
||||
private static final int GETREGISTRY = 7;
|
||||
private static final int GETUPVALUE = 8;
|
||||
private static final int SETFENV = 9;
|
||||
private static final int SETHOOK = 10;
|
||||
private static final int SETLOCAL = 11;
|
||||
private static final int SETMETATABLE = 12;
|
||||
private static final int SETUPVALUE = 13;
|
||||
private static final int TRACEBACK = 14;
|
||||
|
||||
/* maximum stack for a Lua function */
|
||||
private static final int MAXSTACK = 250;
|
||||
|
||||
private static final LuaString LUA = valueOf("Lua");
|
||||
private static final LuaString JAVA = valueOf("Java");
|
||||
private static final LuaString QMARK = valueOf("?");
|
||||
private static final LuaString GLOBAL = valueOf("global");
|
||||
private static final LuaString LOCAL = valueOf("local");
|
||||
private static final LuaString METHOD = valueOf("method");
|
||||
private static final LuaString UPVALUE = valueOf("upvalue");
|
||||
private static final LuaString FIELD = valueOf("field");
|
||||
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 TAILRETURN = valueOf("tail return");
|
||||
|
||||
private static final LuaString FUNC = valueOf("func");
|
||||
private static final LuaString NUPS = valueOf("nups");
|
||||
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");
|
||||
|
||||
public DebugLib() {
|
||||
}
|
||||
|
||||
private LuaTable init() {
|
||||
DEBUG_ENABLED = true;
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, DebugLib.class, NAMES, DEBUG);
|
||||
env.set("debug", t);
|
||||
PackageLib.instance.LOADED.set("debug", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case INIT: return init();
|
||||
case DEBUG: return _debug(args);
|
||||
case GETFENV: return _getfenv(args);
|
||||
case GETHOOK: return _gethook(args);
|
||||
case GETINFO: return _getinfo(args,this);
|
||||
case GETLOCAL: return _getlocal(args);
|
||||
case GETMETATABLE: return _getmetatable(args);
|
||||
case GETREGISTRY: return _getregistry(args);
|
||||
case GETUPVALUE: return _getupvalue(args);
|
||||
case SETFENV: return _setfenv(args);
|
||||
case SETHOOK: return _sethook(args);
|
||||
case SETLOCAL: return _setlocal(args);
|
||||
case SETMETATABLE: return _setmetatable(args);
|
||||
case SETUPVALUE: return _setupvalue(args);
|
||||
case TRACEBACK: return _traceback(args);
|
||||
default: return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------ Debug Info management --------------------------
|
||||
//
|
||||
// when DEBUG_ENABLED is set to true, these functions will be called
|
||||
// by Closure instances as they process bytecodes.
|
||||
//
|
||||
// Each thread will get a DebugState attached to it by the debug library
|
||||
// which will track function calls, hook functions, etc.
|
||||
//
|
||||
static class DebugInfo {
|
||||
LuaValue func;
|
||||
LuaClosure closure;
|
||||
LuaValue[] stack;
|
||||
Varargs varargs, extras;
|
||||
int pc, top;
|
||||
|
||||
private DebugInfo() {
|
||||
func = NIL;
|
||||
}
|
||||
private DebugInfo(LuaValue func) {
|
||||
pc = -1;
|
||||
setfunction( func );
|
||||
}
|
||||
void setargs(Varargs varargs, LuaValue[] stack) {
|
||||
this.varargs = varargs;
|
||||
this.stack = stack;
|
||||
}
|
||||
void setfunction( LuaValue func ) {
|
||||
this.func = func;
|
||||
this.closure = (func instanceof LuaClosure? (LuaClosure) func: null);
|
||||
}
|
||||
void clear() {
|
||||
func = NIL;
|
||||
closure = null;
|
||||
stack = null;
|
||||
varargs = extras = null;
|
||||
pc = top = 0;
|
||||
}
|
||||
public void bytecode(int pc, Varargs extras, int top) {
|
||||
this.pc = pc;
|
||||
this.top = top;
|
||||
this.extras = extras;
|
||||
}
|
||||
public int currentline() {
|
||||
if ( closure == null ) return -1;
|
||||
int[] li = closure.p.lineinfo;
|
||||
return li==null || pc<0 || pc>=li.length? -1: li[pc];
|
||||
}
|
||||
public LuaString[] getfunckind() {
|
||||
if ( closure == null || pc<0 ) return null;
|
||||
int stackpos = (closure.p.code[pc] >> 6) & 0xff;
|
||||
return getobjname(this, stackpos);
|
||||
}
|
||||
public String sourceline() {
|
||||
if ( closure == null ) return func.tojstring();
|
||||
String s = closure.p.source.tojstring();
|
||||
int line = currentline();
|
||||
return (s.startsWith("@")||s.startsWith("=")? s.substring(1): s) + ":" + line;
|
||||
}
|
||||
public String tracename() {
|
||||
// if ( func != null )
|
||||
// return func.tojstring();
|
||||
LuaString[] kind = getfunckind();
|
||||
if ( kind == null )
|
||||
return "function ?";
|
||||
return "function "+kind[0].tojstring();
|
||||
}
|
||||
public LuaString getlocalname(int index) {
|
||||
if ( closure == null ) return null;
|
||||
return closure.p.getlocalname(index, pc);
|
||||
}
|
||||
public String tojstring() {
|
||||
return tracename()+" "+sourceline();
|
||||
}
|
||||
}
|
||||
|
||||
/** DebugState is associated with a Thread */
|
||||
static class DebugState {
|
||||
private final WeakReference thread_ref;
|
||||
private int debugCalls = 0;
|
||||
private DebugInfo[] debugInfo = new DebugInfo[LuaThread.MAX_CALLSTACK+1];
|
||||
private LuaValue hookfunc;
|
||||
private boolean hookcall,hookline,hookrtrn,inhook;
|
||||
private int hookcount,hookcodes;
|
||||
private int line;
|
||||
DebugState(LuaThread thread) {
|
||||
this.thread_ref = new WeakReference(thread);
|
||||
}
|
||||
public DebugInfo nextInfo() {
|
||||
DebugInfo di = debugInfo[debugCalls];
|
||||
if ( di == null )
|
||||
debugInfo[debugCalls] = di = new DebugInfo();
|
||||
return di;
|
||||
}
|
||||
public DebugInfo pushInfo( int calls ) {
|
||||
while ( debugCalls < calls ) {
|
||||
nextInfo();
|
||||
++debugCalls;
|
||||
}
|
||||
return debugInfo[debugCalls-1];
|
||||
}
|
||||
public void popInfo(int calls) {
|
||||
while ( debugCalls > calls )
|
||||
debugInfo[--debugCalls].clear();
|
||||
}
|
||||
void callHookFunc(DebugState ds, LuaString type, LuaValue arg) {
|
||||
if ( inhook || hookfunc == null )
|
||||
return;
|
||||
inhook = true;
|
||||
try {
|
||||
int n = debugCalls;
|
||||
ds.nextInfo().setargs( arg, null );
|
||||
ds.pushInfo(n+1).setfunction(hookfunc);
|
||||
try {
|
||||
hookfunc.call(type,arg);
|
||||
} finally {
|
||||
ds.popInfo(n);
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
inhook = false;
|
||||
}
|
||||
}
|
||||
public void sethook(LuaValue func, boolean call, boolean line, boolean rtrn, int count) {
|
||||
this.hookcount = count;
|
||||
this.hookcall = call;
|
||||
this.hookline = line;
|
||||
this.hookrtrn = rtrn;
|
||||
this.hookfunc = func;
|
||||
}
|
||||
DebugInfo getDebugInfo() {
|
||||
try {
|
||||
return debugInfo[debugCalls-1];
|
||||
} catch ( Exception e ) {
|
||||
if ( debugCalls <= 0 )
|
||||
return debugInfo[debugCalls++] = new DebugInfo();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
DebugInfo getDebugInfo(int level) {
|
||||
return level < 0 || level >= debugCalls? null: debugInfo[debugCalls-level-1];
|
||||
}
|
||||
public DebugInfo findDebugInfo(LuaValue func) {
|
||||
for ( int i=debugCalls; --i>=0; ) {
|
||||
if ( debugInfo[i].func == func ) {
|
||||
return debugInfo[i];
|
||||
}
|
||||
}
|
||||
return new DebugInfo(func);
|
||||
}
|
||||
public String tojstring() {
|
||||
LuaThread thread = (LuaThread) thread_ref.get();
|
||||
return thread != null? DebugLib.traceback(thread, 0): "orphaned thread";
|
||||
}
|
||||
}
|
||||
|
||||
static DebugState getDebugState( LuaThread thread ) {
|
||||
if ( thread.debugState == null )
|
||||
thread.debugState = new DebugState(thread);
|
||||
return (DebugState) thread.debugState;
|
||||
}
|
||||
|
||||
static DebugState getDebugState() {
|
||||
return getDebugState( LuaThread.getRunning() );
|
||||
}
|
||||
|
||||
/** Called by Closures to set up stack and arguments to next call */
|
||||
public static void debugSetupCall(Varargs args, LuaValue[] stack) {
|
||||
DebugState ds = getDebugState();
|
||||
if ( ds.inhook )
|
||||
return;
|
||||
ds.nextInfo().setargs( args, stack );
|
||||
}
|
||||
|
||||
/** Called by Closures and recursing java functions on entry
|
||||
* @param thread the thread for the call
|
||||
* @param calls the number of calls in the call stack
|
||||
* @param func the function called
|
||||
*/
|
||||
public static void debugOnCall(LuaThread thread, int calls, LuaFunction func) {
|
||||
DebugState ds = getDebugState();
|
||||
if ( ds.inhook )
|
||||
return;
|
||||
DebugInfo di = ds.pushInfo(calls);
|
||||
di.setfunction( func );
|
||||
if(CALLS)System.out.println("calling "+func);
|
||||
if ( ds.hookcall )
|
||||
ds.callHookFunc( ds, CALL, LuaValue.NIL );
|
||||
}
|
||||
|
||||
/** Called by Closures and recursing java functions on return
|
||||
* @param thread the thread for the call
|
||||
* @param calls the number of calls in the call stack
|
||||
*/
|
||||
public static void debugOnReturn(LuaThread thread, int calls) {
|
||||
DebugState ds = getDebugState(thread);
|
||||
if ( ds.inhook )
|
||||
return;
|
||||
if(CALLS)System.out.println("returning");
|
||||
try {
|
||||
if ( ds.hookrtrn )
|
||||
ds.callHookFunc( ds, RETURN, LuaValue.NIL );
|
||||
} finally {
|
||||
getDebugState().popInfo(calls);
|
||||
}
|
||||
}
|
||||
|
||||
/** Called by Closures on bytecode execution */
|
||||
public static void debugBytecode( int pc, Varargs extras, int top ) {
|
||||
DebugState ds = getDebugState();
|
||||
if ( ds.inhook )
|
||||
return;
|
||||
DebugInfo di = ds.getDebugInfo();
|
||||
if(TRACE)Print.printState(di.closure, pc, di.stack, top, di.varargs);
|
||||
di.bytecode( pc, extras, top );
|
||||
if ( ds.hookcount > 0 ) {
|
||||
if ( ++ds.hookcodes >= ds.hookcount ) {
|
||||
ds.hookcodes = 0;
|
||||
ds.callHookFunc( ds, COUNT, LuaValue.NIL );
|
||||
}
|
||||
}
|
||||
if ( ds.hookline ) {
|
||||
int newline = di.currentline();
|
||||
if ( newline != ds.line ) {
|
||||
int c = di.closure.p.code[pc];
|
||||
if ( (c&0x3f) != Lua.OP_JMP || ((c>>>14)-0x1ffff) >= 0 ) {
|
||||
ds.line = newline;
|
||||
ds.callHookFunc( ds, LINE, LuaValue.valueOf(newline) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------- library function implementations -----------------
|
||||
|
||||
// j2se subclass may wish to override and provide actual console here.
|
||||
// j2me platform has not System.in to provide console.
|
||||
static Varargs _debug(Varargs args) {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
static Varargs _gethook(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
DebugState ds = getDebugState(thread);
|
||||
return varargsOf(
|
||||
ds.hookfunc,
|
||||
valueOf((ds.hookcall?"c":"")+(ds.hookline?"l":"")+(ds.hookrtrn?"r":"")),
|
||||
valueOf(ds.hookcount));
|
||||
}
|
||||
|
||||
static Varargs _sethook(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
LuaValue func = args.optfunction(a++, null);
|
||||
String str = args.optjstring(a++,"");
|
||||
int count = args.optint(a++,0);
|
||||
boolean call=false,line=false,rtrn=false;
|
||||
for ( int i=0; i<str.length(); i++ )
|
||||
switch ( str.charAt(i) ) {
|
||||
case 'c': call=true; break;
|
||||
case 'l': line=true; break;
|
||||
case 'r': rtrn=true; break;
|
||||
}
|
||||
getDebugState(thread).sethook(func, call, line, rtrn, count);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
static Varargs _getfenv(Varargs args) {
|
||||
LuaValue object = args.arg1();
|
||||
LuaValue env = object.getfenv();
|
||||
return env!=null? env: LuaValue.NIL;
|
||||
}
|
||||
|
||||
static Varargs _setfenv(Varargs args) {
|
||||
LuaValue object = args.arg1();
|
||||
LuaTable table = args.checktable(2);
|
||||
object.setfenv(table);
|
||||
return object;
|
||||
}
|
||||
|
||||
protected static Varargs _getinfo(Varargs args, LuaValue level0func) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
LuaValue func = args.arg(a++);
|
||||
String what = args.optjstring(a++, "nSluf");
|
||||
|
||||
// find the stack info
|
||||
DebugState ds = getDebugState( thread );
|
||||
DebugInfo di = null;
|
||||
if ( func.isnumber() ) {
|
||||
int level = func.checkint();
|
||||
di = level>0?
|
||||
ds.getDebugInfo(level-1):
|
||||
new DebugInfo( level0func );
|
||||
} else {
|
||||
di = ds.findDebugInfo( func.checkfunction() );
|
||||
}
|
||||
if ( di == null )
|
||||
return NIL;
|
||||
|
||||
// start a table
|
||||
LuaTable info = new LuaTable();
|
||||
LuaClosure c = di.closure;
|
||||
for (int i = 0, j = what.length(); i < j; i++) {
|
||||
switch (what.charAt(i)) {
|
||||
case 'S': {
|
||||
if ( c != null ) {
|
||||
Prototype p = c.p;
|
||||
info.set(WHAT, LUA);
|
||||
info.set(SOURCE, p.source);
|
||||
info.set(SHORT_SRC, valueOf(sourceshort(p)));
|
||||
info.set(LINEDEFINED, valueOf(p.linedefined));
|
||||
info.set(LASTLINEDEFINED, valueOf(p.lastlinedefined));
|
||||
} else {
|
||||
String shortName = di.func.tojstring();
|
||||
LuaString name = LuaString.valueOf("[Java] "+shortName);
|
||||
info.set(WHAT, JAVA);
|
||||
info.set(SOURCE, name);
|
||||
info.set(SHORT_SRC, valueOf(shortName));
|
||||
info.set(LINEDEFINED, LuaValue.MINUSONE);
|
||||
info.set(LASTLINEDEFINED, LuaValue.MINUSONE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
int line = di.currentline();
|
||||
info.set( CURRENTLINE, valueOf(line) );
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
info.set(NUPS, valueOf(c!=null? c.p.nups: 0));
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
LuaString[] kind = di.getfunckind();
|
||||
info.set(NAME, kind!=null? kind[0]: QMARK);
|
||||
info.set(NAMEWHAT, kind!=null? kind[1]: EMPTYSTRING);
|
||||
break;
|
||||
}
|
||||
case 'f': {
|
||||
info.set( FUNC, di.func );
|
||||
break;
|
||||
}
|
||||
case 'L': {
|
||||
LuaTable lines = new LuaTable();
|
||||
info.set(ACTIVELINES, lines);
|
||||
// if ( di.luainfo != null ) {
|
||||
// int line = di.luainfo.currentline();
|
||||
// if ( line >= 0 )
|
||||
// lines.set(1, IntValue.valueOf(line));
|
||||
// }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public static String sourceshort(Prototype p) {
|
||||
String name = p.source.tojstring();
|
||||
if ( name.startsWith("@") || name.startsWith("=") )
|
||||
name = name.substring(1);
|
||||
else if ( name.startsWith("\033") )
|
||||
name = "binary string";
|
||||
return name;
|
||||
}
|
||||
|
||||
static Varargs _getlocal(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
int level = args.checkint(a++);
|
||||
int local = args.checkint(a++);
|
||||
|
||||
DebugState ds = getDebugState(thread);
|
||||
DebugInfo di = ds.getDebugInfo(level-1);
|
||||
LuaString name = (di!=null? di.getlocalname(local): null);
|
||||
if ( name != null ) {
|
||||
LuaValue value = di.stack[local-1];
|
||||
return varargsOf( name, value );
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
static Varargs _setlocal(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
int level = args.checkint(a++);
|
||||
int local = args.checkint(a++);
|
||||
LuaValue value = args.arg(a++);
|
||||
|
||||
DebugState ds = getDebugState(thread);
|
||||
DebugInfo di = ds.getDebugInfo(level-1);
|
||||
LuaString name = (di!=null? di.getlocalname(local): null);
|
||||
if ( name != null ) {
|
||||
di.stack[local-1] = value;
|
||||
return name;
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
static LuaValue _getmetatable(Varargs args) {
|
||||
LuaValue object = args.arg(1);
|
||||
LuaValue mt = object.getmetatable();
|
||||
return mt!=null? mt: NIL;
|
||||
}
|
||||
|
||||
static Varargs _setmetatable(Varargs args) {
|
||||
LuaValue object = args.arg(1);
|
||||
try {
|
||||
LuaValue mt = args.opttable(2, null);
|
||||
switch ( object.type() ) {
|
||||
case TNIL: LuaNil.s_metatable = mt; break;
|
||||
case TNUMBER: LuaNumber.s_metatable = mt; break;
|
||||
case TBOOLEAN: LuaBoolean.s_metatable = mt; break;
|
||||
case TSTRING: LuaString.s_metatable = mt; break;
|
||||
case TFUNCTION: LuaFunction.s_metatable = mt; break;
|
||||
case TTHREAD: LuaThread.s_metatable = mt; break;
|
||||
default: object.setmetatable( mt );
|
||||
}
|
||||
return LuaValue.TRUE;
|
||||
} catch ( LuaError e ) {
|
||||
return varargsOf(FALSE, valueOf(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
static Varargs _getregistry(Varargs args) {
|
||||
return new LuaTable();
|
||||
}
|
||||
|
||||
static LuaString findupvalue(LuaClosure c, int up) {
|
||||
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
|
||||
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
|
||||
return c.p.upvalues[up-1];
|
||||
else
|
||||
return LuaString.valueOf( "."+up );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Varargs _getupvalue(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
if ( func instanceof LuaClosure ) {
|
||||
LuaClosure c = (LuaClosure) func;
|
||||
LuaString name = findupvalue(c, up);
|
||||
if ( name != null ) {
|
||||
return varargsOf(name, c.upValues[up-1].getValue() );
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
static LuaValue _setupvalue(Varargs args) {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
int up = args.checkint(2);
|
||||
LuaValue value = args.arg(3);
|
||||
if ( func instanceof LuaClosure ) {
|
||||
LuaClosure c = (LuaClosure) func;
|
||||
LuaString name = findupvalue(c, up);
|
||||
if ( name != null ) {
|
||||
c.upValues[up-1].setValue(value);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
static LuaValue _traceback(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
String message = args.optjstring(a++, null);
|
||||
int level = args.optint(a++,1);
|
||||
String tb = DebugLib.traceback(thread, level-1);
|
||||
return valueOf(message!=null? message+"\n"+tb: tb);
|
||||
}
|
||||
|
||||
// =================== public utilities ====================
|
||||
|
||||
/**
|
||||
* Get a traceback as a string for the current thread
|
||||
*/
|
||||
public static String traceback(int level) {
|
||||
return traceback(LuaThread.getRunning(), level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a traceback for a particular thread.
|
||||
* @param thread LuaThread to provide stack trace for
|
||||
* @param level 0-based level to start reporting on
|
||||
* @return String containing the stack trace.
|
||||
*/
|
||||
public static String traceback(LuaThread thread, int level) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
DebugState ds = getDebugState(thread);
|
||||
sb.append( "stack traceback:" );
|
||||
DebugInfo di = ds.getDebugInfo(level);
|
||||
if ( di != null ) {
|
||||
sb.append( "\n\t" );
|
||||
sb.append( di.sourceline() );
|
||||
sb.append( " in " );
|
||||
while ( (di = ds.getDebugInfo(++level)) != null ) {
|
||||
sb.append( di.tracename() );
|
||||
sb.append( "\n\t" );
|
||||
sb.append( di.sourceline() );
|
||||
sb.append( " in " );
|
||||
}
|
||||
sb.append( "main chunk" );
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get file and line for the nearest calling closure.
|
||||
* @return String identifying the file and line of the nearest lua closure,
|
||||
* or the function name of the Java call if no closure is being called.
|
||||
*/
|
||||
public static String fileline() {
|
||||
DebugState ds = getDebugState(LuaThread.getRunning());
|
||||
DebugInfo di;
|
||||
for ( int i=0, n=ds.debugCalls; i<n; i++ ) {
|
||||
di = ds.getDebugInfo(i);
|
||||
if ( di != null && di.func.isclosure() )
|
||||
return di.sourceline();
|
||||
}
|
||||
return fileline(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file and line for a particular level, even if it is a java function.
|
||||
*
|
||||
* @param level 0-based index of level to get
|
||||
* @return String containing file and line info if available
|
||||
*/
|
||||
public static String fileline(int level) {
|
||||
DebugState ds = getDebugState(LuaThread.getRunning());
|
||||
DebugInfo di = ds.getDebugInfo(level);
|
||||
return di!=null? di.sourceline(): null;
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
|
||||
static void lua_assert(boolean x) {
|
||||
if (!x) throw new RuntimeException("lua_assert failed");
|
||||
}
|
||||
|
||||
|
||||
// return StrValue[] { name, namewhat } if found, null if not
|
||||
static LuaString[] getobjname(DebugInfo di, int stackpos) {
|
||||
LuaString name;
|
||||
if (di.closure != null) { /* a Lua function? */
|
||||
Prototype p = di.closure.p;
|
||||
int pc = di.pc; // currentpc(L, ci);
|
||||
int i;// Instruction i;
|
||||
name = p.getlocalname(stackpos + 1, pc);
|
||||
if (name != null) /* is a local? */
|
||||
return new LuaString[] { name, LOCAL };
|
||||
i = symbexec(p, pc, stackpos); /* try symbolic execution */
|
||||
lua_assert(pc != -1);
|
||||
switch (Lua.GET_OPCODE(i)) {
|
||||
case Lua.OP_GETGLOBAL: {
|
||||
int g = Lua.GETARG_Bx(i); /* global index */
|
||||
// lua_assert(p.k[g].isString());
|
||||
return new LuaString[] { p.k[g].strvalue(), GLOBAL };
|
||||
}
|
||||
case Lua.OP_MOVE: {
|
||||
int a = Lua.GETARG_A(i);
|
||||
int b = Lua.GETARG_B(i); /* move from `b' to `a' */
|
||||
if (b < a)
|
||||
return getobjname(di, b); /* get name for `b' */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETTABLE: {
|
||||
int k = Lua.GETARG_C(i); /* key index */
|
||||
name = kname(p, k);
|
||||
return new LuaString[] { name, FIELD };
|
||||
}
|
||||
case Lua.OP_GETUPVAL: {
|
||||
int u = Lua.GETARG_B(i); /* upvalue index */
|
||||
name = u < p.upvalues.length ? p.upvalues[u] : QMARK;
|
||||
return new LuaString[] { name, UPVALUE };
|
||||
}
|
||||
case Lua.OP_SELF: {
|
||||
int k = Lua.GETARG_C(i); /* key index */
|
||||
name = kname(p, k);
|
||||
return new LuaString[] { name, METHOD };
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 boolean checkreg(Prototype pt,int reg) {
|
||||
return (reg < pt.maxstacksize);
|
||||
}
|
||||
|
||||
static boolean precheck(Prototype pt) {
|
||||
if (!(pt.maxstacksize <= MAXSTACK)) return false;
|
||||
lua_assert(pt.numparams + (pt.is_vararg & Lua.VARARG_HASARG) <= pt.maxstacksize);
|
||||
lua_assert((pt.is_vararg & Lua.VARARG_NEEDSARG) == 0
|
||||
|| (pt.is_vararg & Lua.VARARG_HASARG) != 0);
|
||||
if (!(pt.upvalues.length <= pt.nups)) return false;
|
||||
if (!(pt.lineinfo.length == pt.code.length || pt.lineinfo.length == 0)) return false;
|
||||
if (!(Lua.GET_OPCODE(pt.code[pt.code.length - 1]) == Lua.OP_RETURN)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean checkopenop(Prototype pt,int pc) {
|
||||
int i = pt.code[(pc)+1];
|
||||
switch (Lua.GET_OPCODE(i)) {
|
||||
case Lua.OP_CALL:
|
||||
case Lua.OP_TAILCALL:
|
||||
case Lua.OP_RETURN:
|
||||
case Lua.OP_SETLIST: {
|
||||
if (!(Lua.GETARG_B(i) == 0)) return false;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false; /* invalid instruction after an open call */
|
||||
}
|
||||
}
|
||||
|
||||
//static int checkArgMode (Prototype pt, int r, enum OpArgMask mode) {
|
||||
static boolean checkArgMode (Prototype pt, int r, int mode) {
|
||||
switch (mode) {
|
||||
case Lua.OpArgN: if (!(r == 0)) return false; break;
|
||||
case Lua.OpArgU: break;
|
||||
case Lua.OpArgR: checkreg(pt, r); break;
|
||||
case Lua.OpArgK:
|
||||
if (!(Lua.ISK(r) ? Lua.INDEXK(r) < pt.k.length : r < pt.maxstacksize)) return false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// return last instruction, or 0 if error
|
||||
static int symbexec(Prototype pt, int lastpc, int reg) {
|
||||
int pc;
|
||||
int last; /* stores position of last instruction that changed `reg' */
|
||||
last = pt.code.length - 1; /*
|
||||
* points to final return (a `neutral'
|
||||
* instruction)
|
||||
*/
|
||||
if (!(precheck(pt))) return 0;
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
int i = pt.code[pc];
|
||||
int op = Lua.GET_OPCODE(i);
|
||||
int a = Lua.GETARG_A(i);
|
||||
int b = 0;
|
||||
int c = 0;
|
||||
if (!(op < Lua.NUM_OPCODES)) return 0;
|
||||
if (!checkreg(pt, a)) return 0;
|
||||
switch (Lua.getOpMode(op)) {
|
||||
case Lua.iABC: {
|
||||
b = Lua.GETARG_B(i);
|
||||
c = Lua.GETARG_C(i);
|
||||
if (!(checkArgMode(pt, b, Lua.getBMode(op)))) return 0;
|
||||
if (!(checkArgMode(pt, c, Lua.getCMode(op)))) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.iABx: {
|
||||
b = Lua.GETARG_Bx(i);
|
||||
if (Lua.getBMode(op) == Lua.OpArgK)
|
||||
if (!(b < pt.k.length)) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.iAsBx: {
|
||||
b = Lua.GETARG_sBx(i);
|
||||
if (Lua.getBMode(op) == Lua.OpArgR) {
|
||||
int dest = pc + 1 + b;
|
||||
if (!(0 <= dest && dest < pt.code.length)) return 0;
|
||||
if (dest > 0) {
|
||||
/* cannot jump to a setlist count */
|
||||
int d = pt.code[dest - 1];
|
||||
if ((Lua.GET_OPCODE(d) == Lua.OP_SETLIST && Lua.GETARG_C(d) == 0)) return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Lua.testAMode(op)) {
|
||||
if (a == reg)
|
||||
last = pc; /* change register `a' */
|
||||
}
|
||||
if (Lua.testTMode(op)) {
|
||||
if (!(pc + 2 < pt.code.length)) return 0; /* check skip */
|
||||
if (!(Lua.GET_OPCODE(pt.code[pc + 1]) == Lua.OP_JMP)) return 0;
|
||||
}
|
||||
switch (op) {
|
||||
case Lua.OP_LOADBOOL: {
|
||||
if (!(c == 0 || pc + 2 < pt.code.length)) return 0; /* check its jump */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_LOADNIL: {
|
||||
if (a <= reg && reg <= b)
|
||||
last = pc; /* set registers from `a' to `b' */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETUPVAL:
|
||||
case Lua.OP_SETUPVAL: {
|
||||
if (!(b < pt.nups)) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_GETGLOBAL:
|
||||
case Lua.OP_SETGLOBAL: {
|
||||
if (!(pt.k[b].isstring())) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SELF: {
|
||||
if (!checkreg(pt, a + 1)) return 0;
|
||||
if (reg == a + 1)
|
||||
last = pc;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CONCAT: {
|
||||
if (!(b < c)) return 0; /* at least two operands */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_TFORLOOP: {
|
||||
if (!(c >= 1)) return 0; /* at least one result (control variable) */
|
||||
if (!checkreg(pt, a + 2 + c)) return 0; /* space for results */
|
||||
if (reg >= a + 2)
|
||||
last = pc; /* affect all regs above its base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_FORLOOP:
|
||||
case Lua.OP_FORPREP:
|
||||
if (!checkreg(pt, a + 3)) return 0;
|
||||
/* go through */
|
||||
case Lua.OP_JMP: {
|
||||
int dest = pc + 1 + b;
|
||||
/* not full check and jump is forward and do not skip `lastpc'? */
|
||||
if (reg != Lua.NO_REG && pc < dest && dest <= lastpc)
|
||||
pc += b; /* do the jump */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CALL:
|
||||
case Lua.OP_TAILCALL: {
|
||||
if (b != 0) {
|
||||
if (!checkreg(pt, a + b - 1)) return 0;
|
||||
}
|
||||
c--; /* c = num. returns */
|
||||
if (c == Lua.LUA_MULTRET) {
|
||||
if (!(checkopenop(pt, pc))) return 0;
|
||||
} else if (c != 0)
|
||||
if (!checkreg(pt, a + c - 1)) return 0;
|
||||
if (reg >= a)
|
||||
last = pc; /* affect all registers above base */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_RETURN: {
|
||||
b--; /* b = num. returns */
|
||||
if (b > 0)
|
||||
if (!checkreg(pt, a + b - 1)) return 0;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_SETLIST: {
|
||||
if (b > 0)
|
||||
if (!checkreg(pt, a + b)) return 0;
|
||||
if (c == 0)
|
||||
pc++;
|
||||
break;
|
||||
}
|
||||
case Lua.OP_CLOSURE: {
|
||||
int nup, j;
|
||||
if (!(b < pt.p.length)) return 0;
|
||||
nup = pt.p[b].nups;
|
||||
if (!(pc + nup < pt.code.length)) return 0;
|
||||
for (j = 1; j <= nup; j++) {
|
||||
int op1 = Lua.GET_OPCODE(pt.code[pc + j]);
|
||||
if (!(op1 == Lua.OP_GETUPVAL || op1 == Lua.OP_MOVE)) return 0;
|
||||
}
|
||||
if (reg != Lua.NO_REG) /* tracing? */
|
||||
pc += nup; /* do not 'execute' these pseudo-instructions */
|
||||
break;
|
||||
}
|
||||
case Lua.OP_VARARG: {
|
||||
if (!((pt.is_vararg & Lua.VARARG_ISVARARG) != 0
|
||||
&& (pt.is_vararg & Lua.VARARG_NEEDSARG) == 0)) return 0;
|
||||
b--;
|
||||
if (b == Lua.LUA_MULTRET)
|
||||
if (!(checkopenop(pt, pc))) return 0;
|
||||
if (!checkreg(pt, a + b - 1)) return 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pt.code[last];
|
||||
}
|
||||
|
||||
}
|
@ -1,607 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
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>
|
||||
* 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
|
||||
* {@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
|
||||
* {@link JsePlatform#standardGlobals()} or {@link JmePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* _G.load(new JseIoLib());
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new JseBaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* _G.load(new JseIoLib());
|
||||
* _G.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* 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
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see JseIoLib
|
||||
* @see 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
|
||||
public class IoLib extends OneArgFunction {
|
||||
|
||||
abstract
|
||||
protected class File extends LuaValue{
|
||||
abstract public void write( LuaString string ) throws IOException;
|
||||
abstract public void flush() throws IOException;
|
||||
abstract public boolean isstdfile();
|
||||
abstract public void close() throws IOException;
|
||||
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);
|
||||
// get length remaining to read
|
||||
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 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;
|
||||
|
||||
// delegate method access to file methods table
|
||||
public LuaValue get( LuaValue key ) {
|
||||
return filemethods.get(key);
|
||||
}
|
||||
|
||||
// essentially a userdata instance
|
||||
public int type() {
|
||||
return LuaValue.TUSERDATA;
|
||||
}
|
||||
public String typename() {
|
||||
return "userdata";
|
||||
}
|
||||
|
||||
// displays as "file" type
|
||||
public String tojstring() {
|
||||
return "file: " + Integer.toHexString(hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrap the standard input.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStdin() throws IOException;
|
||||
|
||||
/**
|
||||
* Wrap the standard output.
|
||||
* @return File
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract protected File wrapStdout() throws IOException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param updateMode true if opening in update mode
|
||||
* @param binaryMode true if opening in binary mode
|
||||
* @return File object if successful
|
||||
* @throws IOException if could not be opened
|
||||
*/
|
||||
abstract protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException;
|
||||
|
||||
/**
|
||||
* Open a temporary file.
|
||||
* @return File object if successful
|
||||
* @throws IOException if could not be opened
|
||||
*/
|
||||
abstract protected File tmpFile() throws IOException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws IOException if an i/o exception occurs
|
||||
*/
|
||||
abstract protected File openProgram(String prog, String mode) throws IOException;
|
||||
|
||||
private File infile = null;
|
||||
private File outfile = null;
|
||||
private File errfile = null;
|
||||
|
||||
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 FILE = valueOf("file");
|
||||
private static final LuaValue CLOSED_FILE = valueOf("closed file");
|
||||
|
||||
private static final int IO_CLOSE = 0;
|
||||
private static final int IO_FLUSH = 1;
|
||||
private static final int IO_INPUT = 2;
|
||||
private static final int IO_LINES = 3;
|
||||
private static final int IO_OPEN = 4;
|
||||
private static final int IO_OUTPUT = 5;
|
||||
private static final int IO_POPEN = 6;
|
||||
private static final int IO_READ = 7;
|
||||
private static final int IO_TMPFILE = 8;
|
||||
private static final int IO_TYPE = 9;
|
||||
private static final int IO_WRITE = 10;
|
||||
|
||||
private static final int FILE_CLOSE = 11;
|
||||
private static final int FILE_FLUSH = 12;
|
||||
private static final int FILE_LINES = 13;
|
||||
private static final int FILE_READ = 14;
|
||||
private static final int FILE_SEEK = 15;
|
||||
private static final int FILE_SETVBUF = 16;
|
||||
private static final int FILE_WRITE = 17;
|
||||
|
||||
private static final int IO_INDEX = 18;
|
||||
private static final int LINES_ITER = 19;
|
||||
|
||||
public static final String[] IO_NAMES = {
|
||||
"close",
|
||||
"flush",
|
||||
"input",
|
||||
"lines",
|
||||
"open",
|
||||
"output",
|
||||
"popen",
|
||||
"read",
|
||||
"tmpfile",
|
||||
"type",
|
||||
"write",
|
||||
};
|
||||
|
||||
public static final String[] FILE_NAMES = {
|
||||
"close",
|
||||
"flush",
|
||||
"lines",
|
||||
"read",
|
||||
"seek",
|
||||
"setvbuf",
|
||||
"write",
|
||||
};
|
||||
|
||||
LuaTable filemethods;
|
||||
|
||||
public IoLib() {
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
|
||||
// io lib functions
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, IoLibV.class, IO_NAMES );
|
||||
|
||||
// create file methods table
|
||||
filemethods = new LuaTable();
|
||||
bind(filemethods, IoLibV.class, FILE_NAMES, FILE_CLOSE );
|
||||
|
||||
// set up file metatable
|
||||
LuaTable mt = new LuaTable();
|
||||
bind(mt, IoLibV.class, new String[] { "__index" }, IO_INDEX );
|
||||
t.setmetatable( mt );
|
||||
|
||||
// all functions link to library instance
|
||||
setLibInstance( t );
|
||||
setLibInstance( filemethods );
|
||||
setLibInstance( mt );
|
||||
|
||||
// return the table
|
||||
env.set("io", t);
|
||||
PackageLib.instance.LOADED.set("io", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
private void setLibInstance(LuaTable t) {
|
||||
LuaValue[] k = t.keys();
|
||||
for ( int i=0, n=k.length; i<n; i++ )
|
||||
((IoLibV) t.get(k[i])).iolib = this;
|
||||
}
|
||||
|
||||
static final class IoLibV extends VarArgFunction {
|
||||
public IoLib iolib;
|
||||
public IoLibV() {
|
||||
}
|
||||
public IoLibV(LuaValue env, String name, int opcode, IoLib iolib) {
|
||||
super();
|
||||
this.env = env;
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.iolib = iolib;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case IO_FLUSH: return iolib._io_flush();
|
||||
case IO_TMPFILE: return iolib._io_tmpfile();
|
||||
case IO_CLOSE: return iolib._io_close(args.arg1());
|
||||
case IO_INPUT: return iolib._io_input(args.arg1());
|
||||
case IO_OUTPUT: return iolib._io_output(args.arg1());
|
||||
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_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_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(env);
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
return errorresult(ioe);
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private File input() {
|
||||
return infile!=null? infile: (infile=ioopenfile("-","r"));
|
||||
}
|
||||
|
||||
// io.flush() -> bool
|
||||
public Varargs _io_flush() throws IOException {
|
||||
checkopen(output());
|
||||
outfile.flush();
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
// io.tmpfile() -> file
|
||||
public Varargs _io_tmpfile() throws IOException {
|
||||
return tmpFile();
|
||||
}
|
||||
|
||||
// io.close([file]) -> void
|
||||
public Varargs _io_close(LuaValue file) throws IOException {
|
||||
File f = file.isnil()? output(): checkfile(file);
|
||||
checkopen(f);
|
||||
return ioclose(f);
|
||||
}
|
||||
|
||||
// io.input([file]) -> file
|
||||
public Varargs _io_input(LuaValue file) {
|
||||
infile = file.isnil()? input():
|
||||
file.isstring()? ioopenfile(file.checkjstring(),"r"):
|
||||
checkfile(file);
|
||||
return infile;
|
||||
}
|
||||
|
||||
// io.output(filename) -> file
|
||||
public Varargs _io_output(LuaValue filename) {
|
||||
outfile = filename.isnil()? output():
|
||||
filename.isstring()? ioopenfile(filename.checkjstring(),"w"):
|
||||
checkfile(filename);
|
||||
return outfile;
|
||||
}
|
||||
|
||||
// io.type(obj) -> "file" | "closed file" | nil
|
||||
public Varargs _io_type(LuaValue obj) {
|
||||
File f = optfile(obj);
|
||||
return f!=null?
|
||||
f.isclosed()? CLOSED_FILE: FILE:
|
||||
NIL;
|
||||
}
|
||||
|
||||
// io.popen(prog, [mode]) -> file
|
||||
public Varargs _io_popen(String prog, String mode) throws IOException {
|
||||
return openProgram(prog, mode);
|
||||
}
|
||||
|
||||
// io.open(filename, [mode]) -> file | nil,err
|
||||
public Varargs _io_open(String filename, String mode) throws IOException {
|
||||
return rawopenfile(filename, mode);
|
||||
}
|
||||
|
||||
// io.lines(filename) -> iterator
|
||||
public Varargs _io_lines(String filename) {
|
||||
infile = filename==null? input(): ioopenfile(filename,"r");
|
||||
checkopen(infile);
|
||||
return lines(infile);
|
||||
}
|
||||
|
||||
// io.read(...) -> (...)
|
||||
public Varargs _io_read(Varargs args) throws IOException {
|
||||
checkopen(input());
|
||||
return ioread(infile,args);
|
||||
}
|
||||
|
||||
// io.write(...) -> void
|
||||
public Varargs _io_write(Varargs args) throws IOException {
|
||||
checkopen(output());
|
||||
return iowrite(outfile,args);
|
||||
}
|
||||
|
||||
// file:close() -> void
|
||||
public Varargs _file_close(LuaValue file) throws IOException {
|
||||
return ioclose(checkfile(file));
|
||||
}
|
||||
|
||||
// file:flush() -> void
|
||||
public Varargs _file_flush(LuaValue file) throws IOException {
|
||||
checkfile(file).flush();
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
// file:setvbuf(mode,[size]) -> void
|
||||
public Varargs _file_setvbuf(LuaValue file, String mode, int size) {
|
||||
checkfile(file).setvbuf(mode,size);
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
// file:lines() -> iterator
|
||||
public Varargs _file_lines(LuaValue file) {
|
||||
return lines(checkfile(file));
|
||||
}
|
||||
|
||||
// file:read(...) -> (...)
|
||||
public Varargs _file_read(LuaValue file, Varargs subargs) throws IOException {
|
||||
return ioread(checkfile(file),subargs);
|
||||
}
|
||||
|
||||
// file:seek([whence][,offset]) -> pos | nil,error
|
||||
public Varargs _file_seek(LuaValue file, String whence, int offset) throws IOException {
|
||||
return valueOf( checkfile(file).seek(whence,offset) );
|
||||
}
|
||||
|
||||
// file:write(...) -> void
|
||||
public Varargs _file_write(LuaValue file, Varargs subargs) throws IOException {
|
||||
return iowrite(checkfile(file),subargs);
|
||||
}
|
||||
|
||||
// __index, returns a field
|
||||
public Varargs _io_index(LuaValue v) {
|
||||
return v.equals(STDOUT)?output():
|
||||
v.equals(STDIN)? input():
|
||||
v.equals(STDERR)? errput(): NIL;
|
||||
}
|
||||
|
||||
// lines iterator(s,var) -> var'
|
||||
public Varargs _lines_iter(LuaValue file) throws IOException {
|
||||
return freadline(checkfile(file));
|
||||
}
|
||||
|
||||
private File output() {
|
||||
return outfile!=null? outfile: (outfile=ioopenfile("-","w"));
|
||||
}
|
||||
|
||||
private File errput() {
|
||||
return errfile!=null? errfile: (errfile=ioopenfile("-","w"));
|
||||
}
|
||||
|
||||
private File ioopenfile(String filename, String mode) {
|
||||
try {
|
||||
return rawopenfile(filename, mode);
|
||||
} catch ( Exception e ) {
|
||||
error("io error: "+e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs ioclose(File f) throws IOException {
|
||||
if ( f.isstdfile() )
|
||||
return errorresult("cannot close standard file");
|
||||
else {
|
||||
f.close();
|
||||
return successresult();
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs successresult() {
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
private static Varargs errorresult(Exception ioe) {
|
||||
String s = ioe.getMessage();
|
||||
return errorresult("io error: "+(s!=null? s: ioe.toString()));
|
||||
}
|
||||
|
||||
private static Varargs errorresult(String errortext) {
|
||||
return varargsOf(NIL, valueOf(errortext));
|
||||
}
|
||||
|
||||
private Varargs lines(final File f) {
|
||||
try {
|
||||
return new IoLibV(f,"lnext",LINES_ITER,this);
|
||||
} catch ( Exception e ) {
|
||||
return error("lines: "+e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs iowrite(File f, Varargs args) throws IOException {
|
||||
for ( int i=1, n=args.narg(); i<=n; i++ )
|
||||
f.write( args.checkstring(i) );
|
||||
return LuaValue.TRUE;
|
||||
}
|
||||
|
||||
private Varargs ioread(File f, Varargs args) throws IOException {
|
||||
int i,n=args.narg();
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
LuaValue ai,vi;
|
||||
LuaString fmt;
|
||||
for ( i=0; i<n; ) {
|
||||
item: switch ( (ai = args.arg(i+1)).type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
vi = freadbytes(f,ai.toint());
|
||||
break item;
|
||||
case LuaValue.TSTRING:
|
||||
fmt = ai.checkstring();
|
||||
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 'a': vi = freadall(f); break item;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return argerror( i+1, "(invalid format)" );
|
||||
}
|
||||
if ( (v[i++] = vi).isnil() )
|
||||
break;
|
||||
}
|
||||
return i==0? NIL: varargsOf(v, 0, i);
|
||||
}
|
||||
|
||||
private static File checkfile(LuaValue val) {
|
||||
File f = optfile(val);
|
||||
if ( f == null )
|
||||
argerror(1,"file");
|
||||
checkopen( f );
|
||||
return f;
|
||||
}
|
||||
|
||||
private static File optfile(LuaValue val) {
|
||||
return (val instanceof File)? (File) val: null;
|
||||
}
|
||||
|
||||
private static File checkopen(File file) {
|
||||
if ( file.isclosed() )
|
||||
error("attempt to use a closed file");
|
||||
return file;
|
||||
}
|
||||
|
||||
private File rawopenfile(String filename, String mode) throws IOException {
|
||||
boolean isstdfile = "-".equals(filename);
|
||||
boolean isreadmode = mode.startsWith("r");
|
||||
if ( isstdfile ) {
|
||||
return isreadmode?
|
||||
wrapStdin():
|
||||
wrapStdout();
|
||||
}
|
||||
boolean isappend = mode.startsWith("a");
|
||||
boolean isupdate = mode.indexOf("+") > 0;
|
||||
boolean isbinary = mode.endsWith("b");
|
||||
return openFile( filename, isreadmode, isappend, isupdate, isbinary );
|
||||
}
|
||||
|
||||
|
||||
// ------------- file reading utilitied ------------------
|
||||
|
||||
public static LuaValue freadbytes(File f, int count) throws IOException {
|
||||
byte[] b = new byte[count];
|
||||
int r;
|
||||
if ( ( r = f.read(b,0,b.length) ) < 0 )
|
||||
return NIL;
|
||||
return LuaString.valueOf(b, 0, r);
|
||||
}
|
||||
public static LuaValue freaduntil(File f,boolean lineonly) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int c;
|
||||
try {
|
||||
if ( lineonly ) {
|
||||
loop: while ( (c = f.read()) > 0 ) {
|
||||
switch ( c ) {
|
||||
case '\r': break;
|
||||
case '\n': break loop;
|
||||
default: baos.write(c); break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while ( (c = f.read()) > 0 )
|
||||
baos.write(c);
|
||||
}
|
||||
} catch ( EOFException e ) {
|
||||
c = -1;
|
||||
}
|
||||
return ( c < 0 && baos.size() == 0 )?
|
||||
(LuaValue) NIL:
|
||||
(LuaValue) LuaString.valueOf(baos.toByteArray());
|
||||
}
|
||||
public static LuaValue freadline(File f) throws IOException {
|
||||
return freaduntil(f,true);
|
||||
}
|
||||
public static LuaValue freadall(File f) throws IOException {
|
||||
int n = f.remaining();
|
||||
if ( n >= 0 ) {
|
||||
return freadbytes(f, n);
|
||||
} else {
|
||||
return freaduntil(f,false);
|
||||
}
|
||||
}
|
||||
public static LuaValue freadnumber(File f) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
freadchars(f," \t\r\n",null);
|
||||
freadchars(f,"-+",baos);
|
||||
//freadchars(f,"0",baos);
|
||||
//freadchars(f,"xX",baos);
|
||||
freadchars(f,"0123456789",baos);
|
||||
freadchars(f,".",baos);
|
||||
freadchars(f,"0123456789",baos);
|
||||
//freadchars(f,"eEfFgG",baos);
|
||||
// freadchars(f,"+-",baos);
|
||||
//freadchars(f,"0123456789",baos);
|
||||
String s = baos.toString();
|
||||
return s.length()>0? valueOf( Double.parseDouble(s) ): NIL;
|
||||
}
|
||||
private static void freadchars(File f, String chars, ByteArrayOutputStream baos) throws IOException {
|
||||
int c;
|
||||
while ( true ) {
|
||||
c = f.peek();
|
||||
if ( chars.indexOf(c) < 0 ) {
|
||||
return;
|
||||
}
|
||||
f.read();
|
||||
if ( baos != null )
|
||||
baos.write( c );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,200 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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 org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LuaFunction} common to Java functions exposed to lua.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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>
|
||||
* <li>{@link OneArgFunction}</li>
|
||||
* <li>{@link TwoArgFunction}</li>
|
||||
* <li>{@link ThreeArgFunction}</li>
|
||||
* <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"
|
||||
* with two functions, "sinh", and "cosh":
|
||||
<pre> {@code
|
||||
* import org.luaj.vm2.LuaValue;
|
||||
* import org.luaj.vm2.lib.OneArgFunction;
|
||||
*
|
||||
* public class hyperbolic extends OneArgFunction {
|
||||
*
|
||||
* public hyperbolic() {}
|
||||
*
|
||||
* public LuaValue call(LuaValue libname) {
|
||||
* LuaValue library = tableOf();
|
||||
* library.set( "sinh", new sinh() );
|
||||
* library.set( "cosh", new cosh() );
|
||||
* env.set( "hyperbolic", library );
|
||||
* return library;
|
||||
* }
|
||||
*
|
||||
* static class sinh extends OneArgFunction {
|
||||
* public LuaValue call(LuaValue x) {
|
||||
* return LuaValue.valueOf(Math.sinh(x.checkdouble()));
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* static class cosh extends OneArgFunction {
|
||||
* public LuaValue call(LuaValue x) {
|
||||
* return LuaValue.valueOf(Math.cosh(x.checkdouble()));
|
||||
* }
|
||||
* }
|
||||
*}
|
||||
*}</pre>
|
||||
* The default constructor is used to instantiate the library
|
||||
* in response to {@code require 'hyperbolic'} statement,
|
||||
* provided it is on Javas class path.
|
||||
* This instance is then invoked with the name supplied to require()
|
||||
* as the only argument, and library should initialized whatever global
|
||||
* data it needs to and place it into the environment if needed.
|
||||
* In this case, it creates two function, 'sinh', and 'cosh', and puts
|
||||
* them into a global table called 'hyperbolic.'
|
||||
* It placed the library table into the globals via the {@link #env}
|
||||
* local variable which corresponds to the globals that apply when the
|
||||
* library is loaded.
|
||||
* <p>
|
||||
* To test it, a script such as this can be used:
|
||||
* <pre> {@code
|
||||
* local t = require('hyperbolic')
|
||||
* print( 't', t )
|
||||
* print( 'hyperbolic', hyperbolic )
|
||||
* for k,v in pairs(t) do
|
||||
* print( 'k,v', k,v )
|
||||
* end
|
||||
* print( 'sinh(.5)', hyperbolic.sinh(.5) )
|
||||
* print( 'cosh(.5)', hyperbolic.cosh(.5) )
|
||||
* }</pre>
|
||||
* <p>
|
||||
* It should produce something like:
|
||||
* <pre> {@code
|
||||
* t table: 3dbbd23f
|
||||
* hyperbolic table: 3dbbd23f
|
||||
* k,v cosh function: 3dbbd128
|
||||
* 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.
|
||||
*/
|
||||
abstract public class LibFunction extends LuaFunction {
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
protected int opcode;
|
||||
|
||||
/** The common name for this function, useful for debugging.
|
||||
* <p>
|
||||
* Binding functions initialize this to the name to which it is bound.
|
||||
*/
|
||||
protected String name;
|
||||
|
||||
/** Default constructor for use by subclasses */
|
||||
protected LibFunction() {
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return name != null? name: super.tojstring();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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)
|
||||
*/
|
||||
protected void bind(LuaValue env, Class factory, String[] names ) {
|
||||
bind( env, factory, names, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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[])
|
||||
*/
|
||||
protected void bind(LuaValue env, Class factory, String[] names, int firstopcode ) {
|
||||
try {
|
||||
for ( int i=0, n=names.length; i<n; i++ ) {
|
||||
LibFunction f = (LibFunction) factory.newInstance();
|
||||
f.opcode = firstopcode + i;
|
||||
f.name = names[i];
|
||||
f.env = env;
|
||||
env.set(f.name, f);
|
||||
}
|
||||
} 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() {
|
||||
return new LuaValue[1];
|
||||
}
|
||||
|
||||
/** Java code generation utility to allocate storage for upvalue, initialize with nil */
|
||||
protected static LuaValue[] newupn() {
|
||||
return new LuaValue[] { NIL };
|
||||
}
|
||||
|
||||
/** Java code generation utility to allocate storage for upvalue, initialize with value */
|
||||
protected static LuaValue[] newupl(LuaValue v) {
|
||||
return new LuaValue[] { v };
|
||||
}
|
||||
}
|
@ -1,251 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.util.Random;
|
||||
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
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}.
|
||||
* In Particular the following math functions are <b>not</b> implemented by this library:
|
||||
* <ul>
|
||||
* <li>acos</li>
|
||||
* <li>asin</li>
|
||||
* <li>atan</li>
|
||||
* <li>cosh</li>
|
||||
* <li>log</li>
|
||||
* <li>log10</li>
|
||||
* <li>sinh</li>
|
||||
* <li>tanh</li>
|
||||
* <li>atan2</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 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 JmePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new BaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* _G.load(new MathLib());
|
||||
* System.out.println( _G.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* 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
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see JseMathLib
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.6">http://www.lua.org/manual/5.1/manual.html#5.6</a>
|
||||
*/
|
||||
public class MathLib extends OneArgFunction {
|
||||
|
||||
public static MathLib MATHLIB = null;
|
||||
|
||||
private Random random;
|
||||
|
||||
public MathLib() {
|
||||
MATHLIB = this;
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaTable t = new LuaTable(0,30);
|
||||
t.set( "pi", Math.PI );
|
||||
t.set( "huge", LuaDouble.POSINF );
|
||||
bind( t, MathLib1.class, new String[] {
|
||||
"abs", "ceil", "cos", "deg",
|
||||
"exp", "floor", "rad", "sin",
|
||||
"sqrt", "tan" } );
|
||||
bind( t, MathLib2.class, new String[] {
|
||||
"fmod", "ldexp", "pow", } );
|
||||
bind( t, MathLibV.class, new String[] {
|
||||
"frexp", "max", "min", "modf",
|
||||
"randomseed", "random", } );
|
||||
((MathLibV) t.get("randomseed")).mathlib = this;
|
||||
((MathLibV) t.get("random" )).mathlib = this;
|
||||
env.set("math", t);
|
||||
PackageLib.instance.LOADED.set("math", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
static final class MathLib1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: return valueOf(Math.abs(arg.checkdouble()));
|
||||
case 1: return valueOf(Math.ceil(arg.checkdouble()));
|
||||
case 2: return valueOf(Math.cos(arg.checkdouble()));
|
||||
case 3: return valueOf(Math.toDegrees(arg.checkdouble()));
|
||||
case 4: return dpow(Math.E,arg.checkdouble());
|
||||
case 5: return valueOf(Math.floor(arg.checkdouble()));
|
||||
case 6: return valueOf(Math.toRadians(arg.checkdouble()));
|
||||
case 7: return valueOf(Math.sin(arg.checkdouble()));
|
||||
case 8: return valueOf(Math.sqrt(arg.checkdouble()));
|
||||
case 9: return valueOf(Math.tan(arg.checkdouble()));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
static final class MathLib2 extends TwoArgFunction {
|
||||
protected MathLib mathlib;
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
switch ( opcode ) {
|
||||
case 0: { // fmod
|
||||
double x = arg1.checkdouble();
|
||||
double y = arg2.checkdouble();
|
||||
double q = x/y;
|
||||
double f = x - y * (q>=0? Math.floor(q): Math.ceil(q));
|
||||
return valueOf( f );
|
||||
}
|
||||
case 1: { // ldexp
|
||||
double x = arg1.checkdouble();
|
||||
double y = arg2.checkdouble()+1023.5;
|
||||
long e = (long) ((0!=(1&((int)y)))? Math.floor(y): Math.ceil(y-1));
|
||||
return valueOf(x * Double.longBitsToDouble(e << 52));
|
||||
}
|
||||
case 2: { // pow
|
||||
return dpow(arg1.checkdouble(), arg2.checkdouble());
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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(
|
||||
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):
|
||||
dpow_default(a,b);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
protected static double dpow_default(double a, double b) {
|
||||
if ( b < 0 )
|
||||
return 1 / dpow_default( a, -b );
|
||||
double p = 1;
|
||||
int whole = (int) b;
|
||||
for ( double v=a; whole > 0; whole>>=1, v*=v )
|
||||
if ( (whole & 1) != 0 )
|
||||
p *= v;
|
||||
if ( (b -= whole) > 0 ) {
|
||||
int frac = (int) (0x10000 * b);
|
||||
for ( ; (frac&0xffff)!=0; frac<<=1 ) {
|
||||
a = Math.sqrt(a);
|
||||
if ( (frac & 0x8000) != 0 )
|
||||
p *= a;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static final class MathLibV extends VarArgFunction {
|
||||
protected MathLib mathlib;
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: { // frexp
|
||||
double x = args.checkdouble(1);
|
||||
if ( x == 0 ) return varargsOf(ZERO,ZERO);
|
||||
long bits = Double.doubleToLongBits( x );
|
||||
double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52)));
|
||||
double e = (((int) (bits >> 52)) & 0x7ff) - 1022;
|
||||
return varargsOf( valueOf(m), valueOf(e) );
|
||||
}
|
||||
case 1: { // max
|
||||
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);
|
||||
}
|
||||
case 2: { // min
|
||||
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);
|
||||
}
|
||||
case 3: { // modf
|
||||
double x = args.checkdouble(1);
|
||||
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
|
||||
double fracPart = x - intPart;
|
||||
return varargsOf( valueOf(intPart), valueOf(fracPart) );
|
||||
}
|
||||
case 4: { // randomseed
|
||||
long seed = args.checklong(1);
|
||||
mathlib.random = new Random(seed);
|
||||
return NONE;
|
||||
}
|
||||
case 5: { // random
|
||||
if ( mathlib.random == null )
|
||||
mathlib.random = new Random();
|
||||
|
||||
switch ( args.narg() ) {
|
||||
case 0:
|
||||
return valueOf( mathlib.random.nextDouble() );
|
||||
case 1: {
|
||||
int m = args.checkint(1);
|
||||
if (m<1) argerror(1, "interval is empty");
|
||||
return valueOf( 1 + mathlib.random.nextInt(m) );
|
||||
}
|
||||
default: {
|
||||
int m = args.checkint(1);
|
||||
int n = args.checkint(2);
|
||||
if (n<m) argerror(2, "interval is empty");
|
||||
return valueOf( m + mathlib.random.nextInt(n+1-m) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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 org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that take one argument and
|
||||
* return one value.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
|
||||
* are routed through this method by this class,
|
||||
* dropping or extending arguments with {@code nil} values as required.
|
||||
* <p>
|
||||
* If more than one argument are required, or no arguments are required,
|
||||
* or variable argument or variable return values,
|
||||
* then use one of the related function
|
||||
* {@link ZeroArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #call(LuaValue)
|
||||
* @see LibFunction
|
||||
* @see ZeroArgFunction
|
||||
* @see TwoArgFunction
|
||||
* @see ThreeArgFunction
|
||||
* @see VarArgFunction
|
||||
*/
|
||||
abstract public class OneArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg);
|
||||
|
||||
/** Default constructor */
|
||||
public OneArgFunction() {
|
||||
}
|
||||
|
||||
/** Constructor with specific environment
|
||||
* @param env The environment to apply during constructon.
|
||||
*/
|
||||
public OneArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return call(NIL);
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return call(arg1);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return call(arg1);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call(varargs.arg1());
|
||||
}
|
||||
}
|
@ -1,323 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* The following functions have limited implementations of features
|
||||
* that are not supported well on Jme:
|
||||
* <ul>
|
||||
* <li>{@code execute()}</li>
|
||||
* <li>{@code remove()}</li>
|
||||
* <li>{@code rename()}</li>
|
||||
* <li>{@code tmpname()}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link JmePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new BaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* _G.load(new OsLib());
|
||||
* System.out.println( _G.get("os").get("time").call() );
|
||||
* } </pre>
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* <p>
|
||||
* @see LibFunction
|
||||
* @see JseOsLib
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @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 VarArgFunction {
|
||||
public static String TMP_PREFIX = ".luaj";
|
||||
public static String TMP_SUFFIX = "tmp";
|
||||
|
||||
private static final int INIT = 0;
|
||||
private static final int CLOCK = 1;
|
||||
private static final int DATE = 2;
|
||||
private static final int DIFFTIME = 3;
|
||||
private static final int EXECUTE = 4;
|
||||
private static final int EXIT = 5;
|
||||
private static final int GETENV = 6;
|
||||
private static final int REMOVE = 7;
|
||||
private static final int RENAME = 8;
|
||||
private static final int SETLOCALE = 9;
|
||||
private static final int TIME = 10;
|
||||
private static final int TMPNAME = 11;
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"clock",
|
||||
"date",
|
||||
"difftime",
|
||||
"execute",
|
||||
"exit",
|
||||
"getenv",
|
||||
"remove",
|
||||
"rename",
|
||||
"setlocale",
|
||||
"time",
|
||||
"tmpname",
|
||||
};
|
||||
|
||||
private static final long t0 = System.currentTimeMillis();
|
||||
private static long tmpnames = t0;
|
||||
|
||||
/**
|
||||
* Create and OsLib instance.
|
||||
*/
|
||||
public OsLib() {
|
||||
}
|
||||
|
||||
public LuaValue init() {
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, this.getClass(), NAMES, CLOCK);
|
||||
env.set("os", t);
|
||||
PackageLib.instance.LOADED.set("os", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case INIT:
|
||||
return init();
|
||||
case CLOCK:
|
||||
return valueOf(clock());
|
||||
case DATE: {
|
||||
String s = args.optjstring(1, null);
|
||||
double t = args.optdouble(2,-1);
|
||||
return valueOf( date(s, t==-1? System.currentTimeMillis()/1000.: t) );
|
||||
}
|
||||
case DIFFTIME:
|
||||
return valueOf(difftime(args.checkdouble(1),args.checkdouble(2)));
|
||||
case EXECUTE:
|
||||
return valueOf(execute(args.optjstring(1, null)));
|
||||
case EXIT:
|
||||
exit(args.optint(1, 0));
|
||||
return NONE;
|
||||
case GETENV: {
|
||||
final String val = getenv(args.checkjstring(1));
|
||||
return val!=null? valueOf(val): NIL;
|
||||
}
|
||||
case REMOVE:
|
||||
remove(args.checkjstring(1));
|
||||
return LuaValue.TRUE;
|
||||
case RENAME:
|
||||
rename(args.checkjstring(1), args.checkjstring(2));
|
||||
return LuaValue.TRUE;
|
||||
case SETLOCALE: {
|
||||
String s = setlocale(args.optjstring(1,null), args.optjstring(2, "all"));
|
||||
return s!=null? valueOf(s): NIL;
|
||||
}
|
||||
case TIME:
|
||||
return valueOf(time(args.arg1().isnil()? null: args.checktable(1)));
|
||||
case TMPNAME:
|
||||
return valueOf(tmpname());
|
||||
}
|
||||
return NONE;
|
||||
} catch ( IOException e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an approximation of the amount in seconds of CPU time used by
|
||||
* the program.
|
||||
*/
|
||||
protected double clock() {
|
||||
return (System.currentTimeMillis()-t0) / 1000.;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return diffeence in time values, in seconds
|
||||
*/
|
||||
protected double difftime(double t2, double t1) {
|
||||
return t2 - t1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* If format starts with '!', then the date is formatted in Coordinated
|
||||
* Universal Time. After this optional character, if format is the string
|
||||
* "*t", then date returns a table with the following fields: year
|
||||
* (four digits), month (1--12), day (1--31), hour (0--23), min (0--59),
|
||||
* sec (0--61), wday (weekday, Sunday is 1), yday (day of the year),
|
||||
* and isdst (daylight saving flag, a boolean).
|
||||
*
|
||||
* If format is not "*t", then date returns the date as a string,
|
||||
* formatted according to the same rules as the C function strftime.
|
||||
*
|
||||
* 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 time time since epoch, or -1 if not supplied
|
||||
* @return a LString or a LTable containing date and time,
|
||||
* formatted according to the given string format.
|
||||
*/
|
||||
protected String date(String format, double time) {
|
||||
return new java.util.Date((long)(time*1000)).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 int execute(String command) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the C function exit, with an optional code, to terminate the host program.
|
||||
* @param code
|
||||
*/
|
||||
protected void exit(int code) {
|
||||
/* DAN200 START */
|
||||
//System.exit(code);
|
||||
/* DAN200 END */
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the process environment variable varname,
|
||||
* or null if the variable is not defined.
|
||||
* @param varname
|
||||
* @return String value, or null if not defined
|
||||
*/
|
||||
protected String getenv(String varname) {
|
||||
return System.getProperty(varname);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected void remove(String filename) throws IOException {
|
||||
throw new IOException( "not implemented" );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected void rename(String oldname, String newname) throws IOException {
|
||||
throw new IOException( "not implemented" );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* to the standard C locale.
|
||||
*
|
||||
* 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
|
||||
* cannot be honored.
|
||||
*/
|
||||
protected String setlocale(String locale, String category) {
|
||||
return "C";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected long time(LuaTable table) {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @return String filename to use
|
||||
*/
|
||||
protected String tmpname() {
|
||||
synchronized ( OsLib.class ) {
|
||||
return TMP_PREFIX+(tmpnames++)+TMP_SUFFIX;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,466 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010-2011 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.InputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
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 standard package and module
|
||||
* library functions.
|
||||
*
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link JsePlatform#standardGlobals()} or {@link JmePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new BaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* System.out.println( _G.get("require").call(LuaValue.valueOf("hyperbolic")) );
|
||||
* } </pre>
|
||||
* In practice, the first 4 lines of the above are minimal requirements to get
|
||||
* and initialize a globals table capable of basic reqire, print, and other functions,
|
||||
* so it is much more convenient to use the {@link JsePlatform} and {@link JmePlatform}
|
||||
* utility classes instead.
|
||||
* <p>
|
||||
* This 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 JseBaseLib} documetnation.
|
||||
* @see LibFunction
|
||||
* @see BaseLib
|
||||
* @see JseBaseLib
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.3">http://www.lua.org/manual/5.1/manual.html#5.3</a>
|
||||
*/
|
||||
public class PackageLib extends OneArgFunction {
|
||||
|
||||
public static String DEFAULT_LUA_PATH = "?.lua";
|
||||
|
||||
public InputStream STDIN = null;
|
||||
public PrintStream STDOUT = System.out;
|
||||
public LuaTable LOADED;
|
||||
public LuaTable PACKAGE;
|
||||
|
||||
/** Most recent instance of PackageLib */
|
||||
public static PackageLib instance;
|
||||
|
||||
/** Loader that loads from preload table if found there */
|
||||
public LuaValue preload_loader;
|
||||
|
||||
/** Loader that loads as a lua script using the LUA_PATH */
|
||||
public LuaValue lua_loader;
|
||||
|
||||
/** Loader that loads as a Java class. Class must have public constructor and be a LuaValue */
|
||||
public LuaValue java_loader;
|
||||
|
||||
private static final LuaString _M = valueOf("_M");
|
||||
private static final LuaString _NAME = valueOf("_NAME");
|
||||
private static final LuaString _PACKAGE = valueOf("_PACKAGE");
|
||||
private static final LuaString _DOT = valueOf(".");
|
||||
private static final LuaString _LOADERS = valueOf("loaders");
|
||||
private 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 _SEEALL = valueOf("seeall");
|
||||
private static final LuaString _SENTINEL = valueOf("\u0001");
|
||||
|
||||
private static final int OP_MODULE = 0;
|
||||
private static final int OP_REQUIRE = 1;
|
||||
private static final int OP_LOADLIB = 2;
|
||||
private static final int OP_SEEALL = 3;
|
||||
private static final int OP_PRELOAD_LOADER = 4;
|
||||
private static final int OP_LUA_LOADER = 5;
|
||||
private static final int OP_JAVA_LOADER = 6;
|
||||
|
||||
public PackageLib() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
env.set("require", new PkgLib1(env,"require",OP_REQUIRE,this));
|
||||
env.set("module", new PkgLibV(env,"module",OP_MODULE,this));
|
||||
env.set( "package", PACKAGE=tableOf( new LuaValue[] {
|
||||
_LOADED, LOADED=tableOf(),
|
||||
_PRELOAD, tableOf(),
|
||||
_PATH, valueOf(DEFAULT_LUA_PATH),
|
||||
_LOADLIB, new PkgLibV(env,"loadlib",OP_LOADLIB,this),
|
||||
_SEEALL, new PkgLib1(env,"seeall",OP_SEEALL,this),
|
||||
_LOADERS, listOf(new LuaValue[] {
|
||||
preload_loader = new PkgLibV(env,"preload_loader", OP_PRELOAD_LOADER,this),
|
||||
lua_loader = new PkgLibV(env,"lua_loader", OP_LUA_LOADER,this),
|
||||
java_loader = new PkgLibV(env,"java_loader", OP_JAVA_LOADER,this),
|
||||
}) }) );
|
||||
LOADED.set("package", PACKAGE);
|
||||
return env;
|
||||
}
|
||||
|
||||
static final class PkgLib1 extends OneArgFunction {
|
||||
PackageLib lib;
|
||||
public PkgLib1(LuaValue env,String name, int opcode, PackageLib lib) {
|
||||
this.env = env;
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.lib = lib;
|
||||
}
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case OP_REQUIRE:
|
||||
return lib.require(arg);
|
||||
case OP_SEEALL: {
|
||||
LuaTable t = arg.checktable();
|
||||
LuaValue m = t.getmetatable();
|
||||
if ( m == null )
|
||||
t.setmetatable(m=tableOf());
|
||||
m.set( INDEX, LuaThread.getGlobals() );
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
static final class PkgLibV extends VarArgFunction {
|
||||
PackageLib lib;
|
||||
public PkgLibV(LuaValue env,String name, int opcode, PackageLib lib) {
|
||||
this.env = env;
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.lib = lib;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case OP_MODULE:
|
||||
return lib.module(args);
|
||||
case OP_LOADLIB:
|
||||
return loadlib(args);
|
||||
case OP_PRELOAD_LOADER: {
|
||||
return lib.loader_preload(args);
|
||||
}
|
||||
case OP_LUA_LOADER: {
|
||||
return lib.loader_Lua(args);
|
||||
}
|
||||
case OP_JAVA_LOADER: {
|
||||
return lib.loader_Java(args);
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/** Allow packages to mark themselves as loaded */
|
||||
public void setIsLoaded(String name, LuaTable value) {
|
||||
LOADED.set(name, value);
|
||||
}
|
||||
|
||||
public void setLuaPath( String newLuaPath ) {
|
||||
PACKAGE.set( _PATH, valueOf(newLuaPath) );
|
||||
}
|
||||
|
||||
public String tojstring() {
|
||||
return "package";
|
||||
}
|
||||
|
||||
|
||||
// ======================== Module, Package loading =============================
|
||||
/**
|
||||
* module (name [, ...])
|
||||
*
|
||||
* Creates a module. If there is a table in package.loaded[name], this table
|
||||
* is the module. Otherwise, if there is a global table t with the given
|
||||
* name, this table is the module. Otherwise creates a new table t and sets
|
||||
* it as the value of the global name and the value of package.loaded[name].
|
||||
* This function also initializes t._NAME with the given name, t._M with the
|
||||
* module (t itself), and t._PACKAGE with the package name (the full module
|
||||
* name minus last component; see below). Finally, module sets t as the new
|
||||
* environment of the current function and the new value of
|
||||
* package.loaded[name], so that require returns t.
|
||||
*
|
||||
* If name is a compound name (that is, one with components separated by
|
||||
* dots), module creates (or reuses, if they already exist) tables for each
|
||||
* component. For instance, if name is a.b.c, then module stores the module
|
||||
* table in field c of field b of global a.
|
||||
*
|
||||
* This function may receive optional options after the module name, where
|
||||
* each option is a function to be applied over the module.
|
||||
*/
|
||||
public Varargs module(Varargs args) {
|
||||
LuaString modname = args.checkstring(1);
|
||||
int n = args.narg();
|
||||
LuaValue value = LOADED.get(modname);
|
||||
LuaValue module;
|
||||
if ( ! value.istable() ) { /* not found? */
|
||||
|
||||
/* try global variable (and create one if it does not exist) */
|
||||
LuaValue globals = LuaThread.getGlobals();
|
||||
module = findtable( globals, modname );
|
||||
if ( module == null )
|
||||
error( "name conflict for module '"+modname+"'" );
|
||||
LOADED.set(modname, module);
|
||||
} else {
|
||||
module = (LuaTable) value;
|
||||
}
|
||||
|
||||
|
||||
/* check whether table already has a _NAME field */
|
||||
LuaValue name = module.get(_NAME);
|
||||
if ( name.isnil() ) {
|
||||
modinit( module, modname );
|
||||
}
|
||||
|
||||
// set the environment of the current function
|
||||
LuaFunction f = LuaThread.getCallstackFunction(1);
|
||||
if ( f == null )
|
||||
error("no calling function");
|
||||
if ( ! f.isclosure() )
|
||||
error("'module' not called from a Lua function");
|
||||
f.setfenv(module);
|
||||
|
||||
// apply the functions
|
||||
for ( int i=2; i<=n; i++ )
|
||||
args.arg(i).call( module );
|
||||
|
||||
// returns no results
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param table the table at which to start the search
|
||||
* @param fname the name to look up or create, such as "abc.def.ghi"
|
||||
* @return the table for that name, possible a new one, or null if a non-table has that name already.
|
||||
*/
|
||||
private static final LuaValue findtable(LuaValue table, LuaString fname) {
|
||||
int b, e=(-1);
|
||||
do {
|
||||
e = fname.indexOf(_DOT, b=e+1 );
|
||||
if ( e < 0 )
|
||||
e = fname.m_length;
|
||||
LuaString key = fname.substring(b, e);
|
||||
LuaValue val = table.rawget(key);
|
||||
if ( val.isnil() ) { /* no such field? */
|
||||
LuaTable field = new LuaTable(); /* new table for field */
|
||||
table.set(key, field);
|
||||
table = field;
|
||||
} else if ( ! val.istable() ) { /* field has a non-table value? */
|
||||
return null;
|
||||
} else {
|
||||
table = val;
|
||||
}
|
||||
} while ( e < fname.m_length );
|
||||
return table;
|
||||
}
|
||||
|
||||
private static final void modinit(LuaValue module, LuaString modname) {
|
||||
/* module._M = module */
|
||||
module.set(_M, module);
|
||||
int e = modname.lastIndexOf(_DOT);
|
||||
module.set(_NAME, modname );
|
||||
module.set(_PACKAGE, (e<0? EMPTYSTRING: modname.substring(0,e+1)) );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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.loaders array. By changing this array,
|
||||
* we can change how require looks for a module. The following explanation is based on the
|
||||
* default configuration for package.loaders.
|
||||
*
|
||||
* 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 C loader
|
||||
* using the path stored in package.cpath. If that also fails, it tries an all-in-one loader
|
||||
* (see package.loaders).
|
||||
*
|
||||
* Once a loader is found, require calls the loader with a single argument, modname.
|
||||
* If the loader returns any value, require assigns the returned value to package.loaded[modname].
|
||||
* If the loader returns no 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 signals an error.
|
||||
*/
|
||||
public LuaValue require( LuaValue arg ) {
|
||||
LuaString name = arg.checkstring();
|
||||
LuaValue loaded = LOADED.get(name);
|
||||
if ( loaded.toboolean() ) {
|
||||
if ( loaded == _SENTINEL )
|
||||
error("loop or previous error loading module '"+name+"'");
|
||||
return loaded;
|
||||
}
|
||||
|
||||
/* else must load it; iterate over available loaders */
|
||||
LuaTable tbl = PACKAGE.get(_LOADERS).checktable();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
LuaValue chunk = null;
|
||||
for ( int i=1; true; i++ ) {
|
||||
LuaValue loader = tbl.get(i);
|
||||
if ( loader.isnil() ) {
|
||||
error( "module '"+name+"' not found: "+name+sb );
|
||||
}
|
||||
|
||||
/* call loader with module name as argument */
|
||||
chunk = loader.call(name);
|
||||
if ( chunk.isfunction() )
|
||||
break;
|
||||
if ( chunk.isstring() )
|
||||
sb.append( chunk.tojstring() );
|
||||
}
|
||||
|
||||
// load the module using the loader
|
||||
LOADED.set(name, _SENTINEL);
|
||||
LuaValue result = chunk.call(name);
|
||||
if ( ! result.isnil() )
|
||||
LOADED.set( name, result );
|
||||
else if ( (result = LOADED.get(name)) == _SENTINEL )
|
||||
LOADED.set( name, result = LuaValue.TRUE );
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Varargs loadlib( Varargs args ) {
|
||||
args.checkstring(1);
|
||||
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
|
||||
}
|
||||
|
||||
LuaValue loader_preload( Varargs args ) {
|
||||
LuaString name = args.checkstring(1);
|
||||
LuaValue preload = PACKAGE.get(_PRELOAD).checktable();
|
||||
LuaValue val = preload.get(name);
|
||||
return val.isnil()?
|
||||
valueOf("\n\tno field package.preload['"+name+"']"):
|
||||
val;
|
||||
}
|
||||
|
||||
LuaValue loader_Lua( Varargs args ) {
|
||||
String name = args.checkjstring(1);
|
||||
InputStream is = null;
|
||||
|
||||
|
||||
// get package path
|
||||
LuaValue pp = PACKAGE.get(_PATH);
|
||||
if ( ! pp.isstring() )
|
||||
return valueOf("package.path is not a string");
|
||||
String path = pp.tojstring();
|
||||
|
||||
// check the path elements
|
||||
int e = -1;
|
||||
int n = path.length();
|
||||
StringBuffer sb = null;
|
||||
name = name.replace('.','/');
|
||||
while ( e < n ) {
|
||||
|
||||
// find next template
|
||||
int b = e+1;
|
||||
e = path.indexOf(';',b);
|
||||
if ( e < 0 )
|
||||
e = path.length();
|
||||
String template = path.substring(b,e);
|
||||
|
||||
// create filename
|
||||
int q = template.indexOf('?');
|
||||
String filename = template;
|
||||
if ( q >= 0 ) {
|
||||
filename = template.substring(0,q) + name + template.substring(q+1);
|
||||
}
|
||||
|
||||
// try loading the file
|
||||
Varargs v = BaseLib.loadFile(filename);
|
||||
if ( v.arg1().isfunction() )
|
||||
return v.arg1();
|
||||
|
||||
// report error
|
||||
if ( sb == null )
|
||||
sb = new StringBuffer();
|
||||
sb.append( "\n\t'"+filename+"': "+v.arg(2) );
|
||||
}
|
||||
return valueOf(sb.toString());
|
||||
}
|
||||
|
||||
LuaValue loader_Java( Varargs args ) {
|
||||
String name = args.checkjstring(1);
|
||||
String classname = toClassname( name );
|
||||
Class c = null;
|
||||
LuaValue v = null;
|
||||
try {
|
||||
c = Class.forName(classname);
|
||||
v = (LuaValue) c.newInstance();
|
||||
v.setfenv(env);
|
||||
return v;
|
||||
} catch ( ClassNotFoundException cnfe ) {
|
||||
return valueOf("\n\tno class '"+classname+"'" );
|
||||
} catch ( Exception e ) {
|
||||
return valueOf("\n\tjava load failed on '"+classname+"', "+e );
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert lua filename to valid class name */
|
||||
public static final String toClassname( String filename ) {
|
||||
int n=filename.length();
|
||||
int j=n;
|
||||
if ( filename.endsWith(".lua") )
|
||||
j -= 4;
|
||||
for ( int k=0; k<j; k++ ) {
|
||||
char c = filename.charAt(k);
|
||||
if ( (!isClassnamePart(c)) || (c=='/') || (c=='\\') ) {
|
||||
StringBuffer sb = new StringBuffer(j);
|
||||
for ( int i=0; i<j; i++ ) {
|
||||
c = filename.charAt(i);
|
||||
sb.append(
|
||||
(isClassnamePart(c))? c:
|
||||
((c=='/') || (c=='\\'))? '.': '_' );
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
return n==j? filename: filename.substring(0,j);
|
||||
}
|
||||
|
||||
private static final boolean isClassnamePart(char c) {
|
||||
if ( (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') )
|
||||
return true;
|
||||
switch ( c ) {
|
||||
case '.':
|
||||
case '$':
|
||||
case '_':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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.InputStream;
|
||||
|
||||
/**
|
||||
* Interface for opening application resource files such as scripts sources.
|
||||
* <p>
|
||||
* This is used by required to load files that are part of
|
||||
* the application, and implemented by BaseLib
|
||||
* for both the Jme and Jse platforms.
|
||||
* <p>
|
||||
* The Jme version of base lib {@link BaseLib}
|
||||
* implements {@link BaseLib#FINDER} via {@link Class#getResourceAsStream(String)},
|
||||
* while the Jse version {@link JseBaseLib} implements it using {@link java.io.File#File(String)}.
|
||||
* <p>
|
||||
* The io library does not use this API for file manipulation.
|
||||
* <p>
|
||||
* @see BaseLib
|
||||
* @see BaseLib#FINDER
|
||||
* @see JseBaseLib
|
||||
* @see JmePlatform
|
||||
* @see JsePlatform
|
||||
*/
|
||||
public interface ResourceFinder {
|
||||
|
||||
/**
|
||||
* Try to open a file, or return null if not found.
|
||||
*
|
||||
* @see org.luaj.vm2.lib.BaseLib
|
||||
* @see org.luaj.vm2.lib.jse.JseBaseLib
|
||||
*
|
||||
* @param filename
|
||||
* @return InputStream, or null if not found.
|
||||
*/
|
||||
public InputStream findResource( String filename );
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,124 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 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.
|
||||
*
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link JsePlatform#standardGlobals()} or {@link JmePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new BaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* _G.load(new TableLib());
|
||||
* LuaValue tbl = LuaValue.listOf( new LuaValue[] {
|
||||
* LuaValue.valueOf( "abc" ),
|
||||
* LuaValue.valueOf( "def" ) } );
|
||||
* LuaValue sep = LuaValue.valueOf( "-" );
|
||||
* System.out.println( _G.get("table").get("concat").call( tbl, sep ) );
|
||||
* } </pre>
|
||||
* 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
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.5">http://www.lua.org/manual/5.1/manual.html#5.5</a>
|
||||
*/
|
||||
public class TableLib extends OneArgFunction {
|
||||
|
||||
public TableLib() {
|
||||
}
|
||||
|
||||
private LuaTable init() {
|
||||
LuaTable t = new LuaTable();
|
||||
bind(t, TableLib.class, new String[] { "getn", "maxn", }, 1 );
|
||||
bind(t, TableLibV.class, new String[] {
|
||||
"remove", "concat", "insert", "sort", "foreach", "foreachi", } );
|
||||
env.set("table", t);
|
||||
PackageLib.instance.LOADED.set("table", t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: // init library
|
||||
return init();
|
||||
case 1: // "getn" (table) -> number
|
||||
return arg.checktable().getn();
|
||||
case 2: // "maxn" (table) -> number
|
||||
return valueOf( arg.checktable().maxn());
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
static final class TableLibV extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: { // "remove" (table [, pos]) -> removed-ele
|
||||
LuaTable table = args.checktable(1);
|
||||
int pos = args.narg()>1? args.checkint(2): 0;
|
||||
return table.remove(pos);
|
||||
}
|
||||
case 1: { // "concat" (table [, sep [, i [, j]]]) -> string
|
||||
LuaTable table = args.checktable(1);
|
||||
return table.concat(
|
||||
args.optstring(2,LuaValue.EMPTYSTRING),
|
||||
args.optint(3,1),
|
||||
args.isvalue(4)? args.checkint(4): table.length() );
|
||||
}
|
||||
case 2: { // "insert" (table, [pos,] value) -> prev-ele
|
||||
final LuaTable table = args.checktable(1);
|
||||
final int pos = args.narg()>2? args.checkint(2): 0;
|
||||
final LuaValue value = args.arg( args.narg()>2? 3: 2 );
|
||||
table.insert( pos, value );
|
||||
return NONE;
|
||||
}
|
||||
case 3: { // "sort" (table [, comp]) -> void
|
||||
LuaTable table = args.checktable(1);
|
||||
LuaValue compare = (args.isnoneornil(2)? NIL: args.checkfunction(2));
|
||||
table.sort( compare );
|
||||
return NONE;
|
||||
}
|
||||
case 4: { // (table, func) -> void
|
||||
return args.checktable(1).foreach( args.checkfunction(2) );
|
||||
}
|
||||
case 5: { // "foreachi" (table, func) -> void
|
||||
return args.checktable(1).foreachi( args.checkfunction(2) );
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that take two arguments and
|
||||
* return one value.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
|
||||
* are routed through this method by this class,
|
||||
* dropping or extending arguments with {@code nil} values as required.
|
||||
* <p>
|
||||
* If more or less than three arguments are required,
|
||||
* or variable argument or variable return values,
|
||||
* then use one of the related function
|
||||
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link VarArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #call(LuaValue,LuaValue,LuaValue)
|
||||
* @see LibFunction
|
||||
* @see ZeroArgFunction
|
||||
* @see OneArgFunction
|
||||
* @see TwoArgFunction
|
||||
* @see VarArgFunction
|
||||
*/
|
||||
abstract public class ThreeArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3);
|
||||
|
||||
/** Default constructor */
|
||||
public ThreeArgFunction() {
|
||||
}
|
||||
|
||||
/** Constructor with specific environment
|
||||
* @param env The environment to apply during constructon.
|
||||
*/
|
||||
public ThreeArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return call(NIL, NIL, NIL);
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg) {
|
||||
return call(arg, NIL, NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return call(arg1, arg2, NIL);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call(varargs.arg1(),varargs.arg(2),varargs.arg(3));
|
||||
}
|
||||
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that take two arguments and
|
||||
* return one value.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
|
||||
* are routed through this method by this class,
|
||||
* dropping or extending arguments with {@code nil} values as required.
|
||||
* <p>
|
||||
* If more or less than two arguments are required,
|
||||
* or variable argument or variable return values,
|
||||
* then use one of the related function
|
||||
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #call(LuaValue,LuaValue)
|
||||
* @see LibFunction
|
||||
* @see ZeroArgFunction
|
||||
* @see OneArgFunction
|
||||
* @see ThreeArgFunction
|
||||
* @see VarArgFunction
|
||||
*/
|
||||
abstract public class TwoArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg1, LuaValue arg2);
|
||||
|
||||
/** Default constructor */
|
||||
public TwoArgFunction() {
|
||||
}
|
||||
|
||||
/** Constructor with specific environment
|
||||
* @param env The environment to apply during constructon.
|
||||
*/
|
||||
public TwoArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return call(NIL, NIL);
|
||||
}
|
||||
|
||||
public final LuaValue call(LuaValue arg) {
|
||||
return call(arg, NIL);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return call(arg1, arg2);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call(varargs.arg1(),varargs.arg(2));
|
||||
}
|
||||
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that takes varaiable arguments and
|
||||
* returns multiple return values.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call(LuaValue)}, {@link #invoke()},etc,
|
||||
* are routed through this method by this class,
|
||||
* converting arguments to {@linnk Varargs} and
|
||||
* dropping or extending return values with {@code nil} values as required.
|
||||
* <p>
|
||||
* If between one and three arguments are required, and only one return value is returned,
|
||||
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link ThreeArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #invoke(Varargs)
|
||||
* @see LibFunction
|
||||
* @see ZeroArgFunction
|
||||
* @see OneArgFunction
|
||||
* @see TwoArgFunction
|
||||
* @see ThreeArgFunction
|
||||
*/
|
||||
abstract public class VarArgFunction extends LibFunction {
|
||||
public VarArgFunction() {
|
||||
}
|
||||
|
||||
public VarArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return invoke(NONE).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return invoke(arg).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return invoke(varargsOf(arg1,arg2)).arg1();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return invoke(varargsOf(arg1,arg2,arg3)).arg1();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override and implement for the best performance.
|
||||
* May not have expected behavior for tail calls.
|
||||
* Should not be used if either:
|
||||
* - function needs to be used as a module
|
||||
* - function has a possibility of returning a TailcallVarargs
|
||||
* @param args the arguments to the function call.
|
||||
*/
|
||||
public Varargs invoke(Varargs args) {
|
||||
LuaThread.CallStack cs = LuaThread.onCall(this);
|
||||
try {
|
||||
return this.onInvoke(args).eval();
|
||||
} finally {
|
||||
cs.onReturn();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to provide a call implementation that runs in an environment
|
||||
* that can participate in setfenv, and behaves as expected
|
||||
* when returning TailcallVarargs.
|
||||
* @param args the arguments to the function call.
|
||||
*/
|
||||
public Varargs onInvoke(Varargs args) {
|
||||
return invoke(args);
|
||||
}
|
||||
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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 org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/** Abstract base class for Java function implementations that take no arguments and
|
||||
* return one value.
|
||||
* <p>
|
||||
* Subclasses need only implement {@link LuaValue#call()} to complete this class,
|
||||
* simplifying development.
|
||||
* All other uses of {@link #call(LuaValue)}, {@link #invoke(Varargs)},etc,
|
||||
* are routed through this method by this class.
|
||||
* <p>
|
||||
* If one or more arguments are required, or variable argument or variable return values,
|
||||
* then use one of the related function
|
||||
* {@link OneArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
|
||||
* <p>
|
||||
* See {@link LibFunction} for more information on implementation libraries and library functions.
|
||||
* @see #call()
|
||||
* @see LibFunction
|
||||
* @see OneArgFunction
|
||||
* @see TwoArgFunction
|
||||
* @see ThreeArgFunction
|
||||
* @see VarArgFunction
|
||||
*/
|
||||
abstract public class ZeroArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call();
|
||||
|
||||
/** Default constructor */
|
||||
public ZeroArgFunction() {
|
||||
}
|
||||
|
||||
/** Constructor with specific environment
|
||||
* @param env The environment to apply during constructon.
|
||||
*/
|
||||
public ZeroArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return call();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return call();
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return call();
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
return call();
|
||||
}
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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.jme;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.microedition.io.Connector;
|
||||
import javax.microedition.io.StreamConnection;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.BaseLib;
|
||||
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>
|
||||
* The implementation of the is based on CLDC 1.0 and StreamConnection.
|
||||
* However, seek is not supported.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JmePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new BaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* _G.load(new JmeIoLib());
|
||||
* _G.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* 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
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see IoLib
|
||||
* @see JseIoLib
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.6">http://www.lua.org/manual/5.1/manual.html#5.6</a>
|
||||
*/
|
||||
public class JmeIoLib extends IoLib {
|
||||
|
||||
public JmeIoLib() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected File wrapStdin() throws IOException {
|
||||
return new FileImpl(BaseLib.instance.STDIN);
|
||||
}
|
||||
|
||||
protected File wrapStdout() throws IOException {
|
||||
return new FileImpl(BaseLib.instance.STDOUT);
|
||||
}
|
||||
|
||||
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
|
||||
String url = "file:///" + filename;
|
||||
int mode = readMode? Connector.READ: Connector.READ_WRITE;
|
||||
StreamConnection conn = (StreamConnection) Connector.open( url, mode );
|
||||
File f = readMode?
|
||||
new FileImpl(conn, conn.openInputStream(), null):
|
||||
new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
|
||||
/*
|
||||
if ( appendMode ) {
|
||||
f.seek("end",0);
|
||||
} else {
|
||||
if ( ! readMode )
|
||||
conn.truncate(0);
|
||||
}
|
||||
*/
|
||||
return f;
|
||||
}
|
||||
|
||||
private static void notimplemented() throws IOException {
|
||||
throw new IOException("not implemented");
|
||||
}
|
||||
|
||||
protected File openProgram(String prog, String mode) throws IOException {
|
||||
notimplemented();
|
||||
return null;
|
||||
}
|
||||
|
||||
protected File tmpFile() throws IOException {
|
||||
notimplemented();
|
||||
return null;
|
||||
}
|
||||
|
||||
private final class FileImpl extends File {
|
||||
private final StreamConnection conn;
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
private boolean closed = false;
|
||||
private boolean nobuffer = false;
|
||||
private int lookahead = -1;
|
||||
private FileImpl( StreamConnection conn, InputStream is, OutputStream os ) {
|
||||
this.conn = conn;
|
||||
this.is = is;
|
||||
this.os = os;
|
||||
}
|
||||
private FileImpl( InputStream i ) {
|
||||
this( null, i, null );
|
||||
}
|
||||
private FileImpl( OutputStream o ) {
|
||||
this( null, null, o );
|
||||
}
|
||||
public String tojstring() {
|
||||
return "file ("+this.hashCode()+")";
|
||||
}
|
||||
public boolean isstdfile() {
|
||||
return conn == null;
|
||||
}
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
if ( conn != null ) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
public void flush() throws IOException {
|
||||
if ( os != null )
|
||||
os.flush();
|
||||
}
|
||||
public void write(LuaString s) throws IOException {
|
||||
if ( os != null )
|
||||
os.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else
|
||||
notimplemented();
|
||||
if ( nobuffer )
|
||||
flush();
|
||||
}
|
||||
public boolean isclosed() {
|
||||
return closed;
|
||||
}
|
||||
public int seek(String option, int pos) throws IOException {
|
||||
/*
|
||||
if ( conn != null ) {
|
||||
if ( "set".equals(option) ) {
|
||||
conn.seek(pos);
|
||||
return (int) conn.getFilePointer();
|
||||
} else if ( "end".equals(option) ) {
|
||||
conn.seek(conn.length()+1+pos);
|
||||
return (int) conn.length()+1;
|
||||
} else {
|
||||
conn.seek(conn.getFilePointer()+pos);
|
||||
return (int) conn.getFilePointer();
|
||||
}
|
||||
}
|
||||
*/
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
public void setvbuf(String mode, int size) {
|
||||
nobuffer = "no".equals(mode);
|
||||
}
|
||||
|
||||
// get length remaining to read
|
||||
public int remaining() throws IOException {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// peek ahead one character
|
||||
public int peek() throws IOException {
|
||||
if ( lookahead < 0 )
|
||||
lookahead = is.read();
|
||||
return lookahead;
|
||||
}
|
||||
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
public int read() throws IOException {
|
||||
if ( lookahead >= 0 ) {
|
||||
int c = lookahead;
|
||||
lookahead = -1;
|
||||
return c;
|
||||
}
|
||||
if ( is != null )
|
||||
return is.read();
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return number of bytes read if positive, -1 if eof, throws IOException
|
||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||
int n,i=0;
|
||||
if (is!=null) {
|
||||
if ( length > 0 && lookahead >= 0 ) {
|
||||
bytes[offset] = (byte) lookahead;
|
||||
lookahead = -1;
|
||||
i += 1;
|
||||
}
|
||||
for ( ; i<length; ) {
|
||||
n = is.read(bytes, offset+i, length-i);
|
||||
if ( n < 0 )
|
||||
return ( i > 0 ? i : -1 );
|
||||
i += n;
|
||||
}
|
||||
} else {
|
||||
notimplemented();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.jme;
|
||||
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.BaseLib;
|
||||
import org.luaj.vm2.lib.CoroutineLib;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
import org.luaj.vm2.lib.OsLib;
|
||||
import org.luaj.vm2.lib.PackageLib;
|
||||
import org.luaj.vm2.lib.StringLib;
|
||||
import org.luaj.vm2.lib.TableLib;
|
||||
|
||||
/** The {@link JmePlatform} class is a convenience class to standardize
|
||||
* how globals tables are initialized for the JME platform.
|
||||
* <p>
|
||||
* The JME platform, being limited, cannot implement all libraries in all aspects. The main limitations are
|
||||
* <ul>
|
||||
* <li>Some math functions are not implemented, see {@link MathLib} for details</li>
|
||||
* <li>Scripts are loaded via Class.getResourceAsStream(), see {@link BaseLib} for details</li>
|
||||
* <li>OS functions execute(), remove(), rename(), and tmpname() vary, see {@link OsLib} for details</li>
|
||||
* <li>I/O seek is not implemented, see {@link JmeIoLib} for details</li>
|
||||
* <li>luajava is not available, see {@link LuajavaLib} for details</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 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:
|
||||
* <pre> {@code
|
||||
* LuaValue _G = JmePlatform.standardGlobals();
|
||||
* _G.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* Once globals are created, a simple way to load and run a script is:
|
||||
* <pre> {@code
|
||||
* LoadState.load( getClass().getResourceAsStream("main.lua"), "main.lua", _G ).call();
|
||||
* } </pre>
|
||||
* <p>
|
||||
* although {@code require} could also be used:
|
||||
* <pre> {@code
|
||||
* _G.get("require").call(LuaValue.valueOf("main"));
|
||||
* } </pre>
|
||||
* For this to succeed, the file "main.lua" must be a resource in the class path.
|
||||
* See {@link BaseLib} for details on finding scripts using {@link ResourceFinder}.
|
||||
* <p>
|
||||
* The standard globals will contain all standard libraries in their JME flavors:
|
||||
* <ul>
|
||||
* <li>{@link BaseLib}</li>
|
||||
* <li>{@link PackageLib}</li>
|
||||
* <li>{@link TableLib}</li>
|
||||
* <li>{@link StringLib}</li>
|
||||
* <li>{@link CoroutineLib}</li>
|
||||
* <li>{@link MathLib}</li>
|
||||
* <li>{@link JmeIoLib}</li>
|
||||
* <li>{@link OsLib}</li>
|
||||
* </ul>
|
||||
* 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>
|
||||
* <p>
|
||||
* The class ensures that initialization is done in the correct order,
|
||||
* and that linkage is made to {@link LuaThread#setGlobals(LuaValue)}.
|
||||
* @see JsePlatform
|
||||
* @see LoadState
|
||||
*/
|
||||
public class JmePlatform {
|
||||
|
||||
/**
|
||||
* Create a standard set of globals for JME including all the libraries.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JME libraries
|
||||
* @see #debugGlobals()
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
*/
|
||||
public static LuaTable standardGlobals() {
|
||||
LuaTable _G = new LuaTable();
|
||||
_G.load(new BaseLib());
|
||||
_G.load(new PackageLib());
|
||||
_G.load(new OsLib());
|
||||
_G.load(new MathLib());
|
||||
_G.load(new TableLib());
|
||||
_G.load(new StringLib());
|
||||
_G.load(new CoroutineLib());
|
||||
_G.load(new JmeIoLib());
|
||||
LuaThread.setGlobals(_G);
|
||||
LuaC.install();
|
||||
return _G;
|
||||
}
|
||||
|
||||
/** Create standard globals including the {@link debug} library.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JSE and debug libraries
|
||||
* @see #standarsGlobals()
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see DebugLib
|
||||
*/
|
||||
public static LuaTable debugGlobals() {
|
||||
LuaTable _G = standardGlobals();
|
||||
_G.load(new DebugLib());
|
||||
return _G;
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
org.luaj.vm2.script.LuaScriptEngineFactory
|
@ -1,223 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
import org.luaj.vm2.lua2java.Lua2Java;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
|
||||
/**
|
||||
* lua command for use in java se environments.
|
||||
*/
|
||||
public class lua {
|
||||
private static final String version = Lua._VERSION + "Copyright (c) 2009 Luaj.org.org";
|
||||
|
||||
private static final String usage =
|
||||
"usage: java -cp luaj-jse.jar lua [options] [script [args]].\n" +
|
||||
"Available options are:\n" +
|
||||
" -e stat execute string 'stat'\n" +
|
||||
" -l name require library 'name'\n" +
|
||||
" -i enter interactive mode after executing 'script'\n" +
|
||||
" -v show version information\n" +
|
||||
" -j use lua2java source-to-source compiler\n" +
|
||||
" -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n" +
|
||||
" -n nodebug - do not load debug library by default\n" +
|
||||
" -- stop handling options\n" +
|
||||
" - execute stdin and stop handling options";
|
||||
|
||||
private static void usageExit() {
|
||||
System.out.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private static LuaValue _G;
|
||||
|
||||
public static void main( String[] args ) throws IOException {
|
||||
|
||||
// process args
|
||||
boolean interactive = (args.length == 0);
|
||||
boolean versioninfo = false;
|
||||
boolean processing = true;
|
||||
boolean nodebug = false;
|
||||
boolean luajc = false;
|
||||
boolean lua2java = false;
|
||||
Vector libs = null;
|
||||
try {
|
||||
// stateful argument processing
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
// input file - defer to last stage
|
||||
break;
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
// input file - defer to last stage
|
||||
break;
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'e':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
// input script - defer to last stage
|
||||
break;
|
||||
case 'b':
|
||||
luajc = true;
|
||||
break;
|
||||
case 'j':
|
||||
lua2java = true;
|
||||
break;
|
||||
case 'l':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
libs = libs!=null? libs: new Vector();
|
||||
libs.addElement( args[i] );
|
||||
break;
|
||||
case 'i':
|
||||
interactive = true;
|
||||
break;
|
||||
case 'v':
|
||||
versioninfo = true;
|
||||
break;
|
||||
case 'n':
|
||||
nodebug = true;
|
||||
break;
|
||||
case '-':
|
||||
if ( args[i].length() > 2 )
|
||||
usageExit();
|
||||
processing = false;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
if ( versioninfo )
|
||||
System.out.println(version);
|
||||
|
||||
// new lua state
|
||||
_G = nodebug? JsePlatform.standardGlobals(): JsePlatform.debugGlobals();
|
||||
if ( luajc ) LuaJC.install();
|
||||
if ( lua2java) Lua2Java.install();
|
||||
for ( int i=0, n=libs!=null? libs.size(): 0; i<n; i++ )
|
||||
loadLibrary( (String) libs.elementAt(i) );
|
||||
|
||||
// input script processing
|
||||
processing = true;
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
processScript( new FileInputStream(args[i]), args[i], args, i );
|
||||
break;
|
||||
} else if ( "-".equals( args[i] ) ) {
|
||||
processScript( System.in, "=stdin", args, i );
|
||||
break;
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'l':
|
||||
++i;
|
||||
break;
|
||||
case 'e':
|
||||
++i;
|
||||
processScript( new ByteArrayInputStream(args[i].getBytes()), "string", args, i );
|
||||
break;
|
||||
case '-':
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( interactive )
|
||||
interactiveMode();
|
||||
|
||||
} catch ( IOException ioe ) {
|
||||
System.err.println( ioe.toString() );
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadLibrary( String libname ) throws IOException {
|
||||
LuaValue slibname =LuaValue.valueOf(libname);
|
||||
try {
|
||||
// load via plain require
|
||||
_G.get("require").call(slibname);
|
||||
} catch ( Exception e ) {
|
||||
try {
|
||||
// load as java class
|
||||
LuaValue v = (LuaValue) Class.forName(libname).newInstance();
|
||||
v.setfenv(_G);
|
||||
v.call(slibname, _G);
|
||||
} catch ( Exception f ) {
|
||||
throw new IOException("loadLibrary("+libname+") failed: "+e+","+f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processScript( InputStream script, String chunkname, String[] args, int firstarg ) throws IOException {
|
||||
try {
|
||||
LuaFunction c;
|
||||
try {
|
||||
c = LoadState.load(script, chunkname, _G);
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
Varargs scriptargs = (args!=null? setGlobalArg(args, firstarg): LuaValue.NONE);
|
||||
c.invoke( scriptargs );
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace( System.err );
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs setGlobalArg(String[] args, int i) {
|
||||
LuaTable arg = LuaValue.tableOf();
|
||||
for ( int j=0; j<args.length; j++ )
|
||||
arg.set( j-i, LuaValue.valueOf(args[j]) );
|
||||
_G.set( "arg", arg );
|
||||
return _G.get("unpack").invoke(arg);
|
||||
}
|
||||
|
||||
private static void interactiveMode( ) throws IOException {
|
||||
BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
|
||||
while ( true ) {
|
||||
System.out.print("> ");
|
||||
System.out.flush();
|
||||
String line = reader.readLine();
|
||||
if ( line == null )
|
||||
return;
|
||||
processScript( new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0 );
|
||||
}
|
||||
}
|
||||
}
|
@ -1,213 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.ast.Chunk;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
import org.luaj.vm2.lua2java.JavaCodeGen;
|
||||
import org.luaj.vm2.parser.LuaParser;
|
||||
|
||||
/**
|
||||
* Compile lua sources into java sources.
|
||||
*/
|
||||
public class lua2java {
|
||||
private static final String version = Lua._VERSION + "Copyright (C) 2010 luaj.org";
|
||||
|
||||
private static final String usage =
|
||||
"usage: java -cp luaj-jse.jar lua2java [options] fileordir [, fileordir ...]\n" +
|
||||
"Available options are:\n" +
|
||||
" - process stdin\n" +
|
||||
" -s src source directory\n" +
|
||||
" -d dir destination directory\n" +
|
||||
" -p pkg package prefix to apply to all classes\n" +
|
||||
" -e enc override default character encoding\n" +
|
||||
" -r recursively compile all\n" +
|
||||
" -v verbose\n";
|
||||
|
||||
private static void usageExit() {
|
||||
System.out.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private String srcdir = null;
|
||||
private String destdir = null;
|
||||
private String pkgprefix = null;
|
||||
private String encoding = "ISO8859-1";
|
||||
private boolean recurse = false;
|
||||
private boolean verbose = false;
|
||||
private List files = new ArrayList();
|
||||
|
||||
public static void main( String[] args ) throws IOException {
|
||||
new lua2java( args );
|
||||
}
|
||||
|
||||
private lua2java( String[] args ) throws IOException {
|
||||
|
||||
// process args
|
||||
try {
|
||||
List seeds = new ArrayList ();
|
||||
|
||||
// get stateful args
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! args[i].startsWith("-") ) {
|
||||
seeds.add(args[i]);
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 's':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
srcdir = args[i];
|
||||
break;
|
||||
case 'd':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
destdir = args[i];
|
||||
break;
|
||||
case 'p':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
pkgprefix = args[i];
|
||||
break;
|
||||
case 'e':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
encoding = args[i];
|
||||
break;
|
||||
case 'r':
|
||||
recurse = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
if ( verbose ) {
|
||||
System.out.println(version);
|
||||
System.out.println("srcdir: "+srcdir);
|
||||
System.out.println("destdir: "+destdir);
|
||||
System.out.println("files: "+seeds);
|
||||
System.out.println("encoding: "+encoding);
|
||||
System.out.println("recurse: "+recurse);
|
||||
}
|
||||
|
||||
// need at least one seed
|
||||
if ( seeds.size() <= 0 ) {
|
||||
System.err.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// collect up files to process
|
||||
for ( int i=0; i<seeds.size(); i++ )
|
||||
collectFiles( srcdir+"/"+seeds.get(i) );
|
||||
|
||||
// check for at least one file
|
||||
if ( files.size() <= 0 ) {
|
||||
System.err.println("no files found in "+seeds);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// process input files
|
||||
JsePlatform.standardGlobals();
|
||||
for ( int i=0,n=files.size(); i<n; i++ )
|
||||
processFile( (InputFile) files.get(i) );
|
||||
|
||||
} catch ( Exception ioe ) {
|
||||
System.err.println( ioe.toString() );
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectFiles(String path) {
|
||||
File f = new File(path);
|
||||
if ( f.isDirectory() && recurse )
|
||||
scandir(f,pkgprefix);
|
||||
else if ( f.isFile() ) {
|
||||
File dir = f.getAbsoluteFile().getParentFile();
|
||||
if ( dir != null )
|
||||
scanfile( dir, f, pkgprefix );
|
||||
}
|
||||
}
|
||||
private void scandir(File dir, String javapackage) {
|
||||
File[] f = dir.listFiles();
|
||||
for ( int i=0; i<f.length; i++ )
|
||||
scanfile( dir, f[i], javapackage );
|
||||
}
|
||||
|
||||
private void scanfile(File dir, File f, String javapackage) {
|
||||
if ( f.exists() ) {
|
||||
if ( f.isDirectory() && recurse )
|
||||
scandir( f, (javapackage!=null? javapackage+"."+f.getName(): f.getName()) );
|
||||
else if ( f.isFile() && f.getName().endsWith(".lua") )
|
||||
files.add( new InputFile(dir,f,javapackage) );
|
||||
}
|
||||
}
|
||||
|
||||
class InputFile {
|
||||
public File infile;
|
||||
public File outdir;
|
||||
public File outfile;
|
||||
public String javapackage;
|
||||
public String javaclassname;
|
||||
public InputFile(File dir, File f, String javapackage) {
|
||||
String outdirpath = javapackage!=null? destdir+"/"+javapackage.replace('.', '/'): destdir;
|
||||
this.javaclassname = f.getName().substring(0,f.getName().lastIndexOf('.'));
|
||||
this.javapackage = javapackage;
|
||||
this.infile = f;
|
||||
this.outdir = new File(outdirpath);
|
||||
this.outfile = new File(outdirpath+"/"+this.javaclassname+".java");
|
||||
}
|
||||
}
|
||||
|
||||
private void processFile( InputFile inf ) {
|
||||
inf.outdir.mkdirs();
|
||||
try {
|
||||
if ( verbose )
|
||||
System.out.println(
|
||||
"pkg="+inf.javapackage+" file="+inf.javaclassname+".java dest="+inf.outfile+" src="+inf.infile);
|
||||
FileInputStream in = new FileInputStream(inf.infile);
|
||||
FileOutputStream out = new FileOutputStream(inf.outfile);
|
||||
PrintWriter pw = new PrintWriter(out);
|
||||
LuaParser parser = new LuaParser(in,encoding);
|
||||
Chunk chunk = parser.Chunk();
|
||||
new JavaCodeGen(chunk,pw,inf.javapackage,inf.javaclassname);
|
||||
pw.close();
|
||||
out.close();
|
||||
in.close();
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace( System.err );
|
||||
}
|
||||
}
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.DumpState;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler for lua files to lua bytecode.
|
||||
*/
|
||||
public class luac {
|
||||
private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org";
|
||||
|
||||
private static final String usage =
|
||||
"usage: java -cp luaj-jse.jar luac [options] [filenames].\n" +
|
||||
"Available options are:\n" +
|
||||
" - process stdin\n" +
|
||||
" -l list\n" +
|
||||
" -o name output to file 'name' (default is \"luac.out\")\n" +
|
||||
" -p parse only\n" +
|
||||
" -s strip debug information\n" +
|
||||
" -e little endian format for numbers\n" +
|
||||
" -i<n> number format 'n', (n=0,1 or 4, default="+DumpState.NUMBER_FORMAT_DEFAULT+")\n" +
|
||||
" -v show version information\n" +
|
||||
" -- stop handling options\n";
|
||||
|
||||
private static void usageExit() {
|
||||
System.out.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private boolean list = false;
|
||||
private String output = "luac.out";
|
||||
private boolean parseonly = false;
|
||||
private boolean stripdebug = false;
|
||||
private boolean littleendian = false;
|
||||
private int numberformat = DumpState.NUMBER_FORMAT_DEFAULT;
|
||||
private boolean versioninfo = false;
|
||||
private boolean processing = true;
|
||||
|
||||
public static void main( String[] args ) throws IOException {
|
||||
new luac( args );
|
||||
}
|
||||
|
||||
private luac( String[] args ) throws IOException {
|
||||
|
||||
// process args
|
||||
try {
|
||||
// get stateful args
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
// input file - defer to next stage
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
// input file - defer to next stage
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'l':
|
||||
list = true;
|
||||
break;
|
||||
case 'o':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
output = args[i];
|
||||
break;
|
||||
case 'p':
|
||||
parseonly = true;
|
||||
break;
|
||||
case 's':
|
||||
stripdebug = true;
|
||||
break;
|
||||
case 'e':
|
||||
littleendian = true;
|
||||
break;
|
||||
case 'i':
|
||||
if ( args[i].length() <= 2 )
|
||||
usageExit();
|
||||
numberformat = Integer.parseInt(args[i].substring(2));
|
||||
break;
|
||||
case 'v':
|
||||
versioninfo = true;
|
||||
break;
|
||||
case '-':
|
||||
if ( args[i].length() > 2 )
|
||||
usageExit();
|
||||
processing = false;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
if ( versioninfo )
|
||||
System.out.println(version);
|
||||
|
||||
// open output file
|
||||
OutputStream fos = new FileOutputStream( output );
|
||||
|
||||
// process input files
|
||||
try {
|
||||
JsePlatform.standardGlobals();
|
||||
processing = true;
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! processing || ! args[i].startsWith("-") ) {
|
||||
String chunkname = args[i].substring(0,args[i].length()-4);
|
||||
processScript( new FileInputStream(args[i]), chunkname, fos );
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
processScript( System.in, "=stdin", fos );
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'o':
|
||||
++i;
|
||||
break;
|
||||
case '-':
|
||||
processing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fos.close();
|
||||
}
|
||||
|
||||
} catch ( IOException ioe ) {
|
||||
System.err.println( ioe.toString() );
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
private void processScript( InputStream script, String chunkname, OutputStream out ) throws IOException {
|
||||
try {
|
||||
// create the chunk
|
||||
Prototype chunk = LuaC.instance.compile(script, chunkname);
|
||||
|
||||
// list the chunk
|
||||
if (list)
|
||||
Print.printCode(chunk);
|
||||
|
||||
// write out the chunk
|
||||
if (!parseonly) {
|
||||
DumpState.dump(chunk, out, stripdebug, numberformat, littleendian);
|
||||
}
|
||||
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace( System.err );
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,245 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
import org.luaj.vm2.luajc.LuaJC;
|
||||
|
||||
/**
|
||||
* Compiler for lua files to compile lua sources or lua binaries into java classes.
|
||||
*/
|
||||
public class luajc {
|
||||
private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org";
|
||||
|
||||
private static final String usage =
|
||||
"usage: java -cp luaj-jse.jar,bcel-5.2.jar luajc [options] fileordir [, fileordir ...]\n" +
|
||||
"Available options are:\n" +
|
||||
" - process stdin\n" +
|
||||
" -s src source directory\n" +
|
||||
" -d dir destination directory\n" +
|
||||
" -p pkg package prefix to apply to all classes\n" +
|
||||
" -r recursively compile all\n" +
|
||||
" -l load classes to verify generated bytecode\n" +
|
||||
" -v verbose\n";
|
||||
|
||||
private static void usageExit() {
|
||||
System.out.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
private String srcdir = null;
|
||||
private String destdir = null;
|
||||
private boolean recurse = false;
|
||||
private boolean verbose = false;
|
||||
private boolean loadclasses = false;
|
||||
private String pkgprefix = null;
|
||||
private List files = new ArrayList();
|
||||
|
||||
public static void main( String[] args ) throws IOException {
|
||||
new luajc( args );
|
||||
}
|
||||
|
||||
private luajc( String[] args ) throws IOException {
|
||||
|
||||
// process args
|
||||
List seeds = new ArrayList ();
|
||||
|
||||
// get stateful args
|
||||
for ( int i=0; i<args.length; i++ ) {
|
||||
if ( ! args[i].startsWith("-") ) {
|
||||
seeds.add(args[i]);
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 's':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
srcdir = args[i];
|
||||
break;
|
||||
case 'd':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
destdir = args[i];
|
||||
break;
|
||||
case 'l':
|
||||
loadclasses = true;
|
||||
break;
|
||||
case 'p':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
pkgprefix = args[i];
|
||||
break;
|
||||
case 'r':
|
||||
recurse = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
usageExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// echo version
|
||||
if ( verbose ) {
|
||||
System.out.println(version);
|
||||
System.out.println("srcdir: "+srcdir);
|
||||
System.out.println("destdir: "+srcdir);
|
||||
System.out.println("files: "+seeds);
|
||||
System.out.println("recurse: "+recurse);
|
||||
}
|
||||
|
||||
// need at least one seed
|
||||
if ( seeds.size() <= 0 ) {
|
||||
System.err.println(usage);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// collect up files to process
|
||||
for ( int i=0; i<seeds.size(); i++ )
|
||||
collectFiles( srcdir+"/"+seeds.get(i) );
|
||||
|
||||
// check for at least one file
|
||||
if ( files.size() <= 0 ) {
|
||||
System.err.println("no files found in "+seeds);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// process input files
|
||||
JsePlatform.standardGlobals();
|
||||
for ( int i=0,n=files.size(); i<n; i++ )
|
||||
processFile( (InputFile) files.get(i) );
|
||||
}
|
||||
|
||||
private void collectFiles(String path) {
|
||||
File f = new File(path);
|
||||
if ( f.isDirectory() && recurse )
|
||||
scandir(f,pkgprefix);
|
||||
else if ( f.isFile() ) {
|
||||
File dir = f.getAbsoluteFile().getParentFile();
|
||||
if ( dir != null )
|
||||
scanfile( dir, f, pkgprefix );
|
||||
}
|
||||
}
|
||||
private void scandir(File dir, String javapackage) {
|
||||
File[] f = dir.listFiles();
|
||||
for ( int i=0; i<f.length; i++ )
|
||||
scanfile( dir, f[i], javapackage );
|
||||
}
|
||||
|
||||
private void scanfile(File dir, File f, String javapackage) {
|
||||
if ( f.exists() ) {
|
||||
if ( f.isDirectory() && recurse )
|
||||
scandir( f, (javapackage!=null? javapackage+"."+f.getName(): f.getName()) );
|
||||
else if ( f.isFile() && f.getName().endsWith(".lua") )
|
||||
files.add( new InputFile(dir,f,javapackage) );
|
||||
}
|
||||
}
|
||||
|
||||
class InputFile {
|
||||
public String luachunkname;
|
||||
public String srcfilename;
|
||||
public File infile;
|
||||
public File outdir;
|
||||
public String javapackage;
|
||||
|
||||
public InputFile(File dir, File f, String javapackage) {
|
||||
this.infile = f;
|
||||
String subdir = javapackage!=null? javapackage.replace('.', '/'): null;
|
||||
String outdirpath = subdir!=null? destdir+"/"+subdir: destdir;
|
||||
this.javapackage = javapackage;
|
||||
this.srcfilename = (subdir!=null? subdir+"/": "")+infile.getName();
|
||||
this.luachunkname = (subdir!=null? subdir+"/": "")+infile.getName().substring( 0, infile.getName().lastIndexOf('.') );
|
||||
this.infile = f;
|
||||
this.outdir = new File(outdirpath);
|
||||
}
|
||||
}
|
||||
|
||||
private void processFile( InputFile inf ) {
|
||||
inf.outdir.mkdirs();
|
||||
try {
|
||||
if ( verbose )
|
||||
System.out.println("chunk="+inf.luachunkname+" srcfile="+inf.srcfilename);
|
||||
|
||||
// create the chunk
|
||||
FileInputStream fis = new FileInputStream( inf.infile );
|
||||
final Hashtable t = LuaJC.getInstance().compileAll(fis, inf.luachunkname, inf.srcfilename);
|
||||
fis.close();
|
||||
|
||||
// write out the chunk
|
||||
for ( Enumeration e = t.keys(); e.hasMoreElements(); ) {
|
||||
String key = (String) e.nextElement();
|
||||
byte[] bytes = (byte[]) t.get(key);
|
||||
if ( key.indexOf('/')>=0 ) {
|
||||
String d = (destdir!=null? destdir+"/": "")+key.substring(0,key.lastIndexOf('/'));
|
||||
new File(d).mkdirs();
|
||||
}
|
||||
String destpath = (destdir!=null? destdir+"/": "") + key + ".class";
|
||||
if ( verbose )
|
||||
System.out.println( " "+destpath +" ("+bytes.length+" bytes)");
|
||||
FileOutputStream fos = new FileOutputStream( destpath );
|
||||
fos.write( bytes );
|
||||
fos.close();
|
||||
}
|
||||
|
||||
// try to load the files
|
||||
if ( loadclasses ) {
|
||||
ClassLoader loader = new ClassLoader() {
|
||||
public Class findClass(String classname) throws ClassNotFoundException {
|
||||
byte[] bytes = (byte[]) t.get(classname);
|
||||
if ( bytes != null )
|
||||
return defineClass(classname, bytes, 0, bytes.length);
|
||||
return super.findClass(classname);
|
||||
}
|
||||
};
|
||||
for ( Enumeration e = t.keys(); e.hasMoreElements(); ) {
|
||||
String classname = (String) e.nextElement();
|
||||
try {
|
||||
Class c = loader.loadClass(classname);
|
||||
Object o = c.newInstance();
|
||||
if ( verbose )
|
||||
System.out.println(" loaded "+classname+" as "+o );
|
||||
} catch ( Exception ex ) {
|
||||
System.out.flush();
|
||||
System.err.println(" failed to load "+classname+": "+ex );
|
||||
System.err.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch ( Exception e ) {
|
||||
System.err.println(" failed to load "+inf.srcfilename+": "+e );
|
||||
e.printStackTrace( System.err );
|
||||
System.err.flush();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Block extends Stat {
|
||||
|
||||
public List<Stat> stats = new ArrayList<Stat>();
|
||||
public NameScope scope;
|
||||
|
||||
public void add(Stat s) {
|
||||
if ( s == null )
|
||||
return;
|
||||
stats.add(s);
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
public class Chunk {
|
||||
public final Block block;
|
||||
|
||||
public Chunk(Block b) {
|
||||
this.block = b;
|
||||
}
|
||||
|
||||
public void accept( Visitor visitor ) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
@ -1,313 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
abstract
|
||||
public class Exp {
|
||||
abstract public void accept(Visitor visitor);
|
||||
|
||||
public static Exp constant(LuaValue value) {
|
||||
return new Constant(value);
|
||||
}
|
||||
|
||||
public static Exp numberconstant(String token) {
|
||||
return new Constant( LuaValue.valueOf(token).tonumber() );
|
||||
}
|
||||
|
||||
public static Exp varargs() {
|
||||
return new VarargsExp();
|
||||
}
|
||||
|
||||
public static Exp tableconstructor(TableConstructor tc) {
|
||||
return tc;
|
||||
}
|
||||
|
||||
public static Exp unaryexp(int op, Exp rhs) {
|
||||
if ( rhs instanceof BinopExp ) {
|
||||
BinopExp b = (BinopExp) rhs;
|
||||
if ( precedence(op) > precedence(b.op) )
|
||||
return binaryexp( unaryexp(op, b.lhs), b.op, b.rhs );
|
||||
}
|
||||
return new UnopExp(op, rhs);
|
||||
}
|
||||
|
||||
public static Exp binaryexp(Exp lhs, int op, Exp rhs) {
|
||||
if ( lhs instanceof UnopExp ) {
|
||||
UnopExp u = (UnopExp) lhs;
|
||||
if ( precedence(op) > precedence(u.op) )
|
||||
return unaryexp( u.op, binaryexp( u.rhs, op, rhs ) );
|
||||
}
|
||||
// TODO: cumulate string concatenations together
|
||||
// TODO: constant folding
|
||||
if ( lhs instanceof BinopExp ) {
|
||||
BinopExp b = (BinopExp) lhs;
|
||||
if ( (precedence(op) > precedence(b.op)) ||
|
||||
((precedence(op) == precedence(b.op)) && isrightassoc(op)) )
|
||||
return binaryexp( b.lhs, b.op, binaryexp( b.rhs, op, rhs ) );
|
||||
}
|
||||
if ( rhs instanceof BinopExp ) {
|
||||
BinopExp b = (BinopExp) rhs;
|
||||
if ( (precedence(op) > precedence(b.op)) ||
|
||||
((precedence(op) == precedence(b.op)) && ! isrightassoc(op)) )
|
||||
return binaryexp( binaryexp( lhs, op, b.lhs ), b.op, b.rhs );
|
||||
}
|
||||
return new BinopExp(lhs, op, rhs);
|
||||
}
|
||||
|
||||
static boolean isrightassoc(int op) {
|
||||
switch ( op ) {
|
||||
case Lua.OP_CONCAT:
|
||||
case Lua.OP_POW: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int precedence(int op) {
|
||||
switch ( op ) {
|
||||
case Lua.OP_OR: return 0;
|
||||
case Lua.OP_AND: return 1;
|
||||
case Lua.OP_LT: case Lua.OP_GT: case Lua.OP_LE: case Lua.OP_GE: case Lua.OP_NEQ: case Lua.OP_EQ: return 2;
|
||||
case Lua.OP_CONCAT: return 3;
|
||||
case Lua.OP_ADD: case Lua.OP_SUB: return 4;
|
||||
case Lua.OP_MUL: case Lua.OP_DIV: case Lua.OP_MOD: return 5;
|
||||
case Lua.OP_NOT: case Lua.OP_UNM: case Lua.OP_LEN: return 6;
|
||||
case Lua.OP_POW: return 7;
|
||||
default: throw new IllegalStateException("precedence of bad op "+op);
|
||||
}
|
||||
}
|
||||
|
||||
public static Exp anonymousfunction(FuncBody funcbody) {
|
||||
return new AnonFuncDef(funcbody);
|
||||
}
|
||||
|
||||
/** foo */
|
||||
public static NameExp nameprefix(String name) {
|
||||
return new NameExp(name);
|
||||
}
|
||||
|
||||
/** ( foo.bar ) */
|
||||
public static ParensExp parensprefix(Exp exp) {
|
||||
return new ParensExp(exp);
|
||||
}
|
||||
|
||||
/** foo[exp] */
|
||||
public static IndexExp indexop(PrimaryExp lhs, Exp exp) {
|
||||
return new IndexExp(lhs, exp);
|
||||
}
|
||||
|
||||
/** foo.bar */
|
||||
public static FieldExp fieldop(PrimaryExp lhs, String name) {
|
||||
return new FieldExp(lhs, name);
|
||||
}
|
||||
|
||||
/** foo(2,3) */
|
||||
public static FuncCall functionop(PrimaryExp lhs, FuncArgs args) {
|
||||
return new FuncCall(lhs, args);
|
||||
}
|
||||
|
||||
/** foo:bar(4,5) */
|
||||
public static MethodCall methodop(PrimaryExp lhs, String name, FuncArgs args) {
|
||||
return new MethodCall(lhs, name, args);
|
||||
}
|
||||
|
||||
public boolean isvarexp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isfunccall() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isvarargexp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract public static class PrimaryExp extends Exp {
|
||||
public boolean isvarexp() {
|
||||
return false;
|
||||
}
|
||||
public boolean isfunccall() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
abstract public static class VarExp extends PrimaryExp {
|
||||
public boolean isvarexp() {
|
||||
return true;
|
||||
}
|
||||
public void markHasAssignment() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class NameExp extends VarExp {
|
||||
public final Name name;
|
||||
public NameExp(String name) {
|
||||
this.name = new Name(name);
|
||||
}
|
||||
public void markHasAssignment() {
|
||||
name.variable.hasassignments = true;
|
||||
}
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParensExp extends PrimaryExp {
|
||||
public final Exp exp;
|
||||
public ParensExp(Exp exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FieldExp extends VarExp {
|
||||
public final PrimaryExp lhs;
|
||||
public final Name name;
|
||||
public FieldExp(PrimaryExp lhs, String name) {
|
||||
this.lhs = lhs;
|
||||
this.name = new Name(name);
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class IndexExp extends VarExp {
|
||||
public final PrimaryExp lhs;
|
||||
public final Exp exp;
|
||||
public IndexExp(PrimaryExp lhs, Exp exp) {
|
||||
this.lhs = lhs;
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FuncCall extends PrimaryExp {
|
||||
public final PrimaryExp lhs;
|
||||
public final FuncArgs args;
|
||||
|
||||
public FuncCall(PrimaryExp lhs, FuncArgs args) {
|
||||
this.lhs = lhs;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public boolean isfunccall() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public boolean isvarargexp() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodCall extends FuncCall {
|
||||
public final String name;
|
||||
|
||||
public MethodCall(PrimaryExp lhs, String name, FuncArgs args) {
|
||||
super(lhs, args);
|
||||
this.name = new String(name);
|
||||
}
|
||||
|
||||
public boolean isfunccall() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Constant extends Exp {
|
||||
public final LuaValue value;
|
||||
public Constant(LuaValue value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class VarargsExp extends Exp {
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public boolean isvarargexp() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnopExp extends Exp {
|
||||
public final int op;
|
||||
public final Exp rhs;
|
||||
public UnopExp(int op, Exp rhs) {
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class BinopExp extends Exp {
|
||||
public final Exp lhs,rhs;
|
||||
public final int op;
|
||||
public BinopExp(Exp lhs, int op, Exp rhs) {
|
||||
this.lhs = lhs;
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AnonFuncDef extends Exp {
|
||||
public final FuncBody body;
|
||||
public AnonFuncDef(FuncBody funcbody) {
|
||||
this.body = funcbody;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
|
||||
public class FuncArgs {
|
||||
|
||||
public final List<Exp> exps;
|
||||
|
||||
/** exp1,exp2... */
|
||||
public static FuncArgs explist(List<Exp> explist) {
|
||||
return new FuncArgs(explist);
|
||||
}
|
||||
|
||||
/** {...} */
|
||||
public static FuncArgs tableconstructor(TableConstructor table) {
|
||||
return new FuncArgs(table);
|
||||
}
|
||||
|
||||
/** "mylib" */
|
||||
public static FuncArgs string(LuaString string) {
|
||||
return new FuncArgs(string);
|
||||
}
|
||||
|
||||
public FuncArgs(List<Exp> exps) {
|
||||
this.exps = exps;
|
||||
}
|
||||
|
||||
public FuncArgs(LuaString string) {
|
||||
this.exps = new ArrayList<Exp>();
|
||||
this.exps.add( Exp.constant(string) );
|
||||
}
|
||||
|
||||
public FuncArgs(TableConstructor table) {
|
||||
this.exps = new ArrayList<Exp>();
|
||||
this.exps.add( table );
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
public class FuncBody {
|
||||
public ParList parlist;
|
||||
public Block block;
|
||||
public NameScope scope;
|
||||
|
||||
public FuncBody(ParList parlist, Block block) {
|
||||
this.parlist = parlist!=null? parlist: ParList.EMPTY_PARLIST;
|
||||
this.block = block;
|
||||
}
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FuncName {
|
||||
// example: a.b.c.d:e
|
||||
|
||||
// initial base name: "a"
|
||||
public final Name name;
|
||||
|
||||
// intermediate field accesses: "b", "c", "d"
|
||||
public List<String> dots;
|
||||
|
||||
// optional final method name: "e"
|
||||
public String method;
|
||||
|
||||
public FuncName( String name ) {
|
||||
this.name = new Name(name);
|
||||
}
|
||||
|
||||
public void adddot(String dot) {
|
||||
if ( dots == null )
|
||||
dots = new ArrayList<String>();
|
||||
dots.add(dot);
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
|
||||
public class Name {
|
||||
public final String name;
|
||||
public Variable variable;
|
||||
public Name(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
package org.luaj.vm2.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.ast.Exp.Constant;
|
||||
import org.luaj.vm2.ast.Exp.NameExp;
|
||||
import org.luaj.vm2.ast.Exp.VarExp;
|
||||
import org.luaj.vm2.ast.Stat.Assign;
|
||||
import org.luaj.vm2.ast.Stat.FuncDef;
|
||||
import org.luaj.vm2.ast.Stat.GenericFor;
|
||||
import org.luaj.vm2.ast.Stat.LocalAssign;
|
||||
import org.luaj.vm2.ast.Stat.LocalFuncDef;
|
||||
import org.luaj.vm2.ast.Stat.NumericFor;
|
||||
|
||||
/**
|
||||
* Visitor that resolves names to scopes.
|
||||
* Each Name is resolved to a NamedVarible, possibly in a NameScope
|
||||
* if it is a local, or in no named scope if it is a global.
|
||||
*/
|
||||
public class NameResolver extends Visitor {
|
||||
|
||||
private NameScope scope = null;
|
||||
|
||||
private void pushScope() {
|
||||
scope = new NameScope(scope);
|
||||
}
|
||||
private void popScope() {
|
||||
scope = scope.outerScope;
|
||||
}
|
||||
|
||||
public void visit(NameScope scope) {
|
||||
}
|
||||
|
||||
public void visit(Block block) {
|
||||
pushScope();
|
||||
block.scope = scope;
|
||||
super.visit(block);
|
||||
popScope();
|
||||
}
|
||||
|
||||
public void visit(FuncBody body) {
|
||||
pushScope();
|
||||
scope.functionNestingCount++;
|
||||
body.scope = scope;
|
||||
super.visit(body);
|
||||
popScope();
|
||||
}
|
||||
|
||||
public void visit(LocalFuncDef stat) {
|
||||
defineLocalVar(stat.name);
|
||||
super.visit(stat);
|
||||
}
|
||||
|
||||
public void visit(NumericFor stat) {
|
||||
pushScope();
|
||||
stat.scope = scope;
|
||||
defineLocalVar(stat.name);
|
||||
super.visit(stat);
|
||||
popScope();
|
||||
}
|
||||
|
||||
public void visit(GenericFor stat) {
|
||||
pushScope();
|
||||
stat.scope = scope;
|
||||
defineLocalVars( stat.names );
|
||||
super.visit(stat);
|
||||
popScope();
|
||||
}
|
||||
|
||||
public void visit(NameExp exp) {
|
||||
exp.name.variable = resolveNameReference(exp.name);
|
||||
super.visit(exp);
|
||||
}
|
||||
|
||||
public void visit(FuncDef stat) {
|
||||
stat.name.name.variable = resolveNameReference(stat.name.name);
|
||||
stat.name.name.variable.hasassignments = true;
|
||||
super.visit(stat);
|
||||
}
|
||||
|
||||
public void visit(Assign stat) {
|
||||
super.visit(stat);
|
||||
for ( int i=0, n=stat.vars.size(); i<n; i++ ) {
|
||||
VarExp v = (VarExp) stat.vars.get(i);
|
||||
v.markHasAssignment();
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(LocalAssign stat) {
|
||||
visitExps(stat.values);
|
||||
defineLocalVars( stat.names );
|
||||
int n = stat.names.size();
|
||||
int m = stat.values!=null? stat.values.size(): 0;
|
||||
boolean isvarlist = m>0 && m<n && ((Exp)stat.values.get(m-1)).isvarargexp();
|
||||
for ( int i=0; i<n && i<(isvarlist?m-1:m); i++ )
|
||||
if ( stat.values.get(i) instanceof Constant )
|
||||
((Name)stat.names.get(i)).variable.initialValue = ((Constant) stat.values.get(i)).value;
|
||||
if ( !isvarlist )
|
||||
for ( int i=m; i<n; i++ )
|
||||
((Name)stat.names.get(i)).variable.initialValue = LuaValue.NIL;
|
||||
}
|
||||
|
||||
public void visit(ParList pars) {
|
||||
if ( pars.names != null )
|
||||
defineLocalVars(pars.names);
|
||||
if ( pars.isvararg )
|
||||
scope.define("arg");
|
||||
super.visit(pars);
|
||||
}
|
||||
|
||||
protected void defineLocalVars(List<Name> names) {
|
||||
for ( int i=0, n=names.size(); i<n; i++ )
|
||||
defineLocalVar((Name) names.get(i));
|
||||
}
|
||||
|
||||
protected void defineLocalVar(Name name) {
|
||||
name.variable = scope.define(name.name);
|
||||
}
|
||||
|
||||
protected Variable resolveNameReference(Name name) {
|
||||
Variable v = scope.find(name.name);
|
||||
if ( v.isLocal() && scope.functionNestingCount != v.definingScope.functionNestingCount )
|
||||
v.isupvalue = true;
|
||||
return v;
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class NameScope {
|
||||
|
||||
private static final Set<String> LUA_KEYWORDS = new HashSet<String>();
|
||||
|
||||
static {
|
||||
String[] k = new String[] {
|
||||
"and", "break", "do", "else", "elseif", "end",
|
||||
"false", "for", "function", "if", "in", "local",
|
||||
"nil", "not", "or", "repeat", "return",
|
||||
"then", "true", "until", "while" };
|
||||
for ( int i=0; i<k.length; i++ )
|
||||
LUA_KEYWORDS.add( k[i] );
|
||||
}
|
||||
|
||||
public final Map<String,Variable> namedVariables = new HashMap<String,Variable>();
|
||||
|
||||
public final NameScope outerScope;
|
||||
|
||||
public int functionNestingCount;
|
||||
|
||||
/** Construct default names scope */
|
||||
public NameScope() {
|
||||
this.outerScope = null;
|
||||
this.functionNestingCount = 0;
|
||||
}
|
||||
|
||||
/** Construct name scope within another scope*/
|
||||
public NameScope(NameScope outerScope) {
|
||||
this.outerScope = outerScope;
|
||||
this.functionNestingCount = outerScope!=null? outerScope.functionNestingCount: 0;
|
||||
}
|
||||
|
||||
/** Look up a name. If it is a global name, then throw IllegalArgumentException. */
|
||||
public Variable find( String name ) throws IllegalArgumentException {
|
||||
validateIsNotKeyword(name);
|
||||
for ( NameScope n = this; n!=null; n=n.outerScope )
|
||||
if ( n.namedVariables.containsKey(name) )
|
||||
return (Variable)n.namedVariables.get(name);
|
||||
Variable value = new Variable(name);
|
||||
this.namedVariables.put(name, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Define a name in this scope. If it is a global name, then throw IllegalArgumentException. */
|
||||
public Variable define( String name ) throws IllegalStateException, IllegalArgumentException {
|
||||
validateIsNotKeyword(name);
|
||||
Variable value = new Variable(name, this);
|
||||
this.namedVariables.put(name, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void validateIsNotKeyword(String name) {
|
||||
if ( LUA_KEYWORDS.contains(name) )
|
||||
throw new IllegalArgumentException("name is a keyword: '"+name+"'");
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ParList {
|
||||
public static final List<Name> EMPTY_NAMELIST = new ArrayList<Name>();
|
||||
public static final ParList EMPTY_PARLIST = new ParList(EMPTY_NAMELIST,false);
|
||||
|
||||
public final List<Name> names;
|
||||
public final boolean isvararg;
|
||||
|
||||
public ParList(List<Name> names, boolean isvararg) {
|
||||
this.names = names;
|
||||
this.isvararg = isvararg;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
@ -1,250 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.ast.Exp.VarExp;
|
||||
|
||||
abstract
|
||||
public class Stat {
|
||||
public abstract void accept(Visitor visitor);
|
||||
|
||||
public static Stat block(Block block) {
|
||||
return block;
|
||||
}
|
||||
|
||||
public static Stat whiledo(Exp exp, Block block) {
|
||||
return new WhileDo(exp, block);
|
||||
}
|
||||
|
||||
public static Stat repeatuntil(Block block, Exp exp) {
|
||||
return new RepeatUntil(block, exp);
|
||||
}
|
||||
|
||||
public static Stat breakstat() {
|
||||
return new Break();
|
||||
}
|
||||
|
||||
public static Stat returnstat(List<Exp> exps) {
|
||||
return new Return(exps);
|
||||
}
|
||||
|
||||
public static Stat assignment(List<VarExp> vars, List<Exp> exps) {
|
||||
return new Assign(vars,exps);
|
||||
}
|
||||
|
||||
public static Stat functioncall(Exp.FuncCall funccall) {
|
||||
return new FuncCallStat(funccall);
|
||||
}
|
||||
|
||||
public static Stat localfunctiondef(String name, FuncBody funcbody) {
|
||||
return new LocalFuncDef(name, funcbody);
|
||||
}
|
||||
|
||||
public static Stat fornumeric(String name, Exp initial, Exp limit, Exp step, Block block) {
|
||||
return new NumericFor(name, initial, limit, step, block);
|
||||
}
|
||||
|
||||
public static Stat functiondef(FuncName funcname, FuncBody funcbody) {
|
||||
return new FuncDef( funcname, funcbody );
|
||||
}
|
||||
|
||||
public static Stat forgeneric(List<Name> names, List<Exp> exps, Block block) {
|
||||
return new GenericFor(names, exps, block);
|
||||
}
|
||||
|
||||
public static Stat localassignment(List<Name> names, List<Exp> values) {
|
||||
return new LocalAssign(names, values);
|
||||
}
|
||||
|
||||
public static Stat ifthenelse(Exp ifexp, Block ifblock, List<Exp> elseifexps, List<Block> elseifblocks, Block elseblock) {
|
||||
return new IfThenElse(ifexp, ifblock, elseifexps, elseifblocks, elseblock);
|
||||
}
|
||||
|
||||
public static class Assign extends Stat {
|
||||
public final List<VarExp> vars;
|
||||
public final List<Exp> exps;
|
||||
|
||||
public Assign(List<VarExp> vars, List<Exp> exps) {
|
||||
this.vars = vars;
|
||||
this.exps = exps;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class WhileDo extends Stat {
|
||||
public final Exp exp;
|
||||
public final Block block;
|
||||
public WhileDo( Exp exp, Block block ) {
|
||||
this.exp = exp;
|
||||
this.block = block;
|
||||
}
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class RepeatUntil extends Stat {
|
||||
public final Block block;
|
||||
public final Exp exp;
|
||||
public RepeatUntil( Block block, Exp exp ) {
|
||||
this.block = block;
|
||||
this.exp = exp;
|
||||
}
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class Break extends Stat {
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class Return extends Stat {
|
||||
public final List<Exp> values;
|
||||
public Return(List<Exp> values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
|
||||
public int nreturns() {
|
||||
int n = values!=null? values.size(): 0;
|
||||
if ( n>0 && ((Exp)values.get(n-1)).isvarargexp() )
|
||||
n = -1;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FuncCallStat extends Stat {
|
||||
public final Exp.FuncCall funccall;
|
||||
public FuncCallStat(Exp.FuncCall funccall) {
|
||||
this.funccall = funccall;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class LocalFuncDef extends Stat {
|
||||
public final Name name;
|
||||
public final FuncBody body;
|
||||
public LocalFuncDef(String name, FuncBody body) {
|
||||
this.name = new Name(name);
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class FuncDef extends Stat {
|
||||
public final FuncName name;
|
||||
public final FuncBody body;
|
||||
public FuncDef(FuncName name, FuncBody body) {
|
||||
this.name = name;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenericFor extends Stat {
|
||||
public List<Name> names;
|
||||
public List<Exp> exps;
|
||||
public Block block;
|
||||
public NameScope scope;
|
||||
public GenericFor(List<Name> names, List<Exp> exps, Block block) {
|
||||
this.names = names;
|
||||
this.exps = exps;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class NumericFor extends Stat {
|
||||
public final Name name;
|
||||
public final Exp initial,limit,step;
|
||||
public final Block block;
|
||||
public NameScope scope;
|
||||
public NumericFor(String name, Exp initial, Exp limit, Exp step, Block block) {
|
||||
this.name = new Name(name);
|
||||
this.initial = initial;
|
||||
this.limit = limit;
|
||||
this.step = step;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class LocalAssign extends Stat {
|
||||
public final List<Name> names;
|
||||
public final List<Exp> values;
|
||||
public LocalAssign(List<Name> names, List<Exp> values) {
|
||||
this.names = names;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
|
||||
public static class IfThenElse extends Stat {
|
||||
public final Exp ifexp;
|
||||
public final Block ifblock;
|
||||
public final List<Exp> elseifexps;
|
||||
public final List<Block> elseifblocks;
|
||||
public final Block elseblock;
|
||||
public IfThenElse(Exp ifexp, Block ifblock, List<Exp> elseifexps,
|
||||
List<Block> elseifblocks, Block elseblock) {
|
||||
this.ifexp = ifexp;
|
||||
this.ifblock = ifblock;
|
||||
this.elseifexps = elseifexps;
|
||||
this.elseifblocks = elseifblocks;
|
||||
this.elseblock = elseblock;
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit( this );
|
||||
}
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
|
||||
public class Str {
|
||||
|
||||
private Str() {}
|
||||
|
||||
public static LuaString quoteString(String image) {
|
||||
String s = image.substring(1, image.length()-1);
|
||||
byte[] bytes = unquote(s);
|
||||
return LuaString.valueOf(bytes);
|
||||
}
|
||||
|
||||
public static LuaString charString(String image) {
|
||||
String s = image.substring(1, image.length()-1);
|
||||
byte[] bytes = unquote(s);
|
||||
return LuaString.valueOf(bytes);
|
||||
}
|
||||
|
||||
public static LuaString longString(String image) {
|
||||
int i = image.indexOf('[', image.indexOf('[')+1)+1;
|
||||
String s = image.substring(i,image.length()-i);
|
||||
byte[] b = iso88591bytes(s);
|
||||
return LuaString.valueOf(b);
|
||||
}
|
||||
|
||||
public static byte[] iso88591bytes( String s ) {
|
||||
try {
|
||||
return s.getBytes("ISO8859-1");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("ISO8859-1 not supported");
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] unquote(String s) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
char[] c = s.toCharArray();
|
||||
int n = c.length;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if ( c[i] == '\\' && i<n ) {
|
||||
switch ( c[++i] ) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
int d=(int) (c[i++]-'0');
|
||||
for ( int j=0; i<n && j<2 && c[i]>='0' && c[i]<='9'; i++, j++ )
|
||||
d = d * 10 + (int) (c[i]-'0');
|
||||
baos.write( (byte) d );
|
||||
--i;
|
||||
continue;
|
||||
case 'a': baos.write( (byte) 7 ); continue;
|
||||
case 'b': baos.write( (byte) '\b' ); continue;
|
||||
case 'f': baos.write( (byte) '\f' ); continue;
|
||||
case 'n': baos.write( (byte) '\n' ); continue;
|
||||
case 'r': baos.write( (byte) '\r' ); continue;
|
||||
case 't': baos.write( (byte) '\t' ); continue;
|
||||
case 'v': baos.write( (byte) 11 ); continue;
|
||||
case '"': baos.write( (byte) '"' ); continue;
|
||||
case '\'': baos.write( (byte) '\'' ); continue;
|
||||
case '\\': baos.write( (byte) '\\' ); continue;
|
||||
default: baos.write( (byte) c[i] ); break;
|
||||
}
|
||||
} else {
|
||||
baos.write( (byte) c[i] );
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TableConstructor extends Exp {
|
||||
public List<TableField> fields;
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
public class TableField {
|
||||
|
||||
public final Exp index;
|
||||
public final String name;
|
||||
public final Exp rhs;
|
||||
|
||||
public TableField(Exp index, String name, Exp rhs) {
|
||||
this.index = index;
|
||||
this.name = name;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
public static TableField keyedField(Exp index, Exp rhs) {
|
||||
return new TableField(index, null, rhs);
|
||||
}
|
||||
|
||||
public static TableField namedField(String name, Exp rhs) {
|
||||
return new TableField(null, name, rhs);
|
||||
}
|
||||
|
||||
public static TableField listField(Exp rhs) {
|
||||
return new TableField(null, null, rhs);
|
||||
}
|
||||
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/** Variable is created lua name scopes, and is a named, lua variable that
|
||||
* either refers to a lua local, global, or upvalue storage location.
|
||||
*/
|
||||
public class Variable {
|
||||
|
||||
/** The name as it appears in lua source code */
|
||||
public final String name;
|
||||
|
||||
/** The lua scope in which this variable is defined. */
|
||||
public final NameScope definingScope;
|
||||
|
||||
/** true if this variable is an upvalue */
|
||||
public boolean isupvalue;
|
||||
|
||||
/** true if there are assignments made to this variable */
|
||||
public boolean hasassignments;
|
||||
|
||||
/** When hasassignments == false, and the initial value is a constant, this is the initial value */
|
||||
public LuaValue initialValue;
|
||||
|
||||
/** Global is named variable not associated with a defining scope */
|
||||
public Variable(String name) {
|
||||
this.name = name;
|
||||
this.definingScope = null;
|
||||
}
|
||||
public Variable(String name, NameScope definingScope) {
|
||||
/** Local variable is defined in a particular scope. */
|
||||
this.name = name;
|
||||
this.definingScope = definingScope;
|
||||
}
|
||||
public boolean isLocal() {
|
||||
return this.definingScope != null;
|
||||
}
|
||||
public boolean isConstant() {
|
||||
return ! hasassignments && initialValue != null;
|
||||
}
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.ast.Exp.VarExp;
|
||||
|
||||
abstract public class Visitor {
|
||||
public void visit(Chunk chunk) {
|
||||
chunk.block.accept(this);
|
||||
};
|
||||
public void visit(Block block) {
|
||||
visit(block.scope);
|
||||
if ( block.stats != null )
|
||||
for ( int i=0, n=block.stats.size(); i<n; i++ )
|
||||
((Stat)block.stats.get(i)).accept(this);
|
||||
};
|
||||
public void visit(Stat.Assign stat) {
|
||||
visitVars(stat.vars);
|
||||
visitExps(stat.exps);
|
||||
}
|
||||
public void visit(Stat.Break breakstat) {
|
||||
}
|
||||
public void visit(Stat.FuncCallStat stat) {
|
||||
stat.funccall.accept(this);
|
||||
}
|
||||
public void visit(Stat.FuncDef stat) {
|
||||
stat.body.accept(this);
|
||||
}
|
||||
public void visit(Stat.GenericFor stat) {
|
||||
visit(stat.scope);
|
||||
visitNames(stat.names);
|
||||
visitExps(stat.exps);
|
||||
stat.block.accept(this);
|
||||
}
|
||||
public void visit(Stat.IfThenElse stat) {
|
||||
stat.ifexp.accept(this);
|
||||
stat.ifblock.accept(this);
|
||||
if ( stat.elseifblocks != null )
|
||||
for ( int i=0, n=stat.elseifblocks.size(); i<n; i++ ) {
|
||||
((Exp)stat.elseifexps.get(i)).accept(this);
|
||||
((Block)stat.elseifblocks.get(i)).accept(this);
|
||||
}
|
||||
if ( stat.elseblock != null )
|
||||
visit( stat.elseblock );
|
||||
}
|
||||
public void visit(Stat.LocalAssign stat) {
|
||||
visitNames(stat.names);
|
||||
visitExps(stat.values);
|
||||
}
|
||||
public void visit(Stat.LocalFuncDef stat) {
|
||||
visit(stat.name);
|
||||
stat.body.accept(this);
|
||||
}
|
||||
public void visit(Stat.NumericFor stat) {
|
||||
visit(stat.scope);
|
||||
visit(stat.name);
|
||||
stat.initial.accept(this);
|
||||
stat.limit.accept(this);
|
||||
if ( stat.step != null )
|
||||
stat.step.accept(this);
|
||||
stat.block.accept(this);
|
||||
}
|
||||
public void visit(Stat.RepeatUntil stat) {
|
||||
stat.block.accept(this);
|
||||
stat.exp.accept(this);
|
||||
}
|
||||
public void visit(Stat.Return stat) {
|
||||
visitExps(stat.values);
|
||||
}
|
||||
public void visit(Stat.WhileDo stat) {
|
||||
stat.exp.accept(this);
|
||||
stat.block.accept(this);
|
||||
}
|
||||
public void visit(FuncBody body) {
|
||||
visit(body.scope);
|
||||
body.parlist.accept(this);
|
||||
body.block.accept(this);
|
||||
}
|
||||
public void visit(FuncArgs args) {
|
||||
visitExps(args.exps);
|
||||
}
|
||||
public void visit(TableField field) {
|
||||
if ( field.name != null );
|
||||
visit( field.name );
|
||||
if ( field.index != null )
|
||||
field.index.accept(this);
|
||||
field.rhs.accept(this);
|
||||
}
|
||||
public void visit(Exp.AnonFuncDef exp) {
|
||||
exp.body.accept(this);
|
||||
}
|
||||
public void visit(Exp.BinopExp exp) {
|
||||
exp.lhs.accept(this);
|
||||
exp.rhs.accept(this);
|
||||
}
|
||||
public void visit(Exp.Constant exp) {
|
||||
}
|
||||
public void visit(Exp.FieldExp exp) {
|
||||
exp.lhs.accept(this);
|
||||
visit(exp.name);
|
||||
}
|
||||
public void visit(Exp.FuncCall exp) {
|
||||
exp.lhs.accept(this);
|
||||
exp.args.accept(this);
|
||||
}
|
||||
public void visit(Exp.IndexExp exp) {
|
||||
exp.lhs.accept(this);
|
||||
exp.exp.accept(this);
|
||||
}
|
||||
public void visit(Exp.MethodCall exp) {
|
||||
exp.lhs.accept(this);
|
||||
visit(exp.name);
|
||||
exp.args.accept(this);
|
||||
}
|
||||
public void visit(Exp.NameExp exp) {
|
||||
visit(exp.name);
|
||||
}
|
||||
public void visit(Exp.ParensExp exp) {
|
||||
exp.exp.accept(this);
|
||||
}
|
||||
public void visit(Exp.UnopExp exp) {
|
||||
exp.rhs.accept(this);
|
||||
}
|
||||
public void visit(Exp.VarargsExp exp) {
|
||||
}
|
||||
public void visit(ParList pars) {
|
||||
visitNames(pars.names);
|
||||
}
|
||||
public void visit(TableConstructor table) {
|
||||
if( table.fields != null)
|
||||
for ( int i=0, n=table.fields.size(); i<n; i++ )
|
||||
((TableField)table.fields.get(i)).accept(this);
|
||||
}
|
||||
public void visitVars(List<VarExp> vars) {
|
||||
if ( vars != null )
|
||||
for ( int i=0, n=vars.size(); i<n; i++ )
|
||||
((Exp.VarExp)vars.get(i)).accept(this);
|
||||
}
|
||||
public void visitExps(List<Exp> exps) {
|
||||
if ( exps != null )
|
||||
for ( int i=0, n=exps.size(); i<n; i++ )
|
||||
((Exp)exps.get(i)).accept(this);
|
||||
}
|
||||
public void visitNames(List<Name> names) {
|
||||
if ( names != null )
|
||||
for ( int i=0, n=names.size(); i<n; i++ )
|
||||
visit((Name) names.get(i));
|
||||
}
|
||||
public void visit(Name name) {
|
||||
}
|
||||
public void visit(String name) {
|
||||
}
|
||||
public void visit(NameScope scope) {
|
||||
}
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* Helper class to coerce values from Java to lua within the luajava library.
|
||||
* <p>
|
||||
* This class is primarily used by the {@link LuajavaLib},
|
||||
* but can also be used directly when working with Java/lua bindings.
|
||||
* <p>
|
||||
* To coerce scalar types, the various, generally the {@code valueOf(type)} methods
|
||||
* on {@link LuaValue} may be used:
|
||||
* <ul>
|
||||
* <li>{@link LuaValue#valueOf(boolean)}</li>
|
||||
* <li>{@link LuaValue#valueOf(byte[])}</li>
|
||||
* <li>{@link LuaValue#valueOf(double)}</li>
|
||||
* <li>{@link LuaValue#valueOf(int)}</li>
|
||||
* <li>{@link LuaValue#valueOf(String)}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* To coerce arrays of objects and lists, the {@code listOf(..)} and {@code tableOf(...)} methods
|
||||
* on {@link LuaValue} may be used:
|
||||
* <ul>
|
||||
* <li>{@link LuaValue#listOf(LuaValue[])}</li>
|
||||
* <li>{@link LuaValue#listOf(LuaValue[], org.luaj.vm2.Varargs)}</li>
|
||||
* <li>{@link LuaValue#tableOf(LuaValue[])}</li>
|
||||
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], org.luaj.vm2.Varargs)}</li>
|
||||
* </ul>
|
||||
* The method {@link CoerceJavaToLua#coerce(Object)} looks as the type and dimesioning
|
||||
* of the argument and tries to guess the best fit for corrsponding lua scalar,
|
||||
* table, or table of tables.
|
||||
*
|
||||
* @see CoerceJavaToLua#coerce(Object)
|
||||
* @see LuajavaLib
|
||||
*/
|
||||
public class CoerceJavaToLua {
|
||||
|
||||
static interface Coercion {
|
||||
public LuaValue coerce( Object javaValue );
|
||||
};
|
||||
|
||||
static final Map COERCIONS = new HashMap();
|
||||
|
||||
static {
|
||||
Coercion boolCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Boolean b = (Boolean) javaValue;
|
||||
return b.booleanValue()? LuaValue.TRUE: LuaValue.FALSE;
|
||||
}
|
||||
} ;
|
||||
Coercion intCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Number n = (Number) javaValue;
|
||||
return LuaInteger.valueOf( n.intValue() );
|
||||
}
|
||||
} ;
|
||||
Coercion charCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Character c = (Character) javaValue;
|
||||
return LuaInteger.valueOf( c.charValue() );
|
||||
}
|
||||
} ;
|
||||
Coercion doubleCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
Number n = (Number) javaValue;
|
||||
return LuaDouble.valueOf( n.doubleValue() );
|
||||
}
|
||||
} ;
|
||||
Coercion stringCoercion = new Coercion() {
|
||||
public LuaValue coerce( Object javaValue ) {
|
||||
return LuaString.valueOf( javaValue.toString() );
|
||||
}
|
||||
} ;
|
||||
COERCIONS.put( Boolean.class, boolCoercion );
|
||||
COERCIONS.put( Byte.class, intCoercion );
|
||||
COERCIONS.put( Character.class, charCoercion );
|
||||
COERCIONS.put( Short.class, intCoercion );
|
||||
COERCIONS.put( Integer.class, intCoercion );
|
||||
COERCIONS.put( Long.class, doubleCoercion );
|
||||
COERCIONS.put( Float.class, doubleCoercion );
|
||||
COERCIONS.put( Double.class, doubleCoercion );
|
||||
COERCIONS.put( String.class, stringCoercion );
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerse a Java object to a corresponding lua value.
|
||||
* <p>
|
||||
* Integral types {@code boolean}, {@code byte}, {@code char}, and {@code int}
|
||||
* will become {@link LuaInteger};
|
||||
* {@code long}, {@code float}, and {@code double} will become {@link LuaDouble};
|
||||
* {@code String} and {@code byte[]} will become {@link LuaString};
|
||||
* other types will become {@link LuaUserdata}.
|
||||
* @param o Java object needing conversion
|
||||
* @return {@link LuaValue} corresponding to the supplied Java value.
|
||||
* @see LuaValue
|
||||
* @see LuaInteger
|
||||
* @see LuaDouble
|
||||
* @see LuaString
|
||||
* @see LuaUserdata
|
||||
*/
|
||||
public static LuaValue coerce(Object o) {
|
||||
if ( o == null )
|
||||
return LuaValue.NIL;
|
||||
Class clazz = o.getClass();
|
||||
Coercion c = (Coercion) COERCIONS.get( clazz );
|
||||
if ( c == null ) {
|
||||
c = o instanceof Class? JavaClass.forClass((Class)o):
|
||||
clazz.isArray()? arrayCoercion:
|
||||
instanceCoercion;
|
||||
COERCIONS.put( clazz, c );
|
||||
}
|
||||
return c.coerce(o);
|
||||
}
|
||||
|
||||
static final Coercion instanceCoercion = new Coercion() {
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return new JavaInstance(javaValue);
|
||||
}
|
||||
};
|
||||
|
||||
// should be userdata?
|
||||
static final Coercion arrayCoercion = new Coercion() {
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return new JavaArray(javaValue);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,367 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Helper class to coerce values from lua to Java within the luajava library.
|
||||
* <p>
|
||||
* This class is primarily used by the {@link LuajavaLib},
|
||||
* but can also be used directly when working with Java/lua bindings.
|
||||
* <p>
|
||||
* To coerce to specific Java values, generally the {@code toType()} methods
|
||||
* on {@link LuaValue} may be used:
|
||||
* <ul>
|
||||
* <li>{@link LuaValue#toboolean()}</li>
|
||||
* <li>{@link LuaValue#tobyte()}</li>
|
||||
* <li>{@link LuaValue#tochar()}</li>
|
||||
* <li>{@link LuaValue#toshort()}</li>
|
||||
* <li>{@link LuaValue#toint()}</li>
|
||||
* <li>{@link LuaValue#tofloat()}</li>
|
||||
* <li>{@link LuaValue#todouble()}</li>
|
||||
* <li>{@link LuaValue#tojstring()}</li>
|
||||
* <li>{@link LuaValue#touserdata()}</li>
|
||||
* <li>{@link LuaValue#touserdata(Class)}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For data in lua tables, the various methods on {@link LuaTable} can be used directly
|
||||
* to convert data to something more useful.
|
||||
*
|
||||
* @see LuajavaLib
|
||||
* @see CoerceJavaToLua
|
||||
*/
|
||||
public class CoerceLuaToJava {
|
||||
|
||||
static int SCORE_NULL_VALUE = 0x10;
|
||||
static int SCORE_WRONG_TYPE = 0x100;
|
||||
static int SCORE_UNCOERCIBLE = 0x10000;
|
||||
|
||||
static interface Coercion {
|
||||
public int score( LuaValue value );
|
||||
public Object coerce( LuaValue value );
|
||||
};
|
||||
|
||||
/**
|
||||
* Coerce a LuaValue value to a specified java class
|
||||
* @param value LuaValue to coerce
|
||||
* @param clazz Class to coerce into
|
||||
* @return Object of type clazz (or a subclass) with the corresponding value.
|
||||
*/
|
||||
public static Object coerce(LuaValue value, Class clazz) {
|
||||
return getCoercion(clazz).coerce(value);
|
||||
}
|
||||
|
||||
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static final class BoolCoercion implements Coercion {
|
||||
public String toString() {
|
||||
return "BoolCoercion()";
|
||||
}
|
||||
public int score( LuaValue value ) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public Object coerce(LuaValue value) {
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static final class NumericCoercion implements Coercion {
|
||||
static final int TARGET_TYPE_BYTE = 0;
|
||||
static final int TARGET_TYPE_CHAR = 1;
|
||||
static final int TARGET_TYPE_SHORT = 2;
|
||||
static final int TARGET_TYPE_INT = 3;
|
||||
static final int TARGET_TYPE_LONG = 4;
|
||||
static final int TARGET_TYPE_FLOAT = 5;
|
||||
static final int TARGET_TYPE_DOUBLE = 6;
|
||||
static final String[] TYPE_NAMES = { "byte", "char", "short", "int", "long", "float", "double" };
|
||||
final int targetType;
|
||||
public String toString() {
|
||||
return "NumericCoercion("+TYPE_NAMES[targetType]+")";
|
||||
}
|
||||
NumericCoercion(int targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
public int score( LuaValue value ) {
|
||||
if ( value.isint() ) {
|
||||
switch ( targetType ) {
|
||||
case TARGET_TYPE_BYTE: {
|
||||
int i = value.toint();
|
||||
return (i==(byte)i)? 0: SCORE_WRONG_TYPE;
|
||||
}
|
||||
case TARGET_TYPE_CHAR: {
|
||||
int i = value.toint();
|
||||
return (i==(byte)i)? 1: (i==(char)i)? 0: SCORE_WRONG_TYPE;
|
||||
}
|
||||
case TARGET_TYPE_SHORT: {
|
||||
int i = value.toint();
|
||||
return (i==(byte)i)? 1: (i==(short)i)? 0: SCORE_WRONG_TYPE;
|
||||
}
|
||||
case TARGET_TYPE_INT: {
|
||||
int i = value.toint();
|
||||
return (i==(byte)i)? 2: ((i==(char)i) || (i==(short)i))? 1: 0;
|
||||
}
|
||||
case TARGET_TYPE_FLOAT: return 1;
|
||||
case TARGET_TYPE_LONG: return 1;
|
||||
case TARGET_TYPE_DOUBLE: return 2;
|
||||
default: return SCORE_WRONG_TYPE;
|
||||
}
|
||||
} else if ( value.isnumber() ) {
|
||||
switch ( targetType ) {
|
||||
case TARGET_TYPE_BYTE: return SCORE_WRONG_TYPE;
|
||||
case TARGET_TYPE_CHAR: return SCORE_WRONG_TYPE;
|
||||
case TARGET_TYPE_SHORT: return SCORE_WRONG_TYPE;
|
||||
case TARGET_TYPE_INT: return SCORE_WRONG_TYPE;
|
||||
case TARGET_TYPE_LONG: {
|
||||
double d = value.todouble();
|
||||
return (d==(long)d)? 0: SCORE_WRONG_TYPE;
|
||||
}
|
||||
case TARGET_TYPE_FLOAT: {
|
||||
double d = value.todouble();
|
||||
return (d==(float)d)? 0: SCORE_WRONG_TYPE;
|
||||
}
|
||||
case TARGET_TYPE_DOUBLE: {
|
||||
double d = value.todouble();
|
||||
return ((d==(long)d) || (d==(float)d))? 1: 0;
|
||||
}
|
||||
default: return SCORE_WRONG_TYPE;
|
||||
}
|
||||
} else {
|
||||
return SCORE_UNCOERCIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
public Object coerce(LuaValue value) {
|
||||
switch ( targetType ) {
|
||||
case TARGET_TYPE_BYTE: return new Byte( (byte) value.toint() );
|
||||
case TARGET_TYPE_CHAR: return new Character( (char) value.toint() );
|
||||
case TARGET_TYPE_SHORT: return new Short( (short) value.toint() );
|
||||
case TARGET_TYPE_INT: return new Integer( (int) value.toint() );
|
||||
case TARGET_TYPE_LONG: return new Long( (long) value.todouble() );
|
||||
case TARGET_TYPE_FLOAT: return new Float( (float) value.todouble() );
|
||||
case TARGET_TYPE_DOUBLE: return new Double( (double) value.todouble() );
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class StringCoercion implements Coercion {
|
||||
public static final int TARGET_TYPE_STRING = 0;
|
||||
public static final int TARGET_TYPE_BYTES = 1;
|
||||
final int targetType;
|
||||
public StringCoercion(int targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
public String toString() {
|
||||
return "StringCoercion("+(targetType==TARGET_TYPE_STRING? "String": "byte[]")+")";
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TSTRING:
|
||||
return value.checkstring().isValidUtf8()?
|
||||
(targetType==TARGET_TYPE_STRING? 0: 1):
|
||||
(targetType==TARGET_TYPE_BYTES? 0: SCORE_WRONG_TYPE);
|
||||
case LuaValue.TNIL:
|
||||
return SCORE_NULL_VALUE;
|
||||
default:
|
||||
return targetType == TARGET_TYPE_STRING? SCORE_WRONG_TYPE: SCORE_UNCOERCIBLE;
|
||||
}
|
||||
}
|
||||
public Object coerce(LuaValue value) {
|
||||
if ( value.isnil() )
|
||||
return null;
|
||||
if ( targetType == TARGET_TYPE_STRING )
|
||||
return value.tojstring();
|
||||
LuaString s = value.checkstring();
|
||||
byte[] b = new byte[s.m_length];
|
||||
s.copyInto(0, b, 0, b.length);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
static final class ArrayCoercion implements Coercion {
|
||||
final Class componentType;
|
||||
final Coercion componentCoercion;
|
||||
public ArrayCoercion(Class componentType) {
|
||||
this.componentType = componentType;
|
||||
this.componentCoercion = getCoercion(componentType);
|
||||
}
|
||||
public String toString() {
|
||||
return "ArrayCoercion("+componentType.getName()+")";
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TTABLE:
|
||||
return value.length()==0? 0: componentCoercion.score( value.get(1) );
|
||||
case LuaValue.TUSERDATA:
|
||||
return inheritanceLevels( componentType, value.touserdata().getClass().getComponentType() );
|
||||
case LuaValue.TNIL:
|
||||
return SCORE_NULL_VALUE;
|
||||
default:
|
||||
return SCORE_UNCOERCIBLE;
|
||||
}
|
||||
}
|
||||
public Object coerce(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TTABLE: {
|
||||
int n = value.length();
|
||||
Object a = Array.newInstance(componentType, n);
|
||||
for ( int i=0; i<n; i++ )
|
||||
Array.set(a, i, componentCoercion.coerce(value.get(i+1)));
|
||||
return a;
|
||||
}
|
||||
case LuaValue.TUSERDATA:
|
||||
return value.touserdata();
|
||||
case LuaValue.TNIL:
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine levels of inheritance between a base class and a subclass
|
||||
* @param baseclass base class to look for
|
||||
* @param subclass class from which to start looking
|
||||
* @return number of inheritance levels between subclass and baseclass,
|
||||
* or SCORE_UNCOERCIBLE if not a subclass
|
||||
*/
|
||||
static final int inheritanceLevels( Class baseclass, Class subclass ) {
|
||||
if ( subclass == null )
|
||||
return SCORE_UNCOERCIBLE;
|
||||
if ( baseclass == subclass )
|
||||
return 0;
|
||||
int min = Math.min( SCORE_UNCOERCIBLE, inheritanceLevels( baseclass, subclass.getSuperclass() ) + 1 );
|
||||
Class[] ifaces = subclass.getInterfaces();
|
||||
for ( int i=0; i<ifaces.length; i++ )
|
||||
min = Math.min(min, inheritanceLevels(baseclass, ifaces[i]) + 1 );
|
||||
return min;
|
||||
}
|
||||
|
||||
static final class ObjectCoercion implements Coercion {
|
||||
final Class targetType;
|
||||
ObjectCoercion(Class targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
public String toString() {
|
||||
return "ObjectCoercion("+targetType.getName()+")";
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return inheritanceLevels( targetType, value.isint()? Integer.class: Double.class );
|
||||
case LuaValue.TBOOLEAN:
|
||||
return inheritanceLevels( targetType, Boolean.class );
|
||||
case LuaValue.TSTRING:
|
||||
return inheritanceLevels( targetType, String.class );
|
||||
case LuaValue.TUSERDATA:
|
||||
return inheritanceLevels( targetType, value.touserdata().getClass() );
|
||||
case LuaValue.TNIL:
|
||||
return SCORE_NULL_VALUE;
|
||||
default:
|
||||
return inheritanceLevels( targetType, value.getClass() );
|
||||
}
|
||||
}
|
||||
public Object coerce(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return value.isint()? (Object)new Integer(value.toint()): (Object)new Double(value.todouble());
|
||||
case LuaValue.TBOOLEAN:
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
case LuaValue.TSTRING:
|
||||
return value.tojstring();
|
||||
case LuaValue.TUSERDATA:
|
||||
return value.optuserdata(targetType, null);
|
||||
case LuaValue.TNIL:
|
||||
return null;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
Coercion boolCoercion = new BoolCoercion();
|
||||
Coercion byteCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_BYTE);
|
||||
Coercion charCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_CHAR);
|
||||
Coercion shortCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_SHORT);
|
||||
Coercion intCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_INT);
|
||||
Coercion longCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_LONG);
|
||||
Coercion floatCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_FLOAT);
|
||||
Coercion doubleCoercion = new NumericCoercion(NumericCoercion.TARGET_TYPE_DOUBLE);
|
||||
Coercion stringCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_STRING);
|
||||
Coercion bytesCoercion = new StringCoercion(StringCoercion.TARGET_TYPE_BYTES);
|
||||
|
||||
COERCIONS.put( Boolean.TYPE, boolCoercion );
|
||||
COERCIONS.put( Boolean.class, boolCoercion );
|
||||
COERCIONS.put( Byte.TYPE, byteCoercion );
|
||||
COERCIONS.put( Byte.class, byteCoercion );
|
||||
COERCIONS.put( Character.TYPE, charCoercion );
|
||||
COERCIONS.put( Character.class, charCoercion );
|
||||
COERCIONS.put( Short.TYPE, shortCoercion );
|
||||
COERCIONS.put( Short.class, shortCoercion );
|
||||
COERCIONS.put( Integer.TYPE, intCoercion );
|
||||
COERCIONS.put( Integer.class, intCoercion );
|
||||
COERCIONS.put( Long.TYPE, longCoercion );
|
||||
COERCIONS.put( Long.class, longCoercion );
|
||||
COERCIONS.put( Float.TYPE, floatCoercion );
|
||||
COERCIONS.put( Float.class, floatCoercion );
|
||||
COERCIONS.put( Double.TYPE, doubleCoercion );
|
||||
COERCIONS.put( Double.class, doubleCoercion );
|
||||
COERCIONS.put( String.class, stringCoercion );
|
||||
COERCIONS.put( byte[].class, bytesCoercion );
|
||||
}
|
||||
|
||||
static Coercion getCoercion(Class c) {
|
||||
Coercion co = (Coercion) COERCIONS.get( c );
|
||||
if ( co != null ) {
|
||||
return co;
|
||||
}
|
||||
if ( c.isArray() ) {
|
||||
Class typ = c.getComponentType();
|
||||
co = new ArrayCoercion(c.getComponentType());
|
||||
} else {
|
||||
co = new ObjectCoercion(c);
|
||||
}
|
||||
COERCIONS.put( c, co );
|
||||
return co;
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 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;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java instance of array type.
|
||||
* <p>
|
||||
* Can get elements by their integer key index, as well as the length.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
|
||||
* when an array is supplied.
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaArray extends LuaUserdata {
|
||||
|
||||
static final LuaValue LENGTH = valueOf("length");
|
||||
|
||||
JavaArray(Object instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
public LuaValue get(LuaValue key) {
|
||||
if ( key.equals(LENGTH) )
|
||||
return valueOf(Array.getLength(m_instance));
|
||||
if ( key.isint() ) {
|
||||
int i = key.toint() - 1;
|
||||
return i>=0 && i<Array.getLength(m_instance)?
|
||||
CoerceJavaToLua.coerce(Array.get(m_instance,key.toint()-1)):
|
||||
NIL;
|
||||
}
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
public void set(LuaValue key, LuaValue value) {
|
||||
if ( key.isint() ) {
|
||||
int i = key.toint() - 1;
|
||||
if ( i>=0 && i<Array.getLength(m_instance) )
|
||||
Array.set(m_instance,i,CoerceLuaToJava.coerce(value, m_instance.getClass().getComponentType()));
|
||||
else if ( m_metatable==null || ! settable(this,key,value) )
|
||||
error("array index out of bounds");
|
||||
}
|
||||
else
|
||||
super.set(key, value);
|
||||
}
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 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;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java class.
|
||||
* <p>
|
||||
* Will respond to get() and set() by returning field values, or java methods.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
|
||||
* when a Class is supplied.
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaClass extends JavaInstance implements CoerceJavaToLua.Coercion {
|
||||
|
||||
static final Map classes = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static final LuaValue NEW = valueOf("new");
|
||||
|
||||
Map fields;
|
||||
Map methods;
|
||||
|
||||
static JavaClass forClass(Class c) {
|
||||
JavaClass j = (JavaClass) classes.get(c);
|
||||
if ( j == null )
|
||||
classes.put( c, j = new JavaClass(c) );
|
||||
return j;
|
||||
}
|
||||
|
||||
JavaClass(Class c) {
|
||||
super(c);
|
||||
this.jclass = this;
|
||||
}
|
||||
|
||||
public LuaValue coerce(Object javaValue) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Field getField(LuaValue key) {
|
||||
if ( fields == null ) {
|
||||
Map m = new HashMap();
|
||||
Field[] f = ((Class)m_instance).getFields();
|
||||
for ( int i=0; i<f.length; i++ ) {
|
||||
Field fi = f[i];
|
||||
if ( Modifier.isPublic(fi.getModifiers()) ) {
|
||||
m.put( LuaValue.valueOf(fi.getName()), fi );
|
||||
try {
|
||||
if (!fi.isAccessible())
|
||||
fi.setAccessible(true);
|
||||
} catch (SecurityException s) {
|
||||
}
|
||||
}
|
||||
}
|
||||
fields = m;
|
||||
}
|
||||
return (Field) fields.get(key);
|
||||
}
|
||||
|
||||
LuaValue getMethod(LuaValue key) {
|
||||
if ( methods == null ) {
|
||||
Map namedlists = new HashMap();
|
||||
Method[] m = ((Class)m_instance).getMethods();
|
||||
for ( int i=0; i<m.length; i++ ) {
|
||||
Method mi = m[i];
|
||||
if ( Modifier.isPublic( mi.getModifiers()) ) {
|
||||
String name = mi.getName();
|
||||
List list = (List) namedlists.get(name);
|
||||
if ( list == null )
|
||||
namedlists.put(name, list = new ArrayList());
|
||||
list.add( JavaMethod.forMethod(mi) );
|
||||
}
|
||||
}
|
||||
Map map = new HashMap();
|
||||
Constructor[] c = ((Class)m_instance).getConstructors();
|
||||
List list = new ArrayList();
|
||||
for ( int i=0; i<c.length; i++ )
|
||||
if ( Modifier.isPublic(c[i].getModifiers()) )
|
||||
list.add( JavaConstructor.forConstructor(c[i]) );
|
||||
switch ( list.size() ) {
|
||||
case 0: break;
|
||||
case 1: map.put(NEW, list.get(0)); break;
|
||||
default: map.put(NEW, JavaConstructor.forConstructors( (JavaConstructor[])list.toArray(new JavaConstructor[list.size()]) ) ); break;
|
||||
}
|
||||
|
||||
for ( Iterator it=namedlists.entrySet().iterator(); it.hasNext(); ) {
|
||||
Entry e = (Entry) it.next();
|
||||
String name = (String) e.getKey();
|
||||
List methods = (List) e.getValue();
|
||||
map.put( LuaValue.valueOf(name),
|
||||
methods.size()==1?
|
||||
methods.get(0):
|
||||
JavaMethod.forMethods( (JavaMethod[])methods.toArray(new JavaMethod[methods.size()])) );
|
||||
}
|
||||
methods = map;
|
||||
}
|
||||
return (LuaValue) methods.get(key);
|
||||
}
|
||||
|
||||
public LuaValue getConstructor() {
|
||||
return getMethod(NEW);
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 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;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a particular public Java constructor.
|
||||
* <p>
|
||||
* May be called with arguments to return a JavaInstance
|
||||
* created by calling the constructor.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to {@link JavaClass#new(LuaValue key)}
|
||||
* when the value of key is "new".
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaConstructor extends JavaMember {
|
||||
|
||||
static final Map constructors = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static JavaConstructor forConstructor(Constructor c) {
|
||||
JavaConstructor j = (JavaConstructor) constructors.get(c);
|
||||
if ( j == null )
|
||||
constructors.put( c, j = new JavaConstructor(c) );
|
||||
return j;
|
||||
}
|
||||
|
||||
public static LuaValue forConstructors(JavaConstructor[] array) {
|
||||
return new Overload(array);
|
||||
}
|
||||
|
||||
final Constructor constructor;
|
||||
|
||||
private JavaConstructor(Constructor c) {
|
||||
super( c.getParameterTypes(), c.getModifiers() );
|
||||
this.constructor = c;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
Object[] a = convertArgs(args);
|
||||
try {
|
||||
return CoerceJavaToLua.coerce( constructor.newInstance(a) );
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new LuaError(e.getTargetException());
|
||||
} catch (Exception e) {
|
||||
return LuaValue.error("coercion error "+e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LuaValue that represents an overloaded Java constructor.
|
||||
* <p>
|
||||
* On invocation, will pick the best method from the list, and invoke it.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to calls to {@link JavaClass#get(LuaValue key)}
|
||||
* when key is "new" and there is more than one public constructor.
|
||||
*/
|
||||
static class Overload extends VarArgFunction {
|
||||
final JavaConstructor[] constructors;
|
||||
public Overload(JavaConstructor[] c) {
|
||||
this.constructors = c;
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
JavaConstructor best = null;
|
||||
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
|
||||
for ( int i=0; i<constructors.length; i++ ) {
|
||||
int s = constructors[i].score(args);
|
||||
if ( s < score ) {
|
||||
score = s;
|
||||
best = constructors[i];
|
||||
if ( score == 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// any match?
|
||||
if ( best == null )
|
||||
LuaValue.error("no coercible public method");
|
||||
|
||||
// invoke it
|
||||
return best.invoke(args);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 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;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java instance.
|
||||
* <p>
|
||||
* Will respond to get() and set() by returning field values or methods.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to {@link CoerceJavaToLua#coerce(Object)}
|
||||
* when a subclass of Object is supplied.
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaInstance extends LuaUserdata {
|
||||
|
||||
JavaClass jclass;
|
||||
|
||||
JavaInstance(Object instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
public LuaValue get(LuaValue key) {
|
||||
if ( jclass == null )
|
||||
jclass = JavaClass.forClass(m_instance.getClass());
|
||||
Field f = jclass.getField(key);
|
||||
if ( f != null )
|
||||
try {
|
||||
return CoerceJavaToLua.coerce(f.get(m_instance));
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
LuaValue m = jclass.getMethod(key);
|
||||
if ( m != null )
|
||||
return m;
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
public void set(LuaValue key, LuaValue value) {
|
||||
if ( jclass == null )
|
||||
jclass = JavaClass.forClass(m_instance.getClass());
|
||||
Field f = jclass.getField(key);
|
||||
if ( f != null )
|
||||
try {
|
||||
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
super.set(key, value);
|
||||
}
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 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;
|
||||
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
import org.luaj.vm2.lib.jse.CoerceLuaToJava.Coercion;
|
||||
|
||||
/**
|
||||
* Java method or constructor.
|
||||
* <p>
|
||||
* Primarily handles argument coercion for parameter lists including scoring of compatibility and
|
||||
* java varargs handling.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is an abstract base class for {@link JavaConstructor} and {@link JavaMethod}.
|
||||
* @see JavaConstructor
|
||||
* @see JavaMethod
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
abstract
|
||||
class JavaMember extends VarArgFunction {
|
||||
|
||||
static final int METHOD_MODIFIERS_VARARGS = 0x80;
|
||||
|
||||
final Coercion[] fixedargs;
|
||||
final Coercion varargs;
|
||||
|
||||
protected JavaMember(Class[] params, int modifiers) {
|
||||
boolean isvarargs = ((modifiers & METHOD_MODIFIERS_VARARGS) != 0);
|
||||
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;
|
||||
}
|
||||
|
||||
int score(Varargs args) {
|
||||
int n = args.narg();
|
||||
int s = n>fixedargs.length? CoerceLuaToJava.SCORE_WRONG_TYPE * (n-fixedargs.length): 0;
|
||||
for ( int j=0; j<fixedargs.length; j++ )
|
||||
s += fixedargs[j].score( args.arg(j+1) );
|
||||
if ( varargs != null )
|
||||
for ( int k=fixedargs.length; k<n; k++ )
|
||||
s += varargs.score( args.arg(k+1) );
|
||||
return s;
|
||||
}
|
||||
|
||||
protected Object[] convertArgs(Varargs args) {
|
||||
Object[] a;
|
||||
if ( varargs == null ) {
|
||||
a = new Object[fixedargs.length];
|
||||
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];
|
||||
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) );
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
@ -1,163 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 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;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* LuaValue that represents a Java method.
|
||||
* <p>
|
||||
* Can be invoked via call(LuaValue...) and related methods.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
|
||||
* when a method is named.
|
||||
* @see CoerceJavaToLua
|
||||
* @see CoerceLuaToJava
|
||||
*/
|
||||
class JavaMethod extends JavaMember {
|
||||
|
||||
static final Map methods = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
static JavaMethod forMethod(Method m) {
|
||||
JavaMethod j = (JavaMethod) methods.get(m);
|
||||
if ( j == null )
|
||||
methods.put( m, j = new JavaMethod(m) );
|
||||
return j;
|
||||
}
|
||||
|
||||
static LuaFunction forMethods(JavaMethod[] m) {
|
||||
return new Overload(m);
|
||||
}
|
||||
|
||||
final Method method;
|
||||
|
||||
private JavaMethod(Method m) {
|
||||
super( m.getParameterTypes(), m.getModifiers() );
|
||||
this.method = m;
|
||||
try {
|
||||
if (!m.isAccessible())
|
||||
m.setAccessible(true);
|
||||
} catch (SecurityException s) {
|
||||
}
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return error("method cannot be called without instance");
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return invokeMethod(arg.checkuserdata(), LuaValue.NONE);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return invokeMethod(arg1.checkuserdata(), arg2);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return invokeMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
return invokeMethod(args.checkuserdata(1), args.subargs(2));
|
||||
}
|
||||
|
||||
LuaValue invokeMethod(Object instance, Varargs args) {
|
||||
Object[] a = convertArgs(args);
|
||||
try {
|
||||
return CoerceJavaToLua.coerce( method.invoke(instance, a) );
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new LuaError(e.getTargetException());
|
||||
} catch (Exception e) {
|
||||
return LuaValue.error("coercion error "+e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LuaValue that represents an overloaded Java method.
|
||||
* <p>
|
||||
* On invocation, will pick the best method from the list, and invoke it.
|
||||
* <p>
|
||||
* This class is not used directly.
|
||||
* It is returned by calls to calls to {@link JavaInstance#get(LuaValue key)}
|
||||
* when an overloaded method is named.
|
||||
*/
|
||||
static class Overload extends LuaFunction {
|
||||
|
||||
final JavaMethod[] methods;
|
||||
|
||||
Overload(JavaMethod[] methods) {
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
public LuaValue call() {
|
||||
return error("method cannot be called without instance");
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
return invokeBestMethod(arg.checkuserdata(), LuaValue.NONE);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return invokeBestMethod(arg1.checkuserdata(), arg2);
|
||||
}
|
||||
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
return invokeBestMethod(arg1.checkuserdata(), LuaValue.varargsOf(arg2, arg3));
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
return invokeBestMethod(args.checkuserdata(1), args.subargs(2));
|
||||
}
|
||||
|
||||
private LuaValue invokeBestMethod(Object instance, Varargs args) {
|
||||
JavaMethod best = null;
|
||||
int score = CoerceLuaToJava.SCORE_UNCOERCIBLE;
|
||||
for ( int i=0; i<methods.length; i++ ) {
|
||||
int s = methods[i].score(args);
|
||||
if ( s < score ) {
|
||||
score = s;
|
||||
best = methods[i];
|
||||
if ( score == 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// any match?
|
||||
if ( best == null )
|
||||
LuaValue.error("no coercible public method");
|
||||
|
||||
// invoke it
|
||||
return best.invokeMethod(instance, args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.BaseLib;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.ResourceFinder;
|
||||
|
||||
/**
|
||||
* Subclass of {@link BaseLib} and {@link LibFunction} which implements the lua basic library functions
|
||||
* and provides a directory based {@link ResourceFinder} as the {@link #FINDER}.
|
||||
* <p>
|
||||
* Since JME has no file system by default, {@link BaseLib} implements
|
||||
* {@link ResourceFinder} using {@link Class#getResource(String)}.
|
||||
* The {@link JseBaseLib} implements {@link FINDER} by scanning the current directory
|
||||
* first, then falling back to {@link Class#getResource(String)} if that fails.
|
||||
* Otherwise, the behavior is the same as that of {@link BaseLib}.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new JseBaseLib());
|
||||
* _G.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 BaseLib
|
||||
* @see ResourceFinder
|
||||
* @see #FINDER
|
||||
* @see LibFunction
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.1">http://www.lua.org/manual/5.1/manual.html#5.1</a>
|
||||
*/
|
||||
|
||||
public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
|
||||
|
||||
/** Construct a JSE base library instance */
|
||||
public JseBaseLib() {
|
||||
STDIN = System.in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to open a file in the current working directory,
|
||||
* or fall back to base opener if not found.
|
||||
*
|
||||
* This implementation attempts to open the file using new File(filename).
|
||||
* It falls back to the base implementation that looks it up as a resource
|
||||
* in the class path if not found as a plain file.
|
||||
*
|
||||
* @see org.luaj.vm2.lib.BaseLib
|
||||
* @see org.luaj.vm2.lib.ResourceFinder
|
||||
*
|
||||
* @param filename
|
||||
* @return InputStream, or null if not found.
|
||||
*/
|
||||
public InputStream findResource(String filename) {
|
||||
File f = new File(filename);
|
||||
if ( ! f.exists() )
|
||||
return super.findResource(filename);
|
||||
try {
|
||||
return new FileInputStream(f);
|
||||
} catch ( IOException ioe ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,222 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.BaseLib;
|
||||
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.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new JseBaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* _G.load(new JseIoLib());
|
||||
* _G.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
|
||||
* } </pre>
|
||||
* 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
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see IoLib
|
||||
* @see 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>
|
||||
*/
|
||||
public class JseIoLib extends IoLib {
|
||||
|
||||
public JseIoLib() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected File wrapStdin() throws IOException {
|
||||
return new FileImpl(BaseLib.instance.STDIN);
|
||||
}
|
||||
|
||||
protected File wrapStdout() throws IOException {
|
||||
return new FileImpl(BaseLib.instance.STDOUT);
|
||||
}
|
||||
|
||||
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
|
||||
RandomAccessFile f = new RandomAccessFile(filename,readMode? "r": "rw");
|
||||
if ( appendMode ) {
|
||||
f.seek(f.length());
|
||||
} else {
|
||||
if ( ! readMode )
|
||||
f.setLength(0);
|
||||
}
|
||||
return new FileImpl( f );
|
||||
}
|
||||
|
||||
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() );
|
||||
}
|
||||
|
||||
protected File tmpFile() throws IOException {
|
||||
java.io.File f = java.io.File.createTempFile(".luaj","bin");
|
||||
f.deleteOnExit();
|
||||
return new FileImpl( new RandomAccessFile(f,"rw") );
|
||||
}
|
||||
|
||||
private static void notimplemented() {
|
||||
throw new LuaError("not implemented");
|
||||
}
|
||||
|
||||
private final class FileImpl extends File {
|
||||
private final RandomAccessFile file;
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
private boolean closed = false;
|
||||
private boolean nobuffer = false;
|
||||
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) {
|
||||
this.file = file;
|
||||
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
|
||||
this.os = os;
|
||||
}
|
||||
private FileImpl( RandomAccessFile f ) {
|
||||
this( f, null, null );
|
||||
}
|
||||
private FileImpl( InputStream i ) {
|
||||
this( null, i, null );
|
||||
}
|
||||
private FileImpl( OutputStream o ) {
|
||||
this( null, null, o );
|
||||
}
|
||||
public String tojstring() {
|
||||
return "file ("+this.hashCode()+")";
|
||||
}
|
||||
public boolean isstdfile() {
|
||||
return file == null;
|
||||
}
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
if ( file != null ) {
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
public void flush() throws IOException {
|
||||
if ( os != null )
|
||||
os.flush();
|
||||
}
|
||||
public void write(LuaString s) throws IOException {
|
||||
if ( os != null )
|
||||
os.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else if ( file != null )
|
||||
file.write( s.m_bytes, s.m_offset, s.m_length );
|
||||
else
|
||||
notimplemented();
|
||||
if ( nobuffer )
|
||||
flush();
|
||||
}
|
||||
public boolean isclosed() {
|
||||
return closed;
|
||||
}
|
||||
public int seek(String option, int pos) throws IOException {
|
||||
if ( file != null ) {
|
||||
if ( "set".equals(option) ) {
|
||||
file.seek(pos);
|
||||
} else if ( "end".equals(option) ) {
|
||||
file.seek(file.length()+pos);
|
||||
} else {
|
||||
file.seek(file.getFilePointer()+pos);
|
||||
}
|
||||
return (int) file.getFilePointer();
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
public void setvbuf(String mode, int size) {
|
||||
nobuffer = "no".equals(mode);
|
||||
}
|
||||
|
||||
// get length remaining to read
|
||||
public int remaining() throws IOException {
|
||||
return file!=null? (int) (file.length()-file.getFilePointer()): -1;
|
||||
}
|
||||
|
||||
// peek ahead one character
|
||||
public int peek() throws IOException {
|
||||
if ( is != null ) {
|
||||
is.mark(1);
|
||||
int c = is.read();
|
||||
is.reset();
|
||||
return c;
|
||||
} else if ( file != null ) {
|
||||
long fp = file.getFilePointer();
|
||||
int c = file.read();
|
||||
file.seek(fp);
|
||||
return c;
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return char if read, -1 if eof, throw IOException on other exception
|
||||
public int read() throws IOException {
|
||||
if ( is != null )
|
||||
return is.read();
|
||||
else if ( file != null ) {
|
||||
return file.read();
|
||||
}
|
||||
notimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return number of bytes read if positive, -1 if eof, throws IOException
|
||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||
if (file!=null) {
|
||||
return file.read(bytes, offset, length);
|
||||
} else if (is!=null) {
|
||||
return is.read(bytes, offset, length);
|
||||
} else {
|
||||
notimplemented();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
|
||||
* library.
|
||||
* <p>
|
||||
* It contains all lua math functions, including those not available on the JME platform.
|
||||
* See {@link org.luaj.lib.MathLib} for the exception list.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new JseBaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* _G.load(new JseMathLib());
|
||||
* System.out.println( _G.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
|
||||
* } </pre>
|
||||
* 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
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see JseMathLib
|
||||
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.6">http://www.lua.org/manual/5.1/manual.html#5.6</a>
|
||||
*/
|
||||
public class JseMathLib extends org.luaj.vm2.lib.MathLib {
|
||||
|
||||
public JseMathLib() {}
|
||||
|
||||
public LuaValue call(LuaValue arg) {
|
||||
LuaValue t = super.call(arg);
|
||||
bind( t, JseMathLib1.class, new String[] {
|
||||
"acos", "asin", "atan", "cosh",
|
||||
"exp", "log", "log10", "sinh",
|
||||
"tanh" } );
|
||||
bind( t, JseMathLib2.class, new String[] {
|
||||
"atan2", "pow", } );
|
||||
return t;
|
||||
}
|
||||
|
||||
public static final class JseMathLib1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: return valueOf(Math.acos(arg.checkdouble()));
|
||||
case 1: return valueOf(Math.asin(arg.checkdouble()));
|
||||
case 2: return valueOf(Math.atan(arg.checkdouble()));
|
||||
case 3: return valueOf(Math.cosh(arg.checkdouble()));
|
||||
case 4: return valueOf(Math.exp(arg.checkdouble()));
|
||||
case 5: return valueOf(Math.log(arg.checkdouble()));
|
||||
case 6: return valueOf(Math.log10(arg.checkdouble()));
|
||||
case 7: return valueOf(Math.sinh(arg.checkdouble()));
|
||||
case 8: return valueOf(Math.tanh(arg.checkdouble()));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class JseMathLib2 extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
switch ( opcode ) {
|
||||
case 0: return valueOf(Math.atan2(arg1.checkdouble(), arg2.checkdouble()));
|
||||
case 1: return valueOf(Math.pow(arg1.checkdouble(), arg2.checkdouble()));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Faster, better version of pow() used by arithmetic operator ^ */
|
||||
public double dpow_lib(double a, double b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
|
||||
/**
|
||||
* 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:
|
||||
* <ul>
|
||||
* <li>{@code execute()}</li>
|
||||
* <li>{@code remove()}</li>
|
||||
* <li>{@code rename()}</li>
|
||||
* <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.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* _G.load(new JseBaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* _G.load(new JseOsLib());
|
||||
* System.out.println( _G.get("os").get("time").call() );
|
||||
* } </pre>
|
||||
* Doing so will ensure the library is properly initialized
|
||||
* and loaded into the globals table.
|
||||
* <p>
|
||||
* @see LibFunction
|
||||
* @see OsLib
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @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 JseOsLib extends org.luaj.vm2.lib.OsLib {
|
||||
|
||||
/** return code indicating the execute() threw an I/O exception */
|
||||
public static int EXEC_IOEXCEPTION = 1;
|
||||
|
||||
/** return code indicating the execute() was interrupted */
|
||||
public static int EXEC_INTERRUPTED = -2;
|
||||
|
||||
/** return code indicating the execute() threw an unknown exception */
|
||||
public static int EXEC_ERROR = -3;
|
||||
|
||||
/** public constructor */
|
||||
public JseOsLib() {
|
||||
}
|
||||
|
||||
protected int execute(String command) {
|
||||
Runtime r = Runtime.getRuntime();
|
||||
try {
|
||||
final Process p = r.exec(command);
|
||||
try {
|
||||
p.waitFor();
|
||||
return p.exitValue();
|
||||
} finally {
|
||||
p.destroy();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
return EXEC_IOEXCEPTION;
|
||||
} catch (InterruptedException e) {
|
||||
return EXEC_INTERRUPTED;
|
||||
} catch (Throwable t) {
|
||||
return EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
protected void remove(String filename) throws IOException {
|
||||
File f = new File(filename);
|
||||
if ( ! f.exists() )
|
||||
throw new IOException("No such file or directory");
|
||||
if ( ! f.delete() )
|
||||
throw new IOException("Failed to delete");
|
||||
}
|
||||
|
||||
protected void rename(String oldname, String newname) throws IOException {
|
||||
File f = new File(oldname);
|
||||
if ( ! f.exists() )
|
||||
throw new IOException("No such file or directory");
|
||||
if ( ! f.renameTo(new File(newname)) )
|
||||
throw new IOException("Failed to delete");
|
||||
}
|
||||
|
||||
protected String tmpname() {
|
||||
try {
|
||||
java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
|
||||
return f.getName();
|
||||
} catch ( IOException ioe ) {
|
||||
return super.tmpname();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009-2011 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;
|
||||
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.CoroutineLib;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
import org.luaj.vm2.lib.PackageLib;
|
||||
import org.luaj.vm2.lib.StringLib;
|
||||
import org.luaj.vm2.lib.TableLib;
|
||||
|
||||
/** The {@link 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
|
||||
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
|
||||
* <p>
|
||||
* A simple example of initializing globals and using them from Java is:
|
||||
* <pre> {@code
|
||||
* LuaValue _G = JsePlatform.standardGlobals();
|
||||
* _G.get("print").call(LuaValue.valueOf("hello, world"));
|
||||
* } </pre>
|
||||
* <p>
|
||||
* Once globals are created, a simple way to load and run a script is:
|
||||
* <pre> {@code
|
||||
* LoadState.load( new FileInputStream("main.lua"), "main.lua", _G ).call();
|
||||
* } </pre>
|
||||
* <p>
|
||||
* although {@code require} could also be used:
|
||||
* <pre> {@code
|
||||
* _G.get("require").call(LuaValue.valueOf("main"));
|
||||
* } </pre>
|
||||
* For this to succeed, the file "main.lua" must be in the current directory or a resource.
|
||||
* See {@link JseBaseLib} for details on finding scripts using {@link ResourceFinder}.
|
||||
* <p>
|
||||
* The standard globals will contain all standard libraries plus {@code luajava}:
|
||||
* <ul>
|
||||
* <li>{@link JseBaseLib}</li>
|
||||
* <li>{@link PackageLib}</li>
|
||||
* <li>{@link TableLib}</li>
|
||||
* <li>{@link StringLib}</li>
|
||||
* <li>{@link CoroutineLib}</li>
|
||||
* <li>{@link JseMathLib}</li>
|
||||
* <li>{@link JseIoLib}</li>
|
||||
* <li>{@link JseOsLib}</li>
|
||||
* <li>{@link LuajavaLib}</li>
|
||||
* </ul>
|
||||
* 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,
|
||||
* and that linkage is made to {@link LuaThread#setGlobals(LuaValue)}.
|
||||
* @see JmePlatform
|
||||
*/
|
||||
public class JsePlatform {
|
||||
|
||||
/**
|
||||
* Create a standard set of globals for JSE including all the libraries.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JSE libraries
|
||||
* @see #debugGlobals()
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
*/
|
||||
public static LuaTable standardGlobals() {
|
||||
LuaTable _G = new LuaTable();
|
||||
_G.load(new JseBaseLib());
|
||||
_G.load(new PackageLib());
|
||||
_G.load(new TableLib());
|
||||
_G.load(new StringLib());
|
||||
_G.load(new CoroutineLib());
|
||||
_G.load(new JseMathLib());
|
||||
_G.load(new JseIoLib());
|
||||
_G.load(new JseOsLib());
|
||||
_G.load(new LuajavaLib());
|
||||
LuaThread.setGlobals(_G);
|
||||
LuaC.install();
|
||||
return _G;
|
||||
}
|
||||
|
||||
/** Create standard globals including the {@link debug} library.
|
||||
*
|
||||
* @return Table of globals initialized with the standard JSE and debug libraries
|
||||
* @see #standardGlobals()
|
||||
* @see JsePlatform
|
||||
* @see JmePlatform
|
||||
* @see DebugLib
|
||||
*/
|
||||
public static LuaTable debugGlobals() {
|
||||
LuaTable _G = standardGlobals();
|
||||
_G.load(new DebugLib());
|
||||
return _G;
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/** Analog of Process that pipes input and output to client-specified streams.
|
||||
*/
|
||||
public class JseProcess {
|
||||
|
||||
final Process process;
|
||||
final Thread input,output,error;
|
||||
|
||||
/** Construct a process around a command, with specified streams to redirect input and output to.
|
||||
*
|
||||
* @param cmd The command to execute, including arguments, if any
|
||||
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
|
||||
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
|
||||
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
|
||||
* @throws IOException If the system process could not be created.
|
||||
* @see Process
|
||||
*/
|
||||
public JseProcess(String[] cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
|
||||
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
|
||||
}
|
||||
|
||||
/** Construct a process around a command, with specified streams to redirect input and output to.
|
||||
*
|
||||
* @param cmd The command to execute, including arguments, if any
|
||||
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
|
||||
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
|
||||
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
|
||||
* @throws IOException If the system process could not be created.
|
||||
* @see Process
|
||||
*/
|
||||
public JseProcess(String cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
|
||||
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
|
||||
}
|
||||
|
||||
private JseProcess(Process process, InputStream stdin, OutputStream stdout, OutputStream stderr) {
|
||||
this.process = process;
|
||||
input = stdin == null? null: copyBytes(stdin, process.getOutputStream(), null, process.getOutputStream());
|
||||
output = stdout == null? null: copyBytes(process.getInputStream(), stdout, process.getInputStream(), null);
|
||||
error = stderr == null? null: copyBytes(process.getErrorStream(), stderr, process.getErrorStream(), null);
|
||||
}
|
||||
|
||||
/** Get the exit value of the process. */
|
||||
public int exitValue() {
|
||||
return process.exitValue();
|
||||
}
|
||||
|
||||
/** Wait for the process to complete, and all pending output to finish.
|
||||
* @return The exit status.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public int waitFor() throws InterruptedException {
|
||||
int r = process.waitFor();
|
||||
if (input != null)
|
||||
input.join();
|
||||
if (output != null)
|
||||
output.join();
|
||||
if (error != null)
|
||||
error.join();
|
||||
process.destroy();
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Create a thread to copy bytes from input to output. */
|
||||
private Thread copyBytes(final InputStream input,
|
||||
final OutputStream output, final InputStream ownedInput,
|
||||
final OutputStream ownedOutput) {
|
||||
Thread t = (new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
byte[] buf = new byte[1024];
|
||||
int r;
|
||||
try {
|
||||
while ((r = input.read(buf)) >= 0) {
|
||||
output.write(buf, 0, r);
|
||||
}
|
||||
} finally {
|
||||
if (ownedInput != null)
|
||||
ownedInput.close();
|
||||
if (ownedOutput != null)
|
||||
ownedOutput.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
return t;
|
||||
}
|
||||
}
|
@ -1,195 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.PackageLib;
|
||||
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
|
||||
* <a href="http://www.keplerproject.org/luajava/">luajava</a> documentation pages.
|
||||
* <p>
|
||||
* Typically, this library is included as part of a call to either
|
||||
* {@link JsePlatform#standardGlobals()}
|
||||
* <p>
|
||||
* To instantiate and use it directly,
|
||||
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
|
||||
* <pre> {@code
|
||||
* LuaTable _G = new LuaTable();
|
||||
* LuaThread.setGlobals(_G);
|
||||
* LuaC.install();
|
||||
* _G.load(new BaseLib());
|
||||
* _G.load(new PackageLib());
|
||||
* _G.load(new LuajavaLib());
|
||||
* _G.get("loadstring").call( LuaValue.valueOf(
|
||||
* "sys = luajava.bindClass('java.lang.System')\n"+
|
||||
* "print ( sys:currentTimeMillis() )\n" ) ).call();
|
||||
* } </pre>
|
||||
* This example is not intended to be realistic - only to show how the {@link LuajavaLib}
|
||||
* may be initialized by hand. In practice, the {@code luajava} library is available
|
||||
* on all JSE platforms via the call to {@link JsePlatform#standardGlobals()}
|
||||
* and the luajava api's are simply invoked from lua.
|
||||
* <p>
|
||||
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
|
||||
* @see LibFunction
|
||||
* @see org.luaj.vm2.lib.jse.JsePlatform
|
||||
* @see org.luaj.vm2.lib.jme.JmePlatform
|
||||
* @see LuaC
|
||||
* @see <a href="http://www.keplerproject.org/luajava/manual.html#luareference">http://www.keplerproject.org/luajava/manual.html#luareference</a>
|
||||
*/
|
||||
public class LuajavaLib extends VarArgFunction {
|
||||
|
||||
static final int INIT = 0;
|
||||
static final int BINDCLASS = 1;
|
||||
static final int NEWINSTANCE = 2;
|
||||
static final int NEW = 3;
|
||||
static final int CREATEPROXY = 4;
|
||||
static final int LOADLIB = 5;
|
||||
|
||||
static final String[] NAMES = {
|
||||
"bindClass",
|
||||
"newInstance",
|
||||
"new",
|
||||
"createProxy",
|
||||
"loadLib",
|
||||
};
|
||||
|
||||
static final int METHOD_MODIFIERS_VARARGS = 0x80;
|
||||
|
||||
public LuajavaLib() {
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case INIT: {
|
||||
LuaTable t = new LuaTable();
|
||||
bind( t, LuajavaLib.class, NAMES, BINDCLASS );
|
||||
env.set("luajava", t);
|
||||
PackageLib.instance.LOADED.set("luajava", t);
|
||||
return t;
|
||||
}
|
||||
case BINDCLASS: {
|
||||
final Class clazz = classForName(args.checkjstring(1));
|
||||
return JavaClass.forClass(clazz);
|
||||
}
|
||||
case NEWINSTANCE:
|
||||
case NEW: {
|
||||
// get constructor
|
||||
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: {
|
||||
final int niface = args.narg()-1;
|
||||
if ( niface <= 0 )
|
||||
throw new LuaError("no interfaces");
|
||||
final LuaValue lobj = args.checktable(niface+1);
|
||||
|
||||
// get the interfaces
|
||||
final Class[] ifaces = new Class[niface];
|
||||
for ( int i=0; i<niface; i++ )
|
||||
ifaces[i] = classForName(args.checkjstring(i+1));
|
||||
|
||||
// create the invocation handler
|
||||
InvocationHandler handler = new InvocationHandler() {
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String name = method.getName();
|
||||
LuaValue func = lobj.get(name);
|
||||
if ( func.isnil() )
|
||||
return null;
|
||||
boolean isvarargs = ((method.getModifiers() & METHOD_MODIFIERS_VARARGS) != 0);
|
||||
int n = args!=null? args.length: 0;
|
||||
LuaValue[] v;
|
||||
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));
|
||||
} else {
|
||||
v = new LuaValue[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
v[i] = CoerceJavaToLua.coerce(args[i]);
|
||||
}
|
||||
LuaValue result = func.invoke(v).arg1();
|
||||
return CoerceLuaToJava.coerce(result, method.getReturnType());
|
||||
}
|
||||
};
|
||||
|
||||
// create the proxy object
|
||||
Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), ifaces, handler);
|
||||
|
||||
// return the proxy
|
||||
return LuaValue.userdataOf( proxy );
|
||||
}
|
||||
case LOADLIB: {
|
||||
// get constructor
|
||||
String classname = args.checkjstring(1);
|
||||
String methodname = args.checkjstring(2);
|
||||
Class clazz = classForName(classname);
|
||||
Method method = clazz.getMethod(methodname, new Class[] {});
|
||||
Object result = method.invoke(clazz, new Object[] {});
|
||||
if ( result instanceof LuaValue ) {
|
||||
return (LuaValue) result;
|
||||
} else {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new LuaError("not yet supported: "+this);
|
||||
}
|
||||
} catch (LuaError e) {
|
||||
throw e;
|
||||
} catch (InvocationTargetException ite) {
|
||||
throw new LuaError(ite.getTargetException());
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
}
|
||||
|
||||
// load classes using app loader to allow luaj to be used as an extension
|
||||
protected Class classForName(String name) throws ClassNotFoundException {
|
||||
return Class.forName(name, true, ClassLoader.getSystemClassLoader());
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,189 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.lua2java;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.ast.Block;
|
||||
import org.luaj.vm2.ast.Chunk;
|
||||
import org.luaj.vm2.ast.FuncBody;
|
||||
import org.luaj.vm2.ast.NameScope;
|
||||
import org.luaj.vm2.ast.Variable;
|
||||
import org.luaj.vm2.ast.Visitor;
|
||||
import org.luaj.vm2.ast.Exp.BinopExp;
|
||||
import org.luaj.vm2.ast.Exp.VarargsExp;
|
||||
import org.luaj.vm2.ast.Stat.Return;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
|
||||
|
||||
public class JavaScope extends NameScope {
|
||||
|
||||
private static final int MAX_CONSTNAME_LEN = 8;
|
||||
public static final Set<String> SPECIALS = new HashSet<String>();
|
||||
|
||||
private static final String[] specials = {
|
||||
// keywords used by our code generator
|
||||
"name", "opcode", "env", // "arg",
|
||||
|
||||
// java keywords
|
||||
"abstract", "continue", "for", "new", "switch",
|
||||
"assert", "default", "goto", "package", "synchronized",
|
||||
"boolean", "do", "if", "private", "this",
|
||||
"break", "double", "implements", "protected", "throw",
|
||||
"byte", "else", "import", "public", "throws",
|
||||
"case", "enum", "instanceof", "return", "transient",
|
||||
"catch", "extends", "int", "short", "try",
|
||||
"char", "final", "interface", "static", "void",
|
||||
"class", "finally", "long", "strictfp", "volatile",
|
||||
"const", "float", "native", "super", "while",
|
||||
|
||||
// java literals
|
||||
"false", "null", "true",
|
||||
};
|
||||
|
||||
static {
|
||||
for ( int i=0; i<specials.length; i++ )
|
||||
SPECIALS.add(specials[i]);
|
||||
java.lang.reflect.Field[] fields = LibFunction.class.getFields();
|
||||
for ( int i=0, n=fields.length; i<n; i++ )
|
||||
SPECIALS.add(fields[i].getName());
|
||||
java.lang.reflect.Method[] methods = LibFunction.class.getMethods();
|
||||
for ( int i=0, n=methods.length; i<n; i++ )
|
||||
SPECIALS.add(methods[i].getName());
|
||||
}
|
||||
|
||||
public int nreturns;
|
||||
public boolean needsbinoptmp;
|
||||
public boolean usesvarargs;
|
||||
|
||||
final Set<String> staticnames;
|
||||
final Set<String> javanames = new HashSet<String>();
|
||||
final Map<Object,String> astele2javaname = new HashMap<Object,String>();
|
||||
|
||||
private JavaScope(Set<String> staticnames, JavaScope outerScope) {
|
||||
super(outerScope);
|
||||
this.staticnames = staticnames;
|
||||
}
|
||||
|
||||
public static JavaScope newJavaScope(Chunk chunk) {
|
||||
return new JavaScope(new HashSet<String>(), null).initialize(chunk.block, -1);
|
||||
}
|
||||
|
||||
public JavaScope pushJavaScope(FuncBody body) {
|
||||
return new JavaScope(staticnames, this).initialize(body.block, 0);
|
||||
}
|
||||
|
||||
public JavaScope popJavaScope() {
|
||||
return (JavaScope) outerScope;
|
||||
}
|
||||
|
||||
final String getJavaName(Variable nv) {
|
||||
for ( JavaScope s = this; s != null; s = (JavaScope) s.outerScope )
|
||||
if ( s.astele2javaname.containsKey(nv) )
|
||||
return (String) s.astele2javaname.get(nv);
|
||||
return allocateJavaName( nv, nv.name );
|
||||
}
|
||||
|
||||
final private String allocateJavaName(Object astele, String proposal) {
|
||||
for ( int i=0; true; i++ ) {
|
||||
String jname = proposal+(i==0? "": "$"+i);
|
||||
if ( ! isJavanameInScope(jname) && ! SPECIALS.contains(jname) && !staticnames.contains(jname) ) {
|
||||
javanames.add(jname);
|
||||
astele2javaname.put(astele,jname);
|
||||
return jname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setJavaName(Variable astele, String javaname) {
|
||||
javanames.add(javaname);
|
||||
astele2javaname.put(astele,javaname);
|
||||
}
|
||||
|
||||
private boolean isJavanameInScope(String javaname) {
|
||||
for ( JavaScope s = this; s != null; s = (JavaScope) s.outerScope )
|
||||
if ( s.javanames.contains(javaname) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public String createConstantName(String proposal) {
|
||||
proposal = toLegalJavaName(proposal);
|
||||
for ( int i=0; true; i++ ) {
|
||||
String jname = proposal+(i==0? "": "$"+i);
|
||||
if ( ! isJavanameInScope(jname) && ! SPECIALS.contains(jname) && !staticnames.contains(jname) ) {
|
||||
javanames.add(jname);
|
||||
staticnames.add(jname);
|
||||
return jname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String toLegalJavaName(String string) {
|
||||
String better = string.replaceAll("[^\\w]", "_");
|
||||
if ( better.length() > MAX_CONSTNAME_LEN )
|
||||
better = better.substring(0,MAX_CONSTNAME_LEN);
|
||||
if ( better.length() == 0 || !Character.isJavaIdentifierStart( better.charAt(0) ) )
|
||||
better = "_"+better;
|
||||
return better;
|
||||
}
|
||||
|
||||
private JavaScope initialize(Block block, int nreturns) {
|
||||
NewScopeVisitor v = new NewScopeVisitor(nreturns);
|
||||
block.accept( v );
|
||||
this.nreturns = v.nreturns;
|
||||
this.needsbinoptmp = v.needsbinoptmp;
|
||||
this.usesvarargs = v.usesvarargs;
|
||||
return this;
|
||||
}
|
||||
|
||||
class NewScopeVisitor extends Visitor {
|
||||
int nreturns = 0;
|
||||
boolean needsbinoptmp = false;
|
||||
boolean usesvarargs = false;
|
||||
NewScopeVisitor(int nreturns) {
|
||||
this.nreturns = nreturns;
|
||||
}
|
||||
public void visit(FuncBody body) {}
|
||||
public void visit(Return s) {
|
||||
int n = s.nreturns();
|
||||
nreturns = (nreturns<0||n<0? -1: Math.max(n,nreturns));
|
||||
super.visit(s);
|
||||
}
|
||||
public void visit(BinopExp exp) {
|
||||
switch ( exp.op ) {
|
||||
case Lua.OP_AND: case Lua.OP_OR:
|
||||
needsbinoptmp = true;
|
||||
break;
|
||||
}
|
||||
super.visit(exp);
|
||||
}
|
||||
public void visit(VarargsExp exp) {
|
||||
usesvarargs = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
package org.luaj.vm2.lua2java;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
import javax.tools.ToolProvider;
|
||||
import javax.tools.JavaCompiler.CompilationTask;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||
import org.luaj.vm2.ast.Chunk;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.parser.LuaParser;
|
||||
|
||||
public class Lua2Java implements LuaCompiler {
|
||||
|
||||
public static final Lua2Java instance = new Lua2Java();
|
||||
|
||||
public static final void install() {
|
||||
LoadState.compiler = instance;
|
||||
}
|
||||
|
||||
private Lua2Java() {
|
||||
}
|
||||
|
||||
public LuaFunction load(InputStream stream, String filename, LuaValue env) throws IOException {
|
||||
|
||||
// get first byte
|
||||
if ( ! stream.markSupported() )
|
||||
stream = new BufferedInputStream( stream );
|
||||
stream.mark( 1 );
|
||||
int firstByte = stream.read();
|
||||
stream.reset();
|
||||
|
||||
// we can only sompile sources
|
||||
if ( firstByte != '\033' ) {
|
||||
final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (compiler == null)
|
||||
LuaValue.error("no java compiler");
|
||||
|
||||
// break into package and class
|
||||
if ( filename.endsWith( ".lua") )
|
||||
filename = filename.substring(0, filename.length()-4);
|
||||
String s = filename.replace('\\', '/').replace('/','.').replaceAll("[^\\w]", "_");
|
||||
int p = s.lastIndexOf('.');
|
||||
final String packageName = p>=0? s.substring(0,p): null;
|
||||
final String className = toClassname( s.substring(p+1) );
|
||||
|
||||
// open output file
|
||||
final String pkgSubdir = (packageName!=null? packageName.replace('.','/'): "");
|
||||
final String srcDirRoot = "lua2java/src";
|
||||
final String binDirRoot = "lua2java/classes";
|
||||
final String srcDirname = srcDirRoot+"/"+pkgSubdir;
|
||||
final String binDirname = binDirRoot+"/"+pkgSubdir;
|
||||
final String srcFilename = srcDirname + "/" + className + ".java";
|
||||
|
||||
// make directories
|
||||
new File(srcDirname).mkdirs();
|
||||
new File(binDirname).mkdirs();
|
||||
|
||||
// generate java source
|
||||
try {
|
||||
LuaParser parser = new LuaParser(stream,"ISO8859-1");
|
||||
Chunk chunk = parser.Chunk();
|
||||
File source = new File(srcFilename);
|
||||
Writer writer = new OutputStreamWriter( new FileOutputStream(source) );
|
||||
new JavaCodeGen(chunk,writer,packageName,className);
|
||||
writer.close();
|
||||
|
||||
// set up output location
|
||||
StandardJavaFileManager fm = compiler.getStandardFileManager( null, null, null);
|
||||
fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File[] { new File(binDirRoot) }));
|
||||
|
||||
// compile the file
|
||||
CompilationTask task = compiler.getTask(null, fm, null, null, null, fm.getJavaFileObjects(source));
|
||||
boolean success = task.call().booleanValue();
|
||||
|
||||
// instantiate, config and return
|
||||
if (success) {
|
||||
// create instance
|
||||
ClassLoader cl = new ClassLoader() {
|
||||
public Class findClass(String classname) throws ClassNotFoundException {
|
||||
if ( classname.startsWith(className) ) {
|
||||
File f = new File( binDirname+"/"+classname+".class");
|
||||
long n = f.length();
|
||||
byte[] b = new byte[(int) n];
|
||||
try {
|
||||
DataInputStream dis = new DataInputStream( new FileInputStream(f) );
|
||||
dis.readFully(b);
|
||||
} catch ( Exception e ) {
|
||||
throw new RuntimeException("failed to read class bytes: "+e );
|
||||
}
|
||||
return defineClass(classname, b, 0, b.length);
|
||||
}
|
||||
return super.findClass(classname);
|
||||
}
|
||||
};
|
||||
Class clazz = cl.loadClass(className);
|
||||
Object instance = clazz.newInstance();
|
||||
LuaFunction value = (LuaFunction) instance;
|
||||
value.setfenv( env );
|
||||
return value;
|
||||
} else {
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
LuaValue.error("compile task failed: "+e);
|
||||
}
|
||||
|
||||
// report compilation error
|
||||
LuaValue.error("compile task failed:");
|
||||
return null;
|
||||
}
|
||||
|
||||
// fall back to plain compiler
|
||||
return LuaC.instance.load( stream, filename, env);
|
||||
}
|
||||
|
||||
/** Convert lua filename to valid class name */
|
||||
public static final String toClassname( String filename ) {
|
||||
int n=filename.length();
|
||||
int j=n;
|
||||
if ( filename.endsWith(".lua") )
|
||||
j -= 4;
|
||||
for ( int k=0; k<j; k++ ) {
|
||||
char c = filename.charAt(k);
|
||||
if ( (!isClassnamePart(c)) || (c=='/') || (c=='\\') ) {
|
||||
StringBuffer sb = new StringBuffer(j);
|
||||
for ( int i=0; i<j; i++ ) {
|
||||
c = filename.charAt(i);
|
||||
sb.append(
|
||||
(isClassnamePart(c))? c:
|
||||
((c=='/') || (c=='\\'))? '.': '_' );
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
return n==j? filename: filename.substring(0,j);
|
||||
}
|
||||
|
||||
private static final boolean isClassnamePart(char c) {
|
||||
if ( (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') )
|
||||
return true;
|
||||
switch ( c ) {
|
||||
case '.':
|
||||
case '$':
|
||||
case '_':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.Prototype;
|
||||
|
||||
public class BasicBlock {
|
||||
int pc0,pc1; // range of program counter values for the block
|
||||
BasicBlock[] prev; // previous basic blocks (0-n of these)
|
||||
BasicBlock[] next; // next basic blocks (0, 1, or 2 of these)
|
||||
boolean islive; // true if this block is used
|
||||
|
||||
public BasicBlock(Prototype p, int pc0) {
|
||||
this.pc0 = this.pc1 = pc0;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append( (pc0+1)+"-"+(pc1+1)
|
||||
+(prev!=null? " prv: "+str(prev,1): "")
|
||||
+(next!=null? " nxt: "+str(next,0): "")
|
||||
+"\n" );
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String str(BasicBlock[] b, int p) {
|
||||
if ( b == null )
|
||||
return "";
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("(");
|
||||
for ( int i=0, n=b.length; i<n; i++ ) {
|
||||
if ( i > 0 )
|
||||
sb.append( "," );
|
||||
sb.append( String.valueOf( p==1? b[i].pc1+1: b[i].pc0+1 ) );
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static BasicBlock[] findBasicBlocks(Prototype p) {
|
||||
|
||||
// mark beginnings, endings
|
||||
final int n = p.code.length;
|
||||
final boolean[] isbeg = new boolean[n];
|
||||
final boolean[] isend = new boolean[n];
|
||||
isbeg[0] = true;
|
||||
BranchVisitor bv = new BranchVisitor(isbeg) {
|
||||
public void visitBranch(int pc0, int pc1) {
|
||||
isend[pc0] = true;
|
||||
isbeg[pc1] = true;
|
||||
}
|
||||
public void visitReturn(int pc) {
|
||||
isend[pc] = true;
|
||||
}
|
||||
};
|
||||
visitBranches(p, bv); // 1st time to mark branches
|
||||
visitBranches(p, bv); // 2nd time to catch merges
|
||||
|
||||
// create basic blocks
|
||||
final BasicBlock[] blocks = new BasicBlock[n];
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
isbeg[i] = true;
|
||||
BasicBlock b = new BasicBlock(p,i);
|
||||
blocks[i] = b;
|
||||
while ( !isend[i] && i+1<n && !isbeg[i+1] )
|
||||
blocks[b.pc1=++i] = b;
|
||||
}
|
||||
|
||||
// count previous, next
|
||||
final int[] nnext = new int[n];
|
||||
final int[] nprev = new int[n];
|
||||
visitBranches(p, new BranchVisitor(isbeg) {
|
||||
public void visitBranch(int pc0, int pc1) {
|
||||
nnext[pc0]++;
|
||||
nprev[pc1]++;
|
||||
}
|
||||
});
|
||||
|
||||
// allocate and cross-reference
|
||||
visitBranches( p, new BranchVisitor(isbeg) {
|
||||
public void visitBranch(int pc0, int pc1) {
|
||||
if ( blocks[pc0].next == null ) blocks[pc0].next = new BasicBlock[nnext[pc0]];
|
||||
if ( blocks[pc1].prev == null ) blocks[pc1].prev = new BasicBlock[nprev[pc1]];
|
||||
blocks[pc0].next[--nnext[pc0]] = blocks[pc1];
|
||||
blocks[pc1].prev[--nprev[pc1]] = blocks[pc0];
|
||||
}
|
||||
});
|
||||
return blocks;
|
||||
}
|
||||
|
||||
abstract public static class BranchVisitor {
|
||||
final boolean[] isbeg;
|
||||
public BranchVisitor(boolean[] isbeg) {
|
||||
this.isbeg = isbeg;
|
||||
}
|
||||
public void visitBranch( int frompc, int topc ) {}
|
||||
public void visitReturn( int atpc ) {}
|
||||
}
|
||||
|
||||
public static void visitBranches( Prototype p, BranchVisitor visitor ) {
|
||||
int sbx,j,c;
|
||||
int[] code = p.code;
|
||||
int n = code.length;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
int ins = code[i];
|
||||
switch ( Lua.GET_OPCODE( ins ) ) {
|
||||
case Lua.OP_LOADBOOL:
|
||||
if ( 0 == Lua.GETARG_C(ins) )
|
||||
break;
|
||||
if ( Lua.GET_OPCODE(code[i+1]) == Lua.OP_JMP )
|
||||
throw new IllegalArgumentException("OP_LOADBOOL followed by jump at "+i);
|
||||
visitor.visitBranch( i, i+2 );
|
||||
continue;
|
||||
case Lua.OP_EQ:
|
||||
case Lua.OP_LT:
|
||||
case Lua.OP_LE:
|
||||
case Lua.OP_TEST:
|
||||
case Lua.OP_TESTSET:
|
||||
case Lua.OP_TFORLOOP:
|
||||
if ( Lua.GET_OPCODE(code[i+1]) != Lua.OP_JMP )
|
||||
throw new IllegalArgumentException("test not followed by jump at "+i);
|
||||
sbx = Lua.GETARG_sBx(code[i+1]);
|
||||
++i;
|
||||
j = i + sbx + 1;
|
||||
visitor.visitBranch( i, j );
|
||||
visitor.visitBranch( i, i+1 );
|
||||
continue;
|
||||
case Lua.OP_FORLOOP:
|
||||
sbx = Lua.GETARG_sBx(ins);
|
||||
j = i + sbx + 1;
|
||||
visitor.visitBranch( i, j );
|
||||
visitor.visitBranch( i, i+1 );
|
||||
continue;
|
||||
case Lua.OP_JMP:
|
||||
case Lua.OP_FORPREP:
|
||||
sbx = Lua.GETARG_sBx(ins);
|
||||
j = i + sbx + 1;
|
||||
visitor.visitBranch( i, j );
|
||||
continue;
|
||||
case Lua.OP_TAILCALL:
|
||||
case Lua.OP_RETURN:
|
||||
visitor.visitReturn( i );
|
||||
continue;
|
||||
}
|
||||
if ( i+1<n && visitor.isbeg[i+1] )
|
||||
visitor.visitBranch( i, i+1 );
|
||||
}
|
||||
}
|
||||
|
||||
public static BasicBlock[] findLiveBlocks(BasicBlock[] blocks) {
|
||||
// add reachable blocks
|
||||
Vector next = new Vector ();
|
||||
next.addElement( blocks[0] );
|
||||
while ( ! next.isEmpty() ) {
|
||||
BasicBlock b = (BasicBlock) next.elementAt(0);
|
||||
next.removeElementAt(0);
|
||||
if ( ! b.islive ) {
|
||||
b.islive = true;
|
||||
for ( int i=0, n=b.next!=null? b.next.length: 0; i<n; i++ )
|
||||
if ( ! b.next[i].islive )
|
||||
next.addElement( b.next[i] );
|
||||
}
|
||||
}
|
||||
|
||||
// create list in natural order
|
||||
Vector list = new Vector();
|
||||
for ( int i=0; i<blocks.length; i=blocks[i].pc1+1 )
|
||||
if ( blocks[i].islive )
|
||||
list.addElement(blocks[i]);
|
||||
|
||||
// convert to array
|
||||
BasicBlock[] array = new BasicBlock[list.size()];
|
||||
list.copyInto(array);
|
||||
return array;
|
||||
}
|
||||
}
|
@ -1,791 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.luajc;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.bcel.Constants;
|
||||
import org.apache.bcel.generic.AASTORE;
|
||||
import org.apache.bcel.generic.ALOAD;
|
||||
import org.apache.bcel.generic.ANEWARRAY;
|
||||
import org.apache.bcel.generic.ASTORE;
|
||||
import org.apache.bcel.generic.ArrayType;
|
||||
import org.apache.bcel.generic.BranchInstruction;
|
||||
import org.apache.bcel.generic.ClassGen;
|
||||
import org.apache.bcel.generic.CompoundInstruction;
|
||||
import org.apache.bcel.generic.ConstantPoolGen;
|
||||
import org.apache.bcel.generic.FieldGen;
|
||||
import org.apache.bcel.generic.GOTO;
|
||||
import org.apache.bcel.generic.IFEQ;
|
||||
import org.apache.bcel.generic.IFNE;
|
||||
import org.apache.bcel.generic.Instruction;
|
||||
import org.apache.bcel.generic.InstructionConstants;
|
||||
import org.apache.bcel.generic.InstructionFactory;
|
||||
import org.apache.bcel.generic.InstructionHandle;
|
||||
import org.apache.bcel.generic.InstructionList;
|
||||
import org.apache.bcel.generic.LocalVariableGen;
|
||||
import org.apache.bcel.generic.MethodGen;
|
||||
import org.apache.bcel.generic.ObjectType;
|
||||
import org.apache.bcel.generic.PUSH;
|
||||
import org.apache.bcel.generic.Type;
|
||||
import org.luaj.vm2.Buffer;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaBoolean;
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaNumber;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
public class JavaBuilder {
|
||||
|
||||
private static final String STR_VARARGS = Varargs.class.getName();
|
||||
private static final String STR_LUAVALUE = LuaValue.class.getName();
|
||||
private static final String STR_LUASTRING = LuaString.class.getName();
|
||||
private static final String STR_LUAINTEGER = LuaInteger.class.getName();
|
||||
private static final String STR_LUADOUBLE = LuaDouble.class.getName();
|
||||
private static final String STR_LUANUMBER = LuaNumber.class.getName();
|
||||
private static final String STR_LUABOOLEAN = LuaBoolean.class.getName();
|
||||
private static final String STR_LUATABLE = LuaTable.class.getName();
|
||||
private static final String STR_BUFFER = Buffer.class.getName();
|
||||
private static final String STR_STRING = String.class.getName();
|
||||
|
||||
private static final ObjectType TYPE_VARARGS = new ObjectType(STR_VARARGS);
|
||||
private static final ObjectType TYPE_LUAVALUE = new ObjectType(STR_LUAVALUE);
|
||||
private static final ObjectType TYPE_LUASTRING = new ObjectType(STR_LUASTRING);
|
||||
private static final ObjectType TYPE_LUAINTEGER = new ObjectType(STR_LUAINTEGER);
|
||||
private static final ObjectType TYPE_LUADOUBLE = new ObjectType(STR_LUADOUBLE);
|
||||
private static final ObjectType TYPE_LUANUMBER = new ObjectType(STR_LUANUMBER);
|
||||
private static final ObjectType TYPE_LUABOOLEAN = new ObjectType(STR_LUABOOLEAN);
|
||||
private static final ObjectType TYPE_LUATABLE = new ObjectType(STR_LUATABLE);
|
||||
private static final ObjectType TYPE_BUFFER = new ObjectType(STR_BUFFER);
|
||||
|
||||
private static final ArrayType TYPE_LOCALUPVALUE = new ArrayType( TYPE_LUAVALUE, 1 );
|
||||
private static final ArrayType TYPE_CHARARRAY = new ArrayType( Type.CHAR, 1 );
|
||||
|
||||
|
||||
private static final Class[] NO_INNER_CLASSES = {};
|
||||
|
||||
private static final String STR_FUNCV = VarArgFunction.class.getName();
|
||||
private static final String STR_FUNC0 = ZeroArgFunction.class.getName();
|
||||
private static final String STR_FUNC1 = OneArgFunction.class.getName();
|
||||
private static final String STR_FUNC2 = TwoArgFunction.class.getName();
|
||||
private static final String STR_FUNC3 = ThreeArgFunction.class.getName();
|
||||
|
||||
// argument list types
|
||||
private static final Type[] ARG_TYPES_NONE = {};
|
||||
private static final Type[] ARG_TYPES_INT = { Type.INT };
|
||||
private static final Type[] ARG_TYPES_DOUBLE = { Type.DOUBLE };
|
||||
private static final Type[] ARG_TYPES_STRING = { Type.STRING };
|
||||
private static final Type[] ARG_TYPES_CHARARRAY = { TYPE_CHARARRAY };
|
||||
private static final Type[] ARG_TYPES_VARARGS_INT = { TYPE_VARARGS, Type.INT };
|
||||
private static final Type[] ARG_TYPES_INT_LUAVALUE = { Type.INT, TYPE_LUAVALUE };
|
||||
private static final Type[] ARG_TYPES_INT_VARARGS = { Type.INT, TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE_VARARGS = { TYPE_LUAVALUE, TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUEARRAY = { new ArrayType( TYPE_LUAVALUE, 1 ) };
|
||||
private static final Type[] ARG_TYPES_LUAVALUEARRAY_VARARGS = { new ArrayType( TYPE_LUAVALUE, 1 ), TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE };
|
||||
private static final Type[] ARG_TYPES_VARARGS = { TYPE_VARARGS };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE = { TYPE_LUAVALUE, TYPE_LUAVALUE };
|
||||
private static final Type[] ARG_TYPES_INT_INT = { Type.INT, Type.INT };
|
||||
private static final Type[] ARG_TYPES_LUAVALUE = { TYPE_LUAVALUE };
|
||||
private static final Type[] ARG_TYPES_BUFFER = { TYPE_BUFFER };
|
||||
|
||||
// names, arg types for main prototype classes
|
||||
private static final String[] SUPER_NAME_N = { STR_FUNC0, STR_FUNC1, STR_FUNC2, STR_FUNC3, STR_FUNCV, };
|
||||
private static final ObjectType[] RETURN_TYPE_N = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS, };
|
||||
private static final Type[][] ARG_TYPES_N = { ARG_TYPES_NONE, ARG_TYPES_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE, ARG_TYPES_VARARGS, };
|
||||
private static final String[][] ARG_NAMES_N = { {}, {"arg"}, {"arg1","arg2"}, {"arg1","arg2","arg3"}, {"args"}, };
|
||||
private static final String[] METH_NAME_N = { "call", "call", "call", "call", "onInvoke", };
|
||||
|
||||
|
||||
|
||||
// varable naming
|
||||
private static final String PREFIX_CONSTANT = "k";
|
||||
private static final String PREFIX_UPVALUE = "u";
|
||||
private static final String PREFIX_PLAIN_SLOT = "s";
|
||||
private static final String PREFIX_UPVALUE_SLOT = "a";
|
||||
private static final String NAME_VARRESULT = "v";
|
||||
|
||||
// basic info
|
||||
private final ProtoInfo pi;
|
||||
private final Prototype p;
|
||||
private final String classname;
|
||||
|
||||
// bcel variables
|
||||
private final ClassGen cg;
|
||||
private final ConstantPoolGen cp;
|
||||
private final InstructionFactory factory;
|
||||
|
||||
// main instruction list for the main function of this class
|
||||
private final InstructionList init;
|
||||
private final InstructionList main;
|
||||
private final MethodGen mg;
|
||||
|
||||
// the superclass arg count, 0-3 args, 4=varargs
|
||||
private int superclassType;
|
||||
private static int SUPERTYPE_VARARGS = 4;
|
||||
|
||||
// storage for goto locations
|
||||
private final int[] targets;
|
||||
private final BranchInstruction[] branches;
|
||||
private final InstructionHandle[] branchDestHandles;
|
||||
private InstructionHandle beginningOfLuaInstruction;
|
||||
|
||||
// hold vararg result
|
||||
private LocalVariableGen varresult = null;
|
||||
|
||||
public JavaBuilder(ProtoInfo pi, String classname, String filename) {
|
||||
this.pi = pi;
|
||||
this.p = pi.prototype;
|
||||
this.classname = classname;
|
||||
|
||||
// what class to inherit from
|
||||
superclassType = p.numparams;
|
||||
if ( p.is_vararg != 0 || superclassType >= SUPERTYPE_VARARGS )
|
||||
superclassType = SUPERTYPE_VARARGS;
|
||||
for ( int i=0, n=p.code.length; i<n; i++ ) {
|
||||
int inst = p.code[i];
|
||||
int o = Lua.GET_OPCODE(inst);
|
||||
if ( (o == Lua.OP_TAILCALL) ||
|
||||
((o == Lua.OP_RETURN) && (Lua.GETARG_B(inst) < 1 || Lua.GETARG_B(inst) > 2)) ) {
|
||||
superclassType = SUPERTYPE_VARARGS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// create class generator
|
||||
cg = new ClassGen(classname, SUPER_NAME_N[superclassType], filename,
|
||||
Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);
|
||||
cp = cg.getConstantPool(); // cg creates constant pool
|
||||
|
||||
// main instruction lists
|
||||
factory = new InstructionFactory(cg);
|
||||
init = new InstructionList();
|
||||
main = new InstructionList();
|
||||
|
||||
// create the fields
|
||||
for ( int i=0; i<p.nups; i++ ) {
|
||||
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[i] );
|
||||
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
|
||||
FieldGen fg = new FieldGen(0, uptype, upvalueName(i), cp);
|
||||
cg.addField(fg.getField());
|
||||
}
|
||||
|
||||
// create the method
|
||||
mg = new MethodGen( Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
|
||||
RETURN_TYPE_N[superclassType], // return type
|
||||
ARG_TYPES_N[superclassType], // argument types
|
||||
ARG_NAMES_N[superclassType], // arg names
|
||||
METH_NAME_N[superclassType],
|
||||
STR_LUAVALUE, // method, defining class
|
||||
main, cp);
|
||||
|
||||
// initialize the values in the slots
|
||||
initializeSlots();
|
||||
|
||||
// initialize branching
|
||||
int nc = p.code.length;
|
||||
targets = new int[nc];
|
||||
branches = new BranchInstruction[nc];
|
||||
branchDestHandles = new InstructionHandle[nc];
|
||||
}
|
||||
|
||||
public void initializeSlots() {
|
||||
int slot = 0;
|
||||
createUpvalues(-1, 0, p.maxstacksize);
|
||||
if ( superclassType == SUPERTYPE_VARARGS ) {
|
||||
for ( slot=0; slot<p.numparams; slot++ ) {
|
||||
if ( pi.isInitialValueUsed(slot) ) {
|
||||
append(new ALOAD(1));
|
||||
append(new PUSH(cp, slot+1));
|
||||
append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
|
||||
storeLocal(-1, slot);
|
||||
}
|
||||
}
|
||||
boolean needsarg = ((p.is_vararg & Lua.VARARG_NEEDSARG) != 0);
|
||||
if ( needsarg ) {
|
||||
append(new ALOAD(1));
|
||||
append(new PUSH(cp, 1 + p.numparams));
|
||||
append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, ARG_TYPES_VARARGS_INT, Constants.INVOKESTATIC));
|
||||
storeLocal(-1, slot++ );
|
||||
}
|
||||
else if ( p.numparams > 0 ) {
|
||||
append(new ALOAD(1));
|
||||
append(new PUSH(cp, 1 + p.numparams));
|
||||
append(factory.createInvoke(STR_VARARGS, "subargs", TYPE_VARARGS, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
|
||||
append(new ASTORE(1));
|
||||
}
|
||||
} else {
|
||||
// fixed arg function between 0 and 3 arguments
|
||||
for ( slot=0; slot<p.numparams; slot++ ) {
|
||||
this.plainSlotVars.put( Integer.valueOf(slot), Integer.valueOf(1+slot) );
|
||||
if ( pi.isUpvalueCreate(-1, slot) ) {
|
||||
append(new ALOAD(1+slot));
|
||||
storeLocal(-1, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nil parameters
|
||||
for ( ; slot<p.maxstacksize; slot++ ) {
|
||||
if ( pi.isInitialValueUsed(slot) ) {
|
||||
loadNil();
|
||||
storeLocal(-1, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] completeClass() {
|
||||
|
||||
// add class initializer
|
||||
if ( ! init.isEmpty() ) {
|
||||
MethodGen mg = new MethodGen(Constants.ACC_STATIC, Type.VOID,
|
||||
ARG_TYPES_NONE, new String[] {}, "<clinit>",
|
||||
cg.getClassName(), init, cg.getConstantPool());
|
||||
init.append(InstructionConstants.RETURN);
|
||||
mg.setMaxStack();
|
||||
cg.addMethod(mg.getMethod());
|
||||
init.dispose();
|
||||
}
|
||||
|
||||
// add default constructor
|
||||
cg.addEmptyConstructor(Constants.ACC_PUBLIC);
|
||||
|
||||
// gen method
|
||||
resolveBranches();
|
||||
mg.setMaxStack();
|
||||
cg.addMethod(mg.getMethod());
|
||||
main.dispose();
|
||||
|
||||
// convert to class bytes
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
cg.getJavaClass().dump(baos);
|
||||
return baos.toByteArray();
|
||||
} catch ( IOException ioe ) {
|
||||
throw new RuntimeException("JavaClass.dump() threw "+ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void dup() {
|
||||
append(InstructionConstants.DUP);
|
||||
}
|
||||
|
||||
public void pop() {
|
||||
append(InstructionConstants.POP);
|
||||
}
|
||||
|
||||
public void loadNil() {
|
||||
append(factory.createFieldAccess(STR_LUAVALUE, "NIL", TYPE_LUAVALUE, Constants.GETSTATIC));
|
||||
}
|
||||
|
||||
public void loadNone() {
|
||||
append(factory.createFieldAccess(STR_LUAVALUE, "NONE", TYPE_LUAVALUE, Constants.GETSTATIC));
|
||||
}
|
||||
|
||||
public void loadBoolean(boolean b) {
|
||||
String field = (b? "TRUE": "FALSE");
|
||||
append(factory.createFieldAccess(STR_LUAVALUE, field, TYPE_LUABOOLEAN, Constants.GETSTATIC));
|
||||
}
|
||||
|
||||
private Map<Integer,Integer> plainSlotVars = new HashMap<Integer,Integer>();
|
||||
private Map<Integer,Integer> upvalueSlotVars = new HashMap<Integer,Integer>();
|
||||
private int findSlot( int slot, Map<Integer,Integer> map, String prefix, Type type ) {
|
||||
Integer islot = Integer.valueOf(slot);
|
||||
if ( map.containsKey(islot) )
|
||||
return ((Integer)map.get(islot)).intValue();
|
||||
String name = prefix+slot;
|
||||
LocalVariableGen local = mg.addLocalVariable(name, type, null, null);
|
||||
int index = local.getIndex();
|
||||
map.put(islot, Integer.valueOf(index));
|
||||
return index;
|
||||
}
|
||||
private int findSlotIndex( int slot, boolean isupvalue ) {
|
||||
return isupvalue?
|
||||
findSlot( slot, upvalueSlotVars, PREFIX_UPVALUE_SLOT, TYPE_LOCALUPVALUE ):
|
||||
findSlot( slot, plainSlotVars, PREFIX_PLAIN_SLOT, TYPE_LUAVALUE );
|
||||
}
|
||||
|
||||
public void loadLocal(int pc, int slot) {
|
||||
boolean isupval = pi.isUpvalueRefer(pc, slot);
|
||||
int index = findSlotIndex( slot, isupval );
|
||||
append(new ALOAD(index));
|
||||
if (isupval) {
|
||||
append(new PUSH(cp, 0));
|
||||
append(InstructionConstants.AALOAD);
|
||||
}
|
||||
}
|
||||
|
||||
public void storeLocal(int pc, int slot) {
|
||||
boolean isupval = pi.isUpvalueAssign(pc, slot);
|
||||
int index = findSlotIndex( slot, isupval );
|
||||
if (isupval) {
|
||||
boolean isupcreate = pi.isUpvalueCreate(pc, slot);
|
||||
if ( isupcreate ) {
|
||||
append(factory.createInvoke(classname, "newupe", TYPE_LOCALUPVALUE, ARG_TYPES_NONE, Constants.INVOKESTATIC));
|
||||
append(InstructionConstants.DUP);
|
||||
append(new ASTORE(index));
|
||||
} else {
|
||||
append(new ALOAD(index));
|
||||
}
|
||||
append(InstructionConstants.SWAP);
|
||||
append(new PUSH(cp, 0));
|
||||
append(InstructionConstants.SWAP);
|
||||
append(InstructionConstants.AASTORE);
|
||||
} else {
|
||||
append(new ASTORE(index));
|
||||
}
|
||||
}
|
||||
|
||||
public void createUpvalues(int pc, int firstslot, int numslots) {
|
||||
for ( int i=0; i<numslots; i++ ) {
|
||||
int slot = firstslot + i;
|
||||
boolean isupcreate = pi.isUpvalueCreate(pc, slot);
|
||||
if ( isupcreate ) {
|
||||
int index = findSlotIndex( slot, true );
|
||||
append(factory.createInvoke(classname, "newupn", TYPE_LOCALUPVALUE, ARG_TYPES_NONE, Constants.INVOKESTATIC));
|
||||
append(new ASTORE(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void convertToUpvalue(int pc, int slot) {
|
||||
boolean isupassign = pi.isUpvalueAssign(pc, slot);
|
||||
if ( isupassign ) {
|
||||
int index = findSlotIndex( slot, false );
|
||||
append(new ALOAD(index));
|
||||
append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKESTATIC));
|
||||
int upindex = findSlotIndex( slot, true );
|
||||
append(new ASTORE(upindex));
|
||||
}
|
||||
}
|
||||
|
||||
private static String upvalueName(int upindex) {
|
||||
return PREFIX_UPVALUE+upindex;
|
||||
}
|
||||
|
||||
public void loadUpvalue(int upindex) {
|
||||
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
|
||||
append(InstructionConstants.THIS);
|
||||
if ( isrw ) {
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
|
||||
append(new PUSH(cp,0));
|
||||
append(InstructionConstants.AALOAD);
|
||||
} else {
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LUAVALUE, Constants.GETFIELD));
|
||||
}
|
||||
}
|
||||
|
||||
public void storeUpvalue(int pc, int upindex, int slot) {
|
||||
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
|
||||
append(InstructionConstants.THIS);
|
||||
if ( isrw ) {
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
|
||||
append(new PUSH(cp,0));
|
||||
loadLocal(pc, slot);
|
||||
append(InstructionConstants.AASTORE);
|
||||
} else {
|
||||
loadLocal(pc, slot);
|
||||
append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LUAVALUE, Constants.PUTFIELD));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void newTable( int b, int c ) {
|
||||
append(new PUSH(cp, b));
|
||||
append(new PUSH(cp, c));
|
||||
append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, ARG_TYPES_INT_INT, Constants.INVOKESTATIC));
|
||||
}
|
||||
|
||||
public void loadEnv() {
|
||||
append(InstructionConstants.THIS);
|
||||
append(factory.createFieldAccess(classname, "env", TYPE_LUAVALUE, Constants.GETFIELD));
|
||||
}
|
||||
|
||||
public void loadVarargs() {
|
||||
append(new ALOAD(1));
|
||||
}
|
||||
|
||||
public void loadVarargs(int argindex) {
|
||||
loadVarargs();
|
||||
arg(argindex);
|
||||
}
|
||||
|
||||
public void arg(int argindex) {
|
||||
if ( argindex == 1 ) {
|
||||
append(factory.createInvoke(STR_VARARGS, "arg1", TYPE_LUAVALUE, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL));
|
||||
} else {
|
||||
append(new PUSH(cp, argindex));
|
||||
append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
}
|
||||
|
||||
private int getVarresultIndex() {
|
||||
if ( varresult == null )
|
||||
varresult = mg.addLocalVariable(NAME_VARRESULT, TYPE_VARARGS, null, null);
|
||||
return varresult.getIndex();
|
||||
}
|
||||
|
||||
public void loadVarresult() {
|
||||
append(new ALOAD(getVarresultIndex()));
|
||||
}
|
||||
|
||||
public void storeVarresult() {
|
||||
append(new ASTORE(getVarresultIndex()));
|
||||
}
|
||||
|
||||
public void subargs(int firstarg) {
|
||||
append(new PUSH(cp, firstarg));
|
||||
append(factory.createInvoke(STR_VARARGS, "subargs", TYPE_VARARGS, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void getTable() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "get", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void setTable() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "set", Type.VOID, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void unaryop(int o) {
|
||||
String op;
|
||||
switch (o) {
|
||||
default:
|
||||
case Lua.OP_UNM: op = "neg"; break;
|
||||
case Lua.OP_NOT: op = "not"; break;
|
||||
case Lua.OP_LEN: op = "len"; break;
|
||||
}
|
||||
append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void binaryop(int o) {
|
||||
String op;
|
||||
switch (o) {
|
||||
default:
|
||||
case Lua.OP_ADD: op = "add"; break;
|
||||
case Lua.OP_SUB: op = "sub"; break;
|
||||
case Lua.OP_MUL: op = "mul"; break;
|
||||
case Lua.OP_DIV: op = "div"; break;
|
||||
case Lua.OP_MOD: op = "mod"; break;
|
||||
case Lua.OP_POW: op = "pow"; break;
|
||||
}
|
||||
append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void compareop(int o) {
|
||||
String op;
|
||||
switch (o) {
|
||||
default:
|
||||
case Lua.OP_EQ: op = "eq_b"; break;
|
||||
case Lua.OP_LT: op = "lt_b"; break;
|
||||
case Lua.OP_LE: op = "lteq_b"; break;
|
||||
}
|
||||
append(factory.createInvoke(STR_LUAVALUE, op, Type.BOOLEAN, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void areturn() {
|
||||
append(InstructionConstants.ARETURN);
|
||||
}
|
||||
|
||||
public void toBoolean() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "toboolean", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void tostring() {
|
||||
append(factory.createInvoke(STR_BUFFER, "tostring", TYPE_LUASTRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void isNil() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "isnil", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void testForLoop() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "testfor_b", Type.BOOLEAN, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void loadArrayArgs(int pc, int firstslot, int nargs) {
|
||||
append(new PUSH(cp, nargs));
|
||||
append(new ANEWARRAY(cp.addClass(STR_LUAVALUE)));
|
||||
for ( int i=0; i<nargs; i++ ) {
|
||||
append(InstructionConstants.DUP);
|
||||
append(new PUSH(cp, i));
|
||||
loadLocal(pc, firstslot++);
|
||||
append(new AASTORE());
|
||||
}
|
||||
}
|
||||
|
||||
public void newVarargs(int pc, int firstslot, int nargs) {
|
||||
switch ( nargs ) {
|
||||
case 0: loadNone();
|
||||
break;
|
||||
case 1: loadLocal(pc, firstslot);
|
||||
break;
|
||||
case 2: loadLocal(pc, firstslot); loadLocal(pc, firstslot+1);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS, Constants.INVOKESTATIC));
|
||||
break;
|
||||
case 3: loadLocal(pc, firstslot); loadLocal(pc, firstslot+1); loadLocal(pc, firstslot+2);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS, Constants.INVOKESTATIC));
|
||||
break;
|
||||
default:
|
||||
loadArrayArgs(pc, firstslot, nargs);
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY, Constants.INVOKESTATIC));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void newVarargsVarresult(int pc, int firstslot, int nslots) {
|
||||
loadArrayArgs(pc, firstslot, nslots );
|
||||
loadVarresult();
|
||||
append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY_VARARGS, Constants.INVOKESTATIC));
|
||||
}
|
||||
|
||||
public void call(int nargs) {
|
||||
switch ( nargs ) {
|
||||
case 0: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL)); break;
|
||||
case 1: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL)); break;
|
||||
case 2: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL)); break;
|
||||
case 3: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL)); break;
|
||||
default: throw new IllegalArgumentException("can't call with "+nargs+" args");
|
||||
}
|
||||
}
|
||||
|
||||
public void newTailcallVarargs() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "tailcallOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS, Constants.INVOKESTATIC));
|
||||
}
|
||||
|
||||
public void invoke(int nargs) {
|
||||
switch ( nargs ) {
|
||||
case -1: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL)); break;
|
||||
case 0: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL)); break;
|
||||
case 1: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL)); break;
|
||||
case 2: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS, Constants.INVOKEVIRTUAL)); break;
|
||||
case 3: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS, Constants.INVOKEVIRTUAL)); break;
|
||||
default: throw new IllegalArgumentException("can't invoke with "+nargs+" args");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------ closures ------------------------
|
||||
|
||||
public void closureCreate(String protoname) {
|
||||
append(factory.createNew(new ObjectType(protoname)));
|
||||
append(InstructionConstants.DUP);
|
||||
append(factory.createInvoke(protoname, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
|
||||
append(InstructionConstants.DUP);
|
||||
loadEnv();
|
||||
append(factory.createInvoke(STR_LUAVALUE, "setfenv", Type.VOID, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void closureInitUpvalueFromUpvalue(String protoname, int newup, int upindex) {
|
||||
boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
|
||||
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
|
||||
String srcname = upvalueName(upindex);
|
||||
String destname = upvalueName(newup);
|
||||
append(InstructionConstants.THIS);
|
||||
append(factory.createFieldAccess(classname, srcname, uptype, Constants.GETFIELD));
|
||||
append(factory.createFieldAccess(protoname, destname, uptype, Constants.PUTFIELD));
|
||||
}
|
||||
|
||||
public void closureInitUpvalueFromLocal(String protoname, int newup, int pc, int srcslot) {
|
||||
boolean isrw = pi.isReadWriteUpvalue( pi.vars[srcslot][pc].upvalue );
|
||||
Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
|
||||
String destname = upvalueName(newup);
|
||||
int index = findSlotIndex( srcslot, isrw );
|
||||
append(new ALOAD(index));
|
||||
append(factory.createFieldAccess(protoname, destname, uptype, Constants.PUTFIELD));
|
||||
}
|
||||
|
||||
private Map<LuaValue,String> constants = new HashMap<LuaValue,String>();
|
||||
|
||||
public void loadConstant(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNIL:
|
||||
loadNil();
|
||||
break;
|
||||
case LuaValue.TBOOLEAN:
|
||||
loadBoolean( value.toboolean() );
|
||||
break;
|
||||
case LuaValue.TNUMBER:
|
||||
case LuaValue.TSTRING:
|
||||
String name = (String) constants.get(value);
|
||||
if ( name == null ) {
|
||||
name = value.type() == LuaValue.TNUMBER?
|
||||
value.isinttype()?
|
||||
createLuaIntegerField(value.checkint()):
|
||||
createLuaDoubleField(value.checkdouble()):
|
||||
createLuaStringField(value.checkstring());
|
||||
constants.put(value, name);
|
||||
}
|
||||
append(factory.createGetStatic(classname, name, TYPE_LUAVALUE));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("bad constant type: "+value.type());
|
||||
}
|
||||
}
|
||||
|
||||
private String createLuaIntegerField(int value) {
|
||||
String name = PREFIX_CONSTANT+constants.size();
|
||||
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
|
||||
TYPE_LUAVALUE, name, cp);
|
||||
cg.addField(fg.getField());
|
||||
init.append(new PUSH(cp, value));
|
||||
init.append(factory.createInvoke(STR_LUAVALUE, "valueOf",
|
||||
TYPE_LUAINTEGER, ARG_TYPES_INT, Constants.INVOKESTATIC));
|
||||
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
|
||||
return name;
|
||||
}
|
||||
|
||||
private String createLuaDoubleField(double value) {
|
||||
String name = PREFIX_CONSTANT+constants.size();
|
||||
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
|
||||
TYPE_LUAVALUE, name, cp);
|
||||
cg.addField(fg.getField());
|
||||
init.append(new PUSH(cp, value));
|
||||
init.append(factory.createInvoke(STR_LUAVALUE, "valueOf",
|
||||
TYPE_LUANUMBER, ARG_TYPES_DOUBLE, Constants.INVOKESTATIC));
|
||||
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
|
||||
return name;
|
||||
}
|
||||
|
||||
private String createLuaStringField(LuaString value) {
|
||||
String name = PREFIX_CONSTANT+constants.size();
|
||||
FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
|
||||
TYPE_LUAVALUE, name, cp);
|
||||
cg.addField(fg.getField());
|
||||
LuaString ls = value.checkstring();
|
||||
if ( ls.isValidUtf8() ) {
|
||||
init.append(new PUSH(cp, value.tojstring()));
|
||||
init.append(factory.createInvoke(STR_LUASTRING, "valueOf",
|
||||
TYPE_LUASTRING, ARG_TYPES_STRING, Constants.INVOKESTATIC));
|
||||
} else {
|
||||
char[] c = new char[ls.m_length];
|
||||
for ( int j=0; j<ls.m_length; j++ )
|
||||
c[j] = (char) (0xff & (int) (ls.m_bytes[ls.m_offset+j]));
|
||||
init.append(new PUSH(cp, new String(c)));
|
||||
init.append(factory.createInvoke(STR_STRING, "toCharArray",
|
||||
TYPE_CHARARRAY, Type.NO_ARGS,
|
||||
Constants.INVOKEVIRTUAL));
|
||||
init.append(factory.createInvoke(STR_LUASTRING, "valueOf",
|
||||
TYPE_LUASTRING, ARG_TYPES_CHARARRAY,
|
||||
Constants.INVOKESTATIC));
|
||||
}
|
||||
init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
|
||||
return name;
|
||||
}
|
||||
|
||||
// --------------------- branching support -------------------------
|
||||
public static final int BRANCH_GOTO = 1;
|
||||
public static final int BRANCH_IFNE = 2;
|
||||
public static final int BRANCH_IFEQ = 3;
|
||||
|
||||
public void addBranch( int pc, int branchType, int targetpc ) {
|
||||
switch ( branchType ) {
|
||||
default:
|
||||
case BRANCH_GOTO: branches[pc] = new GOTO(null); break;
|
||||
case BRANCH_IFNE: branches[pc] = new IFNE(null); break;
|
||||
case BRANCH_IFEQ: branches[pc] = new IFEQ(null); break;
|
||||
}
|
||||
targets[pc] = targetpc;
|
||||
append(branches[pc]);
|
||||
}
|
||||
|
||||
|
||||
private void append( Instruction i ) {
|
||||
conditionalSetBeginningOfLua( main.append(i) );
|
||||
}
|
||||
|
||||
private void append( CompoundInstruction i ) {
|
||||
conditionalSetBeginningOfLua( main.append(i) );
|
||||
}
|
||||
|
||||
private void append( BranchInstruction i ) {
|
||||
conditionalSetBeginningOfLua( main.append(i) );
|
||||
}
|
||||
|
||||
private void conditionalSetBeginningOfLua(InstructionHandle ih) {
|
||||
if ( beginningOfLuaInstruction == null )
|
||||
beginningOfLuaInstruction = ih;
|
||||
}
|
||||
|
||||
public void onEndOfLuaInstruction(int pc) {
|
||||
branchDestHandles[pc] = beginningOfLuaInstruction;
|
||||
beginningOfLuaInstruction = null;
|
||||
}
|
||||
|
||||
private void resolveBranches() {
|
||||
int nc = p.code.length;
|
||||
for (int pc = 0; pc < nc; pc++) {
|
||||
if (branches[pc] != null) {
|
||||
int t=targets[pc];
|
||||
while ( t<branchDestHandles.length && branchDestHandles[t] == null )
|
||||
t++;
|
||||
if ( t>= branchDestHandles.length )
|
||||
throw new IllegalArgumentException("no target at or after "+targets[pc]+" op="+Lua.GET_OPCODE(p.code[targets[pc]]));
|
||||
branches[pc].setTarget(branchDestHandles[t]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setlistStack(int pc, int a0, int index0, int nvals) {
|
||||
for ( int i=0; i<nvals; i++ ) {
|
||||
dup();
|
||||
append(new PUSH(cp, index0+i));
|
||||
loadLocal( pc, a0+i );
|
||||
append(factory.createInvoke(STR_LUAVALUE, "rawset", Type.VOID, ARG_TYPES_INT_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
}
|
||||
|
||||
public void setlistVarargs(int index0, int vresultbase) {
|
||||
append(new PUSH(cp, index0));
|
||||
loadVarresult();
|
||||
append(factory.createInvoke(STR_LUAVALUE, "rawsetlist", Type.VOID, ARG_TYPES_INT_VARARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void concatvalue() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "concat", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void concatbuffer() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "concat", TYPE_BUFFER, ARG_TYPES_BUFFER, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void tobuffer() {
|
||||
append(factory.createInvoke(STR_LUAVALUE, "buffer", TYPE_BUFFER, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
|
||||
public void tovalue() {
|
||||
append(factory.createInvoke(STR_BUFFER, "value", TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
|
||||
}
|
||||
}
|
@ -1,463 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.luajc;
|
||||
|
||||
import org.luaj.vm2.Buffer;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.Prototype;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* propogate constants
|
||||
* loader can find inner classes
|
||||
*/
|
||||
public class JavaGen {
|
||||
|
||||
public final String classname;
|
||||
public final byte[] bytecode;
|
||||
public final JavaGen[] inners;
|
||||
|
||||
public JavaGen( Prototype p, String classname, String filename ) {
|
||||
this( new ProtoInfo(p,classname), classname, filename );
|
||||
}
|
||||
|
||||
private JavaGen( ProtoInfo pi, String classname, String filename ) {
|
||||
this.classname = classname;
|
||||
|
||||
// build this class
|
||||
JavaBuilder builder = new JavaBuilder(pi, classname, filename);
|
||||
scanInstructions(pi, classname, builder);
|
||||
this.bytecode = builder.completeClass();
|
||||
|
||||
// build sub-prototypes
|
||||
if ( pi.subprotos != null ) {
|
||||
int n = pi.subprotos.length;
|
||||
inners = new JavaGen[n];
|
||||
for ( int i=0; i<n; i++ )
|
||||
inners[i] = new JavaGen(pi.subprotos[i], closureName(classname,i), filename);
|
||||
} else {
|
||||
inners = null;
|
||||
}
|
||||
}
|
||||
|
||||
private String closureName(String classname, int subprotoindex) {
|
||||
return classname+"$"+subprotoindex;
|
||||
}
|
||||
|
||||
private void scanInstructions(ProtoInfo pi, String classname, JavaBuilder builder) {
|
||||
Prototype p = pi.prototype;
|
||||
int vresultbase = -1;
|
||||
|
||||
for ( int bi=0; bi<pi.blocklist.length; bi++ ) {
|
||||
BasicBlock b0 = pi.blocklist[bi];
|
||||
|
||||
// convert upvalues that are phi-variables
|
||||
for ( int slot=0; slot<p.maxstacksize; slot++ ) {
|
||||
int pc = b0.pc0;
|
||||
boolean c = pi.isUpvalueCreate(pc, slot);
|
||||
if ( c && pi.vars[slot][pc].isPhiVar() )
|
||||
builder.convertToUpvalue(pc, slot);
|
||||
}
|
||||
|
||||
for ( int pc=b0.pc0; pc<=b0.pc1; pc++ ) {
|
||||
|
||||
int pc0 = pc; // closure changes pc
|
||||
int ins = p.code[pc];
|
||||
final int o = Lua.GET_OPCODE(ins);
|
||||
int a = Lua.GETARG_A(ins);
|
||||
int b = Lua.GETARG_B(ins);
|
||||
int bx = Lua.GETARG_Bx(ins);
|
||||
int sbx = Lua.GETARG_sBx(ins);
|
||||
int c = Lua.GETARG_C(ins);
|
||||
|
||||
switch ( o ) {
|
||||
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
|
||||
builder.loadUpvalue( b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
|
||||
builder.storeUpvalue( pc, b, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
|
||||
builder.newTable( b, c );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_MOVE:/* A B R(A):= R(B) */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_UNM: /* A B R(A):= -R(B) */
|
||||
case Lua.OP_NOT: /* A B R(A):= not R(B) */
|
||||
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.unaryop( o );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
|
||||
builder.loadConstant( p.k[bx] );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
|
||||
builder.loadEnv();
|
||||
builder.loadConstant( p.k[bx] );
|
||||
builder.getTable();
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
|
||||
builder.loadEnv();
|
||||
builder.loadConstant( p.k[bx] );
|
||||
builder.loadLocal( pc, a );
|
||||
builder.setTable();
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(B):= nil */
|
||||
builder.loadNil();
|
||||
for ( ; a<=b; a++ ) {
|
||||
if ( a < b )
|
||||
builder.dup();
|
||||
builder.storeLocal( pc, a );
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
|
||||
builder.loadLocal( pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.getTable();
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
|
||||
builder.loadLocal( pc, a );
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.setTable();
|
||||
break;
|
||||
|
||||
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
|
||||
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
|
||||
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
|
||||
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
|
||||
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
|
||||
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.binaryop( o );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
|
||||
builder.loadLocal(pc,b);
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a+1);
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.getTable();
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
|
||||
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
|
||||
for ( int k=b; k<=c; k++ )
|
||||
builder.loadLocal(pc, k);
|
||||
if ( c > b+1 ) {
|
||||
builder.tobuffer();
|
||||
for ( int k=c; --k>=b; )
|
||||
builder.concatbuffer();
|
||||
builder.tovalue();
|
||||
} else {
|
||||
builder.concatvalue();
|
||||
}
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
|
||||
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
|
||||
builder.loadBoolean( b!=0 );
|
||||
builder.storeLocal( pc, a );
|
||||
if ( c!=0 )
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_JMP: /* sBx pc+=sBx */
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||
loadLocalOrConstant( p, builder, pc, b );
|
||||
loadLocalOrConstant( p, builder, pc, c );
|
||||
builder.compareop(o);
|
||||
builder.addBranch(pc, (a!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
|
||||
builder.loadLocal( pc, a );
|
||||
builder.toBoolean();
|
||||
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
break;
|
||||
|
||||
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
|
||||
builder.loadLocal( pc, b );
|
||||
builder.toBoolean();
|
||||
builder.addBranch(pc, (c!=0? JavaBuilder.BRANCH_IFEQ: JavaBuilder.BRANCH_IFNE), pc+2);
|
||||
builder.loadLocal( pc, b );
|
||||
builder.storeLocal( pc, a );
|
||||
break;
|
||||
|
||||
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
|
||||
// load function
|
||||
builder.loadLocal(pc, a);
|
||||
|
||||
// load args
|
||||
int narg = b - 1;
|
||||
switch ( narg ) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
for ( int i=1; i<b; i++ )
|
||||
builder.loadLocal(pc, a+i);
|
||||
break;
|
||||
default: // fixed arg count > 3
|
||||
builder.newVarargs( pc, a+1, b-1 );
|
||||
narg = -1;
|
||||
break;
|
||||
case -1: // prev vararg result
|
||||
loadVarargResults( builder, pc, a+1, vresultbase );
|
||||
narg = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// call or invoke
|
||||
boolean useinvoke = narg<0 || c<1 || c>2;
|
||||
if ( useinvoke )
|
||||
builder.invoke(narg);
|
||||
else
|
||||
builder.call(narg);
|
||||
|
||||
// handle results
|
||||
switch ( c ) {
|
||||
case 1:
|
||||
builder.pop();
|
||||
break;
|
||||
case 2:
|
||||
if ( useinvoke )
|
||||
builder.arg( 1 );
|
||||
builder.storeLocal(pc, a);
|
||||
break;
|
||||
default: // fixed result count - unpack args
|
||||
for ( int i=1; i<c; i++ ) {
|
||||
if ( i+1 < c )
|
||||
builder.dup();
|
||||
builder.arg( i );
|
||||
builder.storeLocal(pc, a+i-1);
|
||||
}
|
||||
break;
|
||||
case 0: // vararg result
|
||||
vresultbase = a;
|
||||
builder.storeVarresult();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
|
||||
// load function
|
||||
builder.loadLocal(pc, a);
|
||||
|
||||
// load args
|
||||
switch ( b ) {
|
||||
case 1:
|
||||
builder.loadNone();
|
||||
break;
|
||||
case 2:
|
||||
builder.loadLocal(pc, a+1);
|
||||
break;
|
||||
default: // fixed arg count > 1
|
||||
builder.newVarargs( pc, a+1, b-1 );
|
||||
break;
|
||||
case 0: // prev vararg result
|
||||
loadVarargResults( builder, pc, a+1, vresultbase );
|
||||
break;
|
||||
}
|
||||
builder.newTailcallVarargs();
|
||||
builder.areturn();
|
||||
break;
|
||||
|
||||
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
if ( c == 1 ) {
|
||||
builder.loadNone();
|
||||
} else {
|
||||
switch ( b ) {
|
||||
case 0: loadVarargResults( builder, pc, a, vresultbase ); break;
|
||||
case 1: builder.loadNone(); break;
|
||||
case 2: builder.loadLocal(pc, a); break;
|
||||
default: builder.newVarargs(pc, a, b-1); break;
|
||||
}
|
||||
}
|
||||
builder.areturn();
|
||||
break;
|
||||
|
||||
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.binaryop( Lua.OP_SUB );
|
||||
builder.storeLocal(pc, a);
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_GOTO, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.binaryop( Lua.OP_ADD );
|
||||
builder.dup();
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a);
|
||||
builder.storeLocal(pc, a+3);
|
||||
builder.loadLocal(pc, a+1); // limit
|
||||
builder.loadLocal(pc, a+2); // step
|
||||
builder.testForLoop();
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+1+sbx);
|
||||
break;
|
||||
|
||||
case Lua.OP_TFORLOOP: /*
|
||||
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
|
||||
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
|
||||
* else pc++
|
||||
*/
|
||||
// v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
|
||||
// if ( (o=v.arg1()).isnil() )
|
||||
// ++pc;
|
||||
builder.loadLocal(pc, a);
|
||||
builder.loadLocal(pc, a+1);
|
||||
builder.loadLocal(pc, a+2);
|
||||
builder.invoke(2); // varresult on stack
|
||||
builder.dup();
|
||||
builder.storeVarresult();
|
||||
builder.arg( 1 );
|
||||
builder.isNil();
|
||||
builder.addBranch(pc, JavaBuilder.BRANCH_IFNE, pc+2);
|
||||
|
||||
// a[2] = a[3] = v[1], leave varargs on stack
|
||||
builder.createUpvalues(pc, a+3, c);
|
||||
builder.loadVarresult();
|
||||
if (c>=2)
|
||||
builder.dup();
|
||||
builder.arg( 1 );
|
||||
builder.dup();
|
||||
builder.storeLocal(pc, a+2);
|
||||
builder.storeLocal(pc, a+3);
|
||||
|
||||
// v[2]..v[c], use varargs from stack
|
||||
for ( int j=2; j<=c; j++ ) {
|
||||
if ( j<c )
|
||||
builder.dup();
|
||||
builder.arg( j );
|
||||
builder.storeLocal(pc, a+2+j);
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
|
||||
int index0 = (c-1)*Lua.LFIELDS_PER_FLUSH + 1;
|
||||
builder.loadLocal( pc, a );
|
||||
if ( b == 0 ) {
|
||||
int nstack = vresultbase - (a+1);
|
||||
if ( nstack > 0 ) {
|
||||
builder.setlistStack( pc, a+1, index0, nstack );
|
||||
index0 += nstack;
|
||||
}
|
||||
builder.setlistVarargs( index0, vresultbase );
|
||||
} else {
|
||||
builder.setlistStack( pc, a+1, index0, b );
|
||||
builder.pop();
|
||||
}
|
||||
break;
|
||||
|
||||
case Lua.OP_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
|
||||
break;
|
||||
|
||||
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||
{
|
||||
Prototype newp = p.p[bx];
|
||||
String protoname = closureName(classname, bx);
|
||||
int nup = newp.nups;
|
||||
builder.closureCreate( protoname );
|
||||
if ( nup > 0 )
|
||||
builder.dup();
|
||||
builder.storeLocal( pc, a );
|
||||
if ( nup > 0 ) {
|
||||
for ( int up=0; up<nup; ++up ) {
|
||||
if ( up+1 < nup )
|
||||
builder.dup();
|
||||
ins = p.code[pc+up+1];
|
||||
b = Lua.GETARG_B(ins);
|
||||
if ( (ins&4) != 0 ) {
|
||||
builder.closureInitUpvalueFromUpvalue( protoname, up, b );
|
||||
} else {
|
||||
builder.closureInitUpvalueFromLocal( protoname, up, pc, b );
|
||||
}
|
||||
}
|
||||
pc += nup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
|
||||
if ( b == 0 ) {
|
||||
builder.loadVarargs();
|
||||
builder.storeVarresult();
|
||||
vresultbase = a;
|
||||
} else {
|
||||
for ( int i=1; i<b; ++a, ++i ) {
|
||||
builder.loadVarargs( i );
|
||||
builder.storeLocal(pc, a);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// let builder process branch instructions
|
||||
builder.onEndOfLuaInstruction( pc0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadVarargResults(JavaBuilder builder, int pc, int a, int vresultbase) {
|
||||
if ( vresultbase <= a ) {
|
||||
builder.loadVarresult();
|
||||
builder.subargs( a+1-vresultbase );
|
||||
} else if ( vresultbase == a ) {
|
||||
builder.loadVarresult();
|
||||
} else {
|
||||
builder.newVarargsVarresult(pc, a, vresultbase-a);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLocalOrConstant(Prototype p, JavaBuilder builder, int pc, int borc) {
|
||||
if ( borc<=0xff )
|
||||
builder.loadLocal( pc, borc );
|
||||
else
|
||||
builder.loadConstant( p.k[borc&0xff] );
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
package org.luaj.vm2.luajc;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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.
|
||||
******************************************************************************/
|
||||
public class JavaLoader extends ClassLoader {
|
||||
|
||||
private final LuaValue env;
|
||||
|
||||
private Map<String,byte[]> unloaded = new HashMap<String,byte[]>();
|
||||
|
||||
public JavaLoader( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public LuaFunction load( Prototype p, String classname, String filename ) {
|
||||
JavaGen jg = new JavaGen( p, classname, filename );
|
||||
return load( jg );
|
||||
}
|
||||
|
||||
public LuaFunction load( JavaGen jg ) {
|
||||
include( jg );
|
||||
return load( jg.classname );
|
||||
}
|
||||
|
||||
public LuaFunction load(String classname) {
|
||||
try {
|
||||
Class c = loadClass( classname );
|
||||
LuaFunction v = (LuaFunction) c.newInstance();
|
||||
v.setfenv(env);
|
||||
return v;
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalStateException("bad class gen: "+e);
|
||||
}
|
||||
}
|
||||
|
||||
public void include( JavaGen jg ) {
|
||||
unloaded.put( jg.classname, jg.bytecode );
|
||||
for ( int i=0, n=jg.inners!=null? jg.inners.length: 0; i<n; i++ )
|
||||
include( jg.inners[i] );
|
||||
}
|
||||
|
||||
public Class findClass(String classname) throws ClassNotFoundException {
|
||||
byte[] bytes = (byte[]) unloaded.get(classname);
|
||||
if ( bytes != null )
|
||||
return defineClass(classname, bytes, 0, bytes.length);
|
||||
return super.findClass(classname);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user