prompto.statement.WhileStatement Maven / Gradle / Ivy
The newest version!
package prompto.statement;
import java.util.ArrayList;
import java.util.List;
import prompto.compiler.CompilerUtils;
import prompto.compiler.Flags;
import prompto.compiler.IInstructionListener;
import prompto.compiler.MethodInfo;
import prompto.compiler.OffsetListenerConstant;
import prompto.compiler.Opcode;
import prompto.compiler.ResultInfo;
import prompto.compiler.StackState;
import prompto.error.PromptoError;
import prompto.error.SyntaxError;
import prompto.expression.IExpression;
import prompto.parser.ICodeSection;
import prompto.parser.ISection;
import prompto.runtime.BreakResult;
import prompto.runtime.Context;
import prompto.store.InvalidValueError;
import prompto.transpiler.Transpiler;
import prompto.type.BooleanType;
import prompto.type.IType;
import prompto.utils.CodeWriter;
import prompto.value.BooleanValue;
import prompto.value.IValue;
public class WhileStatement extends BaseStatement {
IExpression condition;
StatementList statements;
public WhileStatement(IExpression condition, StatementList statements) {
this.condition = condition;
this.statements = statements;
}
public IExpression getCondition() {
return condition;
}
public StatementList getStatements() {
return statements;
}
@Override
public boolean canReturn() {
return true;
}
@Override
public ICodeSection locateCodeSection(ISection section) {
ICodeSection result = statements.locateCodeSection(section);
return result!=null ? result : super.locateCodeSection(section);
}
@Override
public void toDialect(CodeWriter writer) {
switch(writer.getDialect()) {
case E:
toEDialect(writer);
break;
case O:
toODialect(writer);
break;
case M:
toMDialect(writer);
break;
}
}
private void toMDialect(CodeWriter writer) {
toEDialect(writer);
}
private void toEDialect(CodeWriter writer) {
writer.append("while ");
condition.toDialect(writer);
writer.append(" :\n");
writer.indent();
statements.toDialect(writer);
writer.dedent();
}
private void toODialect(CodeWriter writer) {
writer.append("while (");
condition.toDialect(writer);
writer.append(") {\n");
writer.indent();
statements.toDialect(writer);
writer.dedent();
writer.append("}\n");
}
@Override
public IType check(Context context) {
IType cond = condition.check(context);
if(cond!=BooleanType.instance())
throw new SyntaxError("Expected a Boolean condition!");
Context child = context.newChildContext();
return statements.check(child, null);
}
@Override
public IValue interpret(Context context) throws PromptoError {
while(interpretCondition(context)) {
Context child = context.newChildContext();
IValue value = statements.interpret(child);
if(value==BreakResult.instance())
break;
if(value!=null)
return value;
}
return null;
}
private boolean interpretCondition(Context context) throws PromptoError {
Object value = condition.interpret(context);
if(!(value instanceof BooleanValue))
throw new InvalidValueError("Expected a Boolean, got:" + value.getClass().getSimpleName());
return ((BooleanValue)value).getValue();
}
@Override
public ResultInfo compile(Context context, MethodInfo method, Flags flags) {
List breakLoopListeners = new ArrayList<>();
flags = flags.withBreakLoopListeners(breakLoopListeners);
StackState neutralState = method.captureStackState();
method.placeLabel(neutralState);
IInstructionListener loop = method.addOffsetListener(new OffsetListenerConstant(true));
method.activateOffsetListener(loop);
ResultInfo info = condition.compile(context, method, flags.withPrimitive(true));
if(BooleanValue.class==info.getType())
CompilerUtils.BooleanToboolean(method);
IInstructionListener exit = method.addOffsetListener(new OffsetListenerConstant());
method.activateOffsetListener(exit);
method.addInstruction(Opcode.IFEQ, exit);
statements.compile(context, method, flags);
method.inhibitOffsetListener(loop);
method.addInstruction(Opcode.GOTO, loop);
method.inhibitOffsetListener(exit);
for(IInstructionListener listener : breakLoopListeners)
method.inhibitOffsetListener(listener);
method.restoreFullStackState(neutralState);
method.placeLabel(neutralState);
// TODO manage return value in loop
return new ResultInfo(void.class);
}
@Override
public void declare(Transpiler transpiler) {
this.condition.declare(transpiler);
transpiler = transpiler.newChildTranspiler();
this.statements.declare(transpiler);
}
@Override
public boolean transpile(Transpiler transpiler) {
transpiler.append("while(");
this.condition.transpile(transpiler);
transpiler.append(") {");
transpiler.indent();
Transpiler child = transpiler.newChildTranspiler();
this.statements.transpile(child);
child.dedent().flush();
transpiler.append("}").newLine();
return true;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy