forked from JavaTX/JavaCompilerCore
359 lines
12 KiB
Java
Executable File
359 lines
12 KiB
Java
Executable File
// ino.module.MethodCall.8639.package
|
|
package de.dhbwstuttgart.syntaxtree.statement;
|
|
// ino.end
|
|
// ino.module.MethodCall.8639.import
|
|
import java.util.Hashtable;
|
|
|
|
import org.apache.commons.bcel6.Constants;
|
|
import org.apache.commons.bcel6.generic.ClassGen;
|
|
import org.apache.commons.bcel6.generic.InstructionFactory;
|
|
import org.apache.commons.bcel6.generic.InstructionHandle;
|
|
import org.apache.commons.bcel6.generic.InstructionList;
|
|
|
|
import de.dhbwstuttgart.typeinference.Menge;
|
|
import de.dhbwstuttgart.bytecode.ClassGenerator;
|
|
import de.dhbwstuttgart.logger.Logger;
|
|
import de.dhbwstuttgart.myexception.JVMCodeException;
|
|
import de.dhbwstuttgart.syntaxtree.Method;
|
|
import de.dhbwstuttgart.syntaxtree.SyntaxTreeNode;
|
|
import de.dhbwstuttgart.syntaxtree.misc.UsedId;
|
|
import de.dhbwstuttgart.syntaxtree.type.GenericTypeVar;
|
|
import de.dhbwstuttgart.syntaxtree.type.Type;
|
|
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
|
import de.dhbwstuttgart.syntaxtree.type.Void;
|
|
import de.dhbwstuttgart.typeinference.ConstraintsSet;
|
|
import de.dhbwstuttgart.typeinference.JavaCodeResult;
|
|
import de.dhbwstuttgart.typeinference.OderConstraint;
|
|
import de.dhbwstuttgart.typeinference.ResultSet;
|
|
import de.dhbwstuttgart.typeinference.UndConstraint;
|
|
import de.dhbwstuttgart.typeinference.assumptions.ClassAssumption;
|
|
import de.dhbwstuttgart.typeinference.assumptions.MethodAssumption;
|
|
import de.dhbwstuttgart.typeinference.assumptions.TypeAssumptions;
|
|
import de.dhbwstuttgart.typeinference.exceptions.TypeinferenceException;
|
|
|
|
|
|
|
|
|
|
// ino.class.MethodCall.25623.declaration
|
|
public class MethodCall extends Expr
|
|
// ino.end
|
|
// ino.class.MethodCall.25623.body
|
|
{
|
|
public MethodCall(Receiver receiver, String methodName, ArgumentList argumentList, int offset){
|
|
this(offset, 0);
|
|
this.set_Receiver(receiver);
|
|
this.set_Name(methodName);
|
|
this.set_ArgumentList(argumentList);
|
|
}
|
|
|
|
// ino.method.MethodCall.25627.definition
|
|
public MethodCall(int offset, int variableLength)
|
|
// ino.end
|
|
// ino.method.MethodCall.25627.body
|
|
{
|
|
super(offset,variableLength);
|
|
}
|
|
// ino.end
|
|
|
|
// ino.attribute.receiver.25639.declaration
|
|
/**
|
|
* Diese Variable speichert die Expression, welche die Klasse von welcher die Methode aufgerufen wird darstellt.
|
|
*/
|
|
private Receiver receiver;
|
|
// ino.end
|
|
// ino.attribute.arglist.25642.declaration
|
|
private ArgumentList arglist=new ArgumentList();
|
|
|
|
// ino.attribute.parserlog.25663.declaration
|
|
protected static Logger parserlog = Logger.getLogger("parser");
|
|
// ino.end
|
|
|
|
// ino.method.set_ArgumentList.25666.definition
|
|
public void set_ArgumentList(ArgumentList al)
|
|
// ino.end
|
|
// ino.method.set_ArgumentList.25666.body
|
|
{
|
|
this.arglist = al;
|
|
}
|
|
// ino.end
|
|
|
|
// ino.method.getArgumentList.25669.definition
|
|
public ArgumentList getArgumentList()
|
|
// ino.end
|
|
// ino.method.getArgumentList.25669.body
|
|
{
|
|
if(this.arglist==null)return this.arglist = new ArgumentList();
|
|
return this.arglist;
|
|
}
|
|
// ino.end
|
|
|
|
// ino.method.get_Receiver.25672.definition
|
|
public Receiver get_Receiver()
|
|
// ino.end
|
|
// ino.method.get_Receiver.25672.body
|
|
{
|
|
return receiver;
|
|
}
|
|
// ino.end
|
|
|
|
// ino.method.get_Name.25675.definition
|
|
public String get_Name()
|
|
// ino.end
|
|
// ino.method.get_Name.25675.body
|
|
{
|
|
return this.usedid.name.firstElement();
|
|
}
|
|
// ino.end
|
|
|
|
public void set_Name(String name){
|
|
|
|
this.usedid = new UsedId(name, 0);
|
|
}
|
|
|
|
|
|
// ino.method.set_Receiver.25693.definition
|
|
public void set_Receiver(Receiver rec)
|
|
// ino.end
|
|
// ino.method.set_Receiver.25693.body
|
|
{
|
|
receiver=rec;
|
|
}
|
|
// ino.end
|
|
|
|
// ino.method.set_UsedId.25696.definition
|
|
public void set_UsedId(UsedId u)
|
|
// ino.end
|
|
// ino.method.set_UsedId.25696.body
|
|
{
|
|
usedid=u;
|
|
}
|
|
// ino.end
|
|
|
|
// ino.method.set_Expr_Menge.25699.definition
|
|
public void set_Expr_Menge(Menge<Expr> v)
|
|
// ino.end
|
|
// ino.method.set_Expr_Menge.25699.body
|
|
{
|
|
arglist.expr=v;
|
|
}
|
|
// ino.end
|
|
|
|
// ino.method.add_Expr.25702.definition
|
|
public void add_Expr(Expr e)
|
|
// ino.end
|
|
// ino.method.add_Expr.25702.body
|
|
{
|
|
arglist.expr.addElement(e);
|
|
}
|
|
// ino.end
|
|
|
|
|
|
|
|
|
|
|
|
// ino.method.toString.25738.defdescription type=javadoc
|
|
/**
|
|
* <br/>Author: Martin Pl�micke
|
|
* @return
|
|
*/
|
|
// ino.end
|
|
// ino.method.toString.25738.definition
|
|
public String toString()
|
|
// ino.end
|
|
// ino.method.toString.25738.body
|
|
{
|
|
//return receiver/*.toString()*/ + " " + usedid.toString();
|
|
return type + " (" + this.get_Receiver() + "." + this.get_Name() +"(" + this.getArgumentList() + "))";
|
|
}
|
|
// ino.end
|
|
|
|
// ino.method.wandleRefTypeAttributes2GenericAttributes.25741.definition
|
|
public void wandleRefTypeAttributes2GenericAttributes(Menge<Type> paralist, Menge<GenericTypeVar> genericMethodParameters)
|
|
// ino.end
|
|
// ino.method.wandleRefTypeAttributes2GenericAttributes.25741.body
|
|
{
|
|
}
|
|
// ino.end
|
|
|
|
/**
|
|
* @author Andreas Stadelmeier, a10023
|
|
* @return der Name der Methode, welcher dieser MethodCall aufruft.
|
|
*/
|
|
public String getName(){
|
|
return this.usedid.toString();
|
|
}
|
|
|
|
/**
|
|
* @author AI10023 - Andreas Stadelmeier
|
|
*
|
|
* Mögliche Probleme:
|
|
* Wenn die Methode ohne Angabe eines Receivers im Quelltext steht:
|
|
* methodCall(param); -> (bedeutet:) this.methodCall(param);
|
|
* Parser möglicherweise anpassen (siehe JavaParser.jay Zeile 1858 ff)
|
|
*/
|
|
@Override
|
|
public ConstraintsSet TYPEExpr(TypeAssumptions assumptions) {
|
|
//Hier der Ablauf für einen Methodenaufruf:
|
|
ConstraintsSet ret = new ConstraintsSet();
|
|
//Der Return-Type des MEthodenaufrufs ist zunächst unbekannt:
|
|
this.setType(TypePlaceholder.fresh(this));
|
|
//Berechne die Constraints des Receivers
|
|
if(receiver == null){
|
|
receiver = new Receiver(new This(this));
|
|
}
|
|
ret.add(receiver.get_Expr().TYPEExpr(assumptions));
|
|
|
|
//Berechne die Constraints der Argumente aus der Argumentlist (also der Parameter, welche der Funktion übergeben wurden)
|
|
if(this.arglist != null)for(Expr arg : this.arglist.expr){
|
|
ret.add(arg.TYPEExpr(assumptions));
|
|
}
|
|
|
|
//Noch das Overloading-Constraint anhängen:
|
|
ret.add(overloading(assumptions));
|
|
|
|
/*
|
|
//Die Klasse für den Receiver setzen: Das ist für die Bytecodegenerierung notwendig.
|
|
ClassAssumption receiverClassAssumption = assumptions.getClassAssumptionFor(receiver.get_Expr().getType());
|
|
de.dhbwstuttgart.syntaxtree.Class receiverCl = receiverClassAssumption.getAssumedClass();
|
|
this.receiver.setClass(receiverCl);
|
|
*/
|
|
//Die Assumptions für den Receiver setzen:
|
|
this.receiver.setAssumptions(assumptions);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Erstellt die Constraints für den eigentlichen Methodenaufruf.
|
|
* Sucht in den Assumptions nach passenden Methoden und erstellt ein OderConstraintSet.
|
|
* @param assumptions
|
|
* @return
|
|
*/
|
|
public ConstraintsSet overloading(TypeAssumptions assumptions){
|
|
ConstraintsSet ret = new ConstraintsSet();
|
|
//ret.add(new Overloading(assumptions, this, this.getType()).generateConsstraints());
|
|
OderConstraint oCons = new OderConstraint();
|
|
Menge<MethodAssumption> methodAssumptions = assumptions.getMethodAssumptions(this.getName(), this.getArgumentList().size());
|
|
if(methodAssumptions.size()==0)throw new TypeinferenceException("Eine Methode "+this.get_Name()+" ist in den Assumptions nicht vorhanden", this);
|
|
//Alle möglichen Methoden durchgehen:
|
|
for(MethodAssumption methodAssumption : methodAssumptions){
|
|
//Constraint nicht erstellen, falls Rückgabetyp von vorne herein nicht übereinstimmt:
|
|
if(!(this.type instanceof TypePlaceholder) && !this.type.equals(methodAssumption.getAssumedType()))break;
|
|
oCons.addConstraint(constraintsFromMethodAssumption(methodAssumption, assumptions));
|
|
}
|
|
ret.add(oCons);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Spezifikation:
|
|
* overloading determines for all possible overloadings and overridings
|
|
* of a method the constraints, where constraints itself forms
|
|
* the constraints from the receiver type, the argument types, the return
|
|
* type and a given type assumption for the method. If it is a
|
|
* method from a class, which is not the actual class (this), all type
|
|
* variables are replaced by fresh type variables (fresh), as different
|
|
* instances can occur. sargs determines all type assumptions of a
|
|
* method, where the argument types are supertypes of a minimal type
|
|
* assumption.
|
|
*
|
|
* @TODO: wenn es sich um eine Methode einer anderen Klasse handelt, müssen neue TPH vergeben werden und nicht die der Assumption verwendet werden.
|
|
*
|
|
* @return
|
|
*/
|
|
public UndConstraint constraintsFromMethodAssumption(MethodAssumption methodAssumption, TypeAssumptions assumptions){
|
|
UndConstraint methodConstraint = new UndConstraint();
|
|
//Ein Constraint für den ReturnType der Methode...
|
|
methodConstraint.addConstraint(methodAssumption.getAssumedType().TYPE(assumptions, this), this.getType().TYPE(assumptions, this));
|
|
//Ein Constraint für die Parameter der Methode...
|
|
for(int i=0; i<methodAssumption.getParaCount();i++){
|
|
//Type der Argument Expressions <. AssumedType der Parameter
|
|
Type ct1 = this.getArgumentList().argumentAt(i).getType().TYPE(assumptions, this);
|
|
Type ct2 = methodAssumption.getParameterType(i).TYPE(assumptions, this);
|
|
methodConstraint.addConstraint(ct1 , ct2);
|
|
}
|
|
//Ein Constraint für den Receiver der Methode (falls vorhanden)...
|
|
if(this.get_Receiver() != null && this.get_Receiver().get_Expr() != null){
|
|
//TODO: FunN-MethodAssumption darf keine Klasse (Class) als ParentClass besitzen. Denn der Typ der Klasse steht noch nicht fest (bisher ist es immer "FunN").
|
|
methodConstraint.addConstraint(this.get_Receiver().get_Expr().getType().TYPE(assumptions, this), methodAssumption.getParentClassType().TYPE(assumptions, this));
|
|
}
|
|
return methodConstraint;
|
|
}
|
|
|
|
/**
|
|
* Spezifikation:
|
|
* TYPEStmt( Ass, stmt ) =
|
|
* let (stmt : rty, ConS) = TYPEExpr( Ass, stmt )
|
|
* in (stmt : Void, ConS)
|
|
*/
|
|
@Override
|
|
public ConstraintsSet TYPEStmt(TypeAssumptions assumptions){
|
|
ConstraintsSet ret = this.TYPEExpr(assumptions); //TypeExpr aufrufen
|
|
this.setType(new Void(this,0)); //Typ des Statments auf Void setzen, da als alleinstehendes Statement
|
|
return ret;
|
|
}
|
|
|
|
@Override
|
|
|
|
public JavaCodeResult printJavaCode(ResultSet resultSet) {
|
|
JavaCodeResult ret = new JavaCodeResult();
|
|
if(this.receiver != null)ret.attach( this.receiver.printJavaCode(resultSet)).attach(".");
|
|
ret .attach( this.get_Name());
|
|
ret .attach( "(" ).attach( this.getArgumentList().printJavaCode(resultSet)).attach( ")");
|
|
return ret.attach(";");
|
|
|
|
}
|
|
@Override
|
|
public Menge<SyntaxTreeNode> getChildren() {
|
|
Menge<SyntaxTreeNode> ret = new Menge<SyntaxTreeNode>();
|
|
for(Expr e : this.arglist.expr){
|
|
ret.add(e);
|
|
}
|
|
if(this.receiver!=null)ret.add(this.receiver.get_Expr());
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
@Override
|
|
public void parserPostProcessing(SyntaxTreeNode parent) {
|
|
super.parserPostProcessing(parent);
|
|
}
|
|
*/
|
|
|
|
@Override
|
|
public InstructionList genByteCode(ClassGenerator cg) {
|
|
InstructionList il = new InstructionList();
|
|
InstructionFactory _factory = new InstructionFactory(cg, cg.getConstantPool());
|
|
|
|
il.append(receiver.get_Expr().genByteCode(cg));
|
|
|
|
//Herausfinden, ob eine Methode oder ein Interface aufgerufen wird:
|
|
Type receiverType = this.receiver.get_Expr().getType();
|
|
de.dhbwstuttgart.syntaxtree.Class receiverClass = this.receiver.getReceiverClass(cg);
|
|
short kind = 0;
|
|
if(receiverClass.isInterface()){
|
|
kind = Constants.INVOKEINTERFACE;
|
|
}else{//Ansonsten muss es eine Klasse sein:
|
|
kind = Constants.INVOKEVIRTUAL;
|
|
}
|
|
|
|
org.apache.commons.bcel6.generic.Type[] argumentTypen = org.apache.commons.bcel6.generic.Type.NO_ARGS;
|
|
if(this.getArgumentList() != null && this.getArgumentList().size()>0){
|
|
argumentTypen = new org.apache.commons.bcel6.generic.Type[this.getArgumentList().size()];
|
|
int i = 0;
|
|
for(Expr argument : this.arglist.expr){
|
|
argumentTypen[i] = argument.getType().getBytecodeType(cg);
|
|
//Das Argument auf den Stack legen:
|
|
il.append(argument.genByteCode(cg));
|
|
i++;
|
|
}
|
|
}
|
|
|
|
org.apache.commons.bcel6.generic.Type returnType = this.getType().getBytecodeType(cg);
|
|
il.append(_factory.createInvoke(receiver.getReceiverClass(cg).getName().toString(), this.get_Name(), returnType , argumentTypen, kind));
|
|
return il;
|
|
}
|
|
|
|
}
|
|
// ino.end
|