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

commonMain.org.luaj.vm2.lib.LibFunction.kt 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 org.luaj.vm2.lib

import org.luaj.vm2.LuaError
import org.luaj.vm2.LuaFunction
import org.luaj.vm2.LuaValue
import org.luaj.vm2.Varargs
import kotlin.jvm.*
import kotlin.reflect.*

/**
 * Subclass of [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 [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.
 *
 *  * [ZeroArgFunction]
 *  * [OneArgFunction]
 *  * [TwoArgFunction]
 *  * [ThreeArgFunction]
 *  * [VarArgFunction]
 *
 *
 *
 * To be a Java library that can be loaded via `require`, it should have
 * a public constructor that returns a [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;
 * import org.luaj.vm2.lib.*;
 *
 * public class hyperbolic extends TwoArgFunction {
 *
 * public hyperbolic() {}
 *
 * public LuaValue call(LuaValue modname, LuaValue env) {
 * LuaValue library = tableOf();
 * library.set( "sinh", new sinh() );
 * library.set( "cosh", new cosh() );
 * env.set( "hyperbolic", library );
 * return library;
 * }
 *
 * static class sinh extends OneArgFunction {
 * public LuaValue call(LuaValue x) {
 * return LuaValue.valueOf(Math.sinh(x.checkdouble()));
 * }
 * }
 *
 * static class cosh extends OneArgFunction {
 * public LuaValue call(LuaValue x) {
 * return LuaValue.valueOf(Math.cosh(x.checkdouble()));
 * }
 * }
 * }
`
* * The default constructor is used to instantiate the library * in response to `require 'hyperbolic'` statement, * provided it is on Java"s class path. * This instance is then invoked with 2 arguments: the name supplied to require(), * and the environment for this function. The library may ignore these, or use * them to leave side effects in the global environment, for example. * In the previous example, two functions are created, 'sinh', and 'cosh', and placed * into a global table called 'hyperbolic' using the supplied 'env' argument. * * * To test it, a script such as this can be used: *
 `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: *
 `t	table: 3dbbd23f
 * hyperbolic	table: 3dbbd23f
 * k,v	cosh	function: 3dbbd128
 * k,v	sinh	function: 3dbbd242
 * sinh(.5)	0.5210953
 * cosh(.5)	1.127626
`
* * * * See the source code in any of the library functions * such as [BaseLib] or [TableLib] for other examples. */ abstract class LibFunction /** Default constructor for use by subclasses */ protected constructor() : 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. */ @kotlin.jvm.JvmField protected var opcode: Int = 0 /** The common name for this function, useful for debugging. * * * Binding functions initialize this to the name to which it is bound. */ @kotlin.jvm.JvmField protected var name: String? = null override fun tojstring(): String { return if (name != null) name!! else super.tojstring() } /** * Bind a set of library functions, with an offset * * * An array of names is provided, and the first name is bound * with opcode = `firstopcode`, second with `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 */ @JvmOverloads protected fun bind(env: LuaValue, factory: () -> LibFunction, names: Array, firstopcode: Int = 0) { try { var i = 0 val n = names.size while (i < n) { val f = factory() f.opcode = firstopcode + i f.name = names[i] env[f.name!!] = f i++ } } catch (e: Exception) { throw LuaError("bind failed: $e") } } override fun call(): LuaValue { return LuaValue.argerror(1, "value") } override fun call(a: LuaValue): LuaValue { return call() } override fun call(a: LuaValue, b: LuaValue): LuaValue { return call(a) } override fun call(a: LuaValue, b: LuaValue, c: LuaValue): LuaValue { return call(a, b) } open fun call(a: LuaValue, b: LuaValue, c: LuaValue, d: LuaValue): LuaValue { return call(a, b, c) } override fun invoke(args: Varargs): Varargs { when (args.narg()) { 0 -> return call() 1 -> return call(args.arg1()) 2 -> return call(args.arg1(), args.arg(2)) 3 -> return call(args.arg1(), args.arg(2), args.arg(3)) else -> return call(args.arg1(), args.arg(2), args.arg(3), args.arg(4)) } } companion object { /** Java code generation utility to allocate storage for upvalue, leave it empty */ protected fun newupe(): Array { return arrayOfNulls(1) as Array } /** Java code generation utility to allocate storage for upvalue, initialize with nil */ protected fun newupn(): Array { return arrayOf(LuaValue.NIL) } /** Java code generation utility to allocate storage for upvalue, initialize with value */ protected fun newupl(v: LuaValue): Array { return arrayOf(v) } } } /** * 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 */




© 2015 - 2024 Weber Informatics LLC | Privacy Policy