From eef469c7152fcd1ea1f9f1ae5d3985430782b866 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Fri, 16 Nov 2007 00:41:43 +0000 Subject: [PATCH] Add unit tests for part of base library plus fixes to [gs]etfenv, [gs]etmetatable --- src/core/org/luaj/lib/BaseLib.java | 102 +++++++++++----------- src/core/org/luaj/vm/LClosure.java | 7 ++ src/core/org/luaj/vm/LThread.java | 6 ++ src/core/org/luaj/vm/LValue.java | 5 ++ src/core/org/luaj/vm/LuaState.java | 13 +-- src/sample/org/luaj/sample/LuaRunner.java | 9 +- src/test/java/org/luaj/vm/LuaJTest.java | 14 ++- src/test/res/baselib.lua | 92 +++++++++++++++++++ src/test/res/baselib.luac | Bin 0 -> 4448 bytes src/test/res/setfenv.lua | 40 +++++++++ src/test/res/setfenv.luac | Bin 0 -> 2447 bytes 11 files changed, 223 insertions(+), 65 deletions(-) create mode 100644 src/test/res/baselib.lua create mode 100644 src/test/res/baselib.luac create mode 100644 src/test/res/setfenv.lua create mode 100644 src/test/res/setfenv.luac diff --git a/src/core/org/luaj/lib/BaseLib.java b/src/core/org/luaj/lib/BaseLib.java index 7c87600e..f6e589fd 100644 --- a/src/core/org/luaj/lib/BaseLib.java +++ b/src/core/org/luaj/lib/BaseLib.java @@ -47,6 +47,7 @@ public class BaseLib extends LFunction { "tonumber", "rawget", "rawset", + "getfenv", "setfenv", "select", "collectgarbage", @@ -72,15 +73,16 @@ public class BaseLib extends LFunction { private static final int TONUMBER = 11; private static final int RAWGET = 12; private static final int RAWSET = 13; - private static final int SETFENV = 14; - private static final int SELECT = 15; - private static final int COLLECTGARBAGE = 16; - private static final int DOFILE = 17; - private static final int LOADSTRING = 18; - private static final int LOAD = 19; - private static final int TOSTRING = 20; - private static final int UNPACK = 21; - private static final int NEXT = 22; + private static final int GETFENV = 14; + private static final int SETFENV = 15; + private static final int SELECT = 16; + private static final int COLLECTGARBAGE = 17; + private static final int DOFILE = 18; + private static final int LOADSTRING = 19; + private static final int LOAD = 20; + private static final int TOSTRING = 21; + private static final int UNPACK = 22; + private static final int NEXT = 23; public static void install(LTable globals) { for ( int i=1; i2? vm.tointeger(3): 1); + vm.error(vm.tostring(2), vm.gettop()>=3? vm.tointeger(3): 1); break; } case ASSERT: { @@ -211,9 +219,38 @@ public class BaseLib extends LFunction { vm.error( "expected table" ); } } break; - case SETFENV: - setfenv( (LuaState) vm ); + case GETFENV: { + if ( vm.gettop() <= 1 ) { + vm.pushlvalue(vm._G); + } else { + if ( ! vm.isfunction(2) ) { + int i = (vm.isnil(2)? 1: vm.tointeger(2)); + vm.pushlvalue( vm.getStackFrame(i).closure ); + } + vm.getfenv(-1); + } + vm.insert(1); + vm.settop(1); break; + } + case SETFENV: { + LTable t = vm.totable(-1); + if ( vm.setfenv(2) != 0 ) { + vm.remove(1); + break; + } + int i = vm.tointeger(2); + if ( i == 0 ) { + vm._G = t; + vm.settop(0); + } else { + LClosure c = vm.getStackFrame(i-1).closure; + c.luaSetEnv(t); + vm.settop(0); + vm.pushlvalue(c); + } + break; + } case SELECT: select( vm ); break; @@ -269,43 +306,6 @@ public class BaseLib extends LFunction { } } - private void setfenv( LuaState state ) { - LValue f = state.topointer(2); - LValue newenv = state.topointer(3); - - LClosure c = null; - - // Lua reference manual says that first argument, f, can be a "Lua - // function" or an integer. Lots of things extend LFunction, but only - // instances of Closure are "Lua functions". - if ( f instanceof LClosure ) { - c = (LClosure) f; - } else { - int callStackDepth = f.toJavaInt(); - if ( callStackDepth > 0 ) { - CallInfo frame = state.getStackFrame( callStackDepth ); - if ( frame != null ) { - c = frame.closure; - } - } else { - // This is supposed to set the environment of the current - // "thread". But, we have not implemented coroutines yet. - throw new LuaErrorException( "not implemented" ); - } - } - - if ( c != null ) { - if ( newenv instanceof LTable ) { - c.env = (LTable) newenv; - } - state.settop(0); - state.pushlvalue( c ); - return; - } - - state.settop(0); - return; - } // closes the input stream, provided its not null or System.in private static void closeSafely(InputStream is) { diff --git a/src/core/org/luaj/vm/LClosure.java b/src/core/org/luaj/vm/LClosure.java index 3bd7baa5..15fa6b60 100644 --- a/src/core/org/luaj/vm/LClosure.java +++ b/src/core/org/luaj/vm/LClosure.java @@ -57,4 +57,11 @@ public class LClosure extends LFunction { vm.prepStackCall(); return true; } + + /** Set the environment if a thread, or closure, and return 1, otherwise return 0 */ + public int luaSetEnv(LTable t) { + this.env = t; + return 1; + } + } diff --git a/src/core/org/luaj/vm/LThread.java b/src/core/org/luaj/vm/LThread.java index d1a21329..db11f047 100644 --- a/src/core/org/luaj/vm/LThread.java +++ b/src/core/org/luaj/vm/LThread.java @@ -59,6 +59,12 @@ public class LThread extends LValue implements Runnable { return "thread: "+hashCode(); } + /** Set the environment if a thread, or closure, and return 1, otherwise return 0 */ + public int luaSetEnv(LTable t) { + threadVm._G = t; + return 1; + } + public String getStatus() { return NAMES[status]; } diff --git a/src/core/org/luaj/vm/LValue.java b/src/core/org/luaj/vm/LValue.java index 593a6934..1922dca0 100644 --- a/src/core/org/luaj/vm/LValue.java +++ b/src/core/org/luaj/vm/LValue.java @@ -297,4 +297,9 @@ public class LValue { return null; } + /** Set the environment if a thread, or closure, and return 1, otherwise return 0 */ + public int luaSetEnv(LTable t) { + return 0; + } + } diff --git a/src/core/org/luaj/vm/LuaState.java b/src/core/org/luaj/vm/LuaState.java index b2ec26a1..45dd0264 100644 --- a/src/core/org/luaj/vm/LuaState.java +++ b/src/core/org/luaj/vm/LuaState.java @@ -958,8 +958,8 @@ public class LuaState extends Lua { * after filling line number information first when level > 0. */ public void error(String message, int level) { - if ( level > 0 ) - message = getFileLine(cc + 1 - level) + ": " + message; + if ( level > 1 ) + message = getFileLine(cc + 2 - level) + ": " + message; throw new LuaErrorException( message ); } @@ -1117,7 +1117,8 @@ public class LuaState extends Lua { * index. */ public void getfenv(int index) { - notImplemented(); + LValue f = topointer(index); + pushlvalue( ((LClosure) f).env ); } /** @@ -1130,8 +1131,10 @@ public class LuaState extends Lua { * returns 0. Otherwise it returns 1. */ public int setfenv(int index) { - notImplemented(); - return 0; + LTable t = totable(-1); + LValue f = topointer(index); + pop(1); + return f.luaSetEnv(t); } diff --git a/src/sample/org/luaj/sample/LuaRunner.java b/src/sample/org/luaj/sample/LuaRunner.java index ceaefc92..363fbe05 100644 --- a/src/sample/org/luaj/sample/LuaRunner.java +++ b/src/sample/org/luaj/sample/LuaRunner.java @@ -24,15 +24,9 @@ package org.luaj.sample; import java.io.IOException; import java.io.InputStream; -import org.luaj.lib.CoroutineLib; -import org.luaj.lib.MathLib; -import org.luaj.lib.PackageLib; -import org.luaj.lib.StringLib; -import org.luaj.lib.TableLib; -import org.luaj.lib.j2se.LuajavaLib; +import org.luaj.compiler.LuaC; import org.luaj.vm.LClosure; import org.luaj.vm.LPrototype; -import org.luaj.vm.LTable; import org.luaj.vm.LValue; import org.luaj.vm.LoadState; import org.luaj.vm.LuaState; @@ -56,6 +50,7 @@ public class LuaRunner { // add standard bindings state.installStandardLibs(); + LuaC.install(); // load the file InputStream is = LuaRunner.class.getResourceAsStream( script ); diff --git a/src/test/java/org/luaj/vm/LuaJTest.java b/src/test/java/org/luaj/vm/LuaJTest.java index 8fbe079e..f656c0eb 100644 --- a/src/test/java/org/luaj/vm/LuaJTest.java +++ b/src/test/java/org/luaj/vm/LuaJTest.java @@ -6,13 +6,14 @@ import java.io.OutputStream; import junit.framework.TestCase; +import org.luaj.compiler.LuaC; import org.luaj.debug.DebugLuaState; import org.luaj.lib.BaseLib; import org.luaj.lib.j2se.LuajavaLib; public class LuaJTest extends TestCase { - + public void testTest1() throws IOException, InterruptedException { runTest( "test1" ); } @@ -45,6 +46,10 @@ public class LuaJTest extends TestCase { runTest( "autoload" ); } + public void testBaseLib() throws IOException, InterruptedException { + runTest( "baselib" ); + } + public void testBoolean() throws IOException, InterruptedException { runTest( "boolean" ); } @@ -81,6 +86,10 @@ public class LuaJTest extends TestCase { runTest( "select" ); } + public void testSetfenv() throws IOException, InterruptedException { + runTest( "setfenv" ); + } + public void testSetlist() throws IOException, InterruptedException { runTest( "setlist" ); } @@ -108,7 +117,7 @@ public class LuaJTest extends TestCase { public void testUpvalues2() throws IOException, InterruptedException { runTest( "upvalues2" ); } - +//*/ private void runTest( String testName ) throws IOException, InterruptedException { // new lua state @@ -119,6 +128,7 @@ public class LuaJTest extends TestCase { // add luajava LuajavaLib.install( state._G ); + LuaC.install(); // load the file LPrototype p = loadScriptResource( state, testName ); diff --git a/src/test/res/baselib.lua b/src/test/res/baselib.lua new file mode 100644 index 00000000..dd172697 --- /dev/null +++ b/src/test/res/baselib.lua @@ -0,0 +1,92 @@ +-- unit tests for functions in BaseLib.java + +-- assert +print( 'assert(true)', assert(true) ) +print( 'pcall(assert,true)', pcall(assert,true) ) +print( 'pcall(assert,false)', pcall(assert,false) ) +print( 'pcall(assert,nil)', pcall(assert,nil) ) +print( 'pcall(assert,true,"msg")', pcall(assert,true,"msg") ) +print( 'pcall(assert,false,"msg")', pcall(assert,false,"msg") ) +print( 'pcall(assert,nil,"msg")', pcall(assert,nil,"msg") ) +print( 'pcall(assert,false,"msg","msg2")', pcall(assert,false,"msg","msg2") ) + +-- collectgarbage (not supported) +-- dofile (not supported) + +-- error +print( 'pcall(error)', pcall(error) ) +print( 'pcall(error,"msg")', pcall(error,"msg") ) +print( 'pcall(error,"msg",1)', pcall(error,"msg",1) ) +print( 'pcall(error,"msg",2)', pcall(error,"msg",2) ) +local function le(level) + error("msg",level) +end +function ge(level) + error("msg",level) +end +for i = 0,4 do + print( 'pcall(le,i)', i, pcall(le,i) ) + print( 'pcall(ge,i)', i, pcall(ge,i) ) +end + +-- _G +print( '_G["abc"] (before)', _G["abc"] ) +abc='def' +print( '_G["abc"] (after)', _G["abc"] ) + +-- type +print( 'type(nil)', type(nil) ) +print( 'type("a")', type("a") ) +print( 'type(1)', type(1) ) +print( 'type(1.5)', type(1.5) ) +print( 'type(function() end)', type(function() end) ) +print( 'type({})', type({}) ) +print( 'type(true)', type(true) ) +print( 'type(false)', type(false) ) +print( 'pcall(type,type)', pcall(type,type) ) +print( 'pcall(type)', pcall(type) ) +print( '(function() return pcall(type) end)()', (function() return pcall(type) end)() ) +local function la() return pcall(type) end +print( 'la()', la() ) +function ga() return pcall(type) end +print( 'ga()', ga() ) + +-- getfenv, setfenv: tested in setfenv.lua +-- getmetatable, setmetatable +ta = { aa1="aaa1", aa2="aaa2" } +tb = { bb1="bbb1", bb2="bbb2" } +print( 'getmetatable(ta)', getmetatable(ta) ) +print( 'getmetatable(tb)', getmetatable(tb) ) +print( 'setmetatable(ta),{cc1="ccc1"}', type( setmetatable(ta,{cc1="ccc1"}) ) ) +print( 'setmetatable(tb),{dd1="ddd1"}', type( setmetatable(tb,{dd1="ddd1"}) ) ) +print( 'getmetatable(ta)["cc1"]', getmetatable(ta)["cc1"] ) +print( 'getmetatable(tb)["dd1"]', getmetatable(tb)["dd1"] ) +print( 'getmetatable(1)', getmetatable(1) ) +print( 'pcall(setmetatable,1)', pcall(setmetatable,1) ) +print( 'pcall(setmetatable,nil)', pcall(setmetatable,nil) ) +print( 'pcall(setmetatable,"ABC")', pcall(setmetatable,"ABC") ) +print( 'pcall(setmetatable,function() end)', pcall(setmetatable,function() end) ) + +-- ipairs +-- load +-- loadfile +-- loadstring +-- next +-- pairs +-- pcall +-- print +-- rawget +-- rawset +-- select +-- tonumber +-- tostring +-- unpack +--[[ +print( 'pcall(unpack)', pcall(unpack) ); +print( 'unpack({"aa"})', unpack({"aa"}) ); +print( 'unpack({"aa","bb"})', unpack({"aa","bb"}) ); +print( 'unpack({"aa","bb","cc"})', unpack({"aa","bb","cc"}) ); + +-- _VERSION +print( '_VERSION', _VERSION ) +--]] diff --git a/src/test/res/baselib.luac b/src/test/res/baselib.luac new file mode 100644 index 0000000000000000000000000000000000000000..198e2f37716d071d7ac4806f2851cf3782f1ac63 GIT binary patch literal 4448 zcmbtXTW=dh6h33GlQf~XlzU5+no=Avg#?hemF~7!d7x6^m8ME}<4t5~>jry+Kvl(B zsH(~@;8F=5`a?EIR00Xa59lL5fJY==_`aFFx@%LFk-pv8?>pzroU=2t_R$Nw?#H4m z%bJt@B4T^)&<}dv>0sBzW7=v9FDQ`)9vxfcW+d{HL~=(&9mBKcWALKnXJ|D=Ey^`p z6*MVpQLfdM)JlGFt}&*gY8!i@)axdq2@SNdEU{OzL)DKMWlt|BN#BV6`LcufBYOt#X-4kF_td%_DMw~yEuImh&6YIHMd0FD zVGZx22J4ug=4DRv%9)cAAEmri=HrA{`^vn%Psceqk}@9|eja(3;>U*PnkexyujBAt zmUtVyC~54?N(Z=)wVCA*dWqnk*Ll7Fokwi*oJmNM+h_yqgd4 zPOKSRb_TtEC>9SfcR2J1VJjT$`paU?W{g-zXt?PHLCe^*6B`|XyjYKqn{2tkkZ~5r zg?=vp{meMcknQHx;dT?M1r=Sfo*g&SVKcj@$7KZ1#1rFU!B-ota;SzGYSq-hWa$qE z*9Op-pY9h+powgdC$d2be0ybC>JZTWI%`#%tY#)+TQuJGQy)n?hivOHC}vWD-|k^f zIk9aBzMPGFOgRGTRvw zg5f%J-4!Fbx@RaX7g~ctkN%-&tUWKW_H>Wdo|jmILXVkj`{7kTbVJt*{8s2<4%~o6 zw#v?f-Er6r$GqFuH#b+#G&gZ=-Y}txCT3y~&75gg6~|j{U+;Dir;97&aPH_DFOp($ zzZGZ6xnIJ-E6vMQq6d+|ARZd`bj5nU zI(}h&=(WhBj*T1jDRz{}xr6S=7Kw4^2cHKg7k}|wV3BxIv2jH(r6L#)-xuLg68N9_ z0q%&Pujay^V~ae8fw(41 zwb3um)R6lUvT;a*6z^J0E-SbbXpcTf8l-qPG0pXL+z7NsA0!P@yqlQj`T=ePT4i|? zO&jn(f`wic(o$F5xuhn6OL`J`a8CnI=4s$}Vj6gs{}&F!rV9MEFbPMXO#^>|Oar$f zHwHJ{(J>su^E6kgpDa3w~UW3c@Ta6E4w literal 0 HcmV?d00001 diff --git a/src/test/res/setfenv.lua b/src/test/res/setfenv.lua new file mode 100644 index 00000000..ba5b48bb --- /dev/null +++ b/src/test/res/setfenv.lua @@ -0,0 +1,40 @@ +-- unit tests for getfenv, setfenv +local function f3(level,value) + if value then + setfenv( level, {setfenv=setfenv, abc=value} ) + end + return abc +end +local function f2(...) + local r = f3(...) + return abc,r +end +local function f1(...) + local r,s = f2(...) + return abc,r,s +end +print( 'getfenv,setfenv - before') +print( 'getfenv(f1)["abc"]', getfenv(f1)["abc"] ) +print( 'getfenv(f2)["abc"]', getfenv(f2)["abc"] ) +print( 'getfenv(f3)["abc"]', getfenv(f3)["abc"] ) +print( 'getfenv()["abc"]', getfenv()["abc"] ) +print( 'abc,f1()', abc,f1() ) +setfenv(f1,{setfenv=setfenv, abc='ghi'}) +setfenv(f2,{setfenv=setfenv, abc='jkl'}) +setfenv(f3,{setfenv=setfenv, abc='mno'}) +print( 'getfenv,setfenv - after') +print( 'getfenv(f1)["abc"]', getfenv(f1)["abc"] ) +print( 'getfenv(f2)["abc"]', getfenv(f2)["abc"] ) +print( 'getfenv(f3)["abc"]', getfenv(f3)["abc"] ) +print( 'getfenv()["abc"]', getfenv()["abc"] ) +print( 'abc,f1()', abc,f1() ) +print( 'abc,f1(1,"pqr")', abc,f1(1,"pqr") ) +print( 'abc,f1(2,"stu")', abc,f1(2,"stu") ) +print( 'abc,f1(3,"vwx")', abc,f1(3,"vwx") ) +print( 'abc', abc ) +local c = coroutine.create( function() + print( 'pcall(f1,0,"abc")', pcall(f1,0,"234") ) +end ) +print( 'resume', coroutine.resume(c) ) +print( 'abc,pcall(f1)', abc,pcall(f1) ) +print( 'abc (out)', abc ) diff --git a/src/test/res/setfenv.luac b/src/test/res/setfenv.luac new file mode 100644 index 0000000000000000000000000000000000000000..06c06558b02ac69ead947a64b4ab834c2d8387b4 GIT binary patch literal 2447 zcmd5-+foxj5ba4e;o|*<7f>;xhN@_p;JdpjRAKqztKvhz4Wi-VCP5!(QTzjaqIlB( z$XdczP=14-;5oC|Y!@n@~-b5WLM4a*4;u^Vo)=B{nttGB99 zqc1b^4dN8=+74~sHAgLb_*IU`fi23&zQ}9%Npk9OIM3`c z`~U2b`S{uH-h&`3Dq{(1piB)+zE;fpmZ+bHc$JHJCnstvmz)lb7uvCtsYoY#VFupzafnh~a#2n7{A&>f%!2m7syUv&6EXz<$WP5_>12 z%*6IHag<_g9SOsgYUSc|xKbytaHZupE1~fAT|E?5*Ve_l6vyh>N43^;J+V&5A4To;9i8YGoOY7cxtGTj< zQVvn|+-kEUdv2q(3i%}Ls9tGfsamhI$erV%8U_J7Swt8x@a2bVCyWOne;mULU`#8$ zjj;`k;zG`%X+|8SM;xtp@F;BCBD-iPHUa0GGfY&LXULBcSsj8arh#2VFcU_kTz5C! zI!2LW04h(NXgnnt+sJYkj}5cMM#6)R66AvHk_fDH z1O_$R!&vo}@f)T=n`gGfq!^OhtIgmi-0>-l$R^Lsy4kex$UzsS#m1%jjo5uN;v_!l z5qPM*VDPA%QC3me!mJ{#Vf?6dbF4rSxe43?V9s;nIl!?|EiLj3vI?N%5!gYF6Rt{2Sv&cq9aiK=3w3;1iGr zW}5~+DQP$lt{*PI-VbB2r{N;FH1Nqu1E19hS0JZh99$YEz@>rDct2c&y&tZ_J_wWG z2jK?zK`4Ol1-musShfb`+XHY1TpEht4#R?t&58@mj{6#^6=UtHWpf3n^8PQ$r;aZM F`3nlHF0uds literal 0 HcmV?d00001