Compare commits
25 Commits
aa61f90fb1
...
patternMat
Author | SHA1 | Date | |
---|---|---|---|
|
007d55ea3f | ||
4318856fa8 | |||
1ace099d72 | |||
b76e1e46f0 | |||
09c483542d | |||
77411973be | |||
d0d9c46a67 | |||
|
24bf3d350f | ||
b9f9994de3 | |||
|
f0287c4611 | ||
|
edf609f916 | ||
|
14e2af7d2a | ||
|
158adf837a | ||
46b378e3a5 | |||
484a70c15c | |||
c461e89336 | |||
f846142ee1 | |||
443b8b0c09 | |||
ff715a22cf | |||
170955b333 | |||
88d81f4af7 | |||
bb11d24101 | |||
e2bf09548f | |||
|
c33e372446 | ||
|
7c546834c0 |
@@ -15,7 +15,7 @@ jobs:
|
|||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: '21'
|
java-version: '22'
|
||||||
cache: 'maven'
|
cache: 'maven'
|
||||||
- name: Compile project
|
- name: Compile project
|
||||||
run: |
|
run: |
|
||||||
|
@@ -1,9 +1,20 @@
|
|||||||
public class Box<A> {
|
public class Box {
|
||||||
|
|
||||||
A a;
|
a;
|
||||||
|
|
||||||
public Box() { }
|
public Box() { }
|
||||||
public Box(A a) {
|
public Box(a) {
|
||||||
//this.a = a;
|
//this.a = a;
|
||||||
}
|
}
|
||||||
|
set(x) {
|
||||||
|
a = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
get() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
m(b) {
|
||||||
|
//b.set(b.get());
|
||||||
|
}
|
||||||
}
|
}
|
@@ -23,9 +23,7 @@ public class Matrix extends Vector<Vector<Integer>> {
|
|||||||
|
|
||||||
public mul(m) {
|
public mul(m) {
|
||||||
var ret = new Matrix();
|
var ret = new Matrix();
|
||||||
var i = 0;
|
for(v1 : this) {
|
||||||
while(i < size()) {
|
|
||||||
var v1 = this.elementAt(i);
|
|
||||||
var v2 = new Vector<Integer>();
|
var v2 = new Vector<Integer>();
|
||||||
var j = 0;
|
var j = 0;
|
||||||
while(j < v1.size()) {
|
while(j < v1.size()) {
|
||||||
@@ -39,7 +37,6 @@ public class Matrix extends Vector<Vector<Integer>> {
|
|||||||
v2.addElement(erg);
|
v2.addElement(erg);
|
||||||
j++; }
|
j++; }
|
||||||
ret.addElement(v2);
|
ret.addElement(v2);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
20
resources/bytecode/javFiles/OverloadNestedPattern.jav
Normal file
20
resources/bytecode/javFiles/OverloadNestedPattern.jav
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@@ -5,13 +5,29 @@ import java.lang.Float;
|
|||||||
public record Point(Number x, Number y) {}
|
public record Point(Number x, Number y) {}
|
||||||
|
|
||||||
public class OverloadPattern {
|
public class OverloadPattern {
|
||||||
public m(Point(x, y), Point(z, a)) {
|
public Number m(Point(Integer x, Integer y), Point(Float a, Float b)) {
|
||||||
return x + y + z + a;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public m(Point(Float x, Float y)) {
|
public Number m(Point(Integer x, Integer y), Point(Integer a, Integer b)) {
|
||||||
return x * y;
|
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) {
|
public m(Integer x) {
|
||||||
return x;
|
return x;
|
||||||
|
@@ -1,26 +0,0 @@
|
|||||||
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 PaternMatchingHaskellStyle {
|
|
||||||
|
|
||||||
public append(LinkedElem(a, b), list2) {
|
|
||||||
if (b instanceof Elem<?>) {
|
|
||||||
return handleElem(a, (Elem<?>) b, list2);
|
|
||||||
} else if (b instanceof LinkedElem<?>) {
|
|
||||||
return handleLinkedElem(a, (LinkedElem<?>) b, list2);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleElem(a, Elem(e), list2) {
|
|
||||||
return new LinkedElem<>(a, new LinkedElem<>(e, list2));
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleLinkedElem(a, LinkedElem(a,r), list2) {
|
|
||||||
return new LinkedElem<>(a, append(r, list2));
|
|
||||||
}
|
|
||||||
}
|
|
21
resources/bytecode/javFiles/PatternMatchingHaskellStyle.jav
Normal file
21
resources/bytecode/javFiles/PatternMatchingHaskellStyle.jav
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
26
resources/bytecode/javFiles/PatternMatchingListAppend.jav
Normal file
26
resources/bytecode/javFiles/PatternMatchingListAppend.jav
Normal 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() ->
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
14
resources/bytecode/javFiles/SwitchNestedValue.jav
Normal file
14
resources/bytecode/javFiles/SwitchNestedValue.jav
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@@ -109,6 +109,10 @@ public class Codegen {
|
|||||||
this.scope = this.scope.parent;
|
this.scope = this.scope.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocalVar createVariable(TargetType type) {
|
||||||
|
return createVariable("__var" + this.localCounter, type);
|
||||||
|
}
|
||||||
|
|
||||||
LocalVar createVariable(String name, TargetType type) {
|
LocalVar createVariable(String name, TargetType type) {
|
||||||
var local = new LocalVar(localCounter, name, type);
|
var local = new LocalVar(localCounter, name, type);
|
||||||
scope.add(local);
|
scope.add(local);
|
||||||
@@ -1393,8 +1397,10 @@ public class Codegen {
|
|||||||
|
|
||||||
state.breakStack.pop();
|
state.breakStack.pop();
|
||||||
if (aSwitch.isExpression()) {
|
if (aSwitch.isExpression()) {
|
||||||
|
if (aSwitch.type() != null) {
|
||||||
mv.visitVarInsn(ALOAD, state.switchResultValue.peek());
|
mv.visitVarInsn(ALOAD, state.switchResultValue.peek());
|
||||||
unboxPrimitive(state, aSwitch.type());
|
unboxPrimitive(state, aSwitch.type());
|
||||||
|
}
|
||||||
state.popSwitch();
|
state.popSwitch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1431,7 +1437,24 @@ public class Codegen {
|
|||||||
state.mv.visitTypeInsn(CHECKCAST, pat.type().getInternalName());
|
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());
|
var local = state.createVariable(sp.name(), sp.type());
|
||||||
state.mv.visitVarInsn(ASTORE, local.index);
|
state.mv.visitVarInsn(ASTORE, local.index);
|
||||||
} else if (pat instanceof TargetComplexPattern cp) {
|
} else if (pat instanceof TargetComplexPattern cp) {
|
||||||
|
@@ -468,7 +468,7 @@ public class StatementGenerator {
|
|||||||
case RPatternContext rPattern:
|
case RPatternContext rPattern:
|
||||||
RecordPatternContext recordPattern = rPattern.recordPattern();
|
RecordPatternContext recordPattern = rPattern.recordPattern();
|
||||||
return convert(recordPattern);
|
return convert(recordPattern);
|
||||||
case Java17Parser.LPatternContext patternContext: return new LiteralPattern(TypePlaceholder.fresh(patternContext.start), patternContext.literal().get(0).getText(), patternContext.start);
|
case Java17Parser.LPatternContext patternContext: return new LiteralPattern(TypePlaceholder.fresh(patternContext.start), convert(patternContext.literal().get(0)), patternContext.start);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -477,7 +477,8 @@ public class StatementGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private RecordPattern convert(RecordPatternContext recordPatternCtx) {
|
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());
|
List<Pattern> subPattern = subPatternCtx.stream().map(this::convert).collect(Collectors.toList());
|
||||||
IdentifierContext identifierCtx = recordPatternCtx.identifier();
|
IdentifierContext identifierCtx = recordPatternCtx.identifier();
|
||||||
var text = (identifierCtx != null) ? identifierCtx.getText() : null;
|
var text = (identifierCtx != null) ? identifierCtx.getText() : null;
|
||||||
|
@@ -10,6 +10,8 @@ public interface ASTVisitor extends StatementVisitor{
|
|||||||
|
|
||||||
void visit(FormalParameter formalParameter);
|
void visit(FormalParameter formalParameter);
|
||||||
|
|
||||||
|
void visit(LiteralPattern literalPattern);
|
||||||
|
|
||||||
void visit(GenericDeclarationList genericTypeVars);
|
void visit(GenericDeclarationList genericTypeVars);
|
||||||
|
|
||||||
void visit(Field field);
|
void visit(Field field);
|
||||||
|
@@ -37,6 +37,11 @@ public abstract class AbstractASTWalker implements ASTVisitor {
|
|||||||
formalParameter.getType().accept((ASTVisitor) this);
|
formalParameter.getType().accept((ASTVisitor) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(LiteralPattern literalPattern) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(GenericDeclarationList genericTypeVars) {
|
public void visit(GenericDeclarationList genericTypeVars) {
|
||||||
Iterator<GenericTypeVar> genericIterator = genericTypeVars.iterator();
|
Iterator<GenericTypeVar> genericIterator = genericTypeVars.iterator();
|
||||||
|
@@ -12,15 +12,15 @@ import org.antlr.v4.runtime.Token;
|
|||||||
|
|
||||||
public class LiteralPattern extends FormalParameter
|
public class LiteralPattern extends FormalParameter
|
||||||
{
|
{
|
||||||
public final Object value;
|
public final Expression value;
|
||||||
public LiteralPattern(RefTypeOrTPHOrWildcardOrGeneric type, Object value, Token offset) {
|
public LiteralPattern(RefTypeOrTPHOrWildcardOrGeneric type, Expression value, Token offset) {
|
||||||
super((String) value, type, offset);
|
super(null, type, offset);
|
||||||
|
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public FormalParameter withType(RefTypeOrTPHOrWildcardOrGeneric type) {
|
public FormalParameter withType(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||||
return null;
|
return new LiteralPattern(type, value, getOffset());
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void accept(ASTVisitor visitor) {
|
public void accept(ASTVisitor visitor) {
|
||||||
|
@@ -34,7 +34,6 @@ public class ASTFactory {
|
|||||||
private static final HashMap<java.lang.Class, ClassOrInterface> cache = new HashMap<>();
|
private static final HashMap<java.lang.Class, ClassOrInterface> cache = new HashMap<>();
|
||||||
|
|
||||||
public static ClassOrInterface createClass(java.lang.Class jreClass) {
|
public static ClassOrInterface createClass(java.lang.Class jreClass) {
|
||||||
System.out.println(jreClass);
|
|
||||||
if (cache.containsKey(jreClass))
|
if (cache.containsKey(jreClass))
|
||||||
return cache.get(jreClass);
|
return cache.get(jreClass);
|
||||||
|
|
||||||
@@ -174,7 +173,6 @@ public class ASTFactory {
|
|||||||
superClass = (RefType) createType(java.lang.Object.class);
|
superClass = (RefType) createType(java.lang.Object.class);
|
||||||
}
|
}
|
||||||
List<RefType> implementedInterfaces = new ArrayList<>();
|
List<RefType> implementedInterfaces = new ArrayList<>();
|
||||||
System.out.println(jreClass);
|
|
||||||
for (Type jreInterface : jreClass.getGenericInterfaces()) {
|
for (Type jreInterface : jreClass.getGenericInterfaces()) {
|
||||||
implementedInterfaces.add((RefType) createType(jreInterface));
|
implementedInterfaces.add((RefType) createType(jreInterface));
|
||||||
}
|
}
|
||||||
|
@@ -57,6 +57,11 @@ public class OutputGenerator implements ASTVisitor {
|
|||||||
out.append(formalParameter.getName());
|
out.append(formalParameter.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(LiteralPattern literalPattern) {
|
||||||
|
literalPattern.value.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(GenericDeclarationList genericTypeVars) {
|
public void visit(GenericDeclarationList genericTypeVars) {
|
||||||
Iterator<GenericTypeVar> genericIterator = genericTypeVars.iterator();
|
Iterator<GenericTypeVar> genericIterator = genericTypeVars.iterator();
|
||||||
@@ -508,12 +513,11 @@ public class OutputGenerator implements ASTVisitor {
|
|||||||
aRecordPattern.getType().accept(this);
|
aRecordPattern.getType().accept(this);
|
||||||
out.append("(");
|
out.append("(");
|
||||||
List<Pattern> subPatterns = aRecordPattern.getSubPattern();
|
List<Pattern> subPatterns = aRecordPattern.getSubPattern();
|
||||||
int i;
|
for (var i = 0; i < subPatterns.size(); i++) {
|
||||||
for (i = 0; i < subPatterns.size() - 1; i++) {
|
|
||||||
subPatterns.get(i).accept(this);
|
subPatterns.get(i).accept(this);
|
||||||
|
if (i < subPatterns.size() - 1)
|
||||||
out.append(", ");
|
out.append(", ");
|
||||||
}
|
}
|
||||||
subPatterns.get(i).accept(this);
|
|
||||||
String name;
|
String name;
|
||||||
if ((name = aRecordPattern.getName()) != null)
|
if ((name = aRecordPattern.getName()) != null)
|
||||||
out.append(name);
|
out.append(name);
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
package de.dhbwstuttgart.target.generate;
|
package de.dhbwstuttgart.target.generate;
|
||||||
|
|
||||||
import de.dhbwstuttgart.bytecode.CodeGenException;
|
|
||||||
import de.dhbwstuttgart.bytecode.FunNGenerator;
|
import de.dhbwstuttgart.bytecode.FunNGenerator;
|
||||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||||
import de.dhbwstuttgart.environment.ByteArrayClassLoader;
|
import de.dhbwstuttgart.environment.ByteArrayClassLoader;
|
||||||
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
|
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
|
||||||
|
import de.dhbwstuttgart.exceptions.DebugException;
|
||||||
import de.dhbwstuttgart.parser.NullToken;
|
import de.dhbwstuttgart.parser.NullToken;
|
||||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||||
import de.dhbwstuttgart.syntaxtree.*;
|
import de.dhbwstuttgart.syntaxtree.*;
|
||||||
@@ -17,7 +17,7 @@ import de.dhbwstuttgart.target.tree.expression.*;
|
|||||||
import de.dhbwstuttgart.target.tree.type.*;
|
import de.dhbwstuttgart.target.tree.type.*;
|
||||||
import de.dhbwstuttgart.typeinference.result.*;
|
import de.dhbwstuttgart.typeinference.result.*;
|
||||||
|
|
||||||
import java.sql.Array;
|
import java.lang.annotation.Target;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -145,23 +145,79 @@ public class ASTToTargetAST {
|
|||||||
return ret;
|
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) {
|
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) {
|
for (var method : methods) {
|
||||||
// Convert all methods
|
// Convert all methods
|
||||||
var methodsWithTphs = convert(input, method);
|
var methodsWithTphs = convert(input, method);
|
||||||
// Then check for methods with the same signature
|
// Then check for methods with the same signature
|
||||||
var mapOfSignatures = new HashMap<TargetMethod.Signature, List<MethodWithTphs>>();
|
var resMethods = new HashSet<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<TargetMethod>();
|
outer:
|
||||||
for (var methodsWithSignature : mapOfSignatures.values()) {
|
for (var m1 : methodsWithTphs) {
|
||||||
outer: for (var m1 : methodsWithSignature) {
|
for (var m2 : methodsWithTphs) {
|
||||||
for (var m2 : methodsWithSignature) {
|
|
||||||
for (var i = 0; i < m1.args.size(); i++) {
|
for (var i = 0; i < m1.args.size(); i++) {
|
||||||
var arg1 = m1.args.get(i);
|
var arg1 = m1.args.get(i);
|
||||||
var arg2 = m2.args.get(i);
|
var arg2 = m2.args.get(i);
|
||||||
@@ -171,12 +227,18 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 mapOfSignatures.values().stream().toList();
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TargetStructure convert(ClassOrInterface input) {
|
public TargetStructure convert(ClassOrInterface input) {
|
||||||
@@ -223,9 +285,14 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<MethodParameter> convert(ParameterList input, GenerateGenerics generics) {
|
public List<MethodParameter> convert(ParameterList input, GenerateGenerics generics) {
|
||||||
return input.getFormalparalist().stream().map(param ->
|
var res = new ArrayList<MethodParameter>();
|
||||||
new MethodParameter((TargetPattern) convert(param))
|
for (var i = 0; i < input.getFormalparalist().size(); i++) {
|
||||||
).toList();
|
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) {
|
private boolean hasGeneric(Set<TargetGeneric> generics, GenericRefType type) {
|
||||||
@@ -295,10 +362,86 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
private List<TargetMethod> generatePatternOverloads(ClassOrInterface clazz, List<TargetMethod> overloadedMethods) {
|
||||||
if (overloadedMethods.size() <= 1) return overloadedMethods;
|
if (overloadedMethods.size() <= 1) return overloadedMethods;
|
||||||
// Check if we have a pattern as a parameter
|
// Check if we have a pattern as a parameter
|
||||||
var firstMethod = overloadedMethods.getFirst();
|
var firstMethod = overloadedMethods.getFirst();
|
||||||
|
var secondMethod = overloadedMethods.get(1);
|
||||||
if (firstMethod.signature().parameters().stream().noneMatch(mp -> mp.pattern() instanceof TargetComplexPattern)) return overloadedMethods;
|
if (firstMethod.signature().parameters().stream().noneMatch(mp -> mp.pattern() instanceof TargetComplexPattern)) return overloadedMethods;
|
||||||
// Rename existing methods
|
// Rename existing methods
|
||||||
|
|
||||||
@@ -308,8 +451,44 @@ public class ASTToTargetAST {
|
|||||||
res.add(new TargetMethod(method.access(), name, method.block(), method.signature(), method.txSignature()));
|
res.add(new TargetMethod(method.access(), name, method.block(), method.signature(), method.txSignature()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate dispatch method
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +570,6 @@ public class ASTToTargetAST {
|
|||||||
var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics));
|
var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics));
|
||||||
|
|
||||||
signatures.add(new Signature(javaSignature, txSignature, generics));
|
signatures.add(new Signature(javaSignature, txSignature, generics));
|
||||||
System.out.println(javaSignature);
|
|
||||||
var listOfGenerics = collectedGenerics.getOrDefault(javaSignature, new ArrayList<>());
|
var listOfGenerics = collectedGenerics.getOrDefault(javaSignature, new ArrayList<>());
|
||||||
listOfGenerics.add(generics);
|
listOfGenerics.add(generics);
|
||||||
collectedGenerics.put(javaSignature, listOfGenerics);
|
collectedGenerics.put(javaSignature, listOfGenerics);
|
||||||
@@ -414,7 +592,9 @@ public class ASTToTargetAST {
|
|||||||
var list = new ArrayList<MethodParameter>();
|
var list = new ArrayList<MethodParameter>();
|
||||||
for (var i = 0; i < paraList.getFormalparalist().size(); i++) {
|
for (var i = 0; i < paraList.getFormalparalist().size(); i++) {
|
||||||
var param = paraList.getParameterAt(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;
|
return list;
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,7 @@
|
|||||||
package de.dhbwstuttgart.target.generate;
|
package de.dhbwstuttgart.target.generate;
|
||||||
|
|
||||||
import de.dhbwstuttgart.parser.NullToken;
|
import de.dhbwstuttgart.parser.NullToken;
|
||||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
import de.dhbwstuttgart.syntaxtree.*;
|
||||||
import de.dhbwstuttgart.syntaxtree.Constructor;
|
|
||||||
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
|
|
||||||
import de.dhbwstuttgart.syntaxtree.Method;
|
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||||
import de.dhbwstuttgart.syntaxtree.type.Void;
|
import de.dhbwstuttgart.syntaxtree.type.Void;
|
||||||
@@ -170,6 +167,25 @@ public abstract class GenerateGenerics {
|
|||||||
else if (to instanceof RefType t) concreteTypes.put(new TPH(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) {
|
Set<TPH> findTypeVariables(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||||
var result = new HashSet<TPH>();
|
var result = new HashSet<TPH>();
|
||||||
if (type instanceof TypePlaceholder tph) {
|
if (type instanceof TypePlaceholder tph) {
|
||||||
@@ -506,9 +522,7 @@ public abstract class GenerateGenerics {
|
|||||||
|
|
||||||
if (!(method instanceof Constructor))
|
if (!(method instanceof Constructor))
|
||||||
typeVariables.addAll(findTypeVariables(method.getReturnType()));
|
typeVariables.addAll(findTypeVariables(method.getReturnType()));
|
||||||
for (var arg : method.getParameterList().getFormalparalist()) {
|
typeVariables.addAll(findTypeVariables(method.getParameterList()));
|
||||||
typeVariables.addAll(findTypeVariables(arg.getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method.block != null)
|
if (method.block != null)
|
||||||
method.block.accept(new TracingStatementVisitor() {
|
method.block.accept(new TracingStatementVisitor() {
|
||||||
@@ -572,9 +586,7 @@ public abstract class GenerateGenerics {
|
|||||||
|
|
||||||
var usedTphs = new HashSet<TPH>();
|
var usedTphs = new HashSet<TPH>();
|
||||||
// For eliminating inner type variables we need to figure out which ones are actually used
|
// For eliminating inner type variables we need to figure out which ones are actually used
|
||||||
for (var param : method.getParameterList().getFormalparalist()) {
|
usedTphs.addAll(findTypeVariables(method.getParameterList()));
|
||||||
usedTphs.addAll(findTypeVariables(param.getType()));
|
|
||||||
}
|
|
||||||
usedTphs.addAll(findTypeVariables(method.getReturnType()));
|
usedTphs.addAll(findTypeVariables(method.getReturnType()));
|
||||||
referenced.addAll(usedTphs);
|
referenced.addAll(usedTphs);
|
||||||
referenced.addAll(typeVariablesOfClass);
|
referenced.addAll(typeVariablesOfClass);
|
||||||
@@ -672,11 +684,21 @@ public abstract class GenerateGenerics {
|
|||||||
if (p1 instanceof PairLT ptph && ptph.left.resolve().equals(ptph.right.resolve()))
|
if (p1 instanceof PairLT ptph && ptph.left.resolve().equals(ptph.right.resolve()))
|
||||||
result.remove(p1); // TODO This is a bit strange
|
result.remove(p1); // TODO This is a bit strange
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var tph : usedTphs) {
|
for (var tph : usedTphs) {
|
||||||
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.left.equals(tph)))
|
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.left.equals(tph)))
|
||||||
addToPairs(result, new PairEQ(tph, ASTToTargetAST.OBJECT));
|
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) {}
|
private record ToAdd(TypePlaceholder left, TypePlaceholder right) {}
|
||||||
|
@@ -568,6 +568,11 @@ public class StatementToTargetExpression implements ASTVisitor {
|
|||||||
result = new TargetTypePattern(converter.convert(aPattern.getType()), aPattern.getName());
|
result = new TargetTypePattern(converter.convert(aPattern.getType()), aPattern.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(LiteralPattern literalPattern) {
|
||||||
|
result = new TargetExpressionPattern(converter.convert(literalPattern.value));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ExpressionPattern aPattern) {
|
public void visit(ExpressionPattern aPattern) {
|
||||||
result = converter.convert(aPattern.getExpression());
|
result = converter.convert(aPattern.getExpression());
|
||||||
|
@@ -11,4 +11,8 @@ public record MethodParameter(TargetPattern pattern) {
|
|||||||
public MethodParameter withType(TargetType type) {
|
public MethodParameter withType(TargetType type) {
|
||||||
return new MethodParameter(pattern.withType(type));
|
return new MethodParameter(pattern.withType(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MethodParameter withName(String name) {
|
||||||
|
return new MethodParameter(pattern.withName(name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -79,6 +79,10 @@ public record TargetMethod(int access, String name, TargetBlock block, Signature
|
|||||||
return (access & Opcodes.ACC_STATIC) != 0;
|
return (access & Opcodes.ACC_STATIC) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return (access & Opcodes.ACC_PRIVATE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (!(other instanceof TargetMethod otherMethod)) return false;
|
if (!(other instanceof TargetMethod otherMethod)) return false;
|
||||||
|
@@ -9,4 +9,9 @@ public record TargetComplexPattern(TargetType type, String name, List<TargetPatt
|
|||||||
public TargetComplexPattern withType(TargetType type) {
|
public TargetComplexPattern withType(TargetType type) {
|
||||||
return new TargetComplexPattern(type, name, subPatterns);
|
return new TargetComplexPattern(type, name, subPatterns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TargetComplexPattern withName(String name) {
|
||||||
|
return new TargetComplexPattern(type, name, subPatterns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
@@ -12,4 +12,9 @@ public record TargetGuard(TargetPattern inner, TargetExpression expression) impl
|
|||||||
public TargetType type() {
|
public TargetType type() {
|
||||||
return inner.type();
|
return inner.type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TargetGuard withName(String name) {
|
||||||
|
return new TargetGuard(inner.withName(name), expression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ package de.dhbwstuttgart.target.tree.expression;
|
|||||||
|
|
||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
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() {
|
default String name() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -10,4 +10,6 @@ public sealed interface TargetPattern extends TargetExpression permits TargetCom
|
|||||||
TargetPattern withType(TargetType type);
|
TargetPattern withType(TargetType type);
|
||||||
|
|
||||||
TargetType type();
|
TargetType type();
|
||||||
|
|
||||||
|
TargetPattern withName(String name);
|
||||||
}
|
}
|
||||||
|
@@ -7,4 +7,9 @@ public record TargetTypePattern(TargetType type, String name) implements TargetP
|
|||||||
public TargetTypePattern withType(TargetType type) {
|
public TargetTypePattern withType(TargetType type) {
|
||||||
return new TargetTypePattern(type, name);
|
return new TargetTypePattern(type, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TargetTypePattern withName(String name) {
|
||||||
|
return new TargetTypePattern(type, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,9 @@ import de.dhbwstuttgart.parser.scope.JavaClassName;
|
|||||||
import de.dhbwstuttgart.syntaxtree.*;
|
import de.dhbwstuttgart.syntaxtree.*;
|
||||||
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.Statement;
|
import de.dhbwstuttgart.syntaxtree.statement.Statement;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||||
|
import de.dhbwstuttgart.typeinference.assumptions.FieldAssumption;
|
||||||
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
|
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceBlockInformation;
|
||||||
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation;
|
import de.dhbwstuttgart.typeinference.assumptions.TypeInferenceInformation;
|
||||||
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
|
||||||
@@ -100,25 +102,32 @@ public class TYPE {
|
|||||||
ConstraintSet constraintSet = new ConstraintSet();
|
ConstraintSet constraintSet = new ConstraintSet();
|
||||||
|
|
||||||
var subPatternList = recordPattern.getSubPattern();
|
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;
|
int counter = 0;
|
||||||
for (Pattern el : subPatternList){
|
for (Pattern el : subPatternList){
|
||||||
|
|
||||||
if (el instanceof RecordPattern){
|
if (el instanceof RecordPattern){
|
||||||
constraintSet.addAll(addRecursiveParameterConstraints((RecordPattern) el, blockInformation));
|
constraintSet.addAll(addRecursiveParameterConstraints((RecordPattern) el, blockInformation));
|
||||||
} else {
|
} else {
|
||||||
var allClasses = blockInformation.getAvailableClasses();
|
FormalParameter param = (FormalParameter) allClass.getConstructors().getFirst().getParameterList().getParameterAt(counter);
|
||||||
RefTypeOrTPHOrWildcardOrGeneric type;
|
FieldAssumption assumption = new FieldAssumption(param.getName(), allClass, param.getType(), blockInformation.getCurrentTypeScope());
|
||||||
|
|
||||||
for (ClassOrInterface allClass : allClasses) {
|
var fieldCons = new Pair(el.getType(), assumption.getType(resolver), PairOperator.SMALLERDOT);
|
||||||
var typename = recordPattern.getType().toString();
|
var recvCons = new Pair(refType, assumption.getReceiverType(resolver), PairOperator.EQUALSDOT);
|
||||||
var className = allClass.getClassName().getClassName();
|
constraintSet.addUndConstraint(fieldCons);
|
||||||
if(className.equals(typename)){
|
constraintSet.addUndConstraint(recvCons);
|
||||||
type = allClass.getConstructors().get(0).getParameterList().getParameterAt(counter).getType();
|
|
||||||
constraintSet.addUndConstraint(new Pair(el.getType(), type, PairOperator.SMALLERDOT, new SourceLoc(blockInformation.getCurrentClass().getFileName(), el.getOffset().getLine())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
@@ -841,7 +841,7 @@ public class TYPEStmt implements StatementVisitor {
|
|||||||
for (var child : switchStmt.getBlocks()) {
|
for (var child : switchStmt.getBlocks()) {
|
||||||
for (var label : child.getLabels()) {
|
for (var label : child.getLabels()) {
|
||||||
if (label.getPattern() == null) {
|
if (label.getPattern() == null) {
|
||||||
System.out.println("DefaultCase");
|
//System.out.println("DefaultCase");
|
||||||
} else {
|
} else {
|
||||||
constraintsSet.addUndConstraint(
|
constraintsSet.addUndConstraint(
|
||||||
new Pair(
|
new Pair(
|
||||||
@@ -910,10 +910,11 @@ public class TYPEStmt implements StatementVisitor {
|
|||||||
|
|
||||||
for (var subPattern : pattern.getSubPattern()) {
|
for (var subPattern : pattern.getSubPattern()) {
|
||||||
for (Constructor con : constructors) {
|
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())));
|
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);
|
if (subPattern instanceof RecordPattern) recursivelyAddRecordConstraints((RecordPattern) subPattern);
|
||||||
|
else if (subPattern instanceof LiteralPattern lp) lp.value.accept(this);
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,7 @@ public class AllgemeinTest {
|
|||||||
//String className = "VectorNotObject";
|
//String className = "VectorNotObject";
|
||||||
//String className = "WildcardCaptureConversionTest";
|
//String className = "WildcardCaptureConversionTest";
|
||||||
//String className = "CaptureConversion";
|
//String className = "CaptureConversion";
|
||||||
//String className = "Pair";
|
String className = "Pair2";
|
||||||
//String className = "UseWildcardPair";
|
//String className = "UseWildcardPair";
|
||||||
//String className = "Assign";
|
//String className = "Assign";
|
||||||
//String className = "StreamTest";
|
//String className = "StreamTest";
|
||||||
@@ -65,10 +65,10 @@ public class AllgemeinTest {
|
|||||||
//String className = "TripleTest";
|
//String className = "TripleTest";
|
||||||
//String className = "WildcardList";
|
//String className = "WildcardList";
|
||||||
//String className = "List";
|
//String className = "List";
|
||||||
//String className = "Box";
|
//String className = "BoxUse";
|
||||||
//String className = "GenBox";
|
//String className = "GenBox";
|
||||||
//String className = "InnerInf";
|
//String className = "InnerInf";
|
||||||
String className = "Foo";
|
//String className = "Foo";
|
||||||
//PL 2019-10-24: genutzt fuer unterschiedliche Tests
|
//PL 2019-10-24: genutzt fuer unterschiedliche Tests
|
||||||
path = System.getProperty("user.dir")+"/resources/AllgemeinTest/" + className + ".jav";
|
path = System.getProperty("user.dir")+"/resources/AllgemeinTest/" + className + ".jav";
|
||||||
//path = System.getProperty("user.dir")+"/src/test/resources/AllgemeinTest/Overloading_Generics.jav";
|
//path = System.getProperty("user.dir")+"/src/test/resources/AllgemeinTest/Overloading_Generics.jav";
|
||||||
|
@@ -782,6 +782,24 @@ public class TestComplete {
|
|||||||
assertEquals(swtch.invoke(instance, listWithOneElement), 10);
|
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
|
@Test
|
||||||
public void testGenericRecordSwitchCase() throws Exception {
|
public void testGenericRecordSwitchCase() throws Exception {
|
||||||
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "GenericRecordSwitchCase.jav");
|
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "GenericRecordSwitchCase.jav");
|
||||||
@@ -838,7 +856,6 @@ public class TestComplete {
|
|||||||
var instance = clazz.getDeclaredConstructor().newInstance();
|
var instance = clazz.getDeclaredConstructor().newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("Not implemented")
|
|
||||||
@Test
|
@Test
|
||||||
public void testOverloadPattern() throws Exception {
|
public void testOverloadPattern() throws Exception {
|
||||||
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "OverloadPattern.jav");
|
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "OverloadPattern.jav");
|
||||||
@@ -846,19 +863,50 @@ public class TestComplete {
|
|||||||
var rec = classFiles.get("Point");
|
var rec = classFiles.get("Point");
|
||||||
|
|
||||||
var instance = clazz.getDeclaredConstructor().newInstance();
|
var instance = clazz.getDeclaredConstructor().newInstance();
|
||||||
var m1 = clazz.getDeclaredMethod("m", rec);
|
var m1 = clazz.getDeclaredMethod("m", rec, rec);
|
||||||
var m2 = clazz.getDeclaredMethod("m", Integer.class);
|
var m2 = clazz.getDeclaredMethod("m", rec);
|
||||||
|
var m3 = clazz.getDeclaredMethod("m", Integer.class);
|
||||||
|
|
||||||
var pt = rec.getDeclaredConstructor(Number.class, Number.class).newInstance(10, 20);
|
var ptInt = rec.getDeclaredConstructor(Number.class, Number.class).newInstance(1, 2);
|
||||||
assertEquals(m1.invoke(instance, pt), 30);
|
var ptFlt = rec.getDeclaredConstructor(Number.class, Number.class).newInstance(1f, 2f);
|
||||||
assertEquals(m2.invoke(instance, 10), 10);
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("Not implemented")
|
|
||||||
@Test
|
@Test
|
||||||
public void testOverloadPatternMatching() throws Exception {
|
public void testOverloadNestedPattern() throws Exception {
|
||||||
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "PaternMatchingHaskellStyle.jav");
|
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "OverloadNestedPattern.jav");
|
||||||
var clazz = classFiles.get("PaternMatchingHaskellStyle");
|
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 R2 = classFiles.get("Elem");
|
||||||
var R = classFiles.get("LinkedElem");
|
var R = classFiles.get("LinkedElem");
|
||||||
var I = classFiles.get("List");
|
var I = classFiles.get("List");
|
||||||
@@ -867,7 +915,7 @@ public class TestComplete {
|
|||||||
var r2ctor = R2.getDeclaredConstructor(Object.class);
|
var r2ctor = R2.getDeclaredConstructor(Object.class);
|
||||||
|
|
||||||
var instance = clazz.getDeclaredConstructor().newInstance();
|
var instance = clazz.getDeclaredConstructor().newInstance();
|
||||||
var m = clazz.getDeclaredMethod("append", R, I);
|
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 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));
|
var y = rctor.newInstance(r2ctor.newInstance(0), r2ctor.newInstance(0));
|
||||||
@@ -877,6 +925,23 @@ public class TestComplete {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Test
|
||||||
public void testOverloadSwitch() throws Exception {
|
public void testOverloadSwitch() throws Exception {
|
||||||
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SwitchOverload.jav");
|
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "SwitchOverload.jav");
|
||||||
@@ -891,7 +956,7 @@ public class TestComplete {
|
|||||||
var x = rctor.newInstance(10);
|
var x = rctor.newInstance(10);
|
||||||
var d = rctor.newInstance(20.0);
|
var d = rctor.newInstance(20.0);
|
||||||
|
|
||||||
assertEquals(m.invoke(instance, x, 0), 10);
|
assertEquals(m.invoke(instance, x, 0), 50);
|
||||||
assertEquals(m.invoke(instance, d, 0), 40.0);
|
assertEquals(m.invoke(instance, d, 0), 40.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user