/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.examples.lang.imp.visitors;
import java.io.PrintWriter;
import org.whole.examples.lang.imp.model.Addition;
import org.whole.examples.lang.imp.model.And;
import org.whole.examples.lang.imp.model.Arguments;
import org.whole.examples.lang.imp.model.AssignmentExpression;
import org.whole.examples.lang.imp.model.BooleanLiteral;
import org.whole.examples.lang.imp.model.Division;
import org.whole.examples.lang.imp.model.DoWhileStatement;
import org.whole.examples.lang.imp.model.Equals;
import org.whole.examples.lang.imp.model.Expression;
import org.whole.examples.lang.imp.model.ForStatement;
import org.whole.examples.lang.imp.model.FunctionDeclaration;
import org.whole.examples.lang.imp.model.FunctionInvocationExpression;
import org.whole.examples.lang.imp.model.GreaterOrEquals;
import org.whole.examples.lang.imp.model.GreaterThan;
import org.whole.examples.lang.imp.model.IImpEntity;
import org.whole.examples.lang.imp.model.IfElseStatement;
import org.whole.examples.lang.imp.model.IfStatement;
import org.whole.examples.lang.imp.model.IntLiteral;
import org.whole.examples.lang.imp.model.LessOrEquals;
import org.whole.examples.lang.imp.model.LessThan;
import org.whole.examples.lang.imp.model.LoadExpression;
import org.whole.examples.lang.imp.model.Multiplication;
import org.whole.examples.lang.imp.model.Name;
import org.whole.examples.lang.imp.model.NameExpression;
import org.whole.examples.lang.imp.model.Not;
import org.whole.examples.lang.imp.model.NotEquals;
import org.whole.examples.lang.imp.model.Or;
import org.whole.examples.lang.imp.model.Parameter;
import org.whole.examples.lang.imp.model.Parameters;
import org.whole.examples.lang.imp.model.PrintStatement;
import org.whole.examples.lang.imp.model.PrintlnStatement;
import org.whole.examples.lang.imp.model.ReturnStatement;
import org.whole.examples.lang.imp.model.RunExpression;
import org.whole.examples.lang.imp.model.SaveStatement;
import org.whole.examples.lang.imp.model.StringLiteral;
import org.whole.examples.lang.imp.model.Subtraction;
import org.whole.examples.lang.imp.model.VariableDeclaration;
import org.whole.examples.lang.imp.model.WhileStatement;
import org.whole.examples.lang.imp.reflect.ImpEntityDescriptorEnum;
import org.whole.lang.bindings.ExitScopeException;
import org.whole.lang.factories.GenericEntityFactory;
import org.whole.lang.matchers.Matcher;
import org.whole.lang.model.IEntity;
import org.whole.lang.operations.InterpreterOperation;
import org.whole.lang.operations.PrettyPrinterOperation;
import org.whole.lang.util.DataTypeUtils;
import org.whole.lang.util.EntityUtils;
import org.whole.lang.visitors.MissingVariableException;
/**
* @author Riccardo Solmi
*/
public class ImpInterpreterVisitor extends ImpTraverseAllVisitor {
protected final PrintWriter out;
protected String[] parameters; //TODO move in bindingManager
public ImpInterpreterVisitor(InterpreterOperation operation) {
setOperation(operation);
out = operation.getPrintWriter();
}
protected void setLiteral(IEntity entity) {
setResult(EntityUtils.clone(entity));
}
protected IEntity createBooleanLiteral() {
return GenericEntityFactory.instance.create(ImpEntityDescriptorEnum.BooleanLiteral);
}
protected IEntity evaluate(IImpEntity entity) {
entity.accept(this);
return getResult();
}
protected final boolean booleanValue(Expression exp) {
return evaluate(exp).wBooleanValue();
}
protected final int intValue(Expression exp) {
return evaluate(exp).wIntValue();
}
protected final String stringValue(Expression exp) {
return evaluate(exp).wStringValue();
}
boolean isMain = true;
public void visit(FunctionDeclaration entity) {
entity.getType().accept(this);
entity.getName().accept(this);
getBindings().wDef(getResult().wStringValue(), entity);
//TODO entity.getParameters().accept(this);
if (isMain) {
isMain = false;
try {
getBindings().wEnterScope();
stagedVisit(entity.getBody());
} catch (ExitScopeException e) {
} finally {
getBindings().wExitScope();
}
}
}
public void visit(Parameters entity) {
int size = entity.wSize();
parameters = new String[size];
for (int i = 0; i < size; i++) {
((Parameter) entity.wGet(i)).accept(this);
parameters[i] = getResult().wStringValue();
}
}
public void visit(VariableDeclaration entity) {
entity.getType().accept(this);
entity.getName().accept(this);
String name = getResult().wStringValue();
entity.getInitializer().accept(this);
getBindings().wDef(name, getResult());
}
public void visit(FunctionInvocationExpression entity) {
entity.getName().accept(this);
IEntity functionBody = getResult();
if (Matcher.matchImpl(ImpEntityDescriptorEnum.FunctionDeclaration, functionBody)) {
FunctionDeclaration function = (FunctionDeclaration) functionBody;
//bindingManager.getValue(getName());
function.getParameters().accept(this);
try {
getBindings().wEnterScope();
entity.getArguments().accept(this);
stagedVisit(function.getBody());
} catch (ExitScopeException e) {
} finally {
getBindings().wExitScope();
}
} else {
stagedVisit(functionBody);
}
}
public void visit(Arguments entity) {
for (int i = 0; i < entity.wSize(); i++) {
((Expression) entity.wGet(i)).accept(this);
getBindings().wDef(parameters[i], getResult());
}
}
public void visit(ReturnStatement entity) {
super.visit(entity);
throw new ExitScopeException("return");
}
public void visit(IfStatement entity) {
if (booleanValue(entity.getCondition()))
entity.getTrueBody().accept(this);
}
public void visit(IfElseStatement entity) {
if (booleanValue(entity.getCondition()))
entity.getTrueBody().accept(this);
else
entity.getFalseBody().accept(this);
}
public void visit(WhileStatement entity) {
while (booleanValue(entity.getCondition()))
entity.getTrueBody().accept(this);
}
public void visit(DoWhileStatement entity) {
do {
entity.getTrueBody().accept(this);
} while (booleanValue(entity.getCondition()));
}
public void visit(ForStatement entity) {
entity.getInitializer().accept(this);
while (booleanValue(entity.getCondition())) {
entity.getTrueBody().accept(this);
entity.getUpdater().accept(this);
}
}
public void visit(AssignmentExpression entity) {
entity.getName().accept(this);
getBindings().wDef(getResult().wStringValue(), evaluate(entity.getExp()));
}
public void visit(PrintStatement entity) {
IEntity value = evaluate(entity.getExp());
if (!EntityUtils.isData(value) && value.wGetLanguageKit().hasVisitor(PrettyPrinterOperation.ID))
PrettyPrinterOperation.prettyPrint(value, out);
else
out.print(value);
}
public void visit(PrintlnStatement entity) {
IEntity value = evaluate(entity.getExp());
if (!EntityUtils.isData(value) && value.wGetLanguageKit().hasVisitor(PrettyPrinterOperation.ID))
PrettyPrinterOperation.prettyPrint(value, out);
else
out.println(value);
}
public void visit(LoadExpression entity) {
// TODO Auto-generated method stub
super.visit(entity);
}
public void visit(SaveStatement entity) {
// TODO Auto-generated method stub
super.visit(entity);
}
public void visit(RunExpression entity) {
IEntity value = evaluate(entity.getExp());
if (!EntityUtils.isData(value) && value.wGetLanguageKit().hasVisitor(InterpreterOperation.ID))
stagedVisit(value);
}
public void visit(BooleanLiteral entity) {
setLiteral(entity);
}
public void visit(IntLiteral entity) {
setLiteral(entity);
}
public void visit(StringLiteral entity) {
setLiteral(entity);
}
public void visit(Name entity) {
setResult(entity);
// ve().setName(entity.getValue());
}
public void visit(NameExpression entity) {
IEntity value = getBindings().wGet(entity.getValue());
if (value == null)
throw new MissingVariableException(entity.getValue()).withSourceEntity(entity).withBindings(getBindings());
setLiteral(value);
}
public void visit(Addition entity) {
IEntity result1 = evaluate(entity.getExp1());
IEntity result2 = evaluate(entity.getExp2());
boolean isInt1 = DataTypeUtils.getDataKind(result1).isInt();
boolean isInt2 = DataTypeUtils.getDataKind(result2).isInt();
if (isInt1 && isInt2) {
result1.wSetValue(result1.wIntValue() + result2.wIntValue());
setResult(result1);
} else if (isInt2) {
result1.wSetValue(result1.wStringValue() + DataTypeUtils.getAsPresentationString(result2));
setResult(result1);
} else {
result2.wSetValue(result1.wStringValue() + result2.wStringValue());
setResult(result2);
}
}
public void visit(Subtraction entity) {
IEntity result = evaluate(entity.getExp1());
result.wSetValue(result.wIntValue() - intValue(entity.getExp2()));
setResult(result);
}
public void visit(Multiplication entity) {
IEntity result = evaluate(entity.getExp1());
result.wSetValue(result.wIntValue() * intValue(entity.getExp2()));
setResult(result);
}
public void visit(Division entity) {
IEntity result = evaluate(entity.getExp1());
result.wSetValue(result.wIntValue() / intValue(entity.getExp2()));
setResult(result);
}
public void visit(And entity) {
IEntity result = evaluate(entity.getExp1());
result.wSetValue(result.wBooleanValue() && booleanValue(entity.getExp2()));
setResult(result);
}
public void visit(Or entity) {
IEntity result = evaluate(entity.getExp1());
result.wSetValue(result.wBooleanValue() && booleanValue(entity.getExp2()));
setResult(result);
}
public void visit(Not entity) {
IEntity result = evaluate(entity.getExp());
result.wSetValue(!result.wBooleanValue());
setResult(result);
}
public void visit(Equals entity) {
IEntity result = createBooleanLiteral();
IEntity result1 = evaluate(entity.getExp1());
IEntity result2 = evaluate(entity.getExp2());
boolean isInt1 = DataTypeUtils.getDataKind(result1).isInt();
boolean isInt2 = DataTypeUtils.getDataKind(result2).isInt();
if (isInt1 && isInt2)
result.wSetValue(result1.wIntValue() == result2.wIntValue());
else
result.wSetValue(DataTypeUtils.getAsPresentationString(result1)
.equals(DataTypeUtils.getAsPresentationString(result2)));
setResult(result);
}
public void visit(NotEquals entity) {
IEntity result = createBooleanLiteral();
IEntity result1 = evaluate(entity.getExp1());
IEntity result2 = evaluate(entity.getExp2());
boolean isInt1 = DataTypeUtils.getDataKind(result1).isInt();
boolean isInt2 = DataTypeUtils.getDataKind(result2).isInt();
if (isInt1 && isInt2)
result.wSetValue(result1.wIntValue() != result2.wIntValue());
else
result.wSetValue(!DataTypeUtils.getAsPresentationString(result1)
.equals(DataTypeUtils.getAsPresentationString(result2)));
setResult(result);
}
public void visit(LessThan entity) {
IEntity result = createBooleanLiteral();
result.wSetValue(intValue(entity.getExp1()) < intValue(entity.getExp2()));
setResult(result);
}
public void visit(LessOrEquals entity) {
IEntity result = createBooleanLiteral();
result.wSetValue(intValue(entity.getExp1()) <= intValue(entity.getExp2()));
setResult(result);
}
public void visit(GreaterThan entity) {
IEntity result = createBooleanLiteral();
result.wSetValue(intValue(entity.getExp1()) > intValue(entity.getExp2()));
setResult(result);
}
public void visit(GreaterOrEquals entity) {
IEntity result = createBooleanLiteral();
result.wSetValue(intValue(entity.getExp1()) >= intValue(entity.getExp2()));
setResult(result);
}
}