diff --git a/src/core/org/luaj/lib/BaseLib.java b/src/core/org/luaj/lib/BaseLib.java index dfa03d55..a52357c7 100644 --- a/src/core/org/luaj/lib/BaseLib.java +++ b/src/core/org/luaj/lib/BaseLib.java @@ -118,7 +118,8 @@ public class BaseLib extends LFunction { Lua.TYPE_NAMES[type]+" expected, got no value)") ); } - private void checkargtype(LuaState vm, int index, int type) { + private void checkargtype + (LuaState vm, int index, int type) { checkargexists( vm, index, type ); int t = vm.type(index); if ( t != type ) { @@ -164,8 +165,11 @@ public class BaseLib extends LFunction { } case SETMETATABLE: { checkargtype(vm,2,Lua.LUA_TTABLE); + if ( vm.gettop()<3 || ! (vm.isnil(3) || vm.istable(3)) ) + vm.error( "bad argument #2 to '?' (nil or table expected)" ); vm.setmetatable(2); vm.remove(1); + vm.settop(1); break; } case TYPE: { diff --git a/src/core/org/luaj/lib/PackageLib.java b/src/core/org/luaj/lib/PackageLib.java index 81ec0e63..af907669 100644 --- a/src/core/org/luaj/lib/PackageLib.java +++ b/src/core/org/luaj/lib/PackageLib.java @@ -43,7 +43,7 @@ public class PackageLib extends LFunction { public static InputStream STDIN = null; public static PrintStream STDOUT = System.out; - public static LTable LOADED = new LTable(); + public static LTable LOADED = null; private static final LString _M = new LString("_M"); private static final LString _NAME = new LString("_NAME"); @@ -86,6 +86,7 @@ public class PackageLib extends LFunction { pckg = new LTable(); for ( int i=LOADLIB; i<=SEEALL; i++ ) pckg.put( NAMES[i], new PackageLib(i) ); + LOADED = new LTable(); pckg.put( "loaded", LOADED ); pckg.put( _PRELOAD, new LTable() ); LTable loaders = new LTable(3,0); diff --git a/src/core/org/luaj/vm/LTable.java b/src/core/org/luaj/vm/LTable.java index 6116390e..e9066d78 100644 --- a/src/core/org/luaj/vm/LTable.java +++ b/src/core/org/luaj/vm/LTable.java @@ -85,8 +85,6 @@ public class LTable extends LValue { private LTable m_metatable; - - /** Construct an empty LTable with no initial capacity. */ public LTable() { m_vector = EMPTY_ARRAY; @@ -273,8 +271,14 @@ public class LTable extends LValue { /** Valid for tables */ public void luaSetMetatable(LValue metatable) { - this.m_metatable = ( metatable != null && metatable != LNil.NIL ) ? - (LTable) metatable : null; + if ( m_metatable != null && m_metatable.containsKey(TM_METATABLE) ) + throw new LuaErrorException("cannot change a protected metatable"); + if ( metatable == null || metatable == LNil.NIL ) + this.m_metatable = null; + else if ( metatable.luaGetType() == Lua.LUA_TTABLE ) + this.m_metatable = (LTable) metatable; + else + throw new LuaErrorException("nil or table expected, got "+metatable.luaGetTypeName()); } public String toJavaString() { diff --git a/src/core/org/luaj/vm/LValue.java b/src/core/org/luaj/vm/LValue.java index bb1fa380..dce05f83 100644 --- a/src/core/org/luaj/vm/LValue.java +++ b/src/core/org/luaj/vm/LValue.java @@ -31,6 +31,9 @@ public class LValue { /** Metatable tag for intercepting table sets */ public static final LString TM_NEWINDEX = new LString("__newindex"); + /** Metatable tag for intercepting table sets */ + public static final LString TM_METATABLE = new LString("__metatable"); + protected void conversionError(String target) { throw new LuaErrorException( "bad conversion: "+luaGetTypeName()+" to "+target ); } @@ -70,12 +73,12 @@ public class LValue { // unsupported except for numbers public LValue luaBinOpInteger(int opcode, int m_value) { - return arithmeticError("number"); + return arithmeticError(luaGetTypeName()); } // unsupported except for numbers public LValue luaBinOpDouble(int opcode, double m_value) { - return arithmeticError("number"); + return arithmeticError(luaGetTypeName()); } // unsupported except for numbers, strings, and == with various combinations of Nil, Boolean, etc. diff --git a/src/test/java/org/luaj/vm/LuaJTest.java b/src/test/java/org/luaj/vm/LuaJTest.java index feae903b..4e4ef7d3 100644 --- a/src/test/java/org/luaj/vm/LuaJTest.java +++ b/src/test/java/org/luaj/vm/LuaJTest.java @@ -141,7 +141,7 @@ public class LuaJTest extends TestCase { private void runTest( String testName ) throws IOException, InterruptedException { // new lua state - LuaState state = new DebugLuaState(); + LuaState state = LuaState.newState(); // add standard bindings state.installStandardLibs(); diff --git a/src/test/res/baselib.lua b/src/test/res/baselib.lua index 155eecce..9b704db7 100644 --- a/src/test/res/baselib.lua +++ b/src/test/res/baselib.lua @@ -1,14 +1,6 @@ -- unit tests for functions in BaseLib.java -local ids = {} -local function id(obj) - local v = ids[obj] - if v then - return v - end - table.insert(ids,obj) - ids[obj] = type(obj)..'.'..tostring(#ids) - return ids[obj] -end +package.path = "?.lua;src/test/res/?.lua" +require 'ids' -- print print() diff --git a/src/test/res/errors.lua b/src/test/res/errors.lua index 8fe2af99..a6410661 100644 --- a/src/test/res/errors.lua +++ b/src/test/res/errors.lua @@ -1,7 +1,6 @@ -- object ids package.path = "?.lua;src/test/res/?.lua" require 'ids' -ids = {} -- test of common types of errors local function c(f,...) return f(...) end @@ -9,7 +8,6 @@ local function b(...) return c(...) end local function a(...) return pcall(b,...) end s = 'some string' local t = {} - -- error message tests print( 'a(error)', a(error) ) print( 'a(error,"msg")', a(error,"msg") ) diff --git a/src/test/res/metatables.lua b/src/test/res/metatables.lua index 1b7faea3..9593b40c 100644 --- a/src/test/res/metatables.lua +++ b/src/test/res/metatables.lua @@ -1,5 +1,31 @@ +package.path = "?.lua;src/test/res/?.lua" +require 'ids' + -- The purpose of this test case is to demonstrate that -- basic metatable operations on non-table types work. -- i.e. that s.sub(s,...) could be used in place of string.sub(s,...) local s = "hello" print(s:sub(2,4)) + +local t = {} +function op(name,...) + a,b,c,d = pcall( setmetatable, t, ... ) + print( name, id(t), id(getmetatable(t)), id(a), id(b), id(c), id(d) ) +end +op('set{} ',{}) +op('set-nil',nil) +op('set{} ',{}) +op('set') +op('set{} ',{}) +op('set{} ',{}) +op('set{}{}',{},{}) +op('set-nil',nil) +op('set{__}',{__metatable={}}) +op('set{} ',{}) +op('set-nil',nil) +t = {} +op('set{} ',{}) +op('set-nil',nil) +op('set{__}',{__metatable='abc'}) +op('set{} ',{}) +op('set-nil',nil) diff --git a/src/test/res/require.lua b/src/test/res/require.lua index 00faa91f..73e376b6 100644 --- a/src/test/res/require.lua +++ b/src/test/res/require.lua @@ -1,18 +1,6 @@ -- unit tests for require() function -local ids = {} -local ti = table.insert -local function id(obj) - if not obj or type(obj) == 'number' or type(obj) == 'string' or type(obj) == 'boolean' then - return obj - end - local v = ids[obj] - if v then - return v - end - ti(ids,obj) - ids[obj] = type(obj)..'.'..tostring(#ids) - return ids[obj] -end +package.path = "?.lua;src/test/res/?.lua" +require 'ids' -- tests on require package.path='?.lua;src/test/res/?.lua'