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

org.luaj.vm2.lib.BaseLib Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
* Copyright (c) 2009 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.lib;

import java.io.IOException;
import java.io.InputStream;

import org.luaj.vm2.Globals;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;

/** 
 * Subclass of {@link LibFunction} which implements the lua basic library functions. 
 * 

* This contains all library functions listed as "basic functions" in the lua documentation for JME. * The functions dofile and loadfile use the * {@link Globals#finder} instance to find resource files. * Since JME has no file system by default, {@link BaseLib} implements * {@link ResourceFinder} using {@link Class#getResource(String)}, * which is the closest equivalent on JME. * The default loader chain in {@link PackageLib} will use these as well. *

* To use basic library functions that include a {@link ResourceFinder} based on * directory lookup, use {@link org.luaj.vm2.lib.jse.JseBaseLib} instead. *

* Typically, this library is included as part of a call to either * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or * {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()} *

 {@code
 * Globals globals = JsePlatform.standardGlobals();
 * globals.get("print").call(LuaValue.valueOf("hello, world"));
 * } 
*

* For special cases where the smallest possible footprint is desired, * a minimal set of libraries could be loaded * directly via {@link Globals#load(LuaValue)} using code such as: *

 {@code
 * Globals globals = new Globals();
 * globals.load(new JseBaseLib());
 * globals.get("print").call(LuaValue.valueOf("hello, world"));
 * } 
* Doing so will ensure the library is properly initialized * and loaded into the globals table. *

* This is a direct port of the corresponding library in C. * @see org.luaj.vm2.lib.jse.JseBaseLib * @see ResourceFinder * @see Globals#finder * @see LibFunction * @see org.luaj.vm2.lib.jse.JsePlatform * @see org.luaj.vm2.lib.jme.JmePlatform * @see Lua 5.2 Base Lib Reference */ public class BaseLib extends TwoArgFunction implements ResourceFinder { Globals globals; /** Perform one-time initialization on the library by adding base functions * to the supplied environment, and returning it as the return value. * @param modname the module name supplied if this is loaded via 'require'. * @param env the environment to load into, which must be a Globals instance. */ public LuaValue call(LuaValue modname, LuaValue env) { globals = env.checkglobals(); globals.finder = this; globals.baselib = this; env.set( "_G", env ); env.set( "_VERSION", Lua._VERSION ); env.set("assert", new _assert()); env.set("collectgarbage", new collectgarbage()); env.set("dofile", new dofile()); env.set("error", new error()); env.set("getmetatable", new getmetatable()); env.set("load", new load()); env.set("loadfile", new loadfile()); env.set("pcall", new pcall()); env.set("print", new print(this)); env.set("rawequal", new rawequal()); env.set("rawget", new rawget()); env.set("rawlen", new rawlen()); env.set("rawset", new rawset()); env.set("select", new select()); env.set("setmetatable", new setmetatable()); env.set("tonumber", new tonumber()); env.set("tostring", new tostring()); env.set("type", new type()); env.set("xpcall", new xpcall()); next next; env.set("next", next = new next()); env.set("pairs", new pairs(next)); env.set("ipairs", new ipairs()); return env; } /** ResourceFinder implementation * * Tries to open the file as a resource, which can work for JSE and JME. */ public InputStream findResource(String filename) { return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/"+filename); } // "assert", // ( v [,message] ) -> v, message | ERR static final class _assert extends VarArgFunction { public Varargs invoke(Varargs args) { if ( !args.arg1().toboolean() ) error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" ); return args; } } // "collectgarbage", // ( opt [,arg] ) -> value static final class collectgarbage extends VarArgFunction { public Varargs invoke(Varargs args) { String s = args.optjstring(1, "collect"); if ( "collect".equals(s) ) { System.gc(); return ZERO; } else if ( "count".equals(s) ) { Runtime rt = Runtime.getRuntime(); long used = rt.totalMemory() - rt.freeMemory(); return varargsOf(valueOf(used/1024.), valueOf(used%1024)); } else if ( "step".equals(s) ) { System.gc(); return LuaValue.TRUE; } else { this.argerror("gc op"); } return NIL; } } // "dofile", // ( filename ) -> result1, ... final class dofile extends VarArgFunction { public Varargs invoke(Varargs args) { args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); String filename = args.isstring(1)? args.tojstring(1): null; Varargs v = filename == null? loadStream( globals.STDIN, "=stdin", "bt", globals ): loadFile( args.checkjstring(1), "bt", globals ); return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke(); } } // "error", // ( message [,level] ) -> ERR static final class error extends TwoArgFunction { public LuaValue call(LuaValue arg1, LuaValue arg2) { throw arg1.isnil()? new LuaError(null, arg2.optint(1)): arg1.isstring()? new LuaError(arg1.tojstring(), arg2.optint(1)): new LuaError(arg1); } } // "getmetatable", // ( object ) -> table static final class getmetatable extends LibFunction { public LuaValue call() { return argerror(1, "value"); } public LuaValue call(LuaValue arg) { LuaValue mt = arg.getmetatable(); return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL; } } // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg final class load extends VarArgFunction { public Varargs invoke(Varargs args) { LuaValue ld = args.arg1(); args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function"); String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)"); String mode = args.optjstring(3, "bt"); LuaValue env = args.optvalue(4, globals); return loadStream(ld.isstring()? ld.strvalue().toInputStream(): new StringInputStream(ld.checkfunction()), source, mode, env); } } // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg final class loadfile extends VarArgFunction { public Varargs invoke(Varargs args) { args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); String filename = args.isstring(1)? args.tojstring(1): null; String mode = args.optjstring(2, "bt"); LuaValue env = args.optvalue(3, globals); return filename == null? loadStream( globals.STDIN, "=stdin", mode, env ): loadFile( filename, mode, env ); } } // "pcall", // (f, arg1, ...) -> status, result1, ... final class pcall extends VarArgFunction { public Varargs invoke(Varargs args) { LuaValue func = args.checkvalue(1); if (globals != null && globals.debuglib != null) globals.debuglib.onCall(this); try { return varargsOf(TRUE, func.invoke(args.subargs(2))); } catch ( LuaError le ) { final LuaValue m = le.getMessageObject(); return varargsOf(FALSE, m!=null? m: NIL); } catch ( Exception e ) { final String m = e.getMessage(); return varargsOf(FALSE, valueOf(m!=null? m: e.toString())); } finally { if (globals != null && globals.debuglib != null) globals.debuglib.onReturn(); } } } // "print", // (...) -> void final class print extends VarArgFunction { final BaseLib baselib; print(BaseLib baselib) { this.baselib = baselib; } public Varargs invoke(Varargs args) { LuaValue tostring = globals.get("tostring"); for ( int i=1, n=args.narg(); i<=n; i++ ) { if ( i>1 ) globals.STDOUT.print( '\t' ); LuaString s = tostring.call( args.arg(i) ).strvalue(); globals.STDOUT.print(s.tojstring()); } globals.STDOUT.println(); return NONE; } } // "rawequal", // (v1, v2) -> boolean static final class rawequal extends LibFunction { public LuaValue call() { return argerror(1, "value"); } public LuaValue call(LuaValue arg) { return argerror(2, "value"); } public LuaValue call(LuaValue arg1, LuaValue arg2) { return valueOf(arg1.raweq(arg2)); } } // "rawget", // (table, index) -> value static final class rawget extends LibFunction { public LuaValue call() { return argerror(1, "value"); } public LuaValue call(LuaValue arg) { return argerror(2, "value"); } public LuaValue call(LuaValue arg1, LuaValue arg2) { return arg1.checktable().rawget(arg2); } } // "rawlen", // (v) -> value static final class rawlen extends LibFunction { public LuaValue call(LuaValue arg) { return valueOf(arg.rawlen()); } } // "rawset", // (table, index, value) -> table static final class rawset extends LibFunction { public LuaValue call(LuaValue table) { return argerror(2,"value"); } public LuaValue call(LuaValue table, LuaValue index) { return argerror(3,"value"); } public LuaValue call(LuaValue table, LuaValue index, LuaValue value) { LuaTable t = table.checktable(); t.rawset(index.checknotnil(), value); return t; } } // "select", // (f, ...) -> value1, ... static final class select extends VarArgFunction { public Varargs invoke(Varargs args) { int n = args.narg()-1; if ( args.arg1().equals(valueOf("#")) ) return valueOf(n); int i = args.checkint(1); if ( i == 0 || i < -n ) argerror(1,"index out of range"); return args.subargs(i<0? n+i+2: i+1); } } // "setmetatable", // (table, metatable) -> table static final class setmetatable extends LibFunction { public LuaValue call(LuaValue table) { return argerror(2,"value"); } public LuaValue call(LuaValue table, LuaValue metatable) { final LuaValue mt0 = table.checktable().getmetatable(); if ( mt0!=null && !mt0.rawget(METATABLE).isnil() ) error("cannot change a protected metatable"); return table.setmetatable(metatable.isnil()? null: metatable.checktable()); } } // "tonumber", // (e [,base]) -> value static final class tonumber extends LibFunction { public LuaValue call(LuaValue e) { return e.tonumber(); } public LuaValue call(LuaValue e, LuaValue base) { if (base.isnil()) return e.tonumber(); final int b = base.checkint(); if ( b < 2 || b > 36 ) argerror(2, "base out of range"); return e.checkstring().tonumber(b); } } // "tostring", // (e) -> value static final class tostring extends LibFunction { public LuaValue call(LuaValue arg) { LuaValue h = arg.metatag(TOSTRING); if ( ! h.isnil() ) return h.call(arg); LuaValue v = arg.tostring(); if ( ! v.isnil() ) return v; return valueOf(arg.tojstring()); } } // "type", // (v) -> value static final class type extends LibFunction { public LuaValue call(LuaValue arg) { return valueOf(arg.typename()); } } // "xpcall", // (f, err) -> result1, ... final class xpcall extends VarArgFunction { public Varargs invoke(Varargs args) { final LuaThread t = globals.running; final LuaValue preverror = t.errorfunc; t.errorfunc = args.checkvalue(2); try { if (globals != null && globals.debuglib != null) globals.debuglib.onCall(this); try { return varargsOf(TRUE, args.arg1().invoke(args.subargs(3))); } catch ( LuaError le ) { final LuaValue m = le.getMessageObject(); return varargsOf(FALSE, m!=null? m: NIL); } catch ( Exception e ) { final String m = e.getMessage(); return varargsOf(FALSE, valueOf(m!=null? m: e.toString())); } finally { if (globals != null && globals.debuglib != null) globals.debuglib.onReturn(); } } finally { t.errorfunc = preverror; } } } // "pairs" (t) -> iter-func, t, nil static final class pairs extends VarArgFunction { final next next; pairs(next next) { this.next = next; } public Varargs invoke(Varargs args) { return varargsOf( next, args.checktable(1), NIL ); } } // // "ipairs", // (t) -> iter-func, t, 0 static final class ipairs extends VarArgFunction { inext inext = new inext(); public Varargs invoke(Varargs args) { return varargsOf( inext, args.checktable(1), ZERO ); } } // "next" ( table, [index] ) -> next-index, next-value static final class next extends VarArgFunction { public Varargs invoke(Varargs args) { return args.checktable(1).next(args.arg(2)); } } // "inext" ( table, [int-index] ) -> next-index, next-value static final class inext extends VarArgFunction { public Varargs invoke(Varargs args) { return args.checktable(1).inext(args.arg(2)); } } /** * Load from a named file, returning the chunk or nil,error of can't load * @param env * @param mode * @return Varargs containing chunk, or NIL,error-text on error */ public Varargs loadFile(String filename, String mode, LuaValue env) { InputStream is = globals.finder.findResource(filename); if ( is == null ) return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory")); try { return loadStream(is, "@"+filename, mode, env); } finally { try { is.close(); } catch ( Exception e ) { e.printStackTrace(); } } } public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) { try { if ( is == null ) return varargsOf(NIL, valueOf("not found: "+chunkname)); return globals.load(is, chunkname, mode, env); } catch (Exception e) { return varargsOf(NIL, valueOf(e.getMessage())); } } private static class StringInputStream extends InputStream { final LuaValue func; byte[] bytes; int offset, remaining = 0; StringInputStream(LuaValue func) { this.func = func; } public int read() throws IOException { if ( remaining <= 0 ) { LuaValue s = func.call(); if ( s.isnil() ) return -1; LuaString ls = s.strvalue(); bytes = ls.m_bytes; offset = ls.m_offset; remaining = ls.m_length; if (remaining <= 0) return -1; } --remaining; return bytes[offset++]; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy