blob: c1c080beaceb2e0b14cf4a03da49605b2cdcf3c8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2018 Dennis Wagelaar, Vrije Universiteit Brussel.
* 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:
* Dennis Wagelaar, Vrije Universiteit Brussel - initial API and
* implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.m2m.atl.emftvm.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.impl.EObjectImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.m2m.atl.common.ATLLogger;
import org.eclipse.m2m.atl.emftvm.CodeBlock;
import org.eclipse.m2m.atl.emftvm.EmftvmFactory;
import org.eclipse.m2m.atl.emftvm.EmftvmPackage;
import org.eclipse.m2m.atl.emftvm.ExecEnv;
import org.eclipse.m2m.atl.emftvm.Feature;
import org.eclipse.m2m.atl.emftvm.Field;
import org.eclipse.m2m.atl.emftvm.Instruction;
import org.eclipse.m2m.atl.emftvm.Metamodel;
import org.eclipse.m2m.atl.emftvm.Model;
import org.eclipse.m2m.atl.emftvm.Module;
import org.eclipse.m2m.atl.emftvm.Operation;
import org.eclipse.m2m.atl.emftvm.OutputRuleElement;
import org.eclipse.m2m.atl.emftvm.Parameter;
import org.eclipse.m2m.atl.emftvm.Rule;
import org.eclipse.m2m.atl.emftvm.RuleElement;
import org.eclipse.m2m.atl.emftvm.RuleMode;
import org.eclipse.m2m.atl.emftvm.constraints.StackUnderflowValidator;
import org.eclipse.m2m.atl.emftvm.constraints.ValidCodeBlockStackLevelValidator;
import org.eclipse.m2m.atl.emftvm.constraints.Validator;
import org.eclipse.m2m.atl.emftvm.jit.CodeBlockJIT;
import org.eclipse.m2m.atl.emftvm.trace.TraceFactory;
import org.eclipse.m2m.atl.emftvm.trace.TraceLink;
import org.eclipse.m2m.atl.emftvm.trace.TraceLinkSet;
import org.eclipse.m2m.atl.emftvm.trace.TracePackage;
import org.eclipse.m2m.atl.emftvm.util.DuplicateEntryException;
import org.eclipse.m2m.atl.emftvm.util.EMFTVMUtil;
import org.eclipse.m2m.atl.emftvm.util.FieldContainer;
import org.eclipse.m2m.atl.emftvm.util.LazyList;
import org.eclipse.m2m.atl.emftvm.util.ModuleNotFoundException;
import org.eclipse.m2m.atl.emftvm.util.ModuleResolver;
import org.eclipse.m2m.atl.emftvm.util.NativeCodeBlock;
import org.eclipse.m2m.atl.emftvm.util.NativeTypes;
import org.eclipse.m2m.atl.emftvm.util.OCLOperations;
import org.eclipse.m2m.atl.emftvm.util.ResourceIterable;
import org.eclipse.m2m.atl.emftvm.util.StackFrame;
import org.eclipse.m2m.atl.emftvm.util.TimingData;
import org.eclipse.m2m.atl.emftvm.util.TypeHashMap;
import org.eclipse.m2m.atl.emftvm.util.TypeMap;
import org.eclipse.m2m.atl.emftvm.util.Types;
import org.eclipse.m2m.atl.emftvm.util.VMException;
import org.eclipse.m2m.atl.emftvm.util.VMMonitor;
/**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Exec Env</b></em>'.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* </p>
* <ul>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#getMetaModels <em>Meta Models</em>}</li>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#getInputModels <em>Input Models</em>}</li>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#getInoutModels <em>Inout Models</em>}</li>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#getOutputModels <em>Output Models</em>}</li>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#getModules <em>Modules</em>}</li>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#getMatches <em>Matches</em>}</li>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#getTraces <em>Traces</em>}</li>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#getUniqueResults <em>Unique Results</em>}</li>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#isJitDisabled <em>Jit Disabled</em>}</li>
* <li>{@link org.eclipse.m2m.atl.emftvm.impl.ExecEnvImpl#getCurrentPhase <em>Current Phase</em>}</li>
* </ul>
*
* @generated
*/
public class ExecEnvImpl extends EObjectImpl implements ExecEnv {
/**
* Holds data for queued operations.
* @author Dennis Wagelaar <dennis.wagelaar@vub.ac.be>
*/
abstract class QueueEntry {
/**
* The stack frame context in which to perform the queued operation.
*/
protected final StackFrame frame;
/**
* The program counter value.
*/
protected final int pc;
/**
* Creates a new {@link QueueEntry}.
* @param frame the stack frame context in which to perform the queued operation
*/
public QueueEntry(final StackFrame frame) {
this.frame = frame;
this.pc = frame.getPc();
}
/**
* Processes this queue element.
*/
public void process() {
try {
perform();
} catch (final VMException e) {
throw e;
} catch (final Exception e) {
frame.setPc(pc);
throw new VMException(frame, e);
}
}
/**
* Performs the queued operation.
*/
protected abstract void perform();
}
/**
* Hold data for element deletion.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
final class DeletionEntry extends QueueEntry {
/**
* The element to delete.
*/
protected final EObject element;
/**
* Creates a new {@link DeletionEntry}.
* @param element the element to delete
* @param frame the stack frame context in which to perform the deletion
*/
public DeletionEntry(final EObject element, final StackFrame frame) {
super(frame);
this.element = element;
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException
*/
@Override
protected void perform() {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*
* Performs the actual deletion of the element from its model.
*/
@Override
public void process() {
final Model m = getInoutModelOf(element);
try {
m.deleteElement(element);
} catch (final Exception e) {
frame.setPc(pc);
throw new VMException(frame, String.format("Error while deleting element %s from %s: %s",
EMFTVMUtil.toPrettyString(element, ExecEnvImpl.this), getModelID(m), e.getLocalizedMessage()), e);
}
}
/**
* Performs the queued operation for the given <code>ref</code>.
*
* @param o
* the object for which to delete from <code>ref</code>
* @param ref
* the {@link EReference} to perform the delete() for
*/
public void process(final EObject o, final EReference ref) {
try {
assert ref.isMany() || o.eGet(ref) == element;
assert !ref.isMany() || ((Collection<?>) o.eGet(ref)).contains(element);
EMFTVMUtil.remove(ExecEnvImpl.this, o, ref, element);
} catch (final VMException e) {
throw e;
} catch (final Exception e) {
frame.setPc(pc);
final ExecEnv env = frame.getEnv();
throw new VMException(frame, String.format("Error deleting %s.%s from %s: %s", EMFTVMUtil.toPrettyString(o, env),
ref.getName(), EMFTVMUtil.toPrettyString(element, env), e.getMessage()), e);
}
}
}
/**
* Holds data for a queued remap() operation.
* @author <a href="dwagelaar@gmail.com">Dennis Wagelaar</a>
*/
final class RemapEntry extends QueueEntry {
/**
* The source element to remap.
*/
protected final EObject source;
/**
* The target element to map to.
*/
protected final EObject target;
/**
* Creates a new {@link RemapEntry}.
*
* @param source
* the source element to remap
* @param target
* the target element to map to
* @param frame
* the stack frame context in which to perform the set
*/
public RemapEntry(final EObject source, final EObject target, final StackFrame frame) {
super(frame);
this.source = source;
this.target = target;
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException
*/
@Override
protected void perform() {
throw new UnsupportedOperationException();
}
/**
* Performs the queued operation for the given <code>ref</code>.
*
* @param o
* the object for which to remap <code>ref</code>
* @param ref
* the {@link EReference} to perform the remap() for
*/
public void process(final EObject o, final EReference ref) {
try {
assert o.eGet(ref) == source;
EMFTVMUtil.set(ExecEnvImpl.this, o, ref, target);
} catch (final VMException e) {
throw e;
} catch (final Exception e) {
frame.setPc(pc);
final ExecEnv env = frame.getEnv();
throw new VMException(frame, String.format("Error remapping %s.%s from %s to %s: %s", EMFTVMUtil.toPrettyString(o, env),
ref.getName(), EMFTVMUtil.toPrettyString(source, env), EMFTVMUtil.toPrettyString(target, env), e.getMessage()), e);
}
}
/**
* Performs the queued operation for the given <code>ref</code> and <code>index</code>.
*
* @param o
* the object for which to remap <code>ref</code>
* @param ref
* the {@link EReference} to perform the remap() for
* @param index
* the reference value index at which to remap
*/
public void process(final EObject o, final EReference ref, final int index) {
try {
assert o.eGet(ref) instanceof Collection<?>;
assert ((Collection<?>) o.eGet(ref)).contains(source);
assert index < 0 || ((List<?>) o.eGet(ref)).get(index) == source;
EMFTVMUtil.remove(ExecEnvImpl.this, o, ref, source);
EMFTVMUtil.add(ExecEnvImpl.this, o, ref, target, index);
} catch (final VMException e) {
throw e;
} catch (final Exception e) {
frame.setPc(pc);
final ExecEnv env = frame.getEnv();
throw new VMException(frame, String.format("Error remapping %s.%s from %s to %s: %s", EMFTVMUtil.toPrettyString(o, env),
ref.getName(), EMFTVMUtil.toPrettyString(source, env), EMFTVMUtil.toPrettyString(target, env), e.getMessage()), e);
}
}
}
/**
* The cached value of the '{@link #getMetaModels() <em>Meta Models</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getMetaModels()
* @generated
* @ordered
*/
protected Map<String, Metamodel> metaModels;
/**
* The cached value of the '{@link #getInputModels() <em>Input Models</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getInputModels()
* @generated
* @ordered
*/
protected Map<String, Model> inputModels;
/**
* The cached value of the '{@link #getInoutModels() <em>Inout Models</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getInoutModels()
* @generated
* @ordered
*/
protected Map<String, Model> inoutModels;
/**
* The cached value of the '{@link #getOutputModels() <em>Output Models</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getOutputModels()
* @generated
* @ordered
*/
protected Map<String, Model> outputModels;
/**
* The cached value of the '{@link #getModules() <em>Modules</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getModules()
* @generated
* @ordered
*/
protected Map<String, Module> modules;
/**
* The cached value of the '{@link #getMatches() <em>Matches</em>}' reference.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getMatches()
* @generated
* @ordered
*/
protected TraceLinkSet matches;
/**
* The cached value of the '{@link #getTraces() <em>Traces</em>}' reference.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getTraces()
* @generated
* @ordered
*/
protected TraceLinkSet traces;
/**
* The cached value of the '{@link #getUniqueResults() <em>Unique Results</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getUniqueResults()
* @generated
* @ordered
*/
protected Map<TraceLink, Object> uniqueResults;
/**
* The default value of the '{@link #isJitDisabled() <em>Jit Disabled</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isJitDisabled()
* @generated
* @ordered
*/
protected static final boolean JIT_DISABLED_EDEFAULT = false;
/**
* The cached value of the '{@link #isJitDisabled() <em>Jit Disabled</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #isJitDisabled()
* @generated
* @ordered
*/
protected boolean jitDisabled = JIT_DISABLED_EDEFAULT;
/**
* The default value of the '{@link #getCurrentPhase() <em>Current Phase</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getCurrentPhase()
* @generated
* @ordered
*/
protected static final RuleMode CURRENT_PHASE_EDEFAULT = RuleMode.MANUAL;
/**
* The cached value of the '{@link #getCurrentPhase() <em>Current Phase</em>}' attribute.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getCurrentPhase()
* @generated
* @ordered
*/
protected RuleMode currentPhase = CURRENT_PHASE_EDEFAULT;
/**
* The internal value of the '{@link #getMetaModels() <em>Meta Models</em>}' attribute.
*/
protected final Map<String, Metamodel> internalMetaModels =
Collections.synchronizedMap(new HashMap<String, Metamodel>());
/**
* The internal value of the '{@link #getInputModels() <em>Input Models</em>}' attribute.
*/
protected final Map<String, Model> internalInputModels =
Collections.synchronizedMap(new HashMap<String, Model>());
/**
* The internal value of the '{@link #getInoutModels() <em>Inout Models</em>}' attribute.
*/
protected final Map<String, Model> internalInoutModels =
Collections.synchronizedMap(new HashMap<String, Model>());
/**
* The internal value of the '{@link #getOutputModels() <em>Output Models</em>}' attribute.
*/
protected final Map<String, Model> internalOutputModels =
Collections.synchronizedMap(new HashMap<String, Model>());
/**
* The internal value of the '{@link #getModules() <em>Modules</em>}' attribute.
*/
protected final Map<String, Module> internalModules =
Collections.synchronizedMap(new LinkedHashMap<String, Module>());
/**
* Set of modules that have effectively been loaded.
* Intended for keeping track of cyclic imports.
*/
protected final Set<String> loadedModules = new HashSet<String>();
/**
* The chain of '<code>main()</code>' operations to be executed after the automatic rules.
*/
protected final EList<Operation> mainChain = new BasicEList<Operation>();
/**
* The chain of '<code>init()</code>' operations to be executed before the automatic rules.
*/
protected final EList<Operation> initChain = new BasicEList<Operation>();
/**
* Field storage and lookup.
*/
protected final FieldContainer fieldContainer = new FieldContainer();
/**
* Lookup table for operations: (name -> (argcount -> (context -> ?)))
* Depending on the number of arguments (argcount), several nested {@link TypeMap}s are contained,
* eventually pointing to an {@link Operation}.
* Example: for argcount = 2: (name -> (2 -> (context -> (arg1 -> (arg2 -> op)))))
*/
protected final Map<String, Map<Integer, TypeMap<Object, Object>>> operations =
new HashMap<String, Map<Integer,TypeMap<Object,Object>>>();
/**
* Lookup table for static operations: (name -> (argcount -> (context -> ?)))
* Depending on the number of arguments (argcount), several nested {@link TypeMap}s are contained,
* eventually pointing to an {@link Operation}.
* Example: for argcount = 2: (name -> (2 -> (context -> (arg1 -> (arg2 -> op)))))
*/
protected final Map<String, Map<Integer, TypeMap<Object, Object>>> staticOperations =
new HashMap<String, Map<Integer,TypeMap<Object,Object>>>();
/**
* Lookup table for rules: (name -> rule).
*/
protected final Map<String, Rule> rules = new LinkedHashMap<String, Rule>();
/**
* Lookup table of (resource -> model).
*/
protected final Map<Resource, Model> modelOf = new HashMap<Resource, Model>();
/**
* Lookup table of (resource -> model).
*/
protected final Map<Resource, Model> inputModelOf = new HashMap<Resource, Model>();
/**
* Lookup table of (resource -> model).
*/
protected final Map<Resource, Model> inoutModelOf = new HashMap<Resource, Model>();
/**
* Lookup table of (resource -> model).
*/
protected final Map<Resource, Model> outputModelOf = new HashMap<Resource, Model>();
/**
* Lookup table of (resource -> metamodel).
*/
protected final Map<Resource, Metamodel> metaModelOf = new HashMap<Resource, Metamodel>();
/**
* Lookup table of (model -> ID).
*/
protected final Map<Model, String> modelId = new HashMap<Model, String>();
/**
* Lookup table of (metamodel -> ID).
*/
protected final Map<Metamodel, String> metaModelId = new HashMap<Metamodel, String>();
/**
* Model cache initialised?
*/
protected boolean modelCacheInit;
/**
* The {@link VMMonitor} for the currently running VM instance.
*/
protected VMMonitor monitor;
/**
* Queue of elements to be deleted, along with the {@link StackFrame} context in which the deletion takes place.
*/
protected final Map<EObject, DeletionEntry> deletionQueue = new HashMap<EObject, DeletionEntry>();
/**
* {@link Queue} of features/fields to be set, along with the {@link StackFrame}
* context in which the set takes place.
*/
protected final Queue<QueueEntry> setQueue = new LinkedList<QueueEntry>();
/**
* Queue of source/target values to be remapped, along with the {@link StackFrame} context in which the remapping takes place. Only one
* queue entry per source value to remap is supported.
*/
protected final Map<EObject, RemapEntry> remapQueue = new HashMap<EObject, RemapEntry>();
/**
* Code block stack level validator.
*/
protected final Validator<CodeBlock> cbStackValidator = new ValidCodeBlockStackLevelValidator();
/**
* Instruction stack level validator.
*/
protected final Validator<Instruction> instrStackValidator = new StackUnderflowValidator();
private CodeBlockJIT cbJit;
private boolean ruleStateCompiled;
/**
* <!-- begin-user-doc -->
* Creates a new {@link ExecEnvImpl}.
* <!-- end-user-doc -->
*/
protected ExecEnvImpl() {
super();
registerMetaModel(EcorePackage.eNAME.toUpperCase(), EMFTVMUtil.getEcoreMetamodel());
registerMetaModel(EmftvmPackage.eNAME.toUpperCase(), EMFTVMUtil.getEmfTvmMetamodel());
registerMetaModel(TracePackage.eNAME.toUpperCase(), EMFTVMUtil.getTraceMetamodel());
createField("matches", true, Types.EXEC_ENV_TYPE, Types.TRACE_LINK_SET_TYPE, new NativeCodeBlock() {
@Override
public Object execute(final StackFrame frame) {
return getMatches();
}
});
createField("traces", true, Types.EXEC_ENV_TYPE, Types.TRACE_LINK_SET_TYPE, new NativeCodeBlock() {
@Override
public Object execute(final StackFrame frame) {
return getTraces();
}
});
final Module oclModule = OCLOperations.getInstance().getOclModule();
loadModule(new ModuleResolver() {
public Module resolveModule(final String name) throws ModuleNotFoundException {
return oclModule;
}
}, oclModule.getName());
}
/**
* Creates and registers a new {@link Field}.
* @param name field name
* @param isStatic whether the field is static
* @param context field context type model and name
* @param type field type model and name
* @param initialiser field initialiser codeblock
*/
private void createField(final String name, final boolean isStatic,
final String[] context, final String[] type, final CodeBlock initialiser) {
final Field f = EMFTVMUtil.createField(name, isStatic, context, type, initialiser);
registerFeature(f);
}
/**
* <!-- begin-user-doc -->
* Returns the {@link EClass} that correspond to this metaclass.
* @return the {@link EClass} that correspond to this metaclass.
* <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass() {
return EmftvmPackage.Literals.EXEC_ENV;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Map<String, Module> getModules() {
if (modules == null) {
modules = Collections.unmodifiableMap(internalModules);
}
return modules;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public TraceLinkSet getMatches() {
if (matches == null) {
basicGetMatches();
}
if (matches != null && matches.eIsProxy()) {
final InternalEObject oldMatches = (InternalEObject)matches;
matches = (TraceLinkSet)eResolveProxy(oldMatches);
if (matches != oldMatches) {
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.RESOLVE, EmftvmPackage.EXEC_ENV__MATCHES, oldMatches, matches));
}
}
return matches;
}
/**
* <!-- begin-user-doc. -->
* Returns the value of the 'Matches' reference.
* @return the value of the 'Matches' reference.
* <!-- end-user-doc -->
* @generated NOT
*/
public TraceLinkSet basicGetMatches() {
if (matches == null) {
final Map<String, Model> oms = getOutputModels();
final Map<String, Model> ioms = getInoutModels();
if (oms.containsKey("match")) {
matches = (TraceLinkSet)oms.get("match").newElement(TracePackage.eINSTANCE.getTraceLinkSet());
} else if (ioms.containsKey("match")) {
matches = (TraceLinkSet) ioms.get("match").newElement(TracePackage.eINSTANCE.getTraceLinkSet());
} else {
matches = TraceFactory.eINSTANCE.createTraceLinkSet();
}
assert matches != null;
}
return matches;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public TraceLinkSet getTraces() {
if (traces == null) {
basicGetTraces();
}
if (traces != null && traces.eIsProxy()) {
final InternalEObject oldTraces = (InternalEObject)traces;
traces = (TraceLinkSet)eResolveProxy(oldTraces);
if (traces != oldTraces) {
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.RESOLVE, EmftvmPackage.EXEC_ENV__TRACES, oldTraces, traces));
}
}
return traces;
}
/**
* <!-- begin-user-doc. -->
* Returns the value of the 'Traces' reference.
* @return the value of the 'Traces' reference.
* <!-- end-user-doc -->
* @generated NOT
*/
public TraceLinkSet basicGetTraces() {
if (traces == null) {
final Map<String, Model> oms = getOutputModels();
final Map<String, Model> ioms = getInoutModels();
if (oms.containsKey("trace")) {
traces = (TraceLinkSet)oms.get("trace").newElement(TracePackage.eINSTANCE.getTraceLinkSet());
} else if (ioms.containsKey("trace")) {
traces = (TraceLinkSet) ioms.get("trace").newElement(TracePackage.eINSTANCE.getTraceLinkSet());
} else {
traces = TraceFactory.eINSTANCE.createTraceLinkSet();
}
assert traces != null;
}
return traces;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Map<TraceLink, Object> getUniqueResults() {
if (uniqueResults == null) {
uniqueResults = new HashMap<TraceLink, Object>();
}
return uniqueResults;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public boolean isJitDisabled() {
return jitDisabled;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setJitDisabled(final boolean newJitDisabled) {
final boolean oldJitDisabled = jitDisabled;
jitDisabled = newJitDisabled;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, EmftvmPackage.EXEC_ENV__JIT_DISABLED, oldJitDisabled, jitDisabled));
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public RuleMode getCurrentPhase() {
return currentPhase;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public VMMonitor getMonitor() {
return monitor;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public synchronized void setMonitor(final VMMonitor monitor) {
// Reset JIT compiler if monitor changes from or to null
if (this.monitor == null) {
if (monitor != null) {
resetJITCompiler();
}
} else {
if (monitor == null) {
resetJITCompiler();
}
}
this.monitor = monitor;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public synchronized void registerMetaModel(final String name, final Metamodel metamodel) {
internalMetaModels.put(name, metamodel);
clearModelCaches();
resetJITCompiler();
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public synchronized void registerInputModel(final String name, final Model model) {
internalInputModels.put(name, model);
clearModelCaches();
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public synchronized void registerInOutModel(final String name, final Model model) {
internalInoutModels.put(name, model);
clearModelCaches();
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public synchronized void registerOutputModel(final String name, final Model model) {
internalOutputModels.put(name, model);
clearModelCaches();
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void clearModels() {
internalInputModels.clear();
internalInoutModels.clear();
internalOutputModels.clear();
clearModelCaches();
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Metamodel getMetaModel(final Resource resource) {
if (!modelCacheInit) {
cacheModels();
}
return (resource == null) ? null : metaModelOf.get(resource);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueForSet(final EStructuralFeature feature, final EObject object, final Object value, final StackFrame frame) {
setQueue.offer(new QueueEntry(frame) {
@Override
protected void perform() {
EMFTVMUtil.set(ExecEnvImpl.this, object, feature, value);
}
});
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueForSet(final Field field, final Object object, final Object value, final StackFrame frame) {
setQueue.offer(new QueueEntry(frame) {
@Override
protected void perform() {
field.setValue(object, value);
}
});
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueXmiIDForSet(final EObject object, final Object value, final StackFrame frame) {
setQueue.offer(new QueueEntry(frame) {
@Override
protected void perform() {
final Resource resource = object.eResource();
((XMIResource) resource).setID(object, value.toString());
}
});
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueForAdd(final EStructuralFeature feature, final EObject object, final Object value, final int index,
final StackFrame frame) {
setQueue.offer(new QueueEntry(frame) {
@Override
protected void perform() {
EMFTVMUtil.add(ExecEnvImpl.this, object, feature, value, index);
}
});
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueForAdd(final Field field, final Object object, final Object value, final int index, final StackFrame frame) {
setQueue.offer(new QueueEntry(frame) {
@Override
protected void perform() {
if (object instanceof EObject) {
final EObject eo = (EObject) object;
if (getInputModelOf(eo) != null) {
throw new IllegalArgumentException(String.format(
"Cannot add to properties of %s, as it is contained in an input model",
EMFTVMUtil.toPrettyString(eo, ExecEnvImpl.this)));
}
if (getOutputModelOf(eo) != null) {
throw new IllegalArgumentException(String.format(
"Adding to transient field %s of %s, which cannot be read back as %1s is contained in an output model",
field.getName(), EMFTVMUtil.toPrettyString(eo, ExecEnvImpl.this)));
}
}
field.addValue(object, value, index, frame);
}
});
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueXmiIDForAdd(final EObject object, final Object value, final int index, final StackFrame frame) {
setQueue.offer(new QueueEntry(frame) {
@Override
protected void perform() {
final Resource resource = object.eResource();
if (((XMIResource) resource).getID(object) != null) {
throw new IllegalArgumentException(String.format("Cannot add %s to field %s::%s: maximum multiplicity of 1 reached",
value, EMFTVMUtil.toPrettyString(object, ExecEnvImpl.this), EMFTVMUtil.XMI_ID_FEATURE));
}
if (index > 0) {
throw new IndexOutOfBoundsException(String.valueOf(index));
}
((XMIResource) resource).setID(object, value.toString());
}
});
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueForRemove(final EStructuralFeature feature, final EObject object, final Object value, final StackFrame frame) {
setQueue.offer(new QueueEntry(frame) {
@Override
protected void perform() {
EMFTVMUtil.remove(ExecEnvImpl.this, object, feature, value);
}
});
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueForRemove(final Field field, final Object object, final Object value, final StackFrame frame) {
setQueue.offer(new QueueEntry(frame) {
@Override
protected void perform() {
if (object instanceof EObject) {
final EObject eo = (EObject) object;
if (getInputModelOf(eo) != null) {
throw new IllegalArgumentException(String.format(
"Cannot remove from properties of %s, as it is contained in an input model",
EMFTVMUtil.toPrettyString(eo, ExecEnvImpl.this)));
}
if (getOutputModelOf(eo) != null) {
throw new IllegalArgumentException(String.format(
"Removing from transient field %s of %s, which cannot be read back as %1s is contained in an output model",
field.getName(), EMFTVMUtil.toPrettyString(eo, ExecEnvImpl.this)));
}
}
field.removeValue(object, value, frame);
}
});
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueXmiIDForRemove(final EObject object, final Object value, final StackFrame frame) {
setQueue.offer(new QueueEntry(frame) {
@Override
protected void perform() {
final Resource resource = object.eResource();
final XMIResource xmiRes = (XMIResource) resource;
final Object xmiID = xmiRes.getID(object);
if (xmiID == null ? value == null : xmiID.equals(value)) {
xmiRes.setID(object, null);
}
}
});
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void setQueue() {
try {
while (!setQueue.isEmpty()) {
setQueue.poll().process();
}
} finally {
setQueue.clear();
}
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueForRemap(final EObject source, final EObject target, final StackFrame frame) {
if (remapQueue.containsKey(source)) {
throw new IllegalArgumentException(String.format("Source element %s already queued for remap",
EMFTVMUtil.toPrettyString(source, this)));
}
remapQueue.put(source, new RemapEntry(source, target, frame));
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void remapQueue() {
if (remapQueue.isEmpty()) {
return;
}
try {
for (final Model m : getInoutModels().values()) {
final List<EObject> eObjects = new ArrayList<EObject>();
for (final EObject o : new ResourceIterable(m.getResource())) {
eObjects.add(o);
}
// Prevent ConcurrentModificationException by using eObjects copy
for (final EObject o : eObjects) {
// Skip remapping on objects queued for deletion
if (deletionQueue.containsKey(o)) {
continue;
}
for (final EReference ref : o.eClass().getEAllReferences()) {
// Only change changeable references that are not the reverse of a containment reference
if (ref.isChangeable() && !ref.isContainer()) {
final Object val = o.eGet(ref);
if (val instanceof Collection<?>) {
if (val instanceof List<?>) {
final List<?> listVal = (List<?>) val;
for (int index = 0; index < listVal.size(); index++) {
final Object source = listVal.get(index);
if (remapQueue.containsKey(source)) {
remapQueue.get(source).process(o, ref, index);
}
}
} else {
final List<RemapEntry> remapEntries = new ArrayList<RemapEntry>();
for (final Object source : (Collection<?>) val) {
if (remapQueue.containsKey(source)) {
remapEntries.add(remapQueue.get(source));
}
}
for (final RemapEntry remapEntry : remapEntries) {
remapEntry.process(o, ref, -1);
}
}
} else {
if (remapQueue.containsKey(val)) {
remapQueue.get(val).process(o, ref);
}
}
}
}
}
}
} finally {
remapQueue.clear();
}
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Map<String, Metamodel> getMetaModels() {
if (metaModels == null) {
metaModels = Collections.unmodifiableMap(internalMetaModels);
}
return metaModels;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Map<String, Model> getInputModels() {
if (inputModels == null) {
inputModels = Collections.unmodifiableMap(internalInputModels);
}
return inputModels;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Map<String, Model> getInoutModels() {
if (inoutModels == null) {
inoutModels = Collections.unmodifiableMap(internalInoutModels);
}
return inoutModels;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Map<String, Model> getOutputModels() {
if (outputModels == null) {
outputModels = Collections.unmodifiableMap(internalOutputModels);
}
return outputModels;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Module loadModule(final ModuleResolver resolver, final String name) {
return loadModule(resolver, name, true);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public synchronized Module loadModule(final ModuleResolver resolver, final String name, final boolean validate) {
resetJITCompiler();
try {
//detect cyclic imports w.r.t. redefinition
if (internalModules.containsKey(name)) {
if (!loadedModules.contains(name)) {
ATLLogger.warning(String.format(
"Cyclic import of module %s detected; element redefinition will not work",
name));
}
return internalModules.get(name);
}
final Module module = resolver.resolveModule(name);
internalModules.put(name, module);
resolveImports(module, resolver, validate);
for (final Feature f : module.getFeatures()) {
registerFeature(f);
}
for (final Rule r : module.getRules()) {
registerRule(r);
}
// Re-resolve all super-rules, because they may have been redefined
for (final Rule r : getRules()) {
resolveSuperRules(r);
}
if (validate && module.eResource() != null) { // skip built-in native modules
final Object invalidObject = validate(module);
if (invalidObject != null) {
throw new VMException(null, String.format("Byte code validation of %s failed", invalidObject));
}
}
// Bug 426154: validation triggers partial rule state compilation, so always reset:
for (final Rule r : getRules()) {
r.resetState();
}
setRuleStateCompiled(false);
loadedModules.add(name);
return module;
} catch (final Exception e) {
throw new VMException(null, String.format(
"Error during module loading: %s",
e.getMessage()), e);
}
}
/**
* Validates the bytecode of <code>module</code>.
* @param module the module to validate
* @return <code>null</code> if <code>module</code> is valid, otherwise the first invalid object
*/
private Object validate(final Module module) {
final Diagnostic diag = Diagnostician.INSTANCE.validate(module);
if (diag.getSeverity() != Diagnostic.OK) {
return diag;
}
final Model mmodel = EmftvmFactory.eINSTANCE.createModel();
mmodel.setResource(module.eResource());
for (final EObject eObject : mmodel.allInstancesOf(EmftvmPackage.eINSTANCE.getCodeBlock())) {
final CodeBlock cb = (CodeBlock) eObject;
if (!cbStackValidator.validate(cb)) {
return cb;
}
for (final Instruction i : cb.getCode()) {
if (!instrStackValidator.validate(i)) {
return i;
}
}
}
return null;
}
/**
* Resolves the imports list of module.
* @param module
* @param resolver
* @param validate
*/
private void resolveImports(final Module module, final ModuleResolver resolver, final boolean validate) {
final EList<Module> eImports = module.getEImports();
for (final String imp : module.getImports()) {
final Module impModule = loadModule(resolver, imp, validate);
eImports.add(impModule);
}
}
/**
* Registers a {@link Feature} into this {@link ExecEnv}.
* @param feature the {@link Feature} to register
*/
protected void registerFeature(final Feature feature) {
feature.setEContext(findEClassifier(feature.getContextModel(), feature.getContext()));
feature.setEType(findEClassifier(feature.getTypeModel(), feature.getType()));
switch (feature.eClass().getClassifierID()) {
case EmftvmPackage.FIELD:
fieldContainer.registerField((Field)feature);
break;
case EmftvmPackage.OPERATION:
registerOperation((Operation)feature);
break;
default:
throw new IllegalArgumentException(String.format("Feature of class %s not supported", feature.eClass()));
}
}
/**
* Registers op in the corresponding lookup table.
* @param op
*/
private void registerOperation(final Operation op) {
if (op.isStatic()) {
// main() and init() are special, and cannot be invoked programmatically
if (EMFTVMUtil.MAIN_OP_NAME.equals(op.getName()) && op.getParameters().isEmpty()) {
mainChain.add(op);
} else if (EMFTVMUtil.INIT_OP_NAME.equals(op.getName()) && op.getParameters().isEmpty()) {
initChain.add(op);
} else {
registerOperationIn(op, staticOperations);
}
} else {
registerOperationIn(op, operations);
}
}
/**
* Registers op in the corresponding lookup table.
* @param op
* @param reg
*/
@SuppressWarnings("unchecked")
private void registerOperationIn(final Operation op, final Map<String, Map<Integer, TypeMap<Object, Object>>> reg) {
final EList<Parameter> args = op.getParameters();
final Integer argCount = args.size();
final String opname = op.getName();
// register operation in lookup table
Map<Integer, TypeMap<Object, Object>> argcountOpsMap = reg.get(opname);
if (argcountOpsMap == null) {
argcountOpsMap = new HashMap<Integer, TypeMap<Object,Object>>();
reg.put(opname, argcountOpsMap);
}
final EClassifier ectx = op.getEContext();
assert ectx != null;
final Object ctx = EMFTVMUtil.getRegistryType(ectx);
TypeMap<Object, Object> ctxMap = argcountOpsMap.get(argCount);
if (ctxMap == null) {
ctxMap = new TypeHashMap<Object, Object>();
argcountOpsMap.put(argCount, ctxMap);
}
if (argCount == 0) {
ctxMap.put(ctx, op);
} else {
TypeMap<Object, Object> opsMap = (TypeMap<Object, Object>)ctxMap.get(ctx);
if (opsMap == null) {
opsMap = new TypeHashMap<Object, Object>();
ctxMap.put(ctx, opsMap);
}
registerOperationByArgTypes(op, opsMap, getTypesOfParameters(op.getParameters()), 0);
}
}
/**
* Retrieves the registry types of the elements of <pre>eList</pre>.
* @param eList
* @return the registry types of elements
*/
private Object[] getTypesOfParameters(final EList<Parameter> eList) {
final Object[] types = new Object[eList.size()];
for (int i = 0; i < types.length; i++) {
final Parameter par = eList.get(i);
par.setEType(findEClassifier(par.getTypeModel(), par.getType()));
types[i] = EMFTVMUtil.getRegistryType(par.getEType());
}
return types;
}
/**
* Registers op in reg.
* @param op
* @param reg the current depth registry
* @param argTypes the argument types to use for registering
* @param argIndex the current argument index for the current depth registry
*/
@SuppressWarnings("unchecked")
private static void registerOperationByArgTypes(final Operation op, final TypeMap<Object, Object> reg, final Object[] argTypes, final int argIndex) {
final int argCount = argTypes.length;
assert argIndex >= 0 && argIndex < argCount;
final Object regType = argTypes[argIndex];
if (argIndex < argCount - 1) {
TypeMap<Object, Object> nestedReg = (TypeMap<Object, Object>)reg.get(regType);
if (nestedReg == null) {
nestedReg = new TypeHashMap<Object, Object>();
reg.put(regType, nestedReg);
}
registerOperationByArgTypes(op, nestedReg, argTypes, argIndex + 1);
} else {
reg.put(regType, op);
}
}
/**
* Checks whether the types of <pre>first</pre> are more specific than the types of <pre>second</pre>.
* @param first the first list of parameters to compare
* @param second the second list of parameters to compare
* @param index the comparison index (start at 0)
* @return <code>true</code> iff the types of <pre>first</pre> are more specific than the types of <pre>second</pre>
*/
private static boolean isMoreSpecific(
final EList<Parameter> first,
final EList<Parameter> second,
final int index) {
assert first.size() == second.size();
final EClassifier f = first.get(index).getEType();
final EClassifier s = second.get(index).getEType();
assert f != null;
assert s != null;
if (f == s && index < first.size() - 1) {
return isMoreSpecific(first, second, index + 1);
}
if (f instanceof EClass && s instanceof EClass) {
return ((EClass)s).isSuperTypeOf((EClass)f);
} else {
assert f instanceof EClass || f.getInstanceClass() != null;
assert s instanceof EClass || s.getInstanceClass() != null;
final Class<?> fCls = f.getInstanceClass() == null ? EObject.class : f.getInstanceClass();
final Class<?> sCls = s.getInstanceClass() == null ? EObject.class : s.getInstanceClass();
assert fCls != null;
assert sCls != null;
if (fCls == sCls && index < first.size() - 1) {
return isMoreSpecific(first, second, index + 1);
}
return sCls.isAssignableFrom(fCls);
}
}
/**
* Checks whether the types of <pre>first</pre> are more specific than the types of <pre>second</pre>.
* @param first the first operation to compare
* @param second the second operation to compare
* @return <code>true</code> iff the types of <pre>first</pre> are more specific than the types of <pre>second</pre>
*/
private static boolean isMoreSpecific(
final Operation first,
final Operation second) {
final EClassifier f = first.getEContext();
final EClassifier s = second.getEContext();
assert f != null;
assert s != null;
if (f == s) {
return isMoreSpecific(first.getParameters(), second.getParameters(), 0);
}
if (f instanceof EClass && s instanceof EClass) {
return ((EClass) s).isSuperTypeOf((EClass)f);
} else {
assert f instanceof EClass || f.getInstanceClass() != null;
assert s instanceof EClass || s.getInstanceClass() != null;
final Class<?> fCls = f.getInstanceClass() == null ? EObject.class : f.getInstanceClass();
final Class<?> sCls = s.getInstanceClass() == null ? EObject.class : s.getInstanceClass();
assert fCls != null;
assert sCls != null;
if (fCls == sCls) {
return isMoreSpecific(first.getParameters(), second.getParameters(), 0);
}
return sCls.isAssignableFrom(fCls);
}
}
/**
* Registers a {@link Rule} into this {@link ExecEnv}.
* @param rule the {@link Rule} to register
*/
protected void registerRule(final Rule r) {
//TODO check rule redefinition consistency? (types, mapsTo, ...)
final String rName = r.getName();
if (rules.containsKey(rName)) {
final Rule oldRule = rules.get(rName);
if (r.getMode() != oldRule.getMode()) {
throw new IllegalArgumentException(String.format(
"Rule %s with mode %s cannot redefine existing rule with mode %s",
rName, r.getMode(), oldRule.getMode()));
}
}
rules.put(rName, r);
for (final RuleElement re : r.getInputElements()) {
resolveRuleElement(re);
}
for (final OutputRuleElement re : r.getOutputElements()) {
resolveRuleElement(re);
if (!r.isAbstract()) {
final EClassifier eType = re.getEType();
if (eType instanceof EClass && ((EClass)eType).isAbstract()) {
throw new VMException(null, String.format("Non-abstract %s cannot have output elements of an abstract type: \"%s\"", r, re));
}
}
}
for (final Field field : r.getFields()) {
field.setEContext(findEClassifier(field.getContextModel(), field.getContext()));
field.setEType(findEClassifier(field.getTypeModel(), field.getType()));
r.registerField(field);
}
}
/**
* Resolves type references in <pre>re</pre>.
* @param re the rule element to resolve references for
* @throws IllegalArgumentException when a reference cannot be resolved
*/
private void resolveRuleElement(final RuleElement re) {
re.setEType(findEClassifier(re.getTypeModel(), re.getType()));
}
/**
* Resolves the super rule references in rule.
* @param rule the rule to resolve references for
*/
private void resolveSuperRules(final Rule rule) {
final EList<Rule> eSuperRules = rule.getESuperRules();
eSuperRules.clear();
for (final String superRuleName : rule.getSuperRules()) {
final Rule superRule = findRule(superRuleName);
if (superRule == null) {
throw new IllegalArgumentException(String.format(
"Super-rule %s of %s is not found in any module loaded before %s",
superRuleName, rule.getName(), rule.getModule()));
}
//check rule type consistency
if (superRule.getMode() != rule.getMode()) {
throw new IllegalArgumentException(String.format(
"Rule %s with mode %s cannot inherit from super-rule %s with mode %s",
rule.getName(), rule.getMode(), superRule.getName(), superRule.getMode()));
}
//check type consistency of rule element declarations
for (final OutputRuleElement sre : superRule.getOutputElements()) {
for (final OutputRuleElement re : rule.getOutputElements()) {
if (sre.getName().equals(re.getName())) {
if (!((EClass)sre.getEType()).isSuperTypeOf((EClass)re.getEType())) {
throw new IllegalArgumentException(String.format(
"Output element %s of type %s in rule %s is not compatible with element %s of type %s in super-rule %s",
re.getName(),
EMFTVMUtil.toPrettyString(re.getEType(), this),
rule.getName(),
sre.getName(),
EMFTVMUtil.toPrettyString(sre.getEType(), this),
superRule.getName()));
}
}
}
}
eSuperRules.add(superRule);
}
}
/**
* Resolves model references for a {@link Rule}.
* @param rule the {@link Rule} to resolve
*/
protected void resolveRuleModels(final Rule r) {
final Map<String, Model> inModels = new LinkedHashMap<String, Model>(getInputModels());
inModels.putAll(getInoutModels());
for (final RuleElement re : r.getInputElements()) {
resolveRuleElementModels(re, inModels);
}
final Map<String, Model> outModels = new LinkedHashMap<String, Model>(getOutputModels());
outModels.putAll(getInoutModels());
for (final OutputRuleElement re : r.getOutputElements()) {
resolveRuleElementModels(re, outModels);
}
if (r.getMode() != RuleMode.MANUAL) {
r.compileIterables(this);
}
}
/**
* Resolves model references in <pre>re</pre>.
* @param re the rule element to resolve references for
* @param models the map of models resolve from
* @throws IllegalArgumentException when a reference cannot be resolved
*/
private void resolveRuleElementModels(final RuleElement re, final Map<String, Model> models) {
re.setEType(findEClassifier(re.getTypeModel(), re.getType()));
final EList<Model> eModels = re.getEModels();
eModels.clear();
for (final String modelName : re.getModels()) {
final Model model = models.get(modelName);
if (model == null) {
throw new IllegalArgumentException(String.format("Model %s not found for %s", modelName, re));
}
eModels.add(model);
}
}
/**
* Clears model references for a {@link Rule}.
* @param rule the {@link Rule} to resolve
*/
protected void clearRuleModels(final Rule r) {
for (final RuleElement re : r.getInputElements()) {
re.getEModels().clear();
}
for (final OutputRuleElement re : r.getOutputElements()) {
re.getEModels().clear();
}
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
@SuppressWarnings("unchecked")
public Operation findOperation(final Object context, final String name, final Object[] parameterTypes) {
Operation op = null;
final Map<Integer, TypeMap<Object, Object>> argcountOpsMap = operations.get(name);
if (argcountOpsMap != null) {
// There are operations with the given name
final int argCount = parameterTypes.length;
final TypeMap<Object, Object> ctxMap = argcountOpsMap.get(argCount);
if (ctxMap != null) {
// There are operations with argCount arguments
// First try to find with direct types
TypeMap<Object, Object> argMap = (TypeMap<Object, Object>)ctxMap.get(context);
if (argMap != null) {
op = findOperationDirect(argMap, parameterTypes, 0);
}
// Fall back to full resolving algorithm
if (op == null) {
final Set<Object> ctxKeys = new HashSet<Object>();
ctxMap.findAllKeys(context, ctxKeys);
final Set<Operation> ops = new LinkedHashSet<Operation>();
for (final Object ctxKey : ctxKeys) {
// There are operations defined on the given context type
argMap = (TypeMap<Object, Object>)ctxMap.get(ctxKey);
findOperations(argMap, parameterTypes, ops, 0);
}
op = findMostSpecificOperation(ops);
if (op != null) {
// Now register directly under context type
argMap = (TypeMap<Object, Object>)ctxMap.get(context);
if (argMap == null) {
argMap = new TypeHashMap<Object, Object>();
ctxMap.put(context, argMap);
}
registerOperationByArgTypes(op, argMap, parameterTypes, 0);
}
}
}
}
return op;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Operation findOperation(final Object context, final String name) {
Operation op = null;
final Map<Integer, TypeMap<Object, Object>> argcountOpsMap = operations.get(name);
if (argcountOpsMap != null) {
// There are operations with the given name
final TypeMap<Object, Object> ctxMap = argcountOpsMap.get(0);
if (ctxMap != null) {
// There are operations with 0 arguments
// First try to find with direct type
op = (Operation)ctxMap.get(context);
// Fall back to full resolving algorithm
if (op == null) {
final Object ctxKey = ctxMap.findKey(context);
if (ctxKey != null) {
// There is an operation with the given context type
op = (Operation)ctxMap.get(ctxKey);
assert op != null;
// Now register directly under context type
ctxMap.put(context, op);
}
}
}
}
return op;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
@SuppressWarnings("unchecked")
public Operation findOperation(final Object context, final String name, final Object parameterType) {
Operation op = null;
final Map<Integer, TypeMap<Object, Object>> argcountOpsMap = operations.get(name);
if (argcountOpsMap != null) {
// There are operations with the given name
final TypeMap<Object, Object> ctxMap = argcountOpsMap.get(1);
if (ctxMap != null) {
// There are operations with 1 argument
// First try to find with direct types
TypeMap<Object, Object> argMap = (TypeMap<Object, Object>)ctxMap.get(context);
if (argMap != null) {
op = (Operation)argMap.get(parameterType);
}
// Fall back to full resolving algorithm
if (op == null) {
final Set<Object> ctxKeys = new HashSet<Object>();
ctxMap.findAllKeys(context, ctxKeys);
final Set<Operation> ops = new LinkedHashSet<Operation>();
for (final Object ctxKey : ctxKeys) {
// There are operations defined on the given context type
argMap = (TypeMap<Object, Object>)ctxMap.get(ctxKey);
final Set<Object> argTypeKeys = new HashSet<Object>();
argMap.findAllKeys(parameterType, argTypeKeys);
for (final Object argTypeKey : argTypeKeys) {
// There are operations defined on all given parameter types
ops.add((Operation)argMap.get(argTypeKey));
}
}
op = findMostSpecificOperation(ops);
if (op != null) {
// Now register directly under context type
argMap = (TypeMap<Object, Object>)ctxMap.get(context);
if (argMap == null) {
argMap = new TypeHashMap<Object, Object>();
ctxMap.put(context, argMap);
}
argMap.put(parameterType, op);
}
}
}
}
return op;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public boolean hasOperation(final String name, final int argcount) {
final Map<Integer, TypeMap<Object, Object>> argcountOpsMap = operations.get(name);
if (argcountOpsMap != null) { // There are operations with the given name
return argcountOpsMap.get(argcount) != null;
}
return false;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
@SuppressWarnings("unchecked")
public Operation findStaticOperation(final Object context, final String name, final Object[] parameterTypes) {
Operation op = null;
final Map<Integer, TypeMap<Object, Object>> argcountOpsMap = staticOperations.get(name);
if (argcountOpsMap != null) {
// There are operations with the given name
final int argCount = parameterTypes.length;
final TypeMap<Object, Object> ctxMap = argcountOpsMap.get(argCount);
if (ctxMap != null) {
// There are operations with argCount arguments
// Static operations must be defined in exact context type
final TypeMap<Object, Object> argMap = (TypeMap<Object, Object>)ctxMap.get(context);
if (argMap != null) {
// First try to find with direct types
op = findOperationDirect(argMap, parameterTypes, 0);
// Fall back to full resolving algorithm
if (op == null) {
final Set<Operation> ops = new LinkedHashSet<Operation>();
findOperations(argMap, parameterTypes, ops, 0);
op = findMostSpecificOperation(ops);
if (op != null) {
// Now register directly under context type
registerOperationByArgTypes(op, argMap, parameterTypes, 0);
}
}
}
}
}
return op;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Operation findStaticOperation(final Object context, final String name) {
Operation op = null;
final Map<Integer, TypeMap<Object, Object>> argcountOpsMap = staticOperations.get(name);
if (argcountOpsMap != null) {
// There are operations with the given name
final TypeMap<Object, Object> ctxMap = argcountOpsMap.get(0);
if (ctxMap != null) {
// There are operations with 0 arguments
// Static operations must be defined in exact context type
op = (Operation)ctxMap.get(context);
}
}
return op;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
@SuppressWarnings("unchecked")
public Operation findStaticOperation(final Object context, final String name, final Object parameterType) {
Operation op = null;
final Map<Integer, TypeMap<Object, Object>> argcountOpsMap = staticOperations.get(name);
if (argcountOpsMap != null) {
// There are operations with the given name
final TypeMap<Object, Object> ctxMap = argcountOpsMap.get(1);
if (ctxMap != null) {
// There are operations with 1 argument
// Static operations must be defined in exact context type
TypeMap<Object, Object> argMap = (TypeMap<Object, Object>)ctxMap.get(context);
if (argMap != null) {
// First try to find with direct types
op = (Operation)argMap.get(parameterType);
// Fall back to full resolving algorithm
if (op == null) {
final Set<Operation> ops = new LinkedHashSet<Operation>();
final Set<Object> argTypeKeys = new HashSet<Object>();
argMap.findAllKeys(parameterType, argTypeKeys);
for (final Object argTypeKey : argTypeKeys) {
// There are operations defined on all given parameter types
ops.add((Operation)argMap.get(argTypeKey));
}
op = findMostSpecificOperation(ops);
if (op != null) {
// Now register directly under context type
argMap = (TypeMap<Object, Object>)ctxMap.get(context);
if (argMap == null) {
argMap = new TypeHashMap<Object, Object>();
ctxMap.put(context, argMap);
}
argMap.put(parameterType, op);
}
}
}
}
}
return op;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public boolean hasStaticOperation(final String name, final int argcount) {
final Map<Integer, TypeMap<Object, Object>> argcountOpsMap = staticOperations.get(name);
if (argcountOpsMap != null) { // There are operations with the given name
return argcountOpsMap.get(argcount) != null;
}
return false;
}
/**
* Attempts to find an operation using direct type dispatch, ignoring any supertypes.
* @param typeMap
* @param parameterTypes
* @param argIndex
* @return the operation, or <code>null</code>
*/
@SuppressWarnings("unchecked")
private static Operation findOperationDirect(final TypeMap<Object, Object> typeMap, final Object[] parameterTypes,
final int argIndex) {
final int argCount = parameterTypes.length;
assert argIndex >= 0 && argIndex < argCount;
final Object argType = parameterTypes[argIndex];
if (argIndex < argCount - 1) {
final TypeMap<Object, Object> nestedTypeMap = (TypeMap<Object, Object>)typeMap.get(argType);
if (nestedTypeMap != null) {
return findOperationDirect(nestedTypeMap, parameterTypes, argIndex + 1);
}
return null;
} else {
return (Operation)typeMap.get(argType);
}
}
/**
* Finds all operations that correspond to the given types, and adds them to <pre>ops</pre>.
* @param typeMap
* @param parameterTypes
* @param ops
* @param argIndex
*/
@SuppressWarnings("unchecked")
private static void findOperations(final TypeMap<Object, Object> typeMap, final Object[] parameterTypes,
final Set<Operation> ops, final int argIndex) {
final int argCount = parameterTypes.length;
assert argIndex >= 0 && argIndex < argCount;
final Object argType = parameterTypes[argIndex];
final Set<Object> argTypeKeys = new HashSet<Object>();
typeMap.findAllKeys(argType, argTypeKeys);
if (argIndex < argCount - 1) {
for (final Object argTypeKey : argTypeKeys) {
// There are operations defined on the given parameter type so far...
final TypeMap<Object, Object> nestedTypeMap = (TypeMap<Object, Object>)typeMap.get(argTypeKey);
findOperations(nestedTypeMap, parameterTypes, ops, argIndex + 1);
}
} else {
for (final Object argTypeKey : argTypeKeys) {
// There are operations defined on all given parameter types
ops.add((Operation)typeMap.get(argTypeKey));
}
}
}
/**
* Finds the most-specific operation from <pre>ops</pre>, based on context/argument types
* @param ops
* @return Most-specific operation from <pre>ops</pre>, based on context/argument types
* @throws DuplicateEntryException when more than one operation was found to be most-specific
*/
private static Operation findMostSpecificOperation(final Collection<Operation> ops) {
Operation msOp = null;
final Set<Operation> conflicts = new HashSet<Operation>();
// First iteration to find most-specific op
for (final Operation op : ops) {
if (msOp == null || isMoreSpecific(op, msOp)) {
msOp = op;
} else if (!isMoreSpecific(msOp, op)) {
conflicts.add(op); //temporary conflict situation -- may not have found most-specific yet
}
}
assert msOp != null || (ops.isEmpty() && conflicts.isEmpty());
// Second iteration to resolve conflicts
for (final Operation op : conflicts) {
if (!isMoreSpecific(msOp, op)) {
throw new DuplicateEntryException(String.format(
"More than one operation found for given context/arguments: %s and %s",
msOp, op));
}
}
return msOp;
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Field findField(final Object context, final String name) {
return fieldContainer.findField(context, name);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public boolean hasField(final String name) {
return fieldContainer.hasField(name);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Field findStaticField(final Object context, final String name) {
return fieldContainer.findStaticField(context, name);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public boolean hasStaticField(final String name) {
return fieldContainer.hasStaticField(name);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Rule findRule(final String name) {
return rules.get(name);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Object findType(final String modelName, final String typeName) throws ClassNotFoundException {
if (EMFTVMUtil.NATIVE.equals(modelName)) {
return NativeTypes.findType(typeName);
} else {
final Metamodel mm = getMetaModels().get(modelName);
if (mm == null) {
throw new IllegalArgumentException(String.format("Metamodel %s not found", modelName));
}
return mm.findType(typeName);
}
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public synchronized Object run(final TimingData timingData) {
Object result = null;
try {
assert deletionQueue.isEmpty();
if (!isRuleStateCompiled()) {
for (final Rule r : getRules()) {
r.compileState(this); // compile internal state for all registered rules
}
}
for (final Rule r : getRules()) {
resolveRuleModels(r);
}
final Iterator<Operation> mains = mainChain.iterator();
if (!mains.hasNext()) {
throw new UnsupportedOperationException(String.format("Operation %s not found", EMFTVMUtil.MAIN_OP_NAME));
}
// run all init() operations
currentPhase = RuleMode.MANUAL;
for (final Operation init: initChain) {
final CodeBlock cb = init.getBody();
if (cb.getStackLevel() > 0) {
result = cb.execute(new StackFrame(this, cb));
} else {
cb.execute(new StackFrame(this, cb));
}
}
// run all automatic rules before main
final StackFrame rootFrame = new StackFrame(this, mainChain.get(mainChain.size() - 1).getBody());
currentPhase = RuleMode.AUTOMATIC_SINGLE;
matchAllSingle(rootFrame, timingData);
currentPhase = RuleMode.AUTOMATIC_RECURSIVE;
matchAllRecursive(rootFrame, timingData);
// run all main() operations
currentPhase = RuleMode.MANUAL;
while (mains.hasNext()) {
final CodeBlock cb = mains.next().getBody();
if (cb.getStackLevel() > 0) {
result = cb.execute(new StackFrame(this, cb));
} else {
cb.execute(new StackFrame(this, cb));
}
}
// process any leftover queue elements
setQueue();
remapQueue();
deleteQueue();
if (monitor != null) {
monitor.terminated();
}
} catch (final VMException e) {
if (monitor != null) {
monitor.error(e.getFrame(), e.getLocalizedMessage(), e);
monitor.terminated();
}
throw e;
} finally {
currentPhase = null;
this.matches = null;
this.traces = null;
this.uniqueResults = null;
fieldContainer.clear();
for (final Rule r : getRules()) {
r.clearFields();
clearRuleModels(r);
}
assert findStaticField(eClass(), "matches").getStaticValue() == null;
assert findStaticField(eClass(), "traces").getStaticValue() == null;
}
return result;
}
/**
* Finds the {@link EClassifier} for the given (meta-)<pre>modelName</pre> and <pre>typeName</pre>.
* @param modelName the name under which the metamodel that contains the type is registered
* @param typeName the type/metaclass name (may be fully qualified using '<pre>::</pre>')
* @return the type/metaclass, or <code>null</code> if not found
*/
private EClassifier findEClassifier(final String modelName, final String typeName) {
try {
final Object type = findType(modelName, typeName);
if (type instanceof Class<?>) {
// Wrap Java class
final EDataType dt = EcoreFactory.eINSTANCE.createEDataType();
dt.setName(typeName);
dt.setInstanceClass((Class<?>)type);
return dt;
} else {
return (EClassifier)type;
}
} catch (final ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Caches run-time models in various lookup tables.
*/
protected synchronized void cacheModels() {
cacheMetaModels(getMetaModels(), metaModelOf);
cacheModels(getInputModels(), inputModelOf);
cacheModels(getOutputModels(), outputModelOf);
cacheModels(getInoutModels(), inoutModelOf);
cacheModels(getMetaModels(), null);
modelCacheInit = true;
}
/**
* Clears the model caches.
*/
protected synchronized void clearModelCaches() {
metaModelOf.clear();
modelOf.clear();
inputModelOf.clear();
inoutModelOf.clear();
outputModelOf.clear();
metaModelId.clear();
modelId.clear();
modelCacheInit = false;
}
/**
* Caches <code>models</code> in various lookup tables.
* @param models
* @param thisModelOf local resource to model map
*/
private void cacheModels(final Map<String, ? extends Model> models, final Map<Resource, Model> thisModelOf) {
for (final Entry<String, ? extends Model> entry : models.entrySet()) {
final String id = entry.getKey();
final Model model = entry.getValue();
modelOf.put(model.getResource(), model);
if (thisModelOf != null) {
thisModelOf.put(model.getResource(), model);
}
modelId.put(model, id);
}
}
/**
* Caches <code>models</code> in various lookup tables.
* @param models
* @param thisModelOf local resource to model map
*/
private void cacheMetaModels(final Map<String, ? extends Metamodel> models, final Map<Resource, Metamodel> thisModelOf) {
for (final Entry<String, ? extends Metamodel> entry : models.entrySet()) {
final String id = entry.getKey();
final Metamodel model = entry.getValue();
if (thisModelOf != null) {
thisModelOf.put(model.getResource(), model);
}
metaModelId.put(model, id);
}
}
/**
* Matches all {@link RuleMode#AUTOMATIC_SINGLE} rules.
* @param frame the stack frame context
* @param timingData the timing data object to update
*/
private void matchAllSingle(final StackFrame frame, final TimingData timingData) {
final List<Rule> rules = getRules();
// Match automatic single rules
final Set<Rule> matchedRules = new LinkedHashSet<Rule>();
boolean match;
do {
match = false;
for (final Rule rule : rules) {
// Only match rules for which all super-rules have already been matched
if (!matchedRules.contains(rule) && matchedRules.containsAll(rule.getESuperRules())) {
if (rule.matchSingle(frame)) {
match = true;
matchedRules.add(rule); // only add rules that match
}
}
}
} while (match);
// Create traces for automatic single rules
for (final Rule rule : matchedRules) {
rule.createTraces(frame);
}
if (timingData != null) timingData.finishMatch();
// Apply rules
for (final Rule rule : matchedRules) {
rule.apply(frame);
}
setQueue();
remapQueue();
if (timingData != null) timingData.finishApply();
// Run post-apply
for (final Rule rule : matchedRules) {
rule.postApply(frame);
}
setQueue();
remapQueue();
deleteQueue();
if (timingData != null) timingData.finishPostApply();
}
/**
* Matches all {@link RuleMode#AUTOMATIC_RECURSIVE} rules.
* @param frame the stack frame context
* @param timingData the timing data object to update
*/
private void matchAllRecursive(final StackFrame frame, final TimingData timingData) {
final List<Rule> rules = getRules();
final Set<Rule> matchedRules = new LinkedHashSet<Rule>();
boolean outerMatch;
do {
outerMatch = false;
// Match automatic recursive rules
matchedRules.clear();
boolean match;
MATCHER:
do {
match = false;
for (final Rule rule : rules) {
// Only match rules for which all super-rules have already been matched
if (!matchedRules.contains(rule) && matchedRules.containsAll(rule.getESuperRules())) {
final boolean[] matchResult = rule.matchRecursive(frame);
if (matchResult[1]) { // Guaranteed final match
outerMatch = true;
matchedRules.add(rule);
break MATCHER;
} else if (matchResult[0]) {
match = true;
matchedRules.add(rule);
outerMatch |= !rule.isAbstract();
}
}
}
} while (match);
for (final Rule rule : matchedRules) {
if (rule.applyFirst(frame)) {
break;
}
}
} while (outerMatch);
if (timingData != null) {
timingData.finishRecursive();
}
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public LazyList<Rule> getRules() {
return new LazyList<Rule>(rules.values());
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Model getModelOf(final EObject object) {
if (!modelCacheInit) {
cacheModels();
}
final Resource r = object.eResource();
return (r == null) ? null : modelOf.get(r);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public String getModelID(final Model model) {
if (!modelCacheInit) {
cacheModels();
}
return (model == null) ? null : modelId.get(model);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public String getMetaModelID(final Metamodel metamodel) {
if (!modelCacheInit) {
cacheModels();
}
return (metamodel == null) ? null : metaModelId.get(metamodel);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void queueForDelete(final EObject element, final StackFrame frame) {
deletionQueue.put(element, new DeletionEntry(element, frame));
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public void deleteQueue() {
if (deletionQueue.isEmpty()) {
return;
}
try {
// Delete cross-references for all entries
for (final Model m : getInoutModels().values()) {
final List<EObject> eObjects = new ArrayList<EObject>();
for (final EObject o : new ResourceIterable(m.getResource())) {
eObjects.add(o);
}
// Prevent ConcurrentModificationException by using eObjects copy
for (final EObject o : eObjects) {
for (final EReference ref : o.eClass().getEAllReferences()) {
// Only change changeable references that are not the reverse of a containment reference
if (ref.isChangeable() && !ref.isContainer()) {
final Object val = o.eGet(ref);
if (val instanceof Collection<?>) {
final List<DeletionEntry> deletionEntries = new ArrayList<DeletionEntry>();
for (final Object source : (Collection<?>) val) {
if (deletionQueue.containsKey(source)) {
deletionEntries.add(deletionQueue.get(source));
}
}
for (final DeletionEntry deletionEntry : deletionEntries) {
deletionEntry.process(o, ref);
}
} else {
if (deletionQueue.containsKey(val)) {
deletionQueue.get(val).process(o, ref);
}
}
}
}
}
}
// Delete entries from their models
for (final DeletionEntry deletionEntry : deletionQueue.values()) {
deletionEntry.process();
}
} finally {
deletionQueue.clear();
}
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Model getInputModelOf(final EObject object) {
if (!modelCacheInit) {
cacheModels();
}
final Resource r = object.eResource();
return (r == null) ? null : inputModelOf.get(r);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Model getInoutModelOf(final EObject object) {
if (!modelCacheInit) {
cacheModels();
}
final Resource r = object.eResource();
return (r == null) ? null : inoutModelOf.get(r);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated NOT
*/
public Model getOutputModelOf(final EObject object) {
if (!modelCacheInit) {
cacheModels();
}
final Resource r = object.eResource();
return (r == null) ? null : outputModelOf.get(r);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object eGet(final int featureID, final boolean resolve, final boolean coreType) {
switch (featureID) {
case EmftvmPackage.EXEC_ENV__META_MODELS:
return getMetaModels();
case EmftvmPackage.EXEC_ENV__INPUT_MODELS:
return getInputModels();
case EmftvmPackage.EXEC_ENV__INOUT_MODELS:
return getInoutModels();
case EmftvmPackage.EXEC_ENV__OUTPUT_MODELS:
return getOutputModels();
case EmftvmPackage.EXEC_ENV__MODULES:
return getModules();
case EmftvmPackage.EXEC_ENV__MATCHES:
if (resolve) return getMatches();
return basicGetMatches();
case EmftvmPackage.EXEC_ENV__TRACES:
if (resolve) return getTraces();
return basicGetTraces();
case EmftvmPackage.EXEC_ENV__UNIQUE_RESULTS:
return getUniqueResults();
case EmftvmPackage.EXEC_ENV__JIT_DISABLED:
return isJitDisabled();
case EmftvmPackage.EXEC_ENV__CURRENT_PHASE:
return getCurrentPhase();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eSet(final int featureID, final Object newValue) {
switch (featureID) {
case EmftvmPackage.EXEC_ENV__JIT_DISABLED:
setJitDisabled((Boolean)newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eUnset(final int featureID) {
switch (featureID) {
case EmftvmPackage.EXEC_ENV__JIT_DISABLED:
setJitDisabled(JIT_DISABLED_EDEFAULT);
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean eIsSet(final int featureID) {
switch (featureID) {
case EmftvmPackage.EXEC_ENV__META_MODELS:
return metaModels != null;
case EmftvmPackage.EXEC_ENV__INPUT_MODELS:
return inputModels != null;
case EmftvmPackage.EXEC_ENV__INOUT_MODELS:
return inoutModels != null;
case EmftvmPackage.EXEC_ENV__OUTPUT_MODELS:
return outputModels != null;
case EmftvmPackage.EXEC_ENV__MODULES:
return modules != null;
case EmftvmPackage.EXEC_ENV__MATCHES:
return matches != null;
case EmftvmPackage.EXEC_ENV__TRACES:
return traces != null;
case EmftvmPackage.EXEC_ENV__UNIQUE_RESULTS:
return uniqueResults != null;
case EmftvmPackage.EXEC_ENV__JIT_DISABLED:
return jitDisabled != JIT_DISABLED_EDEFAULT;
case EmftvmPackage.EXEC_ENV__CURRENT_PHASE:
return currentPhase != CURRENT_PHASE_EDEFAULT;
}
return super.eIsSet(featureID);
}
/**
* <!-- begin-user-doc. -->
* {@inheritDoc}
* <!-- end-user-doc -->
* @generated
*/
@Override
public String toString() {
if (eIsProxy()) return super.toString();
final StringBuffer result = new StringBuffer(super.toString());
result.append(" (metaModels: ");
result.append(metaModels);
result.append(", inputModels: ");
result.append(inputModels);
result.append(", inoutModels: ");
result.append(inoutModels);
result.append(", outputModels: ");
result.append(outputModels);
result.append(", modules: ");
result.append(modules);
result.append(", uniqueResults: ");
result.append(uniqueResults);
result.append(", jitDisabled: ");
result.append(jitDisabled);
result.append(", currentPhase: ");
result.append(currentPhase);
result.append(')');
return result.toString();
}
/**
* {@inheritDoc}
*/
public synchronized CodeBlockJIT getJITCompiler() {
if (cbJit == null && !isJitDisabled()) {
cbJit = new CodeBlockJIT(this);
}
return cbJit;
}
/**
* Sets the JIT compiler instance for this execution environment to <code>null</code>.
*/
protected synchronized void resetJITCompiler() {
if (cbJit != null) {
cbJit.cleanup(); // Clean up all generated JVM bytecode
}
cbJit = null;
}
/**
* Returns whether the internal state of the rules has been compiled.
* @return the ruleStateCompiled
*/
protected boolean isRuleStateCompiled() {
return ruleStateCompiled;
}
/**
* Sets whether the internal state of the rules has been compiled.
* @param ruleStateCompiled the ruleStateCompiled to set
*/
protected void setRuleStateCompiled(final boolean ruleStateCompiled) {
this.ruleStateCompiled = ruleStateCompiled;
}
} //ExecEnvImpl