it.xsemantics.runtime.XsemanticsRuntimeSystem Maven / Gradle / Ivy
/**
*
*/
package it.xsemantics.runtime;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.util.PolymorphicDispatcher;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Provider;
/**
* All generated systems will inherit from this class.
*
* @author Lorenzo Bettini
*
*/
public class XsemanticsRuntimeSystem {
// The first two params are RuleEnvironment and RuleApplicationTrace
protected static final int INDEX_OF_RULE_PARAMETERS = 2;
// The first param is the RuleApplicationTrace
protected static final int INDEX_OF_AUX_PARAMETERS = 1;
@Inject
protected StringRepresentation stringRepresentation;
@Inject
private Provider cacheProvider;
private XsemanticsCache cache = null;
/**
* @since 1.6
*/
public XsemanticsCache getCache() {
if (cache == null) {
cache = cacheProvider.get();
}
return cache;
}
/**
* @since 1.6
*/
protected T getFromCache(String methodName, RuleEnvironment environment,
RuleApplicationTrace trace, XsemanticsProvider provider,
Object... elements) {
return getCache().get(methodName, environment, trace, provider, elements);
}
protected Predicate getPredicate(String methodName, int numOfArgs) {
return PolymorphicDispatcher.Predicates.forName(methodName, numOfArgs);
}
protected PolymorphicDispatcher buildPolymorphicDispatcher(
final String methodName, int numOfArgs) {
return new PolymorphicDispatcher(
Collections.singletonList(this), getPredicate(methodName,
numOfArgs)) {
@Override
protected T handleNoSuchMethod(Object... params) {
throw noSuchMethodException(methodName, params);
}
};
}
protected PolymorphicDispatcher> buildPolymorphicDispatcher1(
String methodName, int numOfArgs, final String judgmentSymbol,
final String... relationSymbols) {
return new PolymorphicDispatcher>(
Collections.singletonList(this), getPredicate(methodName,
numOfArgs)) {
@Override
protected Result handleNoSuchMethod(Object... params) {
throw noSuchMethodException(
judgmentSymbol, Arrays.asList(relationSymbols),
params);
}
};
}
protected PolymorphicDispatcher> buildPolymorphicDispatcher2(
String methodName, int numOfArgs, final String judgmentSymbol,
final String... relationSymbols) {
return new PolymorphicDispatcher>(
Collections.singletonList(this), getPredicate(methodName,
numOfArgs)) {
@Override
protected Result2 handleNoSuchMethod(
Object... params) {
throw noSuchMethodException(
judgmentSymbol, Arrays.asList(relationSymbols),
params);
}
};
}
protected PolymorphicDispatcher> buildPolymorphicDispatcher3(
String methodName, int numOfArgs, final String judgmentSymbol,
final String... relationSymbols) {
return new PolymorphicDispatcher>(
Collections.singletonList(this), getPredicate(methodName,
numOfArgs)) {
@Override
protected Result3 handleNoSuchMethod(
Object... params) {
throw noSuchMethodException(
judgmentSymbol, Arrays.asList(relationSymbols),
params);
}
};
}
public boolean isResultAssignableTo(Object result, Class> destinationClass) {
// null is always assignable
if (result == null) {
return true;
}
return destinationClass.isAssignableFrom(result.getClass());
}
/**
* Checks whether the result is assignable to the specified
* destinationClass; if not it throws a {@link RuleFailedException}.
*
* @param result
* @param destinationClass
*/
public void checkAssignableTo(Object result, Class> destinationClass) {
if (!isResultAssignableTo(result, destinationClass)) {
throw newRuleFailedException(stringRep(result)
+ " cannot be assigned to " + stringRep(destinationClass));
}
}
public void checkParamsNotNull(Object... objects) {
for (int i = 0; i < objects.length; i++) {
Object object = objects[i];
checkNotNull(object);
}
}
/**
* Checks that the passed object is not null; if it is null it throws a
* {@link RuleFailedException}.
*
* @param object
*/
public void checkNotNull(Object object) {
if (object == null) {
throw newRuleFailedException("passed null object to system");
}
}
public String stringRep(Object object) {
return stringRepresentation.string(object);
}
protected String stringRepForEnv(RuleEnvironment ruleEnvironment) {
if (ruleEnvironment == null) {
return "[]";
}
return stringRepresentation.string(ruleEnvironment);
}
protected String stringRepForParams(Object[] params,
Iterable relationSymbols) {
StringBuilder builder = new StringBuilder();
Iterator it = relationSymbols.iterator();
for (int i = INDEX_OF_RULE_PARAMETERS; i < params.length; i++) {
builder.append(stringRep(params[i]));
if (it.hasNext()) {
builder.append(" " + it.next() + " ");
}
}
return builder.toString();
}
protected String stringRepForParams(Object[] params) {
StringBuilder builder = new StringBuilder();
for (int i = INDEX_OF_AUX_PARAMETERS; i < params.length; i++) {
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(stringRep(params[i]));
}
return builder.toString();
}
protected RuleFailedException noSuchMethodException(
final String judgmentSymbol,
final Iterable relationSymbols, Object... params) {
return newRuleFailedException("cannot find a rule for "
+ judgmentSymbol + " "
+ stringRepForParams(params, relationSymbols));
}
protected RuleFailedException noSuchMethodException(final String name,
Object... params) {
return newRuleFailedException("cannot find an implementation for "
+ name + "(" + stringRepForParams(params) + ")");
}
public void sneakyThrowRuleFailedException(Exception e) {
throw extractRuleFailedException(e);
}
public void sneakyThrowRuleFailedException(String message) {
throw newRuleFailedException(message, null);
}
public void throwForExplicitFail() {
throw newRuleFailedException();
}
public void throwForExplicitFail(String message,
ErrorInformation errorInformation) {
final RuleFailedException ex = newRuleFailedException(message);
ex.addErrorInformation(errorInformation);
throw ex;
}
public void throwRuleFailedException(String message, String issue,
Throwable t, ErrorInformation... errorInformations) {
throw newRuleFailedException(message, issue, t, errorInformations);
}
/**
* @since 1.5
*/
public RuleFailedException newRuleFailedException() {
return createRuleFailedException(null, null, null);
}
/**
* @since 1.5
*/
public RuleFailedException newRuleFailedException(Throwable t) {
return createRuleFailedException(t.toString(), null, t);
}
/**
* @since 1.5
*/
public RuleFailedException newRuleFailedException(String message) {
return createRuleFailedException(message, null, null);
}
public RuleFailedException newRuleFailedException(String message,
String issue, ErrorInformation... errorInformations) {
return newRuleFailedException(message, issue, null, errorInformations);
}
public RuleFailedException newRuleFailedException(String message,
String issue, Throwable t, ErrorInformation... errorInformations) {
final RuleFailedException ruleFailedException = createRuleFailedException(
failed(message), issue, t);
ruleFailedException.addErrorInformations(errorInformations);
return ruleFailedException;
}
/**
* This factory method can be overridden if one needs to provide a custom implementation
* of {@link RuleFailedException}.
*
* @param message
* @param issue
* @param t
* @return
*
* @since 1.5
*/
protected RuleFailedException createRuleFailedException(String message,
String issue, Throwable t) {
return new RuleFailedException(message, issue, t);
}
public RuleFailedException extractRuleFailedException(Exception e) {
if (e instanceof WrappedException) {
WrappedException wrappedException = (WrappedException) e;
Exception exception = wrappedException.exception();
if (exception instanceof RuleFailedException) {
return (RuleFailedException) exception;
}
} else if (e instanceof RuleFailedException) {
return (RuleFailedException) e;
}
return newRuleFailedException(e);
}
protected Result resultForFailure(Exception e) {
return new Result(extractRuleFailedException(e));
}
protected Result2 resultForFailure2(
Exception e) {
return new Result2(extractRuleFailedException(e));
}
protected Result3 resultForFailure3(
Exception e) {
return new Result3(extractRuleFailedException(e));
}
protected String failed(String message) {
return "failed: " + trimIfNotNull(message);
}
protected String trimIfNotNull(String message) {
return message != null ? message.trim() : message;
}
protected String ruleName(String ruleName) {
return trimIfNotNull(ruleName) + ": ";
}
protected String auxFunName(String ruleName) {
return trimIfNotNull(ruleName);
}
/**
* If the passed ruleApplicationTrace is not null, then uses the
* traceElementProvider to create an element to add to the trace.
*
* Using a provider instead of the actual element avoids the creation of
* such element in case the ruleApplicationTrace is null, heavily reducing
* overhead and increasing performance.
*
* See also https
* ://github.com/LorenzoBettini/xsemantics/pull/27
*
* @param ruleApplicationTrace
* @param traceElementProvider
*
* @since 1.6
*/
public void addToTrace(RuleApplicationTrace ruleApplicationTrace,
Provider extends Object> traceElementProvider) {
if (ruleApplicationTrace != null) {
ruleApplicationTrace.addToTrace(traceElementProvider.get());
}
}
public RuleApplicationTrace newTrace(
RuleApplicationTrace ruleApplicationTrace) {
if (ruleApplicationTrace != null) {
return new RuleApplicationTrace();
}
return null;
}
public void addAsSubtrace(RuleApplicationTrace ruleApplicationTrace,
RuleApplicationTrace subTrace) {
if (ruleApplicationTrace != null) {
ruleApplicationTrace.addAsSubtrace(subTrace);
}
}
/**
* This method replaces the previous keyword 'env' in Xsemantics grammar
* (before version 1.5.0).
*
* It is useless to have such element in the grammar, since it has
* exactly the same syntax of this Java method invocation.
*
* @param environment
* @param key
* @param clazz
* @return
* @throws RuleFailedException
* @since 1.5
*/
public T env(RuleEnvironment environment, Object key,
Class extends T> clazz) throws RuleFailedException {
return environmentAccess(environment, key, clazz);
}
@SuppressWarnings("unchecked")
public T environmentAccess(RuleEnvironment environment, Object key,
Class extends T> clazz) throws RuleFailedException {
if (environment == null) {
throw newRuleFailedException("access to null environment");
}
Object value = environment.get(key);
if (value == null) {
throw newRuleFailedException("no mapping in the environment for: "
+ stringRep(key));
}
if (clazz.isAssignableFrom(value.getClass())) {
return (T) value;
}
throw newRuleFailedException("mapped value " + stringRep(value)
+ " cannot be assigned to " + stringRep(clazz));
}
public T clone(T eObject) {
return EcoreUtil.copy(eObject);
}
public RuleEnvironment emptyEnvironment() {
return new RuleEnvironment();
}
public RuleEnvironment environmentEntry(Object key, Object value) {
return new RuleEnvironment(new RuleEnvironmentEntry(key, value));
}
public RuleEnvironment environmentComposition(RuleEnvironment environment,
RuleEnvironment environment2) {
if (environment == null) {
return new RuleEnvironment(environment2);
}
return new RuleEnvironment(environment, environment2);
}
public List getAll(EObject eObject, EStructuralFeature mainFeature,
EStructuralFeature extendFeature, Class extends T> clazz) {
List list = new LinkedList();
if (eObject != null) {
// get all the stuff from the main object
addToList(list, eObject.eGet(mainFeature), clazz);
// follow the extend feature performing the closure
List nodesInRelation = getAllNodesInRelation(eObject,
extendFeature);
for (EObject object : nodesInRelation) {
addToList(list, object.eGet(mainFeature), clazz);
}
}
return list;
}
public List getAllNodesInRelation(EObject eObject,
EStructuralFeature extendFeature) {
List nodes = new LinkedList();
Set seen = new HashSet();
getAllNodesInRelation(eObject, extendFeature, nodes, seen);
return nodes;
}
protected void getAllNodesInRelation(EObject eObject,
EStructuralFeature extendFeature, List nodes,
Set seen) {
if (eObject != null) {
// follow the extend feature performing the closure
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy