diff --git a/src/main/java/org/squiddev/cobalt/Constants.java b/src/main/java/org/squiddev/cobalt/Constants.java
index 1e20fca3..5099ec9f 100644
--- a/src/main/java/org/squiddev/cobalt/Constants.java
+++ b/src/main/java/org/squiddev/cobalt/Constants.java
@@ -241,6 +241,11 @@ public class Constants {
*/
public static final LuaString EMPTYSTRING = valueOf("");
+ /**
+ * The global loaded package table.
+ */
+ public static final LuaString LOADED = valueOf("_LOADED");
+
/**
* Constant limiting metatag loop processing
*/
diff --git a/src/main/java/org/squiddev/cobalt/GlobalRegistry.java b/src/main/java/org/squiddev/cobalt/GlobalRegistry.java
new file mode 100644
index 00000000..0f9f6cc0
--- /dev/null
+++ b/src/main/java/org/squiddev/cobalt/GlobalRegistry.java
@@ -0,0 +1,36 @@
+package org.squiddev.cobalt;
+
+/**
+ * The global registry, a store of Lua values
+ */
+public final class GlobalRegistry {
+ private final LuaTable table = new LuaTable();
+
+ GlobalRegistry() {
+ }
+
+ /**
+ * Get the underlying registry table.
+ *
+ * @return The global debug registry.
+ */
+ public LuaTable get() {
+ return table;
+ }
+
+ /**
+ * Get a subtable in the global {@linkplain #get()} registry table}. If the key exists but is not a table, then
+ * it will be overridden.
+ *
+ * @param name The name of the registry table.
+ * @return The subentry.
+ */
+ public LuaTable getSubTable(LuaString name) {
+ LuaValue value = table.rawget(name);
+ if (value.isTable()) return (LuaTable) value;
+
+ LuaTable newValue = new LuaTable();
+ table.rawset(name, newValue);
+ return newValue;
+ }
+}
diff --git a/src/main/java/org/squiddev/cobalt/LuaState.java b/src/main/java/org/squiddev/cobalt/LuaState.java
index 0c669d66..25124872 100644
--- a/src/main/java/org/squiddev/cobalt/LuaState.java
+++ b/src/main/java/org/squiddev/cobalt/LuaState.java
@@ -28,12 +28,7 @@
import org.squiddev.cobalt.compiler.LuaC;
import org.squiddev.cobalt.debug.DebugHandler;
import org.squiddev.cobalt.debug.DebugHelpers;
-import org.squiddev.cobalt.lib.platform.FileResourceManipulator;
-import org.squiddev.cobalt.lib.platform.ResourceManipulator;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.util.TimeZone;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
@@ -44,16 +39,6 @@
* Global lua state
*/
public final class LuaState {
- /**
- * The active input stream
- */
- public InputStream stdin;
-
- /**
- * The active output stream
- */
- public PrintStream stdout;
-
/**
* The metatable for all strings
*/
@@ -84,31 +69,16 @@ public final class LuaState {
*/
public LuaTable threadMetatable;
- /**
- * Lookup of loaded packages
- */
- public final LuaTable loadedPackages = new LuaTable();
-
- /**
- * The active resource manipulator
- */
- public final ResourceManipulator resourceManipulator;
-
/**
* The compiler for this threstate
*/
- public final LoadState.LuaCompiler compiler;
+ public final LoadState.FunctionFactory compiler;
/**
* The handler for the debugger. Override this for custom debug actions.
*/
public final DebugHandler debug;
- /**
- * The timezone for this state, as used by {@code os}.
- */
- public final TimeZone timezone;
-
/**
* The currently executing thread
*/
@@ -136,29 +106,31 @@ public final class LuaState {
*/
private final ErrorReporter reportError;
+ private final GlobalRegistry registry = new GlobalRegistry();
+
public LuaState() {
this(new LuaState.Builder());
}
private LuaState(Builder builder) {
- stdin = builder.stdin;
- stdout = builder.stdout;
- stringMetatable = builder.stringMetatable;
- booleanMetatable = builder.booleanMetatable;
- numberMetatable = builder.numberMetatable;
- nilMetatable = builder.nilMetatable;
- functionMetatable = builder.functionMetatable;
- threadMetatable = builder.threadMetatable;
- resourceManipulator = builder.resourceManipulator;
compiler = builder.compiler;
debug = builder.debug;
- timezone = builder.timezone;
threader = new YieldThreader(builder.coroutineExecutor);
reportError = builder.reportError;
mainThread = currentThread = new LuaThread(this, new LuaTable());
}
+ /**
+ * Get the global registry, a Lua table used to store Lua values.
+ *
+ * @return The global debug registry.
+ */
+ public GlobalRegistry registry() {
+ return registry;
+ }
+
+
/**
* Abandon this state, instructing any pending thread to terminate.
*/
@@ -247,18 +219,8 @@ public static class Builder {
return thread;
});
- private InputStream stdin = System.in;
- private PrintStream stdout = System.out;
- private LuaTable stringMetatable;
- private LuaTable booleanMetatable;
- private LuaTable numberMetatable;
- private LuaTable nilMetatable;
- private LuaTable functionMetatable;
- private LuaTable threadMetatable;
- private ResourceManipulator resourceManipulator = new FileResourceManipulator();
- private LoadState.LuaCompiler compiler = LuaC.INSTANCE;
+ private LoadState.FunctionFactory compiler = LoadState::interpretedFunction;
private DebugHandler debug = DebugHandler.INSTANCE;
- private TimeZone timezone = TimeZone.getDefault();
private Executor coroutineExecutor = defaultCoroutineExecutor;
private ErrorReporter reportError;
@@ -271,118 +233,13 @@ public LuaState build() {
return new LuaState(this);
}
- /**
- * Set the initial standard input for this Lua state. This defaults to {@link System#in}.
- *
- * @param stdin The new standard input
- * @return This builder
- * @see LuaState#stdin
- */
- public Builder stdin(InputStream stdin) {
- if (stdin == null) throw new NullPointerException("stdin cannot be null");
- this.stdin = stdin;
- return this;
- }
-
- /**
- * Set the initial standard output for this Lua state. This defaults to {@link System#out}.
- *
- * @param stdout The new standard output
- * @return This builder
- * @see LuaState#stdout
- */
- public Builder stdout(PrintStream stdout) {
- if (stdout == null) throw new NullPointerException("stdout cannot be null");
- this.stdout = stdout;
- return this;
- }
-
- /**
- * Set the initial metatable for string values within this Lua State. This defaults to {@code null}.
- *
- * @param metatable The initial metatable
- * @return This builder
- */
- public Builder stringMetatable(LuaTable metatable) {
- stringMetatable = metatable;
- return this;
- }
-
- /**
- * Set the initial metatable for boolean values within this Lua State. This defaults to {@code null}.
- *
- * @param metatable The initial metatable
- * @return This builder
- */
- public Builder booleanMetatable(LuaTable metatable) {
- booleanMetatable = metatable;
- return this;
- }
-
- /**
- * Set the initial metatable for numeric values within this Lua State. This defaults to {@code null}.
- *
- * @param metatable The initial metatable
- * @return This builder
- */
- public Builder numberMetatable(LuaTable metatable) {
- numberMetatable = metatable;
- return this;
- }
-
- /**
- * Set the initial metatable for nil values within this Lua State. This defaults to {@code null}.
- *
- * @param metatable The initial metatable
- * @return This builder
- */
- public Builder nilMetatable(LuaTable metatable) {
- nilMetatable = metatable;
- return this;
- }
-
- /**
- * Set the initial metatable for functions within this Lua State. This defaults to {@code null}.
- *
- * @param metatable The initial metatable
- * @return This builder
- */
- public Builder functionMetatable(LuaTable metatable) {
- functionMetatable = metatable;
- return this;
- }
-
- /**
- * Set the initial metatable for threads within this Lua State. This defaults to {@code null}.
- *
- * @param metatable The initial metatable
- * @return This builder
- */
- public Builder threadMetatable(LuaTable metatable) {
- threadMetatable = metatable;
- return this;
- }
-
- /**
- * Set the resource manipulator that the {@code os} and {@code io} libraries will use. This defaults to a
- * {@link FileResourceManipulator}, which uses the default file system.
- *
- * @param resourceManipulator The new resource manipulator
- * @return This builder
- */
- public Builder resourceManipulator(ResourceManipulator resourceManipulator) {
- if (this.resourceManipulator == null) throw new NullPointerException("resourceManipulator cannot be null");
- this.resourceManipulator = resourceManipulator;
- return this;
- }
-
/**
* Set the compiler for this Lua state. This defaults to using the {@link LuaC} compiler.
*
* @param compiler The new compiler to use
* @return This builder
*/
- public Builder compiler(LoadState.LuaCompiler compiler) {
+ public Builder compiler(LoadState.FunctionFactory compiler) {
if (compiler == null) throw new NullPointerException("compiler cannot be null");
this.compiler = compiler;
return this;
@@ -400,18 +257,6 @@ public Builder debug(DebugHandler debug) {
return this;
}
- /**
- * Set the timezone for this Lua state.
- *
- * @param zone The new timezone
- * @return This builder
- */
- public Builder timezone(TimeZone zone) {
- if (zone == null) throw new NullPointerException("zone cannot be null");
- timezone = zone;
- return this;
- }
-
/**
* Set the coroutine executor for this state.
*
diff --git a/src/main/java/org/squiddev/cobalt/LuaTable.java b/src/main/java/org/squiddev/cobalt/LuaTable.java
index 48fa5bb9..956e6af6 100644
--- a/src/main/java/org/squiddev/cobalt/LuaTable.java
+++ b/src/main/java/org/squiddev/cobalt/LuaTable.java
@@ -24,9 +24,6 @@
*/
package org.squiddev.cobalt;
-import org.squiddev.cobalt.function.LuaFunction;
-import org.squiddev.cobalt.lib.LuaLibrary;
-
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -716,19 +713,6 @@ public LuaValue[] keys() throws LuaError {
return l.toArray(new LuaValue[l.size()]);
}
- /**
- * Load a library instance by setting its environment to {@code this}
- * and calling it, which should initialize the library instance and
- * install itself into this instance.
- *
- * @param state The current lua state
- * @param library The callable {@link LuaFunction} to load into {@code this}
- * @return {@link LuaValue} containing the result of the initialization call.
- */
- public LuaValue load(LuaState state, LuaLibrary library) {
- return library.add(state, this);
- }
-
//region Resizing
/**
diff --git a/src/main/java/org/squiddev/cobalt/LuaThread.java b/src/main/java/org/squiddev/cobalt/LuaThread.java
index 7e1c56a1..c82c3ed5 100644
--- a/src/main/java/org/squiddev/cobalt/LuaThread.java
+++ b/src/main/java/org/squiddev/cobalt/LuaThread.java
@@ -29,7 +29,7 @@
import org.squiddev.cobalt.debug.DebugState;
import org.squiddev.cobalt.function.LuaFunction;
import org.squiddev.cobalt.lib.CoroutineLib;
-import org.squiddev.cobalt.lib.jse.JsePlatform;
+import org.squiddev.cobalt.lib.CoreLibraries;
import java.lang.ref.WeakReference;
import java.util.Objects;
@@ -45,7 +45,7 @@
* A LuaThread is typically created in response to a scripted call to
* {@code coroutine.create()}
*
- * The utility class {@link JsePlatform}
+ * The utility class {@link CoreLibraries}
* sees to it that this initialization is done properly.
* For this reason it is highly recommended to use one of these classes
* when initializing globals.
@@ -55,7 +55,7 @@
* to manage call state, it is possible to yield from anywhere in luaj.
*
* @see LuaValue
- * @see JsePlatform
+ * @see CoreLibraries
* @see CoroutineLib
*/
public class LuaThread extends LuaValue {
diff --git a/src/main/java/org/squiddev/cobalt/LuaValue.java b/src/main/java/org/squiddev/cobalt/LuaValue.java
index 49811f1c..08617840 100644
--- a/src/main/java/org/squiddev/cobalt/LuaValue.java
+++ b/src/main/java/org/squiddev/cobalt/LuaValue.java
@@ -27,7 +27,7 @@
import org.squiddev.cobalt.compiler.LoadState;
import org.squiddev.cobalt.function.LuaClosure;
import org.squiddev.cobalt.function.LuaFunction;
-import org.squiddev.cobalt.lib.jse.JsePlatform;
+import org.squiddev.cobalt.lib.CoreLibraries;
import static org.squiddev.cobalt.Constants.*;
@@ -85,14 +85,14 @@
* }
* For this to work the file must be in the current directory, or in the class path,
* depending on the platform.
- * See {@link JsePlatform} for details.
+ * See {@link CoreLibraries} for details.
*
* In general a {@link LuaError} may be thrown on any operation when the
* types supplied to any operation are illegal from a lua perspective.
* Examples could be attempting to concatenate a NIL value, or attempting arithmetic
* on values that are not number.
*
- * @see JsePlatform
+ * @see CoreLibraries
* @see LoadState
* @see Varargs
*/
@@ -1132,15 +1132,13 @@ public LuaValue getfenv() {
/**
* Set the environment on an object.
*
- * Typically the environment is created once per application via a platform
- * helper method such as {@link JsePlatform#standardGlobals(LuaState)}
* However, any object can serve as an environment if it contains suitable metatag
* values to implement {@link OperationHelper#getTable(LuaState, LuaValue, LuaValue)} to provide the environment
* values.
*
* @param env {@link LuaValue} (typically a {@link LuaTable}) containing the environment.
* @return If the environment could be changed.
- * @see JsePlatform
+ * @see CoreLibraries
*/
public boolean setfenv(LuaTable env) {
return false;
diff --git a/src/main/java/org/squiddev/cobalt/cmd/lua.java b/src/main/java/org/squiddev/cobalt/cmd/lua.java
deleted file mode 100644
index 5bd5836e..00000000
--- a/src/main/java/org/squiddev/cobalt/cmd/lua.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Original Source: Copyright (c) 2009-2011 Luaj.org. All rights reserved.
- * Modifications: Copyright (c) 2015-2020 SquidDev
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package org.squiddev.cobalt.cmd;
-
-import org.squiddev.cobalt.*;
-import org.squiddev.cobalt.compiler.CompileException;
-import org.squiddev.cobalt.compiler.LoadState;
-import org.squiddev.cobalt.function.LuaFunction;
-import org.squiddev.cobalt.lib.LuaLibrary;
-import org.squiddev.cobalt.lib.jse.JsePlatform;
-
-import java.io.*;
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.squiddev.cobalt.Constants.NONE;
-import static org.squiddev.cobalt.ValueFactory.*;
-
-/**
- * org.squiddev.cobalt.cmd.lua command for use in java se environments.
- */
-public class lua {
- private static final String version = Lua._VERSION + "Copyright (c) 2009 Luaj.org.org";
-
- private static final String usage =
- "usage: java -cp luaj-jse.jar org.squiddev.cobalt.cmd.lua [options] [script [args]].\n" +
- "Available options are:\n" +
- " -e stat execute string 'stat'\n" +
- " -l name require library 'name'\n" +
- " -i enter interactive mode after executing 'script'\n" +
- " -v show version information\n" +
- " -n nodebug - do not load debug library by default\n" +
- " -- stop handling options\n" +
- " - execute stdin and stop handling options";
-
- private static void usageExit() {
- System.out.println(usage);
- System.exit(-1);
- }
-
- private static LuaTable _G;
-
- public static void main(String[] args) throws IOException {
-
- // process args
- boolean interactive = (args.length == 0);
- boolean versioninfo = false;
- boolean processing = true;
- List libs = null;
- try {
- // stateful argument processing
- for (int i = 0; i < args.length; i++) {
- if (!processing || !args[i].startsWith("-")) {
- // input file - defer to last stage
- break;
- } else if (args[i].length() <= 1) {
- // input file - defer to last stage
- break;
- } else {
- switch (args[i].charAt(1)) {
- case 'e':
- if (++i >= args.length) {
- usageExit();
- }
- // input script - defer to last stage
- break;
- case 'l':
- if (++i >= args.length) {
- usageExit();
- }
- if (libs == null) libs = new ArrayList<>();
- libs.add(args[i]);
- break;
- case 'i':
- interactive = true;
- break;
- case 'v':
- versioninfo = true;
- break;
- case '-':
- if (args[i].length() > 2) {
- usageExit();
- }
- processing = false;
- break;
- default:
- usageExit();
- break;
- }
- }
- }
-
- // echo version
- if (versioninfo) {
- System.out.println(version);
- }
-
- // new org.squiddev.cobalt.cmd.lua state
- LuaState state = new LuaState();
- _G = JsePlatform.debugGlobals(state);
- for (int i = 0, n = libs != null ? libs.size() : 0; i < n; i++) {
- loadLibrary(state, libs.get(i));
- }
-
- // input script processing
- processing = true;
- for (int i = 0; i < args.length; i++) {
- if (!processing || !args[i].startsWith("-")) {
- processScript(state, new FileInputStream(args[i]), args[i], args, i, false);
- break;
- } else if ("-".equals(args[i])) {
- processScript(state, System.in, "=stdin", args, i, false);
- break;
- } else {
- switch (args[i].charAt(1)) {
- case 'l':
- ++i;
- break;
- case 'e':
- ++i;
- processScript(state, new ByteArrayInputStream(args[i].getBytes()), "string", args, i, false);
- break;
- case '-':
- processing = false;
- break;
- }
- }
- }
-
- if (interactive) {
- interactiveMode(state);
- }
-
- } catch (IOException ioe) {
- System.err.println(ioe.toString());
- System.exit(-2);
- }
- }
-
- private static void loadLibrary(LuaState state, String libname) throws IOException {
- LuaValue slibname = valueOf(libname);
- try {
- // load via plain require
- OperationHelper.noUnwind(state, () ->
- OperationHelper.call(state, OperationHelper.getTable(state, _G, valueOf("require")), slibname));
- } catch (Exception e) {
- try {
- // load as java class
- LuaLibrary v = Class.forName(libname).asSubclass(LuaLibrary.class).newInstance();
- v.add(state, _G);
- } catch (Exception f) {
- throw new IOException("loadLibrary(" + libname + ") failed: " + e + "," + f);
- }
- }
- }
-
- private static void processScript(LuaState state, InputStream script, String chunkname, String[] args, int firstarg, boolean printValue) throws IOException {
- try {
- LuaFunction c;
- try {
- c = LoadState.load(state, script, valueOf(chunkname), _G);
- } finally {
- script.close();
- }
- Varargs scriptargs = (args != null ? setGlobalArg(args, firstarg) : NONE);
- Varargs result = LuaThread.runMain(state, c, scriptargs);
-
- if (printValue && result != NONE) {
- OperationHelper.noUnwind(state, () ->
- OperationHelper.invoke(state, OperationHelper.getTable(state, _G, valueOf("print")), result));
- }
- } catch (CompileException e) {
- System.out.println();
- System.out.println(e.getMessage());
- } catch (LuaError e) {
- System.out.println();
- System.out.println(e.traceback);
- if (e.getCause() != null && e.getCause() != e) e.getCause().printStackTrace(System.out);
- } catch (Exception e) {
- System.out.println();
- e.printStackTrace(System.out);
- }
- }
-
- private static Varargs setGlobalArg(String[] args, int i) {
- LuaTable arg = tableOf();
- LuaValue[] values = new LuaValue[args.length];
- for (int j = 0; j < args.length; j++) {
- arg.rawset(j - i, values[j] = valueOf(args[j]));
- }
- _G.rawset("arg", arg);
- return varargsOf(values);
- }
-
- private static void interactiveMode(LuaState state) throws IOException {
- BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
- while (true) {
- System.out.print("> ");
- System.out.flush();
- String line = reader.readLine();
- if (line == null) {
- return;
- }
- processScript(state, new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0, true);
- }
- }
-}
diff --git a/src/main/java/org/squiddev/cobalt/cmd/luac.java b/src/main/java/org/squiddev/cobalt/cmd/luac.java
deleted file mode 100644
index 6ca2407e..00000000
--- a/src/main/java/org/squiddev/cobalt/cmd/luac.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Original Source: Copyright (c) 2009-2011 Luaj.org. All rights reserved.
- * Modifications: Copyright (c) 2015-2020 SquidDev
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package org.squiddev.cobalt.cmd;
-
-import org.squiddev.cobalt.Lua;
-import org.squiddev.cobalt.LuaState;
-import org.squiddev.cobalt.Print;
-import org.squiddev.cobalt.Prototype;
-import org.squiddev.cobalt.compiler.DumpState;
-import org.squiddev.cobalt.compiler.LuaC;
-import org.squiddev.cobalt.lib.jse.JsePlatform;
-
-import java.io.*;
-
-import static org.squiddev.cobalt.ValueFactory.valueOf;
-
-
-/**
- * Compiler for org.squiddev.cobalt.cmd.lua files to org.squiddev.cobalt.cmd.lua bytecode.
- */
-public class luac {
- private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org";
-
- private static final String usage =
- "usage: java -cp luaj-jse.jar org.squiddev.cobalt.cmd.luac [options] [filenames].\n" +
- "Available options are:\n" +
- " - process stdin\n" +
- " -l list\n" +
- " -o name output to file 'name' (default is \"org.squiddev.cobalt.cmd.luac.out\")\n" +
- " -p parse only\n" +
- " -s strip debug information\n" +
- " -E big endian format for numbers\n" +
- " -i number format 'n', (n=0,1 or 4, default=" + DumpState.NUMBER_FORMAT_DEFAULT + ")\n" +
- " -v show version information\n" +
- " -- stop handling options\n";
-
- private static void usageExit() {
- System.out.println(usage);
- System.exit(-1);
- }
-
- private boolean list = false;
- private String output = "luac.out";
- private boolean parseonly = false;
- private boolean stripdebug = false;
- private boolean littleendian = true;
- private int numberformat = DumpState.NUMBER_FORMAT_DEFAULT;
- private boolean versioninfo = false;
- private boolean processing = true;
-
- public static void main(String[] args) throws IOException {
- new luac(args);
- }
-
- private luac(String[] args) throws IOException {
-
- // process args
- try {
- // get stateful args
- for (int i = 0; i < args.length; i++) {
- if (!processing || !args[i].startsWith("-")) {
- // input file - defer to next stage
- } else if (args[i].length() <= 1) {
- // input file - defer to next stage
- } else {
- switch (args[i].charAt(1)) {
- case 'l':
- list = true;
- break;
- case 'o':
- if (++i >= args.length) {
- usageExit();
- }
- output = args[i];
- break;
- case 'p':
- parseonly = true;
- break;
- case 's':
- stripdebug = true;
- break;
- case 'E':
- littleendian = false;
- break;
- case 'i':
- if (args[i].length() <= 2) {
- usageExit();
- }
- numberformat = Integer.parseInt(args[i].substring(2));
- break;
- case 'v':
- versioninfo = true;
- break;
- case '-':
- if (args[i].length() > 2) {
- usageExit();
- }
- processing = false;
- break;
- default:
- usageExit();
- break;
- }
- }
- }
-
- // echo version
- if (versioninfo) {
- System.out.println(version);
- }
-
- // open output file
-
- // process input files
- OutputStream fos = new FileOutputStream(output);
- try {
- JsePlatform.standardGlobals(new LuaState());
- processing = true;
- for (int i = 0; i < args.length; i++) {
- if (!processing || !args[i].startsWith("-")) {
- processScript(new FileInputStream(args[i]), "@" + args[i], fos);
- } else if (args[i].length() <= 1) {
- processScript(System.in, "=stdin", fos);
- } else {
- switch (args[i].charAt(1)) {
- case 'o':
- ++i;
- break;
- case '-':
- processing = false;
- break;
- }
- }
- }
- } finally {
- fos.close();
- }
-
- } catch (IOException ioe) {
- System.err.println(ioe.toString());
- System.exit(-2);
- }
- }
-
- private void processScript(InputStream script, String chunkname, OutputStream out) throws IOException {
- try {
- // create the chunk
- Prototype chunk = LuaC.compile(script, valueOf(chunkname));
-
- // list the chunk
- if (list) {
- Print.printCode(new PrintWriter(System.out), chunk, false);
- }
-
- // write out the chunk
- if (!parseonly) {
- DumpState.dump(chunk, out, stripdebug, numberformat, littleendian);
- }
-
- } catch (Exception e) {
- e.printStackTrace(System.err);
- } finally {
- script.close();
- }
- }
-}
diff --git a/src/main/java/org/squiddev/cobalt/compiler/BinOpr.java b/src/main/java/org/squiddev/cobalt/compiler/BinOpr.java
index 8955fd2f..1a3bcdce 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/BinOpr.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/BinOpr.java
@@ -31,40 +31,40 @@ enum BinOpr {
this.right = right;
}
- static BinOpr ofToken(int op) {
- switch (op) {
- case '+':
- return ADD;
- case '-':
- return SUB;
- case '*':
- return MUL;
- case '/':
- return DIV;
- case '%':
- return MOD;
- case '^':
- return POW;
- case TK_CONCAT:
- return CONCAT;
- case TK_NE:
- return NE;
- case TK_EQ:
- return EQ;
- case '<':
- return LT;
- case TK_LE:
- return LE;
- case '>':
- return GT;
- case TK_GE:
- return GE;
- case TK_AND:
- return AND;
- case TK_OR:
- return OR;
- default:
- return null;
- }
- }
+ static BinOpr ofToken(int op) {
+ switch (op) {
+ case '+':
+ return ADD;
+ case '-':
+ return SUB;
+ case '*':
+ return MUL;
+ case '/':
+ return DIV;
+ case '%':
+ return MOD;
+ case '^':
+ return POW;
+ case TK_CONCAT:
+ return CONCAT;
+ case TK_NE:
+ return NE;
+ case TK_EQ:
+ return EQ;
+ case '<':
+ return LT;
+ case TK_LE:
+ return LE;
+ case '>':
+ return GT;
+ case TK_GE:
+ return GE;
+ case TK_AND:
+ return AND;
+ case TK_OR:
+ return OR;
+ default:
+ return null;
+ }
+ }
}
diff --git a/src/main/java/org/squiddev/cobalt/compiler/DumpState.java b/src/main/java/org/squiddev/cobalt/compiler/BytecodeDumper.java
similarity index 90%
rename from src/main/java/org/squiddev/cobalt/compiler/DumpState.java
rename to src/main/java/org/squiddev/cobalt/compiler/BytecodeDumper.java
index 09ff798e..52044ada 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/DumpState.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/BytecodeDumper.java
@@ -34,13 +34,7 @@
import java.io.IOException;
import java.io.OutputStream;
-public class DumpState {
-
- /**
- * mark for precompiled code (\033Lua)
- */
- public static final String LUA_SIGNATURE = "\033Lua";
-
+public class BytecodeDumper {
/**
* for header of binary files -- this is Lua 5.1
*/
@@ -56,11 +50,6 @@ public class DumpState {
*/
public static final int LUAC_HEADERSIZE = 12;
- /**
- * expected lua header bytes
- */
- private static final byte[] LUAC_HEADER_SIGNATURE = {'\033', 'L', 'u', 'a'};
-
/**
* set true to allow integer compilation
*/
@@ -94,14 +83,12 @@ public class DumpState {
private static final int SIZEOF_SIZET = 4;
private static final int SIZEOF_INSTRUCTION = 4;
- DataOutputStream writer;
- boolean strip;
- int status;
+ final DataOutputStream writer;
+ final boolean strip;
- public DumpState(OutputStream w, boolean strip) {
+ public BytecodeDumper(OutputStream w, boolean strip) {
this.writer = new DataOutputStream(w);
this.strip = strip;
- this.status = 0;
}
void dumpBlock(final byte[] b, int size) throws IOException {
@@ -244,7 +231,7 @@ void dumpFunction(final Prototype f, final LuaString string) throws IOException
}
void dumpHeader() throws IOException {
- writer.write(LUAC_HEADER_SIGNATURE);
+ writer.write(LoadState.LUA_SIGNATURE);
writer.write(LUAC_VERSION);
writer.write(LUAC_FORMAT);
writer.write(IS_LITTLE_ENDIAN ? 1 : 0);
@@ -258,11 +245,10 @@ void dumpHeader() throws IOException {
/*
* Dump Lua function as precompiled chunk
*/
- public static int dump(Prototype f, OutputStream w, boolean strip) throws IOException {
- DumpState D = new DumpState(w, strip);
+ public static void dump(Prototype f, OutputStream w, boolean strip) throws IOException {
+ BytecodeDumper D = new BytecodeDumper(w, strip);
D.dumpHeader();
D.dumpFunction(f, null);
- return D.status;
}
/**
@@ -271,11 +257,10 @@ public static int dump(Prototype f, OutputStream w, boolean strip) throws IOExce
* @param stripDebug true to strip debugging info, false otherwise
* @param numberFormat one of NUMBER_FORMAT_FLOATS_OR_DOUBLES, NUMBER_FORMAT_INTS_ONLY, NUMBER_FORMAT_NUM_PATCH_INT32
* @param littleendian true to use little endian for numbers, false for big endian
- * @return 0 if dump succeeds
* @throws IOException On stream write errors
* @throws IllegalArgumentException if the number format it not supported
*/
- public static int dump(Prototype f, OutputStream w, boolean stripDebug, int numberFormat, boolean littleendian) throws IOException {
+ public static void dump(Prototype f, OutputStream w, boolean stripDebug, int numberFormat, boolean littleendian) throws IOException {
switch (numberFormat) {
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
case NUMBER_FORMAT_INTS_ONLY:
@@ -284,12 +269,11 @@ public static int dump(Prototype f, OutputStream w, boolean stripDebug, int numb
default:
throw new IllegalArgumentException("number format not supported: " + numberFormat);
}
- DumpState D = new DumpState(w, stripDebug);
+ BytecodeDumper D = new BytecodeDumper(w, stripDebug);
D.IS_LITTLE_ENDIAN = littleendian;
D.NUMBER_FORMAT = numberFormat;
D.SIZEOF_LUA_NUMBER = (numberFormat == NUMBER_FORMAT_INTS_ONLY ? 4 : 8);
D.dumpHeader();
D.dumpFunction(f, null);
- return D.status;
}
}
diff --git a/src/main/java/org/squiddev/cobalt/compiler/BytecodeLoader.java b/src/main/java/org/squiddev/cobalt/compiler/BytecodeLoader.java
index 6c069d52..2342fc97 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/BytecodeLoader.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/BytecodeLoader.java
@@ -36,7 +36,7 @@
/**
* Parser for bytecode
*/
-public final class BytecodeLoader {
+final class BytecodeLoader {
/**
* format corresponding to non-number-patched lua, all numbers are floats or doubles
*/
@@ -83,8 +83,7 @@ public final class BytecodeLoader {
* @param stream The stream to read from
*/
public BytecodeLoader(InputStream stream) {
-
- this.is = new DataInputStream(stream);
+ is = new DataInputStream(stream);
}
private static final LuaValue[] NOVALUES = {};
diff --git a/src/main/java/org/squiddev/cobalt/compiler/CompileException.java b/src/main/java/org/squiddev/cobalt/compiler/CompileException.java
index 98a33312..150efa50 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/CompileException.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/CompileException.java
@@ -30,18 +30,7 @@
public class CompileException extends Exception {
private static final long serialVersionUID = 5563020350887073386L;
- public CompileException() {
- }
-
- public CompileException(String message) {
+ CompileException(String message) {
super(message);
}
-
- public CompileException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public CompileException(Throwable cause) {
- super(cause);
- }
}
diff --git a/src/main/java/org/squiddev/cobalt/compiler/FuncState.java b/src/main/java/org/squiddev/cobalt/compiler/FuncState.java
index 395c04f5..0dee7417 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/FuncState.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/FuncState.java
@@ -44,7 +44,7 @@
* This largely mirrors the same structure in {@code lparser.h}, but also handles emitting code (defined in lcode.h
* in PUC Lua).
*/
-class FuncState {
+final class FuncState {
static class UpvalueDesc {
final LuaString name;
final ExpKind kind;
diff --git a/src/main/java/org/squiddev/cobalt/compiler/IntPtr.java b/src/main/java/org/squiddev/cobalt/compiler/IntPtr.java
index 7d72ae3a..d421a288 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/IntPtr.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/IntPtr.java
@@ -24,7 +24,7 @@
*/
package org.squiddev.cobalt.compiler;
-class IntPtr {
+final class IntPtr {
int value;
IntPtr() {
diff --git a/src/main/java/org/squiddev/cobalt/compiler/Lex.java b/src/main/java/org/squiddev/cobalt/compiler/Lex.java
index 5a60a4dd..7c22fb43 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/Lex.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/Lex.java
@@ -19,7 +19,7 @@
*
* This largely follows the structure and implementation of llex.c.
*/
-class Lex {
+final class Lex {
private static final int EOZ = -1;
static final int MAX_INT = Integer.MAX_VALUE - 2;
diff --git a/src/main/java/org/squiddev/cobalt/compiler/LoadState.java b/src/main/java/org/squiddev/cobalt/compiler/LoadState.java
index 4b3b691d..b1cab4a1 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/LoadState.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/LoadState.java
@@ -31,7 +31,7 @@
import org.squiddev.cobalt.function.LuaClosure;
import org.squiddev.cobalt.function.LuaFunction;
import org.squiddev.cobalt.function.LuaInterpretedFunction;
-import org.squiddev.cobalt.lib.jse.JsePlatform;
+import org.squiddev.cobalt.lib.CoreLibraries;
import java.io.IOException;
import java.io.InputStream;
@@ -40,24 +40,24 @@
/**
* Class to manage loading of {@link Prototype} instances.
- *
+ *
* The {@link LoadState} class exposes one main function,
* namely {@link #load(LuaState, InputStream, LuaString, LuaTable)},
* to be used to load code from a particular input stream.
- *
+ *
* A simple pattern for loading and executing code is
*
- * This should work regardless of which {@link LuaCompiler}
+ * This should work regardless of which {@link FunctionFactory}
* has been installed.
- *
+ *
* Prior to loading code, a compiler should be installed.
+ *
+ * By default, when using {@link CoreLibraries} to construct globals, the {@link LuaC} compiler is installed.
*
- * By default, when using {@link JsePlatform} to construct globals, the {@link LuaC} compiler is installed.
- *
- * @see LuaCompiler
+ * @see FunctionFactory
* @see LuaClosure
* @see LuaFunction
* @see LoadState#load(LuaState, InputStream, LuaString, LuaTable)
@@ -65,39 +65,40 @@
*/
public final class LoadState {
/**
- * Interface for the compiler, if it is installed.
- *
- * See the {@link LuaClosure} documentation for examples of how to use the compiler.
- *
- * @see LuaClosure
- * @see #load(InputStream, LuaString, LuaString, LuaTable)
+ * Signature byte indicating the file is a compiled binary chunk
*/
- public interface LuaCompiler {
+ static final byte[] LUA_SIGNATURE = {27, 'L', 'u', 'a'};
+ /**
+ * Name for compiled chunks
+ */
+ private static final LuaString SOURCE_BINARY_STRING = valueOf("=?");
+
+ /**
+ * Construct our standard Lua function.
+ */
+ public interface FunctionFactory {
/**
- * Load into a Closure or LuaFunction from a Stream and initializes the environment
+ * Create a {@link LuaClosure} from a {@link Prototype} and environment table.
*
- * @param stream Stream to read
- * @param filename Name of chunk
- * @param mode
- * @param env Environment to load
+ * @param prototype The function prototype
+ * @param env The function's environment.
* @return The loaded function
- * @throws IOException On stream read error
- * @throws CompileException If the stream cannot be loaded.
*/
- LuaClosure load(InputStream stream, LuaString filename, LuaString mode, LuaTable env) throws IOException, CompileException;
+ LuaClosure load(Prototype prototype, LuaTable env);
}
- /**
- * Signature byte indicating the file is a compiled binary chunk
- */
- private static final byte[] LUA_SIGNATURE = {27, 'L', 'u', 'a'};
+ private LoadState() {
+ }
/**
- * Name for compiled chunks
+ * A basic {@link FunctionFactory} which loads into
*/
- public static final LuaString SOURCE_BINARY_STRING = valueOf("=?");
-
+ public static LuaClosure interpretedFunction(Prototype prototype, LuaTable env) {
+ LuaInterpretedFunction closure = new LuaInterpretedFunction(prototype, env);
+ closure.nilUpvalues();
+ return closure;
+ }
public static LuaClosure load(LuaState state, InputStream stream, String name, LuaTable env) throws IOException, CompileException {
return load(state, stream, valueOf(name), env);
@@ -120,43 +121,7 @@ public static LuaClosure load(LuaState state, InputStream stream, LuaString name
}
public static LuaClosure load(LuaState state, InputStream stream, LuaString name, LuaString mode, LuaTable env) throws IOException, CompileException {
- if (state.compiler != null) return state.compiler.load(stream, name, mode, env);
-
- int firstByte = stream.read();
- if (firstByte != LUA_SIGNATURE[0]) throw new CompileException("no compiler");
- checkMode(mode, "binary");
-
- Prototype p = loadBinaryChunk(firstByte, stream, name);
- LuaInterpretedFunction closure = new LuaInterpretedFunction(p, env);
- closure.nilUpvalues();
- return closure;
- }
-
- /**
- * Load lua thought to be a binary chunk from its first byte from an input stream.
- *
- * @param firstByte the first byte of the input stream
- * @param stream InputStream to read, after having read the first byte already
- * @param name Name to apply to the loaded chunk
- * @return {@link Prototype} that was loaded
- * @throws IllegalArgumentException If the signature is bac
- * @throws IOException If an IOException occurs
- * @throws CompileException If the stream cannot be loaded.
- */
- public static Prototype loadBinaryChunk(int firstByte, InputStream stream, LuaString name) throws IOException, CompileException {
- name = getSourceName(name);
- // check rest of signature
- if (firstByte != LUA_SIGNATURE[0]
- || stream.read() != LUA_SIGNATURE[1]
- || stream.read() != LUA_SIGNATURE[2]
- || stream.read() != LUA_SIGNATURE[3]) {
- throw new IllegalArgumentException("bad signature");
- }
-
- // load file as a compiled chunk
- BytecodeLoader s = new BytecodeLoader(stream);
- s.loadHeader();
- return s.loadFunction(name);
+ return state.compiler.load(LuaC.compile(stream, name, mode), env);
}
/**
diff --git a/src/main/java/org/squiddev/cobalt/compiler/LuaC.java b/src/main/java/org/squiddev/cobalt/compiler/LuaC.java
index cfd47b86..6575de83 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/LuaC.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/LuaC.java
@@ -25,13 +25,14 @@
package org.squiddev.cobalt.compiler;
-import org.squiddev.cobalt.*;
-import org.squiddev.cobalt.compiler.LoadState.LuaCompiler;
-import org.squiddev.cobalt.function.LuaClosure;
-import org.squiddev.cobalt.function.LuaFunction;
+import org.squiddev.cobalt.Lua;
+import org.squiddev.cobalt.LuaString;
+import org.squiddev.cobalt.LuaValue;
+import org.squiddev.cobalt.Prototype;
+import org.squiddev.cobalt.compiler.LoadState.FunctionFactory;
import org.squiddev.cobalt.function.LuaInterpretedFunction;
import org.squiddev.cobalt.lib.BaseLib;
-import org.squiddev.cobalt.lib.jse.JsePlatform;
+import org.squiddev.cobalt.lib.CoreLibraries;
import java.io.IOException;
import java.io.InputStream;
@@ -48,12 +49,12 @@
* and optionaly instantiates a {@link LuaInterpretedFunction} around the result
* using a user-supplied environment.
*
- * Implements the {@link LuaCompiler} interface for loading
+ * Implements the {@link FunctionFactory} interface for loading
* initialized chunks, which is an interface common to
* lua bytecode compiling and java bytecode compiling.
*
* The {@link LuaC} compiler is installed by default by the
- * {@link JsePlatform} class
+ * {@link CoreLibraries} class
* so in the following example, the default {@link LuaC} compiler
* will be used:
*
*
- * @see LuaCompiler
- * @see JsePlatform
+ * @see FunctionFactory
+ * @see CoreLibraries
* @see BaseLib
* @see LuaValue
- * @see LuaCompiler
+ * @see FunctionFactory
* @see Prototype
*/
-public class LuaC implements LuaCompiler {
- public static final LuaC INSTANCE = new LuaC();
-
+public class LuaC {
protected static void _assert(boolean b) throws CompileException {
if (!b) {
// So technically this should fire a runtime exception but...
@@ -135,14 +134,30 @@ private LuaC() {
}
/**
- * Load into a Closure or LuaFunction, with the supplied initial environment
+ * Load lua thought to be a binary chunk from its first byte from an input stream.
+ *
+ * @param firstByte the first byte of the input stream
+ * @param stream InputStream to read, after having read the first byte already
+ * @param name Name to apply to the loaded chunk
+ * @return {@link Prototype} that was loaded
+ * @throws IllegalArgumentException If the signature is bac
+ * @throws IOException If an IOException occurs
+ * @throws CompileException If the stream cannot be loaded.
*/
- @Override
- public LuaClosure load(InputStream stream, LuaString name, LuaString mode, LuaTable env) throws IOException, CompileException {
- Prototype p = compile(stream, name, mode);
- LuaInterpretedFunction closure = new LuaInterpretedFunction(p, env);
- closure.nilUpvalues();
- return closure;
+ public static Prototype loadBinaryChunk(int firstByte, InputStream stream, LuaString name) throws IOException, CompileException {
+ name = LoadState.getSourceName(name);
+ // check rest of signature
+ if (firstByte != LoadState.LUA_SIGNATURE[0]
+ || stream.read() != LoadState.LUA_SIGNATURE[1]
+ || stream.read() != LoadState.LUA_SIGNATURE[2]
+ || stream.read() != LoadState.LUA_SIGNATURE[3]) {
+ throw new IllegalArgumentException("bad signature");
+ }
+
+ // load file as a compiled chunk
+ BytecodeLoader s = new BytecodeLoader(stream);
+ s.loadHeader();
+ return s.loadFunction(name);
}
public static Prototype compile(InputStream stream, String name) throws IOException, CompileException {
@@ -166,11 +181,11 @@ public static Prototype compile(InputStream stream, LuaString name, LuaString mo
int firstByte = stream.read();
if (firstByte == '\033') {
checkMode(mode, "binary");
- return LoadState.loadBinaryChunk(firstByte, stream, name);
+ return loadBinaryChunk(firstByte, stream, name);
} else {
checkMode(mode, "text");
try {
- return luaY_parser(firstByte, stream, name);
+ return loadTextChunk(firstByte, stream, name);
} catch (UncheckedIOException e) {
throw e.getCause();
}
@@ -180,8 +195,8 @@ public static Prototype compile(InputStream stream, LuaString name, LuaString mo
/**
* Parse the input
*/
- private static Prototype luaY_parser(int firstByte, InputStream z, LuaString name) throws CompileException {
- Parser lexstate = new Parser(z, firstByte, name);
+ private static Prototype loadTextChunk(int firstByte, InputStream stream, LuaString name) throws CompileException {
+ Parser lexstate = new Parser(stream, firstByte, name);
FuncState funcstate = lexstate.openFunc();
funcstate.varargFlags = Lua.VARARG_ISVARARG; /* main func. is always vararg */
@@ -193,8 +208,4 @@ private static Prototype luaY_parser(int firstByte, InputStream z, LuaString nam
LuaC._assert(lexstate.fs == null);
return prototype;
}
-
- public LuaFunction load(Prototype p, LuaTable env) {
- return new LuaInterpretedFunction(p, env);
- }
}
diff --git a/src/main/java/org/squiddev/cobalt/compiler/Parser.java b/src/main/java/org/squiddev/cobalt/compiler/Parser.java
index b0870815..793b26c9 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/Parser.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/Parser.java
@@ -38,7 +38,7 @@
*
* This largely follows the structure and implementation of lparser.c.
*/
-class Parser {
+final class Parser {
private static final int LUAI_MAXCCALLS = 200;
private static final boolean LUA_COMPAT_VARARG = true;
diff --git a/src/main/java/org/squiddev/cobalt/compiler/UnOpr.java b/src/main/java/org/squiddev/cobalt/compiler/UnOpr.java
index 6c269884..e131bd2c 100644
--- a/src/main/java/org/squiddev/cobalt/compiler/UnOpr.java
+++ b/src/main/java/org/squiddev/cobalt/compiler/UnOpr.java
@@ -13,16 +13,16 @@ enum UnOpr {
*/
static final int PRIORITY = 8;
- static UnOpr ofToken(int op) {
- switch (op) {
- case TK_NOT:
- return NOT;
- case '-':
- return MINUS;
- case '#':
- return LEN;
- default:
- return null;
- }
- }
+ static UnOpr ofToken(int op) {
+ switch (op) {
+ case TK_NOT:
+ return NOT;
+ case '-':
+ return MINUS;
+ case '#':
+ return LEN;
+ default:
+ return null;
+ }
+ }
}
diff --git a/src/main/java/org/squiddev/cobalt/function/LibFunction.java b/src/main/java/org/squiddev/cobalt/function/LibFunction.java
index 2efaca02..d9cfc9fd 100644
--- a/src/main/java/org/squiddev/cobalt/function/LibFunction.java
+++ b/src/main/java/org/squiddev/cobalt/function/LibFunction.java
@@ -24,14 +24,13 @@
*/
package org.squiddev.cobalt.function;
+import org.squiddev.cobalt.Constants;
import org.squiddev.cobalt.LuaState;
import org.squiddev.cobalt.LuaTable;
import org.squiddev.cobalt.LuaValue;
import org.squiddev.cobalt.lib.BaseLib;
import org.squiddev.cobalt.lib.TableLib;
-import java.util.function.Supplier;
-
/**
* Subclass of {@link LuaFunction} common to Java functions exposed to lua.
*
@@ -100,7 +99,7 @@
* data it needs to and place it into the environment if needed.
* In this case, it creates two function, 'sinh', and 'cosh', and puts
* them into a global table called 'hyperbolic.'
- * It placed the library table into the globals via the {@link #env}
+ * It placed the library table into the globals via the {@link #getfenv()}
* local variable which corresponds to the globals that apply when the
* library is loaded.
*
@@ -130,20 +129,12 @@
* such as {@link BaseLib} or {@link TableLib} for other examples.
*/
public abstract class LibFunction extends LuaFunction {
-
- /**
- * User-defined opcode to differentiate between instances of the library function class.
- *
- * Subclass will typicall switch on this value to provide the specific behavior for each function.
- */
- protected int opcode;
-
/**
* The common name for this function, useful for debugging.
*
* Binding functions initialize this to the name to which it is bound.
*/
- protected String name;
+ String name;
/**
* Default constructor for use by subclasses
@@ -156,22 +147,8 @@ public String debugName() {
return name != null ? name : super.toString();
}
- /**
- * Bind a set of library functions.
- *
- * An array of names is provided, and the first name is bound
- * with opcode = 0, second with 1, etc.
- *
- * @param env The environment to apply to each bound function
- * @param factory The factory to provide a new instance each time
- * @param names Array of function names
- */
- public static void bind(LuaTable env, Supplier factory, String[] names) {
- for (int i = 0; i < names.length; i++) {
- LibFunction f = factory.get();
- f.opcode = i;
- f.name = names[i];
- env.rawset(f.name, f);
- }
+ public static void setGlobalLibrary(LuaState state, LuaTable env, String name, LuaValue library) {
+ env.rawset(name, library);
+ state.registry().getSubTable(Constants.LOADED).rawset(name, library);
}
}
diff --git a/src/main/java/org/squiddev/cobalt/function/LuaInterpretedFunction.java b/src/main/java/org/squiddev/cobalt/function/LuaInterpretedFunction.java
index 876a9ac6..9806c7e1 100644
--- a/src/main/java/org/squiddev/cobalt/function/LuaInterpretedFunction.java
+++ b/src/main/java/org/squiddev/cobalt/function/LuaInterpretedFunction.java
@@ -31,6 +31,8 @@
import org.squiddev.cobalt.debug.DebugHandler;
import org.squiddev.cobalt.debug.DebugState;
+import java.io.InputStream;
+
import static org.squiddev.cobalt.debug.DebugFrame.*;
import static org.squiddev.cobalt.function.LuaInterpreter.*;
@@ -43,11 +45,11 @@
* There are three main ways {@link LuaInterpretedFunction} instances are created:
*
*
Construct an instance using {@link #LuaInterpretedFunction(Prototype, LuaTable)}
- *
Construct it indirectly by loading a chunk via {@link LoadState.LuaCompiler#load(java.io.InputStream, LuaString, LuaString, LuaTable)}
+ *
Construct it indirectly by loading a chunk via {@link LoadState#load(LuaState, InputStream, String, LuaTable)}
*
Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode processing
*
*
- * To construct it directly, the {@link Prototype} is typically created via a compiler such as {@link LuaC}:
+ * To construct it directly, the {@link Prototype} is typically created via {@linkplain LoadState the compiler}:
*
{@code
* InputStream is = new ByteArrayInputStream("print('hello,world').getBytes());
* Prototype p = LuaC.INSTANCE.compile(is, "script");
@@ -56,7 +58,7 @@
* }
*
* To construct it indirectly, the {@link LuaC} compiler may be used,
- * which implements the {@link LoadState.LuaCompiler} interface:
+ * which implements the {@link LoadState.FunctionFactory} interface:
*
{@code
* LuaFunction f = LuaC.INSTANCE.load(is, "script", _G);
* }
- * This contains all library functions listed as "basic functions" in the lua documentation for JME.
- * The functions dofile and loadfile use the
- * {@link LuaState#resourceManipulator} instance to find resource files.
- * The default loader chain in {@link PackageLib} will use these as well.
- *
- * This is a direct port of the corresponding library in C.
+ * The basic global libraries in the Lua runtime.
*
- * @see ResourceManipulator
+ * @see ResourceLoader
* @see LibFunction
- * @see JsePlatform
+ * @see CoreLibraries
* @see http://www.lua.org/manual/5.1/manual.html#5.1
*/
-public class BaseLib implements LuaLibrary {
- private static final LuaString STDIN_STR = valueOf("=stdin");
+public class BaseLib {
private static final LuaString FUNCTION_STR = valueOf("function");
private static final LuaString LOAD_MODE = valueOf("bt");
private LuaValue next;
private LuaValue inext;
- private static final String[] LIBR_KEYS = {
- "pcall", // (f, arg1, ...) -> status, result1, ...
- "xpcall", // (f, err) -> result1, ...
- "load", // ( func [,chunkname] ) -> chunk | nil, msg
- };
-
- @Override
- public LuaValue add(LuaState state, LuaTable env) {
+ public void add(LuaTable env) {
env.rawset("_G", env);
- env.rawset("_VERSION", valueOf(Lua._VERSION));
+ env.rawset("_VERSION", valueOf("Lua 5.1"));
RegisteredFunction.bind(env, new RegisteredFunction[]{
- RegisteredFunction.of("collectgarbage", BaseLib::collectgarbage),
RegisteredFunction.of("error", BaseLib::error),
RegisteredFunction.ofV("setfenv", BaseLib::setfenv),
RegisteredFunction.ofV("assert", BaseLib::assert_),
- RegisteredFunction.ofV("dofile", BaseLib::dofile),
RegisteredFunction.ofV("getfenv", BaseLib::getfenv),
RegisteredFunction.ofV("getmetatable", BaseLib::getmetatable),
- RegisteredFunction.ofV("loadfile", BaseLib::loadfile),
RegisteredFunction.ofV("loadstring", BaseLib::loadstring),
- RegisteredFunction.ofV("print", BaseLib::print),
RegisteredFunction.ofV("select", BaseLib::select),
- RegisteredFunction.ofV("unpack", BaseLib::unpack),
RegisteredFunction.ofV("type", BaseLib::type),
RegisteredFunction.ofV("rawequal", BaseLib::rawequal),
RegisteredFunction.ofV("rawget", BaseLib::rawget),
@@ -98,35 +76,14 @@ public LuaValue add(LuaState state, LuaTable env) {
RegisteredFunction.ofV("ipairs", this::ipairs),
RegisteredFunction.ofV("rawlen", BaseLib::rawlen),
RegisteredFunction.ofV("next", BaseLib::next),
+ RegisteredFunction.ofFactory("pcall", PCall::new),
+ RegisteredFunction.ofFactory("xpcall", XpCall::new),
+ RegisteredFunction.ofFactory("load", Load::new),
});
- LibFunction.bind(env, BaseLibR::new, LIBR_KEYS);
// remember next, and inext for use in pairs and ipairs
next = env.rawget("next");
inext = RegisteredFunction.ofV("inext", BaseLib::inext).create();
-
- env.rawset("_VERSION", valueOf("Lua 5.1"));
-
- return env;
- }
-
- private static LuaValue collectgarbage(LuaState state, LuaValue arg1, LuaValue arg2) throws LuaError {
- // collectgarbage( opt [,arg] ) -> value
- String s = arg1.optString("collect");
- switch (s) {
- case "collect":
- System.gc();
- return Constants.ZERO;
- case "count":
- Runtime rt = Runtime.getRuntime();
- long used = rt.totalMemory() - rt.freeMemory();
- return valueOf(used / 1024.);
- case "step":
- System.gc();
- return Constants.TRUE;
- default:
- throw ErrorFactory.argError(1, "invalid option");
- }
}
private static LuaValue error(LuaState state, LuaValue arg1, LuaValue arg2) throws LuaError {
@@ -169,17 +126,6 @@ private static Varargs assert_(LuaState state, Varargs args) throws LuaError {
return args;
}
- private static Varargs dofile(LuaState state, Varargs args) throws LuaError, UnwindThrowable {
- // dofile( filename ) -> result1, ...
- Varargs v = args.isNil(1) ?
- BaseLib.loadStream(state, state.stdin, STDIN_STR) :
- BaseLib.loadFile(state, args.arg(1).checkString());
- if (v.isNil(1)) {
- throw new LuaError(v.arg(2).toString());
- } else {
- return OperationHelper.invoke(state, v.first(), Constants.NONE);
- }
- }
private static Varargs getfenv(LuaState state, Varargs args) throws LuaError {
// getfenv( [f] ) -> env
@@ -197,34 +143,12 @@ private static Varargs getmetatable(LuaState state, Varargs args) throws LuaErro
return mt != null ? mt.rawget(Constants.METATABLE).optValue(mt) : Constants.NIL;
}
- private static Varargs loadfile(LuaState state, Varargs args) throws LuaError {
- // loadfile( [filename] ) -> chunk | nil, msg
- return args.isNil(1) ?
- BaseLib.loadStream(state, state.stdin, STDIN_STR) :
- BaseLib.loadFile(state, args.arg(1).checkString());
- }
-
private static Varargs loadstring(LuaState state, Varargs args) throws LuaError {
// loadstring( string [,chunkname] ) -> chunk | nil, msg
LuaString script = args.arg(1).checkLuaString();
return BaseLib.loadStream(state, script.toInputStream(), args.arg(2).optLuaString(script));
}
- private static Varargs print(LuaState state, Varargs args) throws LuaError {
- // print(...) -> void
- return noUnwind(state, () -> {
- LuaValue tostring = OperationHelper.getTable(state, state.getCurrentThread().getfenv(), valueOf("tostring"));
- for (int i = 1, n = args.count(); i <= n; i++) {
- if (i > 1) state.stdout.write('\t');
- LuaString s = OperationHelper.call(state, tostring, args.arg(i)).strvalue();
- int z = s.indexOf((byte) 0, 0);
- state.stdout.write(s.bytes, s.offset, z >= 0 ? z : s.length);
- }
- state.stdout.println();
- return Constants.NONE;
- });
- }
-
private static Varargs select(LuaState state, Varargs args) throws LuaError {
// select(f, ...) -> value1, ...
int n = args.count() - 1;
@@ -234,24 +158,6 @@ private static Varargs select(LuaState state, Varargs args) throws LuaError {
return args.subargs(i < 0 ? n + i + 2 : i + 1);
}
- private static Varargs unpack(LuaState state, Varargs args) throws LuaError {
- // unpack(list [,i [,j]]) -> result1, ...
- int na = args.count();
- LuaTable t = args.arg(1).checkTable();
- int n = t.length();
- int i = na >= 2 ? args.arg(2).optInteger(1) : 1;
- int j = na >= 3 ? args.arg(3).optInteger(n) : n;
- n = j - i + 1;
- if (n < 0) return Constants.NONE;
- if (n == 1) return t.rawget(i);
- if (n == 2) return varargsOf(t.rawget(i), t.rawget(j));
- LuaValue[] v = new LuaValue[n];
- for (int k = 0; k < n; k++) {
- v[k] = t.rawget(i + k);
- }
- return varargsOf(v);
- }
-
private static Varargs type(LuaState state, Varargs args) throws LuaError {
// type(v) -> value
return valueOf(args.checkValue(1).typeName());
@@ -348,93 +254,95 @@ private static Varargs inext(LuaState state, Varargs args) throws LuaError {
return args.arg(1).checkTable().inext(args.arg(2));
}
- private static class BaseLibR extends ResumableVarArgFunction {
+ // pcall(f, arg1, ...) -> status, result1, ...
+ private static class PCall extends ResumableVarArgFunction {
@Override
protected Varargs invoke(LuaState state, DebugFrame di, Varargs args) throws LuaError, UnwindThrowable {
- switch (opcode) {
- case 0: // "pcall", // (f, arg1, ...) -> status, result1, ...
- return pcall(state, di, args.checkValue(1), args.subargs(2), null);
- case 1: // "xpcall", // (f, err) -> result1, ...
- return pcall(state, di, args.checkValue(1), Constants.NONE, args.checkValue(2));
-
- case 2: // "load", // ( func|str [,chunkname[, mode[, env]]] ) -> chunk | nil, msg
- {
- LuaValue scriptGen = args.arg(1);
- LuaString chunkName = args.arg(2).optLuaString(null);
- LuaString mode = args.arg(3).optLuaString(LOAD_MODE);
- LuaTable funcEnv = args.arg(4).optTable(state.getCurrentThread().getfenv());
-
- // If we're a string, load as normal
- LuaValue script = scriptGen.toLuaString();
- if (!script.isNil()) {
- try {
- return LoadState.load(state, ((LuaString) script).toInputStream(), chunkName == null ? (LuaString) script : chunkName, mode, funcEnv);
- } catch (Exception e) {
- return varargsOf(Constants.NIL, LuaError.getMessage(e));
- }
- }
+ return pcallInit(state, di, args.checkValue(1), args.subargs(2), null);
+ }
- LuaFunction function = scriptGen.checkFunction();
- Varargs result = pcall(state, di, new ZeroArgFunction() {
- @Override
- public LuaValue call(LuaState state) throws LuaError {
- try {
- InputStream stream = new StringInputStream(state, function);
- return LoadState.load(state, stream, chunkName == null ? FUNCTION_STR : chunkName, mode, funcEnv);
- } catch (Exception e) {
- throw LuaError.wrapMessage(e);
- }
- }
- }, Constants.NONE, state.getCurrentThread().getErrorFunc());
-
- if (result.first().toBoolean()) {
- return result.arg(2);
- } else {
- return varargsOf(Constants.NIL, result.arg(2));
- }
- }
- default:
- return Constants.NONE;
- }
+ @Override
+ protected Varargs resumeThis(LuaState state, PCallState info, Varargs value) {
+ pcallFinishSuccess(state, info);
+ return info.errored ? varargsOf(Constants.FALSE, value.first()) : varargsOf(Constants.TRUE, value);
}
@Override
- protected Varargs resumeThis(LuaState state, PCallState pState, Varargs value) {
- state.getCurrentThread().setErrorFunc(pState.oldErrorFunc);
+ protected Varargs resumeErrorThis(LuaState state, PCallState object, LuaError error) throws UnwindThrowable {
+ LuaValue result = pcallFinishError(state, object, error);
+ return varargsOf(Constants.FALSE, result);
+ }
+ }
- if (pState.errored) closeUntil(state, pState.frame);
- return finish(pState, value);
+ // xpcall(f, err) -> result1, ...
+ private static class XpCall extends ResumableVarArgFunction {
+ @Override
+ protected Varargs invoke(LuaState state, DebugFrame di, Varargs args) throws LuaError, UnwindThrowable {
+ return pcallInit(state, di, args.checkValue(1), Constants.NONE, args.checkValue(2));
}
@Override
- public Varargs resumeErrorThis(LuaState state, PCallState pState, LuaError error) throws UnwindThrowable {
- LuaValue value;
- if (pState.errored) {
- value = valueOf("error in error handling");
+ protected Varargs resumeThis(LuaState state, PCallState info, Varargs value) {
+ pcallFinishSuccess(state, info);
+ return info.errored ? varargsOf(Constants.FALSE, value.first()) : varargsOf(Constants.TRUE, value);
+ }
+
+ @Override
+ protected Varargs resumeErrorThis(LuaState state, PCallState object, LuaError error) throws UnwindThrowable {
+ LuaValue result = pcallFinishError(state, object, error);
+ return varargsOf(Constants.FALSE, result);
+ }
+ }
+
+ // load( func|str [,chunkname[, mode[, env]]] ) -> chunk | nil, msg
+ private static class Load extends ResumableVarArgFunction {
+ @Override
+ protected Varargs invoke(LuaState state, DebugFrame di, Varargs args) throws LuaError, UnwindThrowable {
+ LuaValue scriptGen = args.arg(1);
+ LuaString chunkName = args.arg(2).optLuaString(null);
+ LuaString mode = args.arg(3).optLuaString(LOAD_MODE);
+ LuaTable funcEnv = args.arg(4).optTable(state.getCurrentThread().getfenv());
+
+ // If we're a string, load as normal
+ LuaValue script = scriptGen.toLuaString();
+ if (!script.isNil()) {
+ try {
+ return LoadState.load(state, ((LuaString) script).toInputStream(), chunkName == null ? (LuaString) script : chunkName, mode, funcEnv);
+ } catch (Exception e) {
+ return varargsOf(Constants.NIL, LuaError.getMessage(e));
+ }
+ }
+
+ LuaFunction function = scriptGen.checkFunction();
+ Varargs result = pcallInit(state, di, new ZeroArgFunction() {
+ @Override
+ public LuaValue call(LuaState state) throws LuaError {
+ try {
+ InputStream stream = new StringInputStream(state, function);
+ return LoadState.load(state, stream, chunkName == null ? FUNCTION_STR : chunkName, mode, funcEnv);
+ } catch (Exception e) {
+ throw LuaError.wrapMessage(e);
+ }
+ }
+ }, Constants.NONE, state.getCurrentThread().getErrorFunc());
+
+ if (result.first().toBoolean()) {
+ return result.arg(2);
} else {
- // Mark this frame as errored, meaning it will not be resumed.
- DebugHandler.getDebugState(state).getStackUnsafe().flags |= FLAG_ERROR;
- // And mark us as being in the error handler.
- pState.errored = true;
- error.fillTraceback(state);
- value = error.value;
+ return varargsOf(Constants.NIL, result.arg(2));
}
+ }
- state.getCurrentThread().setErrorFunc(pState.oldErrorFunc);
- closeUntil(state, pState.frame);
- return finish(pState, value);
+ @Override
+ protected Varargs resumeThis(LuaState state, PCallState pState, Varargs value) {
+ pcallFinishSuccess(state, pState);
+ return pState.errored ? varargsOf(Constants.NIL, value) : value;
}
- private Varargs finish(PCallState pState, Varargs value) {
- switch (opcode) {
- case 0:
- case 1:
- return pState.errored ? varargsOf(Constants.FALSE, value) : varargsOf(Constants.TRUE, value);
- case 2:
- return pState.errored ? varargsOf(Constants.NIL, value) : value;
- default:
- throw new NonResumableException("Cannot resume " + debugName());
- }
+ @Override
+ public Varargs resumeErrorThis(LuaState state, PCallState pState, LuaError error) throws UnwindThrowable {
+ LuaValue result = pcallFinishError(state, pState, error);
+ return varargsOf(Constants.NIL, result);
}
}
@@ -444,8 +352,10 @@ private static final class PCallState {
boolean errored = false;
}
- private static Varargs pcall(LuaState state, DebugFrame di, LuaValue func, Varargs args, LuaValue errFunc) throws
- UnwindThrowable {
+ private static Varargs pcallInit(LuaState state, DebugFrame di, LuaValue func, Varargs args, LuaValue errFunc) throws UnwindThrowable {
+ // FIXME: Move this into a core part of the runtime, so it's not part of library code!
+ // We really should clean up LuaError at the same time.
+
// Mark this frame as being an error handler
PCallState pState = new PCallState();
di.state = pState;
@@ -475,6 +385,30 @@ private static Varargs pcall(LuaState state, DebugFrame di, LuaValue func, Varar
}
}
+ private static void pcallFinishSuccess(LuaState state, PCallState pState) {
+ state.getCurrentThread().setErrorFunc(pState.oldErrorFunc);
+ if (pState.errored) closeUntil(state, pState.frame);
+ }
+
+ private static LuaValue pcallFinishError(LuaState state, PCallState pState, LuaError error) throws UnwindThrowable {
+ LuaValue value;
+ if (pState.errored) {
+ value = valueOf("error in error handling");
+ } else {
+ // Mark this frame as errored, meaning it will not be resumed.
+ DebugHandler.getDebugState(state).getStackUnsafe().flags |= FLAG_ERROR;
+ // And mark us as being in the error handler.
+ pState.errored = true;
+ error.fillTraceback(state);
+ value = error.value;
+ }
+
+ state.getCurrentThread().setErrorFunc(pState.oldErrorFunc);
+ closeUntil(state, pState.frame);
+
+ return value;
+ }
+
private static void closeUntil(LuaState state, DebugFrame top) {
DebugState ds = DebugHandler.getDebugState(state);
DebugHandler handler = state.debug;
@@ -486,30 +420,7 @@ private static void closeUntil(LuaState state, DebugFrame top) {
}
}
- /**
- * Load from a named file, returning the chunk or nil,error of can't load
- *
- * @param state The current lua state
- * @param filename Name of the file
- * @return Varargs containing chunk, or NIL,error-text on error
- */
- public static Varargs loadFile(LuaState state, String filename) {
- InputStream is = state.resourceManipulator.findResource(filename);
- if (is == null) {
- return varargsOf(Constants.NIL, valueOf("cannot open " + filename + ": No such file or directory"));
- }
- try {
- return loadStream(state, is, valueOf("@" + filename));
- } finally {
- try {
- is.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- private static Varargs loadStream(LuaState state, InputStream is, LuaString chunkname) {
+ public static Varargs loadStream(LuaState state, InputStream is, LuaString chunkname) {
try {
if (is == null) {
return varargsOf(Constants.NIL, valueOf("not found: " + chunkname));
diff --git a/src/main/java/org/squiddev/cobalt/lib/Bit32Lib.java b/src/main/java/org/squiddev/cobalt/lib/Bit32Lib.java
index 1af773fa..cb4953cf 100644
--- a/src/main/java/org/squiddev/cobalt/lib/Bit32Lib.java
+++ b/src/main/java/org/squiddev/cobalt/lib/Bit32Lib.java
@@ -25,6 +25,7 @@
package org.squiddev.cobalt.lib;
import org.squiddev.cobalt.*;
+import org.squiddev.cobalt.function.LibFunction;
import org.squiddev.cobalt.function.RegisteredFunction;
import static org.squiddev.cobalt.ErrorFactory.argError;
@@ -33,11 +34,9 @@
/**
* Subclass of LibFunction that implements the Lua standard {@code bit32} library.
*/
-public class Bit32Lib implements LuaLibrary {
- @Override
- public LuaValue add(LuaState state, LuaTable env) {
- LuaTable t = new LuaTable();
- RegisteredFunction.bind(t, new RegisteredFunction[]{
+public class Bit32Lib {
+ public static void add(LuaState state, LuaTable env) {
+ LibFunction.setGlobalLibrary(state, env, "bit32", RegisteredFunction.bind(new RegisteredFunction[]{
RegisteredFunction.ofV("band", Bit32Lib::band),
RegisteredFunction.of("bnot", Bit32Lib::bnot),
RegisteredFunction.ofV("bor", Bit32Lib::bor),
@@ -50,11 +49,7 @@ public LuaValue add(LuaState state, LuaTable env) {
RegisteredFunction.of("lshift", Bit32Lib::lshift),
RegisteredFunction.of("rrotate", Bit32Lib::rrotate),
RegisteredFunction.of("rshift", Bit32Lib::rshift),
- });
-
- env.rawset("bit32", t);
- state.loadedPackages.rawset("bit32", t);
- return t;
+ }));
}
private static Varargs band(LuaState state, Varargs args) throws LuaError {
diff --git a/src/main/java/org/squiddev/cobalt/lib/LuaLibrary.java b/src/main/java/org/squiddev/cobalt/lib/CoreLibraries.java
similarity index 51%
rename from src/main/java/org/squiddev/cobalt/lib/LuaLibrary.java
rename to src/main/java/org/squiddev/cobalt/lib/CoreLibraries.java
index ed210080..404a0599 100644
--- a/src/main/java/org/squiddev/cobalt/lib/LuaLibrary.java
+++ b/src/main/java/org/squiddev/cobalt/lib/CoreLibraries.java
@@ -26,18 +26,47 @@
import org.squiddev.cobalt.LuaState;
import org.squiddev.cobalt.LuaTable;
-import org.squiddev.cobalt.LuaValue;
+import org.squiddev.cobalt.lib.system.SystemLibraries;
/**
- * A library for the environment
+ * The {@link CoreLibraries} class is a convenience class to standardize install "core" (i.e.
+ * non-{@linkplain SystemLibraries system}) into the global state.
*/
-public interface LuaLibrary {
+public final class CoreLibraries {
+ private CoreLibraries() {
+ }
+
+ /**
+ * Create a standard set of globals and setup a thread
+ *
+ * @param state The current lua state
+ * @return Table of globals initialized with the standard JSE libraries
+ * @see #debugGlobals(LuaState)
+ * @see CoreLibraries
+ */
+ public static LuaTable standardGlobals(LuaState state) {
+ LuaTable globals = state.getMainThread().getfenv();
+ new BaseLib().add(globals);
+ TableLib.add(state, globals);
+ StringLib.add(state, globals);
+ CoroutineLib.add(state, globals);
+ new MathLib().add(state, globals);
+ new Utf8Lib().add(state, globals);
+ return globals;
+ }
+
/**
- * Add this library into an environment
+ * Create standard globals including the {@link DebugLib} library.
*
- * @param state The current Lua state
- * @param environment The environment to add to
- * @return The sub-table that was added
+ * @param state The current lua state
+ * @return Table of globals initialized with the standard JSE and debug libraries
+ * @see #standardGlobals(LuaState)
+ * @see CoreLibraries
+ * @see DebugLib
*/
- LuaValue add(LuaState state, LuaTable environment);
+ public static LuaTable debugGlobals(LuaState state) {
+ LuaTable _G = standardGlobals(state);
+ DebugLib.add(state, _G);
+ return _G;
+ }
}
diff --git a/src/main/java/org/squiddev/cobalt/lib/CoroutineLib.java b/src/main/java/org/squiddev/cobalt/lib/CoroutineLib.java
index 366830b3..c5a12eae 100644
--- a/src/main/java/org/squiddev/cobalt/lib/CoroutineLib.java
+++ b/src/main/java/org/squiddev/cobalt/lib/CoroutineLib.java
@@ -29,8 +29,8 @@
import org.squiddev.cobalt.debug.DebugFrame;
import org.squiddev.cobalt.function.LibFunction;
import org.squiddev.cobalt.function.LuaFunction;
+import org.squiddev.cobalt.function.RegisteredFunction;
import org.squiddev.cobalt.function.ResumableVarArgFunction;
-import org.squiddev.cobalt.lib.jse.JsePlatform;
import static org.squiddev.cobalt.ValueFactory.valueOf;
import static org.squiddev.cobalt.ValueFactory.varargsOf;
@@ -39,7 +39,7 @@
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code coroutine}
* library.
- *
+ *
* The coroutine library in luaj has the same behavior as the
* coroutine library in C, but is implemented using Java Threads to maintain
* the call state between invocations. Therefore it can be yielded from anywhere,
@@ -48,101 +48,97 @@
* may not be collected by the garbage collector.
*
* @see LibFunction
- * @see JsePlatform
+ * @see CoreLibraries
* @see http://www.lua.org/manual/5.1/manual.html#5.2
*/
-public class CoroutineLib extends ResumableVarArgFunction