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
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m39s
This commit is contained in:
commit
edf609f916
@ -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: |
|
||||
|
@ -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
@ -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}
|
||||
*
|
||||
|
@ -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}
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
4
pom.xml
4
pom.xml
@ -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>
|
||||
|
15
resources/bytecode/javFiles/Assign.jav
Normal file
15
resources/bytecode/javFiles/Assign.jav
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
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;
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
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));
|
||||
}
|
||||
}
|
19
resources/bytecode/javFiles/PatternMatchingListAppend.jav
Normal file
19
resources/bytecode/javFiles/PatternMatchingListAppend.jav
Normal file
@ -0,0 +1,19 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
17
resources/bytecode/javFiles/PatternMatchingLiteralStyle.jav
Normal file
17
resources/bytecode/javFiles/PatternMatchingLiteralStyle.jav
Normal 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();
|
||||
};
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
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;
|
||||
};
|
||||
}
|
||||
}
|
21
resources/bytecode/javFiles/SwitchOverload.jav
Normal file
21
resources/bytecode/javFiles/SwitchOverload.jav
Normal 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -654,6 +654,7 @@ primaryPattern
|
||||
: typePattern #tPattern
|
||||
| recordPattern #rPattern
|
||||
| '(' pattern ')' #enclosedPattern
|
||||
| literal (',' literal)* #lPattern
|
||||
;
|
||||
|
||||
recordPattern
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -5,6 +5,7 @@ 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 +18,7 @@ import de.dhbwstuttgart.target.tree.expression.*;
|
||||
import de.dhbwstuttgart.target.tree.type.*;
|
||||
import de.dhbwstuttgart.typeinference.result.*;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@ -33,12 +35,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,37 +146,60 @@ 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.
|
||||
record WeakSignature(TargetMethod.Signature signature) {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof WeakSignature other)) 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.equals(p2)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(signature.parameters().stream().map(p -> p.pattern().type()).toArray());
|
||||
}
|
||||
}
|
||||
|
||||
public List<List<TargetMethod>> groupOverloads(ClassOrInterface input, List<Method> methods) {
|
||||
var res = new ArrayList<List<TargetMethod>>();
|
||||
var mapOfSignatures = new HashMap<WeakSignature, List<MethodWithTphs>>();
|
||||
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<>());
|
||||
var signature = new WeakSignature(m.method.signature());
|
||||
var methodsWithSameSignature = mapOfSignatures.getOrDefault(signature, new ArrayList<>());
|
||||
methodsWithSameSignature.add(m);
|
||||
mapOfSignatures.put(m.method.signature(), methodsWithSameSignature);
|
||||
mapOfSignatures.put(signature, methodsWithSameSignature);
|
||||
}
|
||||
}
|
||||
|
||||
for (var methodsWithSignature : mapOfSignatures.values()) {
|
||||
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 : 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) &&
|
||||
!arg1.signature.equals(arg2.signature)) continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
resMethods.add(m1.method);
|
||||
}
|
||||
resMethods.add(m1.method);
|
||||
}
|
||||
res.add(resMethods.stream().toList());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -202,7 +233,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 +247,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 +303,127 @@ 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 TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List<TargetExpression> params, List<TargetComplexPattern> 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();
|
||||
TargetExpression caseBody = new TargetMethodCall(
|
||||
method.signature().returnType(),
|
||||
new TargetThis(classType),
|
||||
params,
|
||||
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<TargetPattern>();
|
||||
|
||||
for (var method : methods) {
|
||||
var patternsRec = new ArrayList<>(patterns);
|
||||
|
||||
TargetExpression expr = null;
|
||||
var i = 0;
|
||||
for (var param : method.signature().parameters()) {
|
||||
if (param.pattern() instanceof TargetComplexPattern pat) {
|
||||
if (i == offset) {
|
||||
patternsRec.add(pat);
|
||||
}
|
||||
if (i > offset) {
|
||||
// Find next pattern
|
||||
var pattern = param.pattern();
|
||||
expr = new TargetLocalVar(pattern.type(), pattern.name());
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
var lastPattern = patternsRec.getLast();
|
||||
if (usedPatterns.contains(lastPattern)) continue;
|
||||
usedPatterns.add(lastPattern);
|
||||
|
||||
var candidates = methods.stream().filter(m -> {
|
||||
var j = 0;
|
||||
for (var param : m.signature().parameters()) {
|
||||
if (j >= patternsRec.size()) return true;
|
||||
if (param.pattern() instanceof TargetComplexPattern) {
|
||||
if (!patternsRec.get(j).equals(param.pattern())) 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();
|
||||
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 = firstMethod.signature().parameters().stream().map(p -> {
|
||||
if (p.pattern() instanceof TargetComplexPattern pat) {
|
||||
return new MethodParameter(pat.type(), pat.name());
|
||||
}
|
||||
return p;
|
||||
}).toList();
|
||||
var parameters = firstMethod.signature().parameters().stream().map( p -> (TargetExpression) 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());
|
||||
var firstPattern = 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(firstPattern.type(), firstPattern.name()), parameters, List.of(), res, classType);
|
||||
var block = new TargetBlock(List.of(stmt));
|
||||
|
||||
var signature = new TargetMethod.Signature(firstMethod.signature().generics(), signatureParams, firstMethod.signature().returnType());
|
||||
var bridgeMethod = new TargetMethod(firstMethod.access(), firstMethod.name(), block, signature, firstMethod.txSignature());
|
||||
|
||||
res.add(bridgeMethod);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -376,11 +470,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 +503,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 +527,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;
|
||||
}
|
||||
|
@ -134,8 +134,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 +154,22 @@ 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(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||
var result = new HashSet<TPH>();
|
||||
if (type instanceof TypePlaceholder tph) {
|
||||
|
@ -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());
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -1,6 +1,8 @@
|
||||
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;
|
||||
@ -9,7 +11,10 @@ import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
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 +84,46 @@ 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();
|
||||
|
||||
int counter = 0;
|
||||
for(Pattern el : subPatternList){
|
||||
|
||||
if(el instanceof RecordPattern){
|
||||
constraintSet.addAll(addRecursiveParameterConstraints((RecordPattern) el, blockInformation));
|
||||
}else{
|
||||
var allClasses = blockInformation.getAvailableClasses();
|
||||
RefTypeOrTPHOrWildcardOrGeneric type;
|
||||
|
||||
for (ClassOrInterface allClass : allClasses) {
|
||||
var typename = recordPattern.getType().toString();
|
||||
var className = allClass.getClassName().getClassName();
|
||||
if(className.equals(typename)){
|
||||
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())));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
return constraintSet;
|
||||
}
|
||||
|
||||
private ConstraintSet getConstraintsConstructor(Constructor m, TypeInferenceInformation info, ClassOrInterface currentClass) {
|
||||
|
@ -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(
|
||||
@ -861,7 +862,7 @@ public class TYPEStmt implements StatementVisitor {
|
||||
for (var child : switchStmt.getBlocks()) {
|
||||
for (var label : child.getLabels()) {
|
||||
if (label.getPattern() == null) {
|
||||
System.out.println("DefaultCase");
|
||||
constraintsSet.addUndConstraint(new Pair(new RefType(new JavaClassName("java.lang.Object"), new NullToken()), switchStmt.getSwitch().getType(), PairOperator.SMALLERDOT, loc(label.getOffset())));
|
||||
}
|
||||
if (label.getPattern() instanceof RecordPattern) {
|
||||
RecordPattern recordPattern = (RecordPattern) label.getPattern();
|
||||
@ -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++;
|
||||
}
|
||||
}
|
||||
|
@ -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,91 @@ 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();
|
||||
}
|
||||
|
||||
@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 +1167,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");
|
||||
|
Loading…
Reference in New Issue
Block a user