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.core.JavaTXCompiler;
|
||||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||||
|
import de.dhbwstuttgart.parser.NullToken;
|
||||||
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
import de.dhbwstuttgart.parser.scope.JavaClassName;
|
||||||
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
|
||||||
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
import de.dhbwstuttgart.syntaxtree.type.RefType;
|
||||||
@ -918,6 +919,9 @@ public class Codegen {
|
|||||||
state.localCounter = localCounter;
|
state.localCounter = localCounter;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TargetForEach forEach:
|
||||||
|
generateForEach(forEach, state);
|
||||||
|
break;
|
||||||
case TargetWhile _while: {
|
case TargetWhile _while: {
|
||||||
Label start = new Label();
|
Label start = new Label();
|
||||||
Label end = 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) {
|
private void generateInstanceOf(State state, TargetInstanceOf instanceOf) {
|
||||||
var mv = state.mv;
|
var mv = state.mv;
|
||||||
|
|
||||||
|
@ -490,15 +490,32 @@ public class StatementGenerator {
|
|||||||
|
|
||||||
private Statement convert(Java17Parser.ForloopContext stmt) {
|
private Statement convert(Java17Parser.ForloopContext stmt) {
|
||||||
var control = stmt.forControl();
|
var control = stmt.forControl();
|
||||||
var block = convert(stmt.statement());
|
if (control.enhancedForControl() != null) {
|
||||||
if (control.enhancedForControl() != null)
|
var forCtrl = control.enhancedForControl();
|
||||||
throw new NotImplementedException();
|
var name = forCtrl.variableDeclaratorId().identifier();
|
||||||
else {
|
|
||||||
|
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(
|
return new ForStmt(
|
||||||
stmt.getStart(),
|
stmt.getStart(),
|
||||||
convert(control.forInit().localVariableDeclaration()),
|
convert(control.forInit().localVariableDeclaration()),
|
||||||
convert(control.expression()), control.forUpdate.expression().stream().map(this::convert).toList(),
|
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);
|
forStmt.block.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ForEachStmt forEachStmt) {
|
||||||
|
forEachStmt.block.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(IfStmt ifStmt) {
|
public void visit(IfStmt ifStmt) {
|
||||||
ifStmt.then_block.accept(this);
|
ifStmt.then_block.accept(this);
|
||||||
|
@ -25,6 +25,8 @@ public interface StatementVisitor {
|
|||||||
|
|
||||||
void visit(ForStmt forStmt);
|
void visit(ForStmt forStmt);
|
||||||
|
|
||||||
|
void visit(ForEachStmt forEachStmt);
|
||||||
|
|
||||||
void visit(IfStmt ifStmt);
|
void visit(IfStmt ifStmt);
|
||||||
|
|
||||||
void visit(InstanceOf instanceOf);
|
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
|
@Override
|
||||||
public void visit(IfStmt ifStmt) {
|
public void visit(IfStmt ifStmt) {
|
||||||
out.append("if(");
|
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));
|
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
|
@Override
|
||||||
public void visit(IfStmt ifStmt) {
|
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);
|
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);
|
forStmt.block.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ForEachStmt forEachStmt) {
|
||||||
|
forEachStmt.block.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(IfStmt ifStmt) {
|
public void visit(IfStmt ifStmt) {
|
||||||
ifStmt.then_block.accept(this);
|
ifStmt.then_block.accept(this);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package de.dhbwstuttgart.target.tree.expression;
|
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);
|
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
|
@Override
|
||||||
public void visit(IfStmt ifStmt) {
|
public void visit(IfStmt ifStmt) {
|
||||||
RefType booleanType = new RefType(ASTFactory.createClass(java.lang.Boolean.class).getClassName(), new NullToken());
|
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);
|
var m = clazz.getDeclaredMethod("m", Integer.class);
|
||||||
assertEquals(m.invoke(instance, 10), 60);
|
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
|
@Test
|
||||||
public void testLambdaRunnable() throws Exception {
|
public void testLambdaRunnable() throws Exception {
|
||||||
|
Loading…
Reference in New Issue
Block a user