Compare commits

..

32 Commits

Author SHA1 Message Date
fb3f822160 Merge branch 'main' into code-generator
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2024-06-21 19:25:35 -04:00
fd6da5cad2 Merge pull request 'johns-branch' (#12) from johns-branch into main
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Reviewed-on: #12
Reviewed-by: i22035 <i22035@hb.dhbw-stuttgart.de>
2024-06-21 16:30:55 +00:00
Bruder John
c44118c872 Fixed all
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2024-06-21 18:28:08 +02:00
Bruder John
0020f582a1 Merge branch 'main' into johns-branch
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-21 18:26:07 +02:00
8b5a0d528e Merge pull request 'Tests, Structure, More' (#10) from Tests into main
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
Reviewed-on: #10
Reviewed-by: Johannes Ehlert <i22005@hb.dhbw-stuttgart.de>
2024-06-21 16:16:53 +00:00
Bruder John
1b91e25d17 fixed tests
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-21 18:09:32 +02:00
Bruder John
9edee73705 Merge branch 'NewParser' into johns-branch
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-21 18:07:18 +02:00
Bruder John
5bf9a4fc73 added wrong type in if clause
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-21 18:06:49 +02:00
6d36eb109c Added Enums for Operators and MainMethodNode
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2024-06-21 18:02:29 +02:00
Bruder John
7b41c45cd5 Fixed all Tests
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-21 17:03:49 +02:00
Bruder John
cf41babcb7 Added BaseType And refferenz Type
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-21 16:42:27 +02:00
Bruder John
b9ada16dd1 Fixed SemanticCheck for new AST and added Some Test
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-21 15:23:48 +02:00
Bruder John
b5738034b0 Merge branch 'NewParser' into johns-branch
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-21 10:47:54 +02:00
50a52a1e87 Added Interface
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-20 18:44:42 +02:00
d3e9fa9b43 Added Public to Attributes
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-20 17:52:54 +02:00
Bruder John
0ec65af9f9 Added Method Check
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-20 16:53:31 +02:00
Bruder John
fd8c3b066a Trying to change to new AST
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-20 11:43:58 +02:00
Lucas
8cc67080ec Small changes
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2024-06-19 17:09:38 +02:00
Lucas
cfcb61d49e Running now possible with make or java.exe -jar in console
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-19 16:32:46 +02:00
Lucas
8f742191bb Small changes
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-19 14:19:47 +02:00
Lucas
102961bccc Added logging
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-19 12:49:46 +02:00
Lucas
f59d7e9918 First Tests for Parser, pls check
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2024-06-17 17:42:50 +02:00
Lucas
0732712e61 Make, Main: Raupenpiler startup
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-17 13:42:56 +02:00
Lucas
b6cc925e02 Fixed Makefile
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2024-06-12 18:01:21 +02:00
Lucas
6a971345d4 Structure and more
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-06-12 11:17:16 +02:00
Lucas
8d6190b130 Structure, Makefile, Docs, TestCompilerOutput, more; TODO: fix marked Problems in Makefile; fix Compiler (look at TestCompilerOutput docs)
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2024-05-31 17:09:04 +02:00
Lucas
9f40949f5a Structure
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-05-31 11:20:31 +02:00
Lucas
1132ff015c Changes in tests
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-05-31 11:05:45 +02:00
Lucas
2a20a91d35 Refactor structure and more
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-05-31 10:55:41 +02:00
Lucas
b2e1745d51 Merge branch 'main' into Tests
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-05-31 10:04:40 +02:00
Lucas
a0e55d7b27 first testrun of the day 2024-05-31 10:00:46 +02:00
Lucas
5a28d88f6a comments 2024-05-31 09:58:07 +02:00
115 changed files with 2176 additions and 897 deletions

6
.gitignore vendored
View File

@ -77,3 +77,9 @@ fabric.properties
.idea/caches/build_file_checksums.ser .idea/caches/build_file_checksums.ser
/target /target
src/main/resources/logs/RaupenLog.log
src/main/resources/output/CompilerInput.class
src/test/resources/output/javac/CompilerInput$Test.class
src/test/resources/output/javac/CompilerInput.class
src/test/resources/output/raupenpiler/CompilerInput.class
src/test/resources/output/raupenpiler/CompilerInput$Test.class

32
pom.xml
View File

@ -4,13 +4,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId> <groupId>de.dhbw-stuttgart</groupId>
<artifactId>JavaCompiler</artifactId> <artifactId>JavaCompiler</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0</version>
<properties> <properties>
<maven.compiler.source>21</maven.compiler.source> <java.version>22</java.version>
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
@ -53,7 +54,28 @@
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version> <!-- Change the version as needed --> <version>3.0.0-M5</version> <!-- Change the version as needed -->
</plugin> </plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>main.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -1,132 +0,0 @@
import oldAst.ASTNode;
import org.antlr.v4.runtime.*;
import oldAst.ProgramNode;
import bytecode.ByteCodeGenerator;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.CommonTokenStream;
import parser.astBuilder.ASTBuilder;
import parser.generated.SimpleJavaLexer;
import parser.generated.SimpleJavaParser;
import semantic.SemanticAnalyzer;
import java.io.IOException;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) throws Exception {
if(args.length > 0) {
} else {
try {
CharStream codeCharStream = CharStreams.fromPath(Paths.get("src/main/resources/CompilerInput.java"));
parseFile(codeCharStream);
} catch (IOException e) {
System.err.println("Error reading the file: " + e.getMessage());
}
}
}
static void parseFile(CharStream codeCharStream) {
/* ------------------------- Scanner -> tokens ------------------------- */
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
// Printing the tokens
// tokenStream.fill();
// List<Token> 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();
/* ------------------------- Parser -> Parsetree ------------------------- */
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
ParseTree parseTree = parser.program(); // parse the input
// 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();
//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);
// }
}
}

View File

@ -1,8 +1,6 @@
package ast; package ast;
import ast.type.AccessModifierNode; import ast.type.AccessModifierNode;
import ast.type.EnumAccessModifierNode;
import bytecode.visitor.ClassVisitor;
import ast.member.ConstructorNode; import ast.member.ConstructorNode;
import ast.member.MemberNode; import ast.member.MemberNode;
import ast.member.MethodNode; import ast.member.MethodNode;
@ -56,8 +54,4 @@ public class ClassNode implements ASTNode, Visitable {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(ClassVisitor classVisitor) {
classVisitor.visit(this);
}
} }

View File

@ -1,4 +0,0 @@
package ast;
public class IdentifierNode {
}

View File

@ -1,6 +1,5 @@
package ast; package ast;
import bytecode.visitor.ProgramVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable; import visitor.Visitable;
@ -19,9 +18,4 @@ public class ProgramNode implements ASTNode, Visitable {
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(ProgramVisitor programVisitor) {
programVisitor.visit(this);
}
} }

View File

