Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e951a60ae6 | ||
|
|
825df05fac | ||
|
|
fab3e73596 | ||
|
|
392c5fa619 | ||
|
|
e21d2d7ced | ||
|
|
5a12545e8f | ||
|
|
d6c59f07f6 | ||
|
|
eb1c5c6629 | ||
|
|
a5c8d93e4c | ||
|
|
e70f071c63 | ||
|
|
f66499b4fe |
No files matched your search
@@ -0,0 +1,13 @@
|
||||
import java.lang.Integer;
|
||||
|
||||
public class Bug409 {
|
||||
public static m() {
|
||||
var n = 0;
|
||||
for (var i = 0; i < 5; i++) {
|
||||
n = n + 1;
|
||||
if (n > 100) { return -1; }
|
||||
if (i == 2) { continue; }
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
public class Bug421 {
|
||||
public m() { return 1 } // Missing semicolon
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
public class Bug422 {}
|
||||
public class Bug422 {}
|
||||
@@ -0,0 +1,5 @@
|
||||
import java.lang.Integer;
|
||||
|
||||
interface Bug423I { Integer f(); }
|
||||
|
||||
public class Bug423 implements Bug423I { }
|
||||
@@ -15,6 +15,7 @@ interface C {
|
||||
}
|
||||
|
||||
class ClassX implements A {
|
||||
void method1() {}
|
||||
}
|
||||
|
||||
record ClassY(Integer myInt) implements C {}
|
||||
|
||||
@@ -1056,6 +1056,7 @@ public class Codegen {
|
||||
}
|
||||
|
||||
Label start = new Label();
|
||||
Label skip = new Label();
|
||||
Label end = new Label();
|
||||
mv.visitLabel(start);
|
||||
if (_for.termination() != null) {
|
||||
@@ -1068,13 +1069,14 @@ public class Codegen {
|
||||
}
|
||||
|
||||
var env = new BreakEnv();
|
||||
env.startLabel = start;
|
||||
env.startLabel = skip;
|
||||
env.endLabel = end;
|
||||
|
||||
state.breakStack.push(env);
|
||||
generate(state, _for.body());
|
||||
state.breakStack.pop();
|
||||
|
||||
mv.visitLabel(skip);
|
||||
if (_for.increment() != null) {
|
||||
_for.increment().forEach(e -> {
|
||||
generate(state, e);
|
||||
@@ -1846,6 +1848,35 @@ public class Codegen {
|
||||
clazz.constructors().forEach(this::generateConstructor);
|
||||
clazz.methods().forEach(this::generateMethod);
|
||||
|
||||
// Check if non abstract class implements all interface methods
|
||||
if ((access & ACC_ABSTRACT) == 0) {
|
||||
for (var intf : clazz.implementingInterfaces()) {
|
||||
var intfClass = compiler.getClass(new JavaClassName(intf.name()));
|
||||
for (var method : intfClass.getMethods()) {
|
||||
if ((method.modifier & ACC_ABSTRACT) != 0) {
|
||||
// Check if the method is implemented in the current class
|
||||
// TODO This is duplicate code, we should probably refactor instances of this pattern
|
||||
var foundMethods = clazz.methods().stream().filter(m -> {
|
||||
if (!m.name().equals(method.name)) return false;
|
||||
if (m.signature().parameters().size() != method.getParameterList().getFormalparalist().size())
|
||||
return false;
|
||||
for (var i = 0; i < m.signature().parameters().size(); i++) {
|
||||
var param1 = m.signature().parameters().get(i).pattern().type();
|
||||
var param2 = converter.convert(
|
||||
method.getParameterList().getParameterAt(i).getType(),
|
||||
ASTToTargetAST.Generics.nullGenerics(compiler).javaGenerics());
|
||||
if (!param1.equals(param2)) return false;
|
||||
}
|
||||
return true;
|
||||
}).toList();
|
||||
if (foundMethods.size() != 1) {
|
||||
throw new CodeGenException("Class " + clazz.qualifiedName() + " does not implement method " + method.name + " from interface " + intfClass.getClassName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clazz.staticConstructor() != null)
|
||||
generateStaticConstructor(clazz.staticConstructor());
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import de.dhbwstuttgart.bytecode.Codegen;
|
||||
import de.dhbwstuttgart.bytecode.FunNGenerator;
|
||||
import de.dhbwstuttgart.environment.CompilationEnvironment;
|
||||
import de.dhbwstuttgart.environment.DirectoryClassLoader;
|
||||
import de.dhbwstuttgart.exceptions.CompilerException;
|
||||
import de.dhbwstuttgart.exceptions.CompilerWarning;
|
||||
import de.dhbwstuttgart.exceptions.DebugException;
|
||||
import de.dhbwstuttgart.exceptions.WarningsException;
|
||||
@@ -171,6 +172,8 @@ public class JavaTXCompiler {
|
||||
|
||||
var numberOfGenerics = decl == null ? 0 : decl.genericTypeVar().size();
|
||||
var className = pkgName + (!pkgName.isEmpty() ? "." : "") + name;
|
||||
if (classRegistry.contains(className))
|
||||
throw new CompilerException("Duplicate class definition: " + className);
|
||||
classRegistry.addName(className, numberOfGenerics);
|
||||
input.add(classRegistry.getName(className));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.dhbwstuttgart.exceptions;
|
||||
|
||||
public class CompilerException extends RuntimeException {
|
||||
public CompilerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,8 @@ package de.dhbwstuttgart.exceptions;
|
||||
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
public class ParserError extends TypeinferenceException{
|
||||
|
||||
public ParserError(Token offset){
|
||||
super("Fehler beim Parsen", offset);
|
||||
public class ParserError extends RuntimeException{
|
||||
public ParserError(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.dhbwstuttgart.parser;
|
||||
|
||||
import de.dhbwstuttgart.environment.CompilationEnvironment;
|
||||
import de.dhbwstuttgart.exceptions.ParserError;
|
||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.SyntaxTreeGenerator;
|
||||
import de.dhbwstuttgart.parser.antlr.Java17Lexer;
|
||||
import de.dhbwstuttgart.parser.antlr.Java17Parser;
|
||||
@@ -8,9 +9,7 @@ import de.dhbwstuttgart.parser.scope.JavaClassRegistry;
|
||||
import de.dhbwstuttgart.syntaxtree.SourceFile;
|
||||
|
||||
import de.dhbwstuttgart.util.Logger;
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -21,13 +20,25 @@ public class JavaTXParser {
|
||||
|
||||
public static Logger logger = new Logger("Parser");
|
||||
|
||||
public static class ThrowingErrorListener extends BaseErrorListener {
|
||||
|
||||
@Override
|
||||
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol,
|
||||
int line, int charPositionInLine, String msg, RecognitionException e) {
|
||||
throw new ParserError("Syntax error at line " + line + ":" + charPositionInLine + " - " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static Java17Parser.SourceFileContext parse(File source) throws IOException, java.lang.ClassNotFoundException {
|
||||
InputStream stream = new FileInputStream(source);
|
||||
// DEPRECATED: ANTLRInputStream input = new ANTLRInputStream(stream);
|
||||
var errorListener = new ThrowingErrorListener();
|
||||
CharStream input = CharStreams.fromStream(stream);
|
||||
Java17Lexer lexer = new Java17Lexer(input);
|
||||
lexer.addErrorListener(errorListener);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
Java17Parser parser = new Java17Parser(tokens);
|
||||
parser.addErrorListener(errorListener);
|
||||
return parser.sourceFile();
|
||||
/*
|
||||
* SyntaxTreeGenerator generator = new SyntaxTreeGenerator(environment.getRegistry(source)); return generator.convert(tree);
|
||||
|
||||
@@ -618,7 +618,7 @@ public class ASTToTargetAST {
|
||||
}
|
||||
}
|
||||
|
||||
private static TargetExpression generateCall(TargetMethod method, List<TargetLocalVar> params, TargetType classType, boolean isInterface) {
|
||||
private static TargetExpression generateCall(TargetMethod method, List<TargetLocalVar> params, TargetType classType) {
|
||||
var mParams = new ArrayList<TargetExpression>();
|
||||
for (var i = 0; i < params.size(); i++) {
|
||||
var tpe = method.signature().parameters().get(i).pattern().type();
|
||||
@@ -626,11 +626,11 @@ public class ASTToTargetAST {
|
||||
}
|
||||
TargetExpression caseBody = new TargetMethodCall(
|
||||
method.signature().returnType(),
|
||||
method.isStatic() ? new TargetClassName(classType) : new TargetThis(classType),
|
||||
new TargetThis(classType),
|
||||
mParams,
|
||||
classType,
|
||||
method.name(),
|
||||
method.isStatic(), isInterface, method.isPrivate()
|
||||
false, false, method.isPrivate()
|
||||
);
|
||||
if (method.signature().returnType() != null) {
|
||||
caseBody = new TargetReturn(caseBody);
|
||||
@@ -638,11 +638,11 @@ public class ASTToTargetAST {
|
||||
return caseBody;
|
||||
}
|
||||
|
||||
private TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List<TargetLocalVar> params, List<TargetPattern> patterns, List<TargetMethod> methods, TargetType classType, boolean isInterface) {
|
||||
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();
|
||||
return generateCall(method, params, classType, isInterface);
|
||||
return generateCall(method, params, classType);
|
||||
}
|
||||
|
||||
var cases = new ArrayList<TargetSwitch.Case>();
|
||||
@@ -691,11 +691,11 @@ public class ASTToTargetAST {
|
||||
}).toList();
|
||||
|
||||
if (candidates.isEmpty()) {
|
||||
var body = new TargetBlock(List.of(generateCall(method, params, classType, isInterface)));
|
||||
var body = new TargetBlock(List.of(generateCall(method, params, classType)));
|
||||
cases.add(new TargetSwitch.Case(List.of(lastPattern), body));
|
||||
} else {
|
||||
//candidates.forEach(m -> Target.logger.info(m.getSignature()));
|
||||
var caseBody = generatePatternOverloadsRec(offset + 1, expr, params, patternsRec, candidates, classType, isInterface);
|
||||
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);
|
||||
|
||||
@@ -787,7 +787,7 @@ public class ASTToTargetAST {
|
||||
var parameters = resParams.stream().map( p -> new TargetLocalVar(p.pattern().type(), p.pattern().name())).toList();
|
||||
|
||||
var classType = new TargetRefType(clazz.getClassName().toString());
|
||||
var stmt = generatePatternOverloadsRec(0, new TargetLocalVar(resParams.getFirst().pattern().type(), resParams.getFirst().pattern().name()), parameters, List.of(), methods, classType, clazz.isInterface());
|
||||
var stmt = generatePatternOverloadsRec(0, new TargetLocalVar(resParams.getFirst().pattern().type(), resParams.getFirst().pattern().name()), parameters, List.of(), methods, classType);
|
||||
var block = new TargetBlock(List.of(stmt));
|
||||
|
||||
var generics = new HashSet<>(firstMethod.signature().generics());
|
||||
@@ -870,7 +870,7 @@ public class ASTToTargetAST {
|
||||
|
||||
// Generate dispatch method
|
||||
var classType = new TargetRefType(clazz.getClassName().toString());
|
||||
var stmt = generatePatternOverloadsRec(0, new TargetLocalVar(signatureParams.getFirst().pattern().type(), signatureParams.getFirst().pattern().name()), parameters, List.of(), res, classType, clazz.isInterface());
|
||||
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 bridgeMethod = new TargetMethod(firstMethod.access(), firstMethod.name(), block, group.signature.java, group.signature.tx, firstMethod.base(), null);
|
||||
|
||||
@@ -256,9 +256,9 @@ public class StatementToTargetExpression implements ASTVisitor {
|
||||
foundMethod = findMethod(receiverName, methodCall.name, signature, converter.compiler).orElseThrow(
|
||||
() -> new DebugException("Method " + methodCall.name + " not found (" + finalSignature + ") on class " + receiverName)
|
||||
);
|
||||
if (foundMethod != null) {
|
||||
signature = foundMethod.getParameterList().getFormalparalist().stream().map(pattern -> converter.convert(pattern.getType(), generics)).toList();
|
||||
}
|
||||
//if (foundMethod != null) {
|
||||
// signature = foundMethod.getParameterList().getFormalparalist().stream().map(pattern -> converter.convert(pattern.getType(), generics)).toList();
|
||||
//}
|
||||
}
|
||||
|
||||
if (!isFunNType) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
import de.dhbwstuttgart.bytecode.CodeGenException;
|
||||
import de.dhbwstuttgart.core.ConsoleInterface;
|
||||
import de.dhbwstuttgart.exceptions.CompilerException;
|
||||
import de.dhbwstuttgart.exceptions.ParserError;
|
||||
import de.dhbwstuttgart.exceptions.WarningsException;
|
||||
import de.dhbwstuttgart.util.Logger;
|
||||
import de.dhbwstuttgart.util.Logger.LogLevel;
|
||||
@@ -1081,6 +1083,7 @@ public class TestComplete {
|
||||
assertEquals(40.0, m.invoke(instance, d, 0));
|
||||
}
|
||||
|
||||
@Disabled("Waiting for #407, skipping for now")
|
||||
@Test
|
||||
public void testPatternMatchingInterface() throws Exception {
|
||||
var classFiles = generateClassFiles(createClassLoader(), false, "Matcher.jav", "PatternMatchingInterface.jav");
|
||||
@@ -1703,4 +1706,43 @@ public class TestComplete {
|
||||
var clazz = classFiles.get("Bug406");
|
||||
clazz.getDeclaredMethod("main", List.class).invoke(null, List.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug423() throws Exception {
|
||||
try {
|
||||
var classFiles = generateClassFiles(createClassLoader(), "Bug423.jav");
|
||||
fail("No exception thrown!");
|
||||
} catch (CodeGenException e) {
|
||||
assertEquals("Class Bug423 does not implement method f from interface Bug423I", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug422() throws Exception {
|
||||
try {
|
||||
var classFiles = generateClassFiles(createClassLoader(), "Bug422.jav");
|
||||
fail("Shouldn't compile!");
|
||||
} catch (CompilerException e) {
|
||||
assertEquals("Duplicate class definition: Bug422", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug421() throws Exception {
|
||||
try {
|
||||
var classFiles = generateClassFiles(createClassLoader(), "Bug421.jav");
|
||||
fail("Shouldn't compile!");
|
||||
} catch (ParserError e) {
|
||||
assertEquals("Syntax error at line 2:26 - no viable alternative at input 'm() { return 1 }'", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug409() throws Exception {
|
||||
var classFiles = generateClassFiles(createClassLoader(), "Bug409.jav");
|
||||
var clazz = classFiles.get("Bug409");
|
||||
var instance = clazz.getDeclaredConstructor().newInstance();
|
||||
var m = clazz.getDeclaredMethod("m");
|
||||
assertEquals(5, m.invoke(instance));
|
||||
}
|
||||
}
|
||||
@@ -202,9 +202,20 @@ public class TestCodegen {
|
||||
@Test
|
||||
public void testFor() throws Exception {
|
||||
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, new JavaClassName("For"));
|
||||
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "forLoop", List.of(), TargetType.Integer, new TargetBlock(List.of(new TargetVarDecl(TargetType.Integer, "sum", new TargetLiteral.IntLiteral(0)), new TargetFor(List.of(new TargetVarDecl(TargetType.Integer, "i", new TargetLiteral.IntLiteral(0))), new TargetBinaryOp.Less(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetLiteral.IntLiteral(10)), List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetBinaryOp.Add(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetLiteral.IntLiteral(1)))), new TargetBlock(List.of(new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "sum"), new TargetBinaryOp.Add(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "sum"), new TargetLocalVar(TargetType.Integer, "i")))))), new TargetReturn(new TargetLocalVar(TargetType.Integer, "sum")))));
|
||||
targetClass.addMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "forLoop", List.of(), TargetType.Integer,
|
||||
new TargetBlock(List.of(new TargetVarDecl(TargetType.Integer, "sum", new TargetLiteral.IntLiteral(0)),
|
||||
new TargetFor(List.of(new TargetVarDecl(TargetType.Integer, "i", new TargetLiteral.IntLiteral(0))),
|
||||
new TargetBinaryOp.Less(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"),
|
||||
new TargetLiteral.IntLiteral(10)), List.of(new TargetAssign(TargetType.Integer,
|
||||
new TargetLocalVar(TargetType.Integer, "i"),
|
||||
new TargetBinaryOp.Add(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "i"), new TargetLiteral.IntLiteral(1)))),
|
||||
new TargetBlock(List.of(
|
||||
new TargetAssign(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "sum"),
|
||||
new TargetBinaryOp.Add(TargetType.Integer, new TargetLocalVar(TargetType.Integer, "sum"),
|
||||
new TargetLocalVar(TargetType.Integer, "i")))))),
|
||||
new TargetReturn(new TargetLocalVar(TargetType.Integer, "sum")))));
|
||||
var clazz = generateClass(targetClass, createClassLoader());
|
||||
assertEquals(clazz.getDeclaredMethod("forLoop").invoke(null), 45);
|
||||
assertEquals(45, clazz.getDeclaredMethod("forLoop").invoke(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user