Initial sources for planned 2.0 luaj vm release. Most interpreter features and library functions working.
This commit is contained in:
18
.classpath
18
.classpath
@@ -1,14 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src/core"/>
|
||||
<classpathentry kind="src" path="src/j2me"/>
|
||||
<classpathentry kind="src" path="src/j2se"/>
|
||||
<classpathentry kind="src" path="src/script"/>
|
||||
<classpathentry kind="src" path="src/test/java"/>
|
||||
<classpathentry kind="src" path="src/sample"/>
|
||||
<classpathentry kind="src" path="src/test/res"/>
|
||||
<classpathentry 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.8.1"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
|
||||
<classpathentry kind="var" path="ANTLR_HOME/lib/antlr-runtime-3.1.3.jar"/>
|
||||
<classpathentry kind="var" path="ANTLR_HOME"/>
|
||||
<classpathentry kind="var" path="WTK_HOME/lib/cldcapi11.jar"/>
|
||||
<classpathentry kind="var" path="WTK_HOME/lib/midpapi20.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
|
||||
144
README.html
144
README.html
@@ -17,7 +17,7 @@
|
||||
Getting Started with LuaJ
|
||||
|
||||
</h1>
|
||||
James Roseborough, Ian Farmer, Version 1.0.1
|
||||
James Roseborough, Ian Farmer, Version 1.9.50
|
||||
<p>
|
||||
<small>
|
||||
Copyright © 2007-2009 Luaj.org.
|
||||
@@ -41,32 +41,36 @@ Freely available under the terms of the
|
||||
|
||||
<!-- ====================================================================== -->
|
||||
<p>
|
||||
<font color=#800000><em>
|
||||
This is a development release for a planned luaj 2.0. The most recent stable release is 1.0.1
|
||||
</em></font>
|
||||
|
||||
|
||||
<h1>1 - <a name="1">Simple Examples</a></h1>
|
||||
|
||||
<h2>Run a script in J2SE</h2>
|
||||
<h2>Run a script in Java SE</h2>
|
||||
|
||||
<p>
|
||||
From the main distribution directory line type:
|
||||
|
||||
<pre>
|
||||
java -cp lib/luaj-j2se-1.0.jar lua src/test/res/test4.lua
|
||||
java -cp lib/luaj-jse-1.9.50.jar lua examples/lua/hello.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You should see the following output:
|
||||
<pre>
|
||||
40
|
||||
hello, world
|
||||
</pre>
|
||||
|
||||
<h2>Compile a script in J2SE</h2>
|
||||
<h2>Compile a script in Java SE</h2>
|
||||
|
||||
<p>
|
||||
From the main distribution directory line type:
|
||||
|
||||
<pre>
|
||||
java -cp lib/luaj-j2se-1.0.jar luac src/test/res/test4.lua
|
||||
java -cp lib/luaj-j2se-1.0.jar lua luac.out
|
||||
java -cp lib/luaj-jse-1.0.jar luac examples/lua/hello.lua
|
||||
java -cp lib/luaj-jse-1.0.jar lua luac.out
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -75,29 +79,27 @@ The compiled output should run and produce the same result.
|
||||
<h2>Run a script in a Java Application</h2>
|
||||
|
||||
<p>
|
||||
The following pattern is used within J2SE
|
||||
The following pattern is used within Java SE
|
||||
|
||||
<pre>
|
||||
import org.luaj.platform.*;
|
||||
import org.luaj.vm.*;
|
||||
import org.luaj.vm2.*;
|
||||
import org.luaj.vm2.lib.*;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
|
||||
String script = "main.lua";
|
||||
Platform.setInstance( new J2sePlatform() );
|
||||
LuaState vm = Platform.newLuaState();
|
||||
org.luaj.compiler.LuaC.install();
|
||||
vm.getglobal( "dofile" );
|
||||
vm.pushstring( script );
|
||||
vm.call( 1, 0 );
|
||||
String script = "examples/lua/hello.lua";
|
||||
LuaC.install();
|
||||
LuaValue _G = JsePlatform.standardGlobals();
|
||||
_G.get("dofile").call( LuaValue.valueOf(script) );
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A simple example may be found in
|
||||
<pre>
|
||||
src/sample/SampleJ2seMain.java
|
||||
examples/jse/SampleJseMain.java
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You must include the library <b>lib/luaj-j2se-1.0.jar</b> in your class path.
|
||||
You must include the library <b>lib/luaj-jse-1.9.50.jar</b> in your class path.
|
||||
|
||||
<h2>Run a script in a MIDlet</h2>
|
||||
|
||||
@@ -105,16 +107,14 @@ You must include the library <b>lib/luaj-j2se-1.0.jar</b> in your class path.
|
||||
The following pattern is used within MIDlets:
|
||||
|
||||
<pre>
|
||||
import org.luaj.platform.*;
|
||||
import org.luaj.vm.*;
|
||||
import org.luaj.vm2.*;
|
||||
import org.luaj.vm2.lib.*;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
|
||||
String script = "main.lua";
|
||||
Platform.setInstance( new J2meMidp20Cldc11Platform( midlet ) );
|
||||
LuaState vm = Platform.newLuaState();
|
||||
org.luaj.compiler.LuaC.install();
|
||||
vm.getglobal( "dofile" );
|
||||
vm.pushstring( script );
|
||||
vm.call( 1, 0 );
|
||||
String script = "examples/lua/hello.lua";
|
||||
LuaC.install();
|
||||
LuaValue _G = JmePlatform.standardGlobals();
|
||||
_G.get("dofile").call( LuaValue.valueOf(script) );
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -124,22 +124,23 @@ Any files included via <em>require()</em> must also be part of the midlet resour
|
||||
<p>
|
||||
A simple example may be found in
|
||||
<pre>
|
||||
src/sample/SampleMIDlet.java
|
||||
examples/jme/SampleMIDlet.java
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You must include the library <b>lib/luaj-j2me-1.0.jar</b> in your midlet jar.
|
||||
You must include the library <b>lib/luaj-jme-1.9.50.jar</b> in your midlet jar.
|
||||
They can be obfuscated if desired.
|
||||
|
||||
<h2>Including the compiler</h2>
|
||||
|
||||
By default, the compiler is not included to minimize footprint.
|
||||
By default, the compiler is not included so as to minimize footprint.
|
||||
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 include it, include the following after the Platform is created,
|
||||
but before the script is executed:
|
||||
To include the Java it, include the following sometime before lua source files are loaded:
|
||||
<pre>
|
||||
org.luaj.compiler.LuaC.install();
|
||||
org.luaj.vm2.compiler.LuaC.install();
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -162,32 +163,35 @@ The standard use of JSR-233 scripting engines may be used:
|
||||
All standard aspects of script engines including compiled statements should be supported.
|
||||
|
||||
<p>
|
||||
You must include the library <b>lib/luaj-j2se-1.0.jar</b> in your class path.
|
||||
You must include the library <b>lib/luaj-jse-1.9.50.jar</b> in your class path.
|
||||
|
||||
<p>
|
||||
A working example may be found in
|
||||
<pre>
|
||||
src/script/ScriptEngineSample.java
|
||||
examples/jse/ScriptEngineSample.java
|
||||
</pre>
|
||||
|
||||
|
||||
<h1>2 - <a name="2">Concepts</a></h1>
|
||||
|
||||
<h2>Platforms</h2>
|
||||
A Platform is required to set up basic filesystem behavior as well as
|
||||
contolling mappings to underlying math functions.
|
||||
<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>J2sePlatform</h3>
|
||||
<h3>JsePlatform</h3>
|
||||
|
||||
This platform is used to set up the basic environment for a J2SE application.
|
||||
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 J2SE.
|
||||
and the math operations include all those supported by Java SE.
|
||||
|
||||
<h3>J2mePlatform</h3>
|
||||
<h3>JmePlatform</h3>
|
||||
|
||||
This platform is used to set up the basic environment for a J2ME application.
|
||||
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 J2ME.
|
||||
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>3 - <a name="3">Libraries</a></h1>
|
||||
@@ -198,7 +202,7 @@ 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 default in J2ME and J2SE platforms:
|
||||
The following libraries are loaded by default in Java ME and Java SE platforms:
|
||||
<pre>
|
||||
base
|
||||
coroutine
|
||||
@@ -220,32 +224,23 @@ The following libraries are optional, but preconfigured for some platforms and t
|
||||
<h2>Optional Libraries</h2>
|
||||
|
||||
<h3>I/O Library</h3>
|
||||
The J2SE platform contains the <em>io</em> library by default.
|
||||
The Java SE platform contains the <em>io</em> library by default.
|
||||
|
||||
<p>
|
||||
The J2ME platform has an optional, partial implementation of the <em>io</em> in
|
||||
The Java ME platform has an optional, partial implementation of the <em>io</em> in
|
||||
<pre>
|
||||
src/j2me/org/luaj/lib/j2me/Cldc10IoLib.java
|
||||
src/jme/org/luaj/vm2/lib/jme/JmeIoLib.java
|
||||
</pre>
|
||||
|
||||
To install into your vm instance use (j2me only):
|
||||
<pre>
|
||||
LuaState vm = Platform.newLuaState();
|
||||
org.luaj.lib.j2me.Cldc10IoLib.install(vm._G);
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
See the sample midlet int <em>src/sample/SampleMIDlet</em> for an example.
|
||||
|
||||
<h3>OS Library</h3>
|
||||
A basic os library implementation for either J2ME or J2SE is provided ins
|
||||
A basic os library implementation for either Java ME or Java SE is provided ins
|
||||
<pre>
|
||||
src/core/org/luaj/lib/OsLib.java
|
||||
</pre>
|
||||
|
||||
A slightly more complete version for J2SE is in:
|
||||
A slightly more complete version for Java SE is in:
|
||||
<pre>
|
||||
src/j2se/org/luaj/lib/j2se/J2seOsLib.java
|
||||
src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
|
||||
</pre>
|
||||
|
||||
Time is a represented as number of milliseconds since the epoch,
|
||||
@@ -260,24 +255,23 @@ The following library is optional:
|
||||
|
||||
Install from Java using:
|
||||
<pre>
|
||||
LuaState vm = Platform.newLuaState();
|
||||
org.luaj.lib.DebugLib.install(vm);
|
||||
org.luaj.vm2.lib.DebugLib.install(vm);
|
||||
</pre>
|
||||
|
||||
or install from lua using</em>:
|
||||
<pre>
|
||||
require 'org.luaj.lib.DebugLib'
|
||||
require 'org.luaj.vm2.lib.DebugLib'
|
||||
</pre>
|
||||
|
||||
The <em>lua</em> command line utility includes the debug library by default.
|
||||
|
||||
|
||||
<h3>The Luajava Library</h3>
|
||||
The J2SE platform includes the <em>luajava</em> library, which simplifies binding to Java classes and methods.
|
||||
The Java SE platform 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 swiing frame on J2SE:
|
||||
The following lua script will open a swiing frame on Java SE:
|
||||
<pre>
|
||||
jframe = luajava.bindClass( "javax.swing.JFrame" )
|
||||
frame = luajava.newInstance( "javax.swing.JFrame", "Texts" );
|
||||
@@ -289,11 +283,11 @@ The following lua script will open a swiing frame on J2SE:
|
||||
<p>
|
||||
See a longer sample in <em>src/test/res/swingapp.lua</em> for details, or try running it using:
|
||||
<pre>
|
||||
java -cp lib/luaj-j2se-1.0.jar lua src/test/res/swingapp.lua
|
||||
java -cp lib/luaj-jse-1.9.50.jar lua src/test/res/swingapp.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The J2ME platform does not include this library, and it cannot be made to work because of the lack of a reflection API in J2SE.
|
||||
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 SE.
|
||||
|
||||
<h1>4 - <a name="4">Building and Testing</a></h1>
|
||||
|
||||
@@ -308,13 +302,13 @@ Other targets exist for creating distribution file an measuring code coverage of
|
||||
<p>
|
||||
A large array of test scripts may be found in
|
||||
<pre>
|
||||
src/test/res/*.lua
|
||||
test/lua/*.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A large set of JUnit tests are invoked by the JUnit 3 suite:
|
||||
<pre>
|
||||
src/test/java/AllTests.lua
|
||||
test/junit/org/luaj/vm2/AllTests.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -323,7 +317,9 @@ These tests are used for to produce code coverage statistics using build-coverag
|
||||
<h1>5 - <a name="5">Downloads</a></h1>
|
||||
|
||||
<h2>Downloads and Project Pages</h2>
|
||||
Downloads are currently hosted on SourceForge
|
||||
Downloads for version 1.0.1 are currently hosted on SourceForge.
|
||||
Downloads of built packages for 2.0 are not yet available.
|
||||
Sources are available via sourceforge.net
|
||||
<br/>
|
||||
<pre>
|
||||
<a href="http://luaj.sourceforge.net/">SourceForge Luaj Project Page</a>
|
||||
@@ -340,7 +336,5 @@ and LuaForge:
|
||||
|
||||
Main changes by version:
|
||||
<table cellspacing="10"><tr><td><table cellspacing="4">
|
||||
<tr valign="top"><td> <b>1.0</b></td><td>Initial publicly supported release.</td></tr>
|
||||
<tr valign="top"><td> <b>1.0.1</b></td><td>Fix arg check and behavior of xpcall() to leave stack intact.
|
||||
Fix debug.sethook() to when called from hook function. Fix debug.gethook() return values. Array support in luajava bindings.</td></tr>
|
||||
</table></td></tr></table>
|
||||
<tr valign="top"><td> <b>1.9.50</b></td><td>Most interpreter features are working. Initial port of all libraries has been done.</td></tr>
|
||||
</table>
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
|
||||
<import file="wtk.xml"/>
|
||||
|
||||
<property environment="env"/>
|
||||
<property name="antlr.version" value="3.1.3"/>
|
||||
<property name="antlr.home" value="${env.ANTLR_HOME}"/>
|
||||
<property name="antlr.tool.jar" value="${antlr.home}/lib/antlr-${antlr.version}.jar"/>
|
||||
<property name="antlr.runtime.jar" value="${antlr.home}/lib/antlr-runtime-${antlr.version}.jar"/>
|
||||
|
||||
<target name="clean" description="Remove all files created by the build/test process.">
|
||||
<delete dir="build" failonerror="no"/>
|
||||
<delete file="cobertura.log" />
|
||||
@@ -42,12 +48,11 @@
|
||||
<javac destdir="${classes.dir}" debug="yes" target="1.5">
|
||||
<classpath refid="cobertura.classpath" />
|
||||
<classpath refid="wtk-libs" />
|
||||
<classpath path="${antlr.runtime.jar}"/>
|
||||
<src path="src/core"/>
|
||||
<src path="src/j2me"/>
|
||||
<src path="src/j2se"/>
|
||||
<src path="src/script"/>
|
||||
<src path="src/sample"/>
|
||||
<src path="src/test/java"/>
|
||||
<src path="src/jme"/>
|
||||
<src path="src/jse"/>
|
||||
<src path="test/junit"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
@@ -57,11 +62,16 @@
|
||||
<cobertura-instrument todir="${instrumented.dir}">
|
||||
<ignore regex="org.apache.log4j.*" />
|
||||
<fileset dir="${classes.dir}">
|
||||
<include name="org/luaj/vm/*.class" />
|
||||
<include name="org/luaj/lib/*.class" />
|
||||
<include name="org/luaj/compiler/*.class" />
|
||||
<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/luajc/antlr/*.class" />
|
||||
<include name="org/luaj/vm2/luajc/lst/*.class" />
|
||||
<include name="org/luaj/vm2/script/*.class" />
|
||||
<exclude name="**/*Test*.class" />
|
||||
<exclude name="org/luaj/vm/require/*.class" />
|
||||
</fileset>
|
||||
</cobertura-instrument>
|
||||
</target>
|
||||
@@ -74,11 +84,8 @@
|
||||
<classpath refid="cobertura.classpath" />
|
||||
<formatter type="xml" />
|
||||
<batchtest todir="${reports.xml.dir}">
|
||||
<fileset dir="src/test/java">
|
||||
<include name="org/luaj/compiler/*.java" />
|
||||
<include name="org/luaj/vm/*.java" />
|
||||
<exclude name="**/Abstract*.java" />
|
||||
<exclude name="**/StandardTest.java" />
|
||||
<fileset dir="test/junit">
|
||||
<include name="org/luaj/vm2/AllTests.java" />
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
|
||||
79
build.xml
79
build.xml
@@ -1,11 +1,20 @@
|
||||
<project default="all">
|
||||
<property file="version.properties"/>
|
||||
|
||||
<property name="jar.name.j2me" value="luaj-j2me-${version}.jar"/>
|
||||
<property name="jar.name.j2se" value="luaj-j2se-${version}.jar"/>
|
||||
|
||||
<property environment="env"/>
|
||||
|
||||
<property name="jar.name.jme" value="luaj-jme-${version}.jar"/>
|
||||
<property name="jar.name.jse" value="luaj-jse-${version}.jar"/>
|
||||
|
||||
<import file="wtk.xml"/>
|
||||
|
||||
<property name="antlr.version" value="3.1.3"/>
|
||||
<property name="antlr.home" value="${env.ANTLR_HOME}"/>
|
||||
<property name="antlr.tool.jar" value="${antlr.home}/lib/antlr-${antlr.version}.jar"/>
|
||||
<property name="antlr.runtime.jar" value="${antlr.home}/lib/antlr-runtime-${antlr.version}.jar"/>
|
||||
<property name="grammar.dir" value="src/jse/org/luaj/vm2/luajc/antlr"/>
|
||||
<property name="grammar.name" value="Lua"/>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="build"/>
|
||||
<delete>
|
||||
@@ -13,11 +22,25 @@
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<target name="generate">
|
||||
<fail unless="env.ANTLR_HOME" message="ANTLR_HOME must be set."/>
|
||||
<available file="${antlr.tool.jar}" property="antlr.tool.exists"/>
|
||||
<fail unless="antlr.tool.exists" message="ANTLR tool not found: ${antlr.tool.jar}"/>
|
||||
<echo>Generating files using ${antlr.tool.jar}</echo>
|
||||
<java classpath="${antlr.tool.jar}"
|
||||
classname="org.antlr.Tool"
|
||||
dir="${grammar.dir}"
|
||||
fork="true"
|
||||
failonerror="true">
|
||||
<arg line="${grammar.name}.g"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="wtk-or-fail">
|
||||
<mkdir dir="build/core/src"/>
|
||||
<mkdir dir="build/core/classes"/>
|
||||
<mkdir dir="build/j2me/classes"/>
|
||||
<mkdir dir="build/j2se/classes"/>
|
||||
<mkdir dir="build/jme/classes"/>
|
||||
<mkdir dir="build/jse/classes"/>
|
||||
<copy todir="build/core/src">
|
||||
<fileset dir="src/core"/>
|
||||
<filterchain>
|
||||
@@ -26,36 +49,32 @@
|
||||
</tokenfilter>
|
||||
</filterchain>
|
||||
</copy>
|
||||
<javac destdir="build/core/classes" encoding="utf-8" source="1.3" target="1.1" bootclasspathref="wtk-libs">
|
||||
<javac destdir="build/core/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs">
|
||||
<src path="build/core/src"/>
|
||||
</javac>
|
||||
<javac destdir="build/j2me/classes" encoding="utf-8" source="1.3" target="1.1" bootclasspathref="wtk-libs">
|
||||
<javac destdir="build/jme/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs">
|
||||
<classpath path="build/core/classes"/>
|
||||
<src path="src/j2me"/>
|
||||
<src path="src/jme"/>
|
||||
</javac>
|
||||
<javac destdir="build/j2se/classes" encoding="utf-8" source="1.3" target="1.3">
|
||||
<classpath path="build/core/classes"/>
|
||||
<src path="src/j2se"/>
|
||||
</javac>
|
||||
<javac destdir="build/j2se/classes" encoding="utf-8" source="1.5" target="1.5">
|
||||
<classpath path="build/core/classes"/>
|
||||
<src path="src/script"/>
|
||||
<javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5">
|
||||
<classpath path="build/core/classes;${antlr.runtime.jar}"/>
|
||||
<src path="src/jse"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="jar-j2me" depends="compile">
|
||||
<jar destfile="${jar.name.j2me}">
|
||||
<target name="jar-jme" depends="compile">
|
||||
<jar destfile="${jar.name.jme}">
|
||||
<fileset dir="build/core/classes"/>
|
||||
<fileset dir="build/j2me/classes"/>
|
||||
<fileset dir="build/jme/classes"/>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="jar-j2se" depends="compile">
|
||||
<jar destfile="${jar.name.j2se}">
|
||||
<target name="jar-jse" depends="compile">
|
||||
<jar destfile="${jar.name.jse}">
|
||||
<fileset dir="build/core/classes"/>
|
||||
<fileset dir="build/j2me/classes"/>
|
||||
<fileset dir="build/j2se/classes"/>
|
||||
<fileset dir="src/script">
|
||||
<fileset dir="build/jme/classes"/>
|
||||
<fileset dir="build/jse/classes"/>
|
||||
<fileset dir="src/jse/">
|
||||
<include name="META-INF/**"/>
|
||||
</fileset>
|
||||
</jar>
|
||||
@@ -64,7 +83,7 @@
|
||||
<target name="doc">
|
||||
<delete dir="docs/api"/>
|
||||
<mkdir dir="docs/api"/>
|
||||
<javadoc packagenames="org.luaj.vm.*"
|
||||
<javadoc packagenames="org.luaj.vm2.*"
|
||||
sourcepath="src/core"
|
||||
defaultexcludes="yes"
|
||||
destdir="docs/api"
|
||||
@@ -88,6 +107,12 @@
|
||||
<copy todir="build/luaj-${version}/src">
|
||||
<fileset dir="src"/>
|
||||
</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"/>
|
||||
@@ -100,11 +125,15 @@
|
||||
<include name="version.properties"/>
|
||||
<include name="wtk.xml"/>
|
||||
<include name="README.html"/>
|
||||
<include name="names.csv"/>
|
||||
<include name=".classpath"/>
|
||||
<include name=".project"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<zip destfile="luaj-${version}.zip"
|
||||
basedir="build" includes="luaj-${version}/**"/>
|
||||
</target>
|
||||
|
||||
<target name="all" depends="clean,jar-j2me,jar-j2se"/>
|
||||
<target name="all" depends="clean,jar-jme,jar-jse"/>
|
||||
|
||||
</project>
|
||||
|
||||
34
examples/jme/SampleMIDlet.java
Normal file
34
examples/jme/SampleMIDlet.java
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
import javax.microedition.midlet.MIDlet;
|
||||
import javax.microedition.midlet.MIDletStateChangeException;
|
||||
|
||||
import org.luaj.vm2.*;
|
||||
import org.luaj.vm2.lib.*;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
|
||||
|
||||
public class SampleMIDlet extends MIDlet {
|
||||
|
||||
// the script will be loaded as a resource
|
||||
private static final String DEFAULT_SCRIPT = "hello.lua";
|
||||
|
||||
protected void startApp() throws MIDletStateChangeException {
|
||||
// get the script as an app property
|
||||
String script = this.getAppProperty("script");
|
||||
if ( script == null )
|
||||
script = DEFAULT_SCRIPT;
|
||||
|
||||
// create an environment to run in
|
||||
LuaC.install();
|
||||
LuaValue _G = JmePlatform.standardGlobals();
|
||||
_G.get("dofile").call( LuaValue.valueOf(script) );
|
||||
}
|
||||
|
||||
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
|
||||
}
|
||||
|
||||
protected void pauseApp() {
|
||||
}
|
||||
|
||||
}
|
||||
20
examples/jse/SampleJseMain.java
Normal file
20
examples/jse/SampleJseMain.java
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
import org.luaj.vm2.*;
|
||||
import org.luaj.vm2.lib.*;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
|
||||
public class SampleJseMain {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String script = "examples/lua/hello.lua";
|
||||
|
||||
// create an environment to run in
|
||||
LuaC.install();
|
||||
LuaValue _G = JsePlatform.standardGlobals();
|
||||
_G.get("dofile").call( LuaValue.valueOf(script) );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
50
examples/jse/ScriptEngineSample.java
Normal file
50
examples/jse/ScriptEngineSample.java
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
public class ScriptEngineSample {
|
||||
|
||||
public static void main(String [] args) {
|
||||
ScriptEngineManager sem = new ScriptEngineManager();
|
||||
ScriptEngine e = sem.getEngineByExtension(".lua");
|
||||
ScriptEngineFactory f = e.getFactory();
|
||||
System.out.println( "Engine name: " +f.getEngineName() );
|
||||
System.out.println( "Engine Version: " +f.getEngineVersion() );
|
||||
System.out.println( "LanguageName: " +f.getLanguageName() );
|
||||
System.out.println( "Language Version: " +f.getLanguageVersion() );
|
||||
String statement = f.getOutputStatement("\"hello, world\"");
|
||||
System.out.println(statement);
|
||||
try {
|
||||
e.eval(statement);
|
||||
|
||||
e.put("x", 25);
|
||||
e.eval("y = math.sqrt(x)");
|
||||
System.out.println( "y="+e.get("y") );
|
||||
|
||||
e.put("x", 2);
|
||||
e.eval("y = math.sqrt(x)");
|
||||
System.out.println( "y="+e.get("y") );
|
||||
|
||||
CompiledScript cs = ((Compilable)e).compile("y = math.sqrt(x); return y");
|
||||
Bindings b = e.createBindings();
|
||||
b.put("x", 3);
|
||||
System.out.println( "eval: "+cs.eval(b) );
|
||||
System.out.println( "y="+b.get("y") );
|
||||
|
||||
try {
|
||||
e.eval("\n\nbogus example\n\n");
|
||||
} catch ( ScriptException se ) {
|
||||
System.out.println("script threw ScriptException as expected, message is '"+se.getMessage()+"'");
|
||||
}
|
||||
} catch (ScriptException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
1
examples/lua/hello.lua
Normal file
1
examples/lua/hello.lua
Normal file
@@ -0,0 +1 @@
|
||||
print( 'hello, world' )
|
||||
29
examples/lua/swingapp.lua
Normal file
29
examples/lua/swingapp.lua
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
frame = luajava.newInstance( "javax.swing.JFrame", "Texts" );
|
||||
pane = luajava.newInstance( "javax.swing.JPanel" );
|
||||
borderFactory = luajava.bindClass( "javax.swing.BorderFactory" )
|
||||
border = borderFactory:createEmptyBorder( 30, 30, 10, 30 )
|
||||
pane:setBorder( border )
|
||||
label = luajava.newInstance( "javax.swing.JLabel", "This is a Label" );
|
||||
|
||||
|
||||
layout = luajava.newInstance( "java.awt.GridLayout", 2, 2 );
|
||||
pane:setLayout( layout )
|
||||
pane:add( label )
|
||||
pane:setBounds( 20, 30, 10, 30 )
|
||||
|
||||
borderLayout = luajava.bindClass( "java.awt.BorderLayout" )
|
||||
frame:getContentPane():add(pane, borderLayout.CENTER )
|
||||
jframe = luajava.bindClass( "javax.swing.JFrame" )
|
||||
frame:setDefaultCloseOperation(jframe.EXIT_ON_CLOSE)
|
||||
frame:pack()
|
||||
frame:setVisible(true)
|
||||
|
||||
local listener = luajava.createProxy("java.awt.event.MouseListener",
|
||||
{
|
||||
mouseClicked = function(me)
|
||||
print("clicked!", me)
|
||||
end
|
||||
})
|
||||
|
||||
frame:addMouseListener(listener)
|
||||
89
names.csv
Normal file
89
names.csv
Normal file
@@ -0,0 +1,89 @@
|
||||
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
|
||||
,toString,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
|
||||
,optString,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
|
||||
,checkString,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
|
||||
|
95
src/core/org/luaj/vm2/Buffer.java
Normal file
95
src/core/org/luaj/vm2/Buffer.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
*/
|
||||
public class Buffer {
|
||||
private static final int DEFAULT_CAPACITY = 64;
|
||||
|
||||
private byte[] bytes;
|
||||
private int length;
|
||||
|
||||
public Buffer() {
|
||||
this(DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new LuaString(bytes, 0, length).toString();
|
||||
}
|
||||
|
||||
public Buffer( int initialCapacity ) {
|
||||
bytes = new byte[ initialCapacity ];
|
||||
length = 0;
|
||||
}
|
||||
|
||||
public void append( byte b ) {
|
||||
ensureCapacity( length + 1 );
|
||||
bytes[ length++ ] = b;
|
||||
}
|
||||
|
||||
public void append( LuaValue val ) {
|
||||
append( val.strvalue() );
|
||||
}
|
||||
|
||||
public void append( LuaString str ) {
|
||||
final int alen = str.length();
|
||||
ensureCapacity( length + alen );
|
||||
str.copyInto( 0, bytes, length, alen );
|
||||
length += alen;
|
||||
}
|
||||
|
||||
public void append( String str ) {
|
||||
char[] chars = str.toCharArray();
|
||||
final int alen = LuaString.lengthAsUtf8( chars );
|
||||
ensureCapacity( length + alen );
|
||||
LuaString.encodeToUtf8( chars, bytes, length );
|
||||
length += alen;
|
||||
}
|
||||
|
||||
public void setLength( int length ) {
|
||||
ensureCapacity( length );
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public LuaString tostrvalue() {
|
||||
return new LuaString( realloc( bytes, length ) );
|
||||
}
|
||||
|
||||
public void ensureCapacity( int minSize ) {
|
||||
if ( minSize > bytes.length )
|
||||
realloc( minSize );
|
||||
}
|
||||
|
||||
private void realloc( int minSize ) {
|
||||
bytes = realloc( bytes, Math.max( bytes.length * 2, minSize ) );
|
||||
}
|
||||
|
||||
private static byte[] realloc( byte[] b, int newSize ) {
|
||||
byte[] newBytes = new byte[ newSize ];
|
||||
System.arraycopy( b, 0, newBytes, 0, Math.min( b.length, newSize ) );
|
||||
return newBytes;
|
||||
}
|
||||
}
|
||||
316
src/core/org/luaj/vm2/LoadState.java
Normal file
316
src/core/org/luaj/vm2/LoadState.java
Normal file
@@ -0,0 +1,316 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/*
|
||||
** Loader to load compiled function prototypes
|
||||
*/
|
||||
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. */
|
||||
public interface LuaCompiler {
|
||||
public Prototype compile(int firstByte, InputStream stream, String name) 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];
|
||||
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
LuaString loadString() throws IOException {
|
||||
int size = loadInt();
|
||||
if ( size == 0 )
|
||||
return null;
|
||||
byte[] bytes = new byte[size];
|
||||
is.readFully( bytes, 0, size );
|
||||
return new LuaString( bytes, 0, bytes.length - 1 );
|
||||
}
|
||||
|
||||
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) );
|
||||
}
|
||||
|
||||
LuaValue loadNumber() throws IOException {
|
||||
if ( luacNumberFormat == NUMBER_FORMAT_INTS_ONLY ) {
|
||||
return LuaInteger.valueOf( loadInt() );
|
||||
} else {
|
||||
return longBitsToLuaNumber( loadInt64() );
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public static Prototype undump( InputStream stream, String name ) throws IOException {
|
||||
// check first byte to see if its a precompiled chunk
|
||||
int c = stream.read();
|
||||
if ( c != LUA_SIGNATURE[0] ) {
|
||||
if ( compiler != null )
|
||||
return compiler.compile(c, stream, name);
|
||||
throw new LuaError("no compiler");
|
||||
}
|
||||
|
||||
// check rest of signature
|
||||
for ( int i=1; i<4; i++ ) {
|
||||
if ( stream.read() != LUA_SIGNATURE[i] )
|
||||
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) );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
38
src/core/org/luaj/vm2/LocVars.java
Normal file
38
src/core/org/luaj/vm2/LocVars.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*******************************************************************************
|
||||
* 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 LocVars {
|
||||
public LuaString varname;
|
||||
public int startpc;
|
||||
public int endpc;
|
||||
|
||||
public LocVars(LuaString varname, int startpc, int endpc) {
|
||||
this.varname = varname;
|
||||
this.startpc = startpc;
|
||||
this.endpc = endpc;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return varname+" "+startpc+"-"+endpc;
|
||||
}
|
||||
}
|
||||
328
src/core/org/luaj/vm2/Lua.java
Normal file
328
src/core/org/luaj/vm2/Lua.java
Normal file
@@ -0,0 +1,328 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* Constants for lua limits and opcodes
|
||||
* @deprecatd these will all move to LuaC or LoadState or DumpState
|
||||
*/
|
||||
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;
|
||||
|
||||
/*===========================================================================
|
||||
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;
|
||||
|
||||
}
|
||||
73
src/core/org/luaj/vm2/LuaBoolean.java
Normal file
73
src/core/org/luaj/vm2/LuaBoolean.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* 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 LuaBoolean extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean booleanValue() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public boolean toboolean() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return v ? "true" : "false";
|
||||
}
|
||||
|
||||
public boolean optboolean(boolean defval) {
|
||||
return this.v;
|
||||
}
|
||||
|
||||
public boolean checkboolean() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
return s_metatable;
|
||||
}
|
||||
}
|
||||
491
src/core/org/luaj/vm2/LuaClosure.java
Normal file
491
src/core/org/luaj/vm2/LuaClosure.java
Normal file
@@ -0,0 +1,491 @@
|
||||
/*******************************************************************************
|
||||
* 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.DebugLib;
|
||||
|
||||
public class LuaClosure extends LuaFunction {
|
||||
private static final UpValue[] NOUPVALUES = new UpValue[0];
|
||||
|
||||
public LuaValue s_metatable;
|
||||
|
||||
public final Prototype p;
|
||||
public final UpValue[] upValues;
|
||||
private UpValue openUpValues = null;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
private final 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;
|
||||
|
||||
// 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.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;
|
||||
{
|
||||
Buffer sb = new Buffer();
|
||||
for ( ; b<=c; )
|
||||
sb.append( stack[b++].checkstring() );
|
||||
stack[a] = sb.tostrvalue();
|
||||
}
|
||||
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 | Lua.MASK_C) ) {
|
||||
case (1<<Lua.POS_B) | (0<<Lua.POS_C): return stack[a].invoke(NONE);
|
||||
case (2<<Lua.POS_B) | (0<<Lua.POS_C): return stack[a].invoke(stack[a+1]);
|
||||
case (1<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(); return NONE;
|
||||
case (2<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1]); return NONE;
|
||||
case (3<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2]); return NONE;
|
||||
case (4<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2],stack[a+3]); return NONE;
|
||||
case (1<<Lua.POS_B) | (2<<Lua.POS_C): return stack[a].call();
|
||||
case (2<<Lua.POS_B) | (2<<Lua.POS_C): return stack[a].call(stack[a+1]);
|
||||
case (3<<Lua.POS_B) | (2<<Lua.POS_C): return stack[a].call(stack[a+1],stack[a+2]);
|
||||
case (4<<Lua.POS_B) | (2<<Lua.POS_C): return stack[a].call(stack[a+1],stack[a+2],stack[a+3]);
|
||||
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
|
||||
switch ( c ) {
|
||||
case 1: stack[a].invoke(v); return NONE;
|
||||
case 2: return stack[a].invoke(v).arg1();
|
||||
default: return stack[a].invoke(v);
|
||||
}
|
||||
}
|
||||
|
||||
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||
closeUpValues();
|
||||
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();
|
||||
LuaValue limit = stack[a + 1].checknumber();
|
||||
LuaValue step = stack[a + 2].checknumber();
|
||||
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)*/
|
||||
closeUpValues( a );
|
||||
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]:
|
||||
findUpValue(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 ) {
|
||||
if ( p.lineinfo!=null && p.lineinfo.length>=pc )
|
||||
le.addTracebackLine(p.source+":"+p.lineinfo[pc-1]);
|
||||
throw le;
|
||||
} catch ( Throwable t ) {
|
||||
LuaError le = new LuaError(t);
|
||||
if ( p.lineinfo!=null && p.lineinfo.length>=pc )
|
||||
le.addTracebackLine(p.source+":"+p.lineinfo[pc-1]);
|
||||
throw le;
|
||||
} finally {
|
||||
LuaThread.onReturn();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: inline, optimize when targs come in ascending order?
|
||||
UpValue findUpValue(LuaValue[] stack, int target) {
|
||||
UpValue prev=null,up=openUpValues;
|
||||
while ( up != null ) {
|
||||
if (up.index == target) {
|
||||
return up;
|
||||
} else if (up.index < target) {
|
||||
break;
|
||||
}
|
||||
up = (prev=up).next;
|
||||
}
|
||||
up = new UpValue(stack, target, up);
|
||||
if ( prev!=null )
|
||||
prev.next = up;
|
||||
else
|
||||
this.openUpValues = up;
|
||||
return up;
|
||||
}
|
||||
|
||||
// TODO: inline?
|
||||
void closeUpValues(int limit) {
|
||||
UpValue prev=null,up=openUpValues;
|
||||
while ( up != null ) {
|
||||
UpValue next = up.next;
|
||||
if ( up.close(limit) ) {
|
||||
if ( prev==null )
|
||||
this.openUpValues = up.next;
|
||||
else
|
||||
prev.next = up.next;
|
||||
up.next = null;
|
||||
} else {
|
||||
prev = up;
|
||||
}
|
||||
up = next;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: inline?
|
||||
void closeUpValues() {
|
||||
UpValue up=openUpValues;
|
||||
while ( up != null ) {
|
||||
UpValue next = up.next;
|
||||
up.close(-1);
|
||||
up.next = null;
|
||||
up = next;
|
||||
}
|
||||
openUpValues = null;
|
||||
}
|
||||
|
||||
}
|
||||
192
src/core/org/luaj/vm2/LuaDouble.java
Normal file
192
src/core/org/luaj/vm2/LuaDouble.java
Normal file
@@ -0,0 +1,192 @@
|
||||
/*******************************************************************************
|
||||
* 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.Hashtable;
|
||||
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
|
||||
public class LuaDouble extends LuaNumber {
|
||||
|
||||
public static final LuaDouble NAN = new LuaDouble( Double.NaN );
|
||||
public static final LuaDouble POSINF = new LuaDouble( Double.POSITIVE_INFINITY );
|
||||
public static final LuaDouble NEGINF = new LuaDouble( Double.NEGATIVE_INFINITY );
|
||||
|
||||
private static Hashtable ALIASES = new Hashtable();
|
||||
static {
|
||||
ALIASES.put( "NaN", "nan" );
|
||||
ALIASES.put( "Infinity", "inf" );
|
||||
ALIASES.put( "-Infinity", "-inf" );
|
||||
}
|
||||
|
||||
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() {
|
||||
return (int) Double.doubleToLongBits(v);
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
// arithmetic equality
|
||||
public boolean eq_b( LuaValue rhs ) { return rhs.eq_b(v); }
|
||||
public boolean eq_b( double rhs ) { return v == rhs; }
|
||||
public boolean eq_b( int rhs ) { return v == rhs; }
|
||||
|
||||
// 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 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 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 divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
|
||||
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
|
||||
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
|
||||
|
||||
/** lua division is always double, specific values for singularities */
|
||||
public static LuaValue ddiv(double lhs, double rhs) {
|
||||
return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF;
|
||||
}
|
||||
|
||||
/** lua module is always wrt double. */
|
||||
public static LuaValue dmod(double lhs, double rhs) {
|
||||
return rhs!=0? valueOf( lhs-rhs*Math.floor(lhs/rhs) ): NAN;
|
||||
}
|
||||
|
||||
// relational operators
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.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 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 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 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; }
|
||||
|
||||
// concatenation
|
||||
public String concat_s(LuaValue rhs) { return rhs.concatTo_s(Double.toString(v)); }
|
||||
public String concatTo_s(String lhs) { return lhs + v; }
|
||||
|
||||
public String toString() {
|
||||
/*
|
||||
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);
|
||||
String s = Double.toString(v);
|
||||
Object n = ALIASES.get(s);
|
||||
return n!=null? (String)n: s;
|
||||
}
|
||||
|
||||
public LuaString strvalue() {
|
||||
return LuaString.valueOf(toString());
|
||||
}
|
||||
|
||||
public LuaString optstring(LuaString defval) {
|
||||
return LuaString.valueOf(toString());
|
||||
}
|
||||
|
||||
public String optString(String defval) {
|
||||
long l = (long)v;
|
||||
return v==l? Long.toString(l): Double.toString(v);
|
||||
}
|
||||
|
||||
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 checkString() {
|
||||
return toString();
|
||||
}
|
||||
public LuaString checkstring() {
|
||||
return LuaString.valueOf(toString());
|
||||
}
|
||||
|
||||
}
|
||||
98
src/core/org/luaj/vm2/LuaError.java
Normal file
98
src/core/org/luaj/vm2/LuaError.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* RuntimeException that is thrown and caught in response to a lua error.
|
||||
* This error does not indicate any problem with the normal functioning
|
||||
* of the Lua VM, but rather indicates that the lua script being interpreted
|
||||
* has encountered a lua error, eigher via LuaState.error() or lua error() calls.
|
||||
*
|
||||
*/
|
||||
public class LuaError extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private LuaValue msgvalue = null;
|
||||
private Vector traceback = null;
|
||||
|
||||
/** Run the error hook if there is one */
|
||||
private static String errorHook(String msg) {
|
||||
LuaThread thread = LuaThread.getRunning();
|
||||
if ( thread.err != null ) {
|
||||
try {
|
||||
return thread.err.call( LuaValue.valueOf(msg) ).toString();
|
||||
} catch ( Throwable t ) {
|
||||
return "error in error handling";
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a LuaErrorException in response to a Throwable that was caught
|
||||
* indicating a problem with the VM rather than the lua code.
|
||||
*
|
||||
* All errors generated from lua code should throw LuaError(String) instead.
|
||||
*/
|
||||
public LuaError(Throwable cause) {
|
||||
this( errorHook( "vm error: "+cause ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a LuaError with a specific message indicating a problem
|
||||
* within the lua code itself such as an argument type error.
|
||||
*
|
||||
* @param message message to supply
|
||||
*/
|
||||
public LuaError(String message) {
|
||||
super( errorHook( message ) );
|
||||
}
|
||||
|
||||
/** Get the message, including source line info if there is any */
|
||||
public String getMessage() {
|
||||
String msg = super.getMessage();
|
||||
return msg!=null && traceback!=null? traceback.elementAt(0)+": "+msg: msg;
|
||||
}
|
||||
|
||||
/** Add a line of traceback info */
|
||||
public void addTracebackLine( String line ) {
|
||||
if ( traceback == null ) {
|
||||
traceback = new Vector();
|
||||
}
|
||||
traceback.addElement( line );
|
||||
}
|
||||
|
||||
/** Print the message and stack trace */
|
||||
public void printStackTrace() {
|
||||
System.out.println( toString() );
|
||||
if ( traceback != null ) {
|
||||
for ( int i=0,n=traceback.size(); i<n; i++ ) {
|
||||
System.out.print("\t");
|
||||
System.out.println(traceback.elementAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
72
src/core/org/luaj/vm2/LuaFunction.java
Normal file
72
src/core/org/luaj/vm2/LuaFunction.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
abstract
|
||||
public class LuaFunction extends LuaValue {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
167
src/core/org/luaj/vm2/LuaInteger.java
Normal file
167
src/core/org/luaj/vm2/LuaInteger.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public final int v;
|
||||
|
||||
/** package protected constructor, @see IntValue.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 toString() {
|
||||
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 String optString(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; }
|
||||
|
||||
// arithmetic equality
|
||||
public boolean eq_b( LuaValue rhs ) { return rhs.eq_b(v); }
|
||||
public boolean eq_b( double rhs ) { return v == rhs; }
|
||||
public boolean eq_b( int rhs ) { return v == rhs; }
|
||||
|
||||
// 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 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 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 divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
|
||||
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
|
||||
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
|
||||
|
||||
// relational operators
|
||||
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.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 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 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 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; }
|
||||
|
||||
// concatenation
|
||||
public String concat_s(LuaValue rhs) { return rhs.concatTo_s(Integer.toString(v)); }
|
||||
public String concatTo_s(String lhs) { return lhs + v; }
|
||||
|
||||
public int checkint() {
|
||||
return v;
|
||||
}
|
||||
public long checklong() {
|
||||
return v;
|
||||
}
|
||||
public double checkdouble() {
|
||||
return v;
|
||||
}
|
||||
public String checkString() {
|
||||
return String.valueOf(v);
|
||||
}
|
||||
public LuaString checkstring() {
|
||||
return valueOf( String.valueOf(v) );
|
||||
}
|
||||
|
||||
}
|
||||
82
src/core/org/luaj/vm2/LuaNil.java
Normal file
82
src/core/org/luaj/vm2/LuaNil.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*******************************************************************************
|
||||
* 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 LuaNil extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
LuaNil() {}
|
||||
|
||||
public int type() {
|
||||
return LuaValue.TNIL;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "nil";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
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 typerror("value");
|
||||
}
|
||||
|
||||
// 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 optString(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; }
|
||||
}
|
||||
61
src/core/org/luaj/vm2/LuaNumber.java
Normal file
61
src/core/org/luaj/vm2/LuaNumber.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
abstract
|
||||
public class LuaNumber extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
public int type() {
|
||||
return TNUMBER;
|
||||
}
|
||||
|
||||
public String typename() {
|
||||
return "number";
|
||||
}
|
||||
|
||||
public LuaNumber checknumber() {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
473
src/core/org/luaj/vm2/LuaString.java
Normal file
473
src/core/org/luaj/vm2/LuaString.java
Normal file
@@ -0,0 +1,473 @@
|
||||
/*******************************************************************************
|
||||
* 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.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.lib.MathLib;
|
||||
import org.luaj.vm2.lib.StringLib;
|
||||
|
||||
public class LuaString extends LuaValue {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
public final byte[] m_bytes;
|
||||
public final int m_offset;
|
||||
public final int m_length;
|
||||
|
||||
public static LuaString valueOf(String string) {
|
||||
char[] c = string.toCharArray();
|
||||
byte[] b = new byte[lengthAsUtf8(c)];
|
||||
encodeToUtf8(c, b, 0);
|
||||
return new LuaString(b);
|
||||
}
|
||||
|
||||
public LuaString(byte[] bytes, int offset, int length) {
|
||||
this.m_bytes = bytes;
|
||||
this.m_offset = offset;
|
||||
this.m_length = length;
|
||||
}
|
||||
|
||||
public LuaString(byte[] bytes) {
|
||||
this.m_bytes = bytes;
|
||||
this.m_offset = 0;
|
||||
this.m_length = bytes.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 toString() {
|
||||
return decodeAsUtf8(m_bytes, m_offset, m_length);
|
||||
}
|
||||
|
||||
// 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() { return checkarith().neg(); }
|
||||
|
||||
// basic binary arithmetic
|
||||
public LuaValue add( LuaValue rhs ) { return checkarith().add(rhs); }
|
||||
public LuaValue add( double lhs ) { return checkarith().add(lhs); }
|
||||
public LuaValue sub( LuaValue rhs ) { return checkarith().sub(rhs); }
|
||||
public LuaValue subFrom( double lhs ) { return checkarith().subFrom(lhs); }
|
||||
public LuaValue mul( LuaValue rhs ) { return checkarith().mul(rhs); }
|
||||
public LuaValue mul( double lhs ) { return checkarith().mul(lhs); }
|
||||
public LuaValue mul( int lhs ) { return checkarith().mul(lhs); }
|
||||
public LuaValue pow( LuaValue rhs ) { return checkarith().pow(rhs); }
|
||||
public LuaValue powWith( double lhs ) { return checkarith().powWith(lhs); }
|
||||
public LuaValue powWith( int lhs ) { return checkarith().powWith(lhs); }
|
||||
public LuaValue div( LuaValue rhs ) { return checkarith().div(rhs); }
|
||||
public LuaValue divInto( double lhs ) { return checkarith().divInto(lhs); }
|
||||
public LuaValue mod( LuaValue rhs ) { return checkarith().mod(rhs); }
|
||||
public LuaValue modFrom( double lhs ) { return checkarith().modFrom(lhs); }
|
||||
|
||||
// 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 String concat_s(LuaValue rhs) { return rhs.concatTo_s(toString()); }
|
||||
public String concatTo_s(String lhs) { return lhs + toString(); }
|
||||
|
||||
// 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 LuaValue checkarith() {
|
||||
LuaValue v = tonumber(10);
|
||||
return v.isnil()? aritherror(): v;
|
||||
}
|
||||
|
||||
public int checkint() {
|
||||
return checknumber().toint();
|
||||
}
|
||||
public LuaInteger checkinteger() {
|
||||
return checknumber().checkinteger();
|
||||
}
|
||||
public long checklong() {
|
||||
return checknumber().tolong();
|
||||
}
|
||||
public double checkdouble() {
|
||||
return checknumber().todouble();
|
||||
}
|
||||
public LuaNumber checknumber() {
|
||||
LuaValue n = tonumber(10);
|
||||
if ( ! n.isnumber() )
|
||||
typerror("number");
|
||||
return (LuaNumber) n;
|
||||
}
|
||||
public LuaValue tonumber() {
|
||||
return tonumber(10);
|
||||
}
|
||||
|
||||
public boolean isnumber() {
|
||||
return ! tonumber(10).isnil();
|
||||
}
|
||||
|
||||
public boolean isint() {
|
||||
return tonumber(10).isint();
|
||||
}
|
||||
|
||||
public boolean islong() {
|
||||
return tonumber(10).islong();
|
||||
}
|
||||
|
||||
public byte tobyte() { return (byte) toint(); }
|
||||
public char tochar() { return (char) toint(); }
|
||||
public double todouble() { LuaValue n=tonumber(10); return n.isnil()? 0: n.todouble(); }
|
||||
public float tofloat() { return (float) todouble(); }
|
||||
public int toint() { LuaValue n=tonumber(10); return n.isnil()? 0: n.toint(); }
|
||||
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 String optString(String defval) {
|
||||
return toString();
|
||||
}
|
||||
|
||||
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 ) {
|
||||
LuaString s = (LuaString) o;
|
||||
if ( s.m_length != m_length )
|
||||
return false;
|
||||
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;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean eq_b( LuaValue val ) {
|
||||
return equals( val );
|
||||
}
|
||||
|
||||
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 checkString() {
|
||||
return toString();
|
||||
}
|
||||
|
||||
public LuaString checkstring() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public InputStream toInputStream() {
|
||||
return new ByteArrayInputStream(m_bytes, m_offset, m_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the bytes of the string into the given byte array.
|
||||
*/
|
||||
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, which is a terribly named C function. */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 ) ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 ) ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// --------------------- utf8 conversion -------------------------
|
||||
|
||||
/**
|
||||
* Convert to Java String interpreting as utf8 characters
|
||||
*/
|
||||
public static String decodeAsUtf8(byte[] bytes, int offset, int length) {
|
||||
int i,j,n,b;
|
||||
for ( i=offset,j=offset+length,n=0; i<j; ++n ) {
|
||||
switch ( 0xC0 & 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.
|
||||
*/
|
||||
public static int lengthAsUtf8(char[] chars) {
|
||||
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. The string should be measured first with lengthAsUtf8
|
||||
* to make sure the given byte array is large enough.
|
||||
*/
|
||||
public static void encodeToUtf8(char[] chars, byte[] bytes, int off) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------- number conversion -----------------------
|
||||
|
||||
/**
|
||||
* convert to a number using a supplied base, or NIL if it can't be converted
|
||||
* @return IntValue, DoubleValue, or NIL depending on the content of the string.
|
||||
*/
|
||||
public LuaValue tonumber( 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 FALSE;
|
||||
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;
|
||||
}
|
||||
LuaValue l = scanlong( base, i, j );
|
||||
return l!=NIL? l: base==10? scandouble(i,j): NIL;
|
||||
}
|
||||
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan and convert a long value, or return NIL if not found.
|
||||
* @return DoubleValue, IntValue, or NIL depending on what is found.
|
||||
*/
|
||||
private LuaValue 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 NIL;
|
||||
x = x * base + digit;
|
||||
}
|
||||
return valueOf(neg? -x: x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan and convert a double value, or return NIL if not a double.
|
||||
* @return DoubleValue, IntValue, or NIL depending on what is found.
|
||||
*/
|
||||
private LuaValue 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 NIL;
|
||||
}
|
||||
}
|
||||
char [] c = new char[end-start];
|
||||
for ( int i=start; i<end; i++ )
|
||||
c[i-start] = (char) m_bytes[i];
|
||||
try {
|
||||
return valueOf( Double.parseDouble(new String(c)));
|
||||
} catch ( Exception e ) {
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
}
|
||||
559
src/core/org/luaj/vm2/LuaTable.java
Normal file
559
src/core/org/luaj/vm2/LuaTable.java
Normal file
@@ -0,0 +1,559 @@
|
||||
/*******************************************************************************
|
||||
* 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 LuaTable extends LuaValue {
|
||||
private static final int MIN_HASH_CAPACITY = 2;
|
||||
private static final LuaString N = valueOf("n");
|
||||
|
||||
protected LuaValue[] array;
|
||||
protected LuaValue[] hashKeys;
|
||||
protected LuaValue[] hashValues;
|
||||
private int hashEntries;
|
||||
private LuaValue m_metatable;
|
||||
|
||||
public LuaTable() {
|
||||
array = NOVALS;
|
||||
hashKeys = NOVALS;
|
||||
hashValues = NOVALS;
|
||||
}
|
||||
|
||||
public LuaTable(int narray, int nhash) {
|
||||
presize(narray, nhash);
|
||||
}
|
||||
|
||||
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++ )
|
||||
array[i] = unnamed[i].optvalue(null);
|
||||
if ( lastarg != null )
|
||||
for ( int i=0,n=lastarg.narg(); i<n; ++i )
|
||||
array[nu+i] = lastarg.arg(i+1).optvalue(null);
|
||||
for ( int i=0; i<nn; i+=2 )
|
||||
if (!named[i+1].isnil())
|
||||
rawset(named[i], named[i+1]);
|
||||
}
|
||||
|
||||
|
||||
public LuaTable(Varargs varargs) {
|
||||
int n = varargs.narg();
|
||||
presize( n, 1 );
|
||||
set(N, valueOf(n));
|
||||
for ( int i=1; i<=n; i++ )
|
||||
set(i, varargs.arg(i));
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
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 i ) {
|
||||
if ( i > array.length )
|
||||
array = resize( array, i );
|
||||
}
|
||||
|
||||
private static LuaValue[] resize( LuaValue[] old, int n ) {
|
||||
LuaValue[] v = new LuaValue[n];
|
||||
System.arraycopy(old, 0, v, 0, old.length);
|
||||
return v;
|
||||
}
|
||||
|
||||
public LuaValue getmetatable() {
|
||||
if ( m_metatable!=null )
|
||||
return m_metatable.rawget(METATABLE).optvalue(m_metatable);
|
||||
return m_metatable;
|
||||
}
|
||||
|
||||
public LuaValue setmetatable(LuaValue metatable) {
|
||||
if ( m_metatable!=null && !m_metatable.rawget(METATABLE).isnil() )
|
||||
error("cannot change a protected metatable");
|
||||
m_metatable = metatable;
|
||||
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 );
|
||||
}
|
||||
|
||||
private 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.checknotnil();
|
||||
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 );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Varargs remove(int pos) {
|
||||
if ( pos == 0 )
|
||||
pos = length();
|
||||
if ( pos < 1 || pos > array.length )
|
||||
return NONE;
|
||||
LuaValue v = rawget(pos);
|
||||
for ( LuaValue r=v; !r.isnil(); ) {
|
||||
r = rawget(pos+1);
|
||||
rawset(pos++, r);
|
||||
}
|
||||
return v.isnil()? NONE: v;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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.tostrvalue();
|
||||
}
|
||||
|
||||
public LuaValue getn() {
|
||||
for ( int n=array.length; --n>0; )
|
||||
if ( array[n]!=null )
|
||||
return LuaInteger.valueOf(n+1);
|
||||
return ZERO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of this table, as lua defines it.
|
||||
*/
|
||||
public int length() {
|
||||
int n=array.length+1,m=0;
|
||||
while ( !rawget(n).isnil() ) {
|
||||
m = n;
|
||||
n += array.length+hashEntries+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());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 nil
|
||||
*/
|
||||
public Varargs inext(LuaValue key) {
|
||||
int i = key.optint(0);
|
||||
return i<0 || i>=array.length || array[i]==null?
|
||||
NIL:
|
||||
varargsOf(LuaInteger.valueOf(i+1),array[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the supplied function once for each key-value pair
|
||||
*
|
||||
* @param func function to call
|
||||
*/
|
||||
public LuaValue foreach(LuaValue func) {
|
||||
LuaValue v = NIL;
|
||||
for ( int i=0; i<array.length; i++ )
|
||||
if ( array[i] != null )
|
||||
if ( !(v = func.call(LuaInteger.valueOf(i+1), array[i])).isnil() )
|
||||
return v;
|
||||
for ( int i=0; i<hashKeys.length; i++ )
|
||||
if ( hashKeys[i] != null )
|
||||
if ( !(v = func.call(hashKeys[i], hashValues[i])).isnil() )
|
||||
return v;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the supplied function once for each key-value pair
|
||||
* in the contiguous array part
|
||||
*
|
||||
* @param func
|
||||
*/
|
||||
public LuaValue foreachi(LuaValue func) {
|
||||
LuaValue v = NIL;
|
||||
for ( int i=0; i<array.length && array[i]!=null; i++ )
|
||||
if ( !(v = func.call(LuaInteger.valueOf(i+1), array[i])).isnil() )
|
||||
return v;
|
||||
return v;
|
||||
}
|
||||
|
||||
// ======================= test hooks =================
|
||||
|
||||
/** Value used in testing to provide the capacity of the array part */
|
||||
int arrayCapacity() {
|
||||
return array.length;
|
||||
}
|
||||
|
||||
/** Value used in testing to provide the capacity of the hash part */
|
||||
int hashCapacity() {
|
||||
return hashKeys.length;
|
||||
}
|
||||
|
||||
/** Value used in testing to provide the total count of elements */
|
||||
int keyCount() {
|
||||
int n = 0;
|
||||
for ( int i=0; i<array.length; i++ )
|
||||
if ( array[i] != null )
|
||||
++n;
|
||||
return n + hashEntries;
|
||||
}
|
||||
|
||||
/** Value used in testing to enumerate the keys */
|
||||
public LuaValue[] keys() {
|
||||
LuaValue[] vals = new LuaValue[keyCount()];
|
||||
int n = 0;
|
||||
for ( int i=0; i<array.length; i++ )
|
||||
if ( array[i] != null )
|
||||
vals[n++] = LuaInteger.valueOf(i+1);
|
||||
for ( int i=0; i<hashKeys.length; i++ )
|
||||
if ( hashKeys[i] != null )
|
||||
vals[n++] = hashKeys[i];
|
||||
return vals;
|
||||
}
|
||||
|
||||
// ======================= hashset =================
|
||||
|
||||
public void hashset(LuaValue key, LuaValue value) {
|
||||
if ( value.isnil() )
|
||||
hashRemove(key);
|
||||
else {
|
||||
if ( checkLoadFactor() )
|
||||
rehash();
|
||||
|
||||
int slot = hashFindSlot( key );
|
||||
if ( hashFillSlot( slot, value ) )
|
||||
return;
|
||||
hashKeys[slot] = key;
|
||||
hashValues[slot] = value;
|
||||
}
|
||||
}
|
||||
|
||||
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.eq_b(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 );
|
||||
}
|
||||
}
|
||||
|
||||
private 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+1 >= (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.
|
||||
//
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
225
src/core/org/luaj/vm2/LuaThread.java
Normal file
225
src/core/org/luaj/vm2/LuaThread.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2;
|
||||
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of lua coroutines using Java Threads
|
||||
*/
|
||||
public class LuaThread extends LuaValue implements Runnable {
|
||||
|
||||
public static LuaValue s_metatable;
|
||||
|
||||
private static final int STATUS_SUSPENDED = 0;
|
||||
private static final int STATUS_RUNNING = 1;
|
||||
private static final int STATUS_NORMAL = 2;
|
||||
private static final int STATUS_DEAD = 3;
|
||||
private static final String[] STATUS_NAMES = {
|
||||
"suspended",
|
||||
"running",
|
||||
"normal",
|
||||
"dead" };
|
||||
|
||||
private int status = STATUS_SUSPENDED;
|
||||
|
||||
private Thread thread;
|
||||
private LuaValue env;
|
||||
private LuaValue func;
|
||||
private Varargs args;
|
||||
public LuaValue err;
|
||||
|
||||
|
||||
public static final int MAX_CALLSTACK = 64;
|
||||
public final LuaFunction[] callstack = new LuaFunction[MAX_CALLSTACK];
|
||||
public int calls = 0;
|
||||
|
||||
private static final LuaThread mainthread = new LuaThread();
|
||||
|
||||
// state of running thread including call stack
|
||||
private static LuaThread running_thread = mainthread;
|
||||
|
||||
// thread-local used by DebugLib to store debugging state
|
||||
public Object debugState;
|
||||
|
||||
|
||||
LuaThread() {
|
||||
}
|
||||
|
||||
public LuaThread(LuaValue func, LuaValue env) {
|
||||
this.env = env;
|
||||
this.func = 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[status];
|
||||
}
|
||||
|
||||
public static LuaThread getRunning() {
|
||||
return running_thread;
|
||||
}
|
||||
|
||||
public static boolean isMainThread(LuaThread r) {
|
||||
return r == mainthread;
|
||||
}
|
||||
|
||||
/** get environment of the running thread, or defval if not defined */
|
||||
public static LuaValue getRunningEnv(LuaValue defval) {
|
||||
return running_thread.env!=null? running_thread.env: defval;
|
||||
}
|
||||
|
||||
public static final void onCall(LuaFunction function) {
|
||||
running_thread.callstack[running_thread.calls++] = function;
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugOnCall(running_thread, running_thread.calls, function);
|
||||
}
|
||||
|
||||
public static final void onReturn() {
|
||||
running_thread.callstack[--running_thread.calls] = null;
|
||||
if (DebugLib.DEBUG_ENABLED)
|
||||
DebugLib.debugOnReturn(running_thread, running_thread.calls);
|
||||
}
|
||||
|
||||
public static int getCallstackDepth() {
|
||||
return running_thread.calls;
|
||||
}
|
||||
|
||||
public static final LuaFunction getCallstackFunction(int level) {
|
||||
return level>=0 || level<running_thread.calls?
|
||||
running_thread.callstack[running_thread.calls-level-1]:
|
||||
null;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
synchronized ( this ) {
|
||||
try {
|
||||
this.args = func.invoke(this.args);
|
||||
} finally {
|
||||
status = STATUS_DEAD;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Varargs yield(Varargs args) {
|
||||
synchronized ( this ) {
|
||||
if ( status != STATUS_RUNNING )
|
||||
error(this+" not running");
|
||||
status = STATUS_SUSPENDED;
|
||||
this.args = args;
|
||||
this.notify();
|
||||
try {
|
||||
this.wait();
|
||||
status = STATUS_RUNNING;
|
||||
return this.args;
|
||||
} catch ( InterruptedException e ) {
|
||||
status = STATUS_DEAD;
|
||||
error( "thread interrupted" );
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Start or resume this thread */
|
||||
public Varargs resume(Varargs args) {
|
||||
|
||||
synchronized ( this ) {
|
||||
if ( status == STATUS_DEAD ) {
|
||||
return varargsOf(FALSE, valueOf("cannot resume dead coroutine"));
|
||||
}
|
||||
|
||||
// set prior thread to normal status while we are running
|
||||
LuaThread prior = running_thread;
|
||||
try {
|
||||
// set our status to running
|
||||
prior.status = STATUS_NORMAL;
|
||||
running_thread = this;
|
||||
this.status = STATUS_RUNNING;
|
||||
|
||||
// copy args in
|
||||
this.args = args;
|
||||
|
||||
// start the thread
|
||||
if ( thread == null ) {
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
// run this vm until it yields
|
||||
this.notify();
|
||||
this.wait();
|
||||
|
||||
// copy return values from yielding stack state
|
||||
return varargsOf(LuaValue.TRUE, this.args);
|
||||
|
||||
} catch ( Throwable t ) {
|
||||
status = STATUS_DEAD;
|
||||
try {
|
||||
return varargsOf(FALSE, valueOf("thread: "+t));
|
||||
} finally {
|
||||
this.notify();
|
||||
}
|
||||
|
||||
} finally {
|
||||
// previous thread is now running again
|
||||
running_thread = prior;
|
||||
prior.status = STATUS_RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
105
src/core/org/luaj/vm2/LuaUserdata.java
Normal file
105
src/core/org/luaj/vm2/LuaUserdata.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*******************************************************************************
|
||||
* 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 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 ( ! (val instanceof LuaUserdata) )
|
||||
return false;
|
||||
LuaUserdata u = (LuaUserdata) val;
|
||||
return m_instance.equals(u.m_instance);
|
||||
}
|
||||
|
||||
public boolean eq_b( LuaValue val ) {
|
||||
return equals(val);
|
||||
}
|
||||
|
||||
}
|
||||
500
src/core/org/luaj/vm2/LuaValue.java
Normal file
500
src/core/org/luaj/vm2/LuaValue.java
Normal file
@@ -0,0 +1,500 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
|
||||
abstract
|
||||
public class LuaValue extends Varargs {
|
||||
|
||||
public static final int TINT = (-2);
|
||||
public static final int TNONE = (-1);
|
||||
public static final int TNIL = 0;
|
||||
public static final int TBOOLEAN = 1;
|
||||
public static final int TLIGHTUSERDATA = 2;
|
||||
public static final int TNUMBER = 3;
|
||||
public static final int TSTRING = 4;
|
||||
public static final int TTABLE = 5;
|
||||
public static final int TFUNCTION = 6;
|
||||
public static final int TUSERDATA = 7;
|
||||
public static final int TTHREAD = 8;
|
||||
public static final int TVALUE = 9;
|
||||
|
||||
public static final String[] TYPE_NAMES = {
|
||||
"nil",
|
||||
"boolean",
|
||||
"lightuserdata",
|
||||
"number",
|
||||
"string",
|
||||
"table",
|
||||
"function",
|
||||
"userdata",
|
||||
"thread",
|
||||
"value",
|
||||
};
|
||||
|
||||
public static final LuaValue NIL = new LuaNil();
|
||||
public static final LuaBoolean TRUE = new LuaBoolean(true);
|
||||
public static final LuaBoolean FALSE = new LuaBoolean(false);
|
||||
public static final LuaValue NONE = new None();
|
||||
public static final LuaNumber ZERO = LuaInteger.valueOf(0);
|
||||
public static final LuaNumber ONE = LuaInteger.valueOf(1);
|
||||
public static final LuaNumber MINUSONE = LuaInteger.valueOf(-1);
|
||||
public static final LuaValue[] NOVALS = {};
|
||||
|
||||
public static final LuaString INDEX = valueOf("__index");
|
||||
public static final LuaString NEWINDEX = valueOf("__newindex");
|
||||
public static final LuaString CALL = valueOf("__call");
|
||||
public static final LuaString MODE = valueOf("__mode");
|
||||
public static final LuaString METATABLE = valueOf("__metatable");
|
||||
public static final LuaString EMPTYSTRING = valueOf("");
|
||||
|
||||
private static int MAXLOCALS = 200;
|
||||
public static final LuaValue[] NILS = new LuaValue[MAXLOCALS];
|
||||
static {
|
||||
for ( int i=0; i<MAXLOCALS; i++ )
|
||||
NILS[i] = NIL;
|
||||
}
|
||||
|
||||
// type
|
||||
abstract public int type();
|
||||
abstract public String typename();
|
||||
|
||||
// type checks
|
||||
public boolean isboolean() { return false; }
|
||||
public boolean isclosure() { return false; }
|
||||
public boolean isfunction() { return false; }
|
||||
public boolean isint() { return false; } // may convert from string
|
||||
public boolean isinttype() { return false; } // will not convert string
|
||||
public boolean islong() { return false; }
|
||||
public boolean isnil() { return false; }
|
||||
public boolean isnumber() { return false; } // may convert from string
|
||||
public boolean isstring() { return false; }
|
||||
public boolean isthread() { return false; }
|
||||
public boolean istable() { return false; }
|
||||
public boolean isuserdata() { return false; }
|
||||
public boolean isuserdata(Class c) { return false; }
|
||||
|
||||
// type coercion to java primitives
|
||||
public boolean toboolean() { return true; }
|
||||
public byte tobyte() { return 0; }
|
||||
public char tochar() { return 0; }
|
||||
public double todouble() { return 0; }
|
||||
public float tofloat() { return 0; }
|
||||
public int toint() { return 0; }
|
||||
public long tolong() { return 0; }
|
||||
public short toshort() { return 0; }
|
||||
public String toString() { return typename() + ": " + Integer.toHexString(hashCode()); }
|
||||
public Object touserdata() { return null; }
|
||||
public Object touserdata(Class c) { return null; }
|
||||
|
||||
// type coercion to lua values
|
||||
/** @return NIL if not a number or convertible to a number */
|
||||
public LuaValue tonumber() { return NIL; }
|
||||
|
||||
// optional argument conversions
|
||||
public boolean optboolean(boolean defval) { typerror("boolean"); return false; }
|
||||
public LuaClosure optclosure(LuaClosure defval) { typerror("closure"); return null; }
|
||||
public double optdouble(double defval) { typerror("double"); return 0; }
|
||||
public LuaFunction optfunction(LuaFunction defval) { typerror("function"); return null; }
|
||||
public int optint(int defval) { typerror("int"); return 0; }
|
||||
public LuaInteger optinteger(LuaInteger defval) { typerror("integer"); return null; }
|
||||
public long optlong(long defval) { typerror("long"); return 0; }
|
||||
public LuaNumber optnumber(LuaNumber defval) { typerror("number"); return null; }
|
||||
public String optString(String defval) { typerror("String"); return null; }
|
||||
public LuaString optstring(LuaString defval) { typerror("string"); return null; }
|
||||
public LuaTable opttable(LuaTable defval) { typerror("table"); return null; }
|
||||
public LuaThread optthread(LuaThread defval) { typerror("thread"); return null; }
|
||||
public Object optuserdata(Object defval) { typerror("object"); return null; }
|
||||
public Object optuserdata(Class c, Object defval) { typerror(c.getName()); return null; }
|
||||
public LuaValue optvalue(LuaValue defval) { return this; }
|
||||
|
||||
// argument type checks
|
||||
public boolean checkboolean() { typerror("boolean"); return false; }
|
||||
public LuaClosure checkclosure() { typerror("closure"); return null; }
|
||||
public double checkdouble() { typerror("double"); return 0; }
|
||||
public LuaValue checkfunction() { typerror("function"); return null; }
|
||||
public int checkint() { typerror("int"); return 0; }
|
||||
public LuaInteger checkinteger() { typerror("integer"); return null; }
|
||||
public long checklong() { typerror("long"); return 0; }
|
||||
public LuaNumber checknumber() { typerror("number"); return null; }
|
||||
public String checkString() { typerror("string"); return null; }
|
||||
public LuaString checkstring() { typerror("string"); return null; }
|
||||
public LuaTable checktable() { typerror("table"); return null; }
|
||||
public LuaThread checkthread() { typerror("thread"); return null; }
|
||||
public Object checkuserdata() { typerror("userdata"); return null; }
|
||||
public Object checkuserdata(Class c) { typerror("userdata"); return null; }
|
||||
public LuaValue checknotnil() { return this; }
|
||||
|
||||
// errors
|
||||
public static LuaValue error(String message) { throw new LuaError(message); }
|
||||
public static LuaValue error(int iarg, String message) { throw new LuaError("arg "+iarg+": "+message); }
|
||||
public static void assert_(boolean b,String msg) { if(!b) throw new LuaError(msg); }
|
||||
public static void argerror(int i,String msg) { throw new LuaError("arg "+i+": "+msg); }
|
||||
protected LuaValue typerror(String expected) { throw new LuaError("expected "+expected+" got "+typename()); }
|
||||
protected LuaValue typerror(int iarg, String expected) { throw new LuaError("arg "+iarg+": expected "+expected+" got "+typename()); }
|
||||
protected LuaValue unimplemented(String fun) { throw new LuaError("'"+fun+"' not implemented for "+typename()); }
|
||||
protected LuaValue aritherror() { throw new LuaError("attempt to perform arithmetic on "+typename()); }
|
||||
protected LuaValue aritherror(String fun) { throw new LuaError("attempt to perform arithmetic '"+fun+"' on "+typename()); }
|
||||
|
||||
// table operations
|
||||
public LuaValue get( LuaValue key ) { return gettable(this,key); }
|
||||
public LuaValue get( int key ) { return get(LuaInteger.valueOf(key)); }
|
||||
public LuaValue get( String key ) { return get(valueOf(key)); }
|
||||
public void set( LuaValue key, LuaValue value ) { settable(this, key, value); }
|
||||
public void set( int key, LuaValue value ) { set(LuaInteger.valueOf(key), value ); }
|
||||
public void set( int key, String value ) { set(key, valueOf(value) ); }
|
||||
public void set( String key, LuaValue value ) { set(valueOf(key), value ); }
|
||||
public void set( String key, double value ) { set(valueOf(key), valueOf(value) ); }
|
||||
public void set( String key, int value ) { set(valueOf(key), valueOf(value) ); }
|
||||
public void set( String key, String value ) { set(valueOf(key), valueOf(value) ); }
|
||||
public LuaValue rawget( LuaValue key ) { return unimplemented("rawget"); }
|
||||
public LuaValue rawget( int key ) { return rawget(valueOf(key)); }
|
||||
public LuaValue rawget( String key ) { return rawget(valueOf(key)); }
|
||||
public void rawset( LuaValue key, LuaValue value ) { unimplemented("rawset"); }
|
||||
public void rawset( int key, LuaValue value ) { rawset(valueOf(key),value); }
|
||||
public void rawset( int key, String value ) { rawset(key,valueOf(value)); }
|
||||
public void rawset( String key, LuaValue value ) { rawset(valueOf(key),value); }
|
||||
public void rawset( String key, double value ) { rawset(valueOf(key),valueOf(value)); }
|
||||
public void rawset( String key, int value ) { rawset(valueOf(key),valueOf(value)); }
|
||||
public void rawset( String key, String value ) { rawset(valueOf(key),valueOf(value)); }
|
||||
public void presize( int i) { unimplemented("presize"); }
|
||||
public Varargs next(LuaValue index) { unimplemented("next"); return null; }
|
||||
public Varargs inext(LuaValue index) { unimplemented("inext"); return null; }
|
||||
|
||||
// varargs references
|
||||
public LuaValue arg(int index) { return index==1? this: NIL; }
|
||||
public int narg() { return 1; };
|
||||
public LuaValue arg1() { return this; }
|
||||
|
||||
// metatable operations
|
||||
public LuaValue getmetatable() { return null; };
|
||||
public LuaValue setmetatable(LuaValue metatable) { return error("setmetatable not allowed for "+typename()); }
|
||||
public LuaValue getfenv() { typerror("function or thread"); return null; }
|
||||
public void setfenv(LuaValue env) { typerror("function or thread"); }
|
||||
|
||||
// function calls
|
||||
public LuaValue call() { return unimplemented("call"); }
|
||||
public LuaValue call(LuaValue arg) { return unimplemented("call"); }
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) { return unimplemented("call"); }
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { return unimplemented("call"); }
|
||||
public LuaValue method(String name) { return this.get(name).call(this); }
|
||||
public LuaValue method(LuaValue name) { return this.get(name).call(this); }
|
||||
public LuaValue method(String name, LuaValue arg) { return this.get(name).call(this,arg); }
|
||||
public LuaValue method(LuaValue name, LuaValue arg) { return this.get(name).call(this,arg); }
|
||||
public LuaValue method(String name, LuaValue arg1, LuaValue arg2) { return this.get(name).call(this,arg1,arg2); }
|
||||
public LuaValue method(LuaValue name, LuaValue arg1, LuaValue arg2) { return this.get(name).call(this,arg1,arg2); }
|
||||
public Varargs invoke() { return invoke(NONE); }
|
||||
public Varargs invoke(Varargs args) { unimplemented("call"); return null; }
|
||||
public Varargs invoke(LuaValue arg,Varargs varargs) { return invoke(varargsOf(arg,varargs)); }
|
||||
public Varargs invoke(LuaValue arg1,LuaValue arg2,Varargs varargs) { return invoke(varargsOf(arg1,arg2,varargs)); }
|
||||
public Varargs invoke(LuaValue[] args) { return invoke(varargsOf(args)); }
|
||||
public Varargs invoke(LuaValue[] args,Varargs varargs) { return invoke(varargsOf(args,varargs)); }
|
||||
public Varargs invokemethod(String name, Varargs args) { return get(name).invoke(varargsOf(this,args)); }
|
||||
public Varargs invokemethod(LuaValue name, Varargs args) { return get(name).invoke(varargsOf(this,args)); }
|
||||
public Varargs invokemethod(String name, LuaValue[] args) { return get(name).invoke(varargsOf(this,varargsOf(args))); }
|
||||
public Varargs invokemethod(LuaValue name, LuaValue[] args) { return get(name).invoke(varargsOf(this,varargsOf(args))); }
|
||||
|
||||
// unary operators
|
||||
public LuaValue not() { return FALSE; }
|
||||
public LuaValue neg() { return aritherror("neg"); }
|
||||
public LuaValue len() { return typerror("len"); }
|
||||
public int length() { typerror("len"); return 0; }
|
||||
public LuaValue getn() { return typerror("getn"); }
|
||||
|
||||
// object equality, used for key comparison
|
||||
public boolean equals(Object obj) { return this == obj; }
|
||||
|
||||
// arithmetic equality
|
||||
public LuaValue eq( LuaValue val ) { return valueOf(eq_b(val)); }
|
||||
public boolean eq_b( LuaValue val ) { return this == val; }
|
||||
public boolean eq_b( double val ) { return false; }
|
||||
public boolean eq_b( int val ) { return false; }
|
||||
public LuaValue neq( LuaValue val ) { return valueOf(!eq_b(val)); }
|
||||
public boolean neq_b( LuaValue val ) { return ! eq_b(val); }
|
||||
public boolean neq_b( double val ) { return ! eq_b(val); }
|
||||
public boolean neq_b( int val ) { return ! eq_b(val); }
|
||||
|
||||
// arithmetic operators
|
||||
public LuaValue add( LuaValue rhs ) { return aritherror("add"); }
|
||||
public LuaValue add(double rhs) { return aritherror("add"); }
|
||||
public LuaValue add(int rhs) { return add((double)rhs); }
|
||||
public LuaValue sub( LuaValue rhs ) { return aritherror("sub"); }
|
||||
public LuaValue subFrom(double lhs) { return aritherror("sub"); }
|
||||
public LuaValue subFrom(int lhs) { return subFrom((double)lhs); }
|
||||
public LuaValue mul( LuaValue rhs ) { return aritherror("mul"); }
|
||||
public LuaValue mul(double rhs) { return aritherror("mul"); }
|
||||
public LuaValue mul(int rhs) { return mul((double)rhs); }
|
||||
public LuaValue pow( LuaValue rhs ) { return aritherror("pow"); }
|
||||
public LuaValue powWith(double lhs) { return aritherror("mul"); }
|
||||
public LuaValue powWith(int lhs) { return powWith((double)lhs); }
|
||||
public LuaValue div( LuaValue rhs ) { return aritherror("div"); }
|
||||
public LuaValue divInto(double lhs) { return aritherror("divInto"); }
|
||||
public LuaValue mod( LuaValue rhs ) { return aritherror("mod"); }
|
||||
public LuaValue modFrom(double lhs) { return aritherror("modFrom"); }
|
||||
|
||||
// relational operators
|
||||
public LuaValue lt( LuaValue rhs ) { return aritherror("lt"); }
|
||||
public boolean lt_b( LuaValue rhs ) { aritherror("lt"); return false; }
|
||||
public boolean lt_b( int rhs ) { aritherror("lt"); return false; }
|
||||
public boolean lt_b( double rhs ) { aritherror("lt"); return false; }
|
||||
public LuaValue lteq( LuaValue rhs ) { return aritherror("lteq"); }
|
||||
public boolean lteq_b( LuaValue rhs ) { aritherror("lteq"); return false; }
|
||||
public boolean lteq_b( int rhs ) { aritherror("lteq"); return false; }
|
||||
public boolean lteq_b( double rhs ) { aritherror("lteq"); return false; }
|
||||
public LuaValue gt( LuaValue rhs ) { return aritherror("gt"); }
|
||||
public boolean gt_b( LuaValue rhs ) { aritherror("gt"); return false; }
|
||||
public boolean gt_b( int rhs ) { aritherror("gt"); return false; }
|
||||
public boolean gt_b( double rhs ) { aritherror("gt"); return false; }
|
||||
public LuaValue gteq( LuaValue rhs ) { return aritherror("gteq"); }
|
||||
public boolean gteq_b( LuaValue rhs ) { aritherror("gteq"); return false; }
|
||||
public boolean gteq_b( int rhs ) { aritherror("gteq"); return false; }
|
||||
public boolean gteq_b( double rhs ) { aritherror("gteq"); return false; }
|
||||
|
||||
// string comparison
|
||||
public int strcmp( LuaValue rhs ) { typerror("attempt to compare "+typename()); return 0; }
|
||||
public int strcmp( LuaString rhs ) { typerror("attempt to compare "+typename()); return 0; }
|
||||
|
||||
// concatenation
|
||||
public LuaValue concat( LuaValue rhs ) { return valueOf(concat_s(rhs)); }
|
||||
public String concat_s( LuaValue rhs ) { error("attempt to concatenate "+this.typename()); return null; }
|
||||
public String concatTo_s( String lhs ) { error("attempt to concatenate "+this.typename()); return null; }
|
||||
|
||||
// boolean operators
|
||||
public LuaValue and( LuaValue rhs ) { return this.toboolean()? rhs: this; }
|
||||
public LuaValue or( LuaValue rhs ) { return this.toboolean()? this: rhs; }
|
||||
|
||||
// for loop helpers
|
||||
/** test numeric for loop */
|
||||
public boolean testfor_b(LuaValue limit, boolean stepgtzero) { return stepgtzero? lteq_b(limit): gteq_b(limit); }
|
||||
/** @deprecated - used in samples only */
|
||||
public boolean testfor_b(LuaValue limit) { return lteq(limit).toboolean(); }
|
||||
/** @deprecated - used in samples only */
|
||||
public boolean testfor_b(LuaValue limit, LuaValue step) { return step.gt_b(0)? lteq_b(limit): gteq_b(limit); }
|
||||
/** @deprecated - used in samples only, use add(1) instead */
|
||||
public LuaValue incr() { return add(ONE); }
|
||||
|
||||
// lua number/string conversion
|
||||
public LuaString strvalue() { typerror("strValue"); return null; }
|
||||
public LuaValue strongvalue() { return this; }
|
||||
|
||||
|
||||
// conversion from java values
|
||||
public static LuaBoolean valueOf(boolean b) { return b? LuaValue.TRUE: FALSE; };
|
||||
public static LuaInteger valueOf(int i) { return LuaInteger.valueOf(i); }
|
||||
public static LuaNumber valueOf(double d) { return LuaDouble.valueOf(d); };
|
||||
public static LuaString valueOf(String s) { return LuaString.valueOf(s); }
|
||||
public static LuaString valueOf(byte[] bytes) { return new LuaString(bytes); }
|
||||
public static LuaString valueOf(byte[] bytes, int off, int len) {
|
||||
return new LuaString(bytes,off,len);
|
||||
}
|
||||
|
||||
// table initializers
|
||||
public static LuaTable tableOf() { return new LuaTable(); }
|
||||
public static LuaTable listOf(LuaValue[] unnamedValues) { return new LuaTable(null,unnamedValues,null); }
|
||||
public static LuaTable listOf(LuaValue[] unnamedValues,Varargs lastarg) { return new LuaTable(null,unnamedValues,lastarg); }
|
||||
public static LuaTable tableOf(LuaValue[] namedValues) { return new LuaTable(namedValues,null,null); }
|
||||
public static LuaTable tableOf(LuaValue[] namedValues, LuaValue[] unnamedValues) {return new LuaTable(namedValues,unnamedValues,null); }
|
||||
public static LuaTable tableOf(LuaValue[] namedValues, LuaValue[] unnamedValues, Varargs lastarg) {return new LuaTable(namedValues,unnamedValues,lastarg); }
|
||||
|
||||
// userdata intializers
|
||||
public static LuaUserdata userdataOf(Object o) { return new LuaUserdata(o); }
|
||||
public static LuaUserdata userdataOf(Object o,LuaValue metatable) { return new LuaUserdata(o,metatable); }
|
||||
|
||||
private static final int MAXTAGLOOP = 100;
|
||||
|
||||
// metatable processing
|
||||
/** get value from metatable operations, or NIL if not defined by metatables */
|
||||
protected static LuaValue gettable(LuaValue t, LuaValue key) {
|
||||
LuaValue tm;
|
||||
int loop = 0;
|
||||
do {
|
||||
if (t.istable()) {
|
||||
LuaValue res = t.rawget(key);
|
||||
if ((!res.isnil()) || (tm = t.metatag(INDEX)).isnil())
|
||||
return res;
|
||||
} else if ((tm = t.metatag(INDEX)).isnil())
|
||||
t.typerror("index");
|
||||
if (tm.isfunction())
|
||||
return tm.call(t, key);
|
||||
t = tm;
|
||||
}
|
||||
while ( ++loop < MAXTAGLOOP );
|
||||
error("loop in gettable");
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/** returns true if value was set via metatable processing, false otherwise */
|
||||
protected static boolean settable(LuaValue t, LuaValue key, LuaValue val) {
|
||||
LuaValue tm;
|
||||
int loop = 0;
|
||||
do {
|
||||
if (t.istable()) {
|
||||
if ((!t.rawget(key).isnil()) || (tm = t.metatag(NEWINDEX)).isnil()) {
|
||||
t.rawset(key, val);
|
||||
return true;
|
||||
}
|
||||
} else if ((tm = t.metatag(NEWINDEX)).isnil())
|
||||
t.typerror("index");
|
||||
if (tm.isfunction()) {
|
||||
tm.call(t, key, val);
|
||||
return true;
|
||||
}
|
||||
t = tm;
|
||||
}
|
||||
while ( ++loop < MAXTAGLOOP );
|
||||
error("loop in settable");
|
||||
return false;
|
||||
}
|
||||
|
||||
public LuaValue metatag(LuaValue tag) {
|
||||
LuaValue mt = getmetatable();
|
||||
if ( mt == null )
|
||||
return NIL;
|
||||
return mt.rawget(tag);
|
||||
}
|
||||
|
||||
private void indexerror() {
|
||||
error( "attempt to index ? (a "+typename()+" value)" );
|
||||
}
|
||||
|
||||
// common varargs constructors
|
||||
public static Varargs varargsOf(final LuaValue[] v) {
|
||||
switch ( v.length ) {
|
||||
case 0: return NONE;
|
||||
case 1: return v[0];
|
||||
case 2: return new PairVarargs(v[0],v[1]);
|
||||
default: return new ArrayVarargs(v,NONE);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(final LuaValue[] v,Varargs r) {
|
||||
switch ( v.length ) {
|
||||
case 0: return r;
|
||||
case 1: return new PairVarargs(v[0],r);
|
||||
default: return new ArrayVarargs(v,r);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(final LuaValue[] v, final int offset, final int length) {
|
||||
switch ( length ) {
|
||||
case 0: return NONE;
|
||||
case 1: return v[offset];
|
||||
case 2: return new PairVarargs(v[offset+0],v[offset+1]);
|
||||
default: return new ArrayPartVarargs(v,offset,length);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(final LuaValue[] v, final int offset, final int length,Varargs more) {
|
||||
switch ( length ) {
|
||||
case 0: return more;
|
||||
case 1: return new PairVarargs(v[offset],more);
|
||||
default: return new ArrayPartVarargs(v,offset,length,more);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(LuaValue v, Varargs r) {
|
||||
switch ( r.narg() ) {
|
||||
case 0: return v;
|
||||
default: return new PairVarargs(v,r);
|
||||
}
|
||||
}
|
||||
public static Varargs varargsOf(LuaValue v1,LuaValue v2,Varargs v3) {
|
||||
switch ( v3.narg() ) {
|
||||
case 0: return new PairVarargs(v1,v2);
|
||||
default: return new ArrayVarargs(new LuaValue[] {v1,v2},v3); }
|
||||
}
|
||||
|
||||
// empty varargs
|
||||
private static final class None extends LuaNil {
|
||||
public LuaValue arg(int i) { return NIL; }
|
||||
public int narg() { return 0; }
|
||||
public LuaValue arg1() { return NIL; }
|
||||
public String toString() { return "none"; }
|
||||
}
|
||||
|
||||
// varargs from array
|
||||
static final class ArrayVarargs extends Varargs {
|
||||
private final LuaValue[] v;
|
||||
private final Varargs r;
|
||||
ArrayVarargs(LuaValue[] v, Varargs r) {
|
||||
this.v = v;
|
||||
this.r = r ;
|
||||
}
|
||||
public LuaValue arg(int i) {
|
||||
return i >=1 && i<=v.length? v[i - 1]: r.arg(i-v.length);
|
||||
}
|
||||
public int narg() {
|
||||
return v.length+r.narg();
|
||||
}
|
||||
public LuaValue arg1() { return v.length>0? v[0]: r.arg1(); }
|
||||
}
|
||||
|
||||
// varargs from array part
|
||||
static final class ArrayPartVarargs extends Varargs {
|
||||
private final int offset;
|
||||
private final LuaValue[] v;
|
||||
private final int length;
|
||||
private final Varargs more;
|
||||
ArrayPartVarargs(LuaValue[] v, int offset, int length) {
|
||||
this.v = v;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
this.more = NONE;
|
||||
}
|
||||
public ArrayPartVarargs(LuaValue[] v, int offset, int length, Varargs more) {
|
||||
this.v = v;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
this.more = more;
|
||||
}
|
||||
public LuaValue arg(int i) {
|
||||
return i>=1&&i<=length? v[i+offset-1]: more.arg(i-length);
|
||||
}
|
||||
public int narg() {
|
||||
return length + more.narg();
|
||||
}
|
||||
public LuaValue arg1() {
|
||||
return length>0? v[offset]: more.arg1();
|
||||
}
|
||||
}
|
||||
|
||||
// varargs from two values
|
||||
static final class PairVarargs extends Varargs {
|
||||
private final LuaValue v1;
|
||||
private final Varargs v2;
|
||||
PairVarargs(LuaValue v1, Varargs v2) {
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
}
|
||||
public LuaValue arg(int i) {
|
||||
return i==1? v1: v2.arg(i-1);
|
||||
}
|
||||
public int narg() {
|
||||
return 1+v2.narg();
|
||||
}
|
||||
public LuaValue arg1() {
|
||||
return v1;
|
||||
}
|
||||
public String toString() {
|
||||
return "{"+v1+","+v2+"}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
377
src/core/org/luaj/vm2/Print.java
Normal file
377
src/core/org/luaj/vm2/Print.java
Normal file
@@ -0,0 +1,377 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public class Print extends Lua {
|
||||
|
||||
/** opcode names */
|
||||
private static final String STRING_FOR_NULL = "null";
|
||||
public static PrintStream ps = System.out;
|
||||
|
||||
private static final String[] luaP_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.toString() );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void printConstant(PrintStream ps, Prototype f, int i) {
|
||||
printValue( ps, f.k[i] );
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public static void printOpCode(Prototype f, int pc) {
|
||||
printOpCode(ps,f,pc);
|
||||
}
|
||||
|
||||
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(luaP_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 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";
|
||||
}
|
||||
|
||||
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.toString():
|
||||
s.substring(0, 32).toString()+"...+"+(s.length()-32)+"b");
|
||||
break;
|
||||
case LuaValue.TFUNCTION:
|
||||
ps.print( ( v instanceof LuaClosure )?
|
||||
((LuaClosure)v).p.toString(): v.toString() );
|
||||
break;
|
||||
case LuaValue.TUSERDATA:
|
||||
Object o = v.touserdata();
|
||||
String n = o.getClass().getName();
|
||||
n = n.substring(n.lastIndexOf('.')+1);
|
||||
ps.print( n+": "+Integer.toHexString(o.hashCode()) );
|
||||
break;
|
||||
default:
|
||||
ps.print(v.toString());
|
||||
}
|
||||
if ( i+1 == top )
|
||||
ps.print(']');
|
||||
ps.print( " | " );
|
||||
}
|
||||
ps.print(varargs);
|
||||
ps.println();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
68
src/core/org/luaj/vm2/Prototype.java
Normal file
68
src/core/org/luaj/vm2/Prototype.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*******************************************************************************
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
}
|
||||
}
|
||||
64
src/core/org/luaj/vm2/UpValue.java
Normal file
64
src/core/org/luaj/vm2/UpValue.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
/** Upvalue used with Closure formulation */
|
||||
public class UpValue {
|
||||
|
||||
LuaValue[] array; // initially the stack, becomes a holder
|
||||
int index;
|
||||
boolean closed;
|
||||
UpValue next = null;
|
||||
|
||||
public UpValue( LuaValue[] stack, int index, UpValue next ) {
|
||||
this.array = stack;
|
||||
this.index = index;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return (closed? "-": "+") + array[index];
|
||||
}
|
||||
|
||||
public LuaValue getValue() {
|
||||
return array[index];
|
||||
}
|
||||
|
||||
public void setValue( LuaValue value ) {
|
||||
array[index] = value;
|
||||
}
|
||||
|
||||
public boolean close( int limit ) {
|
||||
if ( (!closed) && (index>=limit) ) {
|
||||
array = new LuaValue[] { array[index] };
|
||||
index = 0;
|
||||
return (closed = true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
}
|
||||
135
src/core/org/luaj/vm2/Varargs.java
Normal file
135
src/core/org/luaj/vm2/Varargs.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
*/
|
||||
public abstract class Varargs {
|
||||
|
||||
/**
|
||||
* Get the n-th argument value (1-based)
|
||||
*
|
||||
* @param i 1 for the first argument, 2 for the second, etc.
|
||||
* @return Value at position i, or Value.NIL if there is none.
|
||||
*/
|
||||
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
|
||||
* @return Value
|
||||
*/
|
||||
abstract public LuaValue arg1();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// utilities to get specific arguments and type-check them.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// argument types
|
||||
public int type(int i) { return arg(i).type(); }
|
||||
public boolean isnil(int i) { return arg(i).isnil(); }
|
||||
public boolean isfunction(int i) { return arg(i).isfunction(); }
|
||||
public boolean isnumber(int i) { return arg(i).isnumber(); }
|
||||
public boolean isstring(int i) { return arg(i).isstring(); }
|
||||
public boolean istable(int i) { return arg(i).istable(); }
|
||||
public boolean isthread(int i) { return arg(i).isthread(); }
|
||||
public boolean isuserdata(int i) { return arg(i).isuserdata(); }
|
||||
public boolean isvalue(int i) { return i>0 && i<=narg(); }
|
||||
|
||||
// optional argument types
|
||||
public LuaFunction optfunction(int i, LuaFunction defval) { return arg(i).optfunction(defval); }
|
||||
public int optint(int i, int defval) { return arg(i).optint(defval); }
|
||||
public long optlong(int i, long defval) { return arg(i).optlong(defval); }
|
||||
public LuaNumber optnumber(int i, LuaNumber defval) { return arg(i).optnumber(defval); }
|
||||
public String optString(int i, String defval) { return arg(i).optString(defval); }
|
||||
public LuaString optstring(int i, LuaString defval) { return arg(i).optstring(defval); }
|
||||
public LuaValue optvalue(int i, LuaValue defval) { return i>0 && i<=narg()? arg(i): defval; }
|
||||
|
||||
// required argument types
|
||||
public boolean checkboolean(int i) { return arg(i).checkboolean(); }
|
||||
public double checkdouble(int i) { return arg(i).checknumber().todouble(); }
|
||||
public LuaValue checkfunction(int i) { return arg(i).checkfunction(); }
|
||||
public int checkint(int i) { return arg(i).checknumber().toint(); }
|
||||
public long checklong(int i) { return arg(i).checknumber().tolong(); }
|
||||
public LuaValue checknumber(int i) { return arg(i).checknumber(); }
|
||||
public String checkString(int i) { return arg(i).checkString(); }
|
||||
public LuaString checkstring(int i) { return arg(i).checkstring(); }
|
||||
public LuaTable checktable(int i) { return arg(i).checktable(); }
|
||||
public LuaThread checkthread(int i) { return arg(i).checkthread(); }
|
||||
public Object checkuserdata(int i,Class c) { return arg(i).checkuserdata(c); }
|
||||
public LuaValue checkvalue(int i) { return i<=narg()? arg(i): LuaValue.error("value expected"); }
|
||||
public LuaValue checknotnil(int i) { return arg(i).checknotnil(); }
|
||||
|
||||
public void argcheck(boolean test, int i, String msg) { if (!test) LuaValue.argerror(i,msg); }
|
||||
|
||||
public boolean isnoneornil(int i) {
|
||||
return i>narg() || arg(i).isnil();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
Buffer sb = new Buffer();
|
||||
sb.append( "(" );
|
||||
for ( int i=1,n=narg(); i<=n; i++ ) {
|
||||
if (i>1) sb.append( "," );
|
||||
sb.append( arg(i).toString() );
|
||||
}
|
||||
sb.append( ")" );
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
179
src/core/org/luaj/vm2/WeakTable.java
Normal file
179
src/core/org/luaj/vm2/WeakTable.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/*******************************************************************************
|
||||
* 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.lang.ref.WeakReference;
|
||||
|
||||
public class WeakTable extends LuaTable {
|
||||
|
||||
private final boolean weakKeys,weakValues;
|
||||
|
||||
WeakTable( boolean weakKeys, boolean weakValues ) {
|
||||
this.weakKeys = weakKeys;
|
||||
this.weakValues = weakValues;
|
||||
}
|
||||
|
||||
private static class WeakValue extends LuaValue {
|
||||
private final WeakReference ref;
|
||||
public WeakValue(LuaValue val) {
|
||||
ref = new WeakReference(val);
|
||||
}
|
||||
public int type() {
|
||||
return LuaValue.TNIL;
|
||||
}
|
||||
public String typename() {
|
||||
return "value";
|
||||
}
|
||||
public LuaValue strongvalue() {
|
||||
Object o = ref.get();
|
||||
return o!=null? (LuaValue)o: NIL;
|
||||
}
|
||||
}
|
||||
|
||||
private static class WeakUserdata extends LuaValue {
|
||||
private final WeakReference ref;
|
||||
private LuaValue metatable;
|
||||
public WeakUserdata(Object val, LuaValue metatable) {
|
||||
ref = new WeakReference(val);
|
||||
}
|
||||
public int type() {
|
||||
return LuaValue.TNIL;
|
||||
}
|
||||
public String typename() {
|
||||
return "value";
|
||||
}
|
||||
public LuaValue strongvalue() {
|
||||
Object o = ref.get();
|
||||
if ( o == null ) {
|
||||
metatable = null;
|
||||
return NIL;
|
||||
}
|
||||
return userdataOf( o, metatable );
|
||||
}
|
||||
}
|
||||
|
||||
private static class WeakEntry extends LuaValue {
|
||||
private LuaValue key;
|
||||
private LuaValue val;
|
||||
private WeakEntry(LuaValue key, LuaValue val) {
|
||||
this.key = key;
|
||||
this.val = val;
|
||||
}
|
||||
public int type() {
|
||||
return LuaValue.TNIL;
|
||||
}
|
||||
public String typename() {
|
||||
return "weakentry";
|
||||
}
|
||||
public LuaValue strongkey() {
|
||||
LuaValue k = key.strongvalue();
|
||||
LuaValue v = val.strongvalue();
|
||||
if ( k.isnil() || v.isnil() )
|
||||
return key = val = NIL;
|
||||
return k;
|
||||
}
|
||||
public LuaValue strongvalue() {
|
||||
LuaValue k = key.strongvalue();
|
||||
LuaValue v = val.strongvalue();
|
||||
if ( k.isnil() || v.isnil() )
|
||||
return key = val = NIL;
|
||||
return v;
|
||||
}
|
||||
public boolean eq_b(LuaValue rhs) {
|
||||
return strongkey().eq_b(rhs);
|
||||
}
|
||||
public int hashCode() {
|
||||
return strongkey().hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean shouldWeaken( LuaValue value ) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TFUNCTION:
|
||||
case LuaValue.TTHREAD:
|
||||
case LuaValue.TTABLE:
|
||||
case LuaValue.TUSERDATA:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private LuaValue toWeak( 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.checkuserdata(), value.getmetatable() );
|
||||
default: return value;
|
||||
}
|
||||
}
|
||||
|
||||
public LuaValue rawget(int key) {
|
||||
LuaValue v = super.rawget(key);
|
||||
if ( v.isnil() )
|
||||
return NIL;
|
||||
v = v.strongvalue();
|
||||
if ( v.isnil() ) {
|
||||
// TODO: mark table for culling?
|
||||
rawset(key, NIL);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public LuaValue rawget(LuaValue key) {
|
||||
LuaValue v = super.rawget(key);
|
||||
if ( v.isnil() )
|
||||
return NIL;
|
||||
v = v.strongvalue();
|
||||
if ( v.isnil() ) {
|
||||
// TODO: mark table for culling?
|
||||
rawset(key, NIL);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public void rawset(int key, LuaValue val) {
|
||||
if ( val.isnil() || !weakValues || !shouldWeaken(val) ) {
|
||||
super.rawset(key, val);
|
||||
} else {
|
||||
super.rawset(key, toWeak(val));
|
||||
}
|
||||
}
|
||||
|
||||
public void rawset(LuaValue key, LuaValue val) {
|
||||
if ( val.isnil() ) {
|
||||
super.rawset(key, val);
|
||||
} else {
|
||||
boolean weakenKey = weakKeys && shouldWeaken(key);
|
||||
boolean weakenVal = weakValues && shouldWeaken(val);
|
||||
if ( weakenKey ) {
|
||||
WeakEntry e = new WeakEntry( toWeak(key), weakenVal? toWeak(val): val);
|
||||
super.rawset(e, e);
|
||||
} else if ( weakenVal ) {
|
||||
super.rawset(key, toWeak(val));
|
||||
} else {
|
||||
super.rawset(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
267
src/core/org/luaj/vm2/compiler/DumpState.java
Normal file
267
src/core/org/luaj/vm2/compiler/DumpState.java
Normal file
@@ -0,0 +1,267 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
1084
src/core/org/luaj/vm2/compiler/FuncState.java
Normal file
1084
src/core/org/luaj/vm2/compiler/FuncState.java
Normal file
File diff suppressed because it is too large
Load Diff
37
src/core/org/luaj/vm2/compiler/InstructionPtr.java
Normal file
37
src/core/org/luaj/vm2/compiler/InstructionPtr.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
31
src/core/org/luaj/vm2/compiler/IntPtr.java
Normal file
31
src/core/org/luaj/vm2/compiler/IntPtr.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
1905
src/core/org/luaj/vm2/compiler/LexState.java
Normal file
1905
src/core/org/luaj/vm2/compiler/LexState.java
Normal file
File diff suppressed because it is too large
Load Diff
223
src/core/org/luaj/vm2/compiler/LuaC.java
Normal file
223
src/core/org/luaj/vm2/compiler/LuaC.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*******************************************************************************
|
||||
* 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.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.LocVars;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.LoadState.LuaCompiler;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler for Lua
|
||||
*/
|
||||
public class LuaC extends Lua implements LuaCompiler {
|
||||
|
||||
/** 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 = new LuaC();
|
||||
}
|
||||
|
||||
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 = new Hashtable();
|
||||
|
||||
/** Utility method to invoke the compiler for an input stream
|
||||
*/
|
||||
public static Prototype compile(InputStream is, String string) throws IOException {
|
||||
return new LuaC().compile(is.read(), is, string);
|
||||
}
|
||||
|
||||
/** Compile source bytes into a LPrototype.
|
||||
*
|
||||
* Try to compile the file, and return the Prototype on success,
|
||||
* or throw LuaErrorException on syntax error or I/O Exception
|
||||
*
|
||||
* @param firstByte the first byte from the InputStream.
|
||||
* This can be read by the client and tested to see if it is already a binary chunk.
|
||||
* @param stream InputStream to read from.
|
||||
* @param name Name of the chunk
|
||||
* @return null if the first byte indicates it is a binary chunk,
|
||||
* a LPrototype instance if it can be compiled,
|
||||
* or an exception is thrown if there is an error.
|
||||
* @throws IOException if an I/O exception occurs
|
||||
* @throws LuaError if there is a syntax error.
|
||||
*/
|
||||
public Prototype compile(int firstByte, InputStream stream, String name) throws IOException {
|
||||
LuaC compiler = new LuaC();
|
||||
return compiler.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;
|
||||
}
|
||||
|
||||
}
|
||||
403
src/core/org/luaj/vm2/lib/BaseLib.java
Normal file
403
src/core/org/luaj/vm2/lib/BaseLib.java
Normal file
@@ -0,0 +1,403 @@
|
||||
/*******************************************************************************
|
||||
* 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.LuaClosure;
|
||||
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.Prototype;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
/**
|
||||
* Base library implementation, targeted for JME platforms.
|
||||
*
|
||||
* BaseLib instances are typically used as the initial globals table
|
||||
* when creating a new uniqued runtime context.
|
||||
*
|
||||
* Since JME has no file system by default, dofile and loadfile use the
|
||||
* FINDER instance to find resource files. The default loader chain
|
||||
* in PackageLib will use these as well.
|
||||
*
|
||||
* For an implementation that looks in the current directory on JSE,
|
||||
* use org.luaj.lib.j2se.BaseLib instead.
|
||||
*
|
||||
* @see org.luaj.vm2.lib.jse.JseBaseLib
|
||||
*/
|
||||
public class BaseLib extends LuaTable implements ResourceFinder {
|
||||
public static final String VERSION = "Luaj 2.0";
|
||||
|
||||
public static InputStream STDIN = null;
|
||||
public static PrintStream STDOUT = System.out;
|
||||
public static 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;
|
||||
|
||||
/**
|
||||
* Construct a base libarary instance and initialize the functions in it.
|
||||
*/
|
||||
public BaseLib() {
|
||||
this.set( "_G", this );
|
||||
this.set( "_VERSION", VERSION );
|
||||
LibFunction.bind( this, new BaseFunc1().getClass(), new String[] {
|
||||
"getfenv", // ( [f] ) -> env
|
||||
"getmetatable", // ( object ) -> table
|
||||
"tostring", // (e) -> value
|
||||
} );
|
||||
LibFunction.bind( this, new BaseFunc2().getClass(), new String[] {
|
||||
"collectgarbage", // ( opt [,arg] ) -> value
|
||||
"error", // ( message [,level] ) -> ERR
|
||||
"rawequal", // (v1, v2) -> boolean
|
||||
"setfenv", // (f, table) -> void
|
||||
"tonumber", // (e [,base]) -> value
|
||||
} );
|
||||
LibFunction.bind( this, new BaseFuncV().getClass(), new String[] {
|
||||
"assert", // ( v [,message] ) -> v, message | ERR
|
||||
"dofile", // ( filename ) -> result1, ...
|
||||
"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
|
||||
"rawget", // (table, index) -> value
|
||||
"rawset", // (table, index, value) -> table
|
||||
"setmetatable", // (table, metatable) -> table
|
||||
} );
|
||||
|
||||
// pairs and ipars need iterator functions
|
||||
// "next", // ( table, [index] ) -> next-index, next-value
|
||||
// "inext", // not public ( table, [int-index] ) -> next-index, next-value
|
||||
// "ipairs", // (t) -> iter-func, t, 0
|
||||
// "pairs", // (t) -> iter-func, t, nil
|
||||
LuaValue next = new BaseIter(0,"next",null);
|
||||
LuaValue inext = new BaseIter(1,"inext",null);
|
||||
this.set( "pairs", new BaseIter(2,"pairs",next) );
|
||||
this.set( "ipairs", new BaseIter(3,"ipairs",inext) );
|
||||
this.set( "next", next );
|
||||
|
||||
// set the default resource finder if not set already
|
||||
if ( FINDER == null )
|
||||
FINDER = this;
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
public static class BaseFunc1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: { // "getfenv", // ( [f] ) -> env
|
||||
if ( ! arg.isfunction() ) {
|
||||
int i = arg.checkint();
|
||||
arg = (i==0)? (LuaValue) LuaThread.getRunning(): (LuaValue) LuaThread.getCallstackFunction(i-1);
|
||||
if ( arg == null )
|
||||
LuaValue.argerror(1, "invalid level");
|
||||
}
|
||||
return arg.getfenv();
|
||||
}
|
||||
case 1: // "getmetatable", // ( object ) -> table
|
||||
LuaValue mt = arg.getmetatable();
|
||||
return mt!=null? mt: NIL;
|
||||
case 2: // "tostring", // (e) -> value
|
||||
return arg.type() == LuaValue.TSTRING? arg: valueOf(arg.toString());
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BaseFunc2 extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1,LuaValue arg2) {
|
||||
switch ( opcode ) {
|
||||
case 0: // "collectgarbage", // ( opt [,arg] ) -> value
|
||||
String s = arg1.optString("collect");
|
||||
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;
|
||||
}
|
||||
return NIL;
|
||||
case 1: // "error", // ( message [,level] ) -> ERR
|
||||
throw new LuaError( arg1.isnil()? null: arg1.toString() );
|
||||
case 2: // "rawequal", // (v1, v2) -> boolean
|
||||
return valueOf(arg1 == arg2);
|
||||
case 3: { // "setfenv", // (f, table) -> void
|
||||
LuaValue f = arg1;
|
||||
if ( ! f.isfunction() ) {
|
||||
int i = arg1.checkint();
|
||||
f = (i==0)? (LuaValue) LuaThread.getRunning(): (LuaValue) LuaThread.getCallstackFunction(i-1);
|
||||
if ( f == null )
|
||||
LuaValue.argerror(1, "invalid level");
|
||||
}
|
||||
f.setfenv(arg2);
|
||||
return f;
|
||||
}
|
||||
case 4: // "tonumber", // (e [,base]) -> value
|
||||
final int base = arg2.optint(10);
|
||||
if (base == 10) { /* standard conversion */
|
||||
return arg1.tonumber();
|
||||
} else {
|
||||
if ( base < 2 || base > 36 )
|
||||
argerror(2, "base out of range");
|
||||
final LuaString str = arg1.optstring(null);
|
||||
return str!=null? str.tonumber(base): NIL;
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BaseFuncV extends VarArgFunction {
|
||||
private final BaseLib lib;
|
||||
public BaseFuncV() {
|
||||
this.lib = null;
|
||||
}
|
||||
public BaseFuncV(BaseLib lib) {
|
||||
this.lib = lib;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: // "assert", // ( v [,message] ) -> v, message | ERR
|
||||
if ( !args.arg1().toboolean() ) error("assertion failed!");
|
||||
return args;
|
||||
case 1: // "dofile", // ( filename ) -> result1, ...
|
||||
{
|
||||
LuaValue chunk;
|
||||
try {
|
||||
String filename = args.checkString(1);
|
||||
chunk = loadFile(filename).arg1();
|
||||
} catch ( IOException e ) {
|
||||
return error(e.getMessage());
|
||||
}
|
||||
return chunk.invoke();
|
||||
}
|
||||
case 2: // "load", // ( func [,chunkname] ) -> chunk | nil, msg
|
||||
try {
|
||||
LuaValue func = args.checkfunction(1);
|
||||
String chunkname = args.optString(2, "function");
|
||||
Prototype p = LoadState.undump(new StringInputStream(func), chunkname);
|
||||
return new LuaClosure(p,LuaThread.getRunningEnv(env));
|
||||
} catch ( Exception e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
case 3: // "loadfile", // ( [filename] ) -> chunk | nil, msg
|
||||
{
|
||||
try {
|
||||
String filename = args.checkString(1);
|
||||
return loadFile(filename);
|
||||
} catch ( Exception e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
}
|
||||
case 4: // "loadstring", // ( string [,chunkname] ) -> chunk | nil, msg
|
||||
try {
|
||||
LuaString script = args.checkstring(1);
|
||||
LuaString chunkname = args.optstring(2, script);
|
||||
Prototype p = LoadState.undump(script.toInputStream(), chunkname.toString());
|
||||
return new LuaClosure(p,LuaThread.getRunningEnv(env));
|
||||
} catch ( Exception e ) {
|
||||
return varargsOf(NIL, valueOf(e.getMessage()));
|
||||
}
|
||||
case 5: // "pcall", // (f, arg1, ...) -> status, result1, ...
|
||||
try {
|
||||
LuaThread.onCall(this);
|
||||
try {
|
||||
return varargsOf(LuaValue.TRUE, args.arg1().invoke(args.subargs(2)));
|
||||
} finally {
|
||||
LuaThread.onReturn();
|
||||
}
|
||||
} catch ( LuaError le ) {
|
||||
String m = le.getMessage();
|
||||
return varargsOf(FALSE, m!=null? valueOf(m): NIL);
|
||||
} catch ( Exception e ) {
|
||||
String m = e.getMessage();
|
||||
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
|
||||
}
|
||||
case 6: // "xpcall", // (f, err) -> result1, ...
|
||||
try {
|
||||
LuaThread.onCall(this);
|
||||
try {
|
||||
LuaThread thread = LuaThread.getRunning();
|
||||
LuaValue olderr = thread.err;
|
||||
try {
|
||||
thread.err = args.arg(2);
|
||||
return varargsOf(LuaValue.TRUE, args.arg1().invoke(args.subargs(2)));
|
||||
} finally {
|
||||
thread.err = olderr;
|
||||
}
|
||||
} finally {
|
||||
LuaThread.onReturn();
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
try {
|
||||
return args.arg(2).invoke(valueOf(e.getMessage()));
|
||||
} catch ( Exception f ) {
|
||||
return varargsOf(FALSE, valueOf(f.getMessage()));
|
||||
}
|
||||
}
|
||||
case 7: // "print", // (...) -> void
|
||||
{
|
||||
LuaValue tostring = env.get("tostring");
|
||||
for ( int i=1, n=args.narg(); i<=n; i++ ) {
|
||||
if ( i>1 ) STDOUT.write( '\t' );
|
||||
LuaString s = tostring.call( args.arg(i) ).strvalue();
|
||||
int z = s.indexOf((byte)0, 0);
|
||||
STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length );
|
||||
}
|
||||
STDOUT.println();
|
||||
return NONE;
|
||||
}
|
||||
case 8: // "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 )
|
||||
typerror(1,"index out of range");
|
||||
return args.subargs(i<0? n+i+2: i+1);
|
||||
}
|
||||
case 9: // "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 10: // "type", // (v) -> value
|
||||
return valueOf(args.checkvalue(1).typename());
|
||||
case 11: // "rawget", // (table, index) -> value
|
||||
return args.checktable(1).rawget(args.checkvalue(2));
|
||||
case 12: { // "rawset", // (table, index, value) -> table
|
||||
LuaTable t = args.checktable(1);
|
||||
t.rawset(args.checknotnil(2), args.checkvalue(3));
|
||||
return t;
|
||||
}
|
||||
case 13: { // "setmetatable", // (table, metatable) -> table
|
||||
final LuaValue t = args.arg1();
|
||||
final LuaValue mt = args.checkvalue(2);
|
||||
t.setmetatable(mt.isnil()? null: mt.checktable());
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
private Varargs loadFile(String filename) throws IOException {
|
||||
InputStream is = FINDER.findResource(filename);
|
||||
if ( is == null )
|
||||
return varargsOf(NIL, valueOf("not found: "+filename));
|
||||
try {
|
||||
Prototype p = LoadState.undump(is, filename);
|
||||
return new LuaClosure(p,LuaThread.getRunningEnv(env));
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class BaseIter extends VarArgFunction {
|
||||
final LuaValue aux;
|
||||
BaseIter(int opcode, String name, LuaValue aux) {
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
this.aux = aux;
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case 0: // "next" ( table, [index] ) -> next-index, next-value
|
||||
return args.arg1().next(args.arg(2));
|
||||
case 1: // "inext" ( table, [int-index] ) -> next-index, next-value
|
||||
return args.arg1().inext(args.arg(2));
|
||||
case 2: // "pairs" (t) -> iter-func, t, nil
|
||||
return varargsOf( aux, args.checktable(1), NIL );
|
||||
case 3: // "ipairs", // (t) -> iter-func, t, 0
|
||||
return varargsOf( aux, args.checktable(1), ZERO );
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StringInputStream extends InputStream {
|
||||
LuaValue func;
|
||||
byte[] bytes;
|
||||
int offset;
|
||||
StringInputStream(LuaValue func) {
|
||||
this.func = func;
|
||||
}
|
||||
public int read() throws IOException {
|
||||
if ( func == null ) return -1;
|
||||
if ( bytes == null ) {
|
||||
LuaValue s = func.call();
|
||||
if ( s.isnil() ) {
|
||||
func = null;
|
||||
bytes = null;
|
||||
return -1;
|
||||
}
|
||||
bytes = s.toString().getBytes();
|
||||
offset = 0;
|
||||
}
|
||||
if ( offset >= bytes.length )
|
||||
return -1;
|
||||
return bytes[offset++];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
111
src/core/org/luaj/vm2/lib/CoroutineLib.java
Normal file
111
src/core/org/luaj/vm2/lib/CoroutineLib.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.lib;
|
||||
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
public class CoroutineLib extends VarArgFunction {
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"<coroutine>",
|
||||
"create",
|
||||
"resume",
|
||||
"running",
|
||||
"status",
|
||||
"yield",
|
||||
"wrap",
|
||||
"wrapped"
|
||||
};
|
||||
|
||||
private static final int INSTALL = 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 static void install(LuaValue globals) {
|
||||
globals.set("coroutine", createInstance());
|
||||
}
|
||||
|
||||
public static final LuaValue createInstance() {
|
||||
LuaTable t = new LuaTable();
|
||||
CoroutineLib f = new CoroutineLib();
|
||||
LibFunction.bind(t, f.getClass(), NAMES);
|
||||
return t;
|
||||
}
|
||||
|
||||
public CoroutineLib() {}
|
||||
|
||||
private CoroutineLib(String name, int opcode, LuaThread thread) {
|
||||
super(name, opcode, thread);
|
||||
}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case INSTALL:
|
||||
return createInstance();
|
||||
case CREATE: {
|
||||
final LuaValue func = args.checkfunction(1);
|
||||
return new LuaThread(func, func.getfenv() );
|
||||
}
|
||||
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: {
|
||||
final LuaThread r = LuaThread.getRunning();
|
||||
if ( LuaThread.isMainThread( r ) )
|
||||
error("main thread can't yield");
|
||||
return r.yield( args );
|
||||
}
|
||||
case WRAP: {
|
||||
final LuaValue func = args.checkfunction(1);
|
||||
final LuaThread thread = new LuaThread(func, func.getfenv());
|
||||
return new CoroutineLib("wrapped",WRAPPED,thread);
|
||||
}
|
||||
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).toString() );
|
||||
}
|
||||
}
|
||||
default:
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
905
src/core/org/luaj/vm2/lib/DebugLib.java
Normal file
905
src/core/org/luaj/vm2/lib/DebugLib.java
Normal file
@@ -0,0 +1,905 @@
|
||||
/*******************************************************************************
|
||||
* 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.LuaClosure;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaThread;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
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 = false;
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"<debug>",
|
||||
"debug",
|
||||
"getfenv",
|
||||
"gethook",
|
||||
"getinfo",
|
||||
"getlocal",
|
||||
"getmetatable",
|
||||
"getregistry",
|
||||
"getupvalue",
|
||||
"setfenv",
|
||||
"sethook",
|
||||
"setlocal",
|
||||
"setmetatable",
|
||||
"setupvalue",
|
||||
"traceback",
|
||||
};
|
||||
|
||||
private static final int INSTALL = 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 = LuaString.valueOf("Lua");
|
||||
private static final LuaString JAVA = LuaString.valueOf("Java");
|
||||
private static final LuaString QMARK = LuaString.valueOf("?");
|
||||
private static final LuaString GLOBAL = LuaString.valueOf("global");
|
||||
private static final LuaString LOCAL = LuaString.valueOf("local");
|
||||
private static final LuaString METHOD = LuaString.valueOf("method");
|
||||
private static final LuaString UPVALUE = LuaString.valueOf("upvalue");
|
||||
private static final LuaString FIELD = LuaString.valueOf("field");
|
||||
private static final LuaString CALL = LuaString.valueOf("call");
|
||||
private static final LuaString LINE = LuaString.valueOf("line");
|
||||
private static final LuaString RETURN = LuaString.valueOf("return");
|
||||
private static final LuaString TAILRETURN = LuaString.valueOf("tail return");
|
||||
|
||||
private static final LuaString FUNC = LuaString.valueOf("func");
|
||||
private static final LuaString NUPS = LuaString.valueOf("nups");
|
||||
private static final LuaString NAME = LuaString.valueOf("name");
|
||||
private static final LuaString NAMEWHAT = LuaString.valueOf("namewhat");
|
||||
private static final LuaString WHAT = LuaString.valueOf("what");
|
||||
private static final LuaString SOURCE = LuaString.valueOf("source");
|
||||
private static final LuaString SHORT_SRC = LuaString.valueOf("short_src");
|
||||
private static final LuaString LINEDEFINED = LuaString.valueOf("linedefined");
|
||||
private static final LuaString LASTLINEDEFINED = LuaString.valueOf("lastlinedefined");
|
||||
private static final LuaString CURRENTLINE = LuaString.valueOf("currentline");
|
||||
private static final LuaString ACTIVELINES = LuaString.valueOf("activelines");
|
||||
|
||||
public static void install(LuaValue globals) {
|
||||
globals.set("debug", DebugLib.createInstance() );
|
||||
}
|
||||
|
||||
public static final LuaValue createInstance() {
|
||||
LuaTable t = new LuaTable();
|
||||
DebugLib f = new DebugLib();
|
||||
LibFunction.bind(t, f.getClass(), NAMES);
|
||||
if ( ! DEBUG_ENABLED ) {
|
||||
DEBUG_ENABLED = true;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public DebugLib() {}
|
||||
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case INSTALL:
|
||||
return createInstance();
|
||||
case DEBUG:
|
||||
return _debug(args);
|
||||
case GETFENV:
|
||||
return _getfenv(args);
|
||||
case GETHOOK:
|
||||
return _gethook(args);
|
||||
case GETINFO:
|
||||
return _getinfo(args);
|
||||
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.
|
||||
//
|
||||
private 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 Object sourceline() {
|
||||
if ( closure == null ) return func.toString();
|
||||
String s = closure.p.source.toString();
|
||||
int line = currentline();
|
||||
return (s.startsWith("@")||s.startsWith("=")? s.substring(1): s) + ":" + line;
|
||||
}
|
||||
public String tracename() {
|
||||
// if ( func != null )
|
||||
// return func.toString();
|
||||
LuaString[] kind = getfunckind();
|
||||
if ( kind == null )
|
||||
return "function ?";
|
||||
return "function "+kind[0].toString();
|
||||
}
|
||||
public LuaString getlocalname(int index) {
|
||||
if ( closure == null ) return null;
|
||||
return closure.p.getlocalname(index, pc);
|
||||
}
|
||||
public String toString() {
|
||||
return sourceline()+": in "+tracename();
|
||||
}
|
||||
}
|
||||
|
||||
/** DebugState is associated with a Thread */
|
||||
private static class DebugState {
|
||||
private final LuaThread thread;
|
||||
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;
|
||||
private int line;
|
||||
private DebugState(LuaThread thread) {
|
||||
this.thread = 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();
|
||||
}
|
||||
private 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 ( Throwable t ) {
|
||||
t.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;
|
||||
}
|
||||
private DebugInfo getDebugInfo() {
|
||||
return debugInfo[debugCalls-1];
|
||||
}
|
||||
private 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 toString() {
|
||||
return DebugLib.traceback(thread, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static DebugState getDebugState( LuaThread thread ) {
|
||||
if ( thread.debugState == null )
|
||||
thread.debugState = new DebugState(thread);
|
||||
return (DebugState) thread.debugState;
|
||||
}
|
||||
|
||||
private 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 calls */
|
||||
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 running_calls
|
||||
* @param thread */
|
||||
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);
|
||||
ds.getDebugInfo().bytecode( pc, extras, top );
|
||||
if ( ds.hookline ) {
|
||||
int newline = di.currentline();
|
||||
if ( newline != ds.line ) {
|
||||
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.
|
||||
private static Varargs _debug(Varargs args) {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
private 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));
|
||||
}
|
||||
|
||||
private 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.optString(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;
|
||||
}
|
||||
|
||||
private static Varargs _getfenv(Varargs args) {
|
||||
LuaValue object = args.arg1();
|
||||
LuaValue env = object.getfenv();
|
||||
return env!=null? env: LuaValue.NIL;
|
||||
}
|
||||
|
||||
private static Varargs _setfenv(Varargs args) {
|
||||
LuaValue object = args.arg1();
|
||||
LuaTable table = args.checktable(2);
|
||||
object.setfenv(table);
|
||||
return object;
|
||||
}
|
||||
|
||||
protected Varargs _getinfo(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
LuaValue func = args.arg(a++);
|
||||
String what = args.optString(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( this );
|
||||
} 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.toString();
|
||||
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.toString();
|
||||
if ( name.startsWith("@") || name.startsWith("=") )
|
||||
name = name.substring(1);
|
||||
else if ( name.startsWith("\033") )
|
||||
name = "binary string";
|
||||
return name;
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
}
|
||||
|
||||
private static LuaValue _getmetatable(Varargs args) {
|
||||
LuaValue object = args.arg(1);
|
||||
LuaValue mt = object.getmetatable();
|
||||
return mt!=null? mt: NIL;
|
||||
}
|
||||
|
||||
private static Varargs _setmetatable(Varargs args) {
|
||||
LuaValue object = args.arg(1);
|
||||
try {
|
||||
if ( ! args.isnoneornil(2) )
|
||||
object.setmetatable(args.checktable(2));
|
||||
else
|
||||
object.setmetatable(null);
|
||||
return LuaValue.TRUE;
|
||||
} catch ( LuaError e ) {
|
||||
return varargsOf(FALSE, valueOf(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
private static Varargs _getregistry(Varargs args) {
|
||||
return new LuaTable();
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private static LuaValue _traceback(Varargs args) {
|
||||
int a=1;
|
||||
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
|
||||
String message = args.optString(a++, "stack traceback:");
|
||||
int level = args.optint(a++,1);
|
||||
String tb = DebugLib.traceback(thread, level);
|
||||
return valueOf(message+"\n"+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
|
||||
* @param level
|
||||
* @return
|
||||
*/
|
||||
public static String traceback(LuaThread thread, int level) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
DebugState ds = getDebugState(thread);
|
||||
DebugInfo di;
|
||||
for ( int i=level, n=ds.debugCalls; i<n; i++ ) {
|
||||
di = ds.getDebugInfo(i);
|
||||
if ( di != null ) {
|
||||
sb.append( "\t" );
|
||||
sb.append( di.toString() );
|
||||
if ( i<n )
|
||||
sb.append( "\n" );
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
|
||||
private static void lua_assert(boolean x) {
|
||||
if (!x) throw new RuntimeException("lua_assert failed");
|
||||
}
|
||||
|
||||
|
||||
// return StrValue[] { name, namewhat } if found, null if not
|
||||
private 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 */
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private static boolean checkreg(Prototype pt,int reg) {
|
||||
return (reg < pt.maxstacksize);
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private 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) {
|
||||
private 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
|
||||
private 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];
|
||||
}
|
||||
|
||||
}
|
||||
431
src/core/org/luaj/vm2/lib/IoLib.java
Normal file
431
src/core/org/luaj/vm2/lib/IoLib.java
Normal file
@@ -0,0 +1,431 @@
|
||||
/*******************************************************************************
|
||||
* 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.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
|
||||
public class IoLib extends LuaTable {
|
||||
|
||||
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 toString() {
|
||||
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 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;
|
||||
|
||||
|
||||
//protected final Table filemt;
|
||||
protected final LuaTable filemethods;
|
||||
private final LuaValue linesiter;
|
||||
|
||||
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");
|
||||
|
||||
public IoLib() {
|
||||
|
||||
// io lib functions
|
||||
set("flush", new IoFuncV("flush",0));
|
||||
set("tmpfile", new IoFuncV("tmpfile",1));
|
||||
set("close", new IoFuncV("close",2));
|
||||
set("input", new IoFuncV("input",3));
|
||||
set("output", new IoFuncV("output",4));
|
||||
set("type", new IoFuncV("type",5));
|
||||
set("popen", new IoFuncV("popen",6));
|
||||
set("open", new IoFuncV("open",7));
|
||||
set("lines", new IoFuncV("lines",8));
|
||||
set("read", new IoFuncV("read",9));
|
||||
set("write", new IoFuncV("write",10));
|
||||
setmetatable( tableOf(new LuaValue[] {
|
||||
valueOf("__index"),new IoFuncV("__index",11),
|
||||
}) );
|
||||
|
||||
// create file metatable
|
||||
filemethods = tableOf(new LuaValue[] {
|
||||
valueOf("close"), new IoFuncV("close",12),
|
||||
valueOf("flush"), new IoFuncV("flush",13),
|
||||
valueOf("setvbuf"), new IoFuncV("setvbuf",14),
|
||||
valueOf("lines"), new IoFuncV("lines",15),
|
||||
valueOf("read"), new IoFuncV("read",16),
|
||||
valueOf("seek"), new IoFuncV("seek",17),
|
||||
valueOf("write"), new IoFuncV("write",18),
|
||||
});
|
||||
//filemt = tableOf(new Value[]{valueOf("__index"),filemethods});
|
||||
|
||||
// lines iterator
|
||||
linesiter = new IoFuncV("linesiter",19);
|
||||
}
|
||||
|
||||
public class IoFuncV extends VarArgFunction {
|
||||
public IoFuncV(String name, int opcode) {
|
||||
super(name,opcode,IoLib.this);
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
File f;
|
||||
int n;
|
||||
LuaValue v;
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case 0: // io.flush() -> bool
|
||||
checkopen(output());
|
||||
outfile.flush();
|
||||
return LuaValue.TRUE;
|
||||
case 1: // io.tmpfile() -> file
|
||||
return tmpFile();
|
||||
case 2: // io.close([file]) -> void
|
||||
f = args.arg1().isnil()? output(): checkfile(args.arg1());
|
||||
checkopen(f);
|
||||
return ioclose(f);
|
||||
case 3: // io.input([file]) -> file
|
||||
infile = args.arg1().isnil()? input(): args.arg1().isstring()?
|
||||
ioopenfile(args.checkString(1),"r"):
|
||||
checkfile(args.arg1());
|
||||
return infile;
|
||||
|
||||
case 4: // io.output(filename) -> file
|
||||
outfile = args.arg1().isnil()? output(): args.arg1().isstring()?
|
||||
ioopenfile(args.checkString(1),"w"):
|
||||
checkfile(args.arg1());
|
||||
return outfile;
|
||||
case 5: // io.type(obj) -> "file" | "closed file" | nil
|
||||
if ( (f=optfile(args.arg1())) != null )
|
||||
return f.isclosed()? CLOSED_FILE: FILE;
|
||||
return NIL;
|
||||
case 6: // io.popen(prog, [mode]) -> file
|
||||
return openProgram(args.checkString(1),args.optString(2,"r"));
|
||||
case 7: // io.open(filename, [mode]) -> file | nil,err
|
||||
return rawopenfile(args.checkString(1), args.optString(2,"r"));
|
||||
case 8: // io.lines(filename) -> iterator
|
||||
infile = args.arg1().isnil()? input(): ioopenfile(args.checkString(1),"r");
|
||||
checkopen(infile);
|
||||
return lines(infile);
|
||||
case 9: // io.read(...) -> (...)
|
||||
checkopen(infile);
|
||||
return ioread(infile,args);
|
||||
case 10: // io.write(...) -> void
|
||||
checkopen(output());
|
||||
return iowrite(outfile,args);
|
||||
case 11: // __index, returns a field
|
||||
v = args.arg(2);
|
||||
return v.equals(STDOUT)?output():
|
||||
v.equals(STDIN)? input():
|
||||
v.equals(STDERR)? errput(): NIL;
|
||||
|
||||
// ------------ file metatable operations
|
||||
|
||||
case 12: // file:close() -> void
|
||||
return ioclose(checkfile(args.arg1()));
|
||||
case 13: // file:flush() -> void
|
||||
checkfile(args.arg1()).flush();
|
||||
return LuaValue.TRUE;
|
||||
case 14: // file:setvbuf(mode,[size]) -> void
|
||||
f = checkfile(args.arg1());
|
||||
f.setvbuf(args.checkString(2),args.optint(3, 1024));
|
||||
return LuaValue.TRUE;
|
||||
case 15: // file:lines() -> iterator
|
||||
return lines(checkfile(args.arg1()));
|
||||
case 16: // file:read(...) -> (...)
|
||||
f = checkfile(args.arg1());
|
||||
return ioread(f,args.subargs(2));
|
||||
case 17: // file:seek([whence][,offset]) -> pos | nil,error
|
||||
f = checkfile(args.arg1());
|
||||
n = f.seek(args.optString(2,"cur"),args.optint(3,0));
|
||||
return valueOf(n);
|
||||
case 18: // file:write(...) -> void
|
||||
f = checkfile(args.arg1());
|
||||
return iowrite(f,args.subargs(2));
|
||||
case 19: // lines iterator(s,var) -> var'
|
||||
f = checkfile(args.arg1());
|
||||
return freadline(f);
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
return errorresult(ioe);
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private File input() {
|
||||
return infile!=null? infile: (infile=ioopenfile("-","r"));
|
||||
}
|
||||
|
||||
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(IOException 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));
|
||||
}
|
||||
|
||||
// TODO: how to close on finalization
|
||||
private Varargs lines(final File f) throws IOException {
|
||||
return varargsOf( linesiter, f );
|
||||
}
|
||||
|
||||
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];
|
||||
for ( i=0; i<n; i++ ) {
|
||||
if ( args.isnumber(i+1) ) {
|
||||
v[i] = freadbytes(f,args.checkint(i+1));
|
||||
} else {
|
||||
String format = args.checkString(i+1);
|
||||
if ( "*n".equals(format) )
|
||||
v[i] = valueOf( freadnumber(f) );
|
||||
else if ( "*a".equals(format) )
|
||||
v[i] = freadall(f);
|
||||
else if ( "*l".equals(format) )
|
||||
v[i] = freadline(f);
|
||||
else
|
||||
typerror( i+1, "(invalid format)" );
|
||||
}
|
||||
if ( v[i].isnil() )
|
||||
return varargsOf(v,0,i);
|
||||
}
|
||||
return varargsOf(v);
|
||||
}
|
||||
|
||||
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 valueOf(b, 0, r);
|
||||
}
|
||||
public static LuaValue freaduntil(File f,int delim) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int c;
|
||||
try {
|
||||
while ( true ) {
|
||||
c = f.read();
|
||||
if ( c < 0 || c == delim )
|
||||
break;
|
||||
baos.write(c);
|
||||
}
|
||||
} catch ( EOFException e ) {
|
||||
c = -1;
|
||||
}
|
||||
return ( c < 0 && baos.size() == 0 )?
|
||||
(LuaValue) NIL:
|
||||
(LuaValue) valueOf(baos.toByteArray());
|
||||
}
|
||||
public static LuaValue freadline(File f) throws IOException {
|
||||
return freaduntil(f,'\n');
|
||||
}
|
||||
public static LuaValue freadall(File f) throws IOException {
|
||||
int n = f.remaining();
|
||||
if ( n >= 0 ) {
|
||||
return freadbytes(f, n);
|
||||
} else {
|
||||
return freaduntil(f,-1);
|
||||
}
|
||||
}
|
||||
public static double 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? Double.parseDouble(s): 0;
|
||||
}
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
76
src/core/org/luaj/vm2/lib/LibFunction.java
Normal file
76
src/core/org/luaj/vm2/lib/LibFunction.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* 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.LuaFunction;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
;
|
||||
|
||||
|
||||
abstract public class LibFunction extends LuaFunction {
|
||||
|
||||
protected int opcode;
|
||||
protected String name;
|
||||
|
||||
public LibFunction() {
|
||||
}
|
||||
|
||||
public LibFunction(String name, int opcode, LuaValue env) {
|
||||
super(env);
|
||||
this.name = name;
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name!=null? name: super.toString();
|
||||
}
|
||||
|
||||
/** Bind a set of names to class instances, put values into the table. */
|
||||
public static LuaTable bind( LuaTable table, Class libFuncClass, String[] names ) {
|
||||
try {
|
||||
for ( int i=0, n=names.length; i<n; i++ ) {
|
||||
LibFunction f = (LibFunction) libFuncClass.newInstance();
|
||||
f.opcode = i;
|
||||
f.name = names[i];
|
||||
f.env = table;
|
||||
table.set( names[i], f );
|
||||
}
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e.toString());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e.toString());
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/** Bind a complete set of names and classes , put values into the table. */
|
||||
public static LuaTable bind( LuaTable table, Class[] libFuncClasses, String[][] nameLists ) {
|
||||
for ( int j=0, n=libFuncClasses.length; j<n; j++ ) {
|
||||
bind( table, libFuncClasses[j], nameLists[j] );
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
194
src/core/org/luaj/vm2/lib/MathLib.java
Normal file
194
src/core/org/luaj/vm2/lib/MathLib.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Base math library with JME support.
|
||||
*
|
||||
* For j2se support use org.luaj.lib.j2se.MathLib
|
||||
*
|
||||
* @see org.luaj.vm2.lib.jse.JseMathLib
|
||||
*/
|
||||
public class MathLib extends LuaTable {
|
||||
public static MathLib MATHLIB = null;
|
||||
|
||||
private Random random;
|
||||
|
||||
public MathLib() {
|
||||
MATHLIB = this;
|
||||
this.set( "pi", Math.PI );
|
||||
this.set( "huge", LuaDouble.POSINF );
|
||||
LibFunction.bind( this, new MathFunc1().getClass(), new String[] {
|
||||
"abs", "ceil", "cos", "deg",
|
||||
"exp", "floor", "rad", "sin",
|
||||
"sqrt", "tan" } );
|
||||
LibFunction.bind( this, new MathFunc2().getClass(), new String[] {
|
||||
"fmod", "ldexp", "pow", "random",
|
||||
} );
|
||||
LibFunction.bind( this, new MathFuncV().getClass(), new String[] {
|
||||
"frexp", "max", "min", "modf",
|
||||
"randomseed" } );
|
||||
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "math";
|
||||
}
|
||||
|
||||
public static class MathFunc1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: return valueOf(Math.abs(arg.todouble()));
|
||||
case 1: return valueOf(Math.ceil(arg.todouble()));
|
||||
case 2: return valueOf(Math.cos(arg.todouble()));
|
||||
case 3: return valueOf(Math.toDegrees(arg.todouble()));
|
||||
case 4: return dpow(Math.E,arg.todouble());
|
||||
case 5: return valueOf(Math.floor(arg.todouble()));
|
||||
case 6: return valueOf(Math.toRadians(arg.todouble()));
|
||||
case 7: return valueOf(Math.sin(arg.todouble()));
|
||||
case 8: return valueOf(Math.sqrt(arg.todouble()));
|
||||
case 9: return valueOf(Math.tan(arg.todouble()));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MathFunc2 extends TwoArgFunction {
|
||||
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.todouble(), arg2.todouble());
|
||||
}
|
||||
case 3: { // random
|
||||
MathLib lib = (MathLib) env;
|
||||
if ( lib.random == null )
|
||||
lib.random = new Random();
|
||||
if ( arg1.isnil() )
|
||||
return valueOf( lib.random.nextDouble() );
|
||||
int m = arg1.toint();
|
||||
if ( arg2.isnil() )
|
||||
return valueOf( 1 + lib.random.nextInt(m) );
|
||||
else
|
||||
return valueOf( m + lib.random.nextInt(arg2.toint()-m) );
|
||||
}
|
||||
}
|
||||
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_d(a,b):
|
||||
dpow_default(a,b) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to override default dpow behavior with faster implementation.
|
||||
*/
|
||||
public double dpow_d(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;
|
||||
}
|
||||
|
||||
public static class MathFuncV extends VarArgFunction {
|
||||
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) env).random = new Random(seed);
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/core/org/luaj/vm2/lib/OneArgFunction.java
Normal file
57
src/core/org/luaj/vm2/lib/OneArgFunction.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
* 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 public class OneArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg);
|
||||
|
||||
public OneArgFunction() {
|
||||
}
|
||||
|
||||
public OneArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public OneArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, 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());
|
||||
}
|
||||
}
|
||||
292
src/core/org/luaj/vm2/lib/OsLib.java
Normal file
292
src/core/org/luaj/vm2/lib/OsLib.java
Normal file
@@ -0,0 +1,292 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Base implementation of OsLib, with simplified stub functions
|
||||
* for library functions that cannot be implemented uniformly
|
||||
* on J2se and J2me.
|
||||
*
|
||||
* <p>
|
||||
* This can be installed as-is on either platform, or extended
|
||||
* and refined to be used in a complete J2se implementation.
|
||||
*
|
||||
* <p>Contains limited implementations of features not supported well on J2me:
|
||||
* <bl>
|
||||
* <li>execute()</li>
|
||||
* <li>remove()</li>
|
||||
* <li>rename()</li>
|
||||
* <li>tmpname()</li>
|
||||
* </bl>
|
||||
*
|
||||
* @see org.luaj.vm2.lib.jse.JseOsLib
|
||||
*/
|
||||
public class OsLib extends LuaTable {
|
||||
public static String TMP_PREFIX = ".luaj";
|
||||
public static String TMP_SUFFIX = "tmp";
|
||||
|
||||
private static final int CLOCK = 0;
|
||||
private static final int DATE = 1;
|
||||
private static final int DIFFTIME = 2;
|
||||
private static final int EXECUTE = 3;
|
||||
private static final int EXIT = 4;
|
||||
private static final int GETENV = 5;
|
||||
private static final int REMOVE = 6;
|
||||
private static final int RENAME = 7;
|
||||
private static final int SETLOCALE = 8;
|
||||
private static final int TIME = 9;
|
||||
private static final int TMPNAME = 10;
|
||||
|
||||
private static final long t0 = System.currentTimeMillis();
|
||||
private static long tmpnames = t0;
|
||||
|
||||
/**
|
||||
* Create and OsLib instance.
|
||||
*/
|
||||
public OsLib() {
|
||||
String[] NAMES = {
|
||||
"clock",
|
||||
"date",
|
||||
"difftime",
|
||||
"execute",
|
||||
"exit",
|
||||
"getenv",
|
||||
"remove",
|
||||
"rename",
|
||||
"setlocale",
|
||||
"time",
|
||||
"tmpname",
|
||||
};
|
||||
for ( int i=NAMES.length; --i>=0; )
|
||||
set(NAMES[i], new OsFuncV(NAMES[i], i, this));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "os";
|
||||
}
|
||||
|
||||
private class OsFuncV extends VarArgFunction {
|
||||
public OsFuncV(String name, int opcode, OsLib lib) {
|
||||
super(name, opcode, lib);
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case CLOCK:
|
||||
return valueOf(clock());
|
||||
case DATE: {
|
||||
String s = args.optString(1, null);
|
||||
long t = args.optlong(2,-1);
|
||||
return valueOf( date(s, t==-1? System.currentTimeMillis(): t) );
|
||||
}
|
||||
case DIFFTIME:
|
||||
return valueOf(difftime(args.checklong(1),args.checklong(2)));
|
||||
case EXECUTE:
|
||||
return valueOf(execute(args.optString(1, null)));
|
||||
case EXIT:
|
||||
exit(args.optint(1, 0));
|
||||
return NONE;
|
||||
case GETENV: {
|
||||
final String val = getenv(args.checkString(1));
|
||||
return val!=null? valueOf(val): NIL;
|
||||
}
|
||||
case REMOVE:
|
||||
remove(args.checkString(1));
|
||||
return LuaValue.TRUE;
|
||||
case RENAME:
|
||||
rename(args.checkString(1), args.checkString(2));
|
||||
return LuaValue.TRUE;
|
||||
case SETLOCALE: {
|
||||
String s = setlocale(args.optString(1,null), args.optString(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(long t2, long t1) {
|
||||
return (t2 - t1) / 1000.;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, long time) {
|
||||
return new java.util.Date(time).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) {
|
||||
System.exit(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
return TMP_PREFIX+(tmpnames++)+TMP_SUFFIX;
|
||||
}
|
||||
}
|
||||
366
src/core/org/luaj/vm2/lib/PackageLib.java
Normal file
366
src/core/org/luaj/vm2/lib/PackageLib.java
Normal file
@@ -0,0 +1,366 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 200 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.LuaThread;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
|
||||
public class PackageLib extends LuaTable {
|
||||
|
||||
public static String DEFAULT_LUA_PATH = "?.lua";
|
||||
|
||||
public LuaValue _G = null;
|
||||
public InputStream STDIN = null;
|
||||
public PrintStream STDOUT = System.out;
|
||||
public LuaTable LOADED = null;
|
||||
public LuaTable PACKAGE = null;
|
||||
|
||||
private static final LuaString _M = LuaString.valueOf("_M");
|
||||
private static final LuaString _NAME = LuaString.valueOf("_NAME");
|
||||
private static final LuaString _PACKAGE = LuaString.valueOf("_PACKAGE");
|
||||
private static final LuaString _DOT = LuaString.valueOf(".");
|
||||
private static final LuaString _LOADERS = LuaString.valueOf("loaders");
|
||||
private static final LuaString _LOADED = LuaString.valueOf("loaded");
|
||||
private static final LuaString _LOADLIB = LuaString.valueOf("loadlib");
|
||||
private static final LuaString _PRELOAD = LuaString.valueOf("preload");
|
||||
private static final LuaString _PATH = LuaString.valueOf("path");
|
||||
private static final LuaString _SEEALL = LuaString.valueOf("seeall");
|
||||
private static final LuaValue _SENTINEL = EMPTYSTRING;
|
||||
|
||||
private static final int MODULE = 1;
|
||||
private static final int REQUIRE = 2;
|
||||
private static final int LOADLIB = 3;
|
||||
private static final int SEEALL = 4;
|
||||
private static final int PRELOAD_LOADER = 5;
|
||||
private static final int LUA_LOADER = 6;
|
||||
private static final int JAVA_LOADER = 7;
|
||||
|
||||
|
||||
public PackageLib(LuaValue _G) {
|
||||
this._G = _G;
|
||||
_G.set( "module", new PackageFuncV(MODULE, "module", _G) );
|
||||
_G.set( "require", new PackageFuncV(REQUIRE, "require",_G) );
|
||||
_G.set( "package", PACKAGE = tableOf( new LuaValue[] {
|
||||
_LOADED, LOADED=tableOf(),
|
||||
_PRELOAD, tableOf(),
|
||||
_PATH, valueOf(DEFAULT_LUA_PATH),
|
||||
_LOADLIB, new PackageFuncV(LOADLIB, "loadlib",_G),
|
||||
_SEEALL, new PackageFuncV(SEEALL, "seeall",_G),
|
||||
_LOADERS, listOf(new LuaValue[] {
|
||||
new PackageFuncV(PRELOAD_LOADER,"preload_loader",_G),
|
||||
new PackageFuncV(LUA_LOADER, "lua_loader",_G),
|
||||
new PackageFuncV(JAVA_LOADER, "java_loader",_G),
|
||||
}),
|
||||
} ) );
|
||||
}
|
||||
|
||||
private class PackageFuncV extends VarArgFunction {
|
||||
public PackageFuncV(int opcode, String name, LuaValue env) {
|
||||
super(name, opcode, env);
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
switch ( opcode ) {
|
||||
case MODULE:
|
||||
return module(args);
|
||||
case REQUIRE:
|
||||
return require(args);
|
||||
case LOADLIB:
|
||||
return loadlib(args);
|
||||
case SEEALL: {
|
||||
LuaTable t = args.checktable(1);
|
||||
LuaValue m = t.getmetatable();
|
||||
if ( m == null )
|
||||
t.setmetatable(m=tableOf());
|
||||
m.set( INDEX, env );
|
||||
return NONE;
|
||||
}
|
||||
case PRELOAD_LOADER: {
|
||||
return loader_preload(args);
|
||||
}
|
||||
case LUA_LOADER: {
|
||||
return loader_Lua(args);
|
||||
}
|
||||
case JAVA_LOADER: {
|
||||
return 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 toString() {
|
||||
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) */
|
||||
module = findtable( _G, 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(0);
|
||||
if ( f == null )
|
||||
error(1, "no calling 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 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.get(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 NIL;
|
||||
} else {
|
||||
table = val;
|
||||
}
|
||||
} while ( e < fname.m_length );
|
||||
return table;
|
||||
}
|
||||
|
||||
private static 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 Varargs require( Varargs args ) {
|
||||
LuaString name = args.checkstring(1);
|
||||
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+"\n"+sb );
|
||||
}
|
||||
|
||||
/* call loader with module name as argument */
|
||||
chunk = loader.call(name);
|
||||
if ( chunk.isfunction() )
|
||||
break;
|
||||
if ( chunk.isstring() )
|
||||
sb.append( chunk.toString() );
|
||||
}
|
||||
|
||||
// load the module using the loader
|
||||
LOADED.set(name, _SENTINEL);
|
||||
LuaValue result = chunk.call(name);
|
||||
if ( ! result.isnil() )
|
||||
LOADED.set( name, result );
|
||||
else if ( LOADED.get(name) == _SENTINEL )
|
||||
LOADED.set( name, result = LuaValue.TRUE );
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Varargs loadlib( Varargs args ) {
|
||||
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private LuaValue loader_Lua( Varargs args ) {
|
||||
String name = args.checkString(1);
|
||||
InputStream is = null;
|
||||
|
||||
// try to use loadfile for the file
|
||||
LuaValue loadfile = _G.get("loadfile");
|
||||
if ( ! loadfile.isfunction() )
|
||||
return valueOf("loadfile is not a function" );
|
||||
|
||||
|
||||
// get package path
|
||||
LuaValue pp = PACKAGE.get(_PATH);
|
||||
if ( ! pp.isstring() )
|
||||
return valueOf("package.path is not a string");
|
||||
String path = pp.toString();
|
||||
|
||||
// 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 = loadfile.invoke(valueOf(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());
|
||||
}
|
||||
|
||||
private LuaValue loader_Java( Varargs args ) {
|
||||
String name = args.checkString(1);
|
||||
Class c = null;
|
||||
LuaValue v = null;
|
||||
try {
|
||||
c = Class.forName(name);
|
||||
v = (LuaValue) c.newInstance();
|
||||
return v;
|
||||
} catch ( ClassNotFoundException cnfe ) {
|
||||
return valueOf("\n\tno class '"+name+"'" );
|
||||
} catch ( Exception e ) {
|
||||
return valueOf("\n\tjava load failed on '"+name+"', "+e );
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/core/org/luaj/vm2/lib/ResourceFinder.java
Normal file
50
src/core/org/luaj/vm2/lib/ResourceFinder.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* 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.InputStream;
|
||||
|
||||
/**
|
||||
* Interface for opening application resource files such as scripts sources.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Jme version implements FileOpener via getResourceAsStream(),
|
||||
* while the Jse version implements it using new File().
|
||||
*
|
||||
* The io library does not use this API for file manipulation.
|
||||
*/
|
||||
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 );
|
||||
}
|
||||
1139
src/core/org/luaj/vm2/lib/StringLib.java
Normal file
1139
src/core/org/luaj/vm2/lib/StringLib.java
Normal file
File diff suppressed because it is too large
Load Diff
93
src/core/org/luaj/vm2/lib/TableLib.java
Normal file
93
src/core/org/luaj/vm2/lib/TableLib.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
public class TableLib extends LuaTable {
|
||||
|
||||
public TableLib() {
|
||||
LibFunction.bind( this, new TableFunc1().getClass(), new String[] {
|
||||
"getn", // (table) -> number
|
||||
"maxn", // (table) -> number
|
||||
} );
|
||||
LibFunction.bind( this, new TableFuncV().getClass(), new String[] {
|
||||
"remove", // (table [, pos]) -> removed-ele
|
||||
"concat", // (table [, sep [, i [, j]]]) -> string
|
||||
"insert", // (table, [pos,] value) -> prev-ele
|
||||
"sort", // (table [, comp]) -> void
|
||||
"foreach", // (table, func) -> void
|
||||
"foreachi", // (table, func) -> void
|
||||
} );
|
||||
}
|
||||
|
||||
public static class TableFunc1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: return arg.checktable().getn();
|
||||
case 1: return valueOf( arg.checktable().maxn());
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class TableFuncV 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
|
||||
args.checktable(1).sort( args.optvalue(2,NIL) );
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/core/org/luaj/vm2/lib/ThreeArgFunction.java
Normal file
58
src/core/org/luaj/vm2/lib/ThreeArgFunction.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*******************************************************************************
|
||||
* 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 public class ThreeArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3);
|
||||
|
||||
public ThreeArgFunction() {
|
||||
}
|
||||
|
||||
public ThreeArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public ThreeArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, 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));
|
||||
}
|
||||
|
||||
}
|
||||
58
src/core/org/luaj/vm2/lib/TwoArgFunction.java
Normal file
58
src/core/org/luaj/vm2/lib/TwoArgFunction.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*******************************************************************************
|
||||
* 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 public class TwoArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call(LuaValue arg1, LuaValue arg2);
|
||||
|
||||
public TwoArgFunction() {
|
||||
}
|
||||
|
||||
public TwoArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public TwoArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, 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));
|
||||
}
|
||||
|
||||
}
|
||||
57
src/core/org/luaj/vm2/lib/VarArgFunction.java
Normal file
57
src/core/org/luaj/vm2/lib/VarArgFunction.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
* 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 public class VarArgFunction extends LibFunction {
|
||||
|
||||
abstract public Varargs invoke(Varargs args);
|
||||
|
||||
public VarArgFunction() {
|
||||
}
|
||||
|
||||
public VarArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public VarArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, env);
|
||||
}
|
||||
|
||||
public final LuaValue call() {
|
||||
return invoke(NONE).arg1();
|
||||
}
|
||||
|
||||
public final 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();
|
||||
}
|
||||
}
|
||||
57
src/core/org/luaj/vm2/lib/ZeroArgFunction.java
Normal file
57
src/core/org/luaj/vm2/lib/ZeroArgFunction.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
* 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 public class ZeroArgFunction extends LibFunction {
|
||||
|
||||
abstract public LuaValue call();
|
||||
|
||||
public ZeroArgFunction() {
|
||||
}
|
||||
|
||||
public ZeroArgFunction( LuaValue env ) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public ZeroArgFunction( String name, int opcode, LuaValue env ) {
|
||||
super(name, opcode, 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();
|
||||
}
|
||||
}
|
||||
45
src/jme/org/luaj/vm2/lib/JmePlatform.java
Normal file
45
src/jme/org/luaj/vm2/lib/JmePlatform.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
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
|
||||
*/
|
||||
public static LuaTable standardGlobals() {
|
||||
LuaTable _G = new BaseLib();
|
||||
new org.luaj.vm2.lib.PackageLib(_G);
|
||||
_G.set( "io", new org.luaj.vm2.lib.jme.JseIoLib() );
|
||||
_G.set( "math", new org.luaj.vm2.lib.MathLib() );
|
||||
_G.set( "os", new org.luaj.vm2.lib.OsLib() );
|
||||
_G.set( "table", new org.luaj.vm2.lib.TableLib() );
|
||||
_G.set( "string", new org.luaj.vm2.lib.StringLib() );
|
||||
CoroutineLib.install( _G );
|
||||
return _G;
|
||||
}
|
||||
|
||||
}
|
||||
199
src/jme/org/luaj/vm2/lib/jme/JseIoLib.java
Normal file
199
src/jme/org/luaj/vm2/lib/jme/JseIoLib.java
Normal file
@@ -0,0 +1,199 @@
|
||||
/*******************************************************************************
|
||||
* 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 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.lib.BaseLib;
|
||||
import org.luaj.vm2.lib.IoLib;
|
||||
|
||||
/**
|
||||
* Implementation of the lua io library based on CLDC 1.0 and StreamConnection.
|
||||
*
|
||||
* Seek is not supported.
|
||||
*/
|
||||
public class JseIoLib extends IoLib {
|
||||
|
||||
public JseIoLib() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected File wrapStdin() throws IOException {
|
||||
return new FileImpl(BaseLib.STDIN);
|
||||
}
|
||||
|
||||
protected File wrapStdout() throws IOException {
|
||||
return new FileImpl(BaseLib.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 toString() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.luaj.vm2.script.LuaScriptEngineFactory
|
||||
199
src/jse/lua.java
Normal file
199
src/jse/lua.java
Normal file
@@ -0,0 +1,199 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
import org.luaj.vm2.lib.JsePlatform;
|
||||
|
||||
|
||||
/**
|
||||
* 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" +
|
||||
" -- 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 {
|
||||
|
||||
// new lua state
|
||||
LuaC.install();
|
||||
_G = JsePlatform.standardGlobals();
|
||||
DebugLib.install( _G );
|
||||
|
||||
// process args
|
||||
boolean interactive = (args.length == 0);
|
||||
boolean versioninfo = false;
|
||||
boolean processing = true;
|
||||
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 'l':
|
||||
if ( ++i >= args.length )
|
||||
usageExit();
|
||||
loadLibrary( args[i] );
|
||||
break;
|
||||
case 'i':
|
||||
interactive = true;
|
||||
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);
|
||||
|
||||
// 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+1 );
|
||||
break;
|
||||
} else if ( args[i].length() <= 1 ) {
|
||||
processScript( System.in, "-", args, i+1 );
|
||||
break;
|
||||
} else {
|
||||
switch ( args[i].charAt(1) ) {
|
||||
case 'l':
|
||||
++i;
|
||||
break;
|
||||
case 'e':
|
||||
++i;
|
||||
processScript( new ByteArrayInputStream(args[i].getBytes()), args[i], null, 0 );
|
||||
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 offset ) throws IOException {
|
||||
try {
|
||||
LuaClosure c;
|
||||
try {
|
||||
Prototype p = LoadState.undump(script, chunkname );
|
||||
c = new LuaClosure(p,_G);
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
LuaValue[] a = new LuaValue[args.length-offset];
|
||||
for ( int i=0; i<a.length; i++ )
|
||||
a[i] = LuaValue.valueOf(args[offset+i]);
|
||||
c.invoke( a );
|
||||
} catch ( Throwable t ) {
|
||||
t.printStackTrace( System.err );
|
||||
}
|
||||
}
|
||||
|
||||
private static final String[] NOARGS = {};
|
||||
|
||||
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()), "-", NOARGS, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
179
src/jse/luac.java
Normal file
179
src/jse/luac.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
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.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 ( Throwable t ) {
|
||||
t.printStackTrace( System.err );
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
179
src/jse/luajc.java
Normal file
179
src/jse/luajc.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/*******************************************************************************
|
||||
* 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.compiler.DumpState;
|
||||
import org.luaj.vm2.luajc.antlr.AntlrLuaJCompiler;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler for lua files to compile lua sources into java sources.
|
||||
*/
|
||||
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,antlr-3.1.3.jar luajc [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 = "luacj.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 luajc( args );
|
||||
}
|
||||
|
||||
private luajc( 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 {
|
||||
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
|
||||
String source = AntlrLuaJCompiler.compile(script, chunkname);
|
||||
|
||||
// list the chunk
|
||||
if (list)
|
||||
System.out.println(source);
|
||||
|
||||
// write out the chunk
|
||||
if (!parseonly) {
|
||||
FileOutputStream fos = new FileOutputStream( chunkname+".java" );
|
||||
fos.write( source.getBytes() );
|
||||
fos.close();
|
||||
}
|
||||
|
||||
} catch ( Throwable t ) {
|
||||
t.printStackTrace( System.err );
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/jse/org/luaj/vm2/lib/JsePlatform.java
Normal file
52
src/jse/org/luaj/vm2/lib/JsePlatform.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*******************************************************************************
|
||||
* 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.lib.CoroutineLib;
|
||||
import org.luaj.vm2.lib.jse.JseBaseLib;
|
||||
import org.luaj.vm2.lib.jse.JseIoLib;
|
||||
import org.luaj.vm2.lib.jse.JseMathLib;
|
||||
import org.luaj.vm2.lib.jse.JseOsLib;
|
||||
import org.luaj.vm2.lib.jse.LuajavaLib;
|
||||
|
||||
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
|
||||
*/
|
||||
public static LuaTable standardGlobals() {
|
||||
LuaTable _G = new JseBaseLib();
|
||||
new org.luaj.vm2.lib.PackageLib(_G);
|
||||
_G.set( "io", new org.luaj.vm2.lib.jse.JseIoLib() );
|
||||
_G.set( "math", new org.luaj.vm2.lib.jse.JseMathLib() );
|
||||
_G.set( "os", new org.luaj.vm2.lib.jse.JseOsLib() );
|
||||
_G.set( "table", new org.luaj.vm2.lib.TableLib() );
|
||||
_G.set( "string", new org.luaj.vm2.lib.StringLib() );
|
||||
_G.set( "luajava", new org.luaj.vm2.lib.jse.LuajavaLib() );
|
||||
CoroutineLib.install(_G);
|
||||
return _G;
|
||||
}
|
||||
|
||||
}
|
||||
91
src/jse/org/luaj/vm2/lib/jse/CoerceJavaToLua.java
Normal file
91
src/jse/org/luaj/vm2/lib/jse/CoerceJavaToLua.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*******************************************************************************
|
||||
* 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.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.LuaValue;
|
||||
|
||||
|
||||
public class CoerceJavaToLua {
|
||||
|
||||
public static interface Coercion {
|
||||
public LuaValue coerce( Object javaValue );
|
||||
};
|
||||
|
||||
private static 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( Float.class, doubleCoercion );
|
||||
COERCIONS.put( Double.class, doubleCoercion );
|
||||
COERCIONS.put( String.class, stringCoercion );
|
||||
}
|
||||
|
||||
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 )
|
||||
return c.coerce( o );
|
||||
return LuajavaLib.toUserdata( o, clazz );
|
||||
}
|
||||
|
||||
}
|
||||
262
src/jse/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
Normal file
262
src/jse/org/luaj/vm2/lib/jse/CoerceLuaToJava.java
Normal file
@@ -0,0 +1,262 @@
|
||||
/*******************************************************************************
|
||||
* 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.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
|
||||
public class CoerceLuaToJava {
|
||||
|
||||
public static interface Coercion {
|
||||
public Object coerce( LuaValue value );
|
||||
public int score( LuaValue value );
|
||||
};
|
||||
|
||||
private static Map COERCIONS = new HashMap();
|
||||
private static Coercion OBJECT_COERCION;
|
||||
|
||||
static {
|
||||
Coercion boolCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNIL:
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 0;
|
||||
case LuaValue.TNUMBER:
|
||||
return 1;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion byteCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Byte( (byte) value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion charCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Character( (char) value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion shortCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Short( (short) value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion intCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Integer( value.toint() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 0: 1);
|
||||
case LuaValue.TBOOLEAN:
|
||||
case LuaValue.TNIL:
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion longCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Long( value.tolong() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 2);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion floatCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Float( value.tofloat() );
|
||||
}
|
||||
public int score( LuaValue value ) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return 1;
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion doubleCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return new Double( value.todouble() );
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()? 1: 0);
|
||||
case LuaValue.TBOOLEAN:
|
||||
return 2;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion stringCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
return value.toString();
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TUSERDATA:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
Coercion objectCoercion = new Coercion() {
|
||||
public Object coerce(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TUSERDATA:
|
||||
return value.optuserdata(Object.class, null);
|
||||
case LuaValue.TSTRING:
|
||||
return value.toString();
|
||||
case LuaValue.TNUMBER:
|
||||
return (value.isinttype()?
|
||||
new Integer(value.toint()):
|
||||
new Double(value.todouble()));
|
||||
case LuaValue.TBOOLEAN:
|
||||
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
|
||||
case LuaValue.TNIL:
|
||||
return null;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
public int score(LuaValue value) {
|
||||
switch ( value.type() ) {
|
||||
case LuaValue.TSTRING:
|
||||
return 0;
|
||||
default:
|
||||
return 0x10;
|
||||
}
|
||||
}
|
||||
};
|
||||
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( Object.class, objectCoercion );
|
||||
}
|
||||
|
||||
static Object coerceArg(LuaValue v, Class type) {
|
||||
Coercion co = (Coercion) COERCIONS.get( type );
|
||||
if ( co != null )
|
||||
return co.coerce( v );
|
||||
Object o = v.optuserdata(type, null);
|
||||
if ( o != null )
|
||||
return o;
|
||||
return v;
|
||||
}
|
||||
|
||||
static Object[] coerceArgs(LuaValue[] suppliedArgs, Class[] parameterTypes) {
|
||||
int nargs = suppliedArgs.length;
|
||||
int n = parameterTypes.length;
|
||||
Object[] args = new Object[n];
|
||||
for ( int i=0; i<n && i<nargs; i++ )
|
||||
args[i] = coerceArg( suppliedArgs[i], parameterTypes[i] );
|
||||
return args;
|
||||
}
|
||||
|
||||
/*
|
||||
* Score parameter types for match with supplied parameter list
|
||||
*
|
||||
* 1) exact number of args
|
||||
* 2) java has more args
|
||||
* 3) java has less args
|
||||
* 4) types coerce well
|
||||
*/
|
||||
static int scoreParamTypes(LuaValue[] suppliedArgs, Class[] paramTypes) {
|
||||
int nargs = suppliedArgs.length;
|
||||
int njava = paramTypes.length;
|
||||
int score = (njava == nargs? 0: njava > nargs? 0x4000: 0x8000);
|
||||
for ( int i=0; i<nargs && i<njava; i++ ) {
|
||||
LuaValue a = suppliedArgs[i];
|
||||
Class c = paramTypes[i];
|
||||
Coercion co = (Coercion) COERCIONS.get( c );
|
||||
if ( co != null ) {
|
||||
score += co.score( a );
|
||||
} else if ( a.optuserdata(c, null) == null ) {
|
||||
score += 0x10000;
|
||||
} else {
|
||||
score += 0x100;
|
||||
}
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
}
|
||||
73
src/jse/org/luaj/vm2/lib/jse/JseBaseLib.java
Normal file
73
src/jse/org/luaj/vm2/lib/jse/JseBaseLib.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* Base library implementation, targeted for JSE platforms.
|
||||
*
|
||||
* Implements the same library functions as org.luaj.lib.BaseLib,
|
||||
* but looks in the current directory for files loaded via
|
||||
* loadfile(), dofile() and require().
|
||||
*
|
||||
* @see org.luaj.vm2.lib.jse.JseBaseLib
|
||||
*/
|
||||
public class JseBaseLib extends org.luaj.vm2.lib.BaseLib {
|
||||
|
||||
static {
|
||||
STDIN = System.in;
|
||||
}
|
||||
|
||||
/** Construct a JSE base library instance */
|
||||
public JseBaseLib() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
191
src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
Normal file
191
src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*******************************************************************************
|
||||
* 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.lib.IoLib;
|
||||
|
||||
/**
|
||||
* Implementation of the lua io library for J2se using RandomAccessFile
|
||||
* to implement seek.
|
||||
*/
|
||||
public class JseIoLib extends IoLib {
|
||||
|
||||
public JseIoLib() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected File wrapStdin() throws IOException {
|
||||
return new FileImpl(JseBaseLib.STDIN);
|
||||
}
|
||||
|
||||
protected File wrapStdout() throws IOException {
|
||||
return new FileImpl(JseBaseLib.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 toString() {
|
||||
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 ) {
|
||||
int c = file.read();
|
||||
file.seek(file.getFilePointer()-1);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
80
src/jse/org/luaj/vm2/lib/jse/JseMathLib.java
Normal file
80
src/jse/org/luaj/vm2/lib/jse/JseMathLib.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*******************************************************************************
|
||||
* 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 org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* Math library implementation for use on JSE platform.
|
||||
*
|
||||
* Implements all "math" functions, including platform-specific
|
||||
* overrides for pow() and exp()
|
||||
*/
|
||||
public class JseMathLib extends org.luaj.vm2.lib.MathLib {
|
||||
|
||||
public JseMathLib() {
|
||||
LibFunction.bind( this, new J2seMathFunc1().getClass(), new String[] {
|
||||
"acos", "asin", "atan", "cosh",
|
||||
"exp", "log", "log10", "sinh",
|
||||
"tanh" } );
|
||||
LibFunction.bind( this, new J2seMathFunc2().getClass(), new String[] {
|
||||
"atan2", "pow", } );
|
||||
|
||||
}
|
||||
|
||||
public static class J2seMathFunc1 extends OneArgFunction {
|
||||
public LuaValue call(LuaValue arg) {
|
||||
switch ( opcode ) {
|
||||
case 0: return valueOf(Math.acos(arg.todouble()));
|
||||
case 1: return valueOf(Math.asin(arg.todouble()));
|
||||
case 2: return valueOf(Math.atan(arg.todouble()));
|
||||
case 3: return valueOf(Math.cosh(arg.todouble()));
|
||||
case 4: return valueOf(Math.exp(arg.todouble()));
|
||||
case 5: return valueOf(Math.log(arg.todouble()));
|
||||
case 6: return valueOf(Math.log10(arg.todouble()));
|
||||
case 7: return valueOf(Math.sinh(arg.todouble()));
|
||||
case 8: return valueOf(Math.tanh(arg.todouble()));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
public static class J2seMathFunc2 extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue arg1,LuaValue arg2) {
|
||||
switch ( opcode ) {
|
||||
case 0: return valueOf(Math.atan2(arg1.todouble(), arg2.todouble()));
|
||||
case 1: return valueOf(Math.pow(arg1.todouble(), arg2.todouble()));
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Faster, better version of pow() used by arithmetic operator ^ */
|
||||
public double dpow_d(double a, double b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
98
src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
Normal file
98
src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Implementation of the lua os library for J2se.
|
||||
*
|
||||
* <p>Implements features specific to the J2se environment:
|
||||
* <bl>
|
||||
* <li>execute()</li>
|
||||
* <li>remove()</li>
|
||||
* <li>rename()</li>
|
||||
* <li>tmpname()</li>
|
||||
* </bl>
|
||||
*
|
||||
* @see org.luaj.vm2.lib.OsLib
|
||||
*/
|
||||
public class JseOsLib extends org.luaj.vm2.lib.OsLib {
|
||||
|
||||
/** return code indicating the execute() threw an I/O exception */
|
||||
public static int EXEC_IOEXCEPTION = -1;
|
||||
|
||||
/** 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
372
src/jse/org/luaj/vm2/lib/jse/LuajavaLib.java
Normal file
372
src/jse/org/luaj/vm2/lib/jse/LuajavaLib.java
Normal file
@@ -0,0 +1,372 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
|
||||
/** LuaJava-like bindings to Java scripting.
|
||||
*
|
||||
* TODO: coerce types on way in and out, pick method base on arg count ant types.
|
||||
*/
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaUserdata;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
|
||||
public class LuajavaLib extends LuaTable {
|
||||
|
||||
private static final int BINDCLASS = 0;
|
||||
private static final int NEWINSTANCE = 1;
|
||||
private static final int NEW = 2;
|
||||
private static final int CREATEPROXY = 3;
|
||||
private static final int LOADLIB = 4;
|
||||
|
||||
private static final String[] NAMES = {
|
||||
"bindClass",
|
||||
"newInstance",
|
||||
"new",
|
||||
"createProxy",
|
||||
"loadLib" };
|
||||
|
||||
private static final Map classMetatables = new HashMap();
|
||||
|
||||
public static void install(LuaValue globals) {
|
||||
globals.set("luajava", new LuajavaLib());
|
||||
}
|
||||
|
||||
public LuajavaLib() {
|
||||
LibFunction.bind( this, LuajavaFuncV.class, NAMES );
|
||||
}
|
||||
|
||||
// perform a lua call
|
||||
public static class LuajavaFuncV extends VarArgFunction {
|
||||
|
||||
public Varargs invoke(final Varargs args) {
|
||||
try {
|
||||
switch ( opcode ) {
|
||||
case BINDCLASS: {
|
||||
final Class clazz = Class.forName(args.checkString(1));
|
||||
return toUserdata( clazz, clazz );
|
||||
}
|
||||
case NEWINSTANCE:
|
||||
case NEW: {
|
||||
// get constructor
|
||||
final LuaValue c = args.checkvalue(1);
|
||||
final Class clazz = (opcode==NEWINSTANCE? Class.forName(c.toString()): (Class) c.checkuserdata(Class.class));
|
||||
final ParamsList params = new ParamsList( args );
|
||||
final Constructor con = resolveConstructor( clazz, params );
|
||||
|
||||
// coerce args, construct instance
|
||||
Object[] cargs = CoerceLuaToJava.coerceArgs( params.values, con.getParameterTypes() );
|
||||
Object o = con.newInstance( cargs );
|
||||
|
||||
// return result
|
||||
return toUserdata( o, clazz );
|
||||
}
|
||||
|
||||
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] = Class.forName(args.checkString(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;
|
||||
int n = args!=null? args.length: 0;
|
||||
LuaValue[] 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.coerceArg(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.checkString(1);
|
||||
String methodname = args.checkString(2);
|
||||
Class clazz = Class.forName(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 (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParamsList {
|
||||
public final LuaValue[] values;
|
||||
public final Class[] classes;
|
||||
public int hash;
|
||||
ParamsList( Varargs args ) {
|
||||
int n = Math.max(args.narg()-1,0);
|
||||
values = new LuaValue[n];
|
||||
classes = new Class[n];
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
values[i] = args.arg(i+2);
|
||||
classes[i] = values[i].getClass();
|
||||
hash += classes[i].hashCode();
|
||||
}
|
||||
}
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
public boolean equals( Object o ) {
|
||||
return ( o instanceof ParamsList )?
|
||||
Arrays.equals( classes, ((ParamsList) o).classes ):
|
||||
false;
|
||||
}
|
||||
}
|
||||
|
||||
static LuaUserdata toUserdata(Object instance, final Class clazz) {
|
||||
LuaTable mt = (LuaTable) classMetatables.get(clazz);
|
||||
if ( mt == null ) {
|
||||
mt = new LuaTable();
|
||||
mt.set( LuaValue.INDEX, new TwoArgFunction() {
|
||||
public LuaValue call(LuaValue table, LuaValue key) {
|
||||
final String s = key.toString();
|
||||
try {
|
||||
Field f = clazz.getField(s);
|
||||
Object o = f.get(table.checkuserdata(Object.class));
|
||||
return CoerceJavaToLua.coerce( o );
|
||||
} catch (NoSuchFieldException nsfe) {
|
||||
return new LMethod(clazz,s);
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
mt.set( LuaValue.NEWINDEX, new ThreeArgFunction() {
|
||||
public LuaValue call(LuaValue table, LuaValue key, LuaValue val) {
|
||||
String s = key.toString();
|
||||
try {
|
||||
Field f = clazz.getField(s);
|
||||
Object v = CoerceLuaToJava.coerceArg(val, f.getType());
|
||||
f.set(table.checkuserdata(Object.class),v);
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
});
|
||||
classMetatables.put(clazz, mt);
|
||||
}
|
||||
return LuaValue.userdataOf(instance,mt);
|
||||
}
|
||||
|
||||
private static final class LMethod extends VarArgFunction {
|
||||
private final Class clazz;
|
||||
private final String s;
|
||||
private LMethod(Class clazz, String s) {
|
||||
this.clazz = clazz;
|
||||
this.s = s;
|
||||
}
|
||||
public String toString() {
|
||||
return clazz.getName()+"."+s+"()";
|
||||
}
|
||||
public Varargs invoke(Varargs args) {
|
||||
try {
|
||||
// find the method
|
||||
Object instance = args.checkuserdata(1,Object.class);
|
||||
ParamsList params = new ParamsList( args );
|
||||
Method meth = resolveMethod( clazz, s, params );
|
||||
|
||||
// coerce the arguments
|
||||
Object[] margs = CoerceLuaToJava.coerceArgs( params.values, meth.getParameterTypes() );
|
||||
Object result = meth.invoke( instance, margs );
|
||||
|
||||
// coerce the result
|
||||
return CoerceJavaToLua.coerce(result);
|
||||
} catch (Exception e) {
|
||||
throw new LuaError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Map consCache =
|
||||
new HashMap();
|
||||
|
||||
private static Map consIndex =
|
||||
new HashMap();
|
||||
|
||||
private static Constructor resolveConstructor(Class clazz, ParamsList params ) {
|
||||
|
||||
// get the cache
|
||||
Map cache = (Map) consCache.get( clazz );
|
||||
if ( cache == null )
|
||||
consCache.put( clazz, cache = new HashMap() );
|
||||
|
||||
// look up in the cache
|
||||
Constructor c = (Constructor) cache.get( params );
|
||||
if ( c != null )
|
||||
return c;
|
||||
|
||||
// get index
|
||||
Map index = (Map) consIndex.get( clazz );
|
||||
if ( index == null ) {
|
||||
consIndex.put( clazz, index = new HashMap() );
|
||||
Constructor[] cons = clazz.getConstructors();
|
||||
for ( int i=0; i<cons.length; i++ ) {
|
||||
Constructor con = cons[i];
|
||||
Integer n = new Integer( con.getParameterTypes().length );
|
||||
List list = (List) index.get(n);
|
||||
if ( list == null )
|
||||
index.put( n, list = new ArrayList() );
|
||||
list.add( con );
|
||||
}
|
||||
}
|
||||
|
||||
// figure out best list of arguments == supplied args
|
||||
Integer n = new Integer( params.classes.length );
|
||||
List list = (List) index.get(n);
|
||||
if ( list == null )
|
||||
throw new IllegalArgumentException("no constructor with "+n+" args");
|
||||
|
||||
// find constructor with best score
|
||||
int bests = Integer.MAX_VALUE;
|
||||
int besti = 0;
|
||||
for ( int i=0, size=list.size(); i<size; i++ ) {
|
||||
Constructor con = (Constructor) list.get(i);
|
||||
int s = CoerceLuaToJava.scoreParamTypes(params.values, con.getParameterTypes());
|
||||
if ( s < bests ) {
|
||||
bests = s;
|
||||
besti = i;
|
||||
}
|
||||
}
|
||||
|
||||
// put into cache
|
||||
c = (Constructor) list.get(besti);
|
||||
cache.put( params, c );
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
private static Map methCache =
|
||||
new HashMap();
|
||||
|
||||
private static Map methIndex =
|
||||
new HashMap();
|
||||
|
||||
private static Method resolveMethod(Class clazz, String methodName, ParamsList params ) {
|
||||
|
||||
// get the cache
|
||||
Map nameCache = (Map) methCache.get( clazz );
|
||||
if ( nameCache == null )
|
||||
methCache.put( clazz, nameCache = new HashMap() );
|
||||
Map cache = (Map) nameCache.get( methodName );
|
||||
if ( cache == null )
|
||||
nameCache.put( methodName, cache = new HashMap() );
|
||||
|
||||
// look up in the cache
|
||||
Method m = (Method) cache.get( params );
|
||||
if ( m != null )
|
||||
return m;
|
||||
|
||||
// get index
|
||||
Map index = (Map) methIndex.get( clazz );
|
||||
if ( index == null ) {
|
||||
methIndex.put( clazz, index = new HashMap() );
|
||||
Method[] meths = clazz.getMethods();
|
||||
for ( int i=0; i<meths.length; i++ ) {
|
||||
Method meth = meths[i];
|
||||
String s = meth.getName();
|
||||
Integer n = new Integer(meth.getParameterTypes().length);
|
||||
Map map = (Map) index.get(s);
|
||||
if ( map == null )
|
||||
index.put( s, map = new HashMap() );
|
||||
List list = (List) map.get(n);
|
||||
if ( list == null )
|
||||
map.put( n, list = new ArrayList() );
|
||||
list.add( meth );
|
||||
}
|
||||
}
|
||||
|
||||
// figure out best list of arguments == supplied args
|
||||
Map map = (Map) index.get(methodName);
|
||||
if ( map == null )
|
||||
throw new IllegalArgumentException("no method named '"+methodName+"'");
|
||||
Integer n = new Integer( params.classes.length );
|
||||
List list = (List) map.get(n);
|
||||
if ( list == null )
|
||||
throw new IllegalArgumentException("no method named '"+methodName+"' with "+n+" args");
|
||||
|
||||
// find constructor with best score
|
||||
int bests = Integer.MAX_VALUE;
|
||||
int besti = 0;
|
||||
for ( int i=0, size=list.size(); i<size; i++ ) {
|
||||
Method meth = (Method) list.get(i);
|
||||
int s = CoerceLuaToJava.scoreParamTypes(params.values, meth.getParameterTypes());
|
||||
if ( s < bests ) {
|
||||
bests = s;
|
||||
besti = i;
|
||||
}
|
||||
}
|
||||
|
||||
// put into cache
|
||||
m = (Method) list.get(besti);
|
||||
cache.put( params, m );
|
||||
return m;
|
||||
}
|
||||
|
||||
}
|
||||
785
src/jse/org/luaj/vm2/luajc/JavaCodeGenerator.java
Normal file
785
src/jse/org/luaj/vm2/luajc/JavaCodeGenerator.java
Normal file
@@ -0,0 +1,785 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.luaj.vm2.lib.LibFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSChunk;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression;
|
||||
import org.luaj.vm2.luajc.lst.LSField;
|
||||
import org.luaj.vm2.luajc.lst.LSFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSIfStatement;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable;
|
||||
import org.luaj.vm2.luajc.lst.Name;
|
||||
import org.luaj.vm2.luajc.lst.Scope;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.BinopExpr;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.FunctionExpr;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.NumberConstant;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.StringConstant;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.TableConstructor;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.UnopExpr;
|
||||
import org.luaj.vm2.luajc.lst.LSExpression.VarargsRef;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.BreakStat;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.DoBlock;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.ForList;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.ForLoop;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.FunctionCall;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.LocalAssign;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.LocalFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.RepeatUntil;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.ReturnStat;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.VarAssign;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.VarNamedFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSStatement.WhileLoop;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.CallFunction;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.CallMethod;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Field;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Index;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Method;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.NameReference;
|
||||
import org.luaj.vm2.luajc.lst.LSVariable.Parentheses;
|
||||
|
||||
public class JavaCodeGenerator {
|
||||
|
||||
public static String toJava(LSChunk chunk) {
|
||||
JavaCodeGenerator jcg = new JavaCodeGenerator();
|
||||
return jcg.writeChunk( chunk );
|
||||
}
|
||||
|
||||
public final Stack<StringBuffer> stringBuffers = new Stack<StringBuffer>();
|
||||
public StringBuffer sb;
|
||||
private int indent = 0;
|
||||
|
||||
public JavaCodeGenerator() {
|
||||
this.sb = new StringBuffer();
|
||||
}
|
||||
|
||||
private String writeChunk(LSChunk chunk) {
|
||||
pushFunctionContext();
|
||||
writeln( "import org.luaj.vm2.*;" );
|
||||
writeln( "import org.luaj.vm2.lib.*;" );
|
||||
writeln();
|
||||
writeln( "public class "+chunk.chunkname+" extends VarArgFunction {" );
|
||||
++indent;
|
||||
writeln( "public Varargs invoke(Varargs $args) {");
|
||||
++indent;
|
||||
writeFunctionBody( chunk.function );
|
||||
--indent;
|
||||
writeln( "}");
|
||||
--indent;
|
||||
// TODO: write out chunk constants
|
||||
writeln( "}" );
|
||||
return popFunctionContext();
|
||||
}
|
||||
|
||||
private void pushFunctionContext() {
|
||||
stringBuffers.push( sb = new StringBuffer() );
|
||||
}
|
||||
|
||||
private String popFunctionContext() {
|
||||
String v = stringBuffers.pop().toString();
|
||||
sb = stringBuffers.isEmpty()? null: stringBuffers.lastElement();
|
||||
return v;
|
||||
}
|
||||
|
||||
private void writeFunctionBody(LSFunction function) {
|
||||
if ( function.hasandlogic || function.hasorlogic )
|
||||
writeln( "LuaValue $t;" );
|
||||
if ( function.hasvarargassign )
|
||||
writeln( "Varargs $v;" );
|
||||
writeStatements( function.stats );
|
||||
if ( LSStatement.isNextStatementReachable( function.stats ) )
|
||||
writeln( "return NONE;" );
|
||||
}
|
||||
|
||||
private void writeStatements(List<LSStatement> statements) {
|
||||
for ( LSStatement s : statements ) {
|
||||
writeStatement( s );
|
||||
}
|
||||
}
|
||||
|
||||
private void writeStatement(LSStatement s) {
|
||||
if ( s==null ) return;
|
||||
switch ( s.type ) {
|
||||
case functionCall: writeFunctionCall( (LSStatement.FunctionCall) s ); break;
|
||||
case doBlock: writeDoBlock( (LSStatement.DoBlock) s ); break;
|
||||
case whileLoop: writeWhileLoop( (LSStatement.WhileLoop) s ); break;
|
||||
case repeatUntil: writeRepeatUntil( (LSStatement.RepeatUntil) s ); break;
|
||||
case varAssign: writeVarAssign( (LSStatement.VarAssign) s ); break;
|
||||
case forLoop: writeForLoop( (LSStatement.ForLoop) s ); break;
|
||||
case forList: writeForList( (LSStatement.ForList) s ); break;
|
||||
case varNamedFunction: writeVarNamedFunction((LSStatement.VarNamedFunction) s ); break;
|
||||
case localFunction: writeLocalFunction( (LSStatement.LocalFunction) s ); break;
|
||||
case localAssign: writeLocalAssign( (LSStatement.LocalAssign) s ); break;
|
||||
case returnStat: writeReturnStat( (LSStatement.ReturnStat) s ); break;
|
||||
case breakStat: writeBreakStat( (LSStatement.BreakStat) s ); break;
|
||||
case ifStat: writeIfStat( (LSIfStatement) s ); break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeFunctionCall(FunctionCall s) {
|
||||
writeindent();
|
||||
write( eval(s.variable)+";" );
|
||||
writeln();
|
||||
}
|
||||
|
||||
private void writeDoBlock(DoBlock s) {
|
||||
writeln( "{" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private void writeWhileLoop(WhileLoop s) {
|
||||
writeln( "while ("+eval(s.condition)+".toboolean()) {" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private void writeRepeatUntil(RepeatUntil s) {
|
||||
writeln( "do {" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "} while (!"+eval(s.condition)+");" );
|
||||
}
|
||||
|
||||
private void writeForLoop(ForLoop s) {
|
||||
writeln( "{" );
|
||||
++indent;
|
||||
// TODO: name handling, also upvalues!
|
||||
String index = javaName( s.index );
|
||||
String limit = javaName( s.scope.declare("$limit") );
|
||||
String step = javaName( s.scope.declare("$step") );
|
||||
writeln( "LuaValue "+index+"="+eval(s.initial)+";" );
|
||||
writeln( "final LuaValue "+limit+"="+eval(s.limit)+";" );
|
||||
if ( s.step != null ) {
|
||||
writeln( "final LuaValue "+step+"="+eval(s.step)+";" );
|
||||
writeln( "final boolean "+step+"$b="+step+".gt_b(0);" );
|
||||
}
|
||||
if ( s.step != null ) {
|
||||
writeln( "for ( ; "+index+".testfor_b("+limit+","+step+"$b); "+index+"="+index+".add("+step+") ) {" );
|
||||
} else {
|
||||
writeln( "for ( ; "+index+".lteq_b("+limit+"); "+index+"="+index+".add(1) ) {" );
|
||||
}
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private void writeForList(ForList s) {
|
||||
writeln( "{" );
|
||||
++indent;
|
||||
List<String> exprs = evalExpressions(s.expressions, 3, s.scope);
|
||||
// TODO: upvalues handling!
|
||||
String fun = javaName( s.scope.declare("$f") );
|
||||
String sta = javaName( s.scope.declare("$s") );
|
||||
String var = javaName( s.scope.declare("$var") );
|
||||
String res = javaName( s.scope.declare("$res") );
|
||||
writeln( "LuaValue "+fun+"="+exprs.get(0)+";" );
|
||||
writeln( "LuaValue "+sta+"="+exprs.get(1)+";" );
|
||||
writeln( "LuaValue "+var+"="+exprs.get(2)+";" );
|
||||
writeln( "while ( true ) {" );
|
||||
++indent;
|
||||
writeln( "Varargs "+res+" = "+fun+".invoke(varargsOf("+sta+","+var+"));" );
|
||||
for ( int i=1, n=s.names.size(); i<=n; i++ )
|
||||
writeln( "LuaValue "+javaName(s.names.get(i-1))+"="+res+".arg("+i+");" );
|
||||
writeln( var+"="+javaName(s.names.get(0))+";" );
|
||||
writeln( "if ( "+var+".isnil() ) break;" );
|
||||
writeStatements( s.statements );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
private final static Set<String> reserved = new HashSet<String>();
|
||||
static {
|
||||
String[] specials = {
|
||||
// keywors used by our code generator
|
||||
"name", "opcode", "env",
|
||||
|
||||
// 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",
|
||||
};
|
||||
for ( int i=0; i<specials.length; i++ )
|
||||
reserved.add( specials[i] );
|
||||
java.lang.reflect.Field[] f = LibFunction.class.getFields();
|
||||
for ( int i=0; i<f.length; i++ )
|
||||
reserved.add( f[i].getName() );
|
||||
}
|
||||
|
||||
private String javaName(Name name) {
|
||||
return name.innerrevision>0?
|
||||
name.luaname+"$"+name.innerrevision:
|
||||
reserved.contains(name.luaname)? (name.luaname+"$"): name.luaname;
|
||||
}
|
||||
|
||||
private void writeVarNamedFunction(VarNamedFunction s) {
|
||||
String funcdef = evalFuncbody(s.funcbody);
|
||||
writeAssign( s.funcname, funcdef );
|
||||
}
|
||||
|
||||
private String evalFuncbody(LSFunction funcbody) {
|
||||
pushFunctionContext();
|
||||
int n = funcbody.paramnames!=null? funcbody.paramnames.size(): 0;
|
||||
boolean isvararg = (funcbody.isvararg || n > 3);
|
||||
if ( isvararg ) {
|
||||
write( "new VarArgFunction(env) {\n" );
|
||||
++indent;
|
||||
writeln( "public Varargs invoke(Varargs $args) {" );
|
||||
++indent;
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
Name name = funcbody.paramnames.get(i);
|
||||
if ( name.isupvalue )
|
||||
writeln( "final LuaValue[] "+javaName(funcbody.paramnames.get(i))+"={$args.arg("+(i+1)+")};" );
|
||||
else
|
||||
writeln( "LuaValue "+javaName(funcbody.paramnames.get(i))+"=$args.arg("+(i+1)+");" );
|
||||
}
|
||||
if ( (n > 0 && funcbody.usesvarargs) || funcbody.needsarg )
|
||||
writeln( "$args = $args.subargs("+(n+1)+");" );
|
||||
if ( funcbody.needsarg )
|
||||
writeln( "LuaValue arg = new LuaTable($args);" );
|
||||
else if ( funcbody.hasarg )
|
||||
writeln( "LuaValue arg = NIL;" );
|
||||
writeFunctionBody(funcbody);
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeindent();
|
||||
write( "}" );
|
||||
} else {
|
||||
write(
|
||||
n==0? "new ZeroArgFunction(env) {\n":
|
||||
n==1? "new OneArgFunction(env) {\n":
|
||||
n==2? "new TwoArgFunction(env) {\n":
|
||||
"new ThreeArgFunction(env) {\n" );
|
||||
++indent;
|
||||
writeindent();
|
||||
write( "public LuaValue call(");
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if (i>0) write( "," );
|
||||
Name name = funcbody.paramnames.get(i);
|
||||
if ( name.isupvalue )
|
||||
write( "LuaValue "+javaName(name)+"$u" );
|
||||
else
|
||||
write( "LuaValue "+javaName(name) );
|
||||
}
|
||||
write( ") {" );
|
||||
writeln();
|
||||
++indent;
|
||||
|
||||
// upvalues
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
Name name = funcbody.paramnames.get(i);
|
||||
if ( name.isupvalue )
|
||||
writeln( "final LuaValue[] "+javaName(name)+"={"+javaName(name)+"$u};" );
|
||||
}
|
||||
|
||||
// function body
|
||||
writeFunctionBody(funcbody);
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
--indent;
|
||||
writeindent();
|
||||
write( "}" );
|
||||
}
|
||||
return popFunctionContext();
|
||||
}
|
||||
|
||||
private void writeVarAssign(VarAssign s) {
|
||||
int nassign = s.variables.size();
|
||||
List<String> exprs = evalExpressions(s.expressions, nassign, s.scope);
|
||||
for ( int i=0; i<nassign; i++ )
|
||||
writeAssign( s.variables.get(i), exprs.get(i) );
|
||||
for ( int i=nassign; i<exprs.size(); i++ )
|
||||
writeln( exprs.get(i) );
|
||||
}
|
||||
|
||||
private void writeLocalFunction(LocalFunction s) {
|
||||
String funcdef = evalFuncbody(s.funcbody);
|
||||
if ( s.name.isupvalue ) {
|
||||
writeln( "final LuaValue[] "+javaName(s.name)+"={null};" );
|
||||
writeln( javaName(s.name)+"[0]="+funcdef+";" );
|
||||
} else
|
||||
writeln( "LuaValue "+javaName(s.name)+"="+funcdef+";" );
|
||||
}
|
||||
|
||||
private void writeLocalAssign(LocalAssign s) {
|
||||
int nassign = s.names.size();
|
||||
List<String> exprs = evalExpressions(s.expressions, nassign, s.scope);
|
||||
for ( int i=0; i<nassign; i++ ) {
|
||||
Name name= s.names.get(i);
|
||||
if ( name.isupvalue )
|
||||
writeln( "final LuaValue[] "+javaName(name)+"={"+exprs.get(i)+"};" );
|
||||
else
|
||||
writeln( "LuaValue "+javaName(name)+"="+exprs.get(i)+";" );
|
||||
}
|
||||
for ( int i=nassign; i<exprs.size(); i++ )
|
||||
writeln( exprs.get(i)+";" );
|
||||
}
|
||||
|
||||
/** Evaluate expressions for use in assignment
|
||||
* @param scope */
|
||||
private List<String> evalExpressions(List<LSExpression> exprs, int nassign, Scope scope) {
|
||||
int nexpr = (exprs!=null? exprs.size(): 0);
|
||||
List<String> e = new ArrayList<String>(nexpr);
|
||||
boolean hasvarargs = false;
|
||||
for ( int i=0; i<nexpr || i<nassign; i++ ) {
|
||||
if ( i<nexpr-1 || nassign <= nexpr ) {
|
||||
e.add( eval( exprs.get(i) ) );
|
||||
} else if ( i==nexpr-1 ) {
|
||||
int nr = exprs.get(i).getNumReturns();
|
||||
hasvarargs = (nr==-1) || (nr>1);
|
||||
if ( hasvarargs )
|
||||
e.add( "($v="+eval(exprs.get(i))+").arg1()" );
|
||||
else
|
||||
e.add( eval(exprs.get(i)) );
|
||||
} else if (hasvarargs) {
|
||||
e.add( "$v.arg("+(i-nexpr+2)+")" );
|
||||
} else {
|
||||
e.add( "NIL" );
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
private void writeReturnStat(ReturnStat s) {
|
||||
int n = s.expressions!=null? s.expressions.size(): 0;
|
||||
if ( ! s.function.isvararg )
|
||||
writeln( n==0? "return NONE;": "return "+eval(s.expressions.get(0))+";" );
|
||||
else {
|
||||
writeindent();
|
||||
switch ( n ) {
|
||||
case 0:
|
||||
write( "return NONE;" );
|
||||
break;
|
||||
case 1:
|
||||
write( "return "+eval( s.expressions.get(0))+";" );
|
||||
break;
|
||||
case 2: case 3: {
|
||||
write( "return varargsOf(" );
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
if (i>0) write( "," );
|
||||
write( eval( s.expressions.get(i)) );
|
||||
}
|
||||
write( ");" );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
write( "return varargsOf(new LuaValue[] {" );
|
||||
for ( int i=0; i<n-1; i++ ) {
|
||||
if (i>0) write( "," );
|
||||
write( eval( s.expressions.get(i)) );
|
||||
}
|
||||
write( "},"+eval(s.expressions.get(n-1))+");" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
writeln();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBreakStat(BreakStat s) {
|
||||
writeln( "break;" );
|
||||
}
|
||||
|
||||
private void writeIfStat(LSIfStatement s) {
|
||||
writeln( "if ("+eval_bool(s.condition)+") {" );
|
||||
++indent;
|
||||
writeStatements( s.statements );
|
||||
if ( s.elseifs != null ) {
|
||||
for ( LSIfStatement.ElseIf elseif : s.elseifs ) {
|
||||
--indent;
|
||||
writeln( "} else if ("+eval_bool(elseif.condition)+") {" );
|
||||
++indent;
|
||||
writeStatements( elseif.statements );
|
||||
}
|
||||
}
|
||||
if ( s.elsestatements != null ) {
|
||||
--indent;
|
||||
writeln( "} else {" );
|
||||
++indent;
|
||||
writeStatements( s.elsestatements );
|
||||
}
|
||||
--indent;
|
||||
writeln( "}" );
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
// assignment using variables
|
||||
//-------------------------------------------
|
||||
|
||||
/** Write assignment of a particular variable value */
|
||||
private void writeAssign(LSVariable v, String expression) {
|
||||
switch ( v.type ) {
|
||||
case nameVariable: writeNameAssign( (LSVariable.NameReference) v, expression); break;
|
||||
case fieldVariable: writeFieldAssign( (LSVariable.Field) v, expression); break;
|
||||
case methodVariable: writeMethodAssign( (LSVariable.Method) v, expression); break;
|
||||
case parenthesesVariable: writeParenAssign( (LSVariable.Parentheses) v, expression); break;
|
||||
case indexVariable: writeIndexAssign( (LSVariable.Index) v, expression); break;
|
||||
case callFunctionVariable: writeCallFuncAssign((LSVariable.CallFunction)v, expression); break;
|
||||
case callMethodVariable: writeCallMethAssign((LSVariable.CallMethod) v, expression); break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNameAssign(NameReference v, String expression) {
|
||||
if ( v.name.isGlobal() )
|
||||
writeln( "env.set(\""+v.name.luaname+"\","+expression+");");
|
||||
else if ( v.name.isupvalue )
|
||||
writeln( javaName(v.name)+"[0]="+expression+";");
|
||||
else
|
||||
writeln( javaName(v.name)+"="+expression+";");
|
||||
}
|
||||
|
||||
private void writeFieldAssign(Field v, String expression) {
|
||||
String base = eval(v.variable);
|
||||
writeln( base+".set(\""+v.field+"\","+expression+");");
|
||||
}
|
||||
|
||||
private void writeMethodAssign(Method v, String expression) {
|
||||
String base = eval(v.variable);
|
||||
writeln( base+".set(\""+v.method+"\","+expression+");");
|
||||
}
|
||||
|
||||
private void writeParenAssign(Parentheses v, String expression) {
|
||||
throw new IllegalArgumentException("no assignment for parenthesis expressions");
|
||||
}
|
||||
|
||||
private void writeIndexAssign(Index v, String expression) {
|
||||
String base = eval(v.variable);
|
||||
writeln( base+".set("+eval(v.expression)+","+expression+");");
|
||||
}
|
||||
|
||||
private void writeCallFuncAssign(CallFunction v, String expression) {
|
||||
throw new IllegalArgumentException("no assignment for call function expressions");
|
||||
}
|
||||
|
||||
private void writeCallMethAssign(CallMethod v, String expression) {
|
||||
throw new IllegalArgumentException("no assignment for call method expressions");
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
// write out expressions
|
||||
//-------------------------------------------
|
||||
|
||||
private String eval_bool(LSExpression e) {
|
||||
return eval(e)+".toboolean()";
|
||||
}
|
||||
|
||||
/** evaluate the expression to a particular operand type */
|
||||
private String eval(LSExpression e) {
|
||||
if ( e==null ) return "NONE";
|
||||
switch ( e.type ) {
|
||||
case nilConstant: return "NIL";
|
||||
case trueConstant: return "TRUE";
|
||||
case falseConstant: return "FALSE";
|
||||
case unop: return evalUnop( (LSExpression.UnopExpr) e);
|
||||
case binop: return evalBinop( (LSExpression.BinopExpr) e);
|
||||
case functionExpr: return evalFunction((LSExpression.FunctionExpr) e);
|
||||
case tableConstructor: return evalTable( (LSExpression.TableConstructor) e);
|
||||
case numberConstant: return evalNumber( (LSExpression.NumberConstant) e);
|
||||
case stringConstant: return evalString( (LSExpression.StringConstant) e);
|
||||
|
||||
// variable types
|
||||
case nameVariable: return evalNameRef( (LSVariable.NameReference) e);
|
||||
case fieldVariable: return evalField( (LSVariable.Field) e);
|
||||
case methodVariable: return evalMethod( (LSVariable.Method) e);
|
||||
case parenthesesVariable: return evalParen( (LSVariable.Parentheses) e);
|
||||
case indexVariable: return evalIndex( (LSVariable.Index) e);
|
||||
case callFunctionVariable: return evalCallFunc((LSVariable.CallFunction) e);
|
||||
case callMethodVariable: return evalCallMeth((LSVariable.CallMethod) e);
|
||||
case varargsRef: return evalVarargs( (LSExpression.VarargsRef) e);
|
||||
|
||||
default: throw new IllegalArgumentException("unknown expression type: "+e.type);
|
||||
}
|
||||
}
|
||||
|
||||
private String evalUnop(UnopExpr e) {
|
||||
switch ( e.op.type ) {
|
||||
case neg: return eval( e.rhs )+".neg()";
|
||||
case not: return eval( e.rhs )+".not()";
|
||||
case len: return eval( e.rhs )+".len()";
|
||||
}
|
||||
throw new IllegalArgumentException("unknown unary operand: "+e.op );
|
||||
}
|
||||
|
||||
private String evalBinop(BinopExpr e) {
|
||||
switch ( e.op.type ) {
|
||||
case pow: return eval(e.lhs)+".pow("+eval(e.rhs)+")";
|
||||
case mul: return eval(e.lhs)+".mul("+eval(e.rhs)+")";
|
||||
case div: return eval(e.lhs)+".div("+eval(e.rhs)+")";
|
||||
case mod: return eval(e.lhs)+".mod("+eval(e.rhs)+")";
|
||||
case add: return eval(e.lhs)+".add("+eval(e.rhs)+")";
|
||||
case sub: return eval(e.lhs)+".sub("+eval(e.rhs)+")";
|
||||
case concat: return eval(e.lhs)+".concat("+eval(e.rhs)+")";
|
||||
case lt: return eval(e.lhs)+".lt("+eval(e.rhs)+")";
|
||||
case lteq: return eval(e.lhs)+".lteq("+eval(e.rhs)+")";
|
||||
case gt: return eval(e.lhs)+".gt("+eval(e.rhs)+")";
|
||||
case gteq: return eval(e.lhs)+".gteq("+eval(e.rhs)+")";
|
||||
case eq: return eval(e.lhs)+".eq("+eval(e.rhs)+")";
|
||||
case neq: return eval(e.lhs)+".neq("+eval(e.rhs)+")";
|
||||
case and: return "(($t="+eval(e.lhs)+").toboolean()? "+eval(e.rhs)+": $t)";
|
||||
case or: return "(($t="+eval(e.lhs)+").toboolean()? $t: "+eval(e.rhs)+")";
|
||||
default: throw new IllegalStateException("unknoqn binary operator: "+e.op);
|
||||
}
|
||||
}
|
||||
|
||||
private String evalFunction(FunctionExpr e) {
|
||||
return evalFuncbody(e.function);
|
||||
}
|
||||
|
||||
private String evalTable(TableConstructor e) {
|
||||
StringBuffer named = new StringBuffer();
|
||||
StringBuffer numbered = new StringBuffer();
|
||||
LSExpression varargsLastListValue = null;
|
||||
for ( int i=0, n=e.fields.size(); i<n; i++ ) {
|
||||
LSField f = e.fields.get(i);
|
||||
switch ( f.type ) {
|
||||
case keyValue:
|
||||
LSField.KeyValue k = (LSField.KeyValue) f;
|
||||
named.append( eval(k.key)+","+eval(k.value)+",");
|
||||
break;
|
||||
case nameValue:
|
||||
LSField.NameValue nv = (LSField.NameValue) f;
|
||||
named.append( "valueOf(\""+nv.name+"\"),"+eval(nv.value)+",");
|
||||
break;
|
||||
case listValue:
|
||||
LSField.ListValue l = (LSField.ListValue) f;
|
||||
int nr = l.value.getNumReturns();
|
||||
if ( i<n-1 && (nr==1) )
|
||||
numbered.append( eval(l.value)+",");
|
||||
else
|
||||
varargsLastListValue = l.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: generated more targeted constructor
|
||||
return "tableOf("
|
||||
+(named .length()>0? "new LuaValue[] {"+named +"}": "null")+","
|
||||
+(numbered.length()>0? "new LuaValue[] {"+numbered+"}": "null")
|
||||
+(varargsLastListValue!=null? ","+eval(varargsLastListValue): "")+")";
|
||||
}
|
||||
|
||||
private String evalNumber(NumberConstant e) {
|
||||
// TODO: internalize constants
|
||||
return "valueOf("+e.value+")";
|
||||
}
|
||||
|
||||
private String evalString(StringConstant e) {
|
||||
// TODO: internalize constants
|
||||
return "valueOf("+toStrValueInitializer(e.bytes)+")";
|
||||
}
|
||||
|
||||
private String toStrValueInitializer(byte[] bytes) {
|
||||
int n = bytes.length;
|
||||
StringBuffer sb = new StringBuffer(n+2);
|
||||
|
||||
// check for characters beyond ascii 128
|
||||
for ( int i=0; i<n; i++ )
|
||||
if (bytes[i]<0) {
|
||||
sb.append( "new byte[]{" );
|
||||
for ( int j=0; j<n; j++ ) {
|
||||
if ( j>0 ) sb.append(",");
|
||||
byte b = bytes[j];
|
||||
switch ( b ) {
|
||||
case '\n': sb.append( "'\\n'" ); break;
|
||||
case '\r': sb.append( "'\\r'" ); break;
|
||||
case '\t': sb.append( "'\\t'" ); break;
|
||||
case '\\': sb.append( "'\\\\'" ); break;
|
||||
default:
|
||||
if ( b >= ' ' ) {
|
||||
sb.append( '\'');
|
||||
sb.append( (char) b );
|
||||
sb.append( '\'');
|
||||
} else {
|
||||
sb.append( String.valueOf((int)b) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sb.append( "}" );
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
sb.append('"');
|
||||
for ( int i=0; i<n; i++ ) {
|
||||
byte b = bytes[i];
|
||||
switch ( b ) {
|
||||
case '\b': sb.append( "\\b" ); break;
|
||||
case '\f': sb.append( "\\f" ); break;
|
||||
case '\n': sb.append( "\\n" ); break;
|
||||
case '\r': sb.append( "\\r" ); break;
|
||||
case '\t': sb.append( "\\t" ); break;
|
||||
case '"': sb.append( "\\\"" ); break;
|
||||
case '\\': sb.append( "\\\\" ); break;
|
||||
default:
|
||||
if ( b >= ' ' ) {
|
||||
sb.append( (char) b ); break;
|
||||
} else {
|
||||
// convert from UTF-8
|
||||
int u = 0xff & (int) b;
|
||||
if ( u>=0xc0 && i+1<n ) {
|
||||
if ( u>=0xe0 && i+2<n ) {
|
||||
u = ((u & 0xf) << 12) | ((0x3f & bytes[i+1]) << 6) | (0x3f & bytes[i+2]);
|
||||
i+= 2;
|
||||
} else {
|
||||
u = ((u & 0x1f) << 6) | (0x3f & bytes[++i]);
|
||||
}
|
||||
}
|
||||
sb.append( "\\u" );
|
||||
sb.append( Integer.toHexString(0x10000+u).substring(1) );
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append('"');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
private String evalNameRef(NameReference v) {
|
||||
if ( v.name.isGlobal() )
|
||||
return "env.get(\""+v.name.luaname+"\")";
|
||||
else if ( v.name.isupvalue )
|
||||
return javaName(v.name)+"[0]";
|
||||
else
|
||||
return javaName(v.name);
|
||||
}
|
||||
|
||||
private String evalField(Field e) {
|
||||
return eval(e.variable)+".get(\""+e.field+"\")";
|
||||
}
|
||||
|
||||
private String evalMethod(Method e) {
|
||||
// FIXME: check api, fix this
|
||||
return eval(e.variable)+".get(\""+e.method+"\")";
|
||||
}
|
||||
|
||||
private String evalParen(Parentheses e) {
|
||||
return eval(e.expression)+".arg1()";
|
||||
}
|
||||
|
||||
private String evalIndex(Index e) {
|
||||
return eval(e.variable)+".get("+eval(e.expression)+")";
|
||||
}
|
||||
|
||||
private String evalCallFunc(CallFunction e) {
|
||||
int n = e.parameters.size();
|
||||
boolean isVarargsReturn = e.numReturns < 0 || e.numReturns > 1;
|
||||
boolean isVarargsCall = n>0 && e.parameters.get(n-1).getNumReturns() < 0;
|
||||
String base = eval(e.variable);
|
||||
if ( n <= 3 && !isVarargsReturn && !isVarargsCall ) {
|
||||
return base+".call("+evalParamList(e.parameters)+")";
|
||||
} else {
|
||||
String coerce = e.numReturns==1? ".arg1()": "";
|
||||
switch ( n ) {
|
||||
case 0:
|
||||
return base+".invoke()"+coerce;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return base+".invoke("+evalParamList(e.parameters)+")"+coerce;
|
||||
default:
|
||||
if ( isVarargsCall ) {
|
||||
LSExpression last = e.parameters.remove(n-1);
|
||||
return base+".invoke(new LuaValue[]{"+evalParamList(e.parameters)+"},"+eval(last)+")"+coerce;
|
||||
} else {
|
||||
return base+".invoke(new LuaValue[]{"+evalParamList(e.parameters)+"})"+coerce;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String evalCallMeth(CallMethod e) {
|
||||
int n = e.parameters.size();
|
||||
String base = eval(e.variable);
|
||||
if ( n <= 3 && e.numReturns == 0 || e.numReturns == 1 ) {
|
||||
return base+".method(\""+e.method+"\""+(e.parameters.size()>0? ",": "")+evalParamList(e.parameters)+")";
|
||||
} else {
|
||||
return base+".invokemethod(\""+e.method+"\",new LuaValue[]{"+evalParamList(e.parameters)+"})";
|
||||
}
|
||||
}
|
||||
|
||||
private String evalVarargs(VarargsRef e) {
|
||||
switch ( e.numReturns ) {
|
||||
case 0: return "NIL";
|
||||
case 1: return "$args.arg1()";
|
||||
default: return "$args";
|
||||
}
|
||||
}
|
||||
|
||||
private String evalParamList(List<LSExpression> parameters) {
|
||||
if ( parameters == null || parameters.size() == 0 )
|
||||
return "";
|
||||
StringBuffer p = new StringBuffer();
|
||||
for ( int i=0, n=parameters.size(); i<n; i++ ) {
|
||||
if (i>0) p.append(",");
|
||||
p.append( eval( parameters.get(i) ) );
|
||||
}
|
||||
return p.toString();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------
|
||||
// write individual strings and lines
|
||||
//-------------------------------------------
|
||||
|
||||
|
||||
private void writeindent() {
|
||||
for ( int i=0; i<indent; i++ )
|
||||
sb.append( " " );
|
||||
}
|
||||
private void write( String str ) {
|
||||
sb.append( str );
|
||||
}
|
||||
private void writeln() {
|
||||
sb.append( '\n' );
|
||||
}
|
||||
private void writeln( String line ) {
|
||||
writeindent();
|
||||
write( line );
|
||||
writeln();
|
||||
}
|
||||
|
||||
}
|
||||
96
src/jse/org/luaj/vm2/luajc/LuaJCompiler.java
Normal file
96
src/jse/org/luaj/vm2/luajc/LuaJCompiler.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
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.LuaValue;
|
||||
import org.luaj.vm2.luajc.antlr.AntlrLuaJCompiler;
|
||||
|
||||
public class LuaJCompiler {
|
||||
|
||||
public static LuaValue compile( InputStream luaSource, String chunkName, LuaValue env ) throws Exception {
|
||||
String java = compileToJava( luaSource, chunkName );
|
||||
LuaValue chunk = javaCompile( java, chunkName );
|
||||
chunk.setfenv(env);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public static String compileToJava( InputStream luaSource, String chunkName ) throws Exception {
|
||||
return AntlrLuaJCompiler.compile( luaSource, chunkName );
|
||||
}
|
||||
|
||||
|
||||
public static LuaValue javaCompile( String java, String className) throws Exception {
|
||||
final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (compiler == null) {
|
||||
LuaValue.error("no java compiler");
|
||||
}
|
||||
|
||||
// write the file
|
||||
new File("jit").mkdirs();
|
||||
File source = new File("jit/"+className+JavaFileObject.Kind.SOURCE.extension);
|
||||
PrintStream ps = new PrintStream(new FileOutputStream(source));
|
||||
ps.print(java);
|
||||
ps.close();
|
||||
|
||||
// set up output location
|
||||
Iterable<? extends File> dest = Arrays.asList(new File[] { new File("bin") });
|
||||
StandardJavaFileManager fm = compiler.getStandardFileManager( null, null, null);
|
||||
fm.setLocation(StandardLocation.CLASS_OUTPUT, dest);
|
||||
|
||||
// compile the file
|
||||
Iterable<? extends JavaFileObject> compilationUnits = fm.getJavaFileObjects(source);
|
||||
CompilationTask task = compiler.getTask(null, fm, null, null, null, compilationUnits);
|
||||
boolean success = task.call();
|
||||
|
||||
// instantiate, config and return
|
||||
if (success) {
|
||||
// compile sub-prototypes
|
||||
// if ( p.p != null ) {
|
||||
// for ( int i=0, n=p.p.length; i<n; i++ ) {
|
||||
// if ( ! (p.p[i] instanceof JitPrototype) )
|
||||
// p.p[i] = jitCompile( p.p[i] );
|
||||
// }
|
||||
// }
|
||||
|
||||
// create JitPrototype instance
|
||||
Class clazz = Class.forName(className);
|
||||
Object instance = clazz.newInstance();
|
||||
LuaValue value = (LuaValue) instance;
|
||||
return value;
|
||||
}
|
||||
return LuaValue.error("compile task failed");
|
||||
}
|
||||
|
||||
}
|
||||
60
src/jse/org/luaj/vm2/luajc/antlr/AntlrLuaJCompiler.java
Normal file
60
src/jse/org/luaj/vm2/luajc/antlr/AntlrLuaJCompiler.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.antlr;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.antlr.runtime.ANTLRInputStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.luaj.vm2.luajc.JavaCodeGenerator;
|
||||
import org.luaj.vm2.luajc.antlr.LuaLexer;
|
||||
import org.luaj.vm2.luajc.antlr.LuaParser;
|
||||
import org.luaj.vm2.luajc.lst.LSChunk;
|
||||
|
||||
/**
|
||||
* Implementation of lua-to-java compiler using antlr
|
||||
*/
|
||||
public class AntlrLuaJCompiler {
|
||||
|
||||
private final String chunkname;
|
||||
|
||||
public AntlrLuaJCompiler(String chunkname) {
|
||||
this.chunkname = chunkname;
|
||||
}
|
||||
|
||||
public static String compile(InputStream script, String chunkname) throws RecognitionException, IOException {
|
||||
return new AntlrLuaJCompiler(chunkname).docompile( script );
|
||||
}
|
||||
|
||||
private String docompile(InputStream script) throws RecognitionException, IOException {
|
||||
|
||||
ANTLRInputStream input = new ANTLRInputStream(script);
|
||||
LuaLexer lexer = new LuaLexer(input);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
LuaParser parser = new LuaParser(tokens);
|
||||
LSChunk chunk = parser.chunk(chunkname);
|
||||
return new JavaCodeGenerator().toJava( chunk );
|
||||
}
|
||||
|
||||
}
|
||||
301
src/jse/org/luaj/vm2/luajc/antlr/Lua.g
Normal file
301
src/jse/org/luaj/vm2/luajc/antlr/Lua.g
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Lua 5.1 grammar producing typed parse tree.
|
||||
*
|
||||
* Adapted from the grammar produced by Nicolai Mainiero, May 2007
|
||||
*
|
||||
* see http://www.antlr.org/grammar/list
|
||||
*/
|
||||
|
||||
grammar Lua;
|
||||
|
||||
options {
|
||||
backtrack=true;
|
||||
}
|
||||
|
||||
@header {
|
||||
package org.luaj.vm2.luajc.antlr;
|
||||
import org.luaj.vm2.luajc.lst.*;
|
||||
}
|
||||
@lexer::header {
|
||||
package org.luaj.vm2.luajc.antlr;
|
||||
}
|
||||
@members {
|
||||
LSChunk CHK = null;
|
||||
}
|
||||
|
||||
chunk [String chunkname] returns [LSChunk c]
|
||||
@init { CHK = new LSChunk(chunkname); }
|
||||
: funcblock[CHK.function] {$c=CHK;}
|
||||
;
|
||||
|
||||
funcblock [LSFunction f]
|
||||
scope { LSFunction func; }
|
||||
@init { $funcblock::func = $f; }
|
||||
: {CHK.pushScope("body");} block {$f.setStatements($block.stats); CHK.popScope("body"); }
|
||||
;
|
||||
|
||||
block returns [List<LSStatement> stats]
|
||||
@init { $stats = new ArrayList<LSStatement>(); }
|
||||
: (stat {$stats.add($stat.s);} (';')?)*
|
||||
(laststat {$stats.add($laststat.s);} (';')?)?
|
||||
;
|
||||
|
||||
stat returns [LSStatement s]
|
||||
@init { Name name=null; List<Name> names=null; }
|
||||
: varlist1 '=' explist1 { $s=LSStatement.varAssignStatement($varlist1.vars,$explist1.exprs, CHK.peekScope(), $funcblock::func); }
|
||||
| functioncall { $s=LSStatement.functionCallStatement($functioncall.v); }
|
||||
| 'do' {CHK.pushScope("do");} block {CHK.popScope("do");} 'end'
|
||||
{ $s=LSStatement.doBlockStatement($block.stats); }
|
||||
| 'while' exp 'do' {CHK.pushScope("while");} block {CHK.popScope("while");} 'end'
|
||||
{ $s=LSStatement.whileLoopStatement($exp.e,$block.stats); }
|
||||
| 'repeat' {CHK.pushScope("repeat");} block {CHK.popScope("repeat");} 'until' exp
|
||||
{ $s=LSStatement.repeatUntilStatement($block.stats,$exp.e); }
|
||||
| ifstat { $s=$ifstat.s; }
|
||||
| 'for' {CHK.pushScope("fori");} NAME {name=CHK.declare($NAME.text);} '=' e1=exp ',' e2=exp (',' e3=exp)? 'do' {CHK.pushScope("foriblock");} block {CHK.popScope("foriblock");} 'end'
|
||||
{ $s=LSStatement.forLoopStatement(name,$e1.e,$e2.e,$e3.e,$block.stats,CHK.peekScope()); CHK.popScope("fori"); }
|
||||
| 'for' {CHK.pushScope("for");} namelist {names=CHK.declare($namelist.names);} 'in' explist1 'do' {CHK.pushScope("forblock");} block {CHK.popScope("forblock");}'end'
|
||||
{ $s=LSStatement.forListStatement(names,$explist1.exprs,$block.stats,CHK.peekScope(), $funcblock::func); CHK.popScope("for");}
|
||||
| 'function' funcname funcbody { $s=LSStatement.varFunctionStatement($funcname.v,$funcbody.f); }
|
||||
| 'local' 'function' NAME {name=CHK.declare($NAME.text);} funcbody
|
||||
{ $s=LSStatement.localFunctionStatement(name,$funcbody.f); }
|
||||
| 'local' namelist ('=' explist1)? { $s=LSStatement.localAssignStatement(CHK.declare($namelist.names),$explist1.exprs,CHK.peekScope(), $funcblock::func); }
|
||||
;
|
||||
|
||||
ifstat returns [LSStatement s]
|
||||
scope { LSIfStatement current; }
|
||||
: 'if' e1=exp 'then' {CHK.pushScope("if");} b1=block {$ifstat::current=new LSIfStatement($e1.e,$b1.stats); CHK.popScope("if");}
|
||||
('elseif' e2=exp 'then' {CHK.pushScope("elseif");} b2=block {$ifstat::current.addElseif($e2.e,$b2.stats); CHK.popScope("elseif");})*
|
||||
('else' {CHK.pushScope("else");} b3=block {$ifstat::current.addElse($b3.stats); CHK.popScope("else");})?
|
||||
'end'
|
||||
{ $s=$ifstat::current; }
|
||||
;
|
||||
|
||||
laststat returns [LSStatement s]
|
||||
: 'return' (e=explist1)? {$s=LSStatement.returnStatement($funcblock::func,$e.exprs);}
|
||||
| 'break' {$s=LSStatement.breakStatement();}
|
||||
;
|
||||
|
||||
funcname returns [LSVariable v]
|
||||
: n=NAME {$v = LSVariable.nameVariable(CHK.reference($n.text,$funcblock::func));}
|
||||
('.' n2=NAME {$v = $v.fieldVariable($n2.text);})*
|
||||
(':' n3=NAME {$v = $v.methodVariable($n3.text);})?
|
||||
;
|
||||
|
||||
varlist1 returns [List<LSVariable> vars]
|
||||
@init { $vars = new ArrayList<LSVariable>(); }
|
||||
: v1=var {$vars.add($v1.v);}
|
||||
(',' v2=var {$vars.add($v2.v);})*
|
||||
;
|
||||
|
||||
namelist returns [List<String> names]
|
||||
: n=NAME {$names=new ArrayList<String>(); $names.add($n.text);}
|
||||
(',' n2=NAME {$names.add($n2.text);})*
|
||||
;
|
||||
|
||||
explist1 returns [List<LSExpression> exprs]
|
||||
@init { $exprs = new ArrayList<LSExpression>(); }
|
||||
: (e1=exp ',' {$exprs.add($e1.e);})*
|
||||
e2=exp {$exprs.add($e2.e);}
|
||||
;
|
||||
|
||||
exp returns [LSExpression e]
|
||||
: ('nil' { $e=LSExpression.ENIL; }
|
||||
| 'false' { $e=LSExpression.EFALSE; }
|
||||
| 'true' { $e=LSExpression.ETRUE; }
|
||||
| number { $e=LSExpression.numberExpression($number.text); }
|
||||
| string { $e=$string.e; }
|
||||
| '...' { $e=LSExpression.varargsRef(); $funcblock::func.setUsesVarargs(); }
|
||||
| function { $e=LSExpression.functionExpression($function.f); }
|
||||
| prefixexp { $e=$prefixexp.v; }
|
||||
| tableconstructor { $e=$tableconstructor.e;}
|
||||
| unop e1=exp { $e=LSExpression.unopExpression($unop.op,$e1.e,CHK.peekScope());}
|
||||
) (binop e2=exp { $e=LSExpression.binopExpression($e,$binop.op,$e2.e,CHK.peekScope());})*
|
||||
;
|
||||
|
||||
var returns [LSVariable v]
|
||||
scope { LSVariable current; }
|
||||
: (n=NAME {$var::current=LSVariable.nameVariable(CHK.reference($n.text,$funcblock::func));}
|
||||
| '(' exp ')' {$var::current=LSVariable.parenthesesVariable($exp.e);} varSuffix)
|
||||
varSuffix*
|
||||
{$v=$var::current;}
|
||||
;
|
||||
|
||||
varSuffix
|
||||
: (n=nameAndArgs[$var::current] {$var::current=$n.v;})*
|
||||
('[' e=exp ']' {$var::current=$var::current.indexVariable($e.e);}
|
||||
| '.' n2=NAME {$var::current=$var::current.fieldVariable($n2.text);}
|
||||
)
|
||||
;
|
||||
|
||||
prefixexp returns [LSVariable v]
|
||||
scope { LSVariable current; }
|
||||
: e=varOrExp {$prefixexp::current=$e.v;}
|
||||
(n=nameAndArgs[$prefixexp::current] {$prefixexp::current=$n.v;})*
|
||||
{$v=$prefixexp::current;}
|
||||
;
|
||||
|
||||
functioncall returns [LSVariable v]
|
||||
scope { LSVariable current; }
|
||||
: e=varOrExp {$functioncall::current=$e.v;}
|
||||
(n=nameAndArgs[$functioncall::current] {$functioncall::current=$n.v;})+
|
||||
{$v=$functioncall::current;}
|
||||
;
|
||||
|
||||
varOrExp returns [LSVariable v]
|
||||
: var {$v=$var.v;}
|
||||
| '(' exp ')' {$v=LSVariable.parenthesesVariable($exp.e);}
|
||||
;
|
||||
|
||||
nameAndArgs [LSVariable vin] returns [LSVariable v]
|
||||
@init { String method=null; }
|
||||
: (':' n=NAME {method=$n.text;})?
|
||||
a=args {$v=((method==null)?
|
||||
$vin.callFuncVariable($a.exprs):
|
||||
$vin.callMethVariable(method,$a.exprs));}
|
||||
;
|
||||
|
||||
args returns [List<LSExpression> exprs]
|
||||
@init { $exprs = new ArrayList<LSExpression>(); }
|
||||
: '(' (e=explist1 {$exprs=$e.exprs;})? ')'
|
||||
| t=tableconstructor {$exprs.add($t.e);}
|
||||
| s=string {$exprs.add($s.e);}
|
||||
;
|
||||
|
||||
function returns [LSFunction f]
|
||||
: 'function' b=funcbody {$f = $b.f;}
|
||||
;
|
||||
|
||||
funcbody returns [LSFunction f]
|
||||
@init {
|
||||
$f = new LSFunction();
|
||||
$funcblock::func.functions.add($f);
|
||||
}
|
||||
: {CHK.pushScope("func",true);} '(' (parlist1 [f])? ')' funcblock[f] 'end' {CHK.popScope("func");}
|
||||
;
|
||||
|
||||
parlist1 [LSFunction f]
|
||||
: namelist {f.setParameterNames(CHK.declare($namelist.names));} (',' '...' {f.isvararg=true;})?
|
||||
| '...' {f.isvararg=true;}
|
||||
;
|
||||
|
||||
tableconstructor returns [LSExpression e]
|
||||
@init { List<LSField> fields = new ArrayList<LSField>(); }
|
||||
: '{' (fieldlist[fields])? '}' {$e=LSExpression.tableConstructorExpression(fields);}
|
||||
;
|
||||
|
||||
fieldlist [List<LSField> fields]
|
||||
: field [fields] (fieldsep field [fields])* (fieldsep)?
|
||||
;
|
||||
|
||||
field [List<LSField> fields]
|
||||
: '[' k=exp ']' '=' e=exp {$fields.add(LSField.keyValueField($k.e,$e.e));}
|
||||
| n=NAME '=' e=exp {$fields.add(LSField.nameValueField($n.text,$e.e));}
|
||||
| e=exp {$fields.add(LSField.valueField($e.e));}
|
||||
;
|
||||
|
||||
fieldsep
|
||||
: ','
|
||||
| ';'
|
||||
;
|
||||
|
||||
binop returns [BinOp op]
|
||||
: '+' {$op=BinOp.ADD;}
|
||||
| '-' {$op=BinOp.SUB;}
|
||||
| '*' {$op=BinOp.MUL;}
|
||||
| '/' {$op=BinOp.DIV;}
|
||||
| '^' {$op=BinOp.POW;}
|
||||
| '%' {$op=BinOp.MOD;}
|
||||
| '..' {$op=BinOp.CONCAT;}
|
||||
| '<' {$op=BinOp.LT;}
|
||||
| '<=' {$op=BinOp.LTEQ;}
|
||||
| '>' {$op=BinOp.GT;}
|
||||
| '>=' {$op=BinOp.GTEQ;}
|
||||
| '==' {$op=BinOp.EQ;}
|
||||
| '~=' {$op=BinOp.NEQ;}
|
||||
| 'and' {$op=BinOp.AND; $funcblock::func.hasandlogic=true;}
|
||||
| 'or' {$op=BinOp.OR; $funcblock::func.hasorlogic=true;}
|
||||
;
|
||||
|
||||
unop returns [UnOp op]
|
||||
: '-' {$op=UnOp.NEG;}
|
||||
| 'not' {$op=UnOp.NOT;}
|
||||
| '#' {$op=UnOp.LEN;}
|
||||
;
|
||||
|
||||
number
|
||||
: ('-')? INT
|
||||
| ('-')? FLOAT1
|
||||
| ('-')? FLOAT2
|
||||
| ('-')? FLOAT3
|
||||
| ('-')? EXP
|
||||
| HEX
|
||||
;
|
||||
|
||||
string returns [LSExpression e]
|
||||
: NORMALSTRING {$e=LSExpression.normalStringExpression($NORMALSTRING.text);}
|
||||
| CHARSTRING {$e=LSExpression.charStringExpression($CHARSTRING.text);}
|
||||
| LONGSTRING {$e=LSExpression.longStringExpression($LONGSTRING.text);}
|
||||
;
|
||||
|
||||
|
||||
// LEXER
|
||||
|
||||
|
||||
NAME :('a'..'z'|'A'..'Z'|'_')(options{greedy=true;}: 'a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||
;
|
||||
|
||||
INT : ('0'..'9')+;
|
||||
|
||||
FLOAT1 :'.' INT ;
|
||||
|
||||
FLOAT2 :INT '.' ;
|
||||
|
||||
FLOAT3 :INT '.' INT ;
|
||||
|
||||
EXP : (INT | FLOAT1 | FLOAT2 | FLOAT3) ('E'|'e') ('-'|'+')? INT;
|
||||
|
||||
HEX :'0' ('x' | 'X') ('0'..'9'| 'a'..'f' | 'A'..'F')+ ;
|
||||
|
||||
|
||||
|
||||
NORMALSTRING
|
||||
: '"' ( EscapeSequence | ~('\\'|'"') )* '"'
|
||||
;
|
||||
|
||||
CHARSTRING
|
||||
: '\'' ( EscapeSequence | ~('\\'|'\'') )* '\''
|
||||
;
|
||||
|
||||
LONGSTRING
|
||||
: '['('=')*'[' ( EscapeSequence | ~('\\'|']') )* ']'('=')*']'
|
||||
;
|
||||
|
||||
fragment
|
||||
EscapeSequence
|
||||
: '\\' ('a'|'b'|'f'|'n'|'r'|'t'|'v'|'\"'|'\''|'\\'|'\n')
|
||||
| DecimalEscape
|
||||
;
|
||||
|
||||
fragment
|
||||
DecimalEscape
|
||||
: '\\' ('0'..'9') (('0'..'9') ('0'..'9')?)?
|
||||
;
|
||||
|
||||
|
||||
COMMENT
|
||||
: '--[[' ( options {greedy=false;} : . )* '--]]' {skip();}
|
||||
| '--[=[' ( options {greedy=false;} : . )* '--]==]' {skip();}
|
||||
| '--[==[' ( options {greedy=false;} : . )* '--]==]' {skip();}
|
||||
| '--[===[' ( options {greedy=false;} : . )* '--]===]' {skip();}
|
||||
;
|
||||
|
||||
LINE_COMMENT
|
||||
: '--' ~('\n'|'\r')* '\r'? '\n' {skip();}
|
||||
;
|
||||
|
||||
|
||||
WS : (' '|'\t'|'\u000C') {skip();}
|
||||
;
|
||||
|
||||
NEWLINE : ('\r')? '\n' {skip();}
|
||||
;
|
||||
110
src/jse/org/luaj/vm2/luajc/antlr/Lua.tokens
Normal file
110
src/jse/org/luaj/vm2/luajc/antlr/Lua.tokens
Normal file
@@ -0,0 +1,110 @@
|
||||
T__66=66
|
||||
T__64=64
|
||||
T__29=29
|
||||
T__65=65
|
||||
T__28=28
|
||||
T__62=62
|
||||
T__27=27
|
||||
T__63=63
|
||||
T__26=26
|
||||
T__25=25
|
||||
T__24=24
|
||||
T__23=23
|
||||
T__22=22
|
||||
T__21=21
|
||||
T__20=20
|
||||
T__61=61
|
||||
T__60=60
|
||||
FLOAT3=8
|
||||
FLOAT2=7
|
||||
FLOAT1=6
|
||||
T__55=55
|
||||
T__56=56
|
||||
T__57=57
|
||||
NAME=4
|
||||
T__58=58
|
||||
T__51=51
|
||||
T__52=52
|
||||
T__53=53
|
||||
T__54=54
|
||||
EXP=9
|
||||
HEX=10
|
||||
T__59=59
|
||||
DecimalEscape=15
|
||||
COMMENT=16
|
||||
T__50=50
|
||||
T__42=42
|
||||
T__43=43
|
||||
T__40=40
|
||||
T__41=41
|
||||
T__46=46
|
||||
T__47=47
|
||||
T__44=44
|
||||
T__45=45
|
||||
LINE_COMMENT=17
|
||||
T__48=48
|
||||
T__49=49
|
||||
CHARSTRING=12
|
||||
INT=5
|
||||
LONGSTRING=13
|
||||
T__30=30
|
||||
NORMALSTRING=11
|
||||
T__31=31
|
||||
T__32=32
|
||||
WS=18
|
||||
T__33=33
|
||||
T__34=34
|
||||
NEWLINE=19
|
||||
T__35=35
|
||||
T__36=36
|
||||
T__37=37
|
||||
T__38=38
|
||||
T__39=39
|
||||
EscapeSequence=14
|
||||
'..'=56
|
||||
'end'=23
|
||||
'#'=66
|
||||
'>='=60
|
||||
'=='=61
|
||||
'/'=53
|
||||
'then'=33
|
||||
'>'=59
|
||||
'repeat'=25
|
||||
';'=20
|
||||
'='=21
|
||||
'return'=36
|
||||
'for'=27
|
||||
'+'=50
|
||||
')'=45
|
||||
'function'=30
|
||||
'.'=38
|
||||
'^'=54
|
||||
'%'=55
|
||||
'do'=22
|
||||
'elseif'=34
|
||||
'true'=42
|
||||
'}'=49
|
||||
'else'=35
|
||||
'and'=63
|
||||
'break'=37
|
||||
'{'=48
|
||||
'...'=43
|
||||
'~='=62
|
||||
'nil'=40
|
||||
'until'=26
|
||||
'<='=58
|
||||
'false'=41
|
||||
'<'=57
|
||||
'if'=32
|
||||
'not'=65
|
||||
':'=39
|
||||
'('=44
|
||||
'or'=64
|
||||
'*'=52
|
||||
'-'=51
|
||||
'['=46
|
||||
'while'=24
|
||||
'local'=31
|
||||
','=28
|
||||
'in'=29
|
||||
']'=47
|
||||
3814
src/jse/org/luaj/vm2/luajc/antlr/LuaLexer.java
Normal file
3814
src/jse/org/luaj/vm2/luajc/antlr/LuaLexer.java
Normal file
File diff suppressed because it is too large
Load Diff
5168
src/jse/org/luaj/vm2/luajc/antlr/LuaParser.java
Normal file
5168
src/jse/org/luaj/vm2/luajc/antlr/LuaParser.java
Normal file
File diff suppressed because it is too large
Load Diff
63
src/jse/org/luaj/vm2/luajc/lst/BinOp.java
Normal file
63
src/jse/org/luaj/vm2/luajc/lst/BinOp.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
|
||||
public class BinOp {
|
||||
// unary precedence is between POW and MUL
|
||||
public static final int UNARY_PRECEDENCE = 7;
|
||||
|
||||
public enum Type {
|
||||
pow,mul,div,mod,add,sub,concat,lt,lteq,gt,gteq,eq,neq,and,or,
|
||||
}
|
||||
|
||||
public static final BinOp POW = new BinOp(Type.pow, 8, true, "^");
|
||||
public static final BinOp MUL = new BinOp(Type.mul, 6, false, "*");
|
||||
public static final BinOp DIV = new BinOp(Type.div, 6, false, "/");
|
||||
public static final BinOp MOD = new BinOp(Type.mod, 6, false, "%");
|
||||
public static final BinOp ADD = new BinOp(Type.add, 5, false, "+");
|
||||
public static final BinOp SUB = new BinOp(Type.sub, 5, false, "-");
|
||||
public static final BinOp CONCAT = new BinOp(Type.concat, 4, true, "..");
|
||||
public static final BinOp LT = new BinOp(Type.lt, 3, false, "<");
|
||||
public static final BinOp LTEQ = new BinOp(Type.lteq, 3, false, "<=");
|
||||
public static final BinOp GT = new BinOp(Type.gt, 3, false, ">");
|
||||
public static final BinOp GTEQ = new BinOp(Type.gteq, 3, false, ">=");
|
||||
public static final BinOp EQ = new BinOp(Type.eq, 3, false, "==");
|
||||
public static final BinOp NEQ = new BinOp(Type.neq, 3, false, "~=");
|
||||
public static final BinOp AND = new BinOp(Type.and, 2, true, "and");
|
||||
public static final BinOp OR = new BinOp(Type.or, 1, true, "or");
|
||||
|
||||
public final Type type;
|
||||
public final int precedence;
|
||||
public final boolean isrightassoc;
|
||||
public final String luaop;
|
||||
|
||||
private BinOp(Type type, int precedence, boolean isrightassoc, String luaop) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.precedence = precedence;
|
||||
this.isrightassoc = isrightassoc;
|
||||
this.luaop = luaop;
|
||||
}
|
||||
|
||||
public String toString() { return luaop; }
|
||||
}
|
||||
106
src/jse/org/luaj/vm2/luajc/lst/LSChunk.java
Normal file
106
src/jse/org/luaj/vm2/luajc/lst/LSChunk.java
Normal file
@@ -0,0 +1,106 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/* A Lua Source Chunk */
|
||||
public class LSChunk {
|
||||
public static final boolean SCOPES = System.getProperty("SCOPES")!=null;
|
||||
|
||||
public final String chunkname;
|
||||
public final LSFunction function;
|
||||
public Scope scope;
|
||||
|
||||
public LSChunk( String chunkname ) {
|
||||
this.chunkname = chunkname;
|
||||
this.function = new LSFunction( true );
|
||||
this.scope = null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "@"+chunkname+": "+function;
|
||||
}
|
||||
|
||||
/** push a block scope onto the name scope stack */
|
||||
public void pushScope(String name) {
|
||||
scope = new Scope(scope, false);
|
||||
if(SCOPES)System.out.println(space(scope)+"push "+name+" scope="+scope);
|
||||
|
||||
}
|
||||
|
||||
/** push a function scope onto the name scope stack */
|
||||
public void pushScope(String name,boolean isFunction) {
|
||||
scope = new Scope(scope, isFunction);
|
||||
if(SCOPES)System.out.println(space(scope)+"push "+name+" scope="+scope);
|
||||
}
|
||||
|
||||
/** pop a scope from the scope stack */
|
||||
public Scope popScope(String name) {
|
||||
Scope s = scope;
|
||||
scope = scope.parent;
|
||||
if(SCOPES)System.out.println(space(s)+"pop "+name+" scope="+scope);
|
||||
return s;
|
||||
}
|
||||
|
||||
/** return the current scope */
|
||||
public Scope peekScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/** Declare a single name in the current scope, and return the Name element for it */
|
||||
public Name declare(String name) {
|
||||
Name n = scope.declare( name );
|
||||
if(SCOPES)System.out.println(space(scope)+" declared "+n+" scope="+scope);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Declare a list of names in the current scope, and return List of Name for them */
|
||||
public List<Name> declare(List<String> names) {
|
||||
List<Name> results = new ArrayList<Name>(names.size());
|
||||
for ( String s : names )
|
||||
results.add( declare(s) );
|
||||
return results;
|
||||
}
|
||||
|
||||
/** Reference a name, and find either the local scope within the function, the upvalue, or a global name
|
||||
* @param func */
|
||||
public Name reference(String name, LSFunction func) {
|
||||
Name n = scope.reference(name);
|
||||
if ("arg".equals(name) && n.isGlobal() && func.isvararg && !scope.isMainChunkScope()) {
|
||||
n = scope.declare(name);
|
||||
func.setHasArg();
|
||||
}
|
||||
if(SCOPES)System.out.println(space(scope)+" reference "+n+" scope="+scope);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Print out indentation for a scope */
|
||||
private static final String ws = " ";
|
||||
private String space(Scope i) {
|
||||
return ws.substring(0,i.level*2);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
267
src/jse/org/luaj/vm2/luajc/lst/LSExpression.java
Normal file
267
src/jse/org/luaj/vm2/luajc/lst/LSExpression.java
Normal file
@@ -0,0 +1,267 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class LSExpression {
|
||||
public enum Type {
|
||||
unop,
|
||||
binop,
|
||||
functionExpr,
|
||||
tableConstructor,
|
||||
nilConstant,
|
||||
trueConstant,
|
||||
falseConstant,
|
||||
varargsRef,
|
||||
numberConstant,
|
||||
stringConstant,
|
||||
|
||||
// variable types
|
||||
nameVariable,
|
||||
fieldVariable,
|
||||
methodVariable,
|
||||
parenthesesVariable,
|
||||
indexVariable,
|
||||
callFunctionVariable,
|
||||
callMethodVariable,
|
||||
}
|
||||
|
||||
public static final LSExpression ENIL = new LSExpression(Type.nilConstant); // nil
|
||||
public static final LSExpression EFALSE = new LSExpression(Type.falseConstant); // false
|
||||
public static final LSExpression ETRUE = new LSExpression(Type.trueConstant); // true
|
||||
|
||||
public final Type type;
|
||||
|
||||
LSExpression(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LSExpression functionExpression(LSFunction function) {
|
||||
return new FunctionExpr(function);
|
||||
}
|
||||
|
||||
public static LSExpression unopExpression(UnOp unop, LSExpression rhs, Scope scope) {
|
||||
if ( rhs instanceof BinopExpr ) {
|
||||
BinopExpr b = (BinopExpr) rhs;
|
||||
if ( BinOp.UNARY_PRECEDENCE > b.op.precedence )
|
||||
return binopExpression( unopExpression( unop, b.lhs, scope ), b.op, b.rhs, scope );
|
||||
}
|
||||
return new UnopExpr( unop, rhs );
|
||||
}
|
||||
|
||||
public static LSExpression binopExpression(LSExpression lhs, BinOp binop, LSExpression rhs, Scope scope) {
|
||||
if ( lhs instanceof UnopExpr ) {
|
||||
UnopExpr u = (UnopExpr) lhs;
|
||||
if ( binop.precedence > BinOp.UNARY_PRECEDENCE )
|
||||
return unopExpression( u.op, binopExpression( u.rhs, binop, rhs, scope ), scope );
|
||||
}
|
||||
// TODO: cumulate string concatenations together
|
||||
// TODO: constant folding
|
||||
if ( lhs instanceof BinopExpr ) {
|
||||
BinopExpr b = (BinopExpr) lhs;
|
||||
if ( (binop.precedence > b.op.precedence) ||
|
||||
((binop.precedence == b.op.precedence) && binop.isrightassoc) )
|
||||
return binopExpression( b.lhs, b.op, binopExpression( b.rhs, binop, rhs, scope ), scope );
|
||||
}
|
||||
if ( rhs instanceof BinopExpr ) {
|
||||
BinopExpr b = (BinopExpr) rhs;
|
||||
if ( (binop.precedence > b.op.precedence) ||
|
||||
((binop.precedence == b.op.precedence) && ! binop.isrightassoc) )
|
||||
return binopExpression( binopExpression( lhs, binop, b.lhs, scope ), b.op, b.rhs, scope );
|
||||
}
|
||||
return new BinopExpr( lhs, binop, rhs, scope );
|
||||
}
|
||||
|
||||
public static LSExpression numberExpression(String number) {
|
||||
return new NumberConstant(number);
|
||||
}
|
||||
|
||||
public static LSExpression tableConstructorExpression(List<LSField> fields) {
|
||||
return new TableConstructor( fields );
|
||||
}
|
||||
|
||||
public static LSExpression normalStringExpression(String luaSourceString) {
|
||||
return new StringConstant(luaSourceString.substring(1,luaSourceString.length()-1));
|
||||
}
|
||||
|
||||
public static LSExpression charStringExpression(String luaSourceString) {
|
||||
return new StringConstant(luaSourceString.substring(1,luaSourceString.length()-1));
|
||||
}
|
||||
|
||||
public static LSExpression longStringExpression(String luaSourceString) {
|
||||
luaSourceString = luaSourceString.substring(1,luaSourceString.length()-1);
|
||||
luaSourceString = luaSourceString.substring(luaSourceString.indexOf('[',1)+1, luaSourceString.lastIndexOf(']'));
|
||||
return new StringConstant(luaSourceString);
|
||||
}
|
||||
|
||||
public static LSExpression varargsRef() {
|
||||
return new VarargsRef();
|
||||
}
|
||||
|
||||
/** varargs such as "..." */
|
||||
public static class VarargsRef extends LSExpression {
|
||||
public int numReturns = -1;
|
||||
public VarargsRef() {
|
||||
super( Type.varargsRef );
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
this.numReturns = i;
|
||||
}
|
||||
public int getNumReturns() {
|
||||
return numReturns;
|
||||
}
|
||||
public String toString() { return "..."; }
|
||||
}
|
||||
|
||||
/** prefix expression such as "(foo)(bar)" ? */
|
||||
public static class FunctionExpr extends LSExpression {
|
||||
public final LSFunction function;
|
||||
public FunctionExpr( LSFunction function) {
|
||||
super( Type.functionExpr );
|
||||
this.function = function;
|
||||
}
|
||||
public String toString() { return function.toString(); }
|
||||
}
|
||||
|
||||
/** unary operator such as "not foo" */
|
||||
public static class UnopExpr extends LSExpression {
|
||||
public final UnOp op;
|
||||
public final LSExpression rhs;
|
||||
public UnopExpr( UnOp op, LSExpression rhs ) {
|
||||
super( Type.unop );
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
public String toString() { return op.luaop+rhs; }
|
||||
}
|
||||
|
||||
/** binary operator such as "a + b" */
|
||||
public static class BinopExpr extends LSExpression {
|
||||
public final LSExpression lhs;
|
||||
public final BinOp op;
|
||||
public final LSExpression rhs;
|
||||
public final Scope scope;
|
||||
public BinopExpr( LSExpression lhs, BinOp op, LSExpression rhs, Scope scope ) {
|
||||
super( Type.binop );
|
||||
this.lhs = lhs;
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
this.scope = scope;
|
||||
}
|
||||
public String toString() { return lhs+op.luaop+rhs; }
|
||||
}
|
||||
|
||||
/** table constructor such as "{ 'foo', [0]='bar' }" */
|
||||
public static class TableConstructor extends LSExpression {
|
||||
public final List<LSField> fields;
|
||||
public TableConstructor( List<LSField> fields ) {
|
||||
super( Type.tableConstructor );
|
||||
this.fields = fields;
|
||||
int n = fields.size();
|
||||
for ( int i=0; i<n-1; i++ )
|
||||
fields.get(i).setNumReturns(1);
|
||||
if ( n>0 )
|
||||
fields.get(n-1).setNumReturns(-1);
|
||||
}
|
||||
public String toString() { return "{"+fields+"}"; }
|
||||
}
|
||||
|
||||
/** number constants such as '123', "4.56", "0x11fe */
|
||||
public static class NumberConstant extends LSExpression {
|
||||
public final Number value;
|
||||
public NumberConstant( String number ) {
|
||||
super( Type.numberConstant );
|
||||
number = number.toLowerCase();
|
||||
if ( number.startsWith("0x") ) {
|
||||
Long l = Long.parseLong(number.substring(2), 16);
|
||||
value = (l.intValue()==l.longValue()? (Number) Integer.valueOf(l.intValue()): (Number) l);
|
||||
} else {
|
||||
Double d = Double.parseDouble(number);
|
||||
value = (d.doubleValue()==(double)d.intValue()? (Number) Integer.valueOf(d.intValue()): (Number) d);
|
||||
}
|
||||
}
|
||||
public String toString() { return value.toString(); }
|
||||
}
|
||||
|
||||
/** string constants such as 'abc', "def", [[ghi]], and [==[pqr]==] */
|
||||
public static class StringConstant extends LSExpression {
|
||||
public final byte[] bytes;
|
||||
public StringConstant( String luaSourceChars ) {
|
||||
super( Type.stringConstant );
|
||||
this.bytes = unquoteLua( luaSourceChars );
|
||||
}
|
||||
public String toString() { return "\""+new String(bytes)+"\""; }
|
||||
}
|
||||
|
||||
/** Unquote lua quoted sequences, and convert to the bytes represented by the source string. */
|
||||
public static byte[] unquoteLua( String luaSourceChars ) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
char[] c = luaSourceChars.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();
|
||||
}
|
||||
|
||||
/** Set number of return values, return actual number of returns in practice.
|
||||
*
|
||||
* @param i desired number of returns, or -1 for varargs.
|
||||
*/
|
||||
public void setNumReturns(int i) {
|
||||
}
|
||||
|
||||
/** Get actual number of returns for this subexpression, or -1 for varargs.
|
||||
*
|
||||
* @return actual number of returns, or -1 for varargs.
|
||||
*/
|
||||
public int getNumReturns() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
92
src/jse/org/luaj/vm2/luajc/lst/LSField.java
Normal file
92
src/jse/org/luaj/vm2/luajc/lst/LSField.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
public class LSField {
|
||||
public enum Type {
|
||||
keyValue,
|
||||
nameValue,
|
||||
listValue,
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
|
||||
LSField(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LSField keyValueField(LSExpression key, LSExpression value) {
|
||||
return new KeyValue(key, value);
|
||||
}
|
||||
|
||||
public static LSField nameValueField(String name, LSExpression value) {
|
||||
return new NameValue(name, value);
|
||||
}
|
||||
|
||||
public static LSField valueField(LSExpression value) {
|
||||
return new ListValue(value);
|
||||
}
|
||||
|
||||
/** table constructor field with an explicit key index value */
|
||||
public static class KeyValue extends LSField {
|
||||
public final LSExpression key;
|
||||
public final LSExpression value;
|
||||
public KeyValue(LSExpression key, LSExpression value) {
|
||||
super( Type.keyValue );
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
value.setNumReturns(1);
|
||||
}
|
||||
public String toString() { return "["+key+"]="+value; }
|
||||
}
|
||||
|
||||
|
||||
/** table constructor field with an named field for key */
|
||||
public static class NameValue extends LSField {
|
||||
public final String name;
|
||||
public final LSExpression value;
|
||||
public NameValue(String name, LSExpression value) {
|
||||
super( Type.nameValue );
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
value.setNumReturns(1);
|
||||
}
|
||||
public String toString() { return name+"="+value; }
|
||||
}
|
||||
|
||||
/** table constructor field with an implied index key */
|
||||
public static class ListValue extends LSField {
|
||||
public final LSExpression value;
|
||||
public ListValue(LSExpression value) {
|
||||
super( Type.listValue );
|
||||
this.value = value;
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
value.setNumReturns(i);
|
||||
}
|
||||
public String toString() { return value.toString(); }
|
||||
}
|
||||
|
||||
public void setNumReturns(int i) {
|
||||
}
|
||||
|
||||
}
|
||||
75
src/jse/org/luaj/vm2/luajc/lst/LSFunction.java
Normal file
75
src/jse/org/luaj/vm2/luajc/lst/LSFunction.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LSFunction {
|
||||
|
||||
public final List<LSStatement> stats = new ArrayList<LSStatement>();
|
||||
public final List<LSFunction> functions = new ArrayList<LSFunction>();
|
||||
public final List<Name> paramnames = new ArrayList<Name>();
|
||||
|
||||
/** set if this is a vararg function */
|
||||
public boolean isvararg;
|
||||
|
||||
/** needsarg is set if the code is vararg and needs the "arg" table to be created. */
|
||||
public boolean hasarg,needsarg;
|
||||
|
||||
/** max number of returns, or -1 for varargs */
|
||||
public int maxReturns = 0;
|
||||
|
||||
/** set if there are logical subexpressions, or varargs assignment */
|
||||
public boolean hasandlogic, hasorlogic, hasvarargassign, usesvarargs;
|
||||
|
||||
public LSFunction() {
|
||||
}
|
||||
|
||||
public LSFunction(boolean isvararg) {
|
||||
this.isvararg = isvararg;
|
||||
}
|
||||
|
||||
public void setStatements(List<LSStatement> stats) {
|
||||
this.stats.clear();
|
||||
this.stats.addAll(stats);
|
||||
}
|
||||
|
||||
public void setParameterNames(List<Name> list) {
|
||||
this.paramnames.clear();
|
||||
this.paramnames.addAll( list );
|
||||
}
|
||||
|
||||
public String toString() { return "function("+paramnames+") "+stats+" end"; }
|
||||
|
||||
public void setUsesVarargs() {
|
||||
this.usesvarargs = true;
|
||||
if ( this.hasarg )
|
||||
this.needsarg = false;
|
||||
}
|
||||
|
||||
public void setHasArg() {
|
||||
this.hasarg = true;
|
||||
if ( ! this.usesvarargs )
|
||||
this.needsarg = true;
|
||||
}
|
||||
}
|
||||
76
src/jse/org/luaj/vm2/luajc/lst/LSIfStatement.java
Normal file
76
src/jse/org/luaj/vm2/luajc/lst/LSIfStatement.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LSIfStatement extends LSStatement {
|
||||
|
||||
public final LSExpression condition;
|
||||
public final List<LSStatement> statements;
|
||||
public List<ElseIf> elseifs;
|
||||
public List<LSStatement> elsestatements;
|
||||
|
||||
public static class ElseIf {
|
||||
public final LSExpression condition;
|
||||
public final List<LSStatement> statements;
|
||||
public ElseIf(LSExpression condition, List<LSStatement> statements) {
|
||||
this.condition = condition;
|
||||
this.statements = statements;
|
||||
}
|
||||
}
|
||||
|
||||
public LSIfStatement(LSExpression condition, List<LSStatement> statements) {
|
||||
super( Type.ifStat );
|
||||
this.condition = condition;
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
public void addElseif(LSExpression condition, List<LSStatement> statements) {
|
||||
if ( elseifs == null )
|
||||
elseifs = new ArrayList<ElseIf>();
|
||||
elseifs.add( new ElseIf( condition, statements ) );
|
||||
}
|
||||
|
||||
public void addElse(List<LSStatement> statements) {
|
||||
elsestatements = statements;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "if "+condition+" then "+statements+
|
||||
(elseifs!=null? elseifs.toString(): "")+
|
||||
(elsestatements!=null? " else "+elsestatements: "");
|
||||
}
|
||||
public boolean isNextStatementReachable() {
|
||||
if ( isNextStatementReachable(statements) )
|
||||
return true;
|
||||
if ( elseifs != null )
|
||||
for ( ElseIf e : elseifs )
|
||||
if ( isNextStatementReachable(statements) )
|
||||
return true;
|
||||
if ( isNextStatementReachable(elsestatements) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
327
src/jse/org/luaj/vm2/luajc/lst/LSStatement.java
Normal file
327
src/jse/org/luaj/vm2/luajc/lst/LSStatement.java
Normal file
@@ -0,0 +1,327 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LSStatement {
|
||||
|
||||
public enum Type {
|
||||
functionCall,
|
||||
doBlock,
|
||||
whileLoop,
|
||||
repeatUntil,
|
||||
varAssign,
|
||||
forLoop,
|
||||
forList,
|
||||
varNamedFunction,
|
||||
localFunction,
|
||||
localAssign,
|
||||
returnStat,
|
||||
breakStat,
|
||||
ifStat,
|
||||
}
|
||||
|
||||
public final Type type;
|
||||
|
||||
LSStatement( Type type ) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LSStatement functionCallStatement(LSVariable variable) {
|
||||
return new FunctionCall( variable );
|
||||
}
|
||||
|
||||
public static LSStatement doBlockStatement(List<LSStatement> statements) {
|
||||
return new DoBlock( statements );
|
||||
}
|
||||
|
||||
public static LSStatement whileLoopStatement(LSExpression condition, List<LSStatement> statements) {
|
||||
return new WhileLoop( condition, statements );
|
||||
}
|
||||
|
||||
public static LSStatement repeatUntilStatement(List<LSStatement> statements, LSExpression condition) {
|
||||
return new RepeatUntil( statements, condition );
|
||||
}
|
||||
|
||||
public static LSStatement forLoopStatement(Name name, LSExpression initial,
|
||||
LSExpression limit, LSExpression step, List<LSStatement> statements, Scope scope) {
|
||||
return new ForLoop( name, initial, limit, step, statements, scope );
|
||||
}
|
||||
|
||||
public static LSStatement forListStatement(List<Name> names,
|
||||
List<LSExpression> expressions, List<LSStatement> statements, Scope scope, LSFunction function) {
|
||||
return new ForList( names, expressions, statements, scope, function );
|
||||
}
|
||||
|
||||
public static LSStatement varFunctionStatement(LSVariable funcname, LSFunction funcbody) {
|
||||
return new VarNamedFunction( funcname, funcbody );
|
||||
}
|
||||
|
||||
public static LSStatement localFunctionStatement(Name name, LSFunction funcbody) {
|
||||
return new LocalFunction( name, funcbody );
|
||||
}
|
||||
|
||||
public static LSStatement varAssignStatement(List<LSVariable> variables, List<LSExpression> expressions, Scope scope, LSFunction function) {
|
||||
setExprNumReturns( variables.size(), expressions, function );
|
||||
return new VarAssign( variables, expressions, scope );
|
||||
}
|
||||
|
||||
public static LSStatement localAssignStatement(List<Name> names, List<LSExpression> expressions, Scope scope, LSFunction function) {
|
||||
setExprNumReturns( names.size(), expressions, function );
|
||||
return new LocalAssign( names, expressions, scope );
|
||||
}
|
||||
|
||||
public static void setExprNumReturns( int nassign, List<LSExpression> expressions, LSFunction function ) {
|
||||
int nexpr = expressions!=null? expressions.size(): 0;
|
||||
for ( int i=0; i<nexpr; i++ )
|
||||
expressions.get(i).setNumReturns(
|
||||
(nassign<=nexpr)?
|
||||
(i<nassign? 1: 0): // same or more expressions than names
|
||||
(i<nexpr-1? 1: -1) ); // more names than expressions
|
||||
if ( nassign > nexpr && nexpr > 0 && expressions.get(nexpr-1).getNumReturns() == -1 )
|
||||
function.hasvarargassign = true;
|
||||
}
|
||||
|
||||
public static LSStatement returnStatement(LSFunction function, List<LSExpression> expressions) {
|
||||
int n=expressions!=null? expressions.size(): 0;
|
||||
|
||||
// set num returns of subexpressions
|
||||
for ( int i=0; i<n; i++ )
|
||||
expressions.get(i).setNumReturns(i<n-1? 1: -1); // last in list returns vararg
|
||||
int nreturns = 0;
|
||||
if ( n > 0 ) {
|
||||
LSExpression last = expressions.get(n-1);
|
||||
int lastreturns = last.getNumReturns();
|
||||
nreturns = (lastreturns<0? -1: lastreturns+n-1);
|
||||
}
|
||||
|
||||
// change the containing function to varargs if necessary.
|
||||
if ( function.maxReturns != -1 && function.maxReturns < nreturns )
|
||||
function.maxReturns = nreturns;
|
||||
if ( function.maxReturns == -1 || function.maxReturns > 1 || nreturns < 0 )
|
||||
function.isvararg = true;
|
||||
|
||||
return new ReturnStat( function, expressions );
|
||||
}
|
||||
|
||||
public static LSStatement breakStatement() {
|
||||
return new BreakStat();
|
||||
}
|
||||
|
||||
/** Statement representing a function call on a variable, such as "foo.bar()" */
|
||||
public static final class FunctionCall extends LSStatement {
|
||||
public final LSVariable variable;
|
||||
FunctionCall(LSVariable variable) {
|
||||
super( Type.functionCall );
|
||||
this.variable = variable;
|
||||
}
|
||||
public String toString() { return variable.toString()+"();"; }
|
||||
}
|
||||
|
||||
/** do block, such as "do foo = bar end" */
|
||||
public static final class DoBlock extends LSStatement {
|
||||
public final List<LSStatement> statements;
|
||||
DoBlock(List<LSStatement> statements) {
|
||||
super( Type.doBlock );
|
||||
this.statements = statements;
|
||||
}
|
||||
public String toString() { return "do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** while loop, such as "while foo = true do bar() end" */
|
||||
public static final class WhileLoop extends LSStatement {
|
||||
public final LSExpression condition;
|
||||
public final List<LSStatement> statements;
|
||||
WhileLoop(LSExpression condition, List<LSStatement> statements) {
|
||||
super( Type.whileLoop );
|
||||
this.condition = condition;
|
||||
this.statements = statements;
|
||||
}
|
||||
public String toString() { return "while "+condition+" do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** repeat loop, such as "repeat foo() until bar == true" */
|
||||
public static final class RepeatUntil extends LSStatement {
|
||||
public final List<LSStatement> statements;
|
||||
public final LSExpression condition;
|
||||
RepeatUntil(List<LSStatement> statements, LSExpression condition) {
|
||||
super( Type.repeatUntil );
|
||||
this.statements = statements;
|
||||
this.condition = condition;
|
||||
}
|
||||
public String toString() { return "repeat "+statements+" until "+condition+";"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** assignment to variables, such as "x.a,y.b = foo,bar" */
|
||||
public static final class VarAssign extends LSStatement {
|
||||
public final List<LSVariable> variables;
|
||||
public final List<LSExpression> expressions;
|
||||
public final Scope scope;
|
||||
VarAssign(List<LSVariable> variables, List<LSExpression> expressions, Scope scope) {
|
||||
super( Type.varAssign );
|
||||
this.variables = variables;
|
||||
this.expressions = expressions;
|
||||
this.scope = scope;
|
||||
}
|
||||
public String toString() { return variables+"="+expressions+";"; }
|
||||
}
|
||||
|
||||
/** for loop with index, such as "for i=1,10,2 do ... end" */
|
||||
public static final class ForLoop extends LSStatement {
|
||||
public final Name index;
|
||||
public final LSExpression initial;
|
||||
public final LSExpression limit;
|
||||
public final LSExpression step;
|
||||
public final List<LSStatement> statements;
|
||||
public final Scope scope;
|
||||
ForLoop(Name name, LSExpression initial, LSExpression limit, LSExpression step, List<LSStatement> statements, Scope scope) {
|
||||
super( Type.forLoop );
|
||||
this.index = name;
|
||||
this.initial = initial;
|
||||
this.limit = limit;
|
||||
this.step = step;
|
||||
this.statements = statements;
|
||||
this.scope = scope;
|
||||
initial.setNumReturns(1);
|
||||
limit.setNumReturns(1);
|
||||
if ( step != null )
|
||||
step.setNumReturns(1);
|
||||
}
|
||||
public String toString() { return "for "+index+"="+initial+","+limit+","+step+" do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** for loop with variable, such as "for i,j,k in foo() do ... end" */
|
||||
public static final class ForList extends LSStatement {
|
||||
public final List<Name> names;
|
||||
public final List<LSExpression> expressions;
|
||||
public final List<LSStatement> statements;
|
||||
public final Scope scope;
|
||||
ForList(List<Name> names, List<LSExpression> expressions, List<LSStatement> statements, Scope scope, LSFunction function) {
|
||||
super( Type.forList );
|
||||
this.names = names;
|
||||
this.expressions = expressions;
|
||||
this.statements = statements;
|
||||
this.scope = scope;
|
||||
|
||||
// set return value count for each expression in list;
|
||||
int ne = expressions.size();
|
||||
for ( int i=0; i<ne-1 && i<3; i++ )
|
||||
expressions.get(i).setNumReturns(1);
|
||||
if ( ne<=3 ) {
|
||||
expressions.get(ne-1).setNumReturns(3-(ne-1));
|
||||
function.hasvarargassign = true;
|
||||
}
|
||||
}
|
||||
public String toString() { return "for "+names+" in "+expressions+" do "+statements+" end;"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return isNextStatementReachable(statements);
|
||||
}
|
||||
}
|
||||
|
||||
/** variable function declaration, such as "a.b = function() end" */
|
||||
public static final class VarNamedFunction extends LSStatement {
|
||||
public final LSVariable funcname;
|
||||
public final LSFunction funcbody;
|
||||
VarNamedFunction(LSVariable funcname, LSFunction funcbody) {
|
||||
super( Type.varNamedFunction );
|
||||
this.funcname = funcname;
|
||||
this.funcbody = funcbody;
|
||||
}
|
||||
public String toString() { return funcname+"=f:"+funcbody+";"; }
|
||||
}
|
||||
|
||||
/** simple function declaration, such as "a = function() end" */
|
||||
public static final class LocalFunction extends LSStatement {
|
||||
public final Name name;
|
||||
public final LSFunction funcbody;
|
||||
LocalFunction(Name name, LSFunction funcbody) {
|
||||
super( Type.localFunction );
|
||||
this.name = name;
|
||||
this.funcbody = funcbody;
|
||||
}
|
||||
public String toString() { return name+"=f:"+funcbody+";"; }
|
||||
}
|
||||
|
||||
/** assignment, such as "a,b = foo,bar" */
|
||||
public static final class LocalAssign extends LSStatement {
|
||||
public final List<Name> names;
|
||||
public final List<LSExpression> expressions;
|
||||
public final Scope scope;
|
||||
LocalAssign(List<Name> list, List<LSExpression> expressions, Scope scope) {
|
||||
super( Type.localAssign );
|
||||
this.names = list;
|
||||
this.expressions = expressions;
|
||||
this.scope = scope;
|
||||
}
|
||||
public String toString() { return names+"="+expressions+";"; }
|
||||
}
|
||||
|
||||
/** return statement, such as "return foo,bar" */
|
||||
public static final class ReturnStat extends LSStatement {
|
||||
public final LSFunction function;
|
||||
public final List<LSExpression> expressions;
|
||||
ReturnStat(LSFunction function, List<LSExpression> expressions) {
|
||||
super( Type.returnStat );
|
||||
this.function = function;
|
||||
this.expressions = expressions;
|
||||
}
|
||||
public String toString() { return "return "+expressions+";"; }
|
||||
public boolean isNextStatementReachable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** break statement */
|
||||
public static final class BreakStat extends LSStatement {
|
||||
BreakStat() {
|
||||
super( Type.breakStat );
|
||||
}
|
||||
public String toString() { return "break;"; }
|
||||
}
|
||||
|
||||
/** True of this statment could return and therefore the next statement is reachable. */
|
||||
public boolean isNextStatementReachable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isNextStatementReachable(List<LSStatement> stats) {
|
||||
if ( stats == null )
|
||||
return true;
|
||||
for ( LSStatement s : stats )
|
||||
if ( ! s.isNextStatementReachable() )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
172
src/jse/org/luaj/vm2/luajc/lst/LSVariable.java
Normal file
172
src/jse/org/luaj/vm2/luajc/lst/LSVariable.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LSVariable extends LSExpression {
|
||||
|
||||
LSVariable(Type type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
/** name, such as 'foo' */
|
||||
public static LSVariable nameVariable(Name name) {
|
||||
return new NameReference(name);
|
||||
}
|
||||
|
||||
/** table field, such as 'a.b' */
|
||||
public LSVariable fieldVariable(String field) {
|
||||
return new Field(this, field);
|
||||
}
|
||||
|
||||
/** method reference, such as foo:bar */
|
||||
public LSVariable methodVariable(String method) {
|
||||
return new Method(this, method);
|
||||
}
|
||||
|
||||
/** parenthetical reference, such as '(foo())' */
|
||||
public static LSVariable parenthesesVariable(LSExpression expression) {
|
||||
if ( expression != null )
|
||||
expression.setNumReturns(1);
|
||||
return new Parentheses(expression);
|
||||
}
|
||||
|
||||
/** table index, such as 'a[b]' */
|
||||
public LSVariable indexVariable(LSExpression expression) {
|
||||
return new Index(this, expression);
|
||||
}
|
||||
|
||||
/** Variable is a method, such as 'a(x,y)' */
|
||||
public LSVariable callFuncVariable(List<LSExpression> parameters) {
|
||||
int n = parameters.size();
|
||||
for ( int i=0; i<n; i++ )
|
||||
parameters.get(i).setNumReturns(i<n-1? 1: -1);
|
||||
return new CallFunction(this, parameters);
|
||||
}
|
||||
|
||||
/** Variable is a method, such as 'a:b(x,y)' */
|
||||
public LSVariable callMethVariable(String method, List<LSExpression> parameters) {
|
||||
int n = parameters.size();
|
||||
for ( int i=0; i<n; i++ )
|
||||
parameters.get(i).setNumReturns(i<n-1? 1: -1);
|
||||
return new CallMethod(this, method, parameters);
|
||||
}
|
||||
|
||||
/** name, such as 'foo' */
|
||||
public static class NameReference extends LSVariable {
|
||||
public final Name name;
|
||||
public NameReference(Name name) {
|
||||
super( Type.nameVariable );
|
||||
this.name = name;
|
||||
}
|
||||
public String toString() { return name.toString(); }
|
||||
}
|
||||
|
||||
/** field reference, such as foo.bar */
|
||||
public static class Field extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final String field;
|
||||
public Field(LSVariable variable, String field) {
|
||||
super( Type.fieldVariable );
|
||||
this.variable = variable;
|
||||
this.field = field;
|
||||
}
|
||||
public String toString() { return variable+"."+field; }
|
||||
}
|
||||
|
||||
/** method reference, such as foo:bar */
|
||||
public static class Method extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final String method;
|
||||
public Method(LSVariable variable, String method) {
|
||||
super( Type.methodVariable );
|
||||
this.variable = variable;
|
||||
this.method = method;
|
||||
}
|
||||
public String toString() { return variable+":"+method; }
|
||||
}
|
||||
|
||||
/** parenthetical reference, such as '(foo())' */
|
||||
public static class Parentheses extends LSVariable {
|
||||
public final LSExpression expression;
|
||||
public Parentheses(LSExpression expression) {
|
||||
super( Type.parenthesesVariable );
|
||||
this.expression = expression;
|
||||
}
|
||||
public String toString() { return "("+expression+")"; }
|
||||
}
|
||||
|
||||
/** table index, such as 'a[b]' */
|
||||
public static class Index extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final LSExpression expression;
|
||||
public Index(LSVariable variable, LSExpression expression) {
|
||||
super( Type.indexVariable );
|
||||
this.variable = variable;
|
||||
this.expression = expression;
|
||||
}
|
||||
public String toString() { return variable+"["+expression+"]"; }
|
||||
}
|
||||
|
||||
|
||||
/** Variable is a function invocation, such as 'a(x,y)' */
|
||||
public static class CallFunction extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final List<LSExpression> parameters;
|
||||
public int numReturns = 0;
|
||||
public CallFunction(LSVariable variable, List<LSExpression> parameters) {
|
||||
super( Type.callFunctionVariable );
|
||||
this.variable = variable;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
this.numReturns = i;
|
||||
}
|
||||
public int getNumReturns() {
|
||||
return numReturns;
|
||||
}
|
||||
public String toString() { return variable+"("+parameters+")"; }
|
||||
}
|
||||
|
||||
/** Variable is a method invocation, such as 'a:bc()' */
|
||||
public static class CallMethod extends LSVariable {
|
||||
public final LSVariable variable;
|
||||
public final String method;
|
||||
public final List<LSExpression> parameters;
|
||||
public int numReturns = 0;
|
||||
public CallMethod(LSVariable variable, String method, List<LSExpression> parameters) {
|
||||
super( Type.callMethodVariable );
|
||||
this.variable = variable;
|
||||
this.method = method;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
public void setNumReturns(int i) {
|
||||
this.numReturns = i;
|
||||
}
|
||||
public int getNumReturns() {
|
||||
return numReturns;
|
||||
}
|
||||
public String toString() { return variable+":"+method+"("+parameters+")"; }
|
||||
}
|
||||
|
||||
}
|
||||
73
src/jse/org/luaj/vm2/luajc/lst/Name.java
Normal file
73
src/jse/org/luaj/vm2/luajc/lst/Name.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
/** A name in lua source, which resolves to one of:
|
||||
* - global reference
|
||||
* - local that is not an upvalue
|
||||
* - local that is an upvalue
|
||||
*/
|
||||
public class Name {
|
||||
|
||||
/** Name in lua source file */
|
||||
public final String luaname;
|
||||
|
||||
/** 0 if in outermost scope, 1 if in next inner scope, ect. */
|
||||
public final int scopelevel;
|
||||
|
||||
/** 0 if first declaration in global program, 1 if second use, etc. */
|
||||
public final int outerrevision;
|
||||
|
||||
/** 0 if first declaration in nearest enclosing function, 1 if second use, etc */
|
||||
public final int innerrevision;
|
||||
|
||||
/** true if used as an upvalue by some enclosed function */
|
||||
public boolean isupvalue;
|
||||
|
||||
/** Construct a name instance */
|
||||
public Name(String luaname, int scopelevel, int outerrevision, int innterrevision) {
|
||||
super();
|
||||
this.luaname = luaname;
|
||||
this.scopelevel = scopelevel;
|
||||
this.outerrevision = outerrevision;
|
||||
this.innerrevision = innterrevision;
|
||||
}
|
||||
|
||||
/** Construct a name reference representing a global reference */
|
||||
public Name(String name) {
|
||||
this.luaname = name;
|
||||
this.scopelevel = -1;
|
||||
this.outerrevision = -1;
|
||||
this.innerrevision = -1;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return scopelevel<0?
|
||||
"_G$"+luaname:
|
||||
luaname+"$s"+scopelevel+"$v"+outerrevision+"$f"+innerrevision;
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return -1 == outerrevision;
|
||||
}
|
||||
|
||||
}
|
||||
103
src/jse/org/luaj/vm2/luajc/lst/Scope.java
Normal file
103
src/jse/org/luaj/vm2/luajc/lst/Scope.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** A name scope in lua source terms.
|
||||
* Combination of function scope and block scope.
|
||||
*/
|
||||
public class Scope {
|
||||
public final Scope parent;
|
||||
public final int level;
|
||||
public final boolean isFunctionScope;
|
||||
public boolean hasAndOrLogic;
|
||||
public final Map<String,Name> names = new HashMap<String,Name>();
|
||||
|
||||
/** Construct a new default scope for a chunk */
|
||||
public Scope() {
|
||||
this.parent = null;
|
||||
this.isFunctionScope = true;
|
||||
this.level = 0;
|
||||
}
|
||||
|
||||
/** Construct an inner scope
|
||||
* @param parent the outer scope to fall back to, or null if a global scope
|
||||
* @param isFunctionScope true if this is a function scope, false otherwise
|
||||
*/
|
||||
public Scope(Scope parent, boolean isFunctionScope) {
|
||||
this.parent = parent;
|
||||
this.isFunctionScope = isFunctionScope;
|
||||
this.level = parent!=null? parent.level + 1: 0;
|
||||
}
|
||||
|
||||
/** Declare a single name in the current scope, and return the Name element for it */
|
||||
public Name declare(String name) {
|
||||
boolean crossesFunctionBoundary = false;
|
||||
for ( Scope s=this; s!=null; s=s.parent ) {
|
||||
Name n = s.names.get(name);
|
||||
if ( n != null ) {
|
||||
Name result = new Name(name,
|
||||
level,
|
||||
n.outerrevision+1,
|
||||
crossesFunctionBoundary? 0: n.innerrevision+1);
|
||||
names.put(name, result);
|
||||
return result;
|
||||
}
|
||||
if ( s.isFunctionScope )
|
||||
crossesFunctionBoundary = true;
|
||||
}
|
||||
Name result = new Name(name, level, 0, 0);
|
||||
names.put(name, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Reference a name, and find either the local scope within the function, the upvalue, or a global name */
|
||||
public Name reference(String name) {
|
||||
boolean crossesFunctionBoundary = false;
|
||||
for ( Scope s=this; s!=null; s=s.parent ) {
|
||||
Name n = s.names.get(name);
|
||||
if ( n != null ) {
|
||||
if ( crossesFunctionBoundary ) {
|
||||
n.isupvalue = true;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
if ( s.isFunctionScope )
|
||||
crossesFunctionBoundary = true;
|
||||
}
|
||||
// globally scoped name
|
||||
return new Name(name);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String ours = (isFunctionScope? "F": "")+names;
|
||||
return (parent==null? ours: ours+"->"+parent.toString());
|
||||
}
|
||||
|
||||
/** Return true iff this scope is part the main chunk */
|
||||
public boolean isMainChunkScope() {
|
||||
return isFunctionScope? false: parent==null? true: parent.isMainChunkScope();
|
||||
}
|
||||
}
|
||||
|
||||
43
src/jse/org/luaj/vm2/luajc/lst/UnOp.java
Normal file
43
src/jse/org/luaj/vm2/luajc/lst/UnOp.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc.lst;
|
||||
|
||||
public class UnOp {
|
||||
public enum Type {
|
||||
neg,not,len
|
||||
}
|
||||
|
||||
public static final UnOp NEG = new UnOp(Type.neg, "-");
|
||||
public static final UnOp NOT = new UnOp(Type.not, "~");
|
||||
public static final UnOp LEN = new UnOp(Type.len, "#");
|
||||
|
||||
public final Type type;
|
||||
public final String luaop;
|
||||
|
||||
private UnOp(Type type, String luaop) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.luaop = luaop;
|
||||
}
|
||||
|
||||
public String toString() { return luaop; }
|
||||
}
|
||||
303
src/jse/org/luaj/vm2/script/LuaScriptEngine.java
Normal file
303
src/jse/org/luaj/vm2/script/LuaScriptEngine.java
Normal file
@@ -0,0 +1,303 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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.script;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleScriptContext;
|
||||
|
||||
import org.luaj.vm2.LoadState;
|
||||
import org.luaj.vm2.Lua;
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.LuaError;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.JsePlatform;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jim_roseborough
|
||||
*/
|
||||
public class LuaScriptEngine implements ScriptEngine, Compilable {
|
||||
|
||||
private static final String __ENGINE_VERSION__ = Lua._VERSION;
|
||||
private static final String __NAME__ = "Luaj";
|
||||
private static final String __SHORT_NAME__ = "Luaj";
|
||||
private static final String __LANGUAGE__ = "lua";
|
||||
private static final String __LANGUAGE_VERSION__ = "5.1";
|
||||
private static final String __ARGV__ = "arg";
|
||||
private static final String __FILENAME__ = "?";
|
||||
|
||||
static {
|
||||
LuaC.install();
|
||||
}
|
||||
|
||||
private static final ScriptEngineFactory myFactory = new LuaScriptEngineFactory();
|
||||
|
||||
private ScriptContext defaultContext;
|
||||
|
||||
private final LuaValue _G;
|
||||
|
||||
public LuaScriptEngine() {
|
||||
|
||||
// create globals
|
||||
_G = JsePlatform.standardGlobals();
|
||||
|
||||
// set up context
|
||||
ScriptContext ctx = new SimpleScriptContext();
|
||||
ctx.setBindings(createBindings(), ScriptContext.ENGINE_SCOPE);
|
||||
setContext(ctx);
|
||||
|
||||
// set special values
|
||||
put(LANGUAGE_VERSION, __LANGUAGE_VERSION__);
|
||||
put(LANGUAGE, __LANGUAGE__);
|
||||
put(ENGINE, __NAME__);
|
||||
put(ENGINE_VERSION, __ENGINE_VERSION__);
|
||||
put(ARGV, __ARGV__);
|
||||
put(FILENAME, __FILENAME__);
|
||||
put(NAME, __SHORT_NAME__);
|
||||
put("THREADING", null);
|
||||
}
|
||||
|
||||
|
||||
public Object eval(String script) throws ScriptException {
|
||||
return eval(new StringReader(script));
|
||||
}
|
||||
|
||||
public Object eval(String script, ScriptContext context) throws ScriptException {
|
||||
return eval(new StringReader(script), context);
|
||||
}
|
||||
|
||||
public Object eval(String script, Bindings bindings) throws ScriptException {
|
||||
return eval(new StringReader(script), bindings);
|
||||
}
|
||||
|
||||
public Object eval(Reader reader) throws ScriptException {
|
||||
return eval(reader, getContext());
|
||||
}
|
||||
|
||||
public Object eval(Reader reader, ScriptContext scriptContext) throws ScriptException {
|
||||
return compile(reader).eval(scriptContext);
|
||||
}
|
||||
|
||||
public Object eval(Reader reader, Bindings bindings) throws ScriptException {
|
||||
ScriptContext c = getContext();
|
||||
Bindings current = c.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
c.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
|
||||
Object result = eval(reader);
|
||||
c.setBindings(current, ScriptContext.ENGINE_SCOPE);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void put(String key, Object value) {
|
||||
Bindings b = getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
((LuaBindings)b).put(key, value);
|
||||
}
|
||||
|
||||
public Object get(String key) {
|
||||
Bindings b = getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
return ((LuaBindings)b).get(key);
|
||||
}
|
||||
|
||||
public Bindings getBindings(int scope) {
|
||||
return getContext().getBindings(scope);
|
||||
}
|
||||
|
||||
public void setBindings(Bindings bindings, int scope) {
|
||||
getContext().setBindings(bindings, scope);
|
||||
}
|
||||
|
||||
public Bindings createBindings() {
|
||||
return new LuaBindings( _G );
|
||||
}
|
||||
|
||||
public ScriptContext getContext() {
|
||||
return defaultContext;
|
||||
}
|
||||
|
||||
public void setContext(ScriptContext context) {
|
||||
defaultContext = context;
|
||||
}
|
||||
|
||||
public ScriptEngineFactory getFactory() {
|
||||
return myFactory;
|
||||
}
|
||||
|
||||
public CompiledScript compile(String script) throws ScriptException {
|
||||
return compile(new StringReader(script));
|
||||
}
|
||||
|
||||
public CompiledScript compile(Reader reader) throws ScriptException {
|
||||
try {
|
||||
InputStream ris = new Utf8Encoder(reader);
|
||||
try {
|
||||
final Prototype p = LoadState.undump(ris, "script");
|
||||
return new CompiledScript() {
|
||||
public Object eval(ScriptContext context) throws ScriptException {
|
||||
Bindings b = context.getBindings(ScriptContext.ENGINE_SCOPE);
|
||||
LuaBindings lb = (LuaBindings) b;
|
||||
LuaClosure c = new LuaClosure( p, lb.env );
|
||||
return c.call();
|
||||
}
|
||||
public ScriptEngine getEngine() {
|
||||
return LuaScriptEngine.this;
|
||||
}
|
||||
};
|
||||
} catch ( LuaError lee ) {
|
||||
throw new ScriptException(lee.getMessage() );
|
||||
} finally {
|
||||
ris.close();
|
||||
}
|
||||
} catch ( Throwable t ) {
|
||||
throw new ScriptException("eval threw "+t.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// ------ lua bindings -----
|
||||
private static final class LuaBindings implements Bindings {
|
||||
private LuaValue env;
|
||||
private LuaValue mt;
|
||||
private LuaBindings( LuaValue _G ) {
|
||||
mt = LuaValue.tableOf();
|
||||
mt.set( LuaValue.INDEX, _G );
|
||||
clear();
|
||||
}
|
||||
public void clear() {
|
||||
env = LuaValue.tableOf();
|
||||
env.setmetatable(mt);
|
||||
}
|
||||
private Object toJava(LuaValue v) {
|
||||
switch ( v.type() ) {
|
||||
case LuaValue.TNIL: return null;
|
||||
case LuaValue.TSTRING: return v.toString();
|
||||
case LuaValue.TUSERDATA: return v.checkuserdata(Object.class);
|
||||
case LuaValue.TNUMBER: return v.isinttype()? new Integer(v.toint()): new Double(v.todouble());
|
||||
default:
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"LuaBindings cannot convert lua type '"+v.typename()+"' to Java");
|
||||
}
|
||||
}
|
||||
private LuaValue toLua(Object javaValue) {
|
||||
if ( javaValue instanceof Number ) {
|
||||
return LuaValue.valueOf(((Number)javaValue).doubleValue());
|
||||
} else if ( javaValue instanceof String ) {
|
||||
return LuaValue.valueOf(javaValue.toString());
|
||||
} else if ( javaValue == null ) {
|
||||
return LuaValue.NIL;
|
||||
} else {
|
||||
return LuaValue.userdataOf(javaValue);
|
||||
}
|
||||
}
|
||||
public boolean containsKey(Object key) {
|
||||
return ! env.get(toLua(key)).isnil();
|
||||
}
|
||||
public Object get(Object key) {
|
||||
return toJava(env.get(toLua(key)));
|
||||
}
|
||||
public Object put(String name, Object value) {
|
||||
LuaValue key = toLua(name);
|
||||
Object result = toJava(env.get(key));
|
||||
env.set(key, toLua(value));
|
||||
return result;
|
||||
}
|
||||
public void putAll(Map<? extends String, ? extends Object> toMerge) {
|
||||
for ( Iterator it=toMerge.entrySet().iterator(); it.hasNext(); ) {
|
||||
Map.Entry<String, Object> e = (Map.Entry<String, Object>) it.next();
|
||||
put( e.getKey(), e.getValue() );
|
||||
}
|
||||
}
|
||||
public Object remove(Object javakey) {
|
||||
LuaValue key = toLua(javakey);
|
||||
Object result = toJava(env.get(key));
|
||||
env.set(key, LuaValue.NIL);
|
||||
return result;
|
||||
}
|
||||
public boolean containsValue(Object value) {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"containsValue() not supported for LuaBindings");
|
||||
}
|
||||
public Set<java.util.Map.Entry<String, Object>> entrySet() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"entrySet() not supported for LuaBindings");
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"isEmpty() not supported for LuaBindings");
|
||||
}
|
||||
public Set<String> keySet() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"keySet() not supported for LuaBindings");
|
||||
}
|
||||
public int size() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"size() not supported for LuaBindings");
|
||||
}
|
||||
public Collection<Object> values() {
|
||||
throw new java.lang.UnsupportedOperationException(
|
||||
"values() not supported for LuaBindings");
|
||||
}
|
||||
}
|
||||
|
||||
// ------ convert char stream to byte stream for lua compiler -----
|
||||
|
||||
private final class Utf8Encoder extends InputStream {
|
||||
private final Reader r;
|
||||
private final int[] buf = new int[2];
|
||||
private int n;
|
||||
|
||||
private Utf8Encoder(Reader r) {
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if ( n > 0 )
|
||||
return buf[--n];
|
||||
int c = r.read();
|
||||
if ( c < 0x80 )
|
||||
return c;
|
||||
n = 0;
|
||||
if ( c < 0x800 ) {
|
||||
buf[n++] = (0x80 | ( c & 0x3f));
|
||||
return (0xC0 | ((c>>6) & 0x1f));
|
||||
} else {
|
||||
buf[n++] = (0x80 | ( c & 0x3f));
|
||||
buf[n++] = (0x80 | ((c>>6) & 0x3f));
|
||||
return (0xE0 | ((c>>12) & 0x0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
src/jse/org/luaj/vm2/script/LuaScriptEngineFactory.java
Normal file
127
src/jse/org/luaj/vm2/script/LuaScriptEngineFactory.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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.script;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jim_roseborough
|
||||
*/
|
||||
public class LuaScriptEngineFactory implements ScriptEngineFactory {
|
||||
|
||||
private static final String FILEEXT = ".lua";
|
||||
|
||||
private static final String [] MIMETYPES = {
|
||||
"text/plain",
|
||||
"text/lua",
|
||||
"application/lua"
|
||||
};
|
||||
|
||||
private static final String [] NAMES = {
|
||||
"lua",
|
||||
"luaj",
|
||||
};
|
||||
|
||||
private ScriptEngine myScriptEngine;
|
||||
private List<String> extensions;
|
||||
private List<String> mimeTypes;
|
||||
private List<String> names;
|
||||
|
||||
public LuaScriptEngineFactory() {
|
||||
myScriptEngine = new LuaScriptEngine();
|
||||
extensions = Collections.nCopies(1, FILEEXT);
|
||||
mimeTypes = Arrays.asList(MIMETYPES);
|
||||
names = Arrays.asList(NAMES);
|
||||
}
|
||||
|
||||
public String getEngineName() {
|
||||
return getScriptEngine().get(ScriptEngine.ENGINE).toString();
|
||||
}
|
||||
|
||||
public String getEngineVersion() {
|
||||
return getScriptEngine().get(ScriptEngine.ENGINE_VERSION).toString();
|
||||
}
|
||||
|
||||
public List<String> getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
public List<String> getMimeTypes() {
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
public List<String> getNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
public String getLanguageName() {
|
||||
return getScriptEngine().get(ScriptEngine.LANGUAGE).toString();
|
||||
}
|
||||
|
||||
public String getLanguageVersion() {
|
||||
return getScriptEngine().get(ScriptEngine.LANGUAGE_VERSION).toString();
|
||||
}
|
||||
|
||||
public Object getParameter(String key) {
|
||||
return getScriptEngine().get(key).toString();
|
||||
}
|
||||
|
||||
public String getMethodCallSyntax(String obj, String m, String... args) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(obj + ":" + m + "(");
|
||||
int len = args.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(args[i]);
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getOutputStatement(String toDisplay) {
|
||||
return "print(" + toDisplay + ")";
|
||||
}
|
||||
|
||||
public String getProgram(String ... statements) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
int len = statements.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i > 0) {
|
||||
sb.append('\n');
|
||||
}
|
||||
sb.append(statements[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public ScriptEngine getScriptEngine() {
|
||||
return myScriptEngine;
|
||||
}
|
||||
}
|
||||
74
test/java/org/luaj/luajc/TestLuaJ.java
Normal file
74
test/java/org/luaj/luajc/TestLuaJ.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.LuaClosure;
|
||||
import org.luaj.vm2.Print;
|
||||
import org.luaj.vm2.Prototype;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.JsePlatform;
|
||||
|
||||
/** Test the plain old bytecode interpreter */
|
||||
public class TestLuaJ {
|
||||
// create the script
|
||||
public static String name = "script";
|
||||
public static String script =
|
||||
"function r(q,...)\n"+
|
||||
" local a=arg\n"+
|
||||
" return a and a[2]\n"+
|
||||
"end\n" +
|
||||
"function s(q,...)\n"+
|
||||
" local a=arg\n"+
|
||||
" local b=...\n"+
|
||||
" return a and a[2],b\n"+
|
||||
"end\n" +
|
||||
"print( r(111,222,333),s(111,222,333) )";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println(script);
|
||||
|
||||
// create an environment to run in
|
||||
LuaTable _G = JsePlatform.standardGlobals();
|
||||
LuaC.install();
|
||||
|
||||
// compile into a chunk, or load as a class
|
||||
InputStream is = new ByteArrayInputStream( script.getBytes() );
|
||||
Prototype p = LuaC.compile(is, "script");
|
||||
print( p );
|
||||
LuaValue chunk = new LuaClosure(p,_G);
|
||||
chunk.call();
|
||||
}
|
||||
|
||||
private static void print(Prototype p) {
|
||||
System.out.println("--- "+p.is_vararg);
|
||||
Print.printCode(p);
|
||||
if (p.p!=null)
|
||||
for ( int i=0,n=p.p.length; i<n; i++ )
|
||||
print( p.p[i] );
|
||||
}
|
||||
|
||||
}
|
||||
71
test/java/org/luaj/luajc/TestLuaJC.java
Normal file
71
test/java/org/luaj/luajc/TestLuaJC.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*******************************************************************************
|
||||
* 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.luajc;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.JsePlatform;
|
||||
import org.luaj.vm2.luajc.LuaJCompiler;
|
||||
|
||||
public class TestLuaJC {
|
||||
// create the script
|
||||
public static String name = "script";
|
||||
public static String script =
|
||||
"local a='a\\ab\\bf\\fn\\nt\\tv\\vw\\133x\\222y'\n"+
|
||||
"local t={string.byte(a,1,#a)}\n"+
|
||||
"print( table.concat(t,',') )\n";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println(script);
|
||||
|
||||
// create an environment to run in
|
||||
LuaTable _G = JsePlatform.standardGlobals();
|
||||
|
||||
// compile into a chunk, or load as a class
|
||||
LuaValue chunk;
|
||||
if ( ! (args.length>0 && args[0].equals("nocompile")) ) {
|
||||
InputStream is = new ByteArrayInputStream( script.getBytes() );
|
||||
String java =LuaJCompiler.compileToJava(is, "script");
|
||||
System.out.println("java:\n"+java);
|
||||
chunk = LuaJCompiler.javaCompile(java, "script");
|
||||
} else {
|
||||
chunk = (LuaValue) Class.forName("script").newInstance();
|
||||
}
|
||||
chunk.setfenv(_G);
|
||||
|
||||
// call with arguments
|
||||
LuaValue[] vargs = new LuaValue[args.length];
|
||||
for ( int i=0; i<args.length; i++ )
|
||||
vargs[i] = LuaValue.valueOf(args[i]);
|
||||
Varargs cargs = LuaValue.varargsOf(vargs);
|
||||
Varargs v = chunk.invoke(cargs);
|
||||
|
||||
// print the result
|
||||
for ( int i=1; i<=v.narg(); i++ )
|
||||
System.out.println("result["+i+"]: "+v.arg(i));
|
||||
}
|
||||
|
||||
}
|
||||
66
test/junit/org/luaj/vm2/AllTests.java
Normal file
66
test/junit/org/luaj/vm2/AllTests.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*******************************************************************************
|
||||
* 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 junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.luaj.vm2.CompatibiltyTest.LuaJCCompatibilityTest;
|
||||
import org.luaj.vm2.WeakTableTest.WeakKeyTableTest;
|
||||
import org.luaj.vm2.WeakTableTest.WeakKeyValueTableTest;
|
||||
|
||||
public class AllTests {
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite("All Tests for Luaj-vm2");
|
||||
|
||||
// table tests
|
||||
TestSuite vm = new TestSuite("VM Tests");
|
||||
vm.addTestSuite(TypeTest.class);
|
||||
vm.addTestSuite(UnaryBinaryOperatorsTest.class);
|
||||
vm.addTestSuite(MetatableTest.class);
|
||||
vm.addTestSuite(LuaOperationsTest.class);
|
||||
suite.addTest(vm);
|
||||
|
||||
// table tests
|
||||
TestSuite table = new TestSuite("Table Tests");
|
||||
table.addTestSuite(TableTest.class);
|
||||
table.addTestSuite(TableArrayTest.class);
|
||||
table.addTestSuite(TableHashTest.class);
|
||||
table.addTestSuite(WeakTableTest.class);
|
||||
table.addTestSuite(WeakKeyTableTest.class);
|
||||
table.addTestSuite(WeakKeyValueTableTest.class);
|
||||
suite.addTest(table);
|
||||
|
||||
// compatiblity tests
|
||||
suite.addTest(CompatibiltyTest.suite());
|
||||
|
||||
// luajc regression tests
|
||||
TestSuite luajc = new TestSuite("Luajc Tests");
|
||||
luajc.addTestSuite(FragmentsTest.class);
|
||||
luajc.addTest( new TestSuite( LuaJCCompatibilityTest.class, "LuaJC Compatiblity Tests" ) );
|
||||
suite.addTest(luajc);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
}
|
||||
94
test/junit/org/luaj/vm2/CompatibiltyTest.java
Normal file
94
test/junit/org/luaj/vm2/CompatibiltyTest.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*******************************************************************************
|
||||
* 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 junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Compatibility tests for the Luaj VM
|
||||
*
|
||||
* Results are compared for exact match with
|
||||
* the installed C-based lua environment.
|
||||
*/
|
||||
public class CompatibiltyTest {
|
||||
|
||||
private static final String dir = "test/lua";
|
||||
|
||||
abstract protected static class CompatibiltyTestSuite extends ScriptDrivenTest {
|
||||
protected CompatibiltyTestSuite(PlatformType platform) {
|
||||
super(platform,dir);
|
||||
}
|
||||
|
||||
public void testBaseLib() { runTest("baselib"); }
|
||||
public void testCoroutineLib() { runTest("coroutinelib"); }
|
||||
public void testDebugLib() { runTest("debuglib"); }
|
||||
public void testErrors() { runTest("errors"); }
|
||||
public void testFunctions() { runTest("functions"); }
|
||||
public void testIoLib() { runTest("iolib"); }
|
||||
public void testMathLib() { runTest("mathlib"); }
|
||||
public void testOsLib() { runTest("oslib"); }
|
||||
public void testStringLib() { runTest("stringlib"); }
|
||||
public void testTableLib() { runTest("tablelib"); }
|
||||
public void testTailcalls() { runTest("tailcalls"); }
|
||||
public void testUpvalues() { runTest("upvalues"); }
|
||||
public void testVm() { runTest("vm"); }
|
||||
}
|
||||
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite("Compatibility Tests");
|
||||
suite.addTest( new TestSuite( JseCompatibilityTest.class, "JSE Tests" ) );
|
||||
suite.addTest( new TestSuite( JmeCompatibilityTest.class, "JME Tests" ) );
|
||||
return suite;
|
||||
}
|
||||
|
||||
public static class JmeCompatibilityTest extends CompatibiltyTestSuite {
|
||||
public JmeCompatibilityTest() {
|
||||
super(ScriptDrivenTest.PlatformType.JME);
|
||||
}
|
||||
protected void setUp() throws Exception {
|
||||
System.setProperty("JME", "true");
|
||||
super.setUp();
|
||||
}
|
||||
}
|
||||
public static class JseCompatibilityTest extends CompatibiltyTestSuite {
|
||||
public JseCompatibilityTest() {
|
||||
super(ScriptDrivenTest.PlatformType.JSE);
|
||||
}
|
||||
protected void setUp() throws Exception {
|
||||
System.setProperty("JME", "false");
|
||||
super.setUp();
|
||||
}
|
||||
}
|
||||
public static class LuaJCCompatibilityTest extends CompatibiltyTestSuite {
|
||||
public LuaJCCompatibilityTest() {
|
||||
super(ScriptDrivenTest.PlatformType.LUAJIT);
|
||||
}
|
||||
protected void setUp() throws Exception {
|
||||
System.setProperty("JME", "false");
|
||||
super.setUp();
|
||||
}
|
||||
// skipping - not supported yet
|
||||
public void testDebugLib() {}
|
||||
}
|
||||
}
|
||||
212
test/junit/org/luaj/vm2/FragmentsTest.java
Normal file
212
test/junit/org/luaj/vm2/FragmentsTest.java
Normal file
@@ -0,0 +1,212 @@
|
||||
/*******************************************************************************
|
||||
* 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 junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.luajc.LuaJCompiler;
|
||||
|
||||
/**
|
||||
* Test compilation of various fragments that have
|
||||
* caused problems for jit compiling during development.
|
||||
*
|
||||
*/
|
||||
public class FragmentsTest extends TestCase {
|
||||
|
||||
public void runFragment( Varargs expected, String script ) {
|
||||
try {
|
||||
String name = getName();
|
||||
LuaTable _G = org.luaj.vm2.lib.JsePlatform.standardGlobals();
|
||||
InputStream is = new ByteArrayInputStream(script.getBytes("UTF-8"));
|
||||
String java = LuaJCompiler.compileToJava(is, name);
|
||||
LuaValue chunk = LuaJCompiler.javaCompile(java, name);
|
||||
chunk.setfenv(_G);
|
||||
Varargs actual = chunk.invoke();
|
||||
assertEquals( expected.narg(), actual.narg() );
|
||||
for ( int i=1; i<=actual.narg(); i++ )
|
||||
assertEquals( expected.arg(i), actual.arg(i) );
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void testArgParam() {
|
||||
// the name "arg" is treated specially, and ends up masking the argument value in 5.1
|
||||
runFragment( LuaValue.NIL,
|
||||
"function v(arg,...)\n" +
|
||||
" return arg\n" +
|
||||
"end\n" +
|
||||
"return v('abc')\n" );
|
||||
}
|
||||
|
||||
|
||||
public void testMultiAssign() {
|
||||
// arargs evaluations are all done before assignments
|
||||
runFragment( LuaValue.varargsOf(new LuaValue[]{
|
||||
LuaValue.valueOf(111),
|
||||
LuaValue.valueOf(111),
|
||||
LuaValue.valueOf(111)}),
|
||||
"a,b,c = 1,10,100\n" +
|
||||
"a,b,c = a+b+c, a+b+c, a+b+c\n" +
|
||||
"return a,b,c\n" );
|
||||
}
|
||||
|
||||
public void testUpvalues() {
|
||||
runFragment( LuaValue.valueOf(999),
|
||||
"local a = function(x)\n" +
|
||||
" return function(y)\n" +
|
||||
" return x + y\n" +
|
||||
" end\n" +
|
||||
"end\n" +
|
||||
"local b = a(222)\n" +
|
||||
"local c = b(777)\n" +
|
||||
"print( 'c=', c )\n" +
|
||||
"return c\n" );
|
||||
}
|
||||
|
||||
public void testNeedsArgAndHasArg() {
|
||||
runFragment( LuaValue.varargsOf(LuaValue.valueOf(333),LuaValue.NIL,LuaValue.valueOf(222)),
|
||||
"function r(q,...)\n"+
|
||||
" local a=arg\n"+
|
||||
" return a and a[2]\n"+
|
||||
"end\n" +
|
||||
"function s(q,...)\n"+
|
||||
" local a=arg\n"+
|
||||
" local b=...\n"+
|
||||
" return a and a[2],b\n"+
|
||||
"end\n" +
|
||||
"return r(111,222,333),s(111,222,333)" );
|
||||
|
||||
}
|
||||
|
||||
public void testNonAsciiStringLiterals() {
|
||||
runFragment( LuaValue.valueOf("7,8,12,10,9,11,133,222"),
|
||||
"local a='\\a\\b\\f\\n\\t\\v\\133\\222'\n"+
|
||||
"local t={string.byte(a,1,#a)}\n"+
|
||||
"return table.concat(t,',')\n" );
|
||||
}
|
||||
|
||||
public void testControlCharStringLiterals() {
|
||||
runFragment( LuaValue.valueOf("97,0,98,18,99,18,100,18,48,101"),
|
||||
"local a='a\\0b\\18c\\018d\\0180e'\n"+
|
||||
"local t={string.byte(a,1,#a)}\n"+
|
||||
"return table.concat(t,',')\n" );
|
||||
}
|
||||
|
||||
public void testLoopVarNames() {
|
||||
runFragment( LuaValue.valueOf(" 234,1,aa 234,2,bb"),
|
||||
"local w = ''\n"+
|
||||
"function t()\n"+
|
||||
" for f,var in ipairs({'aa','bb'}) do\n"+
|
||||
" local s = 234\n"+
|
||||
" w = w..' '..s..','..f..','..var\n"+
|
||||
" end\n"+
|
||||
"end\n" +
|
||||
"t()\n" +
|
||||
"return w\n" );
|
||||
|
||||
}
|
||||
|
||||
public void testForLoops() {
|
||||
runFragment( LuaValue.valueOf("12345 357 963"),
|
||||
"local s,t,u = '','',''\n"+
|
||||
"for m=1,5 do\n"+
|
||||
" s = s..m\n"+
|
||||
"end\n"+
|
||||
"for m=3,7,2 do\n"+
|
||||
" t = t..m\n"+
|
||||
"end\n"+
|
||||
"for m=9,3,-3 do\n"+
|
||||
" u = u..m\n"+
|
||||
"end\n"+
|
||||
"return s..' '..t..' '..u\n" );
|
||||
}
|
||||
|
||||
public void testLocalFunctionDeclarations() {
|
||||
runFragment( LuaValue.varargsOf(LuaValue.valueOf("function"),LuaValue.valueOf("nil")),
|
||||
"local function aaa()\n"+
|
||||
" return type(aaa)\n"+
|
||||
"end\n"+
|
||||
"local bbb = function()\n"+
|
||||
" return type(bbb)\n"+
|
||||
"end\n"+
|
||||
"return aaa(),bbb()\n" );
|
||||
}
|
||||
|
||||
public void testNilsInTableConstructor() {
|
||||
runFragment( LuaValue.valueOf("1=111 2=222 3=333 "),
|
||||
"local t = { 111, 222, 333, nil, nil }\n"+
|
||||
"local s = ''\n"+
|
||||
"for i,v in ipairs(t) do \n" +
|
||||
" s=s..tostring(i)..'='..tostring(v)..' '\n" +
|
||||
"end\n"+
|
||||
"return s\n" );
|
||||
|
||||
}
|
||||
|
||||
public void testUnreachableCode() {
|
||||
runFragment( LuaValue.valueOf(66),
|
||||
"local function foo(x) return x * 2 end\n" +
|
||||
"local function bar(x, y)\n" +
|
||||
" if x==y then\n" +
|
||||
" return y\n" +
|
||||
" else\n" +
|
||||
" return foo(x)\n" +
|
||||
" end\n" +
|
||||
"end\n" +
|
||||
"return bar(33,44)\n" );
|
||||
|
||||
}
|
||||
public void testVarargsWithParameters() {
|
||||
runFragment( LuaValue.valueOf(222),
|
||||
"local func = function(t,...)\n"+
|
||||
" return (...)\n"+
|
||||
"end\n"+
|
||||
"return func(111,222,333)\n" );
|
||||
}
|
||||
|
||||
public void testNoReturnValuesPlainCall() {
|
||||
runFragment( LuaValue.TRUE,
|
||||
"local testtable = {}\n"+
|
||||
"return pcall( function() testtable[1]=2 end ) )\n" );
|
||||
}
|
||||
|
||||
public void testVarargsInTableConstructor() {
|
||||
runFragment( LuaValue.valueOf(222),
|
||||
"local function foo() return 111,222,333 end\n"+
|
||||
"local t = {'a','b',c='c',foo()}\n"+
|
||||
"return t[4]\n" );
|
||||
}
|
||||
|
||||
public void testVarargsInFirstArg() {
|
||||
runFragment( LuaValue.valueOf(123),
|
||||
"function aaa(x) return x end\n" +
|
||||
"function bbb(y) return y end\n" +
|
||||
"function ccc(z) return z end\n" +
|
||||
"return ccc( aaa(bbb(123)), aaa(456) )\n" );
|
||||
}
|
||||
}
|
||||
262
test/junit/org/luaj/vm2/LuaOperationsTest.java
Normal file
262
test/junit/org/luaj/vm2/LuaOperationsTest.java
Normal file
@@ -0,0 +1,262 @@
|
||||
/*******************************************************************************
|
||||
* 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 java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.TypeTest.MyData;
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
public class LuaOperationsTest extends TestCase {
|
||||
|
||||
private final int sampleint = 77;
|
||||
private final long samplelong = 123400000000L;
|
||||
private final double sampledouble = 55.25;
|
||||
private final String samplestringstring = "abcdef";
|
||||
private final String samplestringint = String.valueOf(sampleint);
|
||||
private final String samplestringlong = String.valueOf(samplelong);
|
||||
private final String samplestringdouble = String.valueOf(sampledouble);
|
||||
private final Object sampleobject = new Object();
|
||||
private final MyData sampledata = new MyData();
|
||||
|
||||
private final LuaValue somenil = LuaValue.NIL;
|
||||
private final LuaValue sometrue = LuaValue.TRUE;
|
||||
private final LuaValue somefalse = LuaValue.FALSE;
|
||||
private final LuaValue zero = LuaValue.ZERO;
|
||||
private final LuaValue intint = LuaValue.valueOf(sampleint);
|
||||
private final LuaValue longdouble = LuaValue.valueOf(samplelong);
|
||||
private final LuaValue doubledouble = LuaValue.valueOf(sampledouble);
|
||||
private final LuaValue stringstring = LuaValue.valueOf(samplestringstring);
|
||||
private final LuaValue stringint = LuaValue.valueOf(samplestringint);
|
||||
private final LuaValue stringlong = LuaValue.valueOf(samplestringlong);
|
||||
private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble);
|
||||
private final LuaTable table = LuaValue.listOf( new LuaValue[] { LuaValue.valueOf("aaa"), LuaValue.valueOf("bbb") } );
|
||||
private final LuaFunction somefunc = new ZeroArgFunction("sample",0,table) { public LuaValue call() { return NONE;}};
|
||||
private final LuaThread thread = new LuaThread(somefunc,table);
|
||||
private final Prototype proto = new Prototype();
|
||||
private final LuaClosure someclosure = new LuaClosure(proto,table);
|
||||
private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject);
|
||||
private final LuaUserdata userdatacls = LuaValue.userdataOf(sampledata);
|
||||
|
||||
private void throwsLuaError(String methodName, Object obj) {
|
||||
try {
|
||||
LuaValue.class.getMethod(methodName).invoke(obj);
|
||||
fail("failed to throw LuaError as required");
|
||||
} catch (InvocationTargetException e) {
|
||||
if ( ! (e.getTargetException() instanceof LuaError) )
|
||||
fail("not a LuaError: "+e.getTargetException());
|
||||
return; // pass
|
||||
} catch ( Exception e ) {
|
||||
fail( "bad exception: "+e );
|
||||
}
|
||||
}
|
||||
|
||||
private void throwsLuaError(String methodName, Object obj, Object arg) {
|
||||
try {
|
||||
LuaValue.class.getMethod(methodName,LuaValue.class).invoke(obj,arg);
|
||||
fail("failed to throw LuaError as required");
|
||||
} catch (InvocationTargetException e) {
|
||||
if ( ! (e.getTargetException() instanceof LuaError) )
|
||||
fail("not a LuaError: "+e.getTargetException());
|
||||
return; // pass
|
||||
} catch ( Exception e ) {
|
||||
fail( "bad exception: "+e );
|
||||
}
|
||||
}
|
||||
|
||||
public void testLen() {
|
||||
throwsLuaError( "len", somenil );
|
||||
throwsLuaError( "len", sometrue );
|
||||
throwsLuaError( "len", somefalse );
|
||||
throwsLuaError( "len", zero );
|
||||
throwsLuaError( "len", intint );
|
||||
throwsLuaError( "len", longdouble );
|
||||
throwsLuaError( "len", doubledouble );
|
||||
assertEquals( LuaInteger.valueOf(samplestringstring.length()), stringstring.len() );
|
||||
assertEquals( LuaInteger.valueOf(samplestringint.length()), stringint.len() );
|
||||
assertEquals( LuaInteger.valueOf(samplestringlong.length()), stringlong.len() );
|
||||
assertEquals( LuaInteger.valueOf(samplestringdouble.length()), stringdouble.len() );
|
||||
assertEquals( LuaInteger.valueOf(2), table.len() );
|
||||
throwsLuaError( "len", somefunc );
|
||||
throwsLuaError( "len", thread );
|
||||
throwsLuaError( "len", someclosure );
|
||||
throwsLuaError( "len", userdataobj );
|
||||
throwsLuaError( "len", userdatacls );
|
||||
}
|
||||
|
||||
public void testLength() {
|
||||
throwsLuaError( "length", somenil );
|
||||
throwsLuaError( "length", sometrue );
|
||||
throwsLuaError( "length", somefalse );
|
||||
throwsLuaError( "length", zero );
|
||||
throwsLuaError( "length", intint );
|
||||
throwsLuaError( "length", longdouble );
|
||||
throwsLuaError( "length", doubledouble );
|
||||
assertEquals( samplestringstring.length(), stringstring.length() );
|
||||
assertEquals( samplestringint.length(), stringint.length() );
|
||||
assertEquals( samplestringlong.length(), stringlong.length() );
|
||||
assertEquals( samplestringdouble.length(), stringdouble.length() );
|
||||
assertEquals( 2, table.length() );
|
||||
throwsLuaError( "length", somefunc );
|
||||
throwsLuaError( "length", thread );
|
||||
throwsLuaError( "length", someclosure );
|
||||
throwsLuaError( "length", userdataobj );
|
||||
throwsLuaError( "length", userdatacls );
|
||||
}
|
||||
|
||||
public void testGetfenv() {
|
||||
throwsLuaError( "getfenv", somenil );
|
||||
throwsLuaError( "getfenv", sometrue );
|
||||
throwsLuaError( "getfenv", somefalse );
|
||||
throwsLuaError( "getfenv", zero );
|
||||
throwsLuaError( "getfenv", intint );
|
||||
throwsLuaError( "getfenv", longdouble );
|
||||
throwsLuaError( "getfenv", doubledouble );
|
||||
throwsLuaError( "getfenv", stringstring );
|
||||
throwsLuaError( "getfenv", stringint );
|
||||
throwsLuaError( "getfenv", stringlong );
|
||||
throwsLuaError( "getfenv", stringdouble );
|
||||
throwsLuaError( "getfenv", table );
|
||||
assertTrue( table == thread.getfenv() );
|
||||
assertTrue( table == someclosure.getfenv() );
|
||||
assertTrue( table == somefunc.getfenv() );
|
||||
throwsLuaError( "getfenv", userdataobj );
|
||||
throwsLuaError( "getfenv", userdatacls );
|
||||
}
|
||||
|
||||
public void testSetfenv() {
|
||||
LuaTable table2 = LuaValue.listOf( new LuaValue[] {
|
||||
LuaValue.valueOf("ccc"),
|
||||
LuaValue.valueOf("ddd") } );
|
||||
throwsLuaError( "setfenv", somenil, table2 );
|
||||
throwsLuaError( "setfenv", sometrue, table2 );
|
||||
throwsLuaError( "setfenv", somefalse, table2 );
|
||||
throwsLuaError( "setfenv", zero, table2 );
|
||||
throwsLuaError( "setfenv", intint, table2 );
|
||||
throwsLuaError( "setfenv", longdouble, table2 );
|
||||
throwsLuaError( "setfenv", doubledouble, table2 );
|
||||
throwsLuaError( "setfenv", stringstring, table2 );
|
||||
throwsLuaError( "setfenv", stringint, table2 );
|
||||
throwsLuaError( "setfenv", stringlong, table2 );
|
||||
throwsLuaError( "setfenv", stringdouble, table2 );
|
||||
throwsLuaError( "setfenv", table, table2 );
|
||||
thread.setfenv(table2);
|
||||
assertTrue( table2 == thread.getfenv() );
|
||||
assertTrue( table == someclosure.getfenv() );
|
||||
assertTrue( table == somefunc.getfenv() );
|
||||
someclosure.setfenv(table2);
|
||||
assertTrue( table2 == someclosure.getfenv() );
|
||||
assertTrue( table == somefunc.getfenv() );
|
||||
somefunc.setfenv(table2);
|
||||
assertTrue( table2 == somefunc.getfenv() );
|
||||
throwsLuaError( "setfenv", userdataobj, table2 );
|
||||
throwsLuaError( "setfenv", userdatacls, table2 );
|
||||
}
|
||||
|
||||
public Prototype createPrototype( String script, String name ) {
|
||||
try {
|
||||
LuaTable _G = org.luaj.vm2.lib.JsePlatform.standardGlobals();
|
||||
InputStream is = new ByteArrayInputStream(script.getBytes("UTF-8"));
|
||||
return LuaC.compile(is, name);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
fail(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void testFunctionClosureThreadEnv() {
|
||||
|
||||
// set up suitable environments for execution
|
||||
LuaValue aaa = LuaValue.valueOf("aaa");
|
||||
LuaValue eee = LuaValue.valueOf("eee");
|
||||
LuaTable _G = org.luaj.vm2.lib.JsePlatform.standardGlobals();
|
||||
LuaC.install();
|
||||
LuaTable newenv = LuaValue.tableOf( new LuaValue[] {
|
||||
LuaValue.valueOf("a"), LuaValue.valueOf("aaa"),
|
||||
LuaValue.valueOf("b"), LuaValue.valueOf("bbb"), } );
|
||||
LuaTable mt = LuaValue.tableOf( new LuaValue[] { LuaValue.INDEX, _G } );
|
||||
newenv.setmetatable(mt);
|
||||
_G.set("a", aaa);
|
||||
newenv.set("a", eee);
|
||||
|
||||
// function tests
|
||||
{
|
||||
LuaFunction f = new ZeroArgFunction("f",0,_G) { public LuaValue call() { return env.get("a");}};
|
||||
assertEquals( aaa, f.call() );
|
||||
f.setfenv(newenv);
|
||||
assertEquals( newenv, f.getfenv() );
|
||||
assertEquals( eee, f.call() );
|
||||
}
|
||||
|
||||
// closure tests
|
||||
{
|
||||
Prototype p = createPrototype( "return a\n", "closuretester" );
|
||||
LuaClosure c = new LuaClosure(p, _G);
|
||||
assertEquals( aaa, c.call() );
|
||||
c.setfenv(newenv);
|
||||
assertEquals( newenv, c.getfenv() );
|
||||
assertEquals( eee, c.call() );
|
||||
}
|
||||
|
||||
// thread tests, functions created in threads inherit the thread's environment initially
|
||||
// those closures created not in any other function get the thread's enviroment
|
||||
Prototype p2 = createPrototype( "return loadstring('return a')", "threadtester" );
|
||||
{
|
||||
LuaThread t = new LuaThread(new LuaClosure(p2,_G), _G);
|
||||
Varargs v = t.resume(LuaValue.NONE);
|
||||
assertEquals(LuaValue.TRUE, v.arg(1) );
|
||||
LuaValue f = v.arg(2);
|
||||
assertEquals( LuaValue.TFUNCTION, f.type() );
|
||||
assertEquals( aaa, f.call() );
|
||||
assertEquals( _G, f.getfenv() );
|
||||
}
|
||||
{
|
||||
// change the thread environment after creation!
|
||||
LuaThread t = new LuaThread(new LuaClosure(p2,_G), _G);
|
||||
t.setfenv(newenv);
|
||||
Varargs v = t.resume(LuaValue.NONE);
|
||||
assertEquals(LuaValue.TRUE, v.arg(1) );
|
||||
LuaValue f = v.arg(2);
|
||||
assertEquals( LuaValue.TFUNCTION, f.type() );
|
||||
assertEquals( eee, f.call() );
|
||||
assertEquals( newenv, f.getfenv() );
|
||||
}
|
||||
{
|
||||
// let the closure have a different environment from the thread
|
||||
Prototype p3 = createPrototype( "return function() return a end", "envtester" );
|
||||
LuaThread t = new LuaThread(new LuaClosure(p3,newenv), _G);
|
||||
Varargs v = t.resume(LuaValue.NONE);
|
||||
assertEquals(LuaValue.TRUE, v.arg(1) );
|
||||
LuaValue f = v.arg(2);
|
||||
assertEquals( LuaValue.TFUNCTION, f.type() );
|
||||
assertEquals( eee, f.call() );
|
||||
assertEquals( newenv, f.getfenv() );
|
||||
}
|
||||
}
|
||||
}
|
||||
366
test/junit/org/luaj/vm2/MetatableTest.java
Normal file
366
test/junit/org/luaj/vm2/MetatableTest.java
Normal file
@@ -0,0 +1,366 @@
|
||||
/*******************************************************************************
|
||||
* 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 junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.TypeTest.MyData;
|
||||
import org.luaj.vm2.lib.StringLib;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
public class MetatableTest extends TestCase {
|
||||
|
||||
private final String samplestring = "abcdef";
|
||||
private final Object sampleobject = new Object();
|
||||
private final MyData sampledata = new MyData();
|
||||
|
||||
private final LuaValue string = LuaValue.valueOf(samplestring);
|
||||
private final LuaTable table = LuaValue.tableOf();
|
||||
private final LuaFunction function = new ZeroArgFunction() { public LuaValue call() { return NONE;}};
|
||||
private final LuaThread thread = new LuaThread(function,table);
|
||||
private final LuaClosure closure = new LuaClosure();
|
||||
private final LuaUserdata userdata = LuaValue.userdataOf(sampleobject);
|
||||
private final LuaUserdata userdatamt = LuaValue.userdataOf(sampledata,table);
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
// needed for metatable ops to work on strings
|
||||
new StringLib();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
LuaBoolean.s_metatable = null;
|
||||
LuaFunction.s_metatable = null;
|
||||
LuaNil.s_metatable = null;
|
||||
LuaNumber.s_metatable = null;
|
||||
// LuaString.s_metatable = null;
|
||||
LuaThread.s_metatable = null;
|
||||
}
|
||||
|
||||
public void testGetMetatable() {
|
||||
assertEquals( null, LuaValue.NIL.getmetatable() );
|
||||
assertEquals( null, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( null, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, table.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
assertEquals( null, userdata.getmetatable() );
|
||||
assertEquals( table, userdatamt.getmetatable() );
|
||||
}
|
||||
|
||||
public void testSetMetatable() {
|
||||
LuaValue mt = LuaValue.tableOf();
|
||||
assertEquals( null, table.getmetatable() );
|
||||
assertEquals( null, userdata.getmetatable() );
|
||||
assertEquals( table, userdatamt.getmetatable() );
|
||||
assertEquals( table, table.setmetatable(mt) );
|
||||
assertEquals( userdata, userdata.setmetatable(mt) );
|
||||
assertEquals( userdatamt, userdatamt.setmetatable(mt) );
|
||||
assertEquals( mt, table.getmetatable() );
|
||||
assertEquals( mt, userdata.getmetatable() );
|
||||
assertEquals( mt, userdatamt.getmetatable() );
|
||||
|
||||
// these all get metatable behind-the-scenes
|
||||
assertEquals( null, LuaValue.NIL.getmetatable() );
|
||||
assertEquals( null, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( null, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
LuaNil.s_metatable = mt;
|
||||
assertEquals( mt, LuaValue.NIL.getmetatable() );
|
||||
assertEquals( null, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( null, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
LuaBoolean.s_metatable = mt;
|
||||
assertEquals( mt, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( null, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
LuaNumber.s_metatable = mt;
|
||||
assertEquals( mt, LuaValue.ONE.getmetatable() );
|
||||
assertEquals( mt, LuaValue.valueOf(1.25).getmetatable() );
|
||||
// assertEquals( null, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
// LuaString.s_metatable = mt;
|
||||
// assertEquals( mt, string.getmetatable() );
|
||||
assertEquals( null, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
assertEquals( null, closure.getmetatable() );
|
||||
LuaFunction.s_metatable = mt;
|
||||
assertEquals( mt, function.getmetatable() );
|
||||
assertEquals( null, thread.getmetatable() );
|
||||
LuaThread.s_metatable = mt;
|
||||
assertEquals( mt, thread.getmetatable() );
|
||||
}
|
||||
|
||||
public void testMetatableIndex() {
|
||||
assertEquals( table, table.setmetatable(null) );
|
||||
assertEquals( userdata, userdata.setmetatable(null) );
|
||||
assertEquals( userdatamt, userdatamt.setmetatable(null) );
|
||||
assertEquals( LuaValue.NIL, table.get(1) );
|
||||
assertEquals( LuaValue.NIL, userdata.get(1) );
|
||||
assertEquals( LuaValue.NIL, userdatamt.get(1) );
|
||||
|
||||
// empty metatable
|
||||
LuaValue mt = LuaValue.tableOf();
|
||||
assertEquals( table, table.setmetatable(mt) );
|
||||
assertEquals( userdata, userdata.setmetatable(mt) );
|
||||
LuaBoolean.s_metatable = mt;
|
||||
LuaFunction.s_metatable = mt;
|
||||
LuaNil.s_metatable = mt;
|
||||
LuaNumber.s_metatable = mt;
|
||||
// LuaString.s_metatable = mt;
|
||||
LuaThread.s_metatable = mt;
|
||||
assertEquals( mt, table.getmetatable() );
|
||||
assertEquals( mt, userdata.getmetatable() );
|
||||
assertEquals( mt, LuaValue.NIL.getmetatable() );
|
||||
assertEquals( mt, LuaValue.TRUE.getmetatable() );
|
||||
assertEquals( mt, LuaValue.ONE.getmetatable() );
|
||||
// assertEquals( StringLib.instance, string.getmetatable() );
|
||||
assertEquals( mt, function.getmetatable() );
|
||||
assertEquals( mt, thread.getmetatable() );
|
||||
|
||||
// plain metatable
|
||||
LuaValue abc = LuaValue.valueOf("abc");
|
||||
mt.set( LuaValue.INDEX, LuaValue.listOf(new LuaValue[] { abc } ) );
|
||||
assertEquals( abc, table.get(1) );
|
||||
assertEquals( abc, userdata.get(1) );
|
||||
assertEquals( abc, LuaValue.NIL.get(1) );
|
||||
assertEquals( abc, LuaValue.TRUE.get(1) );
|
||||
assertEquals( abc, LuaValue.ONE.get(1) );
|
||||
// assertEquals( abc, string.get(1) );
|
||||
assertEquals( abc, function.get(1) );
|
||||
assertEquals( abc, thread.get(1) );
|
||||
|
||||
// plain metatable
|
||||
mt.set( LuaValue.INDEX, new TwoArgFunction() {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
return LuaValue.valueOf( arg1.typename()+"["+arg2.toString()+"]=xyz" );
|
||||
}
|
||||
|
||||
});
|
||||
assertEquals( "table[1]=xyz", table.get(1).toString() );
|
||||
assertEquals( "userdata[1]=xyz", userdata.get(1).toString() );
|
||||
assertEquals( "nil[1]=xyz", LuaValue.NIL.get(1).toString() );
|
||||
assertEquals( "boolean[1]=xyz", LuaValue.TRUE.get(1).toString() );
|
||||
assertEquals( "number[1]=xyz", LuaValue.ONE.get(1).toString() );
|
||||
// assertEquals( "string[1]=xyz", string.get(1).toString() );
|
||||
assertEquals( "function[1]=xyz", function.get(1).toString() );
|
||||
assertEquals( "thread[1]=xyz", thread.get(1).toString() );
|
||||
}
|
||||
|
||||
|
||||
public void testMetatableNewIndex() {
|
||||
// empty metatable
|
||||
LuaValue mt = LuaValue.tableOf();
|
||||
assertEquals( table, table.setmetatable(mt) );
|
||||
assertEquals( userdata, userdata.setmetatable(mt) );
|
||||
LuaBoolean.s_metatable = mt;
|
||||
LuaFunction.s_metatable = mt;
|
||||
LuaNil.s_metatable = mt;
|
||||
LuaNumber.s_metatable = mt;
|
||||
// LuaString.s_metatable = mt;
|
||||
LuaThread.s_metatable = mt;
|
||||
|
||||
// plain metatable
|
||||
final LuaValue fallback = LuaValue.tableOf();
|
||||
LuaValue abc = LuaValue.valueOf("abc");
|
||||
mt.set( LuaValue.NEWINDEX, fallback );
|
||||
table.set(2,abc);
|
||||
userdata.set(3,abc);
|
||||
LuaValue.NIL.set(4,abc);
|
||||
LuaValue.TRUE.set(5,abc);
|
||||
LuaValue.ONE.set(6,abc);
|
||||
// string.set(7,abc);
|
||||
function.set(8,abc);
|
||||
thread.set(9,abc);
|
||||
assertEquals( abc, fallback.get(2) );
|
||||
assertEquals( abc, fallback.get(3) );
|
||||
assertEquals( abc, fallback.get(4) );
|
||||
assertEquals( abc, fallback.get(5) );
|
||||
assertEquals( abc, fallback.get(6) );
|
||||
// assertEquals( abc, StringLib.instance.get(7) );
|
||||
assertEquals( abc, fallback.get(8) );
|
||||
assertEquals( abc, fallback.get(9) );
|
||||
|
||||
// metatable with function call
|
||||
mt.set( LuaValue.NEWINDEX, new ThreeArgFunction() {
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
|
||||
fallback.rawset(arg2, LuaValue.valueOf( "via-func-"+arg3 ));
|
||||
return NONE;
|
||||
}
|
||||
|
||||
});
|
||||
table.set(12,abc);
|
||||
userdata.set(13,abc);
|
||||
LuaValue.NIL.set(14,abc);
|
||||
LuaValue.TRUE.set(15,abc);
|
||||
LuaValue.ONE.set(16,abc);
|
||||
// string.set(17,abc);
|
||||
function.set(18,abc);
|
||||
thread.set(19,abc);
|
||||
LuaValue via = LuaValue.valueOf( "via-func-abc" );
|
||||
assertEquals( via, fallback.get(12) );
|
||||
assertEquals( via, fallback.get(13) );
|
||||
assertEquals( via, fallback.get(14) );
|
||||
assertEquals( via, fallback.get(15) );
|
||||
assertEquals( via, fallback.get(16) );
|
||||
// assertEquals( via, StringLib.instance.get(17) );
|
||||
assertEquals( via, fallback.get(18) );
|
||||
assertEquals( via, fallback.get(19) );
|
||||
}
|
||||
|
||||
|
||||
private void checkTable( LuaValue t,
|
||||
LuaValue aa, LuaValue bb, LuaValue cc, LuaValue dd, LuaValue ee, LuaValue ff, LuaValue gg,
|
||||
LuaValue ra, LuaValue rb, LuaValue rc, LuaValue rd, LuaValue re, LuaValue rf, LuaValue rg ) {
|
||||
assertEquals( aa, t.get("aa") );
|
||||
assertEquals( bb, t.get("bb") );
|
||||
assertEquals( cc, t.get("cc") );
|
||||
assertEquals( dd, t.get("dd") );
|
||||
assertEquals( ee, t.get("ee") );
|
||||
assertEquals( ff, t.get("ff") );
|
||||
assertEquals( gg, t.get("gg") );
|
||||
assertEquals( ra, t.rawget("aa") );
|
||||
assertEquals( rb, t.rawget("bb") );
|
||||
assertEquals( rc, t.rawget("cc") );
|
||||
assertEquals( rd, t.rawget("dd") );
|
||||
assertEquals( re, t.rawget("ee") );
|
||||
assertEquals( rf, t.rawget("ff") );
|
||||
assertEquals( rg, t.rawget("gg") );
|
||||
}
|
||||
|
||||
private LuaValue makeTable( String key1, String val1, String key2, String val2 ) {
|
||||
return LuaValue.tableOf( new LuaValue[] {
|
||||
LuaValue.valueOf(key1), LuaValue.valueOf(val1),
|
||||
LuaValue.valueOf(key2), LuaValue.valueOf(val2),
|
||||
} );
|
||||
}
|
||||
|
||||
public void testRawsetMetatableSet() {
|
||||
// set up tables
|
||||
LuaValue m = makeTable( "aa", "aaa", "bb", "bbb" );
|
||||
m.set(LuaValue.INDEX, m);
|
||||
m.set(LuaValue.NEWINDEX, m);
|
||||
LuaValue s = makeTable( "cc", "ccc", "dd", "ddd" );
|
||||
LuaValue t = makeTable( "cc", "ccc", "dd", "ddd" );
|
||||
t.setmetatable(m);
|
||||
LuaValue aaa = LuaValue.valueOf("aaa");
|
||||
LuaValue bbb = LuaValue.valueOf("bbb");
|
||||
LuaValue ccc = LuaValue.valueOf("ccc");
|
||||
LuaValue ddd = LuaValue.valueOf("ddd");
|
||||
LuaValue ppp = LuaValue.valueOf("ppp");
|
||||
LuaValue qqq = LuaValue.valueOf("qqq");
|
||||
LuaValue rrr = LuaValue.valueOf("rrr");
|
||||
LuaValue sss = LuaValue.valueOf("sss");
|
||||
LuaValue ttt = LuaValue.valueOf("ttt");
|
||||
LuaValue www = LuaValue.valueOf("www");
|
||||
LuaValue xxx = LuaValue.valueOf("xxx");
|
||||
LuaValue yyy = LuaValue.valueOf("yyy");
|
||||
LuaValue zzz = LuaValue.valueOf("zzz");
|
||||
LuaValue nil = LuaValue.NIL;
|
||||
|
||||
// check initial values
|
||||
// values via "bet()" values via "rawget()"
|
||||
checkTable( s, nil,nil,ccc,ddd,nil,nil,nil, nil,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,bbb,ccc,ddd,nil,nil,nil, nil,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
|
||||
// rawset()
|
||||
s.rawset("aa", www);
|
||||
checkTable( s, www,nil,ccc,ddd,nil,nil,nil, www,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,bbb,ccc,ddd,nil,nil,nil, nil,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
s.rawset("cc", xxx);
|
||||
checkTable( s, www,nil,xxx,ddd,nil,nil,nil, www,nil,xxx,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,bbb,ccc,ddd,nil,nil,nil, nil,nil,ccc,ddd,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
t.rawset("bb", yyy);
|
||||
checkTable( s, www,nil,xxx,ddd,nil,nil,nil, www,nil,xxx,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,ddd,nil,nil,nil, nil,yyy,ccc,ddd,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
t.rawset("dd", zzz);
|
||||
checkTable( s, www,nil,xxx,ddd,nil,nil,nil, www,nil,xxx,ddd,nil,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,zzz,nil,nil,nil, nil,yyy,ccc,zzz,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
|
||||
// set() invoking metatables
|
||||
s.set("ee", ppp);
|
||||
checkTable( s, www,nil,xxx,ddd,ppp,nil,nil, www,nil,xxx,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,zzz,nil,nil,nil, nil,yyy,ccc,zzz,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
s.set("cc", qqq);
|
||||
checkTable( s, www,nil,qqq,ddd,ppp,nil,nil, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,zzz,nil,nil,nil, nil,yyy,ccc,zzz,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,nil,nil, aaa,bbb,nil,nil,nil,nil,nil );
|
||||
t.set("ff", rrr);
|
||||
checkTable( s, www,nil,qqq,ddd,ppp,nil,nil, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,zzz,nil,rrr,nil, nil,yyy,ccc,zzz,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,nil, aaa,bbb,nil,nil,nil,rrr,nil );
|
||||
t.set("dd", sss);
|
||||
checkTable( s, www,nil,qqq,ddd,ppp,nil,nil, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,sss,nil,rrr,nil, nil,yyy,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,nil, aaa,bbb,nil,nil,nil,rrr,nil );
|
||||
m.set("gg", ttt);
|
||||
checkTable( s, www,nil,qqq,ddd,ppp,nil,nil, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,sss,nil,rrr,ttt, nil,yyy,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
|
||||
// make s fall back to t
|
||||
s.setmetatable(LuaValue.tableOf(new LuaValue[] {LuaValue.INDEX,t,LuaValue.NEWINDEX,t}));
|
||||
checkTable( s, www,yyy,qqq,ddd,ppp,rrr,ttt, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,sss,nil,rrr,ttt, nil,yyy,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
s.set("aa", www);
|
||||
checkTable( s, www,yyy,qqq,ddd,ppp,rrr,ttt, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,yyy,ccc,sss,nil,rrr,ttt, nil,yyy,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
s.set("bb", zzz);
|
||||
checkTable( s, www,zzz,qqq,ddd,ppp,rrr,ttt, www,nil,qqq,ddd,ppp,nil,nil );
|
||||
checkTable( t, aaa,zzz,ccc,sss,nil,rrr,ttt, nil,zzz,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
s.set("ee", xxx);
|
||||
checkTable( s, www,zzz,qqq,ddd,xxx,rrr,ttt, www,nil,qqq,ddd,xxx,nil,nil );
|
||||
checkTable( t, aaa,zzz,ccc,sss,nil,rrr,ttt, nil,zzz,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,rrr,ttt, aaa,bbb,nil,nil,nil,rrr,ttt );
|
||||
s.set("ff", yyy);
|
||||
checkTable( s, www,zzz,qqq,ddd,xxx,yyy,ttt, www,nil,qqq,ddd,xxx,nil,nil );
|
||||
checkTable( t, aaa,zzz,ccc,sss,nil,yyy,ttt, nil,zzz,ccc,sss,nil,nil,nil );
|
||||
checkTable( m, aaa,bbb,nil,nil,nil,yyy,ttt, aaa,bbb,nil,nil,nil,yyy,ttt );
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
247
test/junit/org/luaj/vm2/ScriptDrivenTest.java
Normal file
247
test/junit/org/luaj/vm2/ScriptDrivenTest.java
Normal file
@@ -0,0 +1,247 @@
|
||||
/*******************************************************************************
|
||||
* 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.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.compiler.LuaC;
|
||||
import org.luaj.vm2.lib.BaseLib;
|
||||
import org.luaj.vm2.lib.CoroutineLib;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
import org.luaj.vm2.luajc.LuaJCompiler;
|
||||
|
||||
abstract
|
||||
public class ScriptDrivenTest extends TestCase {
|
||||
public static final boolean nocompile = "true".equals(System.getProperty("nocompile"));
|
||||
|
||||
public enum PlatformType {
|
||||
JME, JSE, LUAJIT,
|
||||
}
|
||||
|
||||
private final PlatformType platform;
|
||||
private final String basedir;
|
||||
|
||||
protected ScriptDrivenTest( PlatformType platform, String directory ) {
|
||||
this.platform = platform;
|
||||
this.basedir = directory;
|
||||
}
|
||||
|
||||
// */
|
||||
protected void runTest(String testName) {
|
||||
try {
|
||||
|
||||
// create globals
|
||||
LuaC.install();
|
||||
LuaTable _G = null;
|
||||
switch ( platform ) {
|
||||
default:
|
||||
case JSE:
|
||||
case LUAJIT:
|
||||
_G = org.luaj.vm2.lib.JsePlatform.standardGlobals();
|
||||
break;
|
||||
case JME:
|
||||
_G = org.luaj.vm2.lib.JmePlatform.standardGlobals();
|
||||
break;
|
||||
}
|
||||
DebugLib.install( _G );
|
||||
|
||||
// override print()
|
||||
final ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
final PrintStream oldps = BaseLib.STDOUT;
|
||||
final PrintStream ps = new PrintStream( output );
|
||||
BaseLib.STDOUT = ps;
|
||||
|
||||
// run the script
|
||||
try {
|
||||
LuaValue chunk = loadScript(testName, _G);
|
||||
chunk.call(LuaValue.valueOf(platform.toString()));
|
||||
|
||||
ps.flush();
|
||||
final String actualOutput = new String(output.toByteArray());
|
||||
final String expectedOutput = getExpectedOutput(testName);
|
||||
|
||||
assertEquals(expectedOutput, actualOutput);
|
||||
} finally {
|
||||
BaseLib.STDOUT = oldps;
|
||||
ps.close();
|
||||
}
|
||||
} catch ( IOException ioe ) {
|
||||
throw new RuntimeException(ioe.toString());
|
||||
} catch ( InterruptedException ie ) {
|
||||
throw new RuntimeException(ie.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected LuaValue loadScript(String name, LuaTable _G) throws IOException {
|
||||
File file = new File(basedir+"/"+name+".lua");
|
||||
if ( !file.exists() )
|
||||
fail("Could not load script for test case: " + name);
|
||||
|
||||
InputStream script=null;
|
||||
try {
|
||||
// Use "stdin" instead of resource name so that output matches
|
||||
// standard Lua.
|
||||
switch ( this.platform ) {
|
||||
case LUAJIT:
|
||||
if ( nocompile ) {
|
||||
LuaValue c = (LuaValue) Class.forName(name).newInstance();
|
||||
c.setfenv(_G);
|
||||
return c;
|
||||
} else {
|
||||
script = new FileInputStream(file);
|
||||
return LuaJCompiler.compile( script, name, _G);
|
||||
}
|
||||
default:
|
||||
script = new FileInputStream(file);
|
||||
Prototype p = LoadState.undump(script, "stdin");
|
||||
return new LuaClosure(p,_G);
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
throw new IOException( e.toString() );
|
||||
} finally {
|
||||
if ( script != null )
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
|
||||
private String getExpectedOutput(final String name) throws IOException,
|
||||
InterruptedException {
|
||||
String expectedOutputName = basedir+"/"+name+"-expected.out";
|
||||
File file = new File( expectedOutputName );
|
||||
if ( file.exists() ) {
|
||||
InputStream is = new FileInputStream(file);
|
||||
try {
|
||||
return readString(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
} else {
|
||||
file = new File(basedir+"/"+name+".lua");
|
||||
if ( !file.exists() )
|
||||
fail("Could not load script for test case: " + name);
|
||||
InputStream script = new FileInputStream(file);
|
||||
// }
|
||||
try {
|
||||
String luaCommand = System.getProperty("LUA_COMMAND");
|
||||
if ( luaCommand == null )
|
||||
luaCommand = "lua";
|
||||
String[] args = new String[] { luaCommand, "-", platform.toString() };
|
||||
return collectProcessOutput(args, script);
|
||||
} finally {
|
||||
script.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String collectProcessOutput(String[] cmd, final InputStream input)
|
||||
throws IOException, InterruptedException {
|
||||
Runtime r = Runtime.getRuntime();
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final Process p = r.exec(cmd);
|
||||
try {
|
||||
// start a thread to write the given input to the subprocess.
|
||||
Thread inputCopier = (new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
OutputStream processStdIn = p.getOutputStream();
|
||||
try {
|
||||
copy(input, processStdIn);
|
||||
} finally {
|
||||
processStdIn.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
inputCopier.start();
|
||||
|
||||
// start another thread to read output from the subprocess.
|
||||
Thread outputCopier = (new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
InputStream processStdOut = p.getInputStream();
|
||||
try {
|
||||
copy(processStdOut, baos);
|
||||
} finally {
|
||||
processStdOut.close();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
outputCopier.start();
|
||||
|
||||
// start another thread to read output from the subprocess.
|
||||
Thread errorCopier = (new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
InputStream processError = p.getErrorStream();
|
||||
try {
|
||||
copy(processError, System.err);
|
||||
} finally {
|
||||
processError.close();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
errorCopier.start();
|
||||
|
||||
p.waitFor();
|
||||
inputCopier.join();
|
||||
outputCopier.join();
|
||||
errorCopier.join();
|
||||
|
||||
return new String(baos.toByteArray());
|
||||
|
||||
} finally {
|
||||
p.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
private String readString(InputStream is) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
copy(is, baos);
|
||||
return new String(baos.toByteArray());
|
||||
}
|
||||
|
||||
private void copy(InputStream is, OutputStream os) throws IOException {
|
||||
byte[] buf = new byte[1024];
|
||||
int r;
|
||||
while ((r = is.read(buf)) >= 0) {
|
||||
os.write(buf, 0, r);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
355
test/junit/org/luaj/vm2/TableArrayTest.java
Normal file
355
test/junit/org/luaj/vm2/TableArrayTest.java
Normal file
@@ -0,0 +1,355 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import org.luaj.vm2.LuaDouble;
|
||||
import org.luaj.vm2.LuaInteger;
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for tables used as lists.
|
||||
*/
|
||||
public class TableArrayTest extends TestCase {
|
||||
|
||||
protected LuaTable new_Table() {
|
||||
return new LuaTable();
|
||||
}
|
||||
|
||||
protected LuaTable new_Table(int n,int m) {
|
||||
return new LuaTable(n,m);
|
||||
}
|
||||
|
||||
public void testInOrderIntegerKeyInsertion() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( i, LuaString.valueOf( "Test Value! "+i ) );
|
||||
}
|
||||
|
||||
// Ensure all keys are still there.
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
assertEquals( "Test Value! " + i, t.get( i ).toString() );
|
||||
}
|
||||
|
||||
// Ensure capacities make sense
|
||||
assertEquals( 0, t.hashCapacity() );
|
||||
|
||||
assertTrue( t.arrayCapacity() >= 32 );
|
||||
assertTrue( t.arrayCapacity() <= 64 );
|
||||
|
||||
}
|
||||
|
||||
public void testResize() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
// NOTE: This order of insertion is important.
|
||||
t.set(3, LuaInteger.valueOf(3));
|
||||
t.set(1, LuaInteger.valueOf(1));
|
||||
t.set(5, LuaInteger.valueOf(5));
|
||||
t.set(4, LuaInteger.valueOf(4));
|
||||
t.set(6, LuaInteger.valueOf(6));
|
||||
t.set(2, LuaInteger.valueOf(2));
|
||||
|
||||
for ( int i = 1; i < 6; ++i ) {
|
||||
assertEquals(LuaInteger.valueOf(i), t.get(i));
|
||||
}
|
||||
|
||||
assertTrue( t.arrayCapacity() >= 0 && t.arrayCapacity() <= 2 );
|
||||
assertTrue( t.hashCapacity() >= 4 );
|
||||
}
|
||||
|
||||
public void testOutOfOrderIntegerKeyInsertion() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 32; i > 0; --i ) {
|
||||
t.set( i, LuaString.valueOf( "Test Value! "+i ) );
|
||||
}
|
||||
|
||||
// Ensure all keys are still there.
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
assertEquals( "Test Value! "+i, t.get( i ).toString() );
|
||||
}
|
||||
|
||||
// Ensure capacities make sense
|
||||
assertTrue( t.arrayCapacity() >= 0 );
|
||||
assertTrue( t.arrayCapacity() <= 6 );
|
||||
|
||||
assertTrue( t.hashCapacity() >= 16 );
|
||||
assertTrue( t.hashCapacity() <= 64 );
|
||||
|
||||
}
|
||||
|
||||
public void testStringAndIntegerKeys() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 0; i < 10; ++i ) {
|
||||
LuaString str = LuaString.valueOf( String.valueOf( i ) );
|
||||
t.set( i, str );
|
||||
t.set( str, LuaInteger.valueOf( i ) );
|
||||
}
|
||||
|
||||
assertTrue( t.arrayCapacity() >= 9 ); // 1, 2, ..., 9
|
||||
assertTrue( t.arrayCapacity() <= 18 );
|
||||
assertTrue( t.hashCapacity() >= 11 ); // 0, "0", "1", ..., "9"
|
||||
assertTrue( t.hashCapacity() <= 33 );
|
||||
|
||||
LuaValue[] keys = t.keys();
|
||||
|
||||
int intKeys = 0;
|
||||
int stringKeys = 0;
|
||||
|
||||
assertEquals( 20, keys.length );
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
LuaValue k = keys[i];
|
||||
|
||||
if ( k instanceof LuaInteger ) {
|
||||
final int ik = k.toint();
|
||||
assertTrue( ik >= 0 && ik < 10 );
|
||||
final int mask = 1 << ik;
|
||||
assertTrue( ( intKeys & mask ) == 0 );
|
||||
intKeys |= mask;
|
||||
} else if ( k instanceof LuaString ) {
|
||||
final int ik = Integer.parseInt( k.toString() );
|
||||
assertEquals( String.valueOf( ik ), k.toString() );
|
||||
assertTrue( ik >= 0 && ik < 10 );
|
||||
final int mask = 1 << ik;
|
||||
assertTrue( "Key \""+ik+"\" found more than once", ( stringKeys & mask ) == 0 );
|
||||
stringKeys |= mask;
|
||||
} else {
|
||||
fail( "Unexpected type of key found" );
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals( 0x03FF, intKeys );
|
||||
assertEquals( 0x03FF, stringKeys );
|
||||
}
|
||||
|
||||
public void testBadInitialCapacity() {
|
||||
LuaTable t = new_Table(0, 1);
|
||||
|
||||
t.set( "test", LuaString.valueOf("foo") );
|
||||
t.set( "explode", LuaString.valueOf("explode") );
|
||||
assertEquals( 2, t.keyCount() );
|
||||
}
|
||||
|
||||
public void testRemove0() {
|
||||
LuaTable t = new_Table(2, 0);
|
||||
|
||||
t.set( 1, LuaString.valueOf("foo") );
|
||||
t.set( 2, LuaString.valueOf("bah") );
|
||||
assertNotSame(LuaValue.NIL, t.get(1));
|
||||
assertNotSame(LuaValue.NIL, t.get(2));
|
||||
assertEquals(LuaValue.NIL, t.get(3));
|
||||
|
||||
t.set( 1, LuaValue.NIL );
|
||||
t.set( 2, LuaValue.NIL );
|
||||
t.set( 3, LuaValue.NIL );
|
||||
assertEquals(LuaValue.NIL, t.get(1));
|
||||
assertEquals(LuaValue.NIL, t.get(2));
|
||||
assertEquals(LuaValue.NIL, t.get(3));
|
||||
}
|
||||
|
||||
public void testRemove1() {
|
||||
LuaTable t = new_Table(0, 1);
|
||||
assertEquals( 0, t.keyCount() );
|
||||
|
||||
t.set( "test", LuaString.valueOf("foo") );
|
||||
assertEquals( 1, t.keyCount() );
|
||||
t.set( "explode", LuaValue.NIL );
|
||||
assertEquals( 1, t.keyCount() );
|
||||
t.set( 42, LuaValue.NIL );
|
||||
assertEquals( 1, t.keyCount() );
|
||||
t.set( new_Table(), LuaValue.NIL );
|
||||
assertEquals( 1, t.keyCount() );
|
||||
t.set( "test", LuaValue.NIL );
|
||||
assertEquals( 0, t.keyCount() );
|
||||
|
||||
t.set( 10, LuaInteger.valueOf( 5 ) );
|
||||
t.set( 10, LuaValue.NIL );
|
||||
assertEquals( 0, t.keyCount() );
|
||||
}
|
||||
|
||||
public void testRemove2() {
|
||||
LuaTable t = new_Table(0, 1);
|
||||
|
||||
t.set( "test", LuaString.valueOf("foo") );
|
||||
t.set( "string", LuaInteger.valueOf( 10 ) );
|
||||
assertEquals( 2, t.keyCount() );
|
||||
|
||||
t.set( "string", LuaValue.NIL );
|
||||
t.set( "three", LuaDouble.valueOf( 3.14 ) );
|
||||
assertEquals( 2, t.keyCount() );
|
||||
|
||||
t.set( "test", LuaValue.NIL );
|
||||
assertEquals( 1, t.keyCount() );
|
||||
|
||||
t.set( 10, LuaInteger.valueOf( 5 ) );
|
||||
assertEquals( 2, t.keyCount() );
|
||||
|
||||
t.set( 10, LuaValue.NIL );
|
||||
assertEquals( 1, t.keyCount() );
|
||||
|
||||
t.set( "three", LuaValue.NIL );
|
||||
assertEquals( 0, t.keyCount() );
|
||||
}
|
||||
|
||||
public void testInOrderlen() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaValue v = LuaString.valueOf( "Test Value! "+i );
|
||||
t.set( i, v );
|
||||
assertEquals( i, t.length() );
|
||||
assertEquals( i, t.maxn() );
|
||||
}
|
||||
}
|
||||
|
||||
public void testOutOfOrderlen() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int j=8; j<32; j+=8 ) {
|
||||
for ( int i = j; i > 0; --i ) {
|
||||
t.set( i, LuaString.valueOf( "Test Value! "+i ) );
|
||||
}
|
||||
assertEquals( j, t.length() );
|
||||
assertEquals( j, t.maxn() );
|
||||
}
|
||||
}
|
||||
|
||||
public void testStringKeyslen() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( "str-"+i, LuaString.valueOf( "String Key Test Value! "+i ) );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( 0, t.maxn() );
|
||||
}
|
||||
}
|
||||
|
||||
public void testMixedKeyslen() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( "str-"+i, LuaString.valueOf( "String Key Test Value! "+i ) );
|
||||
t.set( i, LuaString.valueOf( "Int Key Test Value! "+i ) );
|
||||
assertEquals( i, t.length() );
|
||||
assertEquals( i, t.maxn() );
|
||||
}
|
||||
}
|
||||
|
||||
private static final void compareLists(LuaTable t,Vector v) {
|
||||
int n = v.size();
|
||||
assertEquals(v.size(),t.length());
|
||||
for ( int j=0; j<n; j++ ) {
|
||||
Object vj = v.elementAt(j);
|
||||
Object tj = t.get(j+1).toString();
|
||||
vj = ((LuaString)vj).toString();
|
||||
assertEquals(vj,tj);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertBeginningOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaString.valueOf("Test Value! "+i);
|
||||
t.insert(1, test);
|
||||
v.insertElementAt(test, 0);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertEndOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaString.valueOf("Test Value! "+i);
|
||||
t.insert(0, test);
|
||||
v.insertElementAt(test, v.size());
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertMiddleOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaString.valueOf("Test Value! "+i);
|
||||
int m = i / 2;
|
||||
t.insert(m+1, test);
|
||||
v.insertElementAt(test, m);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
private static final void prefillLists(LuaTable t,Vector v) {
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaString.valueOf("Test Value! "+i);
|
||||
t.insert(0, test);
|
||||
v.insertElementAt(test, v.size());
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveBeginningOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
prefillLists(t,v);
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.remove(1);
|
||||
v.removeElementAt(0);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveEndOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
prefillLists(t,v);
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.remove(0);
|
||||
v.removeElementAt(v.size()-1);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveMiddleOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
prefillLists(t,v);
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
int m = v.size() / 2;
|
||||
t.remove(m+1);
|
||||
v.removeElementAt(m);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
245
test/junit/org/luaj/vm2/TableHashTest.java
Normal file
245
test/junit/org/luaj/vm2/TableHashTest.java
Normal file
@@ -0,0 +1,245 @@
|
||||
/*******************************************************************************
|
||||
* 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 junit.framework.TestCase;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* Tests for tables used as lists.
|
||||
*/
|
||||
public class TableHashTest extends TestCase {
|
||||
|
||||
protected LuaTable new_Table() {
|
||||
return new LuaTable();
|
||||
}
|
||||
|
||||
protected LuaTable new_Table(int n,int m) {
|
||||
return new LuaTable(n,m);
|
||||
}
|
||||
|
||||
public void testSetRemove() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
assertEquals( 0, t.hashCapacity() );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( 0, t.keyCount() );
|
||||
|
||||
String[] keys = { "abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "wxy", "z01",
|
||||
"cd", "ef", "g", "hi", "jk", "lm", "no", "pq", "rs", };
|
||||
int[] capacities = { 0, 2, 4, 4, 7, 7, 7, 10, 10, 14, 14, 14, 14, 19, 19, 19, 19, 25, 25, 25 };
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
assertEquals( capacities[i], t.hashCapacity() );
|
||||
String si = "Test Value! "+i;
|
||||
t.set( keys[i], si );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( i+1, t.keyCount() );
|
||||
}
|
||||
assertEquals( capacities[keys.length], t.hashCapacity() );
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
LuaValue vi = LuaString.valueOf( "Test Value! "+i );
|
||||
assertEquals( vi, t.get( keys[i] ) );
|
||||
assertEquals( vi, t.get( LuaString.valueOf(keys[i]) ) );
|
||||
assertEquals( vi, t.rawget( keys[i] ) );
|
||||
assertEquals( vi, t.rawget( keys[i] ) );
|
||||
}
|
||||
|
||||
// replace with new values
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
t.set( keys[i], LuaString.valueOf( "Replacement Value! "+i ) );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( keys.length, t.keyCount() );
|
||||
assertEquals( capacities[keys.length], t.hashCapacity() );
|
||||
}
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
LuaValue vi = LuaString.valueOf( "Replacement Value! "+i );
|
||||
assertEquals( vi, t.get( keys[i] ) );
|
||||
}
|
||||
|
||||
// remove
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
t.set( keys[i], LuaValue.NIL );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( keys.length-i-1, t.keyCount() );
|
||||
if ( i<keys.length-1 )
|
||||
assertEquals( capacities[keys.length], t.hashCapacity() );
|
||||
else
|
||||
assertTrue( 0<=t.hashCapacity() );
|
||||
}
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
assertEquals( LuaValue.NIL, t.get( keys[i] ) );
|
||||
}
|
||||
}
|
||||
|
||||
public void testIndexMetatag() {
|
||||
LuaTable t = new_Table();
|
||||
LuaTable mt = new_Table();
|
||||
LuaTable fb = new_Table();
|
||||
|
||||
// set basic values
|
||||
t.set( "ppp", "abc" );
|
||||
t.set( 123, "def" );
|
||||
mt.set(LuaValue.INDEX, fb);
|
||||
fb.set( "qqq", "ghi" );
|
||||
fb.set( 456, "jkl" );
|
||||
|
||||
// check before setting metatable
|
||||
assertEquals( "abc", t.get("ppp").toString() );
|
||||
assertEquals( "def", t.get(123).toString() );
|
||||
assertEquals( "nil", t.get("qqq").toString() );
|
||||
assertEquals( "nil", t.get(456).toString() );
|
||||
assertEquals( "nil", fb.get("ppp").toString() );
|
||||
assertEquals( "nil", fb.get(123).toString() );
|
||||
assertEquals( "ghi", fb.get("qqq").toString() );
|
||||
assertEquals( "jkl", fb.get(456).toString() );
|
||||
assertEquals( "nil", mt.get("ppp").toString() );
|
||||
assertEquals( "nil", mt.get(123).toString() );
|
||||
assertEquals( "nil", mt.get("qqq").toString() );
|
||||
assertEquals( "nil", mt.get(456).toString() );
|
||||
|
||||
// check before setting metatable
|
||||
t.setmetatable(mt);
|
||||
assertEquals( mt, t.getmetatable() );
|
||||
assertEquals( "abc", t.get("ppp").toString() );
|
||||
assertEquals( "def", t.get(123).toString() );
|
||||
assertEquals( "ghi", t.get("qqq").toString() );
|
||||
assertEquals( "jkl", t.get(456).toString() );
|
||||
assertEquals( "nil", fb.get("ppp").toString() );
|
||||
assertEquals( "nil", fb.get(123).toString() );
|
||||
assertEquals( "ghi", fb.get("qqq").toString() );
|
||||
assertEquals( "jkl", fb.get(456).toString() );
|
||||
assertEquals( "nil", mt.get("ppp").toString() );
|
||||
assertEquals( "nil", mt.get(123).toString() );
|
||||
assertEquals( "nil", mt.get("qqq").toString() );
|
||||
assertEquals( "nil", mt.get(456).toString() );
|
||||
|
||||
// set metatable to metatable without values
|
||||
t.setmetatable(fb);
|
||||
assertEquals( "abc", t.get("ppp").toString() );
|
||||
assertEquals( "def", t.get(123).toString() );
|
||||
assertEquals( "nil", t.get("qqq").toString() );
|
||||
assertEquals( "nil", t.get(456).toString() );
|
||||
|
||||
// set metatable to null
|
||||
t.setmetatable(null);
|
||||
assertEquals( "abc", t.get("ppp").toString() );
|
||||
assertEquals( "def", t.get(123).toString() );
|
||||
assertEquals( "nil", t.get("qqq").toString() );
|
||||
assertEquals( "nil", t.get(456).toString() );
|
||||
}
|
||||
|
||||
public void testIndexFunction() {
|
||||
final LuaTable t = new_Table();
|
||||
final LuaTable mt = new_Table();
|
||||
|
||||
final TwoArgFunction fb = new TwoArgFunction() {
|
||||
public LuaValue call(LuaValue tbl, LuaValue key) {
|
||||
assertEquals(tbl, t);
|
||||
return valueOf("from mt: "+key);
|
||||
}
|
||||
};
|
||||
|
||||
// set basic values
|
||||
t.set( "ppp", "abc" );
|
||||
t.set( 123, "def" );
|
||||
mt.set(LuaValue.INDEX, fb);
|
||||
|
||||
// check before setting metatable
|
||||
assertEquals( "abc", t.get("ppp").toString() );
|
||||
assertEquals( "def", t.get(123).toString() );
|
||||
assertEquals( "nil", t.get("qqq").toString() );
|
||||
assertEquals( "nil", t.get(456).toString() );
|
||||
|
||||
|
||||
// check before setting metatable
|
||||
t.setmetatable(mt);
|
||||
assertEquals( mt, t.getmetatable() );
|
||||
assertEquals( "abc", t.get("ppp").toString() );
|
||||
assertEquals( "def", t.get(123).toString() );
|
||||
assertEquals( "from mt: qqq", t.get("qqq").toString() );
|
||||
assertEquals( "from mt: 456", t.get(456).toString() );
|
||||
|
||||
// use raw set
|
||||
t.rawset("qqq", "alt-qqq");
|
||||
t.rawset(456, "alt-456");
|
||||
assertEquals( "abc", t.get("ppp").toString() );
|
||||
assertEquals( "def", t.get(123).toString() );
|
||||
assertEquals( "alt-qqq", t.get("qqq").toString() );
|
||||
assertEquals( "alt-456", t.get(456).toString() );
|
||||
|
||||
// remove using raw set
|
||||
t.rawset("qqq", LuaValue.NIL);
|
||||
t.rawset(456, LuaValue.NIL);
|
||||
assertEquals( "abc", t.get("ppp").toString() );
|
||||
assertEquals( "def", t.get(123).toString() );
|
||||
assertEquals( "from mt: qqq", t.get("qqq").toString() );
|
||||
assertEquals( "from mt: 456", t.get(456).toString() );
|
||||
|
||||
// set metatable to null
|
||||
t.setmetatable(null);
|
||||
assertEquals( "abc", t.get("ppp").toString() );
|
||||
assertEquals( "def", t.get(123).toString() );
|
||||
assertEquals( "nil", t.get("qqq").toString() );
|
||||
assertEquals( "nil", t.get(456).toString() );
|
||||
}
|
||||
|
||||
public void testNext() {
|
||||
final LuaTable t = new_Table();
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.NIL) );
|
||||
|
||||
// insert array elements
|
||||
t.set( 1, "one" );
|
||||
assertEquals( LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2) );
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.ONE) );
|
||||
t.set( 2, "two" );
|
||||
assertEquals( LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2) );
|
||||
assertEquals( LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2) );
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.valueOf(2)) );
|
||||
|
||||
// insert hash elements
|
||||
t.set( "aa", "aaa" );
|
||||
assertEquals( LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2) );
|
||||
assertEquals( LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2) );
|
||||
assertEquals( LuaValue.valueOf("aa"), t.next(LuaValue.valueOf(2)).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("aaa"), t.next(LuaValue.valueOf(2)).arg(2) );
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.valueOf("aa")) );
|
||||
t.set( "bb", "bbb" );
|
||||
assertEquals( LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2) );
|
||||
assertEquals( LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2) );
|
||||
assertEquals( LuaValue.valueOf("aa"), t.next(LuaValue.valueOf(2)).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("aaa"), t.next(LuaValue.valueOf(2)).arg(2) );
|
||||
assertEquals( LuaValue.valueOf("bb"), t.next(LuaValue.valueOf("aa")).arg(1) );
|
||||
assertEquals( LuaValue.valueOf("bbb"), t.next(LuaValue.valueOf("aa")).arg(2) );
|
||||
assertEquals( LuaValue.NIL, t.next(LuaValue.valueOf("bb")) );
|
||||
}
|
||||
}
|
||||
340
test/junit/org/luaj/vm2/TableTest.java
Normal file
340
test/junit/org/luaj/vm2/TableTest.java
Normal file
@@ -0,0 +1,340 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TableTest extends TestCase {
|
||||
|
||||
protected LuaTable new_Table() {
|
||||
return new LuaTable();
|
||||
}
|
||||
|
||||
protected LuaTable new_Table(int n,int m) {
|
||||
return new LuaTable(n,m);
|
||||
}
|
||||
|
||||
public void testInOrderIntegerKeyInsertion() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( i, LuaValue.valueOf( "Test Value! "+i ) );
|
||||
}
|
||||
|
||||
// Ensure all keys are still there.
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
assertEquals( "Test Value! " + i, t.get( i ).toString() );
|
||||
}
|
||||
|
||||
// Ensure capacities make sense
|
||||
assertEquals( 0, t.hashCapacity() );
|
||||
|
||||
assertTrue( t.arrayCapacity() >= 32 );
|
||||
assertTrue( t.arrayCapacity() <= 64 );
|
||||
|
||||
}
|
||||
|
||||
public void testRekeyCount() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
// NOTE: This order of insertion is important.
|
||||
t.set(3, LuaInteger.valueOf(3));
|
||||
t.set(1, LuaInteger.valueOf(1));
|
||||
t.set(5, LuaInteger.valueOf(5));
|
||||
t.set(4, LuaInteger.valueOf(4));
|
||||
t.set(6, LuaInteger.valueOf(6));
|
||||
t.set(2, LuaInteger.valueOf(2));
|
||||
|
||||
for ( int i = 1; i < 6; ++i ) {
|
||||
assertEquals(LuaInteger.valueOf(i), t.get(i));
|
||||
}
|
||||
|
||||
assertTrue( t.arrayCapacity() >= 0 && t.arrayCapacity() <= 2 );
|
||||
assertTrue( t.hashCapacity() >= 4 );
|
||||
}
|
||||
|
||||
public void testOutOfOrderIntegerKeyInsertion() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 32; i > 0; --i ) {
|
||||
t.set( i, LuaValue.valueOf( "Test Value! "+i ) );
|
||||
}
|
||||
|
||||
// Ensure all keys are still there.
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
assertEquals( "Test Value! "+i, t.get( i ).toString() );
|
||||
}
|
||||
|
||||
// Ensure capacities make sense
|
||||
assertTrue( t.arrayCapacity() >= 0 );
|
||||
assertTrue( t.arrayCapacity() <= 6 );
|
||||
|
||||
assertTrue( t.hashCapacity() >= 16 );
|
||||
assertTrue( t.hashCapacity() <= 64 );
|
||||
|
||||
}
|
||||
|
||||
public void testStringAndIntegerKeys() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 0; i < 10; ++i ) {
|
||||
LuaString str = LuaValue.valueOf( String.valueOf( i ) );
|
||||
t.set( i, str );
|
||||
t.set( str, LuaInteger.valueOf( i ) );
|
||||
}
|
||||
|
||||
assertTrue( t.arrayCapacity() >= 9 ); // 1, 2, ..., 9
|
||||
assertTrue( t.arrayCapacity() <= 18 );
|
||||
assertTrue( t.hashCapacity() >= 11 ); // 0, "0", "1", ..., "9"
|
||||
assertTrue( t.hashCapacity() <= 33 );
|
||||
|
||||
LuaValue[] keys = t.keys();
|
||||
|
||||
int intKeys = 0;
|
||||
int stringKeys = 0;
|
||||
|
||||
assertEquals( 20, keys.length );
|
||||
for ( int i = 0; i < keys.length; ++i ) {
|
||||
LuaValue k = keys[i];
|
||||
|
||||
if ( k instanceof LuaInteger ) {
|
||||
final int ik = k.toint();
|
||||
assertTrue( ik >= 0 && ik < 10 );
|
||||
final int mask = 1 << ik;
|
||||
assertTrue( ( intKeys & mask ) == 0 );
|
||||
intKeys |= mask;
|
||||
} else if ( k instanceof LuaString ) {
|
||||
final int ik = Integer.parseInt( k.strvalue().toString() );
|
||||
assertEquals( String.valueOf( ik ), k.strvalue().toString() );
|
||||
assertTrue( ik >= 0 && ik < 10 );
|
||||
final int mask = 1 << ik;
|
||||
assertTrue( "Key \""+ik+"\" found more than once", ( stringKeys & mask ) == 0 );
|
||||
stringKeys |= mask;
|
||||
} else {
|
||||
fail( "Unexpected type of key found" );
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals( 0x03FF, intKeys );
|
||||
assertEquals( 0x03FF, stringKeys );
|
||||
}
|
||||
|
||||
public void testBadInitialCapacity() {
|
||||
LuaTable t = new_Table(0, 1);
|
||||
|
||||
t.set( "test", LuaValue.valueOf("foo") );
|
||||
t.set( "explode", LuaValue.valueOf("explode") );
|
||||
assertEquals( 2, t.keyCount() );
|
||||
}
|
||||
|
||||
public void testRemove0() {
|
||||
LuaTable t = new_Table(2, 0);
|
||||
|
||||
t.set( 1, LuaValue.valueOf("foo") );
|
||||
t.set( 2, LuaValue.valueOf("bah") );
|
||||
assertNotSame(LuaValue.NIL, t.get(1));
|
||||
assertNotSame(LuaValue.NIL, t.get(2));
|
||||
assertEquals(LuaValue.NIL, t.get(3));
|
||||
|
||||
t.set( 1, LuaValue.NIL );
|
||||
t.set( 2, LuaValue.NIL );
|
||||
t.set( 3, LuaValue.NIL );
|
||||
assertEquals(LuaValue.NIL, t.get(1));
|
||||
assertEquals(LuaValue.NIL, t.get(2));
|
||||
assertEquals(LuaValue.NIL, t.get(3));
|
||||
}
|
||||
|
||||
public void testRemove1() {
|
||||
LuaTable t = new_Table(0, 1);
|
||||
|
||||
t.set( "test", LuaValue.valueOf("foo") );
|
||||
t.set( "explode", LuaValue.NIL );
|
||||
t.set( 42, LuaValue.NIL );
|
||||
t.set( new_Table(), LuaValue.NIL );
|
||||
t.set( "test", LuaValue.NIL );
|
||||
assertEquals( 0, t.keyCount() );
|
||||
|
||||
t.set( 10, LuaInteger.valueOf( 5 ) );
|
||||
t.set( 10, LuaValue.NIL );
|
||||
assertEquals( 0, t.keyCount() );
|
||||
}
|
||||
|
||||
public void testRemove2() {
|
||||
LuaTable t = new_Table(0, 1);
|
||||
|
||||
t.set( "test", LuaValue.valueOf("foo") );
|
||||
t.set( "string", LuaInteger.valueOf( 10 ) );
|
||||
assertEquals( 2, t.keyCount() );
|
||||
|
||||
t.set( "string", LuaValue.NIL );
|
||||
t.set( "three", LuaValue.valueOf( 3.14 ) );
|
||||
assertEquals( 2, t.keyCount() );
|
||||
|
||||
t.set( "test", LuaValue.NIL );
|
||||
assertEquals( 1, t.keyCount() );
|
||||
|
||||
t.set( 10, LuaInteger.valueOf( 5 ) );
|
||||
assertEquals( 2, t.keyCount() );
|
||||
|
||||
t.set( 10, LuaValue.NIL );
|
||||
assertEquals( 1, t.keyCount() );
|
||||
|
||||
t.set( "three", LuaValue.NIL );
|
||||
assertEquals( 0, t.keyCount() );
|
||||
}
|
||||
|
||||
public void testInOrderLuaLength() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( i, LuaValue.valueOf( "Test Value! "+i ) );
|
||||
assertEquals( i, t.length() );
|
||||
assertEquals( i, t.maxn() );
|
||||
}
|
||||
}
|
||||
|
||||
public void testOutOfOrderLuaLength() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int j=8; j<32; j+=8 ) {
|
||||
for ( int i = j; i > 0; --i ) {
|
||||
t.set( i, LuaValue.valueOf( "Test Value! "+i ) );
|
||||
}
|
||||
assertEquals( j, t.length() );
|
||||
assertEquals( j, t.maxn() );
|
||||
}
|
||||
}
|
||||
|
||||
public void testStringKeysLuaLength() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( "str-"+i, LuaValue.valueOf( "String Key Test Value! "+i ) );
|
||||
assertEquals( 0, t.length() );
|
||||
assertEquals( 0, t.maxn() );
|
||||
}
|
||||
}
|
||||
|
||||
public void testMixedKeysLuaLength() {
|
||||
LuaTable t = new_Table();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.set( "str-"+i, LuaValue.valueOf( "String Key Test Value! "+i ) );
|
||||
t.set( i, LuaValue.valueOf( "Int Key Test Value! "+i ) );
|
||||
assertEquals( i, t.length() );
|
||||
assertEquals( i, t.maxn() );
|
||||
}
|
||||
}
|
||||
|
||||
private static final void compareLists(LuaTable t,Vector v) {
|
||||
int n = v.size();
|
||||
assertEquals(v.size(),t.length());
|
||||
for ( int j=0; j<n; j++ ) {
|
||||
Object vj = v.elementAt(j);
|
||||
Object tj = t.get(j+1).toString();
|
||||
vj = ((LuaString)vj).toString();
|
||||
assertEquals(vj,tj);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertBeginningOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaValue.valueOf("Test Value! "+i);
|
||||
t.insert(1, test);
|
||||
v.insertElementAt(test, 0);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertEndOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaValue.valueOf("Test Value! "+i);
|
||||
t.insert(0, test);
|
||||
v.insertElementAt(test, v.size());
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertMiddleOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaValue.valueOf("Test Value! "+i);
|
||||
int m = i / 2;
|
||||
t.insert(m+1, test);
|
||||
v.insertElementAt(test, m);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
private static final void prefillLists(LuaTable t,Vector v) {
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
LuaString test = LuaValue.valueOf("Test Value! "+i);
|
||||
t.insert(0, test);
|
||||
v.insertElementAt(test, v.size());
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveBeginningOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
prefillLists(t,v);
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.remove(1);
|
||||
v.removeElementAt(0);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveEndOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
prefillLists(t,v);
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
t.remove(0);
|
||||
v.removeElementAt(v.size()-1);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveMiddleOfList() {
|
||||
LuaTable t = new_Table();
|
||||
Vector v = new Vector();
|
||||
prefillLists(t,v);
|
||||
for ( int i = 1; i <= 32; ++i ) {
|
||||
int m = v.size() / 2;
|
||||
t.remove(m+1);
|
||||
v.removeElementAt(m);
|
||||
compareLists(t,v);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
1242
test/junit/org/luaj/vm2/TypeTest.java
Normal file
1242
test/junit/org/luaj/vm2/TypeTest.java
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user