Compare commits

..

40 Commits

Author SHA1 Message Date
pl@gohorb.ba-horb.de
007d55ea3f modified: resources/AllgemeinTest/Box.jav
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 2m2s
modified:   resources/bytecode/javFiles/Matrix.jav
	modified:   src/test/java/AllgemeinTest.java
2025-05-15 18:04:32 +02:00
4318856fa8 Fix lookup
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 6m20s
2024-12-12 14:21:23 +01:00
1ace099d72 Undo 2024-12-12 14:06:33 +01:00
b76e1e46f0 Make the example fail
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m47s
2024-12-11 13:29:14 +01:00
09c483542d Change grouping, doesnt work yet
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m18s
2024-12-09 16:53:32 +01:00
77411973be Fix generics
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 4m30s
2024-12-04 13:57:55 +01:00
d0d9c46a67 Work on constraints for parameters of generic records
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 6m14s
2024-12-04 12:22:26 +01:00
Ruben
24bf3d350f feat: add Generic Resolver for Records
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 4m54s
2024-11-29 13:50:09 +01:00
b9f9994de3 toString() doesn't return the class name, see #353
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m18s
2024-11-27 12:57:58 +01:00
pl@gohorb.ba-horb.de
f0287c4611 modified: resources/AllgemeinTest/Box.jav
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 6m3s
modified:   src/test/java/AllgemeinTest.java
2024-11-25 15:46:14 +01:00
pl@gohorb.ba-horb.de
edf609f916 Merge branch 'patternMatching' of ssh://gitea.hb.dhbw-stuttgart.de:2222/JavaTX/JavaCompilerCore into patternMatching
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m39s
2024-11-24 08:15:12 +01:00
pl@gohorb.ba-horb.de
14e2af7d2a modified: resources/AllgemeinTest/Box.jav
modified:   src/test/java/AllgemeinTest.java
2024-11-24 08:15:01 +01:00
pl@gohorb.ba-horb.de
158adf837a modified: resources/bytecode/javFiles/PatternMatchingListAppend.jav
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 4m21s
2024-11-21 14:55:52 +01:00
46b378e3a5 Fix value matching and add new test case
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m6s
2024-11-21 14:31:18 +01:00
484a70c15c Fix test case
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m10s
2024-11-20 17:22:05 +01:00
c461e89336 Try to use 22 for test, might fail
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 4m45s
2024-11-20 17:03:37 +01:00
f846142ee1 Add broken value matching
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 40s
2024-11-20 14:44:10 +01:00
443b8b0c09 Test nested record matching, thankfully switch does the heavy lifting, fixes #349
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 42s
2024-11-20 13:17:10 +01:00
ff715a22cf Filter out duplicate patterns
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 43s
2024-11-20 11:37:50 +01:00
170955b333 More complex overloading for switch
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 43s
2024-11-19 15:19:40 +01:00
88d81f4af7 Work on overloading
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 47s
2024-11-19 13:32:55 +01:00
bb11d24101 First implementation of generating a bridge method
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 45s
2024-11-11 15:47:38 +01:00
e2bf09548f Rename test file and some work on the overloading behavior
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 50s
2024-11-07 17:04:43 +01:00
Ruben
c33e372446 feat: change Test-Case
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 43s
2024-10-25 15:58:18 +02:00
pl@gohorb.ba-horb.de
7c546834c0 modified: resources/bytecode/javFiles/PaternMatchingHaskellStyle.jav
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 43s
modified:   src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/StatementGenerator.java
	modified:   src/test/java/TestComplete.java
2024-10-25 15:31:48 +02:00
Ruben
aa61f90fb1 feat: add Example for HaskellStyle Pattern Matching
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 43s
2024-10-25 14:04:50 +02:00
Ruben
b4da20e1d4 feat: add Example for HaskellStyle Pattern Matching 2024-10-25 14:04:03 +02:00
Ruben
4d1950d0ba feat: add Example for HaskellStyle Pattern Matching
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 42s
2024-10-25 12:06:23 +02:00
pl@gohorb.ba-horb.de
cc204f659a modified: resources/bytecode/javFiles/PaternMatchingHaskellStyle.jav
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 42s
2024-10-25 11:12:46 +02:00
pl@gohorb.ba-horb.de
5893338783 new file: resources/bytecode/javFiles/PaternMatchingHaskellStyle.jav
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 51s
2024-10-25 11:10:00 +02:00
e1e744152a Fix overloading considering too many options, fix #348
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 44s
2024-10-11 14:13:55 +02:00
Ruben
fc22299af5 feat: add Literal in Records and LPattern for Syntaxtreegenerator
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 45s
2024-10-09 17:01:28 +02:00
7811ecce63 Fix non chainable parts in dotted expression
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 49s
2024-10-04 16:41:05 +02:00
44754e73ac Remove left over example code
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 6m28s
2024-10-04 15:05:46 +02:00
Ruben
6ee308a712 feat: add Constraints for Records in Parameterlist
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m6s
2024-10-02 17:06:30 +02:00
85d70378ca Merge branch 'patternMatching' of ssh://gitea.hb.dhbw-stuttgart.de:2222/JavaTX/JavaCompilerCore into patternMatching
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m42s
2024-10-02 15:09:25 +02:00
89bbbdacd8 Work on pattern matching in function headers 2024-10-02 15:09:19 +02:00
Ruben
fbde5afb1b feat: changes on Grammar for literals in Records
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Has been cancelled
2024-10-02 15:02:08 +02:00
6ccf2a3df6 Add overloading for switches, see #348
All checks were successful
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 5m1s
2024-10-01 17:28:20 +02:00
b7979ac7e7 Fix tests
All checks were successful
Build and Test with Maven / Build-and-test-with-Maven (push) Successful in 7m41s
2024-09-26 11:31:24 +02:00
48 changed files with 1549 additions and 735 deletions

View File

@@ -15,7 +15,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
java-version: '22'
cache: 'maven'
- name: Compile project
run: |

View File

@@ -1,6 +0,0 @@
sealed interface List<T> permits LinkedElem, Elem {}
record LinkedElem<T>(T a, List<T> l) implements List<T> {}
record Elem<T>(T a) implements List<T> {}
public class SwitchAppend {}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -2147,6 +2147,18 @@ public class Java17ParserBaseListener implements Java17ParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitEnclosedPattern(Java17Parser.EnclosedPatternContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterLPattern(Java17Parser.LPatternContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitLPattern(Java17Parser.LPatternContext ctx) { }
/**
* {@inheritDoc}
*

View File

@@ -1257,6 +1257,13 @@ public class Java17ParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> impl
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitEnclosedPattern(Java17Parser.EnclosedPatternContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitLPattern(Java17Parser.LPatternContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*

View File

@@ -1960,6 +1960,18 @@ public interface Java17ParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitEnclosedPattern(Java17Parser.EnclosedPatternContext ctx);
/**
* Enter a parse tree produced by the {@code lPattern}
* labeled alternative in {@link Java17Parser#primaryPattern}.
* @param ctx the parse tree
*/
void enterLPattern(Java17Parser.LPatternContext ctx);
/**
* Exit a parse tree produced by the {@code lPattern}
* labeled alternative in {@link Java17Parser#primaryPattern}.
* @param ctx the parse tree
*/
void exitLPattern(Java17Parser.LPatternContext ctx);
/**
* Enter a parse tree produced by {@link Java17Parser#recordPattern}.
* @param ctx the parse tree

View File

@@ -1164,6 +1164,13 @@ public interface Java17ParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitEnclosedPattern(Java17Parser.EnclosedPatternContext ctx);
/**
* Visit a parse tree produced by the {@code lPattern}
* labeled alternative in {@link Java17Parser#primaryPattern}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitLPattern(Java17Parser.LPatternContext ctx);
/**
* Visit a parse tree produced by {@link Java17Parser#recordPattern}.
* @param ctx the parse tree

View File

@@ -54,8 +54,8 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<version>3.11.0</version>
<configuration>
<compilerArgs>--enable-preview</compilerArgs>
<source>21</source>
<target>21</target>
<source>22</source>
<target>22</target>
</configuration>
</plugin>
<plugin>

View File

@@ -1,9 +1,20 @@
public class Box<A> {
public class Box {
A a;
a;
public Box() { }
public Box(A a) {
public Box(a) {
//this.a = a;
}
set(x) {
a = x;
}
get() {
return a;
}
m(b) {
//b.set(b.get());
}
}

View File

@@ -0,0 +1,15 @@
import java.lang.Integer;
public class Assign {
public x = 10;
public y = this;
public call() {
return this;
}
public m() {
this.call().call().y.x = 20;
return x;
}
}

View File

@@ -12,7 +12,6 @@ public class GenericRecordSwitchCase {
return switch(o) {
case LinkedElem(a, Elem(e)) -> a ;
case LinkedElem(a, LinkedElem(e, Elem(f))) -> a;
default -> null;
};
}
}

View File

@@ -23,9 +23,7 @@ public class Matrix extends Vector<Vector<Integer>> {
public mul(m) {
var ret = new Matrix();
var i = 0;
while(i < size()) {
var v1 = this.elementAt(i);
for(v1 : this) {
var v2 = new Vector<Integer>();
var j = 0;
while(j < v1.size()) {
@@ -39,7 +37,6 @@ public class Matrix extends Vector<Vector<Integer>> {
v2.addElement(erg);
j++; }
ret.addElement(v2);
i++;
}
return ret;
}

View File

@@ -0,0 +1,20 @@
import java.lang.Object;
import java.lang.Integer;
import java.lang.Float;
public record R(Object nested) {}
public class OverloadNestedPattern {
public Integer m(R(R(Integer a)), R(Integer b)) {
return 1;
}
public Integer m(R(R(Float a)), R(Float b)) {
return 2;
}
public Integer m(R(Integer a), R(Integer b)) {
return 3;
}
}

View File

@@ -2,15 +2,31 @@ import java.lang.Integer;
import java.lang.Number;
import java.lang.Float;
record Point(Number x, Number y) {}
public record Point(Number x, Number y) {}
public class OverloadPattern {
public m(Point(Integer x, Integer y)) {
return x + y;
public Number m(Point(Integer x, Integer y), Point(Float a, Float b)) {
return 1;
}
public m(Point(Float x, Float y)) {
return x * y;
public Number m(Point(Integer x, Integer y), Point(Integer a, Integer b)) {
return 2;
}
public Number m(Point(Float x, Float y), Point(Integer a, Integer b)) {
return 3;
}
public Number m(Point(Float x, Float y), Point(Float a, Float b)) {
return 4;
}
public Number m(Point(Integer x, Integer y)) {
return 5;
}
public Number m(Point(Float x, Float y)) {
return 6;
}
public m(Integer x) {

View File

@@ -0,0 +1,21 @@
import java.lang.Boolean;
sealed interface List<T> permits LinkedElem, Elem {}
public record LinkedElem<T>(T a, List<T> l) implements List<T> {}
public record Elem<T>(T a) implements List<T> {}
public class PatternMatchingHaskellStyle {
public append(LinkedElem(a, b), list2) {
return handleAppend(a, b, list2);
}
private handleAppend(a, Elem(e), list2) {
return new LinkedElem<>(a, new LinkedElem<>(e, list2));
}
private handleAppend(a, LinkedElem(e,r), list2) {
return new LinkedElem<>(a, append(new LinkedElem(e, r), list2));
}
}

View File

@@ -0,0 +1,26 @@
import java.lang.Boolean;
import java.lang.Object;
sealed interface List<T> permits Cons, Empty {}
public record Cons<T>(T a, List<T> l) implements List<T> {}
public record Empty<T>() implements List<T> {}
public class PatternMatchingListAppend {
public append(Cons(a, b), list2) {
return new Cons<>(a, append(b, list2));
}
public append(Empty(), list2) {
return list2;
}
/*public append(a, list2) {
switch(a) {
case Cons(x, y) -> ...
case Empty() ->
}
}*/
}

View File

@@ -0,0 +1,17 @@
import java.lang.Integer;
import java.lang.Double;
import java.lang.Number;
import java.lang.String;
public record R(Number n) {}
public class SwitchOverload {
public f(){}
public m(r) {
return switch(r) {
case R("test") -> f();
};
}
}

View File

@@ -10,7 +10,7 @@ public class SwitchAppend {
case LinkedElem(a, r) -> new LinkedElem<>(a, append(r, l2));
//Alternativ:
//case LinkedElem(a, LinkedElem(e, r)) -> new LinkedElem<>(a, append(new LinkedElem(e, r), l2));
default -> null;
//default -> null;
};
}
}

