package net.sourceforge.javautil.bytecode.api.type.method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import net.sourceforge.javautil.bytecode.BytecodeException;
import net.sourceforge.javautil.bytecode.api.IBytecodeAssignable;
import net.sourceforge.javautil.bytecode.api.BytecodeContext;
import net.sourceforge.javautil.bytecode.api.IBytecodeField;
import net.sourceforge.javautil.bytecode.api.BytecodeFieldDeclared;
import net.sourceforge.javautil.bytecode.api.IBytecodeReferenceable;
import net.sourceforge.javautil.bytecode.api.BytecodeResolutionPool;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable;
import net.sourceforge.javautil.bytecode.api.LiteralValue;
import net.sourceforge.javautil.bytecode.api.TypeDescriptor;
import net.sourceforge.javautil.bytecode.api.type.AbstractType;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeWriterMethod.MathmaticalOperator;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.ArrayConstruction;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.ArrayInitialization;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.CastOperation;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.CoersionOperation;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.ConcatenationOperation;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.MathmaticalOperation;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.MethodInvocation;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.NewInstance;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.TypeLoad;
/**
* The context in which a {@link BytecodeMethodConcrete} or a {@link BytecodeConstructorBase} is written.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class BytecodeContextMethod<W extends IBytecodeWriterMethod> implements BytecodeContext<W> {
protected final BytecodeContext parent;
protected final IBytecodeMethod method;
protected final W writer;
protected List<TypeDescriptor> stack = new ArrayList<TypeDescriptor>();
protected int maxStack = 0;
protected List<BytecodeScope> scopes = new ArrayList<BytecodeScope>();
protected List<BytecodeScope> loops = new ArrayList<BytecodeScope>();
protected List<BytecodeLocalVariableDeclaration> localVariables = new ArrayList<BytecodeLocalVariableDeclaration>();
protected Map<String, BytecodeLocalVariableDeclaration> accessible = new LinkedHashMap<String, BytecodeLocalVariableDeclaration>();
protected List<BytecodeLocalVariableDeclaration> localVariablesStack = new ArrayList<BytecodeLocalVariableDeclaration>();
protected int maxLocal = 0;
protected int currentLocal;
protected List<BytecodeLocalVariableDeclaration> parameters = new ArrayList<BytecodeLocalVariableDeclaration>();
public BytecodeContextMethod(BytecodeContext parent, IBytecodeMethod method, W writer) {
this.parent = parent;
this.writer = writer;
this.method = method;
}
/**
* @return The method this context is for
*/
public IBytecodeMethod getMethod() { return method; }
/**
* @return The maximum amount of local variables at a given point
*/
public int getMaxLocalVariables () { return this.maxLocal; }
/**
* @return The local variables in this context
*/
public List<BytecodeLocalVariableDeclaration> getLocalVariables() {
return localVariables;
}
public BytecodeResolutionPool getResolutionPool() {
return parent.getResolutionPool();
}
public AbstractType getEnclosingType() {
return parent.getEnclosingType();
}
public BytecodeContext getParent() { return parent; }
public W getWriter() { return writer; }
public IBytecodeAssignable resolve(String name) {
if (this.accessible.containsKey(name)) return this.accessible.get(name);
return this.parent == null ? null : this.parent.resolve(name);
}
/**
* @param idx The index of the current lv stack
* @return The lv related to the index
*/
public BytecodeLocalVariableDeclaration getLocalVariable (int idx) {
return this.localVariablesStack.get(idx);
}
/**
* @return The count of parameters formally declared in this context
*/
public int getDeclaredParameterCount () { return this.parameters.size(); }
/**
* @param idx The index of the corresponding declared parameter
* @return The corresponding local variable declaration
*/
public BytecodeLocalVariableDeclaration getDeclaredParameter (int idx) {
return this.parameters.get(idx);
}
/**
* @return The current parameter types
*/
public TypeDescriptor[] getParameterTypes () {
TypeDescriptor[] types = new TypeDescriptor[parameters.size()];
for (int i=0; i<types.length; i++) {
types[i] = this.getDeclaredParameter(i).getType();
}
return types;
}
/**
* This is only for internal use and should not be invoked by third parties.
*
* @param name The name of the parameter
* @param type The type of the parameter
* @param isFinal True if the parameter value is final, otherwise false
* @return The local variable declaration
*/
public BytecodeLocalVariableDeclaration declareParameter (String name, TypeDescriptor type, boolean isFinal) {
BytecodeLocalVariableDeclaration blvd = this.declareLocalVariable(name, type, isFinal);
this.parameters.add(blvd);
return blvd;
}
public BytecodeLocalVariableDeclaration declareLocalVariable (String name, Class<?> type, boolean isFinal) {
return this.declareLocalVariable(name, parent.getResolutionPool().resolve(type.getName()), isFinal);
}
public BytecodeLocalVariableDeclaration declareLocalVariable (String name, IBytecodeResolvable type, boolean isFinal) {
return this.declareLocalVariable(name, type.getType(), isFinal);
}
/**
* @param name The name of the local variable
* @param type The type of the local variable
* @param isFinal True if this variable is final, otherwise false
*/
public BytecodeLocalVariableDeclaration declareLocalVariable (String name, TypeDescriptor type, boolean isFinal) {
if (this.accessible.containsKey(name)) throw new BytecodeException("A local variable by this name is accessible: " + name);
BytecodeLocalVariableDeclaration lv = new BytecodeLocalVariableDeclaration(currentLocal++, name, type,
new BytecodeScope(scopes.get(0), writer.mark(this), scopes.get(0).getEnd()), isFinal
);
this.localVariables.add(lv);
this.localVariablesStack.add(lv);
this.accessible.put(name, lv);
if (this.currentLocal > this.maxLocal) this.maxLocal = currentLocal;
return lv;
}
public void pushLoop (BytecodeScope scope) {
this.loops.add(0, scope);
}
public BytecodeScope popLoop (BytecodeScope scope) {
this.loops.remove(scope); return scope;
}
public BytecodeScope popLoop () {
return this.popLoop(loops.remove(0));
}
public BytecodeScope getCurrentLoop () {
return this.loops.get(0);
}
/**
* @return The amount of scopes currently on the scope stack
*/
public int getScopeCount () { return this.scopes.size(); }
/**
* @param idx The index of the scope
* @return The corresponding scope, or null if no such scope exists
*/
public BytecodeScope getScope (int idx) {
return this.scopes.size() <= idx ? null : this.scopes.get(idx);
}
/**
* @param block The block to add to the block stack
*/
public void push (BytecodeScope scope) { this.scopes.add(0, scope); }
/**
* @param block The block to pop off the stack
* @return The popped block if the same as on the stack, otherwise an exception will be thrown
*/
public BytecodeScope pop (BytecodeScope scope) {
BytecodeScope removed = this.scopes.remove(0);
if (removed != scope) throw new BytecodeException("Block pop() out of order");
List<String> toRemove = new ArrayList<String>();
for (String name : accessible.keySet()) {
if (accessible.get(name).getScope().getParent() == scope) {
toRemove.add(name);
}
}
for (String name : toRemove) {
this.localVariablesStack.remove( this.accessible.remove(name) );
}
this.currentLocal -= toRemove.size();
return removed;
}
/**
* @return The popped off scope
*/
public BytecodeScope popScope () {
return this.pop(scopes.get(0));
}
/**
* @return The maximum amount of items on the stack at any given point
*/
public int getMaxStackSize () { return this.maxStack; }
/**
* @return The amount of items currently on the stack
*/
public int getStackSize () { return this.stack.size(); }
/**
* @param idx The index of the stack item
* @return The item or null if no such item is on the stack
*/
public TypeDescriptor getStack (int idx) {
return this.stack.size() <= idx ? null : this.stack.get(idx);
}
/**
* @param types The types to push onto the stack
*/
public void push (TypeDescriptor type) {
this.stack.add(0, type);
if (this.stack.size() > this.maxStack) this.maxStack = this.stack.size();
}
/**
* @param type The type to pop
* @return The popped type if verified, otherwise throws an exception
*/
public TypeDescriptor pop (TypeDescriptor type) {
TypeDescriptor removed = this.stack.remove(0);
if (!removed.equals(type)) throw new BytecodeException("Type removed from stack inconsistent: " + type.toDescriptorString() + ", expected: " + removed.toDescriptorString());
return removed;
}
/**
* @return The popped off type from the stack
*/
public TypeDescriptor popStack () {
return pop(stack.get(0));
}
/**
* @param clazz The class to resolve
* @return The resolvable wrapper
*/
public IBytecodeResolvable resolve (Class clazz) {
return this.getResolutionPool().resolve(clazz.getName());
}
//
// High Level Bytecode API
//
public IBytecodeReferenceable[] translate (Object... arguments) {
IBytecodeReferenceable[] translated = new IBytecodeReferenceable[arguments.length];
for (int i=0; i<arguments.length; i++) {
if (arguments[i] instanceof IBytecodeReferenceable) {
translated[i] = (IBytecodeReferenceable) arguments[i];
} else {
translated[i] = new LiteralValue(arguments[i]);
}
}
return translated;
}
public void concat (IBytecodeReferenceable... objects) {
this.createConcat(objects).load(this);
}
public ConcatenationOperation createConcat (IBytecodeReferenceable... objects) {
return new ConcatenationOperation(objects);
}
public IBytecodeReferenceable[] getMethodArguments () {
return parameters.toArray(new IBytecodeReferenceable[parameters.size()]);
}
public void returnNull () {
writer.returnValue(this, null);
}
public void throwException (IBytecodeReferenceable instance) {
instance.load(this);
writer.throwException(this);
}
public void newInstance (IBytecodeResolvable type, IBytecodeReferenceable... parameters) {
this.newInstance(type, true, parameters);
}
public void newInstance (IBytecodeResolvable type, boolean duplicate, IBytecodeReferenceable... parameters) {
writer.newInstance(this, type.getType());
if (duplicate) writer.dup(this);
this.construct(null, type, parameters);
}
public NewInstance createNewInstanceInvocation (IBytecodeResolvable type, IBytecodeReferenceable... parameters) {
return new NewInstance(type.getType(), parameters);
}
public CastOperation createCast (TypeDescriptor target, IBytecodeReferenceable value) {
return new CastOperation(target, value);
}
public void cast (TypeDescriptor target, IBytecodeReferenceable value) {
this.createCast(target, value).load(this);
}
public CoersionOperation createCoersion (TypeDescriptor target, IBytecodeReferenceable value) {
return new CoersionOperation(target, value);
}
public void coerce (TypeDescriptor type, IBytecodeReferenceable value) {
this.createCoersion(type, value).load(this);
}
/**
* @see IBytecodeWriterMethod#jump(BytecodeContextMethod, IBytecodeMarker)
*/
public void jump (IBytecodeMarker marker) {
writer.jump(this, marker);
}
/**
* @see IBytecodeWriterMethod#jumpIfException(BytecodeContextMethod, IBytecodeMarker, IBytecodeMarker, IBytecodeMarker, TypeDescriptor)
*/
public void jumpIfException (IBytecodeMarker codeStart, IBytecodeMarker codeEnd, IBytecodeMarker handler, TypeDescriptor type) {
writer.jumpIfException(this, codeStart, codeEnd, handler, type);
}
/**
* @see IBytecodeWriterMethod#jumpFinally(BytecodeContextMethod, IBytecodeMarker, IBytecodeMarker)
*/
public void jumpFinally (IBytecodeMarker codeStart, IBytecodeMarker finallyMarker) {
writer.jumpFinally(this, codeStart, finallyMarker);
}
/**
* @see IBytecodeWriterMethod#mark(BytecodeContextMethod)
*/
public IBytecodeMarker mark () { return writer.mark(this); }
/**
* @see IBytecodeWriterMethod#mark(BytecodeContextMethod, IBytecodeMarker)
*/
public void mark (IBytecodeMarker marker) { writer.mark(this, marker); }
/**
* @see IBytecodeWriterMethod#createMarker(BytecodeContextMethod)
*/
public IBytecodeMarker createMarker () { return writer.createMarker(this); }
/**
* Load the null value onto the stack
*/
public void loadNull () { writer.loadNull(this); }
/**
* @param name The name of a variable
*
* @see #get(IBytecodeReferenceable, IBytecodeReferenceable...)
*/
public void get (String name, IBytecodeReferenceable... indices) {
this.get(resolve(name), indices);
}
public void get (String name) {
IBytecodeReferenceable resolved = resolve(name);
if (resolved instanceof IBytecodeField && !((IBytecodeField)resolved).getAccess().isStatic()) {
resolve("this").load(this);
}
resolved.load(this);
}
public void loadType (IBytecodeResolvable type) {
writer.loadType(this, type);
}
public FieldInstance getThisField (String name) {
return new FieldInstance(resolve("this"), getEnclosingType().getField(getResolutionPool(), name));
}
public IBytecodeField getStaticField (String name) {
return getEnclosingType().getField(getResolutionPool(), name);
}
/**
* @param array The array from which to load the value
* @param indices The indices for the matrix point to load
*/
public void get (IBytecodeReferenceable array, IBytecodeReferenceable... indices) {
array.load(this);
TypeDescriptor type = array.getType();
for (int i=0; i<indices.length; i++) {
indices[i].load(this);
writer.arrayLoad(this, type);
type = type.getComponentType();
}
}
/**
* @param name The name of an array variable
*
* @see #setArrayIndexValue(IBytecodeReferenceable, IBytecodeReferenceable, IBytecodeReferenceable...)
*/
public void set (String name, IBytecodeReferenceable value, IBytecodeReferenceable... indices) {
this.setArrayIndexValue(resolve(name), value, indices);
}
/**
* @param array The array whose indice will be set
* @param value The value to set to the specified indice
* @param indices The set matrix point
*/
public void setArrayIndexValue (IBytecodeReferenceable array, IBytecodeReferenceable value, IBytecodeReferenceable... indices) {
array.load(this);
TypeDescriptor type = array.getType();
int load = indices.length - 1;
for (int i=0; i<load; i++) {
indices[i].load(this);
writer.arrayLoad(this, type);
type = type.getComponentType();
}
indices[load].load(this);
if (value == null) loadNull(); else value.load(this);
writer.arrayStore(this);
}
public void set (String name, String fieldName, IBytecodeReferenceable value) {
this.set(resolve(name), fieldName, value);
}
public void set (IBytecodeReferenceable instance, String fieldName, IBytecodeReferenceable value) {
instance.load(this);
if (value != null) value.load(this);
else writer.loadNull(this);
instance.getType(this).getField(this.getResolutionPool(), fieldName).store(this);
}
/**
* This will resolve the name to an assignable member.
*
* @param name The name of a local variable or class field
*
* @see #set(IBytecodeAssignable, IBytecodeReferenceable)
* @see #resolve(String)
*/
public void set (String name, IBytecodeReferenceable value) {
set(resolve(name), value);
}
/**
*
* @param name An assignable member
* @param value The value to assign
*/
public void set (IBytecodeAssignable assignable, IBytecodeReferenceable value) {
value.load(this);
assignable.store(this);
}
/**
* Add arg1 and arg2.
*
* @param arg1 The first numerical argument
* @param arg2 The second numerical argument
*/
public void add (IBytecodeReferenceable arg1, IBytecodeReferenceable arg2) {
this.writer.doMath(this, arg1, arg2, MathmaticalOperator.Plus);
}
/**
* Minus arg2 from arg1.
*
* @param arg1 The first numerical argument
* @param arg2 The second numerical argument
*/
public void minus (IBytecodeReferenceable arg1, IBytecodeReferenceable arg2) {
this.writer.doMath(this, arg1, arg2, MathmaticalOperator.Minus);
}
/**
* Multiply arg1 by arg2.
*
* @param arg1 The first numerical argument
* @param arg2 The second numerical argument
*/
public void multiply (IBytecodeReferenceable arg1, IBytecodeReferenceable arg2) {
this.writer.doMath(this, arg1, arg2, MathmaticalOperator.Multiply);
}
/**
* Divide arg1 by arg2.
*
* @param arg1 The first numerical argument
* @param arg2 The second numerical argument
*/
public void divide (IBytecodeReferenceable arg1, IBytecodeReferenceable arg2) {
this.writer.doMath(this, arg1, arg2, MathmaticalOperator.Divide);
}
public MathmaticalOperation createDivideOperation (IBytecodeReferenceable arg1, IBytecodeReferenceable arg2) {
return this.createMathOperation(arg1, arg2, MathmaticalOperator.Divide);
}
public MathmaticalOperation createMultiplyOperation (IBytecodeReferenceable arg1, IBytecodeReferenceable arg2) {
return this.createMathOperation(arg1, arg2, MathmaticalOperator.Multiply);
}
public MathmaticalOperation createMinusOperation (IBytecodeReferenceable arg1, IBytecodeReferenceable arg2) {
return this.createMathOperation(arg1, arg2, MathmaticalOperator.Minus);
}
public MathmaticalOperation createAddOperation (IBytecodeReferenceable arg1, IBytecodeReferenceable arg2) {
return this.createMathOperation(arg1, arg2, MathmaticalOperator.Plus);
}
public MathmaticalOperation createMathOperation (IBytecodeReferenceable arg1, IBytecodeReferenceable arg2, MathmaticalOperator operator) {
return new MathmaticalOperation(arg1, arg2, operator);
}
public void systemPrintLn (IBytecodeReferenceable value) {
invoke(resolve(System.class).getField(getResolutionPool(), "out"), "println", value);
}
/**
* Regular no value return.
*/
public void returnVoid () { this.writer.returnVoid(this); }
/**
* @param name The name of the variable to resolve
*
* @see #resolve(String)
*/
public void returnValue (String name) { returnValue(resolve(name)); }
/**
* @param referenceable The value to return
*/
public void returnValue (IBytecodeReferenceable expression) {
TypeDescriptor expectedReturnType = method.getDescriptor().getReturnType();
if (expectedReturnType == null || expectedReturnType == TypeDescriptor.VOID) {
if (expression != null) expression.load(this);
this.returnVoid();
} else {
if (expression == null) this.returnNull();
else {
this.coerce(expectedReturnType, expression);
this.writer.returnValue(this, expectedReturnType);
}
}
}
/**
* @param name The name of a method available to this class
* @param parameters The parameters to pass to the method invocation
*/
public void invokeThis (String name, IBytecodeReferenceable... parameters) {
this.invoke(resolve("this"), name, parameters);
}
/**
* @param name The name of the method in the super class
* @param parameters The parameters to pass to the method invocation
*/
public void invokeSuper (String name, IBytecodeReferenceable... parameters) {
this.createSuperInvocation(name, parameters).load(this);
}
/**
* @param instance The instance on which to invoke the method
* @param name The name of the method to invoke
* @param parameters The parameters to pass to the invocation
*/
public void invoke (IBytecodeReferenceable instance, String name, IBytecodeReferenceable... parameters) {
this.createInvocation(instance, name, parameters).load(this);
}
/**
* @param type The type to invoke the method on
* @param name The name of the static method
* @param parameters The parameters for the method
*/
public void invoke (IBytecodeResolvable type, String name, IBytecodeReferenceable... parameters) {
this.createInvocation(type, name, parameters).load(this);
}
/**
* @param type The type to create
* @param indices The indices of the array
*/
public void newArray (IBytecodeResolvable type, IBytecodeReferenceable... indices) {
this.createArray(type, indices).load(this);
}
/**
* @param type The root component type of the array
* @param indices The indices of the array
* @return The array construction
*/
public ArrayConstruction createArray (IBytecodeResolvable type, IBytecodeReferenceable... indices) {
return new ArrayConstruction(type.getType(), indices);
}
/**
* @param type The root component type of the array
* @param values The values to load into the array
* @return The array initialization
*/
public ArrayInitialization initializeArray (IBytecodeResolvable type, IBytecodeReferenceable... values) {
return new ArrayInitialization(type.getType(), values);
}
/**
* @param parameters The parameters to pass to another constructor
*/
public void thisConstruct (IBytecodeReferenceable... parameters) {
this.construct(resolve("this"), getEnclosingType(), parameters);
}
/**
* @param parameters The parameters to pass to the super constructor
*/
public void superConstruct (IBytecodeReferenceable... parameters) {
IBytecodeResolvable type = this.getEnclosingType().getSuperType();
if (type == null) type = getResolutionPool().resolve(Object.class.getName());
this.construct(resolve("this"), type, parameters);
}
/**
* @param type The type to construct
* @param parameters The parameters to pass
*/
public void construct (IBytecodeReferenceable instance, IBytecodeResolvable type, IBytecodeReferenceable... parameters) {
this.createConstructorInvocation(instance, type, parameters).load(this);
}
/**
* Looks up the super method for the specified parameters
*
* @see #createInvocation(BytecodeContextMethod, IBytecodeMethod, IBytecodeReferenceable...)
*/
public MethodInvocation createSuperInvocation (String name, IBytecodeReferenceable... parameters) {
IBytecodeResolvable st = this.getEnclosingType().getSuperType();
if (st == null) st = this.getResolutionPool().resolve(Object.class.getName());
IBytecodeMethod method = st.findMethod(this.getResolutionPool(), name, getTypes(parameters));
if (method == null)
throw new BytecodeException("No such method could be found: " + name + " for " + st.getType().toDescriptorString());
return this.createInvocation(resolve("this"), method, parameters);
}
/**
* This will allow any resolvable type to be invoked upon
*
* @param type The type to invoke the method on
*
* @see #createInvocation(BytecodeContextMethod, IBytecodeMethod, IBytecodeReferenceable...)
*/
public MethodInvocation createInvocation (IBytecodeReferenceable instance, String name, IBytecodeReferenceable... parameters) {
IBytecodeMethod method = instance.getType(this).findMethod(this.getResolutionPool(), name, getTypes(parameters));
if (method == null)
throw new BytecodeException("No such method could be found: " + name + " for " + instance.getType().toDescriptorString());
return this.createInvocation(instance, method, parameters);
}
/**
* @param type The type for method lookup
* @param name The name of the static method
* @param parameters The parameters for the method invocation
* @return The method invocation
*/
public MethodInvocation createInvocation (IBytecodeResolvable type, String name, IBytecodeReferenceable... parameters) {
IBytecodeMethod method = type.findMethod(this.getResolutionPool(), name, getTypes(parameters));
if (method == null)
throw new BytecodeException("No such method could be found: " + name + " for " + type.getType().toDescriptorString());
return this.createInvocation(null, method, parameters);
}
public TypeLoad createTypeLoad (IBytecodeResolvable type) {
return new TypeLoad(type);
}
/**
* @param context The context in which to invoke the method
* @param method The method to invoke
* @param parameters The parameters to pass to the invocation
* @return The return value
*/
public MethodInvocation createInvocation (IBytecodeReferenceable instance, IBytecodeMethod method, IBytecodeReferenceable... parameters) {
return new MethodInvocation(instance, method, parameters);
}
/**
* @param parameters The parameters to pass to the this() constructor
* @return The method invocation
*/
public MethodInvocation createThisConstructorInvocation (IBytecodeReferenceable... parameters) {
return this.createConstructorInvocation(resolve("this"), getEnclosingType(), parameters);
}
/**
* @param parameters The parameters to pass to the super constructor
* @return The method invocation
*/
public MethodInvocation createSuperConstructorInvocation (IBytecodeReferenceable... parameters) {
IBytecodeResolvable st = getEnclosingType().getSuperType() == null ?
getResolutionPool().resolve(Object.class.getName()) : getEnclosingType().getSuperType();
return this.createConstructorInvocation(resolve("this"), st, parameters);
}
/**
* @param type The type the constructor is for
* @param parameters The parameters to pass to the constructor
* @return The method invocation for the constructor
*/
public MethodInvocation createConstructorInvocation (IBytecodeReferenceable instance, IBytecodeResolvable type, IBytecodeReferenceable... parameters) {
return new MethodInvocation(instance, type.findConstructor(this.getResolutionPool(), getTypes(parameters)), parameters);
}
public TypeDescriptor[] getTypes (IBytecodeReferenceable... arguments) {
TypeDescriptor[] types = new TypeDescriptor[arguments.length];
for (int i=0; i<arguments.length; i++) types[i] = arguments[i].getType();
return types;
}
}