package eu.wietsevenema.lang.oberon.ast.visitors.interpreter;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import xtc.tree.Visitor;
import eu.wietsevenema.lang.oberon.ast.expressions.Expression;
import eu.wietsevenema.lang.oberon.ast.expressions.Identifier;
import eu.wietsevenema.lang.oberon.ast.expressions.ProcedureUndefinedException;
import eu.wietsevenema.lang.oberon.ast.statements.AssignmentStatement;
import eu.wietsevenema.lang.oberon.ast.statements.ElseIfStatement;
import eu.wietsevenema.lang.oberon.ast.statements.IfStatement;
import eu.wietsevenema.lang.oberon.ast.statements.ProcedureCallStatement;
import eu.wietsevenema.lang.oberon.ast.statements.Statement;
import eu.wietsevenema.lang.oberon.ast.statements.WhileStatement;
import eu.wietsevenema.lang.oberon.ast.statements.WithStatement;
import eu.wietsevenema.lang.oberon.exceptions.IdentifierExpectedInParamList;
import eu.wietsevenema.lang.oberon.exceptions.ImmutableException;
import eu.wietsevenema.lang.oberon.exceptions.SymbolAlreadyDeclaredException;
import eu.wietsevenema.lang.oberon.exceptions.SymbolNotDeclaredException;
import eu.wietsevenema.lang.oberon.exceptions.TypeMismatchException;
import eu.wietsevenema.lang.oberon.exceptions.ValueUndefinedException;
import eu.wietsevenema.lang.oberon.exceptions.WrongNumberOfArgsException;
import eu.wietsevenema.lang.oberon.interpreter.Formal;
import eu.wietsevenema.lang.oberon.interpreter.Procedure;
import eu.wietsevenema.lang.oberon.interpreter.InterpreterScope;
import eu.wietsevenema.lang.oberon.interpreter.ValueReference;
import eu.wietsevenema.lang.oberon.interpreter.values.BooleanValue;
import eu.wietsevenema.lang.oberon.interpreter.values.RecordValue;
import eu.wietsevenema.lang.oberon.interpreter.values.Value;
public class StatementEvaluator extends Visitor {
InterpreterScope scope;
public StatementEvaluator(InterpreterScope scope) {
this.scope = scope;
}
public void visit(AssignmentStatement assign) throws SymbolNotDeclaredException, TypeMismatchException,
ImmutableException {
// 1. Retrieve existing reference.
ValueReferenceResolver resolv = new ValueReferenceResolver(scope);
ValueReference currentValRef = (ValueReference) resolv.dispatch(assign.getIdentifier());
if (currentValRef == null) {
throw new SymbolNotDeclaredException("Variable not declared. " + assign.getLocation().toString());
}
// 2. Evaluate expression
ExpressionEvaluator eval = new ExpressionEvaluator(scope);
Value value = (Value) eval.dispatch(assign.getExpression());
// 3. Assign new value
currentValRef.setValue(value);
}
public void visit(ProcedureCallStatement pCall) throws WrongNumberOfArgsException, IdentifierExpectedInParamList,
SymbolAlreadyDeclaredException, SymbolNotDeclaredException, TypeMismatchException,
ProcedureUndefinedException, ValueUndefinedException, ImmutableException {
// Find procedure node.
Procedure procedure = (Procedure) scope.lookupProc(pCall.getIdentifier().getName());
if (procedure == null) {
throw new ProcedureUndefinedException("Procedure " + pCall.getIdentifier().getName() + " undefined.");
}
// Enter scope.
scope = new InterpreterScope(scope);
List<Expression> parameters = pCall.getParameters();
List<Formal> formals = procedure.getFormals();
if (formals.size() != parameters.size()) {
throw new WrongNumberOfArgsException();
}
for (int i = 0; i < formals.size(); i++) {
Formal formal = formals.get(i);
formal.assignParameter(scope, parameters.get(i));
}
procedure.execute(scope);
//Exit scope
scope = scope.getParent();
}
public void visit( WithStatement withStatement) throws SymbolAlreadyDeclaredException{
ExpressionEvaluator exprEval = new ExpressionEvaluator(scope);
RecordValue record = (RecordValue) exprEval.dispatch(withStatement.getRecord());
//Enter new scope and expose members of record.
scope = new InterpreterScope(scope);
for( Entry<Identifier, ValueReference> entry : record.entrySet() ){
Identifier id = entry.getKey();
ValueReference reference = entry.getValue();
String symbol = id.getName();
scope.declareValueReference(symbol, reference);
}
//Execute all statements
StatementEvaluator statEval = new StatementEvaluator(scope);
for(Statement stat: withStatement.getStatements()){
statEval.dispatch(stat);
}
//Exit scope
scope = scope.getParent();
}
public void visit(IfStatement ifStatement) throws TypeMismatchException, ValueUndefinedException {
if (evalCondition(ifStatement.getCondition())) {
// 1. Als de if matched, evalueren we die statement en stoppen de
// evaluatie.
visitStatements(ifStatement.getTrueStatements());
return;
} else {
for (Iterator<ElseIfStatement> iterator = ifStatement.getElseIfs().iterator(); iterator.hasNext();) {
ElseIfStatement elseif = (ElseIfStatement) iterator.next();
if (evalCondition(elseif.getCondition())) {
// 2. Zodra er een elseif is gematched en uitgevoerd stopt
// de evaluatie.
visitStatements(elseif.getTrueStatements());
return;
}
}
// 3. Finally, als zowel het if statement en de elseif's falen te
// matchen, voeren we de else uit.
visitStatements(ifStatement.getFalseStatements());
return;
}
}
private void visitStatements(List<Statement> statements) {
if (!statements.isEmpty()) {
StatementEvaluator statEval = new StatementEvaluator(scope);
for (Statement stat : statements) {
statEval.dispatch(stat);
}
}
}
private boolean evalCondition(Expression exp) throws TypeMismatchException, ValueUndefinedException {
ExpressionEvaluator expEval = new ExpressionEvaluator(scope);
BooleanValue result = (BooleanValue) expEval.dispatch(exp);
return result.getValue();
}
public void visit(WhileStatement whilestat) throws TypeMismatchException, ValueUndefinedException {
StatementEvaluator statEval = new StatementEvaluator(scope);
while (evalCondition(whilestat.getCondition())) {
for (Statement s : whilestat.getStatements()) {
statEval.dispatch(s);
}
}
}
}