package de.dhbwstuttgart.syntaxtree; import org.apache.bcel.Constants; import org.apache.commons.bcel6.generic.FieldGen; import org.apache.commons.bcel6.generic.FieldInstruction; import org.apache.commons.bcel6.generic.InstructionList; import org.apache.commons.bcel6.generic.ObjectType; import org.apache.commons.bcel6.generic.ClassGen; import de.dhbwstuttgart.typeinference.Menge; import de.dhbwstuttgart.bytecode.ClassGenerator; import de.dhbwstuttgart.myexception.JVMCodeException; import de.dhbwstuttgart.syntaxtree.misc.DeclId; 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.SingleConstraint; 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 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.setType(typ); this.set_DeclId(new DeclId(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 this.get_Name().elementAt(0).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 void parserPostProcessing(SyntaxTreeNode parent){ super.parserPostProcessing(parent); if(this.getType() == null)this.setType(TypePlaceholder.fresh(this)); } @Override public Menge getChildren() { Menge ret = super.getChildren(); if(this.wert!=null)ret.add(this.wert); return ret; } public int getVariableLength() { return declid.elementAt(0).get_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); } /* if(this.getType() instanceof GenericTypeVar){ //Falls Typ ein GTV ist muss er syntaktisch kontrolliert werden... GenericTypeVar gtv = (GenericTypeVar) this.getType(); } */ //TypeCheck, falls es sich um einen RefType handelt: Type thisType = this.getType().TYPE(localAssumptions, this); this.setType(thisType); /* if(this.getType()!=null && (this.getType() instanceof RefType)){ Type replaceType = null; replaceType = publicAssumptions.getTypeFor((RefType)this.getType()); if(replaceType == null)throw new TypeinferenceException("Der Typ "+this.getType().getName()+" ist nicht korrekt",this); this.setType(replaceType); } */ SingleConstraint c1 = new SingleConstraint(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(new SingleConstraint(this.wert.getType().TYPE(localAssumptions,this), thisType)); } return ret; } @Override public void wandleRefTypeAttributes2GenericAttributes(Menge paralist){ super.wandleRefTypeAttributes2GenericAttributes(paralist); if(this.getWert()!=null)this.getWert().wandleRefTypeAttributes2GenericAttributes(paralist, new Menge()); //FieldDeclaration hat keine Generischen Variablen, daher leere Liste übergeben } /** * 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) { //Das Feld an die Klasse anfügen: FieldGen field = new FieldGen(0, this.getType().getBytecodeType(cg), this.getDescription(), cg.getConstantPool()); field.addAttribute(cg.getInstructionFactory().createSignatureAttribute(this.getType().getBytecodeSignature(cg))); cg.addField(field.getField()); //Die Felddekleration an den Konstruktor anhängen: InstructionList il = new InstructionList(); il.append(new This(this).genByteCode(cg)); il.append(this.wert.genByteCode(cg)); FieldInstruction putFieldInstruction = cg.getInstructionFactory().createFieldAccess(this.getParentClass().getName().toString(), this.getDescription(), this.getType().getBytecodeType(cg), Constants.PUTFIELD); il.append(putFieldInstruction ); return il; } /*@Override public void genByteCode(ClassGen cg) { // TODO Auto-generated method stub }*/ }