JavaPatternMatching/src/de/dhbwstuttgart/syntaxtree/Class.java
2016-09-16 13:25:20 +02:00

555 lines
20 KiB
Java
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ino.module.Class.8553.package
package de.dhbwstuttgart.syntaxtree;
// ino.end
// ino.module.Class.8553.import
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.lang.model.element.Modifier;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import de.dhbwstuttgart.logger.Logger;
import de.dhbwstuttgart.logger.Section;
import de.dhbwstuttgart.logger.SectionLogger;
import de.dhbwstuttgart.bytecode.ClassGenerator;
import de.dhbwstuttgart.bytecode.DHBWConstantPoolGen;
import de.dhbwstuttgart.bytecode.DHBWInstructionFactory;
import de.dhbwstuttgart.core.IItemWithOffset;
import de.dhbwstuttgart.parser.JavaClassName;
import de.dhbwstuttgart.syntaxtree.modifier.Modifiers;
import de.dhbwstuttgart.syntaxtree.modifier.Static;
import de.dhbwstuttgart.syntaxtree.statement.Block;
import de.dhbwstuttgart.syntaxtree.statement.Expr;
import de.dhbwstuttgart.syntaxtree.statement.Statement;
import de.dhbwstuttgart.syntaxtree.statement.SuperCall;
import de.dhbwstuttgart.syntaxtree.type.GenericTypeVar;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType;
import de.dhbwstuttgart.syntaxtree.type.Type;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.syntaxtree.type.WildcardType;
import de.dhbwstuttgart.typeinference.*;
import de.dhbwstuttgart.typeinference.assumptions.ClassAssumption;
import de.dhbwstuttgart.typeinference.assumptions.TypeAssumptions;
import de.dhbwstuttgart.typeinference.exceptions.DebugException;
import de.dhbwstuttgart.typeinference.exceptions.NotImplementedException;
import de.dhbwstuttgart.typeinference.exceptions.TypeinferenceException;
import de.dhbwstuttgart.typeinference.typedeployment.TypeInsertPoint;
import de.dhbwstuttgart.typeinference.unify.TypeUnify;
import org.apache.bcel.generic.*;
import org.apache.bcel.classfile.*;
import org.apache.bcel.*;
import java.io.*;
/**
* Stellt jede Art von Klasse dar. Auch abstrakte Klassen und Interfaces
*/
public class Class extends GTVDeclarationContext implements IItemWithOffset, Generic, GenericTypeInsertable
// ino.end
// ino.class.Class.23010.body
{
/**
* Log4j - Loggerinstanzen
*/
protected static Logger inferencelog = Logger.getLogger("inference");
protected static Logger codegenlog = Logger.getLogger("codegen");
protected static Logger parserlog = Logger.getLogger("parser");
protected Logger typinferenzLog = Logger.getLogger(Class.class.getName());
protected Modifiers modifiers;
protected JavaClassName name;
private Menge<RefType> superif;
public Class(JavaClassName name, List<Method> methoden, List<Field> felder, Modifiers modifier,
boolean isInterface, RefType superClass, List<RefType> implementedInterfaces, int offset){
super(offset);
}
/**
*
* @param resultSet - Fehlende Typen im Syntaxbaum werden nach diesem ResultSet aufgelöst
* @return
*/
public ByteCodeResult genByteCode(TypeinferenceResults typeinferenceResults) {
InstructionFactory _factory;
DHBWConstantPoolGen _cp;
ClassGenerator _cg;
Menge<ByteCodeResult> results = new Menge<ByteCodeResult>();
SectionLogger logger = Logger.getSectionLogger(this.getClass().getName(), Section.CODEGEN);
logger.debug("Test");
short constants = Constants.ACC_PUBLIC; //Per Definition ist jede Methode public
_cg = new ClassGenerator(name.toString(), this.getSuperClass(), name.getName() + ".java", constants , new String[] { }, typeinferenceResults); //letzter Parameter sind implementierte Interfaces
_cp = _cg.getConstantPool();
_factory = new DHBWInstructionFactory(_cg, _cp);
//Die Felder in Methoden Felder und Konstruktoren aufteilen:
Menge<FieldDeclaration> fieldDeclarations = new Menge<>();
Menge<Constructor> constructors = new Menge<>();
Menge<Method> methods = new Menge<>();
for(Field field : this.fielddecl){
if(field instanceof Constructor)constructors.add((Constructor)field);
if(field instanceof Method && ! (field instanceof Constructor))methods.add((Method)field);
if(field instanceof FieldDeclaration)fieldDeclarations.add((FieldDeclaration)field);
//field.genByteCode(_cg);
}
//Zuerst die Methoden und Felder abarbeiten:
for(Method m : methods){
m.genByteCode(_cg, this);
}
InstructionList fieldInitializations = new InstructionList();
for(FieldDeclaration f : fieldDeclarations){
fieldInitializations.append(f.genByteCode(_cg, typeinferenceResults.getTypeReconstructions().get(0)));
}
//Die Konstruktoren müssen die Feld initialisierungswerte beinhalten:
for(Constructor c : constructors){
c.genByteCode(_cg, fieldInitializations);
}
return new ByteCodeResult(_cg);
}
public JavaClassName getName()
{
return name;
}
public Modifiers getModifiers()
{
return this.modifiers;
}
/**
* Liefert die AccessFlags fuer den Bytecode zurueck.
*/
public short getAccessFlags()
{
short ret = 0;
if (modifiers != null) {
ret = modifiers.calculate_access_flags();
}
return ret;
}
public Menge<RefType> getSuperInterfaces()
{
return superif;
}
private Block class_block;
private Hashtable<String,String> parahash = new Hashtable<String,String>(); // parametrisierten Attrib. werden mit den Paramet.aus paralist verk.
private TypeAssumptions typeAssumptions = null;//muss mit null Initialisiert werden. Darf nur über getTypeAssumptions abgerufen werden.
private Menge<Field> fielddecl = new Menge<Field>();
private GenericDeclarationList genericClassParameters;
private int offset;
private RefType superClass;
public Menge<Field> getFields()
{
return fielddecl;
}
// ino.method.get_ParaList.23101.definition
public List<? extends Type> get_ParaList()
// ino.end
// ino.method.get_ParaList.23101.body
{
//if(this.paralist == null)return new Menge<Type>();
return this.getGenericParameter().getGTVList();
}
// ino.end
// ino.method.set_ParaHash.23104.definition
public void set_ParaHash(Hashtable<String,String> hash)
// ino.end
// ino.method.set_ParaHash.23104.body
{
this.parahash = hash;
}
// ino.end
// ino.method.get_ParaHash.23107.definition
public Hashtable<String,String> get_ParaHash()
// ino.end
// ino.method.get_ParaHash.23107.body
{
return this.parahash;
}
/////////////////////////////////////////////////////////////////////////
// TypeReconstructionAlgorithmus
/////////////////////////////////////////////////////////////////////////
// ino.method.TRProg.23110.defdescription type=javadoc
/**
* Ausgangspunkt f�r den Typrekonstruktionsalgorithmus. Hier werden zun�chst
* die Mengen von Typannahmen V_fields_methods und V_i erstellt, die als Eingabe
* f�r den Algorithmus dienen.<br/>
* (siehe Algorithmus 5.17 TRProg, Martin Pl�micke)
* <br/>Author: J�rg B�uerle
* @param supportData
* @param globalAssumptions
* @return Liste aller bisher berechneten, m�glichen Typkombinationen
* @throws CTypeReconstructionException
*/
// ino.end
// ino.method.TRProg.23110.definition
public ConstraintsSet typeReconstruction(TypeAssumptions globalAssumptions)
// ino.end
// ino.method.TRProg.23110.body
{
/*
*/
//////////////////////////////
// Und los geht's:
//////////////////////////////
inferencelog.info("Rufe TRStart()...", Section.TYPEINFERENCE);
//////////////////////////////
// Ab hier ...
// @author A10023 - Andreas Stadelmeier:
//////////////////////////////
//Erzeuge Assumptions:
TypeAssumptions assumptions = this.getPrivateFieldAssumptions();
//Globale Assumptions anfügen:
assumptions.add(globalAssumptions);
ConstraintsSet oderConstraints = new ConstraintsSet();
for(Type gparam : this.get_ParaList()){
if(gparam instanceof GenericTypeVar)assumptions.add(((GenericTypeVar)gparam).createAssumptions()); //Constraints für die Generischen Variablen erstellen und diese dem AssumptionsSet hinzufügen
}
for(Type gparam : this.get_ParaList()){
if(gparam instanceof GenericTypeVar)oderConstraints.add(((GenericTypeVar)gparam).TYPE(assumptions)); //Constraints für die Generischen Variablen erstellen und diese dem AssumptionsSet hinzufügen
}
typinferenzLog.debug("Erstellte Assumptions: "+assumptions, Section.TYPEINFERENCE);
//Gibt es hier eine ClassCastException stimmt etwas grundsätzlich nicht!
//this.superClass = (RefType)this.superClass.TYPE(assumptions, this);
for(Field f:this.getFields()){
oderConstraints.add(f.TYPE(assumptions));
}
typinferenzLog.debug("Erstellte Constraints: "+oderConstraints, Section.TYPEINFERENCE);
return oderConstraints;
}
/**
* Ermittelt alle privaten Felder und Methoden der Klasse und Erstellt eine Assumption für diese.
* Bemerkung: Momentan werden noch alle Felder dieser Klasse zurückgegeben.
* @return Die erstellten TypeAssumptions
*/
private TypeAssumptions getPrivateFieldAssumptions() {
if(this.typeAssumptions != null)return this.typeAssumptions; //Das sorgt dafür, dass die Assumptions nur einmalig generiert werden.
TypeAssumptions assumptions = new TypeAssumptions(this.getName());
for(Field field : this.getFields()){
if(!field.isPublic())assumptions.add(field.createTypeAssumptions(this));
}
this.typeAssumptions = assumptions; //Diese müssen anschließend nicht wieder generiert werden.
return assumptions;
}
/**
* <br/>Author: Martin Pl�micke
* @return
*/
public String toString()
{
//return superclassid.toString() + body.toString();
//geaendert PL 07-07-28
return name.getName();
}
public String getTypeInformation(Menge<Method> methodList, Menge<Expr> fieldList){
String ret = this.name+": ";
for(Expr field : fieldList){
ret+=field.getTypeInformation()+"\n";
}
for(Method m : methodList){
ret+=m.getTypeInformation()+"\n";
}
return ret;
}
/**
* Generiert den JavaCode dieser Klasse im Falle für das übergebene resultSet.
* Dem ResultSet entsprechend werden in diesem Java-Code die TypePlaceholder durch die in ResultSet stehenden Typen ersetzt.
* @return Java-Sourcefile
*/
public String printJavaCode(TypeinferenceResultSet reconstructionResult){
JavaCodeResult ret = new JavaCodeResult("class ");
JavaCodeResult classBodyCode = new JavaCodeResult();
if(this.modifiers!=null)classBodyCode.attach(this.modifiers.printJavaCode(reconstructionResult.getUnifiedConstraints())).attach(" ");
classBodyCode.attach(this.name + " extends ").attach(this.superClass.printJavaCode(reconstructionResult.getUnifiedConstraints())).attach("\n");
JavaCodeResult bodyString = new JavaCodeResult("{\n");
for(Field field : this.fielddecl)bodyString.attach( field.printJavaCode(reconstructionResult.getUnifiedConstraints()) ).attach( "\n" );
bodyString.attach("}\n");
classBodyCode.attach(bodyString);
//Zuerst die generischen Parameter für diese Klasse berechnen:
//this.createGenericTypeVars(classBodyCode.getUnresolvedTPH());
if(this.genericClassParameters != null && this.genericClassParameters.size()>0){
ret.attach("<");
Iterator<GenericTypeVar> it = this.genericClassParameters.iterator();
while(it.hasNext()){
GenericTypeVar tph = it.next();
ret.attach(tph.printJavaCode(reconstructionResult.getUnifiedConstraints()));
if(it.hasNext())ret.attach(", ");
}
ret.attach(">");
}
String stringReturn = ret.attach(classBodyCode).toString();
return stringReturn;
}
/**
* Errechnet die Generischen Parameter der Klasse für diese Klasse.
* Die berechneten Variablen werden anschließend in die this.genericTypeVars eingesetzt. Dabei werden alte genericTypeVars überschrieben.
* @param tphs : Alle übriggebliebenen TypePLaceholder
private void createGenericTypeVars(Menge<TypePlaceholder> tphs){
this.genericClassParameters = new GenericDeclarationList(new Menge<GenericTypeVar>());
for(TypePlaceholder tph : tphs){
GenericTypeVar toAdd = new GenericTypeVar(tph,this.getOffset());
if(!this.genericClassParameters.contains(toAdd))this.genericClassParameters.add(toAdd);
}
}
*/
/**
* Errechnet die Generischen Parameter der Klasse für diese Klasse.
* Die berechneten Variablen werden anschließend in die this.genericTypeVars eingesetzt. Dabei werden alte genericTypeVars überschrieben.
* @param reconstructionResult
public void createGenericTypeVars(TypeinferenceResultSet reconstructionResult){
this.genericClassParameters = new Menge<GenericTypeVar>();
for(Pair pair : reconstructionResult.getUnifiedConstraints()){
if(pair.TA2 instanceof TypePlaceholder && pair.TA1 instanceof TypePlaceholder){// if(pair.OperatorSmallerExtends() || pair.OperatorSmaller()){
Type ta1=reconstructionResult.getUnifiedConstraints().getTypeEqualTo(pair.TA1);
Type ta2=reconstructionResult.getUnifiedConstraints().getTypeEqualTo(pair.TA2);
this.genericClassParameters.add(new GenericTypeVar(new Pair(ta1,ta2),this.getOffset()));
}
}
for(Pair pair : reconstructionResult.getConstraints()){
if( ! reconstructionResult.getUnifiedConstraints().contains(pair.TA1)){
this.genericClassParameters.add(new GenericTypeVar(pair.TA1,this.getOffset()));
}
if( ! reconstructionResult.getUnifiedConstraints().contains(pair.TA2)){
this.genericClassParameters.add(new GenericTypeVar(pair.TA2, this.getOffset()));
}
}
}
*/
public int getOffset(){
return this.offset;
}
/**
* Erstellt einen RefType, welcher auf diese Klasse verweist
* Ersetzt alle Generischen Variablen in der Parameterliste mit TPH
* @return
*/
public RefType getType() {
/*
Menge<Type> parameter = new Menge<Type>();
for(Type param : this.get_ParaList()){
parameter.add(((GenericTypeVar)param).getTypePlaceHolder());//(TypePlaceholder.fresh()); //Hier ist kein ReplacementListener notwendig. Der Typ soll nie eingesetzt werden. Der TPH wird nur gebraucht, damit das Unifizieren funktioniert.
}
*/
return new RefType(this.getName().toString(), this.get_ParaList(),this, 0);
}
/**
* Ermittelt die Sichtbaren Felder und Methoden der Klasse.
* (Momentan sind im Projekt alle Felder und Methoden "package private", da der Parser keine Access-Modifier einlesen kann.
* @return
*/
public TypeAssumptions getPublicFieldAssumptions() {
TypeAssumptions ret = new TypeAssumptions();//this.getPrivateFieldAssumptions();
ret.addClassAssumption(new ClassAssumption(this));
for(Field f : this.getFields()){
if(f.isPublic())ret.add(f.createTypeAssumptions(this));
}
for(GenericTypeVar gtv : this.getGenericParameter()){
ret.add(gtv.createAssumptions());
}
return ret;
}
@Override
public SyntaxTreeNode getParent() {
return this;
}
@Override
public Menge<SyntaxTreeNode> getChildren() {
Menge<SyntaxTreeNode> ret = new Menge<SyntaxTreeNode>();
//for(Field f : this.getFields()){
// ret.add(f);
//}
ret.addAll(this.getFields());
ret.addAll(this.get_ParaList());
ret.addAll(this.getGenericParameter().getGTVList());
return ret;
}
@Override
public boolean equals(Object obj){
if(!(obj instanceof Class))return false;
Class cl = (Class) obj;
if(!(cl.getName().equals(this.getName())))return false;
return true;
}
@Override
public GenericDeclarationList getGenericParameter() {
return this.genericClassParameters;
}
@Override
public String getDescription(){
return "class "+this.getName();
}
@Override
public int getVariableLength() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void setGenericParameter(GenericDeclarationList params) {
this.genericClassParameters = params;
}
@Override
public String getGenericVarDeclarationString(String genericVarDeclaration) {
if(this.genericClassParameters != null){
return ", "+genericVarDeclaration;
}else{
return "<"+genericVarDeclaration+">";
}
}
@Override
public int getGenericVarDeclarationOffset(){
// Falls Generische Parameterliste vorhanden, hier Wert der Liste zurückgegebn
if(this.genericClassParameters != null){
return this.genericClassParameters.getEndOffset();
}else{
return this.offset;
}
}
/**
* Die Super Klasse dieser Klasse.
* @return null für Klasse Object
*/
public RefType getSuperClass(){
return this.superClass;
}
@Override
public boolean isClass() {
return true;
}
public boolean isInterface(){
return false;
}
/*
private Collection<? extends ByteCodeResult> getGenericClasses() {
Collection<ByteCodeResult> results = new Menge<>();
for(Field field : this.fielddecl){
Type type = field.getType();
//Der Type des Feldes
if(type instanceof RefType){
RefType refType = (RefType) type;
if(!refType.getCombinedType(null).equals(refType.get_Name().replace(".", "%"))){
results.addAll(generateGenericClass(refType.getCombinedType(null), new Class("java/util/Vector",-1)));
}
}
if(field instanceof Method){
Method method = (Method) field;
ParameterList parameterList = method.getParameterList();
//Die Typen der Methodenparameter
for(FormalParameter parameter: parameterList){
Type parameterType = parameter.getType();
if(parameterType instanceof RefType){
RefType refType = (RefType) parameterType;
if(!refType.getCombinedType(null).equals(refType.get_Name().replace(".", "%"))){
results.addAll(generateGenericClass(refType.getCombinedType(null), new Class("java/util/Vector",-1)));
}
}
}
}
}
return results;
}
*/
/*
private Menge<ByteCodeResult> generateGenericClass(String name, Class superClass){
//TODO: bytecode -- Generics hinzuf<75>gen
//Type superClassType = superClass.getType();
//TODO: bytecode
//ClassGenerator genericClassGenerator = new ClassGenerator(name, superClassType, name + ".java", Constants.ACC_PUBLIC , new String[] { }, new TypeinferenceResultSet(null, null, null));
//TODO: bytecode -- Namen der neuen Klasse
Class generatedClass = new Class(name, 0);
//TODO: bytecode -- alle Konstruktoren generieren
Block konstruktorBlock = new Block();
konstruktorBlock.setType(new de.dhbwstuttgart.syntaxtree.type.Void(konstruktorBlock, 0));
konstruktorBlock.statements.add(new SuperCall(konstruktorBlock));
Constructor standardKonstruktor = new Constructor(Method.createEmptyMethod(konstruktorBlock, name, superClass), superClass);
standardKonstruktor.parserPostProcessing(generatedClass);
generatedClass.addField(standardKonstruktor);
return generatedClass.genByteCode(new TypeinferenceResultSet(generatedClass, new Menge<>(), new ResultSet()));
}
*/
}
// ino.end