Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
4b2edaa6ff
@ -4,6 +4,7 @@ import TypeCheck.AbstractType;
|
||||
import TypeCheck.TypeCheckException;
|
||||
import TypeCheck.TypeCheckHelper;
|
||||
import TypeCheck.TypeCheckResult;
|
||||
import abstractSyntaxTree.Expression.IExpression;
|
||||
import abstractSyntaxTree.Node;
|
||||
import abstractSyntaxTree.Program;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
@ -18,11 +19,13 @@ import java.util.Objects;
|
||||
public class FieldDecl extends AbstractType implements Node {
|
||||
|
||||
public String type; // from parser
|
||||
public String identifier; // from parser
|
||||
public String identifier;// from parser
|
||||
public IExpression expression; // value of the field
|
||||
|
||||
public FieldDecl(String type, String identifier){
|
||||
public FieldDecl(String type, String identifier, IExpression expression){
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
this.expression = expression;
|
||||
}
|
||||
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, String>> typeContext) throws TypeCheckException {
|
||||
|
||||
@ -46,7 +49,6 @@ public class FieldDecl extends AbstractType implements Node {
|
||||
}
|
||||
|
||||
public void codeGen(ClassWriter cw) {
|
||||
//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();
|
||||
}
|
||||
|
@ -53,12 +53,10 @@ public class MethodDecl implements Node {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//TODO: Es wird kein Bytecode für Standardkonstruktoren für die Klassen generiert
|
||||
//TODO: Stack computing schlägt fehl --> Reihenfolge aufruf? --> Sobald if-else / if / while drin sind? --> vllt auch schon bei MethodenDecl
|
||||
//Need to get the returnType of the method if it is an object
|
||||
// methodContext (class, (returnType, (identifier, parameter)))
|
||||
public void codeGen(ClassWriter cw, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
|
||||
// typeContext (class, (type, identifier))
|
||||
public void codeGen(ClassWriter cw, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, List<FieldDecl> fieldDecls) throws Exception {
|
||||
|
||||
localVars.put("this", classThatContainsMethod);
|
||||
for (Parameter param : parameters.parameterList) {
|
||||
@ -73,18 +71,40 @@ public class MethodDecl implements Node {
|
||||
|
||||
//Call the superclass constructor
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
|
||||
HashMap<String, String> classFields = typeContext.get(classThatContainsMethod);
|
||||
|
||||
for (Map.Entry<String, String> entry : classFields.entrySet()) {
|
||||
String fieldName = entry.getKey();
|
||||
for (FieldDecl field : fieldDecls) {
|
||||
if (field.identifier.equals(fieldName)) {
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
field.expression.codeGen(mv, localVars, typeContext, methodContext);
|
||||
descriptor = getFieldDescriptor(field.type);
|
||||
mv.visitFieldInsn(Opcodes.PUTFIELD, classThatContainsMethod, fieldName, descriptor);
|
||||
} else {
|
||||
throw new Exception("Field " + fieldName + " not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Load the parameters onto the stack
|
||||
int localVarIndex = 1;
|
||||
for (Parameter param : parameters.parameterList) {
|
||||
String paramType = param.type;
|
||||
switch(paramType) {
|
||||
case "int", "boolean", "char" -> mv.visitVarInsn(Opcodes.ILOAD, localVarIndex);
|
||||
default -> mv.visitVarInsn(Opcodes.ALOAD, localVarIndex);
|
||||
case "int", "boolean", "char" -> {
|
||||
mv.visitVarInsn(Opcodes.ILOAD, localVarIndex);
|
||||
mv.visitVarInsn(Opcodes.ISTORE, localVarIndex);
|
||||
}
|
||||
default -> {
|
||||
mv.visitVarInsn(Opcodes.ALOAD, localVarIndex);
|
||||
mv.visitVarInsn(Opcodes.ASTORE, localVarIndex);
|
||||
}
|
||||
}
|
||||
localVarIndex++;
|
||||
}
|
||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", descriptor, false);
|
||||
|
||||
mv.visitCode();
|
||||
codeBlock.codeGen(mv, localVars, typeContext, methodContext);
|
||||
@ -171,6 +191,19 @@ public class MethodDecl implements Node {
|
||||
return descriptor.toString();
|
||||
}
|
||||
|
||||
private String getFieldDescriptor(String type) {
|
||||
switch (type) {
|
||||
case "int":
|
||||
return "I";
|
||||
case "boolean":
|
||||
return "Z";
|
||||
case "char":
|
||||
return "C";
|
||||
default:
|
||||
return "L" + type + ";";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -6,6 +6,7 @@ import TypeCheck.TypeCheckResult;
|
||||
import abstractSyntaxTree.Expression.IExpression;
|
||||
import abstractSyntaxTree.Node;
|
||||
import abstractSyntaxTree.Parameter.ParameterList;
|
||||
import abstractSyntaxTree.Statement.BlockStatement;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
@ -88,8 +89,21 @@ public class RefType extends AbstractType implements Node {
|
||||
field.codeGen(cw);
|
||||
}
|
||||
|
||||
boolean hasCustomConstructor = false;
|
||||
for (MethodDecl method : methodDecls) {
|
||||
method.codeGen(cw, methodContext, typeContext);
|
||||
if (method.name.equals(name) && method.returnType == null) {
|
||||
hasCustomConstructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasCustomConstructor) {
|
||||
MethodDecl standardConstructor = new MethodDecl(name, null, name, new ParameterList(new ArrayList<>()), new BlockStatement(new ArrayList<>(), "void"));
|
||||
standardConstructor.codeGen(cw, methodContext, typeContext, fieldDecls);
|
||||
}
|
||||
|
||||
for (MethodDecl method : methodDecls) {
|
||||
method.codeGen(cw, methodContext, typeContext, fieldDecls);
|
||||
}
|
||||
cw.visitEnd();
|
||||
}
|
||||
|
@ -76,97 +76,87 @@ public class BinaryExpression extends AbstractType implements IExpression{
|
||||
Label expressionEnd = new Label(); //End of the whole expression
|
||||
|
||||
// Bytecode for the binary operation
|
||||
if (operator.equals("+") || operator.equals("-") || operator.equals("*") || operator.equals("/")) {
|
||||
switch (operator) {
|
||||
case "&&":
|
||||
case "+" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitInsn(Opcodes.IADD);
|
||||
}
|
||||
case "-" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitInsn(Opcodes.ISUB);
|
||||
}
|
||||
case "*" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitInsn(Opcodes.IMUL);
|
||||
}
|
||||
case "/" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitInsn(Opcodes.IDIV);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (operator) {
|
||||
case "&&" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // IFEQ --> "if equals to zero" (false) --> if left exp is false
|
||||
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // If right exp is false, jump to the end of the whole expression
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, operationFalse);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.GOTO, operationTrue); // If it reaches this point, the right exp is true
|
||||
break;
|
||||
|
||||
case "||":
|
||||
}
|
||||
case "||" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitJumpInsn(Opcodes.IFNE, operationTrue); // IFNE --> "if not equals to zero" (true) --> if left exp is true
|
||||
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitJumpInsn(Opcodes.IFNE, operationTrue);
|
||||
break;
|
||||
|
||||
case "==":
|
||||
}
|
||||
case "==" -> {
|
||||
// Keep in mind that only primitive types are allowed in this case (at this time)
|
||||
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression
|
||||
break;
|
||||
|
||||
case "<":
|
||||
}
|
||||
case "<" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal
|
||||
break;
|
||||
|
||||
case ">":
|
||||
}
|
||||
case ">" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal
|
||||
break;
|
||||
|
||||
case "<=":
|
||||
}
|
||||
case "<=" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal
|
||||
break;
|
||||
|
||||
case ">=":
|
||||
}
|
||||
case ">=" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal
|
||||
break;
|
||||
|
||||
case "!=":
|
||||
}
|
||||
case "!=" -> {
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal
|
||||
break;
|
||||
|
||||
case "+":
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitInsn(Opcodes.IADD);
|
||||
break;
|
||||
|
||||
case "-":
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitInsn(Opcodes.ISUB);
|
||||
break;
|
||||
|
||||
case "*":
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitInsn(Opcodes.IMUL);
|
||||
break;
|
||||
|
||||
case "/":
|
||||
left.codeGen(mv, localVars, typeContext, methodContext);
|
||||
right.codeGen(mv, localVars, typeContext, methodContext);
|
||||
mv.visitInsn(Opcodes.IDIV);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new TypeCheckException("The operator " + operator + " is not known.");
|
||||
}
|
||||
|
||||
default -> throw new TypeCheckException("The operator " + operator + " is not known.");
|
||||
}
|
||||
mv.visitLabel(operationFalse);
|
||||
mv.visitInsn(Opcodes.ICONST_0); // Push false on the stack
|
||||
mv.visitJumpInsn(Opcodes.GOTO, expressionEnd); // Jump to the end of the expression (skip the true push)
|
||||
@ -176,6 +166,7 @@ public class BinaryExpression extends AbstractType implements IExpression{
|
||||
|
||||
mv.visitLabel(expressionEnd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
@ -46,33 +46,29 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) 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");
|
||||
}
|
||||
String type = null;
|
||||
|
||||
// if it's a local variable
|
||||
if (localVars.containsKey(identifier)) {
|
||||
type = localVars.get(identifier);
|
||||
// Find the index of the variable
|
||||
int index = -1;
|
||||
int counter = 0;
|
||||
for (String key : localVars.keySet()){
|
||||
if (key.equals(identifier)){
|
||||
index = counter+1; // +1 because the first local variable is at index 1, 0 is used for "this"
|
||||
for (String key : localVars.keySet()) {
|
||||
if (key.equals(identifier)) {
|
||||
index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this"
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (index == -1){
|
||||
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 "boolean":
|
||||
switch (type) {
|
||||
case "int", "boolean", "char":
|
||||
mv.visitVarInsn(Opcodes.ILOAD, index);
|
||||
break;
|
||||
case "void":
|
||||
@ -81,6 +77,30 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{
|
||||
mv.visitVarInsn(Opcodes.ALOAD, index);
|
||||
break;
|
||||
}
|
||||
// If it's a field
|
||||
} else if (typeContext.get(thisClass).get(identifier) != null){
|
||||
type = typeContext.get(thisClass).get(identifier);
|
||||
|
||||
// Load "this" onto the stack
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
// Get the field from "this"
|
||||
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, identifier, getFieldDescriptor(type));
|
||||
} else
|
||||
throw new Exception("Variable " + identifier + " not found");
|
||||
}
|
||||
|
||||
//TODO move this to a helper class and remove the doubled code in MethodDecl and in other places
|
||||
private String getFieldDescriptor(String type) {
|
||||
switch (type) {
|
||||
case "int":
|
||||
return "I";
|
||||
case "boolean":
|
||||
return "Z";
|
||||
case "char":
|
||||
return "C";
|
||||
default:
|
||||
return "L" + type + ";";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,6 +42,7 @@ public class Program implements Node {
|
||||
typeContext.put(oneClass.name, classVars);
|
||||
|
||||
// build method context
|
||||
|
||||
HashMap<String, HashMap<String, ParameterList>> identifierAndMethod = new HashMap<>();
|
||||
for (MethodDecl methodDecl : oneClass.methodDecls){
|
||||
if(methodDecl.returnType == null) continue;
|
||||
@ -52,15 +53,14 @@ public class Program implements Node {
|
||||
methodContext.put(oneClass.name, identifierAndMethod);
|
||||
}
|
||||
|
||||
|
||||
int mainCounter = 0;
|
||||
// check if main exists
|
||||
for(RefType oneClass : classes){
|
||||
if(oneClass.hasMain)
|
||||
mainCounter++;
|
||||
}
|
||||
// if(mainCounter != 1)
|
||||
// throw new TypeCheckException("There is not 1 Main method.");
|
||||
if(mainCounter != 1)
|
||||
throw new TypeCheckException("There is not 1 Main method.");
|
||||
|
||||
// typecheck each class
|
||||
TypeCheckResult result = new TypeCheckResult();
|
||||
@ -72,7 +72,7 @@ public class Program implements Node {
|
||||
}
|
||||
|
||||
public void codeGen() throws Exception{
|
||||
try (JarOutputStream jos = new JarOutputStream(new FileOutputStream("output.jar"))) {
|
||||
try {
|
||||
for (RefType oneClass : classes) {
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, oneClass.name, null, "java/lang/Object", null);
|
||||
@ -88,30 +88,9 @@ public class Program implements Node {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
/*// Write the bytecode to a .class file in the .jar file
|
||||
JarEntry entry = new JarEntry(oneClass.name + ".class");
|
||||
jos.putNextEntry(entry);
|
||||
jos.write(bytecode);
|
||||
jos.closeEntry();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
|
||||
/*
|
||||
for(RefType oneClass : classes){
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC,oneClass.name, null,
|
||||
"java/lang/Object", null);
|
||||
oneClass.codeGen(cw);
|
||||
|
||||
cw.visitEnd();
|
||||
byte[] bytecode = cw.toByteArray();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -54,7 +54,7 @@ public class IfElseStatement extends AbstractType implements IStatement{
|
||||
}
|
||||
|
||||
|
||||
|
||||
//TODO: There are 2 NOPs and one athrow on the stack between the if-Block and else-Block execution --> I have no idea why
|
||||
@Override
|
||||
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
|
||||
|
||||
@ -67,7 +67,8 @@ public class IfElseStatement extends AbstractType implements IStatement{
|
||||
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0)
|
||||
ifStatement.codeGen(mv, blockLocalVars, typeContext, methodContext); //If the condition is true, execute the ifBlock
|
||||
mv.visitJumpInsn(Opcodes.GOTO, statementEnd); //Jump to the end of the if-else statement
|
||||
|
||||
mv.visitJumpInsn(Opcodes.GOTO, statementEnd); //Jump to the end of the else statement
|
||||
|
||||
mv.visitLabel(conditionFalse);
|
||||
elseStatement.codeGen(mv, blockLocalVars, typeContext, methodContext); //If the condition is false, execute the elseBlock
|
||||
|
@ -55,7 +55,19 @@ public class LocalVarDecl extends AbstractType implements IStatement{
|
||||
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
|
||||
localVars.put(identifier, type);
|
||||
|
||||
int index = localVars.size() - 1;
|
||||
int index = -1;
|
||||
int counter = 0;
|
||||
for (String key : localVars.keySet()){
|
||||
if (key.equals(identifier)){
|
||||
index = counter+1; // +1 because the first local variable is at index 1, 0 is used for "this"
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (index == -1){
|
||||
throw new Exception("Variable " + identifier + " not found");
|
||||
}
|
||||
|
||||
if (expression != null) {
|
||||
expression.codeGen(mv, localVars, typeContext,methodContext);
|
||||
@ -72,11 +84,7 @@ public class LocalVarDecl extends AbstractType implements IStatement{
|
||||
|
||||
// Set a default value for the variable --> less problems
|
||||
switch (type) {
|
||||
case "int":
|
||||
mv.visitInsn(Opcodes.ICONST_1);
|
||||
mv.visitVarInsn(Opcodes.ISTORE, index);
|
||||
break;
|
||||
case "boolean":
|
||||
case "int", "boolean", "char":
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitVarInsn(Opcodes.ISTORE, index);
|
||||
break;
|
||||
|
@ -55,7 +55,6 @@ public class WhileStatement extends AbstractType implements IStatement {
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); // Checks if the condition is false (0)
|
||||
|
||||
statement.codeGen(mv, blockLocalVars, typeContext, methodContext);
|
||||
//statement.codeGen(mv);
|
||||
//TODO: If the block ends with a return statement, we might have to pop it from the stack
|
||||
// So the next iteration starts with a clean stack
|
||||
mv.visitJumpInsn(Opcodes.GOTO, LoopStart); // Jump to the start of the while loop
|
||||
|
@ -56,7 +56,12 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
|
||||
}
|
||||
|
||||
public Node generateFieldDecl(DecafParser.LocalVarDeclContext ctx) {
|
||||
return new FieldDecl(ctx.type().getText(), ctx.Identifier().getText());
|
||||
if (ctx.expression() != null) {
|
||||
IExpression expression = (IExpression) visit(ctx.expression());
|
||||
return new FieldDecl(ctx.type().getText(), ctx.Identifier().getText(), expression);
|
||||
} else {
|
||||
return new FieldDecl(ctx.type().getText(), ctx.Identifier().getText(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -198,7 +203,6 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
|
||||
return new AssignStatementExpression(ctx.Assign().getText(),(IExpression) left, (IExpression) right);
|
||||
}
|
||||
|
||||
//
|
||||
@Override
|
||||
public Node visitMethodCall(DecafParser.MethodCallContext ctx) {
|
||||
String methodName = ctx.Identifier().getText();
|
||||
|
Loading…
Reference in New Issue
Block a user