Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance rule interpretation errors #4462

Merged
merged 7 commits into from Nov 1, 2017
@@ -61,7 +61,7 @@ public void execute(JobExecutionContext context) throws JobExecutionException {
try {
script.execute(RuleContextHelper.getContext(rule, injector));
} catch (ScriptExecutionException e) {
logger.error("Error during the execution of rule {}: {}", rule.getName(), e.getMessage());
logger.error("Error during the execution of rule '{}': {}", rule.getName(), e.getMessage());
}
} else {
logger.debug("Scheduled rule '{}' does not exist", ruleName);
@@ -310,8 +310,8 @@ private void runStartupRules() {
triggerManager.removeRule(STARTUP, rule);
} catch (ScriptExecutionException e) {
if (!e.getMessage().contains("cannot be resolved to an item or type")) {
logger.error("Error during the execution of startup rule '{}': {}",
new Object[] { rule.getName(), e.getCause().getMessage() });
logger.error("Error during the execution of startup rule '{}': {}", rule.getName(),
e.getCause().getMessage());
triggerManager.removeRule(STARTUP, rule);
} else {
logger.debug(
@@ -7,6 +7,11 @@
*/
package org.eclipse.smarthome.model.script.engine;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.util.LineAndColumn;

/**
* A detailed error information for a script
*
@@ -28,7 +33,7 @@

/**
* Creates new ScriptError.
*
*
* @param message Error Message
* @param line Line number, or -1 if unknown
* @param column Column number, or -1 if unknown
@@ -41,10 +46,28 @@ public ScriptError(final String message, final int line, final int column, final
this.length = length;
}

/**
* Creates new ScriptError.
*
* This constructor uses the given EObject instance to calculate the exact position.
*
* @param message Error Message
* @param atEObject the EObject instance to use for calculating the position
*
*/
public ScriptError(final String message, final EObject atEObject) {
this.message = message;
INode node = NodeModelUtils.getNode(atEObject);
LineAndColumn lac = NodeModelUtils.getLineAndColumn(node, node.getOffset());
this.line = lac.getLine();
this.column = lac.getColumn();
this.length = node.getEndOffset() - node.getOffset();
}

/**
* Returns a message containing the String passed to a constructor as well as line and column numbers if any of
* these are known.
*
*
* @return The error message.
*/
public String getMessage() {
@@ -66,7 +89,7 @@ public String getMessage() {

/**
* Get the line number on which an error occurred.
*
*
* @return The line number. Returns -1 if a line number is unavailable.
*/
public int getLineNumber() {
@@ -75,7 +98,7 @@ public int getLineNumber() {

/**
* Get the column number on which an error occurred.
*
*
* @return The column number. Returns -1 if a column number is unavailable.
*/
public int getColumnNumber() {
@@ -84,7 +107,7 @@ public int getColumnNumber() {

/**
* Get the number of columns affected by the error.
*
*
* @return The number of columns. Returns -1 if unavailable.
*/
public int getLength() {
@@ -29,6 +29,12 @@ protected ScriptException(String message) {
errors.add(new ScriptError(message, 0, 0, -1));
}

protected ScriptException(ScriptError scriptError) {
super(scriptError.getMessage());
this.errors = new ArrayList<ScriptError>(1);
errors.add(scriptError);
}

/**
* @param message
* @param cause
@@ -64,7 +70,7 @@ private ScriptException(final Throwable cause, final String scriptText, final Sc

/**
* Creates a ScriptException with one Error.
*
*
* @param errors
*/
private ScriptException(final String scriptText, final ScriptError error) {
@@ -81,7 +87,7 @@ public ScriptException(String message, Throwable cause) {

/**
* All Errors that lead to this Exception.
*
*
* @return List of Error. Size >= 1, there is at last one ScriptError.
*/
public List<ScriptError> getErrors() {
@@ -95,9 +101,9 @@ public void setScriptText(final String scriptText) {
/**
* Returns a concatenation of all errors in contained ScriptError instances.
* Separated by newline, except for last error; no \n if only one error.
*
*
* @return The Message.
*
*
* @see ScriptError#getMessage()
*/
@Override
@@ -21,6 +21,10 @@ public ScriptExecutionException(final String message, final int line, final int
super(message, null, line, column, length);
}

public ScriptExecutionException(final ScriptError scriptError) {
super(scriptError);
}

public ScriptExecutionException(final String message, final Throwable cause, final int line, final int column,
final int length) {
super(cause, message, null, line, column, length);
@@ -8,21 +8,30 @@
package org.eclipse.smarthome.model.script.interpreter;

import com.google.inject.Inject
import org.eclipse.emf.ecore.EObject
import org.eclipse.smarthome.core.items.Item
import org.eclipse.smarthome.core.items.ItemNotFoundException
import org.eclipse.smarthome.core.items.ItemRegistry
import org.eclipse.smarthome.core.types.Type
import org.eclipse.smarthome.model.script.engine.ScriptExecutionException
import org.eclipse.smarthome.model.script.lib.NumberExtensions
import org.eclipse.smarthome.model.script.scoping.StateAndCommandProvider
import org.eclipse.xtext.common.types.JvmField
import org.eclipse.xtext.common.types.JvmIdentifiableElement
import org.eclipse.xtext.naming.QualifiedName
import org.eclipse.xtext.nodemodel.INode
import org.eclipse.xtext.nodemodel.util.NodeModelUtils
import org.eclipse.xtext.util.CancelIndicator
import org.eclipse.xtext.util.LineAndColumn
import org.eclipse.xtext.xbase.XAbstractFeatureCall
import org.eclipse.xtext.xbase.XCastedExpression
import org.eclipse.xtext.xbase.XExpression
import org.eclipse.xtext.xbase.XFeatureCall
import org.eclipse.xtext.xbase.XMemberFeatureCall
import org.eclipse.xtext.xbase.interpreter.IEvaluationContext
import org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter
import org.eclipse.xtext.xbase.jvmmodel.IJvmModelAssociations
import org.eclipse.smarthome.model.script.engine.ScriptError

/**
* The script interpreter handles ESH specific script components, which are not known
@@ -66,12 +75,20 @@ public class ScriptInterpreter extends XbaseInterpreter {
override protected invokeFeature(JvmIdentifiableElement feature, XAbstractFeatureCall featureCall,
Object receiverObj, IEvaluationContext context, CancelIndicator indicator) {
if (feature != null && feature.eIsProxy) {
throw new RuntimeException(
"The name '" + featureCall.toString() + "' cannot be resolved to an item or type.");
if (featureCall instanceof XMemberFeatureCall) {
throw new ScriptExecutionException(new ScriptError(

This comment has been minimized.

Copy link
@ThomDietrich

This comment has been minimized.

Copy link
@sjka

sjka Oct 27, 2017

Author Contributor

argh, good spot! No idea why there were tabs, but that's history now 😉

This comment has been minimized.

This comment has been minimized.

Copy link
@sjka

sjka Oct 27, 2017

Author Contributor

Awesome, thanks for the hint! I started wondering already how you spotted them...

This comment has been minimized.

"'" + featureCall.getConcreteSyntaxFeatureName() + "' is not a member of '" + receiverObj?.getClass()?.getName() + "'.", featureCall));
} else if (featureCall instanceof XFeatureCall) {
throw new ScriptExecutionException(new ScriptError(
"The name '" + featureCall.getConcreteSyntaxFeatureName() + "' cannot be resolved to an item or type.", featureCall));
} else {
throw new ScriptExecutionException(new ScriptError(
"Unknown variable or command '" + featureCall.getConcreteSyntaxFeatureName() + "'.", featureCall));
}
}
super.invokeFeature(feature, featureCall, receiverObj, context, indicator)
super.invokeFeature(feature, featureCall, receiverObj, context, indicator)
}

def protected Type getStateOrCommand(String name) {
for (Type type : stateAndCommandProvider.getAllTypes()) {
if (type.toString == name) {
@@ -118,4 +135,19 @@ public class ScriptInterpreter extends XbaseInterpreter {
return super.doEvaluate(expression, context, indicator)
}

override Object _doEvaluate(XCastedExpression castedExpression, IEvaluationContext context, CancelIndicator indicator) {
try {
return super._doEvaluate(castedExpression, context, indicator)
} catch (RuntimeException e) {
if (e.cause instanceof ClassCastException) {
val Object result = internalEvaluate(castedExpression.getTarget(), context, indicator);
throw new ScriptExecutionException(new ScriptError(
"Could not cast " + result + " to " + castedExpression.getType().getType().getQualifiedName(), castedExpression));
} else {
throw e;
}
}
}


}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.