johns-branch #12
@ -1,6 +1,5 @@
|
|||||||
import oldAst.ASTNode;
|
import ast.*;
|
||||||
import org.antlr.v4.runtime.*;
|
import org.antlr.v4.runtime.*;
|
||||||
import oldAst.ProgramNode;
|
|
||||||
import bytecode.ByteCodeGenerator;
|
import bytecode.ByteCodeGenerator;
|
||||||
import org.antlr.v4.runtime.CharStream;
|
import org.antlr.v4.runtime.CharStream;
|
||||||
import org.antlr.v4.runtime.CharStreams;
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
@ -9,16 +9,15 @@ import semantic.SemanticVisitor;
|
|||||||
import typechecker.TypeCheckResult;
|
import typechecker.TypeCheckResult;
|
||||||
import visitor.Visitable;
|
import visitor.Visitable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MethodNode implements MemberNode {
|
public class MethodNode implements MemberNode, Visitable {
|
||||||
AccessModifierNode accesModifier;
|
AccessModifierNode accesModifier;
|
||||||
TypeNode type;
|
TypeNode type;
|
||||||
Boolean voidType;
|
Boolean voidType;
|
||||||
String identifier;
|
String identifier;
|
||||||
List<ParameterNode> parameters;
|
List<ParameterNode> parameters;
|
||||||
BlockNode block;
|
public BlockNode block;
|
||||||
|
|
||||||
public MethodNode() {}
|
public MethodNode() {}
|
||||||
|
|
||||||
@ -55,6 +54,8 @@ public class MethodNode implements MemberNode {
|
|||||||
return isSame;
|
return isSame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||||
return visitor.analyze(this);
|
return visitor.analyze(this);
|
||||||
@ -64,6 +65,6 @@ public class MethodNode implements MemberNode {
|
|||||||
public void accept(MethodVisitor methodVisitor) {
|
public void accept(MethodVisitor methodVisitor) {
|
||||||
methodVisitor.visit(this);
|
methodVisitor.visit(this);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,6 @@ package ast.statement;
|
|||||||
|
|
||||||
import ast.ASTNode;
|
import ast.ASTNode;
|
||||||
import ast.expression.ExpressionNode;
|
import ast.expression.ExpressionNode;
|
||||||
import ast.type.TypeNode;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ReturnStatementNode implements ASTNode {
|
public class ReturnStatementNode implements ASTNode {
|
||||||
public ExpressionNode expression;
|
public ExpressionNode expression;
|
||||||
|
@ -4,11 +4,10 @@ import ast.ClassNode;
|
|||||||
import ast.member.FieldNode;
|
import ast.member.FieldNode;
|
||||||
import ast.member.MemberNode;
|
import ast.member.MemberNode;
|
||||||
import ast.member.MethodNode;
|
import ast.member.MethodNode;
|
||||||
import ast.type.BaseTypeNode;
|
import ast.type.TypeNode;
|
||||||
import bytecode.visitor.ClassVisitor;
|
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;
|
||||||
@ -25,8 +24,8 @@ public class ClassCodeGen implements ClassVisitor {
|
|||||||
@Override
|
@Override
|
||||||
public void visit(ClassNode classNode) {
|
public void visit(ClassNode classNode) {
|
||||||
classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
classWriter.visit(Opcodes.V1_5, mapper.mapAccessTypeToOpcode(classNode.accessType), classNode.identifier, null,
|
// classWriter.visit(Opcodes.V1_5, mapper.mapAccessTypeToOpcode(classNode.accessType), classNode.identifier, null,
|
||||||
"java/lang/Object", null);
|
// "java/lang/Object", null);
|
||||||
|
|
||||||
for (MemberNode memberNode : classNode.members) {
|
for (MemberNode memberNode : classNode.members) {
|
||||||
if (memberNode instanceof FieldNode) {
|
if (memberNode instanceof FieldNode) {
|
||||||
@ -45,8 +44,8 @@ public class ClassCodeGen implements ClassVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(FieldNode fieldNode) {
|
public void visit(FieldNode fieldNode) {
|
||||||
if(fieldNode.type instanceof BaseTypeNode baseTypeNode){
|
if(fieldNode.type instanceof TypeNode baseTypeNode){
|
||||||
classWriter.visitField(mapper.mapAccessTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(baseTypeNode.enumType), null, null );
|
// classWriter.visitField(mapper.mapAccessTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(baseTypeNode.enumType), null, null );
|
||||||
}
|
}
|
||||||
classWriter.visitEnd();
|
classWriter.visitEnd();
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,41 @@
|
|||||||
package bytecode;
|
package bytecode;
|
||||||
|
|
||||||
import ast.parameter.ParameterNode;
|
|
||||||
import ast.type.*;
|
import ast.type.*;
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import ast.type.BaseTypeNode;
|
|
||||||
|
|
||||||
public class Mapper {
|
public class Mapper {
|
||||||
public int mapAccessTypeToOpcode(AccessTypeNode type) {
|
// public int mapAccessTypeToOpcode(AccessModifierNode type) {
|
||||||
switch (type.enumAccessTypeNode) {
|
// switch (type.enumAccessTypeNode) {
|
||||||
case EnumAccessTypeNode.PUBLIC:
|
// case EnumAccessTypeNode.PUBLIC:
|
||||||
return Opcodes.ACC_PUBLIC;
|
// return Opcodes.ACC_PUBLIC;
|
||||||
case EnumAccessTypeNode.PRIVATE:
|
// case EnumAccessTypeNode.PRIVATE:
|
||||||
return Opcodes.ACC_PRIVATE;
|
// return Opcodes.ACC_PRIVATE;
|
||||||
}
|
// }
|
||||||
return 0;
|
// return 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public String generateMethodDescriptor(BaseTypeNode baseTypeNode, ParameterListNode parameterListNode) {
|
// public String generateMethodDescriptor(BaseTypeNode baseTypeNode, ParameterListNode parameterListNode) {
|
||||||
String descriptor = "(";
|
// String descriptor = "(";
|
||||||
for(ParameterNode parameterNode : parameterListNode.parameters) {
|
// for(ParameterNode parameterNode : parameterListNode.parameters) {
|
||||||
descriptor += getTypeChar(EnumTypeNode.INT);
|
// descriptor += getTypeChar(EnumTypeNode.INT);
|
||||||
}
|
// }
|
||||||
descriptor += ")";
|
// descriptor += ")";
|
||||||
descriptor += getTypeChar(baseTypeNode.enumType);
|
// descriptor += getTypeChar(baseTypeNode.enumType);
|
||||||
return descriptor;
|
// return descriptor;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public String getTypeChar(EnumTypeNode enumTypeNode) {
|
// public String getTypeChar(TypeEnum enumTypeNode) {
|
||||||
String typeChar = "";
|
// String typeChar = "";
|
||||||
switch (enumTypeNode) {
|
// switch (enumTypeNode) {
|
||||||
case EnumTypeNode.INT:
|
// case TypeEnum.INT:
|
||||||
typeChar = "I";
|
// typeChar = "I";
|
||||||
break;
|
// break;
|
||||||
case EnumTypeNode.CHAR:
|
// case TypeEnum.CHAR:
|
||||||
typeChar = "C";
|
// typeChar = "C";
|
||||||
break;
|
// break;
|
||||||
case EnumTypeNode.BOOLEAN:
|
// case TypeEnum.BOOLEAN:
|
||||||
typeChar = "Z";
|
// typeChar = "Z";
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
return typeChar;
|
// return typeChar;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,8 @@ package bytecode;
|
|||||||
|
|
||||||
import ast.member.ConstructorNode;
|
import ast.member.ConstructorNode;
|
||||||
import ast.member.MethodNode;
|
import ast.member.MethodNode;
|
||||||
import ast.parameter.ParameterNode;
|
|
||||||
import ast.type.BaseTypeNode;
|
|
||||||
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;
|
||||||
@ -31,12 +27,12 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
|
|||||||
|
|
||||||
@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.visibility),
|
||||||
"<init>",
|
// "<init>",
|
||||||
"()V",
|
// "()V",
|
||||||
null,
|
// null,
|
||||||
null);
|
// null);
|
||||||
methodVisitor.visitCode();
|
methodVisitor.visitCode();
|
||||||
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);
|
||||||
@ -47,52 +43,52 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MethodNode methodNode) {
|
public void visit(MethodNode methodNode) {
|
||||||
if (methodNode.type instanceof BaseTypeNode baseTypeNode) {
|
// if (methodNode.type instanceof BaseTypeNode baseTypeNode) {
|
||||||
methodVisitor = classWriter.visitMethod(mapper.mapAccessTypeToOpcode(methodNode.visibility),
|
// methodVisitor = classWriter.visitMethod(mapper.mapAccessTypeToOpcode(methodNode.visibility),
|
||||||
methodNode.identifier,
|
// methodNode.identifier,
|
||||||
mapper.generateMethodDescriptor(baseTypeNode, 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) {
|
// for (ParameterNode parameterNode : methodNode.parameters.parameters) {
|
||||||
localVaribales.add(parameterNode.identifier);
|
// localVaribales.add(parameterNode.identifier);
|
||||||
}
|
// }
|
||||||
|
|
||||||
//test();
|
//test();
|
||||||
methodVisitor.visitMaxs(1, localVaribales.size());
|
methodVisitor.visitMaxs(1, localVaribales.size());
|
||||||
methodVisitor.visitEnd();
|
methodVisitor.visitEnd();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void test() {
|
// public void test() {
|
||||||
Label start = new Label();
|
// Label start = new Label();
|
||||||
Label loop = new Label();
|
// Label loop = new Label();
|
||||||
Label end = new Label();
|
// Label end = new Label();
|
||||||
methodVisitor.visitLabel(start);
|
// methodVisitor.visitLabel(start);
|
||||||
//methodVisitor.visitVarInsn(Opcodes.ICONST_M1, 99);
|
// //methodVisitor.visitVarInsn(Opcodes.ICONST_M1, 99);
|
||||||
//methodVisitor.visitInsn(Opcodes.ICONST_5);
|
// //methodVisitor.visitInsn(Opcodes.ICONST_5);
|
||||||
methodVisitor.visitLdcInsn(99);
|
// methodVisitor.visitLdcInsn(99);
|
||||||
// methodVisitor.visitInsn(Opcodes.ICONST_0);
|
// // methodVisitor.visitInsn(Opcodes.ICONST_0);
|
||||||
//methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
|
// //methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
|
||||||
methodVisitor.visitVarInsn(Opcodes.ISTORE, 1);
|
// methodVisitor.visitVarInsn(Opcodes.ISTORE, 1);
|
||||||
methodVisitor.visitLabel(loop);
|
// methodVisitor.visitLabel(loop);
|
||||||
methodVisitor.visitVarInsn(Opcodes.ILOAD, 1);
|
// methodVisitor.visitVarInsn(Opcodes.ILOAD, 1);
|
||||||
methodVisitor.visitInsn(Opcodes.ICONST_5);
|
// methodVisitor.visitInsn(Opcodes.ICONST_5);
|
||||||
methodVisitor.visitJumpInsn(Opcodes.IF_ICMPGE, end);
|
// methodVisitor.visitJumpInsn(Opcodes.IF_ICMPGE, end);
|
||||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC,
|
// methodVisitor.visitFieldInsn(Opcodes.GETSTATIC,
|
||||||
"java/lang/System", "out",
|
// "java/lang/System", "out",
|
||||||
"Ljava/io/PrintStream;");
|
// "Ljava/io/PrintStream;");
|
||||||
methodVisitor.visitLdcInsn("Bytecode");
|
// methodVisitor.visitLdcInsn("Bytecode");
|
||||||
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
|
// methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
|
||||||
"java/io/PrintStream", "println",
|
// "java/io/PrintStream", "println",
|
||||||
"(Ljava/lang/String;)V", false);
|
// "(Ljava/lang/String;)V", false);
|
||||||
methodVisitor.visitIincInsn(1, 1);
|
// methodVisitor.visitIincInsn(1, 1);
|
||||||
methodVisitor.visitJumpInsn(Opcodes.GOTO, loop);
|
// methodVisitor.visitJumpInsn(Opcodes.GOTO, loop);
|
||||||
methodVisitor.visitLabel(end);
|
// methodVisitor.visitLabel(end);
|
||||||
methodVisitor.visitVarInsn(Opcodes.ILOAD, 1);
|
// methodVisitor.visitVarInsn(Opcodes.ILOAD, 1);
|
||||||
methodVisitor.visitInsn(Opcodes.IRETURN);
|
// methodVisitor.visitInsn(Opcodes.IRETURN);
|
||||||
methodVisitor.visitEnd();
|
// methodVisitor.visitEnd();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package semantic;
|
package semantic;
|
||||||
|
|
||||||
import oldAst.type.TypeNode;
|
import ast.type.TypeNode;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
@ -1,25 +1,16 @@
|
|||||||
package semantic;
|
package semantic;
|
||||||
|
|
||||||
|
|
||||||
import oldAst.*;
|
|
||||||
import oldAst.expression.*;
|
|
||||||
import oldAst.member.FieldNode;
|
|
||||||
import oldAst.member.MemberNode;
|
|
||||||
|
|
||||||
import oldAst.member.MethodNode;
|
|
||||||
import oldAst.parameter.ParameterListNode;
|
|
||||||
import oldAst.parameter.ParameterNode;
|
|
||||||
import oldAst.statement.*;
|
|
||||||
import oldAst.type.ReferenceTypeNode;
|
|
||||||
import oldAst.expression.This;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import oldAst.type.BaseTypeNode;
|
import ast.*;
|
||||||
import oldAst.type.TypeNode;
|
import ast.member.*;
|
||||||
|
import ast.statement.*;
|
||||||
|
import ast.statement.ifstatement.IfStatementNode;
|
||||||
|
import ast.type.*;
|
||||||
import semantic.context.Context;
|
import semantic.context.Context;
|
||||||
import semantic.exeptions.AlreadyDeclearedException;
|
import semantic.exeptions.AlreadyDeclearedException;
|
||||||
import semantic.exeptions.NotDeclearedException;
|
import semantic.exeptions.NotDeclearedException;
|
||||||
@ -90,10 +81,7 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
|||||||
for(MethodNode methode : currentClass.getMethods()){
|
for(MethodNode methode : currentClass.getMethods()){
|
||||||
if(methode.equals(methodNode))
|
if(methode.equals(methodNode))
|
||||||
break;
|
break;
|
||||||
if(methode.isSame(methodNode)){
|
|
||||||
errors.add(new AlreadyDeclearedException("This method has already been declared"));
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var result = methodNode.accept(this);
|
var result = methodNode.accept(this);
|
||||||
valid = valid && result.isValid();
|
valid = valid && result.isValid();
|
||||||
@ -110,32 +98,6 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
|||||||
|
|
||||||
currentScope.pushScope();
|
currentScope.pushScope();
|
||||||
|
|
||||||
//Parameter
|
|
||||||
ParameterListNode parameterListNode = methodNode.parameters;
|
|
||||||
if (parameterListNode != null) {
|
|
||||||
List<ParameterNode> parameters = parameterListNode.parameters;
|
|
||||||
for (ParameterNode parameter : parameters) {
|
|
||||||
if (currentScope.contains(parameter.identifier)) {
|
|
||||||
errors.add(new AlreadyDeclearedException("Duplicated Parameter " + parameter.identifier));
|
|
||||||
return new TypeCheckResult(false, null);
|
|
||||||
} else {
|
|
||||||
currentScope.addLocalVar(parameter.identifier, parameter.type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Statements
|
|
||||||
List<StatementNode> statements = methodNode.statements;
|
|
||||||
for (StatementNode statement : statements) {
|
|
||||||
if (statement instanceof AssignmentStatementNode assignmentStatementNode) {
|
|
||||||
var result = assignmentStatementNode.accept(this);
|
|
||||||
valid = valid && result.isValid();
|
|
||||||
} else if (statement instanceof VariableDeclarationStatementNode variableDeclarationStatementNode) {
|
|
||||||
var result = variableDeclarationStatementNode.accept(this);
|
|
||||||
valid = valid && result.isValid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentScope.popScope();
|
currentScope.popScope();
|
||||||
return new TypeCheckResult(valid, null);
|
return new TypeCheckResult(valid, null);
|
||||||
}
|
}
|
||||||
@ -151,80 +113,6 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
|||||||
return new TypeCheckResult(true, null);
|
return new TypeCheckResult(true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeCheckResult analyze(AssignmentStatementNode assignmentStatementNode) {
|
|
||||||
boolean valid = true;
|
|
||||||
ExpressionNode expressionNodeLeft = assignmentStatementNode.expressionLeft;
|
|
||||||
var resultLeft = expressionNodeLeft.accept(this);
|
|
||||||
valid = valid && resultLeft.isValid();
|
|
||||||
ExpressionNode expressionNodeRight = assignmentStatementNode.expressionRight;
|
|
||||||
var resultRight = expressionNodeRight.accept(this);
|
|
||||||
valid = valid && resultRight.isValid();
|
|
||||||
|
|
||||||
if(Objects.equals(resultLeft.getType(), resultRight.getType())){
|
|
||||||
System.out.println("SAME TYPE");
|
|
||||||
} else {
|
|
||||||
errors.add(new TypeMismatchException("Type mismatch"));
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TypeCheckResult(valid, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeCheckResult analyze(BinaryExpressionNode toCheck) {
|
|
||||||
boolean valid = true;
|
|
||||||
ExpressionNode left = toCheck.left;
|
|
||||||
var resultLeft = left.accept(this);
|
|
||||||
ExpressionNode right = toCheck.right;
|
|
||||||
var resultRight = right.accept(this);
|
|
||||||
|
|
||||||
switch (toCheck.operator) {
|
|
||||||
case ASSIGNMENT:
|
|
||||||
if(Objects.equals(resultRight.getType(), resultLeft.getType())){
|
|
||||||
System.out.println("Correct Type");
|
|
||||||
} else {
|
|
||||||
valid = false;
|
|
||||||
errors.add(new TypeMismatchException("Type Mismatch " + resultLeft.getType() + " and " + resultRight.getType()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DOT:
|
|
||||||
return new TypeCheckResult(true, resultRight.getType());
|
|
||||||
default:
|
|
||||||
throw new RuntimeException("Unexpected operator: " + toCheck.operator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TypeCheckResult(valid, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeCheckResult analyze(IdentifierExpressionNode toCheck) {
|
|
||||||
if(toCheck.name == "this"){
|
|
||||||
return new TypeCheckResult(true, null);
|
|
||||||
} else if (currentFields.get(toCheck.name) == null) {
|
|
||||||
errors.add(new AlreadyDeclearedException("Not declared " + toCheck.name + " in this scope"));
|
|
||||||
return new TypeCheckResult(false, null);
|
|
||||||
} else {
|
|
||||||
return new TypeCheckResult(false, currentFields.get(toCheck.name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeCheckResult analyze(UnaryExpressionNode toCheck) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeCheckResult analyze(VariableDeclarationStatementNode toCheck) {
|
|
||||||
if (currentScope.contains(toCheck.identifier)) {
|
|
||||||
errors.add(new AlreadyDeclearedException("Already declared " + toCheck.identifier + " in this scope"));
|
|
||||||
return new TypeCheckResult(false, null);
|
|
||||||
} else {
|
|
||||||
currentScope.addLocalVar(toCheck.identifier, toCheck.type);
|
|
||||||
}
|
|
||||||
return new TypeCheckResult(true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeCheckResult analyze(IfStatementNode toCheck) {
|
public TypeCheckResult analyze(IfStatementNode toCheck) {
|
||||||
return null;
|
return null;
|
||||||
@ -240,40 +128,4 @@ public class SemanticAnalyzer implements SemanticVisitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeCheckResult analyze(LiteralNode toCheck) {
|
|
||||||
return new TypeCheckResult(true, toCheck.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeCheckResult analyze(InstVar toCheck) {
|
|
||||||
boolean valid = true;
|
|
||||||
|
|
||||||
var result = toCheck.expression.accept(this);
|
|
||||||
|
|
||||||
if(result.getType() instanceof BaseTypeNode){
|
|
||||||
throw new RuntimeException("BaseType has no Methods or Fields");
|
|
||||||
} else {
|
|
||||||
//Get typ of Field
|
|
||||||
|
|
||||||
var type = (ReferenceTypeNode)result.getType();
|
|
||||||
var classContext = context.getClass(type.getIdentifier());
|
|
||||||
|
|
||||||
if(classContext == null){
|
|
||||||
errors.add(new NotDeclearedException("Not declared " + type.getIdentifier() + " in this scope"));
|
|
||||||
return new TypeCheckResult(false, null);
|
|
||||||
} else {
|
|
||||||
var field = classContext.getField(toCheck.identifier);
|
|
||||||
|
|
||||||
return new TypeCheckResult(valid, field.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeCheckResult analyze(This toCheck) {
|
|
||||||
return new TypeCheckResult(true, toCheck.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,18 +1,10 @@
|
|||||||
package semantic;
|
package semantic;
|
||||||
|
|
||||||
|
|
||||||
import ast.ClassNode;
|
import ast.*;
|
||||||
import ast.expression.LiteralNode;
|
import ast.member.*;
|
||||||
import ast.ProgramNode;
|
|
||||||
import ast.expression.BinaryExpressionNode;
|
|
||||||
import ast.expression.IdentifierExpressionNode;
|
|
||||||
import ast.expression.InstVar;
|
|
||||||
import ast.expression.unaryexpression.UnaryExpressionNode;
|
|
||||||
import ast.member.FieldNode;
|
|
||||||
import ast.member.MethodNode;
|
|
||||||
import ast.statement.*;
|
import ast.statement.*;
|
||||||
import ast.expression.This;
|
import ast.statement.ifstatement.*;
|
||||||
import ast.statement.ifstatement.IfStatementNode;
|
|
||||||
import typechecker.TypeCheckResult;
|
import typechecker.TypeCheckResult;
|
||||||
|
|
||||||
public interface SemanticVisitor {
|
public interface SemanticVisitor {
|
||||||
@ -25,25 +17,10 @@ public interface SemanticVisitor {
|
|||||||
|
|
||||||
TypeCheckResult analyze(FieldNode toCheck);
|
TypeCheckResult analyze(FieldNode toCheck);
|
||||||
|
|
||||||
TypeCheckResult analyze(AssignmentStatementNode toCheck);
|
|
||||||
|
|
||||||
TypeCheckResult analyze(BinaryExpressionNode toCheck);
|
|
||||||
|
|
||||||
TypeCheckResult analyze(IdentifierExpressionNode toCheck);
|
|
||||||
|
|
||||||
TypeCheckResult analyze(UnaryExpressionNode toCheck);
|
|
||||||
|
|
||||||
TypeCheckResult analyze(VariableDeclarationStatementNode toCheck);
|
|
||||||
|
|
||||||
TypeCheckResult analyze(IfStatementNode toCheck);
|
TypeCheckResult analyze(IfStatementNode toCheck);
|
||||||
|
|
||||||
TypeCheckResult analyze(ReturnStatementNode toCheck);
|
TypeCheckResult analyze(ReturnStatementNode toCheck);
|
||||||
|
|
||||||
TypeCheckResult analyze(WhileStatementNode toCheck);
|
TypeCheckResult analyze(WhileStatementNode toCheck);
|
||||||
|
|
||||||
TypeCheckResult analyze(LiteralNode toCheck);
|
|
||||||
|
|
||||||
TypeCheckResult analyze(InstVar toCheck);
|
|
||||||
|
|
||||||
TypeCheckResult analyze(This toCheck);
|
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package semantic.context;
|
package semantic.context;
|
||||||
|
|
||||||
import oldAst.ClassNode;
|
import ast.ClassNode;
|
||||||
import oldAst.member.FieldNode;
|
import ast.member.FieldNode;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class ClassContext {
|
public class ClassContext {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package semantic.context;
|
package semantic.context;
|
||||||
|
|
||||||
import oldAst.ProgramNode;
|
import ast.ProgramNode;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class Context {
|
public class Context {
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package semantic.context;
|
package semantic.context;
|
||||||
|
|
||||||
import oldAst.member.FieldNode;
|
import ast.member.FieldNode;
|
||||||
import oldAst.type.AccessTypeNode;
|
import ast.type.*;
|
||||||
import oldAst.type.TypeNode;
|
|
||||||
|
|
||||||
public class FieldContext {
|
public class FieldContext {
|
||||||
|
|
||||||
private AccessTypeNode accessModifier;
|
private AccessModifierNode accessModifier;
|
||||||
private TypeNode type;
|
private TypeNode type;
|
||||||
|
|
||||||
public FieldContext(FieldNode field) {
|
public FieldContext(FieldNode field) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package typechecker;
|
package typechecker;
|
||||||
|
|
||||||
|
|
||||||
import oldAst.type.TypeNode;
|
import ast.type.TypeNode;
|
||||||
|
|
||||||
public class TypeCheckResult {
|
public class TypeCheckResult {
|
||||||
|
|
||||||
|
@ -1,76 +1,36 @@
|
|||||||
package semantic;
|
package semantic;
|
||||||
|
|
||||||
import oldAst.ClassNode;
|
import ast.*;
|
||||||
import oldAst.expression.LiteralNode;
|
import ast.block.BlockNode;
|
||||||
import oldAst.ProgramNode;
|
import ast.member.MethodNode;
|
||||||
import oldAst.expression.*;
|
|
||||||
import oldAst.member.FieldNode;
|
|
||||||
import oldAst.member.MemberNode;
|
|
||||||
import oldAst.member.MethodNode;
|
|
||||||
import oldAst.parameter.ParameterListNode;
|
|
||||||
import oldAst.parameter.ParameterNode;
|
|
||||||
import oldAst.statement.AssignmentStatementNode;
|
|
||||||
import oldAst.statement.StatementNode;
|
|
||||||
import oldAst.type.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static parser.generated.SimpleJavaParser.Identifier;
|
||||||
|
|
||||||
public class Mocker {
|
public class Mocker {
|
||||||
|
|
||||||
public static ProgramNode mockCorrectProgrammNode(){
|
public static ProgramNode mockCorrectClass(){
|
||||||
|
ProgramNode p = new ProgramNode();
|
||||||
|
|
||||||
ProgramNode programNode = new ProgramNode();
|
ClassNode c = new ClassNode();
|
||||||
List<ClassNode> classList = new ArrayList<ClassNode>();
|
c.identifier = "testClass";
|
||||||
AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
|
|
||||||
ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
|
|
||||||
|
|
||||||
MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar1");
|
MethodNode m = new MethodNode();
|
||||||
classNode.members.add(memberNode1);
|
|
||||||
|
|
||||||
MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "objectVar");
|
BlockNode b = new BlockNode();
|
||||||
classNode.members.add(memberNode2);
|
|
||||||
|
|
||||||
List<ParameterNode> parameterNodeList = new ArrayList<ParameterNode>();
|
|
||||||
ParameterNode parameterNode1 = new ParameterNode(new BaseTypeNode(EnumTypeNode.INT), "param1");
|
|
||||||
parameterNodeList.add(parameterNode1);
|
|
||||||
ParameterListNode parameterListNode = new ParameterListNode(parameterNodeList);
|
|
||||||
|
|
||||||
List<StatementNode> statementNodeList = new ArrayList<StatementNode>();
|
|
||||||
|
|
||||||
ExpressionNode expressionNodeLeft = new InstVar(new This("testClass"), "objectVar");
|
// b.statements.add();
|
||||||
|
|
||||||
LiteralNode expressionNodeRight = new LiteralNode();
|
m.block = b;
|
||||||
expressionNodeRight.setType(new BaseTypeNode(EnumTypeNode.INT));
|
|
||||||
|
|
||||||
StatementNode statementNode1 = new AssignmentStatementNode(expressionNodeLeft, expressionNodeRight);
|
c.members.add(m);
|
||||||
statementNodeList.add(statementNode1);
|
|
||||||
|
|
||||||
MemberNode memberNode3 = new MethodNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar2",parameterListNode, statementNodeList );
|
|
||||||
classNode.members.add(memberNode3);
|
|
||||||
|
|
||||||
classList.add(classNode);
|
|
||||||
programNode.classes = classList;
|
|
||||||
|
|
||||||
return programNode;
|
|
||||||
|
|
||||||
|
p.classes.add(c);
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProgramNode mockFieldNodeAlreadyDeclaredProgrammNode(){
|
|
||||||
ProgramNode programNode = new ProgramNode();
|
|
||||||
List<ClassNode> classList = new ArrayList<ClassNode>();
|
|
||||||
AccessTypeNode accessTypeNode = new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
|
|
||||||
ClassNode classNode = new ClassNode(accessTypeNode, "testClass");
|
|
||||||
|
|
||||||
MemberNode memberNode1 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar");
|
|
||||||
classNode.members.add(memberNode1);
|
|
||||||
|
|
||||||
MemberNode memberNode2 = new FieldNode(accessTypeNode, new BaseTypeNode(EnumTypeNode.INT), "testVar");
|
|
||||||
classNode.members.add(memberNode2);
|
|
||||||
|
|
||||||
classList.add(classNode);
|
|
||||||
programNode.classes = classList;
|
|
||||||
|
|
||||||
return programNode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,161 +1,13 @@
|
|||||||
package semantic;
|
package semantic;
|
||||||
|
|
||||||
|
|
||||||
import oldAst.*;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import semantic.exeptions.AlreadyDeclearedException;
|
|
||||||
import semantic.exeptions.TypeMismatchException;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
public class SemanticTest {
|
public class SemanticTest {
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void init() {
|
|
||||||
SemanticAnalyzer.clearAnalyzier();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void alreadyDeclaredLocalFieldVar() {
|
public void correctClass(){
|
||||||
|
|
||||||
//Arrange
|
|
||||||
|
|
||||||
ProgramNode programNode = Mocker.mockFieldNodeAlreadyDeclaredProgrammNode();
|
|
||||||
|
|
||||||
//Act
|
|
||||||
|
|
||||||
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
|
||||||
|
|
||||||
//Assert
|
|
||||||
|
|
||||||
assertEquals(1, SemanticAnalyzer.errors.size());
|
|
||||||
assertEquals(true, SemanticAnalyzer.errors.get(0) instanceof AlreadyDeclearedException);
|
|
||||||
assertEquals(null, typedAst);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void alreadyDecleared() {
|
|
||||||
|
|
||||||
//Arrange
|
|
||||||
|
|
||||||
ProgramNode programNode = Mocker.mockFieldNodeAlreadyDeclaredProgrammNode();
|
|
||||||
|
|
||||||
//Act
|
|
||||||
|
|
||||||
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
|
||||||
|
|
||||||
//Assert
|
|
||||||
|
|
||||||
assertEquals(1, SemanticAnalyzer.errors.size());
|
|
||||||
assertInstanceOf(AlreadyDeclearedException.class, SemanticAnalyzer.errors.getFirst());
|
|
||||||
assertNull(typedAst);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldWorkWithNoError() {
|
|
||||||
|
|
||||||
//Arrange
|
|
||||||
|
|
||||||
ProgramNode programNode = Mocker.mockCorrectProgrammNode();
|
|
||||||
|
|
||||||
//Act
|
|
||||||
|
|
||||||
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
|
||||||
|
|
||||||
//Assert
|
|
||||||
|
|
||||||
assertEquals(0, SemanticAnalyzer.errors.size());
|
|
||||||
assertEquals(programNode, typedAst);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void refTypeCorrect() {
|
|
||||||
|
|
||||||
//Arrange
|
|
||||||
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
ProgramNode programNode = null;
|
|
||||||
try{
|
|
||||||
programNode = objectMapper.readValue(new File("src/test/resources/semantic/correctRefType.json"), ProgramNode.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Act
|
|
||||||
|
|
||||||
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
|
||||||
|
|
||||||
//Assert
|
|
||||||
|
|
||||||
assertEquals(0, SemanticAnalyzer.errors.size());
|
|
||||||
assertEquals(programNode, typedAst);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void jsonWriteTest() {
|
|
||||||
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
|
|
||||||
//Arrange
|
|
||||||
|
|
||||||
ProgramNode programNode = Mocker.mockCorrectProgrammNode();
|
|
||||||
try{
|
|
||||||
objectMapper.writeValue(new File("src/test/resources/semantic/test.json"), programNode);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void jsonReadTest() {
|
|
||||||
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
|
|
||||||
ProgramNode programNode1 = null;
|
|
||||||
try{
|
|
||||||
programNode1 = objectMapper.readValue(new File("src/test/resources/semantic/test.json"), ProgramNode.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgramNode programNode2 = Mocker.mockCorrectProgrammNode();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void typeMismatch() {
|
|
||||||
|
|
||||||
//Arrange
|
|
||||||
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
ProgramNode programNode = null;
|
|
||||||
try{
|
|
||||||
programNode = objectMapper.readValue(new File("src/test/resources/semantic/refTypeMismatch.json"), ProgramNode.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Act
|
|
||||||
|
|
||||||
ASTNode typedAst = SemanticAnalyzer.generateTast(programNode);
|
|
||||||
|
|
||||||
//Assert
|
|
||||||
|
|
||||||
assertEquals(1, SemanticAnalyzer.errors.size());
|
|
||||||
assertInstanceOf(TypeMismatchException.class, SemanticAnalyzer.errors.getFirst());
|
|
||||||
assertNull(typedAst);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
41
src/test/java/semantic/endToTAST/CorrectTest.java
Normal file
41
src/test/java/semantic/endToTAST/CorrectTest.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package semantic.endToTAST;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class CorrectTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void first(){
|
||||||
|
|
||||||
|
CharStream codeCharStream = null;
|
||||||
|
try {
|
||||||
|
codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/semantic/endToTAST/Test.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);
|
||||||
|
|
||||||
|
System.out.println("Test");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
7
src/test/resources/semantic/endToTAST/Test.java
Normal file
7
src/test/resources/semantic/endToTAST/Test.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
public class Test {
|
||||||
|
|
||||||
|
public void test(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user