Merge branch 'code-generator' of https://gitea.hb.dhbw-stuttgart.de/i22005/NichtHaskell2.0 into NewParser

This commit is contained in:
i22035 2024-07-02 20:10:54 +02:00
commit 4ca6972ccd
77 changed files with 1786 additions and 350 deletions

2
.idea/misc.xml generated
View File

@ -6,7 +6,7 @@
<PerGrammarGenerationSettings> <PerGrammarGenerationSettings>
<option name="fileName" value="$PROJECT_DIR$/src/main/java/parser/SimpleJava.g4" /> <option name="fileName" value="$PROJECT_DIR$/src/main/java/parser/SimpleJava.g4" />
<option name="autoGen" value="true" /> <option name="autoGen" value="true" />
<option name="outputDir" value="C:\Users\Johannes\Documents\Github\JavaCompiler\src\main\java" /> <option name="outputDir" value="C:\Users\ARB00075\Documents\DH\Compilerbau\NichtHaskell2.0\src\main\java" />
<option name="libDir" value="" /> <option name="libDir" value="" />
<option name="encoding" value="" /> <option name="encoding" value="" />
<option name="pkg" value="parser.generated" /> <option name="pkg" value="parser.generated" />

View File

@ -4,6 +4,7 @@ import ast.type.AccessModifierNode;
import ast.members.ConstructorNode; import ast.members.ConstructorNode;
import ast.members.MemberNode; import ast.members.MemberNode;
import ast.members.MethodNode; import ast.members.MethodNode;
import bytecode.visitor.ClassVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable; import visitor.Visitable;
@ -44,4 +45,9 @@ 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,5 +1,6 @@
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;
@ -18,4 +19,9 @@ 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

@ -8,4 +8,6 @@ public interface IExpressionNode extends ASTNode, Visitable {
ITypeNode getType(); ITypeNode getType();
void setType(ITypeNode type);
} }

View File

@ -2,10 +2,14 @@ package ast.expressions.binaryexpressions;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import ast.type.type.*; import ast.type.type.*;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable;
public class BinaryNode implements IExpressionNode { public class BinaryNode implements IExpressionNode, Visitable {
private ITypeNode typeNode;
@Override @Override
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
@ -14,6 +18,16 @@ public class BinaryNode implements IExpressionNode {
@Override @Override
public ITypeNode getType() { public ITypeNode getType() {
return null; return typeNode;
}
@Override
public void setType(ITypeNode type) {
this.typeNode = type;
}
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
} }
} }

View File

@ -1,6 +1,7 @@
package ast.expressions.binaryexpressions; package ast.expressions.binaryexpressions;
import ast.type.type.*; import ast.type.type.*;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -8,6 +9,7 @@ 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;
@ -34,9 +36,10 @@ public class CalculationNode extends BinaryNode {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override @Override
public ITypeNode getType() { public void accept(MethodVisitor methodVisitor) {
return null; methodVisitor.visit(this);
} }
} }

View File

@ -1,6 +1,6 @@
package ast.expressions.binaryexpressions; package ast.expressions.binaryexpressions;
import ast.type.type.*; import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -35,8 +35,8 @@ public class DotNode extends BinaryNode {
} }
@Override @Override
public ITypeNode getType() { public void accept(MethodVisitor methodVisitor) {
return null; methodVisitor.visit(this);
} }
} }

View File

@ -4,6 +4,7 @@ import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
import ast.type.type.*; import ast.type.type.*;
import ast.type.ValueNode; import ast.type.ValueNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -37,8 +38,8 @@ public class DotSubstractionNode extends BinaryNode {
} }
@Override @Override
public ITypeNode getType() { public void accept(MethodVisitor methodVisitor) {
return null; methodVisitor.visit(this);
} }
} }

View File

@ -3,6 +3,7 @@ package ast.expressions.binaryexpressions;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import ast.expressions.unaryexpressions.UnaryNode; import ast.expressions.unaryexpressions.UnaryNode;
import ast.type.type.*; import ast.type.type.*;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -43,8 +44,8 @@ public class NonCalculationNode extends BinaryNode {
} }
@Override @Override
public ITypeNode getType() { public void accept(MethodVisitor methodVisitor) {
return null; methodVisitor.visit(this);
} }
} }

View File

