Compare commits
14 Commits
c5fc378eed
...
f24e279596
Author | SHA1 | Date | |
---|---|---|---|
f24e279596 | |||
|
27f50b9c66 | ||
85ae06048c | |||
cd845cd91c | |||
78d5528733 | |||
|
88a25207e9 | ||
|
4e56760dd6 | ||
|
347bdcbd94 | ||
|
d594bacb7d | ||
|
eb313464f0 | ||
|
34d17660ef | ||
|
cc6d26e17d | ||
|
f9743efddc | ||
|
b37e065857 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -83,3 +83,4 @@ src/test/resources/output/javac/CompilerInput$Test.class
|
|||||||
src/test/resources/output/javac/CompilerInput.class
|
src/test/resources/output/javac/CompilerInput.class
|
||||||
src/test/resources/output/raupenpiler/CompilerInput.class
|
src/test/resources/output/raupenpiler/CompilerInput.class
|
||||||
src/test/resources/output/raupenpiler/CompilerInput$Test.class
|
src/test/resources/output/raupenpiler/CompilerInput$Test.class
|
||||||
|
.idea/inspectionProfiles/Project_Default.xml
|
||||||
|
@ -15,30 +15,20 @@ public class ClassNode implements ASTNode, Visitable {
|
|||||||
public AccessModifierNode accessType;
|
public AccessModifierNode accessType;
|
||||||
public String identifier;
|
public String identifier;
|
||||||
public List<MemberNode> members = new ArrayList<>();
|
public List<MemberNode> members = new ArrayList<>();
|
||||||
public boolean hasConstructor;
|
|
||||||
|
|
||||||
public ClassNode() {}
|
public ClassNode(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public ClassNode(String accessType, String identifier){
|
public ClassNode(String accessType, String identifier){
|
||||||
this.accessType = new AccessModifierNode(accessType);
|
this.accessType = new AccessModifierNode(accessType);
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
hasConstructor = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMember(MemberNode member) {
|
public void addMember(MemberNode member) {
|
||||||
if (member instanceof ConstructorNode) {
|
|
||||||
this.hasConstructor = true;
|
|
||||||
}
|
|
||||||
members.add(member);
|
members.add(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ensureConstructor(){
|
|
||||||
if(!hasConstructor) {
|
|
||||||
ConstructorNode constructor = new ConstructorNode(new AccessModifierNode("public"), identifier);
|
|
||||||
members.addFirst(constructor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MethodNode> getMethods(){
|
public List<MethodNode> getMethods(){
|
||||||
List<MethodNode> methods = new ArrayList<>();
|
List<MethodNode> methods = new ArrayList<>();
|
||||||
for (MemberNode member : members) {
|
for (MemberNode member : members) {
|
||||||
|
@ -8,17 +8,13 @@ import visitor.Visitable;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class BlockNode implements ASTNode, Visitable {
|
public class BlockNode implements IStatementNode, Visitable {
|
||||||
public List<IStatementNode> statements = new ArrayList<>();
|
public List<IStatementNode> statements = new ArrayList<>();
|
||||||
public Boolean hasReturnStatement = false;
|
|
||||||
|
|
||||||
public BlockNode() {}
|
public BlockNode() {}
|
||||||
|
|
||||||
public void addStatement(IStatementNode statement) {
|
public void addStatement(IStatementNode statement) {
|
||||||
statements.add(statement);
|
statements.add(statement);
|
||||||
if(statement instanceof ReturnNode) {
|
|
||||||
hasReturnStatement = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package ast.statements;
|
package ast.statements;
|
||||||
|
|
||||||
import ast.ASTNode;
|
import ast.ASTNode;
|
||||||
|
import semantic.SemanticVisitor;
|
||||||
|
import typechecker.TypeCheckResult;
|
||||||
|
|
||||||
public class ElseNode implements ASTNode {
|
public class ElseNode implements IStatementNode {
|
||||||
BlockNode block;
|
BlockNode block;
|
||||||
|
|
||||||
public ElseNode(BlockNode block) {
|
public ElseNode(BlockNode block) {
|
||||||
@ -10,4 +12,8 @@ public class ElseNode implements ASTNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package ast.statements;
|
package ast.statements;
|
||||||
|
|
||||||
import ast.ASTNode;
|
import ast.ASTNode;
|
||||||
|
import semantic.SemanticVisitor;
|
||||||
|
import typechecker.TypeCheckResult;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class IfElseNode implements ASTNode {
|
public class IfElseNode implements IStatementNode {
|
||||||
IfNode ifStatement;
|
IfNode ifStatement;
|
||||||
List<IfNode> elseIfStatements = new ArrayList<>();
|
List<IfNode> elseIfStatements = new ArrayList<>();
|
||||||
ElseNode elseStatement;
|
ElseNode elseStatement;
|
||||||
@ -19,4 +21,8 @@ public class IfElseNode implements ASTNode {
|
|||||||
elseIfStatements.add(elseIfStament);
|
elseIfStatements.add(elseIfStament);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,20 @@ package ast.statements;
|
|||||||
|
|
||||||
import ast.ASTNode;
|
import ast.ASTNode;
|
||||||
import ast.expressions.IExpressionNode;
|
import ast.expressions.IExpressionNode;
|
||||||
|
import semantic.SemanticVisitor;
|
||||||
|
import typechecker.TypeCheckResult;
|
||||||
|
|
||||||
public class IfNode implements ASTNode {
|
public class IfNode implements IStatementNode {
|
||||||
public IExpressionNode expression;
|
IExpressionNode expression;
|
||||||
public BlockNode block;
|
BlockNode block;
|
||||||
|
|
||||||
public IfNode(IExpressionNode expression, BlockNode block) {
|
public IfNode(IExpressionNode expression, BlockNode block) {
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.block = block;
|
this.block = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
package ast.statements;
|
|
||||||
|
|
||||||
public class StatementNode {
|
|
||||||
}
|
|
@ -2,23 +2,21 @@ package ast.statements;
|
|||||||
|
|
||||||
import ast.ASTNode;
|
import ast.ASTNode;
|
||||||
import ast.expressions.IExpressionNode;
|
import ast.expressions.IExpressionNode;
|
||||||
import bytecode.visitor.MethodVisitor;
|
|
||||||
import semantic.SemanticVisitor;
|
import semantic.SemanticVisitor;
|
||||||
import typechecker.TypeCheckResult;
|
import typechecker.TypeCheckResult;
|
||||||
import visitor.Visitable;
|
|
||||||
|
|
||||||
public class WhileNode extends StatementNode implements ASTNode, Visitable {
|
public class WhileNode implements IStatementNode {
|
||||||
public IExpressionNode expression;
|
IExpressionNode expression;
|
||||||
public BlockNode block;
|
BlockNode block;
|
||||||
|
|
||||||
public WhileNode(IExpressionNode expression, BlockNode block) {
|
public WhileNode(IExpressionNode expression, BlockNode block) {
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.block = block;
|
this.block = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void test() {
|
||||||
public void accept(MethodVisitor methodVisitor) {
|
return;
|
||||||
methodVisitor.visit(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,13 +20,11 @@ import java.nio.file.Paths;
|
|||||||
* <p> <code> cd .\src\test\ </code>
|
* <p> <code> cd .\src\test\ </code>
|
||||||
* <p> <code> make clean compile-raupenpiler </code>
|
* <p> <code> make clean compile-raupenpiler </code>
|
||||||
* <p> Start Raupenpiler using jar:
|
* <p> Start Raupenpiler using jar:
|
||||||
* <p> <code> java.exe -jar path_to_jar\JavaCompiler-1.0-SNAPSHOT-jar-with-dependencies.jar 'path_to_input_file.java' 'path_to_output_directory' </code>
|
* <p> <code> java.exe -jar path_to_jar\JavaCompiler-1.0-jar-with-dependencies.jar 'path_to_input_file.java' 'path_to_output_directory' </code>
|
||||||
* <p> Example (jar needs to be in the target directory, compile with make or mvn package first):
|
* <p> Example (jar needs to be in the target directory, compile with make or mvn package first):
|
||||||
* <code> java.exe -jar .\target\JavaCompiler-1.0-SNAPSHOT-jar-with-dependencies.jar 'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' </code>
|
* <code> java.exe -jar .\target\JavaCompiler-1.0-jar-with-dependencies.jar 'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' </code>
|
||||||
*/
|
*/
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
if (args.length == 2) {
|
if (args.length == 2) {
|
||||||
// args[0] is the input file path
|
// args[0] is the input file path
|
||||||
|
@ -16,18 +16,18 @@ import java.util.List;
|
|||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Beispiel für Logging-Arten:
|
* Beispiel für Logging-Arten:
|
||||||
<p><code>logger.severe("Schwerwiegender Fehler");</code>
|
* <p><code>logger.severe("Schwerwiegender Fehler");</code>
|
||||||
<p><code>logger.warning("Warnung");</code>
|
* <p><code>logger.warning("Warnung");</code>
|
||||||
<p><code>logger.info("Information");</code>
|
* <p><code>logger.info("Information");</code>
|
||||||
<p><code>logger.config("Konfigurationshinweis");</code>
|
* <p><code>logger.config("Konfigurationshinweis");</code>
|
||||||
<p><code>logger.fine("Fein");</code>
|
* <p><code>logger.fine("Fein");</code>
|
||||||
<p><code>logger.finer("Feiner");</code>
|
* <p><code>logger.finer("Feiner");</code>
|
||||||
<p><code>logger.finest("Am feinsten");</code>
|
* <p><code>logger.finest("Am feinsten");</code>
|
||||||
<p>You may toggle the logging level of the console and file handlers by
|
* <p>You may toggle the logging level of the console and file handlers by
|
||||||
changing the level ALL/OFF/etc. in the constructor.
|
* changing the level ALL/OFF/etc. in the constructor.
|
||||||
<code>consoleHandler.setLevel(Level.OFF);</code>
|
* <code>consoleHandler.setLevel(Level.OFF);</code>
|
||||||
<code>fileHandler.setLevel(Level.ALL);</code>
|
* <code>fileHandler.setLevel(Level.ALL);</code>
|
||||||
*/
|
*/
|
||||||
public class RaupenLogger {
|
public class RaupenLogger {
|
||||||
|
|
||||||
@ -172,9 +172,9 @@ public class RaupenLogger {
|
|||||||
}
|
}
|
||||||
String indentString = " ".repeat(indent * 2);
|
String indentString = " ".repeat(indent * 2);
|
||||||
logger.info(indentString + abstractSyntaxTree.getClass());
|
logger.info(indentString + abstractSyntaxTree.getClass());
|
||||||
|
//for (ASTNode child : abstractSyntaxTree.getChildren()) {
|
||||||
// for (ASTNode child : node.) {
|
// logAST(child, indent + 1);
|
||||||
// printAST(child, indent + 1);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,11 +44,28 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ASTNode visitClassDeclaration(SimpleJavaParser.ClassDeclarationContext ctx) {
|
public ASTNode visitClassDeclaration(SimpleJavaParser.ClassDeclarationContext ctx) {
|
||||||
ClassNode classNode = new ClassNode(ctx.AccessModifier().getText(), ctx.Identifier().getText());
|
ClassNode classNode;
|
||||||
for (SimpleJavaParser.MemberDeclarationContext member : ctx.memberDeclaration()) {
|
if(ctx.AccessModifier() != null){
|
||||||
classNode.addMember((MemberNode) visit(member));
|
classNode = new ClassNode(ctx.AccessModifier().getText(), ctx.Identifier().getText());
|
||||||
}
|
}
|
||||||
classNode.ensureConstructor();
|
else{
|
||||||
|
classNode = new ClassNode("public", ctx.Identifier().getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasConstructor = false;
|
||||||
|
|
||||||
|
for (SimpleJavaParser.MemberDeclarationContext member : ctx.memberDeclaration()) {
|
||||||
|
MemberNode memberNode = (MemberNode) visit(member);
|
||||||
|
if(memberNode instanceof ConstructorNode){
|
||||||
|
hasConstructor = true;
|
||||||
|
}
|
||||||
|
classNode.addMember(memberNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!hasConstructor){
|
||||||
|
classNode.members.addFirst(new ConstructorNode(new AccessModifierNode("public"), ctx.Identifier().getText()));
|
||||||
|
}
|
||||||
|
|
||||||
return classNode;
|
return classNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,13 +77,16 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
|
|||||||
constructorNode.addParameter((ParameterNode) visit(parameter));
|
constructorNode.addParameter((ParameterNode) visit(parameter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
constructorNode.block.addStatement(new ReturnNode(null));
|
||||||
return constructorNode;
|
return constructorNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ASTNode visitMethodDeclaration(SimpleJavaParser.MethodDeclarationContext ctx) {
|
public ASTNode visitMethodDeclaration(SimpleJavaParser.MethodDeclarationContext ctx) {
|
||||||
if(ctx.MainMethodDeclaration() != null) {
|
if(ctx.MainMethodDeclaration() != null) {
|
||||||
return new MainMethodNode((BlockNode) visit(ctx.blockStatement()));
|
MainMethodNode mainMethod = new MainMethodNode((BlockNode) visit(ctx.blockStatement()));
|
||||||
|
mainMethod.block.addStatement(new ReturnNode(null));
|
||||||
|
return mainMethod;
|
||||||
} else {
|
} else {
|
||||||
if(ctx.type() != null) {
|
if(ctx.type() != null) {
|
||||||
MethodNode methodNode = new MethodNode(ctx.AccessModifier().getText(), createTypeNode(ctx.type().getText()), false, ctx.Identifier().getText(), (BlockNode) visit(ctx.blockStatement()));
|
MethodNode methodNode = new MethodNode(ctx.AccessModifier().getText(), createTypeNode(ctx.type().getText()), false, ctx.Identifier().getText(), (BlockNode) visit(ctx.blockStatement()));
|
||||||
@ -83,6 +103,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
|
|||||||
methodNode.addParameter((ParameterNode) visit(parameter));
|
methodNode.addParameter((ParameterNode) visit(parameter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
methodNode.block.addStatement(new ReturnNode(null));
|
||||||
return methodNode;
|
return methodNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,6 +129,8 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
|
|||||||
return visitBlockStatement(ctx.blockStatement());
|
return visitBlockStatement(ctx.blockStatement());
|
||||||
} else if(ctx.whileStatement() != null) {
|
} else if(ctx.whileStatement() != null) {
|
||||||
return visitWhileStatement(ctx.whileStatement());
|
return visitWhileStatement(ctx.whileStatement());
|
||||||
|
} else if(ctx.doWhileStatement() != null) {
|
||||||
|
return visitDoWhileStatement(ctx.doWhileStatement());
|
||||||
} else if(ctx.forStatement() != null) {
|
} else if(ctx.forStatement() != null) {
|
||||||
return visitForStatement(ctx.forStatement());
|
return visitForStatement(ctx.forStatement());
|
||||||
} else if(ctx.ifElseStatement() != null) {
|
} else if(ctx.ifElseStatement() != null) {
|
||||||
@ -134,9 +157,6 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
|
|||||||
for(SimpleJavaParser.StatementContext statement : ctx.statement()) {
|
for(SimpleJavaParser.StatementContext statement : ctx.statement()) {
|
||||||
blockNode.addStatement((IStatementNode) visit(statement));
|
blockNode.addStatement((IStatementNode) visit(statement));
|
||||||
}
|
}
|
||||||
if(!blockNode.hasReturnStatement) {
|
|
||||||
blockNode.addStatement(new ReturnNode(null));
|
|
||||||
}
|
|
||||||
return blockNode;
|
return blockNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,28 +181,30 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
|
|||||||
@Override
|
@Override
|
||||||
public ASTNode visitForStatement(SimpleJavaParser.ForStatementContext ctx) {
|
public ASTNode visitForStatement(SimpleJavaParser.ForStatementContext ctx) {
|
||||||
|
|
||||||
List<StatementNode> statements = new ArrayList<>();
|
List<IStatementNode> statements = new ArrayList<>();
|
||||||
|
|
||||||
//init
|
//init
|
||||||
if(ctx.statementExpression(0) != null){
|
int i = 0;
|
||||||
statements.add((StatementNode) visit(ctx.statementExpression(0)));
|
if(ctx.localVariableDeclaration() != null) {
|
||||||
} else if (ctx.localVariableDeclaration() != null) {
|
statements.add((IStatementNode) visit(ctx.localVariableDeclaration()));
|
||||||
statements.add((StatementNode) visit(ctx.localVariableDeclaration()));
|
} else if(ctx.statementExpression(i) != null){
|
||||||
|
statements.add((IStatementNode) visit(ctx.statementExpression(i)));
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//condition
|
//condition
|
||||||
IExpressionNode condition = (IExpressionNode) visit(ctx.expression());
|
IExpressionNode condition = (IExpressionNode) visit(ctx.expression());
|
||||||
|
|
||||||
//ink
|
//ink
|
||||||
IStatementNode increment = null;
|
IStatementNode crement = null;
|
||||||
if(ctx.statementExpression(1) != null){
|
if(ctx.statementExpression(i) != null){
|
||||||
increment = (IStatementNode) visit(ctx.statementExpression(1));
|
crement = (IStatementNode) visit(ctx.statementExpression(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockNode forBlock = (BlockNode) visit(ctx.blockStatement());
|
BlockNode forBlock = (BlockNode) visit(ctx.blockStatement());
|
||||||
|
|
||||||
if(increment != null){
|
if(crement != null){
|
||||||
forBlock.addStatement((increment));
|
forBlock.addStatement((crement));
|
||||||
}
|
}
|
||||||
|
|
||||||
WhileNode While = new WhileNode(condition, forBlock);
|
WhileNode While = new WhileNode(condition, forBlock);
|
||||||
@ -190,7 +212,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
|
|||||||
statements.add(While);
|
statements.add(While);
|
||||||
|
|
||||||
BlockNode resultBlock = new BlockNode();
|
BlockNode resultBlock = new BlockNode();
|
||||||
for(StatementNode statement : statements) {
|
for(IStatementNode statement : statements) {
|
||||||
resultBlock.addStatement((IStatementNode) statement);
|
resultBlock.addStatement((IStatementNode) statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
||||||
package parser.generated;
|
package parser.generated;
|
||||||
|
|
||||||
import org.antlr.v4.runtime.ParserRuleContext;
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
||||||
package parser.generated;
|
package parser.generated;
|
||||||
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
|
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
||||||
package parser.generated;
|
package parser.generated;
|
||||||
import org.antlr.v4.runtime.Lexer;
|
import org.antlr.v4.runtime.Lexer;
|
||||||
import org.antlr.v4.runtime.CharStream;
|
import org.antlr.v4.runtime.CharStream;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
||||||
package parser.generated;
|
package parser.generated;
|
||||||
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
||||||
package parser.generated;
|
package parser.generated;
|
||||||
import org.antlr.v4.runtime.atn.*;
|
import org.antlr.v4.runtime.atn.*;
|
||||||
import org.antlr.v4.runtime.dfa.DFA;
|
import org.antlr.v4.runtime.dfa.DFA;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated from C:/Users/Maxi/Documents/DHBW/Compilerbau/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
// Generated from C:/Users/janni/Desktop/NichtHaskell2.0/src/main/java/parser/grammar/SimpleJava.g4 by ANTLR 4.13.1
|
||||||
package parser.generated;
|
package parser.generated;
|
||||||
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package semantic;
|
package semantic;
|
||||||
|
|
||||||
import ast.type.type.*;
|
import ast.type.type.*;
|
||||||
import semantic.exeptions.AlreadyDeclearedException;
|
import semantic.exceptions.AlreadyDeclaredException;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
@ -16,7 +16,7 @@ public class Scope {
|
|||||||
|
|
||||||
public void addLocalVar(String name, ITypeNode type) {
|
public void addLocalVar(String name, ITypeNode type) {
|
||||||
if (this.contains(name)) {
|
if (this.contains(name)) {
|
||||||
throw new AlreadyDeclearedException("Variable " + name + " already exists in this scope");
|
throw new AlreadyDeclaredException("Variable " + name + " already exists in this scope");
|
||||||
}
|
}
|
||||||
localVars.peek().put(name, type);
|
localVars.peek().put(name, type);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
|
|||||||
import ast.statements.*;
|
import ast.statements.*;
|
||||||
import ast.type.type.*;
|
import ast.type.type.*;
|
||||||
import semantic.context.Context;
|
import semantic.context.Context;
|
||||||
import semantic.exeptions.*;
|
import semantic.exceptions.*;
|
||||||
import typechecker.TypeCheckResult;
|
import typechecker.TypeCheckResult;
|
||||||
|
|
||||||
public class SemanticAnalyzer implements SemanticVisitor {
|
public class SemanticAnalyzer implements SemanticVisitor {
|
||||||
@ -116,7 +116,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
|||||||
if (Objects.equals(otherMethod, methodNode))
|
if (Objects.equals(otherMethod, methodNode))
|
||||||
break;
|
break;
|
||||||
if (otherMethod.isSame(methodNode)) {
|
if (otherMethod.isSame(methodNode)) {
|
||||||
errors.add(new AlreadyDeclearedException(
|
errors.add(new AlreadyDeclaredException(
|
||||||
"Method " + methodNode.getIdentifier() + " is already defined in class "
|
"Method " + methodNode.getIdentifier() + " is already defined in class "
|
||||||
+ currentClass.identifier));
|
+ currentClass.identifier));
|
||||||
valid = false;
|
valid = false;
|
||||||
@ -129,8 +129,8 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
|||||||
valid = valid && result.isValid();
|
valid = valid && result.isValid();
|
||||||
try {
|
try {
|
||||||
currentScope.addLocalVar(parameter.identifier, parameter.type);
|
currentScope.addLocalVar(parameter.identifier, parameter.type);
|
||||||
} catch (AlreadyDeclearedException e) {
|
} catch (AlreadyDeclaredException e) {
|
||||||
errors.add(new AlreadyDeclearedException(parameter.identifier));
|
errors.add(new AlreadyDeclaredException(parameter.identifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
|||||||
@Override
|
@Override
|
||||||
public TypeCheckResult analyze(FieldNode toCheck) {
|
public TypeCheckResult analyze(FieldNode toCheck) {
|
||||||
if (currentFields.get(toCheck.identifier) != null) {
|
if (currentFields.get(toCheck.identifier) != null) {
|
||||||
errors.add(new AlreadyDeclearedException("Already declared " + toCheck.identifier));
|
errors.add(new AlreadyDeclaredException("Already declared " + toCheck.identifier));
|
||||||
return new TypeCheckResult(false, null);
|
return new TypeCheckResult(false, null);
|
||||||
} else {
|
} else {
|
||||||
currentFields.put(toCheck.identifier, toCheck.type);
|
currentFields.put(toCheck.identifier, toCheck.type);
|
||||||
@ -361,7 +361,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
|||||||
} else if(currentFields.get(unary.identifier) != null) {
|
} else if(currentFields.get(unary.identifier) != null) {
|
||||||
return new TypeCheckResult(valid, currentFields.get(unary.identifier));
|
return new TypeCheckResult(valid, currentFields.get(unary.identifier));
|
||||||
} else {
|
} else {
|
||||||
errors.add(new NotDeclearedException("Var is not Decleared"));
|
errors.add(new NotDeclaredException("Var is not Declared"));
|
||||||
}
|
}
|
||||||
return new TypeCheckResult(valid, null);
|
return new TypeCheckResult(valid, null);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package semantic.exceptions;
|
||||||
|
|
||||||
|
public class AlreadyDeclaredException extends RuntimeException {
|
||||||
|
|
||||||
|
public AlreadyDeclaredException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package semantic.exeptions;
|
package semantic.exceptions;
|
||||||
|
|
||||||
public class AlreadyDefinedException extends RuntimeException {
|
public class AlreadyDefinedException extends RuntimeException {
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package semantic.exeptions;
|
package semantic.exceptions;
|
||||||
|
|
||||||
public class MultipleReturnTypes extends RuntimeException {
|
public class MultipleReturnTypes extends RuntimeException {
|
||||||
|
|
@ -0,0 +1,9 @@
|
|||||||
|
package semantic.exceptions;
|
||||||
|
|
||||||
|
public class NotDeclaredException extends RuntimeException {
|
||||||
|
|
||||||
|
public NotDeclaredException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package semantic.exeptions;
|
package semantic.exceptions;
|
||||||
|
|
||||||
public class TypeMismatchException extends RuntimeException {
|
public class TypeMismatchException extends RuntimeException {
|
||||||
|
|
9
src/main/java/semantic/exceptions/UnknownException.java
Normal file
9
src/main/java/semantic/exceptions/UnknownException.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package semantic.exceptions;
|
||||||
|
|
||||||
|
public class UnknownException extends RuntimeException {
|
||||||
|
|
||||||
|
public UnknownException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
package semantic.exeptions;
|
|
||||||
|
|
||||||
public class AlreadyDeclearedException extends RuntimeException {
|
|
||||||
|
|
||||||
public AlreadyDeclearedException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package semantic.exeptions;
|
|
||||||
|
|
||||||
public class NotDeclearedException extends RuntimeException {
|
|
||||||
|
|
||||||
public NotDeclearedException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,16 +1,14 @@
|
|||||||
public class CompilerInput {
|
public class Compiler {
|
||||||
|
public int add(int i, int j) {
|
||||||
public int a;
|
return i+j;
|
||||||
|
}
|
||||||
public static int testMethod(char x){
|
}
|
||||||
return 0;
|
|
||||||
}
|
public class Node {
|
||||||
|
public void main() {
|
||||||
public class Test {
|
Compiler compiler = new Compiler();
|
||||||
|
int i = compiler.add(5, 8);
|
||||||
public static int testMethod(char x, int a){
|
return i;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,20 +10,33 @@ compile-javac:
|
|||||||
compile-raupenpiler:
|
compile-raupenpiler:
|
||||||
cd ../.. ; mvn -DskipTests install
|
cd ../.. ; mvn -DskipTests install
|
||||||
cd ../.. ; mvn exec:java -Dexec.mainClass="main.Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' "
|
cd ../.. ; mvn exec:java -Dexec.mainClass="main.Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' "
|
||||||
|
cp ../main/resources/output/CompilerInput.class .java/resources/output/raupenpiler
|
||||||
|
|
||||||
test: test-javac test-raupenpiler
|
test: compile-javac compile-raupenpiler test-javac test-raupenpiler
|
||||||
|
|
||||||
test-javac:
|
test-javac:
|
||||||
#compile-javac
|
# gleich wie bei raupenpiler, kann ich ohne funktionierenden Compiler nicht testen
|
||||||
#java -cp .\resources\output\javac CompilerInput
|
|
||||||
|
|
||||||
test-raupenpiler:
|
test-raupenpiler:
|
||||||
#java -cp .\resources\output\raupenpiler CompilerInput
|
# move the compiled class to the test/main folder
|
||||||
|
mv ../main/resources/output/CompilerInput.class .java/main/
|
||||||
|
# compile the test class
|
||||||
|
javac .java/main.EndToEndTester.java
|
||||||
|
# run the test class
|
||||||
|
java .java/main.EndToEndTester
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
# clean output folders
|
||||||
|
rm -f ../main/resources/output/*.class
|
||||||
rm -f ./resources/output/javac/*.class
|
rm -f ./resources/output/javac/*.class
|
||||||
rm -f ./resources/output/raupenpiler/*.class
|
rm -f ./resources/output/raupenpiler/*.class
|
||||||
rm -f ./java/*.class
|
# clean logs
|
||||||
rm -f ../main/resources/output/*.class
|
|
||||||
rm -f ../main/resources/logs/*.log
|
rm -f ../main/resources/logs/*.log
|
||||||
|
# clean test/main folders from .class files for End-to-End tests
|
||||||
|
rm -f ./java/main/*.class
|
||||||
|
# clean javac output from featureTests
|
||||||
|
rm -f ./resources/input/featureTests/*.class
|
||||||
|
|
||||||
|
@ -78,8 +78,8 @@ Compiled Classfile
|
|||||||
|
|
||||||
wenn beides erfolgreich
|
wenn beides erfolgreich
|
||||||
|
|
||||||
- Ergebnis vom eigenen Compiler mithilfe von main.TestCompilerOutput ausführen
|
- Ergebnis vom eigenen Compiler mithilfe von main.EndToEndTester ausführen
|
||||||
- (Ergebnis von javac mithilfe von main.TestCompilerOutput ausführen)
|
- (Ergebnis von javac mithilfe von main.EndToEndTester ausführen)
|
||||||
|
|
||||||
### Andis Tipps:
|
### Andis Tipps:
|
||||||
|
|
||||||
@ -89,4 +89,5 @@ wenn beides erfolgreich
|
|||||||
- mvn package
|
- mvn package
|
||||||
- javac tester // tester compilen
|
- javac tester // tester compilen
|
||||||
- java tester // tester ausführen
|
- java tester // tester ausführen
|
||||||
- -> tester ist in unserem Fall main.TestCompilerOutput.java
|
- -> tester ist in unserem Fall main.EndToEndTester.java
|
||||||
|
- -> Hab ich alles umgesetzt
|
@ -1,6 +0,0 @@
|
|||||||
package main;
|
|
||||||
|
|
||||||
public class EmptyClassExample {
|
|
||||||
private class Inner {
|
|
||||||
}
|
|
||||||
} // -o für outout
|
|
@ -3,18 +3,18 @@ package main;
|
|||||||
/**
|
/**
|
||||||
* This class is used to test the output of the compiler.
|
* This class is used to test the output of the compiler.
|
||||||
*
|
*
|
||||||
* <p>Im gleichen Ordner wie diese Datei (main.TestCompilerOutput.java) muss die selbst kompilierte CompilerInput.class Datei sein.
|
* <p>Im gleichen Ordner wie diese Datei (EndToEndTester.java) muss die selbst kompilierte CompilerInput.class Datei sein.
|
||||||
* <br><strong>Hinweis:</strong> Diese muss man also vom Ordner <code> main/resources/output </code> in diesen Ordner hier (test/java) rein kopieren. (bis es eine bessere Lösung gibt)</p>
|
* <br><strong>Hinweis:</strong> Diese muss man also vom Ordner <code> main/resources/output </code> in diesen Ordner hier (test/java/main) rein kopieren. (bis es eine bessere Lösung gibt -> bin grad in der Make dran das alles hier automatisch zu machen)</p>
|
||||||
*
|
*
|
||||||
* <p>Die selbst kompilierte .class Datei wird dann hier drin geladen und eine Instanz von ihr erstellt, es können auch Methoden aufgerufen werden.
|
* <p>Die selbst kompilierte .class Datei wird dann hier drin geladen und eine Instanz von ihr erstellt, es können auch Methoden aufgerufen werden.
|
||||||
* <p>Diese main.TestCompilerOutput.java Datei wird dann in <code> \src\test\java> </code> mit <code>javac .\main.TestCompilerOutput.java</code> kompiliert und mit <code>java main.TestCompilerOutput</code> ausgeführt.
|
* <p>Diese EndToEndTester.java Datei wird dann in <code> \src\test\java> </code> mit <code>javac .\main.EndToEndTester.java</code> kompiliert und mit <code>java main.EndToEndTester</code> ausgeführt.
|
||||||
* Wenn unser Compiler funktioniert, sollten keine Errors kommen (sondern nur die Ausgaben, die wir in der CompilerInput.java Datei gemacht haben,
|
* Wenn unser Compiler funktioniert, sollten keine Errors kommen (sondern nur die Ausgaben, die wir in der CompilerInput.java Datei gemacht haben,
|
||||||
* oder Methoden, die wir hier aufrufen).</p>
|
* oder Methoden, die wir hier aufrufen).</p>
|
||||||
*
|
*
|
||||||
* <p><strong>PROBLEM:</strong> Hier kommen Errors, was eigentlich heißt, dass der Compiler nicht funktioniert, der Test sollte eigentlich passen.
|
* <p><strong>PROBLEM:</strong> Hier kommen Errors, was eigentlich heißt, dass der Compiler nicht funktioniert, der Test sollte eigentlich passen.
|
||||||
* <br><strong>DENN:</strong> Wenn ich statt unserem CompilerInput.class die CompilerInput.class von javac verwende (aus <code> src/test/resources/output/javac </code>), dann funktioniert es.</p>
|
* <br><strong>DENN:</strong> Wenn ich statt unserem CompilerInput.class die CompilerInput.class von javac verwende (aus <code> src/test/resources/output/javac </code>), dann funktioniert es.</p>
|
||||||
*/
|
*/
|
||||||
public class TestCompilerOutput {
|
public class EndToEndTester {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
try {
|
try {
|
||||||
// Try to load the class named "CompilerInput"
|
// Try to load the class named "CompilerInput"
|
@ -3,71 +3,45 @@ package main;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
|
||||||
import org.antlr.v4.runtime.CharStreams;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import javax.tools.JavaCompiler;
|
import javax.tools.JavaCompiler;
|
||||||
import javax.tools.ToolProvider;
|
import javax.tools.ToolProvider;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class FailureTest {
|
public class FailureTest {
|
||||||
private static final List<String> TEST_FILES = Arrays.asList(
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass1.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass2.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass3.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass4.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass5.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass6.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass7.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass8.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass9.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass10.java",
|
|
||||||
"src/main/test/resources/input/failureTests/TestClass11.java"
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test method checks if invalid Java files fail to compile as expected.
|
* This test method checks if invalid Java files fail to compile as expected.
|
||||||
* It uses the JavaCompiler from the ToolProvider to compile the files.
|
* It uses the JavaCompiler from the ToolProvider to compile the files.
|
||||||
* The test passes if all the files fail to compile.
|
* The test passes if all the files fail to compile.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void invalidJavaFilesTest() {
|
public void areTestFilesActuallyFailTest() {
|
||||||
// Get the system Java compiler
|
// Get the system Java compiler
|
||||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
|
||||||
|
|
||||||
// Assert that the compiler is available
|
// Assert that the compiler is available
|
||||||
assertNotNull(compiler, "Java Compiler is not available");
|
assertNotNull(javac, "Java Compiler is not available");
|
||||||
|
|
||||||
// Iterate over the test files
|
String directoryPath = "src/test/resources/input/failureTests";
|
||||||
for (String fileName : TEST_FILES) {
|
File folder = new File(directoryPath);
|
||||||
// Create a File object for the current file
|
|
||||||
File file = new File(fileName);
|
|
||||||
|
|
||||||
|
if (folder.isDirectory()) {
|
||||||
|
File[] files = folder.listFiles((dir, name) -> name.endsWith(".java"));
|
||||||
|
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
// Try to compile the file and get the result
|
// Try to compile the file and get the result
|
||||||
// The run method returns 0 if the compilation was successful, and non-zero otherwise
|
// The run method returns 0 if the compilation was successful, and non-zero otherwise
|
||||||
int result = compiler.run(null, null, null, file.getPath());
|
int result = javac.run(null, null, null, file.getPath());
|
||||||
|
|
||||||
// Assert that the compilation failed (i.e., the result is non-zero)
|
// Assert that the compilation failed (i.e., the result is non-zero)
|
||||||
assertTrue(result != 0, "Expected compilation failure for " + fileName);
|
assertTrue(result != 0, "Expected compilation failure for " + file.getName());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("No files found in the directory.");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// schmeißt John Fehler, wenn namen doppelt sind?
|
System.out.println("The provided path is not a directory.");
|
||||||
// Input: ParseTree mit genanntem Fehler
|
|
||||||
// Output: Fehlermeldung
|
|
||||||
@Test
|
|
||||||
void typedASTTest() throws IOException {
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/main/EmptyClassExample.java"));
|
|
||||||
Main.compileFile(codeCharStream, "src/main/test/resources/output");
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Error reading the file: " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
46
src/test/java/main/FeatureTest.java
Normal file
46
src/test/java/main/FeatureTest.java
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package main;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import javax.tools.JavaCompiler;
|
||||||
|
import javax.tools.ToolProvider;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class FeatureTest {
|
||||||
|
/**
|
||||||
|
* This test method checks if valid Java files compile successfully.
|
||||||
|
* It uses the JavaCompiler from the ToolProvider to compile the files.
|
||||||
|
* The test passes if all the files compile without errors.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void areTestFilesActuallyValid() {
|
||||||
|
// Get the system Java compiler
|
||||||
|
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
|
||||||
|
// Assert that the compiler is available
|
||||||
|
assertNotNull(javac, "Java Compiler is not available");
|
||||||
|
|
||||||
|
String directoryPath = "src/test/resources/input/featureTests";
|
||||||
|
File folder = new File(directoryPath);
|
||||||
|
|
||||||
|
if (folder.isDirectory()) {
|
||||||
|
File[] files = folder.listFiles((dir, name) -> name.endsWith(".java"));
|
||||||
|
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
// Try to compile the file and get the result
|
||||||
|
// The run method returns 0 if the compilation was successful, and non-zero otherwise
|
||||||
|
int result = javac.run(null, null, null, file.getPath());
|
||||||
|
|
||||||
|
// Assert that the compilation succeeded (i.e., the result is zero)
|
||||||
|
assertEquals(0, result, "Expected compilation success for " + file.getName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("No files found in the directory.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("The provided path is not a directory.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,14 +7,14 @@ import org.antlr.v4.runtime.CharStreams;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* run: mvn test
|
* run every test: mvn test
|
||||||
|
* Nutzen dieser Klasse: Eigentlich nicht vorhanden, in der Main gibts nichts zu testen
|
||||||
*/
|
*/
|
||||||
public class MainTest {
|
public class MainTest {
|
||||||
@Test
|
@Test
|
||||||
void testEmptyClass() {
|
void test() {
|
||||||
CharStream codeCharStream = null;
|
CharStream codeCharStream = null;
|
||||||
try {
|
try {
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/CompilerInput.java"));
|
codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/CompilerInput.java"));
|
||||||
|
51
src/test/java/parser/AstBuilderTest.java
Normal file
51
src/test/java/parser/AstBuilderTest.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package parser;
|
||||||
|
|
||||||
|
|
||||||
|
import ast.ASTNode;
|
||||||
|
import ast.ClassNode;
|
||||||
|
import ast.ProgramNode;
|
||||||
|
import ast.members.ConstructorNode;
|
||||||
|
import ast.members.MemberNode;
|
||||||
|
import ast.type.AccessModifierNode;
|
||||||
|
import org.antlr.v4.runtime.CharStream;
|
||||||
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import parser.astBuilder.ASTBuilder;
|
||||||
|
import parser.generated.SimpleJavaLexer;
|
||||||
|
import parser.generated.SimpleJavaParser;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DisplayName("Untyped Abstract Syntax Tree")
|
||||||
|
class AstBuilderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptyClassTest(){
|
||||||
|
MemberNode constructor = new ConstructorNode(new AccessModifierNode("public"),"EmptyClass");
|
||||||
|
ClassNode emptyClass = new ClassNode("public", "EmptyClass");
|
||||||
|
emptyClass.addMember(constructor);
|
||||||
|
var expected = new ProgramNode();
|
||||||
|
expected.addClass(emptyClass);
|
||||||
|
|
||||||
|
CharStream testFile = null;
|
||||||
|
try {
|
||||||
|
testFile = CharStreams.fromFileName("src/test/resources/input/javaCases/EmptyClass.java");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
SimpleJavaLexer lexer = new SimpleJavaLexer(testFile);
|
||||||
|
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
||||||
|
tokenStream.fill();
|
||||||
|
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
||||||
|
ParseTree parseTree = parser.program();
|
||||||
|
ASTBuilder astBuilder = new ASTBuilder();
|
||||||
|
var actual = astBuilder.visit(parseTree);
|
||||||
|
|
||||||
|
assertThat(actual).isEqualToComparingFieldByFieldRecursively(expected);
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@ import org.antlr.v4.runtime.*;
|
|||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import parser.astBuilder.ASTBuilder;
|
|
||||||
import parser.generated.SimpleJavaLexer;
|
import parser.generated.SimpleJavaLexer;
|
||||||
import parser.generated.SimpleJavaParser;
|
import parser.generated.SimpleJavaParser;
|
||||||
|
|
||||||
@ -13,41 +12,13 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class ParserTest {
|
public class ParserTest {
|
||||||
|
/*
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void init() { // noch nicht benötigt
|
public void init() { // noch nicht benötigt
|
||||||
String inputFilePath = "src/main/resources/input/CompilerInput.java";
|
String inputFilePath = "src/main/resources/input/CompilerInput.java";
|
||||||
String outputDirectoryPath = "src/main/resources/output";
|
String outputDirectoryPath = "src/main/resources/output";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This test method is used to test the scanner functionality of the SimpleJavaLexer.
|
|
||||||
* It creates a CharStream from a string representing a simple Java class declaration,
|
|
||||||
* and uses the SimpleJavaLexer to tokenize this input.
|
|
||||||
* It then compares the actual tokens and their types produced by the lexer to the expected tokens and their types.
|
|
||||||
*/
|
*/
|
||||||
@Test
|
|
||||||
public void scannerTest() {
|
|
||||||
// Create a CharStream from a string representing a simple Java class declaration
|
|
||||||
CharStream inputCharStream = CharStreams.fromString("public class Name {}");
|
|
||||||
|
|
||||||
// Use the SimpleJavaLexer to tokenize the input
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
tokenStream.fill();
|
|
||||||
|
|
||||||
// Prepare the expected results
|
|
||||||
List<Token> actualTokens = tokenStream.getTokens();
|
|
||||||
List<String> expectedTokens = Arrays.asList("public", "class", "Name", "{", "}", "<EOF>");
|
|
||||||
List<String> expectedTokenTypes = Arrays.asList(null, null, "IDENTIFIER", null, null, "EOF");
|
|
||||||
|
|
||||||
// Compare the actual tokens and their types to the expected tokens and their types
|
|
||||||
assertEquals(expectedTokens.size(), actualTokens.size());
|
|
||||||
for (int i = 0; i < expectedTokens.size(); i++) {
|
|
||||||
assertEquals(expectedTokens.get(i), actualTokens.get(i).getText());
|
|
||||||
assertEquals(expectedTokenTypes.get(i), SimpleJavaLexer.VOCABULARY.getSymbolicName(actualTokens.get(i).getType()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parserTest() {
|
public void parserTest() {
|
||||||
@ -63,38 +34,20 @@ public class ParserTest {
|
|||||||
ParseTree parseTree = parser.program(); // parse the input
|
ParseTree parseTree = parser.program(); // parse the input
|
||||||
|
|
||||||
//Variante 1 (geht)
|
//Variante 1 (geht)
|
||||||
|
String expectedParseTreeAsString = "(program (classDeclaration public class Name { }))";
|
||||||
String actualParseTreeAsString = parseTree.toStringTree(parser);
|
String actualParseTreeAsString = parseTree.toStringTree(parser);
|
||||||
String expectedParseTreeAsString = "(program (classDeclaration (accessType public) class Name { }))";
|
|
||||||
|
|
||||||
assertEquals(actualParseTreeAsString, expectedParseTreeAsString);
|
assertEquals(expectedParseTreeAsString, actualParseTreeAsString);
|
||||||
|
|
||||||
//Variante 2 (geht nicht)
|
// Variante 2 (geht nicht)
|
||||||
// - Sollte es gehen und es liegt am Parser? (keine Ahnung) -> Bitte Fehler (actual und expected) durchlesen
|
// - Sollte es gehen und es liegt am Parser? (keine Ahnung) -> Bitte Fehler (actual und expected) durchlesen
|
||||||
Map<String, Object> actualTreeStructure = buildTreeStructure(parseTree, parser);
|
// ist die Methode parseStringToTree() korrekt? -> (glaub nicht)
|
||||||
Map<String, Object> expectedTreeStructure = parseStringToTree(expectedParseTreeAsString);
|
Map<String, Object> expectedTreeStructure = parseStringToTree(expectedParseTreeAsString);
|
||||||
|
Map<String, Object> actualTreeStructure = buildTreeStructure(parseTree, parser);
|
||||||
|
|
||||||
assertEquals(actualTreeStructure, expectedTreeStructure);
|
// assertEquals(expectedTreeStructure, actualTreeStructure);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void astBuilderTest() {
|
|
||||||
// TODO: Implement this test method
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* AST builder -> AST */
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
// ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
//String actualASTasString = new ASTBuilder().visit(parseTree).toString();
|
|
||||||
|
|
||||||
// ProgramNode actualAST = new ASTBuilder().visit(parseTree);
|
|
||||||
// ProgramNode expectedAST = new ProgramNode();
|
|
||||||
// expectedAST.add(new ProgramNode.ClassNode("Name", new ProgramNode()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Helpers Variante 2.1
|
// Helpers Variante 2.1
|
||||||
@ -146,7 +99,7 @@ public class ParserTest {
|
|||||||
for (char ch : input.toCharArray()) {
|
for (char ch : input.toCharArray()) {
|
||||||
if (ch == '(') {
|
if (ch == '(') {
|
||||||
if (depth == 0) {
|
if (depth == 0) {
|
||||||
if (currentToken.length() > 0) {
|
if (!currentToken.isEmpty()) {
|
||||||
node.put("node", currentToken.toString().trim());
|
node.put("node", currentToken.toString().trim());
|
||||||
currentToken.setLength(0);
|
currentToken.setLength(0);
|
||||||
}
|
}
|
||||||
@ -163,7 +116,7 @@ public class ParserTest {
|
|||||||
currentToken.append(ch);
|
currentToken.append(ch);
|
||||||
}
|
}
|
||||||
} else if (Character.isWhitespace(ch) && depth == 0) {
|
} else if (Character.isWhitespace(ch) && depth == 0) {
|
||||||
if (currentToken.length() > 0) {
|
if (!currentToken.isEmpty()) {
|
||||||
node.put("node", currentToken.toString().trim());
|
node.put("node", currentToken.toString().trim());
|
||||||
currentToken.setLength(0);
|
currentToken.setLength(0);
|
||||||
}
|
}
|
||||||
@ -172,7 +125,7 @@ public class ParserTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentToken.length() > 0) {
|
if (!currentToken.isEmpty()) {
|
||||||
node.put("node", currentToken.toString().trim());
|
node.put("node", currentToken.toString().trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
45
src/test/java/parser/ScannerTest.java
Normal file
45
src/test/java/parser/ScannerTest.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package parser;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.CharStream;
|
||||||
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.Token;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import parser.generated.SimpleJavaLexer;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class ScannerTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test method is used to test the scanner functionality of the SimpleJavaLexer.
|
||||||
|
* It creates a CharStream from a string representing a simple Java class declaration,
|
||||||
|
* and uses the SimpleJavaLexer to tokenize this input.
|
||||||
|
* It then compares the actual tokens and their types produced by the lexer to the expected tokens and their types.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void scannerTest() {
|
||||||
|
// Create a CharStream from a string representing a simple Java class declaration
|
||||||
|
CharStream inputCharStream = CharStreams.fromString("public class Name {}");
|
||||||
|
|
||||||
|
// Use the SimpleJavaLexer to tokenize the input
|
||||||
|
SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream);
|
||||||
|
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
||||||
|
tokenStream.fill();
|
||||||
|
|
||||||
|
// Prepare the expected results
|
||||||
|
List<String> expectedTokens = Arrays.asList("public", "class", "Name", "{", "}", "<EOF>");
|
||||||
|
List<String> expectedTokenTypes = Arrays.asList("AccessModifier", "Class", "Identifier", "OpenCurlyBracket", "ClosedCurlyBracket", "EOF");
|
||||||
|
List<Token> actualTokens = tokenStream.getTokens();
|
||||||
|
|
||||||
|
// Compare the actual tokens and their types to the expected tokens and their types
|
||||||
|
assertEquals(expectedTokens.size(), actualTokens.size());
|
||||||
|
for (int i = 0; i < expectedTokens.size(); i++) {
|
||||||
|
assertEquals(expectedTokens.get(i), actualTokens.get(i).getText());
|
||||||
|
assertEquals(expectedTokenTypes.get(i), SimpleJavaLexer.VOCABULARY.getSymbolicName(actualTokens.get(i).getType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,282 +0,0 @@
|
|||||||
package semantic;
|
|
||||||
|
|
||||||
import ast.ASTNode;
|
|
||||||
import ast.ProgramNode;
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
|
||||||
import org.antlr.v4.runtime.CharStreams;
|
|
||||||
import org.antlr.v4.runtime.CommonTokenStream;
|
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import parser.astBuilder.ASTBuilder;
|
|
||||||
import parser.generated.SimpleJavaLexer;
|
|
||||||
import parser.generated.SimpleJavaParser;
|
|
||||||
import semantic.exeptions.AlreadyDeclearedException;
|
|
||||||
import semantic.exeptions.MultipleReturnTypes;
|
|
||||||
import semantic.exeptions.NotDeclearedException;
|
|
||||||
import semantic.exeptions.TypeMismatchException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
public class EndToTAST {
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setup(){
|
|
||||||
SemanticAnalyzer.clearAnalyzer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CorrectTest(){
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/CorrectTest.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program(); // parse the input
|
|
||||||
|
|
||||||
/* ------------------------- AST builder -> AST ------------------------- */
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
|
|
||||||
assertEquals(SemanticAnalyzer.errors.size(), 0);
|
|
||||||
assertNotNull(tast);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void notDecleared() {
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/NotDecleared.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program(); // parse the input
|
|
||||||
|
|
||||||
/* ------------------------- AST builder -> AST ------------------------- */
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
assertFalse(SemanticAnalyzer.errors.isEmpty());
|
|
||||||
assertInstanceOf(NotDeclearedException.class, SemanticAnalyzer.errors.getFirst());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void typeMismatch(){
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/TypeMismatchIntBool.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program();
|
|
||||||
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
assertFalse(SemanticAnalyzer.errors.isEmpty());
|
|
||||||
assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void parameterAlreadyDecleared(){
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/ParameterAlreadyDecleared.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program();
|
|
||||||
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
assertFalse(SemanticAnalyzer.errors.isEmpty());
|
|
||||||
assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void fieldAlreadyDecleared(){
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/FieldAlreadyDecleared.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program();
|
|
||||||
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
assertFalse(SemanticAnalyzer.errors.isEmpty());
|
|
||||||
assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void typeMismatchRefType(){
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/TypeMismatchRefType.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program();
|
|
||||||
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
assertFalse(SemanticAnalyzer.errors.isEmpty());
|
|
||||||
assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void correctRetType(){
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/CorrectRetType.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program();
|
|
||||||
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
assertTrue(SemanticAnalyzer.errors.isEmpty());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void retTypeMismatch(){
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/retTypeMismatch.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program();
|
|
||||||
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
assertFalse(SemanticAnalyzer.errors.isEmpty());
|
|
||||||
assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void multipleRetType(){
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/MultipleRetTypes.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program();
|
|
||||||
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
assertFalse(SemanticAnalyzer.errors.isEmpty());
|
|
||||||
assertInstanceOf(MultipleReturnTypes.class, SemanticAnalyzer.errors.getFirst());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void wrongTypeInIfClause(){
|
|
||||||
|
|
||||||
CharStream codeCharStream = null;
|
|
||||||
try {
|
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/WrongIfClause.java"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
|
||||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
|
||||||
|
|
||||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
|
||||||
ParseTree parseTree = parser.program();
|
|
||||||
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
|
||||||
|
|
||||||
ASTNode tast = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
|
|
||||||
assertFalse(SemanticAnalyzer.errors.isEmpty());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
218
src/test/java/semantic/EndToTypedAstTest.java
Normal file
218
src/test/java/semantic/EndToTypedAstTest.java
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
package semantic;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.CharStream;
|
||||||
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
|
||||||
|
import ast.ASTNode;
|
||||||
|
import ast.ProgramNode;
|
||||||
|
|
||||||
|
import parser.astBuilder.ASTBuilder;
|
||||||
|
import parser.generated.SimpleJavaLexer;
|
||||||
|
import parser.generated.SimpleJavaParser;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class EndToTypedAstTest {
|
||||||
|
private static final Map<String, Class<?>> exceptionMap = new HashMap<>();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exceptionsTest() {
|
||||||
|
String directoryPath = "src/test/resources/input/typedAstExceptionsTests";
|
||||||
|
File folder = new File(directoryPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
loadCustomExceptions();
|
||||||
|
System.out.println("Custom exceptions loaded successfully.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to load custom exceptions", e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (folder.isDirectory()) {
|
||||||
|
File[] files = folder.listFiles((_, name) -> name.endsWith(".java"));
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
String expectedException = extractExpectedException(file);
|
||||||
|
|
||||||
|
SemanticAnalyzer.clearAnalyzer();
|
||||||
|
CharStream codeCharStream;
|
||||||
|
try {
|
||||||
|
codeCharStream = CharStreams.fromPath(Paths.get(file.getPath()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
||||||
|
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
||||||
|
|
||||||
|
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
||||||
|
ParseTree parseTree = parser.program();
|
||||||
|
|
||||||
|
ASTBuilder astBuilder = new ASTBuilder();
|
||||||
|
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
||||||
|
|
||||||
|
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
||||||
|
|
||||||
|
if (expectedException != null) {
|
||||||
|
System.out.println("Testing the file: " + file.getName());
|
||||||
|
assertFalse(SemanticAnalyzer.errors.isEmpty(), "Expected an exception, but none was found.");
|
||||||
|
assertInstanceOf(getExceptionClass(expectedException), SemanticAnalyzer.errors.getFirst());
|
||||||
|
} else {
|
||||||
|
System.out.println("No expected exception specified.");
|
||||||
|
// If no expected exception is specified, you might want to add a different check
|
||||||
|
// e.g., assertTrue(SemanticAnalyzer.errors.isEmpty(), "No exceptions expected, but some were found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("No files found in the directory.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("The provided path is not a directory.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void featureTest(){
|
||||||
|
String directoryPath = "src/test/resources/input/typedAstFeaturesTests";
|
||||||
|
File folder = new File(directoryPath);
|
||||||
|
if (folder.isDirectory()) {
|
||||||
|
File[] files = folder.listFiles((_, name) -> name.endsWith(".java"));
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
SemanticAnalyzer.clearAnalyzer();
|
||||||
|
CharStream codeCharStream;
|
||||||
|
try {
|
||||||
|
codeCharStream = CharStreams.fromPath(Paths.get(file.getPath()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
||||||
|
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
||||||
|
|
||||||
|
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
||||||
|
ParseTree parseTree = parser.program();
|
||||||
|
|
||||||
|
ASTBuilder astBuilder = new ASTBuilder();
|
||||||
|
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
|
||||||
|
|
||||||
|
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
||||||
|
|
||||||
|
System.out.println("Testing the file: " + file.getName());
|
||||||
|
assertTrue(SemanticAnalyzer.errors.isEmpty());
|
||||||
|
assertNotNull(typedAst);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("No files found in the directory.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("The provided path is not a directory.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------ Helpers ------------------
|
||||||
|
/**
|
||||||
|
* This method is used to extract the expected exception from a given file.
|
||||||
|
* It reads the file line by line and uses a regular expression to match the expected exception annotation.
|
||||||
|
* The expected exception annotation should be in the format: "// @expected: ExceptionName".
|
||||||
|
* If the expected exception annotation is found, it returns the name of the expected exception.
|
||||||
|
* If the expected exception annotation is not found, it returns null.
|
||||||
|
*
|
||||||
|
* @param file The file from which the expected exception is to be extracted.
|
||||||
|
* @return The name of the expected exception, or null if the expected exception annotation is not found.
|
||||||
|
*/
|
||||||
|
private String extractExpectedException(File file) {
|
||||||
|
String annotationPattern = "//\\s*@expected:\\s*(\\S+)";
|
||||||
|
Pattern pattern = Pattern.compile(annotationPattern);
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
Matcher matcher = pattern.matcher(line);
|
||||||
|
if (matcher.find()) {
|
||||||
|
return matcher.group(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is used to retrieve the Class object associated with a given exception name.
|
||||||
|
* It first prints the original exception name, then appends the package name to the exception name and prints it.
|
||||||
|
* It then retrieves the Class object from the exceptionMap using the fully qualified exception name.
|
||||||
|
* If the Class object is not found in the exceptionMap, it throws a RuntimeException.
|
||||||
|
*
|
||||||
|
* @param exceptionName The name of the exception for which the Class object is to be retrieved.
|
||||||
|
* @return The Class object associated with the given exception name.
|
||||||
|
* @throws RuntimeException If the Class object for the given exception name is not found in the exceptionMap.
|
||||||
|
*/
|
||||||
|
private Class<?> getExceptionClass(String exceptionName) {
|
||||||
|
System.out.println(exceptionName);
|
||||||
|
exceptionName = "semantic.exceptions." + exceptionName;
|
||||||
|
System.out.println(exceptionName);
|
||||||
|
Class<?> exceptionClass = exceptionMap.get(exceptionName);
|
||||||
|
if (exceptionClass == null) {
|
||||||
|
throw new RuntimeException("Exception class not found: " + exceptionName);
|
||||||
|
}
|
||||||
|
return exceptionClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is used to load custom exceptions from a specified package.
|
||||||
|
* It first constructs the directory path from the package name and checks if the directory exists.
|
||||||
|
* If the directory does not exist, it throws an IllegalArgumentException.
|
||||||
|
* It then creates a URLClassLoader to load the classes from the directory.
|
||||||
|
* It iterates over all the files in the directory, and for each file, it constructs the class name and loads the class.
|
||||||
|
* If the loaded class is a subtype of Throwable, it adds the class to the exceptionMap.
|
||||||
|
*
|
||||||
|
* @throws Exception If any error occurs during class loading.
|
||||||
|
*/
|
||||||
|
private static void loadCustomExceptions() throws Exception {
|
||||||
|
final String packName = "semantic.exceptions";
|
||||||
|
final String dirForMyClasses = "src/main/java/%s".formatted(packName.replace(".", "/"));
|
||||||
|
File folder = new File(dirForMyClasses);
|
||||||
|
if (!folder.isDirectory()) {
|
||||||
|
throw new IllegalArgumentException("The provided path is not a directory.");
|
||||||
|
}
|
||||||
|
|
||||||
|
URL[] urls = {folder.toURI().toURL()};
|
||||||
|
URLClassLoader classLoader;
|
||||||
|
try {
|
||||||
|
classLoader = new URLClassLoader(urls);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to create class loader", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (File file : Objects.requireNonNull(folder.listFiles())) {
|
||||||
|
String className = packName + "." + file.getName().replaceAll("\\.(?:class|java)$", "");
|
||||||
|
System.out.printf("Loading custom exception: %s (=> %s)", file.getName(), className);
|
||||||
|
Class<?> cls = classLoader.loadClass(className);
|
||||||
|
|
||||||
|
if (Throwable.class.isAssignableFrom(cls)) { // Check if the class is a subtype of Throwable
|
||||||
|
exceptionMap.put(className, cls);
|
||||||
|
System.out.println("Loaded custom exception: " + className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,5 @@
|
|||||||
package semantic;
|
package semantic;
|
||||||
|
|
||||||
import ast.*;
|
|
||||||
import ast.members.FieldNode;
|
|
||||||
import ast.members.MemberNode;
|
|
||||||
import ast.members.MethodNode;
|
|
||||||
import ast.parameters.ParameterNode;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import semantic.exeptions.AlreadyDeclearedException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
public class SemanticTest {
|
public class SemanticTest {
|
||||||
|
|
||||||
|
|
||||||
@ -35,7 +22,7 @@ public class SemanticTest {
|
|||||||
// ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
// ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
||||||
//
|
//
|
||||||
// assertEquals(1, SemanticAnalyzer.errors.size());
|
// assertEquals(1, SemanticAnalyzer.errors.size());
|
||||||
// assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst());
|
// assertInstanceOf(AlreadyDeclaredException.class, SemanticAnalyzer.errors.getFirst());
|
||||||
// assertNull(typedAst);
|
// assertNull(typedAst);
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
package resources;
|
|
||||||
|
|
||||||
public class AllFeaturesClassExample {
|
public class AllFeaturesClassExample {
|
||||||
int a;
|
int a;
|
||||||
boolean b;
|
boolean b;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
package resources;
|
|
||||||
|
|
||||||
public class CombinedExample {
|
public class CombinedExample {
|
||||||
int number;
|
int number;
|
||||||
boolean flag;
|
boolean flag;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
package resources;
|
|
||||||
|
|
||||||
public class MoreFeaturesClassExample {
|
public class MoreFeaturesClassExample {
|
||||||
int hallo;
|
int hallo;
|
||||||
private class Inner {
|
private class Inner {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
package resources.featureTests;
|
|
||||||
|
|
||||||
public class BooleanOperations {
|
public class BooleanOperations {
|
||||||
boolean flag;
|
boolean flag;
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
package resources.featureTests;
|
|
||||||
|
|
||||||
public class CharManipulation {
|
public class CharManipulation {
|
||||||
char letter;
|
char letter;
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
package resources.featureTests;
|
|
||||||
|
|
||||||
public class ConditionalStatements {
|
public class ConditionalStatements {
|
||||||
int number;
|
int number;
|
||||||
|
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
public class EmptyClassExample {
|
||||||
|
}
|
@ -1,5 +1,3 @@
|
|||||||
package resources.featureTests;
|
|
||||||
|
|
||||||
public class LoopExamples {
|
public class LoopExamples {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// For loop example
|
// For loop example
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
package resources.featureTests;
|
|
||||||
|
|
||||||
public class MethodOverloading {
|
public class MethodOverloading {
|
||||||
public int add(int a, int b) {
|
public int add(int a, int b) {
|
||||||
return a + b;
|
return a + b;
|
||||||
|
1
src/test/resources/input/javaCases/EmptyClass.java
Normal file
1
src/test/resources/input/javaCases/EmptyClass.java
Normal file
@ -0,0 +1 @@
|
|||||||
|
class EmptyClass { }
|
7
src/test/resources/input/javaCases/MultipleClasses.java
Normal file
7
src/test/resources/input/javaCases/MultipleClasses.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
class EmptyClass1{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmptyClass2{
|
||||||
|
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
// @expected: AlreadyDeclaredException
|
||||||
public class Example {
|
public class Example {
|
||||||
|
|
||||||
public int a;
|
public int a;
|
@ -1,3 +1,4 @@
|
|||||||
|
// @expected: MultipleReturnTypes
|
||||||
public class Example {
|
public class Example {
|
||||||
|
|
||||||
public static int testMethod(int x, char c){
|
public static int testMethod(int x, char c){
|
@ -1,3 +1,4 @@
|
|||||||
|
// @expected: NotDeclaredException
|
||||||
public class Test {
|
public class Test {
|
||||||
public static int testMethod(int x){
|
public static int testMethod(int x){
|
||||||
int a = b;
|
int a = b;
|
@ -1,3 +1,4 @@
|
|||||||
|
// @expected: AlreadyDeclaredException
|
||||||
public class Example {
|
public class Example {
|
||||||
|
|
||||||
public static int testMethod(char a, int a){
|
public static int testMethod(char a, int a){
|
@ -1,3 +1,4 @@
|
|||||||
|
// @expected: TypeMismatchException
|
||||||
public class Example {
|
public class Example {
|
||||||
|
|
||||||
public static int testMethod(char x){
|
public static int testMethod(char x){
|
@ -1,3 +1,4 @@
|
|||||||
|
// @expected: TypeMismatchException
|
||||||
public class Test {
|
public class Test {
|
||||||
|
|
||||||
public boolean b;
|
public boolean b;
|
@ -1,3 +1,4 @@
|
|||||||
|
// @expected: TypeMismatchException
|
||||||
public class Test {
|
public class Test {
|
||||||
|
|
||||||
public static int testMethod(ExampleA exampleA, ExampleB exampleB){
|
public static int testMethod(ExampleA exampleA, ExampleB exampleB){
|
@ -1,3 +1,4 @@
|
|||||||
|
// @expected: TypeMismatchException
|
||||||
public class Example {
|
public class Example {
|
||||||
|
|
||||||
public static void testMethod(int x){
|
public static void testMethod(int x){
|
Loading…
Reference in New Issue
Block a user