All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.luaj.vm2.Globals Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2012 Luaj.org. All rights reserved.
 *
 * 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.luaj.vm2;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.Reader;

import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.DebugLib;
import org.luaj.vm2.lib.IoLib;
import org.luaj.vm2.lib.PackageLib;
import org.luaj.vm2.lib.ResourceFinder;

/**
 * Global environment used by luaj.  Contains global variables referenced by executing lua.
 * 

* *

Constructing and Initializing Instances

* Typically, this is constructed indirectly by a call to * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}, * and then used to load lua scripts for execution as in the following example. *
 {@code
 * Globals globals = JsePlatform.standardGlobals();
 * globals.load( new StringReader("print 'hello'"), "main.lua" ).call(); 
 * } 
* The creates a complete global environment with the standard libraries loaded. *

* For specialized circumstances, the Globals may be constructed directly and loaded * with only those libraries that are needed, for example. *

 {@code
 * Globals globals = new Globals();
 * globals.load( new BaseLib() ); 
 * } 
* *

Loading and Executing Lua Code

* Globals contains convenience functions to load and execute lua source code given a Reader. * A simple example is: *
 {@code
 * globals.load( new StringReader("print 'hello'"), "main.lua" ).call(); 
 * } 
* *

Fine-Grained Control of Compiling and Loading Lua

* Executable LuaFunctions are created from lua code in several steps *
    *
  • find the resource using the platform's {@link ResourceFinder} *
  • compile lua to lua bytecode using {@link Compiler} *
  • load lua bytecode to a {@link Prototype} using {@link Undumper} *
  • construct {@link LuaClosure} from {@link Prototype} with {@link Globals} using {@link Loader} *
*

* There are alternate flows when the direct lua-to-Java bytecode compiling {@link org.luaj.vm2.luajc.LuaJC} is used. *

    *
  • compile lua to lua bytecode using {@link Compiler} or load precompiled code using {@link Undumper} *
  • convert lua bytecode to equivalent Java bytecode using {@link org.luaj.vm2.luajc.LuaJC} that implements {@link Loader} directly *
* *

Java Field

* Certain public fields are provided that contain the current values of important global state: *
    *
  • {@link #STDIN} Current value for standard input in the laaded {@link IoLib}, if any. *
  • {@link #STDOUT} Current value for standard output in the loaded {@link IoLib}, if any. *
  • {@link #STDERR} Current value for standard error in the loaded {@link IoLib}, if any. *
  • {@link #finder} Current loaded {@link ResourceFinder}, if any. *
  • {@link #compiler} Current loaded {@link Compiler}, if any. *
  • {@link #undumper} Current loaded {@link Undumper}, if any. *
  • {@link #loader} Current loaded {@link Loader}, if any. *
* *

Lua Environment Variables

* When using {@link org.luaj.vm2.lib.jse.JsePlatform} or {@link org.luaj.vm2.lib.jme.JmePlatform}, * these environment variables are created within the Globals. *
    *
  • "_G" Pointer to this Globals. *
  • "_VERSION" String containing the version of luaj. *
* *

Use in Multithreaded Environments

* In a multi-threaded server environment, each server thread should create one Globals instance, * which will be logically distinct and not interfere with each other, but share certain * static immutable resources such as class data and string data. *

* * @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jme.JmePlatform * @see LuaValue * @see Compiler * @see Loader * @see Undumper * @see ResourceFinder * @see org.luaj.vm2.compiler.LuaC * @see org.luaj.vm2.luajc.LuaJC */ public class Globals extends LuaTable { /** The current default input stream. */ public InputStream STDIN = null; /** The current default output stream. */ public PrintStream STDOUT = System.out; /** The current default error stream. */ public PrintStream STDERR = System.err; /** The installed ResourceFinder for looking files by name. */ public ResourceFinder finder; /** The currently running thread. Should not be changed by non-library code. */ public LuaThread running = new LuaThread(this); /** The BaseLib instance loaded into this Globals */ public BaseLib baselib; /** The PackageLib instance loaded into this Globals */ public PackageLib package_; /** The DebugLib instance loaded into this Globals, or null if debugging is not enabled */ public DebugLib debuglib; /** Interface for module that converts a Prototype into a LuaFunction with an environment. */ public interface Loader { /** Convert the prototype into a LuaFunction with the supplied environment. */ LuaFunction load(Prototype prototype, String chunkname, LuaValue env) throws IOException; } /** Interface for module that converts lua source text into a prototype. */ public interface Compiler { /** Compile lua source into a Prototype. The InputStream is assumed to be in UTF-8. */ Prototype compile(InputStream stream, String chunkname) throws IOException; } /** Interface for module that loads lua binary chunk into a prototype. */ public interface Undumper { /** Load the supplied input stream into a prototype. */ Prototype undump(InputStream stream, String chunkname) throws IOException; } /** Check that this object is a Globals object, and return it, otherwise throw an error. */ public Globals checkglobals() { return this; } /** The installed loader. * @see Loader */ public Loader loader; /** The installed compiler. * @see Compiler */ public Compiler compiler; /** The installed undumper. * @see Undumper */ public Undumper undumper; /** Convenience function for loading a file that is either binary lua or lua source. * @param filename Name of the file to load. * @return LuaValue that can be call()'ed or invoke()'ed. * @throws LuaError if the file could not be loaded. */ public LuaValue loadfile(String filename) { try { return load(finder.findResource(filename), "@"+filename, "bt", this); } catch (Exception e) { return error("load "+filename+": "+e); } } /** Convenience function to load a string value as a script. Must be lua source. * @param script Contents of a lua script, such as "print 'hello, world.'" * @param chunkname Name that will be used within the chunk as the source. * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls. * @throws LuaError if the script could not be compiled. */ public LuaValue load(String script, String chunkname) { return load(new StrReader(script), chunkname); } /** Convenience function to load a string value as a script. Must be lua source. * @param script Contents of a lua script, such as "print 'hello, world.'" * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls. * @throws LuaError if the script could not be compiled. */ public LuaValue load(String script) { return load(new StrReader(script), script); } /** Convenience function to load a string value as a script with a custom environment. * Must be lua source. * @param script Contents of a lua script, such as "print 'hello, world.'" * @param chunkname Name that will be used within the chunk as the source. * @param environment LuaTable to be used as the environment for the loaded function. * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls. * @throws LuaError if the script could not be compiled. */ public LuaValue load(String script, String chunkname, LuaTable environment) { return load(new StrReader(script), chunkname, environment); } /** Load the content form a reader as a text file. Must be lua source. * The source is converted to UTF-8, so any characters appearing in quoted literals * above the range 128 will be converted into multiple bytes. * @param reader Reader containing text of a lua script, such as "print 'hello, world.'" * @param chunkname Name that will be used within the chunk as the source. * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls. * @throws LuaError if the script could not be compiled. */ public LuaValue load(Reader reader, String chunkname) { return load(new UTF8Stream(reader), chunkname, "t", this); } /** Load the content form a reader as a text file, supplying a custom environment. * Must be lua source. The source is converted to UTF-8, so any characters * appearing in quoted literals above the range 128 will be converted into * multiple bytes. * @param reader Reader containing text of a lua script, such as "print 'hello, world.'" * @param chunkname Name that will be used within the chunk as the source. * @param environment LuaTable to be used as the environment for the loaded function. * @return LuaValue that may be executed via .call(), .invoke(), or .method() calls. * @throws LuaError if the script could not be compiled. */ public LuaValue load(Reader reader, String chunkname, LuaTable environment) { return load(new UTF8Stream(reader), chunkname, "t", environment); } /** Load the content form an input stream as a binary chunk or text file. * @param is InputStream containing a lua script or compiled lua" * @param chunkname Name that will be used within the chunk as the source. * @param mode String containing 'b' or 't' or both to control loading as binary or text or either. * @param environment LuaTable to be used as the environment for the loaded function. * */ public LuaValue load(InputStream is, String chunkname, String mode, LuaValue environment) { try { Prototype p = loadPrototype(is, chunkname, mode); return loader.load(p, chunkname, environment); } catch (LuaError l) { throw l; } catch (Exception e) { return error("load "+chunkname+": "+e); } } /** Load lua source or lua binary from an input stream into a Prototype. * The InputStream is either a binary lua chunk starting with the lua binary chunk signature, * or a text input file. If it is a text input file, it is interpreted as a UTF-8 byte sequence. * @param is Input stream containing a lua script or compiled lua" * @param chunkname Name that will be used within the chunk as the source. * @param mode String containing 'b' or 't' or both to control loading as binary or text or either. */ public Prototype loadPrototype(InputStream is, String chunkname, String mode) throws IOException { if (mode.indexOf('b') >= 0) { if (undumper == null) error("No undumper."); if (!is.markSupported()) is = new BufferedStream(is); is.mark(4); final Prototype p = undumper.undump(is, chunkname); if (p != null) return p; is.reset(); } if (mode.indexOf('t') >= 0) { return compilePrototype(is, chunkname); } error("Failed to load prototype "+chunkname+" using mode '"+mode+"'"); return null; } /** Compile lua source from a Reader into a Prototype. The characters in the reader * are converted to bytes using the UTF-8 encoding, so a string literal containing * characters with codepoints 128 or above will be converted into multiple bytes. */ public Prototype compilePrototype(Reader reader, String chunkname) throws IOException { return compilePrototype(new UTF8Stream(reader), chunkname); } /** Compile lua source from an InputStream into a Prototype. * The input is assumed to be UTf-8, but since bytes in the range 128-255 are passed along as * literal bytes, any ASCII-compatible encoding such as ISO 8859-1 may also be used. */ public Prototype compilePrototype(InputStream stream, String chunkname) throws IOException { if (compiler == null) error("No compiler."); return compiler.compile(stream, chunkname); } /** Function which yields the current thread. * @param args Arguments to supply as return values in the resume function of the resuming thread. * @return Values supplied as arguments to the resume() call that reactivates this thread. */ public Varargs yield(Varargs args) { if (running == null || running.isMainThread()) throw new LuaError("cannot yield main thread"); final LuaThread.State s = running.state; return s.lua_yield(args); } /** Reader implementation to read chars from a String in JME or JSE. */ static class StrReader extends Reader { final String s; int i = 0; final int n; StrReader(String s) { this.s = s; n = s.length(); } public void close() throws IOException { i = n; } public int read() throws IOException { return i < n ? s.charAt(i++) : -1; } public int read(char[] cbuf, int off, int len) throws IOException { int j = 0; for (; j < len && i < n; ++j, ++i) cbuf[off+j] = s.charAt(i); return j > 0 || len == 0 ? j : -1; } } /* Abstract base class to provide basic buffered input storage and delivery. * This class may be moved to its own package in the future. */ abstract static class AbstractBufferedStream extends InputStream { protected byte[] b; protected int i = 0, j = 0; protected AbstractBufferedStream(int buflen) { this.b = new byte[buflen]; } abstract protected int avail() throws IOException; public int read() throws IOException { int a = avail(); return (a <= 0 ? -1 : 0xff & b[i++]); } public int read(byte[] b) throws IOException { return read(b, 0, b.length); } public int read(byte[] b, int i0, int n) throws IOException { int a = avail(); if (a <= 0) return -1; final int n_read = Math.min(a, n); System.arraycopy(this.b, i, b, i0, n_read); i += n_read; return n_read; } public long skip(long n) throws IOException { final long k = Math.min(n, j - i); i += k; return k; } public int available() throws IOException { return j - i; } } /** Simple converter from Reader to InputStream using UTF8 encoding that will work * on both JME and JSE. * This class may be moved to its own package in the future. */ static class UTF8Stream extends AbstractBufferedStream { private final char[] c = new char[32]; private final Reader r; UTF8Stream(Reader r) { super(96); this.r = r; } protected int avail() throws IOException { if (i < j) return j - i; int n = r.read(c); if (n < 0) return -1; if (n == 0) { int u = r.read(); if (u < 0) return -1; c[0] = (char) u; n = 1; } j = LuaString.encodeToUtf8(c, n, b, i = 0); return j; } public void close() throws IOException { r.close(); } } /** Simple buffered InputStream that supports mark. * Used to examine an InputStream for a 4-byte binary lua signature, * and fall back to text input when the signature is not found, * as well as speed up normal compilation and reading of lua scripts. * This class may be moved to its own package in the future. */ static class BufferedStream extends AbstractBufferedStream { private final InputStream s; public BufferedStream(InputStream s) { this(128, s); } BufferedStream(int buflen, InputStream s) { super(buflen); this.s = s; } protected int avail() throws IOException { if (i < j) return j - i; if (j >= b.length) i = j = 0; // leave previous bytes in place to implement mark()/reset(). int n = s.read(b, j, b.length - j); if (n < 0) return -1; if (n == 0) { int u = s.read(); if (u < 0) return -1; b[j] = (byte) u; n = 1; } j += n; return n; } public void close() throws IOException { s.close(); } public synchronized void mark(int n) { if (i > 0 || n > b.length) { byte[] dest = n > b.length ? new byte[n] : b; System.arraycopy(b, i, dest, 0, j - i); j -= i; i = 0; b = dest; } } public boolean markSupported() { return true; } public synchronized void reset() throws IOException { i = 0; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy