/**
* 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.scripts.visitors;
import static org.whole.lang.operations.PrettyPrinterOperation.toPrettyPrintString;
import java.io.PrintWriter;
import java.io.Writer;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.whole.lang.bindings.BindingManagerFactory;
import org.whole.lang.bindings.IBindingManager;
import org.whole.lang.matchers.Matcher;
import org.whole.lang.model.IEntity;
import org.whole.lang.operations.InterpreterOperation;
import org.whole.lang.scripts.bindings.BindingsAdapter;
import org.whole.lang.scripts.model.IScriptsEntity;
import org.whole.lang.scripts.model.LanguageName;
import org.whole.lang.scripts.model.Script;
import org.whole.lang.scripts.model.Source;
import org.whole.lang.scripts.reflect.ScriptsEntityDescriptorEnum;
import org.whole.lang.util.EntityUtils;
import org.whole.lang.visitors.IVisitor;
import org.whole.lang.visitors.VisitException;
/**
* @author Enrico Persiani
*/
public class ScriptsInterpreterVisitor extends ScriptsIdentityDefaultVisitor {
protected InterpreterOperation op() {
return (InterpreterOperation) getOperation();
}
@Override
public void visit(IScriptsEntity entity) {
Script s = Matcher.findAncestor(ScriptsEntityDescriptorEnum.Script, entity);
if (s != null)
visit(s);
throw new VisitException();
}
@Override
public void visit(Script entity) {
Writer outputWriter = op().getWriter();
IBindingManager bm = getBindings();
BindingsAdapter bindingsAdapter = new BindingsAdapter(bm, true);
LanguageName languageName = entity.getLanguageName();
/*
* TODO
* if contains an upper level fragment fail
*/
Source source = entity.getSource();
IEntity sourceRoot = EntityUtils.isFragment(source) ? source.wGetRoot() : source;
IEntity result0 = bm.getResult();
IVisitor ov = op().setVisitor(sourceRoot, 0, op().getVisitor(sourceRoot, 1));
op().stagedVisit(source);
IEntity sourceModel = bm.getResult();
//workaround restore previous value (also for self and queryIterator?)
bm.setResult(result0);
op().setVisitor(sourceRoot, 0, ov);
String sourceString = toPrettyPrintString(sourceModel);
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(languageName.getValue());
if (scriptEngine == null)
throw new VisitException("Cannot find an interpreter for the language: "+languageName);
scriptEngine.setBindings(bindingsAdapter, ScriptContext.ENGINE_SCOPE);
PrintWriter printWriter = new PrintWriter(outputWriter);
scriptEngine.getContext().setWriter(printWriter);
scriptEngine.getContext().setErrorWriter(printWriter);
Object result = null;
bm.wEnterScope();
do {
try {
result = scriptEngine.eval(sourceString);
break;
} catch (ScriptException e) {
bm.wExitScope();
if (!bindingsAdapter.isAutoboxing())
throw new VisitException("Script Interpreter failure.", e);
bindingsAdapter.setAutoboxing(false);
bm.wEnterScope();
}
} while (true);
bm.wExitScope(true);
if (result instanceof IEntity)
bm.setResult((IEntity) result);
else if (result != null)
bm.setResult(BindingManagerFactory.instance.createSpecificValue(result));
}
}