
com.alibaba.qlexpress4.runtime.instruction.WhileInstruction Maven / Gradle / Ivy
package com.alibaba.qlexpress4.runtime.instruction;
import com.alibaba.qlexpress4.QLOptions;
import com.alibaba.qlexpress4.exception.ErrorReporter;
import com.alibaba.qlexpress4.exception.QLErrorCodes;
import com.alibaba.qlexpress4.runtime.*;
import com.alibaba.qlexpress4.runtime.scope.QvmBlockScope;
import com.alibaba.qlexpress4.runtime.util.ThrowUtils;
import com.alibaba.qlexpress4.utils.PrintlnUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.function.Consumer;
/**
* Operation: while (condition) do body
* Input: 0
* Output: 0
*
* Author: DQinYuan
*/
public class WhileInstruction extends QLInstruction {
private final QLambdaDefinition condition;
private final QLambdaDefinition body;
private final int whileScopeMaxStackSize;
public WhileInstruction(ErrorReporter errorReporter, QLambdaDefinition condition, QLambdaDefinition body,
int whileScopeMaxStackSize) {
super(errorReporter);
this.condition = condition;
this.body = body;
this.whileScopeMaxStackSize = whileScopeMaxStackSize;
}
@Override
public QResult execute(QContext qContext, QLOptions qlOptions) {
DelegateQContext whileScopeContext = new DelegateQContext(qContext,
new QvmBlockScope(qContext, Collections.emptyMap(), whileScopeMaxStackSize, ExceptionTable.EMPTY));
QLambda conditionLambda = condition.toLambda(whileScopeContext, qlOptions, false);
QLambda bodyLambda = body.toLambda(whileScopeContext, qlOptions, true);
whileBody:
while (evalCondition(conditionLambda)) {
try {
QResult bodyResult = bodyLambda.call();
switch (bodyResult.getResultType()) {
case RETURN:
return bodyResult;
case BREAK:
break whileBody;
}
} catch (Throwable t) {
throw ThrowUtils.wrapThrowable(t, errorReporter,
"WHILE_BODY_EXECUTE_ERROR", "while body execute error");
}
}
return QResult.NEXT_INSTRUCTION;
}
@Override
public int stackInput() {
return 0;
}
@Override
public int stackOutput() {
return 0;
}
@Override
public void println(int index, int depth, Consumer debug) {
PrintlnUtils.printlnByCurDepth(depth, index + ": While", debug);
PrintlnUtils.printlnByCurDepth(depth+1, "Condition", debug);
condition.println(depth+2, debug);
PrintlnUtils.printlnByCurDepth(depth+1, "Body", debug);
body.println(depth+2, debug);
}
private boolean evalCondition(QLambda conditionLambda) {
try {
Object conditionResult = conditionLambda.call().getResult().get();
if (!(conditionResult instanceof Boolean)) {
throw errorReporter.report(QLErrorCodes.WHILE_CONDITION_BOOL_REQUIRED.name(),
QLErrorCodes.WHILE_CONDITION_BOOL_REQUIRED.getErrorMsg());
}
return (boolean) conditionResult;
} catch (Throwable t) {
throw ThrowUtils.wrapThrowable(t, errorReporter, QLErrorCodes.WHILE_CONDITION_ERROR.name(),
QLErrorCodes.WHILE_CONDITION_ERROR.getErrorMsg());
}
}
}