| /******************************************************************************* |
| * Copyright (c) 2011 Vrije Universiteit Brussel. |
| * Copyright (c) 2017 Dennis Wagelaar. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * Contributors: |
| * Dennis Wagelaar, Vrije Universiteit Brussel - initial API and |
| * implementation and/or initial documentation |
| *******************************************************************************/ |
| package org.eclipse.m2m.atl.emftvm.util; |
| |
| import java.io.IOException; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.InvocationTargetException; |
| import java.text.ParseException; |
| import java.text.SimpleDateFormat; |
| import java.util.Calendar; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TimeZone; |
| |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| 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.ExecEnv; |
| 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.trace.SourceElement; |
| import org.eclipse.m2m.atl.emftvm.trace.SourceElementList; |
| import org.eclipse.m2m.atl.emftvm.trace.TargetElement; |
| import org.eclipse.m2m.atl.emftvm.trace.TraceLinkSet; |
| import org.eclipse.m2m.atl.emftvm.trace.TracedRule; |
| |
| /** |
| * Provides native operations on simple OCL types. |
| * @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a> |
| */ |
| public final class OCLOperations { |
| |
| /** |
| * {@link LazyList} that resolves default trace links. |
| */ |
| public static class ResolveList extends LazyList<Object> { |
| |
| /** |
| * {@link Iterator} that resolves default trace links. |
| */ |
| public class ResolveIterator extends CachingIterator { |
| |
| /** |
| * Creates a new {@link ResolveIterator}. |
| */ |
| public ResolveIterator() { |
| super(dataSource.iterator()); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Object next() { |
| Object next = inner.next(); |
| final SourceElement se = tls.getDefaultSourceElement(next); |
| if (se != null && !se.isMapsToSelf()) { |
| final EList<TargetElement> seMapsTo = se.getMapsTo(); |
| if (!seMapsTo.isEmpty()) { |
| assert seMapsTo.get(0).getObject().eResource() != null; |
| next = seMapsTo.get(0).getObject(); |
| } else { |
| for (final TargetElement te : se.getSourceOf().getTargetElements()) { |
| if (te.getMapsTo().isEmpty()) { // default mapping |
| assert te.getObject().eResource() != null; |
| next = te.getObject(); |
| break; |
| } |
| } |
| } |
| } |
| updateCache(next); |
| return next; |
| } |
| } |
| |
| protected final TraceLinkSet tls; |
| |
| /** |
| * Creates a new {@link ResolveList} around <code>dataSource</code>. |
| * @param dataSource he underlying collection |
| * @param frame the current {@link StackFrame} |
| */ |
| public ResolveList(final Collection<Object> dataSource, final StackFrame frame) { |
| super(dataSource); |
| this.tls = frame.getEnv().getTraces(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Iterator<Object> iterator() { |
| if (dataSource == null) { |
| return Collections.unmodifiableCollection(cache).iterator(); |
| } |
| return new ResolveIterator(); // extends CachingIterator |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public int size() { |
| if (dataSource == null) { |
| return cache.size(); |
| } |
| return ((Collection<Object>)dataSource).size(); |
| } |
| |
| } |
| |
| /** |
| * {@link LazyList} that resolves unique trace links within a given traced rule. |
| */ |
| public static class UniqueResolveList extends ResolveList { |
| |
| /** |
| * {@link Iterator} that resolves unique trace links for a given rule. |
| */ |
| public class UniqueResolveIterator extends ResolveIterator { |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Object next() { |
| Object next = inner.next(); |
| final SourceElement se = tr.getUniqueSourceElement(next); |
| if (se != null && !se.isMapsToSelf()) { |
| final EList<TargetElement> seMapsTo = se.getMapsTo(); |
| if (!seMapsTo.isEmpty()) { |
| assert seMapsTo.get(0).getObject().eResource() != null; |
| next = seMapsTo.get(0).getObject(); |
| } else { |
| for (final TargetElement te : se.getSourceOf().getTargetElements()) { |
| if (te.getMapsTo().isEmpty()) { // default mapping |
| assert te.getObject().eResource() != null; |
| next = te.getObject(); |
| break; |
| } |
| } |
| } |
| } |
| updateCache(next); |
| return next; |
| } |
| } |
| |
| protected final TracedRule tr; |
| |
| /** |
| * Creates a new {@link UniqueResolveList} around <code>dataSource</code>. |
| * @param dataSource he underlying collection |
| * @param frame the current {@link StackFrame} |
| * @param rule the name of the rule to resolve the unique traces for |
| */ |
| public UniqueResolveList(final Collection<Object> dataSource, final StackFrame frame, |
| final String rule) { |
| super(dataSource, frame); |
| this.tr = tls.getLinksByRule(rule, false); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Iterator<Object> iterator() { |
| if (dataSource == null) { |
| return Collections.unmodifiableCollection(cache).iterator(); |
| } |
| if (tr == null) { |
| return new CachingIterator(dataSource.iterator()); // no need to trace |
| } else { |
| return new UniqueResolveIterator(); // extends CachingIterator |
| } |
| } |
| |
| } |
| |
| private static OCLOperations instance; |
| |
| private final Module oclModule; |
| |
| /** |
| * Do not use. |
| */ |
| private OCLOperations() { |
| super(); |
| oclModule = EmftvmFactory.eINSTANCE.createModule(); |
| oclModule.setName("OCL"); |
| createOperations(); |
| } |
| |
| /** |
| * Returns the singleton instance of {@link OCLOperations}. |
| * @return the singleton instance of {@link OCLOperations}. |
| */ |
| public static OCLOperations getInstance() { |
| if (instance == null) { |
| instance = new OCLOperations(); |
| } |
| return instance; |
| } |
| |
| /** |
| * Adds native operations to the oclModule. |
| */ |
| private void createOperations() { |
| ///////////////////////////////////////////////////////////////////// |
| // OclAny |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "debug", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| final StringBuffer buf = new StringBuffer(); |
| if (object instanceof String) { |
| buf.append('\''); |
| buf.append((String)object); |
| buf.append('\''); |
| } else if (object instanceof LazyCollection<?>) { |
| buf.append(((LazyCollection<?>)object).asString(frame.getEnv())); |
| } else { |
| buf.append(EMFTVMUtil.toPrettyString(object, frame.getEnv())); |
| } |
| ATLLogger.info(buf.toString()); |
| return object; |
| } |
| }); |
| createOperation(false, "debug", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"message"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| final StringBuffer buf = new StringBuffer((String)frame.getLocal(0, 1)); |
| buf.append(": "); |
| if (object instanceof String) { |
| buf.append('\''); |
| buf.append((String)object); |
| buf.append('\''); |
| } else if (object instanceof LazyCollection<?>) { |
| buf.append(((LazyCollection<?>) object).asString(frame.getEnv())); |
| } else { |
| buf.append(EMFTVMUtil.toPrettyString(object, frame.getEnv())); |
| } |
| ATLLogger.info(buf.toString()); |
| return object; |
| } |
| }); |
| createOperation(false, "toString", Types.OCL_ANY_TYPE, Types.STRING_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| return EMFTVMUtil.toPrettyString(object, frame.getEnv()); |
| } |
| }); |
| createOperation(false, "oclAsType", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"type"}, Types.CLASSIFIER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| final EClassifier type = (EClassifier)frame.getLocal(0, 1); |
| if (!type.isInstance(object)) { |
| throw new IllegalArgumentException(String.format( |
| "%s is not an instance of %s", |
| object, type)); |
| } |
| return object; |
| |
| } |
| }); |
| createOperation(false, "oclAsType", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"type"}, Types.JAVA_CLASS_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| final Class<?> type = (Class<?>)frame.getLocal(0, 1); |
| if (!type.isInstance(object)) { |
| throw new IllegalArgumentException(String.format( |
| "%s is not an instance of %s", |
| object, type)); |
| } |
| return object; |
| |
| } |
| }); |
| createOperation(false, "oclIsTypeOf", Types.OCL_ANY_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"type"}, Types.CLASSIFIER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| final EClassifier type = (EClassifier)frame.getLocal(0, 1); |
| if (type instanceof EClass) { |
| return o instanceof EObject && ((EObject) o).eClass() == type; |
| } else if (o != null) { |
| final Class<?> ic = type.getInstanceClass(); |
| if (ic == null) { |
| throw new IllegalArgumentException(String.format("EClassifier %s must have an instance class", type)); |
| } |
| return o.getClass() == ic; |
| } else { |
| return false; |
| } |
| } |
| }); |
| createOperation(false, "oclIsTypeOf", Types.OCL_ANY_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"type"}, Types.JAVA_CLASS_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| final Class<?> type = (Class<?>)frame.getLocal(0, 1); |
| return o != null ? o.getClass() == type : false; |
| } |
| }); |
| createOperation(false, "oclIsKindOf", Types.OCL_ANY_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"type"}, Types.CLASSIFIER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| final EClassifier type = (EClassifier)frame.getLocal(0, 1); |
| return type.isInstance(o); |
| } |
| }); |
| createOperation(false, "oclIsKindOf", Types.OCL_ANY_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"type"}, Types.JAVA_CLASS_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| final Class<?> type = (Class<?>)frame.getLocal(0, 1); |
| return type.isInstance(o); |
| } |
| }); |
| createOperation(false, "oclType", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| if (o instanceof EObject) { |
| return ((EObject)o).eClass(); |
| } else if (o != null) { |
| return o.getClass(); |
| } else { |
| return Void.TYPE; |
| } |
| } |
| }); |
| createOperation(false, "=", Types.OCL_ANY_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"o"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| final Object o2 = frame.getLocal(0, 1); |
| return o == null ? o2 == null : o.equals(o2); |
| } |
| }); |
| createOperation(false, "=~", Types.OCL_ANY_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"o"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| final Object o2 = frame.getLocal(0, 1); |
| return o == null ? o2 == null : o.equals(o2); |
| } |
| }); |
| createOperation(false, "=~|", Types.OCL_ANY_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"o"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| final Object o2 = frame.getLocal(0, 1); |
| return o == null ? o2 == null : o.equals(o2); |
| } |
| }); |
| createOperation(false, "<>", Types.OCL_ANY_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"o"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| final Object o2 = frame.getLocal(0, 1); |
| return !(o == null ? o2 == null : o.equals(o2)); |
| } |
| }); |
| createOperation(false, "isInModel", Types.OCL_ANY_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"model"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object o = frame.getLocal(0, 0); |
| if (o instanceof EObject) { |
| final String mName = (String)frame.getLocal(0, 1); |
| final ExecEnv env = frame.getEnv(); |
| Model model = env.getInputModels().get(mName); |
| if (model == null) { |
| model = env.getInoutModels().get(mName); |
| } |
| if (model == null) { |
| model = env.getOutputModels().get(mName); |
| } |
| if (model != null) { |
| return model.getResource() == ((EObject)o).eResource(); |
| } else { |
| return false; |
| } |
| } else { |
| return false; |
| } |
| } |
| }); |
| createOperation(false, "refImmediateComposite", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| if (object instanceof EObject) { |
| return ((EObject)object).eContainer(); |
| } |
| throw new VMException(frame, String.format( |
| "Cannot retrieve immediate composite for regular objects: %s", |
| object)); |
| } |
| }); |
| createOperation(false, "refGetValue", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"propname"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| if (object instanceof EObject) { |
| final String propname = (String)frame.getLocal(0, 1); |
| final EObject eo = (EObject)object; |
| final EClass ecls = eo.eClass(); |
| final EStructuralFeature sf = ecls.getEStructuralFeature(propname); |
| if (sf == null) { |
| throw new VMException(frame, String.format( |
| "Cannot find property %s::%s", ecls.getName(), propname)); |
| } |
| return ((EObject)object).eGet(sf); |
| } |
| throw new VMException(frame, String.format( |
| "Cannot retrieve properties for regular objects: %s", |
| object)); |
| } |
| }); |
| createOperation(false, "refSetValue", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"propname"}, Types.STRING_TYPE}, {{"value"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| if (object instanceof EObject) { |
| final String propname = (String)frame.getLocal(0, 1); |
| final Object value = frame.getLocal(0, 2); |
| final EObject eo = (EObject)object; |
| final EClass ecls = eo.eClass(); |
| final EStructuralFeature sf = ecls.getEStructuralFeature(propname); |
| if (sf == null) { |
| throw new VMException(frame, String.format( |
| "Cannot find property %s::%s", ecls.getName(), propname)); |
| } |
| ((EObject)object).eSet(sf, value); |
| return object; |
| } |
| throw new VMException(frame, String.format( |
| "Cannot set properties for regular objects: %s", |
| object)); |
| } |
| }); |
| createOperation(false, "refUnsetValue", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"propname"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| if (object instanceof EObject) { |
| final String propname = (String)frame.getLocal(0, 1); |
| final EObject eo = (EObject)object; |
| final EClass ecls = eo.eClass(); |
| final EStructuralFeature sf = ecls.getEStructuralFeature(propname); |
| if (sf == null) { |
| throw new VMException(frame, String.format( |
| "Cannot find property %s::%s", ecls.getName(), propname)); |
| } |
| ((EObject)object).eUnset(sf); |
| return object; |
| } |
| throw new VMException(frame, String.format( |
| "Cannot unset properties for regular objects: %s", |
| object)); |
| } |
| }); |
| createOperation(false, "refInvokeOperation", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"opname"}, Types.STRING_TYPE}, {{"arguments"}, Types.SEQUENCE_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| final String opname = (String)frame.getLocal(0, 1); |
| final List<?> args = (List<?>)frame.getLocal(0, 2); |
| return EMFTVMUtil.invokeNative(frame, object, opname, args.toArray()); |
| } |
| }); |
| createOperation(false, "resolve", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| final SourceElement se = frame.getEnv().getTraces().getDefaultSourceElement(object); |
| if (se != null && !se.isMapsToSelf()) { |
| final EList<TargetElement> seMapsTo = se.getMapsTo(); |
| if (!seMapsTo.isEmpty()) { |
| assert seMapsTo.get(0).getObject().eResource() != null; |
| return seMapsTo.get(0).getObject(); |
| } |
| for (final TargetElement te : se.getSourceOf().getTargetElements()) { |
| if (te.getMapsTo().isEmpty()) { // default mapping |
| assert te.getObject().eResource() != null; |
| return te.getObject(); |
| } |
| } |
| } |
| return object; |
| } |
| }); |
| createOperation(false, "resolve", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"rule"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| final String rule = (String) frame.getLocal(0, 1); |
| final TracedRule tr = frame.getEnv().getTraces().getLinksByRule(rule, false); |
| if (tr != null) { |
| final SourceElement se = tr.getUniqueSourceElement(object); |
| if (se != null && !se.isMapsToSelf()) { |
| final EList<TargetElement> seMapsTo = se.getMapsTo(); |
| if (!seMapsTo.isEmpty()) { |
| assert seMapsTo.get(0).getObject().eResource() != null; |
| return seMapsTo.get(0).getObject(); |
| } |
| for (final TargetElement te : se.getSourceOf().getTargetElements()) { |
| if (te.getMapsTo().isEmpty()) { // default mapping |
| assert te.getObject().eResource() != null; |
| return te.getObject(); |
| } |
| } |
| } |
| } |
| return object; |
| } |
| }); |
| createOperation(false, "remap", Types.OCL_ANY_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"to"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object source = frame.getLocal(0, 0); |
| final Object target = frame.getLocal(0, 1); |
| if (source instanceof EObject && target instanceof EObject && source != target) { // different physical objects |
| frame.getEnv().queueForRemap((EObject) source, (EObject) target, frame); |
| } |
| return target; |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // Collection |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "toString", Types.COLLECTION_TYPE, Types.STRING_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public Object execute(final StackFrame frame) { |
| final LazyCollection<Object> coll = (LazyCollection<Object>)frame.getLocal(0, 0); |
| return coll.asString(frame.getEnv()); |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // Bag |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "-", Types.BAG_TYPE, Types.BAG_TYPE, |
| new String[][][] { { { "coll" }, Types.COLLECTION_TYPE } }, new NativeCodeBlock() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public Object execute(final StackFrame frame) { |
| final LazyBag<Object> self = (LazyBag<Object>) frame.getLocal(0, 0); |
| final LazyCollection<Object> coll = (LazyCollection<Object>) frame.getLocal(0, 1); |
| return self.excludingAll(coll); |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // OrderedSet |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "-", Types.ORDERED_SET_TYPE, Types.ORDERED_SET_TYPE, |
| new String[][][] { { { "coll" }, Types.COLLECTION_TYPE } }, new NativeCodeBlock() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public Object execute(final StackFrame frame) { |
| final LazyOrderedSet<Object> self = (LazyOrderedSet<Object>) frame.getLocal(0, 0); |
| final LazyCollection<Object> coll = (LazyCollection<Object>) frame.getLocal(0, 1); |
| return self.excludingAll(coll); |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // Sequence |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "-", Types.SEQUENCE_TYPE, Types.SEQUENCE_TYPE, |
| new String[][][] { { { "coll" }, Types.COLLECTION_TYPE } }, new NativeCodeBlock() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public Object execute(final StackFrame frame) { |
| final LazyList<Object> self = (LazyList<Object>) frame.getLocal(0, 0); |
| final LazyCollection<Object> coll = (LazyCollection<Object>) frame.getLocal(0, 1); |
| return self.excludingAll(coll); |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // Set |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "-", Types.SET_TYPE, Types.SET_TYPE, |
| new String[][][] { { { "coll" }, Types.COLLECTION_TYPE } }, |
| new NativeCodeBlock() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public Object execute(final StackFrame frame) { |
| final LazySet<Object> self = (LazySet<Object>) frame.getLocal(0, 0); |
| final LazyCollection<Object> coll = (LazyCollection<Object>) frame.getLocal(0, 1); |
| return self.excludingAll(coll); |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // JavaCollection |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "resolve", Types.JAVA_COLLECTION_TYPE, Types.SEQUENCE_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Collection<Object> object = (Collection<Object>)frame.getLocal(0, 0); |
| return new ResolveList(object, frame); |
| } |
| }); |
| createOperation(false, "resolve", Types.JAVA_COLLECTION_TYPE, Types.SEQUENCE_TYPE, |
| new String[][][]{{{"rule"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Collection<Object> object = (Collection<Object>)frame.getLocal(0, 0); |
| final String rule = (String)frame.getLocal(0, 1); |
| return new UniqueResolveList(object, frame, rule); |
| } |
| }); |
| createOperation(false, "=~", Types.JAVA_COLLECTION_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"o"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Collection<?> o = (Collection<?>)frame.getLocal(0, 0); |
| final Object o2 = frame.getLocal(0, 1); |
| if (o2 instanceof Collection<?>) { |
| return o.containsAll((Collection<?>)o2); |
| } else { |
| return o.contains(o2); |
| } |
| } |
| }); |
| createOperation(false, "=~|", Types.JAVA_COLLECTION_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"o"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Collection<?> o = (Collection<?>)frame.getLocal(0, 0); |
| final Object o2 = frame.getLocal(0, 1); |
| if (o2 instanceof Collection<?>) { |
| return o.containsAll((Collection<?>)o2); |
| } else { |
| return o.contains(o2); |
| } |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // JavaList |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "=~|", Types.JAVA_LIST_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"o"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final List<?> o = (List<?>)frame.getLocal(0, 0); |
| final Object o2 = frame.getLocal(0, 1); |
| if (o2 instanceof Collection<?>) { |
| final Collection<?> coll2 = (Collection<?>)o2; |
| final int sizediff = o.size() - coll2.size(); |
| if (sizediff < 0) { |
| return false; |
| } else { |
| return o.subList(sizediff, o.size()).containsAll(coll2); |
| } |
| } else if (o.size() > 0) { |
| final Object last = o.get(o.size() - 1); |
| return last == null ? o2 == null : last.equals(o2); |
| } else { |
| return false; |
| } |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // Map |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "including", Types.MAP_TYPE, Types.SET_TYPE, |
| new String[][][]{{{"key"}, Types.OCL_ANY_TYPE}, {{"value"}, Types.OCL_ANY_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Map<Object, Object> o = new HashMap<Object, Object>((Map<?, ?>)frame.getLocal(0, 0)); |
| final Object key = frame.getLocal(0, 1); |
| final Object value = frame.getLocal(0, 2); |
| o.put(key, value); |
| return o; |
| } |
| }); |
| createOperation(false, "getKeys", Types.MAP_TYPE, Types.SET_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Map<?, ?> o = (Map<?, ?>)frame.getLocal(0, 0); |
| return new LazySetOnSet<Object>((Set<Object>)o.keySet()); |
| } |
| }); |
| createOperation(false, "getValues", Types.MAP_TYPE, Types.SET_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @SuppressWarnings("unchecked") |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Map<?, ?> o = (Map<?, ?>)frame.getLocal(0, 0); |
| return new LazyBagOnCollection<Object>((Collection<Object>)o.values()); |
| } |
| }); |
| createOperation(false, "union", Types.MAP_TYPE, Types.SET_TYPE, |
| new String[][][]{{{"m"}, Types.MAP_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Map<Object, Object> o = new HashMap<Object, Object>((Map<?, ?>)frame.getLocal(0, 0)); |
| final Map<?, ?> m = (Map<?, ?>)frame.getLocal(0, 1); |
| o.putAll(m); |
| return o; |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // ExecEnv |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(true, "resolveTemp", Types.EXEC_ENV_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"var"}, Types.OCL_ANY_TYPE}, {{"target_pattern_name"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| final String name = (String)frame.getLocal(0, 1); |
| if (object instanceof List<?>) { |
| final SourceElementList sel = frame.getEnv().getTraces().getDefaultSourceElements((List<?>)object); |
| if (sel != null) { |
| assert !sel.getSourceElements().isEmpty(); |
| final TargetElement te = sel.getSourceElements().get(0).getSourceOf().getTargetElement(name); |
| if (te != null) { |
| return te.getObject(); |
| } |
| } |
| } else { |
| final SourceElement se = frame.getEnv().getTraces().getDefaultSourceElement(object); |
| if (se != null) { |
| final TargetElement te = se.getSourceOf().getTargetElement(name); |
| if (te != null) { |
| return te.getObject(); |
| } |
| } |
| } |
| throw new VMException(frame, String.format( |
| "Cannot resolve default trace target '%s' for %s", |
| name, EMFTVMUtil.toPrettyString(object, frame.getEnv()))); |
| } |
| }); |
| createOperation(true, "resolveTemp", Types.EXEC_ENV_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"var"}, Types.OCL_ANY_TYPE}, |
| {{"rule_name"}, Types.STRING_TYPE}, |
| {{"target_pattern_name"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Object object = frame.getLocal(0, 0); |
| final String rule = (String)frame.getLocal(0, 1); |
| final String name = (String)frame.getLocal(0, 2); |
| if (object instanceof List<?>) { |
| final TracedRule tr = frame.getEnv().getTraces().getLinksByRule(rule, false); |
| if (tr != null) { |
| final SourceElementList sel = tr.getUniqueSourceElements((List<?>)object); |
| if (sel != null) { |
| assert !sel.getSourceElements().isEmpty(); |
| final TargetElement te = sel.getSourceElements().get(0).getSourceOf().getTargetElement(name); |
| if (te != null) { |
| return te.getObject(); |
| } |
| } |
| } |
| } else { |
| final TracedRule tr = frame.getEnv().getTraces().getLinksByRule(rule, false); |
| if (tr != null) { |
| final SourceElement se = tr.getUniqueSourceElement(object); |
| if (se != null) { |
| final TargetElement te = se.getSourceOf().getTargetElement(name); |
| if (te != null) { |
| return te.getObject(); |
| } |
| } |
| } |
| } |
| throw new VMException(frame, String.format( |
| "Cannot resolve unique trace target '%s::%s' for %s", |
| rule, name, EMFTVMUtil.toPrettyString(object, frame.getEnv()))); |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // Class |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "allInstances", Types.CLASS_TYPE, Types.SEQUENCE_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final EClass c = (EClass)frame.getLocal(0, 0); |
| return EMFTVMUtil.findAllInstances(c, frame.getEnv()); |
| } |
| }); |
| createOperation(false, "allInstancesFrom", Types.CLASS_TYPE, Types.SEQUENCE_TYPE, |
| new String[][][]{{{"metamodel"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final EClass c = (EClass)frame.getLocal(0, 0); |
| final String mm = (String)frame.getLocal(0, 1); |
| return EMFTVMUtil.findAllInstIn(mm, c, frame.getEnv()); |
| } |
| }); |
| createOperation(false, "conformsTo", Types.CLASS_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"type"}, Types.CLASS_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final EClass c = (EClass)frame.getLocal(0, 0); |
| final EClass c2 = (EClass)frame.getLocal(0, 1); |
| return c2.isSuperTypeOf(c); |
| } |
| }); |
| createOperation(false, "conformsTo", Types.CLASS_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"type"}, Types.JAVA_CLASS_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final EClass c = (EClass)frame.getLocal(0, 0); |
| final Class<?> c2 = (Class<?>)frame.getLocal(0, 1); |
| final Class<?> ic = c.getInstanceClass(); |
| if (ic != null) { |
| return c2.isAssignableFrom(ic); |
| } else { |
| return c2 == Object.class; // everything is an Object |
| } |
| } |
| }); |
| createOperation(false, "newInstance", Types.CLASS_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final EClass type = (EClass)frame.getLocal(0, 0); |
| return type.getEPackage().getEFactoryInstance().create(type); |
| } |
| }); |
| createOperation(false, "newInstanceIn", Types.CLASS_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"modelname"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final EClass type = (EClass)frame.getLocal(0, 0); |
| final String modelname = (String)frame.getLocal(0, 1); |
| final ExecEnv env = frame.getEnv(); |
| Model model = env.getOutputModels().get(modelname); |
| if (model == null) { |
| model = env.getInoutModels().get(modelname); |
| } |
| if (model == null) { |
| throw new IllegalArgumentException(String.format("Inout/output model %s not found", modelname)); |
| } |
| return model.newElement(type); |
| } |
| }); |
| createOperation(false, "getInstanceById", Types.CLASS_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"id"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final EClass type = (EClass)frame.getLocal(0, 0); |
| final String id = (String)frame.getLocal(0, 1); |
| final ExecEnv env = frame.getEnv(); |
| final List<Model> models = new LazyListOnCollection<Model>( |
| env.getInputModels().values()).union(new LazyListOnCollection<Model>( |
| env.getInoutModels().values())); |
| for (final Model model : models) { |
| final EObject instance = model.getResource().getEObject(id); |
| if (type.isInstance(instance)) { |
| return instance; |
| } |
| } |
| return null; |
| } |
| }); |
| createOperation(false, "getInstanceById", Types.CLASS_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"modelname"}, Types.STRING_TYPE}, {{"id"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final EClass type = (EClass)frame.getLocal(0, 0); |
| final String modelname = (String)frame.getLocal(0, 1); |
| final String id = (String)frame.getLocal(0, 2); |
| final ExecEnv env = frame.getEnv(); |
| Model model = env.getInputModels().get(modelname); |
| if (model == null) { |
| model = env.getInoutModels().get(modelname); |
| } |
| if (model == null) { |
| throw new IllegalArgumentException(String.format("Input/inout model %s not found", modelname)); |
| } |
| final EObject instance = model.getResource().getEObject(id); |
| if (type.isInstance(instance)) { |
| return instance; |
| } else { |
| return null; |
| } |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // JavaClass |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "conformsTo", Types.JAVA_CLASS_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"type"}, Types.CLASS_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Class<?> c = (Class<?>)frame.getLocal(0, 0); |
| final EClass c2 = (EClass)frame.getLocal(0, 1); |
| final Class<?> ic2 = c2.getInstanceClass(); |
| if (ic2 != null) { |
| return ic2.isAssignableFrom(c); |
| } else { |
| return false; |
| } |
| } |
| }); |
| createOperation(false, "conformsTo", Types.JAVA_CLASS_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"type"}, Types.JAVA_CLASS_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Class<?> c = (Class<?>)frame.getLocal(0, 0); |
| final Class<?> c2 = (Class<?>)frame.getLocal(0, 1); |
| return c2.isAssignableFrom(c); |
| } |
| }); |
| createOperation(false, "getName", Types.JAVA_CLASS_TYPE, Types.STRING_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Class<?> c = (Class<?>)frame.getLocal(0, 0); |
| return NativeTypes.typeName(c); |
| } |
| }); |
| createOperation(false, "refInvokeStaticOperation", Types.JAVA_CLASS_TYPE, Types.OCL_ANY_TYPE, |
| new String[][][]{{{"opname"}, Types.STRING_TYPE}, {{"arguments"}, Types.SEQUENCE_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Class<?> c = (Class<?>)frame.getLocal(0, 0); |
| final String opname = (String)frame.getLocal(0, 1); |
| final List<?> args = (List<?>)frame.getLocal(0, 2); |
| return EMFTVMUtil.invokeNativeStatic(frame, c, opname, args.toArray()); |
| } |
| }); |
| createOperation(false, "refNewInstance", Types.JAVA_CLASS_TYPE, Types.OCL_ANY_TYPE, new String[][][] { { { "arguments" }, |
| Types.SEQUENCE_TYPE } }, new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Class<?> c = (Class<?>) frame.getLocal(0, 0); |
| final Object[] args = ((List<?>) frame.getLocal(0, 1)).toArray(); |
| final Constructor<?> constructor = EMFTVMUtil.findConstructor(c, EMFTVMUtil.getArgumentClasses(args)); |
| if (constructor != null) { |
| try { |
| return EMFTVMUtil.emf2vm(frame.getEnv(), null, constructor.newInstance(args)); |
| } catch (final InvocationTargetException e) { |
| final Throwable target = e.getTargetException(); |
| if (target instanceof VMException) { |
| throw (VMException) target; |
| } else { |
| throw new VMException(frame, target); |
| } |
| } catch (final VMException e) { |
| throw e; |
| } catch (final Exception e) { |
| throw new VMException(frame, e); |
| } |
| } |
| throw new UnsupportedOperationException(String.format("%s::<init>(%s)", EMFTVMUtil.getTypeName(frame.getEnv(), c), |
| EMFTVMUtil.getTypeNames(frame.getEnv(), EMFTVMUtil.getArgumentTypes(args)))); |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // Real |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "+", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) + (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "+", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) + (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "-", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return -(Double)frame.getLocal(0, 0); |
| } |
| }); |
| createOperation(false, "-", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) - (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "-", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) - (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "*", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) * (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "*", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) * (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "neg", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return -(Double)frame.getLocal(0, 0); |
| } |
| }); |
| createOperation(false, "/", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) / (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "/", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) / (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "abs", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.abs((Double)frame.getLocal(0, 0)); |
| } |
| }); |
| createOperation(false, "floor", Types.REAL_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Double.valueOf(Math.floor((Double)frame.getLocal(0, 0))).intValue(); |
| } |
| }); |
| createOperation(false, "round", Types.REAL_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Double.valueOf(Math.round((Double)frame.getLocal(0, 0))).intValue(); |
| } |
| }); |
| createOperation(false, "max", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.max((Double)frame.getLocal(0, 0), (Double)frame.getLocal(0, 1)); |
| } |
| }); |
| createOperation(false, "max", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.max((Double)frame.getLocal(0, 0), (Integer)frame.getLocal(0, 1)); |
| } |
| }); |
| createOperation(false, "min", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.min((Double)frame.getLocal(0, 0), (Double)frame.getLocal(0, 1)); |
| } |
| }); |
| createOperation(false, "min", Types.REAL_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.min((Double)frame.getLocal(0, 0), (Integer)frame.getLocal(0, 1)); |
| } |
| }); |
| createOperation(false, "<", Types.REAL_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) < (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "<", Types.REAL_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) < (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, ">", Types.REAL_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) > (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, ">", Types.REAL_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) > (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "<=", Types.REAL_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) <= (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "<=", Types.REAL_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) <= (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, ">=", Types.REAL_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) >= (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, ">=", Types.REAL_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Double)frame.getLocal(0, 0) >= (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // Integer |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "neg", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return -(Integer)frame.getLocal(0, 0); |
| } |
| }); |
| createOperation(false, "+", Types.INTEGER_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) + (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "+", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) + (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "-", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return -(Integer)frame.getLocal(0, 0); |
| } |
| }); |
| createOperation(false, "-", Types.INTEGER_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) - (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "-", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) - (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "*", Types.INTEGER_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) * (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "*", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) * (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "/", Types.INTEGER_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) / (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "/", Types.INTEGER_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return ((Integer)frame.getLocal(0, 0)).doubleValue() / (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "abs", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.abs((Integer)frame.getLocal(0, 0)); |
| } |
| }); |
| createOperation(false, "div", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) / (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "mod", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) % (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "max", Types.INTEGER_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.max((Integer)frame.getLocal(0, 0), (Double)frame.getLocal(0, 1)); |
| |
| } |
| }); |
| createOperation(false, "max", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.max((Integer)frame.getLocal(0, 0), (Integer)frame.getLocal(0, 1)); |
| } |
| }); |
| createOperation(false, "min", Types.INTEGER_TYPE, Types.REAL_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.min((Integer)frame.getLocal(0, 0), (Double)frame.getLocal(0, 1)); |
| } |
| }); |
| createOperation(false, "min", Types.INTEGER_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Math.min((Integer)frame.getLocal(0, 0), (Integer)frame.getLocal(0, 1)); |
| } |
| }); |
| createOperation(false, "<", Types.INTEGER_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) < (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "<", Types.INTEGER_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) < (Integer)frame.getLocal(0, 1); |
| |
| } |
| }); |
| createOperation(false, ">", Types.INTEGER_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) > (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, ">", Types.INTEGER_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) > (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "<=", Types.INTEGER_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) <= (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "<=", Types.INTEGER_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) <= (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, ">=", Types.INTEGER_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"r"}, Types.REAL_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) >= (Double)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, ">=", Types.INTEGER_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (Integer)frame.getLocal(0, 0) >= (Integer)frame.getLocal(0, 1); |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // String |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "+", Types.STRING_TYPE, Types.STRING_TYPE, |
| new String[][][]{{{"s"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return (String)frame.getLocal(0, 0) + (String)frame.getLocal(0, 1); |
| } |
| }); |
| createOperation(false, "size", Types.STRING_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return ((String)frame.getLocal(0, 0)).length(); |
| } |
| }); |
| createOperation(false, "substring", Types.STRING_TYPE, Types.STRING_TYPE, |
| new String[][][]{{{"lower"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| try { |
| return ((String)frame.getLocal(0, 0)).substring( |
| (Integer)frame.getLocal(0, 1) - 1); |
| } catch (final IndexOutOfBoundsException e) { |
| throw new VMException(frame, e); |
| } |
| } |
| }); |
| createOperation(false, "substring", Types.STRING_TYPE, Types.STRING_TYPE, |
| new String[][][]{{{"lower"}, Types.INTEGER_TYPE}, {{"upper"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| try { |
| return ((String)frame.getLocal(0, 0)).substring( |
| (Integer)frame.getLocal(0, 1) - 1, |
| (Integer)frame.getLocal(0, 2)); |
| } catch (final IndexOutOfBoundsException e) { |
| throw new VMException(frame, e); |
| } |
| } |
| }); |
| createOperation(false, "toInteger", Types.STRING_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| try { |
| return Integer.parseInt((String)frame.getLocal(0, 0)); |
| } catch (final NumberFormatException e) { |
| throw new VMException(frame, e); |
| } |
| } |
| }); |
| createOperation(false, "toReal", Types.STRING_TYPE, Types.REAL_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| try { |
| return Double.parseDouble((String)frame.getLocal(0, 0)); |
| } catch (final NumberFormatException e) { |
| throw new VMException(frame, e); |
| } |
| } |
| }); |
| createOperation(false, "indexOf", Types.STRING_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{{{"s"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return ((String)frame.getLocal(0, 0)).indexOf((String)frame.getLocal(0, 1)) + 1; |
| } |
| }); |
| createOperation(false, "lastIndexOf", Types.STRING_TYPE, Types.INTEGER_TYPE, |
| new String[][][]{{{"s"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return ((String)frame.getLocal(0, 0)).lastIndexOf((String)frame.getLocal(0, 1)) + 1; |
| } |
| }); |
| createOperation(false, "at", Types.STRING_TYPE, Types.STRING_TYPE, |
| new String[][][]{{{"i"}, Types.INTEGER_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| try { |
| return String.valueOf(((String)frame.getLocal(0, 0)) |
| .charAt((Integer)frame.getLocal(0, 1) - 1)); |
| } catch (final IndexOutOfBoundsException e) { |
| throw new VMException(frame, e); |
| } |
| } |
| }); |
| createOperation(false, "characters", Types.STRING_TYPE, Types.SEQUENCE_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| LazyList<String> seq = new LazyList<String>(); |
| for (final char c : ((String)frame.getLocal(0, 0)).toCharArray()) { |
| seq = seq.append(String.valueOf(c)); |
| } |
| return seq; |
| } |
| }); |
| createOperation(false, "toBoolean", Types.STRING_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return Boolean.parseBoolean((String)frame.getLocal(0, 0)); |
| } |
| }); |
| createOperation(false, "toUpper", Types.STRING_TYPE, Types.STRING_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return ((String)frame.getLocal(0, 0)).toUpperCase(); |
| } |
| }); |
| createOperation(false, "toLower", Types.STRING_TYPE, Types.STRING_TYPE, |
| new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return ((String)frame.getLocal(0, 0)).toLowerCase(); |
| } |
| }); |
| createOperation(false, "writeTo", Types.STRING_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"path"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| try { |
| return EMFTVMUtil.writeToWithCharset( |
| (String)frame.getLocal(0, 0), |
| (String)frame.getLocal(0, 1), |
| null); |
| |
| } catch (final IOException e) { |
| throw new VMException(frame, e); |
| } |
| } |
| }); |
| createOperation(false, "writeToWithCharset", Types.STRING_TYPE, Types.BOOLEAN_TYPE, |
| new String[][][]{{{"path"}, Types.STRING_TYPE}, {{"charset"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| try { |
| return EMFTVMUtil.writeToWithCharset( |
| (String)frame.getLocal(0, 0), |
| (String)frame.getLocal(0, 1), |
| (String)frame.getLocal(0, 2)); |
| |
| } catch (final IOException e) { |
| throw new VMException(frame, e); |
| } |
| } |
| }); |
| createOperation(false, "toDate", Types.STRING_TYPE, Types.JAVA_DATE_TYPE, |
| new String[][][]{{{"format"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| try { |
| return new SimpleDateFormat((String) frame.getLocal(1)).parse((String) frame.getLocal(0)); |
| } catch (final ParseException e) { |
| throw new VMException(frame, e); |
| } |
| } |
| }); |
| createOperation(false, "toDate", Types.STRING_TYPE, Types.JAVA_DATE_TYPE, |
| new String[][][]{{{"format"}, Types.STRING_TYPE}, {{"locale"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| try { |
| return new SimpleDateFormat((String) frame.getLocal(1), EMFTVMUtil.getLocale((String) frame.getLocal(2))) |
| .parse((String) frame.getLocal(0)); |
| } catch (final ParseException e) { |
| throw new VMException(frame, e); |
| } |
| } |
| }); |
| ///////////////////////////////////////////////////////////////////// |
| // Date |
| ///////////////////////////////////////////////////////////////////// |
| createOperation(false, "toString", Types.JAVA_DATE_TYPE, Types.STRING_TYPE, |
| new String[][][]{{{"format"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return new SimpleDateFormat((String) frame.getLocal(1)).format((Date) frame.getLocal(0)); |
| } |
| }); |
| createOperation(false, "toString", Types.JAVA_DATE_TYPE, Types.STRING_TYPE, |
| new String[][][]{{{"format"}, Types.STRING_TYPE}, {{"locale"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| return new SimpleDateFormat((String) frame.getLocal(1), EMFTVMUtil.getLocale((String) frame.getLocal(2))) |
| .format((Date) frame.getLocal(0)); |
| } |
| }); |
| createOperation(false, "toTuple", Types.JAVA_DATE_TYPE, Types.TUPLE_TYPE, new String[][][]{}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Calendar cal = Calendar.getInstance(); |
| cal.setTime((Date) frame.getLocal(0)); |
| return Tuple.fromCalendar(cal); |
| } |
| }); |
| createOperation(false, "toTuple", Types.JAVA_DATE_TYPE, Types.TUPLE_TYPE, |
| new String[][][]{{{"timezone"}, Types.STRING_TYPE}}, |
| new NativeCodeBlock() { |
| @Override |
| public Object execute(final StackFrame frame) { |
| final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone((String) frame.getLocal(1))); |
| cal.setTime((Date) frame.getLocal(0)); |
| return Tuple.fromCalendar(cal); |
| } |
| }); |
| } |
| |
| /** |
| * Creates and registers a new {@link Operation}. |
| * @param isStatic whether the created operation is static |
| * @param name operation name |
| * @param context operation context [type model, type name] |
| * @param returnType operation return [type model, type name] |
| * @param parameters operations parameters: [[[name], [type model, type name]], ...] |
| * @param body operation body |
| * @return a new {@link Operation}. |
| * @see Types |
| */ |
| private Operation createOperation(final boolean isStatic, final String name, final String[] context, |
| final String[] returnType, final String[][][] parameters, final CodeBlock body) { |
| final Operation op = EMFTVMUtil.createOperation(isStatic, name, context, returnType, parameters, body); |
| oclModule.getFeatures().add(op); |
| return op; |
| } |
| |
| /** |
| * @return the oclModule |
| */ |
| public Module getOclModule() { |
| return oclModule; |
| } |
| } |