public static Object invoke(InvocationState invocationState,Class<?> targetClass,Object o,Object functionalObject,Class<?> invoker,String method,boolean[] primitives,Object[] args) throws Throwable {
  if (primitives.length != args.length)   throw new LtBug("primitives.length should equal to args.length");
  List<Method> methodList=new ArrayList<>();
  Queue<Class<?>> interfaces=new ArrayDeque<>();
  Class<?> c=o == null ? targetClass : o.getClass();
  while (c != null) {
    Collections.addAll(interfaces,c.getInterfaces());
    fillMethodCandidates(c,invoker,method,args,methodList,o == null);
    c=c.getSuperclass();
  }
  c=o == null ? targetClass : o.getClass();
  Collections.addAll(interfaces,c.getInterfaces());
  while (!interfaces.isEmpty()) {
    Class<?> i=interfaces.remove();
    fillMethodCandidates(i,invoker,method,args,methodList,o == null);
    Collections.addAll(interfaces,i.getInterfaces());
  }
  if (methodList.isEmpty()) {
    if (c.isArray()) {
      if (method.equals("get") && args.length >= 1 && args[0] instanceof Integer) {
        Object res=Array.get(o,(Integer)args[0]);
        if (args.length == 1)         return res;
        boolean[] bs=new boolean[primitives.length - 1];
        Object[] as=new Object[args.length - 1];
        for (int i=1; i < args.length; ++i) {
          bs[i - 1]=primitives[i];
          as[i - 1]=args[i];
        }
        return invoke(invocationState,targetClass,res,null,invoker,"get",bs,as);
      }
 else       if (method.equals("set") && args.length >= 2 && args[0] instanceof Integer) {
        if (args.length == 2) {
          Array.set(o,(Integer)args[0],args[1]);
          return args[1];
        }
 else {
          Object elem=Array.get(o,(Integer)args[0]);
          boolean[] bs=new boolean[primitives.length - 1];
          Object[] as=new Object[args.length - 1];
          for (int i=1; i < args.length; ++i) {
            bs[i - 1]=primitives[i];
            as[i - 1]=args[i];
          }
          return invoke(invocationState,targetClass,elem,null,invoker,"set",bs,as);
        }
      }
    }
 else {
      if (args.length == 1 && isBoxType(c) && isBoxType(args[0].getClass())) {
        return invokePrimitive(o,method,args[0]);
      }
 else       if (args.length == 0 && isBoxType(c)) {
        return invokePrimitive(o,method);
      }
 else       if (method.equals("add") && args.length == 1 && (args[0] instanceof String || o instanceof String)) {
        return String.valueOf(o) + String.valueOf(args[0]);
      }
 else       if (method.equals("set")) {
        return invoke(invocationState,targetClass,o,functionalObject,invoker,"put",primitives,args);
      }
 else       if (method.equals("logicNot") && args.length == 0) {
        return !LtRuntime.castToBool(o);
      }
    }
    if (!invocationState.isCallingReverse) {
      if (o != null && args.length == 1 && args[0] != null) {
        String methodName="reverse_" + method;
        Object _2=args[0];
        InvocationState reverseInvocationState=new InvocationState();
        reverseInvocationState.isCallingReverse=true;
        try {
          return invoke(reverseInvocationState,_2.getClass(),_2,null,invoker,methodName,new boolean[]{false},new Object[]{o});
        }
 catch (        Throwable t) {
          if (reverseInvocationState.methodFound) {
            throw t;
          }
        }
      }
      if (functionalObject != null) {
        InvocationState callFunctionalState=new InvocationState();
        try {
          return callFunctionalObject(callFunctionalState,functionalObject,invoker,args);
        }
 catch (        Throwable t) {
          if (callFunctionalState.methodFound)           throw t;
        }
      }
      invocationState.methodFound=false;
      Method call=null;
      try {
        Class<?> cc=targetClass;
        if (o != null) {
          cc=o.getClass();
        }
        call=cc.getMethod("call",Object.class,String.class,boolean[].class,Object[].class);
        if (Modifier.isStatic(call.getModifiers()) && !call.getReturnType().equals(void.class)) {
          invocationState.methodFound=true;
        }
      }
 catch (      NoSuchMethodException ignore) {
      }
      if (invocationState.methodFound) {
        assert call != null;
        try {
          return call.invoke(null,o,method,primitives,args);
        }
 catch (        InvocationTargetException e) {
          throw e.getTargetException();
        }
      }
    }
    if (!invocationState.fromField && !invocationState.isCallingReverse) {
      Object result=LtRuntime.getField(o,method,invoker);
      if (result != null && !result.equals(Unit.get())) {
        invocationState.methodFound=true;
        return callFunctionalObject(result,invoker,args);
      }
    }
    StringBuilder sb=new StringBuilder().append(o == null ? targetClass.getName() : o.getClass().getName()).append("#").append(method).append("(");
    boolean isFirst=true;
    for (    Object arg : args) {
      if (isFirst)       isFirst=false;
 else       sb.append(", ");
      sb.append(arg == null ? "null" : arg.getClass().getName());
    }
    sb.append(")");
    throw new LtRuntimeException("cannot find method to invoke: " + sb.toString());
  }
  Method methodToInvoke=findBestMatch(methodList,args,primitives);
  invocationState.methodFound=true;
  transToRequiredType(args,methodToInvoke.getParameterTypes());
  methodToInvoke.setAccessible(true);
  try {
    Object res=methodToInvoke.invoke(o,args);
    if (methodToInvoke.getReturnType() == void.class)     return Unit.get();
 else     return res;
  }
 catch (  InvocationTargetException e) {
    throw e.getTargetException();
  }
}

