25 Commits

Author SHA1 Message Date
4f688474a2 Revert "Merge remote-tracking branch 'origin/Endabgabe' into code-generator"
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
This reverts commit 721e1caa79, reversing
changes made to 6d3e1f859e.
2024-07-04 13:59:20 -04:00
5fc3927c5d Revert "Add typenode again"
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
This reverts commit fbff03c3d7.
2024-07-04 13:59:12 -04:00
a4d08aacb8 Revert "Some changes"
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
This reverts commit 8eba420d48.
2024-07-04 13:58:53 -04:00
8eba420d48 Some changes
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 12:29:23 -04:00
fbff03c3d7 Add typenode again
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 11:31:21 -04:00
721e1caa79 Merge remote-tracking branch 'origin/Endabgabe' into code-generator 2024-07-04 11:30:54 -04:00
6d3e1f859e Increment/Decrement assign
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 11:20:10 -04:00
f6b34bf70b readme.md gelöscht
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 15:16:39 +00:00
430d551f7d README.md aktualisiert
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 15:08:02 +00:00
8e0d627505 Readme fixed
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 17:06:49 +02:00
6b6051cad8 Readme fixed
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 17:04:48 +02:00
1f8e045b1e Readme 2024-07-04 17:03:49 +02:00
ceb1231632 Fixed Renaming Errors
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 17:02:02 +02:00
Maximilian Stahl
31929878b0 Merge remote-tracking branch 'origin/Endabgabe' into Endabgabe
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
# Conflicts:
#	src/main/java/semantic/SemanticAnalyzer.java
#	src/test/java/semantic/SemanticTest.java
2024-07-04 16:55:15 +02:00
Lucas
ea97f34398 Merge remote-tracking branch 'origin/Endabgabe' into Endabgabe
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 16:49:27 +02:00
Lucas
2f7b310254 refactoring, readme 2024-07-04 16:49:14 +02:00
Bruder John
9b8155ebab added class identifier to member acces node
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 16:31:45 +02:00
entep01
4775c3f47e Fixes and changed For Builder 2024-07-04 16:30:19 +02:00
Bruder John
2e3a7850a4 Fix Double Name 2024-07-04 16:29:42 +02:00
Bruder John
d925a3258c Add Class name to Memberaccesnode and identifier to assignable
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 15:58:46 +02:00
Lucas
fb5372bc8f make clean
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 15:22:37 +02:00
Lucas
f29be4fd8c E2E tests done
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 15:22:05 +02:00
Bruder John
34bb86c7f4 fixed if Check
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2024-07-04 10:40:13 +02:00
Bruder John
c0e197e2d0 added type to expression
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 09:09:55 +02:00
Bruder John
ae872ed906 removed Begin to Tast test
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
2024-07-04 08:29:50 +02:00
31 changed files with 3175 additions and 384 deletions

35
pom.xml
View File

@@ -23,6 +23,24 @@
<version>5.11.0-M2</version> <version>5.11.0-M2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-engine</artifactId>
<version>1.11.0-M2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0-M2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.antlr</groupId> <groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId> <artifactId>antlr4-runtime</artifactId>
@@ -44,18 +62,6 @@
<version>3.26.0</version> <version>3.26.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0-M2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
@@ -65,6 +71,11 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<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 -->
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>

68
readme.md Normal file
View File

