Merge branch 'master' of https://gitea.hb.dhbw-stuttgart.de/i22022/NichtHaskell
# Conflicts: # src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java # src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java # src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java # src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java
This commit is contained in:
commit
5fa6664850
@ -12,6 +12,7 @@ import org.objectweb.asm.Opcodes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FieldDecl extends AbstractType implements Node {
|
||||
|
||||
@ -43,18 +44,13 @@ public class FieldDecl extends AbstractType implements Node {
|
||||
//write field table
|
||||
}
|
||||
|
||||
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, List<MethodDecl> fieldsOrMethods) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void codeGen(ClassWriter cw) {
|
||||
//TODO: Do we have fields with initial values?
|
||||
//TODO: Do we have fields with initial values? --> No dont think so --> assign
|
||||
FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
|
||||
private String getFieldDescriptor() {
|
||||
//TODO: Maybe we have to check for arrays?
|
||||
switch (type) {
|
||||
case "int":
|
||||
return "I";
|
||||
@ -66,4 +62,13 @@ public class FieldDecl extends AbstractType implements Node {
|
||||
return "L" + type + ";";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FieldDecl fieldDecl = (FieldDecl) o;
|
||||
return ( Objects.equals(type, fieldDecl.type)
|
||||
&& Objects.equals(identifier, fieldDecl.identifier));
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,7 @@ import abstractSyntaxTree.Statement.BlockStatement;
|
||||
import abstractSyntaxTree.Statement.IStatement;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.*;
|
||||
|
||||
public class MethodDecl implements Node {
|
||||
|
||||
@ -25,7 +22,8 @@ public class MethodDecl implements Node {
|
||||
public String returnType;
|
||||
public BlockStatement codeBlock;
|
||||
|
||||
public HashMap<String, String> localVars;
|
||||
//TODO: Can this be a linked hash map? --> need it to be to get the index of local variables
|
||||
public LinkedHashMap<String, String> localVars;
|
||||
|
||||
public MethodDecl(String classThatContainsMethod, String returnType, String name, ParameterList parameters, BlockStatement codeBlock){
|
||||
this.classThatContainsMethod = classThatContainsMethod;
|
||||
@ -33,7 +31,7 @@ public class MethodDecl implements Node {
|
||||
this.name = name;
|
||||
this.parameters = parameters;
|
||||
this.codeBlock = codeBlock;
|
||||
this.localVars = new HashMap<>();
|
||||
this.localVars = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
|
||||
@ -119,7 +117,7 @@ public class MethodDecl implements Node {
|
||||
for (Parameter param : parameters.parameterList) {
|
||||
switch (param.type) {
|
||||
case "int" -> descriptor.append("I");
|
||||
case "boolean" -> descriptor.append("Z");
|
||||
case "bool" -> descriptor.append("Z");
|
||||
case "char" -> descriptor.append("C");
|
||||
case "void" -> descriptor.append("V");
|
||||
default -> {
|
||||
@ -139,7 +137,7 @@ public class MethodDecl implements Node {
|
||||
} else {
|
||||
switch (returnType) {
|
||||
case "int" -> descriptor.append("I");
|
||||
case "boolean" -> descriptor.append("Z");
|
||||
case "bool" -> descriptor.append("Z");
|
||||
case "char" -> descriptor.append("C");
|
||||
case "void" -> descriptor.append("V");
|
||||
default -> {
|
||||
@ -160,4 +158,16 @@ public class MethodDecl implements Node {
|
||||
}
|
||||
return descriptor.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
MethodDecl methodDecl = (MethodDecl) o;
|
||||
return (Objects.equals(name, methodDecl.name)
|
||||
&& Objects.equals(parameters, methodDecl.parameters)
|
||||
&& Objects.equals(returnType, methodDecl.returnType)
|
||||
&& Objects.equals(codeBlock, methodDecl.codeBlock));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import org.objectweb.asm.Opcodes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class RefType extends AbstractType implements Node {
|
||||
|
||||
@ -84,10 +85,21 @@ public class RefType extends AbstractType implements Node {
|
||||
}
|
||||
|
||||
for (MethodDecl method : methodDecls) {
|
||||
// method.codeGen(cw);
|
||||
method.codeGen(cw, methodContext);
|
||||
}
|
||||
cw.visitEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
System.out.println("Dont forget me ;)");
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
RefType refType = (RefType) o;
|
||||
return ( Objects.equals(name, refType.name)
|
||||
&& Objects.equals(fieldDecls, refType.fieldDecls)
|
||||
&& Objects.equals(methodDecls, refType.methodDecls)
|
||||
&& Objects.equals(hasMain, refType.hasMain));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import org.objectweb.asm.*;
|
||||
|
||||
import java.beans.Expression;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
public class BinaryExpression extends AbstractType implements IExpression{
|
||||
@ -16,6 +17,12 @@ public class BinaryExpression extends AbstractType implements IExpression{
|
||||
public IExpression left;
|
||||
public IExpression right;
|
||||
|
||||
public BinaryExpression(String operator, IExpression left, IExpression right) {
|
||||
this.operator = operator;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
|
||||
TypeCheckHelper helper = new TypeCheckHelper();
|
||||
@ -60,7 +67,7 @@ public class BinaryExpression extends AbstractType implements IExpression{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv) throws Exception {
|
||||
public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
|
||||
// Label for the jump instruction
|
||||
Label operationFalse = new Label(); //Operation is false
|
||||
Label operationTrue = new Label(); //Operation is true
|
||||
@ -70,88 +77,88 @@ public class BinaryExpression extends AbstractType implements IExpression{
|
||||
// Bytecode for the binary operation
|
||||
switch (operator) {
|
||||
case "&&":
|
||||
left.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // IFEQ --> "if equals to zero" (false) --> if left exp is false
|
||||
|
||||
right.codeGen(mv);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // If right exp is false, jump to the end of the whole expression
|
||||
|
||||
mv.visitJumpInsn(Opcodes.GOTO, operationTrue); // If it reaches this point, the right exp is true
|
||||
break;
|
||||
|
||||
case "||":
|
||||
left.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
mv.visitJumpInsn(Opcodes.IFNE, operationTrue); // IFNE --> "if not equals to zero" (true) --> if left exp is true
|
||||
|
||||
right.codeGen(mv);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
mv.visitJumpInsn(Opcodes.IFNE, operationTrue);
|
||||
break;
|
||||
|
||||
case "==":
|
||||
// Keep in mind that only primitive types are allowed in this case (at this time)
|
||||
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression
|
||||
break;
|
||||
|
||||
case "<":
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal
|
||||
break;
|
||||
|
||||
case ">":
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal
|
||||
break;
|
||||
|
||||
case "<=":
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal
|
||||
break;
|
||||
|
||||
case ">=":
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal
|
||||
break;
|
||||
|
||||
case "!=":
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal
|
||||
break;
|
||||
|
||||
case "+":
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
mv.visitInsn(Opcodes.IADD);
|
||||
break;
|
||||
|
||||
case "-":
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
mv.visitInsn(Opcodes.ISUB);
|
||||
break;
|
||||
|
||||
case "*":
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
mv.visitInsn(Opcodes.IMUL);
|
||||
break;
|
||||
|
||||
case "/":
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
left.codeGen(mv, typeContext, localVars);
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
mv.visitInsn(Opcodes.IDIV);
|
||||
break;
|
||||
|
||||
|
@ -1,16 +1,18 @@
|
||||
package abstractSyntaxTree.Expression;
|
||||
|
||||
import TypeCheck.TypeCheckResult;
|
||||
import abstractSyntaxTree.Node;
|
||||
import abstractSyntaxTree.Parameter.ParameterList;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public interface IExpression {
|
||||
public interface IExpression extends Node {
|
||||
// typeCheck method
|
||||
//TypeCheckResult typeCheck() throws Exception;
|
||||
TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception;
|
||||
|
||||
// visit method for code generation
|
||||
void codeGen(MethodVisitor mv) throws Exception;
|
||||
void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception;
|
||||
}
|
||||
|
@ -5,15 +5,17 @@ import abstractSyntaxTree.Class.RefType;
|
||||
import abstractSyntaxTree.Parameter.ParameterList;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class InstVarExpression implements IExpression{
|
||||
|
||||
//TODO: We have to decide upon more parameters and where they come from, for
|
||||
// example here we need the index of the field, the class reference and the field name
|
||||
private RefType classRef;
|
||||
private String fieldName;
|
||||
public RefType classRef;
|
||||
public String fieldName;
|
||||
|
||||
public InstVarExpression(RefType classRef, String fieldName){
|
||||
this.classRef = classRef;
|
||||
@ -32,11 +34,33 @@ public class InstVarExpression implements IExpression{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv) throws Exception {
|
||||
throw new ExecutionControl.NotImplementedException("CodeGen not implemented for InstVarExpression");
|
||||
// typeContext: (ClassName, (FieldName, FieldType))
|
||||
public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
|
||||
// Load "this" onto the stack
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
|
||||
//ALOAD the index of the var
|
||||
//GETFIELD the field
|
||||
//visitFieldInsn(Opcodes.GETFIELD, "class reference", "field name", type);
|
||||
//Get the field information
|
||||
String fieldType = typeContext.get(classRef.name).get(fieldName);
|
||||
|
||||
String fieldDescriptor;
|
||||
|
||||
switch (fieldType) {
|
||||
case "int":
|
||||
fieldDescriptor = "I";
|
||||
break;
|
||||
case "boolean":
|
||||
fieldDescriptor = "Z";
|
||||
break;
|
||||
case "char":
|
||||
fieldDescriptor = "C";
|
||||
break;
|
||||
default:
|
||||
//TODO: We need the fully qualified name of the class here in field type
|
||||
fieldDescriptor = "L" + fieldType + ";";
|
||||
break;
|
||||
}
|
||||
|
||||
// Load the variable onto the stack
|
||||
mv.visitFieldInsn(Opcodes.GETFIELD, classRef.name, fieldName, fieldDescriptor);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,10 @@ package abstractSyntaxTree.Expression;
|
||||
|
||||
import TypeCheck.TypeCheckHelper;
|
||||
import TypeCheck.TypeCheckResult;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import abstractSyntaxTree.Parameter.ParameterList;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
@ -24,7 +28,41 @@ public class LocalVarIdentifier implements IExpression{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv) throws Exception {
|
||||
public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
|
||||
// Check if the variable is in the list of local variables
|
||||
String type = localVars.get(identifier);
|
||||
if (type == null){
|
||||
throw new Exception("Variable " + identifier + " not declared");
|
||||
}
|
||||
|
||||
// Load the variable onto the stack
|
||||
int index = -1;
|
||||
int counter = 0;
|
||||
for (String key : localVars.keySet()){
|
||||
if (key.equals(identifier)){
|
||||
index = counter;
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (index == -1){
|
||||
throw new Exception("Variable " + identifier + " not found");
|
||||
}
|
||||
|
||||
// Load the variable onto the stack
|
||||
switch (type){
|
||||
case "int":
|
||||
mv.visitVarInsn(Opcodes.ILOAD, index);
|
||||
break;
|
||||
case "bool":
|
||||
mv.visitVarInsn(Opcodes.ILOAD, index);
|
||||
break;
|
||||
case "void":
|
||||
break;
|
||||
default:
|
||||
mv.visitVarInsn(Opcodes.ALOAD, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ import TypeCheck.AbstractType;
|
||||
import TypeCheck.TypeCheckHelper;
|
||||
import TypeCheck.TypeCheckResult;
|
||||
import abstractSyntaxTree.Datatype.IDatatype;
|
||||
import abstractSyntaxTree.Parameter.ParameterList;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
public class UnaryExpression extends AbstractType implements IExpression{
|
||||
@ -18,7 +18,6 @@ public class UnaryExpression extends AbstractType implements IExpression{
|
||||
this.operator = operator;
|
||||
this.operand = operand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception {
|
||||
TypeCheckResult result = new TypeCheckResult();
|
||||
@ -50,7 +49,7 @@ public class UnaryExpression extends AbstractType implements IExpression{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv) throws Exception {
|
||||
public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
|
||||
|
||||
operand.codeGen(mv);
|
||||
|
||||
|
@ -104,4 +104,14 @@ public class Program implements Node {
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Program program = (Program) o;
|
||||
System.out.println(classes);
|
||||
System.out.println(program.classes);
|
||||
return (Objects.equals(classes, program.classes));
|
||||
}
|
||||
}
|
@ -6,11 +6,14 @@ import abstractSyntaxTree.Parameter.ParameterList;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public interface IStatement extends Node {
|
||||
|
||||
TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception;
|
||||
|
||||
void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception;
|
||||
void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars) throws Exception;
|
||||
|
||||
void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext) throws Exception;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import TypeCheck.TypeCheckHelper;
|
||||
import TypeCheck.TypeCheckResult;
|
||||
import abstractSyntaxTree.Parameter.ParameterList;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -30,6 +31,25 @@ public class LocalVarDecl implements IStatement{
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
|
||||
localVars.put(identifier, type);
|
||||
|
||||
// Set a default value for the variable --> less problems
|
||||
int index = localVars.size()-1;
|
||||
|
||||
switch (type){
|
||||
case "int":
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitVarInsn(Opcodes.ISTORE, index);
|
||||
break;
|
||||
case "bool":
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitVarInsn(Opcodes.ISTORE, index);
|
||||
break;
|
||||
case "void":
|
||||
break;
|
||||
default:
|
||||
mv.visitInsn(Opcodes.ACONST_NULL);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ public class ReturnStatement extends AbstractType implements IStatement{
|
||||
if (expression != null) {
|
||||
expression.codeGen(mv);
|
||||
//Get the Type of the expression
|
||||
//TODO: Resolve how do we get the type of the expression
|
||||
String type = expression.typeCheck(null, null, null).type;
|
||||
|
||||
if (type.equals("int") || type.equals("bool") || type.equals("char")) {
|
||||
|
@ -11,12 +11,13 @@ import abstractSyntaxTree.Statement.IStatement;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class AssignStatementExpression extends AbstractType implements IExpression, IStatement {
|
||||
public String operator;
|
||||
public IExpression left;
|
||||
public IExpression right;
|
||||
private InstVarExpression instVar;
|
||||
|
||||
public AssignStatementExpression(String operator, IExpression leftExpression, IExpression rightExpression){
|
||||
this.operator = operator;
|
||||
@ -51,9 +52,9 @@ public class AssignStatementExpression extends AbstractType implements IExpressi
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
|
||||
// if (left instanceof VarRefExpression varRef) {
|
||||
//
|
||||
// }
|
||||
if (left instanceof VarRefExpression varRef) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -62,9 +63,48 @@ public class AssignStatementExpression extends AbstractType implements IExpressi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv) throws Exception {
|
||||
left.codeGen(mv);
|
||||
right.codeGen(mv);
|
||||
public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
|
||||
//TODO: Do we need the value on the stack after assigning it?
|
||||
//TODO: WE do not differentiate between InstanceVar and FieldVar
|
||||
|
||||
// Call the codeGen on the right expression which will push the value of the right expression onto the stack
|
||||
right.codeGen(mv, typeContext, localVars);
|
||||
|
||||
if (left instanceof LocalVarIdentifier) {
|
||||
LocalVarIdentifier localVar = (LocalVarIdentifier) left;
|
||||
String varName = localVar.getIdentifier();
|
||||
|
||||
//Get the index of the local variable
|
||||
int index = -1;
|
||||
int counter = 0;
|
||||
for (String key : localVars.keySet()){
|
||||
if (key.equals(varName)){
|
||||
index = counter;
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (index == -1){
|
||||
throw new Exception("Variable " + varName + " not found");
|
||||
}
|
||||
|
||||
String type = localVars.get(localVar.getIdentifier());
|
||||
switch (type) {
|
||||
case "int":
|
||||
case "bool":
|
||||
mv.visitVarInsn(Opcodes.ISTORE, index);
|
||||
break;
|
||||
default:
|
||||
mv.visitVarInsn(Opcodes.ASTORE, index);
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (left instanceof InstVarExpression){
|
||||
instVar = (InstVarExpression) left;
|
||||
|
||||
// Load "this" onto the stack
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
|
||||
// if (left instanceof VarRefExpression varRef) {
|
||||
// //TODO: Implement the handling of a variable reference --> I need a list of local variables
|
||||
|
@ -12,6 +12,7 @@ import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class MethodCallStatementExpression extends AbstractType implements IExpression, IStatement {
|
||||
@ -50,27 +51,44 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
//Errors occur due to the change in parameter in the RefType class
|
||||
// I need the methodContext here to get the method descriptor
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv) throws Exception {
|
||||
public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
|
||||
//Generate Bytecode for the receiver
|
||||
if(classThatHasTheMethodIfNotThis != null){
|
||||
// classThatHasTheMethodIfNotThis.codeGen(new ClassWriter(ClassWriter.COMPUTE_FRAMES));
|
||||
//TODO: classThatHasTheMethodIfNotThis must be an object --> instance of the class not the class itself
|
||||
//classThatHasTheMethodIfNotThis.codeGen();
|
||||
|
||||
String descriptor;
|
||||
List<MethodDecl> methodDecls = thisClass.methodDecls;
|
||||
for (MethodDecl methodDecl : methodDecls) {
|
||||
if (methodDecl.name.equals(methodName)) {
|
||||
//Get the method descriptor
|
||||
descriptor = methodDecl.getMethodDescriptor(methodContext);
|
||||
}
|
||||
}
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, classThatHasTheMethodIfNotThis.name, methodName, descriptor, false);
|
||||
|
||||
} else {
|
||||
// Load this onto the stack
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
}
|
||||
|
||||
for (IExpression argument : arguments) {
|
||||
argument.codeGen(mv);
|
||||
argument.codeGen(mv, typeContext, localVars);
|
||||
}
|
||||
|
||||
//We need the class reference and the return type of the method
|
||||
//mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, thisClass.name, methodName, return type);
|
||||
|
||||
// Get the method descriptor
|
||||
String descriptor;
|
||||
List<MethodDecl> methodDecls = thisClass.methodDecls;
|
||||
for (MethodDecl methodDecl : methodDecls) {
|
||||
if (methodDecl.name.equals(methodName)) {
|
||||
//Get the method descriptor
|
||||
descriptor = methodDecl.getMethodDescriptor(methodContext);
|
||||
}
|
||||
}
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, thisClass.name, methodName, descriptor, false);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import abstractSyntaxTree.Class.FieldDecl;
|
||||
import abstractSyntaxTree.Class.MethodDecl;
|
||||
import abstractSyntaxTree.Class.RefType;
|
||||
import abstractSyntaxTree.Expression.BinaryExpression;
|
||||
import abstractSyntaxTree.Expression.IExpression;
|
||||
import abstractSyntaxTree.Node;
|
||||
import abstractSyntaxTree.Parameter.Parameter;
|
||||
import abstractSyntaxTree.Parameter.ParameterList;
|
||||
@ -114,7 +115,8 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
|
||||
|
||||
@Override
|
||||
public Node visitReturnStmt(DecafParser.ReturnStmtContext ctx) {
|
||||
return new ReturnStatement(new BinaryExpression());
|
||||
Node expression = visitExpression(ctx.expression());
|
||||
return new ReturnStatement((IExpression) expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -132,22 +134,25 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
|
||||
if (ctx.elseStmt() != null) {
|
||||
return visitIfStmt(ctx.ifStmt());
|
||||
} else {
|
||||
Node expression = visitExpression(ctx.ifStmt().expression());
|
||||
Node ifStatement = visitStatement(ctx.ifStmt().statement());
|
||||
Node elseStatement = visitStatement(ctx.elseStmt().statement());
|
||||
return new IfElseStatement(new BinaryExpression(), (IStatement) ifStatement, (IStatement) elseStatement);
|
||||
return new IfElseStatement((IExpression) expression, (IStatement) ifStatement, (IStatement) elseStatement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visitIfStmt(DecafParser.IfStmtContext ctx) {
|
||||
Node expression = visitExpression(ctx.expression());
|
||||
Node statement = visitStatement(ctx.statement());
|
||||
return new IfStatement(new BinaryExpression(), (IStatement) statement);
|
||||
return new IfStatement((IExpression) expression, (IStatement) statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visitWhileStmt(DecafParser.WhileStmtContext ctx) {
|
||||
Node expression = visitExpression(ctx.expression());
|
||||
Node statement = visitStatement(ctx.statement());
|
||||
return new WhileStatement(new BinaryExpression(), (IStatement) statement);
|
||||
return new WhileStatement((IExpression) expression, (IStatement) statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -167,7 +172,6 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Node visitAssign(DecafParser.AssignContext ctx) {
|
||||
return new AssignStatementExpression("", null, null);
|
||||
@ -182,4 +186,79 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
|
||||
public Node visitNewDecl(DecafParser.NewDeclContext ctx) {
|
||||
return super.visitNewDecl(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visitExpression(DecafParser.ExpressionContext ctx) {
|
||||
if (ctx.subExpression() != null) {
|
||||
|
||||
} else if (ctx.binaryExpr() != null) {
|
||||
return visitBinaryExpr(ctx.binaryExpr());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visitBinaryExpr(DecafParser.BinaryExprContext ctx) {
|
||||
if (ctx.calcExpr() != null) {
|
||||
return visitCalcExpr(ctx.calcExpr());
|
||||
} else if (ctx.nonCalcExpr() != null) {
|
||||
return visitNonCalcExpr(ctx.nonCalcExpr());
|
||||
} else if (ctx.value() != null) {
|
||||
//todo
|
||||
} else if (ctx.binaryExpr() != null) {
|
||||
//todo
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visitCalcExpr(DecafParser.CalcExprContext ctx) {
|
||||
if (ctx.calcExpr() != null) {
|
||||
Node left = visitCalcExpr(ctx.calcExpr());
|
||||
Node right = visitDotExpr(ctx.dotExpr());
|
||||
return new BinaryExpression(ctx.LineOperator().getText(), (IExpression) left, (IExpression) right);
|
||||
} else {
|
||||
visitDotExpr(ctx.dotExpr());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visitDotExpr(DecafParser.DotExprContext ctx) {
|
||||
if (ctx.dotExpr() != null) {
|
||||
Node left = visitDotExpr(ctx.dotExpr());
|
||||
Node right = visitDotSubExpr(ctx.dotSubExpr());
|
||||
return new BinaryExpression(ctx.DotOperator().getText(), (IExpression) left, (IExpression) right);
|
||||
} else {
|
||||
visitDotSubExpr(ctx.dotSubExpr());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//todo
|
||||
@Override
|
||||
public Node visitDotSubExpr(DecafParser.DotSubExprContext ctx) {
|
||||
return super.visitDotSubExpr(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visitNonCalcExpr(DecafParser.NonCalcExprContext ctx) {
|
||||
String operator;
|
||||
if(ctx.nonCalcOperator().LogicalOpertor() != null) {
|
||||
operator = ctx.nonCalcOperator().LogicalOpertor().getText();
|
||||
} else {
|
||||
operator = ctx.nonCalcOperator().ComparisonOperator().getText();
|
||||
}
|
||||
Node left = visitSubExpression(ctx.subExpression());
|
||||
Node right = visitExpression(ctx.expression());
|
||||
return new BinaryExpression(operator, (IExpression) left, (IExpression) right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visitSubExpression(DecafParser.SubExpressionContext ctx) {
|
||||
if (ctx.subExpression() != null) {
|
||||
visitSubExpression(ctx.subExpression());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
44
src/test/java/AST/AstComparer.java
Normal file
44
src/test/java/AST/AstComparer.java
Normal file
@ -0,0 +1,44 @@
|
||||
package AST;
|
||||
|
||||
import ASTs.emptyClassAST;
|
||||
import abstractSyntaxTree.Program;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import abstractSyntaxTree.Statement.BlockStatement;
|
||||
import gen.DecafLexer;
|
||||
import gen.DecafParser;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.junit.Test;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import abstractSyntaxTree.ASTGenerator;
|
||||
|
||||
public class AstComparer {
|
||||
|
||||
private static String BASE_DIR;
|
||||
public AstComparer(String base_directory){
|
||||
BASE_DIR = base_directory + "/";
|
||||
}
|
||||
|
||||
|
||||
public void astComparison(String sourceFilePath, Program expectedAST) throws Exception {
|
||||
// Read the source file
|
||||
String content = new String(Files.readAllBytes(Paths.get(BASE_DIR + sourceFilePath)));
|
||||
CharStream codeCharStream = CharStreams.fromString(content);
|
||||
|
||||
// Setup Lexer and Parser
|
||||
DecafLexer lexer = new DecafLexer(codeCharStream);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
DecafParser parser = new DecafParser(tokens);
|
||||
ParseTree tree = parser.program();
|
||||
|
||||
// Generate AST
|
||||
ASTGenerator generator = new ASTGenerator();
|
||||
Program generatedAST = (Program) generator.visit(tree);
|
||||
|
||||
// Assert that both ASTs are equal
|
||||
assertEquals("The generated AST does not match the expected AST", expectedAST, generatedAST);
|
||||
}
|
||||
|
||||
}
|
28
src/test/java/AST/testAll.java
Normal file
28
src/test/java/AST/testAll.java
Normal file
@ -0,0 +1,28 @@
|
||||
package AST;
|
||||
import ASTs.emptyClassAST;
|
||||
import abstractSyntaxTree.Program;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class testAll {
|
||||
|
||||
AstComparer astComparer;
|
||||
public testAll()
|
||||
{
|
||||
this.astComparer = new AstComparer("src/test/resources");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestAstGeneration()
|
||||
{
|
||||
System.out.println("Current working directory: " + new File(".").getAbsolutePath());
|
||||
Program testEmptyClassAST = emptyClassAST.getEmptyProgramm();
|
||||
|
||||
try {
|
||||
astComparer.astComparison("basicClasses/emptyClass.java", testEmptyClassAST);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
24
src/test/java/ASTs/emptyClassAST.java
Normal file
24
src/test/java/ASTs/emptyClassAST.java
Normal file
@ -0,0 +1,24 @@
|
||||
package ASTs;
|
||||
|
||||
import abstractSyntaxTree.*;
|
||||
import abstractSyntaxTree.Class.FieldDecl;
|
||||
import abstractSyntaxTree.Class.MethodDecl;
|
||||
import abstractSyntaxTree.Class.RefType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class emptyClassAST {
|
||||
|
||||
|
||||
public static Program getEmptyProgramm() {
|
||||
List<FieldDecl> emptyFieldDeclList = new ArrayList<>();
|
||||
List<MethodDecl> emptyMethodDeclList = new ArrayList<>();
|
||||
RefType emptyClass = new RefType("emptyClass", emptyFieldDeclList, emptyMethodDeclList, false);
|
||||
List<RefType> classes = new ArrayList<>();
|
||||
classes.add(emptyClass);
|
||||
|
||||
return (new Program(classes));
|
||||
}
|
||||
|
||||
}
|
34
src/test/java/ASTs/emptyClassWithConstructorAST.java
Normal file
34
src/test/java/ASTs/emptyClassWithConstructorAST.java
Normal file
@ -0,0 +1,34 @@
|
||||
package ASTs;
|
||||
|
||||
import abstractSyntaxTree.Class.FieldDecl;
|
||||
import abstractSyntaxTree.Class.MethodDecl;
|
||||
import abstractSyntaxTree.Class.RefType;
|
||||
import abstractSyntaxTree.Parameter.Parameter;
|
||||
import abstractSyntaxTree.Parameter.ParameterList;
|
||||
import abstractSyntaxTree.Program;
|
||||
import abstractSyntaxTree.Statement.BlockStatement;
|
||||
import abstractSyntaxTree.Statement.IStatement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class emptyClassWithConstructorAST extends Program {
|
||||
public emptyClassWithConstructorAST()
|
||||
{
|
||||
super(staticClasses());
|
||||
}
|
||||
private static List<RefType> staticClasses() {
|
||||
List<FieldDecl> fieldDeclList = new ArrayList<>();
|
||||
|
||||
ParameterList emptyParameterList = new ParameterList(new ArrayList<>());
|
||||
List<IStatement> emptyIStatementList = new ArrayList<>();
|
||||
BlockStatement emptyBlockStatement = new BlockStatement(emptyIStatementList, "void");
|
||||
MethodDecl constructor = new MethodDecl("emptyClassWithConstructor", "null", "emptyClassWithConstructor", emptyParameterList, emptyBlockStatement);
|
||||
List<MethodDecl> methodDeclList = new ArrayList<>();
|
||||
methodDeclList.add(constructor);
|
||||
RefType emptyClass = new RefType("emptyClass", fieldDeclList, methodDeclList, false);
|
||||
List<RefType> classes = new ArrayList<>();
|
||||
classes.add(emptyClass);
|
||||
return classes;
|
||||
}
|
||||
}
|
80
src/test/java/ASTs/fourClassesAST.java
Normal file
80
src/test/java/ASTs/fourClassesAST.java
Normal file
@ -0,0 +1,80 @@
|
||||
package ASTs;
|
||||
|
||||
import abstractSyntaxTree.Class.FieldDecl;
|
||||
import abstractSyntaxTree.Class.MethodDecl;
|
||||
import abstractSyntaxTree.Class.RefType;
|
||||
import abstractSyntaxTree.Expression.IExpression;
|
||||
import abstractSyntaxTree.Expression.InstVarExpression;
|
||||
import abstractSyntaxTree.Parameter.Parameter;
|
||||
import abstractSyntaxTree.Parameter.ParameterList;
|
||||
import abstractSyntaxTree.Program;
|
||||
import abstractSyntaxTree.Statement.BlockStatement;
|
||||
import abstractSyntaxTree.Statement.IStatement;
|
||||
import abstractSyntaxTree.Statement.ReturnStatement;
|
||||
import abstractSyntaxTree.StatementExpression.AssignStatementExpression;
|
||||
import abstractSyntaxTree.StatementExpression.NewStatementExpression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
public class fourClassesAST extends Program {
|
||||
|
||||
public fourClassesAST()
|
||||
{
|
||||
super(staticClasses());
|
||||
}
|
||||
private static List<RefType> staticClasses() {
|
||||
|
||||
/////////// Classes ///////////
|
||||
|
||||
///////// Class: FourClasses /////////
|
||||
|
||||
/////// Fields ///////
|
||||
List<FieldDecl> fieldDeclList = new ArrayList<>();
|
||||
|
||||
ParameterList emptyParameterList = new ParameterList(new ArrayList<>());
|
||||
|
||||
/////// Methods ///////
|
||||
|
||||
// Main //
|
||||
|
||||
List<IStatement> emptyIStatementList = new ArrayList<>();
|
||||
BlockStatement emptyBlockStatement = new BlockStatement(emptyIStatementList, "void");
|
||||
MethodDecl constructor = new MethodDecl("emptyClassWithConstructor", "null", "emptyClassWithConstructor", emptyParameterList, emptyBlockStatement);
|
||||
|
||||
//IStatement
|
||||
List<IStatement> fourClassesMainBlockIstatements = new ArrayList<>();
|
||||
|
||||
IExpression atntiLeft = new InstVarExpression("Test", "t");
|
||||
IExpression atntiRight = new NewStatementExpression();
|
||||
AssignStatementExpression atnti = new AssignStatementExpression(atntiLeft, "=", );
|
||||
|
||||
|
||||
ReturnStatement fcmbiReturn = new ReturnStatement();
|
||||
|
||||
fourClassesMainBlockIstatements.add(atnti);
|
||||
//BlockStatement
|
||||
BlockStatement fourClassesMainBlock = new BlockStatement(fourClassesMainBlockIstatements, "int");
|
||||
|
||||
//Parameter
|
||||
Parameter intI = new Parameter("int", "i");
|
||||
List<Parameter> fourClassesMainParameterList = new ArrayList<>();
|
||||
|
||||
ParameterList fourClassesMainParameters = new ParameterList(fourClassesMainParameterList);
|
||||
|
||||
MethodDecl fourClassesMain = new MethodDecl("fourClasses", "int", "main", fourClassesMainParameters, fourClassesMainBlock);
|
||||
List<MethodDecl> MethodDeclList = new ArrayList<>();
|
||||
|
||||
RefType emptyClass = new RefType("emptyClass", fieldDeclList, MethodDeclList, false);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
List<RefType> classes = new ArrayList<>();
|
||||
classes.add(emptyClass);
|
||||
return classes;
|
||||
}
|
||||
}*/
|
@ -5,7 +5,6 @@ import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
@ -40,8 +39,6 @@ public class JavaLexerTest {
|
||||
}*/
|
||||
|
||||
// Compare tokens
|
||||
//assertEquals("Number of tokens does not match expected", expectedTokens.size(), tokenList.size());
|
||||
|
||||
for (int i = 0; i < tokenList.size(); i++) {
|
||||
Token token = tokenList.get(i);
|
||||
String tokenData = String.format("%s: \"%s\"", lexer.getVocabulary().getSymbolicName(token.getType()), token.getText());
|
||||
|
34
src/test/java/Tokens/TestAll.java
Normal file
34
src/test/java/Tokens/TestAll.java
Normal file
@ -0,0 +1,34 @@
|
||||
package Tokens;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestAll {
|
||||
JavaLexerTest testLexer;
|
||||
public TestAll(){
|
||||
testLexer = new JavaLexerTest("src/test/resources");
|
||||
}
|
||||
|
||||
private static void main(String[] args){
|
||||
TestAll tester = new TestAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyClass() throws Exception {
|
||||
testLexer.testTokens("basicClasses/emptyClass.java", "basicClasses/emptyClass.tokens");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyClassWithConstructor() throws Exception {
|
||||
testLexer.testTokens("basicClasses/EmptyClassWithConstructor.java", "basicClasses/EmptyClassWithConstructor.tokens");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFourClasses() throws Exception {
|
||||
testLexer.testTokens("basicClasses/FourClasses.java", "basicClasses/FourClasses.tokens");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublicEmptyClass() throws Exception {
|
||||
testLexer.testTokens("basicClasses/PublicEmptyClass.java", "basicClasses/PublicEmptyClass.tokens");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user