public static Object invoke ( InvocationState invocationState , Class < ? > targetClass , Object o , Object functionalObject , Class < ? > invoker , String method , boolean [ ] primitives , Object [ ] args ) throws Throwable { if ( primitives . length != args . length ) throw new LtBug ( "primitives.length should equal to args.length" ) ; List < Method > methodList = new ArrayList < > ( ) ; Queue < Class < ? > > interfaces = new ArrayDeque < > ( ) ; Class < ? > c = o == null ? targetClass : o . getClass ( ) ; while ( c != null ) { Collections . addAll ( interfaces , c . getInterfaces ( ) ) ; fillMethodCandidates ( c , invoker , method , args , methodList , o == null ) ; c = c . getSuperclass ( ) ; } c = o == null ? targetClass : o . getClass ( ) ; Collections . addAll ( interfaces , c . getInterfaces ( ) ) ; while ( ! interfaces . isEmpty ( ) ) { Class < ? > i = interfaces . remove ( ) ; fillMethodCandidates ( i , invoker , method , args , methodList , o == null ) ; Collections . addAll ( interfaces , i . getInterfaces ( ) ) ; } if ( methodList . isEmpty ( ) ) { if ( c . isArray ( ) ) { if ( method . equals ( "get" ) && args . length >= 1 && args [ 0 ] instanceof Integer ) { Object res = Array . get ( o , ( Integer ) args [ 0 ] ) ; if ( args . length == 1 ) return res ; boolean [ ] bs = new boolean [ primitives . length - 1 ] ; Object [ ] as = new Object [ args . length - 1 ] ; for ( int i = 1 ; i < args . length ; ++ i ) { bs [ i - 1 ] = primitives [ i ] ; as [ i - 1 ] = args [ i ] ; } return invoke ( invocationState , targetClass , res , null , invoker , "get" , bs , as ) ; } else if ( method . equals ( "set" ) && args . length >= 2 && args [ 0 ] instanceof Integer ) { if ( args . length == 2 ) { Array . set ( o , ( Integer ) args [ 0 ] , args [ 1 ] ) ; return args [ 1 ] ; } else { Object elem = Array . get ( o , ( Integer ) args [ 0 ] ) ; boolean [ ] bs = new boolean [ primitives . length - 1 ] ; Object [ ] as = new Object [ args . length - 1 ] ; for ( int i = 1 ; i < args . length ; ++ i ) { bs [ i - 1 ] = primitives [ i ] ; as [ i - 1 ] = args [ i ] ; } return invoke ( invocationState , targetClass , elem , null , invoker , "set" , bs , as ) ; } } } else { if ( args . length == 1 && isBoxType ( c ) && isBoxType ( args [ 0 ] . getClass ( ) ) ) { return invokePrimitive ( o , method , args [ 0 ] ) ; } else if ( args . length == 0 && isBoxType ( c ) ) { return invokePrimitive ( o , method ) ; } else if ( method . equals ( "add" ) && args . length == 1 && ( args [ 0 ] instanceof String || o instanceof String ) ) { return String . valueOf ( o ) + String . valueOf ( args [ 0 ] ) ; } else if ( method . equals ( "set" ) ) { return invoke ( invocationState , targetClass , o , functionalObject , invoker , "put" , primitives , args ) ; } else if ( method . equals ( "logicNot" ) && args . length == 0 ) { return ! LtRuntime . castToBool ( o ) ; } } if ( ! invocationState . isCallingReverse ) { if ( o != null && args . length == 1 && args [ 0 ] != null ) { String methodName = "reverse_" + method ; Object _2 = args [ 0 ] ; InvocationState reverseInvocationState = new InvocationState ( ) ; reverseInvocationState . isCallingReverse = true ; try { return invoke ( reverseInvocationState , _2 . getClass ( ) , _2 , null , invoker , methodName , new boolean [ ] { false } , new Object [ ] { o } ) ; } catch ( Throwable t ) { if ( reverseInvocationState . methodFound ) { throw t ; } } } if ( functionalObject != null ) { InvocationState callFunctionalState = new InvocationState ( ) ; try { return callFunctionalObject ( callFunctionalState , functionalObject , invoker , args ) ; } catch ( Throwable t ) { if ( callFunctionalState . methodFound ) throw t ; } } invocationState . methodFound = false ; Method call = null ; try { Class < ? > cc = targetClass ; if ( o != null ) { cc = o . getClass ( ) ; } call = cc . getMethod ( "call" , Object . class , String . class , boolean [ ] . class , Object [ ] . class ) ; if ( Modifier . isStatic ( call . getModifiers ( ) ) && ! call . getReturnType ( ) . equals ( void . class ) ) { invocationState . methodFound = true ; } } catch ( NoSuchMethodException ignore ) { } if ( invocationState . methodFound ) { assert call != null ; try { return call . invoke ( null , o , method , primitives , args ) ; } catch ( InvocationTargetException e ) { throw e . getTargetException ( ) ; } } } if ( ! invocationState . fromField && ! invocationState . isCallingReverse ) { Object result = LtRuntime . getField ( o , method , invoker ) ; if ( result != null && ! result . equals ( Unit . get ( ) ) ) { invocationState . methodFound = true ; return callFunctionalObject ( result , invoker , args ) ; } } StringBuilder sb = new StringBuilder ( ) . append ( o == null ? targetClass . getName ( ) : o . getClass ( ) . getName ( ) ) . append ( "#" ) . append ( method ) . append ( "(" ) ; boolean isFirst = true ; for ( Object arg : args ) { if ( isFirst ) isFirst = false ; else sb . append ( ", " ) ; sb . append ( arg == null ? "null" : arg . getClass ( ) . getName ( ) ) ; } sb . append ( ")" ) ; throw new LtRuntimeException ( "cannot find method to invoke: " + sb . toString ( ) ) ; } Method methodToInvoke = findBestMatch ( methodList , args , primitives ) ; invocationState . methodFound = true ; transToRequiredType ( args , methodToInvoke . getParameterTypes ( ) ) ; methodToInvoke . setAccessible ( true ) ; try { Object res = methodToInvoke . invoke ( o , args ) ; if ( methodToInvoke . getReturnType ( ) == void . class ) return Unit . get ( ) ; else return res ; } catch ( InvocationTargetException e ) { throw e . getTargetException ( ) ; } }
invoke method with a invocationstate .
