blob: de78362aa290c0828b4f2b9a965909a4423ad4d2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 Christian Pontesegger and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
package org.eclipse.ease;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ease.debugging.model.EaseDebugLastExecutionResult;
import org.eclipse.ease.debugging.model.EaseDebugVariable;
import org.eclipse.ease.debugging.model.EaseDebugVariable.Type;
/**
* Adds generic REPL support to the AbstractScriptEngine.
*/
public abstract class AbstractReplScriptEngine extends AbstractScriptEngine implements IReplEngine {
/** Indicator to terminate once this Job gets IDLE. */
private volatile boolean fTerminateOnIdle = true;
/** Result of last script execution. */
private ScriptResult fLastExecutionResult = null;
/**
* Constructor. Sets the name for the underlying job.
*
* @param name
* name of script engine job
*/
public AbstractReplScriptEngine(final String name) {
super(name);
}
@Override
public final void setTerminateOnIdle(final boolean terminate) {
fTerminateOnIdle = terminate;
// if the engine remains active when IDLE this is likely a shell, therefore hide its job from users
if (getState() == Job.NONE)
// we can only set this before the engine got started
setSystem(!terminate);
synchronized (this) {
notifyAll();
}
}
@Override
public boolean getTerminateOnIdle() {
return fTerminateOnIdle;
}
/**
* Get termination status of the interpreter. A terminated interpreter cannot be restarted.
*
* @return true if interpreter is terminated.
*/
@Override
protected boolean isTerminated() {
return fTerminateOnIdle && isIdle();
}
/**
* Get idle status of the interpreter. The interpreter is IDLE if there are no pending execution requests and the interpreter is not terminated.
*
* @return true if interpreter is IDLE
*/
@Override
public boolean isIdle() {
return super.isTerminated();
}
@Override
public void terminate() {
setTerminateOnIdle(true);
super.terminate();
}
@Override
public Collection<EaseDebugVariable> getDefinedVariables() {
final Collection<EaseDebugVariable> result = new HashSet<>();
for (final Entry<String, Object> entry : getVariables().entrySet()) {
if (acceptVariable(entry.getValue())) {
final EaseDebugVariable variable = createVariable(entry.getKey(), entry.getValue());
result.add(variable);
}
}
return result;
}
protected boolean acceptVariable(Object value) {
return true;
}
protected Collection<EaseDebugVariable> getDefinedVariables(Object scope) {
return null;
}
protected EaseDebugVariable createVariable(String name, Object value) {
final String referenceType = getTypeName(value);
final EaseDebugVariable variable = new EaseDebugVariable(name, value, referenceType);
// TODO find nicer approach to set type
if ("Java Object".equals(referenceType))
variable.setType(Type.JAVA_OBJECT);
else
variable.getValue().setVariables(getDefinedVariables(value));
return variable;
}
protected String getTypeName(Object object) {
switch (getType(object)) {
case NATIVE_ARRAY:
String languageName = getDescription().getSupportedScriptTypes().get(0).getName();
return languageName + " Array";
case NATIVE_OBJECT:
languageName = getDescription().getSupportedScriptTypes().get(0).getName();
return languageName + " Object";
case NATIVE:
languageName = getDescription().getSupportedScriptTypes().get(0).getName();
return "Generic " + languageName;
case JAVA_OBJECT:
return "Java Object";
case JAVA_PRIMITIVE:
if (object instanceof Integer)
return "int";
if (object instanceof Byte)
return "byte";
if (object instanceof Short)
return "short";
if (object instanceof Boolean)
return "boolean";
if (object instanceof Character)
return "char";
if (object instanceof Long)
return "long";
if (object instanceof Double)
return "double";
if (object instanceof Float)
return "float";
// fall through
default:
return "";
}
}
@Override
public ScriptObjectType getType(Object object) {
if (object != null) {
if ((object instanceof Integer) || (object instanceof Byte) || (object instanceof Short) || (object instanceof Boolean)
|| (object instanceof Character) || (object instanceof Long) || (object instanceof Double) || (object instanceof Float))
return ScriptObjectType.JAVA_PRIMITIVE;
if (ScriptResult.VOID.equals(object))
return ScriptObjectType.VOID;
return ScriptObjectType.JAVA_OBJECT;
} else
return ScriptObjectType.NULL;
}
@Override
public String toString(Object object) {
if (ScriptResult.VOID.equals(object))
return "<undefined>";
if (object != null)
return object.toString();
return "null";
}
protected final String buildArrayString(List<Object> elements) {
final StringBuilder output = new StringBuilder("[");
for (final Object element : elements)
output.append(", ").append(toString(element));
output.append(']');
if (output.length() > 4)
output.delete(1, 3);
return output.toString();
}
protected final String buildObjectString(Map<String, Object> elements) {
final StringBuilder output = new StringBuilder("{");
for (final Entry<String, Object> entry : elements.entrySet())
output.append(", ").append(entry.getKey()).append(": ").append(toString(entry.getValue()));
output.append('}');
if (output.length() > 4)
output.delete(1, 3);
return output.toString();
}
@Override
protected void notifyExecutionListeners(Script script, int status) {
if (IExecutionListener.SCRIPT_END == status)
fLastExecutionResult = script.getResult();
super.notifyExecutionListeners(script, status);
}
@Override
public EaseDebugVariable getLastExecutionResult() {
if (fLastExecutionResult != null) {
if (ScriptResult.VOID.equals(fLastExecutionResult.getResult())) {
return new EaseDebugLastExecutionResult("no method return value", ScriptResult.VOID, "");
} else if (fLastExecutionResult.hasException()) {
return new EaseDebugLastExecutionResult("script exception", fLastExecutionResult.getException());
} else {
final EaseDebugVariable variable = createVariable("script returned", fLastExecutionResult.getResult());
return new EaseDebugLastExecutionResult(variable);
}
} else
return new EaseDebugLastExecutionResult("no method return value", null, "");
}
@Override
protected void teardownEngine() throws ScriptEngineException {
fLastExecutionResult = null;
}
}