/**
 *  @(#) InvokeEvaluator.java
 *
 * JReversePro - Java Decompiler / Disassembler.
 * Copyright (C) 2008 Karthik Kumar.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *  
 *  	http://www.apache.org/licenses/LICENSE-2.0 
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 **/
package net.sf.jrevpro.ast.evaluator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import net.sf.jrevpro.ast.expression.Expression;
import net.sf.jrevpro.ast.expression.InstanceMethodAccessExpression;
import net.sf.jrevpro.ast.expression.MethodAccessExpression;
import net.sf.jrevpro.ast.intermediate.CompleteLine;
import net.sf.jrevpro.jvm.TypeInferrer;
import net.sf.jrevpro.reflect.instruction.Instruction;

/**
 * Evaluates the following invoke instructions.
 * 
 * <p>
 * <ul>
 * <li>invokeVirtual</li>
 * <li>invokeInterface</li>
 * <li>invokeSpecial</li>
 * <li>invokeStatic</li>
 * </ul>
 * 
 * @author akkumar
 * 
 */
public class InvokeEvaluator extends AbstractInstructionEvaluator {

  /**
   * @param context
   */
  public InvokeEvaluator(EvaluatorContext context) {
    super(context);
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * net.sf.jrevpro.decompile.evaluator.AbstractInstructionEvaluator#evaluate
   * (net.sf.jrevpro.reflect.instruction.Instruction)
   */
  @Override
  void evaluate(Instruction ins) {

    switch (ins.opcode) {
    case OPCODE_INVOKEVIRTUAL:
    case OPCODE_INVOKEINTERFACE:

      processInvokeInstruction(ins);
      break;

    }

  }

  /*
   * (non-Javadoc)
   * 
   * @seenet.sf.jrevpro.decompile.evaluator.AbstractInstructionEvaluator#
   * getProcessingOpcodes()
   */
  @Override
  Iterable<Integer> getProcessingOpcodes() {
    return Arrays.asList(OPCODE_INVOKEVIRTUAL, OPCODE_INVOKEINTERFACE);
  }

  /**
   * Processes an invoke instruction - invokespecial, invokeinterface,
   * invokevirtual.
   * 
   * @param ins
   *          Current Instruction that is to be operated on the JVM stack.
   * @param flagInvokeSpecial
   *          if this instruction is invokespecial.
   */
  private void processInvokeInstruction(Instruction ins) {
    int offset = ins.getArgUnsignedShort();
    int classIndex = pool.getPtr1(offset);

    int nameIndex = pool.getPtr2(offset);
    String methodName = pool.getFirstDirectName(nameIndex);
    String className = pool.getClassName(classIndex);
    String argsList = pool.getEntryValue(pool.getPtr2(nameIndex));

    List<String> jvmArgTypes = TypeInferrer.getArguments(argsList);
    int popMax = jvmArgTypes.size();
    // Equals Number of Arguments

    String methodType = TypeInferrer.getReturnType(argsList);

    List<Expression> argValues = new ArrayList<Expression>(popMax);
    for (int i = popMax - 1; i >= 0; i--) {
      // add arguments in reverse order
      argValues.add(0, evalMachine.pop());
    }

    Expression accessTarget = evalMachine.pop();

    MethodAccessExpression mex = new InstanceMethodAccessExpression(
        accessTarget, methodName, methodType, argValues, false);

    if (!methodType.equals(String.valueOf(JVM_TYPE_VOID))) {
      // Non-void method - Push the result back onto the stack
      evalMachine.push(mex);
    } else {
      statements.append(new CompleteLine(ins, mex));
    }

  }

}

@@ -1844,17 +1844,16 @@
 ERFACE:%0A
-%0A
       pr
@@ -2227,23 +2227,8 @@
 on -
- invokespecial,
  inv
@@ -2362,90 +2362,8 @@
 ck.%0A
-   * @param flagInvokeSpecial%0A   *          if this instruction is invokespecial.%0A
    *
@@ -2975,176 +2975,34 @@
 s = 
-new ArrayList%3CExpression%3E(popMax);%0A    for (int i = popMax - 1; i %3E= 0; i--) %7B%0A      // add arguments in reverse order%0A      argValues.add(0, evalMachine.pop());%0A    %7D%0A
+this.getArguments(popMax);
 %0A   
@@ -3414,10 +3414,534 @@
 %7D%0A%0A  %7D%0A%0A
+  /**%0A   * Retrieve the top N expressions from the expression stack.%0A   * %0A   * @param numArguments%0A   *          Number of arguments for which expressions need to be retrieved%0A   *          from the stack.%0A   * @return%0A   */%0A  List%3CExpression%3E getArguments(int numArguments) %7B%0A    List%3CExpression%3E expressions = new ArrayList%3CExpression%3E(numArguments);%0A    for (int i = numArguments - 1; i %3E= 0; i--) %7B%0A      // add arguments in reverse order%0A      expressions.add(0, evalMachine.pop());%0A    %7D%0A    return expressions;%0A  %7D%0A%0A
 %7D%0A

Refactor InvokeEvaluator to get arguments for an invoke instruction.