JavaPatternMatching/src/de/dhbwstuttgart/syntaxtree/FieldDeclaration.java

175 lines
6.2 KiB
Java

package de.dhbwstuttgart.syntaxtree;
import org.apache.bcel.generic.FieldGen;
import org.apache.bcel.generic.FieldInstruction;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.Const;
import org.apache.bcel.generic.ClassGen;
import de.dhbwstuttgart.typeinference.Menge;
import de.dhbwstuttgart.bytecode.ClassGenerator;
import de.dhbwstuttgart.syntaxtree.statement.Expr;
import de.dhbwstuttgart.syntaxtree.statement.This;
import de.dhbwstuttgart.syntaxtree.type.GenericTypeVar;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.Type;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.typeinference.ConstraintsSet;
import de.dhbwstuttgart.typeinference.JavaCodeResult;
import de.dhbwstuttgart.typeinference.OderConstraint;
import de.dhbwstuttgart.typeinference.ResultSet;
import de.dhbwstuttgart.typeinference.TypeinferenceResultSet;
import de.dhbwstuttgart.typeinference.UndConstraint;
import de.dhbwstuttgart.typeinference.assumptions.FieldAssumption;
import de.dhbwstuttgart.typeinference.assumptions.TypeAssumptions;
import de.dhbwstuttgart.typeinference.exceptions.TypeinferenceException;
/**
* Eine Feldinitialisation steht für eine Felddeklaration mit gleichzeitiger Wertzuweisung
* Beispiel: 'public Feld FeldVar = FeldWert;'
* @author janulrich
*
*/
public class FieldDeclaration extends Field{
private Expr wert;
private String name;
//private Type type;
//private Menge<GenericTypeVar> parameter;
/**
* Dieser Konstruktor der FieldDeclaration erstellt den Syntaxknoten vollständig.
* Kein nachträgliches hinzfügen von Informationen oder aufrufen von parserPostProcessing ist notwendig.
*/
public FieldDeclaration(String name, Type typ){
super(0);//Dieser Deklarator wird nicht vom Parser aufgerufen. Dadurch gibt es auch keinen Offset
this.typ = typ;
this.name = name;
}
public FieldDeclaration(int offset){
super(offset);
}
public void setWert(Expr initialExpression){
this.wert = initialExpression;
}
public Expr getWert(){
return this.wert;
}
public String getIdentifier(){
return name;
}
@Override
public String toString()
{
if(getWert()!=null)return super.toString() + "=" + getWert().toString();
return super.toString();
}
public JavaCodeResult printJavaCode(ResultSet resultSet) {
JavaCodeResult ret = new JavaCodeResult();
JavaCodeResult toAttach = this.getType().printJavaCode(resultSet).attach(" ").attach( this.getIdentifier());
if(this.wert!=null)toAttach.attach(" = ").attach(this.getWert().printJavaCode(resultSet) );
toAttach.attach( ";");
ret.attach(toAttach);
return ret;
}
@Override
public TypeAssumptions createTypeAssumptions(Class classmember) {
//////////////////////////////
//Felder:
//////////////////////////////
TypeAssumptions assumptions = new TypeAssumptions();
/*
* Der Feld-Assumption muss ein TPH als Typ hinzugefügt werden, falls er Typlos initialisiert wurde. Dies kann auch der Type-Algorithmus der Inst/FieldVar - Klasse machen.
* Wird das Feld mit einem Typ initialisiert so muss dieser auch in die Assumptions.
*/
if(this.getType() == null)throw new TypeinferenceException("Der Typ eines Feldes darf nicht null sein", this);
//assumptions.add(TypeAssumptions.createFieldVarAssumption(classmember.getName(), this.getName(), this.getType()));
assumptions.addAssumption(new FieldAssumption(this,classmember));
return assumptions;
}
@Override
public Menge<SyntaxTreeNode> getChildren() {
Menge<SyntaxTreeNode> ret = super.getChildren();
if(this.wert!=null)ret.add(this.wert);
return ret;
}
public int getVariableLength()
{
return name.length();
}
@Override
public ConstraintsSet TYPE(TypeAssumptions publicAssumptions) {
if(this.wert == null && (this.getType() == null || this.getType() instanceof TypePlaceholder))
throw new TypeinferenceException("Typlose Felder müssen mit Wert initialisiert werden", this);
ConstraintsSet ret = new ConstraintsSet();
TypeAssumptions localAssumptions = publicAssumptions.clone();
for(GenericTypeVar gp : this.getGenericParameter()){
localAssumptions.add(gp.createAssumptions());
}
for(GenericTypeVar gp : this.getGenericParameter()){
gp.TYPE(localAssumptions);
}
//TypeCheck, falls es sich um einen RefType handelt:
Type thisType = this.getType();
UndConstraint c1 = ConstraintsSet.createSingleConstraint(thisType, thisType);
ret.add(c1); //Damit die TypVariable des Felds in den Constraints auftaucht
if(this.wert!=null){
//Falls bei der Deklaration ein Wert zugewiesen wird, verhält sich das Constraintserzeugen wie bei dem Assign-Statement:
ret.add(this.wert.TYPEExpr(localAssumptions));
ret.add(ConstraintsSet.createSingleConstraint(this.wert.getType().TYPE(localAssumptions,this), thisType));
}
return ret;
}
/**
* Das besondere bei genByteCode einer FieldDeclaration ist, dass ein InstructionList zurückgegeben wird.
* Dieser muss in jeden Konstruktor eingefügt werden um das Feld zu initialisieren.
* @param cg
* @return - Die InstructionList, welche das Feld initialisiert
*/
public InstructionList genByteCode(ClassGenerator cg, TypeinferenceResultSet rs) {
//Das Feld an die Klasse anfügen:
FieldGen field = new FieldGen(0, this.getType().getBytecodeType(cg, rs), this.getDescription(), cg.getConstantPool());
field.addAttribute(cg.getInstructionFactory().createSignatureAttribute(this.getType().getBytecodeSignature(cg, rs)));
cg.addField(field.getField());
//Die Felddekleration an den Konstruktor anhängen:
InstructionList il = new InstructionList();
il.append(new This(this).genByteCode(cg, rs));
if(wert != null){
il.append(this.wert.genByteCode(cg, rs));
}
FieldInstruction putFieldInstruction =
cg.getInstructionFactory().createFieldAccess(this.getParentClass().getName().toString(),
this.getDescription(), this.getType().getBytecodeType(cg, rs), Const.PUTFIELD);
il.append(putFieldInstruction );
return il;
}
/*@Override
public void genByteCode(ClassGen cg) {
// TODO Auto-generated method stub
}*/
}