content: /*******************************************************************************
   * Copyright (c) 2009-2011 Luaj.org. All rights reserved.
   * <p/>
   * 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:
   * <p/>
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   * <p/>
   * 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;
  
  //TODO 与3.0不一样
  
  import org.luaj.vm2.LuaError;
  import org.luaj.vm2.LuaFunction;
  import org.luaj.vm2.LuaValue;
  import org.luaj.vm2.Varargs;
  
  import java.lang.reflect.Method;
  
  /**
   * Subclass of {@link LuaFunction} common to Java functions exposed to lua.
   * <p/>
   * 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.
   * <p/>
   * 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.
   * <p/>
   * 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.
   * <ul>
   * <li>{@link ZeroArgFunction}</li>
   * <li>{@link OneArgFunction}</li>
   * <li>{@link TwoArgFunction}</li>
   * <li>{@link ThreeArgFunction}</li>
   * <li>{@link VarArgFunction}</li>
   * </ul>
   * <p/>
   * 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.
   * <p/>
   * For example, the following code will implement a library called "hyperbolic"
   * with two functions, "sinh", and "cosh":
   * <pre> {@code
   * import org.luaj.vm2.LuaValue;
   * import org.luaj.vm2.lib.*;
   * <p/>
   * public class hyperbolic extends TwoArgFunction {
   * <p/>
   * 	public hyperbolic() {}
   * <p/>
   * 	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;
   * 	}
   * <p/>
   * 	static class sinh extends OneArgFunction {
   * 		public LuaValue call(LuaValue x) {
   * 			return LuaValue.valueOf(Math.sinh(x.checkdouble()));
   * 		}
   * 	}
   * <p/>
   * 	static class cosh extends OneArgFunction {
   * 		public LuaValue call(LuaValue x) {
   * 			return LuaValue.valueOf(Math.cosh(x.checkdouble()));
   * 		}
   * 	}
   * }
   * }</pre>
   * The default constructor is used to instantiate the library
   * in response to {@code require 'hyperbolic'} statement,
   * provided it is on Java&quot;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.
   * <p/>
   * To test it, a script such as this can be used:
   * <pre> {@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) )
   * }</pre>
   * <p/>
   * It should produce something like:
   * <pre> {@code
   * t	table: 3dbbd23f
   * hyperbolic	table: 3dbbd23f
   * k,v	cosh	function: 3dbbd128
   * k,v	sinh	function: 3dbbd242
   * sinh(.5)	0.5210953
   * cosh(.5)	1.127626
   * }</pre>
   * <p/>
   * See the source code in any of the library functions
   * such as {@link BaseLib} or {@link TableLib} for other examples.
   */
  abstract public class LibFunction extends LuaFunction {
  
      /**
       * User-defined opcode to differentiate between instances of the library function class.
       * <p/>
       * Subclass will typicall switch on this value to provide the specific behavior for each function.
       */
      public int opcode;
  
      //反射方法
      public Method method;
  
      /**
       * The common name for this function, useful for debugging.
       * <p/>
       * Binding functions initialize this to the name to which it is bound.
       */
      public String name;
  
      /**
       * Default constructor for use by subclasses
       */
      protected LibFunction() {
      }
  
      public String tojstring() {
          return name != null ? name : super.tojstring();
      }
  
      /**
       * Bind a set of library functions.
       * <p/>
       * 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)
       */
      protected void bind(LuaValue env, Class factory, String[] names) {
          bind(env, factory, names, 0);
      }
  
      /**
       * Bind a set of library functions, with an offset
       * <p/>
       * 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[])
       */
      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.newInstance();
                  f.opcode = firstopcode + i;
                  f.name = names[i];
                  env.set(f.name, f);
              }
          } catch (Exception e) {
              throw new LuaError("bind failed: " + 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};
      }
  
      public LuaValue call() {
          return argerror(1, "value");
      }
  
      public LuaValue call(LuaValue a) {
          return call();
      }
  
      public LuaValue call(LuaValue a, LuaValue b) {
          return call(a);
      }
  
      public LuaValue call(LuaValue a, LuaValue b, LuaValue c) {
          return call(a, b);
      }
  
      public LuaValue call(LuaValue a, LuaValue b, LuaValue c, LuaValue d) {
          return call(a, b, c);
      }
  
      public Varargs invoke(Varargs args) {
          switch (args.narg()) {
              case 0:
                  return call();
              case 1:
                  return call(args.arg1());
              case 2:
                  return call(args.arg1(), args.arg(2));
              case 3:
                  return call(args.arg1(), args.arg(2), args.arg(3));
              default:
                  return call(args.arg1(), args.arg(2), args.arg(3), args.arg(4));
          }
      }
  } 
  