diff --git a/src/core/org/luaj/lib/BaseLib.java b/src/core/org/luaj/lib/BaseLib.java index 9189dc1c..9e0c517d 100644 --- a/src/core/org/luaj/lib/BaseLib.java +++ b/src/core/org/luaj/lib/BaseLib.java @@ -13,14 +13,11 @@ import java.io.PrintStream; import org.luaj.vm.CallInfo; import org.luaj.vm.LClosure; import org.luaj.vm.LFunction; -import org.luaj.vm.LInteger; import org.luaj.vm.LNil; -import org.luaj.vm.LNumber; import org.luaj.vm.LString; import org.luaj.vm.LTable; import org.luaj.vm.LValue; import org.luaj.vm.Lua; -import org.luaj.vm.LuaErrorException; import org.luaj.vm.LuaState; import org.luaj.vm.Platform; @@ -134,21 +131,38 @@ public class BaseLib extends LFunction { vm.resettop(); break; } - case IPAIRS: - case PAIRS: { + case IPAIRS: { LTable t = vm.checktable(2); vm.resettop(); - vm.pushjavafunction( (id==IPAIRS)? inext: next ); + vm.pushjavafunction( inext ); + vm.pushlvalue( t ); + vm.pushinteger( 0 ); + break; + } + case PAIRS: { + LTable t = vm.checktable(2); + vm.resettop(); + vm.pushjavafunction( next ); vm.pushlvalue( t ); vm.pushnil(); break; } - case INEXT: + case INEXT: { + int i = vm.checkint(3) + 1; + LTable t = vm.checktable(2); + LValue v = t.get(i); + vm.resettop(); + if ( !v.isNil() ) { + vm.pushinteger(i); + vm.pushlvalue(v); + } + break; + } case NEXT: { LTable t = vm.checktable(2); - LValue v = vm.topointer(3); + LValue k = vm.topointer(3); vm.resettop(); - t.next(vm,v,(id==INEXT)); + t.next(vm,k,false); break; } case GETMETATABLE: { @@ -230,7 +244,7 @@ public class BaseLib extends LFunction { } case LOADFILE: - loadfile(vm, vm.optstring(2,"")); + loadfile(vm, vm.optstring(2,null)); break; case TONUMBER: { @@ -411,6 +425,13 @@ public class BaseLib extends LFunction { } // return true if loaded, false if error put onto the stack + /** Load a chunk from an input stream, leaving it on the stack if successful, + * then close the input stream if it is not STDIN + * + * @param vm LuaState to load into + * @param is input stream to load from + * @return true if loaded and only item on stack, false if nil+error put onto stack + */ static boolean loadis(LuaState vm, InputStream is, String chunkname ) { try { vm.resettop(); @@ -426,12 +447,17 @@ public class BaseLib extends LFunction { } - // return true if loaded, false if error put onto stack - public static boolean loadfile( LuaState vm, String fileName ) { + /** Load a file into a chunk given a filename, leaving it on the stack if successful + * + * @param vm LuaState to load into + * @param fileName file to load, or null to use STDIN + * @return true if loaded and only item on stack, false if nil+error put onto stack + */ + private static boolean loadfile( LuaState vm, String fileName ) { InputStream is; String script; - if ( ! "".equals(fileName) ) { + if ( fileName != null ) { script = fileName; is = Platform.getInstance().openFile(fileName); if ( is == null ) { @@ -439,8 +465,8 @@ public class BaseLib extends LFunction { return false; } } else { - is = STDIN; - script = "-"; + is = STDIN != null? STDIN: new ByteArrayInputStream(new byte[0]); + script = "-"; } // use vm to load the script @@ -449,12 +475,11 @@ public class BaseLib extends LFunction { // if load succeeds, return 0 for success, 1 for error (as per lua spec) private void dofile( LuaState vm ) { - String filename = vm.checkstring(2); + String filename = vm.optstring(2,null); if ( loadfile( vm, filename ) ) { - int s = vm.pcall(1, 0, 0); - setResult( vm, LInteger.valueOf( s!=0? 1: 0 ) ); + vm.call(0, 0); } else { - vm.error("cannot open "+filename); + vm.error( vm.tostring(-1) ); } } diff --git a/src/core/org/luaj/lib/StringLib.java b/src/core/org/luaj/lib/StringLib.java index fabc2dcd..66975fab 100644 --- a/src/core/org/luaj/lib/StringLib.java +++ b/src/core/org/luaj/lib/StringLib.java @@ -21,12 +21,16 @@ ******************************************************************************/ package org.luaj.lib; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.luaj.compiler.DumpState; +import org.luaj.vm.LClosure; import org.luaj.vm.LFunction; import org.luaj.vm.LNumber; import org.luaj.vm.LString; import org.luaj.vm.LTable; import org.luaj.vm.LValue; -import org.luaj.vm.Lua; import org.luaj.vm.LuaState; @@ -204,7 +208,15 @@ public class StringLib extends LFunction { * TODO: port dumping code as optional add-on */ static void dump( LuaState vm ) { - vm.error("dump() not supported"); + LFunction f = vm.checkfunction(2); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + DumpState.dump( ((LClosure)f).p, baos, true ); + vm.resettop(); + vm.pushlstring(baos.toByteArray()); + } catch (IOException e) { + vm.error( e.getMessage() ); + } } /** diff --git a/src/test/errors/baselibargs.lua b/src/test/errors/baselibargs.lua index 155e321d..5e9da711 100644 --- a/src/test/errors/baselibargs.lua +++ b/src/test/errors/baselibargs.lua @@ -1,7 +1,6 @@ package.path = "?.lua;src/test/errors/?.lua" require 'args' - -- arg types for basic library functions -- assert @@ -17,7 +16,8 @@ checkallerrors('collectgarbage',{notanil},'bad argument #1') -- dofile banner('dofile') -checkallpass('dofile', {{nil,'src/test/errors/args.lua'}}) +checkallpass('dofile', {}) +checkallpass('dofile', {{'src/test/errors/args.lua'}}) checkallerrors('dofile', {{'args.lua'}}, 'cannot open args.lua') checkallerrors('dofile', {nonstring}, 'bad argument #1') @@ -50,11 +50,17 @@ checkallerrors('load', {somefunction,{afunction,atable}}, 'bad argument #2') -- loadfile banner('loadfile') checkallpass('loadfile', {}) +checkallpass('loadfile', {{'bogus'}}) +checkallpass('loadfile', {{'src/test/errors/args.lua'}}) +checkallpass('loadfile', {{'args.lua'}}) checkallerrors('loadfile', {nonstring}, 'bad argument #1') -- loadstring banner('loadstring') -checkallpass('loadstring', {{'return'},{nil,astring}}) +checkallpass('loadstring', {{'return'}}) +checkallpass('loadstring', {{'return'},{'mychunk'}}) +checkallpass('loadstring', {{'return a ... b'},{'mychunk'}}) +checkallerrors('loadstring', {{'return a ... b'},{'mychunk'}},'hello') checkallerrors('loadstring', {notastring,{nil,astring,anumber}}, 'bad argument #1') checkallerrors('loadstring', {{'return'},{afunction,atable}}, 'bad argument #2') diff --git a/src/test/errors/modulelibargs.lua b/src/test/errors/modulelibargs.lua index 5a55b169..8282bc83 100644 --- a/src/test/errors/modulelibargs.lua +++ b/src/test/errors/modulelibargs.lua @@ -5,13 +5,13 @@ require 'args' -- require banner('require') -checkallpass('require',{{'math'}}) +checkallpass('require',{{'math','coroutine','package','string','table'}},true) checkallerrors('require',{{anumber}},'not found') checkallerrors('require',{{anil,aboolean,afunction,atable}},'bad argument') -- package.loadlib banner('package.loadlib') -checkallpass('package.loadlib',{{'foo'},{'bar'}}) +checkallpass('package.loadlib',{{'foo'},{'bar'}},true) checkallerrors('package.loadlib',{notastring},'bad argument') -- package.seeall @@ -20,11 +20,30 @@ checkallpass('package.seeall',{sometable}) checkallerrors('package.seeall',{notatable},'bad argument') --- module (last because it pretty much breaks this chunk) +-- module tests - require special rigging +banner('module') print( pcall( function() - banner('module') - checkallpass('module',{somenumber,{package.seeall},{nil,afunction}}) - checkallerrors('module',{{aboolean,atable,afunction}},'bad argument') - checkallerrors('module',{{aboolean,atable,afunction},{package.seeall}},'bad argument') - checkallerrors('module',{somestring,{astring,anumber,aboolean,atable}},'attempt to call a') + checkallpass('module',{{20001}}) +end ) ) +print( pcall( function() + checkallpass('module',{{20002},{package.seeall}}) +end ) ) +print( pcall( function() + checkallpass('module',{{20003},{package.seeall},{function() end}}) +end ) ) +print( pcall( function() + checkallerrors('module',{{aboolean,atable,function() end}},'bad argument') + checkallerrors('module',{{aboolean,atable,function() end},{package.seeall}},'bad argument') +end ) ) +print( pcall( function() + checkallerrors('module',{{'testmodule1'},{'pqrs'}},'attempt to call') +end ) ) +print( pcall( function() + checkallerrors('module',{{'testmodule2'},{aboolean}},'attempt to call') +end ) ) +print( pcall( function() + checkallerrors('module',{{'testmodule3'},{athread}},'attempt to call') +end ) ) +print( pcall( function() + checkallerrors('module',{{'testmodule4'},{atable}},'attempt to call') end ) ) diff --git a/src/test/errors/stringlibargs.lua b/src/test/errors/stringlibargs.lua index 1467e271..0ee44ad3 100644 --- a/src/test/errors/stringlibargs.lua +++ b/src/test/errors/stringlibargs.lua @@ -12,17 +12,27 @@ checkallerrors('string.byte',{somestring,{astring,afunction,atable}},'bad argume checkallerrors('string.byte',{notastring,{nil,111}},'bad argument') -- string.char -banner('string.char') -checkallpass('string.char',{{nil,0,1,40,127,128,255,'0','1','255','1.2',1.2}}) -checkallpass('string.char',{{0,127,255},{0,127,255}}) -checkallpass('string.char',{}) -checkallerrors('string.char',{{-1,256}},'bad argument #1') -checkallerrors('string.char',{notanumber,{23,'45',6.7}},'bad argument #1') -checkallerrors('string.char',{{23,'45',6.7},nonnumber},'bad argument #2') +function string_char(...) + return string.byte( string.char( ... ) ) +end +banner('string_char') +checkallpass('string.char',{{60}}) +checkallpass('string.char',{{60},{70}}) +checkallpass('string.char',{{60},{70},{80}}) +checkallpass('string_char',{{nil,0,9,40,127,128,255,'0','9','255','9.2',9.2}}) +checkallpass('string_char',{{0,127,255},{0,127,255}}) +checkallpass('string_char',{}) +checkallerrors('string_char',{},'bad argument #1') +checkallerrors('string_char',{{-1,256}},'bad argument #1') +checkallerrors('string_char',{notanumber,{23,'45',6.7}},'bad argument #1') +checkallerrors('string_char',{{23,'45',6.7},nonnumber},'bad argument #2') -- string.dump banner('string.dump') -checkallpass('string.dump',{{afunction}}) +local someupval = 435 +local function funcwithupvals() return someupval end +checkallpass('string.dump',{{function() return 123 end}}) +checkallpass('string.dump',{{funcwithupvals}}) checkallerrors('string.dump',{notafunction},'bad argument') -- string.find diff --git a/src/test/java/org/luaj/vm/ScriptDrivenTest.java b/src/test/java/org/luaj/vm/ScriptDrivenTest.java index 66734d93..2bee28f1 100644 --- a/src/test/java/org/luaj/vm/ScriptDrivenTest.java +++ b/src/test/java/org/luaj/vm/ScriptDrivenTest.java @@ -27,11 +27,7 @@ public class ScriptDrivenTest extends TestCase { InterruptedException { // set platform relative to directory - Platform.setInstance(new J2sePlatform() { - public InputStream openFile(String fileName) { - return super.openFile(basedir+"/"+fileName); - } - }); + Platform.setInstance(new J2sePlatform()); // new lua state LuaState state = Platform.newLuaState();