@ -1,13 +1,19 @@
package ast.expressions.unaryexpressions; package ast.expressions.unaryexpressions;
import ast.ASTNode; import ast.ASTNode;
import bytecode.visitor.MethodVisitor;
import ast.type.type.ITypeNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class MemberAccessNode implements ASTNode { public class MemberAccessNode implements ASTNode, Visitable {
public Boolean thisExpr; public Boolean thisExpr;
public List<String> identifiers = new ArrayList<>(); public List<String> identifiers = new ArrayList<>();
private ITypeNode typeNode;
public MemberAccessNode(Boolean thisExpr) { public MemberAccessNode(Boolean thisExpr) {
this.thisExpr = thisExpr; this.thisExpr = thisExpr;
@ -17,4 +23,21 @@ public class MemberAccessNode implements ASTNode {
identifiers.add(identifier); identifiers.add(identifier);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
public ITypeNode getTypeNode() {
return typeNode;
}
public void setTypeNode(ITypeNode typeNode) {
this.typeNode = typeNode;
}
} }

View File

@ -2,12 +2,26 @@ package ast.expressions.unaryexpressions;
import ast.ASTNode; import ast.ASTNode;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable;
public class NotNode implements ASTNode { public class NotNode implements ASTNode, Visitable {
public IExpressionNode expression; public IExpressionNode expression;
public NotNode(IExpressionNode expression) { public NotNode(IExpressionNode expression) {
this.expression = expression; this.expression = expression;
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return null;
}
} }

View File

@ -4,6 +4,7 @@ import ast.expressions.IExpressionNode;
import ast.statements.IStatementNode; import ast.statements.IStatementNode;
import ast.type.type.*; import ast.type.type.*;
import ast.type.ValueNode; import ast.type.ValueNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -61,4 +62,9 @@ public class UnaryNode implements IExpressionNode {
this.type = type; this.type = type;
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@ -0,0 +1,11 @@
package ast.literal;
public class BooleanLiteralNode {
private String value;
public BooleanLiteralNode(String value) {this.value = value;}
public String getValue() {
return value;
}
}

View File

@ -0,0 +1,11 @@
package ast.literal;
public class CharLiteralNode {
public String value;
public CharLiteralNode(String value) {this.value = value;}
public String getValue() {
return value;
}
}

View File

@ -0,0 +1,31 @@
package ast.literal;
import ast.expressions.IExpressionNode;
import ast.type.type.ITypeNode;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
public class LiteralNode implements IExpressionNode {
public String value;
private ITypeNode type;
public LiteralNode(String value, ITypeNode type) {
this.value = value;
this.type = type;
}
public ITypeNode getType() {
return type;
}
public void setType(ITypeNode type) {
this.type = type;
}
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return null;
}
}

View File

@ -3,11 +3,14 @@ package ast.members;
import ast.parameters.ParameterNode; import ast.parameters.ParameterNode;
import ast.statements.BlockNode; import ast.statements.BlockNode;
import ast.type.AccessModifierNode; import ast.type.AccessModifierNode;
import bytecode.visitor.MethodVisitor;
import visitor.Visitable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
public class ConstructorNode extends MethodNode { public class ConstructorNode extends MethodNode implements Visitable {
public AccessModifierNode accessType; public AccessModifierNode accessType;
public String identifier; public String identifier;
public List<ParameterNode> parameters = new ArrayList<>(); public List<ParameterNode> parameters = new ArrayList<>();
@ -23,4 +26,22 @@ public class ConstructorNode extends MethodNode {
parameters.add(parameterNode); parameters.add(parameterNode);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
public boolean isSame(MethodNode methodNode) {
if (!(Objects.equals(this.identifier, methodNode.getIdentifier()))
|| getParameters().size() != methodNode.getParameters().size()) {
return false;
}
for (int i = 0; i < this.getParameters().size(); i++) {
if (!this.getParameters().get(i).type.equals(methodNode.getParameters().get(i).type)) {
return false;
}
}
return true;
}
} }

View File

@ -2,6 +2,8 @@ package ast.members;
import ast.type.AccessModifierNode; import ast.type.AccessModifierNode;
import ast.type.type.ITypeNode; import ast.type.type.ITypeNode;
import bytecode.visitor.ClassVisitor;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable; import visitor.Visitable;
@ -22,4 +24,9 @@ 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

@ -1,11 +1,18 @@
package ast.members; package ast.members;
import ast.statements.BlockNode; import ast.statements.BlockNode;
import bytecode.visitor.MethodVisitor;
import visitor.Visitable;
public class MainMethodNode extends MethodNode { public class MainMethodNode extends MethodNode implements Visitable {
public BlockNode block; public BlockNode block;
public MainMethodNode(BlockNode block) { public MainMethodNode(BlockNode block) {
this.block = block; this.block = block;
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@ -21,7 +21,8 @@ public class MethodNode implements MemberNode, Visitable {
public List<ParameterNode> parameters = new ArrayList<>(); public List<ParameterNode> parameters = new ArrayList<>();
public BlockNode block; public BlockNode block;
public MethodNode() {} public MethodNode() {
}
public MethodNode(String accessModifier, ITypeNode type, Boolean voidType, String identifier, BlockNode block){ public MethodNode(String accessModifier, ITypeNode type, Boolean voidType, String identifier, BlockNode block){
this.accesModifier = new AccessModifierNode(accessModifier); this.accesModifier = new AccessModifierNode(accessModifier);
@ -46,7 +47,7 @@ public class MethodNode implements MemberNode, Visitable {
} }
for (int i = 0; i < this.getParameters().size(); i++) { for (int i = 0; i < this.getParameters().size(); i++) {
if (this.getParameters().get(i).type.equals(methodNode.getParameters().get(i).type)) { if (!this.getParameters().get(i).type.equals(methodNode.getParameters().get(i).type)) {
return false; return false;
} }
} }

View File

@ -0,0 +1,11 @@
package ast.statement;
import ast.statements.IStatementNode;
import java.util.List;
public class BlockStatementNode {
List<IStatementNode> statements;
public BlockStatementNode(List<IStatementNode> statements) {this.statements = statements;}
}

View File

@ -1,6 +1,7 @@
package ast.statementexpressions; package ast.statementexpressions;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -18,4 +19,9 @@ public class AssignNode implements IStatementExpressionNode {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@ -1,11 +1,13 @@
package ast.statementexpressions; package ast.statementexpressions;
import ast.expressions.unaryexpressions.MemberAccessNode; import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.type.type.ITypeNode;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
public class AssignableNode implements IStatementExpressionNode { public class AssignableNode implements IStatementExpressionNode {
public String identifier; public String identifier;
private ITypeNode typeNode;
public MemberAccessNode memberAccess; public MemberAccessNode memberAccess;
@ -22,4 +24,12 @@ public class AssignableNode implements IStatementExpressionNode {
return visitor.analyze(this); return visitor.analyze(this);
} }
public ITypeNode getTypeNode() {
return typeNode;
}
public void setTypeNode(ITypeNode typeNode) {
this.typeNode = typeNode;
}
} }

View File

@ -1,6 +1,7 @@
package ast.statementexpressions; package ast.statementexpressions;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -24,4 +25,9 @@ public class NewDeclarationNode implements IStatementExpressionNode {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@ -2,8 +2,10 @@ package ast.statementexpressions.crementexpressions;
import ast.statementexpressions.AssignableNode; import ast.statementexpressions.AssignableNode;
import ast.statementexpressions.IStatementExpressionNode; import ast.statementexpressions.IStatementExpressionNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import visitor.Visitable;
public class DecrementNode implements IStatementExpressionNode { public class DecrementNode implements IStatementExpressionNode {
public CrementType crementType; public CrementType crementType;
@ -18,5 +20,4 @@ public class DecrementNode implements IStatementExpressionNode {
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this); return visitor.analyze(this);
} }
} }

View File

@ -2,6 +2,7 @@ package ast.statementexpressions.crementexpressions;
import ast.statementexpressions.AssignableNode; import ast.statementexpressions.AssignableNode;
import ast.statementexpressions.IStatementExpressionNode; import ast.statementexpressions.IStatementExpressionNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -18,5 +19,4 @@ public class IncrementNode implements IStatementExpressionNode {
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this); return visitor.analyze(this);
} }
} }

View File

@ -2,11 +2,15 @@ package ast.statementexpressions.methodcallstatementnexpressions;
import ast.ASTNode; import ast.ASTNode;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable;
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, Visitable {
public String identifier; public String identifier;
public List<IExpressionNode> expressions = new ArrayList<>(); public List<IExpressionNode> expressions = new ArrayList<>();
@ -17,4 +21,14 @@ public class ChainedMethodNode implements ASTNode {
public void addExpression(IExpressionNode expression) { public void addExpression(IExpressionNode expression) {
expressions.add(expression); expressions.add(expression);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return null;
}
} }

View File

@ -2,6 +2,7 @@ package ast.statementexpressions.methodcallstatementnexpressions;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import ast.statements.IStatementNode; import ast.statements.IStatementNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -32,4 +33,9 @@ public class MethodCallNode implements IStatementNode {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@ -3,8 +3,12 @@ package ast.statementexpressions.methodcallstatementnexpressions;
import ast.ASTNode; import ast.ASTNode;
import ast.expressions.unaryexpressions.MemberAccessNode; import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.statementexpressions.NewDeclarationNode; import ast.statementexpressions.NewDeclarationNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable;
public class TargetNode implements ASTNode { public class TargetNode implements ASTNode, Visitable {
public Boolean thisTar; public Boolean thisTar;
public MemberAccessNode memberAccess; public MemberAccessNode memberAccess;
public NewDeclarationNode newDeclaration; public NewDeclarationNode newDeclaration;
@ -25,4 +29,15 @@ public class TargetNode implements ASTNode {
public TargetNode(String identifier) { public TargetNode(String identifier) {
this.identifier = identifier; this.identifier = identifier;
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -0,0 +1,10 @@
package ast.statements;
import java.util.List;
public class BlockStatementNode {
List<IStatementNode> statements;
public BlockStatementNode(List<IStatementNode> statements) {this.statements = statements;}
}

View File

@ -1,11 +1,10 @@
package ast.statements; package ast.statements;
import ast.ASTNode;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
public class ElseNode implements IStatementNode { public class ElseNode implements IStatementNode {
BlockNode block; public BlockNode block;
public ElseNode(BlockNode block) { public ElseNode(BlockNode block) {
this.block = block; this.block = block;
@ -14,6 +13,6 @@ public class ElseNode implements IStatementNode {
@Override @Override
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return null; return visitor.analyze(this);
} }
} }

View File

@ -1,6 +1,5 @@
package ast.statements; package ast.statements;
import ast.ASTNode;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -8,9 +7,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class IfElseNode implements IStatementNode { public class IfElseNode implements IStatementNode {
IfNode ifStatement; public IfNode ifStatement;
List<IfNode> elseIfStatements = new ArrayList<>(); public List<IfNode> elseIfStatements = new ArrayList<>();
ElseNode elseStatement; public ElseNode elseStatement;
public IfElseNode(IfNode ifStatement, ElseNode elseNode) { public IfElseNode(IfNode ifStatement, ElseNode elseNode) {
this.ifStatement = ifStatement; this.ifStatement = ifStatement;
@ -23,6 +22,6 @@ public class IfElseNode implements IStatementNode {
@Override @Override
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return null; return visitor.analyze(this);
} }
} }

View File

@ -1,13 +1,12 @@
package ast.statements; package ast.statements;
import ast.ASTNode;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
public class IfNode implements IStatementNode { public class IfNode implements IStatementNode {
IExpressionNode expression; public IExpressionNode expression;
BlockNode block; public BlockNode block;
public IfNode(IExpressionNode expression, BlockNode block) { public IfNode(IExpressionNode expression, BlockNode block) {
this.expression = expression; this.expression = expression;
@ -16,6 +15,6 @@ public class IfNode implements IStatementNode {
@Override @Override
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return null; return visitor.analyze(this);
} }
} }

View File

@ -2,6 +2,7 @@ package ast.statements;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import ast.type.type.*; import ast.type.type.*;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -23,4 +24,9 @@ public class LocalVariableDeclarationNode implements IStatementNode {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@ -1,6 +1,7 @@
package ast.statements; package ast.statements;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -21,4 +22,9 @@ public class ReturnNode implements IStatementNode {
return visitor.analyze(this); return visitor.analyze(this);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@ -5,8 +5,8 @@ import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
public class WhileNode implements IStatementNode { public class WhileNode implements IStatementNode {
IExpressionNode expression; public IExpressionNode expression;
BlockNode block; public BlockNode block;
public WhileNode(IExpressionNode expression, BlockNode block) { public WhileNode(IExpressionNode expression, BlockNode block) {
this.expression = expression; this.expression = expression;
@ -15,6 +15,6 @@ public class WhileNode implements IStatementNode {
@Override @Override
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return null; return visitor.analyze(this);
} }
} }

View File

@ -1,8 +1,12 @@
package ast.type; package ast.type;
import ast.ASTNode; import ast.ASTNode;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor;
import typechecker.TypeCheckResult;
import visitor.Visitable;
public class ValueNode implements ASTNode { public class ValueNode implements ASTNode, Visitable {
public EnumValueNode valueType; public EnumValueNode valueType;
public String value; public String value;
@ -10,4 +14,14 @@ public class ValueNode implements ASTNode {
this.valueType = valueType; this.valueType = valueType;
this.value = value; this.value = value;
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
@Override
public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.analyze(this);
}
} }

View File

@ -2,21 +2,89 @@ package bytecode;
import ast.ProgramNode; import ast.ProgramNode;
import ast.ClassNode; import ast.ClassNode;
import ast.members.MainMethodNode;
import ast.members.MemberNode;
import bytecode.visitor.ProgramVisitor; import bytecode.visitor.ProgramVisitor;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
public class ByteCodeGenerator implements ProgramVisitor { public class ByteCodeGenerator implements ProgramVisitor {
private final String outputDirectoryPath; private JarOutputStream jarOutputStream;
private ByteArrayOutputStream byteArrayOutputStream;
private String outputDirectory;
private boolean generateJar;
private boolean generateClassFiles;
public ByteCodeGenerator(String outputDirectoryPath) { public ByteCodeGenerator(String outputDirectory, boolean generateJar, boolean generateClassFiles) {
this.outputDirectoryPath = outputDirectoryPath; this.outputDirectory = outputDirectory;
this.generateJar = generateJar;
this.generateClassFiles = generateClassFiles;
} }
@Override @Override
public void visit(ProgramNode programNode) { public void visit(ProgramNode programNode) {
if(generateJar) {
byteArrayOutputStream = new ByteArrayOutputStream();
try {
Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
boolean foundMainClass = false;
for (ClassNode classNode : programNode.classes) {
if (foundMainClass) {
break;
}
for (MemberNode memberNode : classNode.members) {
if (memberNode instanceof MainMethodNode) {
manifest.getMainAttributes().putValue("Main-Class", classNode.identifier);
foundMainClass = true;
break;
}
}
}
jarOutputStream = new JarOutputStream(byteArrayOutputStream, manifest);
} catch (IOException e) {
throw new RuntimeException(e);
}
for (ClassNode classDeclarationNode : programNode.classes) { for (ClassNode classDeclarationNode : programNode.classes) {
// ClassCodeGen classCodeGen = new ClassCodeGen(); ClassCodeGen classCodeGen = new ClassCodeGen(jarOutputStream, outputDirectory, generateJar, generateClassFiles);
// classDeclarationNode.accept(classCodeGen); classDeclarationNode.accept(classCodeGen);
}
try {
jarOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
saveJarFile(byteArrayOutputStream.toByteArray(), "output.jar");
} else {
for (ClassNode classDeclarationNode : programNode.classes) {
ClassCodeGen classCodeGen = new ClassCodeGen(jarOutputStream, outputDirectory, generateJar, generateClassFiles);
classDeclarationNode.accept(classCodeGen);
}
}
}
private void saveJarFile(byte[] jarBytes, String jarFileName) {
File directory = new File(outputDirectory);
if (!directory.exists()) {
directory.mkdirs();
}
File jarFile = new File(directory, jarFileName);
try (FileOutputStream fos = new FileOutputStream(jarFile)) {
fos.write(jarBytes);
} catch (IOException e) {
e.printStackTrace();
} }
} }
} }

View File

@ -10,26 +10,35 @@ 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;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
public class ClassCodeGen implements ClassVisitor { public class ClassCodeGen implements ClassVisitor {
private Mapper mapper; private Mapper mapper;
private ClassWriter classWriter; private ClassWriter classWriter;
private final String outputDirectoryPath; private JarOutputStream jarOutputStream;
private String outputDirectory;
private boolean generateJar;
private boolean generateClassFiles;
public ClassCodeGen(String outputDirectoryPath) { public ClassCodeGen(JarOutputStream jarOutputStream, String outputDirectory, boolean generateJar, boolean generateClassFiles) {
this.outputDirectoryPath = outputDirectoryPath;
mapper = new Mapper(); mapper = new Mapper();
this.jarOutputStream = jarOutputStream;
this.outputDirectory = outputDirectory;
this.generateJar = generateJar;
this.generateClassFiles = generateClassFiles;
} }
@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) {
@ -40,29 +49,31 @@ public class ClassCodeGen implements ClassVisitor {
} }
} }
classWriter.visitEnd(); if (generateJar) {
printIntoClassFile(classWriter.toByteArray(), classNode.identifier); writeToJar(classWriter.toByteArray(), classNode.identifier);
}
if (generateClassFiles) {
printIntoClassFile(classWriter.toByteArray(), classNode.identifier, outputDirectory);
}
classWriter.visitEnd(); classWriter.visitEnd();
} }
@Override @Override
public void visit(FieldNode fieldNode) { public void visit(FieldNode fieldNode) {
if(fieldNode.type instanceof BaseType baseTypeNode){ if (fieldNode.type instanceof BaseType) {
// classWriter.visitField(mapper.mapAccessTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(baseTypeNode.enumType), null, null ); classWriter.visitField(mapper.mapAccessTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar((BaseType) fieldNode.type), null, null);
} }
classWriter.visitEnd(); classWriter.visitEnd();
} }
private void printIntoClassFile(byte[] byteCode, String name) { private void printIntoClassFile(byte[] byteCode, String name, String outputDirectory) {
// String outputDirectoryPath = "src/main/resources/output"; File directory = new File(outputDirectory);
// System.out.println("Output directory path: " + outputDirectoryPath);
File directory = new File(outputDirectoryPath);
if (!directory.exists()) { if (!directory.exists()) {
directory.mkdirs(); directory.mkdirs();
} }
String filePath = outputDirectoryPath + "/" + name + ".class"; String filePath = outputDirectory + "/" + name + ".class";
try { try {
FileOutputStream fileOutputStream = new FileOutputStream(filePath); FileOutputStream fileOutputStream = new FileOutputStream(filePath);
fileOutputStream.write(byteCode); fileOutputStream.write(byteCode);
@ -71,4 +82,15 @@ public class ClassCodeGen implements ClassVisitor {
e.printStackTrace(); e.printStackTrace();
} }
} }
private void writeToJar(byte[] byteCode, String className) {
try {
JarEntry jarEntry = new JarEntry(className + ".class");
jarOutputStream.putNextEntry(jarEntry);
jarOutputStream.write(byteCode);
jarOutputStream.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
}
} }

View File

@ -1,41 +1,60 @@
package bytecode; package bytecode;
import ast.parameters.ParameterNode;
import ast.type.*; import ast.type.*;
import ast.type.type.BaseType;
import ast.type.type.ReferenceType;
import ast.type.type.TypeEnum;
import org.objectweb.asm.Opcodes;
import java.util.List;
public class Mapper { public class Mapper {
// public int mapAccessTypeToOpcode(AccessModifierNode type) { public int mapAccessTypeToOpcode(AccessModifierNode accessModifierNode) {
// switch (type.enumAccessTypeNode) { switch (accessModifierNode.accessType) {
// case EnumAccessTypeNode.PUBLIC: case EnumAccessModifierNode.PUBLIC:
// return Opcodes.ACC_PUBLIC; return Opcodes.ACC_PUBLIC;
// case EnumAccessTypeNode.PRIVATE: case EnumAccessModifierNode.PRIVATE:
// return Opcodes.ACC_PRIVATE; return Opcodes.ACC_PRIVATE;
// } case EnumAccessModifierNode.PUBLIC_STATIC:
// return 0; return Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;
// } case EnumAccessModifierNode.PRIVATE_STATIC:
return Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC;
}
return 0;
}
// public String generateMethodDescriptor(BaseTypeNode baseTypeNode, ParameterListNode parameterListNode) { public String generateMethodDescriptor(BaseType type, List<ParameterNode> parameters) {
// String descriptor = "("; String descriptor = "(";
// for(ParameterNode parameterNode : parameterListNode.parameters) { for (ParameterNode parameterNode : parameters) {
// descriptor += getTypeChar(EnumTypeNode.INT); if(parameterNode.type instanceof BaseType) {
// } descriptor += getTypeChar((BaseType) parameterNode.type);
// descriptor += ")"; } else {
// descriptor += getTypeChar(baseTypeNode.enumType); ReferenceType referenceType = (ReferenceType) parameterNode.type;
// return descriptor; descriptor += "L" + referenceType.getIdentifier() + ";";
// } }
}
descriptor += ")";
descriptor += getTypeChar(type);
return descriptor;
}
// public String getTypeChar(TypeEnum enumTypeNode) { public String getTypeChar(BaseType type) {
// String typeChar = ""; String typeChar = "";
// switch (enumTypeNode) { switch (type.getTypeEnum()) {
// case TypeEnum.INT: case TypeEnum.INT:
// typeChar = "I"; typeChar = "I";
// break; break;
// case TypeEnum.CHAR: case TypeEnum.CHAR:
// typeChar = "C"; typeChar = "C";
// break; break;
// case TypeEnum.BOOLEAN: case TypeEnum.BOOL:
// typeChar = "Z"; typeChar = "Z";
// break; break;
// } case TypeEnum.VOID:
// return typeChar; typeChar = "V";
// } break;
}
return typeChar;
}
} }

View File

@ -1,9 +1,31 @@
package bytecode; package bytecode;
import ast.expressions.IExpressionNode;
import ast.expressions.binaryexpressions.*;
import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.expressions.unaryexpressions.NotNode;
import ast.expressions.unaryexpressions.UnaryNode;
import ast.members.ConstructorNode; import ast.members.ConstructorNode;
import ast.members.MainMethodNode;
import ast.members.MethodNode; import ast.members.MethodNode;
import ast.parameters.ParameterNode;
import ast.statementexpressions.AssignNode;
import ast.statementexpressions.NewDeclarationNode;
import ast.statementexpressions.crementexpressions.CrementType;
import ast.statementexpressions.crementexpressions.DecrementNode;
import ast.statementexpressions.crementexpressions.IncrementNode;
import ast.statementexpressions.methodcallstatementnexpressions.ChainedMethodNode;
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
import ast.statementexpressions.methodcallstatementnexpressions.TargetNode;
import ast.statements.*;
import ast.type.ValueNode;
import ast.type.type.BaseType;
import ast.type.type.ReferenceType;
import ast.type.type.TypeEnum;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -25,70 +47,489 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
localVaribales = new ArrayList<>(); localVaribales = new ArrayList<>();
} }
// Method nodes
@Override @Override
public void visit(ConstructorNode constructorNode) { public void visit(ConstructorNode constructorNode) {
// methodVisitor = methodVisitor =
// classWriter.visitMethod(mapper.mapAccessTypeToOpcode(constructorNode.visibility), classWriter.visitMethod(mapper.mapAccessTypeToOpcode(constructorNode.accessType),
// "<init>", "<init>",
// "()V", mapper.generateMethodDescriptor(new BaseType(TypeEnum.VOID), constructorNode.parameters),
// null, null,
// null); null);
methodVisitor.visitCode(); methodVisitor.visitCode();
localVaribales.add("this");
// Add all method parameters to localVariables
for (ParameterNode parameterNode : constructorNode.parameters) {
localVaribales.add(parameterNode.identifier);
}
methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(1, 1); // Visit all statements
for (IStatementNode statementNode : constructorNode.block.statements) {
if (statementNode != null) {
statementNode.accept(this);
}
}
methodVisitor.visitMaxs(0, 0);
methodVisitor.visitEnd();
}
@Override
public void visit(MainMethodNode mainMethodNode) {
methodVisitor = classWriter.visitMethod(mapper.mapAccessTypeToOpcode(mainMethodNode.accesModifier),
mainMethodNode.getIdentifier(),
"([Ljava/lang/String;)V",
null,
null);
methodVisitor.visitCode();
localVaribales.add("this");
localVaribales.add("args");
// Visit all statements
for (IStatementNode statementNode : mainMethodNode.block.statements) {
statementNode.accept(this);
}
methodVisitor.visitMaxs(0, 0);
methodVisitor.visitEnd(); methodVisitor.visitEnd();
} }
@Override @Override
public void visit(MethodNode methodNode) { public void visit(MethodNode methodNode) {
// if (methodNode.type instanceof BaseTypeNode baseTypeNode) { methodVisitor = classWriter.visitMethod(mapper.mapAccessTypeToOpcode(methodNode.accesModifier),
// methodVisitor = classWriter.visitMethod(mapper.mapAccessTypeToOpcode(methodNode.visibility), methodNode.getIdentifier(),
// methodNode.identifier, mapper.generateMethodDescriptor((BaseType) methodNode.getType(), methodNode.parameters),
// mapper.generateMethodDescriptor(baseTypeNode, methodNode.parameters), null,
// null, null);
// null);
methodVisitor.visitCode(); methodVisitor.visitCode();
localVaribales.add("this"); localVaribales.add("this");
// for (ParameterNode parameterNode : methodNode.parameters.parameters) { // Add all method parameters to localVariables
// localVaribales.add(parameterNode.identifier); for (ParameterNode parameterNode : methodNode.parameters) {
// } localVaribales.add(parameterNode.identifier);
//test();
methodVisitor.visitMaxs(1, localVaribales.size());
methodVisitor.visitEnd();
// }
} }
// public void test() { // Visit all statements
// Label start = new Label(); for (IStatementNode statementNode : methodNode.block.statements) {
// Label loop = new Label(); statementNode.accept(this);
// Label end = new Label(); }
// methodVisitor.visitLabel(start);
// //methodVisitor.visitVarInsn(Opcodes.ICONST_M1, 99); methodVisitor.visitMaxs(0, 0);
// //methodVisitor.visitInsn(Opcodes.ICONST_5); methodVisitor.visitEnd();
// methodVisitor.visitLdcInsn(99); }
// // methodVisitor.visitInsn(Opcodes.ICONST_0);
// //methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
// methodVisitor.visitVarInsn(Opcodes.ISTORE, 1); // Binary expressions
// methodVisitor.visitLabel(loop);
// methodVisitor.visitVarInsn(Opcodes.ILOAD, 1); @Override
// methodVisitor.visitInsn(Opcodes.ICONST_5); public void visit(BinaryNode binaryNode) {
// methodVisitor.visitJumpInsn(Opcodes.IF_ICMPGE, end); binaryNode.accept(this);
// methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, }
// "java/lang/System", "out",
// "Ljava/io/PrintStream;"); @Override
// methodVisitor.visitLdcInsn("Bytecode"); public void visit(CalculationNode calculationNode) {
// methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, if (calculationNode.dotExpression != null) {
// "java/io/PrintStream", "println", calculationNode.dotExpression.accept(this);
// "(Ljava/lang/String;)V", false); }
// methodVisitor.visitIincInsn(1, 1); if (calculationNode.calculationExpression != null) {
// methodVisitor.visitJumpInsn(Opcodes.GOTO, loop); calculationNode.calculationExpression.accept(this);
// methodVisitor.visitLabel(end); }
// methodVisitor.visitVarInsn(Opcodes.ILOAD, 1); if (calculationNode.operator != null) {
// methodVisitor.visitInsn(Opcodes.IRETURN); switch (calculationNode.operator) {
// methodVisitor.visitEnd(); case PLUS:
// } methodVisitor.visitInsn(IADD);
break;
case MINUS:
methodVisitor.visitInsn(ISUB);
break;
}
}
}
@Override
public void visit(DotNode dotNode) {
if (dotNode.dotExpression != null) {
dotNode.dotExpression.accept(this);
}
if (dotNode.dotSubstractionExpression != null) {
dotNode.dotSubstractionExpression.accept(this);
}
if (dotNode.operator != null) {
switch (dotNode.operator) {
case DIV:
methodVisitor.visitInsn(IDIV);
break;
case MULT:
methodVisitor.visitInsn(IMUL);
break;
case MOD:
methodVisitor.visitInsn(IREM);
break;
}
}
}
@Override
public void visit(DotSubstractionNode dotSubstractionNode) {
if (dotSubstractionNode.value != null) {
dotSubstractionNode.value.accept(this);
} else if (dotSubstractionNode.identifier != null) {
methodVisitor.visitVarInsn(ILOAD, localVaribales.indexOf(dotSubstractionNode.identifier));
} else if (dotSubstractionNode.memberAccess != null) {
dotSubstractionNode.memberAccess.accept(this);
} else if (dotSubstractionNode.methodCall != null) {
dotSubstractionNode.methodCall.accept(this);
} else if (dotSubstractionNode.calculationExpression != null) {
dotSubstractionNode.calculationExpression.accept(this);
}
}
@Override
public void visit(NonCalculationNode nonCalculationNode) {
Label labelFalse = new Label();
Label labelTrue = new Label();
// TODO: Null check
switch (nonCalculationNode.operator) {
case AND:
nonCalculationNode.unaryExpression.accept(this);
methodVisitor.visitJumpInsn(IFEQ, labelFalse); // Value compared to 0 (false)
nonCalculationNode.expression.accept(this);
methodVisitor.visitJumpInsn(IFEQ, labelFalse);
break;
case OR:
nonCalculationNode.unaryExpression.accept(this);
methodVisitor.visitJumpInsn(IFNE, labelTrue);
nonCalculationNode.expression.accept(this);
methodVisitor.visitJumpInsn(IFEQ, labelFalse);
break;
case GREATER:
nonCalculationNode.unaryExpression.accept(this);
nonCalculationNode.expression.accept(this);
methodVisitor.visitJumpInsn(IF_ICMPLE, labelFalse);
break;
case LESS:
nonCalculationNode.unaryExpression.accept(this);
nonCalculationNode.expression.accept(this);
methodVisitor.visitJumpInsn(IF_ICMPGE, labelFalse);
break;
case GREATER_EQUAL:
nonCalculationNode.unaryExpression.accept(this);
nonCalculationNode.expression.accept(this);
methodVisitor.visitJumpInsn(IF_ICMPLT, labelFalse);
break;
case LESS_EQUAL:
nonCalculationNode.unaryExpression.accept(this);
nonCalculationNode.expression.accept(this);
methodVisitor.visitJumpInsn(IF_ICMPGT, labelFalse);
break;
case EQUAL:
nonCalculationNode.unaryExpression.accept(this);
nonCalculationNode.expression.accept(this);
if (nonCalculationNode.unaryExpression.getType() instanceof BaseType && nonCalculationNode.expression.getType() instanceof BaseType) {
methodVisitor.visitJumpInsn(IF_ICMPNE, labelFalse);
} else {
methodVisitor.visitJumpInsn(IF_ACMPNE, labelFalse);
}
break;
case NOT_EQUAL:
nonCalculationNode.unaryExpression.accept(this);
nonCalculationNode.expression.accept(this);
if (nonCalculationNode.unaryExpression.getType() instanceof BaseType && nonCalculationNode.expression.getType() instanceof BaseType) {
methodVisitor.visitJumpInsn(IF_ACMPEQ, labelFalse);
} else {
methodVisitor.visitJumpInsn(IF_ACMPEQ, labelFalse);
}
break;
}
Label labelEndLogicalExpression = new Label();
methodVisitor.visitLabel(labelTrue);
methodVisitor.visitInsn(ICONST_1); // true
methodVisitor.visitJumpInsn(GOTO, labelEndLogicalExpression);
methodVisitor.visitLabel(labelFalse);
methodVisitor.visitInsn(ICONST_0); // false
methodVisitor.visitLabel(labelEndLogicalExpression);
}
// Unary expressions
@Override
public void visit(MemberAccessNode memberAccessNode) {
if (memberAccessNode.thisExpr) {
// methodVisitor.visitFieldInsn(PUTFIELD, memberAccessNode.identifiers.get(0), memberAccessNode.identifiers.get(1), );
}
}
@Override
public void visit(NotNode notNode) {
Label labelFalse = new Label();
Label labelTrue = new Label();
notNode.expression.accept(this);
methodVisitor.visitJumpInsn(Opcodes.IFNE, labelFalse); // false if value is true (value != 0)
Label labelEndLogicalExpression = new Label();
methodVisitor.visitLabel(labelTrue);
methodVisitor.visitInsn(ICONST_1); // true
methodVisitor.visitJumpInsn(GOTO, labelEndLogicalExpression);
methodVisitor.visitLabel(labelFalse);
methodVisitor.visitInsn(ICONST_0); // false
methodVisitor.visitLabel(labelEndLogicalExpression);
}
@Override
public void visit(UnaryNode unaryNode) {
if (unaryNode.thisExp != null) {
methodVisitor.visitVarInsn(ALOAD, 0); // this
} else if (unaryNode.identifier != null) {
methodVisitor.visitVarInsn(ILOAD, localVaribales.indexOf(unaryNode.identifier));
} else if (unaryNode.memberAccess != null) {
unaryNode.memberAccess.accept(this);
} else if (unaryNode.value != null) {
unaryNode.value.accept(this);
} else if (unaryNode.notExpression != null) {
unaryNode.notExpression.accept(this);
} else if (unaryNode.statement != null) {
unaryNode.statement.accept(this);
} else if (unaryNode.expression != null) {
unaryNode.expression.accept(this);
}
}
// Statements
@Override
public void visit(IfElseNode ifElseNode) {
Label elseLabel = new Label();
Label[] elseIfLabels = new Label[ifElseNode.elseIfStatements.size()];
for (int i = 0; i < ifElseNode.elseIfStatements.size(); i++) {
elseIfLabels[i] = new Label();
}
ifElseNode.ifStatement.expression.accept(this);
if (ifElseNode.elseIfStatements.isEmpty()) {
// No else if
methodVisitor.visitJumpInsn(IFEQ, elseLabel);
} else {
// else if statements
methodVisitor.visitJumpInsn(IFEQ, elseIfLabels[0]);
}
ifElseNode.ifStatement.block.accept(this); // accept if block
Label endLabel = new Label();
methodVisitor.visitJumpInsn(GOTO, endLabel);
for (int i = 0; i < ifElseNode.elseIfStatements.size(); i++) {
methodVisitor.visitLabel(elseIfLabels[i]);
ifElseNode.elseIfStatements.get(i).expression.accept(this);
if (i + 1 < elseIfLabels.length) {
// at least one more else if
methodVisitor.visitJumpInsn(IFEQ, elseIfLabels[i + 1]);
} else {
methodVisitor.visitJumpInsn(IFEQ, elseLabel);
}
ifElseNode.elseIfStatements.get(i).block.accept(this);
methodVisitor.visitJumpInsn(GOTO, endLabel);
}
if (ifElseNode.elseStatement != null) {
methodVisitor.visitLabel(elseLabel);
ifElseNode.elseStatement.block.accept(this);
}
methodVisitor.visitLabel(endLabel);
}
@Override
public void visit(LocalVariableDeclarationNode localVariableDeclarationNode) {
if (localVariableDeclarationNode.expression != null) {
// Process expression
localVariableDeclarationNode.expression.accept(this);
// Store result of expression in variable
if (localVaribales.contains(localVariableDeclarationNode.identifier)) {
if (localVariableDeclarationNode.type instanceof BaseType) {
methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(localVariableDeclarationNode.identifier));
} else if (localVariableDeclarationNode.type instanceof ReferenceType) {
methodVisitor.visitVarInsn(ASTORE, localVaribales.indexOf(localVariableDeclarationNode.identifier));
}
} else {
localVaribales.add(localVariableDeclarationNode.identifier);
if (localVariableDeclarationNode.type instanceof BaseType) {
methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(localVariableDeclarationNode.identifier));
} else if (localVariableDeclarationNode.type instanceof ReferenceType) {
methodVisitor.visitVarInsn(ASTORE, localVaribales.indexOf(localVariableDeclarationNode.identifier));
}
}
} else {
if (!localVaribales.contains(localVariableDeclarationNode.identifier)) {
localVaribales.add(localVariableDeclarationNode.identifier);
}
}
}
@Override
public void visit(AssignNode assignNode) {
// Process expression
if (assignNode.expression instanceof IncrementNode) {
IncrementNode incrementNode = (IncrementNode) assignNode.expression;
if (incrementNode.crementType.equals(CrementType.PREFIX)) { // ++i
methodVisitor.visitIincInsn(localVaribales.indexOf(incrementNode.assignableExpression.identifier), 1);
assign(assignNode);
} else if (incrementNode.crementType.equals(CrementType.SUFFIX)) { // Suffix: i++
assign(assignNode);
methodVisitor.visitIincInsn(localVaribales.indexOf(incrementNode.assignableExpression.identifier), 1);
}
} else if (assignNode.expression instanceof DecrementNode) {
DecrementNode decrementNode = (DecrementNode) assignNode.expression;
if (decrementNode.crementType.equals(CrementType.PREFIX)) {
methodVisitor.visitIincInsn(localVaribales.indexOf(decrementNode.assignableExpression.identifier), -1);
assign(assignNode);
} else if (decrementNode.crementType.equals(CrementType.SUFFIX)) {
assign(assignNode);
methodVisitor.visitIincInsn(localVaribales.indexOf(decrementNode.assignableExpression.identifier), 1);
}
} else {
assignNode.expression.accept(this);
}
}
private void assign(AssignNode assignNode) {
// Store result of expression in variable
if (assignNode.assignable.memberAccess.thisExpr) {
// Global var
methodVisitor.visitVarInsn(ALOAD, 0);
if (assignNode.expression instanceof BaseType) {
//methodVisitor.visitFieldInsn(PUTFIELD, class name, var identifier, mapper.getTypeChar(((BaseTypeNode) type).enumType));
} else if (assignNode.expression instanceof ReferenceType) {
//methodVisitor.visitFieldInsn(PUTFIELD, class name, var identifier, "L"class name object +";");
}
} else {
// Local var
if (assignNode.expression instanceof BaseType) {
methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(assignNode.assignable.identifier));
} else if (assignNode.expression instanceof ReferenceType) {
methodVisitor.visitVarInsn(ASTORE, localVaribales.indexOf(assignNode.assignable.identifier));
}
}
}
@Override
public void visit(NewDeclarationNode newDeclarationNode) {
methodVisitor.visitTypeInsn(NEW, newDeclarationNode.identifier);
methodVisitor.visitInsn(DUP);
for (IExpressionNode expressionNode : newDeclarationNode.expressions) {
expressionNode.accept(this);
}
// TODO
//methodVisitor.visitMethodInsn(INVOKESPECIAL, class name, "<init>", mapper.generateMethodDescriptor(), false);
// TODO: kann ein Field auch definiert werden? Abfrage ob local var oder field
localVaribales.add(newDeclarationNode.identifier);
}
@Override
public void visit(ValueNode valueNode) {
switch (valueNode.valueType) {
case INT_VALUE:
int intValue = Integer.parseInt(valueNode.value);
if (intValue >= Byte.MIN_VALUE && intValue <= Byte.MAX_VALUE) { // load int as byte
methodVisitor.visitIntInsn(BIPUSH, intValue);
} else if (intValue >= Short.MIN_VALUE && intValue <= Short.MAX_VALUE) { // load int as short
methodVisitor.visitIntInsn(SIPUSH, intValue);
} else { // load int as const
methodVisitor.visitLdcInsn(intValue);
}
break;
case BOOLEAN_VALUE:
if (valueNode.value.equals("true")) {
methodVisitor.visitInsn(ICONST_1);
} else {
methodVisitor.visitInsn(ICONST_0);
}
break;
case CHAR_VALUE:
char charValue = valueNode.value.charAt(0);
if (charValue <= Byte.MAX_VALUE) { // load char as byte
methodVisitor.visitIntInsn(BIPUSH, charValue);
} else if (charValue <= Short.MAX_VALUE) { // load char as short
methodVisitor.visitIntInsn(SIPUSH, charValue);
} else { // load char as const
methodVisitor.visitLdcInsn(charValue);
}
break;
case NULL_VALUE:
methodVisitor.visitInsn(ACONST_NULL);
break;
}
}
@Override
public void visit(ReturnNode returnNode) {
if (returnNode.voidReturn) { // Return nothing
methodVisitor.visitInsn(RETURN);
} else { // Return something
// Process expression
returnNode.expression.accept(this);
// Return result of expression
if (returnNode.expression.getType() instanceof BaseType) {
methodVisitor.visitInsn(IRETURN);
} else if (returnNode.expression.getType() instanceof ReferenceType) {
methodVisitor.visitInsn(ARETURN);
}
}
}
@Override
public void visit(WhileNode whileNode) {
Label loopLabel = new Label();
Label endOfLoopLabel = new Label();
methodVisitor.visitLabel(loopLabel);
// while loop
whileNode.expression.accept(this);
methodVisitor.visitJumpInsn(IFEQ, endOfLoopLabel); // if condition is false, jump out of loop
// TODO: Unterscheidung bei increment/decrement der for Schleife
if (whileNode.block.statements.size() == 2) { // For loop
whileNode.block.statements.get(0).accept(this);
} else {
whileNode.block.statements.get(0).accept(this);
}
whileNode.block.accept(this);
methodVisitor.visitJumpInsn(GOTO, loopLabel);
methodVisitor.visitLabel(endOfLoopLabel);
}
@Override
public void visit(ChainedMethodNode chainedMethodNode) {
}
@Override
public void visit(MethodCallNode methodCallNode) {
}
@Override
public void visit(TargetNode targetNode) {
}
} }

View File

@ -1,9 +1,57 @@
package bytecode.visitor; package bytecode.visitor;
import ast.expressions.binaryexpressions.*;
import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.expressions.unaryexpressions.NotNode;
import ast.expressions.unaryexpressions.UnaryNode;
import ast.members.ConstructorNode; import ast.members.ConstructorNode;
import ast.members.MainMethodNode;
import ast.members.MethodNode; import ast.members.MethodNode;
import ast.statementexpressions.AssignNode;
import ast.statementexpressions.AssignableNode;
import ast.statementexpressions.NewDeclarationNode;
import ast.statementexpressions.crementexpressions.DecrementNode;
import ast.statementexpressions.crementexpressions.IncrementNode;
import ast.statementexpressions.methodcallstatementnexpressions.ChainedMethodNode;
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
import ast.statementexpressions.methodcallstatementnexpressions.TargetNode;
import ast.statements.*;
import ast.type.ValueNode;
public interface MethodVisitor { public interface MethodVisitor {
// members
void visit(ConstructorNode constructorNode); void visit(ConstructorNode constructorNode);
void visit(MethodNode methodNode); void visit(MethodNode methodNode);
void visit(MainMethodNode mainMethodNode);
// Binary expressions
void visit(BinaryNode binaryNode);
void visit(CalculationNode calculationNode);
void visit(DotNode dotNode);
void visit(DotSubstractionNode dotSubstractionNode);
void visit(NonCalculationNode nonCalculationNode);
// Unary expressions
void visit(MemberAccessNode memberAccessNode);
void visit(NotNode notExpressionNode);
void visit(UnaryNode unaryExpressionNode);
// statements
void visit(IfElseNode ifElseNode);
void visit(LocalVariableDeclarationNode localVariableDeclarationNode);
void visit(ReturnNode returnNode);
void visit(WhileNode whileNode);
// statement expression
void visit(ChainedMethodNode chainedMethodNode);
void visit(MethodCallNode methodCallNode);
void visit(TargetNode targetNode);
void visit(AssignNode assignNode);
void visit(NewDeclarationNode newDeclarationNode);
// type
void visit(ValueNode valueNode);
} }

View File

@ -9,6 +9,7 @@ import java.util.Objects;
import ast.*; import ast.*;
import ast.expressions.IExpressionNode; import ast.expressions.IExpressionNode;
import ast.expressions.binaryexpressions.*; import ast.expressions.binaryexpressions.*;
import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.expressions.unaryexpressions.UnaryNode; import ast.expressions.unaryexpressions.UnaryNode;
import ast.members.ConstructorNode; import ast.members.ConstructorNode;
import ast.members.FieldNode; import ast.members.FieldNode;
@ -21,8 +22,13 @@ import ast.statementexpressions.NewDeclarationNode;
import ast.statementexpressions.crementexpressions.DecrementNode; import ast.statementexpressions.crementexpressions.DecrementNode;
import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.crementexpressions.IncrementNode;
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode; import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
import ast.statementexpressions.methodcallstatementnexpressions.TargetNode;
import ast.statements.*; import ast.statements.*;
import ast.type.AccessModifierNode;
import ast.type.EnumAccessModifierNode;
import ast.type.ValueNode;
import ast.type.type.*; import ast.type.type.*;
import com.sun.jdi.IntegerType;
import semantic.context.Context; import semantic.context.Context;
import semantic.exceptions.*; import semantic.exceptions.*;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
@ -134,26 +140,20 @@ public class SemanticAnalyzer implements SemanticVisitor {
} }
} }
// Check if this method is already declared
currentMethodReturnType = methodNode.getType(); currentMethodReturnType = methodNode.getType();
currentNullType = currentMethodReturnType; // Solange nicht in einem Assign oder Methoden-Aufruf dieser Typ currentNullType = currentMethodReturnType;
ITypeNode resultType = new BaseType(TypeEnum.VOID);
// gesetzt ist, ist dieser der Rückgabewert der Methode
var result = methodNode.block.accept(this); var result = methodNode.block.accept(this);
valid = valid && result.isValid(); valid = valid && result.isValid();
currentScope.popScope(); currentScope.popScope();
resultType = result.getType(); ITypeNode resultType = result.getType();
if (resultType == null) { if (resultType == null) {
resultType = new BaseType(TypeEnum.VOID); resultType = new BaseType(TypeEnum.VOID);
} }
if (!resultType.equals(methodNode.getType())) { if (methodNode.getType() == null) {
errors.add(new TypeMismatchException("Method-Declaration " + methodNode.getIdentifier() + " with type " methodNode.setType(new BaseType(TypeEnum.VOID));
+ methodNode.getType() + " has at least one Mismatching return Type:"));
valid = false;
} }
return new TypeCheckResult(valid, resultType); return new TypeCheckResult(valid, resultType);
@ -174,65 +174,98 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override @Override
public TypeCheckResult analyze(IfNode toCheck) { public TypeCheckResult analyze(IfNode toCheck) {
toCheck.block.accept(this);
var resultExpression = toCheck.expression.accept(this);
if (resultExpression.isValid()) {
if (!resultExpression.getType().equals(new BaseType(TypeEnum.BOOL))) {
errors.add(new TypeMismatchException("Expression must be Boolean"));
return new TypeCheckResult(false, new BaseType(TypeEnum.VOID));
}
}
return new TypeCheckResult(true, null); return new TypeCheckResult(true, null);
} }
@Override @Override
public TypeCheckResult analyze(ReturnNode toCheck) { public TypeCheckResult analyze(ReturnNode toCheck) {
if (toCheck.expression != null) {
if(toCheck.expression != null){
var result = toCheck.expression.accept(this); var result = toCheck.expression.accept(this);
return new TypeCheckResult(true, result.getType()); if (result.isValid()) {
} else { if (!result.getType().equals(currentMethodReturnType)) {
return new TypeCheckResult(false, null); errors.add(new TypeMismatchException("Mismatched return Type from method"));
} }
}
return new TypeCheckResult(true, result.getType());
} else if (toCheck.voidReturn) {
return new TypeCheckResult(true, new BaseType(TypeEnum.VOID));
}
return new TypeCheckResult(true, null);
} }
@Override @Override
public TypeCheckResult analyze(WhileNode toCheck) { public TypeCheckResult analyze(WhileNode toCheck) {
return null; var expResult = toCheck.expression.accept(this);
var blockRes = toCheck.block.accept(this);
return new TypeCheckResult(expResult.isValid() && blockRes.isValid(), blockRes.getType());
} }
@Override @Override
public TypeCheckResult analyze(ParameterNode toCheck) { public TypeCheckResult analyze(ParameterNode toCheck) {
return new TypeCheckResult(true, toCheck.type);
return new TypeCheckResult(true, null);
} }
@Override @Override
public TypeCheckResult analyze(BlockNode blockNode) { public TypeCheckResult analyze(BlockNode blockNode) {
ITypeNode blockReturnType = null; ITypeNode blockReturnType = null;
if (blockNode.statements.isEmpty()) {
return new TypeCheckResult(true, null);
}
for (IStatementNode statementNode : blockNode.statements) { for (IStatementNode statementNode : blockNode.statements) {
var result = statementNode.accept(this); var result = statementNode.accept(this);
if(result.getType() != null){ if(!(statementNode instanceof IncrementNode) && !(statementNode instanceof DecrementNode)){
if(blockReturnType == null){ if (result.getType() != null) {
if (blockReturnType == null) {
blockReturnType = result.getType(); blockReturnType = result.getType();
} else { } else {
if (!blockReturnType.equals(result.getType())) {
errors.add(new MultipleReturnTypes("There are multiple Return types")); errors.add(new MultipleReturnTypes("There are multiple Return types"));
} }
} }
} }
}
}
return new TypeCheckResult(true, blockReturnType); return new TypeCheckResult(true, blockReturnType);
} }
@Override @Override
public TypeCheckResult analyze(AssignableNode toCheck) { public TypeCheckResult analyze(AssignableNode toCheck) {
return new TypeCheckResult(true, currentFields.get(toCheck.identifier));
if (toCheck.memberAccess != null) {
var result = toCheck.memberAccess.accept(this);
toCheck.setTypeNode(result.getType());
return result;
} else {
if (currentFields.get(toCheck.identifier) != null) {
var type = currentFields.get(toCheck.identifier);
toCheck.setTypeNode(type);
return new TypeCheckResult(true, type);
} else if (currentScope.getLocalVar(toCheck.identifier) != null) {
var type = currentScope.getLocalVar(toCheck.identifier);
return new TypeCheckResult(true, type);
}
}
return new TypeCheckResult(true, null);
} }
@Override @Override
public TypeCheckResult analyze(ElseNode toCheck) { public TypeCheckResult analyze(ElseNode toCheck) {
return null; return toCheck.block.accept(this);
} }
/*@Override
public TypeCheckResult analyze(ForNode toCheck) {
return null;
}*/
@Override @Override
public TypeCheckResult analyze(AssignNode toCheck) { public TypeCheckResult analyze(AssignNode toCheck) {
AssignableNode assignable = toCheck.assignable; AssignableNode assignable = toCheck.assignable;
@ -258,33 +291,61 @@ public class SemanticAnalyzer implements SemanticVisitor {
currentNullType = lResult.getType(); currentNullType = lResult.getType();
var rResult = rExpression.accept(this); var rResult = rExpression.accept(this);
if (!Objects.equals(currentScope.getLocalVar(toCheck.assignable.identifier), rExpression.getType())) { if (!Objects.equals(lResult.getType(), rResult.getType())) {
errors.add(new TypeMismatchException( errors.add(new TypeMismatchException(
"Mismatch types in Assign-Statement: cannot convert from \"" + lResult.getType() + "\" to \"" "Mismatch types in Assign-Statement: cannot convert from \"" + lResult.getType() + "\" to \""
+ rResult.getType() + "\"")); + rResult.getType() + "\""));
valid = false; valid = false;
} }
// else {
// toCheck.setType(assignable.getType());
// }
valid = valid && lResult.isValid() && rResult.isValid(); valid = valid && lResult.isValid() && rResult.isValid();
currentNullType = null; currentNullType = null;
return new TypeCheckResult(valid, null); // return type is null to get the return type sufficently return new TypeCheckResult(valid, null); // return type is null to get the return type sufficently
} }
@Override @Override
public TypeCheckResult analyze(DecrementNode toCheck) { public TypeCheckResult analyze(DecrementNode decrementNode) {
return null; return decrementNode.assignableExpression.accept(this);
} }
@Override @Override
public TypeCheckResult analyze(IfElseNode toCheck) { public TypeCheckResult analyze(IfElseNode toCheck) {
return new TypeCheckResult(true, null); var resultIf = toCheck.ifStatement.accept(this);
var resultElse = toCheck.elseStatement.accept(this);
return new TypeCheckResult(resultIf.isValid() && resultElse.isValid(), new BaseType(TypeEnum.VOID));
} }
@Override @Override
public TypeCheckResult analyze(MethodCallNode toCheck) { public TypeCheckResult analyze(MethodCallNode toCheck) {
return null;
if (toCheck.target.identifier != null) {
var targetType = currentScope.getLocalVar(toCheck.target.identifier);
if (targetType == null) {
targetType = currentFields.get(toCheck.target.identifier);
}
if (targetType instanceof ReferenceType reference) {
var type = getTypeFromMethod(toCheck, reference);
if (type != null) {
return new TypeCheckResult(true, type);
} else {
return new TypeCheckResult(false, null);
}
}
} else {
if (toCheck.target.thisTar) {
var type = getTypeFromMethod(toCheck, new ReferenceType(currentClass.identifier));
if (type != null) {
return new TypeCheckResult(true, type);
}
} else {
var result = toCheck.target.accept(this);
if (result.getType() instanceof ReferenceType reference) {
return new TypeCheckResult(true, getTypeFromMethod(toCheck, reference));
}
}
}
return new TypeCheckResult(false, null);
} }
@Override @Override
@ -295,6 +356,9 @@ public class SemanticAnalyzer implements SemanticVisitor {
TypeCheckResult result = localVarDecl.expression.accept(this); TypeCheckResult result = localVarDecl.expression.accept(this);
var resultType = localVarDecl.expression.getType(); var resultType = localVarDecl.expression.getType();
if (result.getType() != null) {
resultType = result.getType();
}
valid = result.isValid() && valid; valid = result.isValid() && valid;
if (!Objects.equals(resultType, localVarDecl.type)) { if (!Objects.equals(resultType, localVarDecl.type)) {
@ -316,12 +380,17 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override @Override
public TypeCheckResult analyze(NewDeclarationNode toCheck) { public TypeCheckResult analyze(NewDeclarationNode toCheck) {
if (context.containsClass(toCheck.identifier)) {
return new TypeCheckResult(true, new ReferenceType(toCheck.identifier));
}
return null; return null;
} }
@Override @Override
public TypeCheckResult analyze(IncrementNode toCheck) { public TypeCheckResult analyze(IncrementNode toCheck) {
return null; return toCheck.assignableExpression.accept(this);
} }
@Override @Override
@ -332,38 +401,223 @@ public class SemanticAnalyzer implements SemanticVisitor {
@Override @Override
public TypeCheckResult analyze(CalculationNode calcNode) { public TypeCheckResult analyze(CalculationNode calcNode) {
if (calcNode.calculationExpression != null) { if (calcNode.calculationExpression != null) {
calcNode.calculationExpression.accept(this); var calcRes = calcNode.calculationExpression.accept(this);
if (calcNode.dotExpression != null) {
var dotRes = calcNode.dotExpression.accept(this);
switch (calcNode.operator) {
case PLUS, MINUS:
if (calcRes.getType() instanceof BaseType calcType && dotRes.getType() instanceof BaseType dotType &&
calcType.getTypeEnum().equals(TypeEnum.INT) && dotType.getTypeEnum().equals(TypeEnum.INT)) {
return new TypeCheckResult(true, new BaseType(TypeEnum.INT));
} }
return null; break;
default:
}
} else {
return new TypeCheckResult(calcRes.isValid(), calcRes.getType());
}
} else if (calcNode.dotExpression != null) {
var dotRes = calcNode.dotExpression.accept(this);
return new TypeCheckResult(dotRes.isValid(), dotRes.getType());
}
return new TypeCheckResult(false, null);
} }
@Override @Override
public TypeCheckResult analyze(DotNode toCheck) { public TypeCheckResult analyze(DotNode toCheck) {
return null; if (toCheck.dotSubstractionExpression != null) {
return toCheck.dotSubstractionExpression.accept(this);
}
return new TypeCheckResult(false, null);
} }
@Override @Override
public TypeCheckResult analyze(DotSubstractionNode toCheck) { public TypeCheckResult analyze(DotSubstractionNode toCheck) {
if (toCheck.value != null) {
return toCheck.value.accept(this);
} else if (toCheck.memberAccess != null) {
return toCheck.memberAccess.accept(this);
} else if (toCheck.methodCall != null) {
return toCheck.methodCall.accept(this);
} else if (toCheck.identifier != null) {
if (currentScope.contains(toCheck.identifier)) {
return new TypeCheckResult(true, currentScope.getLocalVar(toCheck.identifier));
} else if (currentFields.get(toCheck.identifier) != null) {
return new TypeCheckResult(true, currentFields.get(toCheck.identifier));
}
} else if (toCheck.calculationExpression != null) {
return toCheck.calculationExpression.accept(this);
}
return null; return null;
} }
@Override @Override
public TypeCheckResult analyze(NonCalculationNode toCheck) { public TypeCheckResult analyze(NonCalculationNode nonCalculationNode) {
return null; var expResult = nonCalculationNode.expression.accept(this);
var unaryResult = nonCalculationNode.unaryExpression.accept(this);
switch (nonCalculationNode.operator) {
case LESS, LESS_EQUAL, GREATER, GREATER_EQUAL:
if (expResult.getType() instanceof BaseType expResultType && expResultType.getTypeEnum().equals(TypeEnum.INT) &&
unaryResult.getType() instanceof BaseType unaryResultType && unaryResultType.getTypeEnum().equals(TypeEnum.INT)) {
return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL));
} else {
errors.add(new TypeMismatchException("Both types must be Integer"));
}
break;
case OR, AND:
if (expResult.getType() instanceof BaseType expResultType && expResultType.getTypeEnum().equals(TypeEnum.INT) &&
unaryResult.getType() instanceof BaseType unaryResultType && unaryResultType.getTypeEnum().equals(TypeEnum.INT)) {
return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL));
} else {
errors.add(new TypeMismatchException("Both types must be Boolean"));
}
break;
case EQUAL, NOT_EQUAL:
if (expResult.getType() instanceof BaseType expResultType && unaryResult.getType() instanceof BaseType unaryResultType
&& Objects.equals(expResultType, unaryResultType)) {
return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL));
} else {
errors.add(new TypeMismatchException("Both types must be the same"));
}
}
return new TypeCheckResult(false, null);
} }
@Override @Override
public TypeCheckResult analyze(UnaryNode unary) { public TypeCheckResult analyze(UnaryNode unary) {
var valid = true; var valid = true;
if (unary.identifier != null) {
if (currentScope.contains(unary.identifier)) { if (currentScope.contains(unary.identifier)) {
return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier)); return new TypeCheckResult(valid, currentScope.getLocalVar(unary.identifier));
} else if(currentFields.get(unary.identifier) != null) { } else if (currentFields.get(unary.identifier) != null) {
return new TypeCheckResult(valid, currentFields.get(unary.identifier)); return new TypeCheckResult(valid, currentFields.get(unary.identifier));
} else if (unary.statement != null) {
var result = unary.statement.accept(this);
unary.setType(result.getType());
return result;
} else { } else {
errors.add(new NotDeclaredException("Var is not Declared")); errors.add(new NotDeclaredException("Var is not Declared"));
} }
return new TypeCheckResult(valid, null); } else if (unary.statement != null) {
var result = unary.statement.accept(this);
return new TypeCheckResult(result.isValid(), result.getType());
} else if (unary.value != null) {
var result = unary.value.accept(this);
return new TypeCheckResult(result.isValid(), result.getType());
} else if (unary.memberAccess != null) {
var result = unary.memberAccess.accept(this);
return new TypeCheckResult(result.isValid(), result.getType());
} else if (unary.expression != null) {
var result = unary.expression.accept(this);
return new TypeCheckResult(result.isValid(), result.getType());
}
return new TypeCheckResult(false, null);
}
@Override
public TypeCheckResult analyze(MemberAccessNode memberAccessNode) {
ITypeNode currentType = null;
for (String s : memberAccessNode.identifiers) {
if (currentType == null) {
if (currentScope.getLocalVar(s) != null) {
currentType = currentScope.getLocalVar(s);
} else if (currentFields.get(s) != null) {
currentType = currentFields.get(s);
} else {
errors.add(new NotDeclaredException(s + "Not Declared"));
return new TypeCheckResult(false, null);
}
} else {
if (currentType instanceof ReferenceType reference) {
var currentTypeClass = context.getClass(reference.getIdentifier());
var currentField = currentTypeClass.getField(s);
if (currentField.getAccessModifier().accessType == EnumAccessModifierNode.PUBLIC) {
currentType = currentField.getType();
} else {
errors.add(new NotVisibleException("This field is not visible"));
return new TypeCheckResult(false, null);
}
}
}
}
return new TypeCheckResult(true, currentType);
}
@Override
public TypeCheckResult analyze(TargetNode targetNode) {
if (targetNode.memberAccess != null) {
return targetNode.memberAccess.accept(this);
}
return null;
}
@Override
public TypeCheckResult analyze(ValueNode valueNode) {
switch (valueNode.valueType) {
case INT_VALUE -> {
return new TypeCheckResult(true, new BaseType(TypeEnum.INT));
}
case CHAR_VALUE -> {
return new TypeCheckResult(true, new BaseType(TypeEnum.CHAR));
}
case BOOLEAN_VALUE -> {
return new TypeCheckResult(true, new BaseType(TypeEnum.BOOL));
}
default -> {
return new TypeCheckResult(false, null);
}
}
}
private ITypeNode getTypeFromMethod(MethodCallNode toCheck, ReferenceType reference) {
var classContext = context.getClass(reference.getIdentifier());
if (classContext == null) {
errors.add(new NotDeclaredException(toCheck.target.identifier + "is not Defined"));
} else {
var methods = classContext.getMethods();
for (var method : methods) {
if (toCheck.identifier.equals(method.getIdentifier())) {
if (method.getParameters().size() == toCheck.parameters.size() && !(method instanceof ConstructorNode)) {
boolean same = true;
for (int i = 0; i < method.getParameters().size(); i++) {
var result1 = method.getParameters().get(i).accept(this);
var result2 = toCheck.parameters.get(i).accept(this);
if (!Objects.equals(result1.getType(), result2.getType())) {
same = false;
}
}
if (same) {
if (method.accesModifier.accessType == EnumAccessModifierNode.PUBLIC) {
if (method.getType() == null) {
return new BaseType(TypeEnum.VOID);
}
return method.getType();
} else {
errors.add(new NotVisibleException("This Method is not Visible"));
}
}
}
}
}
errors.add(new WrongOverloading("No Method found with this parameters"));
}
return null;
} }
} }