@@ -0,0 +1,68 @@
# "Nicht Haskel 2.0" Java Compiler
Realisation of a subset of the Java Standard Compiler in the course Compiler Construction of the 4th semester Computer Science at the Duale Hochschule Suttgart (Horb).
This project aims to provide a simplified version of the Java compiler, focusing on key language features and demonstrating the principles of compiler construction.
## Realised Java syntax
- **Data types**: `int`, `boolean`, `char`
- **Access modifier**: `public`, `protected`, `private`
- **Operators**: `=` `+` `-` `*` `%` `/` `>` `<` `>=` `<=` `==` `!=` `!` `&&` `||` `++` `--`
- **Keywords**: `class`, `this`, `while`, `do`, `if`, `else`, `for`, `return`, `new`, `switch`, `case`, `break`, `default`, `:`
- **Statements**:
- `if` ... `if else` ... `else`;
- `while` ... ;
- `do` ... `while`;
- `for`;
- `switch` ... `case` ... ;
- **Comments**:
- Single line: `// comment`
- Multi-line: `/* comment */`
- **Further functions**:
- All methods are overloadable
- High maintainability and expandability through implementation of the visitor pattern
- Logging Input and Outputs
- Error Handling in the Semantic Check
## Project Structure
```plain
src/
└── main/
├── java/
│ ├── ast/ -> Defining the structure of the AST
│ ├── bytecode/ -> Generate Java bytecode
│ ├── main/ -> Running the compiler
│ ├── parser/
│ │ ├── astBuilder/ -> Builder creating the AST
│ │ ├── generated/ -> Antlr generated grammar
│ │ └── grammar/ -> Antlr grammar
│ ├── semantic/ -> Running the semantic check
│ └── visitor/ -> Visitor interface
└── resources/
test/
└── java/
│ ├── main/ -> MainTest, E2ETests, UtilityTests
│ ├── parser/ -> Performs tests on the parser
│ └── semantic/ -> Performs tests on the semantic check
└── resources/ -> Ressources for running the Tests
```
## Class-Diagramm AST
![AST Diagramm](ast.png)
## Used Tools
- [Maven 4.0](https://maven.apache.org/index.html)
- Used for automating the build process and managing dependencies.
- [ANTLR4 v.13.1](https://www.antlr.org/)
- Used to parse the input Java code into the Abstract Syntax Tree.
## How to run the compiler
## Download
```bash

View File

@@ -9,7 +9,6 @@ public class CalculationNode extends BinaryNode {
public CalculationNode calculationExpression; public CalculationNode calculationExpression;
public EnumLineOperator operator; public EnumLineOperator operator;
public DotNode dotExpression; public DotNode dotExpression;
private ITypeNode typeNode;
public CalculationNode(CalculationNode calculationExpression, String operator, DotNode dotExpression) { public CalculationNode(CalculationNode calculationExpression, String operator, DotNode dotExpression) {
this.calculationExpression = calculationExpression; this.calculationExpression = calculationExpression;

View File

@@ -7,7 +7,7 @@ import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable; import visitor.Visitable;
public class DecrementNode implements IStatementExpressionNode { public class DecrementNode implements IStatementExpressionNode, Visitable {
public CrementType crementType; public CrementType crementType;
public AssignableNode assignableExpression; public AssignableNode assignableExpression;
@@ -20,4 +20,9 @@ public class DecrementNode implements IStatementExpressionNode {
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@@ -5,8 +5,9 @@ import ast.statementexpressions.IStatementExpressionNode;
import bytecode.visitor.MethodVisitor; import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable;
public class IncrementNode implements IStatementExpressionNode { public class IncrementNode implements IStatementExpressionNode, Visitable {
public CrementType crementType; public CrementType crementType;
public AssignableNode assignableExpression; public AssignableNode assignableExpression;
@@ -19,4 +20,9 @@ public class IncrementNode implements IStatementExpressionNode {
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@@ -22,11 +22,6 @@ public class ChainedMethodNode implements ASTNode, Visitable {
expressions.add(expression); expressions.add(expression);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
@Override @Override
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return null; return null;

View File

@@ -27,7 +27,7 @@ public class ClassCodeGen implements ClassVisitor {
private boolean generateClassFiles; private boolean generateClassFiles;
public ClassCodeGen(JarOutputStream jarOutputStream, String outputDirectory, boolean generateJar, boolean generateClassFiles) { public ClassCodeGen(JarOutputStream jarOutputStream, String outputDirectory, boolean generateJar, boolean generateClassFiles) {
mapper = new Mapper(); this.mapper = new Mapper();
this.jarOutputStream = jarOutputStream; this.jarOutputStream = jarOutputStream;
this.outputDirectory = outputDirectory; this.outputDirectory = outputDirectory;
this.generateJar = generateJar; this.generateJar = generateJar;

View File

@@ -3,6 +3,7 @@ package bytecode;
import ast.parameters.ParameterNode; import ast.parameters.ParameterNode;
import ast.type.*; import ast.type.*;
import ast.type.type.BaseType; import ast.type.type.BaseType;
import ast.type.type.ITypeNode;
import ast.type.type.ReferenceType; import ast.type.type.ReferenceType;
import ast.type.type.TypeEnum; import ast.type.type.TypeEnum;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
@@ -24,7 +25,7 @@ public class Mapper {
return 0; return 0;
} }
public String generateMethodDescriptor(BaseType type, List<ParameterNode> parameters) { public String generateMethodDescriptor(ITypeNode type, List<ParameterNode> parameters) {
String descriptor = "("; String descriptor = "(";
for (ParameterNode parameterNode : parameters) { for (ParameterNode parameterNode : parameters) {
if(parameterNode.type instanceof BaseType) { if(parameterNode.type instanceof BaseType) {
@@ -35,7 +36,11 @@ public class Mapper {
} }
} }
descriptor += ")"; descriptor += ")";
descriptor += getTypeChar(type); if(type instanceof BaseType) {
descriptor += getTypeChar((BaseType) type);
} else if(type instanceof ReferenceType) {
descriptor += "L" + ((ReferenceType) type).getIdentifier() +";";
}
return descriptor; return descriptor;
} }

View File

@@ -14,9 +14,7 @@ import ast.statementexpressions.NewDeclarationNode;
import ast.statementexpressions.crementexpressions.CrementType; import ast.statementexpressions.crementexpressions.CrementType;
import ast.statementexpressions.crementexpressions.DecrementNode; import ast.statementexpressions.crementexpressions.DecrementNode;
import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.crementexpressions.IncrementNode;
import ast.statementexpressions.methodcallstatementnexpressions.ChainedMethodNode;
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
import ast.statementexpressions.methodcallstatementnexpressions.TargetNode;
import ast.statements.*; import ast.statements.*;
import ast.type.ValueNode; import ast.type.ValueNode;
import ast.type.type.BaseType; import ast.type.type.BaseType;
@@ -71,10 +69,8 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
// Visit all statements // Visit all statements
for (IStatementNode statementNode : constructorNode.block.statements) { for (IStatementNode statementNode : constructorNode.block.statements) {
if (statementNode != null) {
statementNode.accept(this); statementNode.accept(this);
} }
}
methodVisitor.visitMaxs(0, 0); methodVisitor.visitMaxs(0, 0);
methodVisitor.visitEnd(); methodVisitor.visitEnd();
@@ -105,7 +101,7 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
public void visit(MethodNode methodNode) { public void visit(MethodNode methodNode) {
methodVisitor = classWriter.visitMethod(mapper.mapAccessTypeToOpcode(methodNode.accesModifier), methodVisitor = classWriter.visitMethod(mapper.mapAccessTypeToOpcode(methodNode.accesModifier),
methodNode.getIdentifier(), methodNode.getIdentifier(),
mapper.generateMethodDescriptor((BaseType) methodNode.getType(), methodNode.parameters), mapper.generateMethodDescriptor(methodNode.getType(), methodNode.parameters),
null, null,
null); null);
@@ -241,7 +237,7 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
nonCalculationNode.unaryExpression.accept(this); nonCalculationNode.unaryExpression.accept(this);
nonCalculationNode.expression.accept(this); nonCalculationNode.expression.accept(this);
if (nonCalculationNode.unaryExpression.getType() instanceof BaseType && nonCalculationNode.expression.getType() instanceof BaseType) { if (nonCalculationNode.unaryExpression.getType() instanceof BaseType && nonCalculationNode.expression.getType() instanceof BaseType) {
methodVisitor.visitJumpInsn(IF_ACMPEQ, labelFalse); methodVisitor.visitJumpInsn(IF_ICMPEQ, labelFalse);
} else { } else {
methodVisitor.visitJumpInsn(IF_ACMPEQ, labelFalse); methodVisitor.visitJumpInsn(IF_ACMPEQ, labelFalse);
} }
@@ -266,9 +262,17 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
@Override @Override
public void visit(MemberAccessNode memberAccessNode) { public void visit(MemberAccessNode memberAccessNode) {
// Only used to get, not to put // Only used to get, not to put
if (memberAccessNode.thisExpr) { // Field int localVarIndex = localVariables.indexOf("memberAccessNode.identifier"); // TODO
// methodVisitor.visitFieldInsn(GETFIELD, memberAccessNode.identifiers.get(0), memberAccessNode.identifiers.get(1), ); if (localVarIndex >= 0) { // local var object
} else { // Object Attribut methodVisitor.visitVarInsn(ALOAD, localVarIndex);
} else { // this field
methodVisitor.visitVarInsn(ALOAD, 0);
}
if (memberAccessNode.getTypeNode() instanceof BaseType) {
methodVisitor.visitFieldInsn(GETFIELD, memberAccessNode.identifiers.get(0), memberAccessNode.identifiers.get(1), mapper.getTypeChar((BaseType) memberAccessNode.getTypeNode()));
} else if (memberAccessNode.getTypeNode() instanceof ReferenceType) {
methodVisitor.visitFieldInsn(GETFIELD, memberAccessNode.identifiers.get(0), memberAccessNode.identifiers.get(1), "L" + ((ReferenceType) memberAccessNode.getTypeNode()).getIdentifier() + ";");
} }
} }
@@ -331,6 +335,7 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
// else if statements // else if statements
methodVisitor.visitJumpInsn(IFEQ, elseIfLabels[0]); methodVisitor.visitJumpInsn(IFEQ, elseIfLabels[0]);
} }
ifElseNode.ifStatement.block.accept(this); // accept if block ifElseNode.ifStatement.block.accept(this); // accept if block
Label endLabel = new Label(); Label endLabel = new Label();
@@ -362,22 +367,17 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
if (localVariableDeclarationNode.expression != null) { if (localVariableDeclarationNode.expression != null) {
// Process expression // Process expression
localVariableDeclarationNode.expression.accept(this); localVariableDeclarationNode.expression.accept(this);
// Store result of expression in variable // add local var to list if not in list
if (localVariables.contains(localVariableDeclarationNode.identifier)) { if (!localVariables.contains(localVariableDeclarationNode.identifier)) {
if (localVariableDeclarationNode.type instanceof BaseType) {
methodVisitor.visitVarInsn(ISTORE, localVariables.indexOf(localVariableDeclarationNode.identifier));
} else if (localVariableDeclarationNode.type instanceof ReferenceType) {
methodVisitor.visitVarInsn(ASTORE, localVariables.indexOf(localVariableDeclarationNode.identifier));
}
} else {
localVariables.add(localVariableDeclarationNode.identifier); localVariables.add(localVariableDeclarationNode.identifier);
}
if (localVariableDeclarationNode.type instanceof BaseType) { if (localVariableDeclarationNode.type instanceof BaseType) {
methodVisitor.visitVarInsn(ISTORE, localVariables.indexOf(localVariableDeclarationNode.identifier)); methodVisitor.visitVarInsn(ISTORE, localVariables.indexOf(localVariableDeclarationNode.identifier));
} else if (localVariableDeclarationNode.type instanceof ReferenceType) { } else if (localVariableDeclarationNode.type instanceof ReferenceType) {
methodVisitor.visitVarInsn(ASTORE, localVariables.indexOf(localVariableDeclarationNode.identifier)); methodVisitor.visitVarInsn(ASTORE, localVariables.indexOf(localVariableDeclarationNode.identifier));
} }
}
} else { } else {
// Local var declaration
if (!localVariables.contains(localVariableDeclarationNode.identifier)) { if (!localVariables.contains(localVariableDeclarationNode.identifier)) {
localVariables.add(localVariableDeclarationNode.identifier); localVariables.add(localVariableDeclarationNode.identifier);
} }
@@ -386,40 +386,106 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
@Override @Override
public void visit(AssignNode assignNode) { public void visit(AssignNode assignNode) {
// Process expression if (assignNode.assignable.memberAccess != null) { // this / object
if (assignNode.expression instanceof IncrementNode) {
if (((IncrementNode) assignNode.expression).crementType.equals(CrementType.PREFIX)) { // ++i
fieldOrObjectVarPrefixCrementAssign(assignNode);
} else { // i++
fieldOrObjectVarSuffixCrementAssign(assignNode);
}
} else if (assignNode.expression instanceof DecrementNode) {
if (((DecrementNode) assignNode.expression).crementType.equals(CrementType.PREFIX)) {
fieldOrObjectVarPrefixCrementAssign(assignNode);
} else {
fieldOrObjectVarSuffixCrementAssign(assignNode);
}
} else {
assignFieldOrObjectVar(assignNode);
}
} else { // local var
if (assignNode.expression instanceof IncrementNode || assignNode.expression instanceof DecrementNode) {
localVarCrementAssign(assignNode);
} else {
assignNode.expression.accept(this);
assignLocalVar(assignNode);
}
}
}
private void localVarCrementAssign(AssignNode assignNode) {
if (assignNode.expression instanceof IncrementNode) { if (assignNode.expression instanceof IncrementNode) {
IncrementNode incrementNode = (IncrementNode) assignNode.expression; IncrementNode incrementNode = (IncrementNode) assignNode.expression;
if (incrementNode.crementType.equals(CrementType.PREFIX)) { // ++i if (incrementNode.crementType.equals(CrementType.PREFIX)) { // ++i
methodVisitor.visitIincInsn(localVariables.indexOf(incrementNode.assignableExpression.identifier), 1); incrementNode.accept(this);
assign(assignNode); assignLocalVar(assignNode);
} else if (incrementNode.crementType.equals(CrementType.SUFFIX)) { // Suffix: i++ } else { // i++
assign(assignNode); loadBeforeCrement(assignNode);
methodVisitor.visitIincInsn(localVariables.indexOf(incrementNode.assignableExpression.identifier), 1); assignLocalVar(assignNode);
incrementNode.accept(this);
} }
} else if (assignNode.expression instanceof DecrementNode) { } else if (assignNode.expression instanceof DecrementNode) {
DecrementNode decrementNode = (DecrementNode) assignNode.expression; DecrementNode decrementNode = (DecrementNode) assignNode.expression;
if (decrementNode.crementType.equals(CrementType.PREFIX)) { if (decrementNode.crementType.equals(CrementType.PREFIX)) {
methodVisitor.visitIincInsn(localVariables.indexOf(decrementNode.assignableExpression.identifier), -1); decrementNode.accept(this);
assign(assignNode); assignLocalVar(assignNode);
} else if (decrementNode.crementType.equals(CrementType.SUFFIX)) {
assign(assignNode);
methodVisitor.visitIincInsn(localVariables.indexOf(decrementNode.assignableExpression.identifier), 1);
}
} else { } else {
assignNode.expression.accept(this); loadBeforeCrement(assignNode);
assign(assignNode); assignLocalVar(assignNode);
decrementNode.accept(this);
}
} }
} }
private void assign(AssignNode assignNode) { private void fieldOrObjectVarPrefixCrementAssign(AssignNode assignNode) {
if (assignNode.assignable.memberAccess.thisExpr) { int localVarIndex = localVariables.indexOf(assignNode.assignable.identifier);
assignField(assignNode); if(localVarIndex >= 0) { // object
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
} else if(assignNode.assignable.memberAccess.thisExpr) { // field
methodVisitor.visitVarInsn(ALOAD, 0);
} else { } else {
assignLocalVar(assignNode); localVariables.add(assignNode.assignable.identifier);
methodVisitor.visitVarInsn(ALOAD, localVariables.indexOf(assignNode.assignable.identifier));
} }
assignNode.expression.accept(this);
methodVisitor.visitInsn(DUP_X1);
if (assignNode.expression instanceof BaseType) {
methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) assignNode.expression.getType()));
} else if (assignNode.expression instanceof ReferenceType) {
ReferenceType referenceType = (ReferenceType) assignNode.expression.getType();
methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), "L" + referenceType.getIdentifier() + ";");
}
}
private void fieldOrObjectVarSuffixCrementAssign(AssignNode assignNode) {
int localVarIndex = localVariables.indexOf(assignNode.assignable.identifier);
if(localVarIndex >= 0) { // object
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
} else if(assignNode.assignable.memberAccess.thisExpr) { // field
methodVisitor.visitVarInsn(ALOAD, 0);
} else {
localVariables.add(assignNode.assignable.identifier);
methodVisitor.visitVarInsn(ALOAD, localVariables.indexOf(assignNode.assignable.identifier));
}
loadBeforeCrement(assignNode);
if (assignNode.expression instanceof BaseType) {
methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) assignNode.expression.getType()));
} else if (assignNode.expression instanceof ReferenceType) {
ReferenceType referenceType = (ReferenceType) assignNode.expression.getType();
methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), "L" + referenceType.getIdentifier() + ";");
}
assignNode.expression.accept(this);
} }
private void assignLocalVar(AssignNode assignNode) { private void assignLocalVar(AssignNode assignNode) {
methodVisitor.visitInsn(DUP);
if (!localVariables.contains(assignNode.assignable.identifier)) {
localVariables.add(assignNode.assignable.identifier);
}
if (assignNode.expression instanceof BaseType) { if (assignNode.expression instanceof BaseType) {
methodVisitor.visitVarInsn(ISTORE, localVariables.indexOf(assignNode.assignable.identifier)); methodVisitor.visitVarInsn(ISTORE, localVariables.indexOf(assignNode.assignable.identifier));
} else if (assignNode.expression instanceof ReferenceType) { } else if (assignNode.expression instanceof ReferenceType) {
@@ -427,7 +493,20 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
} }
} }
private void assignField(AssignNode assignNode) { private void assignFieldOrObjectVar(AssignNode assignNode) {
int localVarIndex = localVariables.indexOf(assignNode.assignable.identifier);
if (localVarIndex >= 0) { // object
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
} else if (assignNode.assignable.memberAccess.thisExpr) { // this
methodVisitor.visitVarInsn(ALOAD, 0);
} else {
localVariables.add(assignNode.assignable.identifier);
methodVisitor.visitVarInsn(ALOAD, localVariables.indexOf(assignNode.assignable.identifier));
}
assignNode.expression.accept(this);
methodVisitor.visitInsn(DUP_X1);
if (assignNode.expression instanceof BaseType) { if (assignNode.expression instanceof BaseType) {
methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) assignNode.expression.getType())); methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) assignNode.expression.getType()));
} else if (assignNode.expression instanceof ReferenceType) { } else if (assignNode.expression instanceof ReferenceType) {
@@ -436,6 +515,86 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
} }
} }
private void loadBeforeCrement(AssignNode assignNode) {
if(assignNode.expression instanceof IncrementNode) {
IncrementNode incrementNode = (IncrementNode) assignNode.expression;
if(incrementNode.assignableExpression.memberAccess != null) {
incrementNode.assignableExpression.memberAccess.accept(this);
} else {
if(assignNode.assignable.getTypeNode() instanceof BaseType) {
methodVisitor.visitVarInsn(ILOAD, localVariables.indexOf(assignNode.assignable.identifier));
} else if(assignNode.assignable.getTypeNode() instanceof ReferenceType) {
methodVisitor.visitVarInsn(ALOAD, localVariables.indexOf(assignNode.assignable.identifier));
}
}
} else if(assignNode.expression instanceof DecrementNode) {
DecrementNode decrementNode = (DecrementNode) assignNode.expression;
if(decrementNode.assignableExpression.memberAccess != null) {
decrementNode.assignableExpression.memberAccess.accept(this);
} else {
if(assignNode.assignable.getTypeNode() instanceof BaseType) {
methodVisitor.visitVarInsn(ILOAD, localVariables.indexOf(assignNode.assignable.identifier));
} else if(assignNode.assignable.getTypeNode() instanceof ReferenceType) {
methodVisitor.visitVarInsn(ALOAD, localVariables.indexOf(assignNode.assignable.identifier));
}
}
}
}
@Override
public void visit(IncrementNode incrementNode) {
if (incrementNode.assignableExpression.memberAccess != null) { // Object var / field
int localVarIndex = localVariables.indexOf(incrementNode.assignableExpression.identifier);
if (localVarIndex >= 0) { // object
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
} else { // this
methodVisitor.visitVarInsn(ALOAD, 0);
}
if (incrementNode.assignableExpression.memberAccess.getTypeNode() instanceof BaseType) {
methodVisitor.visitFieldInsn(GETFIELD, incrementNode.assignableExpression.memberAccess.identifiers.get(0), incrementNode.assignableExpression.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) incrementNode.assignableExpression.memberAccess.getTypeNode()));
} else if (incrementNode.assignableExpression.memberAccess.getTypeNode() instanceof ReferenceType) {
methodVisitor.visitFieldInsn(GETFIELD, incrementNode.assignableExpression.memberAccess.identifiers.get(0), incrementNode.assignableExpression.memberAccess.identifiers.get(1), "L" + (((ReferenceType) incrementNode.assignableExpression.memberAccess.getTypeNode()).getIdentifier() + ";"));
}
methodVisitor.visitInsn(DUP);
methodVisitor.visitInsn(ICONST_1);
methodVisitor.visitInsn(IADD);
if (incrementNode.assignableExpression.memberAccess.getTypeNode() instanceof BaseType) {
methodVisitor.visitFieldInsn(PUTFIELD, incrementNode.assignableExpression.memberAccess.identifiers.get(0), incrementNode.assignableExpression.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) incrementNode.assignableExpression.memberAccess.getTypeNode()));
} else if (incrementNode.assignableExpression.memberAccess.getTypeNode() instanceof ReferenceType) {
methodVisitor.visitFieldInsn(PUTFIELD, incrementNode.assignableExpression.memberAccess.identifiers.get(0), incrementNode.assignableExpression.memberAccess.identifiers.get(1), "L" + (((ReferenceType) incrementNode.assignableExpression.memberAccess.getTypeNode()).getIdentifier() + ";"));
}
} else { // local var
methodVisitor.visitIincInsn(localVariables.indexOf(incrementNode.assignableExpression.identifier), 1);
}
}
@Override
public void visit(DecrementNode decrementNode) {
if (decrementNode.assignableExpression.memberAccess != null) { // Object var / field
int localVarIndex = localVariables.indexOf(decrementNode.assignableExpression.identifier);
if (localVarIndex >= 0) { // object
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
} else { // this
methodVisitor.visitVarInsn(ALOAD, 0);
}
methodVisitor.visitInsn(DUP);
if (decrementNode.assignableExpression.memberAccess.getTypeNode() instanceof BaseType) {
methodVisitor.visitFieldInsn(GETFIELD, decrementNode.assignableExpression.memberAccess.identifiers.get(0), decrementNode.assignableExpression.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) decrementNode.assignableExpression.memberAccess.getTypeNode()));
} else if (decrementNode.assignableExpression.memberAccess.getTypeNode() instanceof ReferenceType) {
methodVisitor.visitFieldInsn(GETFIELD, decrementNode.assignableExpression.memberAccess.identifiers.get(0), decrementNode.assignableExpression.memberAccess.identifiers.get(1), "L" + (((ReferenceType) decrementNode.assignableExpression.memberAccess.getTypeNode()).getIdentifier() + ";"));
}
methodVisitor.visitInsn(ICONST_1);
methodVisitor.visitInsn(ISUB);
if (decrementNode.assignableExpression.memberAccess.getTypeNode() instanceof BaseType) {
methodVisitor.visitFieldInsn(PUTFIELD, decrementNode.assignableExpression.memberAccess.identifiers.get(0), decrementNode.assignableExpression.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) decrementNode.assignableExpression.memberAccess.getTypeNode()));
} else if (decrementNode.assignableExpression.memberAccess.getTypeNode() instanceof ReferenceType) {
methodVisitor.visitFieldInsn(PUTFIELD, decrementNode.assignableExpression.memberAccess.identifiers.get(0), decrementNode.assignableExpression.memberAccess.identifiers.get(1), "L" + (((ReferenceType) decrementNode.assignableExpression.memberAccess.getTypeNode()).getIdentifier() + ";"));
}
} else { // local var
methodVisitor.visitIincInsn(localVariables.indexOf(decrementNode.assignableExpression.identifier), -1);
}
}
@Override @Override
public void visit(NewDeclarationNode newDeclarationNode) { public void visit(NewDeclarationNode newDeclarationNode) {
methodVisitor.visitTypeInsn(NEW, newDeclarationNode.identifier); methodVisitor.visitTypeInsn(NEW, newDeclarationNode.identifier);
@@ -446,7 +605,6 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
parameterNodes.add(new ParameterNode(expressionNode.getType(), "")); parameterNodes.add(new ParameterNode(expressionNode.getType(), ""));
} }
methodVisitor.visitMethodInsn(INVOKESPECIAL, newDeclarationNode.identifier, "<init>", mapper.generateMethodDescriptor(new BaseType(TypeEnum.VOID), parameterNodes), false); methodVisitor.visitMethodInsn(INVOKESPECIAL, newDeclarationNode.identifier, "<init>", mapper.generateMethodDescriptor(new BaseType(TypeEnum.VOID), parameterNodes), false);
localVariables.add(newDeclarationNode.identifier);
} }
@Override @Override
@@ -518,11 +676,6 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
methodVisitor.visitLabel(endOfLoopLabel); methodVisitor.visitLabel(endOfLoopLabel);
} }
@Override
public void visit(ChainedMethodNode chainedMethodNode) {
// TODO: Erstmal abwarten
}
@Override @Override
public void visit(MethodCallNode methodCallNode) { public void visit(MethodCallNode methodCallNode) {
List<ParameterNode> parameterNodes = new ArrayList<>(); List<ParameterNode> parameterNodes = new ArrayList<>();
@@ -530,7 +683,6 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
expressionNode.accept(this); expressionNode.accept(this);
parameterNodes.add(new ParameterNode(expressionNode.getType(), "")); parameterNodes.add(new ParameterNode(expressionNode.getType(), ""));
} }
// TODO: Klassenname und Returntype methodVisitor.visitMethodInsn(INVOKEVIRTUAL, methodCallNode.target.memberAccess.identifiers.get(0), methodCallNode.identifier, mapper.generateMethodDescriptor(methodCallNode.type, parameterNodes), false);
//methodVisitor.visitMethodInsn(INVOKEVIRTUAL, classname, methodCallNode.identifier, mapper.generateMethodDescriptor(returntype, parameterNodes), false);
} }
} }

View File

@@ -5,6 +5,5 @@ import ast.members.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

@@ -39,12 +39,14 @@ public interface MethodVisitor {
// statements // statements
void visit(IfElseNode ifElseNode); void visit(IfElseNode ifElseNode);
void visit(IncrementNode incrementNode);
void visit(DecrementNode decrementNode);
void visit(LocalVariableDeclarationNode localVariableDeclarationNode); void visit(LocalVariableDeclarationNode localVariableDeclarationNode);
void visit(ReturnNode returnNode); void visit(ReturnNode returnNode);
void visit(WhileNode whileNode); void visit(WhileNode whileNode);
// statement expression // statement expression
void visit(ChainedMethodNode chainedMethodNode);
void visit(MethodCallNode methodCallNode); void visit(MethodCallNode methodCallNode);
void visit(AssignNode assignNode); void visit(AssignNode assignNode);

View File

@@ -253,6 +253,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
if (toCheck.memberAccess != null) { if (toCheck.memberAccess != null) {
var result = toCheck.memberAccess.accept(this); var result = toCheck.memberAccess.accept(this);
toCheck.identifier = toCheck.memberAccess.identifiers.getLast();
toCheck.setTypeNode(result.getType()); toCheck.setTypeNode(result.getType());
return result; return result;
} else { } else {
@@ -316,11 +317,15 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override @Override
public TypeCheckResult analyze(IfElseNode toCheck) { public TypeCheckResult analyze(IfElseNode toCheck) {
var resultIf = toCheck.ifStatement.accept(this); var resultIf = toCheck.ifStatement.accept(this);
if(toCheck.elseStatement != null){
var resultElse = toCheck.elseStatement.accept(this); var resultElse = toCheck.elseStatement.accept(this);
return new TypeCheckResult(resultIf.isValid() && resultElse.isValid(), new BaseType(TypeEnum.VOID)); return new TypeCheckResult(resultIf.isValid() && resultElse.isValid(), new BaseType(TypeEnum.VOID));
} }
return new TypeCheckResult(resultIf.isValid(), new BaseType(TypeEnum.VOID));
}
@Override @Override
public TypeCheckResult analyze(MethodCallNode toCheck) { public TypeCheckResult analyze(MethodCallNode toCheck) {
@@ -454,6 +459,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
case PLUS, MINUS: case PLUS, MINUS:
if (calcRes.getType() instanceof BaseType calcType && dotRes.getType() instanceof BaseType dotType && if (calcRes.getType() instanceof BaseType calcType && dotRes.getType() instanceof BaseType dotType &&
calcType.getTypeEnum().equals(TypeEnum.INT) && dotType.getTypeEnum().equals(TypeEnum.INT)) { calcType.getTypeEnum().equals(TypeEnum.INT) && dotType.getTypeEnum().equals(TypeEnum.INT)) {
calcNode.setType(new BaseType(TypeEnum.INT));
return new TypeCheckResult(true, new BaseType(TypeEnum.INT)); return new TypeCheckResult(true, new BaseType(TypeEnum.INT));
} }
break; break;
@@ -461,10 +467,12 @@ public class SemanticAnalyzer implements SemanticVisitor {
} }
} else { } else {
calcNode.setType(calcNode.getType());
return new TypeCheckResult(calcRes.isValid(), calcRes.getType()); return new TypeCheckResult(calcRes.isValid(), calcRes.getType());
} }
} else if (calcNode.dotExpression != null) { } else if (calcNode.dotExpression != null) {
var dotRes = calcNode.dotExpression.accept(this); var dotRes = calcNode.dotExpression.accept(this);
calcNode.setType(dotRes.getType());
return new TypeCheckResult(dotRes.isValid(), dotRes.getType()); return new TypeCheckResult(dotRes.isValid(), dotRes.getType());
} }
return new TypeCheckResult(false, null); return new TypeCheckResult(false, null);
@@ -473,7 +481,9 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override @Override
public TypeCheckResult analyze(DotNode toCheck) { public TypeCheckResult analyze(DotNode toCheck) {
if (toCheck.dotSubstractionExpression != null) { if (toCheck.dotSubstractionExpression != null) {
return toCheck.dotSubstractionExpression.accept(this); var result = toCheck.dotSubstractionExpression.accept(this);
toCheck.setType(result.getType());
return result;
} }
return new TypeCheckResult(false, null); return new TypeCheckResult(false, null);
} }
@@ -481,19 +491,35 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override @Override
public TypeCheckResult analyze(DotSubstractionNode toCheck) { public TypeCheckResult analyze(DotSubstractionNode toCheck) {
if (toCheck.value != null) { if (toCheck.value != null) {
return toCheck.value.accept(this); var result = toCheck.value.accept(this);
toCheck.setType(result.getType());
return result;
} else if (toCheck.memberAccess != null) { } else if (toCheck.memberAccess != null) {
return toCheck.memberAccess.accept(this); var result = toCheck.memberAccess.accept(this);
toCheck.setType(result.getType());
return result;
} else if (toCheck.methodCall != null) { } else if (toCheck.methodCall != null) {
return toCheck.methodCall.accept(this); var result = toCheck.methodCall.accept(this);
toCheck.setType(result.getType());
return result;
} else if (toCheck.identifier != null) { } else if (toCheck.identifier != null) {
if (currentScope.contains(toCheck.identifier)) { if (currentScope.contains(toCheck.identifier)) {
return new TypeCheckResult(true, currentScope.getLocalVar(toCheck.identifier)); var type = currentScope.getLocalVar(toCheck.identifier);
toCheck.setType(type);
return new TypeCheckResult(true, type);
} else if (currentFields.get(toCheck.identifier) != null) { } else if (currentFields.get(toCheck.identifier) != null) {
return new TypeCheckResult(true, currentFields.get(toCheck.identifier)); var type = currentFields.get(toCheck.identifier);
toCheck.setType(type);
MemberAccessNode memberAccessNode = new MemberAccessNode(false);
memberAccessNode.identifiers.add(currentClass.identifier);
memberAccessNode.identifiers.add(toCheck.identifier);
toCheck.memberAccess = memberAccessNode;
return new TypeCheckResult(true, type);
} }
} else if (toCheck.calculationExpression != null) { } else if (toCheck.calculationExpression != null) {
return toCheck.calculationExpression.accept(this); var result = toCheck.calculationExpression.accept(this);
toCheck.setType(result.getType());
return result;
} }
return null; return null;
} }
@@ -513,8 +539,8 @@ public class SemanticAnalyzer implements SemanticVisitor {
} }
break; break;
case OR, AND: case OR, AND:
if (expResult.getType() instanceof BaseType expResultType && expResultType.getTypeEnum().equals(TypeEnum.INT) && if (expResult.getType() instanceof BaseType expResultType && expResultType.getTypeEnum().equals(TypeEnum.BOOL) &&
unaryResult.getType() instanceof BaseType unaryResultType && unaryResultType.getTypeEnum().equals(TypeEnum.INT)) { unaryResult.getType() instanceof BaseType unaryResultType && unaryResultType.getTypeEnum().equals(TypeEnum.BOOL)) {
return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL)); return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL));
} else { } else {
errors.add(new TypeMismatchException("Both types must be Boolean")); errors.add(new TypeMismatchException("Both types must be Boolean"));
@@ -538,13 +564,17 @@ public class SemanticAnalyzer implements SemanticVisitor {
if (unary.identifier != null) { if (unary.identifier != null) {
if (currentScope.contains(unary.identifier)) { if (currentScope.contains(unary.identifier)) {
return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier)); var type = currentScope.getLocalVar(unary.identifier);
unary.setType(type);
return new TypeCheckResult(valid, type);
} else if (currentFields.get(unary.identifier) != null) { } else if (currentFields.get(unary.identifier) != null) {
MemberAccessNode memberAccessNode = new MemberAccessNode(false); MemberAccessNode memberAccessNode = new MemberAccessNode(false);
memberAccessNode.identifiers.add(currentClass.identifier); memberAccessNode.identifiers.add(currentClass.identifier);
memberAccessNode.identifiers.add(unary.identifier); memberAccessNode.identifiers.add(unary.identifier);
unary.memberAccess = memberAccessNode; unary.memberAccess = memberAccessNode;
return new TypeCheckResult(valid, currentFields.get(unary.identifier)); var type = currentFields.get(unary.identifier);
unary.setType(type);
return new TypeCheckResult(valid,type );
} else if (unary.statement != null) { } else if (unary.statement != null) {
var result = unary.statement.accept(this); var result = unary.statement.accept(this);
unary.setType(result.getType()); unary.setType(result.getType());
@@ -554,15 +584,19 @@ public class SemanticAnalyzer implements SemanticVisitor {
} }
} else if (unary.statement != null) { } else if (unary.statement != null) {
var result = unary.statement.accept(this); var result = unary.statement.accept(this);
unary.setType(result.getType());
return new TypeCheckResult(result.isValid(), result.getType()); return new TypeCheckResult(result.isValid(), result.getType());
} else if (unary.value != null) { } else if (unary.value != null) {
var result = unary.value.accept(this); var result = unary.value.accept(this);
unary.setType(result.getType());
return new TypeCheckResult(result.isValid(), result.getType()); return new TypeCheckResult(result.isValid(), result.getType());
} else if (unary.memberAccess != null) { } else if (unary.memberAccess != null) {
var result = unary.memberAccess.accept(this); var result = unary.memberAccess.accept(this);
unary.setType(result.getType());
return new TypeCheckResult(result.isValid(), result.getType()); return new TypeCheckResult(result.isValid(), result.getType());
} else if (unary.expression != null) { } else if (unary.expression != null) {
var result = unary.expression.accept(this); var result = unary.expression.accept(this);
unary.setType(result.getType());
return new TypeCheckResult(result.isValid(), result.getType()); return new TypeCheckResult(result.isValid(), result.getType());
} }
@@ -575,11 +609,15 @@ public class SemanticAnalyzer implements SemanticVisitor {
ITypeNode currentType = null; ITypeNode currentType = null;
int start = 0; int start = 0;
if(!memberAccessNode.identifiers.isEmpty()){ if(!memberAccessNode.identifiers.isEmpty()){
if(currentFields.get(memberAccessNode.identifiers.get(0)) != null){ if(currentFields.get(memberAccessNode.identifiers.getFirst()) != null){
memberAccessNode.identifiers.add(0, currentClass.identifier); memberAccessNode.identifiers.addFirst(currentClass.identifier);
start = 1; start++;
} }
} }
if(context.getClasses().get(memberAccessNode.identifiers.getFirst()) == null){
memberAccessNode.identifiers.addFirst(currentClass.identifier);
start++;
}
for (int i = start; i < memberAccessNode.identifiers.size(); i++) { for (int i = start; i < memberAccessNode.identifiers.size(); i++) {
String s = memberAccessNode.identifiers.get(i); String s = memberAccessNode.identifiers.get(i);
@@ -597,7 +635,8 @@ public class SemanticAnalyzer implements SemanticVisitor {
} else { } else {
if (currentType instanceof ReferenceType reference) { if (currentType instanceof ReferenceType reference) {
var currentTypeClass = context.getClass(reference.getIdentifier()); var currentTypeClass = context.getClass(reference.getIdentifier());
memberAccessNode.identifiers.add(i, reference.getIdentifier());
i++;
var currentField = currentTypeClass.getField(s); var currentField = currentTypeClass.getField(s);
if (currentField.getAccessModifier().accessType == EnumAccessModifierNode.PUBLIC) { if (currentField.getAccessModifier().accessType == EnumAccessModifierNode.PUBLIC) {
currentType = currentField.getType(); currentType = currentField.getType();

View File

@@ -8,7 +8,6 @@ public class Node {
public void main() { public void main() {
Compiler compiler = new Compiler(); Compiler compiler = new Compiler();
int i = compiler.add(5, 8); int i = compiler.add(5, 8);
return i;
} }
} }

View File

@@ -10,13 +10,7 @@ compile-javac:
compile-raupenpiler: compile-raupenpiler:
cd ../.. ; mvn -DskipTests install cd ../.. ; mvn -DskipTests install
cd ../.. ; mvn exec:java -DgenJar=true -DgenClass=true -Dexec.mainClass="main.Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output'" cd ../.. ; mvn exec:java -DgenJar=true -DgenClass=true -Dexec.mainClass="main.Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output'"
cp ../main/resources/output/CompilerInput.class .java/resources/output/raupenpiler # cp ../main/resources/output/CompilerInput.class .java/resources/output/raupenpiler
test: compile-javac compile-raupenpiler test-javac test-raupenpiler
test-javac:
# gleich wie bei raupenpiler, kann ich ohne funktionierenden Compiler nicht testen
test-raupenpiler: test-raupenpiler:
# move the compiled class to the test/main folder # move the compiled class to the test/main folder
@@ -29,17 +23,19 @@ test-raupenpiler:
clean: clean:
# clean output folders # clean main output folders
rm -f ../main/resources/output/*.class rm -f ../main/resources/output/*.class
rm -f ../main/resources/output/*.jar rm -f ../main/resources/output/*.jar
# clean resources output folders
rm -f ./resources/output/javac/*.class rm -f ./resources/output/javac/*.class
rm -f ./resources/output/raupenpiler/*.class rm -f ./resources/output/raupenpiler/*.class
rm -f ./resources/output/raupenpiler/*.jar
# clean logs # clean logs
rm -f ../main/resources/logs/*.log rm -f ../main/resources/logs/*
# clean test/java/main folders from .class files for End-to-End tests # clean test/java/main folders from .class files for End-to-End tests
rm -f ./java/main/*.class rm -f ./java/main/*.class
# clean javac output from combinedFeatureTests # clean javac output from every folder
rm -f ./resources/input/combinedFeatureTests/*.class rm -f ./resources/input/*/*.class
rm -f ./resources/input/singleFeatureTests/*.class # clean test results from maven surefire plugin
rm -f ./resources/input/typedAstFeatureTests/*.class rm -f ../../target/surefire-reports/*.txt

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
package main; package main;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import javax.tools.JavaCompiler; import javax.tools.JavaCompiler;
@@ -26,13 +27,17 @@ public class InputFilesTest {
// Assert that the compiler is available // Assert that the compiler is available
assertNotNull(javac, "Java Compiler is not available"); assertNotNull(javac, "Java Compiler is not available");
File folder1 = new File("src/test/resources/input/combinedFeatureTests"); File combinedFeatureTests = new File("src/test/resources/input/combinedFeatureTests");
File folder2 = new File("src/test/resources/input/singleFeatureTests"); File endabgabeTests = new File("src/test/resources/input/endabgabeTests");
File folder3 = new File("src/test/resources/input/typedAstFeatureTests"); File singleFeatureSemanticTests = new File("src/test/resources/input/singleFeatureSemanticTests");
File singleFeatureTests = new File("src/test/resources/input/singleFeatureTests");
File typedAstFeatureTests = new File("src/test/resources/input/typedAstFeatureTests");
List<File> files = getJavaFilesFromDirectory(folder1); List<File> files = getJavaFilesFromDirectory(combinedFeatureTests);
files.addAll(getJavaFilesFromDirectory(folder2)); // files.addAll(getJavaFilesFromDirectory(endabgabeTests));
files.addAll(getJavaFilesFromDirectory(folder3)); // files.addAll(getJavaFilesFromDirectory(singleFeatureSemanticTests));
files.addAll(getJavaFilesFromDirectory(singleFeatureTests));
// files.addAll(getJavaFilesFromDirectory(typedAstFeatureTests));
if (!files.isEmpty()) { if (!files.isEmpty()) {
for (File file : files) { for (File file : files) {
@@ -47,6 +52,133 @@ public class InputFilesTest {
} }
} }
@Test
public void areCombinedFeatureTestsValid() throws IOException {
// Get the system Java compiler
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
// Assert that the compiler is available
assertNotNull(javac, "Java Compiler is not available");
File combinedFeatureTests = new File("src/test/resources/input/combinedFeatureTests");
List<File> files = getJavaFilesFromDirectory(combinedFeatureTests);
if (!files.isEmpty()) {
for (File file : files) {
// Try to compile the file and get the result
int result = javac.run(null, null, null, file.getPath());
// Assert that the compilation succeeded (i.e., the result is zero)
assertEquals(0, result, "Expected compilation success for " + file.getName());
}
} else {
System.out.println("No files found in the directories.");
}
}
@Test
@Disabled
public void areEndabgabeTestsActuallyValid() throws IOException {
// Get the system Java compiler
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
// Assert that the compiler is available
assertNotNull(javac, "Java Compiler is not available");
File endabgabeTests = new File("src/test/resources/input/endabgabeTests");
List<File> files = getJavaFilesFromDirectory(endabgabeTests);
if (!files.isEmpty()) {
for (File file : files) {
// Try to compile the file and get the result
int result = javac.run(null, null, null, file.getPath());
// Assert that the compilation succeeded (i.e., the result is zero)
assertEquals(0, result, "Expected compilation success for " + file.getName());
}
} else {
System.out.println("No files found in the directories.");
}
}
@Test
@Disabled
public void areSingleFeatureSemanticTestsActuallyValid() throws IOException {
// Get the system Java compiler
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
// Assert that the compiler is available
assertNotNull(javac, "Java Compiler is not available");
File singleFeatureSemanticTests = new File("src/test/resources/input/singleFeatureSemanticTests");
List<File> files = getJavaFilesFromDirectory(singleFeatureSemanticTests);
if (!files.isEmpty()) {
for (File file : files) {
// Try to compile the file and get the result
int result = javac.run(null, null, null, file.getPath());
// Assert that the compilation succeeded (i.e., the result is zero)
assertEquals(0, result, "Expected compilation success for " + file.getName());
}
} else {
System.out.println("No files found in the directories.");
}
}
@Test
public void areSingleFeatureTestsActuallyValid() throws IOException {
// Get the system Java compiler
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
// Assert that the compiler is available
assertNotNull(javac, "Java Compiler is not available");
File singleFeatureTests = new File("src/test/resources/input/singleFeatureTests");
List<File> files = getJavaFilesFromDirectory(singleFeatureTests);
if (!files.isEmpty()) {
for (File file : files) {
// Try to compile the file and get the result
int result = javac.run(null, null, null, file.getPath());
// Assert that the compilation succeeded (i.e., the result is zero)
assertEquals(0, result, "Expected compilation success for " + file.getName());
}
} else {
System.out.println("No files found in the directories.");
}
}
@Test
@Disabled
public void areTypedAstFeatureTestsActuallyValid() throws IOException {
// Get the system Java compiler
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
// Assert that the compiler is available
assertNotNull(javac, "Java Compiler is not available");
File typedAstFeatureTests = new File("src/test/resources/input/typedAstFeatureTests");
List<File> files = getJavaFilesFromDirectory(typedAstFeatureTests);
if (!files.isEmpty()) {
for (File file : files) {
// Try to compile the file and get the result
int result = javac.run(null, null, null, file.getPath());
// Assert that the compilation succeeded (i.e., the result is zero)
assertEquals(0, result, "Expected compilation success for " + file.getName());
}
} else {
System.out.println("No files found in the directories.");
}
}
/** /**
* This test method checks if invalid Java files fail to compile as expected. * This test method checks if invalid Java files fail to compile as expected.

View File

@@ -1,28 +1,25 @@
package main; package main;
import org.junit.jupiter.api.Test; import org.junit.runner.RunWith;
import org.antlr.v4.runtime.CharStream; import org.junit.runners.Suite;
import org.antlr.v4.runtime.CharStreams; import parser.ParserTest;
import parser.ScannerTest;
import java.io.IOException; import semantic.EndToTypedAstTest;
import java.nio.file.Paths; import semantic.SemanticTest;
/** /**
* run every test: mvn test * This class is a test suite that runs all the test classes in the project.
* Nutzen dieser Klasse: Eigentlich nicht vorhanden, in der Main gibts nichts zu testen * <p> run: <code> mvn test </code>
* <p> check results in console or <code> target/surefire-reports </code>
*/ */
@RunWith(Suite.class)
@Suite.SuiteClasses({
InputFilesTest.class,
ScannerTest.class,
ParserTest.class,
SemanticTest.class,
EndToTypedAstTest.class
})
public class MainTest { public class MainTest {
@Test // This class remains empty, it is used only as a holder for the above annotations
void test() {
CharStream codeCharStream = null;
try {
codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/CompilerInput.java"));
Main.compileFile(codeCharStream, "src/main/test/resources/output");
} catch (IOException e) {
System.err.println("Error reading the file: " + e.getMessage());
} }
}
}

View File

@@ -1,145 +0,0 @@
package main;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import org.antlr.v4.runtime.CharStream;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class ReflectionsTest {
@Test
public void testSimpleJavaLexerClass() throws ClassNotFoundException, NoSuchMethodException {
Class<?> clazz = Class.forName("parser.generated.SimpleJavaLexer");
// Class Name
assertEquals("parser.generated.SimpleJavaLexer", clazz.getName());
// Constructors
Constructor<?>[] actualConstructors = clazz.getDeclaredConstructors();
assertTrue(actualConstructors.length > 0, "No constructors found");
Constructor<?> expectedConstructor = clazz.getConstructor(CharStream.class);
boolean constructorFound = false;
for (Constructor<?> constructor : actualConstructors) {
if (constructor.equals(expectedConstructor)) {
constructorFound = true;
break;
}
}
assertTrue(constructorFound, "Expected constructor not found in actual constructors");
// Methods
Method[] actualMethodNames = clazz.getDeclaredMethods();
assertTrue(actualMethodNames.length > 0);
Arrays.stream(actualMethodNames).forEach(method -> System.out.println("Method: " + method.getName()));
List<String> expectedMethodNames = Arrays.asList(
"getTokenNames",
"getVocabulary",
"getGrammarFileName",
"getRuleNames",
"getSerializedATN",
"getChannelNames",
"getModeNames",
"getATN",
"makeRuleNames",
"makeLiteralNames",
"makeSymbolicNames"
);
for (Method method : actualMethodNames) {
assertTrue(expectedMethodNames.contains(method.getName()));
}
for (String expectedMethodName : expectedMethodNames) {
boolean methodFound = false;
for (Method method : actualMethodNames) {
if (method.getName().equals(expectedMethodName)) {
methodFound = true;
break;
}
}
assertTrue(methodFound, "Expected method " + expectedMethodName + " not found in actual methods");
}
// Fields
Field[] actualFieldNames = clazz.getDeclaredFields();
assertTrue(actualFieldNames.length > 0);
Arrays.stream(actualFieldNames).forEach(field -> System.out.println("Field: " + field.getName()));
List<String> expectedFieldNames = Arrays.asList(
"_decisionToDFA",
"_sharedContextCache",
"channelNames",
"modeNames",
"ruleNames",
"_LITERAL_NAMES",
"_SYMBOLIC_NAMES",
"VOCABULARY",
"tokenNames",
"_serializedATN",
"_ATN"
);
for (Field field : actualFieldNames) {
assertTrue(expectedFieldNames.contains(field.getName()));
}
}
@Test
public void testSimpleJavaParserClass() throws ClassNotFoundException {
Class<?> clazz = Class.forName("parser.generated.SimpleJavaParser");
// Class Name
assertEquals("parser.generated.SimpleJavaParser", clazz.getName());
// Constructors
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
assertTrue(constructors.length > 0);
// Methods
Method[] methods = clazz.getDeclaredMethods();
assertTrue(methods.length > 0);
Arrays.stream(methods).forEach(method -> System.out.println("Method: " + method.getName()));
// Fields
Field[] fields = clazz.getDeclaredFields();
assertTrue(fields.length > 0);
Arrays.stream(fields).forEach(field -> System.out.println("Field: " + field.getName()));
}
@Test
public void testASTBuilderClass() throws ClassNotFoundException {
Class<?> clazz = Class.forName("parser.astBuilder.ASTBuilder");
// Class Name
assertEquals("parser.astBuilder.ASTBuilder", clazz.getName());
// Constructors
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
assertTrue(constructors.length > 0);
// Methods
Method[] methods = clazz.getDeclaredMethods();
assertTrue(methods.length > 0);
Arrays.stream(methods).forEach(method -> System.out.println("Method: " + method.getName()));
// Fields
Field[] fields = clazz.getDeclaredFields();
assertTrue(fields.length > 0);
Arrays.stream(fields).forEach(field -> System.out.println("Field: " + field.getName()));
}
// Similarly, you can add tests for SemanticAnalyzer and ByteCodeGenerator
}

View File

@@ -1,45 +0,0 @@
package semantic;
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.Test;
import parser.astBuilder.ASTBuilder;
import parser.generated.SimpleJavaLexer;
import parser.generated.SimpleJavaParser;
import java.io.IOException;
import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class BeginnToTAST {
@Test
public void FieldTests() {
SemanticAnalyzer.clearAnalyzer();
CharStream codeCharStream = null;
try {
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/input/johnsTests/FieldTests.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);
var result = SemanticAnalyzer.generateTast(abstractSyntaxTree);
assertTrue(SemanticAnalyzer.errors.isEmpty());
}
}

View File

@@ -281,6 +281,74 @@ public class EndToTypedAstTest {
} }
@Test
public void VariableCompare(){
ASTNode tast = SemanticHelper.generateTypedASTFrom("src/test/resources/input/singleFeatureSemanticTests/VariableCompare.java");
SemanticAnalyzer.generateTast(tast);
assertTrue(SemanticAnalyzer.errors.isEmpty());
}
@Test
public void IfExpressionInt(){
ASTNode tast = SemanticHelper.generateTypedASTFrom("src/test/resources/input/singleFeatureSemanticTests/IfExpressionInt.java");
SemanticAnalyzer.generateTast(tast);
assertFalse(SemanticAnalyzer.errors.isEmpty());
assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst());
}
@Test
public void SelectWrongMethodCauseParameter(){
ASTNode tast = SemanticHelper.generateTypedASTFrom("src/test/resources/input/singleFeatureSemanticTests/SelectWrongMethodCauseParameter.java");
SemanticAnalyzer.generateTast(tast);
assertFalse(SemanticAnalyzer.errors.isEmpty());
assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst());
}
@Test
public void SelectRightMethodCauseParameter(){
ASTNode tast = SemanticHelper.generateTypedASTFrom("src/test/resources/input/singleFeatureSemanticTests/SelectRightMethodCauseParameter.java");
SemanticAnalyzer.generateTast(tast);
assertTrue(SemanticAnalyzer.errors.isEmpty());
}
@Test
public void VariableCalculation(){
ASTNode tast = SemanticHelper.generateTypedASTFrom("src/test/resources/input/singleFeatureSemanticTests/VariableCalculation.java");
SemanticAnalyzer.generateTast(tast);
assertTrue(SemanticAnalyzer.errors.isEmpty());
}
@Test
public void Expression(){
ASTNode tast = SemanticHelper.generateTypedASTFrom("src/test/resources/input/singleFeatureSemanticTests/Expression.java");
SemanticAnalyzer.generateTast(tast);
assertTrue(SemanticAnalyzer.errors.isEmpty());
}
// ------------------ Helpers ------------------ // ------------------ Helpers ------------------
/** /**

View File

@@ -14,6 +14,9 @@ import java.io.IOException;
public class SemanticHelper { public class SemanticHelper {
public static ASTNode generateTypedASTFrom(String filePath) { public static ASTNode generateTypedASTFrom(String filePath) {
SemanticAnalyzer.clearAnalyzer();
CharStream testFile = null; CharStream testFile = null;
try { try {
testFile = CharStreams.fromFileName(filePath); testFile = CharStreams.fromFileName(filePath);

View File

@@ -1,5 +1,441 @@
package semantic; package semantic;
import ast.ASTNode;
import ast.ClassNode;
import ast.ProgramNode;
import ast.expressions.IExpressionNode;
import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.expressions.unaryexpressions.UnaryNode;
import ast.members.ConstructorNode;
import ast.members.FieldNode;
import ast.members.MethodNode;
import ast.parameters.ParameterNode;
import ast.statementexpressions.AssignNode;
import ast.statementexpressions.AssignableNode;
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
import ast.statements.BlockNode;
import ast.statements.ReturnNode;
import ast.type.AccessModifierNode;
import ast.type.EnumValueNode;
import ast.type.ValueNode;
import ast.type.type.BaseType;
import ast.type.type.TypeEnum;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import parser.Helper;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class SemanticTest { public class SemanticTest {
@BeforeEach
public void setUp() {
SemanticAnalyzer.clearAnalyzer();
}
@Test
@DisplayName("Empty Class Test")
public void emptyClassTest() {
ClassNode emptyClass = Helper.generateEmptyClass("EmptyClass");
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(emptyClass);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Multiple Empty Classes Test")
public void multipleEmptyClassesTest() {
ClassNode class1 = Helper.generateEmptyClass("MultipleClasses");
ClassNode class2 = Helper.generateEmptyClass("TestClass2");
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
abstractSyntaxTree.addClass(class2);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Empty Class Test with Constructor")
public void emptyClassWithConstructorTest() {
ClassNode class1 = Helper.generateEmptyClass("EmptyClassWithConstructor");
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Field Test")
public void fieldTest() {
ClassNode class1 = Helper.generateEmptyClass("Field");
class1.addMember(new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"));
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Field Test with Accessmodifier")
public void fieldTestWithModifier() {
ClassNode class1 = Helper.generateEmptyClass("FieldWithAccessModifier");
class1.addMember(new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"));
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Comments Ignore Test")
public void commentsIgnoreTest() {
ClassNode class1 = Helper.generateEmptyClass("Comments");
class1.addMember(new FieldNode(new AccessModifierNode("private"), new BaseType(TypeEnum.INT), "a"));
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Constructor Parameter Test")
public void constructorParameterTest() {
BlockNode block = new BlockNode();
block.addStatement(new ReturnNode(null));
ConstructorNode constructor = new ConstructorNode("public", "ConstructorParameter", block);
constructor.addParameter(new ParameterNode(new BaseType(TypeEnum.INT), "a"));
constructor.addParameter(new ParameterNode(new BaseType(TypeEnum.INT), "b"));
ClassNode class1 = new ClassNode("public", "ConstructorParameter");
class1.addMember(constructor);
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("This Dot Test")
public void thisDotTest() {
BlockNode block = new BlockNode();
MemberAccessNode memberAccess = new MemberAccessNode(true);
memberAccess.addIdentifier("a");
AssignableNode assignable = new AssignableNode(memberAccess);
ValueNode value = new ValueNode(EnumValueNode.INT_VALUE, "1");
IExpressionNode expression = new UnaryNode(value);
block.addStatement(new AssignNode(assignable, expression));
block.addStatement(new ReturnNode(null));
ConstructorNode constructor = new ConstructorNode("public", "ThisDot", block);
ClassNode class1 = new ClassNode("public", "ThisDot");
class1.addMember(new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"));
class1.addMember(constructor);
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Constructor This Dot Test")
public void constructorThisDotTest() {
BlockNode block = new BlockNode();
MemberAccessNode memberAccess = new MemberAccessNode(true);
memberAccess.addIdentifier("a");
AssignableNode assignable = new AssignableNode(memberAccess);
IExpressionNode expression = new UnaryNode("a");
block.addStatement(new AssignNode(assignable, expression));
block.addStatement(new ReturnNode(null));
ConstructorNode constructor = new ConstructorNode("public", "ConstructorThisDot", block);
constructor.addParameter(new ParameterNode(new BaseType(TypeEnum.INT), "a"));
ClassNode class1 = new ClassNode("public", "ConstructorThisDot");
class1.addMember(new FieldNode(new AccessModifierNode("private"), new BaseType(TypeEnum.INT), "a"));
class1.addMember(constructor);
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Void Methoden Test")
public void voidMethodenTest() {
ClassNode class1 = Helper.generateEmptyClass("VoidMethod");
BlockNode block = new BlockNode();
block.addStatement(new ReturnNode(null));
class1.addMember(new MethodNode("public", null, true, "test", block));
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Constructor Method call Test")
public void constructorMethodCallTest() {
BlockNode blockCon = new BlockNode();
MemberAccessNode memberAccess = new MemberAccessNode(true);
memberAccess.addIdentifier("a");
AssignableNode assignable = new AssignableNode(memberAccess);
IExpressionNode expression = new UnaryNode(new MethodCallNode(null, "testMethod"));
blockCon.addStatement(new AssignNode(assignable, expression));
blockCon.addStatement(new ReturnNode(null));
ConstructorNode constructor = new ConstructorNode("public", "ConstructorMethodCall", blockCon);
BlockNode blockMethod = new BlockNode();
blockMethod.addStatement(new ReturnNode(new UnaryNode(new ValueNode(EnumValueNode.INT_VALUE, "1"))));
MethodNode method = new MethodNode("public", new BaseType(TypeEnum.INT), false, "testMethod", blockMethod);
ClassNode class1 = new ClassNode("public", "ConstructorMethodCall");
class1.addMember(new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"));
class1.addMember(constructor);
class1.addMember(method);
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Constructor Method call Parameters Test")
public void constructorMethodCallParametersTest() {
BlockNode blockCon = new BlockNode();
MemberAccessNode memberAccess = new MemberAccessNode(true);
memberAccess.addIdentifier("a");
AssignableNode assignable = new AssignableNode(memberAccess);
MethodCallNode methodCall = new MethodCallNode(null, "testMethod");
methodCall.addExpression(new UnaryNode("a"));
IExpressionNode expression = new UnaryNode(methodCall);
blockCon.addStatement(new AssignNode(assignable, expression));
blockCon.addStatement(new ReturnNode(null));
ConstructorNode constructor = new ConstructorNode("public", "ConstructorMethodCallParameters", blockCon);
constructor.addParameter(new ParameterNode(new BaseType(TypeEnum.INT), "a"));
BlockNode blockMethod = new BlockNode();
blockMethod.addStatement(new ReturnNode(new UnaryNode("a")));
MethodNode method = new MethodNode("public", new BaseType(TypeEnum.INT), false, "testMethod", blockMethod);
method.addParameter(new ParameterNode(new BaseType(TypeEnum.INT), "a"));
ClassNode class1 = new ClassNode("public", "ConstructorMethodCallParameters");
class1.addMember(new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"));
class1.addMember(constructor);
class1.addMember(method);
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Char Test")
public void charTest() {
BlockNode blockCon = new BlockNode();
MemberAccessNode memberAccess = new MemberAccessNode(true);
memberAccess.addIdentifier("a");
AssignableNode assignable = new AssignableNode(memberAccess);
MethodCallNode methodCall = new MethodCallNode(null, "testMethod");
methodCall.addExpression(new UnaryNode("a"));
IExpressionNode expression = new UnaryNode(methodCall);
blockCon.addStatement(new AssignNode(assignable, expression));
blockCon.addStatement(new ReturnNode(null));
ConstructorNode constructor = new ConstructorNode("public", "Char", blockCon);
constructor.addParameter(new ParameterNode(new BaseType(TypeEnum.CHAR), "a"));
BlockNode blockMethod = new BlockNode();
blockMethod.addStatement(new ReturnNode(new UnaryNode("a")));
MethodNode method = new MethodNode("public", new BaseType(TypeEnum.CHAR), false, "testMethod", blockMethod);
method.addParameter(new ParameterNode(new BaseType(TypeEnum.CHAR), "a"));
ClassNode class1 = new ClassNode("public", "Char");
class1.addMember(new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.CHAR), "a"));
class1.addMember(constructor);
class1.addMember(method);
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Null Test")
public void nullTest() {
BlockNode blockCon = new BlockNode();
MemberAccessNode memberAccess = new MemberAccessNode(true);
memberAccess.addIdentifier("a");
AssignableNode assignable = new AssignableNode(memberAccess);
blockCon.addStatement(new AssignNode(assignable, new UnaryNode(new ValueNode(EnumValueNode.NULL_VALUE, "null"))));
blockCon.addStatement(new ReturnNode(null));
ConstructorNode constructor = new ConstructorNode("public", "Null", blockCon);
ClassNode class1 = new ClassNode("public", "Null");
class1.addMember(new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"));
class1.addMember(constructor);
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(class1);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
@Test
@DisplayName("Self Reference Test")
public void selfReferenceTest() {
}
@Test
@DisplayName("Variable Compare Test")
public void variableCompareTest() {
}
@Test
@DisplayName("Variable Calculation Test")
public void variableCalculationTest() {
}
@Test
@DisplayName("Main Method Test")
public void mainMethodTest() {
}
@Test
@DisplayName("While Test")
public void whileTest() {
}
@Test
@DisplayName("Do While Test")
public void doWhileTest() {
}
@Test
@DisplayName("For Test")
public void forTest() {
}
@Test
@DisplayName("Increment Test")
public void incrementTest() {
ClassNode classNode = Helper.generateEmptyClass("Increment");
classNode.addMember(new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a"));
ProgramNode abstractSyntaxTree = new ProgramNode();
abstractSyntaxTree.addClass(classNode);
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
for (Exception runtimeException : SemanticAnalyzer.errors) {
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst);
}
} }

View File

@@ -0,0 +1,10 @@
class VariableCompare{
void trueMethod(boolean a, int c) {
if(a && c == 10){
}
}
}

View File

@@ -1,4 +1,3 @@
// @expected: TypeMismatchException
public class Test{ public class Test{
public void test(int x){ public void test(int x){

View File

@@ -0,0 +1,22 @@
// @expected: TypeMismatchException
public class Test{
public int i;
public boolean b;
public int test(){
return test(b);
}
public void test(int a){
}
public int test(boolean bool){
int ret = 1;
return ret;
}
}

View File

@@ -0,0 +1,34 @@
class VariableCalculation{
int aPlusB(int a, int b){
return a + b;
}
int aMinusB(int a, int b){
return a - b;
}
int aTimeB(int a, int b){
return a * b;
}
int aDivB(int a, int b){
return a / b;
}
int complexCalc (int a, int b){
return a * b / 1 * 3;
}
boolean aSmallerB (int a, int b){
return a < b;
}
boolean aGreaterB (int a, int b){
return a > b;
}
boolean aEqualsB (int a, int b){
return a == b;
}
}

View File

@@ -0,0 +1,30 @@
class VariableCompare{
boolean trueMethod() {
return true;
}
boolean falseMethod(){
return false;
}
boolean trueAndTrueMethod(){
return true && true;
}
boolean trueAndFalseMethod(){
return true && false;
}
boolean falseAndFalseMethod(){
return false && false;
}
boolean trueOrTrueMethod(){
return true || true;
}
boolean falseOrFalseMethod(){
return false || false;
}
}

View File

@@ -1,13 +1,16 @@
public class Klasse1 { public class Compiler {
public int test; Node node;
public int add(int i, int j) {
public int test1() { node = new Node();
test = 5; node.x = 1;
return 1; return i+j;
}
} }
public void test2() { public class Node {
int testInt; public int x;
testInt = this.test1(); public void main() {
Compiler compiler = new Compiler();
int i = compiler.add(5, 8);
} }
} }