Add loadstring and other standard library commands (untested)
This commit is contained in:
@@ -1,7 +1,11 @@
|
|||||||
package lua.addon.luacompat;
|
package lua.addon.luacompat;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
import lua.CallInfo;
|
import lua.CallInfo;
|
||||||
import lua.GlobalState;
|
import lua.GlobalState;
|
||||||
@@ -22,6 +26,9 @@ import lua.value.LValue;
|
|||||||
|
|
||||||
public class LuaCompat extends LFunction {
|
public class LuaCompat extends LFunction {
|
||||||
|
|
||||||
|
public static InputStream STDIN = null;
|
||||||
|
public static PrintStream STDOUT = System.out;
|
||||||
|
|
||||||
public static void install() {
|
public static void install() {
|
||||||
LTable globals = GlobalState.getGlobalsTable();
|
LTable globals = GlobalState.getGlobalsTable();
|
||||||
for ( int i = 0; i < GLOBAL_NAMES.length; ++i ) {
|
for ( int i = 0; i < GLOBAL_NAMES.length; ++i ) {
|
||||||
@@ -54,6 +61,12 @@ public class LuaCompat extends LFunction {
|
|||||||
"setfenv",
|
"setfenv",
|
||||||
"select",
|
"select",
|
||||||
"collectgarbage",
|
"collectgarbage",
|
||||||
|
"dofile",
|
||||||
|
"loadstring",
|
||||||
|
"load",
|
||||||
|
"tostring",
|
||||||
|
"unpack",
|
||||||
|
"next",
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final String[] MATH_NAMES = {
|
public static final String[] MATH_NAMES = {
|
||||||
@@ -76,15 +89,22 @@ public class LuaCompat extends LFunction {
|
|||||||
private static final int SETFENV = 4;
|
private static final int SETFENV = 4;
|
||||||
private static final int SELECT = 5;
|
private static final int SELECT = 5;
|
||||||
private static final int COLLECTGARBAGE = 6;
|
private static final int COLLECTGARBAGE = 6;
|
||||||
|
private static final int DOFILE = 7;
|
||||||
|
private static final int LOADSTRING = 8;
|
||||||
|
private static final int LOAD = 9;
|
||||||
|
private static final int TOSTRING = 10;
|
||||||
|
private static final int UNPACK= 11;
|
||||||
|
private static final int NEXT= 12;
|
||||||
|
|
||||||
private static final int MATH_BASE = 10;
|
|
||||||
|
private static final int MATH_BASE = 20;
|
||||||
private static final int ABS = MATH_BASE + 0;
|
private static final int ABS = MATH_BASE + 0;
|
||||||
private static final int MAX = MATH_BASE + 1;
|
private static final int MAX = MATH_BASE + 1;
|
||||||
private static final int MIN = MATH_BASE + 2;
|
private static final int MIN = MATH_BASE + 2;
|
||||||
private static final int MODF = MATH_BASE + 3;
|
private static final int MODF = MATH_BASE + 3;
|
||||||
private static final int SIN = MATH_BASE + 4;
|
private static final int SIN = MATH_BASE + 4;
|
||||||
|
|
||||||
private static final int STRING_BASE = 20;
|
private static final int STRING_BASE = 30;
|
||||||
private static final int REP = STRING_BASE + 0;
|
private static final int REP = STRING_BASE + 0;
|
||||||
private static final int SUB = STRING_BASE + 1;
|
private static final int SUB = STRING_BASE + 1;
|
||||||
|
|
||||||
@@ -132,6 +152,25 @@ public class LuaCompat extends LFunction {
|
|||||||
System.gc();
|
System.gc();
|
||||||
vm.setResult();
|
vm.setResult();
|
||||||
break;
|
break;
|
||||||
|
case DOFILE:
|
||||||
|
dofile(vm, vm.getArg(0));
|
||||||
|
break;
|
||||||
|
case LOADSTRING:
|
||||||
|
vm.setResult( loadstring(vm, vm.getArg(0), vm.getArgAsString(1)) );
|
||||||
|
break;
|
||||||
|
case LOAD:
|
||||||
|
vm.setResult( load(vm, vm.getArg(0), vm.getArgAsString(1)) );
|
||||||
|
break;
|
||||||
|
case TOSTRING:
|
||||||
|
vm.setResult( tostring(vm, vm.getArg(0)) );
|
||||||
|
break;
|
||||||
|
case UNPACK:
|
||||||
|
vm.setResult();
|
||||||
|
unpack(vm, vm.getArg(0), vm.getArgAsInt(1), vm.getArgAsInt(2));
|
||||||
|
break;
|
||||||
|
case NEXT:
|
||||||
|
vm.setResult( next(vm, vm.getArg(0), vm.getArgAsInt(1)) );
|
||||||
|
break;
|
||||||
|
|
||||||
// Math functions
|
// Math functions
|
||||||
case ABS:
|
case ABS:
|
||||||
@@ -195,7 +234,6 @@ public class LuaCompat extends LFunction {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void select( VM vm ) {
|
private void select( VM vm ) {
|
||||||
LValue arg = vm.getArg( 0 );
|
LValue arg = vm.getArg( 0 );
|
||||||
if ( arg instanceof LNumber ) {
|
if ( arg instanceof LNumber ) {
|
||||||
@@ -295,6 +333,40 @@ public class LuaCompat extends LFunction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// closes the input stream, provided its not null or System.in
|
||||||
|
private static void closeSafely(InputStream is) {
|
||||||
|
try {
|
||||||
|
if ( is != null && is != STDIN )
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// closes the output stream, provided its not null or STDOUT
|
||||||
|
private static void closeSafely(OutputStream os) {
|
||||||
|
try {
|
||||||
|
if ( os != null && os != STDOUT )
|
||||||
|
os.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// closes the input stream
|
||||||
|
private static LValue inputStreamToClosureThenClose(VM vm, InputStream is, String chunkname ) {
|
||||||
|
try {
|
||||||
|
Proto p = LoadState.undump(vm, is, chunkname);
|
||||||
|
return new Closure( (StackState) vm, p);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
closeSafely( is );
|
||||||
|
}
|
||||||
|
return LNil.NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private LValue loadfile( VM vm, LValue fileName ) {
|
private LValue loadfile( VM vm, LValue fileName ) {
|
||||||
InputStream is;
|
InputStream is;
|
||||||
|
|
||||||
@@ -303,25 +375,92 @@ public class LuaCompat extends LFunction {
|
|||||||
script = fileName.luaAsString().toJavaString();
|
script = fileName.luaAsString().toJavaString();
|
||||||
is = getClass().getResourceAsStream( "/"+script );
|
is = getClass().getResourceAsStream( "/"+script );
|
||||||
} else {
|
} else {
|
||||||
is = System.in;
|
is = STDIN;
|
||||||
script = "-";
|
script = "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( is != null ) {
|
if ( is != null )
|
||||||
try {
|
return inputStreamToClosureThenClose( vm, is, script );
|
||||||
Proto p = LoadState.undump(vm, is, script);
|
|
||||||
return new Closure( (StackState) vm, p);
|
|
||||||
} catch (IOException e) {
|
|
||||||
} finally {
|
|
||||||
if ( is != System.in ) {
|
|
||||||
try {
|
|
||||||
is.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return LNil.NIL;
|
return LNil.NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LValue dofile( VM vm, LValue fileName ) {
|
||||||
|
LValue chunk = loadfile( vm, fileName );
|
||||||
|
if ( chunk != LNil.NIL ) {
|
||||||
|
vm.doCall((Closure) chunk, null);
|
||||||
|
} else {
|
||||||
|
vm.setResult();
|
||||||
|
vm.push("file not found: "+fileName);
|
||||||
|
vm.lua_error();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LValue loadstring(VM vm, LValue string, String chunkname) {
|
||||||
|
InputStream is = string.luaAsString().toInputStream();
|
||||||
|
return inputStreamToClosureThenClose( vm, is, chunkname );
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: convert this to stream?
|
||||||
|
private LValue load(VM vm, LValue chunkPartLoader, String chunkname) {
|
||||||
|
if ( ! (chunkPartLoader instanceof Closure) ) {
|
||||||
|
vm.setResult();
|
||||||
|
vm.push("not a function: "+chunkPartLoader);
|
||||||
|
vm.lua_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
// load all the parts
|
||||||
|
Closure c = (Closure) chunkPartLoader;
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
while ( true ) {
|
||||||
|
vm.doCall( c, null );
|
||||||
|
LValue r = vm.getArg(0);
|
||||||
|
if ( ! (r instanceof LString) )
|
||||||
|
break;
|
||||||
|
LString s = (LString) r;
|
||||||
|
s.write(baos, 0, s.length());
|
||||||
|
}
|
||||||
|
} catch ( Exception e ) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
closeSafely( baos );
|
||||||
|
}
|
||||||
|
|
||||||
|
// load from the byte array
|
||||||
|
InputStream is = new ByteArrayInputStream( baos.toByteArray() );
|
||||||
|
return inputStreamToClosureThenClose( vm, is, chunkname );
|
||||||
|
}
|
||||||
|
|
||||||
|
private LValue tostring(VM vm, LValue arg) {
|
||||||
|
return arg.luaAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LTable toTable(VM vm, LValue list) {
|
||||||
|
if ( ! (list instanceof LTable) ) {
|
||||||
|
vm.setResult();
|
||||||
|
vm.push("not a list: "+list);
|
||||||
|
vm.lua_error();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (LTable) list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unpack(VM vm, LValue list, int i, int j) {
|
||||||
|
LTable t = toTable(vm, list);
|
||||||
|
if ( t == null )
|
||||||
|
return;
|
||||||
|
if ( i == 0 )
|
||||||
|
i = 1;
|
||||||
|
if ( j == 0 )
|
||||||
|
j = t.size();
|
||||||
|
LValue[] keys = t.getKeys();
|
||||||
|
for ( int k=i; k<=j; k++ )
|
||||||
|
vm.push( t.get(keys[k-1]) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private LValue next(VM vm, LValue table, int index) {
|
||||||
|
throw new java.lang.RuntimeException("next() not supported yet");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import java.io.OutputStream;
|
|||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
|
||||||
import lua.value.LFunction;
|
import lua.value.LFunction;
|
||||||
|
import lua.value.LNil;
|
||||||
import lua.value.LTable;
|
import lua.value.LTable;
|
||||||
import lua.value.LValue;
|
import lua.value.LValue;
|
||||||
|
|
||||||
@@ -17,13 +18,19 @@ final class Builtin extends LFunction {
|
|||||||
table.put( NAMES[i], new Builtin(i) );
|
table.put( NAMES[i], new Builtin(i) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String[] NAMES = {
|
||||||
|
"print",
|
||||||
|
"pairs",
|
||||||
|
"getmetatable",
|
||||||
|
"setmetatable",
|
||||||
|
"type",
|
||||||
|
"pcall" };
|
||||||
private static final int PRINT = 0;
|
private static final int PRINT = 0;
|
||||||
private static final int PAIRS = 1;
|
private static final int PAIRS = 1;
|
||||||
private static final int GETMETATABLE = 2;
|
private static final int GETMETATABLE = 2;
|
||||||
private static final int SETMETATABLE = 3;
|
private static final int SETMETATABLE = 3;
|
||||||
private static final int TYPE = 4;
|
private static final int TYPE = 4;
|
||||||
|
private static final int PCALL = 5;
|
||||||
private static final String[] NAMES = { "print", "pairs", "getmetatable", "setmetatable", "type" };
|
|
||||||
|
|
||||||
private static PrintStream stdout = System.out;
|
private static PrintStream stdout = System.out;
|
||||||
|
|
||||||
@@ -63,6 +70,10 @@ final class Builtin extends LFunction {
|
|||||||
case TYPE:
|
case TYPE:
|
||||||
vm.setResult( vm.getArg(0).luaGetType() );
|
vm.setResult( vm.getArg(0).luaGetType() );
|
||||||
break;
|
break;
|
||||||
|
case PCALL:
|
||||||
|
// TODO: implement pcall
|
||||||
|
vm.setResult( LNil.NIL );
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
luaUnsupportedOperation();
|
luaUnsupportedOperation();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,4 +140,10 @@ public interface VM {
|
|||||||
*/
|
*/
|
||||||
public void setResult(LValue val);
|
public void setResult(LValue val);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a Lua error. The error message(which can actually be a Lua value of any type)
|
||||||
|
* must be on the top of the stack.
|
||||||
|
*/
|
||||||
|
public void lua_error();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user