View File

@ -2,6 +2,7 @@ package semantic;
import ast.*; import ast.*;
import ast.expressions.binaryexpressions.*; import ast.expressions.binaryexpressions.*;
import ast.expressions.unaryexpressions.MemberAccessNode;
import ast.expressions.unaryexpressions.UnaryNode; import ast.expressions.unaryexpressions.UnaryNode;
import ast.members.*; import ast.members.*;
import ast.parameters.ParameterNode; import ast.parameters.ParameterNode;
@ -11,7 +12,9 @@ import ast.statementexpressions.NewDeclarationNode;
import ast.statementexpressions.crementexpressions.DecrementNode; import ast.statementexpressions.crementexpressions.DecrementNode;
import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.crementexpressions.IncrementNode;
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 typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
public interface SemanticVisitor { public interface SemanticVisitor {
@ -38,8 +41,6 @@ public interface SemanticVisitor {
TypeCheckResult analyze(ElseNode toCheck); TypeCheckResult analyze(ElseNode toCheck);
//TypeCheckResult analyze(ForNode toCheck);
TypeCheckResult analyze(AssignNode toCheck); TypeCheckResult analyze(AssignNode toCheck);
TypeCheckResult analyze(DecrementNode toCheck); TypeCheckResult analyze(DecrementNode toCheck);
@ -66,4 +67,10 @@ public interface SemanticVisitor {
TypeCheckResult analyze(UnaryNode toCheck); TypeCheckResult analyze(UnaryNode toCheck);
TypeCheckResult analyze(MemberAccessNode toCheck);
TypeCheckResult analyze(TargetNode toCheck);
TypeCheckResult analyze(ValueNode toCheck);
} }

View File

@ -2,11 +2,15 @@ package semantic.context;
import ast.ClassNode; import ast.ClassNode;
import ast.members.FieldNode; import ast.members.FieldNode;
import ast.members.MethodNode;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
public class ClassContext { public class ClassContext {
private HashMap<String, FieldContext> fields; private HashMap<String, FieldContext> fields;
private ArrayList<MethodNode> methods = new ArrayList<>();
public ClassContext(ClassNode classNode) { public ClassContext(ClassNode classNode) {
@ -15,6 +19,8 @@ public class ClassContext {
classNode.members.forEach(member -> { classNode.members.forEach(member -> {
if(member instanceof FieldNode fieldNode) { if(member instanceof FieldNode fieldNode) {
fields.put(fieldNode.identifier, new FieldContext(fieldNode)); fields.put(fieldNode.identifier, new FieldContext(fieldNode));
}else if(member instanceof MethodNode methodNode) {
methods.add(methodNode);
} }
}); });
@ -24,4 +30,8 @@ public class ClassContext {
return fields.get(name); return fields.get(name);
} }
public ArrayList<MethodNode> getMethods() {
return methods;
}
} }

View File

@ -21,4 +21,8 @@ public class Context {
return classes.get(identifier); return classes.get(identifier);
} }
public boolean containsClass(String identifier) {
return classes.containsKey(identifier);
}
} }

View File

@ -18,4 +18,8 @@ public class FieldContext {
return type; return type;
} }
public AccessModifierNode getAccessModifier() {
return accessModifier;
}
} }

