Next patch from Heiko

See https://bugs.eclipse.org/bugs/show_bug.cgi?id=247406
This commit is contained in:
jkohnlein 2008-09-22 15:21:57 +00:00
parent 9e5d55916c
commit 54857e60be
4 changed files with 246 additions and 82 deletions

View file

@ -8,9 +8,6 @@
*******************************************************************************/
package org.eclipse.xtext.resource.metamodel;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;

View file

@ -0,0 +1,111 @@
/*******************************************************************************
* 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.resource.metamodel;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.RuleCall;
/**
* @author Heiko Behrens - Initial contribution and API
*
*/
public class Xtext2ECoreInterpretationContext {
private EClassifierInfos eClassifierInfos;
Set<EClassifierInfo> currentTypes = new HashSet<EClassifierInfo>();
boolean isRuleCallAllowed = true;
private Xtext2ECoreInterpretationContext(EClassifierInfos classifierInfos) {
super();
this.eClassifierInfos = classifierInfos;
}
public Xtext2ECoreInterpretationContext(EClassifierInfos eClassifierInfos, EClassifierInfo currentType) {
this(eClassifierInfos);
currentTypes.add(currentType);
}
private Xtext2ECoreInterpretationContext(Collection<EClassifierInfo> currentTypes,
EClassifierInfos classifierInfos, boolean isRuleCallAllowed) {
this(classifierInfos);
this.currentTypes.addAll(currentTypes);
this.isRuleCallAllowed = isRuleCallAllowed;
}
public Xtext2ECoreInterpretationContext(EClassifierInfo newType, EClassifierInfos classifierInfos,
boolean isRuleCallAllowed2) {
this(classifierInfos);
this.currentTypes.add(newType);
}
public void addFeature(Assignment assignment) throws TransformationException {
String featureName = assignment.getFeature();
boolean isMultivalue = GrammarUtil.isMultipleAssignment(assignment);
EClassifierInfo featureTypeInfo;
if (GrammarUtil.isBooleanAssignment(assignment)) {
featureTypeInfo = getEClassifierInfoOrThrowException("ecore::EBoolean", assignment);
isMultivalue = false;
}
else {
RuleCall featureRuleCall = (RuleCall) assignment.getTerminal();
AbstractRule featureTypeRule = GrammarUtil.calledRule(featureRuleCall);
String featureTypeName = GrammarUtil.getReturnTypeName(featureTypeRule);
featureTypeInfo = getEClassifierInfoOrThrowException(featureTypeName, assignment);
}
for (EClassifierInfo type : currentTypes)
type.addFeature(featureName, featureTypeInfo, isMultivalue);
}
private EClassifierInfo getEClassifierInfoOrThrowException(String typeName, AbstractElement parserElement)
throws TransformationException {
EClassifierInfo featureTypeInfo = eClassifierInfos.getInfo(typeName);
if (featureTypeInfo == null) {
throw new TransformationException("Cannot resolve type " + typeName, parserElement);
}
return featureTypeInfo;
}
public Xtext2ECoreInterpretationContext spawnContextForGroup() {
Xtext2ECoreInterpretationContext result = new Xtext2ECoreInterpretationContext(currentTypes, eClassifierInfos,
isRuleCallAllowed);
return result;
}
public Xtext2ECoreInterpretationContext spawnContextWith(EClassifierInfo newType) {
if (!isRuleCallAllowed)
throw new IllegalStateException("Cannot change type twice within a rule");
Xtext2ECoreInterpretationContext result = new Xtext2ECoreInterpretationContext(newType, eClassifierInfos,
isRuleCallAllowed);
return result;
}
public Xtext2ECoreInterpretationContext mergeSpawnedContexts(List<Xtext2ECoreInterpretationContext> contexts) {
Xtext2ECoreInterpretationContext result = new Xtext2ECoreInterpretationContext(eClassifierInfos);
// result's current types is union of all groups' types
// result's isRuleCallAllowed is false if any group's value is false
for (Xtext2ECoreInterpretationContext context : contexts) {
result.currentTypes.addAll(context.currentTypes);
result.isRuleCallAllowed &= context.isRuleCallAllowed;
}
return result;
}
}

View file

