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

nl.weeaboo.lua2.lib.LibFunction Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2009-2011 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 nl.weeaboo.lua2.lib;

import static nl.weeaboo.lua2.vm.LuaNil.NIL;

import nl.weeaboo.lua2.LuaException;
import nl.weeaboo.lua2.io.LuaSerializable;
import nl.weeaboo.lua2.stdlib.BaseLib;
import nl.weeaboo.lua2.stdlib.TableLib;
import nl.weeaboo.lua2.vm.LuaFunction;
import nl.weeaboo.lua2.vm.LuaValue;

/**
 * Subclass of {@link LuaFunction} common to Java functions exposed to lua.
 * 

* To provide for common implementations in JME and JSE, library functions are typically grouped on one or * more library classes and an opcode per library function is defined and used to key the switch to the * correct function within the library. *

* Since lua functions can be called with too few or too many arguments, and there are overloaded * {@link LuaValue#call()} functions with varying number of arguments, a Java function exposed in lua needs to * handle the argument fixup when a function is called with a number of arguments differs from that expected. *

* To simplify the creation of library functions, there are 5 direct subclasses to handle common cases based * on number of argument values and number of return return values. *

    *
  • {@link ZeroArgFunction}
  • *
  • {@link OneArgFunction}
  • *
  • {@link TwoArgFunction}
  • *
  • {@link ThreeArgFunction}
  • *
  • {@link VarArgFunction}
  • *
*

* To be a Java library that can be loaded via {@code require}, it should have a public constructor that * returns a {@link LuaValue} that, when executed, initializes the library. *

* For example, the following code will implement a library called "hyperbolic" with two functions, "sinh", * and "cosh": * *

 * 
 * import org.luaj.vm2.LuaValue;
 * public class hyperbolic extends org.luaj.vm2.lib.OneArgFunction {
 *     public hyperbolic() {}
 *     public LuaValue call(LuaValue arg) {
 *         switch ( opcode ) {
 *         case 0: {
 *             LuaValue t = tableOf();
 *             this.bind(t, hyperbolic.class, new String[] { "sinh", "cosh" }, 1 );
 *             env.set("hyperbolic", t);
 *             return t;
 *         }
 *         case 1: return valueOf(Math.sinh(arg.todouble()));
 *         case 2: return valueOf(Math.cosh(arg.todouble()));
 *         default: return error("bad opcode: "+opcode);
 *         }
 *     }
 * }
 * 
 * 
* * The default constructor is both to instantiate the library in response to {@code require 'hyperbolic'} * statement, provided it is on Javas class path, and to instantiate copies of the {@code hyperbolic} class * when initializing library instances. . The instance returned by the default constructor will be invoked as * part of library loading. In response, it creates two more instances, one for each library function, in the * body of the {@code switch} statement {@code case 0} via the * bind(LuaValue, Class, String[], int) utility method. It also registers the table in the * globals via the {@code env} local variable, which should be the global environment unless it has been * changed. {@code case 1} and {@code case 2} will be called when {@code hyperbolic.sinh} * {@code hyperbolic.sinh} and {@code hyperbolic.cosh} are invoked. *

* To test it, a script such as this can be used: * *

 * {@code
 * local t = require('hyperbolic')
 * print( 't', t )
 * print( 'hyperbolic', hyperbolic )
 * for k,v in pairs(t) do
 *     print( 'k,v', k,v )
 * end
 * print( 'sinh(.5)', hyperbolic.sinh(.5) )
 * print( 'cosh(.5)', hyperbolic.cosh(.5) )
 * }
 * 
*

* It should produce something like: * *

 * {@code
 * t    table: 3dbbd23f
 * hyperbolic    table: 3dbbd23f
 * k,v    cosh    cosh
 * k,v    sinh    sinh
 * sinh(.5)    0.5210953
 * cosh(.5)    1.127626
 * }
 * 
*

* See the source code in any of the library functions such as {@link BaseLib} or {@link TableLib} for * specific examples. */ @LuaSerializable public abstract class LibFunction extends LuaFunction { private static final long serialVersionUID = -4025668290315326469L; /** * 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; /** Default constructor for use by subclasses */ protected LibFunction() { } @Override public String tojstring() { if (name != null) { return typename() + ":" + name; } else { return super.tojstring(); } } /** * 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 Class to instantiate for each bound function * @param names array of String names, one for each function. * @see #bind(LuaValue, Class, String[], int) */ @Deprecated protected void bind(LuaValue env, Class factory, String[] names) { bind(env, factory, names, 0); } /** * Bind a set of library functions, with an offset *

* An array of names is provided, and the first name is bound with opcode = {@code firstopcode}, second * with {@code firstopcode+1}, etc. * * @param env The environment to apply to each bound function * @param factory the Class to instantiate for each bound function * @param names array of String names, one for each function. * @param firstopcode the first opcode to use * @see #bind(LuaValue, Class, String[]) */ @Deprecated protected void bind(LuaValue env, Class factory, String[] names, int firstopcode) { try { for (int i = 0, n = names.length; i < n; i++) { LibFunction f = (LibFunction)factory.getConstructor().newInstance(); f.opcode = firstopcode + i; f.name = names[i]; f.env = env; env.set(names[i], f); } } catch (Exception e) { throw LuaException.wrap("Bind failed: " + factory.getName(), e); } } /** * Java code generation utility to allocate storage for upvalue, leave it empty */ protected static LuaValue[] newupe() { return new LuaValue[1]; } /** * Java code generation utility to allocate storage for upvalue, initialize with nil */ protected static LuaValue[] newupn() { return new LuaValue[] { NIL }; } /** * Java code generation utility to allocate storage for upvalue, initialize with value */ protected static LuaValue[] newupl(LuaValue v) { return new LuaValue[] { v }; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy