Another patch from Heiko

- Replaces Xtend-Transformer and passes all Tests from AutoTestSuite.
- Added EcoreUtil2.GetCommonCompatibleTyp
see https://bugs.eclipse.org/bugs/attachment.cgi?id=113708
This commit is contained in:
jkohnlein 2008-09-29 08:18:51 +00:00
parent 3db14e20f0
commit b6ccf855d9
10 changed files with 674 additions and 198 deletions

View file

@ -1,13 +1,24 @@
/*******************************************************************************
* Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
@ -17,91 +28,148 @@ import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.xtext.resource.ClassloaderClasspathUriResolver;
import org.eclipse.xtext.resource.XtextResourceSet;
/**
* @author Heiko Behrens
*/
public class EcoreUtil2 extends EcoreUtil {
private static Logger log = Logger.getLogger(EcoreUtil2.class);
@SuppressWarnings("unchecked")
public static <T extends EObject> T getContainerOfType(EObject ele, Class<T> type) {
if (type.isAssignableFrom(ele.getClass()))
return (T) ele;
if (ele.eContainer() != null)
return getContainerOfType(ele.eContainer(), type);
return null;
}
private static Logger log = Logger.getLogger(EcoreUtil2.class);
@SuppressWarnings("unchecked")
public static <T extends EObject> List<T> getAllContentsOfType(EObject ele, Class<T> type) {
List<T> result = new ArrayList<T>();
TreeIterator<EObject> allContents = ele.eAllContents();
while (allContents.hasNext()) {
EObject object = allContents.next();
if (type.isAssignableFrom(object.getClass())) {
result.add((T) object);
}
}
return result;
}
@SuppressWarnings("unchecked")
public static <T extends EObject> T getContainerOfType(EObject ele, Class<T> type) {
if (type.isAssignableFrom(ele.getClass()))
return (T) ele;
if (ele.eContainer() != null)
return getContainerOfType(ele.eContainer(), type);
return null;
}
@SuppressWarnings("unchecked")
public static <T> List<T> typeSelect(List<?> elements, Class<T> clazz) {
List<T> result = new ArrayList<T>();
for (Object ele : elements) {
if (ele != null && clazz.isAssignableFrom(ele.getClass())) {
result.add((T) ele);
}
}
return result;
}
@SuppressWarnings("unchecked")
public static <T extends EObject> List<T> getAllContentsOfType(EObject ele, Class<T> type) {
List<T> result = new ArrayList<T>();
TreeIterator<EObject> allContents = ele.eAllContents();
while (allContents.hasNext()) {
EObject object = allContents.next();
if (type.isAssignableFrom(object.getClass())) {
result.add((T) object);
}
}
return result;
}
public static List<EObject> eAllContentsAsList(EObject ele) {
List<EObject> result = new ArrayList<EObject>();
TreeIterator<EObject> iterator = ele.eAllContents();
while (iterator.hasNext())
result.add(iterator.next());
return result;
}
@SuppressWarnings("unchecked")
public static <T> List<T> typeSelect(List<?> elements, Class<T> clazz) {
List<T> result = new ArrayList<T>();
for (Object ele : elements) {
if (ele != null && clazz.isAssignableFrom(ele.getClass())) {
result.add((T) ele);
}
}
return result;
}
/**
public static List<EObject> eAllContentsAsList(EObject ele) {
List<EObject> result = new ArrayList<EObject>();
TreeIterator<EObject> iterator = ele.eAllContents();
while (iterator.hasNext())
result.add(iterator.next());
return result;
}
/**
*/
public static final EPackage loadEPackage(String uriAsString, ClassLoader classLoader) {
if (EPackage.Registry.INSTANCE.containsKey(uriAsString))
return EPackage.Registry.INSTANCE.getEPackage(uriAsString);
URI uri = URI.createURI(uriAsString);
uri = new ClassloaderClasspathUriResolver().resolve(classLoader, uri);
Resource resource = new ResourceSetImpl().getResource(uri, true);
for (TreeIterator<EObject> allContents = resource.getAllContents(); allContents.hasNext();) {
EObject next = allContents.next();
if (next instanceof EPackage) {
EPackage ePackage = (EPackage) next;
// if (ePackage.getNsURI() != null && ePackage.getNsURI().equals(uriAsString)) {
return ePackage;
// }
}
}
log.error("Could not load EPackage with nsURI" + uriAsString);
return null;
}
public static final EPackage loadEPackage(String uriAsString, ClassLoader classLoader) {
if (EPackage.Registry.INSTANCE.containsKey(uriAsString))
return EPackage.Registry.INSTANCE.getEPackage(uriAsString);
URI uri = URI.createURI(uriAsString);
uri = new ClassloaderClasspathUriResolver().resolve(classLoader, uri);
Resource resource = new ResourceSetImpl().getResource(uri, true);
for (TreeIterator<EObject> allContents = resource.getAllContents(); allContents.hasNext();) {
EObject next = allContents.next();
if (next instanceof EPackage) {
EPackage ePackage = (EPackage) next;
// if (ePackage.getNsURI() != null &&
// ePackage.getNsURI().equals(uriAsString)) {
return ePackage;
// }
}
}
log.error("Could not load EPackage with nsURI" + uriAsString);
return null;
}
public static void saveEPackage(EPackage ePackage, String path) throws IOException {
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("ecore", new XMIResourceFactoryImpl());
URI uri = URI.createFileURI(path + "/" + ePackage.getName() + ".ecore");
Resource metaModelResource = new ResourceSetImpl().createResource(uri);
metaModelResource.getContents().add(ePackage);
metaModelResource.save(null);
}
public static void saveEPackage(EPackage ePackage, String path) throws IOException {
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("ecore", new XMIResourceFactoryImpl());
URI uri = URI.createFileURI(path + "/" + ePackage.getName() + ".ecore");
Resource metaModelResource = new ResourceSetImpl().createResource(uri);
metaModelResource.getContents().add(ePackage);
metaModelResource.save(null);
}
public static String getURIFragment(EObject eObject) {
Resource resource = eObject.eResource();
String fragment = resource.getURIFragment(eObject);
return fragment;
}
public static String getURIFragment(EObject eObject) {
Resource resource = eObject.eResource();
String fragment = resource.getURIFragment(eObject);
return fragment;
}
public static EList<EObject> loadModel(String string, ClassLoader classLoader) {
URI uri = URI.createURI(string);
XtextResourceSet xtextResourceSet = new XtextResourceSet();
xtextResourceSet.setClasspathURIContext(classLoader);
XtextResourceSet xtextResourceSet = new XtextResourceSet();
xtextResourceSet.setClasspathURIContext(classLoader);
Resource resource = xtextResourceSet.getResource(uri, true);
return resource.getContents();
}
public static EClassifier getCompatibleType(EClassifier typeA, EClassifier typeB) {
if (typeA.equals(typeB))
return typeA;
// no common type for simple datatypes available
if (!(typeA instanceof EClass && typeB instanceof EClass))
return null;
List<EClass> sortedCandidates = getSortedCommonCompatibleTypeCandidates((EClass) typeA, (EClass) typeB);
for (EClass candidate : sortedCandidates)
if (isCommonCompatibleType(candidate, sortedCandidates))
return candidate;
return null;
}
private static class EClassTypeHierarchyComparator implements Comparator<EClass> {
public int compare(EClass classA, EClass classB) {
if (classA.getEAllSuperTypes().contains(classB))
return -1;
if (classB.getEAllSuperTypes().contains(classA))
return 1;
else
return 0;
}
}
private static boolean isLooslyCompatibleWith(EClass classA, EClass classB) {
return classA.equals(classB) || classA.getEAllSuperTypes().contains(classB)
|| classB.getEAllSuperTypes().contains(classA);
}
private static boolean isCommonCompatibleType(EClass candidate, List<EClass> candidates) {
for (EClass otherCandidate : candidates)
if (!isLooslyCompatibleWith(candidate, otherCandidate))
return false;
return true;
}
private static List<EClass> getSortedCommonCompatibleTypeCandidates(EClass classA, EClass classB) {
List<EClass> ca = new ArrayList<EClass>(classA.getEAllSuperTypes());
ca.add(classA);
List<EClass> cb = new ArrayList<EClass>(classB.getEAllSuperTypes());
cb.add(classB);
cb.retainAll(ca);
ca.retainAll(cb);
List<EClass> intersection = ca;
Collections.sort(intersection, new EClassTypeHierarchyComparator());
return intersection;
}
}

