From 5979835783df25350213aad0b36c7c8fff4df4c2 Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Wed, 18 Jun 2014 09:06:08 +0200 Subject: [PATCH] =?UTF-8?q?GenericVarAssumption=20eingef=C3=BChrt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mycompiler/SyntaxTreeNode.java | 2 +- src/mycompiler/myclass/Method.java | 11 +++- src/mycompiler/mytype/GenericTypeVar.java | 17 ++++++ src/typinferenz/TypeInsertSet.java | 23 ++++++- src/typinferenz/assumptions/Assumption.java | 6 ++ .../assumptions/GenericVarAssumption.java | 24 ++++++++ .../assumptions/TypeAssumptions.java | 21 ++++++- test/parser/GeneralParserTest.java | 1 + test/parser/GenericFieldVarTest.jav | 3 + .../InsertSingleTypeTest.java | 60 +++++++++++++++++++ .../SingleTypeInsertTest.jav | 3 + .../TypeInsertTests/LambdaTest10.jav | 9 +++ .../TypeInsertTests/LambdaTest10.java | 18 ++++++ 13 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 src/typinferenz/assumptions/GenericVarAssumption.java create mode 100644 test/parser/GenericFieldVarTest.jav create mode 100644 test/plugindevelopment/InsertSingleTypeTest.java create mode 100644 test/plugindevelopment/SingleTypeInsertTest.jav create mode 100644 test/plugindevelopment/TypeInsertTests/LambdaTest10.jav create mode 100644 test/plugindevelopment/TypeInsertTests/LambdaTest10.java diff --git a/src/mycompiler/SyntaxTreeNode.java b/src/mycompiler/SyntaxTreeNode.java index 162fe915..1c8c6e2b 100644 --- a/src/mycompiler/SyntaxTreeNode.java +++ b/src/mycompiler/SyntaxTreeNode.java @@ -16,7 +16,7 @@ import mycompiler.mytype.Pair; import mycompiler.mytype.Type; import mycompiler.mytype.TypePlaceholder; -public abstract class SyntaxTreeNode { +public abstract class SyntaxTreeNode{ protected SyntaxTreeNode parent; diff --git a/src/mycompiler/myclass/Method.java b/src/mycompiler/myclass/Method.java index e3def173..75221dbe 100755 --- a/src/mycompiler/myclass/Method.java +++ b/src/mycompiler/myclass/Method.java @@ -546,6 +546,14 @@ public class Method extends Field implements IItemWithOffset, TypeInsertable public ConstraintsSet TYPE(TypeAssumptions ass) { + ConstraintsSet ret = new ConstraintsSet(); + TypeAssumptions localAss = new TypeAssumptions(); + localAss.add(ass); //Die globalen Assumptions anhängen + //Generische Parameterdeklarationen den Assumptions anfügen: + for(GenericTypeVar gtv : this.genericMethodParameters){ + ret.add(gtv.TYPE(localAss)); + } + //TypeCheck, falls es sich um einen RefType handelt: if(this.returntype!=null && (this.returntype instanceof RefType)&& !(this.returntype instanceof mycompiler.mytype.Void)){//Sonderfall der Methode: Ihr Typ darf Void definiert werden. @@ -554,9 +562,6 @@ public class Method extends Field implements IItemWithOffset, TypeInsertable if(replaceType == null)throw new TypeinferenceException("Der Typ "+this.getType().getName()+" ist nicht korrekt",this); this.returntype = replaceType; } - ConstraintsSet ret = new ConstraintsSet(); - TypeAssumptions localAss = new TypeAssumptions(); - localAss.add(ass); //Die globalen Assumptions anhängen //Die Parameter zu den Assumptions hinzufügen: if(this.parameterlist!=null)for(FormalParameter param : this.parameterlist){ diff --git a/src/mycompiler/mytype/GenericTypeVar.java b/src/mycompiler/mytype/GenericTypeVar.java index 98a1053a..b7237304 100755 --- a/src/mycompiler/mytype/GenericTypeVar.java +++ b/src/mycompiler/mytype/GenericTypeVar.java @@ -14,12 +14,18 @@ import java.util.Vector; + + + import mycompiler.mytypereconstruction.replacementlistener.CReplaceTypeEvent; import mycompiler.mytypereconstruction.replacementlistener.ITypeReplacementListener; +import typinferenz.ConstraintsSet; import typinferenz.JavaCodeResult; import typinferenz.ResultSet; +import typinferenz.SingleConstraint; import typinferenz.TypeInsertPoint; import typinferenz.TypeInsertable; +import typinferenz.assumptions.TypeAssumptions; // ino.class.GenericTypeVar.26505.description type=javadoc @@ -36,6 +42,7 @@ public class GenericTypeVar extends Type { Type genericTypeVar; Vector extendVars = new Vector(); + private Pair genericConstraint; /** * Eine Registry f�r alle Generic-Instanzen, die vor der Bytecode-Generierung durch * Ihre Superklasse ersetzt werden m�ssen. Siehe "Type Erasure" in Sun Spezifikation. @@ -54,6 +61,9 @@ public class GenericTypeVar extends Type super(offset); genericTypeVar = genericTypeVarExtendsVar.TA1; if(genericTypeVarExtendsVar.TA2!=null)this.extendVars.add(genericTypeVarExtendsVar.TA2); + else{ + this.genericConstraint = genericTypeVarExtendsVar; + } this.name = genericTypeVar.toString(); } @@ -182,6 +192,13 @@ public class GenericTypeVar extends Type return this.name; } + public ConstraintsSet TYPE(TypeAssumptions ass){ + ConstraintsSet ret = new ConstraintsSet(); + if(this.genericConstraint != null)ret.add(new SingleConstraint(this.genericConstraint.TA1, this.genericConstraint.TA2)); + ass.addGenericVarAssumption(this); + return ret; + } + } // ino.end diff --git a/src/typinferenz/TypeInsertSet.java b/src/typinferenz/TypeInsertSet.java index 76ca85a5..edf4cb80 100644 --- a/src/typinferenz/TypeInsertSet.java +++ b/src/typinferenz/TypeInsertSet.java @@ -17,6 +17,7 @@ import mycompiler.mytype.TypePlaceholder; * Diese müssen gemeinsam eingesetzt werden. * Das TypeInsertSet löst zudem Abhängigkeiten auf. Wird eine Generische Variable eingesetzt, * müssen alle mit ihr in Verbindung stehenden Typen ebenfalls eingesetzt werden. + * TODO: Es müssen eigentlich nur die generischen Variablendeklarationen eingesetzt werden. * @author janulrich * */ @@ -30,8 +31,6 @@ public class TypeInsertSet { /** * Fügt einen TypeInsertPoint dem TypeInsertSet hinzu. - * Dabei werden alle involvierten TPHs berechnet und zurückgeliefert. - * Die von diesen TPHs abhängigen Typen müssen anschließend ebenfalls dem TypeInsertSet angefügt werden. * @param typeInsertPoint * @return */ @@ -46,6 +45,26 @@ public class TypeInsertSet { if(!this.genericTypeInsertPoints.contains(typeInsertPoint))this.genericTypeInsertPoints.add(typeInsertPoint); } + /** + * Fügt nur einen einzelnen TypeInsertPoint in fileContent ein. + * @param tip + * @param fileContent + * @return + */ + public String insertType(TypeInsertPoint tip, String fileContent){ + TypeInsertSet tis = new TypeInsertSet(); + int additionalOffset = 0; + String ret = fileContent; + JavaCodeResult unresolvedTPHs = tip.insertType(ret, additionalOffset); + for(TypePlaceholder tph : unresolvedTPHs.getUnresolvedTPH()){ + GenericTypeInsertPoint genericTIP = new GenericTypeInsertPoint((TypeInsertable)tip.getGenericTypeVarInsertNode(),tph,tip.getResultSet()); + tis.add(genericTIP); + } + tis.add(tip); + + return tis.insertAllTypes(fileContent); + } + /** * Fügt alle Typen dieses TypeInsertSets in den übergebenen Quellcode ein * TODO: Beim Einsetzen eines Typs alle Abhängigkeiten auflösen. Benutze Generische Variablen müssen an allen Punkte eingesetzt werden diff --git a/src/typinferenz/assumptions/Assumption.java b/src/typinferenz/assumptions/Assumption.java index 8e92c5e8..d370d85f 100644 --- a/src/typinferenz/assumptions/Assumption.java +++ b/src/typinferenz/assumptions/Assumption.java @@ -9,6 +9,12 @@ public class Assumption { private TypeInsertable typable; + /** + * Wird dieser Konstruktor benutzt müssen alle Methoden der Klasse Assumption überschrieben werden. + */ + protected Assumption(){ + } + public Assumption(TypeInsertable ass){ this.typable = ass; } diff --git a/src/typinferenz/assumptions/GenericVarAssumption.java b/src/typinferenz/assumptions/GenericVarAssumption.java new file mode 100644 index 00000000..be5a01cb --- /dev/null +++ b/src/typinferenz/assumptions/GenericVarAssumption.java @@ -0,0 +1,24 @@ +package typinferenz.assumptions; + +import mycompiler.mystatement.LocalVarDecl; +import mycompiler.mytype.GenericTypeVar; +import mycompiler.mytype.RefType; +import mycompiler.mytype.Type; + +public class GenericVarAssumption extends Assumption{ + + private GenericTypeVar genericVar; + + public GenericVarAssumption(GenericTypeVar genericVar){ + super(); + this.genericVar = genericVar; + } + + public Type getAssumedType() { + return new RefType(genericVar.getTypePlaceHolder().getName(), -1); + } + + public String getIdentifier(){ + return genericVar.getTypePlaceHolder().getName(); + } +} diff --git a/src/typinferenz/assumptions/TypeAssumptions.java b/src/typinferenz/assumptions/TypeAssumptions.java index bbd5292a..adbcf850 100755 --- a/src/typinferenz/assumptions/TypeAssumptions.java +++ b/src/typinferenz/assumptions/TypeAssumptions.java @@ -52,6 +52,7 @@ public class TypeAssumptions { private Vector fieldAssumptions = new Vector(); private Vector localVarAssumptions = new Vector(); private Vector parameterAssumptions = new Vector(); + private Vector genericVarAssumptions = new Vector(); private Vector classAssumptions = new Vector(); /** @@ -165,7 +166,11 @@ public class TypeAssumptions { for(LocalVarAssumption ass : this.localVarAssumptions){ if(ass.getIdentifier().equals(variableName))return ass.getAssumedType(); } - + //Ebenso wie die Generischen Variablen: + for(GenericVarAssumption ass : this.genericVarAssumptions){ + + } + //und zuletzt die Felder der Klasse in dessen Namensraum sich dieses AssumptionSet befindet. if(inScope!=null){ for(FieldAssumption ass : this.getAssumptionsFor(inScope.getName())){ @@ -218,6 +223,7 @@ public class TypeAssumptions { for(Assumption f : this.fieldAssumptions)ret.add(f); for(Assumption f : this.parameterAssumptions)ret.add(f); for(Assumption f : this.constructorAssumptions)ret.add(f); + for(Assumption f : this.genericVarAssumptions)ret.add(f); return ret; } @@ -233,6 +239,7 @@ public class TypeAssumptions { if(ass instanceof LocalVarAssumption)if(!this.localVarAssumptions.contains(ass))this.localVarAssumptions.add((LocalVarAssumption)ass);//this.localVarAssumptions.add((LocalVarAssumption)ass);// if(ass instanceof ParameterAssumption)if(!this.parameterAssumptions.contains(ass))this.parameterAssumptions.add((ParameterAssumption)ass);//this.parameterAssumptions.add((ParameterAssumption)ass); if(ass instanceof FieldAssumption)if(!this.fieldAssumptions.contains(ass))this.fieldAssumptions.add((FieldAssumption)ass);//this.fieldAssumptions.add((FieldAssumption)ass); + if(ass instanceof GenericVarAssumption)if(!this.genericVarAssumptions.contains(ass))this.genericVarAssumptions.add((GenericVarAssumption)ass); } @@ -273,6 +280,7 @@ public class TypeAssumptions { ret += "FieldVar Assumptions:\n" + this.fieldAssumptions.toString() + "\n"; ret += "LocalVar Assumptions:\n" + this.localVarAssumptions.toString() + "\n"; ret += "Parameter Assumptions:\n" + this.parameterAssumptions.toString() + "\n"; + ret += "Generic Var Assumptions:\n" + this.genericVarAssumptions.toString() + "\n"; ret += "Konstruktor Assumptions:\n" + this.constructorAssumptions.toString() + "\n"; ret += "Class Assumptions:\n" + this.classAssumptions.toString() + "\n"; //return assumptions.toString(); @@ -287,7 +295,6 @@ public class TypeAssumptions { * @return null, falls der Typ nicht vorhanden ist. */ public Type getTypeFor(RefType t){ - //TODO: Die Parameterliste noch kontrollieren: (hier könnte es Constraints geben: "? extends String") //Alle bekannten Klassen nach diesem Typ durchsuchen: String typName = t.getName(); String[] names = typName.split("[.]"); @@ -308,6 +315,11 @@ public class TypeAssumptions { return ret; } } + //Auch die generischen Variablen durchsuchen: + for(GenericVarAssumption ass : this.genericVarAssumptions){ + if(ass.getIdentifier().equals(t.getName()))return ass.getAssumedType(); + } + return null; } @@ -335,6 +347,11 @@ public class TypeAssumptions { return null; } + public void addGenericVarAssumption( + GenericTypeVar genericTypeVar) { + this.genericVarAssumptions.add(new GenericVarAssumption(genericTypeVar)); + } + /** * Prüft einen Typ auf das vorhandensein in den BasicAssumptions. * Dabei werden alle Konstruktoren nach diesem Typ durchsucht. Denn jede Klasse hat einen Konstruktor und der muss in den TypeAssumptions vorhanden sein. diff --git a/test/parser/GeneralParserTest.java b/test/parser/GeneralParserTest.java index 596cbea7..3349d324 100644 --- a/test/parser/GeneralParserTest.java +++ b/test/parser/GeneralParserTest.java @@ -31,6 +31,7 @@ public class GeneralParserTest{ filenames.add("FieldInitializationTest.jav"); filenames.add("ImportTest.jav"); filenames.add("BoundedParameter.jav"); + filenames.add("GenericFieldVarTest.jav"); MyCompilerAPI compiler = MyCompiler.getAPI(); try{ for(String filename : filenames) diff --git a/test/parser/GenericFieldVarTest.jav b/test/parser/GenericFieldVarTest.jav new file mode 100644 index 00000000..a47b41eb --- /dev/null +++ b/test/parser/GenericFieldVarTest.jav @@ -0,0 +1,3 @@ +class Test{ + A var; +} diff --git a/test/plugindevelopment/InsertSingleTypeTest.java b/test/plugindevelopment/InsertSingleTypeTest.java new file mode 100644 index 00000000..0c6ae47c --- /dev/null +++ b/test/plugindevelopment/InsertSingleTypeTest.java @@ -0,0 +1,60 @@ +package plugindevelopment; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Vector; + +import org.junit.Test; + +import junit.framework.TestCase; +import mycompiler.MyCompiler; +import mycompiler.MyCompilerAPI; +import mycompiler.myparser.JavaParser.yyException; +import mycompiler.mytypereconstruction.TypeinferenceResultSet; +import typinferenz.TypeInsertPoint; +import typinferenz.TypeInsertSet; + +public class InsertSingleTypeTest { + private static final String testFile = "SingleTypeInsertTest.jav"; + + @Test + public void test1(){ + TypeinferenceResultSet res = test(testFile); + TypeInsertPoint p = res.getTypeInsertionPoints().points.firstElement(); + try { + System.out.println(res.getTypeInsertionPoints().insertType(p, this.getFileContent(rootDirectory + testFile))); + } catch (IOException e) { + TestCase.fail(); + e.printStackTrace(); + } + } + + static final String rootDirectory = System.getProperty("user.dir")+"/test/plugindevelopment/"; + + public static TypeinferenceResultSet test(String sourceFileToInfere){ + String inferedSource = ""; + MyCompilerAPI compiler = MyCompiler.getAPI(); + try { + compiler.parse(new File(rootDirectory + sourceFileToInfere)); + Vector results = compiler.typeReconstruction(); + TestCase.assertTrue("Es darf nicht mehr als eine Lösungsmöglichkeit geben und nicht "+results.size(), results.size()==1); + return results.firstElement(); + } catch (IOException | yyException e) { + e.printStackTrace(); + TestCase.fail(); + return null; + } + } + + //Source: https://stackoverflow.com/questions/326390/how-to-create-a-java-string-from-the-contents-of-a-file + //PS: benötigt Java 7 + public static String getFileContent(String path)throws IOException + { + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return StandardCharsets.UTF_8.decode(ByteBuffer.wrap(encoded)).toString(); + } +} diff --git a/test/plugindevelopment/SingleTypeInsertTest.jav b/test/plugindevelopment/SingleTypeInsertTest.jav new file mode 100644 index 00000000..8039f897 --- /dev/null +++ b/test/plugindevelopment/SingleTypeInsertTest.jav @@ -0,0 +1,3 @@ +class Test{ +var; +} \ No newline at end of file diff --git a/test/plugindevelopment/TypeInsertTests/LambdaTest10.jav b/test/plugindevelopment/TypeInsertTests/LambdaTest10.jav new file mode 100644 index 00000000..f1787ac4 --- /dev/null +++ b/test/plugindevelopment/TypeInsertTests/LambdaTest10.jav @@ -0,0 +1,9 @@ +class Test{ + +m; + + CT methode(){ +return m; +} + +} \ No newline at end of file diff --git a/test/plugindevelopment/TypeInsertTests/LambdaTest10.java b/test/plugindevelopment/TypeInsertTests/LambdaTest10.java new file mode 100644 index 00000000..ef9af4c8 --- /dev/null +++ b/test/plugindevelopment/TypeInsertTests/LambdaTest10.java @@ -0,0 +1,18 @@ +package plugindevelopment.TypeInsertTests; + +import java.util.Vector; + +import org.junit.Test; + +public class LambdaTest10 { + + private static final String TEST_FILE = "LambdaTest10.jav"; + + @Test + public void run(){ + Vector mustContain = new Vector(); + //mustContain.add("A a"); + MultipleTypesInsertTester.test(this.TEST_FILE, mustContain); + } + +}