View File

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

View File

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

View File

@ -26,11 +26,37 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
public class EndToTypedAstTest { public class EndToTypedAstTest {
private static final Map<String, Class<?>> exceptionMap = new HashMap<>(); private static final Map<String, Class<?>> exceptionMap = new HashMap<>();
@Test
public void testOnlyOneFile() {
SemanticAnalyzer.clearAnalyzer();
CharStream codeCharStream = null;
try {
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/input/typedAstFeaturesTests/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);
var result = SemanticAnalyzer.generateTast(abstractSyntaxTree);
assertTrue(SemanticAnalyzer.errors.isEmpty());
}
@Test @Test
public void exceptionsTest() { public void exceptionsTest() {
String directoryPath = "src/test/resources/input/typedAstExceptionsTests"; String directoryPath = "src/test/resources/input/typedAstExceptionsTests";
@ -88,7 +114,7 @@ public class EndToTypedAstTest {
} }
@Test @Test
public void featureTest(){ public void featureTest() {
String directoryPath = "src/test/resources/input/typedAstFeaturesTests"; String directoryPath = "src/test/resources/input/typedAstFeaturesTests";
File folder = new File(directoryPath); File folder = new File(directoryPath);
if (folder.isDirectory()) { if (folder.isDirectory()) {
@ -115,6 +141,9 @@ public class EndToTypedAstTest {
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree); ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
System.out.println("Testing the file: " + file.getName()); System.out.println("Testing the file: " + file.getName());
for(Exception runtimeException : SemanticAnalyzer.errors){
runtimeException.printStackTrace();
}
assertTrue(SemanticAnalyzer.errors.isEmpty()); assertTrue(SemanticAnalyzer.errors.isEmpty());
assertNotNull(typedAst); assertNotNull(typedAst);
} }
@ -127,9 +156,8 @@ public class EndToTypedAstTest {
} }
// ------------------ Helpers ------------------ // ------------------ Helpers ------------------
/** /**
* This method is used to extract the expected exception from a given file. * This method is used to extract the expected exception from a given file.
* It reads the file line by line and uses a regular expression to match the expected exception annotation. * It reads the file line by line and uses a regular expression to match the expected exception annotation.
@ -167,7 +195,7 @@ public class EndToTypedAstTest {
* @return The Class object associated with the given exception name. * @return The Class object associated with the given exception name.
* @throws RuntimeException If the Class object for the given exception name is not found in the exceptionMap. * @throws RuntimeException If the Class object for the given exception name is not found in the exceptionMap.
*/ */
private Class<?> getExceptionClass(String exceptionName) { private Class<?> getExceptionClass(String exceptionName) {
System.out.println(exceptionName); System.out.println(exceptionName);
exceptionName = "semantic.exceptions." + exceptionName; exceptionName = "semantic.exceptions." + exceptionName;
System.out.println(exceptionName); System.out.println(exceptionName);
@ -176,7 +204,7 @@ private Class<?> getExceptionClass(String exceptionName) {
throw new RuntimeException("Exception class not found: " + exceptionName); throw new RuntimeException("Exception class not found: " + exceptionName);
} }
return exceptionClass; return exceptionClass;
} }
/** /**
* This method is used to load custom exceptions from a specified package. * This method is used to load custom exceptions from a specified package.

View File

@ -1,102 +0,0 @@
package semantic;
import ast.*;
import ast.members.FieldNode;
import ast.members.MethodNode;
import ast.parameters.ParameterNode;
import ast.type.AccessModifierNode;
import ast.type.type.*;
public class Mocker {
public static ASTNode mockTwoSameFields(){
ProgramNode p = new ProgramNode();
ClassNode c = new ClassNode();
c.identifier = "testClass";
FieldNode f1 = new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a");
c.members.add(f1);
FieldNode f2 = new FieldNode(new AccessModifierNode("public"), new BaseType(TypeEnum.INT), "a");
c.members.add(f2);
p.classes.add(c);
return p;
}
public static ASTNode mockSimpleMethod(){
ProgramNode p = new ProgramNode();
ClassNode c = new ClassNode();
MethodNode methodNode = new MethodNode();
//Parameter
ParameterNode parameterNode = new ParameterNode(new BaseType(TypeEnum.INT), "a");
methodNode.addParameter(parameterNode);
//Statements
//Block
methodNode.block = new ast.statements.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 ast.statements.BlockNode();
methodNode.setType(new BaseType(TypeEnum.INT));
methodNode.setIdentifier("testMethod");
c.members.add(methodNode);
MethodNode methodNode1 = new MethodNode();
methodNode1.block = new ast.statements.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 ast.statements.BlockNode();
methodNode.setIdentifier("testMethod");
c.members.add(methodNode);
MethodNode methodNode1 = new MethodNode();
methodNode1.block = new ast.statements.BlockNode();
methodNode1.setIdentifier("testMethod1");
c.members.add(methodNode1);
p.classes.add(c);
return p;
}
}

View File

@ -3,6 +3,18 @@ package semantic;
public class SemanticTest { public class SemanticTest {
public void test(){
}
public void test(int a, boolean b){
}
public void test(boolean b, int a){
}
// @Test // @Test
// public void alreadyDeclaredLocalFieldVar() { // public void alreadyDeclaredLocalFieldVar() {
// ProgramNode programNode = new ProgramNode(); // ProgramNode programNode = new ProgramNode();

View File

@ -0,0 +1,9 @@
// @expected: TypeMismatchException
public class AllFeaturesClassExample {
public void controlStructures(int a, boolean bool) {
while (a > bool) {
a--;
}
}
}

View File

@ -0,0 +1,13 @@
// @expected: TypeMismatchException
public class Test{
public void test(boolean b){
if(b == 2){
} else {
}
}
}

View File

@ -0,0 +1,20 @@
// @expected: NotVisibleException
public class Test{
public Car c;
public int test(){
return c.speed;
}
}
public class Car{
private int speed;
public int getSpeed(){
return speed;
}
}

View File

@ -0,0 +1,14 @@
// @expected: TypeMismatchException
public class Test{
public void test(int x){
if(x){
} else {
}
}
}

View File

@ -0,0 +1,21 @@
// @expected: NotVisibleException
public class Test {
public int firstInt;
public Car ca;
public int speed(){
return ca.getSpeed();
}
}
public class Car{
private int speed;
private int getSpeed(){
return speed;
}
}

View File

@ -0,0 +1,19 @@
// @expected: WrongOverloading
public class Test{
public void test(int x){
if(this.get()){
} else {
}
}
public boolean b;
public boolean get(int c){
return b;
}
}

View File

@ -1,4 +1,4 @@
// @expected: MultipleReturnTypes // @expected: TypeMismatchException
public class Example { public class Example {
public static int testMethod(int x, char c){ public static int testMethod(int x, char c){

View File

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

View File

@ -1,8 +0,0 @@
// @expected: TypeMismatchException
public class Example {
public static void testMethod(int x){
}
}

View File

@ -0,0 +1,20 @@
public class Test {
public int firstInt;
public Car ca;
public int speed(){
return ca.getSpeed();
}
}
public class Car{
private int speed;
public int getSpeed(){
return speed;
}
}

View File

@ -0,0 +1,19 @@
public class Test{
public Car c;
public int test(){
return c.getSpeed();
}
}
public class Car{
private int speed;
public int getSpeed(){
return speed;
}
}

View File

@ -0,0 +1,18 @@
public class Test{
public void test(int x){
if(this.get(x)){
} else {
}
}
public boolean b;
public boolean get(int c){
return b;
}
}

View File

@ -0,0 +1,12 @@
public class Test{
public void test(boolean b){
if(b == true){
} else {
}
}
}

View File

@ -1,18 +1,38 @@
public class Example { public class AllFeaturesClassExample {
int a;
public int a; boolean b;
char c;
public static int testMethod(int b, boolean bo){
a = b;
if(bo){
public void controlStructures(int adf, boolean bool) {
if (a > (10 + 8)) {
} else {
} }
return a;
while (a > adf) {
a--;
}
for (int i = 0; i < 5; i++) {
}
} }
public static void testMethod(int b){ // void logicalOperations() {
// Logische UND-Operation
// if (b && a > 5) {
// System.out.println("a ist größer als 5 und b ist wahr");
// }
} // Logische ODER-Operation
// if (b || a < 5) {
// System.out.println("b ist wahr oder a ist kleiner als 5");
// }
// }
// public static void main(String[] args) {
// AllFeaturesClassExample obj = new AllFeaturesClassExample(12, true, 'a');
// obj.controlStructures();
// }
} }

View File

@ -0,0 +1,64 @@
public class AllFeaturesClassExample {
int a;
boolean b;
char c;
public void controlStructures(int adf, boolean bool) {
if (a > (10 + 8)) {
} else {
}
while (a > adf) {
a--;
}
for (int i = 0; i < 5; i++) {
}
}
// void logicalOperations() {
// // Logische UND-Operation
// if (b && a > 5) {
//// System.out.println("a ist größer als 5 und b ist wahr");
// }
//
// // Logische ODER-Operation
// if (b || a < 5) {
//// System.out.println("b ist wahr oder a ist kleiner als 5");
// }
// }
// public static void main(String[] args) {
// AllFeaturesClassExample obj = new AllFeaturesClassExample(12, true, 'a');
// obj.controlStructures();
// }
}
public class Test {
public Car c;
public int test(boolean b, int x) {
if (b == true) {
return c.getSpeed();
} else {
return x;
}
}
}
public class Car {
private int speed;
public int getSpeed() {
return speed;
}
}

View File

@ -0,0 +1,13 @@
public class Car{
public void test(boolean boo){
if(boo){
} else {
}
}
}

View File

@ -0,0 +1,13 @@
public class Car{
public int getSpeed(boolean bool, int a, int b){
if(bool){
return a;
} else {
return b;
}
}
}

View File

@ -0,0 +1,21 @@
public class Test{
public int i;
public boolean b;
public int test(){
return this.test(b);
}
public void test(int a){
}
public int test(boolean bool){
int ret = 1;
return ret;
}
}

View File

@ -0,0 +1,13 @@
public class Car{
private int speed;
public int getSpeed(){
return speed;
}
public int test(){
return this.getSpeed();
}
}

View File

@ -0,0 +1,13 @@
public class Car{
private int speed;
public void getSpeed(boolean boo){
if(boo){
} else {
}
}
}