| /******************************************************************************* |
| * Copyright (c) 2006, 2008 Eclipse.org |
| * |
| * 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 |
| *******************************************************************************/ |
| package org.eclipse.gmf.internal.xpand; |
| |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.LinkedHashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| |
| import org.eclipse.emf.common.util.Enumerator; |
| import org.eclipse.emf.ecore.EAnnotation; |
| import org.eclipse.emf.ecore.EAttribute; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EDataType; |
| import org.eclipse.emf.ecore.EEnum; |
| import org.eclipse.emf.ecore.EEnumLiteral; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EOperation; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EParameter; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.ETypedElement; |
| import org.eclipse.emf.ecore.EcoreFactory; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.gmf.internal.xpand.expression.PolymorphicResolver; |
| import org.eclipse.gmf.internal.xpand.migration.Activator; |
| import org.eclipse.gmf.internal.xpand.model.XpandDefinitionWrap; |
| import org.eclipse.gmf.internal.xpand.model.XpandIterator; |
| |
| /** |
| * XXX Guess, will need special support to recognize the fact |
| * EJavaObject.isSupertypeOf(EObject) |
| * |
| * @author artem |
| */ |
| @SuppressWarnings("unchecked") |
| public class BuiltinMetaModel { |
| public final static String SET = "Set"; |
| public final static String LIST = "List"; |
| |
| |
| protected static EPackage XECORE = EcoreFactory.eINSTANCE.createEPackage(); |
| |
| static { |
| XECORE.setName("xecore"); |
| XECORE.setNsPrefix("xecore"); |
| XECORE.setNsURI("uri:org.eclipse.modeling/m2t/xpand/xecore/1.0"); |
| } |
| |
| private static EClass PARAMETERIZED_TYPE = EcoreFactory.eINSTANCE.createEClass(); |
| private static EReference PT_INNER_TYPE_REF = EcoreFactory.eINSTANCE.createEReference(); |
| private static EAttribute PT_INNER_TYPE_ATTR = EcoreFactory.eINSTANCE.createEAttribute(); |
| |
| static { |
| PARAMETERIZED_TYPE.setName("ParameterizedType"); |
| PARAMETERIZED_TYPE.getESuperTypes().add(EcorePackage.eINSTANCE.getEClass()); |
| PARAMETERIZED_TYPE.setAbstract(true); |
| PT_INNER_TYPE_REF.setName("innerType"); |
| PT_INNER_TYPE_REF.setContainment(false); |
| PT_INNER_TYPE_REF.setEType(EcorePackage.eINSTANCE.getEClass()); |
| |
| PARAMETERIZED_TYPE.getEStructuralFeatures().add(PT_INNER_TYPE_REF); |
| |
| PT_INNER_TYPE_ATTR.setName("innerDataType"); |
| PT_INNER_TYPE_ATTR.setEType(EcorePackage.eINSTANCE.getEDataType()); |
| PARAMETERIZED_TYPE.getEStructuralFeatures().add(PT_INNER_TYPE_ATTR); |
| XECORE.getEClassifiers().add(PARAMETERIZED_TYPE); |
| } |
| |
| /** |
| * Checks whether classifier is one of user's model extension classes |
| * (conforming to ParameterizedType from our extended ECore meta-model). |
| * EClassifier instances available in analyze() methods are param |
| * candidates. |
| * |
| * @param parameterizedTypeM1 - |
| * e.g. EClass "Order", or XEClass "OrderList" |
| */ |
| public static boolean isParameterizedType(EClassifier parameterizedTypeM1) { |
| return PARAMETERIZED_TYPE.isSuperTypeOf(parameterizedTypeM1.eClass()); |
| } |
| |
| // XXX revisit invocations, this check is doubled with isParameterizedType, perhaps, can refactor it |
| public static boolean isCollectionType(EClassifier parameterizedTypeM1) { |
| // XXX this implementation is not really 'isCollectionType', it's just a copy of what was in the original code |
| return isAssignableFrom(CollectionTypesSupport.COLLECTION_OF_OBJECT, parameterizedTypeM1); |
| } |
| |
| public static EClassifier getInnerType(EClassifier parameterizedTypeM1) { |
| assert isParameterizedType(parameterizedTypeM1); |
| if (parameterizedTypeM1.eIsSet(PT_INNER_TYPE_REF)) { |
| return (EClass) parameterizedTypeM1.eGet(PT_INNER_TYPE_REF); |
| } else { |
| return (EDataType) parameterizedTypeM1.eGet(PT_INNER_TYPE_ATTR); |
| } |
| } |
| |
| /** |
| * NOTE, parameterizedTypeM1 is M1 instance, you can't pass {@link BuiltinMetaModel#COLLECTION_TYPE} (or {@link BuiltinMetaModel#LIST_TYPE}) here, |
| * because COLLECTION_TYPE just extends PARAMETERIZED_TYPE, but still instance of EClass. We could, however, have COLLECTION_TYPE to be an |
| * instance of PARAMETERIZED_TYPE, and then we could use this method. The reasons not to do so (at least, now) are |
| * (a) didn't think it over yet (b) looks like extending M2 (sic!) dynamically, though I don't like even M1 polluting with type |
| * that happens. |
| * @param parameterizedTypeM1 |
| * @param innerTypeM1 |
| * @return |
| */ |
| public static EClass cloneParametrizedType(EClassifier parameterizedTypeM1, EClassifier innerTypeM1) { |
| assert isParameterizedType(parameterizedTypeM1); |
| return collectionTypes.getCollectionType(parameterizedTypeM1.eClass(), innerTypeM1); |
| } |
| |
| /*package*/ static EClass internalNewParameterizedType(EClass parameterizedTypeM2, EClassifier inner) { |
| assert PARAMETERIZED_TYPE.isSuperTypeOf(parameterizedTypeM2); |
| EObject anInstance = XECORE.getEFactoryInstance().create(parameterizedTypeM2); |
| assert anInstance instanceof EClass : "EClass is first supertype with instanceClass set"; |
| // e.g. "OrderCollection" or "IntegerList" |
| ((EClass) anInstance).setName(inner.getName() + parameterizedTypeM2.getName()); |
| anInstance.eSet(inner instanceof EClass ? PT_INNER_TYPE_REF : PT_INNER_TYPE_ATTR, inner); |
| return (EClass) anInstance; |
| } |
| |
| public static final EClass VOID = EcoreFactory.eINSTANCE.createEClass(); |
| |
| static { |
| VOID.setName("void"); |
| XECORE.getEClassifiers().add(VOID); |
| } |
| |
| protected static CollectionTypesSupport collectionTypes = new CollectionTypesSupport(); |
| |
| static { |
| collectionTypes.init(XECORE, PARAMETERIZED_TYPE); |
| } |
| /** |
| * @param name |
| * @return true if name is one of M2 collection meta-types (either Collection, List, Set) |
| */ |
| public static boolean isCollectionMetaType(String name) { |
| return collectionTypes.isCollectionMetaType(name); |
| } |
| |
| public static EClass getCollectionType(String metaTypeName, EClassifier innerType) { |
| return collectionTypes.getCollectionType(metaTypeName, innerType); |
| } |
| |
| // XXX actually, it's odd to use abstract and vague 'collection' |
| public static EClass getCollectionType(EClassifier innerType) { |
| return collectionTypes.getCollectionType(innerType); |
| } |
| public static EClass getListType(EClassifier innerType) { |
| return collectionTypes.getListType(innerType); |
| } |
| public static EClass getSetType(EClassifier innerType) { |
| return collectionTypes.getSetType(innerType); |
| } |
| |
| public static final EClass DEFINITION_TYPE = EcoreFactory.eINSTANCE.createEClass(); |
| |
| static { |
| DEFINITION_TYPE.setName("xpand2::Definition"); |
| DEFINITION_TYPE.getESuperTypes().add(EcorePackage.eINSTANCE.getEClass()); |
| XECORE.getEClassifiers().add(DEFINITION_TYPE); |
| } |
| |
| public static final EClass ITERATOR_TYPE = EcoreFactory.eINSTANCE.createEClass(); |
| |
| static { |
| ITERATOR_TYPE.setName("xpand2::Iterator"); |
| ITERATOR_TYPE.getESuperTypes().add(EcorePackage.eINSTANCE.getEClass()); |
| XECORE.getEClassifiers().add(ITERATOR_TYPE); |
| } |
| |
| /** |
| * ECore doesn't support 'return types' for Enums, to my best knowledge, |
| * they are all integers. original EEnumType returns itself as static |
| * property's return type BTW, what if we'd like to get string value, name, |
| * instead |
| */ |
| public static EClassifier getReturnType(EEnumLiteral sp) { |
| return sp.getEEnum(); |
| } |
| |
| // TODO obj.getClass lookup tree? |
| public static EClassifier getType(Object obj) { |
| if (obj == null) { |
| return VOID; |
| } |
| if (obj instanceof Enumerator) { |
| // unlike original impl, we don't return Enum as type |
| // mostly because it's just too hard to look for actual enum |
| // XXX perhaps, EEnumLiteral.getEEnum could help? |
| return EcorePackage.eINSTANCE.getEEnumerator(); |
| } |
| if (obj instanceof EObject) { |
| return ((EObject) obj).eClass(); |
| } |
| if (obj instanceof Collection) { |
| EClassifier type = null; |
| if (!((Collection) obj).isEmpty()) { |
| // FIXME respect all! elements in the collection, not only the first one |
| type = getType(((Collection) obj).iterator().next()); |
| } |
| if (obj instanceof Set) { |
| return collectionTypes.getSetType(type); |
| } |
| if (obj instanceof List) { |
| return collectionTypes.getListType(type); |
| } |
| return collectionTypes.getCollectionType(type); |
| } |
| if (obj instanceof Boolean) { |
| return EcorePackage.eINSTANCE.getEBoolean(); |
| } |
| if ((obj instanceof Byte) || (obj instanceof Integer) || (obj instanceof Long) || obj instanceof Short) { |
| return EcorePackage.eINSTANCE.getEInt(); |
| } |
| if ((obj instanceof Float) || (obj instanceof Double)) { |
| return EcorePackage.eINSTANCE.getEDouble(); |
| } |
| if (obj instanceof String) { |
| return EcorePackage.eINSTANCE.getEString(); |
| } |
| if (obj instanceof XpandDefinitionWrap) { |
| return DEFINITION_TYPE; |
| } |
| if (obj instanceof XpandIterator) { |
| return ITERATOR_TYPE; |
| } |
| return EcorePackage.eINSTANCE.getEJavaObject(); |
| } |
| |
| /** |
| * FIXME HACK!!! |
| */ |
| public static Object newInstance(EClassifier t) { |
| if (isCollectionType(t)) { |
| return collectionTypes.newInstance(t); |
| } |
| if (t.getInstanceClass() != null) { |
| try { |
| return t.getInstanceClass().newInstance(); |
| } catch (Exception ex) { |
| ex.printStackTrace(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * FIXME what if args has null or getType() returns null - we can't find an |
| * op then, and it's caller who knows how to handle this. |
| * |
| * @param name |
| * @param args |
| * @param instance |
| * @return |
| */ |
| public static Operation executableOperation(String name, Object[] args, Object instance) { |
| EClassifier[] argTypes = new EClassifier[args.length]; |
| for (int i = 0; i < args.length; i++) { |
| argTypes[i] = getType(args[i]); |
| } |
| EOperation metaOp = findOperation(getType(instance), name, argTypes); |
| if (metaOp == null) { |
| return null; |
| } |
| if (InternalOperation.isInternalOp(metaOp)) { |
| for (List<InternalOperation> ops : internalOperationsMap.values()) { |
| for (InternalOperation internalOp : ops) { |
| if (internalOp.metaOp == metaOp) { |
| return new OperationEx(instance, args, internalOp); |
| } |
| } |
| } |
| throw new IllegalStateException("Can't find implementation of built-in operation" + metaOp); |
| } |
| return new Operation(instance, args, metaOp); |
| } |
| |
| public static EOperation findOperation(EClassifier targetType, String name, EClassifier[] args) { |
| List<EOperation> allOp; |
| if (hasBuiltinSupport(targetType)) { |
| // this one is to cover m2 types that are *propagated* to user's model, m1. Those like |
| // boolean, integer, string, etc. |
| allOp = findInternalOp(targetType); |
| } else if (hasBuiltinSupport(targetType.eClass())){ |
| // this one is to cover collection types, because we register their operations |
| // against meta-model (m2) instance, rather than against M1 |
| allOp = findInternalOp(targetType.eClass()); |
| } else { |
| if (false == (targetType instanceof EClass)) { |
| return null; |
| } else { |
| allOp = new LinkedList<EOperation>(((EClass) targetType).getEAllOperations()); |
| allOp.addAll(findInternalOp(EcorePackage.eINSTANCE.getEJavaObject())); |
| } |
| } |
| return PolymorphicResolver.filterOperation(allOp, name, targetType, Arrays.asList(args)); |
| } |
| |
| private static Map<String, String> attrNameSubsts = new TreeMap<String, String>(); |
| public static EOperation Collection_IsEmpty; |
| public static EOperation Collection_Add; |
| public static EOperation Collection_AddAll; |
| public static EOperation Collection_Clear; |
| public static EOperation Collection_Flatten; |
| public static EOperation Collection_Size; |
| public static EOperation Collection_Union; |
| public static EOperation Collection_Intersect; |
| public static EOperation Collection_Without; |
| public static EOperation Collection_ToSet; |
| public static EOperation Collection_ToList; |
| public static EOperation Collection_Contains; |
| public static EOperation Collection_ContainsAll; |
| public static EOperation List_Get; |
| public static EOperation List_First; |
| public static EOperation List_Last; |
| public static EOperation List_WithoutFirst; |
| public static EOperation List_WithoutLast; |
| public static EOperation List_PurgeDups; |
| public static EOperation List_IndexOf; |
| public static EOperation Boolean_NE; |
| public static EOperation Int_Plus_Int; |
| public static EOperation Int_Plus_Double; |
| public static EOperation Int_Minus_Int; |
| public static EOperation Int_Minus_Double; |
| public static EOperation Int_Mult_Int; |
| public static EOperation Int_Mult_Double; |
| public static EOperation Int_Div_Int; |
| public static EOperation Int_Div_Double; |
| public static EOperation Int_Unary_Minus; |
| public static EOperation Int_GreatOrEqual; |
| public static EOperation Int_LessOrEqual; |
| public static EOperation Int_Less; |
| public static EOperation Int_Greater; |
| public static EOperation Int_UpTo; |
| public static EOperation Double_Plus_Double; |
| public static EOperation Double_Plus_Int; |
| public static EOperation Double_Minus_Double; |
| public static EOperation Double_Minus_Int; |
| public static EOperation Double_Mult_Double; |
| public static EOperation Double_Mult_Int; |
| public static EOperation Double_Div_Double; |
| public static EOperation Double_Div_Int; |
| public static EOperation Double_Unary_Minus; |
| public static EOperation Object_EQ; |
| public static EOperation EString_ToFirstUpper; |
| public static EOperation EString_Plus_EJavaObject; |
| public static EOperation EString_ToFirstLower; |
| public static EOperation EString_ToCharList; |
| public static EOperation EString_StartsWith; |
| public static EOperation EString_EndsWith; |
| public static EOperation EString_SubString_StartEnd; |
| public static EOperation EString_SubString; |
| public static EOperation EString_ToUpperCase; |
| public static EOperation EString_ToLowerCase; |
| public static EOperation EString_ReplaceAll; |
| public static EOperation EString_ReplaceFirst; |
| public static EOperation EString_Split; |
| public static EOperation EString_Matches; |
| public static EOperation EString_Trim; |
| public static EOperation EString_Length; |
| public static EOperation Object_CompareTo; |
| public static EOperation Object_ToString; |
| public static EOperation Object_NotEQ; |
| static { |
| attrNameSubsts.put("default_", "default"); |
| } |
| public static EStructuralFeature getAttribute(EClassifier type, String name) { |
| if (hasBuiltinSupport(type)) { |
| return findInternalAttr(type, name); |
| } |
| if (type instanceof EClass) { |
| return ((EClass) type).getEStructuralFeature(attrNameSubsts.containsKey(name) ? attrNameSubsts.get(name): name); |
| } |
| if (type instanceof EEnum || type == EcorePackage.eINSTANCE.getEEnumLiteral() || type == EcorePackage.eINSTANCE.getEEnumerator()) { |
| return EcorePackage.eINSTANCE.getEEnumLiteral().getEStructuralFeature(name); |
| } |
| return null; |
| } |
| public static Object getValue(EStructuralFeature prop, Object instance) { |
| if (instance instanceof Enumerator) { |
| if (prop == EcorePackage.eINSTANCE.getEEnumLiteral_Literal()) { |
| return ((Enumerator) instance).getLiteral(); |
| } |
| if (prop == EcorePackage.eINSTANCE.getENamedElement_Name()) { |
| return ((Enumerator) instance).getName(); |
| } |
| if (prop == EcorePackage.eINSTANCE.getEEnumLiteral_Value()) { |
| return ((Enumerator) instance).getValue(); |
| } |
| } |
| if (instance instanceof EObject) { |
| return ((EObject) instance).eGet(prop); |
| } |
| // handle collection/set/list properties? |
| return "HeyHo!"; |
| } |
| |
| private static boolean hasBuiltinSupport(EClassifier type) { |
| return internalOperationsMap.containsKey(type); |
| } |
| |
| private static EStructuralFeature findInternalAttr(EClassifier type, String name) { |
| if (type instanceof EClass) { |
| return ((EClass) type).getEStructuralFeature(name); |
| } |
| if (type instanceof EDataType && type == EcorePackage.eINSTANCE.getEEnumerator()) { |
| // I do not know where EMF uses EEnumLiteralImpl and where Enumerator for EEnum value. |
| return EcorePackage.eINSTANCE.getEEnumLiteral().getEStructuralFeature(name); |
| } |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| private static final Map<EClassifier,List<InternalOperation>> internalOperationsMap = new HashMap<EClassifier, List<InternalOperation>>(); |
| |
| static { |
| final EcorePackage ecorePkg = EcorePackage.eINSTANCE; |
| final OperationFactory opf = new OperationFactory(); |
| |
| final List<InternalOperation> objectOps = new LinkedList<InternalOperation>(); |
| objectOps.add(new InternalOperation<Object>(Object_CompareTo = opf.create("compareTo", ecorePkg.getEBoolean(), ecorePkg.getEJavaObject())) { |
| @Override |
| public Object evaluate(Object target, Object[] params) { |
| if (target == null) { |
| return params[0] == null ? 0 : -1; |
| } |
| if (params[0] == null) { |
| return 1; |
| } |
| if (target instanceof Comparable) { |
| return ((Comparable) target).compareTo(params[0]); |
| } |
| // note, unlike ObjectTypeImpl we don't invoke toString registered against metatype here |
| return String.valueOf(target).compareTo(String.valueOf(params[0])); |
| } |
| }); |
| objectOps.add(new InternalOperation<Object>(Object_ToString = opf.create("toString", ecorePkg.getEString())) { |
| @Override |
| public Object evaluate(Object target, Object[] params) { |
| return String.valueOf(target); |
| } |
| }); |
| objectOps.add(new InternalOperation<Object>(Object_EQ = opf.create("==", boolean.class, Object.class)) { |
| @Override |
| public Object evaluate(Object target, Object[] params) { |
| return target == null ? params[0] == null : target.equals(params[0]); |
| } |
| }); |
| objectOps.add(new InternalOperation<Object>(Object_NotEQ = opf.create("!=", boolean.class, Object.class)) { |
| @Override |
| public Object evaluate(Object target, Object[] params) { |
| return target == null ? params[0] != null : !target.equals(params[0]); |
| } |
| }); |
| List<InternalOperation> unmodifiableObjectOps = Collections.unmodifiableList(objectOps); |
| internalOperationsMap.put(ecorePkg.getEJavaObject(), unmodifiableObjectOps); |
| // EEnumerator are enum literal instances at runtime (#evaluate), |
| // while EEnum are their types during #analyze phase |
| internalOperationsMap.put(ecorePkg.getEEnumerator(), unmodifiableObjectOps); |
| internalOperationsMap.put(ecorePkg.getEEnum(), unmodifiableObjectOps); |
| |
| final List<InternalOperation> stringOps = new LinkedList<InternalOperation>(); |
| |
| stringOps.add(new InternalOperation<String>(EString_Plus_EJavaObject = opf.create("+",ecorePkg.getEString(),ecorePkg.getEJavaObject())) { |
| @Override |
| public Object evaluate(String target, Object[] params) { |
| return target + String.valueOf(params[0]); |
| } |
| }); |
| stringOps.add(new InternalOperation<String>(EString_ToFirstUpper = opf.create("toFirstUpper",ecorePkg.getEString())) { |
| @Override |
| public Object evaluate(String target, Object[] params) { |
| return StringHelper.firstUpper(target); |
| } |
| }); |
| stringOps.add(new InternalOperation<String>(EString_ToFirstLower = opf.create("toFirstLower",ecorePkg.getEString())) { |
| @Override |
| public Object evaluate(String target, Object[] params) { |
| return StringHelper.firstLower(target); |
| } |
| }); |
| stringOps.add(new InternalOperation<String>(EString_ToCharList = opf.create("toCharList",collectionTypes.getListType(ecorePkg.getEString()))) { |
| @Override |
| public Object evaluate(String target, Object[] params) { |
| ArrayList<String> rv = new ArrayList<String>(target.length()); |
| for (int i = 0; i < target.length(); i++) { |
| rv.add(target.substring(i, i+1)); |
| } |
| return rv; |
| } |
| }); |
| InternalOperation internalOp; |
| stringOps.add(internalOp = opf.createReflective(String.class, "startsWith", String.class)); |
| EString_StartsWith = internalOp.metaOp; |
| stringOps.add(internalOp = opf.createReflective(String.class, "endsWith", String.class)); |
| EString_EndsWith = internalOp.metaOp; |
| InternalOperation subStringOp = opf.createReflective(String.class, "substring", int.class, int.class); |
| subStringOp.metaOp.setName("subString"); |
| EString_SubString_StartEnd = subStringOp.metaOp; |
| stringOps.add(subStringOp); |
| subStringOp = opf.createReflective(String.class, "substring", int.class); |
| subStringOp.metaOp.setName("subString"); |
| EString_SubString = subStringOp.metaOp; |
| stringOps.add(subStringOp); |
| stringOps.add(internalOp = opf.createReflective(String.class, "toUpperCase")); |
| EString_ToUpperCase = internalOp.metaOp; |
| stringOps.add(internalOp = opf.createReflective(String.class, "toLowerCase")); |
| EString_ToLowerCase = internalOp.metaOp; |
| stringOps.add(internalOp = opf.createReflective(String.class, "replaceAll", String.class, String.class)); |
| EString_ReplaceAll = internalOp.metaOp; |
| stringOps.add(internalOp = opf.createReflective(String.class, "replaceFirst", String.class, String.class)); |
| EString_ReplaceFirst = internalOp.metaOp; |
| stringOps.add(internalOp = opf.createReflective(String.class, "split", String.class)); |
| EString_Split = internalOp.metaOp; |
| stringOps.add(internalOp = opf.createReflective(String.class, "matches", String.class)); |
| EString_Matches = internalOp.metaOp; |
| stringOps.add(internalOp = opf.createReflective(String.class, "trim")); |
| EString_Trim = internalOp.metaOp; |
| stringOps.add(internalOp = opf.createReflective(String.class, "length")); |
| EString_Length = internalOp.metaOp; |
| stringOps.addAll(unmodifiableObjectOps); |
| internalOperationsMap.put(ecorePkg.getEString(), Collections.unmodifiableList(stringOps)); |
| |
| final List<InternalOperation> booleanOps = new LinkedList<InternalOperation>(); |
| booleanOps.add(new InternalOperation<Boolean>(Boolean_NE = opf.create("!", boolean.class)) { |
| @Override |
| public Object evaluate(Boolean target, Object[] params) { |
| return Boolean.valueOf(!target.booleanValue()); |
| } |
| }); |
| booleanOps.addAll(unmodifiableObjectOps); |
| internalOperationsMap.put(ecorePkg.getEBoolean(), Collections.unmodifiableList(booleanOps)); |
| final List<InternalOperation> voidOps = new LinkedList<InternalOperation>(); |
| voidOps.addAll(unmodifiableObjectOps); |
| internalOperationsMap.put(VOID, Collections.unmodifiableList(voidOps)); |
| |
| //--------------------------------------------------------------------------------- |
| class InternalSumOp extends InternalOperation<Number> { |
| InternalSumOp(EOperation metaOp) { |
| super(metaOp); |
| } |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| if (target instanceof Double || params[0] instanceof Double) { |
| return new Double(target.doubleValue() + ((Number) params[0]).doubleValue()); |
| } else { |
| return new Integer(target.intValue() + ((Number) params[0]).intValue()); |
| } |
| } |
| |
| }; |
| class InternalSubOp extends InternalOperation<Number> { |
| InternalSubOp(EOperation metaOp) { |
| super(metaOp); |
| } |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| if (target instanceof Double || params[0] instanceof Double) { |
| return new Double(target.doubleValue() - ((Number) params[0]).doubleValue()); |
| } else { |
| return new Integer(target.intValue() - ((Number) params[0]).intValue()); |
| } |
| } |
| |
| }; |
| class InternalMulOp extends InternalOperation<Number> { |
| InternalMulOp(EOperation metaOp) { |
| super(metaOp); |
| } |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| if (target instanceof Double || params[0] instanceof Double) { |
| return new Double(target.doubleValue() * ((Number) params[0]).doubleValue()); |
| } else { |
| return new Integer(target.intValue() * ((Number) params[0]).intValue()); |
| } |
| } |
| |
| }; |
| class InternalDivOp extends InternalOperation<Number> { |
| InternalDivOp(EOperation metaOp) { |
| super(metaOp); |
| } |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| if (target instanceof Double || params[0] instanceof Double) { |
| return new Double(target.doubleValue() / ((Number) params[0]).doubleValue()); |
| } else { |
| return new Integer(target.intValue() / ((Number) params[0]).intValue()); |
| } |
| } |
| |
| }; |
| class InternalNegateOp extends InternalOperation<Number> { |
| InternalNegateOp(EOperation metaOp) { |
| super(metaOp); |
| } |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| if (target instanceof Double) { |
| return -target.doubleValue(); |
| } |
| return -target.intValue(); |
| } |
| } |
| //--------------------------------------------------------------------------------- |
| |
| final List<InternalOperation> intOps = new LinkedList<InternalOperation>(); |
| intOps.add(new InternalSumOp(Int_Plus_Int = opf.create("+", int.class, int.class))); |
| intOps.add(new InternalSumOp(Int_Plus_Double = opf.create("+", int.class, double.class))); |
| intOps.add(new InternalSubOp(Int_Minus_Int = opf.create("-", int.class, int.class))); |
| intOps.add(new InternalSubOp(Int_Minus_Double = opf.create("-", double.class, double.class))); |
| intOps.add(new InternalMulOp(Int_Mult_Int = opf.create("*", int.class, int.class))); |
| intOps.add(new InternalMulOp(Int_Mult_Double = opf.create("*", int.class, double.class))); |
| intOps.add(new InternalDivOp(Int_Div_Int = opf.create("/", int.class, int.class))); |
| intOps.add(new InternalDivOp(Int_Div_Double = opf.create("/", int.class, double.class))); |
| intOps.add(new InternalNegateOp(Int_Unary_Minus = opf.create("-", int.class))); |
| // intOps.add(new InternalOperation<Number>(opf.create("==", boolean.class, int.class)) { |
| // @Override |
| // public Object evaluate(Number target, Object[] params) { |
| // //we may need this to handle cases like {Long(5), Long(4)}.exists(a | a == 5) |
| // return Boolean.valueOf(target.intValue() == ((Integer) params[0]).intValue()); |
| // } |
| // |
| // }); |
| intOps.add(new InternalOperation<Number>(Int_GreatOrEqual = opf.create(">=", boolean.class, int.class)) { |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| return Boolean.valueOf(target.intValue() >= ((Number) params[0]).intValue()); |
| } |
| }); |
| intOps.add(new InternalOperation<Number>(Int_LessOrEqual = opf.create("<=", boolean.class, int.class)) { |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| return Boolean.valueOf(target.intValue() <= ((Number) params[0]).intValue()); |
| } |
| }); |
| intOps.add(new InternalOperation<Number>(Int_Less = opf.create("<", boolean.class, int.class)) { |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| return Boolean.valueOf(target.intValue() < ((Number) params[0]).intValue()); |
| } |
| }); |
| intOps.add(new InternalOperation<Number>(Int_Greater = opf.create(">", boolean.class, int.class)) { |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| return Boolean.valueOf(target.intValue() > ((Number) params[0]).intValue()); |
| } |
| }); |
| intOps.add(new InternalOperation<Number>(Int_UpTo = opf.create("upTo", collectionTypes.getListType(ecorePkg.getEInt()), ecorePkg.getEInt())) { |
| @Override |
| public Object evaluate(Number target, Object[] params) { |
| final ArrayList<Integer> result = new ArrayList<Integer>(); |
| for (int l1 = target.intValue(), l2 = ((Number) params[0]).intValue(); l1 <= l2; l1++) { |
| result.add(new Integer(l1)); |
| } |
| return result; |
| } |
| |
| }); |
| intOps.addAll(unmodifiableObjectOps); |
| List<InternalOperation> unmodifiableListIntOps = Collections.unmodifiableList(intOps); |
| internalOperationsMap.put(ecorePkg.getEIntegerObject(), unmodifiableListIntOps); |
| internalOperationsMap.put(ecorePkg.getEInt(), unmodifiableListIntOps); |
| |
| final List<InternalOperation> doubleOps = new LinkedList<InternalOperation>(); |
| doubleOps.add(new InternalSumOp(Double_Plus_Double = opf.create("+", double.class, double.class))); |
| doubleOps.add(new InternalSumOp(Double_Plus_Int = opf.create("+", double.class, int.class))); |
| doubleOps.add(new InternalSubOp(Double_Minus_Double = opf.create("-", double.class, double.class))); |
| doubleOps.add(new InternalSubOp(Double_Minus_Int = opf.create("-", double.class, int.class))); |
| doubleOps.add(new InternalMulOp(Double_Mult_Double = opf.create("*", double.class, double.class))); |
| doubleOps.add(new InternalMulOp(Double_Mult_Int = opf.create("*", double.class, int.class))); |
| doubleOps.add(new InternalDivOp(Double_Div_Double = opf.create("/", double.class, double.class))); |
| doubleOps.add(new InternalDivOp(Double_Div_Int = opf.create("/", double.class, int.class))); |
| doubleOps.add(new InternalNegateOp(Double_Unary_Minus = opf.create("-", double.class))); |
| doubleOps.addAll(unmodifiableObjectOps); |
| internalOperationsMap.put(ecorePkg.getEDouble(), doubleOps); |
| |
| final List<InternalOperation> collectionOps = new LinkedList<InternalOperation>(); |
| collectionOps.add(new InternalOperation<Collection>(Collection_IsEmpty = opf.create("isEmpty", ecorePkg.getEBoolean())) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| // TODO isEmpty is rather attribute |
| return target.isEmpty(); |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_Add = opf.create("add", CollectionTypesSupport.COLLECTION_OF_OBJECT, ecorePkg.getEJavaObject())) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| target.add(params[0]); |
| return target; |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_AddAll = opf.create("addAll", CollectionTypesSupport.COLLECTION_OF_OBJECT, CollectionTypesSupport.COLLECTION_OF_OBJECT)) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| target.addAll((Collection) params[0]); |
| return target; |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_Clear = opf.create("clear", CollectionTypesSupport.COLLECTION_OF_OBJECT)) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| target.clear(); |
| return target; |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_Flatten = opf.create("flatten", CollectionTypesSupport.COLLECTION_OF_OBJECT)) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| LinkedList rv = new LinkedList(); |
| for (Object o : target) { |
| if (o instanceof Collection) { |
| // XXX unlike original xpand, we do not flatten recursively |
| rv.addAll((Collection) o); |
| } else { |
| rv.add(o); |
| } |
| } |
| return rv; |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_Size = opf.create("size", ecorePkg.getEInt())) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| return target.size(); |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_Union = opf.create("union", CollectionTypesSupport.COLLECTION_OF_OBJECT, CollectionTypesSupport.COLLECTION_OF_OBJECT)) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| LinkedHashSet<Object> rv = new LinkedHashSet<Object>(target); |
| rv.addAll((Collection) params[0]); |
| return rv; |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_Intersect = opf.create("intersect", CollectionTypesSupport.COLLECTION_OF_OBJECT, CollectionTypesSupport.COLLECTION_OF_OBJECT)) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| LinkedHashSet<Object> rv = new LinkedHashSet<Object>(target); |
| rv.retainAll((Collection) params[0]); |
| return rv; |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_Without = opf.create("without", CollectionTypesSupport.COLLECTION_OF_OBJECT, CollectionTypesSupport.COLLECTION_OF_OBJECT)) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| LinkedHashSet<Object> rv = new LinkedHashSet<Object>(target); |
| rv.removeAll((Collection) params[0]); |
| return rv; |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_ToSet = opf.create("toSet", CollectionTypesSupport.SET_OF_OBJECT)) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| return new LinkedHashSet<Object>(target); |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_ToList = opf.create("toList", CollectionTypesSupport.LIST_OF_OBJECT)) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| return new LinkedList<Object>(target); |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_Contains = opf.create("contains", ecorePkg.getEBoolean(), ecorePkg.getEJavaObject())) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| return target.contains(params[0]); |
| } |
| }); |
| collectionOps.add(new InternalOperation<Collection>(Collection_ContainsAll = opf.create("containsAll", ecorePkg.getEBoolean(), CollectionTypesSupport.COLLECTION_OF_OBJECT)) { |
| @Override |
| public Object evaluate(Collection target, Object[] params) { |
| return target.containsAll((Collection) params[0]); |
| } |
| }); |
| List<InternalOperation> unmodifiableListCollectionOps = Collections.unmodifiableList(collectionOps); |
| internalOperationsMap.put(CollectionTypesSupport.COLLECTION_TYPE, unmodifiableListCollectionOps); |
| internalOperationsMap.put(CollectionTypesSupport.SET_TYPE, unmodifiableListCollectionOps); |
| final List<InternalOperation> listOps = new LinkedList<InternalOperation>(unmodifiableListCollectionOps); |
| listOps.add(new InternalOperation<List>(List_Get = opf.create("get", ecorePkg.getEJavaObject(), ecorePkg.getEInt())) { |
| @Override |
| public Object evaluate(List target, Object[] params) { |
| int index = ((Number) params[0]).intValue(); |
| return index < target.size() ? target.get(index) : null; |
| } |
| }); |
| listOps.add(new InternalOperation<List>(List_First = opf.create("first", ecorePkg.getEJavaObject())) { |
| @Override |
| public Object evaluate(List target, Object[] params) { |
| return target.isEmpty() ? null : target.get(0); |
| } |
| }); |
| listOps.add(new InternalOperation<List>(List_Last = opf.create("last", ecorePkg.getEJavaObject())) { |
| @Override |
| public Object evaluate(List target, Object[] params) { |
| return target.isEmpty() ? null : target.get(target.size() - 1); |
| } |
| }); |
| listOps.add(new InternalOperation<List>(List_WithoutFirst = opf.create("withoutFirst", CollectionTypesSupport.LIST_OF_OBJECT)) { |
| @Override |
| public Object evaluate(List target, Object[] params) { |
| if (!target.isEmpty()) { |
| LinkedList rv = new LinkedList(target); |
| rv.removeFirst(); |
| return rv; |
| } |
| return target; |
| } |
| }); |
| listOps.add(new InternalOperation<List>(List_WithoutLast = opf.create("withoutLast", CollectionTypesSupport.LIST_OF_OBJECT)) { |
| @Override |
| public Object evaluate(List target, Object[] params) { |
| if (!target.isEmpty()) { |
| LinkedList rv = new LinkedList(target); |
| rv.removeLast(); |
| return rv; |
| } |
| return target; |
| } |
| }); |
| listOps.add(new InternalOperation<List>(List_PurgeDups = opf.create("purgeDups", CollectionTypesSupport.LIST_OF_OBJECT)) { |
| @Override |
| public Object evaluate(List target, Object[] params) { |
| if (target.isEmpty()) { |
| return target; |
| } |
| return new LinkedList<Object>(new LinkedHashSet<Object>(target)); |
| } |
| }); |
| listOps.add(new InternalOperation<List>(List_IndexOf = opf.create("indexOf", ecorePkg.getEInt(), ecorePkg.getEJavaObject())) { |
| @Override |
| public Object evaluate(List target, Object[] params) { |
| return target.indexOf(params[0]); |
| } |
| }); |
| internalOperationsMap.put(CollectionTypesSupport.LIST_TYPE, Collections.unmodifiableList(listOps)); |
| |
| final List<InternalOperation> definitionOps = new LinkedList<InternalOperation>(); |
| definitionOps.add(new InternalOperation<XpandDefinitionWrap>(opf.create("proceed", VOID)) { |
| @Override |
| public Object evaluate(XpandDefinitionWrap target, Object[] params) { |
| target.proceed(); |
| return null; |
| } |
| }); |
| internalOperationsMap.put(DEFINITION_TYPE, Collections.unmodifiableList(definitionOps)); |
| |
| final List<InternalOperation> iteratorOps = new LinkedList<InternalOperation>(); |
| iteratorOps.add(new InternalOperation<XpandIterator>(opf.create("isFirstIteration", ecorePkg.getEBoolean())) { |
| @Override |
| public Object evaluate(XpandIterator target, Object[] params) { |
| return target.isFirstIteration(); |
| } |
| }); |
| internalOperationsMap.put(ITERATOR_TYPE, Collections.unmodifiableList(iteratorOps)); |
| } |
| |
| private static List<EOperation> findInternalOp(EClassifier targetType) { |
| List<InternalOperation> ops = internalOperationsMap.get(targetType); |
| if (ops != null) { |
| List<EOperation> rv = new ArrayList<EOperation>(ops.size()); |
| for (InternalOperation iop : ops) { |
| rv.add(iop.metaOp); |
| } |
| return rv; |
| } |
| if (targetType.eClass() == EcorePackage.eINSTANCE.getEClass()) { |
| // not instanceof because parametric type and all other XECore |
| // classes have different operations, at least |
| // meanwhile, when they are dynamic |
| return((EClass) targetType).getEAllOperations(); |
| } |
| // TODO Auto-generated method stub |
| // String length, +, startsWith, endsWith, subString, toUpperCase, toFirstUpper, toFirstLower, toCharList, replaceAll, replaceFirst, split, matches, trim |
| // Int/Real +-*/ > >= < <= != == |
| // Collection toList, toSet, toString, add, addAll, contains, containsAll, remove, removeAll, without, intersect, flatten ; |
| // properties - size, isEmpty |
| // List get, indexOf, last, first, withoutFirst, withoutLast |
| // Set - none |
| return null; |
| } |
| |
| public static EClassifier getTypedElementType(ETypedElement p) { |
| if (p.isMany()) { |
| return p.isOrdered() ? getListType(p.getEType()) : p.isUnique() ? getSetType(p.getEType()) : getCollectionType(p.getEType()); |
| } |
| return p.getEType(); |
| } |
| |
| private static class OperationFactory { |
| EOperation create(String name, Class returnType, Class ... params) { |
| EClassifier[] paramsNew = new EClassifier[params.length]; |
| for (int i = 0; i < paramsNew.length; i++) { |
| paramsNew[i] = toEClassifier(params[i]); |
| assert params[i] != null; |
| } |
| EClassifier rt = toEClassifier(returnType); |
| assert rt != null : "Unrecognized return type:" + returnType; |
| return create(name, rt, paramsNew); |
| } |
| |
| /** |
| * NOTE, targetType is NOT operation's return type, but method owning class |
| */ |
| InternalOperation createReflective(Class targetType, String methodName, Class ... params) { |
| try { |
| final Method m = targetType.getMethod(methodName, params); |
| assert m != null; |
| return new InternalOperation<Object>(create(methodName, m.getReturnType(), params)) { |
| public Object evaluate(Object target, Object[] params) { |
| try { |
| Object rv = m.invoke(target, params); |
| if (rv != null && rv.getClass().isArray()) { |
| return new LinkedList(Arrays.asList((Object[]) rv)); |
| } |
| return rv; |
| } catch (Exception e) { |
| Activator.logError(e); |
| return null; |
| } |
| } |
| }; |
| } catch (NoSuchMethodException ex) { |
| assert false : ex.getMessage(); |
| } |
| return null; |
| } |
| |
| private EClassifier toEClassifier(Class targetType) { |
| if (targetType == void.class) { |
| return VOID; |
| } |
| for (EClassifier c : EcorePackage.eINSTANCE.getEClassifiers()) { |
| if (c.getInstanceClass() == targetType) { |
| return c; |
| } |
| } |
| if (targetType.isArray()) { |
| EClassifier t = toEClassifier(targetType.getComponentType()); |
| assert t != null : "Unrecognized array component type:" + targetType; |
| return getListType(t); |
| } |
| // TODO other packages |
| return null; |
| } |
| |
| EOperation create(String name, EClassifier returnType, EClassifier ... params) { |
| EOperation op = EcoreFactory.eINSTANCE.createEOperation(); |
| op.setName(name); |
| op.setEType(returnType); |
| for (EClassifier c : params) { |
| EParameter p1 = EcoreFactory.eINSTANCE.createEParameter(); |
| p1.setName("arg" + c.getName()); |
| p1.setEType(c); |
| op.getEParameters().add(p1); |
| } |
| return op; |
| } |
| } |
| |
| private static abstract class InternalOperation<T> { |
| private final EOperation metaOp; |
| private static String INTERNAL_OP_ANNOTATION = "::internalop::"; |
| |
| private InternalOperation(EOperation metaOp) { |
| assert metaOp != null; |
| this.metaOp = metaOp; |
| EAnnotation internalOpAnn = EcoreFactory.eINSTANCE.createEAnnotation(); |
| internalOpAnn.setSource(INTERNAL_OP_ANNOTATION); |
| metaOp.getEAnnotations().add(internalOpAnn); |
| } |
| |
| public abstract Object evaluate(T target, Object[] params); |
| |
| static boolean isInternalOp(EOperation op) { |
| return op.getEAnnotation(INTERNAL_OP_ANNOTATION) != null; |
| } |
| } |
| |
| public static class OperationEx extends Operation { |
| private final InternalOperation<Object> internalOp; |
| private OperationEx(Object targetObject, Object[] args, InternalOperation<Object> internalOp) { |
| super(targetObject, args, internalOp.metaOp); |
| this.internalOp = internalOp; |
| } |
| @Override |
| public Object evaluate() { |
| return internalOp.evaluate(targetObject, args); |
| } |
| } |
| |
| private static final Map<EOperation, Method> externalOpImplementations = new HashMap<EOperation, Method>(); |
| |
| public static void registerOperationImpl(EOperation metaOp, Method implementation) { |
| assert metaOp != null; |
| assert implementation != null; |
| assert Modifier.isStatic(implementation.getModifiers()); |
| externalOpImplementations.put(metaOp, implementation); |
| } |
| |
| public static class Operation { |
| protected final EOperation metaOp; |
| protected final Object[] args; |
| protected final Object targetObject; |
| |
| private Operation(Object targetObject, Object[] args, EOperation metaOp) { |
| this.targetObject = targetObject; |
| this.args = args; |
| this.metaOp = metaOp; |
| |
| } |
| public Object evaluate() { |
| try { |
| final Method m; |
| if (externalOpImplementations.containsKey(metaOp)) { |
| m = externalOpImplementations.get(metaOp); |
| } else { |
| m = targetObject.getClass().getMethod(metaOp.getName(), getParameterClasses()); |
| } |
| return m.invoke(targetObject, args); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private Class[] getParameterClasses() { |
| List<EParameter> emfParams = metaOp.getEParameters(); |
| final Class[] paramClasses = new Class[emfParams.size()]; |
| for (int i = 0, x = emfParams.size(); i < x; i++) { |
| final EParameter param = emfParams.get(i); |
| // XXX works only for generated classes, or those with instance |
| // class set, |
| // and doesn't work with dynamic models, right? |
| paramClasses[i] = param.getEType().getInstanceClass(); |
| } |
| return paramClasses; |
| } |
| } |
| |
| /** |
| * @return true if first argument is more general and second is more |
| * specific, think Object and String |
| * @see AbstractTypeImpl.isAssignableFrom(this, t) |
| */ |
| public static boolean isAssignableFrom(EClassifier c1, EClassifier t) { |
| if ((t == null) || (c1 == null)) { |
| return false; |
| } |
| if (BuiltinMetaModel.primEquals(c1, t)) { |
| return true; |
| } |
| if (t.equals(VOID)) { |
| return true; |
| } |
| if (false == (t instanceof EClass)) { |
| if (c1 instanceof EEnum && t == EcorePackage.eINSTANCE.getEEnumerator()) { |
| return true; // HACK - any enumerator instance can be assigned to any enum attribute. |
| } |
| if (c1 instanceof EDataType && t instanceof EDataType) { |
| return isCompatibleDataTypes((EDataType) c1, (EDataType) t); |
| } |
| return false; |
| } |
| if (c1 instanceof EDataType) { |
| Class c1Class = ((EDataType) c1).getInstanceClass(); |
| return c1Class.isAssignableFrom(t.getInstanceClass() == null ? Object.class : t.getInstanceClass()); |
| } |
| if (isParameterizedType(c1) && isParameterizedType(t)) { |
| return c1.eClass().isSuperTypeOf(t.eClass()) && isAssignableFrom(getInnerType(c1), getInnerType(t)); |
| } |
| // == c1.isSuperTypeOf(t); |
| for (EClass superType : ((EClass) t).getEAllSuperTypes()) { |
| if (BuiltinMetaModel.primEquals(superType, c1)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static boolean primEquals(EClassifier c1, EClassifier obj) { |
| if (obj == null) { |
| return false; |
| } |
| if (c1 == obj) { |
| return true; |
| } |
| final boolean namesEqual = c1.getName().equals(obj.getName()); |
| if (!namesEqual) { |
| return false; |
| } |
| if (c1.getEPackage() == null) { |
| return obj.getEPackage() == null; |
| } |
| if (obj.getEPackage() == null) { |
| return false; |
| } |
| if (c1.getEPackage().getNsURI() == null) { |
| return obj.getEPackage().getNsURI() == null; |
| } |
| return c1.getEPackage().getNsURI().equals(obj.getEPackage().getNsURI()); |
| } |
| |
| private static boolean isCompatibleDataTypes(EDataType dt1, EDataType dt2) { |
| try { |
| final Class dt1Class = dt1.getInstanceClass(); |
| final Class dt2Class = dt2.getInstanceClass(); |
| if (dt1Class != null && dt2Class != null) { |
| if (dt1Class == Object.class) { |
| // anything (with or without wrapping) can be assigned to object |
| return true; |
| } |
| if (dt1Class.isPrimitive() && !dt2Class.isPrimitive()) { |
| Field f = dt2Class.getField("TYPE"); |
| return dt1Class.equals(f.get(null)); |
| } else if (!dt1Class.isPrimitive() && dt2Class.isPrimitive()) { |
| Field f = dt1Class.getField("TYPE"); |
| return dt2Class.equals(f.get(null)); |
| } |
| return dt1Class.isAssignableFrom(dt2Class); |
| } |
| if (dt1Class != null && dt2Class == null) { |
| // special case for dt2 datatype from dynamic model instance |
| // (e.g. model file in same workspace as template) |
| // hence no instance classes yet, but anything is assignable to Object |
| // Fixed while resolving #analyze of enum literals compare (==) |
| return dt1Class == Object.class; |
| } |
| } catch (NoSuchFieldException ex) { |
| // IGNORE |
| } catch (IllegalAccessException ex) { |
| // IGNORE |
| } |
| return false; |
| } |
| public static List<EStructuralFeature> getAllFeatures(EClassifier targetType) { |
| // FIXME @see getAllOperations |
| if (targetType instanceof EClass) { |
| return ((EClass) targetType).getEAllStructuralFeatures(); |
| } |
| return Collections.emptyList(); |
| } |
| |
| public static List<EOperation> getAllOperation(EClassifier targetType) { |
| // FIXME - either have datatypes like int/real as 'honest' EClasses, or |
| // provide their operations here |
| if (hasBuiltinSupport(targetType)) { |
| return findInternalOp(targetType); |
| } |
| if (targetType instanceof EClass) { |
| return ((EClass) targetType).getEAllOperations(); |
| } |
| /* |
| * XXX might be not bad idea to use java reflection to provide |
| * datatype's possible operations if (targetType instanceof EDataType && |
| * false == targetType instanceof EEnum) { EDataType dt = (EDataType) |
| * targetType; dt.getInstanceClass().getMethods() } |
| */ |
| return Collections.emptyList(); |
| } |
| } |