/** * 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.lang.scheme.visitors; import java.io.PrintWriter; import org.whole.lang.model.IEntity; import org.whole.lang.operations.InterpreterOperation; import org.whole.lang.scheme.factories.SchemeEntityFactory; import org.whole.lang.scheme.model.AndExpression; import org.whole.lang.scheme.model.ApplyExpression; import org.whole.lang.scheme.model.Branch; import org.whole.lang.scheme.model.Branches; import org.whole.lang.scheme.model.BuiltinValue; import org.whole.lang.scheme.model.ClosureValue; import org.whole.lang.scheme.model.CondExpression; import org.whole.lang.scheme.model.ConstExpression; import org.whole.lang.scheme.model.Definition; import org.whole.lang.scheme.model.Definitions; import org.whole.lang.scheme.model.ISchemeEntity; import org.whole.lang.scheme.model.IdExpression; import org.whole.lang.scheme.model.LambdaExpression; import org.whole.lang.scheme.model.LocalExpression; import org.whole.lang.scheme.model.OrExpression; import org.whole.lang.scheme.model.SchemeEnvironment; import org.whole.lang.scheme.model.SchemeExpression; import org.whole.lang.scheme.reflect.SchemeEntityDescriptorEnum; import org.whole.lang.util.EntityUtils; import org.whole.lang.visitors.VisitException; /** * @author Riccardo Solmi */ public class SchemeInterpreterVisitor extends SchemeTraverseAllVisitor { protected final SchemeValueInterpreter valueInterpreter; protected final PrintWriter out; protected String[] parameters; //TODO move in bindingManager public SchemeInterpreterVisitor(InterpreterOperation operation) { setOperation(operation); out = operation.getPrintWriter(); valueInterpreter = new SchemeValueInterpreter(this); } protected void setLiteral(IEntity entity) { setResult(EntityUtils.clone(entity)); } protected IEntity evaluate(ISchemeEntity entity) { entity.accept(this); return getResult(); } protected final boolean booleanValue(SchemeExpression exp) { return evaluate(exp).wBooleanValue(); } protected final int intValue(SchemeExpression exp) { return evaluate(exp).wIntValue(); } protected final String stringValue(SchemeExpression exp) { return evaluate(exp).wStringValue(); } @Override public void visit(Definitions entity) { super.visit(entity); IEntity mainDefine = getBindings().wGet("main"); if (mainDefine == null) throw new VisitException("expected the definition of: main"); stagedVisit(mainDefine); } @Override public void visit(Definition entity) { String definitionName = entity.getName().wStringValue(); IEntity definitionBody = entity.getExpression(); getBindings().wDef(definitionName, definitionBody); } public void visit(AndExpression entity) { IEntity exprs = entity.getExpressions(); if (!exprs.wGetEntityDescriptor().equals(SchemeEntityDescriptorEnum.SchemeExpressions)) throw new VisitException("expected a "+SchemeEntityDescriptorEnum.SchemeExpressions); boolean result = true; for (int i = 0; i < exprs.wSize(); i++) result = result && booleanValue(((SchemeExpression) exprs.wGet(i))); setResult(SchemeEntityFactory.instance.createBooleanValue(result)); } public void visit(OrExpression entity) { IEntity exprs = entity.getExpressions(); if (!exprs.wGetEntityDescriptor().equals(SchemeEntityDescriptorEnum.SchemeExpressions)) throw new VisitException("expected a "+SchemeEntityDescriptorEnum.SchemeExpressions); boolean result = true; for (int i = 0; i < exprs.wSize(); i++) result = result || booleanValue(((SchemeExpression) exprs.wGet(i))); setResult(SchemeEntityFactory.instance.createBooleanValue(result)); } public void visit(ApplyExpression entity) { IEntity exprs = entity.getExpressions(); if (!exprs.wGetEntityDescriptor().equals(SchemeEntityDescriptorEnum.SchemeExpressions)) throw new VisitException("expected a "+SchemeEntityDescriptorEnum.SchemeExpressions); if (exprs.wIsEmpty()) throw new VisitException("empty application"); ConstExpression head = (ConstExpression) evaluate((SchemeExpression) exprs.wGet(0)); ConstExpression[] args = new ConstExpression[exprs.wSize()-1]; for (int i = 1; i < exprs.wSize(); i++) args[i-1] = (ConstExpression) evaluate(((SchemeExpression) exprs.wGet(i))); apply(head, args); } public void visit(CondExpression entity) { boolean prune = false; Branches branches = (Branches) entity.getBranches(); if (!branches.wGetEntityDescriptor().equals(SchemeEntityDescriptorEnum.Branches)) throw new VisitException("expected a "+SchemeEntityDescriptorEnum.Branches); for (int i = 0; i < branches.wSize() && !prune; i++) { Branch branch = (Branch) entity.wGet(i); if (booleanValue(branch.getTest())) { branch.getBody().accept(this); return; } } entity.getElseBody().accept(this); } public void visit(IdExpression entity) { setResult(getBindings().wGet(entity.getValue())); } public void visit(LambdaExpression entity) { setResult(SchemeEntityFactory.instance.createClosureValue( entity.getArgs(), entity.getBody(), SchemeEntityFactory.instance.createSchemeEnvironment(getBindings()))); } public void visit(LocalExpression entity) { getBindings().wEnterScope(); Definitions defs = entity.getDefinitions(); if (!defs.wGetEntityDescriptor().equals(SchemeEntityDescriptorEnum.Definitions)) throw new VisitException("expected a "+SchemeEntityDescriptorEnum.Definitions); for (int i = 0; i < defs.wSize(); i++) { IEntity e = defs.wGet(i); if (e.wGetEntityDescriptor().equals(SchemeEntityDescriptorEnum.Definition)) { Definition def = ((Definition) e); getBindings().wDef(def.getName().wStringValue(), def.getExpression()); } } entity.getBody().accept(this); getBindings().wExitScope(); } protected void apply(ConstExpression head, ConstExpression[] args) { valueInterpreter.args = args; head.accept(valueInterpreter); } public static class SchemeValueInterpreter extends SchemeIdentityVisitor { private SchemeInterpreterVisitor expressionInterpreter; protected ConstExpression[] args; public SchemeValueInterpreter(SchemeInterpreterVisitor expressionInterpreter) { this.expressionInterpreter = expressionInterpreter; } public void visit(BuiltinValue entity) { //TODO } public void visit(ClosureValue entity) { if (args.length != entity.getArgs().wSize()) throw new VisitException("wrong number of arguments: " + args.length + " instead of " + entity.getArgs().wSize()); expressionInterpreter.getBindings().wEnterScope(((SchemeEnvironment) entity.getEnv()).getValue(), false); IEntity names = entity.getArgs(); for (int i=0; i<names.wSize(); i++) { expressionInterpreter.getBindings().wDef(names.wGet(i).wStringValue(), args[i]); } entity.getBody().accept(expressionInterpreter); expressionInterpreter.getBindings().wExitScope(); } } }