Add "require" support.
This commit is contained in:
@@ -15,6 +15,7 @@ import lua.VM;
|
|||||||
import lua.io.Closure;
|
import lua.io.Closure;
|
||||||
import lua.io.LoadState;
|
import lua.io.LoadState;
|
||||||
import lua.io.Proto;
|
import lua.io.Proto;
|
||||||
|
import lua.value.LBoolean;
|
||||||
import lua.value.LDouble;
|
import lua.value.LDouble;
|
||||||
import lua.value.LFunction;
|
import lua.value.LFunction;
|
||||||
import lua.value.LInteger;
|
import lua.value.LInteger;
|
||||||
@@ -28,29 +29,34 @@ public class LuaCompat extends LFunction {
|
|||||||
|
|
||||||
public static InputStream STDIN = null;
|
public static InputStream STDIN = null;
|
||||||
public static PrintStream STDOUT = System.out;
|
public static PrintStream STDOUT = System.out;
|
||||||
|
public static LTable LOADED = new LTable();
|
||||||
|
|
||||||
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 ) {
|
installNames( globals, GLOBAL_NAMES, GLOBALS_BASE );
|
||||||
globals.put( GLOBAL_NAMES[i], new LuaCompat( i ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// math lib
|
||||||
LTable math = new LTable();
|
LTable math = new LTable();
|
||||||
for ( int i = 0; i < MATH_NAMES.length; ++i ) {
|
installNames( math, MATH_NAMES, MATH_BASE );
|
||||||
math.put( MATH_NAMES[i], new LuaCompat( MATH_BASE + i ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some handy constants
|
|
||||||
math.put( "huge", new LDouble( Double.MAX_VALUE ) );
|
math.put( "huge", new LDouble( Double.MAX_VALUE ) );
|
||||||
math.put( "pi", new LDouble( Math.PI ) );
|
math.put( "pi", new LDouble( Math.PI ) );
|
||||||
|
|
||||||
globals.put( "math", math );
|
globals.put( "math", math );
|
||||||
|
|
||||||
|
// string lib
|
||||||
LTable string = LString.getMetatable();
|
LTable string = LString.getMetatable();
|
||||||
for ( int i = 0; i < STRING_NAMES.length; ++i ) {
|
installNames( string, STRING_NAMES, STRING_BASE );
|
||||||
string.put( STRING_NAMES[i], new LuaCompat( STRING_BASE + i ) );
|
|
||||||
}
|
|
||||||
globals.put( "string", string );
|
globals.put( "string", string );
|
||||||
|
|
||||||
|
// packages lib
|
||||||
|
LTable pckg = new LTable();
|
||||||
|
installNames( pckg, PACKAGE_NAMES, PACKAGES_BASE );
|
||||||
|
globals.put( "package", pckg );
|
||||||
|
pckg.put( "loaded", LOADED );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void installNames( LTable table, String[] names, int indexBase ) {
|
||||||
|
for ( int i=0; i<names.length; i++ )
|
||||||
|
table.put( names[i], new LuaCompat(indexBase+i) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String[] GLOBAL_NAMES = {
|
public static final String[] GLOBAL_NAMES = {
|
||||||
@@ -67,6 +73,8 @@ public class LuaCompat extends LFunction {
|
|||||||
"tostring",
|
"tostring",
|
||||||
"unpack",
|
"unpack",
|
||||||
"next",
|
"next",
|
||||||
|
"module",
|
||||||
|
"require",
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final String[] MATH_NAMES = {
|
public static final String[] MATH_NAMES = {
|
||||||
@@ -94,19 +102,27 @@ public class LuaCompat extends LFunction {
|
|||||||
"upper",
|
"upper",
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final int ASSERT = 0;
|
public static final String[] PACKAGE_NAMES = {
|
||||||
private static final int LOADFILE = 1;
|
"loalib",
|
||||||
private static final int TONUMBER = 2;
|
"seeall",
|
||||||
private static final int RAWGET = 3;
|
};
|
||||||
private static final int SETFENV = 4;
|
|
||||||
private static final int SELECT = 5;
|
private static final int GLOBALS_BASE = 0;
|
||||||
private static final int COLLECTGARBAGE = 6;
|
private static final int ASSERT = GLOBALS_BASE + 0;
|
||||||
private static final int DOFILE = 7;
|
private static final int LOADFILE = GLOBALS_BASE + 1;
|
||||||
private static final int LOADSTRING = 8;
|
private static final int TONUMBER = GLOBALS_BASE + 2;
|
||||||
private static final int LOAD = 9;
|
private static final int RAWGET = GLOBALS_BASE + 3;
|
||||||
private static final int TOSTRING = 10;
|
private static final int SETFENV = GLOBALS_BASE + 4;
|
||||||
private static final int UNPACK= 11;
|
private static final int SELECT = GLOBALS_BASE + 5;
|
||||||
private static final int NEXT= 12;
|
private static final int COLLECTGARBAGE = GLOBALS_BASE + 6;
|
||||||
|
private static final int DOFILE = GLOBALS_BASE + 7;
|
||||||
|
private static final int LOADSTRING = GLOBALS_BASE + 8;
|
||||||
|
private static final int LOAD = GLOBALS_BASE + 9;
|
||||||
|
private static final int TOSTRING = GLOBALS_BASE + 10;
|
||||||
|
private static final int UNPACK = GLOBALS_BASE + 11;
|
||||||
|
private static final int NEXT = GLOBALS_BASE + 12;
|
||||||
|
private static final int MODULE = GLOBALS_BASE + 13;
|
||||||
|
private static final int REQUIRE = GLOBALS_BASE + 14;
|
||||||
|
|
||||||
|
|
||||||
private static final int MATH_BASE = 20;
|
private static final int MATH_BASE = 20;
|
||||||
@@ -132,8 +148,12 @@ public class LuaCompat extends LFunction {
|
|||||||
private static final int SUB = STRING_BASE + 12;
|
private static final int SUB = STRING_BASE + 12;
|
||||||
private static final int UPPER = STRING_BASE + 13;
|
private static final int UPPER = STRING_BASE + 13;
|
||||||
|
|
||||||
|
private static final int PACKAGES_BASE = 50;
|
||||||
|
private static final int LOADLIB = PACKAGES_BASE + 0;
|
||||||
|
private static final int SEEALL = PACKAGES_BASE + 1;
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
private LuaCompat( int id ) {
|
private LuaCompat( int id ) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
@@ -195,6 +215,12 @@ public class LuaCompat extends LFunction {
|
|||||||
case NEXT:
|
case NEXT:
|
||||||
vm.setResult( next(vm, vm.getArg(0), vm.getArgAsInt(1)) );
|
vm.setResult( next(vm, vm.getArg(0), vm.getArgAsInt(1)) );
|
||||||
break;
|
break;
|
||||||
|
case MODULE:
|
||||||
|
module(vm);
|
||||||
|
break;
|
||||||
|
case REQUIRE:
|
||||||
|
require(vm);
|
||||||
|
break;
|
||||||
|
|
||||||
// Math functions
|
// Math functions
|
||||||
case ABS:
|
case ABS:
|
||||||
@@ -257,6 +283,13 @@ public class LuaCompat extends LFunction {
|
|||||||
StrLib.upper( vm );
|
StrLib.upper( vm );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// package functions
|
||||||
|
case LOADLIB:
|
||||||
|
loadlib(vm);
|
||||||
|
break;
|
||||||
|
case SEEALL:
|
||||||
|
seeall(vm);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
luaUnsupportedOperation();
|
luaUnsupportedOperation();
|
||||||
@@ -500,4 +533,66 @@ public class LuaCompat extends LFunction {
|
|||||||
throw new java.lang.RuntimeException("next() not supported yet");
|
throw new java.lang.RuntimeException("next() not supported yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ======================== Module, Package loading =============================
|
||||||
|
|
||||||
|
public static void module( VM vm ) {
|
||||||
|
vm.lua_error( "module not implemented" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 static void require( VM vm ) {
|
||||||
|
LString modname = vm.getArgAsLuaString(0);
|
||||||
|
if ( LOADED.containsKey(modname) )
|
||||||
|
vm.setResult( LOADED.get(modname) );
|
||||||
|
else {
|
||||||
|
String s = modname.toJavaString();
|
||||||
|
if ( ! loadfile(vm, s+".luac") && ! loadfile(vm, s+".lua") )
|
||||||
|
vm.lua_error( "not found: "+s );
|
||||||
|
else if ( 0 == vm.lua_pcall(0, 1) ) {
|
||||||
|
LValue result = vm.getArg(0);
|
||||||
|
if ( result != LNil.NIL )
|
||||||
|
LOADED.put(modname, result);
|
||||||
|
else if ( ! LOADED.containsKey(modname) ) {
|
||||||
|
LOADED.put(modname, LBoolean.TRUE);
|
||||||
|
vm.setResult( LBoolean.TRUE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadlib( VM vm ) {
|
||||||
|
vm.lua_error( "loadlib not implemented" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void seeall( VM vm ) {
|
||||||
|
vm.lua_error( "seeall not implemented" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import lua.io.Proto;
|
|||||||
|
|
||||||
public class DebugStackState extends StackState implements DebugRequestListener {
|
public class DebugStackState extends StackState implements DebugRequestListener {
|
||||||
|
|
||||||
private static final boolean DEBUG = false;
|
|
||||||
|
|
||||||
public Map<Integer,Boolean> breakpoints = new HashMap<Integer,Boolean>();
|
public Map<Integer,Boolean> breakpoints = new HashMap<Integer,Boolean>();
|
||||||
private boolean exiting = false;
|
private boolean exiting = false;
|
||||||
private boolean suspended = false;
|
private boolean suspended = false;
|
||||||
@@ -32,34 +30,30 @@ public class DebugStackState extends StackState implements DebugRequestListener
|
|||||||
Proto p = call.closure.p;
|
Proto p = call.closure.p;
|
||||||
if ( p != null && p.source != null )
|
if ( p != null && p.source != null )
|
||||||
source = p.source.toJavaString();
|
source = p.source.toJavaString();
|
||||||
if ( p.lineinfo != null && p.lineinfo.length > call.pc )
|
if ( p.lineinfo != null && p.lineinfo.length > call.pc-1 )
|
||||||
line = String.valueOf( p.lineinfo[call.pc] );
|
line = String.valueOf( p.lineinfo[call.pc-1] );
|
||||||
// TODO: reverse lookup on function name ????
|
// TODO: reverse lookup on function name ????
|
||||||
func = call.closure.luaAsString().toJavaString();
|
func = call.closure.luaAsString().toJavaString();
|
||||||
}
|
}
|
||||||
return source+":"+line+"("+func+")";
|
return source+":"+line+"("+func+")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void printLuaTrace(String message) {
|
||||||
// override and fill in line number info
|
System.out.println( "Lua error: "+message );
|
||||||
public void lua_error(String message) {
|
|
||||||
super.lua_error( getFileLine(cc)+": "+message );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void printLuaTrace() {
|
|
||||||
System.out.println( "Lua location: "+getFileLine(cc) );
|
|
||||||
for ( int cindex=cc-1; cindex>=0; cindex-- )
|
for ( int cindex=cc-1; cindex>=0; cindex-- )
|
||||||
System.out.println( "\tin "+getFileLine( cindex ) );
|
System.out.println( "\tcalled by "+getFileLine( cindex ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// intercept exceptions and fill in line numbers
|
// intercept exceptions and fill in line numbers
|
||||||
public void exec() {
|
public void exec() {
|
||||||
try {
|
try {
|
||||||
super.exec();
|
super.exec();
|
||||||
} catch ( Exception t ) {
|
} catch ( RuntimeException t ) {
|
||||||
|
String message = getFileLine(cc)+": "+t.getMessage();
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
printLuaTrace();
|
printLuaTrace(message);
|
||||||
System.out.flush();
|
System.out.flush();
|
||||||
|
throw new RuntimeException( message, t );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user