package me.august.lumen.compile.parser.ast.stmt;
import me.august.lumen.common.BytecodeUtil;
import me.august.lumen.compile.analyze.ASTVisitor;
import me.august.lumen.compile.analyze.VisitorConsumer;
import me.august.lumen.compile.codegen.BuildContext;
import me.august.lumen.compile.parser.ast.CodeBlock;
import me.august.lumen.compile.parser.ast.expr.Expression;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class EachStmt implements CodeBlock, VisitorConsumer, Loop {
private Label repeat;
private Label exit;
private String ident;
private Expression expr;
private Body body;
private int counterIndex;
private int arrayIndex;
private int targetIndex;
public EachStmt(String ident, Expression expr, Body body) {
this.ident = ident;
this.expr = expr;
this.body = body;
}
public Label getRepeatLabel() {
return repeat;
}
public Label getExitLabel() {
return exit;
}
public void setCounterIndex(int counterIndex) {
this.counterIndex = counterIndex;
}
public void setArrayIndex(int arrayIndex) {
this.arrayIndex = arrayIndex;
}
public void setTargetIndex(int targetIndex) {
this.targetIndex = targetIndex;
}
@Override
public void generate(MethodVisitor visitor, BuildContext context) {
repeat = new Label();
exit = new Label();
visitor.visitInsn(Opcodes.ICONST_0);
visitor.visitVarInsn(Opcodes.ISTORE, counterIndex);
expr.generate(visitor, context);
visitor.visitVarInsn(
BytecodeUtil.storeInstruction(expr.expressionType()), arrayIndex
);
visitor.visitLabel(repeat);
visitor.visitVarInsn(Opcodes.ILOAD, counterIndex);
visitor.visitVarInsn(
BytecodeUtil.loadInstruction(expr.expressionType()), arrayIndex
);
visitor.visitInsn(Opcodes.ARRAYLENGTH);
visitor.visitJumpInsn(Opcodes.IF_ICMPGE, exit);
Type type = BytecodeUtil.componentType(expr.expressionType());
expr.generate(visitor, context);
visitor.visitVarInsn(Opcodes.ILOAD, counterIndex);
visitor.visitInsn(BytecodeUtil.arrayLoadOpcode(type));
visitor.visitVarInsn(BytecodeUtil.storeInstruction(type), targetIndex);
body.generate(visitor, context);
visitor.visitIincInsn(counterIndex, 1);
visitor.visitJumpInsn(Opcodes.GOTO, repeat);
visitor.visitLabel(exit);
}
@Override
public void accept(ASTVisitor astVisitor) {
expr.accept(astVisitor);
astVisitor.visitEachStmt(this);
body.accept(astVisitor);
}
public String getIdent() {
return ident;
}
public Expression getExpr() {
return expr;
}
}