org.eclipse.xtend.expression.ExecutionContextImpl Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2005, 2007 committers of openArchitectureWare and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* committers of openArchitectureWare - initial API and implementation
*******************************************************************************/
package org.eclipse.xtend.expression;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
import org.eclipse.internal.xtend.expression.ast.AbstractVisitor;
import org.eclipse.internal.xtend.expression.ast.DeclaredParameter;
import org.eclipse.internal.xtend.expression.ast.Identifier;
import org.eclipse.internal.xtend.expression.ast.SyntaxElement;
import org.eclipse.internal.xtend.type.baseimpl.PolymorphicResolver;
import org.eclipse.internal.xtend.type.baseimpl.TypesComparator;
import org.eclipse.internal.xtend.util.Cache;
import org.eclipse.internal.xtend.util.Pair;
import org.eclipse.internal.xtend.util.Triplet;
import org.eclipse.internal.xtend.xtend.XtendFile;
import org.eclipse.internal.xtend.xtend.ast.Around;
import org.eclipse.internal.xtend.xtend.ast.Extension;
import org.eclipse.internal.xtend.xtend.ast.ExtensionFile;
import org.eclipse.internal.xtend.xtend.types.AdviceContext;
import org.eclipse.xtend.typesystem.MetaModel;
import org.eclipse.xtend.typesystem.Operation;
import org.eclipse.xtend.typesystem.Property;
import org.eclipse.xtend.typesystem.Type;
/**
* @author Sven Efftinge (http://www.efftinge.de)
* @author Arno Haase
* @author Peter Friese
*/
public class ExecutionContextImpl implements ExecutionContext {
private final static Log log = LogFactory.getLog(ExecutionContextImpl.class);
private static final List NO_TYPES = Collections.emptyList();
private static final Type[] NO_TYPES_ARR = new Type[0];
private static final String[] NO_STRINGS = new String[0];
protected ResourceManager resourceManager;
private final Map variables = new HashMap();
private Map globalVars;
private ProgressMonitor monitor;
/**
* this field is conceptually final, i.e. it is set only at object construction time. To simplify implementation, it is however technically not
* final. This is done so that the cloneWith/WithoutResource methods can delegate to cloneContext and afterwards modify the instance. That
* provides cloneContext as a single method for subclasses to override.
*/
private Resource currentResource;
protected final TypeSystemImpl typeSystem;
protected ExceptionHandler exceptionHandler;
protected NullEvaluationHandler nullEvaluationHandler;
protected VetoableCallback callback;
@SuppressWarnings("serial")
protected final static class ExtensionsForNameAndTypeCacheKey extends Triplet> {
final int hash;
public ExtensionsForNameAndTypeCacheKey(final Resource first, final String second, final List third) {
super(first, second, third);
hash = super.hashCode();
}
@Override
public int hashCode() {
return hash;
}
}
class ExtensionsForNameAndTypeCache extends Cache>, Extension> {
@Override
protected Extension createNew(final Triplet> arg0) {
return PolymorphicResolver.getExtension(internalAllExtensions(arg0.getFirst()), arg0.getSecond(), arg0.getThird());
}
}
public ExecutionContextImpl() {
this((Map) null);
}
public ExecutionContextImpl(final TypeSystemImpl ts) {
this(ts, null);
}
public ExecutionContextImpl(final Map globalVars) {
this(new ResourceManagerDefaultImpl(), null, new TypeSystemImpl(), new HashMap(), globalVars, null, null, null, null, null,
null, null, null);
}
public ExecutionContextImpl(final TypeSystemImpl ts, final Map globalVars) {
this(new ResourceManagerDefaultImpl(), null, ts, new HashMap(), globalVars, null, null, null, null, null, null, null, null);
}
public ExecutionContextImpl(final ResourceManager resourceManager, final TypeSystemImpl typeSystem, final Map globalVars) {
this(resourceManager, null, typeSystem, new HashMap(), globalVars, null, null, null, null, null, null, null, null);
}
public ExecutionContextImpl(final ResourceManager resourceManager, final Resource resource, final TypeSystemImpl typeSystem,
final Map variables, final Map globalVars, final ProgressMonitor monitor,
final ExceptionHandler exceptionHandler, final List advices, final NullEvaluationHandler neh2,
final Map> extensionPerResourceMap, final VetoableCallback callback,
final Cache>, Extension> extensionsForNameAndTypesCache,
final Map>, Type> extensionsReturnTypeCache) {
if (extensionPerResourceMap != null) {
allExtensionsPerResource = extensionPerResourceMap;
} else {
allExtensionsPerResource = new HashMap>();
}
if (extensionsForNameAndTypesCache != null) {
this.extensionsForNameAndTypesCache = extensionsForNameAndTypesCache;
} else {
this.extensionsForNameAndTypesCache = new ExtensionsForNameAndTypeCache();
}
if (extensionsReturnTypeCache != null) {
this.extensionsReturnTypeCache = extensionsReturnTypeCache;
}
this.resourceManager = resourceManager;
currentResource = resource;
this.typeSystem = typeSystem;
if (variables != null) {
this.variables.putAll(variables);
}
if (globalVars == null) {
this.globalVars = new HashMap();
} else {
this.globalVars = globalVars;
}
this.monitor = monitor;
this.exceptionHandler = exceptionHandler;
if (advices != null) {
registeredExtensionAdvices = advices;
}
nullEvaluationHandler = neh2;
this.callback = callback;
}
public VetoableCallback getCallback() {
return callback;
}
public void registerMetaModel(final MetaModel mm) {
typeSystem.registerMetaModel(mm);
}
public List getMetaModels() {
return typeSystem.getMetaModels();
}
public Operation findOperation(final String name, final Object target, final Object[] params) {
return typeSystem.findOperation(name, target, params);
}
public Property findProperty(final String name, final Object target) {
return typeSystem.findProperty(name, target);
}
public Type[] findTypesForPrefix(final String prefix) {
return typeSystem.findTypesForPrefix(prefix, getImportedNamespaces());
}
public Type[] getAllTypes() {
return typeSystem.getAllTypes();
}
public Set getNamespaces() {
return typeSystem.getNamespaces();
}
public Type getBooleanType() {
return typeSystem.getBooleanType();
}
public Type getCollectionType(final Type innerType) {
return typeSystem.getCollectionType(innerType);
}
public Type getFeatureType() {
return typeSystem.getFeatureType();
}
public Type getIntegerType() {
return typeSystem.getIntegerType();
}
public Type getListType(final Type innerType) {
return typeSystem.getListType(innerType);
}
public Type getObjectType() {
return typeSystem.getObjectType();
}
public Type getOperationType() {
return typeSystem.getOperationType();
}
public Type getPropertyType() {
return typeSystem.getPropertyType();
}
public Type getRealType() {
return typeSystem.getRealType();
}
public Type getSetType(final Type innerType) {
return typeSystem.getSetType(innerType);
}
public Type getStaticPropertyType() {
return typeSystem.getStaticPropertyType();
}
public Type getStringType() {
return typeSystem.getStringType();
}
public Type getType(final Object obj) {
return typeSystem.getType(obj);
}
public Type getTypeForName(final String name) {
return typeSystem.getTypeForName(name, getImportedNamespaces());
}
protected String[] getImportedNamespaces() {
return currentResource != null ? currentResource.getImportedNamespaces() : NO_STRINGS;
}
public Type getTypeType() {
return typeSystem.getTypeType();
}
public Type getVoidType() {
return typeSystem.getVoidType();
}
public ExecutionContextImpl cloneContext() {
return new ExecutionContextImpl(resourceManager, currentResource, typeSystem, variables, globalVars, monitor, exceptionHandler,
registeredExtensionAdvices, nullEvaluationHandler, allExtensionsPerResource, callback, extensionsForNameAndTypesCache,
extensionsReturnTypeCache);
}
/**
* @deprecated Use getResourceManager().setFileEncoding() instead
*/
@Deprecated
public void setFileEncoding(final String encoding) {
if (resourceManager != null) {
resourceManager.setFileEncoding(encoding);
}
}
public Variable getVariable(final String name) {
return variables.get(name);
}
public Map getVisibleVariables() {
return Collections.unmodifiableMap(variables);
}
public Map getGlobalVariables() {
return globalVars;
}
public ExecutionContext cloneWithVariable(final Variable v) {
final ExecutionContextImpl result = cloneContext();
result.variables.put(v.getName(), v);
return result;
}
public ExecutionContext cloneWithoutVariables() {
final ExecutionContextImpl result = cloneContext();
result.variables.clear();
return result;
}
public ExecutionContext cloneWithResource(final Resource ns) {
final ExecutionContextImpl ctx = cloneContext();
ctx.currentResource = ns;
return ctx;
}
public ExecutionContext cloneWithoutResource() {
final ExecutionContextImpl ctx = cloneContext();
ctx.currentResource = null;
return ctx;
}
public ExecutionContext cloneWithoutMonitor() {
final ExecutionContextImpl ctx = cloneContext();
ctx.setMonitor(null);
return ctx;
}
public Resource currentResource() {
return currentResource;
}
public Set extends Extension> getAllExtensions() {
return internalAllExtensions(currentResource());
}
protected Map> allExtensionsPerResource = null;
private Set extends Extension> internalAllExtensions(final Resource currentResource2) {
Set allExtensions = allExtensionsPerResource.get(currentResource2);
if (allExtensions == null) {
ExecutionContext ctx = cloneWithResource(currentResource2);
allExtensions = new HashSet();
final Resource res = currentResource2;
if (res != null) {
if (res instanceof XtendFile) {
final List extensionList = ((XtendFile) res).getExtensions();
for (Extension element : extensionList) {
element.init(ctx);
allExtensions.add(advise(element));
}
}
final String[] extensions = res.getImportedExtensions();
for (final String extension : extensions) {
final Object o = resourceManager.loadResource(extension, XtendFile.FILE_EXTENSION);
final XtendFile extFile = (XtendFile) o;
if (extFile != null) {
ctx = cloneWithResource(extFile);
final List extensionList = extFile.getPublicExtensions(resourceManager, ctx);
for (final Extension element : extensionList) {
element.init(ctx);
allExtensions.add(advise(element));
}
}
}
}
allExtensionsPerResource.put(currentResource2, allExtensions);
}
return allExtensions;
}
protected Cache>, Extension> extensionsForNameAndTypesCache;
public Extension getExtensionForTypes(final String functionName, final Type[] parameterTypes) {
ExtensionsForNameAndTypeCacheKey key = new ExtensionsForNameAndTypeCacheKey(currentResource(), functionName,
parameterTypes != null ? Arrays.asList(parameterTypes) : NO_TYPES);
return extensionsForNameAndTypesCache.get(key);
}
public Extension getExtension(final String functionName, final Object[] actualParameters) {
if (actualParameters.length == 0) {
return getExtensionForTypes(functionName, NO_TYPES_ARR);
}
final Type[] types = new Type[actualParameters.length];
for (int i = 0; i < types.length; i++) {
types[i] = getType(actualParameters[i]);
}
return getExtensionForTypes(functionName, types);
}
public void setMonitor(final ProgressMonitor monitor) {
this.monitor = monitor;
}
public ProgressMonitor getMonitor() {
return monitor;
}
public void preTask(final Object element) {
if (monitor == null) {
return;
}
monitor.preTask(element, this);
}
public void postTask(final Object element) {
if (monitor == null) {
return;
}
monitor.postTask(element, this);
}
public void handleRuntimeException(final RuntimeException ex, final SyntaxElement element, final Map additionalContextInfo) {
if (exceptionHandler == null) {
throw ex;
}
exceptionHandler.handleRuntimeException(ex, element, this, additionalContextInfo);
}
public ResourceManager getResourceManager() {
return resourceManager;
}
protected List registeredExtensionAdvices = new LinkedList();
public void registerExtensionAdvices(final String fullyQualifiedName) {
final XtendFile ext = (XtendFile) resourceManager.loadResource(fullyQualifiedName, XtendFile.FILE_EXTENSION);
if (ext == null) {
throw new IllegalArgumentException("Couldn't find extension file '" + fullyQualifiedName + "'");
}
final List as = ext.getArounds();
for (Around around : as) {
if (registeredExtensionAdvices.contains(around)) {
log.warn("advice " + around.toString() + " already registered!");
} else {
registeredExtensionAdvices.add(around);
}
}
}
public List getExtensionAdvices() {
return registeredExtensionAdvices;
}
private final TypesComparator typesComparator = new TypesComparator();
private Extension advise(final Extension element) {
if ((registeredExtensionAdvices == null) || registeredExtensionAdvices.isEmpty()) {
return element;
}
Extension _element = element;
for (Around a : getExtensionAdvices()) {
if (a.nameMatches(_element.getQualifiedName())) {
List paramTypes = a.getParamTypes(this);
List extPTypes = _element.getParameterTypes();
int diff = extPTypes.size() - paramTypes.size();
if (diff >= 0) {
if ((diff > 0) && a.isWildparams()) { // fill wildcard
// params with
// Object types
for (int i = 0; i < diff; i++) {
paramTypes.add(getObjectType());
}
}
if (typesComparator.compare(paramTypes, extPTypes) >= 0) {
_element = new ExtensionAdvisor(a, _element);
}
}
}
}
return _element;
}
class ExtensionAdvisor implements Extension {
private final Extension delegate;
private final Around advice;
public ExtensionAdvisor(final Around advice, final Extension delegate) {
this.delegate = delegate;
this.advice = advice;
}
public Object evaluate(final Object[] parameters, final ExecutionContext ctx) {
ExecutionContext _ctx = ctx;
_ctx = _ctx.cloneWithVariable(new Variable(Around.CONTEXT_PARAM_NAME, new AdviceContext(delegate, _ctx, parameters)));
for (int i = 0; i < advice.getParams().size(); i++) {
_ctx = _ctx.cloneWithVariable(new Variable(advice.getParams().get(i).getName().toString(), parameters[i]));
}
_ctx = _ctx.cloneWithResource(advice.getParent());
return advice.getExpression().evaluate(_ctx);
}
public void analyze(final ExecutionContext ctx, final Set issues) {
delegate.analyze(ctx, issues);
}
public int getEnd() {
return delegate.getEnd();
}
public ExtensionFile getExtensionFile() {
return delegate.getExtensionFile();
}
public String getFileName() {
return delegate.getFileName();
}
public List getFormalParameters() {
return delegate.getFormalParameters();
}
public int getLine() {
return delegate.getLine();
}
public String getName() {
return delegate.getName();
}
public List getParameterNames() {
return delegate.getParameterNames();
}
public List getParameterTypes() {
return delegate.getParameterTypes();
}
public Type getReturnType(final Type[] parameters, final ExecutionContext ctx, final Set issues) {
return ctx.getReturnType(delegate, parameters, issues);
}
public Type getReturnType() {
return delegate.getReturnType();
}
public Identifier getReturnTypeIdentifier() {
return delegate.getReturnTypeIdentifier();
}
public int getStart() {
return delegate.getStart();
}
public String getNameString(final ExecutionContext context) {
return delegate.getNameString(context);
}
public void init(final ExecutionContext ctx) {
delegate.init(ctx);
}
public boolean isCached() {
return delegate.isCached();
}
public boolean isPrivate() {
return delegate.isPrivate();
}
public void setExtensionFile(final ExtensionFile file) {
delegate.setExtensionFile(file);
}
public String toOutlineString() {
return delegate.toOutlineString();
}
@Override
public String toString() {
return delegate.toString();
}
public String getQualifiedName() {
return delegate.getQualifiedName();
}
public final Object accept(final AbstractVisitor visitor) {
return visitor.visit(this);
}
}
public Object handleNullEvaluation(final SyntaxElement element) {
if (nullEvaluationHandler != null) {
return nullEvaluationHandler.handleNullEvaluation(element, this);
}
return null;
}
public void release() {
typeSystem.release();
}
/**
* @deprecated Use {@link #setVetoableCallBack(VetoableCallback)}
*/
@Deprecated
public void setCallBack(final Callback callback) {
this.callback = new VetoableCallbackAdapter(callback);
}
public void setVetoableCallBack(final VetoableCallback callback) {
this.callback = callback;
}
protected Map>, Type> extensionsReturnTypeCache = new HashMap>, Type>();
public Type getReturnType(final Extension extension, final Type[] paramTypes, final Set issues) {
final List value = paramTypes.length > 0 ? Arrays.asList(paramTypes) : NO_TYPES;
Pair> key = new Pair>(extension.getQualifiedName(), value);
if (extensionsReturnTypeCache.containsKey(key)) {
return extensionsReturnTypeCache.get(key);
}
Type result = extension.getReturnType(paramTypes, this, issues);
extensionsReturnTypeCache.put(key, result);
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy