mjanicek / rembulan

Rembulan, an implementation of Lua 5.3 for the Java Virtual Machine
Apache License 2.0
163 stars 28 forks source link

CallException: net.sandius.rembulan.lib.BadArgumentException: bad argument #1 to 'ipairs' (table expected, got light userdata) #23

Open JuKu opened 6 years ago

JuKu commented 6 years ago

I get this exception:

net.sandius.rembulan.exec.CallException: net.sandius.rembulan.lib.BadArgumentException: bad argument #1 to 'ipairs' (table expected, got light userdata)

    at net.sandius.rembulan.exec.DirectCallExecutor$Result.get(DirectCallExecutor.java:184)
    at net.sandius.rembulan.exec.DirectCallExecutor.execute(DirectCallExecutor.java:310)
    at net.sandius.rembulan.exec.DirectCallExecutor.resume(DirectCallExecutor.java:252)
    at net.sandius.rembulan.exec.DirectCallExecutor.call(DirectCallExecutor.java:228)
    at com.jukusoft.mmo.engine.applayer.script.lua.LuaScriptEngine.execFunc(LuaScriptEngine.java:77)
    at com.jukusoft.mmo.engine.applayer.script.lua.LuaScriptEngineTest.testExecGlobalFunc(LuaScriptEngineTest.java:102)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: net.sandius.rembulan.lib.BadArgumentException: bad argument #1 to 'ipairs' (table expected, got light userdata)
    at net.sandius.rembulan.lib.impl.ArgumentIterator.badArgument(ArgumentIterator.java:117)
    at net.sandius.rembulan.lib.impl.ArgumentIterator.nextStrict(ArgumentIterator.java:181)
    at net.sandius.rembulan.lib.impl.ArgumentIterator.nextTable(ArgumentIterator.java:354)
    at net.sandius.rembulan.lib.impl.DefaultBasicLib$IPairs.invoke(DefaultBasicLib.java:380)
    at net.sandius.rembulan.lib.impl.AbstractLibFunction.invoke(AbstractLibFunction.java:36)
    at net.sandius.rembulan.runtime.AbstractFunctionAnyArg.invoke(AbstractFunctionAnyArg.java:31)
    at net.sandius.rembulan.runtime.Dispatch.mt_invoke(Dispatch.java:64)
    at net.sandius.rembulan.runtime.Dispatch.call(Dispatch.java:199)
    at engine0$0.run(script_add:3)
    at engine0$0.invoke(script_add)
    at net.sandius.rembulan.runtime.AbstractFunction1.invoke(AbstractFunction1.java:57)
    at net.sandius.rembulan.runtime.Dispatch.mt_invoke(Dispatch.java:95)
    at net.sandius.rembulan.runtime.Dispatch.call(Dispatch.java:402)
    at net.sandius.rembulan.runtime.Coroutine$BootstrapResumable.resume(Coroutine.java:89)
    at net.sandius.rembulan.runtime.ResumeInfo.resume(ResumeInfo.java:35)
    at net.sandius.rembulan.runtime.Call$Resumer.continueCurrentCoroutine(Call.java:513)
    at net.sandius.rembulan.runtime.Call$Resumer.resume(Call.java:537)
    at net.sandius.rembulan.runtime.Call.resume(Call.java:232)
    at net.sandius.rembulan.runtime.Call.access$000(Call.java:37)
    at net.sandius.rembulan.runtime.Call$CallContinuation.resume(Call.java:181)
    at net.sandius.rembulan.exec.DirectCallExecutor.execute(DirectCallExecutor.java:290)
    ... 28 more

What does this exception means?

Source code:

public class LuaScriptEngine implements IScriptEngine {

    protected StateContext state = null;
    protected Table env = null;

    //map with all registered global lua functions
    protected ObjectObjectMap<String, LuaFunction> luaFunctions = new ObjectObjectHashMap<>();

    public LuaScriptEngine () {
        //initialize state
        this.state = StateContexts.newDefaultInstance();
        this.env = StandardLibrary.in(RuntimeEnvironments.system()).installInto(state);

        //register global functions
        this.env.rawset("logd", new LogDebugFunc());
        this.env.rawset("logi", new LogInfoFunc());

        this.env.rawset("now", new NowFunc());
    }

