Add "require" support.

This commit is contained in:
James Roseborough
2007-09-20 18:17:10 +00:00
parent fc8c790b0d
commit d45bd96536
2 changed files with 139 additions and 50 deletions

View File

@@ -15,6 +15,7 @@ import lua.VM;
import lua.io.Closure;
import lua.io.LoadState;
import lua.io.Proto;
import lua.value.LBoolean;
import lua.value.LDouble;
import lua.value.LFunction;
import lua.value.LInteger;
@@ -28,31 +29,36 @@ public class LuaCompat extends LFunction {
public static InputStream STDIN = null;
public static PrintStream STDOUT = System.out;
public static LTable LOADED = new LTable();
public static void install() {
LTable globals = GlobalState.getGlobalsTable();
for ( int i = 0; i < GLOBAL_NAMES.length; ++i ) {
globals.put( GLOBAL_NAMES[i], new LuaCompat( i ) );
}
installNames( globals, GLOBAL_NAMES, GLOBALS_BASE );
// math lib
LTable math = new LTable();
for ( int i = 0; i < MATH_NAMES.length; ++i ) {
math.put( MATH_NAMES[i], new LuaCompat( MATH_BASE + i ) );
}
// Some handy constants
installNames( math, MATH_NAMES, MATH_BASE );
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 );
// string lib
LTable string = LString.getMetatable();
for ( int i = 0; i < STRING_NAMES.length; ++i ) {
string.put( STRING_NAMES[i], new LuaCompat( STRING_BASE + i ) );
}
installNames( string, STRING_NAMES, STRING_BASE );
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 = {
"assert",
"loadfile",
@@ -67,6 +73,8 @@ public class LuaCompat extends LFunction {
"tostring",
"unpack",
"next",
"module",
"require",
};
public static final String[] MATH_NAMES = {
@@ -93,28 +101,36 @@ public class LuaCompat extends LFunction {
"sub",
"upper",
};
public static final String[] PACKAGE_NAMES = {
"loalib",
"seeall",
};
private static final int ASSERT = 0;
private static final int LOADFILE = 1;
private static final int TONUMBER = 2;
private static final int RAWGET = 3;
private static final int SETFENV = 4;
private static final int SELECT = 5;
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 GLOBALS_BASE = 0;
private static final int ASSERT = GLOBALS_BASE + 0;
private static final int LOADFILE = GLOBALS_BASE + 1;
private static final int TONUMBER = GLOBALS_BASE + 2;
private static final int RAWGET = GLOBALS_BASE + 3;
private static final int SETFENV = GLOBALS_BASE + 4;
private static final int SELECT = GLOBALS_BASE + 5;
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 ABS = MATH_BASE + 0;
private static final int MAX = MATH_BASE + 1;
private static final int MIN = MATH_BASE + 2;
private static final int MODF = MATH_BASE + 3;
private static final int SIN = MATH_BASE + 4;
private static final int ABS = MATH_BASE + 0;
private static final int MAX = MATH_BASE + 1;
private static final int MIN = MATH_BASE + 2;
private static final int MODF = MATH_BASE + 3;
private static final int SIN = MATH_BASE + 4;
private static final int STRING_BASE = 30;
private static final int BYTE = STRING_BASE + 0;
@@ -132,8 +148,12 @@ public class LuaCompat extends LFunction {
private static final int SUB = STRING_BASE + 12;
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 LuaCompat( int id ) {
this.id = id;
}
@@ -195,6 +215,12 @@ public class LuaCompat extends LFunction {
case NEXT:
vm.setResult( next(vm, vm.getArg(0), vm.getArgAsInt(1)) );
break;
case MODULE:
module(vm);
break;
case REQUIRE:
require(vm);
break;
// Math functions
case ABS:
@@ -256,7 +282,14 @@ public class LuaCompat extends LFunction {
case UPPER:
StrLib.upper( vm );
break;
// package functions
case LOADLIB:
loadlib(vm);
break;
case SEEALL:
seeall(vm);
break;
default:
luaUnsupportedOperation();
@@ -500,4 +533,66 @@ public class LuaCompat extends LFunction {
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" );
}
}

View File

@@ -12,8 +12,6 @@ import lua.io.Proto;
public class DebugStackState extends StackState implements DebugRequestListener {
private static final boolean DEBUG = false;
public Map<Integer,Boolean> breakpoints = new HashMap<Integer,Boolean>();
private boolean exiting = false;
private boolean suspended = false;
@@ -32,34 +30,30 @@ public class DebugStackState extends StackState implements DebugRequestListener
Proto p = call.closure.p;
if ( p != null && p.source != null )
source = p.source.toJavaString();
if ( p.lineinfo != null && p.lineinfo.length > call.pc )
line = String.valueOf( p.lineinfo[call.pc] );
if ( p.lineinfo != null && p.lineinfo.length > call.pc-1 )
line = String.valueOf( p.lineinfo[call.pc-1] );
// TODO: reverse lookup on function name ????
func = call.closure.luaAsString().toJavaString();
}
return source+":"+line+"("+func+")";
}
// override and fill in line number info
public void lua_error(String message) {
super.lua_error( getFileLine(cc)+": "+message );
}
private void printLuaTrace() {
System.out.println( "Lua location: "+getFileLine(cc) );
private void printLuaTrace(String message) {
System.out.println( "Lua error: "+message );
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
public void exec() {
try {
super.exec();
} catch ( Exception t ) {
t.printStackTrace();
printLuaTrace();
} catch ( RuntimeException t ) {
String message = getFileLine(cc)+": "+t.getMessage();
t.printStackTrace();
printLuaTrace(message);
System.out.flush();
throw new RuntimeException( message, t );
}
}