/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
* * Tijs van der Storm - Tijs.van.der.Storm@cwi.nl
* * Mark Hills - Mark.Hills@cwi.nl (CWI)
* * Arnold Lankamp - Arnold.Lankamp@cwi.nl
* * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.semantics.dynamic;
import java.util.List;
import java.util.Stack;
import org.eclipse.imp.pdb.facts.IConstructor;
import org.eclipse.imp.pdb.facts.IInteger;
import org.eclipse.imp.pdb.facts.IString;
import org.eclipse.imp.pdb.facts.IValue;
import org.rascalmpl.ast.Assignable;
import org.rascalmpl.ast.Bound;
import org.rascalmpl.ast.Case;
import org.rascalmpl.ast.Catch;
import org.rascalmpl.ast.DataTarget;
import org.rascalmpl.ast.Label;
import org.rascalmpl.ast.LocalVariableDeclaration;
import org.rascalmpl.ast.QualifiedName;
import org.rascalmpl.ast.Target;
import org.rascalmpl.ast.Type;
import org.rascalmpl.interpreter.Accumulator;
import org.rascalmpl.interpreter.AssignableEvaluator;
import org.rascalmpl.interpreter.IEvaluator;
import org.rascalmpl.interpreter.asserts.NotYetImplemented;
import org.rascalmpl.interpreter.control_exceptions.BreakException;
import org.rascalmpl.interpreter.control_exceptions.ContinueException;
import org.rascalmpl.interpreter.control_exceptions.Failure;
import org.rascalmpl.interpreter.control_exceptions.Filtered;
import org.rascalmpl.interpreter.control_exceptions.InterruptException;
import org.rascalmpl.interpreter.env.Environment;
import org.rascalmpl.interpreter.matching.IBooleanResult;
import org.rascalmpl.interpreter.result.Result;
import org.rascalmpl.interpreter.result.ResultFactory;
import org.rascalmpl.interpreter.staticErrors.UndeclaredVariable;
import org.rascalmpl.interpreter.staticErrors.UnexpectedType;
import org.rascalmpl.interpreter.staticErrors.UnguardedAppend;
import org.rascalmpl.interpreter.staticErrors.UninitializedVariable;
import org.rascalmpl.interpreter.utils.Cases;
import org.rascalmpl.interpreter.utils.Cases.CaseBlock;
import org.rascalmpl.interpreter.utils.Names;
public abstract class Statement extends org.rascalmpl.ast.Statement {
static public class Append extends org.rascalmpl.ast.Statement.Append {
public Append(IConstructor node, DataTarget __param2,
org.rascalmpl.ast.Statement __param3) {
super(node, __param2, __param3);
}
protected Accumulator getTarget(IEvaluator<Result<IValue>> __eval) {
if (__eval.__getAccumulators().empty()) {
throw new UnguardedAppend(this);
}
if (!this.getDataTarget().isEmpty()) {
String label = org.rascalmpl.interpreter.utils.Names.name(this.getDataTarget().getLabel());
Accumulator accu = findDataTarget(__eval, label);
if (accu == null) {
throw new UnguardedAppend(this); // TODO: better error
}
return accu;
}
return __eval.__getAccumulators().peek();
}
private Accumulator findDataTarget(IEvaluator<Result<IValue>> __eval,
String label) {
Stack<Accumulator> accus = __eval.__getAccumulators();
// Search backwards, to allow nested fors with same label.
for (int i = accus.size() - 1; i >= 0; i--) {
Accumulator accu = accus.get(i);
if (accu.hasLabel(label)) {
return accu;
}
}
return null;
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
Accumulator target = null;
if (__eval.__getAccumulators().empty()) {
throw new UnguardedAppend(this);
}
if (!this.getDataTarget().isEmpty()) {
String label = org.rascalmpl.interpreter.utils.Names.name(this
.getDataTarget().getLabel());
target = findDataTarget(__eval, label);
if (target == null) {
throw new UnguardedAppend(this); // TODO: better error
// message
}
} else {
target = __eval.__getAccumulators().peek();
}
Result<IValue> result = this.getStatement().interpret(__eval);
target.append(result);
return result;
}
}
static public class Assert extends org.rascalmpl.ast.Statement.Assert {
public Assert(IConstructor __param1, org.rascalmpl.ast.Expression __param2) {
super(__param1, __param2);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
Result<IValue> r = this.getExpression().interpret(__eval);
if (!r.getType().equals(
org.rascalmpl.interpreter.Evaluator.__getTf().boolType())) {
throw new UnexpectedType(
org.rascalmpl.interpreter.Evaluator.__getTf()
.boolType(), r.getType(), this);
}
if (r.getValue().isEqual(__eval.__getVf().bool(false))) {
throw org.rascalmpl.interpreter.utils.RuntimeExceptionFactory
.assertionFailed(this, __eval.getStackTrace());
}
return r;
}
}
static public class AssertWithMessage extends
org.rascalmpl.ast.Statement.AssertWithMessage {
public AssertWithMessage(IConstructor __param1,
org.rascalmpl.ast.Expression __param2,
org.rascalmpl.ast.Expression __param3) {
super(__param1, __param2, __param3);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
Result<IValue> r = this.getExpression().interpret(__eval);
if (!r.getType().equals(
org.rascalmpl.interpreter.Evaluator.__getTf().boolType())) {
throw new UnexpectedType(
org.rascalmpl.interpreter.Evaluator.__getTf()
.boolType(), r.getType(), this);
}
if (r.getValue().isEqual(__eval.__getVf().bool(false))) {
Result<IValue> msgValue = this.getMessage().interpret(__eval);
// IString msg = __eval.__getVf().string(
// org.rascalmpl.interpreter.utils.StringUtils.unescapeBase(msgValue.getValue().toString());
throw org.rascalmpl.interpreter.utils.RuntimeExceptionFactory
.assertionFailed((IString) msgValue.getValue(), __eval.getCurrentAST(), __eval
.getStackTrace());
}
return r;
}
}
static public class Assignment extends
org.rascalmpl.ast.Statement.Assignment {
public Assignment(IConstructor __param1, Assignable __param2,
org.rascalmpl.ast.Assignment __param3,
org.rascalmpl.ast.Statement __param4) {
super(__param1, __param2, __param3, __param4);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
Result<IValue> right = this.getStatement().interpret(__eval);
// if(this.getAssignable().isSlice() && !this.getOperator().isDefault()){
// throw new UnsupportedOperation("Slicing assignment only implemented for simple assignment operator (=)", __eval.getCurrentAST());
// }
return this.getAssignable().assignment(
new AssignableEvaluator(__eval.getCurrentEnvt(), this
.getOperator(), right, __eval));
}
}
static public class Break extends org.rascalmpl.ast.Statement.Break {
public Break(IConstructor __param1, Target __param2) {
super(__param1, __param2);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
if (getTarget().isEmpty()) {
throw new BreakException();
}
else {
throw new BreakException(Names.name(getTarget().getName()));
}
}
}
static public class Continue extends org.rascalmpl.ast.Statement.Continue {
public Continue(IConstructor __param1, Target __param2) {
super(__param1, __param2);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
if (getTarget().isEmpty()) {
throw new ContinueException();
}
else {
throw new ContinueException(Names.name(getTarget().getName()));
}
}
}
static public class DoWhile extends org.rascalmpl.ast.Statement.DoWhile {
public DoWhile(IConstructor __param1, Label __param2,
org.rascalmpl.ast.Statement __param3,
org.rascalmpl.ast.Expression __param4) {
super(__param1, __param2, __param3, __param4);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
org.rascalmpl.ast.Statement body = this.getBody();
org.rascalmpl.ast.Expression generator = this.getCondition();
IBooleanResult gen;
Environment old = __eval.getCurrentEnvt();
String label = null;
if (!this.getLabel().isEmpty()) {
label = org.rascalmpl.interpreter.utils.Names.name(this
.getLabel().getName());
}
__eval.__getAccumulators().push(
new Accumulator(__eval.__getVf(), label));
IValue value = null;
try {
while (true) {
try {
try {
body.interpret(__eval);
}
catch (BreakException e) {
value = __eval.__getAccumulators().pop().done();
return org.rascalmpl.interpreter.result.ResultFactory
.makeResult(value.getType(), value, __eval);
}
catch (ContinueException e) {
// just continue;
}
gen = generator.getBacktracker(__eval);
gen.init();
if (__eval.isInterrupted()) {
throw new InterruptException(__eval.getStackTrace(), __eval.getCurrentAST().getLocation());
}
if (!(gen.hasNext() && gen.next())) {
value = __eval.__getAccumulators().pop().done();
return org.rascalmpl.interpreter.result.ResultFactory
.makeResult(value.getType(), value, __eval);
}
} finally {
__eval.unwind(old);
}
}
}
finally {
if (value == null) {
// make sure to pop the accumulators even in the case of exceptions
__eval.__getAccumulators().pop().done();
}
}
}
}
static public class EmptyStatement extends
org.rascalmpl.ast.Statement.EmptyStatement {
public EmptyStatement(IConstructor __param1) {
super(__param1);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
return org.rascalmpl.interpreter.result.ResultFactory.nothing();
}
}
static public class Expression extends
org.rascalmpl.ast.Statement.Expression {
public Expression(IConstructor __param1, org.rascalmpl.ast.Expression __param2) {
super(__param1, __param2);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
Environment old = __eval.getCurrentEnvt();
try {
__eval.pushEnv();
return this.getExpression().interpret(__eval);
} finally {
__eval.unwind(old);
}
}
}
static public class Fail extends org.rascalmpl.ast.Statement.Fail {
public Fail(IConstructor __param1, Target __param2) {
super(__param1, __param2);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
if (!this.getTarget().isEmpty()) {
throw new Failure(Names.name(this.getTarget().getName()));
}
throw new Failure();
}
}
static public class Filter extends org.rascalmpl.ast.Statement.Filter {
public Filter(IConstructor __param1) {
super(__param1);
}
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
throw new Filtered();
}
}
static public class For extends org.rascalmpl.ast.Statement.For {
public For(IConstructor __param1, Label __param2,
List<org.rascalmpl.ast.Expression> __param3,
org.rascalmpl.ast.Statement __param4) {
super(__param1, __param2, __param3, __param4);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
org.rascalmpl.ast.Statement body = this.getBody();
List<org.rascalmpl.ast.Expression> generators = this
.getGenerators();
int size = generators.size();
IBooleanResult[] gens = new IBooleanResult[size];
Environment old = __eval.getCurrentEnvt();
Environment[] olds = new Environment[size];
Result<IValue> result = org.rascalmpl.interpreter.result.ResultFactory
.makeResult(org.rascalmpl.interpreter.Evaluator.__getTf()
.voidType(), __eval.__getVf().list(), __eval);
String label = null;
if (!this.getLabel().isEmpty()) {
label = org.rascalmpl.interpreter.utils.Names.name(this
.getLabel().getName());
}
__eval.__getAccumulators().push(
new Accumulator(__eval.__getVf(), label));
// TODO: does this prohibit that the body influences the behavior
// of the generators??
int i = 0;
boolean normalCflow = false;
try {
olds[0] = __eval.getCurrentEnvt();
__eval.pushEnv();
gens[0] = generators.get(0).getBacktracker(__eval);
gens[0].init();
while (i >= 0 && i < size) {
if (__eval.isInterrupted()) {
throw new InterruptException(__eval.getStackTrace(), __eval.getCurrentAST().getLocation());
}
if (gens[i].hasNext() && gens[i].next()) {
if (i == size - 1) {
// NB: no result handling here.
__eval.setCurrentAST(body);
try {
body.interpret(__eval);
}
catch (Failure e) {
// TODO: failure should undo variable assignments outside the scope of the for!
if (!e.hasLabel()) {
continue;
}
else if (!getLabel().isEmpty() && e.getLabel().equals(Names.name(getLabel().getName()))) {
continue;
}
throw e;
}
catch (ContinueException e) {
if (!e.hasLabel() && getLabel().isEmpty()) {
continue;
}
else if (!getLabel().isEmpty() && e.getLabel().equals(Names.name(getLabel().getName()))) {
continue;
}
throw e;
}
catch (BreakException e) {
if (!e.hasLabel() && getLabel().isEmpty()) {
break;
}
else if (!getLabel().isEmpty() && e.getLabel().equals(Names.name(getLabel().getName()))) {
break;
}
throw e;
}
} else {
i++;
olds[i] = __eval.getCurrentEnvt();
__eval.pushEnv();
gens[i] = generators.get(i).getBacktracker(__eval);
gens[i].init();
}
} else {
__eval.unwind(olds[i]);
i--;
}
}
// TODO: this is not enough, we must also detect
// break and return a list result then.
normalCflow = true;
} finally {
IValue value = __eval.__getAccumulators().pop().done();
if (normalCflow) {
result = org.rascalmpl.interpreter.result.ResultFactory
.makeResult(value.getType(), value, __eval);
}
__eval.unwind(old);
}
return result;
}
}
static public class FunctionDeclaration extends
org.rascalmpl.ast.Statement.FunctionDeclaration {
public FunctionDeclaration(IConstructor __param1,
org.rascalmpl.ast.FunctionDeclaration __param2) {
super(__param1, __param2);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
return this.getFunctionDeclaration().interpret(__eval);
}
}
static public class GlobalDirective extends
org.rascalmpl.ast.Statement.GlobalDirective {
public GlobalDirective(IConstructor __param1, Type __param2,
List<QualifiedName> __param3) {
super(__param1, __param2, __param3);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
throw new NotYetImplemented(this); // TODO
}
}
static public class IfThen extends org.rascalmpl.ast.Statement.IfThen {
public IfThen(IConstructor __param1, Label __param2,
List<org.rascalmpl.ast.Expression> __param3,
org.rascalmpl.ast.Statement __param4) {
super(__param1, __param2, __param3, __param4);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
org.rascalmpl.ast.Statement body = this.getThenStatement();
List<org.rascalmpl.ast.Expression> generators = this
.getConditions();
int size = generators.size();
IBooleanResult[] gens = new IBooleanResult[size];
Environment[] olds = new Environment[size];
Environment old = __eval.getCurrentEnvt();
int i = 0;
try {
olds[0] = __eval.getCurrentEnvt();
__eval.pushEnv();
gens[0] = generators.get(0).getBacktracker(__eval);
gens[0].init();
while (i >= 0 && i < size) {
if (__eval.isInterrupted()) {
throw new InterruptException(__eval.getStackTrace(), __eval.getCurrentAST().getLocation());
}
if (gens[i].hasNext() && gens[i].next()) {
if (i == size - 1) {
__eval.setCurrentAST(body);
try {
return body.interpret(__eval);
}
catch (Failure e) {
if (!e.hasLabel()) {
continue;
}
else if (!getLabel().isEmpty() && e.getLabel().equals(Names.name(getLabel().getName()))) {
continue;
}
throw e;
}
}
else {
i++;
gens[i] = generators.get(i).getBacktracker(__eval);
gens[i].init();
olds[i] = __eval.getCurrentEnvt();
__eval.pushEnv();
}
} else {
__eval.unwind(olds[i]);
__eval.pushEnv();
i--;
}
}
} finally {
__eval.unwind(old);
}
return org.rascalmpl.interpreter.result.ResultFactory.nothing();
}
}
static public class IfThenElse extends
org.rascalmpl.ast.Statement.IfThenElse {
public IfThenElse(IConstructor __param1, Label __param2,
List<org.rascalmpl.ast.Expression> __param3,
org.rascalmpl.ast.Statement __param4,
org.rascalmpl.ast.Statement __param5) {
super(__param1, __param2, __param3, __param4, __param5);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
org.rascalmpl.ast.Statement body = this.getThenStatement();
List<org.rascalmpl.ast.Expression> generators = this
.getConditions();
int size = generators.size();
IBooleanResult[] gens = new IBooleanResult[size];
Environment[] olds = new Environment[size];
Environment old = __eval.getCurrentEnvt();
int i = 0;
try {
olds[0] = __eval.getCurrentEnvt();
__eval.pushEnv();
gens[0] = generators.get(0).getBacktracker(__eval);
gens[0].init();
while (i >= 0 && i < size) {
if (__eval.isInterrupted()) {
throw new InterruptException(__eval.getStackTrace(), __eval.getCurrentAST().getLocation());
}
if (gens[i].hasNext() && gens[i].next()) {
if (i == size - 1) {
__eval.setCurrentAST(body);
try {
return body.interpret(__eval);
}
catch (Failure e) {
if (!e.hasLabel()) {
continue;
}
else if (!getLabel().isEmpty() && e.getLabel().equals(Names.name(getLabel().getName()))) {
continue;
}
throw e;
}
}
else {
i++;
gens[i] = generators.get(i).getBacktracker(__eval);
gens[i].init();
olds[i] = __eval.getCurrentEnvt();
__eval.pushEnv();
}
} else {
__eval.unwind(olds[i]);
__eval.pushEnv();
i--;
}
}
} finally {
__eval.unwind(old);
}
org.rascalmpl.ast.Statement elsePart = this.getElseStatement();
__eval.setCurrentAST(elsePart);
return elsePart.interpret(__eval);
}
}
static public class Insert extends org.rascalmpl.ast.Statement.Insert {
public Insert(IConstructor __param1, DataTarget __param2,
org.rascalmpl.ast.Statement __param3) {
super(__param1, __param2, __param3);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
throw new org.rascalmpl.interpreter.control_exceptions.Insert(this
.getStatement().interpret(__eval));
}
}
static public class NonEmptyBlock extends
org.rascalmpl.ast.Statement.NonEmptyBlock {
public NonEmptyBlock(IConstructor __param1, Label __param2,
List<org.rascalmpl.ast.Statement> __param3) {
super(__param1, __param2, __param3);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
Result<IValue> r = org.rascalmpl.interpreter.result.ResultFactory
.nothing();
Environment old = __eval.getCurrentEnvt();
__eval.pushEnv(this);
try {
for (org.rascalmpl.ast.Statement stat : this.getStatements()) {
__eval.setCurrentAST(stat);
r = stat.interpret(__eval);
}
} finally {
__eval.unwind(old);
}
return r;
}
}
static public class Return extends org.rascalmpl.ast.Statement.Return {
public Return(IConstructor __param1, org.rascalmpl.ast.Statement __param2) {
super(__param1, __param2);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
throw new org.rascalmpl.interpreter.control_exceptions.Return(this
.getStatement().interpret(__eval), this.getStatement()
.getLocation());
}
}
static public class Solve extends org.rascalmpl.ast.Statement.Solve {
public Solve(IConstructor __param1, List<QualifiedName> __param2,
Bound __param3, org.rascalmpl.ast.Statement __param4) {
super(__param1, __param2, __param3, __param4);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
int size = this.getVariables().size();
QualifiedName vars[] = new QualifiedName[size];
IValue currentValue[] = new IValue[size];
Environment old = __eval.getCurrentEnvt();
try {
List<QualifiedName> varList = this.getVariables();
for (int i = 0; i < size; i++) {
QualifiedName var = varList.get(i);
vars[i] = var;
Result<IValue> tmp = __eval.getCurrentEnvt().getSimpleVariable(var);
if (tmp == null) {
throw new UndeclaredVariable(Names.fullName(var), var);
}
if (tmp.getValue() == null) {
throw new UninitializedVariable(Names.fullName(var),
var);
}
currentValue[i] = tmp.getValue();
}
__eval.pushEnv();
org.rascalmpl.ast.Statement body = this.getBody();
int max = -1;
Bound bound = this.getBound();
if (bound.isDefault()) {
Result<IValue> res = bound.getExpression()
.interpret(__eval);
if (!res.getType().isInteger()) {
throw new UnexpectedType(
org.rascalmpl.interpreter.Evaluator.__getTf()
.integerType(), res.getType(), this);
}
max = ((IInteger) res.getValue()).intValue();
if (max <= 0) {
throw org.rascalmpl.interpreter.utils.RuntimeExceptionFactory
.indexOutOfBounds((IInteger) res.getValue(),
__eval.getCurrentAST(), __eval
.getStackTrace());
}
}
Result<IValue> bodyResult = null;
boolean change = true;
int iterations = 0;
while (change && (max == -1 || iterations < max)) {
change = false;
iterations++;
if (__eval.isInterrupted()) {
throw new InterruptException(__eval.getStackTrace(), __eval.getCurrentAST().getLocation());
}
bodyResult = body.interpret(__eval);
for (int i = 0; i < size; i++) {
QualifiedName var = vars[i];
Result<IValue> v = __eval.getCurrentEnvt().getVariable(
var);
if (currentValue[i] == null
|| !v.getValue().isEqual(currentValue[i])) {
change = true;
currentValue[i] = v.getValue();
}
}
}
return bodyResult;
} finally {
__eval.unwind(old);
}
}
}
static public class Switch extends org.rascalmpl.ast.Statement.Switch {
private List<CaseBlock> blocks;
public Switch(IConstructor __param1, Label __param2,
org.rascalmpl.ast.Expression __param3, List<Case> cases) {
super(__param1, __param2, __param3, cases);
blocks = Cases.precompute(cases);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
Result<IValue> subject = this.getExpression().interpret(__eval);
for (CaseBlock cs : blocks) {
if (cs.matchAndEval(__eval, subject)) {
return org.rascalmpl.interpreter.result.ResultFactory
.nothing();
}
}
return ResultFactory.nothing();
}
}
static public class Throw extends org.rascalmpl.ast.Statement.Throw {
public Throw(IConstructor __param1, org.rascalmpl.ast.Statement __param2) {
super(__param1, __param2);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
throw new org.rascalmpl.interpreter.control_exceptions.Throw(this
.getStatement().interpret(__eval).getValue(), __eval
.getCurrentAST(), __eval.getStackTrace());
}
}
static public class Try extends org.rascalmpl.ast.Statement.Try {
public Try(IConstructor __param1, org.rascalmpl.ast.Statement __param2,
List<Catch> __param3) {
super(__param1, __param2, __param3);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
return evalStatementTry(__eval, this.getBody(), this.getHandlers(), null);
}
static public Result<IValue> evalStatementTry(IEvaluator<Result<IValue>> eval, org.rascalmpl.ast.Statement body, java.util.List<Catch> handlers, org.rascalmpl.ast.Statement finallyBody) {
Result<IValue> res = org.rascalmpl.interpreter.result.ResultFactory.nothing();
try {
res = body.interpret(eval);
} catch (org.rascalmpl.interpreter.control_exceptions.Throw e) {
IValue eValue = e.getException();
boolean handled = false;
for (Catch c : handlers) {
if (c.isDefault()) {
res = c.getBody().interpret(eval);
handled = true;
break;
}
if (Cases.matchAndEval(makeResult(eValue.getType(), eValue, eval), c.getPattern(), c.getBody(), eval)) {
handled = true;
break;
}
}
if (!handled)
throw e;
} finally {
if (finallyBody != null) {
finallyBody.interpret(eval);
}
}
return res;
}
}
static public class TryFinally extends
org.rascalmpl.ast.Statement.TryFinally {
public TryFinally(IConstructor __param1, org.rascalmpl.ast.Statement __param2,
List<org.rascalmpl.ast.Catch> __param3, org.rascalmpl.ast.Statement __param4) {
super(__param1, __param2, __param3, __param4);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
return org.rascalmpl.semantics.dynamic.Statement.Try.evalStatementTry(__eval, this.getBody(), this.getHandlers(),
this.getFinallyBody());
}
}
static public class VariableDeclaration extends
org.rascalmpl.ast.Statement.VariableDeclaration {
public VariableDeclaration(IConstructor __param1,
LocalVariableDeclaration __param2) {
super(__param1, __param2);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
return this.getDeclaration().interpret(__eval);
}
}
static public class Visit extends org.rascalmpl.ast.Statement.Visit {
public Visit(IConstructor __param1, Label __param2,
org.rascalmpl.ast.Visit __param3) {
super(__param1, __param2, __param3);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
return this.getVisit().interpret(__eval);
}
}
static public class While extends org.rascalmpl.ast.Statement.While {
public While(IConstructor __param1, Label __param2,
List<org.rascalmpl.ast.Expression> __param3,
org.rascalmpl.ast.Statement __param4) {
super(__param1, __param2, __param3, __param4);
}
@Override
public Result<IValue> interpret(IEvaluator<Result<IValue>> __eval) {
IValue value = null;
__eval.setCurrentAST(this);
__eval.notifyAboutSuspension(this);
org.rascalmpl.ast.Statement body = this.getBody();
List<org.rascalmpl.ast.Expression> generators = this
.getConditions();
int size = generators.size();
IBooleanResult[] gens = new IBooleanResult[size];
Environment[] olds = new Environment[size];
Environment old = __eval.getCurrentEnvt();
String label = null;
if (!this.getLabel().isEmpty()) {
label = org.rascalmpl.interpreter.utils.Names.name(this
.getLabel().getName());
}
__eval.__getAccumulators().push(
new Accumulator(__eval.__getVf(), label));
try {
// a while statement is different from a for statement, the body of
// the while can influence the
// variables that are used to test the condition of the loop
// while does not iterate over all possible matches, rather it
// produces every time the first match
// that makes the condition true
loop: while (true) {
int i = 0;
try {
if (__eval.isInterrupted()) {
throw new InterruptException(__eval.getStackTrace(), __eval.getCurrentAST().getLocation());
}
olds[0] = __eval.getCurrentEnvt();
gens[0] = generators.get(0).getBacktracker(__eval);
gens[0].init();
conditions:while (i >= 0 && i < size) {
__eval.unwind(olds[i]);
__eval.pushEnv();
if (__eval.isInterrupted()) {
throw new InterruptException(__eval.getStackTrace(), __eval.getCurrentAST().getLocation());
}
if (gens[i].hasNext() && gens[i].next()) {
if (i == size - 1) {
__eval.setCurrentAST(body);
try {
body.interpret(__eval);
continue loop;
}
catch (Failure e) {
// try next assignment of generators!
// TODO: failure should undo assignment
if (!e.hasLabel() && getLabel().isEmpty()) {
continue conditions;
}
else if (!getLabel().isEmpty() && e.getLabel().equals(Names.name(getLabel().getName()))) {
continue conditions;
}
throw e;
}
catch (ContinueException e) {
// try next assignment of generators!
if (!e.hasLabel() && getLabel().isEmpty()) {
continue loop;
}
else if (!getLabel().isEmpty() && e.getLabel().equals(Names.name(getLabel().getName()))) {
continue loop;
}
throw e;
}
catch (BreakException e) {
if (!e.hasLabel() && getLabel().isEmpty()) {
value = __eval.__getAccumulators().pop().done();
return org.rascalmpl.interpreter.result.ResultFactory
.makeResult(value.getType(), value, __eval);
}
else if (!getLabel().isEmpty() && e.getLabel().equals(Names.name(getLabel().getName()))) {
value = __eval.__getAccumulators().pop().done();
return org.rascalmpl.interpreter.result.ResultFactory
.makeResult(value.getType(), value, __eval);
}
throw e;
}
}
else {
i++;
gens[i] = generators
.get(i).getBacktracker(__eval);
gens[i].init();
olds[i] = __eval.getCurrentEnvt();
}
} else {
i--;
}
}
} finally {
__eval.unwind(old);
}
value = __eval.__getAccumulators().pop().done();
return org.rascalmpl.interpreter.result.ResultFactory
.makeResult(value.getType(), value, __eval);
}
}
finally {
if (value == null) {
// make sure to always pop the accumulator when it hasn't been popped yet
__eval.__getAccumulators().pop().done();
}
}
}
}
public Statement(IConstructor __param1) {
super(__param1);
}
}