    /**
     * compile lua script as string to function
     *
     * //@param rootClassPrefix  the class name prefix for compiled classes, must not be {@code null}
     */
    @Override
    public void compile (String scriptName, String programStr) throws ScriptLoadException {
        Log.d("Scripts", "compile script '" + scriptName + "'");

        scriptName = "script_" + scriptName;

        //compile
        ChunkLoader loader = CompilerChunkLoader.of("engine");
        LuaFunction func = null;
        try {
            func = loader.loadTextChunk(new Variable(env), scriptName, programStr);
        } catch (LoaderException e) {
            Log.e("Scripts", "Couldn't compile lua script: " + programStr + ", error: " + e.getLuaStyleErrorMessage(), e);
            throw new ScriptLoadException("Coulnd't compile script: " + programStr + ", error: " + e.getLuaStyleErrorMessage());
        }

        this.luaFunctions.put(scriptName, func);
    }

    @Override
    public Object execFunc(String funcName, Object... args) throws CallException {
        // get a reference to the function
        LuaFunction func = (LuaFunction) env.rawget(funcName);

        if (func == null) {
            throw new NullPointerException("lua function cannot be null.");
        }

        try {
            Object[] objs = DirectCallExecutor.newExecutor().call(state, func, args);

            if (objs.length > 0) {
                return objs[0];
            } else {
                //it's a void method
                return null;
            }
        } catch (CallException e) {
            Log.w("Scripts", "CallException: ", e);
            throw e;
            //throw new ScriptExecutionException("CallException: " + e.getLocalizedMessage());
        } catch (CallPausedException e) {
            Log.w("Scripts", "CallPausedException: ", e);
        } catch (InterruptedException e) {
            Log.w("Scripts", "InterruptedException: ", e);
        }

        return null;
    }

    @Override
    public Object execFunc(String funcName) throws CallException {
        return this.execFunc(funcName, new Object[0]);
    }

    @Override
    public Object execScript(String scriptName, Object... args) {
        scriptName = "script_" + scriptName;

        LuaFunction func = this.luaFunctions.get(scriptName);

        if (func == null) {
            throw new IllegalStateException("lua script '" + scriptName + "' doesn't exists in cache, you have to compile it first!");
        }

        Log.d("Scripts", "execute lua script '" + scriptName + "'");

        try {
            Object[] objs = DirectCallExecutor.newExecutor().call(state, func);

            if (objs.length > 0) {
                return objs[0];
            } else {
                //it's a void method
                return null;
            }
        } catch (CallException e) {
            Log.w("Scripts", "CallException: ", e);
        } catch (CallPausedException e) {
            Log.w("Scripts", "CallPausedException: ", e);
        } catch (InterruptedException e) {
            Log.w("Scripts", "InterruptedException: ", e);
        }

        return null;
    }

    protected void printEnvDebug () {
        for (long i = 0; i < env.rawlen(); i++) {
            Log.d("Scripts", "rawget[" + i + "]: " + env.rawget(i));
        }
    }

}

Test method which throws this exception:

@Test
    public void testExecGlobalFunc () throws ScriptLoadException, CallException {
        GameTime time = GameTime.getInstance();
        time.setTime(System.currentTimeMillis());

        LuaScriptEngine engine = new LuaScriptEngine();
        engine.compile("add", "function add (a)\n" +
                "      local sum = 0\n" +
                "      for i,v in ipairs(a) do\n" +
                "        sum = sum + v\n" +
                "      end\n" +
                "      return sum\n" +
                "    end");
        engine.execScript("add");

        engine.printEnvDebug();

        assertEquals(6, engine.execFunc("add", new int[] {1, 2, 3}));
    }
JuKu commented 6 years ago

I already have found the solution: I have to use class Table instead of an array:

@Test
    public void testExecGlobalFunc () throws ScriptLoadException, CallException {
        GameTime time = GameTime.getInstance();
        time.setTime(System.currentTimeMillis());

        LuaScriptEngine engine = new LuaScriptEngine();
        engine.compile("add", "function add (a)\n" +
                "      local sum = 0\n" +
                "      for i,v in ipairs(a) do\n" +
                "        print(v);" +
                "        sum = sum + v\n" +
                "      end\n" +
                "      return sum\n" +
                "    end");
        engine.execScript("add");

        engine.printEnvDebug();

        Table table = new DefaultTable();
        table.rawset(1l, new Long(1));
        table.rawset(2l, new Long(2));
        table.rawset(3l, new Long(3));
        assertEquals(6l, engine.execFunc("add", table));
    }