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 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 getChildren() { Menge 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 }*/ }