package se.krka.kahlua.require; import se.krka.kahlua.vm.*; import se.krka.kahlua.stdlib.BaseLib; import se.krka.kahlua.luaj.compiler.LuaCompiler; import java.io.Reader; import java.io.IOException; import java.util.Map; import java.util.HashMap; public class Require implements JavaFunction { private enum State { LOADING, LOADED, BROKEN; }; private static class Result { public final String errorMessage; public final State state; private Result(String errorMessage, State state) { this.errorMessage = errorMessage; this.state = state; } public static final Result LOADING = new Result(null, State.LOADING); public static final Result LOADED = new Result(null, State.LOADED); public static Result error(String s) { return new Result(s, State.BROKEN); } } public void install(LuaState state) { LuaTable env = state.getEnvironment(); env.rawset("require", this); env.rawset(this, new HashMap<String, Result>()); } private final LuaSourceProvider luaSourceProvider; public Require(LuaSourceProvider luaSourceProvider) { this.luaSourceProvider = luaSourceProvider; } public int call(LuaCallFrame callFrame, int nArguments) { LuaTable env = callFrame.getEnvironment(); Map<String, Result> states = (Map<String, Result>) callFrame.thread.state.tableGet(env, this); BaseLib.luaAssert(nArguments >= 1, "not enough args"); String path = (String) callFrame.get(0); Result result = states.get(path); if (result == null) { setState(states, path, Result.LOADING); Reader source = luaSourceProvider.getLuaSource(path); if (source == null) { error(states, path, "Does not exist: " + path); } try { LuaClosure luaClosure = LuaCompiler.loadis(source, path, env); setState(states, path, Result.LOADING); callFrame.thread.state.call(luaClosure, null, null, null); setState(states, path, Result.LOADED); return 0; } catch (IOException e) { error(states, path, "Error in: " + path + ": " + e.getMessage()); } catch (RuntimeException e) { error(states, path, "Error in: " + path + ": " + e.getMessage()); } } if (result == Result.LOADING) { error(states, path, "Circular dependency found for: " + path); } if (result.state == State.BROKEN) { BaseLib.fail(result.errorMessage); } return 0; } private void error(Map<String, Result> states, String path, String s) { setState(states, path, Result.error(s)); BaseLib.fail(s); } private void setState(Map<String, Result> requireLookuptable, String path, Result result) { requireLookuptable.put(path, result); } }