Add loadstring and other standard library commands (untested)

This commit is contained in:
James Roseborough
2007-09-15 00:51:30 +00:00
parent 6d0e9bb566
commit 5efda81b17
3 changed files with 177 additions and 21 deletions

View File

@@ -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 ) {
@@ -294,7 +332,41 @@ public class LuaCompat extends LFunction {
state.setResult(); state.setResult();
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");
}
} }

View File

@@ -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();
} }

View File

@@ -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();
} }