@ -1,17 +1,29 @@
package ast.block; package ast.block;
import ast.ASTNode; import ast.ASTNode;
import ast.statement.StatementNode; import ast.statement.IStatementNode;
import ast.statement.ReturnStatementNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable;
import java.beans.Visibility;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class BlockNode implements ASTNode { public class BlockNode implements ASTNode, Visitable {
public List<StatementNode> statements = new ArrayList<>(); public List<IStatementNode> statements = new ArrayList<>();
public Boolean hasReturnStatement = false;
public BlockNode() {} public BlockNode() {}
public void addStatement(StatementNode statement) { public void addStatement(IStatementNode statement) {
statements.add(statement); statements.add(statement);
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -1,6 +0,0 @@
package ast.expression;
import visitor.Visitable;
public abstract class ExpressionNode implements Visitable {
}

View File

@ -0,0 +1,11 @@
package ast.expression;
import ast.ASTNode;
import ast.type.type.ITypeNode;
import visitor.Visitable;
public interface IExpressionNode extends ASTNode, Visitable {
ITypeNode getType();
}

View File

@ -1,4 +0,0 @@
package ast.expression.binaryexpression;
public class BinaryExpression {
}

View File

@ -0,0 +1,19 @@
package ast.expression.binaryexpression;
import ast.expression.IExpressionNode;
import ast.type.type.*;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class BinaryExpressionNode implements IExpressionNode {
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
@Override
public ITypeNode getType() {
return null;
}
}

View File

@ -1,19 +1,40 @@
package ast.expression.binaryexpression; package ast.expression.binaryexpression;
import ast.ASTNode; import ast.type.type.*;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class CalculationExpressionNode implements ASTNode { public class CalculationExpressionNode extends BinaryExpressionNode {
CalculationExpressionNode calculationExpression; public CalculationExpressionNode calculationExpression;
String operator; public EnumLineOperator operator;
DotExpressionNode dotExpression; public DotExpressionNode dotExpression;
public CalculationExpressionNode(CalculationExpressionNode calculationExpression, String operator, DotExpressionNode dotExpression) { public CalculationExpressionNode(CalculationExpressionNode calculationExpression, String operator, DotExpressionNode dotExpression) {
this.calculationExpression = calculationExpression; this.calculationExpression = calculationExpression;
this.operator = operator; setOperator(operator);
this.dotExpression = dotExpression; this.dotExpression = dotExpression;
} }
public CalculationExpressionNode(DotExpressionNode dotExpression) { public CalculationExpressionNode(DotExpressionNode dotExpression) {
this.dotExpression = dotExpression; this.dotExpression = dotExpression;
} }
private void setOperator(String operator) {
if(operator.equals("+")) {
this.operator = EnumLineOperator.PLUS;
} else if(operator.equals("-")) {
this.operator = EnumLineOperator.MINUS;
}
}
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
@Override
public ITypeNode getType() {
return null;
}
} }

View File

@ -1,19 +1,42 @@
package ast.expression.binaryexpression; package ast.expression.binaryexpression;
import ast.ASTNode; import ast.type.type.*;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class DotExpressionNode implements ASTNode { public class DotExpressionNode extends BinaryExpressionNode {
DotExpressionNode dotExpression; public DotExpressionNode dotExpression;
String operator; public EnumDotOperator operator;
DotSubstractionExpressionNode dotSubstractionExpression; public DotSubstractionExpressionNode dotSubstractionExpression;
public DotExpressionNode(DotExpressionNode dotExpression, String operator, DotSubstractionExpressionNode dotSubstractionExpression) { public DotExpressionNode(DotExpressionNode dotExpression, String operator, DotSubstractionExpressionNode dotSubstractionExpression) {
this.dotExpression = dotExpression; this.dotExpression = dotExpression;
this.operator = operator; setOperator(operator);
this.dotSubstractionExpression = dotSubstractionExpression; this.dotSubstractionExpression = dotSubstractionExpression;
} }
public DotExpressionNode(DotSubstractionExpressionNode dotSubstractionExpression) { public DotExpressionNode(DotSubstractionExpressionNode dotSubstractionExpression) {
this.dotSubstractionExpression = dotSubstractionExpression; this.dotSubstractionExpression = dotSubstractionExpression;
} }
private void setOperator(String operator) {
if(operator.equals("*")) {
this.operator = EnumDotOperator.MULT;
} else if(operator.equals("/")) {
this.operator = EnumDotOperator.DIV;
} else if(operator.equals("%")) {
this.operator = EnumDotOperator.MOD;
}
}
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
@Override
public ITypeNode getType() {
return null;
}
} }

View File

@ -1,16 +1,18 @@
package ast.expression.binaryexpression; package ast.expression.binaryexpression;
import ast.ASTNode;
import ast.expression.unaryexpression.MemberAccessNode; import ast.expression.unaryexpression.MemberAccessNode;
import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode; import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode;
import ast.type.type.*;
import ast.type.ValueNode; import ast.type.ValueNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class DotSubstractionExpressionNode implements ASTNode { public class DotSubstractionExpressionNode extends BinaryExpressionNode {
ValueNode value; public ValueNode value;
String identifier; public String identifier;
MemberAccessNode memberAccess; public MemberAccessNode memberAccess;
MethodCallStatementExpressionNode methodCall; public MethodCallStatementExpressionNode methodCall;
CalculationExpressionNode calculationExpression; public CalculationExpressionNode calculationExpression;
public DotSubstractionExpressionNode(ValueNode value) { public DotSubstractionExpressionNode(ValueNode value) {
this.value = value; this.value = value;
@ -28,4 +30,15 @@ public class DotSubstractionExpressionNode implements ASTNode {
this.methodCall = methodCall; this.methodCall = methodCall;
this.calculationExpression = calculationExpression; this.calculationExpression = calculationExpression;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
@Override
public ITypeNode getType() {
return null;
}
} }

View File

@ -0,0 +1,5 @@
package ast.expression.binaryexpression;
public enum EnumDotOperator {
MULT, DIV, MOD
}

View File

@ -0,0 +1,5 @@
package ast.expression.binaryexpression;
public enum EnumLineOperator {
PLUS, MINUS
}

View File

@ -0,0 +1,5 @@
package ast.expression.binaryexpression;
public enum EnumNonCalculationOperator {
AND, OR, GREATER, LESS, GREATER_EQUAL, LESS_EQUAL, EQUAL, NOT_EQUAL
}

View File

@ -1,17 +1,50 @@
package ast.expression.binaryexpression; package ast.expression.binaryexpression;
import ast.ASTNode; import ast.expression.IExpressionNode;
import ast.expression.ExpressionNode;
import ast.expression.unaryexpression.UnaryExpressionNode; import ast.expression.unaryexpression.UnaryExpressionNode;
import ast.type.type.*;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class NonCalculationExpressionNode implements ASTNode { public class NonCalculationExpressionNode extends BinaryExpressionNode {
UnaryExpressionNode unaryExpression; public UnaryExpressionNode unaryExpression;
String operator; public EnumNonCalculationOperator operator;
ExpressionNode expression; public IExpressionNode expression;
public NonCalculationExpressionNode(UnaryExpressionNode unaryExpression, String operator, ExpressionNode expression) { public NonCalculationExpressionNode(UnaryExpressionNode unaryExpression, String operator, IExpressionNode expression) {
this.unaryExpression = unaryExpression; this.unaryExpression = unaryExpression;
this.operator = operator; setOperator(operator);
this.expression = expression; this.expression = expression;
} }
private void setOperator(String operator) {
if(operator.equals("&&")) {
this.operator = EnumNonCalculationOperator.AND;
} else if(operator.equals("||")) {
this.operator = EnumNonCalculationOperator.OR;
} else if(operator.equals(">")) {
this.operator = EnumNonCalculationOperator.GREATER;
} else if(operator.equals("<")) {
this.operator = EnumNonCalculationOperator.LESS;
} else if(operator.equals(">=")) {
this.operator = EnumNonCalculationOperator.GREATER_EQUAL;
} else if(operator.equals("<=")) {
this.operator = EnumNonCalculationOperator.LESS_EQUAL;
} else if(operator.equals("==")) {
this.operator = EnumNonCalculationOperator.EQUAL;
} else if(operator.equals("!=")) {
this.operator = EnumNonCalculationOperator.NOT_EQUAL;
}
}
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
@Override
public ITypeNode getType() {
return null;
}
} }

View File

@ -16,4 +16,5 @@ public class MemberAccessNode implements ASTNode {
public void addIdentifier(String identifier) { public void addIdentifier(String identifier) {
identifiers.add(identifier); identifiers.add(identifier);
} }
} }

View File

@ -1,12 +1,13 @@
package ast.expression.unaryexpression; package ast.expression.unaryexpression;
import ast.ASTNode; import ast.ASTNode;
import ast.expression.ExpressionNode; import ast.expression.IExpressionNode;
public class NotExpressionNode implements ASTNode { public class NotExpressionNode implements ASTNode {
ExpressionNode expression; public IExpressionNode expression;
public NotExpressionNode(ExpressionNode expression) { public NotExpressionNode(IExpressionNode expression) {
this.expression = expression; this.expression = expression;
} }
} }

View File

@ -1,20 +1,23 @@
package ast.expression.unaryexpression; package ast.expression.unaryexpression;
import ast.ASTNode; import ast.expression.IExpressionNode;
import ast.expression.ExpressionNode; import ast.statement.IStatementNode;
import ast.statement.StatementNode; import ast.type.type.*;
import ast.type.ValueNode; import ast.type.ValueNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import java.util.Objects; import java.util.Objects;
public class UnaryExpressionNode implements ASTNode { public class UnaryExpressionNode implements IExpressionNode {
String thisExp; public String thisExp;
String identifier; public String identifier;
MemberAccessNode memberAccess; public MemberAccessNode memberAccess;
ValueNode value; public ValueNode value;
NotExpressionNode notExpression; public NotExpressionNode notExpression;
StatementNode statement; public IStatementNode statement;
ExpressionNode expression; public IExpressionNode expression;
private ITypeNode type;
public UnaryExpressionNode(String value) { public UnaryExpressionNode(String value) {
if(Objects.equals(value, "this")) { if(Objects.equals(value, "this")) {
@ -36,11 +39,26 @@ public class UnaryExpressionNode implements ASTNode {
this.notExpression = notExpression; this.notExpression = notExpression;
} }
public UnaryExpressionNode(StatementNode statement) { public UnaryExpressionNode(IStatementNode statement) {
this.statement = statement; this.statement = statement;
} }
public UnaryExpressionNode(ExpressionNode expression) { public UnaryExpressionNode(IExpressionNode expression) {
this.expression = expression; this.expression = expression;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
@Override
public ITypeNode getType() {
return type;
}
public void setType(ITypeNode type) {
this.type = type;
}
} }

View File

@ -3,7 +3,8 @@ package ast.member;
import ast.block.BlockNode; import ast.block.BlockNode;
import ast.parameter.ParameterNode; import ast.parameter.ParameterNode;
import ast.type.AccessModifierNode; import ast.type.AccessModifierNode;
import bytecode.visitor.MethodVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable; import visitor.Visitable;
import java.util.ArrayList; import java.util.ArrayList;
@ -20,8 +21,8 @@ public class ConstructorNode extends MethodNode implements Visitable {
this.identifier = identifier; this.identifier = identifier;
} }
public ConstructorNode(AccessModifierNode accessType, String identifier, BlockNode body) { public ConstructorNode(String accessType, String identifier, BlockNode body) {
this.accessType = accessType; this.accessType = new AccessModifierNode(accessType);
this.identifier = identifier; this.identifier = identifier;
this.body = body; this.body = body;
} }

View File

@ -1,18 +1,17 @@
package ast.member; package ast.member;
import ast.type.AccessModifierNode; import ast.type.AccessModifierNode;
import ast.type.TypeNode; import ast.type.type.ITypeNode;
import bytecode.visitor.ClassVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable; import visitor.Visitable;
public class FieldNode implements MemberNode, Visitable { public class FieldNode implements MemberNode, Visitable {
public AccessModifierNode accessTypeNode; public AccessModifierNode accessTypeNode;
public TypeNode type; public ITypeNode type;
public String identifier; public String identifier;
public FieldNode(AccessModifierNode accessTypeNode, TypeNode type, String name){ public FieldNode(AccessModifierNode accessTypeNode, ITypeNode type, String name){
this.accessTypeNode = accessTypeNode; this.accessTypeNode = accessTypeNode;
this.type = type; this.type = type;
this.identifier = name; this.identifier = name;
@ -23,8 +22,4 @@ public class FieldNode implements MemberNode, Visitable {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(ClassVisitor classVisitor) {
classVisitor.visit(this);
}
} }

View File

@ -0,0 +1,11 @@
package ast.member;
import ast.block.BlockNode;
public class MainMethodNode extends MethodNode {
public BlockNode block;
public MainMethodNode(BlockNode block) {
this.block = block;
}
}

View File

@ -3,31 +3,28 @@ package ast.member;
import ast.block.BlockNode; import ast.block.BlockNode;
import ast.parameter.ParameterNode; import ast.parameter.ParameterNode;
import ast.type.AccessModifierNode; import ast.type.AccessModifierNode;
import ast.type.TypeNode; import ast.type.type.*;
import bytecode.visitor.MethodVisitor; import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable; import visitor.Visitable;
import java.util.List; import java.util.List;
import java.util.Objects;
public class MethodNode implements MemberNode, Visitable { public class MethodNode implements MemberNode, Visitable {
public AccessModifierNode accesModifier; public AccessModifierNode accesModifier;
public TypeNode type; private ITypeNode type;
public Boolean voidType; public Boolean voidType;
public String identifier; private String identifier;
public List<ParameterNode> parameters; public List<ParameterNode> parameters = new ArrayList<>();
public BlockNode block; public BlockNode block;
public MethodNode() { public MethodNode() {
} }
public MethodNode(BlockNode block) { public MethodNode(String accessModifier, ITypeNode type, Boolean voidType, String identifier, BlockNode block){
this.block = block; this.accesModifier = new AccessModifierNode(accessModifier);
}
public MethodNode(AccessModifierNode accessModifier, TypeNode type, Boolean voidType, String identifier, BlockNode block) {
this.accesModifier = accessModifier;
this.type = type; this.type = type;
this.voidType = voidType; this.voidType = voidType;
this.identifier = identifier; this.identifier = identifier;
@ -38,23 +35,24 @@ public class MethodNode implements MemberNode, Visitable {
this.parameters.add(parameter); this.parameters.add(parameter);
} }
/* public List<ParameterNode> getParameters() {
return parameters;
}
public boolean isSame(MethodNode methodNode){ public boolean isSame(MethodNode methodNode){
boolean isSame = false; if (!(Objects.equals(this.identifier, methodNode.getIdentifier())) || type.equals(methodNode.type)
if(methodNode.identifier.equals(identifier)){ || getParameters().size() != methodNode.getParameters().size()) {
if(parameters != null && methodNode.parameters != null){ return false;
if(parameters.parameters.size() == methodNode.parameters.parameters.size()){ }
for(int i = 0; i < parameters.parameters.size(); i++){
if(parameters.parameters.get(i).identifier.equals(methodNode.parameters.parameters.get(i).identifier)){ for (int i = 0; i < this.getParameters().size(); i++) {
isSame = true; if (this.getParameters().get(i).type.equals(methodNode.getParameters().get(i).type)) {
return false;
} }
} }
return true;
} }
}
}
return isSame;
}
*/
@Override @Override
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this); return visitor.analyze(this);
@ -65,5 +63,20 @@ public class MethodNode implements MemberNode, Visitable {
methodVisitor.visit(this); methodVisitor.visit(this);
} }
public String getIdentifier() {
return identifier;
}
public ITypeNode getType() {
return type;
}
public void setType(ITypeNode type) {
this.type = type;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
} }

View File

@ -1,14 +1,23 @@
package ast.parameter; package ast.parameter;
import ast.ASTNode; import ast.ASTNode;
import ast.type.TypeNode; import ast.type.type.*;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable;
public class ParameterNode implements ASTNode { public class ParameterNode implements ASTNode {
public TypeNode type; public TypeNode type;
public String identifier; public String identifier;
public ParameterNode(TypeNode type, String identifier) { public ParameterNode(ITypeNode type, String identifier) {
this.type = type; this.type = type;
this.identifier = identifier; this.identifier = identifier;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -1,23 +1,31 @@
package ast.statement; package ast.statement;
import ast.ASTNode; import ast.ASTNode;
import ast.expression.ExpressionNode; import ast.expression.IExpressionNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class ForStatementNode implements ASTNode { public class ForStatementNode implements IStatementNode {
ExpressionNode statementExpressionInit; public IExpressionNode statementExpressionInit;
StatementNode localVariableDeclarationInit; public IStatementNode localVariableDeclarationInit;
ExpressionNode expression; public IExpressionNode expression;
ExpressionNode statementExpression; public IExpressionNode statementExpression;
public ForStatementNode(ExpressionNode statementExpressionInit, ExpressionNode expression, ExpressionNode statementExpression) { public ForStatementNode(IExpressionNode statementExpressionInit, IExpressionNode expression, IExpressionNode statementExpression) {
this.statementExpressionInit = statementExpressionInit; this.statementExpressionInit = statementExpressionInit;
this.expression = expression; this.expression = expression;
this.statementExpression = statementExpression; this.statementExpression = statementExpression;
} }
public ForStatementNode(StatementNode localVariableDeclarationInit, ExpressionNode expression, ExpressionNode statementExpression) { public ForStatementNode(IStatementNode localVariableDeclarationInit, IExpressionNode expression, IExpressionNode statementExpression) {
this.localVariableDeclarationInit = localVariableDeclarationInit; this.localVariableDeclarationInit = localVariableDeclarationInit;
this.expression = expression; this.expression = expression;
this.statementExpression = statementExpression; this.statementExpression = statementExpression;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -0,0 +1,7 @@
package ast.statement;
import ast.ASTNode;
import visitor.Visitable;
public interface IStatementNode extends ASTNode, Visitable {
}

View File

@ -1,19 +1,26 @@
package ast.statement; package ast.statement;
import ast.ASTNode; import ast.expression.IExpressionNode;
import ast.expression.ExpressionNode; import ast.type.type.*;
import ast.type.TypeNode; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class LocalVariableDeclarationNode implements ASTNode { public class LocalVariableDeclarationNode implements IStatementNode {
public TypeNode type; public ITypeNode type;
public String identifier; public String identifier;
public String assign; public String assign;
public ExpressionNode expression; public IExpressionNode expression;
public LocalVariableDeclarationNode(TypeNode type, String identifier, String assign, ExpressionNode expression) { public LocalVariableDeclarationNode(ITypeNode type, String identifier, String assign, IExpressionNode expression) {
this.type = type; this.type = type;
this.identifier = identifier; this.identifier = identifier;
this.assign = assign; this.assign = assign;
this.expression = expression; this.expression = expression;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -1,30 +1,24 @@
package ast.statement; package ast.statement;
import ast.ASTNode; import ast.expression.IExpressionNode;
import ast.expression.ExpressionNode;
import ast.type.TypeNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable;
import java.util.ArrayList; public class ReturnStatementNode implements IStatementNode {
import java.util.List; public IExpressionNode expression;
public Boolean voidReturn = false;
public class ReturnStatementNode implements ASTNode, Visitable { public ReturnStatementNode(IExpressionNode expression) {
public ExpressionNode expression; if(expression != null) {
public ReturnStatementNode(ExpressionNode expression) {
this.expression = expression; this.expression = expression;
} else {
voidReturn = true;
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
} }
@Override @Override
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return null; return visitor.analyze(this);
} }
} }

View File

@ -1,6 +0,0 @@
package ast.statement;
import visitor.Visitable;
public abstract class StatementNode implements Visitable {
}

View File

@ -2,14 +2,22 @@ package ast.statement;
import ast.ASTNode; import ast.ASTNode;
import ast.block.BlockNode; import ast.block.BlockNode;
import ast.expression.ExpressionNode; import ast.expression.IExpressionNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class WhileStatementNode implements ASTNode { public class WhileStatementNode implements IStatementNode {
ExpressionNode expression; public IExpressionNode expression;
BlockNode block; public BlockNode block;
public WhileStatementNode(ExpressionNode expression, BlockNode block) { public WhileStatementNode(IExpressionNode expression, BlockNode block) {
this.expression = expression; this.expression = expression;
this.block = block; this.block = block;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -2,11 +2,20 @@ package ast.statement.ifstatement;
import ast.ASTNode; import ast.ASTNode;
import ast.block.BlockNode; import ast.block.BlockNode;
import ast.statement.IStatementNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class ElseStatementNode implements ASTNode { public class ElseStatementNode implements IStatementNode {
BlockNode block; public BlockNode block;
public ElseStatementNode(BlockNode block) { public ElseStatementNode(BlockNode block) {
this.block = block; this.block = block;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -1,13 +1,16 @@
package ast.statement.ifstatement; package ast.statement.ifstatement;
import ast.ASTNode; import ast.ASTNode;
import ast.statement.IStatementNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class IfElseStatementNode implements ASTNode { public class IfElseStatementNode implements IStatementNode {
IfStatementNode ifStatement; public IfStatementNode ifStatement;
List<ElseStatementNode> elseStatements = new ArrayList<>(); public List<ElseStatementNode> elseStatements = new ArrayList<>();
public IfElseStatementNode(IfStatementNode ifStatement) { public IfElseStatementNode(IfStatementNode ifStatement) {
this.ifStatement = ifStatement; this.ifStatement = ifStatement;
@ -17,4 +20,9 @@ public class IfElseStatementNode implements ASTNode {
elseStatements.add(elseStatement); elseStatements.add(elseStatement);
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -2,14 +2,23 @@ package ast.statement.ifstatement;
import ast.ASTNode; import ast.ASTNode;
import ast.block.BlockNode; import ast.block.BlockNode;
import ast.expression.ExpressionNode; import ast.expression.IExpressionNode;
import ast.statement.IStatementNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class IfStatementNode implements ASTNode { public class IfStatementNode implements IStatementNode {
ExpressionNode expression; public IExpressionNode expression;
BlockNode block; public BlockNode block;
public IfStatementNode(ExpressionNode expression, BlockNode block) { public IfStatementNode(IExpressionNode expression, BlockNode block) {
this.expression = expression; this.expression = expression;
this.block = block; this.block = block;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -1,14 +1,21 @@
package ast.statement.statementexpression; package ast.statement.statementexpression;
import ast.ASTNode; import ast.expression.IExpressionNode;
import ast.expression.ExpressionNode; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class AssignStatementExpressionNode implements ASTNode { public class AssignStatementExpressionNode implements IStatementExpressionNode {
public AssignableExpressionNode assignable; public AssignableExpressionNode assignable;
public ExpressionNode expression; public IExpressionNode expression;
public AssignStatementExpressionNode(AssignableExpressionNode assignable, ExpressionNode expression) { public AssignStatementExpressionNode(AssignableExpressionNode assignable, IExpressionNode expression) {
this.assignable = assignable; this.assignable = assignable;
this.expression = expression; this.expression = expression;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -1,10 +1,12 @@
package ast.statement.statementexpression; package ast.statement.statementexpression;
import ast.ASTNode;
import ast.expression.unaryexpression.MemberAccessNode; import ast.expression.unaryexpression.MemberAccessNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class AssignableExpressionNode implements ASTNode { public class AssignableExpressionNode implements IStatementExpressionNode {
public String identifier; public String identifier;
public MemberAccessNode memberAccess; public MemberAccessNode memberAccess;
public AssignableExpressionNode(String identifier) { public AssignableExpressionNode(String identifier) {
@ -14,4 +16,10 @@ public class AssignableExpressionNode implements ASTNode {
public AssignableExpressionNode(MemberAccessNode memberAccess) { public AssignableExpressionNode(MemberAccessNode memberAccess) {
this.memberAccess = memberAccess; this.memberAccess = memberAccess;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -0,0 +1,5 @@
package ast.statement.statementexpression;
import ast.statement.IStatementNode;
public interface IStatementExpressionNode extends IStatementNode {}

View File

@ -1,5 +0,0 @@
package ast.statement.statementexpression;
public class IncrementExpression {
}

View File

@ -1,20 +1,28 @@
package ast.statement.statementexpression; package ast.statement.statementexpression;
import ast.ASTNode; import ast.ASTNode;
import ast.expression.ExpressionNode; import ast.expression.IExpressionNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class NewDeclarationStatementExpressionNode implements ASTNode { public class NewDeclarationStatementExpressionNode implements IStatementExpressionNode {
String identifier; public String identifier;
List<ExpressionNode> expressions = new ArrayList<>(); public List<IExpressionNode> expressions = new ArrayList<>();
public NewDeclarationStatementExpressionNode(String identifier) { public NewDeclarationStatementExpressionNode(String identifier) {
this.identifier = identifier; this.identifier = identifier;
} }
public void addExpression(ExpressionNode expression) { public void addExpression(IExpressionNode expression) {
expressions.add(expression); expressions.add(expression);
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -2,12 +2,21 @@ package ast.statement.statementexpression.crementExpression;
import ast.ASTNode; import ast.ASTNode;
import ast.statement.statementexpression.AssignableExpressionNode; import ast.statement.statementexpression.AssignableExpressionNode;
import ast.statement.statementexpression.IStatementExpressionNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class DecrementExpressionNode implements ASTNode { public class DecrementExpressionNode implements IStatementExpressionNode {
CrementType crementType; public CrementType crementType;
AssignableExpressionNode assignableExpression; public AssignableExpressionNode assignableExpression;
public DecrementExpressionNode(CrementType crementType, AssignableExpressionNode assignableExpression) { public DecrementExpressionNode(CrementType crementType, AssignableExpressionNode assignableExpression) {
this.assignableExpression = assignableExpression; this.assignableExpression = assignableExpression;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -2,12 +2,21 @@ package ast.statement.statementexpression.crementExpression;
import ast.ASTNode; import ast.ASTNode;
import ast.statement.statementexpression.AssignableExpressionNode; import ast.statement.statementexpression.AssignableExpressionNode;
import ast.statement.statementexpression.IStatementExpressionNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class IncrementExpressionNode implements ASTNode { public class IncrementExpressionNode implements IStatementExpressionNode {
CrementType crementType; public CrementType crementType;
AssignableExpressionNode assignableExpression; public AssignableExpressionNode assignableExpression;
public IncrementExpressionNode(CrementType crementType, AssignableExpressionNode assignableExpression) { public IncrementExpressionNode(CrementType crementType, AssignableExpressionNode assignableExpression) {
this.assignableExpression = assignableExpression; this.assignableExpression = assignableExpression;
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -1,20 +1,20 @@
package ast.statement.statementexpression.methodcallstatementnexpression; package ast.statement.statementexpression.methodcallstatementnexpression;
import ast.ASTNode; import ast.ASTNode;
import ast.expression.ExpressionNode; import ast.expression.IExpressionNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class ChainedMethodNode implements ASTNode { public class ChainedMethodNode implements ASTNode {
String identifier; public String identifier;
List<ExpressionNode> expressions = new ArrayList<>(); public List<IExpressionNode> expressions = new ArrayList<>();
public ChainedMethodNode(String identifier) { public ChainedMethodNode(String identifier) {
this.identifier = identifier; this.identifier = identifier;
} }
public void addExpression(ExpressionNode expression) { public void addExpression(IExpressionNode expression) {
expressions.add(expression); expressions.add(expression);
} }
} }

View File

@ -1,16 +1,19 @@
package ast.statement.statementexpression.methodcallstatementnexpression; package ast.statement.statementexpression.methodcallstatementnexpression;
import ast.ASTNode; import ast.ASTNode;
import ast.expression.ExpressionNode; import ast.expression.IExpressionNode;
import ast.statement.statementexpression.IStatementExpressionNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class MethodCallStatementExpressionNode implements ASTNode { public class MethodCallStatementExpressionNode implements IStatementExpressionNode {
TargetNode target; public TargetNode target;
List<ChainedMethodNode> chainedMethods = new ArrayList<>(); public List<ChainedMethodNode> chainedMethods = new ArrayList<>();
String identifier; public String identifier;
List<ExpressionNode> expressions = new ArrayList<>(); public List<IExpressionNode> expressions = new ArrayList<>();
public MethodCallStatementExpressionNode(TargetNode target, String identifier) { public MethodCallStatementExpressionNode(TargetNode target, String identifier) {
this.target = target; this.target = target;
@ -21,9 +24,13 @@ public class MethodCallStatementExpressionNode implements ASTNode {
chainedMethods.add(chainedMethode); chainedMethods.add(chainedMethode);
} }
public void addExpression(ExpressionNode expression) { public void addExpression(IExpressionNode expression) {
expressions.add(expression); expressions.add(expression);
} }
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -5,10 +5,10 @@ import ast.expression.unaryexpression.MemberAccessNode;
import ast.statement.statementexpression.NewDeclarationStatementExpressionNode; import ast.statement.statementexpression.NewDeclarationStatementExpressionNode;
public class TargetNode implements ASTNode { public class TargetNode implements ASTNode {
Boolean thisTar; public Boolean thisTar;
MemberAccessNode memberAccess; public MemberAccessNode memberAccess;
NewDeclarationStatementExpressionNode newDeclaration; public NewDeclarationStatementExpressionNode newDeclaration;
String identifier; public String identifier;
public TargetNode(Boolean thisTar) { public TargetNode(Boolean thisTar) {
this.thisTar = thisTar; this.thisTar = thisTar;

View File

@ -1,5 +0,0 @@
package ast.type;
public enum EnumTypeNode {
INT, BOOLEAN, CHAR, IDENTIFIER
}

View File

@ -1,25 +0,0 @@
package ast.type;
public class TypeNode {
public EnumTypeNode type;
public TypeNode(String type) {
setType(type);
}
private void setType(String type) {
switch(type) {
case "int":
this.type = EnumTypeNode.INT;
break;
case "boolean":
this.type = EnumTypeNode.BOOLEAN;
break;
case "char":
this.type = EnumTypeNode.CHAR;
break;
default:
this.type = EnumTypeNode.IDENTIFIER;
}
}
}

View File

@ -3,8 +3,8 @@ package ast.type;
import ast.ASTNode; import ast.ASTNode;
public class ValueNode implements ASTNode { public class ValueNode implements ASTNode {
EnumValueNode valueType; public EnumValueNode valueType;
String value; public String value;
public ValueNode(EnumValueNode valueType, String value) { public ValueNode(EnumValueNode valueType, String value) {
this.valueType = valueType; this.valueType = valueType;

View File

@ -0,0 +1,30 @@
package ast.type.type;
public class BaseType implements ITypeNode {
private TypeEnum typeEnum;
public BaseType(TypeEnum typeEnum) {
this.typeEnum = typeEnum;
}
public TypeEnum getTypeEnum() {
return typeEnum;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BaseType other = (BaseType) obj;
if (typeEnum != other.typeEnum)
return false;
return true;
}
}

View File

@ -0,0 +1,5 @@
package ast.type.type;
public interface ITypeNode {
}

View File

@ -0,0 +1,33 @@
package ast.type.type;
public class ReferenceType implements ITypeNode{
private String identifier;
public ReferenceType(String identifier) {
this.identifier = identifier;
}
public String getIdentifier() {
return identifier;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ReferenceType other = (ReferenceType) obj;
if (identifier == null) {
if (other.identifier != null)
return false;
} else if (!identifier.equals(other.identifier))
return false;
return true;
}
}

View File

@ -0,0 +1,9 @@
package ast.type.type;
public enum TypeEnum {
VOID,
INT,
CHAR,
BOOL;
}

View File

@ -9,7 +9,6 @@ import bytecode.visitor.ClassVisitor;
import java.io.File; import java.io.File;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@ -30,8 +29,8 @@ public class ClassCodeGen implements ClassVisitor {
@Override @Override
public void visit(ClassNode classNode) { public void visit(ClassNode classNode) {
classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
classWriter.visit(Opcodes.V1_5, mapper.mapAccessTypeToOpcode(classNode.accessType), classNode.identifier, null, // classWriter.visit(Opcodes.V1_5, mapper.mapAccessTypeToOpcode(classNode.accessType), classNode.identifier, null,
"java/lang/Object", null); // "java/lang/Object", null);
for (MemberNode memberNode : classNode.members) { for (MemberNode memberNode : classNode.members) {
if (memberNode instanceof FieldNode) { if (memberNode instanceof FieldNode) {
@ -62,7 +61,7 @@ public class ClassCodeGen implements ClassVisitor {
directory.mkdirs(); directory.mkdirs();
} }
String filePath = directoryPath + "/" + name + ".class"; String filePath = outputDirectoryPath + "/" + name + ".class";
try { try {
FileOutputStream fileOutputStream = new FileOutputStream(filePath); FileOutputStream fileOutputStream = new FileOutputStream(filePath);
fileOutputStream.write(byteCode); fileOutputStream.write(byteCode);

View File

@ -1,6 +1,5 @@
package bytecode; package bytecode;
import ast.parameter.ParameterNode;
import ast.type.*; import ast.type.*;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
@ -31,19 +30,19 @@ public class Mapper {
return descriptor; return descriptor;
} }
public String getTypeChar(EnumTypeNode enumTypeNode) { // public String getTypeChar(TypeEnum enumTypeNode) {
String typeChar = ""; // String typeChar = "";
switch (enumTypeNode) { // switch (enumTypeNode) {
case EnumTypeNode.INT: // case TypeEnum.INT:
typeChar = "I"; // typeChar = "I";
break; // break;
case EnumTypeNode.CHAR: // case TypeEnum.CHAR:
typeChar = "C"; // typeChar = "C";
break; // break;
case EnumTypeNode.BOOLEAN: // case TypeEnum.BOOLEAN:
typeChar = "Z"; // typeChar = "Z";
break; // break;
} // }
return typeChar; // return typeChar;
} // }
} }

View File

@ -5,5 +5,6 @@ import ast.member.FieldNode;
public interface ClassVisitor { public interface ClassVisitor {
void visit(ClassNode classNode); void visit(ClassNode classNode);
void visit(FieldNode fieldNode); void visit(FieldNode fieldNode);
} }

View File

@ -0,0 +1,108 @@
package main;
import ast.ASTNode;
import ast.ProgramNode;
import parser.astBuilder.ASTBuilder;
import parser.generated.SimpleJavaLexer;
import parser.generated.SimpleJavaParser;
import semantic.SemanticAnalyzer;
import bytecode.ByteCodeGenerator;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.IOException;
import java.nio.file.Paths;
/**
* Start Raupenpiler using make:
* <p> <code> cd .\src\test\ </code>
* <p> <code> make clean compile-raupenpiler </code>
* <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> 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>
*/
public class Main {
public static void main(String[] args) throws Exception {
if (args.length == 2) {
// args[0] is the input file path
// args[1] is the output directory path
String inputFilePath = args[0];
String outputDirectoryPath = args[1];
System.out.println("Compiling file: " + inputFilePath);
try {
CharStream inputCharStream = CharStreams.fromPath(Paths.get(inputFilePath));
compileFile(inputCharStream, outputDirectoryPath);
} catch (IOException e) {
System.err.println("Error reading the file: " + e.getMessage());
}
}
/* !!! Else Branch (main ohne args starten) ist nicht zur Verwendung vorgesehen, immer mit args starten !!!
else {
try {
CharStream codeCharStream = CharStreams.fromPath(Paths.get("src/main/resources/input/CompilerInput.java"));
compileFile(codeCharStream);
} catch (IOException e) {
System.err.println("Error reading the file: " + e.getMessage());
}
}
*/
}
/**
* This method is used to compile a file from a given CharStream and output the bytecode to a specified directory.
* It goes through the following steps:
* <p>1. Scanner: It uses the SimpleJavaLexer to tokenize the input CharStream.
* <p>2. Parser: It uses the SimpleJavaParser to parse the tokens and generate a ParseTree.
* <p>3. AST Builder: It uses the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST).
* <p>4. Semantic Analyzer: It uses the SemanticAnalyzer to generate a typed AST.
* <p>5. Bytecode Generator: It uses the ByteCodeGenerator to generate bytecode from the typed AST and output it to the specified directory.
*
* @param inputCharStream The CharStream representing the input file to be compiled.
* @param outputDirectoryPath The path of the directory where the output bytecode should be written.
*/
static void compileFile(CharStream inputCharStream, String outputDirectoryPath) {
// Initialize the logger
new RaupenLogger();
/* ------------------------- Scanner -> tokens ------------------------- */
// Use the SimpleJavaLexer to tokenize the input CharStream
SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
tokenStream.fill();
// Log the tokens
RaupenLogger.logScanner(tokenStream);
/*------------------------- Parser -> Parsetree -------------------------*/
// Use the SimpleJavaParser to parse the tokens and generate a ParseTree
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
ParseTree parseTree = parser.program(); // parse the input
// Log the ParseTree
RaupenLogger.logParser(parseTree, parser);
/*------------------------- AST builder -> AST -------------------------*/
// Use the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST)
ASTBuilder astBuilder = new ASTBuilder();
ASTNode abstractSyntaxTree = astBuilder.visit(parseTree);
// Log the AST
RaupenLogger.logAST(abstractSyntaxTree);
/*------------------------- Semantic Analyzer -> typed AST -------------------------*/
// Use the SemanticAnalyzer to generate a typed AST
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
// Log the typed AST
RaupenLogger.logSemanticAnalyzer(typedAst);
/*------------------------- Bytecode Generator -> Bytecode -------------------------*/
// Use the ByteCodeGenerator to generate bytecode from the typed AST and output it to the specified directory
ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(outputDirectoryPath);
assert typedAst != null;
byteCodeGenerator.visit((ProgramNode) typedAst);
// Log the bytecode generation
RaupenLogger.logBytecodeGenerator();
}
}

View File

@ -0,0 +1,180 @@
package main;
import ast.ASTNode;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import parser.generated.SimpleJavaLexer;
import parser.generated.SimpleJavaParser;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.*;
/**
Beispiel für Logging-Arten:
<p><code>logger.severe("Schwerwiegender Fehler");</code>
<p><code>logger.warning("Warnung");</code>
<p><code>logger.info("Information");</code>
<p><code>logger.config("Konfigurationshinweis");</code>
<p><code>logger.fine("Fein");</code>
<p><code>logger.finer("Feiner");</code>
<p><code>logger.finest("Am feinsten");</code>
<p>You may toggle the logging level of the console and file handlers by
changing the level ALL/OFF/etc. in the constructor.
<code>consoleHandler.setLevel(Level.OFF);</code>
<code>fileHandler.setLevel(Level.ALL);</code>
*/
public class RaupenLogger {
static Logger logger = Logger.getLogger("RaupenLogs");
public RaupenLogger() {
// ------------------------- Logging -------------------------
logger.setLevel(Level.ALL);
logger.getParent().getHandlers()[0].setLevel(Level.ALL);
logger.setUseParentHandlers(false);
// Custom formatter class
class CustomFormatter extends Formatter {
private final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss dd-MM-yyyy");
@Override
public String format(LogRecord record) {
return formatMessage(record) + System.lineSeparator();
}
@Override
public String getHead(Handler h) {
Date now = new Date();
String dateTime = dateFormat.format(now);
return "Log Start Time: " + dateTime + "\n"
+ "Logger Name: " + h.getFormatter().getClass().getName() + "\n\n";
}
}
try {
// Configure console handler
Handler consoleHandler = new ConsoleHandler();
// Toggle console logging on/off
consoleHandler.setLevel(Level.OFF);
consoleHandler.setFormatter(new CustomFormatter());
logger.addHandler(consoleHandler);
// Configure file handler
Handler fileHandler = new FileHandler("src/main/resources/logs/RaupenLog.log");
// Toggle file logging on/off
fileHandler.setLevel(Level.ALL);
fileHandler.setFormatter(new CustomFormatter());
logger.addHandler(fileHandler);
} catch (SecurityException | IOException e) {
e.printStackTrace();
}
}
public static void logScanner(CommonTokenStream tokenStream) {
// Printing the tokens
logger.info("-------------------- Scanner -> Tokens --------------------");
List<Token> tokens = tokenStream.getTokens();
for (Token token : tokens) {
String tokenType =
SimpleJavaLexer.VOCABULARY.getSymbolicName(token.getType());
String tokenText = token.getText();
// logger.info("Token Type: " + tokenType + ", Token Text: " + tokenText);
logger.info(tokenType + " " + tokenText);
}
logger.info("\n");
}
public static void logParser(ParseTree parseTree, SimpleJavaParser parser) {
// Printing the parse tree
logger.info("-------------------- Parser -> Parsetree --------------------");
logger.info(parseTree.toStringTree(parser)); //one line representation
logTree(parseTree, parser, 0);
logger.info("\n");
}
public static void logAST(ASTNode abstractSyntaxTree) {
// Printing the AST
logger.info("-------------------- AST builder -> AST --------------------");
// logger.info("AST: " + ast.toString());
logAST(abstractSyntaxTree, 0);
logger.info("\n");
}
public static void logSemanticAnalyzer(ASTNode typedAst) {
// Printing the typed AST
logger.info("-------------------- Semantic Analyzer -> typed AST --------------------");
logAST(typedAst, 0);
logger.info("\n");
}
public static void logBytecodeGenerator() {
// Printing the bytecode
logger.info("-------------------- Bytecode Generator -> Bytecode --------------------");
logger.info("Bytecode generated");
logger.info("\n");
}
/* ------------------------- Printing methods ------------------------- */
/**
* 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 logTree(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];
logger.info(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
logger.info(indentString + tree.getText());
}
// Recursively print the children of the current node, increasing the
// indentation level
for (int i = 0; i < tree.getChildCount(); i++) {
logTree(tree.getChild(i), parser, indent + 1);
}
}
// TODO: Fix this method
public static void logAST(ASTNode abstractSyntaxTree, int indent) {
if (abstractSyntaxTree == null) {
logger.severe("AST is null !!!");
return;
}
String indentString = " ".repeat(indent * 2);
logger.info(indentString + abstractSyntaxTree.getClass());
// for (ASTNode child : node.) {
// printAST(child, indent + 1);
// }
}
}

View File

@ -10,11 +10,9 @@ import ast.expression.binaryexpression.NonCalculationExpressionNode;
import ast.expression.unaryexpression.MemberAccessNode; import ast.expression.unaryexpression.MemberAccessNode;
import ast.expression.unaryexpression.NotExpressionNode; import ast.expression.unaryexpression.NotExpressionNode;
import ast.expression.unaryexpression.UnaryExpressionNode; import ast.expression.unaryexpression.UnaryExpressionNode;
import ast.member.MethodNode; import ast.member.*;
import ast.statement.ifstatement.ElseStatementNode; import ast.statement.ifstatement.ElseStatementNode;
import ast.statement.ifstatement.IfElseStatementNode; import ast.statement.ifstatement.IfElseStatementNode;
import ast.member.ConstructorNode;
import ast.member.MemberNode;
import ast.parameter.ParameterNode; import ast.parameter.ParameterNode;
import ast.statement.*; import ast.statement.*;
import ast.statement.ifstatement.IfStatementNode; import ast.statement.ifstatement.IfStatementNode;
@ -28,6 +26,7 @@ import ast.statement.statementexpression.methodcallstatementnexpression.ChainedM
import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode; import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode;
import ast.statement.statementexpression.methodcallstatementnexpression.TargetNode; import ast.statement.statementexpression.methodcallstatementnexpression.TargetNode;
import ast.type.*; import ast.type.*;
import ast.type.type.*;
import org.antlr.v4.runtime.tree.TerminalNode; import org.antlr.v4.runtime.tree.TerminalNode;
import parser.generated.*; import parser.generated.*;
@ -53,7 +52,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
@Override @Override
public ASTNode visitConstructorDeclaration(SimpleJavaParser.ConstructorDeclarationContext ctx) { public ASTNode visitConstructorDeclaration(SimpleJavaParser.ConstructorDeclarationContext ctx) {
ConstructorNode constructorNode = new ConstructorNode((AccessModifierNode) visit(ctx.AccessModifier()), ctx.Identifier().getText(), (BlockNode) visit(ctx.block())); ConstructorNode constructorNode = new ConstructorNode(ctx.AccessModifier().getText(), ctx.Identifier().getText(), (BlockNode) visit(ctx.block()));
for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) {
constructorNode.addParameter((ParameterNode) visit(parameter)); constructorNode.addParameter((ParameterNode) visit(parameter));
} }
@ -63,16 +62,16 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
@Override @Override
public ASTNode visitMethodDeclaration(SimpleJavaParser.MethodDeclarationContext ctx) { public ASTNode visitMethodDeclaration(SimpleJavaParser.MethodDeclarationContext ctx) {
if(ctx.MainMethodDeclaration() != null) { if(ctx.MainMethodDeclaration() != null) {
return new MethodNode((BlockNode) visit(ctx.block())); return new MainMethodNode((BlockNode) visit(ctx.block()));
} else { } else {
if(ctx.type() != null) { if(ctx.type() != null) {
MethodNode methodNode = new MethodNode((AccessModifierNode) visit(ctx.AccessModifier()), (TypeNode) visit(ctx.type()), false, ctx.Identifier().getText(), (BlockNode) visit(ctx.block())); MethodNode methodNode = new MethodNode(ctx.AccessModifier().getText(), createTypeNode(ctx.type().getText()), false, ctx.Identifier().getText(), (BlockNode) visit(ctx.block()));
for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) {
methodNode.addParameter((ParameterNode) visit(parameter)); methodNode.addParameter((ParameterNode) visit(parameter));
} }
return methodNode; return methodNode;
} else { } else {
MethodNode methodNode = new MethodNode((AccessModifierNode) visit(ctx.AccessModifier()), null, true, ctx.Identifier().getText(), (BlockNode) visit(ctx.block())); MethodNode methodNode = new MethodNode(ctx.AccessModifier().getText(), null, true, ctx.Identifier().getText(), (BlockNode) visit(ctx.block()));
for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) { for(SimpleJavaParser.ParameterContext parameter : ctx.parameterList().parameter()) {
methodNode.addParameter((ParameterNode) visit(parameter)); methodNode.addParameter((ParameterNode) visit(parameter));
} }
@ -81,9 +80,14 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
} }
} }
@Override
public ASTNode visitFieldDeclaration(SimpleJavaParser.FieldDeclarationContext ctx) {
return new FieldNode(new AccessModifierNode(ctx.AccessModifier().getText()), createTypeNode(ctx.type().getText()), ctx.Identifier().getText());
}
@Override @Override
public ASTNode visitParameter(SimpleJavaParser.ParameterContext ctx) { public ASTNode visitParameter(SimpleJavaParser.ParameterContext ctx) {
return new ParameterNode(new TypeNode(ctx.type().getText()), ctx.Identifier().getText()); return new ParameterNode(createTypeNode(ctx.type().getText()), ctx.Identifier().getText());
} }
@Override @Override
@ -108,34 +112,37 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
@Override @Override
public ASTNode visitReturnStatement(SimpleJavaParser.ReturnStatementContext ctx) { public ASTNode visitReturnStatement(SimpleJavaParser.ReturnStatementContext ctx) {
return new ReturnStatementNode((ExpressionNode) visit(ctx.expression())); return new ReturnStatementNode((IExpressionNode) visit(ctx.expression()));
} }
@Override @Override
public ASTNode visitLocalVariableDeclaration(SimpleJavaParser.LocalVariableDeclarationContext ctx) { public ASTNode visitLocalVariableDeclaration(SimpleJavaParser.LocalVariableDeclarationContext ctx) {
return new LocalVariableDeclarationNode(new TypeNode(ctx.type().getText()), ctx.Identifier().getText(), ctx.Assign().getText(), (ExpressionNode) visit(ctx.expression())); return new LocalVariableDeclarationNode(createTypeNode(ctx.type().getText()), ctx.Identifier().getText(), ctx.Assign().getText(), (IExpressionNode) visit(ctx.expression()));
} }
@Override @Override
public ASTNode visitBlock(SimpleJavaParser.BlockContext ctx) { public ASTNode visitBlock(SimpleJavaParser.BlockContext ctx) {
BlockNode blockNode = new BlockNode(); BlockNode blockNode = new BlockNode();
for(SimpleJavaParser.StatementContext statement : ctx.statement()) { for(SimpleJavaParser.StatementContext statement : ctx.statement()) {
blockNode.addStatement((StatementNode) visit(statement)); blockNode.addStatement((IStatementNode) visit(statement));
}
if(!blockNode.hasReturnStatement) {
blockNode.addStatement(new ReturnStatementNode(null));
} }
return blockNode; return blockNode;
} }
@Override @Override
public ASTNode visitWhileStatement(SimpleJavaParser.WhileStatementContext ctx) { public ASTNode visitWhileStatement(SimpleJavaParser.WhileStatementContext ctx) {
return new WhileStatementNode((ExpressionNode) visit(ctx.expression()), (BlockNode) visit(ctx.block())); return new WhileStatementNode((IExpressionNode) visit(ctx.expression()), (BlockNode) visit(ctx.block()));
} }
@Override @Override
public ASTNode visitForStatement(SimpleJavaParser.ForStatementContext ctx) { public ASTNode visitForStatement(SimpleJavaParser.ForStatementContext ctx) {
if(ctx.statementExpression(0) != null) { if(ctx.statementExpression(0) != null) {
return new ForStatementNode((ExpressionNode) visit(ctx.statementExpression(0)), (ExpressionNode) visit(ctx.expression()), (ExpressionNode) visit(ctx.statementExpression(1))); return new ForStatementNode((IExpressionNode) visit(ctx.statementExpression(0)), (IExpressionNode) visit(ctx.expression()), (IExpressionNode) visit(ctx.statementExpression(1)));
} else if(ctx.localVariableDeclaration() != null) { } else if(ctx.localVariableDeclaration() != null) {
return new ForStatementNode((StatementNode) visit(ctx.localVariableDeclaration()), (ExpressionNode) visit(ctx.expression()), (ExpressionNode) visit(ctx.statementExpression(1))); return new ForStatementNode((IStatementNode) visit(ctx.localVariableDeclaration()), (IExpressionNode) visit(ctx.expression()), (IExpressionNode) visit(ctx.statementExpression(1)));
} }
return null; return null;
} }
@ -151,7 +158,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
@Override @Override
public ASTNode visitIfStatement(SimpleJavaParser.IfStatementContext ctx) { public ASTNode visitIfStatement(SimpleJavaParser.IfStatementContext ctx) {
return new IfStatementNode((ExpressionNode) visit(ctx.expression()), (BlockNode) visit(ctx.block())); return new IfStatementNode((IExpressionNode) visit(ctx.expression()), (BlockNode) visit(ctx.block()));
} }
@Override @Override
@ -175,14 +182,14 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
@Override @Override
public ASTNode visitAssign(SimpleJavaParser.AssignContext ctx) { public ASTNode visitAssign(SimpleJavaParser.AssignContext ctx) {
return new AssignStatementExpressionNode((AssignableExpressionNode) visit(ctx.assignableExpression()), (ExpressionNode) visit(ctx.expression())); return new AssignStatementExpressionNode((AssignableExpressionNode) visit(ctx.assignableExpression()), (IExpressionNode) visit(ctx.expression()));
} }
@Override @Override
public ASTNode visitNewDeclaration(SimpleJavaParser.NewDeclarationContext ctx) { public ASTNode visitNewDeclaration(SimpleJavaParser.NewDeclarationContext ctx) {
NewDeclarationStatementExpressionNode newDeclarationStatementExpressionNode = new NewDeclarationStatementExpressionNode(ctx.Identifier().getText()); NewDeclarationStatementExpressionNode newDeclarationStatementExpressionNode = new NewDeclarationStatementExpressionNode(ctx.Identifier().getText());
for(SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) { for(SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) {
newDeclarationStatementExpressionNode.addExpression((ExpressionNode) visit(expression)); newDeclarationStatementExpressionNode.addExpression((IExpressionNode) visit(expression));
} }
return newDeclarationStatementExpressionNode; return newDeclarationStatementExpressionNode;
} }
@ -194,7 +201,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
methodCallStatementExpressionNode.addChainedMethod((ChainedMethodNode) visit(chainedMethod)); methodCallStatementExpressionNode.addChainedMethod((ChainedMethodNode) visit(chainedMethod));
} }
for(SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) { for(SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) {
methodCallStatementExpressionNode.addExpression((ExpressionNode) visit(expression)); methodCallStatementExpressionNode.addExpression((IExpressionNode) visit(expression));
} }
return methodCallStatementExpressionNode; return methodCallStatementExpressionNode;
} }
@ -217,7 +224,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
public ASTNode visitChainedMethod(SimpleJavaParser.ChainedMethodContext ctx) { public ASTNode visitChainedMethod(SimpleJavaParser.ChainedMethodContext ctx) {
ChainedMethodNode chainedMethodNode = new ChainedMethodNode(ctx.Identifier().getText()); ChainedMethodNode chainedMethodNode = new ChainedMethodNode(ctx.Identifier().getText());
for(SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) { for(SimpleJavaParser.ExpressionContext expression : ctx.argumentList().expression()) {
chainedMethodNode.addExpression((ExpressionNode) visit(expression)); chainedMethodNode.addExpression((IExpressionNode) visit(expression));
} }
return chainedMethodNode; return chainedMethodNode;
} }
@ -295,9 +302,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
} else if(ctx.notExpression() != null) { } else if(ctx.notExpression() != null) {
return new UnaryExpressionNode((NotExpressionNode) visitNotExpression(ctx.notExpression())); return new UnaryExpressionNode((NotExpressionNode) visitNotExpression(ctx.notExpression()));
} else if(ctx.statementExpression() != null) { } else if(ctx.statementExpression() != null) {
return new UnaryExpressionNode((StatementNode) visitStatementExpression(ctx.statementExpression())); return new UnaryExpressionNode((IStatementNode) visitStatementExpression(ctx.statementExpression()));
} else if(ctx.expression() != null) { } else if(ctx.expression() != null) {
return new UnaryExpressionNode((ExpressionNode) visitExpression(ctx.expression())); return new UnaryExpressionNode((IExpressionNode) visitExpression(ctx.expression()));
} }
return null; return null;
} }
@ -332,7 +339,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
@Override @Override
public ASTNode visitNotExpression(SimpleJavaParser.NotExpressionContext ctx) { public ASTNode visitNotExpression(SimpleJavaParser.NotExpressionContext ctx) {
return new NotExpressionNode((ExpressionNode) visitExpression(ctx.expression())); return new NotExpressionNode((IExpressionNode) visitExpression(ctx.expression()));
} }
@ -382,7 +389,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
@Override @Override
public ASTNode visitNonCalculationExpression(SimpleJavaParser.NonCalculationExpressionContext ctx) { public ASTNode visitNonCalculationExpression(SimpleJavaParser.NonCalculationExpressionContext ctx) {
return new NonCalculationExpressionNode((UnaryExpressionNode) visit(ctx.unaryExpression()), ctx.nonCalculationOperator().getText(), (ExpressionNode) visit(ctx.expression())); return new NonCalculationExpressionNode((UnaryExpressionNode) visit(ctx.unaryExpression()), ctx.nonCalculationOperator().getText(), (IExpressionNode) visit(ctx.expression()));
} }
@Override @Override
@ -394,4 +401,15 @@ public class ASTBuilder extends SimpleJavaBaseVisitor<ASTNode> {
} }
return null; return null;
} }
public ITypeNode createTypeNode(String identifier){
return switch (identifier) {
case "int" -> new BaseType(TypeEnum.INT);
case "boolean" -> new BaseType(TypeEnum.BOOL);
case "char" -> new BaseType(TypeEnum.CHAR);
case "void" -> new BaseType(TypeEnum.VOID);
default -> new ReferenceType(identifier);
};
}
} }

View File

@ -1,27 +1,35 @@
package semantic; package semantic;
import oldAst.type.TypeNode; import ast.type.type.*;
import semantic.exeptions.AlreadyDeclearedException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Stack; import java.util.Stack;
public class Scope { public class Scope {
private Stack<HashMap<String, TypeNode>> localVars; private Stack<HashMap<String, ITypeNode>> localVars;
public Scope() { public Scope() {
localVars = new Stack<HashMap<String, TypeNode>>(); localVars = new Stack<HashMap<String, ITypeNode>>();
} }
public void addLocalVar(String name, TypeNode type) { public void addLocalVar(String name, ITypeNode type) {
if (this.contains(name)) { if (this.contains(name)) {
throw new RuntimeException("Variable " + name + " already exists in this scope"); throw new AlreadyDeclearedException("Variable " + name + " already exists in this scope");
} }
localVars.peek().put(name, type); localVars.peek().put(name, type);
} }
public ITypeNode getLocalVar(String name) {
for (HashMap<String, ITypeNode> map : localVars) {
return map.get(name);
}
return null;
}
public boolean contains(String name) { public boolean contains(String name) {
for (HashMap<String, TypeNode> map : localVars) { for (HashMap<String, ITypeNode> map : localVars) {
if (map.containsKey(name)) { if (map.containsKey(name)) {
return true; return true;
} }
@ -30,7 +38,7 @@ public class Scope {
} }
public void pushScope() { public void pushScope() {
localVars.push(new HashMap<String, TypeNode>()); localVars.push(new HashMap<String, ITypeNode>());
} }
public void popScope() { public void popScope() {

View File

@ -1,40 +1,44 @@
package semantic; package semantic;
import oldAst.*;
import oldAst.expression.*;
import oldAst.member.FieldNode;
import oldAst.member.MemberNode;
import oldAst.member.MethodNode;
import oldAst.parameter.ParameterListNode;
import oldAst.parameter.ParameterNode;
import oldAst.statement.*;
import oldAst.type.ReferenceTypeNode;
import oldAst.expression.This;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import oldAst.type.BaseTypeNode; import ast.*;
import oldAst.type.TypeNode; import ast.block.BlockNode;
import ast.expression.IExpressionNode;
import ast.expression.binaryexpression.*;
import ast.expression.unaryexpression.UnaryExpressionNode;
import ast.member.*;
import ast.parameter.ParameterNode;
import ast.statement.*;
import ast.statement.ifstatement.ElseStatementNode;
import ast.statement.ifstatement.IfElseStatementNode;
import ast.statement.ifstatement.IfStatementNode;
import ast.statement.statementexpression.AssignStatementExpressionNode;
import ast.statement.statementexpression.AssignableExpressionNode;
import ast.statement.statementexpression.NewDeclarationStatementExpressionNode;
import ast.statement.statementexpression.crementExpression.DecrementExpressionNode;
import ast.statement.statementexpression.crementExpression.IncrementExpressionNode;
import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode;
import ast.type.type.*;
import semantic.context.Context; import semantic.context.Context;
import semantic.exeptions.AlreadyDeclearedException; import semantic.exeptions.*;
import semantic.exeptions.NotDeclearedException;
import semantic.exeptions.TypeMismatchException;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
public class SemanticAnalyzer implements SemanticVisitor { public class SemanticAnalyzer implements SemanticVisitor {
private static HashMap<String, TypeNode> currentFields = new HashMap<>(); private static HashMap<String, ITypeNode> currentFields = new HashMap<>();
public static ArrayList<Exception> errors = new ArrayList<>(); public static ArrayList<Exception> errors = new ArrayList<>();
private Context context; private static Context context;
private static Scope currentScope; private static Scope currentScope;
private static ClassNode currentClass; private static ClassNode currentClass;
private static ITypeNode currentNullType;
private ITypeNode currentMethodReturnType;
public static ASTNode generateTast(ASTNode node) { public static ASTNode generateTast(ASTNode node) {
SemanticAnalyzer semanticCheck = new SemanticAnalyzer(); SemanticAnalyzer semanticCheck = new SemanticAnalyzer();
@ -50,7 +54,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
return null; return null;
} }
public static void clearAnalyzier(){ public static void clearAnalyzer() {
currentFields.clear(); currentFields.clear();
errors.clear(); errors.clear();
currentScope = null; currentScope = null;
@ -90,10 +94,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
for (MethodNode methode : currentClass.getMethods()) { for (MethodNode methode : currentClass.getMethods()) {
if (methode.equals(methodNode)) if (methode.equals(methodNode))
break; break;
if(methode.isSame(methodNode)){
errors.add(new AlreadyDeclearedException("This method has already been declared"));
valid = false;
}
} }
var result = methodNode.accept(this); var result = methodNode.accept(this);
valid = valid && result.isValid(); valid = valid && result.isValid();
@ -106,38 +107,59 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override @Override
public TypeCheckResult analyze(MethodNode methodNode) { public TypeCheckResult analyze(MethodNode methodNode) {
if (methodNode instanceof ConstructorNode) {
return new TypeCheckResult(true, new BaseType(TypeEnum.VOID));
} else {
var valid = true; var valid = true;
for (var otherMethod : currentClass.getMethods()) {
if (Objects.equals(otherMethod, methodNode))
break;
if (otherMethod.isSame(methodNode)) {
errors.add(new AlreadyDeclearedException(
"Method " + methodNode.getIdentifier() + " is already defined in class "
+ currentClass.identifier));
valid = false;
}
}
currentScope.pushScope(); currentScope.pushScope();
for (var parameter : methodNode.getParameters()) {
//Parameter var result = parameter.accept(this);
ParameterListNode parameterListNode = methodNode.parameters; valid = valid && result.isValid();
if (parameterListNode != null) { try {
List<ParameterNode> parameters = parameterListNode.parameters;
for (ParameterNode parameter : parameters) {
if (currentScope.contains(parameter.identifier)) {
errors.add(new AlreadyDeclearedException("Duplicated Parameter " + parameter.identifier));
return new TypeCheckResult(false, null);
} else {
currentScope.addLocalVar(parameter.identifier, parameter.type); currentScope.addLocalVar(parameter.identifier, parameter.type);
} } catch (AlreadyDeclearedException e) {
} errors.add(new AlreadyDeclearedException(parameter.identifier));
} }
//Statements
List<StatementNode> statements = methodNode.statements;
for (StatementNode statement : statements) {
if (statement instanceof AssignmentStatementNode assignmentStatementNode) {
var result = assignmentStatementNode.accept(this);
valid = valid && result.isValid();
} else if (statement instanceof VariableDeclarationStatementNode variableDeclarationStatementNode) {
var result = variableDeclarationStatementNode.accept(this);
valid = valid && result.isValid();
}
} }
// Check if this method is already declared
currentMethodReturnType = methodNode.getType();
currentNullType = currentMethodReturnType; // Solange nicht in einem Assign oder Methoden-Aufruf dieser Typ
ITypeNode resultType = new BaseType(TypeEnum.VOID);
// gesetzt ist, ist dieser der Rückgabewert der Methode
var result = methodNode.block.accept(this);
valid = valid && result.isValid();
currentScope.popScope(); currentScope.popScope();
return new TypeCheckResult(valid, null); resultType = result.getType();
if (resultType == null) {
resultType = new BaseType(TypeEnum.VOID);
}
if (!resultType.equals(methodNode.getType())) {
errors.add(new TypeMismatchException("Method-Declaration " + methodNode.getIdentifier() + " with type "
+ methodNode.getType() + " has at least one Mismatching return Type:"));
valid = false;
}
return new TypeCheckResult(valid, resultType);
}
} }
@Override @Override
@ -151,88 +173,21 @@ public class SemanticAnalyzer implements SemanticVisitor {
return new TypeCheckResult(true, null); return new TypeCheckResult(true, null);
} }
@Override
public TypeCheckResult analyze(AssignmentStatementNode assignmentStatementNode) {
boolean valid = true;
ExpressionNode expressionNodeLeft = assignmentStatementNode.expressionLeft;
var resultLeft = expressionNodeLeft.accept(this);
valid = valid && resultLeft.isValid();
ExpressionNode expressionNodeRight = assignmentStatementNode.expressionRight;
var resultRight = expressionNodeRight.accept(this);
valid = valid && resultRight.isValid();
if(Objects.equals(resultLeft.getType(), resultRight.getType())){
System.out.println("SAME TYPE");
} else {
errors.add(new TypeMismatchException("Type mismatch"));
valid = false;
}
return new TypeCheckResult(valid, null);
}
@Override
public TypeCheckResult analyze(BinaryExpressionNode toCheck) {
boolean valid = true;
ExpressionNode left = toCheck.left;
var resultLeft = left.accept(this);
ExpressionNode right = toCheck.right;
var resultRight = right.accept(this);
switch (toCheck.operator) {
case ASSIGNMENT:
if(Objects.equals(resultRight.getType(), resultLeft.getType())){
System.out.println("Correct Type");
} else {
valid = false;
errors.add(new TypeMismatchException("Type Mismatch " + resultLeft.getType() + " and " + resultRight.getType()));
}
break;
case DOT:
return new TypeCheckResult(true, resultRight.getType());
default:
throw new RuntimeException("Unexpected operator: " + toCheck.operator);
}
return new TypeCheckResult(valid, null);
}
@Override
public TypeCheckResult analyze(IdentifierExpressionNode toCheck) {
if(toCheck.name == "this"){
return new TypeCheckResult(true, null);
} else if (currentFields.get(toCheck.name) == null) {
errors.add(new AlreadyDeclearedException("Not declared " + toCheck.name + " in this scope"));
return new TypeCheckResult(false, null);
} else {
return new TypeCheckResult(false, currentFields.get(toCheck.name));
}
}
@Override
public TypeCheckResult analyze(UnaryExpressionNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(VariableDeclarationStatementNode toCheck) {
if (currentScope.contains(toCheck.identifier)) {
errors.add(new AlreadyDeclearedException("Already declared " + toCheck.identifier + " in this scope"));
return new TypeCheckResult(false, null);
} else {
currentScope.addLocalVar(toCheck.identifier, toCheck.type);
}
return new TypeCheckResult(true, null);
}
@Override @Override
public TypeCheckResult analyze(IfStatementNode toCheck) { public TypeCheckResult analyze(IfStatementNode toCheck) {
return null; return new TypeCheckResult(true, null);
} }
@Override @Override
public TypeCheckResult analyze(ReturnStatementNode toCheck) { public TypeCheckResult analyze(ReturnStatementNode toCheck) {
return null;
if(toCheck.expression != null){
var result = toCheck.expression.accept(this);
return new TypeCheckResult(true, result.getType());
} else {
return new TypeCheckResult(false, null);
}
} }
@Override @Override
@ -241,39 +196,175 @@ public class SemanticAnalyzer implements SemanticVisitor {
} }
@Override @Override
public TypeCheckResult analyze(LiteralNode toCheck) { public TypeCheckResult analyze(ParameterNode toCheck) {
return new TypeCheckResult(true, toCheck.getType());
return new TypeCheckResult(true, null);
} }
@Override @Override
public TypeCheckResult analyze(InstVar toCheck) { public TypeCheckResult analyze(BlockNode blockNode) {
boolean valid = true; ITypeNode blockReturnType = null;
for (IStatementNode statementNode : blockNode.statements) {
var result = toCheck.expression.accept(this); var result = statementNode.accept(this);
if(result.getType() != null){
if(result.getType() instanceof BaseTypeNode){ if(blockReturnType == null){
throw new RuntimeException("BaseType has no Methods or Fields"); blockReturnType = result.getType();
} else { } else {
//Get typ of Field errors.add(new MultipleReturnTypes("There are multiple Return types"));
var type = (ReferenceTypeNode)result.getType();
var classContext = context.getClass(type.getIdentifier());
if(classContext == null){
errors.add(new NotDeclearedException("Not declared " + type.getIdentifier() + " in this scope"));
return new TypeCheckResult(false, null);
} else {
var field = classContext.getField(toCheck.identifier);
return new TypeCheckResult(valid, field.getType());
} }
} }
}
return new TypeCheckResult(true, blockReturnType);
}
@Override
public TypeCheckResult analyze(AssignableExpressionNode toCheck) {
return new TypeCheckResult(true, currentFields.get(toCheck.identifier));
} }
@Override @Override
public TypeCheckResult analyze(This toCheck) { public TypeCheckResult analyze(ElseStatementNode toCheck) {
return new TypeCheckResult(true, toCheck.getType()); return null;
}
@Override
public TypeCheckResult analyze(ForStatementNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(AssignStatementExpressionNode toCheck) {
AssignableExpressionNode assignable = toCheck.assignable;
var oldNullType = currentNullType;
currentNullType = currentFields.get(toCheck.assignable.identifier);
IExpressionNode rExpression = toCheck.expression;
currentNullType = oldNullType;
var valid = true;
// This check currently handles things like :
/**
* private int i;
* void foo(int i){
* i = i;
* }
*/
if (assignable.equals(rExpression)) {
errors.add(new TypeMismatchException("Cannot assign to self"));
valid = false;
}
var lResult = assignable.accept(this);
currentNullType = lResult.getType();
var rResult = rExpression.accept(this);
if (!Objects.equals(currentScope.getLocalVar(toCheck.assignable.identifier), rExpression.getType())) {
errors.add(new TypeMismatchException(
"Mismatch types in Assign-Statement: cannot convert from \"" + lResult.getType() + "\" to \""
+ rResult.getType() + "\""));
valid = false;
}
// else {
// toCheck.setType(assignable.getType());
// }
valid = valid && lResult.isValid() && rResult.isValid();
currentNullType = null;
return new TypeCheckResult(valid, null); // return type is null to get the return type sufficently
}
@Override
public TypeCheckResult analyze(DecrementExpressionNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(IfElseStatementNode toCheck) {
return new TypeCheckResult(true, null);
}
@Override
public TypeCheckResult analyze(MethodCallStatementExpressionNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(LocalVariableDeclarationNode localVarDecl) {
var valid = true;
if (localVarDecl.expression != null) {
TypeCheckResult result = localVarDecl.expression.accept(this);
var resultType = localVarDecl.expression.getType();
valid = result.isValid() && valid;
if (!Objects.equals(resultType, localVarDecl.type)) {
errors.add(new TypeMismatchException(
"Type mismatch: cannot convert from " + resultType + " to " + localVarDecl.type));
valid = false;
}
}
try {
currentScope.addLocalVar(localVarDecl.identifier, localVarDecl.type);
} catch (AlreadyDefinedException e) {
errors.add(new AlreadyDefinedException(e.getMessage()));
valid = false;
}
return new TypeCheckResult(valid, null);
}
@Override
public TypeCheckResult analyze(NewDeclarationStatementExpressionNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(IncrementExpressionNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(BinaryExpressionNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(CalculationExpressionNode calcNode) {
if (calcNode.calculationExpression != null) {
calcNode.calculationExpression.accept(this);
}
return null;
}
@Override
public TypeCheckResult analyze(DotExpressionNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(DotSubstractionExpressionNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(NonCalculationExpressionNode toCheck) {
return null;
}
@Override
public TypeCheckResult analyze(UnaryExpressionNode unary) {
var valid = true;
if (currentScope.contains(unary.identifier)) {
return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier));
} else if(currentFields.get(unary.identifier) != null) {
return new TypeCheckResult(valid, currentFields.get(unary.identifier));
} else {
errors.add(new NotDeclearedException("Var is not Decleared"));
}
return new TypeCheckResult(valid, null);
} }
} }

View File

@ -1,18 +1,20 @@
package semantic; package semantic;
import ast.ClassNode; import ast.*;
import ast.expression.LiteralNode; import ast.block.BlockNode;
import ast.ProgramNode; import ast.expression.binaryexpression.*;
import ast.expression.BinaryExpressionNode;
import ast.expression.IdentifierExpressionNode;
import ast.expression.InstVar;
import ast.expression.unaryexpression.UnaryExpressionNode; import ast.expression.unaryexpression.UnaryExpressionNode;
import ast.member.FieldNode; import ast.member.*;
import ast.member.MethodNode; import ast.parameter.ParameterNode;
import ast.statement.*; import ast.statement.*;
import ast.expression.This; import ast.statement.ifstatement.*;
import ast.statement.ifstatement.IfStatementNode; import ast.statement.statementexpression.AssignStatementExpressionNode;
import ast.statement.statementexpression.AssignableExpressionNode;
import ast.statement.statementexpression.NewDeclarationStatementExpressionNode;
import ast.statement.statementexpression.crementExpression.DecrementExpressionNode;
import ast.statement.statementexpression.crementExpression.IncrementExpressionNode;
import ast.statement.statementexpression.methodcallstatementnexpression.MethodCallStatementExpressionNode;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
public interface SemanticVisitor { public interface SemanticVisitor {
@ -25,25 +27,46 @@ public interface SemanticVisitor {
TypeCheckResult analyze(FieldNode toCheck); TypeCheckResult analyze(FieldNode toCheck);
TypeCheckResult analyze(AssignmentStatementNode toCheck);
TypeCheckResult analyze(BinaryExpressionNode toCheck);
TypeCheckResult analyze(IdentifierExpressionNode toCheck);
TypeCheckResult analyze(UnaryExpressionNode toCheck);
TypeCheckResult analyze(VariableDeclarationStatementNode toCheck);
TypeCheckResult analyze(IfStatementNode toCheck); TypeCheckResult analyze(IfStatementNode toCheck);
TypeCheckResult analyze(ReturnStatementNode toCheck); TypeCheckResult analyze(ReturnStatementNode toCheck);
TypeCheckResult analyze(WhileStatementNode toCheck); TypeCheckResult analyze(WhileStatementNode toCheck);
TypeCheckResult analyze(LiteralNode toCheck); TypeCheckResult analyze(ParameterNode toCheck);
TypeCheckResult analyze(InstVar toCheck); TypeCheckResult analyze(BlockNode toCheck);
TypeCheckResult analyze(AssignableExpressionNode toCheck);
TypeCheckResult analyze(ElseStatementNode toCheck);
TypeCheckResult analyze(ForStatementNode toCheck);
TypeCheckResult analyze(AssignStatementExpressionNode toCheck);
TypeCheckResult analyze(DecrementExpressionNode toCheck);
TypeCheckResult analyze(IfElseStatementNode toCheck);
TypeCheckResult analyze(MethodCallStatementExpressionNode toCheck);
TypeCheckResult analyze(LocalVariableDeclarationNode toCheck);
TypeCheckResult analyze(NewDeclarationStatementExpressionNode toCheck);
TypeCheckResult analyze(IncrementExpressionNode toCheck);
TypeCheckResult analyze(BinaryExpressionNode toCheck);
TypeCheckResult analyze(CalculationExpressionNode toCheck);
TypeCheckResult analyze(DotExpressionNode toCheck);
TypeCheckResult analyze(DotSubstractionExpressionNode toCheck);
TypeCheckResult analyze(NonCalculationExpressionNode toCheck);
TypeCheckResult analyze(UnaryExpressionNode toCheck);
TypeCheckResult analyze(This toCheck);
} }

View File

@ -1,7 +1,7 @@
package semantic.context; package semantic.context;
import oldAst.ClassNode; import ast.ClassNode;
import oldAst.member.FieldNode; import ast.member.FieldNode;
import java.util.HashMap; import java.util.HashMap;
public class ClassContext { public class ClassContext {

View File

@ -1,6 +1,6 @@
package semantic.context; package semantic.context;
import oldAst.ProgramNode; import ast.ProgramNode;
import java.util.HashMap; import java.util.HashMap;
public class Context { public class Context {

View File

@ -1,20 +1,20 @@
package semantic.context; package semantic.context;
import oldAst.member.FieldNode; import ast.member.FieldNode;
import oldAst.type.AccessTypeNode; import ast.type.*;
import oldAst.type.TypeNode; import ast.type.type.*;
public class FieldContext { public class FieldContext {
private AccessTypeNode accessModifier; private AccessModifierNode accessModifier;
private TypeNode type; private ITypeNode type;
public FieldContext(FieldNode field) { public FieldContext(FieldNode field) {
accessModifier = field.accessTypeNode; accessModifier = field.accessTypeNode;
type = field.type; type = field.type;
} }
public TypeNode getType() { public ITypeNode getType() {
return type; return type;
} }

View File

@ -0,0 +1,9 @@
package semantic.exeptions;
public class AlreadyDefinedException extends RuntimeException {
public AlreadyDefinedException(String message) {
super(message);
}
}

View File

@ -0,0 +1,9 @@
package semantic.exeptions;
public class MultipleReturnTypes extends RuntimeException {
public MultipleReturnTypes(String message) {
super(message);
}
}

View File

@ -1,14 +1,14 @@
package typechecker; package typechecker;
import oldAst.type.TypeNode; import ast.type.type.ITypeNode;
public class TypeCheckResult { public class TypeCheckResult {
private boolean valid; private boolean valid;
private TypeNode type; private ITypeNode type;
public TypeCheckResult(boolean valid, TypeNode type) { public TypeCheckResult(boolean valid, ITypeNode type) {
this.valid = valid; this.valid = valid;
this.type = type; this.type = type;
} }
@ -17,7 +17,7 @@ public class TypeCheckResult {
return valid; return valid;
} }
public TypeNode getType() { public ITypeNode getType() {
return type; return type;
} }
} }

View File

@ -1,22 +0,0 @@
public class Example {
public int a;
public static int testMethod(char x){
a = 12;
a = x;
}
}
public class Test {
public static int testMethod(char x, int a){
}
}

View File

@ -0,0 +1,16 @@
public class CompilerInput {
public int a;
public static int testMethod(char x){
return 0;
}
public class Test {
public static int testMethod(char x, int a){
return 0;
}
}
}

View File

@ -1,11 +0,0 @@
public class Tester {
public static void main(String[] args) {
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

29
src/test/Makefile Normal file
View File

@ -0,0 +1,29 @@
# Makefile
### IntelliJs play buttons do not work. Run in "src/test" folder with "make" command to run all
### Or run only parts with "make compile-javac", "make clean" etc.
all: compile-javac compile-raupenpiler
compile-javac:
javac -d .\resources\output\javac .\resources\input\CompilerInput.java
compile-raupenpiler:
cd ../.. ; mvn -DskipTests install
cd ../.. ; mvn exec:java -Dexec.mainClass="main.Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' "
test: test-javac test-raupenpiler
test-javac:
#compile-javac
#java -cp .\resources\output\javac CompilerInput
test-raupenpiler:
#java -cp .\resources\output\raupenpiler CompilerInput
clean:
rm -f ./resources/output/javac/*.class
rm -f ./resources/output/raupenpiler/*.class
rm -f ./java/*.class
rm -f ../main/resources/output/*.class
rm -f ../main/resources/logs/*.log

View File

@ -1,5 +1,7 @@
# Scanner # Scanner
## Scanner Input ## Scanner Input
### Beispiel 1: Empty Class ### Beispiel 1: Empty Class
String empty class = "public class Name {}"; String empty class = "public class Name {}";
@ -15,6 +17,9 @@
"}" "}"
## Scanner Output ## Scanner Output
CommonTokenStream
### Beispiel 1: Empty Class ### Beispiel 1: Empty Class
Token Type; Token Text Token Type; Token Text
@ -25,54 +30,63 @@ Type gibts nur bei Terminalen, Text bei allen
Bsp von Ihm mal: Bsp von Ihm mal:
[TokPublic,TokClass,TokIdentifier "Name",TokLeftBrace,TokRightBrace] [TokPublic,TokClass,TokIdentifier "Name",TokLeftBrace,TokRightBrace]
### Beispiel 2: Filled Class
[TokClass,TokIdentifier "javaFileInput.Example",TokLeftBrace]
[TokIf,TokLeftParen,TokIdentifier "x",TokLessThan,TokNumber 5,TokRightParen,TokLeftBrace]
[TokFor,TokLeftParen,TokIdentifier "int",TokIdentifier "i",TokAssign,TokNumber 0,TokSemicolon,TokIdentifier "i",TokLessThan,TokNumber 10,TokSemicolon,TokIdentifier "i",TokPlus,TokPlus,TokRightParen,TokLeftBrace]
[TokWhile,TokLeftParen,TokIdentifier "true",TokRightParen,TokLeftBrace]
[TokIdentifier "x",TokAssign,TokNumber 5,TokSemicolon]
[TokRightBrace]
# Parser # Parser
## Parser Input ## Parser Input
CommonTokenStream
(Scanner Output) (Scanner Output)
## Parser Output (AST) ## Parser Output (AST)
(program (classDeclaration (accessType public) class Name { }))
ParseTree
### Beispiel 1: Empty Class ### Beispiel 1: Empty Class
### Beispiel 2: Filled Class
# Semantische Analyse / Typcheck # Semantische Analyse / Typcheck
## Typcheck Input ## Typcheck Input
(Parser Output = AST) (Parser Output = AST)
## Typcheck Output ## Typcheck Output
### Beispiel 1: Empty Class ### Beispiel 1: Empty Class
### Beispiel 2: Filled Class
# Bytecodegenerierung # Bytecodegenerierung
## Bytecodegenerierung Input ## Bytecodegenerierung Input
(Typcheck Output = vom Typcheck eventuell manipulierter AST) (Typcheck Output = vom Typcheck eventuell manipulierter AST)
## Bytecodegenerierung Output ## Bytecodegenerierung Output
### Beispiel 1: Empty Class ### Beispiel 1: Empty Class
Compiled Classfile Compiled Classfile
public class javaFileInput.Example { public class javaFileInput.Example {
} }
## E2E Tests:
- Testdatei mit Main ausführen/kompilieren
- Testdatei mit "javac -d output .\CompilerInput.java" kompilieren
- -> Dateien mit javap vergleichen
### Beispiel 2: Filled Class wenn beides erfolgreich
- Ergebnis vom eigenen Compiler mithilfe von main.TestCompilerOutput ausführen
- (Ergebnis von javac mithilfe von main.TestCompilerOutput ausführen)
### Andis Tipps:
- cp mitgeben
- makefile
- java -jar pfadtocompiler.jar EmptyClass.java
- mvn package
- javac tester // tester compilen
- java tester // tester ausführen
- -> tester ist in unserem Fall main.TestCompilerOutput.java

View File

@ -1,3 +1,5 @@
package main;
public class EmptyClassExample { public class EmptyClassExample {
private class Inner { private class Inner {
} }

View File

@ -1,3 +1,5 @@
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;
@ -15,17 +17,17 @@ import java.util.List;
public class FailureTest { public class FailureTest {
private static final List<String> TEST_FILES = Arrays.asList( private static final List<String> TEST_FILES = Arrays.asList(
"src/main/test/resources/failureTests/TestClass1.java", "src/main/test/resources/input/failureTests/TestClass1.java",
"src/main/test/resources/failureTests/TestClass2.java", "src/main/test/resources/input/failureTests/TestClass2.java",
"src/main/test/resources/failureTests/TestClass3.java", "src/main/test/resources/input/failureTests/TestClass3.java",
"src/main/test/resources/failureTests/TestClass4.java", "src/main/test/resources/input/failureTests/TestClass4.java",
"src/main/test/resources/failureTests/TestClass5.java", "src/main/test/resources/input/failureTests/TestClass5.java",
"src/main/test/resources/failureTests/TestClass6.java", "src/main/test/resources/input/failureTests/TestClass6.java",
"src/main/test/resources/failureTests/TestClass7.java", "src/main/test/resources/input/failureTests/TestClass7.java",
"src/main/test/resources/failureTests/TestClass8.java", "src/main/test/resources/input/failureTests/TestClass8.java",
"src/main/test/resources/failureTests/TestClass9.java", "src/main/test/resources/input/failureTests/TestClass9.java",
"src/main/test/resources/failureTests/TestClass10.java", "src/main/test/resources/input/failureTests/TestClass10.java",
"src/main/test/resources/failureTests/TestClass11.java" "src/main/test/resources/input/failureTests/TestClass11.java"
); );
/** /**
@ -62,8 +64,8 @@ public class FailureTest {
void typedASTTest() throws IOException { void typedASTTest() throws IOException {
CharStream codeCharStream = null; CharStream codeCharStream = null;
try { try {
codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/EmptyClassExample.java")); codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/main/EmptyClassExample.java"));
Main.parsefile(codeCharStream); Main.compileFile(codeCharStream, "src/main/test/resources/output");
} catch (IOException e) { } catch (IOException e) {
System.err.println("Error reading the file: " + e.getMessage()); System.err.println("Error reading the file: " + e.getMessage());
} }

View File

@ -1,12 +1,8 @@
package main;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import parser.ASTBuilder;
import oldAst.ClassNode;
import oldAst.ProgramNode;
import bytecode.ByteCodeGenerator;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -21,8 +17,8 @@ public class MainTest {
void testEmptyClass() { void testEmptyClass() {
CharStream codeCharStream = null; CharStream codeCharStream = null;
try { try {
codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/EmptyClassExample.java")); codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/CompilerInput.java"));
Main.parsefile(codeCharStream); Main.compileFile(codeCharStream, "src/main/test/resources/output");
} catch (IOException e) { } catch (IOException e) {
System.err.println("Error reading the file: " + e.getMessage()); System.err.println("Error reading the file: " + e.getMessage());
} }

View File

@ -0,0 +1,45 @@
package main;
/**
* 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.
* <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>
*
* <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.
* 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>
*
* <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>
*/
public class TestCompilerOutput {
public static void main(String[] args) {
try {
// Try to load the class named "CompilerInput"
Class<?> cls = Class.forName("CompilerInput");
// Print a success message if the class is loaded successfully
System.out.println("Class loaded successfully: " + cls.getName());
// Try to create an instance of the loaded class
Object instance = cls.getDeclaredConstructor().newInstance();
// Print a success message if the instance is created successfully
System.out.println("Instance created: " + instance);
// If the class has a main method, you can invoke it
// cls.getMethod("main", String[].class).invoke(null, (Object) new String[]{});
// If the class has other methods, you can invoke them as well
// Example: cls.getMethod("someMethod").invoke(instance);
} catch (ClassNotFoundException e) {
// Print an error message if the class is not found
System.err.println("Class not found: " + e.getMessage());
} catch (Exception e) {
// Print an error message if any other exception occurs during class loading or instance creation
System.err.println("Error during class loading or execution: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,185 @@
package parser;
import org.antlr.v4.runtime.*;
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 static org.junit.jupiter.api.Assertions.*;
import java.util.*;
public class ParserTest {
@BeforeEach
public void init() { // noch nicht benötigt
String inputFilePath = "src/main/resources/input/CompilerInput.java";
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
public void parserTest() {
// init
CharStream inputCharStream = CharStreams.fromString("public class Name {}");
SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
tokenStream.fill();
/* Parser -> Parsetree */
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
ParseTree parseTree = parser.program(); // parse the input
//Variante 1 (geht)
String actualParseTreeAsString = parseTree.toStringTree(parser);
String expectedParseTreeAsString = "(program (classDeclaration (accessType public) class Name { }))";
assertEquals(actualParseTreeAsString, expectedParseTreeAsString);
//Variante 2 (geht nicht)
// - Sollte es gehen und es liegt am Parser? (keine Ahnung) -> Bitte Fehler (actual und expected) durchlesen
Map<String, Object> actualTreeStructure = buildTreeStructure(parseTree, parser);
Map<String, Object> expectedTreeStructure = parseStringToTree(expectedParseTreeAsString);
assertEquals(actualTreeStructure, expectedTreeStructure);
}
@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
public static Map<String, Object> buildTreeStructure(ParseTree tree, Parser parser) {
return buildTree(tree, parser, 0);
}
private static Map<String, Object> buildTree(ParseTree tree, Parser parser, int indent) {
Map<String, Object> node = new HashMap<>();
if (tree instanceof RuleContext) {
int ruleIndex = ((RuleContext) tree).getRuleIndex();
String ruleName = parser.getRuleNames()[ruleIndex];
node.put("rule", ruleName);
} else {
node.put("text", tree.getText());
}
List<Map<String, Object>> children = new ArrayList<>();
for (int i = 0; i < tree.getChildCount(); i++) {
children.add(buildTree(tree.getChild(i), parser, indent + 1));
}
if (!children.isEmpty()) {
node.put("children", children);
}
return node;
}
// Helpers Variante 2.2
public static Map<String, Object> parseStringToTree(String input) {
input = input.trim();
if (input.startsWith("(") && input.endsWith(")")) {
input = input.substring(1, input.length() - 1).trim();
}
return parse(input);
}
private static Map<String, Object> parse(String input) {
Map<String, Object> node = new HashMap<>();
StringBuilder currentToken = new StringBuilder();
List<Map<String, Object>> children = new ArrayList<>();
int depth = 0;
boolean inToken = false;
for (char ch : input.toCharArray()) {
if (ch == '(') {
if (depth == 0) {
if (currentToken.length() > 0) {
node.put("node", currentToken.toString().trim());
currentToken.setLength(0);
}
} else {
currentToken.append(ch);
}
depth++;
} else if (ch == ')') {
depth--;
if (depth == 0) {
children.add(parse(currentToken.toString().trim()));
currentToken.setLength(0);
} else {
currentToken.append(ch);
}
} else if (Character.isWhitespace(ch) && depth == 0) {
if (currentToken.length() > 0) {
node.put("node", currentToken.toString().trim());
currentToken.setLength(0);
}
} else {
currentToken.append(ch);
}
}
if (currentToken.length() > 0) {
node.put("node", currentToken.toString().trim());
}
if (!children.isEmpty()) {
node.put("children", children);
}
return node;
}
}

View File

@ -0,0 +1,282 @@
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());
}
}

View File

@ -1,76 +1,103 @@
package semantic; package semantic;
import oldAst.ClassNode; import ast.*;
import oldAst.expression.LiteralNode; import ast.block.BlockNode;
import oldAst.ProgramNode; import ast.member.FieldNode;
import oldAst.expression.*; import ast.member.MethodNode;
import oldAst.member.FieldNode; import ast.parameter.ParameterNode;
import oldAst.member.MemberNode; import ast.type.AccessModifierNode;
import oldAst.member.MethodNode; import ast.type.type.*;
import oldAst.parameter.ParameterListNode;
import oldAst.parameter.ParameterNode;
import oldAst.statement.AssignmentStatementNode;
import oldAst.statement.StatementNode;
import oldAst.type.*;
import java.util.ArrayList;
import java.util.List;
public class Mocker { public class Mocker {
public static ProgramNode mockCorrectProgrammNode(){ public static ASTNode mockTwoSameFields(){
ProgramNode p = new ProgramNode();
ProgramNode programNode = new ProgramNode(); ClassNode c = new ClassNode();
List<ClassNode> classList = new ArrayList<ClassNode>(); c.identifier = "testClass";
AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar1"); FieldNode f1 = new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a");
classNode.members.add(memberNode1);
MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "objectVar"); c.members.add(f1);
classNode.members.add(memberNode2);
List<ParameterNode> parameterNodeList = new ArrayList<ParameterNode>(); FieldNode f2 = new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a");
ParameterNode parameterNode1 = new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "param1");
parameterNodeList.add(parameterNode1);
ParameterListNode parameterListNode = new ParameterListNode(parameterNodeList);
List<StatementNode> statementNodeList = new ArrayList<StatementNode>(); c.members.add(f2);
ExpressionNode expressionNodeLeft = new InstVar(new This("testClass"), "objectVar");
LiteralNode expressionNodeRight = new LiteralNode();
expressionNodeRight.setType(new BaseTypeNode(EnumTypeNode.INT));
StatementNode statementNode1 = new AssignmentStatementNode(expressionNodeLeft, expressionNodeRight);
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;
return programNode;
p.classes.add(c);
return p;
} }
public static ProgramNode mockFieldNodeAlreadyDeclaredProgrammNode(){ public static ASTNode mockSimpleMethod(){
ProgramNode programNode = new ProgramNode(); ProgramNode p = new ProgramNode();
List<ClassNode> classList = new ArrayList<ClassNode>();
AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar"); ClassNode c = new ClassNode();
classNode.members.add(memberNode1);
MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar"); MethodNode methodNode = new MethodNode();
classNode.members.add(memberNode2);
classList.add(classNode); //Parameter
programNode.classes = classList; ParameterNode parameterNode = new ParameterNode(new BaseType(TypeEnum.INT), "a");
return programNode; methodNode.addParameter(parameterNode);
//Statements
//Block
methodNode.block = new BlockNode();
c.members.add(methodNode);
p.classes.add(c);
return p;
} }
public static ASTNode mockTwoSameMethods(){
ProgramNode p = new ProgramNode();
ClassNode c = new ClassNode();
MethodNode methodNode = new MethodNode();
methodNode.block = new BlockNode();
methodNode.setType(new BaseType(TypeEnum.INT));
methodNode.setIdentifier("testMethod");
c.members.add(methodNode);
MethodNode methodNode1 = new MethodNode();
methodNode1.block = new BlockNode();
methodNode1.setType(new BaseType(TypeEnum.INT));
methodNode1.setIdentifier("testMethod");
c.members.add(methodNode1);
p.classes.add(c);
return p;
}
public static ASTNode mockTwoDifferentMethods(){
ProgramNode p = new ProgramNode();
ClassNode c = new ClassNode();
MethodNode methodNode = new MethodNode();
methodNode.block = new BlockNode();
methodNode.setIdentifier("testMethod");
c.members.add(methodNode);
MethodNode methodNode1 = new MethodNode();
methodNode1.block = new BlockNode();
methodNode1.setIdentifier("testMethod1");
c.members.add(methodNode1);
p.classes.add(c);
return p;
}
} }

View File

@ -1,162 +1,114 @@
package semantic; package semantic;
import ast.*;
import ast.member.FieldNode;
import ast.member.MemberNode;
import ast.member.MethodNode;
import ast.parameter.ParameterNode;
import oldAst.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import semantic.exeptions.AlreadyDeclearedException; import semantic.exeptions.AlreadyDeclearedException;
import semantic.exeptions.TypeMismatchException; import java.util.ArrayList;
import java.util.List;
import java.io.File; import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class SemanticTest { public class SemanticTest {
@BeforeEach
public void init() { // @Test
SemanticAnalyzer.clearAnalyzier(); // public void alreadyDeclaredLocalFieldVar() {
} // ProgramNode programNode = new ProgramNode();
// List<ClassNode> classList = new ArrayList<>();
@Test // AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
public void alreadyDeclaredLocalFieldVar() { // ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
//
//Arrange // SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer();
// ASTNode tast = semanticAnalyzer.generateTast(ast);
ProgramNode programNode = Mocker.mockFieldNodeAlreadyDeclaredProgrammNode(); //
// MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar");
//Act // classNode.members.add(memberNode2);
//
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); // classList.add(classNode);
// programNode.classes = classList;
//Assert //
// ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
assertEquals(1, SemanticAnalyzer.errors.size()); //
assertEquals(true, SemanticAnalyzer.errors.get(0) instanceof AlreadyDeclearedException); // assertEquals(1, SemanticAnalyzer.errors.size());
assertEquals(null, typedAst); // assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst());
// assertNull(typedAst);
} // }
//
@Test // @Test
public void alreadyDecleared() { // public void shouldWorkWithNoError() {
// ProgramNode programNode = new ProgramNode();
//Arrange // List<ClassNode> classList = new ArrayList<>();
// AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
ProgramNode programNode = Mocker.mockFieldNodeAlreadyDeclaredProgrammNode(); // ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
//
//Act // SemanticAnalyzer semanticAnalyzer = new SemanticAnalyzer();
// ASTNode tast = semanticAnalyzer.generateTast(ast);
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); //
// assertEquals(semanticAnalyzer.errors.size(), 0);
//Assert // assertNotNull(tast);
//
assertEquals(1, SemanticAnalyzer.errors.size()); // MemberNode memberNode3 = getMemberNode(accessTypeNode);
assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst()); // classNode.members.add(memberNode3);
assertNull(typedAst); //
// classList.add(classNode);
} // programNode.classes = classList;
//
@Test // ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
public void shouldWorkWithNoError() { //
// assertEquals(0, SemanticAnalyzer.errors.size());
//Arrange // assertEquals(programNode, typedAst);
// }
ProgramNode programNode = Mocker.mockCorrectProgrammNode(); //
// /**
//Act // * This method is used to create a MemberNode representing a method.
// * It first creates a list of ParameterNodes and adds a ParameterNode to it.
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); // * Then, it creates a ParameterListNode using the list of ParameterNodes.
// * After that, it creates a list of StatementNodes and adds a StatementNode to it by calling the getStatementNode method.
//Assert // * Finally, it creates a MethodNode using the provided AccessTypeNode, a BaseTypeNode representing the return type of the method,
// * the method name, the ParameterListNode, and the list of StatementNodes, and returns this MethodNode.
assertEquals(0, SemanticAnalyzer.errors.size()); // *
assertEquals(programNode, typedAst); // * @param accessTypeNode The AccessTypeNode representing the access type of the method.
// * @return The created MemberNode representing the method.
} // */
//private static MemberNode getMemberNode(AccessTypeNode accessTypeNode) {
@Test // List<ParameterNode> parameterNodeList = new ArrayList<>();
public void refTypeCorrect() { // ParameterNode parameterNode1 = new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "param1");
// parameterNodeList.add(parameterNode1);
//Arrange // ParameterListNode parameterListNode = new ParameterListNode(parameterNodeList);
//
ObjectMapper objectMapper = new ObjectMapper(); // List<StatementNode> statementNodeList = new ArrayList<>();
ProgramNode programNode = null; //
try{ // StatementNode statementNode1 = getStatementNode();
programNode = objectMapper.readValue(new File("src/test/resources/semantic/correctRefType.json"), ProgramNode.class); // statementNodeList.add(statementNode1);
} catch (Exception e) { //
e.printStackTrace(); // return new MethodNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2", parameterListNode, statementNodeList);
} //}
//
//Act // /**
// * This method is used to create a StatementNode for an assignment operation.
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode); // * It first creates two IdentifierExpressionNodes for 'this' and 'objectVar'.
// * Then, it creates a BinaryExpressionNode to represent the operation 'this.objectVar'.
//Assert // * After that, it creates a LiteralNode to represent the integer value 1.
// * Finally, it creates another BinaryExpressionNode to represent the assignment operation 'this.objectVar = 1',
assertEquals(0, SemanticAnalyzer.errors.size()); // * and wraps this expression in an AssignmentStatementNode.
assertEquals(programNode, typedAst); // *
// * @return The created AssignmentStatementNode representing the assignment operation 'this.objectVar = 1'.
} // */
//private static StatementNode getStatementNode() {
@Test // ExpressionNode expressionNodeObjectVariableLeft = new IdentifierExpressionNode("this");
public void jsonWriteTest() { // ExpressionNode expressionNodeObjectVariableRight = new IdentifierExpressionNode("objectVar");
//
ObjectMapper objectMapper = new ObjectMapper(); // ExpressionNode expressionNodeLeft = new BinaryExpressionNode(expressionNodeObjectVariableLeft, expressionNodeObjectVariableRight, ExpresssionOperator.DOT);
//
//Arrange // ExpressionNode expressionNodeRight = new LiteralNode(1);
//
ProgramNode programNode = Mocker.mockCorrectProgrammNode(); // BinaryExpressionNode expressionNode = new BinaryExpressionNode(expressionNodeLeft, expressionNodeRight, ExpresssionOperator.ASSIGNMENT);
try{ //
objectMapper.writeValue(new File("src/test/resources/semantic/test.json"), programNode); // return new AssignmentStatementNode(expressionNode);
} catch (Exception e) { //}
e.printStackTrace();
}
}
@Test
public void jsonReadTest() {
ObjectMapper objectMapper = new ObjectMapper();
ProgramNode programNode1 = null;
try{
programNode1 = objectMapper.readValue(new File("src/test/resources/semantic/test.json"), ProgramNode.class);
} catch (Exception e) {
e.printStackTrace();
}
ProgramNode programNode2 = Mocker.mockCorrectProgrammNode();
}
@Test
public void typeMismatch() {
//Arrange
ObjectMapper objectMapper = new ObjectMapper();
ProgramNode programNode = null;
try{
programNode = objectMapper.readValue(new File("src/test/resources/semantic/refTypeMismatch.json"), ProgramNode.class);
} catch (Exception e) {
e.printStackTrace();
}
//Act
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
//Assert
assertEquals(1, SemanticAnalyzer.errors.size());
assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst());
assertNull(typedAst);
}
} }

View File

@ -0,0 +1,16 @@
public class CompilerInput {
public int a;
public static int testMethod(char x){
return 0;
}
public class Test {
public static int testMethod(char x, int a){
return 0;
}
}
}

Some files were not shown because too many files have changed in this diff Show More