/*
* Copyright 2007-2013
* Licensed under GNU Lesser General Public License
*
* This file is part of EpochX: genetic programming software for research
*
* EpochX 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.
*
* EpochX 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 EpochX. If not, see <http://www.gnu.org/licenses/>.
*
* The latest version is available from: http://www.epochx.org
*/
package org.epochx.interpret;
import javax.script.*;
import org.epochx.Individual;
import org.epochx.source.SourceGenerator;
/**
* The ScriptingInterpreter provides a generic interpreter for any language
* which supports the javax.scripting API (JSR 223). Two constructors are
* provided, one which receives the name of an installed scripting engine or
* one of its aliases, for example "ruby", "jruby" and "javascript" would be
* valid engine names. The second constructor receives a script engine directly
* which makes it possible to easily plug in support for new languages by
* implementing a ScriptEngine (or otherwise obtaining an implementation).
*
* <p>
* It is often the case that performance can improved by handling evaluation and
* execution in a language specific way, so subclasses of this class may be
* available for some languages. Where available these language specific classes
* should be used in preference to this general class.
*
* <p>
* The javax.scripting API was added to Java in version 1.6 and as such this
* class and any subclasses require a 1.6 compatible JRE.
*
* @see RubyInterpreter
* @see GroovyInterpreter
*
* @since 2.0
*/
public class ScriptingInterpreter<T extends Individual> implements Interpreter<T> {
// The language specific scripting engine.
private ScriptEngine engine;
private SourceGenerator<T> generator;
/**
* Constructs a <code>ScriptingInterpreter</code> for a named scripting engine. A list
* of installed ScriptEngine names can be obtained with the following code:
*
* <blockquote><code>
* ScriptEngineManager mgr = new ScriptEngineManager();
* List<ScriptEngineFactory> factories = mgr.getEngineFactories();
* List<String> engineNames = new ArrayList<String>();
* for (ScriptEngineFactory factory: factories) {
* engineNames.addAll(factory.getNames());
* }
* </code></blockquote>
*
* @param generator the SourceGenerator to use to convert individuals to source code
* @param engineName the name of the scripting engine to use
*/
public ScriptingInterpreter(SourceGenerator<T> generator, String engineName) {
this.generator = generator;
ScriptEngineManager manager = new ScriptEngineManager();
engine = manager.getEngineByName(engineName);
if (engine == null) {
throw new IllegalArgumentException("no engine matching alias " + engineName);
}
}
/**
* Constructs a <code>ScriptingInterpreter</code> for the given <code>ScriptEngine</code>.
*
* @param generator the SourceGenerator to use to convert individuals to source code
* @param engine the scripting engine to use
*/
public ScriptingInterpreter(SourceGenerator<T> generator, ScriptEngine engine) {
this.generator = generator;
this.engine = engine;
}
/**
* {@inheritDoc}
*/
@Override
public Object[] eval(T program, String[] argNames, Object[][] argValues) throws MalformedProgramException {
int noParamSets = argValues.length;
int noParams = argNames.length;
final Object[] results = new Object[noParamSets];
String expression = generator.getSource(program);
// Evaluate each argument set.
for (int i = 0; i < noParamSets; i++) {
Object[] paramSet = argValues[i];
try {
for (int j = 0; j < noParams; i++) {
engine.put(argNames[j], paramSet[j]);
}
results[i] = engine.eval(expression);
} catch (final ScriptException e) {
throw new MalformedProgramException();
}
}
return results;
}
/**
* {@inheritDoc}
*/
@Override
public void exec(T program, String[] argNames, Object[][] argValues)
throws MalformedProgramException {
eval(program, argNames, argValues);
}
/**
* Returns the scripting engine performing the evaluation and execution.
*
* @return the script engine
*/
public ScriptEngine getEngine() {
return engine;
}
/**
* Returns the source generator being used to convert individuals to source code.
*
* @return the current source generator
*/
public SourceGenerator<T> getSourceGenerator() {
return generator;
}
/**
* Sets the source generator to use to convert individuals to source code
*
* @param the source generator to set
*/
public void setSourceGenerator(SourceGenerator<T> generator) {
this.generator = generator;
}
}