diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml new file mode 100644 index 0000000..96ab991 --- /dev/null +++ b/.gitea/workflows/test.yml @@ -0,0 +1,15 @@ +name: Gitea Actions Demo +run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀 +on: [push] + +jobs: + Explore-Gitea-Actions: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + - name: Run the Maven verify phase + run: mvn --batch-mode --update-snapshots verify \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index f26d89f..bb14756 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -40,7 +40,7 @@ - + \ No newline at end of file diff --git a/src/main/java/Main.java b/src/main/java/Main.java index a4c274d..94d29cf 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -1,18 +1,21 @@ import ast.ASTNode; -import ast.ClassNode; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.Token; import ast.ProgramNode; import bytecode.ByteCodeGenerator; 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.antlr.v4.runtime.CommonTokenStream; import parser.ASTBuilder; import parser.generated.SimpleJavaLexer; import parser.generated.SimpleJavaParser; import semantic.SemanticAnalyzer; +import bytecode.ByteCodeGenerator; import java.io.IOException; import java.nio.file.Paths; +import java.util.List; public class Main { public static void main(String[] args) throws Exception { @@ -30,20 +33,103 @@ public class Main { static void parseFile(CharStream codeCharStream) { + /* ------------------------- Scanner -> tokens ------------------------- */ SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); - CommonTokenStream tokens = new CommonTokenStream(lexer); - SimpleJavaParser parser = new SimpleJavaParser(tokens); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); - ParseTree tree = parser.program(); // parse the input + // Printing the tokens +// tokenStream.fill(); +// List tokens = tokenStream.getTokens(); +// System.out.println("-------------------- Scanner -> tokens --------------------"); +// for (Token token : tokens) { +// String tokenType = SimpleJavaLexer.VOCABULARY.getSymbolicName(token.getType()); +// String tokenText = token.getText(); +// // System.out.println("Token Type: " + tokenType + ", Token Text: " + +// // tokenText); +// System.out.println(tokenType + " " + tokenText); +// } +// System.out.println(); - ASTBuilder builder = new ASTBuilder(); - ProgramNode ast = (ProgramNode) builder.visit(tree); // build the AST + /* ------------------------- Parser -> Parsetree ------------------------- */ + SimpleJavaParser parser = new SimpleJavaParser(tokenStream); + ParseTree parseTree = parser.program(); // parse the input - ProgramNode typedAst = (ProgramNode) SemanticAnalyzer.generateTast(ast); + // Printing the parse tree +// System.out.println("-------------------- Parser -> Parsetree --------------------"); +// System.out.println(parseTree.toStringTree(parser)); +// printTree(parseTree, parser, 0); +// System.out.println(); + /* ------------------------- AST builder -> AST ------------------------- */ + ASTBuilder astBuilder = new ASTBuilder(); + ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree); + + // Printing the AST +// System.out.println("-------------------- AST builder -> AST --------------------"); +// // System.out.println("AST: " + ast.toString()); +// printAST(abstractSyntaxTree, 0); +// System.out.println(); + + /* + * ------------------------- Semantic Analyzer -> Tast ------------------------- + */ + SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer(); + ProgramNode typedAst = (ProgramNode) semanticAnalyzer.generateTast(abstractSyntaxTree); + + // Printing the Tast + System.out.println("Tast generated"); + + /* + * ------------------------- Bytecode Generator -> Bytecode + * ------------------------- + */ ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(); - if (typedAst != null) - byteCodeGenerator.visit(typedAst); + //byteCodeGenerator.generateByteCode(abstractSyntaxTree); + byteCodeGenerator.visit(typedAst); + System.out.println("Bytecode generated"); + + } + + /** + * This method is used to print the parse tree in a structured format. + * It recursively traverses the tree and prints the rule names and text of the + * nodes. + * + * @param tree The parse tree to be printed. + * @param parser The parser used to parse the input. It's used to get the rule + * names. + * @param indent The current indentation level. It's used to format the output. + */ + public static void printTree(ParseTree tree, Parser parser, int indent) { + // Create an indentation string based on the current indentation level + String indentString = " ".repeat(indent * 2); + + // If the tree node is an instance of RuleContext (i.e., it's an internal node), + // print the rule name + if (tree instanceof RuleContext) { + int ruleIndex = ((RuleContext) tree).getRuleIndex(); + String ruleName = parser.getRuleNames()[ruleIndex]; + System.out.println(indentString + ruleName); + } else { + // If the tree node is not an instance of RuleContext (i.e., it's a leaf node), + // print the text of the node + System.out.println(indentString + tree.getText()); + } + + // Recursively print the children of the current node, increasing the + // indentation level + for (int i = 0; i < tree.getChildCount(); i++) { + printTree(tree.getChild(i), parser, indent + 1); + } + } + + public static void printAST(ASTNode node, int indent) { + String indentString = " ".repeat(indent * 2); + System.out.println(indentString + node.getClass().toString()); + + // for (ASTNode child : node.) { + // printAST(child, indent + 1); + // } } } \ No newline at end of file diff --git a/src/main/java/ast/ASTNode.java b/src/main/java/ast/ASTNode.java index 9944050..3ef48fa 100644 --- a/src/main/java/ast/ASTNode.java +++ b/src/main/java/ast/ASTNode.java @@ -1,7 +1,12 @@ package ast; -public interface ASTNode { +//import java.util.List; +public interface ASTNode { + /** + * Please implement this method to return a list of children of each node. + */ + // public List getChildren(); } diff --git a/src/main/java/ast/VarNode.java b/src/main/java/ast/VarNode.java deleted file mode 100644 index 9349eb4..0000000 --- a/src/main/java/ast/VarNode.java +++ /dev/null @@ -1,29 +0,0 @@ -package ast; - -import semantic.SemanticVisitor; -import typechecker.TypeCheckResult; -import visitor.Visitable; - -public class VarNode implements ASTNode, Visitable { - - private String identifier; - private String type; - - public VarNode(String type, String identifier){ - this.type = type; - this.identifier = identifier; - } - - public String getType(){ - return type; - } - - public String getIdentifier(){ - return identifier; - } - - @Override - public TypeCheckResult accept(SemanticVisitor visitor) { - return visitor.analyze(this); - } -} diff --git a/src/main/java/ast/expression/BinaryExpressionNode.java b/src/main/java/ast/expression/BinaryExpressionNode.java index c912408..e4a0e41 100644 --- a/src/main/java/ast/expression/BinaryExpressionNode.java +++ b/src/main/java/ast/expression/BinaryExpressionNode.java @@ -7,9 +7,9 @@ import visitor.Visitable; public class BinaryExpressionNode implements ExpressionNode, Visitable { public ExpressionNode left; public ExpressionNode right; - public String operator; // Stores the operator as a string (e.g., "+", "-", "&&") + public ExpresssionOperator operator; // Stores the operator as a string (e.g., "+", "-", "&&") - public BinaryExpressionNode(ExpressionNode left, ExpressionNode right, String operator) { + public BinaryExpressionNode(ExpressionNode left, ExpressionNode right, ExpresssionOperator operator) { this.left = left; this.right = right; this.operator = operator; diff --git a/src/main/java/ast/expression/ExpresssionOperator.java b/src/main/java/ast/expression/ExpresssionOperator.java new file mode 100644 index 0000000..b1f62a3 --- /dev/null +++ b/src/main/java/ast/expression/ExpresssionOperator.java @@ -0,0 +1,14 @@ +package ast.expression; + +public enum ExpresssionOperator { + DOT, // . + PLUS, // + + MINUS, // - + MULTIPLY, // * + DIVIDE, // / + NOT, // ! + ASSIGNMENT, // = + EQUALS, // == + UNEQUALS, // != + ERROR //TODO: Remove This +} diff --git a/src/main/java/ast/expression/UnaryExpressionNode.java b/src/main/java/ast/expression/UnaryExpressionNode.java index 24d1832..be1a660 100644 --- a/src/main/java/ast/expression/UnaryExpressionNode.java +++ b/src/main/java/ast/expression/UnaryExpressionNode.java @@ -18,3 +18,5 @@ public class UnaryExpressionNode implements ExpressionNode, Visitable { return visitor.analyze(this); } } + + diff --git a/src/main/java/ast/statement/AssignmentStatementNode.java b/src/main/java/ast/statement/AssignmentStatementNode.java index 9f6a395..f9fd38e 100644 --- a/src/main/java/ast/statement/AssignmentStatementNode.java +++ b/src/main/java/ast/statement/AssignmentStatementNode.java @@ -1,17 +1,14 @@ package ast.statement; -import ast.VarNode; -import ast.expression.ExpressionNode; +import ast.expression.BinaryExpressionNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; import visitor.Visitable; public class AssignmentStatementNode extends StatementNode implements Visitable { - public VarNode varNode; - public ExpressionNode expression; + public BinaryExpressionNode expression; - public AssignmentStatementNode(VarNode varNode, ExpressionNode expression) { - this.varNode = varNode; + public AssignmentStatementNode(BinaryExpressionNode expression) { this.expression = expression; } diff --git a/src/main/java/classFileOutput/Example.class b/src/main/java/classFileOutput/Example.class index 925c770..522ae9e 100644 Binary files a/src/main/java/classFileOutput/Example.class and b/src/main/java/classFileOutput/Example.class differ diff --git a/src/main/java/parser/ASTBuilder.java b/src/main/java/parser/ASTBuilder.java index ff41738..0f3b09c 100644 --- a/src/main/java/parser/ASTBuilder.java +++ b/src/main/java/parser/ASTBuilder.java @@ -3,6 +3,7 @@ package parser; import ast.*; import ast.expression.BinaryExpressionNode; import ast.expression.ExpressionNode; +import ast.expression.ExpresssionOperator; import ast.expression.IdentifierExpressionNode; import ast.expression.UnaryExpressionNode; import ast.member.FieldNode; @@ -137,14 +138,14 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitAssignmentStatement(SimpleJavaParser.AssignmentStatementContext ctx) { - VarNode varNode = (VarNode) visit(ctx.var()); - ExpressionNode expression = (ExpressionNode) visit(ctx.expression()); - return new AssignmentStatementNode(varNode, expression); + + BinaryExpressionNode expression = (BinaryExpressionNode) visit(ctx.expression()); + return new AssignmentStatementNode(expression); } @Override public ASTNode visitVar(SimpleJavaParser.VarContext ctx) { - return new VarNode("int", ctx.getText()); + return null; } @Override @@ -180,8 +181,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { if (ctx.getChildCount() == 3 && ctx.getChild(1) instanceof TerminalNode) { ExpressionNode left = (ExpressionNode) visit(ctx.expression(0)); ExpressionNode right = (ExpressionNode) visit(ctx.expression(1)); - String operator = ctx.getChild(1).getText(); - return new BinaryExpressionNode(left, right, operator); + return new BinaryExpressionNode(left, right, ExpresssionOperator.ERROR); } // Handle unary operations else if (ctx.getChildCount() == 2) { diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index e6cdc99..9ccfe98 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -22,12 +22,12 @@ import typechecker.TypeCheckResult; public class SemanticAnalyzer implements SemanticVisitor { - private ArrayList currentFields = new ArrayList<>(); + private static ArrayList currentFields = new ArrayList<>(); public static ArrayList errors = new ArrayList<>(); - private Scope currentScope; - private ClassNode currentClass; + private static Scope currentScope; + private static ClassNode currentClass; public static ASTNode generateTast(ASTNode node) { SemanticAnalyzer semanticCheck = new SemanticAnalyzer(); @@ -43,6 +43,13 @@ public class SemanticAnalyzer implements SemanticVisitor { return null; } + public static void clearAnalyzier(){ + currentFields.clear(); + errors.clear(); + currentScope = null; + currentClass = null; + } + @Override public TypeCheckResult analyze(ProgramNode node) { @@ -138,21 +145,17 @@ public class SemanticAnalyzer implements SemanticVisitor { @Override public TypeCheckResult analyze(AssignmentStatementNode assignmentStatementNode) { - if (assignmentStatementNode.expression instanceof LiteralNode literalNode) { - TypeCheckResult varResult = assignmentStatementNode.varNode.accept(this); - TypeCheckResult expressionResult = assignmentStatementNode.expression.accept(this); - } - return new TypeCheckResult(true, null); - } - - @Override - public TypeCheckResult analyze(VarNode toCheck) { - return new TypeCheckResult(true, null); + boolean valid = true; + BinaryExpressionNode binaryExpressionNode = assignmentStatementNode.expression; + var result = binaryExpressionNode.accept(this); + valid = valid && result.isValid(); + return new TypeCheckResult(valid, null); } @Override public TypeCheckResult analyze(BinaryExpressionNode toCheck) { - return null; + boolean valid = true; + return new TypeCheckResult(valid, null); } @Override diff --git a/src/main/java/semantic/SemanticVisitor.java b/src/main/java/semantic/SemanticVisitor.java index 99d0cb8..66db83e 100644 --- a/src/main/java/semantic/SemanticVisitor.java +++ b/src/main/java/semantic/SemanticVisitor.java @@ -3,7 +3,6 @@ package semantic; import ast.ClassNode; import ast.ProgramNode; -import ast.VarNode; import ast.expression.BinaryExpressionNode; import ast.expression.IdentifierExpressionNode; import ast.expression.UnaryExpressionNode; @@ -24,8 +23,6 @@ public interface SemanticVisitor { TypeCheckResult analyze(AssignmentStatementNode toCheck); - TypeCheckResult analyze(VarNode toCheck); - TypeCheckResult analyze(BinaryExpressionNode toCheck); TypeCheckResult analyze(IdentifierExpressionNode toCheck); diff --git a/src/main/resources/CompilerInput.java b/src/main/resources/CompilerInput.java index 2efd50e..1cbe5ca 100644 --- a/src/main/resources/CompilerInput.java +++ b/src/main/resources/CompilerInput.java @@ -2,9 +2,17 @@ public class Example { public int a; - public static int testMethod(char x, int a){ - + public static int testMethod(char x){ } +} + +public class Test { + + public static int testMethod(char x, int a){ + + + + } } \ No newline at end of file diff --git a/src/main/test/java/TestSpecs.md b/src/main/test/TestSpecs.md similarity index 89% rename from src/main/test/java/TestSpecs.md rename to src/main/test/TestSpecs.md index f459ee6..6fd5a41 100644 --- a/src/main/test/java/TestSpecs.md +++ b/src/main/test/TestSpecs.md @@ -17,6 +17,12 @@ ## Scanner Output ### Beispiel 1: Empty Class +Token Type; Token Text +Type gibts nur bei Terminalen, Text bei allen + + [null "public", null "class", IDENTIFIER "Name", null "{", null "}", EOF ""] + + Bsp von Ihm mal: [TokPublic,TokClass,TokIdentifier "Name",TokLeftBrace,TokRightBrace] ### Beispiel 2: Filled Class diff --git a/src/main/test/java/EmptyClassExample.class b/src/main/test/java/EmptyClassExample.class new file mode 100644 index 0000000..7a73bad Binary files /dev/null and b/src/main/test/java/EmptyClassExample.class differ diff --git a/src/main/test/java/EmptyClassExample.java b/src/main/test/java/EmptyClassExample.java index 290e747..9f54ec6 100644 --- a/src/main/test/java/EmptyClassExample.java +++ b/src/main/test/java/EmptyClassExample.java @@ -1,4 +1,4 @@ public class EmptyClassExample { private class Inner { } -} \ No newline at end of file +} // -o für outout \ No newline at end of file diff --git a/src/main/test/java/FailureTest.java b/src/main/test/java/FailureTest.java new file mode 100644 index 0000000..bc63d91 --- /dev/null +++ b/src/main/test/java/FailureTest.java @@ -0,0 +1,72 @@ +import static org.junit.jupiter.api.Assertions.assertNotNull; +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 javax.tools.JavaCompiler; +import javax.tools.ToolProvider; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +public class FailureTest { + private static final List TEST_FILES = Arrays.asList( + "src/main/test/resources/failureTests/TestClass1.java", + "src/main/test/resources/failureTests/TestClass2.java", + "src/main/test/resources/failureTests/TestClass3.java", + "src/main/test/resources/failureTests/TestClass4.java", + "src/main/test/resources/failureTests/TestClass5.java", + "src/main/test/resources/failureTests/TestClass6.java", + "src/main/test/resources/failureTests/TestClass7.java", + "src/main/test/resources/failureTests/TestClass8.java", + "src/main/test/resources/failureTests/TestClass9.java", + "src/main/test/resources/failureTests/TestClass10.java", + "src/main/test/resources/failureTests/TestClass11.java" + ); + + /** + * This test method checks if invalid Java files fail to compile as expected. + * It uses the JavaCompiler from the ToolProvider to compile the files. + * The test passes if all the files fail to compile. + */ + @Test + public void invalidJavaFilesTest() { + // Get the system Java compiler + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + + // Assert that the compiler is available + assertNotNull(compiler, "Java Compiler is not available"); + + // Iterate over the test files + for (String fileName : TEST_FILES) { + // Create a File object for the current file + File file = new File(fileName); + + // 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 = compiler.run(null, null, null, file.getPath()); + + // Assert that the compilation failed (i.e., the result is non-zero) + assertTrue(result != 0, "Expected compilation failure for " + fileName); + } + } + + // schmeißt John Fehler, wenn namen doppelt sind? + // 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/EmptyClassExample.java")); + Main.parsefile(codeCharStream); + } catch (IOException e) { + System.err.println("Error reading the file: " + e.getMessage()); + } + } +} + diff --git a/src/main/test/java/MainTest.java b/src/main/test/java/MainTest.java index 234add6..f9e848e 100644 --- a/src/main/test/java/MainTest.java +++ b/src/main/test/java/MainTest.java @@ -21,7 +21,7 @@ public class MainTest { void testEmptyClass() { CharStream codeCharStream = null; try { - codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/java/EmptyClassExample.java")); + codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/EmptyClassExample.java")); Main.parsefile(codeCharStream); } catch (IOException e) { System.err.println("Error reading the file: " + e.getMessage()); diff --git a/src/main/test/java/Tester.java b/src/main/test/java/Tester.java index b0e86c8..777c50b 100644 --- a/src/main/test/java/Tester.java +++ b/src/main/test/java/Tester.java @@ -1,5 +1,11 @@ public class Tester { public static void main(String[] args) { - new EmptyClassExample(); + new EmptyClassExample(); + // cp mitgeben } } +// java -jar pfadtocompiler.jar EmptyClass.java +//mit bash scipt ode rmakefile test automatisieren +//mvn package +// javac tester // tester compilen +// java tester // tester ausführen \ No newline at end of file diff --git a/src/main/test/java/make.md b/src/main/test/java/make.md new file mode 100644 index 0000000..e69de29 diff --git a/src/main/test/java/AllFeaturesClassExample.java b/src/main/test/resources/AllFeaturesClassExample.java similarity index 98% rename from src/main/test/java/AllFeaturesClassExample.java rename to src/main/test/resources/AllFeaturesClassExample.java index 1a8493d..69ab631 100644 --- a/src/main/test/java/AllFeaturesClassExample.java +++ b/src/main/test/resources/AllFeaturesClassExample.java @@ -1,3 +1,5 @@ +package resources; + public class AllFeaturesClassExample { int a; boolean b; diff --git a/src/main/test/resources/CombinedExample.java b/src/main/test/resources/CombinedExample.java new file mode 100644 index 0000000..e3dae84 --- /dev/null +++ b/src/main/test/resources/CombinedExample.java @@ -0,0 +1,25 @@ +package resources; + +public class CombinedExample { + int number; + boolean flag; + char letter; + + public CombinedExample(int number, boolean flag, char letter) { + this.number = number; + this.flag = flag; + this.letter = letter; + } + + public void displayValues() { + System.out.println("Number: " + number); + System.out.println("Flag: " + flag); + System.out.println("Letter: " + letter); + } + + public static void main(String[] args) { + CombinedExample obj = new CombinedExample(10, true, 'X'); + obj.displayValues(); + } +} + diff --git a/src/main/test/java/MoreFeaturesClassExample.java b/src/main/test/resources/MoreFeaturesClassExample.java similarity index 84% rename from src/main/test/java/MoreFeaturesClassExample.java rename to src/main/test/resources/MoreFeaturesClassExample.java index 4f6fbf3..c58b5a2 100644 --- a/src/main/test/java/MoreFeaturesClassExample.java +++ b/src/main/test/resources/MoreFeaturesClassExample.java @@ -1,3 +1,5 @@ +package resources; + public class MoreFeaturesClassExample { int hallo; private class Inner { diff --git a/src/main/test/resources/failureTests/TestClass1.java b/src/main/test/resources/failureTests/TestClass1.java new file mode 100644 index 0000000..10001a9 --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass1.java @@ -0,0 +1,6 @@ +// Syntax Error: Missing semicolon +public class TestClass1 { + public static void main(String[] args) { + System.out.println("Hello, World!") // Missing semicolon here + } +} diff --git a/src/main/test/resources/failureTests/TestClass10.java b/src/main/test/resources/failureTests/TestClass10.java new file mode 100644 index 0000000..9ed631e --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass10.java @@ -0,0 +1,10 @@ +// Semantic Error: Non-static method called from static context +public class TestClass10 { + public static void main(String[] args) { + greet(); // Non-static method 'greet' cannot be referenced from a static context + } + + public void greet() { + System.out.println("Hi!"); + } +} diff --git a/src/main/test/resources/failureTests/TestClass11.java b/src/main/test/resources/failureTests/TestClass11.java new file mode 100644 index 0000000..c944035 --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass11.java @@ -0,0 +1,10 @@ +//Compile error: (4, 9) java: variable number is already defined in method main(java.lang.String[]) +public class TestClass10 { + public static void main(String[] args) { + // Declare and initialize an integer variable named 'number' with the value 12 + int number = 12; + + // This line will cause a compile-time error because 'number' is already defined in this scope + int number =13; + } +} \ No newline at end of file diff --git a/src/main/test/resources/failureTests/TestClass2.java b/src/main/test/resources/failureTests/TestClass2.java new file mode 100644 index 0000000..d04ea39 --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass2.java @@ -0,0 +1,6 @@ +// Syntax Error: Unclosed string literal +public class TestClass2 { + public static void main(String[] args) { + System.out.println("Hello, World!); // Unclosed string literal + } +} diff --git a/src/main/test/resources/failureTests/TestClass3.java b/src/main/test/resources/failureTests/TestClass3.java new file mode 100644 index 0000000..75c1b39 --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass3.java @@ -0,0 +1,10 @@ +// Syntax Error: Missing parentheses in method declaration +public class TestClass3 { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } + + public void greet { // Missing parentheses + System.out.println("Hi!"); + } +} diff --git a/src/main/test/resources/failureTests/TestClass4.java b/src/main/test/resources/failureTests/TestClass4.java new file mode 100644 index 0000000..f1ee5ec --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass4.java @@ -0,0 +1,4 @@ +// Syntax Error: Missing class body +public class TestClass4 {- + // Missing class body +} diff --git a/src/main/test/resources/failureTests/TestClass5.java b/src/main/test/resources/failureTests/TestClass5.java new file mode 100644 index 0000000..535ce99 --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass5.java @@ -0,0 +1,7 @@ +// Semantic Error: Variable used before declaration +public class TestClass5 { + public static void main(String[] args) { + System.out.println(number); // Variable 'number' used before declaration + int number = 10; + } +} diff --git a/src/main/test/resources/failureTests/TestClass6.java b/src/main/test/resources/failureTests/TestClass6.java new file mode 100644 index 0000000..c8c3e60 --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass6.java @@ -0,0 +1,10 @@ +// Semantic Error: Method with wrong return type +public class TestClass6 { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } + + public int greet() { // Method should return int, but no return statement is provided + System.out.println("Hi!"); + } +} diff --git a/src/main/test/resources/failureTests/TestClass7.java b/src/main/test/resources/failureTests/TestClass7.java new file mode 100644 index 0000000..0e89cbd --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass7.java @@ -0,0 +1,5 @@ +// Syntax Error: Unmatched braces +public class TestClass7 { + public static void main(String[] args) { + System.out.println("Hello, World!"); + // Missing closing brace for the class diff --git a/src/main/test/resources/failureTests/TestClass8.java b/src/main/test/resources/failureTests/TestClass8.java new file mode 100644 index 0000000..6aa2510 --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass8.java @@ -0,0 +1,14 @@ +// Semantic Error: Duplicate method definition +public class TestClass8 { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } + + public void greet() { + System.out.println("Hi!"); + } + + public void greet() { // Duplicate method definition + System.out.println("Hello!"); + } +} diff --git a/src/main/test/resources/failureTests/TestClass9.java b/src/main/test/resources/failureTests/TestClass9.java new file mode 100644 index 0000000..fb873e6 --- /dev/null +++ b/src/main/test/resources/failureTests/TestClass9.java @@ -0,0 +1,6 @@ +// Syntax Error: Incompatible types +public class TestClass9 { + public static void main(String[] args) { + int number = "Hello"; // Incompatible types: String cannot be converted to int + } +} diff --git a/src/main/test/resources/featureTests/BooleanOperations.java b/src/main/test/resources/featureTests/BooleanOperations.java new file mode 100644 index 0000000..17d4a15 --- /dev/null +++ b/src/main/test/resources/featureTests/BooleanOperations.java @@ -0,0 +1,24 @@ +package resources.featureTests; + +public class BooleanOperations { + boolean flag; + + public BooleanOperations(boolean flag) { + this.flag = flag; + } + + public boolean isFlag() { + return flag; + } + + public void toggleFlag() { + flag = !flag; + } + + public static void main(String[] args) { + BooleanOperations obj = new BooleanOperations(true); + System.out.println(obj.isFlag()); + obj.toggleFlag(); + System.out.println(obj.isFlag()); + } +} diff --git a/src/main/test/resources/featureTests/CharManipulation.java b/src/main/test/resources/featureTests/CharManipulation.java new file mode 100644 index 0000000..7b70ad2 --- /dev/null +++ b/src/main/test/resources/featureTests/CharManipulation.java @@ -0,0 +1,24 @@ +package resources.featureTests; + +public class CharManipulation { + char letter; + + public CharManipulation(char letter) { + this.letter = letter; + } + + public char getLetter() { + return letter; + } + + public void setLetter(char letter) { + this.letter = letter; + } + + public static void main(String[] args) { + CharManipulation obj = new CharManipulation('A'); + System.out.println(obj.getLetter()); + obj.setLetter('B'); + System.out.println(obj.getLetter()); + } +} diff --git a/src/main/test/resources/featureTests/ConditionalStatements.java b/src/main/test/resources/featureTests/ConditionalStatements.java new file mode 100644 index 0000000..8b26079 --- /dev/null +++ b/src/main/test/resources/featureTests/ConditionalStatements.java @@ -0,0 +1,30 @@ +package resources.featureTests; + +public class ConditionalStatements { + int number; + + public ConditionalStatements(int number) { + this.number = number; + } + + public void checkNumber() { + if (number > 0) { + System.out.println("The number is positive."); + } else if (number < 0) { + System.out.println("The number is negative."); + } else { + System.out.println("The number is zero."); + } + } + + public static void main(String[] args) { + ConditionalStatements obj1 = new ConditionalStatements(5); + ConditionalStatements obj2 = new ConditionalStatements(-3); + ConditionalStatements obj3 = new ConditionalStatements(0); + + obj1.checkNumber(); + obj2.checkNumber(); + obj3.checkNumber(); + } +} + diff --git a/src/main/test/resources/featureTests/LoopExamples.java b/src/main/test/resources/featureTests/LoopExamples.java new file mode 100644 index 0000000..2eb2927 --- /dev/null +++ b/src/main/test/resources/featureTests/LoopExamples.java @@ -0,0 +1,18 @@ +package resources.featureTests; + +public class LoopExamples { + public static void main(String[] args) { + // For loop example + for (int i = 0; i < 5; i++) { + System.out.println("For loop iteration: " + i); + } + + // While loop example + int j = 0; + while (j < 5) { + System.out.println("While loop iteration: " + j); + j++; + } + } +} + diff --git a/src/main/test/resources/featureTests/MethodOverloading.java b/src/main/test/resources/featureTests/MethodOverloading.java new file mode 100644 index 0000000..3ca1d13 --- /dev/null +++ b/src/main/test/resources/featureTests/MethodOverloading.java @@ -0,0 +1,18 @@ +package resources.featureTests; + +public class MethodOverloading { + public int add(int a, int b) { + return a + b; + } + + public int add(int a, int b, int c) { + return a + b + c; + } + + public static void main(String[] args) { + MethodOverloading obj = new MethodOverloading(); + System.out.println("Sum of 2 and 3: " + obj.add(2, 3)); + System.out.println("Sum of 1, 2, and 3: " + obj.add(1, 2, 3)); + } +} + diff --git a/src/test/java/semantic/SemanticTest.java b/src/test/java/semantic/SemanticTest.java new file mode 100644 index 0000000..83287ca --- /dev/null +++ b/src/test/java/semantic/SemanticTest.java @@ -0,0 +1,107 @@ +package semantic; + + +import ast.*; +import ast.expression.BinaryExpressionNode; +import ast.expression.ExpressionNode; +import ast.expression.ExpresssionOperator; +import ast.expression.IdentifierExpressionNode; +import ast.member.FieldNode; +import ast.member.MemberNode; +import ast.member.MethodNode; +import ast.parameter.ParameterListNode; +import ast.parameter.ParameterNode; +import ast.statement.AssignmentStatementNode; +import ast.statement.StatementNode; +import ast.type.AccessTypeNode; +import ast.type.BaseTypeNode; +import ast.type.EnumAccessTypeNode; +import ast.type.EnumTypeNode; +import org.junit.jupiter.api.BeforeEach; +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.assertEquals; + +public class SemanticTest { + + @BeforeEach + public void init() { + SemanticAnalyzer.clearAnalyzier(); + } + + @Test + public void alreadyDeclaredLocalFieldVar(){ + + ProgramNode programNode = new ProgramNode(); + List classList = new ArrayList(); + AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC); + ClassNode classNode = new ClassNode(accessTypeNode, "testClass"); + + MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar"); + classNode.members.add(memberNode1); + + MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar"); + classNode.members.add(memberNode2); + + classList.add(classNode); + programNode.classes = classList; + + ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); + + assertEquals(1, SemanticAnalyzer.errors.size()); + assertEquals(true, SemanticAnalyzer.errors.get(0) instanceof AlreadyDeclearedException); + assertEquals(null, typedAst); + + } + + @Test + public void shouldWorkWithNoError(){ + + ProgramNode programNode = new ProgramNode(); + List classList = new ArrayList(); + AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC); + ClassNode classNode = new ClassNode(accessTypeNode, "testClass"); + + MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar1"); + classNode.members.add(memberNode1); + + MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2"); + classNode.members.add(memberNode2); + + List parameterNodeList = new ArrayList(); + ParameterNode parameterNode1 = new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "param1"); + parameterNodeList.add(parameterNode1); + ParameterListNode parameterListNode = new ParameterListNode(parameterNodeList); + + List statementNodeList = new ArrayList(); + + ExpressionNode expressionNodeObjectVariableLeft = new IdentifierExpressionNode("this"); + ExpressionNode expressionNodeObjectVariableRight = new IdentifierExpressionNode("objectVar"); + + ExpressionNode expressionNodeLeft = new BinaryExpressionNode(expressionNodeObjectVariableLeft, expressionNodeObjectVariableRight, ExpresssionOperator.DOT); + + ExpressionNode expressionNodeRight = new LiteralNode(1); + + BinaryExpressionNode expressionNode = new BinaryExpressionNode(expressionNodeLeft, expressionNodeRight, ExpresssionOperator.ASSIGNMENT); + + StatementNode statementNode1 = new AssignmentStatementNode(expressionNode); + statementNodeList.add(statementNode1); + + MemberNode memberNode3 = new MethodNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2",parameterListNode, statementNodeList ); + classNode.members.add(memberNode3); + + classList.add(classNode); + programNode.classes = classList; + + ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); + + assertEquals(0, SemanticAnalyzer.errors.size()); + assertEquals(programNode, typedAst); + + } + +}