View file

@ -307,6 +307,10 @@ public class GrammarUtil {
public static boolean isMultipleAssignment(Assignment a) {
return "+=".equals(a.getOperator());
}
public static boolean isMultipleAssignment(Action a) {
return "+=".equals(a.getOperator());
}
public static boolean isOptionalCardinality(AbstractElement e) {
return e.getCardinality() != null && (e.getCardinality().equals("?") || e.getCardinality().equals("*"));

View file

@ -12,8 +12,12 @@ import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.resource.metamodel.ErrorAcceptor.ErrorCode;
/**
* @author Jan Köhnlein - Initial contribution and API
@ -49,7 +53,8 @@ public abstract class EClassifierInfo {
public abstract boolean addSupertype(EClassifierInfo superTypeInfo);
public abstract boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue);
public abstract boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue,
boolean isContainment, EObject parserElement) throws TransformationException;
static class EClassInfo extends EClassifierInfo {
@ -65,19 +70,40 @@ public abstract class EClassifierInfo {
if (!(superTypeInfo instanceof EClassInfo)) {
throw new IllegalArgumentException("superTypeInfo must represent EClass");
}
EClass eClass = (EClass) getEClassifier();
EClass eClass = getEClass();
EClass superEClass = (EClass) superTypeInfo.getEClassifier();
return eClass.getESuperTypes().add(superEClass);
if(eClass.equals(superEClass))
// cannot add class as it's own superclass
// this usually happens due to a rule call
return false;
else
return eClass.getESuperTypes().add(superEClass);
}
private EStructuralFeature findFeatureInClassIgnoringSuperclasses(EClass eClass, String featureName) {
for (EStructuralFeature feature : eClass.getEStructuralFeatures())
if (feature.getName().equals(featureName))
return feature;
return null;
}
@Override
public boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue) {
public boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue,
boolean isContainment, EObject parserElement) throws TransformationException {
EClassifier featureClassifier = featureType.getEClassifier();
return addFeature(featureName, featureClassifier, isMultivalue, isContainment, parserElement);
}
private boolean addFeature(String featureName, EClassifier featureClassifier, boolean isMultivalue,
boolean isContainment, EObject parserElement) throws TransformationException {
EStructuralFeature newFeature;
if (featureClassifier instanceof EClass)
newFeature = EcoreFactory.eINSTANCE.createEReference();
if (featureClassifier instanceof EClass) {
EReference reference = EcoreFactory.eINSTANCE.createEReference();
reference.setContainment(isContainment);
newFeature = reference;
}
else
newFeature = EcoreFactory.eINSTANCE.createEAttribute();
newFeature.setName(featureName);
@ -85,8 +111,40 @@ public abstract class EClassifierInfo {
newFeature.setLowerBound(0);
newFeature.setUpperBound(isMultivalue ? -1 : 1);
EList<EStructuralFeature> features = ((EClass) getEClassifier()).getEStructuralFeatures();
return features.add(newFeature);
EList<EStructuralFeature> features = getEClass().getEStructuralFeatures();
EStructuralFeature existentFeature = findFeatureInClassIgnoringSuperclasses(getEClass(), featureName);
if (existentFeature == null) {
// feature does not exist, yet
return features.add(newFeature);
}
else {
if (newFeature.getLowerBound() != existentFeature.getLowerBound()
|| newFeature.getUpperBound() != existentFeature.getUpperBound())
throw new TransformationException(ErrorCode.FeatureWithDifferentConfigurationAlreadyExists,
"feature with different cardinality already exists " + newFeature, parserElement);
else {
// TODO Extract into something more genreral that can be used for uplifting
// same name but different type => feature should have
// compatible type
// remove and add again to overcome problem with reference
// vs. attribute
EClassifier compatibleType = EcoreUtil2.getCompatibleType(existentFeature.getEType(), newFeature
.getEType());
if (compatibleType == null)
throw new TransformationException(ErrorCode.NoCompatibleFeatureTypeAvailable,
"Cannot find compatible type for features", parserElement);
int oldIndex = features.indexOf(existentFeature);
features.remove(existentFeature);
addFeature(featureName, compatibleType, isMultivalue, isContainment, parserElement);
existentFeature = findFeatureInClassIgnoringSuperclasses(getEClass(), featureName);
features.move(oldIndex, existentFeature);
return true;
}
}
}
private EClass getEClass() {
return ((EClass) getEClassifier());
}
}
@ -102,7 +160,8 @@ public abstract class EClassifierInfo {
}
@Override
public boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue) {
public boolean addFeature(String featureName, EClassifierInfo featureType, boolean isMultivalue,
boolean isContainment, EObject parserElement) throws TransformationException {
throw new UnsupportedOperationException("Cannot add feature to simple datatype");
}

View file

@ -10,12 +10,14 @@ package org.eclipse.xtext.resource.metamodel;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.TypeRef;
@ -47,48 +49,62 @@ public class EClassifierInfos {
return infoMap.get(qualifiedName);
}
private EClassifierInfo getInfo(EClassifier eClassifier) {
for(EClassifierInfo info: infoMap.values())
if(info.getEClassifier().equals(eClassifier))
return info;
return null;
}
public void addAll(EClassifierInfos classInfos) {
infoMap.putAll(classInfos.infoMap);
}
private String getCompatibleTypeNameOf(String typeA, String typeB) {
EClassifier classifierA = getInfo(typeA).getEClassifier();
EClassifier classifierB = getInfo(typeB).getEClassifier();
if (classifierA.equals(classifierB))
return typeA;
if (classifierA instanceof EDataType || classifierB instanceof EDataType)
throw new IllegalArgumentException(
"Simple Datatypes (lexer rules or keywords) do not have a common supertype (" + typeA + ", "
+ typeB + ")");
private EClassifierInfo getCompatibleType(EClassifierInfo infoA, EClassifierInfo infoB) {
if (infoA.equals(infoB))
return infoA;
// TODO EClass commonSupertype = EcoreUtil2.getCommonCompatibleType((EClass) classifierA, (EClass) classifierB);
EClass commonSupertype = classifierA.equals(classifierB) ? (EClass)classifierA : null;
if(commonSupertype != null)
return getQualifiedNameFor(commonSupertype);
else
return "ecore::EObject";
if (infoA.getEClassifier() instanceof EDataType || infoB.getEClassifier() instanceof EDataType)
throw new IllegalArgumentException(
"Simple Datatypes (lexer rules or keywords) do not have a common supertype (" + infoA + ", "
+ infoB + ")");
EClassifier compatibleType = EcoreUtil2.getCompatibleType((EClass)infoA.getEClassifier(), (EClass)infoB.getEClassifier());
return getInfo(compatibleType);
}
private String getQualifiedNameFor(EClass eClass) {
private String getQualifiedNameFor(EClassifierInfo classifierInfo) {
// lookup could be improved
for (String key : infoMap.keySet()) {
EClassifierInfo info = infoMap.get(key);
if (info.getEClassifier().equals(eClass))
if (info.equals(classifierInfo))
return key;
}
return null;
}
public String getCompatibleTypeNameOf(Collection<String> typeNames) {
Iterator<String> i = typeNames.iterator();
public EClassifierInfo getCompatibleTypeOf(Collection<EClassifierInfo> types) {
Iterator<EClassifierInfo> i = types.iterator();
if (!i.hasNext())
throw new IllegalArgumentException("Empty set of types cannot have a common super type.");
throw new IllegalArgumentException("Empty set of types cannot have a compatible type.");
String result = i.next();
EClassifierInfo result = i.next();
while (i.hasNext())
result = getCompatibleTypeNameOf(result, i.next());
result = getCompatibleType(result, i.next());
return result;
}
public String getCompatibleTypeNameOf(Collection<String> typeNames) {
Collection<EClassifierInfo> types = new HashSet<EClassifierInfo>();
for (String typeName : typeNames)
types.add(getInfo(typeName));
EClassifierInfo compatibleType = getCompatibleTypeOf(types);
if (compatibleType != null)
return getQualifiedNameFor(compatibleType);
else
return "ecore::EObject";
}
}

View file

@ -16,12 +16,8 @@ import org.eclipse.emf.ecore.EObject;
*/
public interface ErrorAcceptor {
public enum ErrorCode {
NoSuchTypeAvailable,
MoreThanOneTypeChangeInOneRule,
CannotLoadMetamodel,
MissingAliasForReferencedMetamodel,
CannotCreateTypeInSealedMetamodel
NoSuchTypeAvailable, MoreThanOneTypeChangeInOneRule, CannotLoadMetamodel, CannotCreateTypeInSealedMetamodel, FeatureWithDifferentConfigurationAlreadyExists, NoCompatibleFeatureTypeAvailable, AliasForMetamodelAlreadyExists
}
public void acceptError(ErrorCode errorCode, String message, EObject element);
}

View file

@ -16,6 +16,7 @@ import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.Alternatives;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.CrossReference;
@ -62,6 +63,7 @@ public class Xtext2ECoreInterpretationContext {
public void addFeature(Assignment assignment) throws TransformationException {
String featureName = assignment.getFeature();
boolean isMultivalue = GrammarUtil.isMultipleAssignment(assignment);
boolean isContainment = true;
EClassifierInfo featureTypeInfo;
if (GrammarUtil.isBooleanAssignment(assignment)) {
@ -70,11 +72,17 @@ public class Xtext2ECoreInterpretationContext {
}
else {
String featureTypeName = getTerminalTypeName(assignment.getTerminal());
isContainment = !(assignment.getTerminal() instanceof CrossReference);
featureTypeInfo = getEClassifierInfoOrThrowException(featureTypeName, assignment);
}
addFeature(featureName, featureTypeInfo, isMultivalue, isContainment, assignment);
}
public void addFeature(String featureName, EClassifierInfo featureTypeInfo, boolean isMultivalue,
boolean isContainment, EObject parserElement) throws TransformationException {
for (EClassifierInfo type : currentTypes)
type.addFeature(featureName, featureTypeInfo, isMultivalue);
type.addFeature(featureName, featureTypeInfo, isMultivalue, isContainment, parserElement);
}
private String getTerminalTypeName(AbstractElement terminal) {
@ -87,6 +95,8 @@ public class Xtext2ECoreInterpretationContext {
CrossReference crossReference = (CrossReference) terminal;
return GrammarUtil.getQualifiedName(crossReference.getType());
}
else if (terminal instanceof Keyword)
return "ecore::EString";
else {
// terminal is ParenthesizedElement
// must be either: alternative of lexer rules and keywords or
@ -136,7 +146,7 @@ public class Xtext2ECoreInterpretationContext {
return result;
}
public Xtext2ECoreInterpretationContext spawnContextWith(EClassifierInfo newType, EObject parserElement)
public Xtext2ECoreInterpretationContext spawnContextWithCalledRule(EClassifierInfo newType, EObject parserElement)
throws TransformationException {
if (!isRuleCallAllowed)
throw new TransformationException(ErrorCode.MoreThanOneTypeChangeInOneRule,
@ -156,4 +166,12 @@ public class Xtext2ECoreInterpretationContext {
return result;
}
public EClassifierInfo getCurrentCompatibleType() {
return eClassifierInfos.getCompatibleTypeOf(currentTypes);
}
public Xtext2ECoreInterpretationContext spawnContextWithReferencedType(EClassifierInfo referencedType, EObject parserElement) {
return new Xtext2ECoreInterpretationContext(referencedType, eClassifierInfos, false);
}
}

View file

@ -9,9 +9,13 @@
package org.eclipse.xtext.resource.metamodel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
@ -66,6 +70,17 @@ public class Xtext2EcoreTransformer {
public Xtext2EcoreTransformer() {
}
public static List<EPackage> doTransform(Grammar grammar) throws Exception {
Xtext2EcoreTransformer transformer = new Xtext2EcoreTransformer();
try {
return transformer.transform(grammar);
}
catch (Exception e) {
e.printStackTrace();
throw e;
}
}
/*
* pre-conditions - ensure non-duplicate aliases - ensure all aliases have
* matching metamodel declarations
@ -73,20 +88,33 @@ public class Xtext2EcoreTransformer {
public List<EPackage> transform(Grammar grammar) {
this.grammar = grammar;
eClassifierInfos = new EClassifierInfos();
generatedEPackages = new HashMap<String, EPackage>();
superGrammar = GrammarUtil.getSuperGrammar(grammar);
eClassifierInfos = new EClassifierInfos();
if (superGrammar != null)
collectEClassInfosOfSuperGrammar();
collectEPackages();
// create types:
// iterate rules
// - typeref in actions
// type hierarchy
// - actions
deriveTypes();
deriveFeatures();
normalizeGeneratedPackages();
return getGeneratedPackagesSortedByName();
}
private List<EPackage> getGeneratedPackagesSortedByName() {
ArrayList<EPackage> result = new ArrayList<EPackage>(generatedEPackages.values());
Collections.sort(result, new Comparator<EPackage>() {
public int compare(EPackage o1, EPackage o2) {
return o1.getName().compareTo(o2.getName());
}
});
return result;
}
private void deriveTypes() {
for (AbstractRule rule : grammar.getRules()) {
// - return types (lexer and parser rules)
try {
EClassifierInfo generatedEClass = findOrCreateEClass(rule);
if (rule instanceof ParserRule) {
@ -95,13 +123,12 @@ public class Xtext2EcoreTransformer {
}
}
catch (TransformationException e) {
reportError(e.getErrorCode(), e.getMessage(), e.getErroneousElement());
reportError(e);
}
}
}
// create features
// iterate rules
// - feature in actions
private void deriveFeatures() {
for (AbstractRule rule : grammar.getRules()) {
try {
if (rule instanceof ParserRule) {
@ -109,17 +136,9 @@ public class Xtext2EcoreTransformer {
}
}
catch (TransformationException e) {
reportError(e.getErrorCode(), e.getMessage(), e.getErroneousElement());
reportError(e);
}
}
// feature normalization
// - uplift of common feature to supertype
// - removal in subtype if already in supertype
// - don't combine features with different EDatatypes
fillGeneratedPackages();
return new ArrayList<EPackage>(generatedEPackages.values());
}
private void collectEClassInfosOfSuperGrammar() {
@ -151,7 +170,17 @@ public class Xtext2EcoreTransformer {
else if (element instanceof RuleCall && !GrammarUtil.isOptionalCardinality(element)) {
RuleCall ruleCall = (RuleCall) element;
AbstractRule calledRule = GrammarUtil.findRuleForName(grammar, ruleCall.getName());
return context.spawnContextWith(findOrCreateEClass(calledRule), ruleCall);
return context.spawnContextWithCalledRule(findOrCreateEClass(calledRule), ruleCall);
}
else if (element instanceof Action) {
Action action = (Action) element;
TypeRef actionTypeRef = action.getTypeName();
EClassifierInfo actionType = findOrCreateEClass(actionTypeRef);
EClassifierInfo currentCompatibleType = context.getCurrentCompatibleType();
context = context.spawnContextWithReferencedType(actionType, action);
context.addFeature(action.getFeature(), currentCompatibleType, GrammarUtil.isMultipleAssignment(action),
true, action);
return context;
}
return context;
@ -184,8 +213,15 @@ public class Xtext2EcoreTransformer {
return result;
}
private void fillGeneratedPackages() {
private void normalizeGeneratedPackages() {
// TODO Implement
// feature normalization
// - uplift of common feature to supertype
// - removal in subtype if already in supertype
// - don't combine features with different EDatatypes
// NOTE: package dependencies
}
private void deriveTypesAndHierarchy(EClassifierInfo ruleReturnType, AbstractElement element)
@ -224,43 +260,49 @@ public class Xtext2EcoreTransformer {
}
private void collectEPackages() {
// TODO derive alias configuration from supergrammar
Set<String> usedAliases = new HashSet<String>();
EList<AbstractMetamodelDeclaration> metamodelDeclarations = grammar.getMetamodelDeclarations();
for (AbstractMetamodelDeclaration metamodelDeclaration : metamodelDeclarations) {
if (metamodelDeclaration instanceof ReferencedMetamodel) {
// load imported metamodel
ReferencedMetamodel referencedMetamodel = (ReferencedMetamodel) metamodelDeclaration;
EPackage referencedEPackage;
try {
referencedEPackage = GrammarUtil.loadEPackage(referencedMetamodel);
}
catch (RuntimeException e) {
referencedEPackage = null;
}
if (referencedEPackage == null) {
reportError(ErrorCode.CannotLoadMetamodel, "Cannot not load metamodel "
+ referencedMetamodel.getUri(), referencedMetamodel);
}
else {
String alias = referencedMetamodel.getAlias();
if (Strings.isEmpty(alias)) {
reportError(ErrorCode.MissingAliasForReferencedMetamodel,
"Referenced metamodels must have an alias", referencedMetamodel);
try {
String alias = Strings.emptyIfNull(metamodelDeclaration.getAlias());
if (usedAliases.contains(alias))
throw new TransformationException(ErrorCode.AliasForMetamodelAlreadyExists, "alias already exists "
+ alias, metamodelDeclaration);
usedAliases.add(alias);
if (metamodelDeclaration instanceof ReferencedMetamodel) {
// load imported metamodel
ReferencedMetamodel referencedMetamodel = (ReferencedMetamodel) metamodelDeclaration;
EPackage referencedEPackage;
try {
referencedEPackage = GrammarUtil.loadEPackage(referencedMetamodel);
}
else {
collectClassInfosOf(referencedEPackage, alias);
catch (RuntimeException e) {
referencedEPackage = null;
}
if (referencedEPackage == null)
throw new TransformationException(ErrorCode.CannotLoadMetamodel, "Cannot not load metamodel "
+ referencedMetamodel.getUri(), referencedMetamodel);
collectClassInfosOf(referencedEPackage, alias);
}
else if (metamodelDeclaration instanceof GeneratedMetamodel) {
// instantiate EPackages for generated metamodel
GeneratedMetamodel generatedMetamodel = (GeneratedMetamodel) metamodelDeclaration;
EPackage generatedEPackage = EcoreFactory.eINSTANCE.createEPackage();
generatedEPackage.setName(generatedMetamodel.getName());
generatedEPackage.setNsPrefix(generatedMetamodel.getName());
generatedEPackage.setNsURI(generatedMetamodel.getNsURI());
generatedEPackages.put(alias, generatedEPackage);
}
}
else if (metamodelDeclaration instanceof GeneratedMetamodel) {
// instantiate EPackages for generated metamodel
GeneratedMetamodel generatedMetamodel = (GeneratedMetamodel) metamodelDeclaration;
EPackage generatedEPackage = EcoreFactory.eINSTANCE.createEPackage();
generatedEPackage.setName(generatedMetamodel.getName());
generatedEPackage.setNsPrefix(generatedMetamodel.getName());
generatedEPackage.setNsURI(generatedMetamodel.getNsURI());
String alias = Strings.emptyIfNull(generatedMetamodel.getAlias());
generatedEPackages.put(alias, generatedEPackage);
catch (TransformationException e) {
reportError(e);
}
}
}
@ -284,6 +326,10 @@ public class Xtext2EcoreTransformer {
errorAcceptor.acceptError(errorCode, message, erroneousElement);
}
private void reportError(TransformationException exception) {
reportError(exception.getErrorCode(), exception.getMessage(), exception.getErroneousElement());
}
private EClassifierInfo findOrCreateEClass(AbstractRule rule) throws TransformationException {
TypeRef typeRef = getOrFakeReturnType(rule);
return findOrCreateEClass(typeRef);

View file

@ -0,0 +1,68 @@
/*******************************************************************************
* Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext;
import junit.framework.TestCase;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EcoreFactory;
/**
* @author Heiko Behrens - Initial contribution and API
*/
public class EcoreUtil2Tests extends TestCase {
private EClass createEClass(String name) {
EClass result = EcoreFactory.eINSTANCE.createEClass();
result.setName(name);
return result;
}
public void testCommonCompatibleType01() {
EClass a = createEClass("a");
EClass b = createEClass("b");
EClass c = createEClass("c");
EClass d = createEClass("d");
EClass e = createEClass("e");
EClass f = createEClass("f");
c.getESuperTypes().add(a);
d.getESuperTypes().add(c);
d.getESuperTypes().add(b);
e.getESuperTypes().add(c);
f.getESuperTypes().add(a);
f.getESuperTypes().add(b);
f.getESuperTypes().add(e);
assertSame(a, EcoreUtil2.getCompatibleType(a, a));
assertSame(null, EcoreUtil2.getCompatibleType(d, f));
assertSame(c, EcoreUtil2.getCompatibleType(d, e));
assertSame(b, EcoreUtil2.getCompatibleType(b, f));
assertSame(null, EcoreUtil2.getCompatibleType(b, c));
}
public void testCommonCompatibleType02() {
EClass a = createEClass("a");
EClass b = createEClass("b");
EClass c = createEClass("c");
EClass d = createEClass("d");
EClass e = createEClass("e");
b.getESuperTypes().add(a);
c.getESuperTypes().add(a);
d.getESuperTypes().add(b);
d.getESuperTypes().add(c);
e.getESuperTypes().add(b);
e.getESuperTypes().add(c);
assertSame(a, EcoreUtil2.getCompatibleType(a, a));
assertSame(a, EcoreUtil2.getCompatibleType(b, c));
assertSame(b, EcoreUtil2.getCompatibleType(b, d));
assertSame(a, EcoreUtil2.getCompatibleType(d, e));
}
}

View file

@ -13,6 +13,7 @@ public class AutoTestSuite {
public static Test suite() {
TestSuite suite = new TestSuite("org.eclipse.xtext.generator.tests");
suite.addTestSuite(org.eclipse.xtext.XtextGrammarTest.class);
suite.addTestSuite(org.eclipse.xtext.EcoreUtil2Tests.class);
suite.addTestSuite(org.eclipse.xtext.generator.resource.ResourceTest.class);
suite.addTestSuite(org.eclipse.xtext.grammarinheritance.InheritanceTest.class);
suite.addTestSuite(org.eclipse.xtext.grammarinheritance.ToEcoreTrafoTest.class);

View file

@ -43,22 +43,27 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
errorAcceptorMock = createMock(ErrorAcceptor.class);
with(XtextStandaloneSetup.class);
}
private EPackage getEPackageFromGrammar(String xtextGrammar) throws Exception {
Grammar grammar = (Grammar) getModel(xtextGrammar);
replay(errorAcceptorMock);
xtext2EcoreTransformer.setErrorAcceptor(errorAcceptorMock);
List<EPackage> metamodels = xtext2EcoreTransformer.transform(grammar);
verify(errorAcceptorMock);
assertNotNull(metamodels);
List<EPackage> metamodels = getEPackagesFromGrammar(xtextGrammar);
assertEquals(1, metamodels.size());
EPackage result = metamodels.get(0);
assertNotNull(result);
return result;
}
private List<EPackage> getEPackagesFromGrammar(String xtextGrammar) throws Exception {
Grammar grammar = (Grammar) getModel(xtextGrammar);
replay(errorAcceptorMock);
xtext2EcoreTransformer.setErrorAcceptor(errorAcceptorMock);
List<EPackage> metamodels = xtext2EcoreTransformer.transform(grammar);
verify(errorAcceptorMock);
assertNotNull(metamodels);
return metamodels;
}
private EAttribute assertAttributeConfiguration(EClass eClass, int attributeIndex, String featureName,
String featureTypeName) {
EAttribute feature = eClass.getEAttributes().get(attributeIndex);
@ -77,19 +82,19 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
return feature;
}
private EReference assertReferenceConfiguration(EClass eClass, int referenceIndex, String featureName,
String featureTypeName, int lowerBound, int upperBound) {
String featureTypeName, boolean isContainment, int lowerBound, int upperBound) {
EReference reference = eClass.getEReferences().get(referenceIndex);
assertEquals(featureName, reference.getName());
assertNotNull(reference.getEType());
assertEquals(featureTypeName, reference.getEType().getName());
assertEquals(isContainment, reference.isContainment());
assertEquals(lowerBound, reference.getLowerBound());
assertEquals(upperBound, reference.getUpperBound());
return reference;
}
public void testTypesOfImplicitSuperGrammar() throws Exception {
final String xtextGrammar = "language test generate test 'http://test' MyRule: myFeature=INT;";
Grammar grammar = (Grammar) getModel(xtextGrammar);
@ -307,6 +312,72 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertAttributeConfiguration(ruleD, 3, "featureD2", "EString");
}
public void testFeaturesAndInheritanceOfActions01() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: ({Add.a=current} '+'|{Sub.a=current} '-') featureAS=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(3, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
assertNotNull(ruleA);
EClass add = (EClass) ePackage.getEClassifier("Add");
assertNotNull(add);
EClass sub = (EClass) ePackage.getEClassifier("Sub");
assertNotNull(sub);
// test inheritance
assertTrue(ruleA.getESuperTypes().isEmpty());
assertEquals(1, add.getESuperTypes().size());
assertEquals(ruleA, add.getESuperTypes().get(0));
assertEquals(1, sub.getESuperTypes().size());
assertEquals(ruleA, sub.getESuperTypes().get(0));
// test features
assertEquals(0, ruleA.getEAttributes().size());
assertEquals(1, add.getEAttributes().size());
assertAttributeConfiguration(add, 0, "featureAS", "EString");
assertEquals(1, add.getEReferences().size());
assertReferenceConfiguration(add, 0, "a", "RuleA", true, 0, 1);
assertEquals(1, sub.getEAttributes().size());
assertAttributeConfiguration(sub, 0, "featureAS", "EString");
assertEquals(1, sub.getEReferences().size());
assertReferenceConfiguration(sub, 0, "a", "RuleA", true, 0, 1);
}
public void testFeaturesAndInheritanceOfActions02() throws Exception {
String grammar = "";
grammar += "language org.eclipse.xtext.testlanguages.ActionTestLanguage ";
grammar += "generate ActionLang";
grammar += " 'http://www.eclipse.org/2008/tmf/xtext/ActionLang'";
grammar += "";
grammar += " Model:";
grammar += " (children+=Element)*;";
grammar += "";
grammar += " Element returns Type:";
grammar += " Item ( { Item.items+=current } items+=Item );";
grammar += "";
grammar += " Item returns Type:";
grammar += " { Thing.content=current } name=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(4, ePackage.getEClassifiers().size());
EClass model = (EClass) ePackage.getEClassifier("Model");
assertNotNull(model);
EClass type = (EClass) ePackage.getEClassifier("Type");
assertNotNull(type);
EClass item = (EClass) ePackage.getEClassifier("Item");
assertNotNull(item);
EClass thing = (EClass) ePackage.getEClassifier("Thing");
assertNotNull(thing);
// type hierarchy
assertEquals(0, model.getESuperTypes().size());
assertEquals(0, type.getESuperTypes().size());
assertEquals(1, item.getESuperTypes().size());
assertSame(type, item.getESuperTypes().get(0));
assertEquals(1, thing.getESuperTypes().size());
assertSame(type, thing.getESuperTypes().get(0));
}
public void testAssignedRuleCall() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: callA1=RuleB callA2+=RuleB simpleFeature=ID; RuleB: featureB=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
@ -315,12 +386,12 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertNotNull(ruleA);
EClass ruleB = (EClass) ePackage.getEClassifier("RuleB");
assertNotNull(ruleB);
assertEquals(1, ruleA.getEAttributes().size());
assertAttributeConfiguration(ruleA, 0, "simpleFeature", "EString");
assertEquals(2, ruleA.getEReferences().size());
assertReferenceConfiguration(ruleA, 0, "callA1", "RuleB", 0, 1);
assertReferenceConfiguration(ruleA, 1, "callA2", "RuleB", 0, -1);
assertReferenceConfiguration(ruleA, 0, "callA1", "RuleB", true, 0, 1);
assertReferenceConfiguration(ruleA, 1, "callA2", "RuleB", true, 0, -1);
assertEquals(1, ruleB.getEAttributes().size());
assertAttributeConfiguration(ruleB, 0, "featureB", "EString");
}
@ -333,19 +404,24 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertNotNull(ruleA);
EClass typeB = (EClass) ePackage.getEClassifier("TypeB");
assertNotNull(typeB);
assertEquals(1, ruleA.getEAttributes().size());
assertAttributeConfiguration(ruleA, 0, "simpleFeature", "EString");
assertEquals(2, ruleA.getEReferences().size());
assertReferenceConfiguration(ruleA, 0, "refA1", "TypeB", 0, 1);
assertReferenceConfiguration(ruleA, 1, "refA2", "TypeB", 0, -1);
assertReferenceConfiguration(ruleA, 0, "refA1", "TypeB", false, 0, 1);
assertReferenceConfiguration(ruleA, 1, "refA2", "TypeB", false, 0, -1);
assertEquals(1, typeB.getEAttributes().size());
assertAttributeConfiguration(typeB, 0, "featureB", "EString");
}
public void testAssignedParenthesizedElement() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: featureA1?=(RuleB) refA1=(RuleB) refA2=(RuleB|RuleC) refA3+=(RuleB|RuleC|RuleD) refA4=(RuleB|RuleD) featureA2+=('a'|'b'); RuleB returns TypeB: RuleC? featureB=ID; RuleC: featureC=ID; RuleD returns TypeB: featureD=ID;";
String grammar = " language test generate test 'http://test'";
grammar += " RuleA: featureA1?=(RuleB) refA1=(RuleB) refA2=(RuleB|RuleC) refA3+=(RuleB|RuleC|RuleD) refA4=(RuleB|RuleD) featureA2+=('a'|'b');";
grammar += " RuleB returns TypeB: RuleC? featureB=ID;";
grammar += " RuleC: featureC=ID;";
grammar += " RuleD returns TypeB: featureD=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(3, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
assertNotNull(ruleA);
@ -357,41 +433,165 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertNotNull(ruleC);
assertEquals(1, ruleC.getESuperTypes().size());
assertEquals(typeB, ruleC.getESuperTypes().get(0));
assertEquals(2, ruleA.getEAttributes().size());
assertAttributeConfiguration(ruleA, 0, "featureA1", "EBoolean");
assertAttributeConfiguration(ruleA, 1, "featureA2", "EString", 0, -1);
assertEquals(4, ruleA.getEReferences().size());
assertReferenceConfiguration(ruleA, 0, "refA1", "TypeB", 0, 1);
assertReferenceConfiguration(ruleA, 0, "refA1", "TypeB", true, 0, 1);
// TODO should be common compatible type according to #248430
assertReferenceConfiguration(ruleA, 1, "refA2", "EObject", 0, 1);
assertReferenceConfiguration(ruleA, 2, "refA3", "EObject", 0, -1);
assertReferenceConfiguration(ruleA, 3, "refA4", "TypeB", 0, 1);
assertReferenceConfiguration(ruleA, 1, "refA2", "TypeB", true, 0, 1);
assertReferenceConfiguration(ruleA, 2, "refA3", "TypeB", true, 0, -1);
assertReferenceConfiguration(ruleA, 3, "refA4", "TypeB", true, 0, 1);
}
public void testAssignedKeyWord() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: featureA?=('+'|'-') featureB=('*'|'/');";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(1, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
assertEquals(2, ruleA.getEAttributes().size());
assertAttributeConfiguration(ruleA, 0, "featureA", "EBoolean", 0, 1);
assertAttributeConfiguration(ruleA, 1, "featureB", "EString", 0, 1);
}
public void testImportWithoutAlias() throws Exception {
final String grammar = "language test generate test 'http://test' import 'http://www.eclipse.org/emf/2002/Ecore' RuleA: feature=ID;";
errorAcceptorMock.acceptError(same(ErrorCode.MissingAliasForReferencedMetamodel), (String)anyObject(), (EObject)anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.AliasForMetamodelAlreadyExists), (String) anyObject(),
(EObject) anyObject());
getEPackageFromGrammar(grammar);
}
public void testGenerateTwoModels() throws Exception {
String grammar = "";
grammar += " language test";
grammar += " generate t1 'http://t1'";
grammar += " generate t2 'http://t2' as t2";
grammar += " RuleA: featureA=ID;";
grammar += " RuleB returns t2::TypeB: featureB=ID;";
List<EPackage> ePackages = getEPackagesFromGrammar(grammar);
assertEquals(2, ePackages.size());
EPackage t1 = ePackages.get(0);
assertEquals("t1", t1.getName());
assertEquals(1, t1.getEClassifiers().size());
EClassifier ruleA = t1.getEClassifier("RuleA");
assertNotNull(ruleA);
EPackage t2 = ePackages.get(1);
assertEquals(1, t2.getEClassifiers().size());
assertEquals("t2", t2.getName());
EClassifier typeB = t2.getEClassifier("TypeB");
assertNotNull(typeB);
}
public void testUseSameModelAlias() throws Exception {
String grammar = "";
grammar += " language test";
grammar += " generate t1 'http://t1' as target";
grammar += " generate t2 'http://t2' as target";
grammar += " RuleA: featureA=ID;"; // no alias => cannot be created
grammar += " RuleB returns target::TypeB: featureB=ID;";
errorAcceptorMock.acceptError(same(ErrorCode.AliasForMetamodelAlreadyExists), (String) anyObject(),
(EObject) anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.CannotCreateTypeInSealedMetamodel), (String) anyObject(),
(EObject) anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.NoSuchTypeAvailable), (String) anyObject(),
(EObject) anyObject());
List<EPackage> ePackages = getEPackagesFromGrammar(grammar);
assertEquals(1, ePackages.size());
EPackage t1 = ePackages.get(0);
assertEquals("t1", t1.getName());
assertEquals(1, t1.getEClassifiers().size());
EClassifier ruleA = t1.getEClassifier("TypeB");
assertNotNull(ruleA);
}
public void testModifyingSealedModel() throws Exception {
final String grammar = "language test generate test 'http://test' import 'http://www.eclipse.org/emf/2002/Ecore' as ecore RuleA returns ecore::SomeNewTypeA: feature=ID;";
errorAcceptorMock.acceptError(same(ErrorCode.CannotCreateTypeInSealedMetamodel), (String)anyObject(), (EObject)anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.NoSuchTypeAvailable), (String)anyObject(), (EObject)anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.CannotCreateTypeInSealedMetamodel), (String) anyObject(),
(EObject) anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.NoSuchTypeAvailable), (String) anyObject(), (EObject) anyObject());
getEPackageFromGrammar(grammar);
}
public void testImportingUnknownModel() throws Exception {
final String grammar = "language test generate test 'http://test' import 'http://www.unknownModel' as unknownModel RuleA: feature=ID;";
errorAcceptorMock.acceptError(same(ErrorCode.CannotLoadMetamodel), (String)anyObject(), (EObject)anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.CannotLoadMetamodel), (String) anyObject(), (EObject) anyObject());
getEPackageFromGrammar(grammar);
}
public void testMoreThanOneRuleCall() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: RuleB RuleC; RuleB: featureB=ID; RuleC: featureC=ID;";
errorAcceptorMock.acceptError(same(ErrorCode.MoreThanOneTypeChangeInOneRule), (String)anyObject(), (EObject)anyObject());
errorAcceptorMock.acceptError(same(ErrorCode.MoreThanOneTypeChangeInOneRule), (String) anyObject(),
(EObject) anyObject());
getEPackageFromGrammar(grammar);
}
public void testRuleCallAndAction() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: RuleB {TypeC.B = current}; RuleB: featureB=ID;";
getEPackageFromGrammar(grammar);
}
public void testRuleCallActionAndRuleCall() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: RuleB {TypeC.B = current} RuleB; RuleB: featureB=ID;";
errorAcceptorMock.acceptError(same(ErrorCode.MoreThanOneTypeChangeInOneRule), (String) anyObject(),
(EObject) anyObject());
getEPackageFromGrammar(grammar);
}
public void testAddingFeatureTwice() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA returns TypeA: featureA=ID; RuleB returns TypeA: featureA=STRING;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(1, ePackage.getEClassifiers().size());
EClass typeA = (EClass) ePackage.getEClassifier("TypeA");
assertNotNull(typeA);
assertEquals(1, typeA.getEAttributes().size());
assertAttributeConfiguration(typeA, 0, "featureA", "EString");
}
public void testAddingDifferentFeaturesWithSameName01() throws Exception {
// simple datatypes do not have a common compatible type
final String grammar = "" +
" language test generate test 'http://test'" +
" RuleA returns TypeA: featureA=ID;" +
" RuleB returns TypeA: featureA=INT;";
errorAcceptorMock.acceptError(same(ErrorCode.NoCompatibleFeatureTypeAvailable), (String) anyObject(),
(EObject) anyObject());
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(1, ePackage.getEClassifiers().size());
EClass typeA = (EClass) ePackage.getEClassifier("TypeA");
assertNotNull(typeA);
assertEquals(1, typeA.getEAttributes().size());
assertAttributeConfiguration(typeA, 0, "featureA", "EString");
}
public void testAddingDifferentFeaturesWithSameName02() throws Exception {
String grammar = "language test generate test 'http://test'";
grammar += " RuleA returns TypeA: featureA=RuleD;";
grammar += " RuleB returns TypeA: featureA=RuleC;";
grammar += " RuleC: RuleD;";
grammar += " RuleD: featureD=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(3, ePackage.getEClassifiers().size());
EClass typeA = (EClass) ePackage.getEClassifier("TypeA");
assertNotNull(typeA);
EClass ruleC = (EClass) ePackage.getEClassifier("RuleC");
assertNotNull(ruleC);
EClass ruleD = (EClass) ePackage.getEClassifier("RuleD");
assertNotNull(ruleD);
assertEquals(1, typeA.getEReferences().size());
assertReferenceConfiguration(typeA, 0, "featureA", "RuleC", true, 0, 1);
}
}