@ -14,7 +14,6 @@ import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
@ -31,7 +30,6 @@ import org.eclipse.xtext.GeneratedMetamodel;
import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Group;
import org.eclipse.xtext.LexerRule;
import org.eclipse.xtext.ParserRule;
import org.eclipse.xtext.ReferencedMetamodel;
import org.eclipse.xtext.RuleCall;
@ -69,6 +67,8 @@ public class Xtext2EcoreTransformer {
// create types:
// iterate rules
// - typeref in actions
// type hierarchy
// - actions
for (AbstractRule rule : grammar.getRules()) {
// - return types (lexer and parser rules)
try {
@ -85,9 +85,7 @@ public class Xtext2EcoreTransformer {
// create features
// iterate rules
// - assignments
// - feature in actions
// multiplicity!
for (AbstractRule rule : grammar.getRules()) {
try {
if (rule instanceof ParserRule) {
@ -99,10 +97,6 @@ public class Xtext2EcoreTransformer {
}
}
// type hierarchy
// - rule calls (optionality)
// - actions
// feature normalization
// - uplift of common feature to supertype
// - removal in subtype if already in supertype
@ -118,28 +112,42 @@ public class Xtext2EcoreTransformer {
this.getEClassifierInfos().addAll(transformer.getEClassifierInfos());
}
private InterpretationContext deriveFeatures(InterpretationContext context, AbstractElement element)
throws TransformationException {
private Xtext2ECoreInterpretationContext deriveFeatures(Xtext2ECoreInterpretationContext context,
AbstractElement element) throws TransformationException {
if (element instanceof Assignment) {
Assignment assignment = (Assignment) element;
context.addFeature(assignment);
}
else if (element instanceof Alternatives) {
Alternatives alternatives = (Alternatives) element;
List<Xtext2ECoreInterpretationContext> contexts = new ArrayList<Xtext2ECoreInterpretationContext>();
for (AbstractElement group : alternatives.getGroups()) {
contexts.add(deriveFeatures(context, group));
}
if (!GrammarUtil.isOptionalCardinality(alternatives))
return context.mergeSpawnedContexts(contexts);
}
else if (element instanceof Group) {
Group group = (Group) element;
return deriveFeatures(context, group.getAbstractTokens());
return deriveFeatures(context.spawnContextForGroup(), group.getAbstractTokens());
}
else if (element instanceof RuleCall && !GrammarUtil.isOptionalCardinality(element)) {
RuleCall ruleCall = (RuleCall) element;
AbstractRule calledRule = GrammarUtil.findRuleForName(grammar, ruleCall.getName());
context = context.clone();
context.currentType = findOrCreateEClass(calledRule);
try {
return context.spawnContextWith(findOrCreateEClass(calledRule));
}
catch (IllegalStateException e) {
throw new TransformationException(e.getMessage(), ruleCall);
}
}
return context;
}
private InterpretationContext deriveFeatures(InterpretationContext context, EList<AbstractElement> elements)
throws TransformationException {
private Xtext2ECoreInterpretationContext deriveFeatures(Xtext2ECoreInterpretationContext context,
EList<AbstractElement> elements) throws TransformationException {
for (AbstractElement element : elements) {
context = deriveFeatures(context, element);
}
@ -148,8 +156,7 @@ public class Xtext2EcoreTransformer {
private void deriveFeatures(ParserRule rule) throws TransformationException {
EClassifierInfo classInfo = findOrCreateEClass(rule);
boolean isGenerated = classInfo.isGenerated();
InterpretationContext context = new InterpretationContext(classInfo, isGenerated, true);
Xtext2ECoreInterpretationContext context = new Xtext2ECoreInterpretationContext(eClassifierInfos, classInfo);
deriveFeatures(context, rule.getAlternatives());
}
@ -206,53 +213,6 @@ public class Xtext2EcoreTransformer {
calledRuleReturnType.addSupertype(superType);
}
class InterpretationContext {
public InterpretationContext(EClassifierInfo currentType, boolean isGeneratedType, boolean isRuleCallAllowed) {
super();
this.currentType = currentType;
this.isGeneratedType = isGeneratedType;
this.isRuleCallAllowed = isRuleCallAllowed;
}
public void addFeature(Assignment assignment) throws TransformationException {
String featureName = assignment.getFeature();
boolean isMultivalue = GrammarUtil.isMultipleAssignment(assignment);
EClassifierInfo featureTypeInfo;
if (GrammarUtil.isBooleanAssignment(assignment)) {
featureTypeInfo = getEClassifierInfoOrThrowException("ecore::EBoolean", assignment);
isMultivalue = false;
}
else {
RuleCall featureRuleCall = (RuleCall) assignment.getTerminal();
AbstractRule featureTypeRule = GrammarUtil.calledRule(featureRuleCall);
String featureTypeName = GrammarUtil.getReturnTypeName(featureTypeRule);
featureTypeInfo = getEClassifierInfoOrThrowException(featureTypeName, assignment);
}
currentType.addFeature(featureName, featureTypeInfo, isMultivalue);
}
private EClassifierInfo getEClassifierInfoOrThrowException(String typeName, AbstractElement parserElement)
throws TransformationException {
EClassifierInfo featureTypeInfo = eClassifierInfos.getInfo(typeName);
if (featureTypeInfo == null) {
throw new TransformationException("Cannot resolve type " + typeName, parserElement);
}
return featureTypeInfo;
}
public InterpretationContext clone() {
return new InterpretationContext(currentType, isGeneratedType, isRuleCallAllowed);
}
// TODO : Use set of types to reflect mandatory actions
EClassifierInfo currentType;
boolean isGeneratedType;
boolean isRuleCallAllowed = true;
}
private void collectEPackages() {
EList<AbstractMetamodelDeclaration> metamodelDeclarations = grammar.getMetamodelDeclarations();
for (AbstractMetamodelDeclaration metamodelDeclaration : metamodelDeclarations) {

View file

@ -33,8 +33,7 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
with(XtextStandaloneSetup.class);
}
private EPackage getEPackageFromGrammar(String xtextGrammar)
throws Exception {
private EPackage getEPackageFromGrammar(String xtextGrammar) throws Exception {
Grammar grammar = (Grammar) getModel(xtextGrammar);
Xtext2EcoreTransformer xtext2EcoreTransformer = new Xtext2EcoreTransformer();
List<EPackage> metamodels = xtext2EcoreTransformer.transform(grammar);
@ -46,22 +45,22 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
return result;
}
private EAttribute assertFeatureConfiguration(EClass eClass, int attributeIndex,
String featureName, String featureTypeName) {
private EAttribute assertFeatureConfiguration(EClass eClass, int attributeIndex, String featureName,
String featureTypeName) {
EAttribute feature = eClass.getEAttributes().get(attributeIndex);
assertEquals(featureName, feature.getName());
assertNotNull(feature.getEType());
assertEquals(featureTypeName, feature.getEType().getName());
return feature;
}
private EAttribute assertFeatureConfiguration(EClass eClass, int attributeIndex,
String featureName, String featureTypeName, int lowerBound, int upperBound) {
private EAttribute assertFeatureConfiguration(EClass eClass, int attributeIndex, String featureName,
String featureTypeName, int lowerBound, int upperBound) {
EAttribute feature = assertFeatureConfiguration(eClass, attributeIndex, featureName, featureTypeName);
assertEquals(lowerBound, feature.getLowerBound());
assertEquals(upperBound, feature.getUpperBound());
return feature;
}
@ -153,7 +152,7 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertFeatureConfiguration(ruleA, 1, "featureB", "EInt", 0, -1);
}
public void testFeatureAndInheritanceOptionalRuleCall() throws Exception {
public void testFeaturesAndInheritanceOptionalRuleCall() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: RuleB? featureA=INT; RuleB: featureB=STRING;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(2, ePackage.getEClassifiers().size());
@ -161,15 +160,15 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertNotNull(ruleA);
EClass ruleB = (EClass) ePackage.getEClassifier("RuleB");
assertNotNull(ruleB);
assertEquals(1, ruleA.getEAttributes().size());
assertFeatureConfiguration(ruleA, 0, "featureA", "EInt");
assertEquals(1, ruleB.getEAttributes().size());
assertFeatureConfiguration(ruleB, 0, "featureB", "EString");
}
public void testFeatureAndInheritanceMandatoryRuleCall() throws Exception {
public void testFeaturesAndInheritanceMandatoryRuleCall() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: RuleB featureA=INT; RuleB: featureB=STRING;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(2, ePackage.getEClassifiers().size());
@ -177,12 +176,109 @@ public class Xtext2EcoreTransformerTests extends AbstractGeneratorTest {
assertNotNull(ruleA);
EClass ruleB = (EClass) ePackage.getEClassifier("RuleB");
assertNotNull(ruleB);
assertEquals(0, ruleA.getEAttributes().size());
assertEquals(2, ruleB.getEAttributes().size());
assertFeatureConfiguration(ruleB, 0, "featureA", "EInt");
assertFeatureConfiguration(ruleB, 1, "featureB", "EString");
}
public void testFeaturesAndInheritanceOfMandatoryAlternativeRuleCalls() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: (RuleB|RuleC featureC1=ID) featureA=ID; RuleB: featureB=ID; RuleC: featureC2=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(3, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
assertNotNull(ruleA);
EClass ruleB = (EClass) ePackage.getEClassifier("RuleB");
assertNotNull(ruleB);
EClass ruleC = (EClass) ePackage.getEClassifier("RuleC");
assertNotNull(ruleC);
// test inheritance
assertTrue(ruleA.getESuperTypes().isEmpty());
assertEquals(1, ruleB.getESuperTypes().size());
assertEquals(ruleA, ruleB.getESuperTypes().get(0));
assertEquals(1, ruleC.getESuperTypes().size());
assertEquals(ruleA, ruleC.getESuperTypes().get(0));
// test all features are separated
assertEquals(0, ruleA.getEAttributes().size());
assertEquals(2, ruleB.getEAttributes().size());
assertFeatureConfiguration(ruleB, 0, "featureA", "EString");
assertFeatureConfiguration(ruleB, 1, "featureB", "EString");
assertEquals(3, ruleC.getEAttributes().size());
assertFeatureConfiguration(ruleC, 0, "featureC1", "EString");
assertFeatureConfiguration(ruleC, 1, "featureA", "EString");
assertFeatureConfiguration(ruleC, 2, "featureC2", "EString");
}
public void testFeaturesAndInheritanceOfOptionalOptionalRuleCalls() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: (RuleB|RuleC featureC1=ID)? featureA=ID; RuleB: featureB=ID; RuleC: featureC2=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(3, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
assertNotNull(ruleA);
EClass ruleB = (EClass) ePackage.getEClassifier("RuleB");
assertNotNull(ruleB);
EClass ruleC = (EClass) ePackage.getEClassifier("RuleC");
assertNotNull(ruleC);
// test inheritance
assertTrue(ruleA.getESuperTypes().isEmpty());
assertEquals(1, ruleB.getESuperTypes().size());
assertEquals(ruleA, ruleB.getESuperTypes().get(0));
assertEquals(1, ruleC.getESuperTypes().size());
assertEquals(ruleA, ruleC.getESuperTypes().get(0));
// test all features are separated
assertEquals(1, ruleA.getEAttributes().size());
assertFeatureConfiguration(ruleA, 0, "featureA", "EString");
assertEquals(1, ruleB.getEAttributes().size());
assertFeatureConfiguration(ruleB, 0, "featureB", "EString");
assertEquals(2, ruleC.getEAttributes().size());
assertFeatureConfiguration(ruleC, 0, "featureC1", "EString");
assertFeatureConfiguration(ruleC, 1, "featureC2", "EString");
}
public void testFeaturesAndInheritanceOfNestedRuleCalls() throws Exception {
final String grammar = "language test generate test 'http://test' RuleA: ((RuleB|RuleC featureC1=ID)? featureBC=ID | (RuleC|RuleD featureD1=ID) featureCD=ID) featureA=ID; RuleB: featureB2=ID; RuleC: featureC2=ID; RuleD: featureD2=ID;";
EPackage ePackage = getEPackageFromGrammar(grammar);
assertEquals(4, ePackage.getEClassifiers().size());
EClass ruleA = (EClass) ePackage.getEClassifier("RuleA");
assertNotNull(ruleA);
EClass ruleB = (EClass) ePackage.getEClassifier("RuleB");
assertNotNull(ruleB);
EClass ruleC = (EClass) ePackage.getEClassifier("RuleC");
assertNotNull(ruleC);
EClass ruleD = (EClass) ePackage.getEClassifier("RuleD");
assertNotNull(ruleD);
// test inheritance
assertTrue(ruleA.getESuperTypes().isEmpty());
assertEquals(1, ruleB.getESuperTypes().size());
assertEquals(ruleA, ruleB.getESuperTypes().get(0));
assertEquals(1, ruleC.getESuperTypes().size());
assertEquals(ruleA, ruleC.getESuperTypes().get(0));
assertEquals(1, ruleD.getESuperTypes().size());
assertEquals(ruleA, ruleD.getESuperTypes().get(0));
// test all features are separated
assertEquals(2, ruleA.getEAttributes().size());
assertFeatureConfiguration(ruleA, 0, "featureBC", "EString");
assertFeatureConfiguration(ruleA, 1, "featureA", "EString");
assertEquals(1, ruleB.getEAttributes().size());
assertFeatureConfiguration(ruleB, 0, "featureB2", "EString");
assertEquals(4, ruleC.getEAttributes().size());
assertFeatureConfiguration(ruleC, 0, "featureC1", "EString");
assertFeatureConfiguration(ruleC, 1, "featureCD", "EString");
assertFeatureConfiguration(ruleC, 2, "featureA", "EString");
assertFeatureConfiguration(ruleC, 3, "featureC2", "EString");
assertEquals(4, ruleD.getEAttributes().size());
assertFeatureConfiguration(ruleD, 0, "featureD1", "EString");
assertFeatureConfiguration(ruleD, 1, "featureCD", "EString");
assertFeatureConfiguration(ruleD, 2, "featureA", "EString");
assertFeatureConfiguration(ruleD, 3, "featureD2", "EString");
}
}