View File

@@ -0,0 +1,14 @@
import java.lang.Object;
import java.lang.Integer;
public record R(Integer i) {}
public class SwitchNestedValue {
public main(r) {
return switch(r) {
case R(10) -> 1;
case R(20) -> 2;
case R(i) -> 3;
};
}
}

View File

@@ -0,0 +1,21 @@
import java.lang.Integer;
import java.lang.Double;
import java.lang.Number;
public record R(Number n) {}
public class SwitchOverload {
Number f(Double d) { return d * 2; }
Number f(Integer i) { return i * 5; }
public m(r, x) {
x = x + x;
return switch(r) {
case R(o) -> {
x = x + x;
yield f(o);
}
};
}
}

View File

@@ -654,6 +654,7 @@ primaryPattern
: typePattern #tPattern
| recordPattern #rPattern
| '(' pattern ')' #enclosedPattern
| literal (',' literal)* #lPattern
;
recordPattern

View File

@@ -13,6 +13,7 @@ import de.dhbwstuttgart.target.generate.StatementToTargetExpression;
import de.dhbwstuttgart.target.tree.*;
import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*;
import org.antlr.v4.codegen.Target;
import org.objectweb.asm.*;
import java.lang.invoke.*;
@@ -108,6 +109,10 @@ public class Codegen {
this.scope = this.scope.parent;
}
LocalVar createVariable(TargetType type) {
return createVariable("__var" + this.localCounter, type);
}
LocalVar createVariable(String name, TargetType type) {
var local = new LocalVar(localCounter, name, type);
scope.add(local);
@@ -1294,8 +1299,7 @@ public class Codegen {
state.enterScope();
// This is the index to start the switch from
mv.visitInsn(ICONST_0);
if (aSwitch.isExpression())
state.pushSwitch();
state.pushSwitch();
// To be able to skip ahead to the next case
var start = new Label();
@@ -1393,8 +1397,10 @@ public class Codegen {
state.breakStack.pop();
if (aSwitch.isExpression()) {
mv.visitVarInsn(ALOAD, state.switchResultValue.peek());
unboxPrimitive(state, aSwitch.type());
if (aSwitch.type() != null) {
mv.visitVarInsn(ALOAD, state.switchResultValue.peek());
unboxPrimitive(state, aSwitch.type());
}
state.popSwitch();
}
@@ -1431,7 +1437,24 @@ public class Codegen {
state.mv.visitTypeInsn(CHECKCAST, pat.type().getInternalName());
}
if (pat instanceof TargetTypePattern sp) {
if (pat instanceof TargetExpressionPattern ep) {
var cur = state.createVariable(pat.type());
state.mv.visitVarInsn(ASTORE, cur.index);
var expr = new Equal(pat.type(), new TargetLocalVar(cur.type, cur.name), ep.expression());
generate(state, expr);
var cont = new Label();
state.mv.visitJumpInsn(IFNE, cont);
for (var i = 0; i < depth - 1; i++) {
state.mv.visitInsn(POP);
}
state.mv.visitVarInsn(ALOAD, state.switchResultValue.peek());
state.mv.visitLdcInsn(index + 1);
state.mv.visitJumpInsn(GOTO, start);
state.mv.visitLabel(cont);
} else if (pat instanceof TargetTypePattern sp) {
var local = state.createVariable(sp.name(), sp.type());
state.mv.visitVarInsn(ASTORE, local.index);
} else if (pat instanceof TargetComplexPattern cp) {
@@ -1522,29 +1545,26 @@ public class Codegen {
mv.visitEnd();
}
private int bindLocalVariables(State state, TargetPattern pattern, int offset, int field) {
if (pattern instanceof TargetComplexPattern cp) {
state.mv.visitVarInsn(ALOAD, offset);
private void bindLocalVariables(State state, TargetComplexPattern cp, int offset) {
state.mv.visitVarInsn(ALOAD, offset);
var clazz = findClass(new JavaClassName(cp.type().name()));
if (clazz == null) throw new CodeGenException("Class definition for '" + cp.type().name() + "' not found");
var clazz = findClass(new JavaClassName(cp.type().name()));
if (clazz == null) throw new CodeGenException("Class definition for '" + cp.type().name() + "' not found");
for (var i = 0; i < cp.subPatterns().size(); i++) {
var subPattern = cp.subPatterns().get(i);
for (var i = 0; i < cp.subPatterns().size(); i++) {
var subPattern = cp.subPatterns().get(i);
if (i < cp.subPatterns().size() - 1)
state.mv.visitInsn(DUP);
if (i < cp.subPatterns().size() - 1)
state.mv.visitInsn(DUP);
extractField(state, cp.type(), i, clazz);
state.mv.visitTypeInsn(CHECKCAST, subPattern.type().getInternalName());
state.mv.visitVarInsn(ASTORE, offset);
offset = bindLocalVariables(state, subPattern, offset, i);
extractField(state, cp.type(), i, clazz);
state.mv.visitTypeInsn(CHECKCAST, subPattern.type().getInternalName());
offset = state.createVariable(subPattern.name(), subPattern.type()).index;
state.mv.visitVarInsn(ASTORE, offset);
if (subPattern instanceof TargetComplexPattern cp2) {
bindLocalVariables(state, cp2, offset);
}
} else if (pattern instanceof TargetTypePattern tp) {
offset++;
state.createVariable(tp.name(), tp.type());
} else throw new NotImplementedException();
return offset;
}
}
private void generateMethod(TargetMethod method) {
@@ -1563,8 +1583,14 @@ public class Codegen {
if (method.block() != null) {
mv.visitCode();
var state = new State(method.signature().returnType(), mv, method.isStatic() ? 0 : 1);
var offset = 1;
for (var param : method.signature().parameters()) {
bindLocalVariables(state, param.pattern(), 1, 0);
state.createVariable(param.pattern().name(), param.pattern().type());
}
for (var param : method.signature().parameters()) {
if (param.pattern() instanceof TargetComplexPattern cp)
bindLocalVariables(state, cp, offset);
offset++;
}
generate(state, method.block());
if (method.signature().returnType() == null)

View File

@@ -14,6 +14,8 @@ import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.type.Void;
import de.dhbwstuttgart.target.tree.expression.TargetUnaryOp;
import de.dhbwstuttgart.target.generate.StatementToTargetExpression;
import org.antlr.v4.runtime.Token;
import de.dhbwstuttgart.exceptions.NotImplementedException;
@@ -101,7 +103,6 @@ import de.dhbwstuttgart.parser.scope.JavaClassRegistry;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import org.stringtemplate.v4.ST;
public class StatementGenerator {
@@ -152,7 +153,7 @@ public class StatementGenerator {
: TypePlaceholder.fresh(fp.getStart());
}
ret.add(new FormalParameter(paramName, type, fp.getStart()));
localVars.put(paramName, type);
localVars.put(paramName, type);
}
}
return new ParameterList(ret, ret.get(0).getOffset());
@@ -441,6 +442,7 @@ public class StatementGenerator {
}
private Pattern convert(PatternContext pattern) {
return switch (pattern) {
case PPatternContext pPattern -> {
yield convert(pPattern.primaryPattern());
@@ -455,6 +457,7 @@ public class StatementGenerator {
}
private FormalParameter convert(PrimaryPatternContext pPattern) {
switch (pPattern) {
case TPatternContext tPattern:
TypePatternContext typePattern = tPattern.typePattern();
@@ -465,21 +468,25 @@ public class StatementGenerator {
case RPatternContext rPattern:
RecordPatternContext recordPattern = rPattern.recordPattern();
return convert(recordPattern);
default:
throw new NotImplementedException();
case Java17Parser.LPatternContext patternContext: return new LiteralPattern(TypePlaceholder.fresh(patternContext.start), convert(patternContext.literal().get(0)), patternContext.start);
default:
throw new NotImplementedException();
}
}
private RecordPattern convert(RecordPatternContext recordPatternCtx) {
List<PatternContext> subPatternCtx = recordPatternCtx.recordStructurePattern().recordComponentPatternList().pattern();
var cpl = recordPatternCtx.recordStructurePattern().recordComponentPatternList();
List<PatternContext> subPatternCtx = cpl == null ? List.of() : cpl.pattern();
List<Pattern> subPattern = subPatternCtx.stream().map(this::convert).collect(Collectors.toList());
IdentifierContext identifierCtx = recordPatternCtx.identifier();
var text = (identifierCtx != null) ? identifierCtx.getText() : null;
//Hier evtl. Typ anpassen -> wenn kein Typ bekannt ist push neuen Typ auf Hashtable
var type = recordPatternCtx.typeType() == null ? TypePlaceholder.fresh(recordPatternCtx.getStart()) : TypeGenerator.convert(recordPatternCtx.typeType(), reg, generics);
if (text != null) localVars.put(text, type);
return new RecordPattern(subPattern, text, type, recordPatternCtx.getStart());
var ret = new RecordPattern(subPattern, text, type, recordPatternCtx.getStart());
return ret;
}
private Statement convert(Java17Parser.WhileloopContext stmt) {
@@ -586,7 +593,7 @@ public class StatementGenerator {
initValue = convert(varDecl.variableInitializer().expression());
}
var fieldEntry = fields.get(name.getText());
return (new Assign(new AssignToField(new FieldVar(new This(varDecl.getStart()), (fieldEntry.modifiers() & Modifier.STATIC) != 0, name.getText(), type, varDecl.getStart())), initValue, name.getStart()));
return (new Assign(new AssignToField(new FieldVar(new This(varDecl.getStart()), name.getText(), type, varDecl.getStart())), initValue, name.getStart()));
}
private Statement convert(Java17Parser.BreakstmtContext stmt) {
@@ -700,8 +707,7 @@ public class StatementGenerator {
if (!Objects.isNull(expr.methodCall())) {
return convert(expr.methodCall(), expr.expression(), offset);
} else if (!Objects.isNull(expr.identifier())) {
// FIXME This is not the right way of handling any of this
return generateLocalOrFieldVarOrClassName(expr.getText(), offset);
return new FieldVar(convert(expr.expression()), expr.identifier().getText(), TypePlaceholder.fresh(expr.identifier().start), offset);
} else {
// Für alle anderen Optionen, wie Feldzugriff, Aufrufe von super oder explizite
// generische Invokationen
@@ -777,64 +783,25 @@ public class StatementGenerator {
/**
* Der Parser kann nicht zwischen einer lokalen Variable, einem Feldzugriff und einer Klassenangabe unterscheiden.
*
*
* @param expression
* @param offset
* @return
*/
private Expression generateLocalOrFieldVarOrClassName(String expression, Token offset) {
// FIXME Why does this take a String argument???
String[] parts = expression.split("\\.");
if (parts.length < 2) {
// Check for localVar:
if (localVars.get(expression) != null) {
return new LocalVar(expression, localVars.get(expression), offset);
} else if (fields.get(expression) != null) {// PL 2018-11-01 fields eingefuegt, damit die fields immer die
// gleiche TPH bekommen
var field = fields.get(expression);
return new FieldVar(new This(offset), Modifier.isStatic(field.modifiers()), expression, fields.get(expression).type(), offset);
} else if (reg.contains(expression)) {
return generateStaticClassName(expression, offset);
} else {
// lokale Variable wurde ohne "var"-Keyword deklariert und direkt mit Wert versehen
localVars.put(expression, TypePlaceholder.fresh(offset));
return new LocalVar(expression, localVars.get(expression), offset);
}
}
return generateFieldVarOrClassname(expression, offset);
}
private Expression generateFieldVarOrClassname(String expression, Token offset) {
String[] parts = expression.split("\\.");
String whole = "";
Expression receiver = null;
for (String part : parts) {
whole += part;
// Check for Classname:
if (reg.contains(whole)) {
receiver = generateStaticClassName(whole, offset);
break;
}
whole += ".";
}
var fieldName = parts[parts.length - 1];
var isStatic = false;
if (parts.length < 2 || parts[0].contentEquals("this")) {
receiver = new This(offset);
isStatic = Modifier.isStatic(fields.get(fieldName).modifiers());
} else if (parts[0].contentEquals("super")) {
receiver = new Super(TypePlaceholder.fresh(offset), offset);
isStatic = Modifier.isStatic(compiler.getClass(new JavaClassName(superClass.getName().toString())).getField(fieldName).orElseThrow().modifier);
} else if (receiver == null) { // Handelt es sich um keinen Statischen Klassennamen:
String part = expression.substring(0, expression.length() - (1 + parts[parts.length - 1].length()));
receiver = generateLocalOrFieldVarOrClassName(part, offset);
// Check for localVar:
if (localVars.get(expression) != null) {
return new LocalVar(expression, localVars.get(expression), offset);
} else if (fields.get(expression) != null) {// PL 2018-11-01 fields eingefuegt, damit die fields immer die
// gleiche TPH bekommen
return new FieldVar(new This(offset), expression, fields.get(expression).type(), offset);
} else if (reg.contains(expression)) {
return generateStaticClassName(expression, offset);
} else {
StaticClassName cname = (StaticClassName) receiver;
var javaClassName = reg.getName(cname.getType().toString());
isStatic = Modifier.isStatic(compiler.getClass(javaClassName).getField(fieldName).orElseThrow().modifier);
// lokale Variable wurde ohne "var"-Keyword deklariert und direkt mit Wert versehen
localVars.put(expression, TypePlaceholder.fresh(offset));
return new LocalVar(expression, localVars.get(expression), offset);
}
return new FieldVar(receiver, isStatic, fieldName, TypePlaceholder.fresh(offset), offset);
}
private Expression convert(Java17Parser.ArrayaccessexpressionContext arrayaccess) {
@@ -870,10 +837,8 @@ public class StatementGenerator {
private Statement convert(AssignexpressionContext expr) {
switch (expr.bop.getText()) {
case "=":
ExpressionContext leftside = expr.expression(0);
AssignLeftSide leftHandSide = convert(leftside.getText(), leftside.getStart());
Statement ret = new Assign(leftHandSide, convert(expr.expression(1)), expr.getStart());
return ret;
AssignLeftSide leftHandSide = convertAssignLHS(convert(expr.expression(0)));
return new Assign(leftHandSide, convert(expr.expression(1)), expr.getStart());
case "+=":
case "-=":
case "*=":
@@ -890,8 +855,8 @@ public class StatementGenerator {
}
}
private AssignLeftSide convert(String leftHandSide, Token start) {
Expression leftSide = generateLocalOrFieldVarOrClassName(leftHandSide, start);
private AssignLeftSide convertAssignLHS(Expression expr) {
Expression leftSide = expr;
if (leftSide instanceof FieldVar)
return new AssignToField((FieldVar) leftSide);
else if (leftSide instanceof LocalVar)

View File

@@ -269,7 +269,7 @@ public class SyntaxTreeGenerator {
}
fielddecl.add(new Field(fieldname, fieldtype, fieldmodifiers, fieldoffset));
constructorParameters.add(new FormalParameter(fieldname, fieldtype, fieldoffset));
FieldVar fieldvar = new FieldVar(new This(offset), false, fieldname, fieldtype, fieldoffset);
FieldVar fieldvar = new FieldVar(new This(offset), fieldname, fieldtype, fieldoffset);
constructorStatements.add(new Assign(new AssignToField(fieldvar), new LocalVar(fieldname, fieldtype, fieldoffset), offset));
Statement returnStatement = new Return(fieldvar, offset);
methods.add(new Method(allmodifiers.get("public"), fieldname, fieldtype, new ParameterList(new ArrayList<>(), offset), new Block(Arrays.asList(returnStatement), offset), new GenericDeclarationList(new ArrayList<>(), offset), offset));

View File

@@ -10,6 +10,8 @@ public interface ASTVisitor extends StatementVisitor{
void visit(FormalParameter formalParameter);
void visit(LiteralPattern literalPattern);
void visit(GenericDeclarationList genericTypeVars);
void visit(Field field);

View File

@@ -37,6 +37,11 @@ public abstract class AbstractASTWalker implements ASTVisitor {
formalParameter.getType().accept((ASTVisitor) this);
}
@Override
public void visit(LiteralPattern literalPattern) {
}
@Override
public void visit(GenericDeclarationList genericTypeVars) {
Iterator<GenericTypeVar> genericIterator = genericTypeVars.iterator();

View File

@@ -0,0 +1,29 @@
package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.syntaxtree.ASTVisitor;
import de.dhbwstuttgart.syntaxtree.Pattern;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.statement.Expression;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import org.antlr.v4.runtime.Token;
public class LiteralPattern extends FormalParameter
{
public final Expression value;
public LiteralPattern(RefTypeOrTPHOrWildcardOrGeneric type, Expression value, Token offset) {
super(null, type, offset);
this.value = value;
}
@Override
public FormalParameter withType(RefTypeOrTPHOrWildcardOrGeneric type) {
return new LiteralPattern(type, value, getOffset());
}
@Override
public void accept(ASTVisitor visitor) {
visitor.visit(this);
}
}

View File

@@ -3,6 +3,7 @@ package de.dhbwstuttgart.syntaxtree;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.statement.*;
public interface StatementVisitor {
void visit(ArgumentList argumentList);

View File

@@ -34,7 +34,6 @@ public class ASTFactory {
private static final HashMap<java.lang.Class, ClassOrInterface> cache = new HashMap<>();
public static ClassOrInterface createClass(java.lang.Class jreClass) {
System.out.println(jreClass);
if (cache.containsKey(jreClass))
return cache.get(jreClass);
@@ -174,7 +173,6 @@ public class ASTFactory {
superClass = (RefType) createType(java.lang.Object.class);
}
List<RefType> implementedInterfaces = new ArrayList<>();
System.out.println(jreClass);
for (Type jreInterface : jreClass.getGenericInterfaces()) {
implementedInterfaces.add((RefType) createType(jreInterface));
}

View File

@@ -17,13 +17,11 @@ public class FieldVar extends Expression {
public final String fieldVarName;
public final Expression receiver;
public final boolean isStatic;
public FieldVar(Expression receiver, boolean isStatic, String fieldVarName, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) {
public FieldVar(Expression receiver, String fieldVarName, RefTypeOrTPHOrWildcardOrGeneric type, Token offset) {
super(type, offset);
this.fieldVarName = fieldVarName;
this.receiver = receiver;
this.isStatic = isStatic;
}
@Override

View File

@@ -8,6 +8,7 @@ import org.antlr.v4.runtime.Token;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
public class RefType extends RefTypeOrTPHOrWildcardOrGeneric
@@ -49,10 +50,7 @@ public class RefType extends RefTypeOrTPHOrWildcardOrGeneric
@Override
public int hashCode() {
int hash = 0;
hash += super.hashCode();
hash += this.name.hashCode();//Nur den Name hashen. Sorgt für langsame, aber funktionierende HashMaps
return hash;
return this.name.hashCode();//Nur den Name hashen. Sorgt für langsame, aber funktionierende HashMaps
}
public RefType(JavaClassName fullyQualifiedName, List<RefTypeOrTPHOrWildcardOrGeneric> parameter, Token offset) {
@@ -83,6 +81,7 @@ public class RefType extends RefTypeOrTPHOrWildcardOrGeneric
public boolean equals(Object obj)
{
if(obj instanceof RefType){
if (!Objects.equals(this.name, ((RefType) obj).name)) return false;
boolean ret = true;
//if(!(super.equals(obj))) PL 2020-03-12 muss vll. einkommentiert werden

View File

@@ -57,6 +57,11 @@ public class OutputGenerator implements ASTVisitor {
out.append(formalParameter.getName());
}
@Override
public void visit(LiteralPattern literalPattern) {
literalPattern.value.accept(this);
}
@Override
public void visit(GenericDeclarationList genericTypeVars) {
Iterator<GenericTypeVar> genericIterator = genericTypeVars.iterator();
@@ -508,12 +513,11 @@ public class OutputGenerator implements ASTVisitor {
aRecordPattern.getType().accept(this);
out.append("(");
List<Pattern> subPatterns = aRecordPattern.getSubPattern();
int i;
for (i = 0; i < subPatterns.size() - 1; i++) {
for (var i = 0; i < subPatterns.size(); i++) {
subPatterns.get(i).accept(this);
out.append(", ");
if (i < subPatterns.size() - 1)
out.append(", ");
}
subPatterns.get(i).accept(this);
String name;
if ((name = aRecordPattern.getName()) != null)
out.append(name);

View File

@@ -1,10 +1,10 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.bytecode.CodeGenException;
import de.dhbwstuttgart.bytecode.FunNGenerator;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.environment.ByteArrayClassLoader;
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
import de.dhbwstuttgart.exceptions.DebugException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*;
@@ -17,6 +17,7 @@ import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.result.*;
import java.lang.annotation.Target;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -33,12 +34,18 @@ public class ASTToTargetAST {
protected List<Generics> all;
public Generics generics;
public List<Generics> currentMethodOverloads;
final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>();
final Map<Method, Set<SignaturePair>> tphsInMethods = new HashMap<>();
private Method currentMethod;
public final JavaTXCompiler compiler;
public List<RefTypeOrTPHOrWildcardOrGeneric> findAllVariants(RefTypeOrTPHOrWildcardOrGeneric type) {
return javaGenerics().stream().map(generics -> generics.resolve(type)).distinct().toList();
}
public List<GenericsResult> txGenerics() {
return all.stream().map(generics -> new GenericsResult(generics.txGenerics)).toList();
}
@@ -138,38 +145,100 @@ public class ASTToTargetAST {
return ret;
}
// This is used to serve as a custom equality to signature that performs a weak check without going into record patterns.
// The two signatures are considered equal if all the argument types match.
// This also turns equal if both types implement a sealed super interface
class PatternSignature {
final TargetMethod.Signature signature;
final String name;
PatternSignature(String name, TargetMethod.Signature signature) {
this.signature = signature;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof PatternSignature other)) return false;
if (!this.name.equals(other.name)) return false;
if (other.signature.parameters().size() != signature.parameters().size()) return false;
for (var i = 0; i < signature.parameters().size(); i++) {
var p1 = signature.parameters().get(i).pattern().type();
var p2 = other.signature.parameters().get(i).pattern().type();
if (p1 instanceof TargetGenericType && p2 instanceof TargetGenericType) continue;
if (!p1.equals(p2) && commonSuperInterfaceTypes(p1, p2).isEmpty()) return false;
}
return true;
}
@Override
public int hashCode() {
return signature.parameters().size();
}
}
// This finds a common sealed interface type to group together methods that use different records
private List<ClassOrInterface> commonSuperInterfaceTypes(TargetType a, TargetType b) {
if (a instanceof TargetGenericType && b instanceof TargetGenericType) return List.of(ASTFactory.createClass(Object.class));
if (a instanceof TargetRefType ta && b instanceof TargetRefType tb) {
var res = new HashSet<ClassOrInterface>();
var cla = compiler.getClass(new JavaClassName(ta.name()));
var clb = compiler.getClass(new JavaClassName(tb.name()));
while (!cla.equals(ASTFactory.createClass(Object.class))) {
var clb2 = clb;
while (!clb2.equals(ASTFactory.createClass(Object.class))) {
for (var intfa : cla.getSuperInterfaces()) {
for (var intfb : clb.getSuperInterfaces()) {
if (intfa.equals(intfb)) {
var clintf = compiler.getClass(intfa.getName());
if (clintf.isSealed()) {
res.add(clintf);
}
}
}
}
clb2 = compiler.getClass(clb2.getSuperClass().getName());
}
cla = compiler.getClass(cla.getSuperClass().getName());
}
return res.stream().toList();
}
return List.of();
}
public List<List<TargetMethod>> groupOverloads(ClassOrInterface input, List<Method> methods) {
var res = new ArrayList<List<TargetMethod>>();
var mapOfSignatures = new HashMap<PatternSignature, List<TargetMethod>>();
for (var method : methods) {
// Convert all methods
var methodsWithTphs = convert(input, method);
// Then check for methods with the same signature
var mapOfSignatures = new HashMap<TargetMethod.Signature, List<MethodWithTphs>>();
for (var m : methodsWithTphs) {
var methodsWithSameSignature = mapOfSignatures.getOrDefault(m.method.signature(), new ArrayList<>());
methodsWithSameSignature.add(m);
mapOfSignatures.put(m.method.signature(), methodsWithSameSignature);
}
var resMethods = new HashSet<MethodWithTphs>();
var resMethods = new HashSet<TargetMethod>();
for (var methodsWithSignature : mapOfSignatures.values()) {
outer: for (var m1 : methodsWithSignature) {
for (var m2 : methodsWithSignature) {
for (var i = 0; i < m1.args.size(); i++) {
var arg1 = m1.args.get(i);
var arg2 = m2.args.get(i);
if (arg1.parameter.equals(arg2.parameter)) {
if (isSupertype(arg1.signature, arg2.signature) &&
outer:
for (var m1 : methodsWithTphs) {
for (var m2 : methodsWithTphs) {
for (var i = 0; i < m1.args.size(); i++) {
var arg1 = m1.args.get(i);
var arg2 = m2.args.get(i);
if (arg1.parameter.equals(arg2.parameter)) {
if (isSupertype(arg1.signature, arg2.signature) &&
!arg1.signature.equals(arg2.signature)) continue outer;
}
}
}
resMethods.add(m1.method);
}
resMethods.add(m1);
}
for (var m : resMethods) {
var signature = new PatternSignature(m.method.name(), m.method.signature());
var methodsWithSameSignature = mapOfSignatures.getOrDefault(signature, new ArrayList<>());
methodsWithSameSignature.add(m.method);
mapOfSignatures.put(signature, methodsWithSameSignature);
}
res.add(resMethods.stream().toList());
}
return res;
return mapOfSignatures.values().stream().toList();
}
public TargetStructure convert(ClassOrInterface input) {
@@ -202,7 +271,7 @@ public class ASTToTargetAST {
var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList();
var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList();
var fields = input.getFieldDecl().stream().map(this::convert).toList();
var methods = groupOverloads(input, input.getMethods()).stream().flatMap(List::stream).toList();
var methods = groupOverloads(input, input.getMethods()).stream().map(m -> generatePatternOverloads(input, m)).flatMap(List::stream).toList();
TargetMethod staticConstructor = null;
if (input.getStaticInitializer().isPresent())
@@ -216,9 +285,14 @@ public class ASTToTargetAST {
}
public List<MethodParameter> convert(ParameterList input, GenerateGenerics generics) {
return input.getFormalparalist().stream().map(param ->
new MethodParameter((TargetPattern) convert(param))
).toList();
var res = new ArrayList<MethodParameter>();
for (var i = 0; i < input.getFormalparalist().size(); i++) {
var param = input.getFormalparalist().get(i);
var pattern = (TargetPattern) convert(param);
if (pattern instanceof TargetComplexPattern) pattern = pattern.withName("__var" + i);
res.add(new MethodParameter(pattern));
}
return res;
}
private boolean hasGeneric(Set<TargetGeneric> generics, GenericRefType type) {
@@ -267,69 +341,154 @@ public class ASTToTargetAST {
return result;
}
private String encodeName(String name, ParameterList params) {
private String encodeName(String name, TargetMethod.Signature params) {
var res = new StringBuilder();
res.append(name);
res.append('$');
for (var param : params.getFormalparalist()) {
if (param instanceof RecordPattern rp) {
res.append(FunNGenerator.encodeType(convert(param.getType())));
for (var pattern : rp.getSubPattern()) {
res.append(FunNGenerator.encodeType(convert(pattern.getType())));
}
}
for (var param : params.parameters()) {
encodeName(param.pattern(), res);
}
return res.toString();
}
private List<TargetMethod> convert(ClassOrInterface clazz, List<Method> overloadedMethods) {
if (overloadedMethods.size() == 1) {
return convert(clazz, overloadedMethods.getFirst()).stream().map(m -> m.method()).toList();
}
var methods = new ArrayList<Method>();
for (var method : overloadedMethods) {
var newMethod = new Method(
method.modifier,
method.name,
//encodeName(method.name, method.getParameterList()),
method.getReturnType(),
method.getParameterList(),
method.block,
method.getGenerics(),
method.getOffset()
);
methods.add(newMethod);
}
// TODO Record overloading
/*var template = overloadedMethods.get(0);
var pParams = new ArrayList<Pattern>();
var i = 0;
for (var par : template.getParameterList()) {
pParams.add(switch (par) {
case RecordPattern rp -> new RecordPattern(rp.getSubPattern(), "par" + i, rp.getType(), new NullToken());
default -> par;
});
i++;
}
var params = new ParameterList(pParams, new NullToken());
var statements = new ArrayList<Statement>();
statements.add(new Return(makeRecordSwitch(template.getReturnType(), params, res), new NullToken()));
var block = new Block(statements, new NullToken());
var entryPoint = new Method(template.modifier, template.name, template.getReturnType(), params, block, template.getGenerics(), new NullToken());
res.add(entryPoint); // TODO*/
var res = new ArrayList<TargetMethod>();
for (var method : methods) {
var overloads = convert(clazz, method);
for (var m : overloads) {
var overload = m.method;
if (res.contains(overload)) throw new CodeGenException("Duplicate method found: " + overload.name() + " with signature " + overload.signature().getSignature());
res.add(overload);
private void encodeName(TargetPattern pattern, StringBuilder res) {
if (pattern instanceof TargetComplexPattern cp) {
res.append(FunNGenerator.encodeType(cp.type()));
for (var pat : cp.subPatterns()) {
encodeName(pat, res);
}
} else {
res.append(FunNGenerator.encodeType(pattern.type()));
}
}
private TargetType unwrap(TargetType type) {
if (type instanceof TargetRefType ref) {
if (!ref.params().isEmpty()) return new TargetRefType(ref.name());
}
return type;
}
private TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List<TargetLocalVar> params, List<TargetPattern> patterns, List<TargetMethod> methods, TargetType classType) {
if (methods.isEmpty()) throw new DebugException("Couldn't find a candidate for switch overloading");
if (methods.size() == 1) {
var method = methods.getFirst();
var mParams = new ArrayList<TargetExpression>();
for (var i = 0; i < params.size(); i++) {
var tpe = method.signature().parameters().get(i).pattern().type();
mParams.add(new TargetLocalVar(tpe, params.get(i).name()));
}
TargetExpression caseBody = new TargetMethodCall(
method.signature().returnType(),
new TargetThis(classType),
mParams,
classType,
method.name(),
false, false, method.isPrivate()
);
if (method.signature().returnType() != null) {
caseBody = new TargetReturn(caseBody);
}
return caseBody;
}
var cases = new ArrayList<TargetSwitch.Case>();
var usedPatterns = new HashSet<TargetType>();
for (var method : methods) {
var patternsRec = new ArrayList<>(patterns);
TargetExpression expr = null;
var i = 0;
for (var param : method.signature().parameters()) {
if (i == offset) {
patternsRec.add(param.pattern());
}
if (i > offset) {
// Find next pattern
expr = params.get(i);
break;
}
i++;
}
var lastPattern = patternsRec.getLast();
var type = unwrap(lastPattern.type());
if (usedPatterns.contains(type)) continue;
usedPatterns.add(type);
var candidates = methods.stream().filter(m -> {
var j = 0;
for (var param : m.signature().parameters()) {
if (j >= patternsRec.size()) return true;
if (!patternsRec.get(j).type().equals(param.pattern().type())) return false;
j++;
}
return true;
}).toList();
var caseBody = generatePatternOverloadsRec(offset + 1, expr, params, patternsRec, candidates, classType);
var body = new TargetBlock(List.of(caseBody));
var case_ = new TargetSwitch.Case(List.of(lastPattern), body);
cases.add(case_);
}
return new TargetSwitch(switchExpr, cases, null, true);
}
private List<TargetMethod> generatePatternOverloads(ClassOrInterface clazz, List<TargetMethod> overloadedMethods) {
if (overloadedMethods.size() <= 1) return overloadedMethods;
// Check if we have a pattern as a parameter
var firstMethod = overloadedMethods.getFirst();
var secondMethod = overloadedMethods.get(1);
if (firstMethod.signature().parameters().stream().noneMatch(mp -> mp.pattern() instanceof TargetComplexPattern)) return overloadedMethods;
// Rename existing methods
var res = new ArrayList<TargetMethod>();
for (var method : overloadedMethods) {
var name = encodeName(method.name(), method.signature());
res.add(new TargetMethod(method.access(), name, method.block(), method.signature(), method.txSignature()));
}
var signatureParams = new ArrayList<MethodParameter>();
for (var i = 0; i < firstMethod.signature().parameters().size(); i++) {
var p1 = firstMethod.signature().parameters().get(i).pattern();
var t1 = p1.type();
var t2 = secondMethod.signature().parameters().get(i).pattern().type();
var commonSubTypes = new HashSet<>(commonSuperInterfaceTypes(t1, t2));
for (var m : overloadedMethods.subList(2, overloadedMethods.size())) {
var t3 = m.signature().parameters().get(i).pattern().type();
commonSubTypes.retainAll(commonSuperInterfaceTypes(t1, t3));
}
if (commonSubTypes.size() != 1) throw new DebugException("Invalid overload");
// TODO accept multiple types
var superType = commonSubTypes.iterator().next();
String name;
if (p1 instanceof TargetComplexPattern) name = "__var" + i;
else name = p1.name();
signatureParams.add(new MethodParameter(new TargetRefType(superType.getClassName().toString()), name));
}
var commonSubTypes = new HashSet<>(commonSuperInterfaceTypes(firstMethod.signature().returnType(), secondMethod.signature().returnType()));
for (var m : overloadedMethods.subList(2, overloadedMethods.size())) {
commonSubTypes.retainAll(commonSuperInterfaceTypes(firstMethod.signature().returnType(), m.signature().returnType()));
}
var returnType = commonSubTypes.isEmpty() ? TargetType.Object : new TargetRefType(commonSubTypes.iterator().next().getClassName().toString());
var parameters = signatureParams.stream().map( p -> new TargetLocalVar(p.pattern().type(), p.pattern().name())).toList();
//var patterns = List.of((TargetComplexPattern) firstMethod.signature().parameters().stream()
// .filter(p -> p.pattern() instanceof TargetComplexPattern).findFirst().orElseThrow().pattern());
// Generate dispatch method
var classType = new TargetRefType(clazz.getClassName().getClassName());
var stmt = generatePatternOverloadsRec(0, new TargetLocalVar(signatureParams.getFirst().pattern().type(), signatureParams.getFirst().pattern().name()), parameters, List.of(), res, classType);
var block = new TargetBlock(List.of(stmt));
var signature = new TargetMethod.Signature(Set.of(), signatureParams, returnType);
var bridgeMethod = new TargetMethod(firstMethod.access(), firstMethod.name(), block, signature, firstMethod.txSignature());
res.add(bridgeMethod);
return res;
}
@@ -376,11 +535,16 @@ public class ASTToTargetAST {
record MethodWithTphs(TargetMethod method, List<SignaturePairTarget> args) {}
record Signature(TargetMethod.Signature java, TargetMethod.Signature tx, Generics generics) {}
private List<MethodWithTphs> convert(ClassOrInterface currentClass, Method method) {
generics = all.getFirst();
List<MethodWithTphs> result = new ArrayList<>();
this.currentMethod = method;
List<Signature> signatures = new ArrayList<>();
HashMap<TargetMethod.Signature, List<Generics>> collectedGenerics = new HashMap<>();
for (var s : all) {
generics = s;
var javaGenerics = this.generics.javaGenerics.generics(currentClass, method);
@@ -404,8 +568,18 @@ public class ASTToTargetAST {
var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType);
var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics));
var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature);
signatures.add(new Signature(javaSignature, txSignature, generics));
var listOfGenerics = collectedGenerics.getOrDefault(javaSignature, new ArrayList<>());
listOfGenerics.add(generics);
collectedGenerics.put(javaSignature, listOfGenerics);
}
for (var signature : signatures) {
generics = signature.generics;
currentMethodOverloads = collectedGenerics.get(signature.java);
var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), signature.java, signature.tx);
var concreteParams = tphsInMethods.getOrDefault(method, new HashSet<>()).stream().map(sig -> new SignaturePairTarget(convert(sig.signature), convert(sig.parameter))).toList();
result.add(new MethodWithTphs(newMethod, concreteParams));
@@ -418,7 +592,9 @@ public class ASTToTargetAST {
var list = new ArrayList<MethodParameter>();
for (var i = 0; i < paraList.getFormalparalist().size(); i++) {
var param = paraList.getParameterAt(i);
list.add(new MethodParameter((TargetPattern) convert(param)).withType(convert(superList.getParameterAt(i).getType(), generics)));
var pattern = (TargetPattern) convert(param);
if (pattern instanceof TargetComplexPattern) pattern = pattern.withName("__var" + i);
list.add(new MethodParameter(pattern).withType(convert(superList.getParameterAt(i).getType(), generics)));
}
return list;
}

View File

@@ -1,10 +1,7 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Constructor;
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.syntaxtree.type.Void;
@@ -134,8 +131,8 @@ public abstract class GenerateGenerics {
final Map<Method, Set<Pair>> familyOfMethods = new HashMap<>();
final Set<PairLT> simplifiedConstraints = new HashSet<>();
final Map<TPH, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
final Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>();
Map<TPH, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>();
GenerateGenerics(ASTToTargetAST astToTargetAST, ResultSet constraints) {
this.astToTargetAST = astToTargetAST;
@@ -154,6 +151,41 @@ public abstract class GenerateGenerics {
System.out.println("Simplified constraints: " + simplifiedConstraints);
}
/*public record GenericsState(Map<TPH, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes, Map<TypePlaceholder, TypePlaceholder> equality) {}
public GenericsState store() {
return new GenericsState(new HashMap<>(concreteTypes), new HashMap<>(equality));
}
public void restore(GenericsState state) {
this.concreteTypes = state.concreteTypes;
this.equality = state.equality;
}
public void addOverlay(TypePlaceholder from, RefTypeOrTPHOrWildcardOrGeneric to) {
if (to instanceof TypePlaceholder t) equality.put(from, t);
else if (to instanceof RefType t) concreteTypes.put(new TPH(from), t);
}*/
Set<TPH> findTypeVariables(ParameterList params) {
var res = new HashSet<TPH>();
for (var param : params.getFormalparalist()) {
res.addAll(findTypeVariables(param));
}
return res;
}
Set<TPH> findTypeVariables(Pattern pattern) {
var res = new HashSet<TPH>();
if (pattern instanceof RecordPattern rp) {
for (var subPattern : rp.getSubPattern()) {
res.addAll(findTypeVariables(subPattern));
}
}
res.addAll(findTypeVariables(pattern.getType()));
return res;
}
Set<TPH> findTypeVariables(RefTypeOrTPHOrWildcardOrGeneric type) {
var result = new HashSet<TPH>();
if (type instanceof TypePlaceholder tph) {
@@ -490,9 +522,7 @@ public abstract class GenerateGenerics {
if (!(method instanceof Constructor))
typeVariables.addAll(findTypeVariables(method.getReturnType()));
for (var arg : method.getParameterList().getFormalparalist()) {
typeVariables.addAll(findTypeVariables(arg.getType()));
}
typeVariables.addAll(findTypeVariables(method.getParameterList()));
if (method.block != null)
method.block.accept(new TracingStatementVisitor() {
@@ -556,9 +586,7 @@ public abstract class GenerateGenerics {
var usedTphs = new HashSet<TPH>();
// For eliminating inner type variables we need to figure out which ones are actually used
for (var param : method.getParameterList().getFormalparalist()) {
usedTphs.addAll(findTypeVariables(param.getType()));
}
usedTphs.addAll(findTypeVariables(method.getParameterList()));
usedTphs.addAll(findTypeVariables(method.getReturnType()));
referenced.addAll(usedTphs);
referenced.addAll(typeVariablesOfClass);
@@ -656,11 +684,21 @@ public abstract class GenerateGenerics {
if (p1 instanceof PairLT ptph && ptph.left.resolve().equals(ptph.right.resolve()))
result.remove(p1); // TODO This is a bit strange
}
for (var tph : usedTphs) {
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.left.equals(tph)))
addToPairs(result, new PairEQ(tph, ASTToTargetAST.OBJECT));
}
var all = new HashSet<>(result);
for (var p : all) {
if (p instanceof PairEQ peq && peq.right.equals(ASTToTargetAST.OBJECT)) {
for (var p2 : all) {
if (p2 instanceof PairLT && p2.left.equals(p.left)) {
result.remove(p);
break;
}
}
}
}
}
private record ToAdd(TypePlaceholder left, TypePlaceholder right) {}

View File

@@ -1,24 +1,21 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.exceptions.DebugException;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.factory.PrimitiveMethodsGenerator;
import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.target.tree.MethodParameter;
import de.dhbwstuttgart.target.tree.TargetGeneric;
import de.dhbwstuttgart.target.tree.TargetMethod;
import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*;
import javax.swing.text.html.Option;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
public class StatementToTargetExpression implements ASTVisitor {
@@ -143,7 +140,11 @@ public class StatementToTargetExpression implements ASTVisitor {
@Override
public void visit(FieldVar fieldVar) {
result = new TargetFieldVar(converter.convert(fieldVar.getType()), converter.convert(fieldVar.receiver.getType()), fieldVar.isStatic, converter.convert(fieldVar.receiver), fieldVar.fieldVarName);
var isStatic = false;
var type = converter.convert(fieldVar.receiver.getType());
var clazz = converter.compiler.getClass(new JavaClassName(type.name()));
var field = clazz.getField(fieldVar.fieldVarName).orElseThrow();
result = new TargetFieldVar(converter.convert(fieldVar.getType()), type, Modifier.isStatic(field.modifier), converter.convert(fieldVar.receiver), fieldVar.fieldVarName);
}
@Override
@@ -386,9 +387,94 @@ public class StatementToTargetExpression implements ASTVisitor {
result = new TargetTernary(converter.convert(ternary.getType()), converter.convert(ternary.cond), converter.convert(ternary.iftrue), converter.convert(ternary.iffalse));
}
record TypeVariants(RefTypeOrTPHOrWildcardOrGeneric in, List<RefTypeOrTPHOrWildcardOrGeneric> types) {}
private List<TypeVariants> extractAllPatterns(Pattern pattern) {
return switch (pattern) {
case GuardedPattern guarded -> extractAllPatterns(guarded.getNestedPattern());
case RecordPattern recordPattern -> recordPattern.getSubPattern().stream()
.map(this::extractAllPatterns)
.flatMap(List::stream).toList();
case FormalParameter param -> List.of(new TypeVariants(param.getType(), converter.findAllVariants(param.getType())));
default -> List.of();
};
}
record TypePair(RefTypeOrTPHOrWildcardOrGeneric in, RefTypeOrTPHOrWildcardOrGeneric out) {}
private void cartesianProduct(
List<TypeVariants> variants, int index,
List<RefTypeOrTPHOrWildcardOrGeneric> current,
List<List<RefTypeOrTPHOrWildcardOrGeneric>> result) {
if (index == variants.size()) {
result.add(new ArrayList<>(current));
return;
}
var currentSet = variants.get(index).types;
for (var element: currentSet) {
current.add(element);
cartesianProduct(variants, index + 1, current, result);
current.removeLast();
}
}
private List<List<TypePair>> cartesianProduct(List<TypeVariants> variants) {
var prod = new ArrayList<List<RefTypeOrTPHOrWildcardOrGeneric>>();
cartesianProduct(variants, 0, new ArrayList<>(), prod);
var res = new ArrayList<List<TypePair>>();
for (var list : prod) {
var l = new ArrayList<TypePair>();
for (var i = 0; i < list.size(); i++) {
l.add(new TypePair(variants.get(i).in, list.get(i)));
}
res.add(l);
}
return res;
}
@Override
public void visit(Switch switchStmt) {
var cases = switchStmt.getBlocks().stream().filter(s -> !s.isDefault()).map(converter::convert).toList();
var variants = converter.findAllVariants(switchStmt.getSwitch().getType());
var returns = converter.findAllVariants(switchStmt.getType());
var canBeOverloaded = variants.size() == 1 && returns.size() == 1;
var cases = switchStmt.getBlocks().stream().filter(s -> !s.isDefault()).map(case_ -> {
var overloads = new ArrayList<TargetSwitch.Case>();
if (canBeOverloaded) {
for (var label: case_.getLabels()) {
var product = cartesianProduct(extractAllPatterns(label.getPattern()));
for (var l : product) {
var oldGenerics = converter.generics;
// Set the generics to matching result set
for (var generics : converter.currentMethodOverloads) {
var java = generics.javaGenerics();
var equals = true;
for (var pair : l) {
if (!java.getType(pair.in).equals(pair.out)) {
equals = false; break;
}
}
if (equals) {
converter.generics = generics;
break;
}
}
overloads.add(converter.convert(case_));
converter.generics = oldGenerics;
}
}
} else {
overloads.add(converter.convert(case_));
}
return overloads;
}).flatMap(List::stream).toList();
TargetSwitch.Case default_ = null;
for (var block : switchStmt.getBlocks()) {
@@ -482,6 +568,11 @@ public class StatementToTargetExpression implements ASTVisitor {
result = new TargetTypePattern(converter.convert(aPattern.getType()), aPattern.getName());
}
@Override
public void visit(LiteralPattern literalPattern) {
result = new TargetExpressionPattern(converter.convert(literalPattern.value));
}
@Override
public void visit(ExpressionPattern aPattern) {
result = converter.convert(aPattern.getExpression());

View File

@@ -11,4 +11,8 @@ public record MethodParameter(TargetPattern pattern) {
public MethodParameter withType(TargetType type) {
return new MethodParameter(pattern.withType(type));
}
public MethodParameter withName(String name) {
return new MethodParameter(pattern.withName(name));
}
}

View File

@@ -18,6 +18,19 @@ public record TargetMethod(int access, String name, TargetBlock block, Signature
public String getDescriptor() {
return TargetMethod.getDescriptor(returnType, parameters.stream().map(MethodParameter::pattern).map(TargetPattern::type).toArray(TargetType[]::new));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Signature signature = (Signature) o;
return Objects.equals(parameters, signature.parameters);
}
@Override
public int hashCode() {
return Objects.hash(parameters);
}
}
public static String getDescriptor(TargetType returnType, TargetType... parameters) {
@@ -66,6 +79,10 @@ public record TargetMethod(int access, String name, TargetBlock block, Signature
return (access & Opcodes.ACC_STATIC) != 0;
}
public boolean isPrivate() {
return (access & Opcodes.ACC_PRIVATE) != 0;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof TargetMethod otherMethod)) return false;

View File

@@ -9,4 +9,9 @@ public record TargetComplexPattern(TargetType type, String name, List<TargetPatt
public TargetComplexPattern withType(TargetType type) {
return new TargetComplexPattern(type, name, subPatterns);
}
@Override
public TargetComplexPattern withName(String name) {
return new TargetComplexPattern(type, name, subPatterns);
}
}

View File

@@ -0,0 +1,20 @@
package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetExpressionPattern(TargetExpression expression) implements TargetPattern {
@Override
public TargetPattern withType(TargetType type) {
return this;
}
@Override
public TargetType type() {
return expression.type();
}
@Override
public TargetPattern withName(String name) {
return this;
}
}

View File

@@ -12,4 +12,9 @@ public record TargetGuard(TargetPattern inner, TargetExpression expression) impl
public TargetType type() {
return inner.type();
}
@Override
public TargetGuard withName(String name) {
return new TargetGuard(inner.withName(name), expression);
}
}

View File

@@ -2,7 +2,7 @@ package de.dhbwstuttgart.target.tree.expression;
import de.dhbwstuttgart.target.tree.type.TargetType;
public sealed interface TargetPattern extends TargetExpression permits TargetComplexPattern, TargetGuard, TargetTypePattern {
public sealed interface TargetPattern extends TargetExpression permits TargetComplexPattern, TargetExpressionPattern, TargetGuard, TargetTypePattern {
default String name() {
return null;
}
@@ -10,4 +10,6 @@ public sealed interface TargetPattern extends TargetExpression permits TargetCom
TargetPattern withType(TargetType type);
TargetType type();
TargetPattern withName(String name);
}

View File

@@ -7,4 +7,9 @@ public record TargetTypePattern(TargetType type, String name) implements TargetP
public TargetTypePattern withType(TargetType type) {
return new TargetTypePattern(type, name);
}
@Override
public TargetTypePattern withName(String name) {
return new TargetTypePattern(type, name);
}
}

View File

@@ -13,7 +13,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TypeInsertPlacer extends AbstractASTWalker{
public class TypeInsertPlacer extends AbstractASTWalker {
Set<TypeInsert> inserts = new HashSet<>();
private ResultSet withResults;
String pkgName;

View File

@@ -1,15 +1,22 @@
package de.dhbwstuttgart.typeinference.typeAlgo;
import de.dhbwstuttgart.exceptions.DebugException;
import de.dhbwstuttgart.parser.SourceLoc;
import de.dhbwstuttgart.parser.antlr.Java17Parser;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.statement.Statement;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.typeinference.assumptions.FieldAssumption;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.constraints.Pair;
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
import de.dhbwstuttgart.util.BiRelation;
import org.antlr.v4.runtime.Token;
import java.util.*;
@@ -79,8 +86,53 @@ public class TYPE {
if(m.block == null)return new ConstraintSet(); //Abstrakte Methoden generieren keine Constraints
TypeInferenceBlockInformation blockInfo = new TypeInferenceBlockInformation(info.getAvailableClasses(), currentClass, m);
TYPEStmt methodScope = new TYPEStmt(blockInfo);
ConstraintSet constraintSet = new ConstraintSet();
m.getParameterList().getFormalparalist().forEach(el -> {
if(el instanceof RecordPattern){
constraintSet.addAll(addRecursiveParameterConstraints((RecordPattern) el, blockInfo));
}
});
m.block.accept(methodScope);
return methodScope.getConstraints();
constraintSet.addAll(methodScope.getConstraints());
return constraintSet;
}
public ConstraintSet addRecursiveParameterConstraints(RecordPattern recordPattern, TypeInferenceBlockInformation blockInformation){
ConstraintSet constraintSet = new ConstraintSet();
var subPatternList = recordPattern.getSubPattern();
var resolver = new GenericsResolverSameName();
var refType = (RefType) recordPattern.getType();
var allClasses = blockInformation.getAvailableClasses();
var typename = refType.getName().getClassName();
ClassOrInterface allClass = allClasses.stream().filter(c -> c.getClassName().getClassName().equals(typename)).findFirst().orElseThrow();
int counter = 0;
for (Pattern el : subPatternList){
if (el instanceof RecordPattern){
constraintSet.addAll(addRecursiveParameterConstraints((RecordPattern) el, blockInformation));
} else {
FormalParameter param = (FormalParameter) allClass.getConstructors().getFirst().getParameterList().getParameterAt(counter);
FieldAssumption assumption = new FieldAssumption(param.getName(), allClass, param.getType(), blockInformation.getCurrentTypeScope());
var fieldCons = new Pair(el.getType(), assumption.getType(resolver), PairOperator.SMALLERDOT);
var recvCons = new Pair(refType, assumption.getReceiverType(resolver), PairOperator.EQUALSDOT);
constraintSet.addUndConstraint(fieldCons);
constraintSet.addUndConstraint(recvCons);
for (var i = 0; i < refType.getParaList().size(); i++) {
constraintSet.addUndConstraint(new Pair(refType.getParaList().get(i),
((RefType)assumption.getReceiverType(resolver)).getParaList().get(i),
PairOperator.EQUALSDOT));
}
}
counter++;
}
return constraintSet;
}
private ConstraintSet getConstraintsConstructor(Constructor m, TypeInferenceInformation info, ClassOrInterface currentClass) {

View File

@@ -117,6 +117,8 @@ public class TYPEStmt implements StatementVisitor {
public void visit(FieldVar fieldVar) {
fieldVar.receiver.accept(this);
Set<Constraint> oderConstraints = new HashSet<>();
for (FieldAssumption fieldAssumption : info.getFields(fieldVar.fieldVarName)) {
Constraint constraint = new Constraint();
GenericsResolver resolver = getResolverInstance();
@@ -128,7 +130,6 @@ public class TYPEStmt implements StatementVisitor {
throw new TypeinferenceException("Kein Feld " + fieldVar.fieldVarName + " gefunden", fieldVar.getOffset());
constraintsSet.addOderConstraint(oderConstraints);
}
@Override
public void visit(ForStmt forStmt) {
forStmt.initializer.forEach(s -> s.accept(this));
@@ -840,7 +841,7 @@ public class TYPEStmt implements StatementVisitor {
for (var child : switchStmt.getBlocks()) {
for (var label : child.getLabels()) {
if (label.getPattern() == null) {
System.out.println("DefaultCase");
//System.out.println("DefaultCase");
} else {
constraintsSet.addUndConstraint(
new Pair(
@@ -909,10 +910,11 @@ public class TYPEStmt implements StatementVisitor {
for (var subPattern : pattern.getSubPattern()) {
for (Constructor con : constructors) {
System.out.println("----------------------\n" + subPattern.getType() + " | " + con.getParameterList().getParameterAt(counter).getType() + "\n----------------------\n");
//System.out.println("----------------------\n" + subPattern.getType() + " | " + con.getParameterList().getParameterAt(counter).getType() + "\n----------------------\n");
constraintsSet.addUndConstraint(new Pair(subPattern.getType(), con.getParameterList().getParameterAt(counter).getType(), PairOperator.SMALLERDOT, loc(con.getParameterList().getParameterAt(counter).getOffset())));
}
if (subPattern instanceof RecordPattern) recursivelyAddRecordConstraints((RecordPattern) subPattern);
else if (subPattern instanceof LiteralPattern lp) lp.value.accept(this);
counter++;
}
}

View File

@@ -55,7 +55,7 @@ public class AllgemeinTest {
//String className = "VectorNotObject";
//String className = "WildcardCaptureConversionTest";
//String className = "CaptureConversion";
//String className = "Pair";
String className = "Pair2";
//String className = "UseWildcardPair";
//String className = "Assign";
//String className = "StreamTest";
@@ -65,10 +65,10 @@ public class AllgemeinTest {
//String className = "TripleTest";
//String className = "WildcardList";
//String className = "List";
//String className = "Box";
//String className = "BoxUse";
//String className = "GenBox";
//String className = "InnerInf";
String className = "Foo";
//String className = "Foo";
//PL 2019-10-24: genutzt fuer unterschiedliche Tests
path = System.getProperty("user.dir")+"/resources/AllgemeinTest/" + className + ".jav";
//path = System.getProperty("user.dir")+"/src/test/resources/AllgemeinTest/Overloading_Generics.jav";

View File

@@ -728,7 +728,12 @@ public class TestComplete {
assertEquals(res, expected);
}
@Test
public void testSwitchRecordLiteral() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "PatternMatchingLiteralStyle.jav");
var clazz = classFiles.get("SwitchOverload");
}
@Test
public void testSwitchCaseHeritageDetection() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SwitchCaseHeritageDetection.jav");
@@ -777,6 +782,24 @@ public class TestComplete {
assertEquals(swtch.invoke(instance, listWithOneElement), 10);
}
@Test
public void testSwitchNestedValue() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SwitchNestedValue.jav");
var clazz = classFiles.get("SwitchNestedValue");
var rec = classFiles.get("R");
var instance = clazz.getDeclaredConstructor().newInstance();
var m = clazz.getDeclaredMethod("main", rec);
var ctor = rec.getDeclaredConstructor(Integer.class);
var r1 = ctor.newInstance(10);
var r2 = ctor.newInstance(20);
var r3 = ctor.newInstance(30);
assertEquals(m.invoke(instance, r1), 1);
assertEquals(m.invoke(instance, r2), 2);
assertEquals(m.invoke(instance, r3), 3);
}
@Test
public void testGenericRecordSwitchCase() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "GenericRecordSwitchCase.jav");
@@ -784,11 +807,11 @@ public class TestComplete {
var clazz = classFiles.get("GenericRecordSwitchCase");
var instance = clazz.getDeclaredConstructor().newInstance();
var swtch = clazz.getDeclaredMethod("main", Object.class);
var linkedElem = classFiles.get("LinkedElem");
var listInterface = classFiles.get("List");
var elem = classFiles.get("Elem");
var swtch = clazz.getDeclaredMethod("main", linkedElem);
var constructorLinkedElem = linkedElem.getConstructor(Object.class, listInterface);
@@ -833,7 +856,6 @@ public class TestComplete {
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Ignore("Not implemented")
@Test
public void testOverloadPattern() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "OverloadPattern.jav");
@@ -841,12 +863,101 @@ public class TestComplete {
var rec = classFiles.get("Point");
var instance = clazz.getDeclaredConstructor().newInstance();
var m1 = clazz.getDeclaredMethod("m", rec);
var m2 = clazz.getDeclaredMethod("m", Integer.class);
var m1 = clazz.getDeclaredMethod("m", rec, rec);
var m2 = clazz.getDeclaredMethod("m", rec);
var m3 = clazz.getDeclaredMethod("m", Integer.class);
var pt = rec.getDeclaredConstructor(Number.class, Number.class).newInstance(10, 20);
assertEquals(m1.invoke(instance, pt), 30);
assertEquals(m2.invoke(instance, 10), 10);
var ptInt = rec.getDeclaredConstructor(Number.class, Number.class).newInstance(1, 2);
var ptFlt = rec.getDeclaredConstructor(Number.class, Number.class).newInstance(1f, 2f);
assertEquals(m1.invoke(instance, ptInt, ptFlt), 1);
assertEquals(m1.invoke(instance, ptInt, ptInt), 2);
assertEquals(m1.invoke(instance, ptFlt, ptInt), 3);
assertEquals(m1.invoke(instance, ptFlt, ptFlt), 4);
assertEquals(m2.invoke(instance, ptInt), 5);
assertEquals(m2.invoke(instance, ptFlt), 6);
assertEquals(m3.invoke(instance, 10), 10);
}
@Test
public void testOverloadNestedPattern() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "OverloadNestedPattern.jav");
var clazz = classFiles.get("OverloadNestedPattern");
var rec = classFiles.get("R");
var instance = clazz.getDeclaredConstructor().newInstance();
var ctor = rec.getDeclaredConstructor(Object.class);
var r1 = ctor.newInstance(1);
var r2 = ctor.newInstance(r1);
var m = clazz.getDeclaredMethod("m", rec, rec);
assertEquals(m.invoke(instance, r2, r1), 1);
var r3 = ctor.newInstance(2f);
var r4 = ctor.newInstance(r3);
assertEquals(m.invoke(instance, r4, r3), 2);
assertEquals(m.invoke(instance, r1, r1), 3);
}
//@Ignore("Not implemented")
@Test
public void testPatternMatchingHaskellStyle() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "PatternMatchingHaskellStyle.jav");
var clazz = classFiles.get("PatternMatchingHaskellStyle");
var R2 = classFiles.get("Elem");
var R = classFiles.get("LinkedElem");
var I = classFiles.get("List");
var rctor = R.getDeclaredConstructor(Object.class, I);
var r2ctor = R2.getDeclaredConstructor(Object.class);
var instance = clazz.getDeclaredConstructor().newInstance();
var m = clazz.getDeclaredMethod("append$LLinkedElem$_$LTPH$_$LLinkedElem$_$LTPH$_$", R, Object.class);
var x = rctor.newInstance(rctor.newInstance(0, rctor.newInstance(0, r2ctor.newInstance(0))), r2ctor.newInstance(0));
var y = rctor.newInstance(r2ctor.newInstance(0), r2ctor.newInstance(0));
assertEquals(m.invoke(instance, x, y), null);
assertEquals(m.invoke(instance, y, y), null);
}
@Test
public void testPatternMatchingListAppend() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "PatternMatchingListAppend.jav");
var clazz = classFiles.get("PatternMatchingListAppend");
var instance = clazz.getDeclaredConstructor().newInstance();
var Cons = classFiles.get("Cons");
var Empty = classFiles.get("Empty");
var List = classFiles.get("List");
var ConsCtor = Cons.getDeclaredConstructor(Object.class, List);
var EmptyCtor = Empty.getDeclaredConstructor();
var list1 = ConsCtor.newInstance(1, ConsCtor.newInstance(2, ConsCtor.newInstance(3, EmptyCtor.newInstance())));
var list2 = ConsCtor.newInstance(4, ConsCtor.newInstance(5, ConsCtor.newInstance(6, EmptyCtor.newInstance())));
}
@Test
public void testOverloadSwitch() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SwitchOverload.jav");
var clazz = classFiles.get("SwitchOverload");
var R = classFiles.get("R");
var rctor = R.getDeclaredConstructor(Number.class);
var instance = clazz.getDeclaredConstructor().newInstance();
var m = clazz.getDeclaredMethod("m", R, Integer.class);
var x = rctor.newInstance(10);
var d = rctor.newInstance(20.0);
assertEquals(m.invoke(instance, x, 0), 50);
assertEquals(m.invoke(instance, d, 0), 40.0);
}
@Test
@@ -1066,6 +1177,15 @@ public class TestComplete {
var instance = clazz.getDeclaredConstructor().newInstance();
}
@Test
public void testAssign() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Assign.jav");
var clazz = classFiles.get("Assign");
var instance = clazz.getDeclaredConstructor().newInstance();
var m = clazz.getDeclaredMethod("m");
assertEquals(m.invoke(instance), 20);
}
@Test
public void testBug122() throws Exception {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug122.jav");