Add ForEach loop
This commit is contained in:
parent
6cc40162da
commit
b80cc726c8
15
resources/bytecode/javFiles/ForEach.jav
Normal file
15
resources/bytecode/javFiles/ForEach.jav
Normal file
@ -0,0 +1,15 @@
|
||||
import java.util.ArrayList;
|
||||
import java.lang.Integer;
|
||||
|
||||
public class ForEach {
|
||||
m() {
|
||||
var list = new ArrayList<>();
|
||||
list.add(1); list.add(2); list.add(3);
|
||||
|
||||
var sum = 0;
|
||||
for (var i : list) {
|
||||
sum = sum + i;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package de.dhbwstuttgart.bytecode;
|
||||
|
||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||
@ -918,6 +919,9 @@ public class Codegen {
|
||||
state.localCounter = localCounter;
|
||||
break;
|
||||
}
|
||||
case TargetForEach forEach:
|
||||
generateForEach(forEach, state);
|
||||
break;
|
||||
case TargetWhile _while: {
|
||||
Label start = new Label();
|
||||
Label end = new Label();
|
||||
@ -1041,6 +1045,35 @@ public class Codegen {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateForEach(TargetForEach forEach, State state) {
|
||||
state.enterScope();
|
||||
TargetVarDecl vd = (TargetVarDecl) forEach.vardecl();
|
||||
var localVar = state.createVariable(vd.name(), vd.varType());
|
||||
|
||||
var expr = forEach.expression();
|
||||
// TODO Check for arrays
|
||||
var mv = state.mv;
|
||||
generate(state, expr);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Iterable", "iterator", "()Ljava/util/Iterator;", true);
|
||||
var start = new Label();
|
||||
var end = new Label();
|
||||
mv.visitLabel(start);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z", true);
|
||||
mv.visitJumpInsn(IFEQ, end);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;", true);
|
||||
mv.visitVarInsn(ASTORE, localVar.index);
|
||||
|
||||
generate(state, forEach.body());
|
||||
|
||||
mv.visitJumpInsn(GOTO, start);
|
||||
mv.visitLabel(end);
|
||||
mv.visitInsn(POP);
|
||||
|
||||
state.exitScope();
|
||||
}
|
||||
|
||||
private void generateInstanceOf(State state, TargetInstanceOf instanceOf) {
|
||||
var mv = state.mv;
|
||||
|
||||
|
@ -490,15 +490,32 @@ public class StatementGenerator {
|
||||
|
||||
private Statement convert(Java17Parser.ForloopContext stmt) {
|
||||
var control = stmt.forControl();
|
||||
var block = convert(stmt.statement());
|
||||
if (control.enhancedForControl() != null)
|
||||
throw new NotImplementedException();
|
||||
else {
|
||||
if (control.enhancedForControl() != null) {
|
||||
var forCtrl = control.enhancedForControl();
|
||||
var name = forCtrl.variableDeclaratorId().identifier();
|
||||
|
||||
RefTypeOrTPHOrWildcardOrGeneric type;
|
||||
if (Objects.isNull(forCtrl.typeType()) || !Objects.isNull(forCtrl.VAR())) {
|
||||
type = TypePlaceholder.fresh(forCtrl.getStart());
|
||||
} else {
|
||||
type = TypeGenerator.convert(forCtrl.typeType(), reg, generics);
|
||||
}
|
||||
|
||||
var vardecl = new LocalVarDecl(name.getText(), type, name.getStart());
|
||||
this.localVars.put(name.getText(), type);
|
||||
|
||||
return new ForEachStmt(
|
||||
stmt.getStart(),
|
||||
vardecl,
|
||||
convert(forCtrl.expression()),
|
||||
convert(stmt.statement())
|
||||
);
|
||||
} else {
|
||||
return new ForStmt(
|
||||
stmt.getStart(),
|
||||
convert(control.forInit().localVariableDeclaration()),
|
||||
convert(control.expression()), control.forUpdate.expression().stream().map(this::convert).toList(),
|
||||
block
|
||||
convert(stmt.statement())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -166,6 +166,11 @@ public abstract class AbstractASTWalker implements ASTVisitor {
|
||||
forStmt.block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForEachStmt forEachStmt) {
|
||||
forEachStmt.block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
ifStmt.then_block.accept(this);
|
||||
|
@ -25,6 +25,8 @@ public interface StatementVisitor {
|
||||
|
||||
void visit(ForStmt forStmt);
|
||||
|
||||
void visit(ForEachStmt forEachStmt);
|
||||
|
||||
void visit(IfStmt ifStmt);
|
||||
|
||||
void visit(InstanceOf instanceOf);
|
||||
|
@ -0,0 +1,26 @@
|
||||
package de.dhbwstuttgart.syntaxtree.statement;
|
||||
|
||||
import de.dhbwstuttgart.parser.NullToken;
|
||||
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
import de.dhbwstuttgart.syntaxtree.type.Void;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
public class ForEachStmt extends Statement {
|
||||
|
||||
public final Statement statement;
|
||||
public final Expression expression;
|
||||
public final Statement block;
|
||||
|
||||
public ForEachStmt(Token offset, Statement stmt, Expression expression, Statement block) {
|
||||
super(new Void(new NullToken()), offset);
|
||||
this.statement = stmt;
|
||||
this.expression = expression;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(StatementVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
@ -244,6 +244,11 @@ public class OutputGenerator implements ASTVisitor {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForEachStmt forEachStmt) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
out.append("if(");
|
||||
|
@ -144,6 +144,11 @@ public class StatementToTargetExpression implements ASTVisitor {
|
||||
result = new TargetFor(forStmt.initializer.stream().map(converter::convert).toList(), converter.convert(forStmt.condition), forStmt.loopExpr.stream().map(converter::convert).toList(), converter.convert(forStmt.block));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForEachStmt forEachStmt) {
|
||||
result = new TargetForEach(converter.convert(forEachStmt.statement), converter.convert(forEachStmt.expression), converter.convert(forEachStmt.block));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
result = new TargetIf(converter.convert(ifStmt.expr), converter.convert(ifStmt.then_block), ifStmt.else_block != null ? converter.convert(ifStmt.else_block) : null);
|
||||
|
@ -66,6 +66,11 @@ public abstract class TracingStatementVisitor implements StatementVisitor {
|
||||
forStmt.block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForEachStmt forEachStmt) {
|
||||
forEachStmt.block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
ifStmt.then_block.accept(this);
|
||||
|
@ -1,4 +1,4 @@
|
||||
package de.dhbwstuttgart.target.tree.expression;
|
||||
|
||||
public record TargetForEach(TargetExpression vardecl, TargetExpression list) implements TargetExpression {
|
||||
public record TargetForEach(TargetExpression vardecl, TargetExpression expression, TargetExpression body) implements TargetExpression {
|
||||
}
|
||||
|
@ -128,6 +128,15 @@ public class TYPEStmt implements StatementVisitor {
|
||||
forStmt.block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForEachStmt forEachStmt) {
|
||||
var iterableType = new RefType(ASTFactory.createClass(java.lang.Iterable.class).getClassName(), Arrays.asList(forEachStmt.statement.getType()), new NullToken());
|
||||
constraintsSet.addUndConstraint(new Pair(forEachStmt.expression.getType(), iterableType, PairOperator.SMALLERDOT));
|
||||
forEachStmt.statement.accept(this);
|
||||
forEachStmt.expression.accept(this);
|
||||
forEachStmt.block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
RefType booleanType = new RefType(ASTFactory.createClass(java.lang.Boolean.class).getClassName(), new NullToken());
|
||||
|
@ -737,6 +737,15 @@ public class TestComplete {
|
||||
var m = clazz.getDeclaredMethod("m", Integer.class);
|
||||
assertEquals(m.invoke(instance, 10), 60);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForEach() throws Exception {
|
||||
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "ForEach.jav");
|
||||
var clazz = classFiles.get("ForEach");
|
||||
var instance = clazz.getDeclaredConstructor().newInstance();
|
||||
var m = clazz.getDeclaredMethod("m");
|
||||
assertEquals(m.invoke(instance), 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLambdaRunnable() throws Exception {
|
||||
|
Loading…
Reference in New Issue
Block a user