mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 08:48:55 +00:00
[263773] Xtext grammar enhancements (src)
- Explicit rule calls and super rule calls - name=super::ID - name=Terminals::ID - feature=com::acme::MyLang::SomeRule - Parser rule fragments - fragment DeclarationOwner: declarations+=Declaration+; - Parameterized rule calls: - IdOrKeyword<AllowKeyword>: <AllowKeyword> ‘keyword’ | ID; This commit contains the changes to the Xtext core plugins without any changes to generated code.
This commit is contained in:
parent
1f642242c2
commit
9185cb9cca
61 changed files with 1891 additions and 403 deletions
|
@ -44,6 +44,7 @@ import org.junit.After;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
|
@ -261,9 +262,9 @@ public abstract class AbstractXtextTests extends Assert implements ResourceLoadH
|
|||
checkNodeModel(resource);
|
||||
if (expectedErrors != UNKNOWN_EXPECTATION) {
|
||||
if (expectedErrors == EXPECT_ERRORS)
|
||||
assertFalse(resource.getErrors().toString(), resource.getErrors().isEmpty());
|
||||
assertFalse(Joiner.on('\n').join(resource.getErrors()), resource.getErrors().isEmpty());
|
||||
else
|
||||
assertEquals(resource.getErrors().toString(), expectedErrors, resource.getErrors().size());
|
||||
assertEquals(Joiner.on('\n').join(resource.getErrors()), expectedErrors, resource.getErrors().size());
|
||||
}
|
||||
for(Diagnostic d: resource.getErrors()) {
|
||||
if (d instanceof ExceptionDiagnostic)
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.eclipse.emf.common.notify.Adapter;
|
|||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.junit4.util.ParseHelper;
|
||||
import org.eclipse.xtext.junit4.validation.ValidationTestHelper;
|
||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
||||
|
@ -66,6 +67,9 @@ public class SerializerTester {
|
|||
|
||||
@Inject
|
||||
protected ValidationTestHelper validationHelper;
|
||||
|
||||
@Inject
|
||||
private IGrammarAccess grammarAccess;
|
||||
|
||||
/**
|
||||
* @since 2.3
|
||||
|
@ -174,7 +178,7 @@ public class SerializerTester {
|
|||
if (Iterables.size(contexts) != 1) {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("One context is expected, but " + Iterables.size(contexts) + " have been found\n");
|
||||
msg.append("Contexts: " + Joiner.on(", ").join(Iterables.transform(contexts, new Context2NameFunction())));
|
||||
msg.append("Contexts: " + Joiner.on(", ").join(Iterables.transform(contexts, new Context2NameFunction().toFunction(grammarAccess.getGrammar()))));
|
||||
msg.append("Semantic Object: " + EmfFormatter.objPath(semanticObject));
|
||||
Assert.fail(msg.toString());
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.eclipse.xtext.Grammar
|
|||
import org.eclipse.xtext.GrammarUtil
|
||||
import org.eclipse.xtext.Keyword
|
||||
import org.eclipse.xtext.RuleCall
|
||||
import org.eclipse.xtext.RuleNames
|
||||
import org.eclipse.xtext.TypeRef
|
||||
import org.eclipse.xtext.XtextRuntimeModule
|
||||
import org.eclipse.xtext.formatting.ILineSeparatorInformation
|
||||
|
@ -137,9 +138,18 @@ class GrammarAccessExtensions {
|
|||
|
||||
/**
|
||||
* Creates an identifier for a Rule which is a valid Java identifier and unique within
|
||||
* the Rule's grammar.
|
||||
* the Rule's grammar and its super grammars.
|
||||
*/
|
||||
def String gaRuleIdentifier(AbstractRule rule) {
|
||||
val plainName = RuleNames.getRuleNames(rule).getUniqueRuleName(rule);
|
||||
return toJavaIdentifier(plainName, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identifier for a Rule which is a valid Java identifier and unique within
|
||||
* the grammar that defines the rule.
|
||||
*/
|
||||
def String gaBaseRuleIdentifier(AbstractRule rule) {
|
||||
rule.name.toJavaIdentifier(true)
|
||||
}
|
||||
|
||||
|
@ -223,6 +233,13 @@ class GrammarAccessExtensions {
|
|||
def String gaRuleAccessMethodName(AbstractRule rule) {
|
||||
'get' + rule.gaRuleIdentifier + 'Rule'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method name for accessing a rule via a GrammarAccess implementation.
|
||||
*/
|
||||
def String gaBaseRuleAccessMethodName(AbstractRule rule) {
|
||||
'get' + rule.gaBaseRuleIdentifier + 'Rule'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method name for accessing a rule's content via a ParserRuleAccess implementation.
|
||||
|
@ -231,6 +248,13 @@ class GrammarAccessExtensions {
|
|||
'get' + rule.gaRuleIdentifier + 'Access'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method name for accessing a rule's content via a ParserRuleAccess implementation.
|
||||
*/
|
||||
def String gaBaseRuleElementsMethodName(AbstractRule rule) {
|
||||
'get' + rule.gaBaseRuleIdentifier + 'Access'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method name for accessing an element via a GrammarAccess implementation.
|
||||
*/
|
||||
|
@ -245,6 +269,14 @@ class GrammarAccessExtensions {
|
|||
def String gaRuleAccessorClassName(AbstractRule rule) {
|
||||
rule.gaRuleIdentifier + 'Elements'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the simple class name of a rule's facade. A GrammarAccess implementation has
|
||||
* a facade for each parser rule, which contains the methods for accessing the rule's elements.
|
||||
*/
|
||||
def String gaBaseRuleAccessorClassName(AbstractRule rule) {
|
||||
rule.gaBaseRuleIdentifier + 'Elements'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invocation of the rule accessor method as Java statement.
|
||||
|
@ -253,12 +285,26 @@ class GrammarAccessExtensions {
|
|||
rule.gaRuleAccessMethodName + '()'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invocation of the rule accessor method as Java statement.
|
||||
*/
|
||||
def String gaBaseRuleAccessor(AbstractRule rule) {
|
||||
rule.gaBaseRuleAccessMethodName + '()'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invocation of the rule's content accessor method as Java statement.
|
||||
*/
|
||||
def String gaElementsAccessor(AbstractRule rule) {
|
||||
rule.gaRuleElementsMethodName + '()'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invocation of the rule's content accessor method as Java statement.
|
||||
*/
|
||||
def String gaBaseElementsAccessor(AbstractRule rule) {
|
||||
rule.gaBaseRuleElementsMethodName + '()'
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invocation of the element accessor method as Java statement.
|
||||
|
@ -327,7 +373,7 @@ class GrammarAccessExtensions {
|
|||
return result;
|
||||
}
|
||||
|
||||
@FinalFieldsConstructor
|
||||
@FinalFieldsConstructor
|
||||
protected static class LineSeparatorModule extends XtextRuntimeModule {
|
||||
|
||||
val ILineSeparatorInformation lineSeparatorInformation;
|
||||
|
|
|
@ -77,6 +77,10 @@ class GrammarAccessFragment2 extends AbstractGeneratorFragment2 {
|
|||
writeGrammar(language)
|
||||
}
|
||||
|
||||
def protected String getQualifiedName(AbstractRule rule) {
|
||||
return GrammarUtil.getGrammar(rule).name + '.' + rule.name
|
||||
}
|
||||
|
||||
protected def void writeGrammar(LanguageConfig2 language) {
|
||||
val isSaving = Wrapper.wrap(false)
|
||||
val ResourceSet cloneInto = new ResourceSetImpl
|
||||
|
@ -246,7 +250,7 @@ class GrammarAccessFragment2 extends AbstractGeneratorFragment2 {
|
|||
|
||||
protected def StringConcatenationClient parserRuleClasses(ParserRule it) '''
|
||||
public class «gaRuleAccessorClassName» extends «AbstractParserRuleElementFinder» {
|
||||
private final «ParserRule» rule = («ParserRule») «GrammarUtil».findRuleForName(getGrammar(), "«name»");
|
||||
private final «ParserRule» rule = («ParserRule») «GrammarUtil».findRuleForName(getGrammar(), "«qualifiedName»");
|
||||
«FOR e : containedAbstractElements»
|
||||
private final «e.eClass» «e.gaElementAccessorLocalVarName» = «e.loadElementStatement»;
|
||||
«ENDFOR»
|
||||
|
@ -263,7 +267,7 @@ class GrammarAccessFragment2 extends AbstractGeneratorFragment2 {
|
|||
|
||||
protected def StringConcatenationClient parserRuleClasses(EnumRule it) '''
|
||||
public class «gaRuleAccessorClassName» extends «AbstractEnumRuleElementFinder» {
|
||||
private final «EnumRule» rule = («EnumRule») «GrammarUtil».findRuleForName(getGrammar(), "«name»");
|
||||
private final «EnumRule» rule = («EnumRule») «GrammarUtil».findRuleForName(getGrammar(), "«qualifiedName»");
|
||||
«FOR e : containedAbstractElements»
|
||||
private final «e.eClass» «e.gaElementAccessorLocalVarName» = «e.loadElementStatement»;
|
||||
«ENDFOR»
|
||||
|
@ -299,7 +303,7 @@ class GrammarAccessFragment2 extends AbstractGeneratorFragment2 {
|
|||
'''
|
||||
|
||||
protected def dispatch StringConcatenationClient initializer(TerminalRule it) '''
|
||||
this.«gaRuleAccessorLocalVarName» = («TerminalRule») «GrammarUtil».findRuleForName(getGrammar(), "«name»");
|
||||
this.«gaRuleAccessorLocalVarName» = («TerminalRule») «GrammarUtil».findRuleForName(getGrammar(), "«qualifiedName»");
|
||||
'''
|
||||
|
||||
protected def dispatch StringConcatenationClient getter(ParserRule it, Grammar original) '''
|
||||
|
@ -309,8 +313,8 @@ class GrammarAccessFragment2 extends AbstractGeneratorFragment2 {
|
|||
return «gaRuleAccessorLocalVarName»;
|
||||
}
|
||||
«ELSE»
|
||||
public «grammar.grammarAccess».«gaRuleAccessorClassName» «gaElementsAccessor» {
|
||||
return «usedGrammar(original).gaGrammarAccessLocalVarName».«gaElementsAccessor»;
|
||||
public «grammar.grammarAccess».«gaBaseRuleAccessorClassName» «gaElementsAccessor» {
|
||||
return «usedGrammar(original).gaGrammarAccessLocalVarName».«gaBaseElementsAccessor»;
|
||||
}
|
||||
«ENDIF»
|
||||
|
||||
|
@ -342,7 +346,7 @@ class GrammarAccessFragment2 extends AbstractGeneratorFragment2 {
|
|||
«IF grammar === original»
|
||||
return «gaRuleAccessorLocalVarName»;
|
||||
«ELSE»
|
||||
return «usedGrammar(original).gaGrammarAccessLocalVarName».«gaRuleAccessor»;
|
||||
return «usedGrammar(original).gaGrammarAccessLocalVarName».«gaBaseRuleAccessor»;
|
||||
«ENDIF»
|
||||
}
|
||||
'''
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<component id="org.eclipse.xtext" version="2">
|
||||
<resource path="META-INF/MANIFEST.MF">
|
||||
<filter comment="version will be generated during buckminster build" id="927989779">
|
||||
<filter id="927989779">
|
||||
<message_arguments>
|
||||
<message_argument value="2.9.0"/>
|
||||
<message_argument value="org.eclipse.xtext.util"/>
|
||||
|
@ -24,6 +24,175 @@
|
|||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
<resource path="emf-gen/org/eclipse/xtext/XtextPackage.java" type="org.eclipse.xtext.XtextPackage">
|
||||
<filter id="388194388">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage"/>
|
||||
<message_argument value="GROUP_FEATURE_COUNT"/>
|
||||
<message_argument value="4"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="388194388">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage"/>
|
||||
<message_argument value="PARSER_RULE_FEATURE_COUNT"/>
|
||||
<message_argument value="5"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="388194388">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage"/>
|
||||
<message_argument value="RULE_CALL_FEATURE_COUNT"/>
|
||||
<message_argument value="4"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
<resource path="emf-gen/org/eclipse/xtext/XtextPackage.java" type="org.eclipse.xtext.XtextPackage$Literals">
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="COMPOSITE_CONDITION"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="COMPOSITE_CONDITION__LEFT"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="COMPOSITE_CONDITION__RIGHT"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="CONDITION"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="CONJUNCTION"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="DISJUNCTION"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="GROUP__GUARD_CONDITION"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="LITERAL_CONDITION"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="LITERAL_CONDITION__TRUE"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="NAMED_ARGUMENT"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="NAMED_ARGUMENT__CALLED_BY_NAME"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="NAMED_ARGUMENT__PARAMETER"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="NAMED_ARGUMENT__VALUE"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="NEGATION"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="NEGATION__VALUE"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="PARAMETER"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="PARAMETER_REFERENCE"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="PARAMETER_REFERENCE__PARAMETER"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="PARAMETER__NAME"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="PARSER_RULE__FRAGMENT"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="PARSER_RULE__PARAMETERS"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="PARSER_RULE__WILDCARD"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="RULE_CALL__ARGUMENTS"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
<filter id="403767336">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.xtext.XtextPackage.Literals"/>
|
||||
<message_argument value="RULE_CALL__EXPLICITLY_CALLED"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
<resource path="src-gen/org/eclipse/xtext/AbstractXtextRuntimeModule.java" type="org.eclipse.xtext.AbstractXtextRuntimeModule">
|
||||
<filter comment="the parse tree constructor is no longer used" id="338792546">
|
||||
<message_arguments>
|
||||
|
|
|
@ -32,6 +32,10 @@
|
|||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="definesHiddenTokens" eType="ecore:EDataType platform:/resource/org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="hiddenTokens" unique="false"
|
||||
upperBound="-1" eType="#//AbstractRule"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="parameters" upperBound="-1"
|
||||
eType="#//Parameter" containment="true"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="fragment" eType="ecore:EDataType platform:/resource/org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="wildcard" eType="ecore:EDataType platform:/resource/org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="TypeRef">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="metamodel" eType="#//AbstractMetamodelDeclaration"/>
|
||||
|
@ -53,6 +57,9 @@
|
|||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="RuleCall" eSuperTypes="#//AbstractElement">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="rule" eType="#//AbstractRule"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="arguments" upperBound="-1"
|
||||
eType="#//NamedArgument" containment="true"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="explicitlyCalled" eType="ecore:EDataType platform:/resource/org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="Assignment" eSuperTypes="#//AbstractElement">
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="feature" eType="ecore:EDataType platform:/resource/org.eclipse.emf.ecore/model/Ecore.ecore#//EString"/>
|
||||
|
@ -84,7 +91,10 @@
|
|||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="Alternatives" eSuperTypes="#//CompoundElement"/>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="UnorderedGroup" eSuperTypes="#//CompoundElement"/>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="Group" eSuperTypes="#//CompoundElement"/>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="Group" eSuperTypes="#//CompoundElement">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="guardCondition" eType="#//Condition"
|
||||
containment="true"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="CharacterRange" eSuperTypes="#//AbstractElement">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="left" eType="#//Keyword"
|
||||
containment="true"/>
|
||||
|
@ -96,4 +106,32 @@
|
|||
eType="#//AbstractElement" containment="true"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="EOF" eSuperTypes="#//AbstractElement"/>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="Parameter">
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType platform:/resource/org.eclipse.emf.ecore/model/Ecore.ecore#//EString"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="NamedArgument">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="parameter" eType="#//Parameter"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="value" eType="#//Condition"
|
||||
containment="true"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="calledByName" eType="ecore:EDataType platform:/resource/org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="Condition"/>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="Conjunction" eSuperTypes="#//CompositeCondition"/>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="Negation" eSuperTypes="#//Condition">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="value" eType="#//Condition"
|
||||
containment="true"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="Disjunction" eSuperTypes="#//CompositeCondition"/>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="CompositeCondition" eSuperTypes="#//Condition">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="left" eType="#//Condition"
|
||||
containment="true"/>
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="right" eType="#//Condition"
|
||||
containment="true"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="ParameterReference" eSuperTypes="#//Condition">
|
||||
<eStructuralFeatures xsi:type="ecore:EReference" name="parameter" eType="#//Parameter"/>
|
||||
</eClassifiers>
|
||||
<eClassifiers xsi:type="ecore:EClass" name="LiteralCondition" eSuperTypes="#//Condition">
|
||||
<eStructuralFeatures xsi:type="ecore:EAttribute" name="true" eType="ecore:EDataType platform:/resource/org.eclipse.emf.ecore/model/Ecore.ecore#//EBoolean"/>
|
||||
</eClassifiers>
|
||||
</ecore:EPackage>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
forceOverwrite="true" modelName="Xtext" updateClasspath="false" rootExtendsClass="org.eclipse.emf.ecore.impl.MinimalEObjectImpl$Container"
|
||||
importerID="org.eclipse.emf.importer.ecore" complianceLevel="5.0" copyrightFields="false"
|
||||
editPluginID="org.eclipse.xtext.edit" editorPluginID="org.eclipse.xtext.editor"
|
||||
usedGenPackages="../../../../org.eclipse.emf.ecore/model/Ecore.genmodel#//ecore">
|
||||
usedGenPackages="platform:/resource/org.eclipse.emf.ecore/model/Ecore.genmodel#//ecore">
|
||||
<foreignModel>Xtext.ecore</foreignModel>
|
||||
<genPackages prefix="Xtext" basePackage="org.eclipse" disposableProviderFactory="true"
|
||||
ecorePackage="Xtext.ecore#/">
|
||||
|
@ -33,6 +33,9 @@
|
|||
<genClasses ecoreClass="Xtext.ecore#//ParserRule">
|
||||
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Xtext.ecore#//ParserRule/definesHiddenTokens"/>
|
||||
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference Xtext.ecore#//ParserRule/hiddenTokens"/>
|
||||
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference Xtext.ecore#//ParserRule/parameters"/>
|
||||
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Xtext.ecore#//ParserRule/fragment"/>
|
||||
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Xtext.ecore#//ParserRule/wildcard"/>
|
||||
</genClasses>
|
||||
<genClasses ecoreClass="Xtext.ecore#//TypeRef">
|
||||
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference Xtext.ecore#//TypeRef/metamodel"/>
|
||||
|
@ -53,6 +56,8 @@
|
|||
</genClasses>
|
||||
<genClasses ecoreClass="Xtext.ecore#//RuleCall">
|
||||
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference Xtext.ecore#//RuleCall/rule"/>
|
||||
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference Xtext.ecore#//RuleCall/arguments"/>
|
||||
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Xtext.ecore#//RuleCall/explicitlyCalled"/>
|
||||
</genClasses>
|
||||
<genClasses ecoreClass="Xtext.ecore#//Assignment">
|
||||
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Xtext.ecore#//Assignment/feature"/>
|
||||
|
@ -88,5 +93,17 @@
|
|||
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference Xtext.ecore#//CompoundElement/elements"/>
|
||||
</genClasses>
|
||||
<genClasses ecoreClass="Xtext.ecore#//EOF"/>
|
||||
<genClasses ecoreClass="Xtext.ecore#//Parameter">
|
||||
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Xtext.ecore#//Parameter/name"/>
|
||||
</genClasses>
|
||||
<genClasses ecoreClass="Xtext.ecore#//ConditionalBranch">
|
||||
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference Xtext.ecore#//ConditionalBranch/parameter"/>
|
||||
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Xtext.ecore#//ConditionalBranch/filtered"/>
|
||||
</genClasses>
|
||||
<genClasses ecoreClass="Xtext.ecore#//NamedArgument">
|
||||
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference Xtext.ecore#//NamedArgument/parameter"/>
|
||||
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute Xtext.ecore#//NamedArgument/literalValue"/>
|
||||
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference Xtext.ecore#//NamedArgument/value"/>
|
||||
</genClasses>
|
||||
</genPackages>
|
||||
</genmodel:GenModel>
|
||||
|
|
|
@ -55,6 +55,9 @@ import org.eclipse.xtext.resource.DerivedStateAwareResource;
|
|||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.util.Strings;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import com.google.common.collect.MapMaker;
|
||||
|
||||
|
@ -179,27 +182,12 @@ public class EcoreUtil2 extends EcoreUtil {
|
|||
return target;
|
||||
}
|
||||
|
||||
@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;
|
||||
return Lists.newArrayList(Iterators.filter(ele.eAllContents(), type));
|
||||
}
|
||||
|
||||
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(clazz.cast(ele));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return Lists.newArrayList(Iterables.filter(elements, clazz));
|
||||
}
|
||||
|
||||
public static <T> List<T> collect(Collection<? extends EObject> instances, int featureId, Class<T> type) {
|
||||
|
@ -217,19 +205,8 @@ public class EcoreUtil2 extends EcoreUtil {
|
|||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends EObject> List<T> eAllOfType(EObject ele, Class<T> type) {
|
||||
List<T> result = new ArrayList<T>();
|
||||
if (type.isAssignableFrom(ele.getClass()))
|
||||
result.add((T) ele);
|
||||
TreeIterator<EObject> allContents = ele.eAllContents();
|
||||
while (allContents.hasNext()) {
|
||||
EObject object = allContents.next();
|
||||
if (type.isAssignableFrom(object.getClass())) {
|
||||
result.add((T) object);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return Lists.newArrayList(Iterators.filter(eAll(ele), type));
|
||||
}
|
||||
|
||||
public static TreeIterator<EObject> eAll(final EObject obj) {
|
||||
|
@ -291,20 +268,11 @@ public class EcoreUtil2 extends EcoreUtil {
|
|||
}
|
||||
|
||||
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;
|
||||
return Lists.newArrayList(ele.eAllContents());
|
||||
}
|
||||
|
||||
public static List<EObject> eAllContentsAsList(Resource resource) {
|
||||
List<EObject> result = new ArrayList<EObject>();
|
||||
TreeIterator<EObject> iterator = resource.getAllContents();
|
||||
while (iterator.hasNext()) {
|
||||
result.add(iterator.next());
|
||||
}
|
||||
return result;
|
||||
return Lists.newArrayList(resource.getAllContents());
|
||||
}
|
||||
|
||||
public static final EPackage loadEPackage(String uriAsString, ClassLoader classLoader) {
|
||||
|
@ -412,10 +380,11 @@ public class EcoreUtil2 extends EcoreUtil {
|
|||
}
|
||||
|
||||
private static void collectAllSuperTypes(Set<EClass> collectedTypes, EClass eClass) {
|
||||
for (EClass superType : eClass.getESuperTypes())
|
||||
for (EClass superType : eClass.getESuperTypes()) {
|
||||
if (collectedTypes.add(superType)) {
|
||||
collectAllSuperTypes(collectedTypes, superType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,6 +15,8 @@ import static org.eclipse.xtext.EcoreUtil2.*;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -39,6 +41,8 @@ import org.eclipse.xtext.xtext.CurrentTypeFinder;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein
|
||||
|
@ -179,8 +183,7 @@ public class GrammarUtil {
|
|||
public static boolean isEObjectRuleCall(EObject grammarElement) {
|
||||
if (grammarElement instanceof RuleCall) {
|
||||
AbstractRule calledRule = ((RuleCall) grammarElement).getRule();
|
||||
return calledRule != null && calledRule instanceof ParserRule
|
||||
&& calledRule.getType().getClassifier() instanceof EClass;
|
||||
return isEObjectRule(calledRule);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -189,8 +192,13 @@ public class GrammarUtil {
|
|||
* @since 2.0
|
||||
*/
|
||||
public static boolean isEObjectRule(EObject grammarElement) {
|
||||
return grammarElement instanceof ParserRule
|
||||
&& ((ParserRule) grammarElement).getType().getClassifier() instanceof EClass;
|
||||
if (grammarElement instanceof ParserRule) {
|
||||
ParserRule rule = (ParserRule) grammarElement;
|
||||
TypeRef type = rule.getType();
|
||||
// wildcard fragments are considered to be EObjectRules, too
|
||||
return type == null || type.getClassifier() instanceof EClass;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,6 +219,24 @@ public class GrammarUtil {
|
|||
return GrammarUtil.containingAssignment(ele) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
public static boolean isEObjectFragmentRuleCall(EObject ele) {
|
||||
if (ele instanceof RuleCall) {
|
||||
AbstractRule rule = ((RuleCall) ele).getRule();
|
||||
return isEObjectFragmentRule(rule);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
public static boolean isEObjectFragmentRule(AbstractRule rule) {
|
||||
return rule instanceof ParserRule && ((ParserRule) rule).isFragment();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
|
@ -224,7 +250,7 @@ public class GrammarUtil {
|
|||
if (grammarElement instanceof RuleCall) {
|
||||
AbstractRule calledRule = ((RuleCall) grammarElement).getRule();
|
||||
return calledRule != null && calledRule instanceof ParserRule
|
||||
&& calledRule.getType().getClassifier() instanceof EDataType;
|
||||
&& calledRule.getType() != null && calledRule.getType().getClassifier() instanceof EDataType;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -248,56 +274,102 @@ public class GrammarUtil {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ruleName
|
||||
* the name of the rule that should be found. May be a qualified name with a dot as a delimiter.
|
||||
*/
|
||||
public static AbstractRule findRuleForName(Grammar grammar, String ruleName) {
|
||||
if (ruleName == null)
|
||||
return null;
|
||||
for (AbstractRule rule : grammar.getRules()) {
|
||||
if (ruleName.equals(rule.getName())) {
|
||||
return rule;
|
||||
}
|
||||
int lastIndex = ruleName.lastIndexOf('.');
|
||||
if (lastIndex == -1) {
|
||||
return findRuleForNameRecursively(grammar, null, ruleName, Sets.<Grammar>newHashSet());
|
||||
} else {
|
||||
return findRuleForNameRecursively(grammar, ruleName.substring(0, lastIndex), ruleName.substring(lastIndex + 1), Sets.<Grammar>newHashSet());
|
||||
}
|
||||
for (Grammar usedGrammar : grammar.getUsedGrammars()) {
|
||||
AbstractRule rule = findRuleForName(usedGrammar, ruleName);
|
||||
if (rule != null) {
|
||||
return rule;
|
||||
}
|
||||
|
||||
private static AbstractRule findRuleForNameRecursively(Grammar grammar, String langName, String ruleName, Set<Grammar> visited) {
|
||||
if (visited.add(grammar)) {
|
||||
if (langName == null || langName.equals(grammar.getName())) {
|
||||
for (AbstractRule rule : grammar.getRules()) {
|
||||
if (ruleName.equals(rule.getName())) {
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
if (langName != null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
for (Grammar usedGrammar : grammar.getUsedGrammars()) {
|
||||
AbstractRule rule = findRuleForNameRecursively(usedGrammar, langName, ruleName, visited);
|
||||
if (rule != null) {
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Grammar> allUsedGrammars(Grammar grammar) {
|
||||
List<Grammar> grammars = new ArrayList<Grammar>();
|
||||
collectAllUsedGrammars(grammars, grammar);
|
||||
return grammars;
|
||||
Collection<Grammar> visitedGrammars = new LinkedHashSet<Grammar>();
|
||||
for(Grammar used: grammar.getUsedGrammars())
|
||||
collectAllUsedGrammars(used, grammar, visitedGrammars);
|
||||
return new ArrayList<Grammar>(visitedGrammars);
|
||||
}
|
||||
|
||||
private static void collectAllUsedGrammars(List<Grammar> grammars, Grammar grammar) {
|
||||
grammars.addAll(grammar.getUsedGrammars());
|
||||
for (Grammar g : grammar.getUsedGrammars())
|
||||
collectAllUsedGrammars(grammars, g);
|
||||
|
||||
private static void collectAllUsedGrammars(Grammar grammar, Grammar start, Collection<Grammar> result) {
|
||||
if (grammar == start || !result.add(grammar))
|
||||
return;
|
||||
for(Grammar usedGrammar: grammar.getUsedGrammars()) {
|
||||
collectAllUsedGrammars(usedGrammar, start, result);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<AbstractRule> allRules(Grammar grammar) {
|
||||
final List<AbstractRule> result = new ArrayList<AbstractRule>();
|
||||
final Set<String> names = new HashSet<String>();
|
||||
final Set<Grammar> grammars = new HashSet<Grammar>();
|
||||
collectAllRules(grammar, result, grammars, names);
|
||||
return result;
|
||||
final Set<AbstractRule> result = Sets.newLinkedHashSet();
|
||||
final Set<AbstractRule> explicitlyCalled = Sets.newHashSet();
|
||||
final Set<String> seenNames = Sets.newHashSet();
|
||||
final Set<Grammar> seenGrammars = Sets.newHashSet();
|
||||
collectAllRules(grammar, result, explicitlyCalled, seenNames, seenGrammars);
|
||||
return Lists.newArrayList(result);
|
||||
}
|
||||
|
||||
private static void collectAllRules(Grammar grammar, List<AbstractRule> result, Set<Grammar> visitedGrammars,
|
||||
Set<String> knownRulenames) {
|
||||
if (!visitedGrammars.add(grammar))
|
||||
private static void collectAllRules(
|
||||
Grammar grammar,
|
||||
Set<AbstractRule> result,
|
||||
Set<AbstractRule> explicitlyCalled,
|
||||
Set<String> seenNames,
|
||||
Set<Grammar> seenGrammars) {
|
||||
if (!seenGrammars.add(grammar))
|
||||
return;
|
||||
|
||||
for (AbstractRule rule : grammar.getRules()) {
|
||||
if (knownRulenames.add(rule.getName())) {
|
||||
// we need to iterate the rules twice in case an explicit call to a
|
||||
// rule is made from a rule defined later
|
||||
// this explicitly called rule needs to be added
|
||||
// to the set of all rules even though it may
|
||||
// have been specialized in the sub grammar
|
||||
if (!seenNames.contains(rule.getName()) || explicitlyCalled.contains(rule)) {
|
||||
AbstractElement body = rule.getAlternatives();
|
||||
if (body != null) {
|
||||
Iterator<EObject> contents = eAll(body);
|
||||
while(contents.hasNext()) {
|
||||
EObject content = contents.next();
|
||||
if (content instanceof RuleCall) {
|
||||
AbstractRule calledRule = ((RuleCall) content).getRule();
|
||||
explicitlyCalled.add(calledRule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (AbstractRule rule : grammar.getRules()) {
|
||||
if (seenNames.add(rule.getName()) || explicitlyCalled.contains(rule)) {
|
||||
result.add(rule);
|
||||
}
|
||||
}
|
||||
|
||||
for (Grammar usedGrammar : grammar.getUsedGrammars()) {
|
||||
collectAllRules(usedGrammar, result, visitedGrammars, knownRulenames);
|
||||
collectAllRules(usedGrammar, result, explicitlyCalled, seenNames, seenGrammars);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,8 +421,13 @@ public class GrammarUtil {
|
|||
final BidiIterator<INode> leafNodes = node.getAsTreeIterable().iterator();
|
||||
while (leafNodes.hasPrevious()) {
|
||||
INode previous = leafNodes.previous();
|
||||
if (previous instanceof ILeafNode && !((ILeafNode) previous).isHidden())
|
||||
return previous.getText();
|
||||
if (previous instanceof ILeafNode && !((ILeafNode) previous).isHidden()) {
|
||||
String result = previous.getText();
|
||||
if (result != null && result.startsWith("^")) {
|
||||
result = result.substring(1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
256
plugins/org.eclipse.xtext/src/org/eclipse/xtext/RuleNames.java
Normal file
256
plugins/org.eclipse.xtext/src/org/eclipse/xtext/RuleNames.java
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.common.notify.impl.AdapterImpl;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Different kinds of name mapping for rules in a grammar.
|
||||
*
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
@Singleton
|
||||
public class RuleNames {
|
||||
|
||||
static class Adapter extends AdapterImpl {
|
||||
private RuleNames ruleNames;
|
||||
|
||||
Adapter(RuleNames ruleNames) {
|
||||
this.ruleNames = ruleNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdapterForType(Object type) {
|
||||
return RuleNames.class.equals(type);
|
||||
}
|
||||
|
||||
public RuleNames getRuleNames() {
|
||||
return ruleNames;
|
||||
}
|
||||
}
|
||||
|
||||
private final Grammar contextGrammar;
|
||||
|
||||
/**
|
||||
* All rules by simple name.
|
||||
*/
|
||||
private final ListMultimap<String, AbstractRule> simpleNameToRules;
|
||||
/**
|
||||
* A mapping from qualified name to rule.
|
||||
*/
|
||||
private final Map<String, AbstractRule> qualifiedNameToRule;
|
||||
/**
|
||||
* The name that is unique or qualified depending on the occurrence.
|
||||
* It may either be a mapping from {@code ID} to rule or {@code com.acme.ID} to
|
||||
* rule depending on the fact if the ID rule is overridden in the context grammar.
|
||||
*/
|
||||
private final BiMap<String, AbstractRule> nameToRule;
|
||||
/**
|
||||
* The name that is used in code, e.g. the grammar access method names.
|
||||
*/
|
||||
private final BiMap<String, AbstractRule> uniqueNameToRule;
|
||||
/**
|
||||
* The name that is used in the generated Antlr grammar.
|
||||
*/
|
||||
private final BiMap<String, AbstractRule> antlrNameToRule;
|
||||
|
||||
private final List<AbstractRule> allRules;
|
||||
|
||||
public static RuleNames getRuleNames(Grammar grammar, boolean cache) {
|
||||
if (cache) {
|
||||
Adapter adapter = (Adapter) EcoreUtil.getAdapter(grammar.eAdapters(), RuleNames.class);
|
||||
if (adapter == null) {
|
||||
return new RuleNames(grammar, true);
|
||||
}
|
||||
return adapter.getRuleNames();
|
||||
}
|
||||
return new RuleNames(grammar, false);
|
||||
}
|
||||
|
||||
public static RuleNames getRuleNames(AbstractRule rule) {
|
||||
Adapter adapter = (Adapter) EcoreUtil.getAdapter(rule.eAdapters(), RuleNames.class);
|
||||
if (adapter == null) {
|
||||
throw new IllegalStateException("Cannot find adapter");
|
||||
}
|
||||
return adapter.getRuleNames();
|
||||
}
|
||||
|
||||
public static void ensureAdapterInstalled(Grammar grammar) {
|
||||
getRuleNames(grammar, true);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public RuleNames(IGrammarAccess grammarAccess) {
|
||||
this(grammarAccess.getGrammar(), false);
|
||||
}
|
||||
|
||||
public RuleNames(Grammar grammar, boolean installAdapter) {
|
||||
this.contextGrammar = grammar;
|
||||
Adapter adapter = new Adapter(this);
|
||||
if (installAdapter) {
|
||||
installAdapterIfMissing(adapter, grammar);
|
||||
}
|
||||
List<AbstractRule> allRules = GrammarUtil.allRules(grammar);
|
||||
ImmutableListMultimap.Builder<String, AbstractRule> simpleNameToRulesBuilder = ImmutableListMultimap.builder();
|
||||
ImmutableMap.Builder<String, AbstractRule> qualifiedNameToRuleBuilder = ImmutableMap.builder();
|
||||
ImmutableBiMap.Builder<String, AbstractRule> uniqueNameToRuleBuilder = ImmutableBiMap.builder();
|
||||
ImmutableBiMap.Builder<String, AbstractRule> antlrNameToRuleBuilder = ImmutableBiMap.builder();
|
||||
|
||||
Map<String, AbstractRule> names = Maps.newHashMap();
|
||||
Set<String> usedAntlrNames = Sets.newHashSet();
|
||||
Set<String> usedUniqueNames = Sets.newHashSet();
|
||||
for(AbstractRule rule: allRules) {
|
||||
String name = rule.getName();
|
||||
simpleNameToRulesBuilder.put(name, rule);
|
||||
String qualifiedName = getQualifiedName(rule);
|
||||
qualifiedNameToRuleBuilder.put(qualifiedName, rule);
|
||||
String uniqueName = name;
|
||||
String antlrRuleName;
|
||||
if (names.containsKey(name)) {
|
||||
name = qualifiedName;
|
||||
uniqueName = getInheritedUniqueName(rule, usedUniqueNames);
|
||||
antlrRuleName = getInheritedAntlrRuleName(rule, usedAntlrNames);
|
||||
} else {
|
||||
antlrRuleName = getDefaultAntlrRuleName(rule);
|
||||
}
|
||||
names.put(name, rule);
|
||||
if (!usedUniqueNames.add(uniqueName)) {
|
||||
throw new IllegalStateException(uniqueName);
|
||||
}
|
||||
uniqueNameToRuleBuilder.put(uniqueName, rule);
|
||||
if (!usedAntlrNames.add(antlrRuleName)) {
|
||||
throw new IllegalStateException(antlrRuleName);
|
||||
}
|
||||
antlrNameToRuleBuilder.put(antlrRuleName, rule);
|
||||
if (installAdapter) {
|
||||
installAdapterIfMissing(adapter, rule);
|
||||
}
|
||||
}
|
||||
simpleNameToRules = simpleNameToRulesBuilder.build();
|
||||
qualifiedNameToRule = qualifiedNameToRuleBuilder.build();
|
||||
nameToRule = ImmutableBiMap.copyOf(names);
|
||||
uniqueNameToRule = uniqueNameToRuleBuilder.build();
|
||||
antlrNameToRule = antlrNameToRuleBuilder.build();
|
||||
this.allRules = ImmutableList.copyOf(allRules);
|
||||
}
|
||||
|
||||
private void installAdapterIfMissing(Adapter adapter, EObject context) {
|
||||
if (EcoreUtil.getAdapter(context.eAdapters(), RuleNames.class) == null) {
|
||||
context.eAdapters().add(adapter);
|
||||
} else {
|
||||
throw new IllegalStateException("Duplicate adapter");
|
||||
}
|
||||
}
|
||||
|
||||
public List<AbstractRule> getRulesBySimpleName(String name) {
|
||||
return simpleNameToRules.get(name);
|
||||
}
|
||||
|
||||
public AbstractRule getRuleByQualifiedName(String name) {
|
||||
return qualifiedNameToRule.get(name);
|
||||
}
|
||||
|
||||
public String getQualifiedName(AbstractRule rule) {
|
||||
return GrammarUtil.getGrammar(rule).getName() + "." + rule.getName();
|
||||
}
|
||||
|
||||
public String getUniqueRuleName(AbstractRule rule) {
|
||||
return uniqueNameToRule.inverse().get(rule);
|
||||
}
|
||||
|
||||
public AbstractRule getRuleByUniqueName(String uniqueName) {
|
||||
return uniqueNameToRule.get(uniqueName);
|
||||
}
|
||||
|
||||
public String getAntlrRuleName(AbstractRule rule) {
|
||||
return antlrNameToRule.inverse().get(rule);
|
||||
}
|
||||
|
||||
public AbstractRule getRuleByAntlrName(String name) {
|
||||
return antlrNameToRule.get(name);
|
||||
}
|
||||
|
||||
public String getBestRuleName(AbstractRule rule) {
|
||||
return nameToRule.inverse().get(rule);
|
||||
}
|
||||
|
||||
public Grammar getContextGrammar() {
|
||||
return contextGrammar;
|
||||
}
|
||||
|
||||
public List<AbstractRule> getAllRules() {
|
||||
return allRules;
|
||||
}
|
||||
|
||||
public Iterable<ParserRule> getAllParserRules() {
|
||||
return Iterables.filter(allRules, ParserRule.class);
|
||||
}
|
||||
|
||||
private String getInheritedAntlrRuleName(AbstractRule rule, Set<String> usedNames) {
|
||||
if (rule instanceof ParserRule || rule instanceof EnumRule) {
|
||||
String candidate = "super" + rule.getName();
|
||||
int i = 1;
|
||||
while(usedNames.contains(candidate)) {
|
||||
candidate = "super" + i + rule.getName();
|
||||
i++;
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
if (rule instanceof TerminalRule) {
|
||||
String candidate = "SUPER_" + rule.getName();
|
||||
int i = 1;
|
||||
while(usedNames.contains(candidate)) {
|
||||
candidate = "SUPER_" + i + "_" + rule.getName();
|
||||
i++;
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
throw new IllegalArgumentException(rule.eClass().getName());
|
||||
}
|
||||
|
||||
private String getInheritedUniqueName(AbstractRule rule, Set<String> usedNames) {
|
||||
String grammarName = GrammarUtil.getName(GrammarUtil.getGrammar(rule));
|
||||
String candidate = grammarName + rule.getName();
|
||||
int i = 1;
|
||||
while(usedNames.contains(candidate)) {
|
||||
candidate = grammarName + i + rule.getName();
|
||||
i++;
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
private String getDefaultAntlrRuleName(AbstractRule rule) {
|
||||
if (rule instanceof ParserRule || rule instanceof EnumRule) {
|
||||
return "rule" + rule.getName();
|
||||
}
|
||||
if (rule instanceof TerminalRule) {
|
||||
return "RULE_" + rule.getName().toUpperCase();
|
||||
}
|
||||
throw new IllegalArgumentException(rule.eClass().getName());
|
||||
}
|
||||
|
||||
}
|
|
@ -12,13 +12,13 @@ import "http://www.eclipse.org/emf/2002/Ecore" as ecore
|
|||
|
||||
Grammar:
|
||||
'grammar' name=GrammarID ('with' usedGrammars+=[Grammar|GrammarID] (',' usedGrammars+=[Grammar|GrammarID])*)?
|
||||
(definesHiddenTokens?='hidden' '(' (hiddenTokens+=[AbstractRule] (',' hiddenTokens+=[AbstractRule])*)? ')')?
|
||||
(definesHiddenTokens?='hidden' '(' (hiddenTokens+=[AbstractRule|RuleID] (',' hiddenTokens+=[AbstractRule|RuleID])*)? ')')?
|
||||
metamodelDeclarations+=AbstractMetamodelDeclaration*
|
||||
(rules+=AbstractRule)+
|
||||
;
|
||||
|
||||
GrammarID returns ecore::EString:
|
||||
ID ('.' ID)*;
|
||||
ValidID ('.' ValidID)*;
|
||||
|
||||
AbstractRule : ParserRule | TerminalRule | EnumRule;
|
||||
|
||||
|
@ -28,25 +28,46 @@ AbstractMetamodelDeclaration :
|
|||
// constraint: typeSelect(GeneratedMetamodel).size() == typeSelect(GeneratedMetamodel).alias.size()
|
||||
// generated metamodels have to have different aliases
|
||||
GeneratedMetamodel :
|
||||
'generate' name=ID ePackage=[ecore::EPackage|STRING] ('as' alias=ID)?;
|
||||
'generate' name=ValidID ePackage=[ecore::EPackage|STRING] ('as' alias=ValidID)?;
|
||||
|
||||
// referenced metamodels may share aliases with other referenced metamodels
|
||||
// and with generated metamodels
|
||||
ReferencedMetamodel :
|
||||
'import' ePackage=[ecore::EPackage|STRING] ('as' alias=ID)?;
|
||||
'import' ePackage=[ecore::EPackage|STRING] ('as' alias=ValidID)?;
|
||||
|
||||
//fragment Alias returns AbstractMetamodelDeclaration:
|
||||
// 'as' alias=ValidID
|
||||
//;
|
||||
|
||||
ParserRule :
|
||||
name=ID ('returns' type=TypeRef)? (definesHiddenTokens?='hidden' '(' (hiddenTokens+=[AbstractRule] (',' hiddenTokens+=[AbstractRule])*)? ')')?':'
|
||||
(
|
||||
^fragment?='fragment' RuleNameAndParams (wildcard?='*' | ('returns' type=TypeRef)?)
|
||||
| RuleNameAndParams ('returns' type=TypeRef)?
|
||||
)
|
||||
(definesHiddenTokens?='hidden' '(' (hiddenTokens+=[AbstractRule|RuleID] (',' hiddenTokens+=[AbstractRule|RuleID])*)? ')')? ':'
|
||||
alternatives=Alternatives
|
||||
';'
|
||||
;
|
||||
|
||||
fragment RuleNameAndParams returns ParserRule:
|
||||
name=ValidID ('<' (parameters+=Parameter (',' parameters+=Parameter)*)? '>')?
|
||||
;
|
||||
|
||||
Parameter:
|
||||
name=ID
|
||||
;
|
||||
|
||||
TypeRef :
|
||||
(metamodel=[AbstractMetamodelDeclaration] '::')? classifier=[ecore::EClassifier]
|
||||
;
|
||||
|
||||
Alternatives returns AbstractElement:
|
||||
UnorderedGroup ({Alternatives.elements+=current} ('|' elements+=UnorderedGroup)+)?
|
||||
ConditionalBranch ({Alternatives.elements+=current} ('|' elements+=ConditionalBranch)+)?
|
||||
;
|
||||
|
||||
ConditionalBranch returns AbstractElement:
|
||||
UnorderedGroup
|
||||
| {Group} '<' guardCondition=Disjunction '>' (elements+=AbstractToken)+
|
||||
;
|
||||
|
||||
UnorderedGroup returns AbstractElement:
|
||||
|
@ -64,11 +85,11 @@ AbstractToken returns AbstractElement:
|
|||
|
||||
/* SuppressWarnings[potentialOverride]: Handled in CardinalityAwareEcoreFactory */
|
||||
AbstractTokenWithCardinality returns AbstractElement:
|
||||
(Assignment | AbstractTerminal) (cardinality=('?'|'*'|'+'))?
|
||||
(Assignment | AbstractTerminal) cardinality=('?'|'*'|'+')?
|
||||
;
|
||||
|
||||
Action returns Action:
|
||||
'{' type=TypeRef ('.' feature=ID operator=('='|'+=') 'current')? '}'
|
||||
'{' type=TypeRef ('.' feature=ValidID operator=('='|'+=') 'current')? '}'
|
||||
;
|
||||
|
||||
AbstractTerminal returns AbstractElement:
|
||||
|
@ -82,8 +103,6 @@ AbstractTerminal returns AbstractElement:
|
|||
PredicatedRuleCall |
|
||||
// We have to make this one explicit since the ParenthesizedElement does not
|
||||
// create an object but we have to set the predicated flag
|
||||
// TODO: As soon as we have an own element for parenthesized elements with
|
||||
// cardinality, we should refactor this part of the grammar
|
||||
PredicatedGroup
|
||||
;
|
||||
|
||||
|
@ -92,7 +111,60 @@ Keyword :
|
|||
;
|
||||
|
||||
RuleCall :
|
||||
rule=[AbstractRule]
|
||||
rule=[AbstractRule|RuleID] ('<' arguments+=NamedArgument (',' arguments+=NamedArgument)* '>')?
|
||||
;
|
||||
|
||||
NamedArgument:
|
||||
( parameter=[Parameter|ID] calledByName?= '=')?
|
||||
( value=ConditionOrLiteral )
|
||||
;
|
||||
|
||||
ConditionOrLiteral returns Condition:
|
||||
LiteralCondition | Disjunction
|
||||
;
|
||||
|
||||
LiteralCondition:
|
||||
{LiteralCondition} (true?='true' | 'false')
|
||||
;
|
||||
|
||||
Disjunction returns Condition:
|
||||
Conjunction ({Disjunction.left=current} '|' right=Conjunction)*
|
||||
;
|
||||
|
||||
Conjunction returns Condition:
|
||||
Negation ({Conjunction.left=current} '&' right=Negation)*
|
||||
;
|
||||
|
||||
Negation returns Condition:
|
||||
Atom | {Negation} '!' value=Negation
|
||||
;
|
||||
|
||||
Atom returns Condition:
|
||||
ParameterReference | ParenthesizedCondition
|
||||
;
|
||||
|
||||
ParenthesizedCondition returns Condition:
|
||||
'(' Disjunction ')'
|
||||
;
|
||||
|
||||
ParameterReference:
|
||||
parameter=[Parameter|ID]
|
||||
;
|
||||
|
||||
TerminalRuleCall returns RuleCall:
|
||||
rule=[AbstractRule|RuleID]
|
||||
;
|
||||
|
||||
RuleID returns ecore::EString:
|
||||
ValidID ('::' ValidID)*
|
||||
;
|
||||
|
||||
ValidID returns ecore::EString:
|
||||
ID | 'true' | 'false'
|
||||
;
|
||||
|
||||
Boolean returns ecore::EBoolean:
|
||||
'true' | 'false'
|
||||
;
|
||||
|
||||
PredicatedKeyword returns Keyword:
|
||||
|
@ -100,11 +172,11 @@ PredicatedKeyword returns Keyword:
|
|||
;
|
||||
|
||||
PredicatedRuleCall returns RuleCall:
|
||||
(predicated?='=>' | firstSetPredicated?='->') rule=[AbstractRule]
|
||||
(predicated?='=>' | firstSetPredicated?='->') rule=[AbstractRule] ('<' arguments+=NamedArgument (',' arguments+=NamedArgument)* '>')?
|
||||
;
|
||||
|
||||
Assignment returns Assignment:
|
||||
(predicated?='=>' | firstSetPredicated?='->')? feature=ID operator=('+='|'='|'?=') ^terminal=AssignableTerminal
|
||||
(predicated?='=>' | firstSetPredicated?='->')? feature=ValidID operator=('+='|'='|'?=') ^terminal=AssignableTerminal
|
||||
;
|
||||
|
||||
AssignableTerminal returns AbstractElement:
|
||||
|
@ -136,7 +208,7 @@ PredicatedGroup returns Group:
|
|||
;
|
||||
|
||||
TerminalRule :
|
||||
'terminal' (^fragment?='fragment' name=ID | name=ID ('returns' type=TypeRef)?) ':'
|
||||
'terminal' (^fragment?='fragment' name=ValidID | name=ValidID ('returns' type=TypeRef)?) ':'
|
||||
alternatives=TerminalAlternatives
|
||||
';'
|
||||
;
|
||||
|
@ -151,11 +223,11 @@ TerminalGroup returns AbstractElement:
|
|||
|
||||
/* SuppressWarnings[potentialOverride]: Handled in CardinalityAwareEcoreFactory */
|
||||
TerminalToken returns AbstractElement:
|
||||
TerminalTokenElement (cardinality=('?'|'*'|'+'))?
|
||||
TerminalTokenElement cardinality=('?'|'*'|'+')?
|
||||
;
|
||||
|
||||
TerminalTokenElement returns AbstractElement:
|
||||
CharacterRange | RuleCall | ParenthesizedTerminalElement | AbstractNegatedToken | Wildcard | ^EOF
|
||||
CharacterRange | TerminalRuleCall | ParenthesizedTerminalElement | AbstractNegatedToken | Wildcard | ^EOF
|
||||
;
|
||||
|
||||
ParenthesizedTerminalElement returns AbstractElement:
|
||||
|
@ -187,7 +259,7 @@ CharacterRange returns AbstractElement:
|
|||
;
|
||||
|
||||
EnumRule:
|
||||
'enum' name=ID ('returns' type=TypeRef)? ':'
|
||||
'enum' name=ValidID ('returns' type=TypeRef)? ':'
|
||||
alternatives=EnumLiterals
|
||||
';'
|
||||
;
|
||||
|
|
|
@ -31,6 +31,17 @@ public class DefaultTerminalConverters extends AbstractDeclarativeValueConverter
|
|||
return idValueConverter;
|
||||
}
|
||||
|
||||
@Inject
|
||||
private AbstractIDValueConverter terminalsIdValueConverter;
|
||||
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
@ValueConverter(rule = "org.eclipse.xtext.common.Terminals.ID")
|
||||
public IValueConverter<String> TerminalsID() {
|
||||
return terminalsIdValueConverter;
|
||||
}
|
||||
|
||||
@Inject
|
||||
private INTValueConverter intValueConverter;
|
||||
|
||||
|
@ -38,6 +49,17 @@ public class DefaultTerminalConverters extends AbstractDeclarativeValueConverter
|
|||
public IValueConverter<Integer> INT() {
|
||||
return intValueConverter;
|
||||
}
|
||||
|
||||
@Inject
|
||||
private INTValueConverter terminalsIntValueConverter;
|
||||
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
@ValueConverter(rule = "org.eclipse.xtext.common.Terminals.INT")
|
||||
public IValueConverter<Integer> TerminalsINT() {
|
||||
return terminalsIntValueConverter;
|
||||
}
|
||||
|
||||
@Inject
|
||||
private STRINGValueConverter stringValueConverter;
|
||||
|
@ -47,4 +69,15 @@ public class DefaultTerminalConverters extends AbstractDeclarativeValueConverter
|
|||
return stringValueConverter;
|
||||
}
|
||||
|
||||
@Inject
|
||||
private STRINGValueConverter terminalsStringValueConverter;
|
||||
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
@ValueConverter(rule = "org.eclipse.xtext.common.Terminals.STRING")
|
||||
public IValueConverter<String> TerminalsSTRING() {
|
||||
return terminalsStringValueConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,9 +14,12 @@ import org.eclipse.xtext.conversion.ValueConverter;
|
|||
import org.eclipse.xtext.conversion.impl.AbstractNullSafeConverter;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
*/
|
||||
@Singleton
|
||||
public class Ecore2XtextTerminalConverters extends DefaultTerminalConverters {
|
||||
|
||||
private static final Pattern ID_PATTERN = Pattern.compile("\\p{Alpha}\\w*");
|
||||
|
|
|
@ -12,13 +12,22 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.eclipse.xtext.conversion.impl.AbstractDeclarativeValueConverterService;
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*
|
||||
* Annotate methods in your own {@link AbstractDeclarativeValueConverterService}
|
||||
* to mark them as contributions to all known value converters.
|
||||
*
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||
public @interface ValueConverter {
|
||||
/**
|
||||
* The name of the rule that is converted by this value converter.
|
||||
* May be a qualified name, e.g. {@code com.acme.MySuperLang.MyDataTypeRule} to
|
||||
* provide value converters for inherited rules that are called with the explicit
|
||||
* notation {@code super::MyDataTypeRule} or {@code com::acme::MySuperLang::MyDataTypeRule}.
|
||||
*/
|
||||
String rule();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ package org.eclipse.xtext.conversion.impl;
|
|||
|
||||
import static org.eclipse.xtext.GrammarUtil.*;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -22,6 +23,7 @@ import org.eclipse.xtext.Grammar;
|
|||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleNames;
|
||||
import org.eclipse.xtext.TerminalRule;
|
||||
import org.eclipse.xtext.conversion.IValueConverter;
|
||||
import org.eclipse.xtext.conversion.IValueConverterService;
|
||||
|
@ -55,6 +57,9 @@ public abstract class AbstractDeclarativeValueConverterService extends AbstractV
|
|||
@Inject
|
||||
protected DefaultTerminalConverter.Factory defaultTerminalConverterFactory;
|
||||
|
||||
@Inject
|
||||
private RuleNames ruleNames;
|
||||
|
||||
@Inject
|
||||
public void setGrammar(IGrammarAccess grammarAccess) {
|
||||
this.grammar = grammarAccess.getGrammar();
|
||||
|
@ -105,33 +110,48 @@ public abstract class AbstractDeclarativeValueConverterService extends AbstractV
|
|||
* @nooverride This method is not intended to be re-implemented or extended by clients.
|
||||
* @noreference This method is not intended to be referenced by clients.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void internalRegisterForClass(Class<?> clazz, Map<String, IValueConverter<Object>> converters) {
|
||||
recursiveRegisterForClass(clazz, converters);
|
||||
registerEFactoryConverters(converters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
protected void recursiveRegisterForClass(Class<?> clazz, Map<String, IValueConverter<Object>> converters) {
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
Set<String> thisConverters = Sets.newHashSet();
|
||||
recursiveRegisterForClass(methods, thisConverters, true, converters);
|
||||
recursiveRegisterForClass(methods, thisConverters, false, converters);
|
||||
if (clazz.getSuperclass() != null) {
|
||||
recursiveRegisterForClass(clazz.getSuperclass(), converters);
|
||||
}
|
||||
}
|
||||
|
||||
private void recursiveRegisterForClass(Method[] methods, Set<String> thisConverters, boolean onlyExplicitConverters,
|
||||
Map<String, IValueConverter<Object>> converters) {
|
||||
for (Method method : methods) {
|
||||
if (isConfigurationMethod(method)) {
|
||||
try {
|
||||
String ruleName = method.getAnnotation(ValueConverter.class).rule();
|
||||
AbstractRule rule = GrammarUtil.findRuleForName(getGrammar(), ruleName);
|
||||
if (rule != null) {
|
||||
if (rule instanceof TerminalRule) {
|
||||
if (((TerminalRule) rule).isFragment())
|
||||
throw new IllegalStateException("Tried to register a value converter for a fragment terminal rule: '" + ruleName + "'");
|
||||
if (onlyExplicitConverters ^ ruleName.indexOf('.') < 0) {
|
||||
AbstractRule rule = GrammarUtil.findRuleForName(getGrammar(), ruleName);
|
||||
if (rule != null) {
|
||||
if (rule instanceof TerminalRule) {
|
||||
if (((TerminalRule) rule).isFragment())
|
||||
throw new IllegalStateException("Tried to register a value converter for a fragment terminal rule: '" + ruleName + "'");
|
||||
}
|
||||
if (!thisConverters.add(ruleName)) {
|
||||
throw new IllegalStateException("Tried to register two value converters for rule '" + ruleName + "'");
|
||||
}
|
||||
IValueConverter<Object> converter = registerIfMissing(ruleName, rule, method, converters);
|
||||
String qualifiedName = ruleNames.getQualifiedName(rule);
|
||||
registerIfMissing(qualifiedName, rule, converter, method, converters);
|
||||
} else {
|
||||
log.trace("Tried to register value converter for rule '" + ruleName
|
||||
+ "' which is not available in the grammar.");
|
||||
}
|
||||
if (!thisConverters.add(ruleName)) {
|
||||
throw new IllegalStateException("Tried to register two value converters for rule '" + ruleName + "'");
|
||||
}
|
||||
if (!converters.containsKey(ruleName)) {
|
||||
IValueConverter<Object> valueConverter = (IValueConverter<Object>) method.invoke(this);
|
||||
if (valueConverter instanceof IValueConverter.RuleSpecific)
|
||||
((IValueConverter.RuleSpecific) valueConverter).setRule(rule);
|
||||
converters.put(ruleName, valueConverter);
|
||||
}
|
||||
} else
|
||||
log.trace("Tried to register value converter for rule '" + ruleName
|
||||
+ "' which is not available in the grammar.");
|
||||
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
throw e;
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
@ -141,10 +161,35 @@ public abstract class AbstractDeclarativeValueConverterService extends AbstractV
|
|||
}
|
||||
}
|
||||
}
|
||||
if (clazz.getSuperclass() != null) {
|
||||
internalRegisterForClass(clazz.getSuperclass(), converters);
|
||||
}
|
||||
|
||||
private IValueConverter<Object> registerIfMissing(String name, AbstractRule rule, Method method,
|
||||
Map<String, IValueConverter<Object>> converters) throws IllegalAccessException, InvocationTargetException {
|
||||
if (!converters.containsKey(name)) {
|
||||
IValueConverter<Object> valueConverter = reflectiveGetConverter(method, rule);
|
||||
converters.put(name, valueConverter);
|
||||
return valueConverter;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private IValueConverter<Object> reflectiveGetConverter(Method method, AbstractRule rule)
|
||||
throws IllegalAccessException, InvocationTargetException {
|
||||
IValueConverter<Object> valueConverter = (IValueConverter<Object>) method.invoke(this);
|
||||
if (valueConverter instanceof IValueConverter.RuleSpecific)
|
||||
((IValueConverter.RuleSpecific) valueConverter).setRule(rule);
|
||||
return valueConverter;
|
||||
}
|
||||
|
||||
private void registerIfMissing(String name, AbstractRule rule, IValueConverter<Object> valueConverter, Method method,
|
||||
Map<String, IValueConverter<Object>> converters) throws IllegalAccessException, InvocationTargetException {
|
||||
if (!converters.containsKey(name)) {
|
||||
if (valueConverter == null) {
|
||||
valueConverter = reflectiveGetConverter(method, rule);
|
||||
}
|
||||
converters.put(name, valueConverter);
|
||||
}
|
||||
registerEFactoryConverters(converters);
|
||||
}
|
||||
|
||||
protected boolean isConfigurationMethod(Method method) {
|
||||
|
@ -159,20 +204,33 @@ public abstract class AbstractDeclarativeValueConverterService extends AbstractV
|
|||
*/
|
||||
protected void registerEFactoryConverters(Map<String, IValueConverter<Object>> converters) {
|
||||
for (ParserRule parserRule : allParserRules(getGrammar())) {
|
||||
if (isDatatypeRule(parserRule) && !converters.containsKey(parserRule.getName())) {
|
||||
EDataType datatype = (EDataType) parserRule.getType().getClassifier();
|
||||
converters.put(parserRule.getName(), new EFactoryValueConverter(datatype));
|
||||
if (isDatatypeRule(parserRule)) {
|
||||
registerIfMissing(parserRule.getName(), parserRule, converters);
|
||||
registerIfMissing(ruleNames.getQualifiedName(parserRule), parserRule, converters);
|
||||
}
|
||||
}
|
||||
for (TerminalRule terminalRule : allTerminalRules(getGrammar())) {
|
||||
if (!terminalRule.isFragment()) {
|
||||
String terminalRuleName = terminalRule.getName();
|
||||
if (!converters.containsKey(terminalRuleName)) {
|
||||
converters.put(terminalRuleName, defaultTerminalConverterFactory.create(terminalRule));
|
||||
}
|
||||
registerIfMissing(terminalRule.getName(), terminalRule, converters);
|
||||
registerIfMissing(ruleNames.getQualifiedName(terminalRule), terminalRule, converters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerIfMissing(String name, TerminalRule terminalRule,
|
||||
Map<String, IValueConverter<Object>> converters) {
|
||||
if (!converters.containsKey(name)) {
|
||||
converters.put(name, defaultTerminalConverterFactory.create(terminalRule));
|
||||
}
|
||||
}
|
||||
|
||||
private void registerIfMissing(String name, ParserRule parserRule,
|
||||
Map<String, IValueConverter<Object>> converters) {
|
||||
if (!converters.containsKey(name)) {
|
||||
EDataType datatype = (EDataType) parserRule.getType().getClassifier();
|
||||
converters.put(name, new EFactoryValueConverter(datatype));
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultTerminalConverterFactory(DefaultTerminalConverter.Factory defaultTerminalConverterFactory) {
|
||||
this.defaultTerminalConverterFactory = defaultTerminalConverterFactory;
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.eclipse.xtext.conversion.ValueConverterException;
|
|||
import org.eclipse.xtext.parser.antlr.ITokenDefProvider;
|
||||
import org.eclipse.xtext.parser.antlr.Lexer;
|
||||
import org.eclipse.xtext.parser.antlr.LexerBindings;
|
||||
import org.eclipse.xtext.parser.antlr.TokenTool;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
@ -109,7 +110,7 @@ public abstract class AbstractLexerBasedConverter<T> extends AbstractValueConver
|
|||
// TODO: rename to getLexerRuleName() on next API change
|
||||
protected String getRuleName(Token token) {
|
||||
String result = getTokenDefMap().get(token.getType());
|
||||
return result.substring("RULE_".length());
|
||||
return TokenTool.getLexerRuleName(result);
|
||||
}
|
||||
|
||||
protected Map<Integer, String> getTokenDefMap() {
|
||||
|
|
|
@ -10,7 +10,6 @@ package org.eclipse.xtext.formatting.impl;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EClass;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.Action;
|
||||
|
@ -108,8 +107,7 @@ public class MatcherState extends AbstractNFAState<MatcherState, MatcherTransiti
|
|||
}
|
||||
|
||||
public boolean isParserRuleCall() {
|
||||
return element instanceof RuleCall
|
||||
&& ((RuleCall) element).getRule().getType().getClassifier() instanceof EClass;
|
||||
return GrammarUtil.isEObjectRuleCall(element);
|
||||
}
|
||||
|
||||
public boolean isParserRuleCallOptional() {
|
||||
|
|
|
@ -18,7 +18,6 @@ import java.util.Set;
|
|||
|
||||
import org.eclipse.emf.common.notify.Adapter;
|
||||
import org.eclipse.emf.common.notify.impl.AdapterImpl;
|
||||
import org.eclipse.emf.ecore.EClass;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
|
@ -144,8 +143,7 @@ public class AbstractNFAState<S extends INFAState<S, T>, T extends INFATransitio
|
|||
addOutgoing(((Assignment) element).getTerminal(), visited, isRuleCall, loopCenter);
|
||||
else if (element instanceof CrossReference)
|
||||
addOutgoing(((CrossReference) element).getTerminal(), visited, isRuleCall, loopCenter);
|
||||
else if (element instanceof RuleCall
|
||||
&& ((RuleCall) element).getRule().getType().getClassifier() instanceof EClass) {
|
||||
else if (GrammarUtil.isEObjectRuleCall(element)) {
|
||||
addOutgoing(((RuleCall) element).getRule().getAlternatives(), visited, true, loopCenter);
|
||||
collectOutgoingByContainer(element, visited, isRuleCall, loopCenter);
|
||||
} else {
|
||||
|
@ -213,7 +211,7 @@ public class AbstractNFAState<S extends INFAState<S, T>, T extends INFATransitio
|
|||
|
||||
protected boolean filter(AbstractElement ele) {
|
||||
AbstractRule rule = GrammarUtil.containingRule(ele);
|
||||
if (rule == null || !(rule.getType().getClassifier() instanceof EClass))
|
||||
if (rule == null || !GrammarUtil.isEObjectRule(rule))
|
||||
return true;
|
||||
return builder.filter(ele);
|
||||
}
|
||||
|
@ -227,7 +225,7 @@ public class AbstractNFAState<S extends INFAState<S, T>, T extends INFATransitio
|
|||
for (EObject root : element.eResource().getContents())
|
||||
if (root instanceof Grammar)
|
||||
for (AbstractRule rule : ((Grammar) root).getRules())
|
||||
if (rule.getType().getClassifier() instanceof EClass)
|
||||
if (GrammarUtil.isEObjectRule(rule))
|
||||
for (AbstractElement ele : EcoreUtil2.eAllOfType(rule, AbstractElement.class))
|
||||
if (!builder.filter(ele))
|
||||
builder.getState(ele).getOutgoing();
|
||||
|
|
|
@ -169,7 +169,7 @@ public class GrammarElementTitleSwitch extends XtextSwitch<String> implements Fu
|
|||
o = (o == null) ? "" : o;
|
||||
String result;
|
||||
if (showActionAsRuleCall && f != null) {
|
||||
result = f + o + new Context2NameFunction().apply(object) + card(object);
|
||||
result = f + o + new Context2NameFunction().toFunction(null).apply(object) + card(object);
|
||||
} else {
|
||||
String t = object.getType() != null && object.getType().getClassifier() != null ? object.getType()
|
||||
.getClassifier().getName() : "null";
|
||||
|
|
|
@ -17,8 +17,11 @@ import org.eclipse.emf.ecore.EObject;
|
|||
import org.eclipse.emf.ecore.EReference;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.Assignment;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.diagnostics.IDiagnosticConsumer;
|
||||
import org.eclipse.xtext.linking.lazy.LazyLinkingResource;
|
||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
||||
|
@ -123,9 +126,17 @@ public abstract class AbstractCleaningLinker extends AbstractLinker {
|
|||
EObject grammarElement = node.getGrammarElement();
|
||||
if (grammarElement instanceof AbstractElement) {
|
||||
ICompositeNode parent = node.getParent();
|
||||
if (parent != null && !parent.hasDirectSemanticElement()) {
|
||||
Assignment assignment = GrammarUtil.containingAssignment(grammarElement);
|
||||
return assignment == null;
|
||||
if (parent != null) {
|
||||
if (!parent.hasDirectSemanticElement()) {
|
||||
Assignment assignment = GrammarUtil.containingAssignment(grammarElement);
|
||||
return assignment == null;
|
||||
}
|
||||
if (grammarElement instanceof Action) {
|
||||
ParserRule rule = (ParserRule) GrammarUtil.containingRule(grammarElement);
|
||||
if (rule.isFragment()) {
|
||||
return parent.getGrammarElement() instanceof RuleCall;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -18,8 +18,11 @@ import org.eclipse.emf.common.util.TreeIterator;
|
|||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.EReference;
|
||||
import org.eclipse.emf.ecore.util.InternalEList;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.CrossReference;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.diagnostics.DiagnosticMessage;
|
||||
import org.eclipse.xtext.diagnostics.IDiagnosticConsumer;
|
||||
import org.eclipse.xtext.diagnostics.IDiagnosticProducer;
|
||||
|
@ -53,22 +56,29 @@ public class Linker extends AbstractCleaningLinker {
|
|||
if (node == null)
|
||||
return;
|
||||
Set<EReference> handledReferences = new HashSet<EReference>();
|
||||
ensureLinked(obj, producer, node, handledReferences);
|
||||
ensureLinked(obj, producer, node, handledReferences, false);
|
||||
producer.setNode(node);
|
||||
setDefaultValues(obj, handledReferences, producer);
|
||||
}
|
||||
|
||||
private void ensureLinked(EObject obj, IDiagnosticProducer producer, ICompositeNode node,
|
||||
Set<EReference> handledReferences) {
|
||||
Set<EReference> handledReferences, boolean dontCheckParent) {
|
||||
for(INode abstractNode = node.getFirstChild(); abstractNode != null; abstractNode = abstractNode.getNextSibling()) {
|
||||
if (abstractNode.getGrammarElement() instanceof CrossReference) {
|
||||
CrossReference ref = (CrossReference) abstractNode.getGrammarElement();
|
||||
EObject grammarElement = abstractNode.getGrammarElement();
|
||||
if (grammarElement instanceof CrossReference) {
|
||||
CrossReference ref = (CrossReference) grammarElement;
|
||||
producer.setNode(abstractNode);
|
||||
ensureIsLinked(obj, abstractNode, ref, handledReferences, producer);
|
||||
} else if (grammarElement instanceof RuleCall && abstractNode instanceof ICompositeNode) {
|
||||
RuleCall ruleCall = (RuleCall) grammarElement;
|
||||
AbstractRule calledRule = ruleCall.getRule();
|
||||
if (calledRule instanceof ParserRule && ((ParserRule) calledRule).isFragment()) {
|
||||
ensureLinked(obj, producer, (ICompositeNode) abstractNode, handledReferences, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldCheckParentNode(node)) {
|
||||
ensureLinked(obj, producer, node.getParent(), handledReferences);
|
||||
if (!dontCheckParent && shouldCheckParentNode(node)) {
|
||||
ensureLinked(obj, producer, node.getParent(), handledReferences, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,10 +87,11 @@ public class Linker extends AbstractCleaningLinker {
|
|||
}
|
||||
|
||||
private void setDefaultValues(EObject obj, Set<EReference> references, IDiagnosticProducer producer) {
|
||||
for (EReference ref : obj.eClass().getEAllReferences())
|
||||
for (EReference ref : obj.eClass().getEAllReferences()) {
|
||||
if (canSetDefaultValues(ref) && !references.contains(ref) && !obj.eIsSet(ref) && !ref.isDerived()) {
|
||||
setDefaultValue(obj, ref, producer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean canSetDefaultValues(EReference ref) {
|
||||
|
|
|
@ -28,11 +28,13 @@ import org.eclipse.emf.ecore.resource.Resource;
|
|||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
import org.eclipse.emf.ecore.util.InternalEList;
|
||||
import org.eclipse.xtext.AbstractMetamodelDeclaration;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.CrossReference;
|
||||
import org.eclipse.xtext.EcoreUtil2;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.diagnostics.IDiagnosticConsumer;
|
||||
import org.eclipse.xtext.diagnostics.IDiagnosticProducer;
|
||||
import org.eclipse.xtext.linking.impl.AbstractCleaningLinker;
|
||||
|
@ -110,11 +112,11 @@ public class LazyLinker extends AbstractCleaningLinker {
|
|||
ICompositeNode node = NodeModelUtils.getNode(obj);
|
||||
if (node == null)
|
||||
return;
|
||||
installProxies(obj, producer, settingsToLink, node);
|
||||
installProxies(obj, producer, settingsToLink, node, false);
|
||||
}
|
||||
|
||||
private void installProxies(EObject obj, IDiagnosticProducer producer,
|
||||
Multimap<EStructuralFeature.Setting, INode> settingsToLink, ICompositeNode parentNode) {
|
||||
Multimap<EStructuralFeature.Setting, INode> settingsToLink, ICompositeNode parentNode, boolean dontCheckParent) {
|
||||
final EClass eClass = obj.eClass();
|
||||
if (eClass.getEAllReferences().size() - eClass.getEAllContainments().size() == 0)
|
||||
return;
|
||||
|
@ -137,10 +139,16 @@ public class LazyLinker extends AbstractCleaningLinker {
|
|||
createAndSetProxy(obj, node, eRef);
|
||||
afterCreateAndSetProxy(obj, node, eRef, crossReference, producer);
|
||||
}
|
||||
} else if (grammarElement instanceof RuleCall && node instanceof ICompositeNode) {
|
||||
RuleCall ruleCall = (RuleCall) grammarElement;
|
||||
AbstractRule calledRule = ruleCall.getRule();
|
||||
if (calledRule instanceof ParserRule && ((ParserRule) calledRule).isFragment()) {
|
||||
installProxies(obj, producer, settingsToLink, (ICompositeNode) node, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldCheckParentNode(parentNode)) {
|
||||
installProxies(obj, producer, settingsToLink, parentNode.getParent());
|
||||
if (!dontCheckParent && shouldCheckParentNode(parentNode)) {
|
||||
installProxies(obj, producer, settingsToLink, parentNode.getParent(), dontCheckParent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,11 @@ import com.google.inject.Inject;
|
|||
*/
|
||||
public abstract class AbstractSplittingTokenSource implements TokenSource {
|
||||
|
||||
public static final String LEXER_RULE_PREFIX = "RULE_";
|
||||
/**
|
||||
* @deprecated use {@link TokenTool#LEXER_RULE_PREFIX} if strictly necessary.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String LEXER_RULE_PREFIX = TokenTool.LEXER_RULE_PREFIX;
|
||||
|
||||
private TokenSource delegate;
|
||||
|
||||
|
@ -74,9 +78,7 @@ public abstract class AbstractSplittingTokenSource implements TokenSource {
|
|||
}
|
||||
|
||||
public String getLexerRuleName(String antlrTokenDef) {
|
||||
if (antlrTokenDef.startsWith(LEXER_RULE_PREFIX))
|
||||
return antlrTokenDef.substring(LEXER_RULE_PREFIX.length());
|
||||
return antlrTokenDef;
|
||||
return TokenTool.getLexerRuleName(antlrTokenDef);
|
||||
}
|
||||
|
||||
@Inject
|
||||
|
|
|
@ -62,7 +62,7 @@ public class AntlrTokenDefProvider implements ITokenDefProvider {
|
|||
antlrTokenDef = Strings.convertFromJavaString(antlrTokenDef, true);
|
||||
antlrTokenDef = "'" + antlrTokenDef + "'";
|
||||
tokenDefMap.put(antlrTokenType, antlrTokenDef);
|
||||
} else if (antlrTokenDef.startsWith("RULE_") || isKeywordToken(antlrTokenDef)) {
|
||||
} else if (antlrTokenDef.startsWith("RULE_") || isKeywordToken(antlrTokenDef) || antlrTokenDef.startsWith("SUPER_")) {
|
||||
tokenDefMap.put(antlrTokenType, antlrTokenDef);
|
||||
}
|
||||
line = br.readLine();
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.parser.antlr;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.antlr.runtime.CommonToken;
|
||||
import org.antlr.runtime.Token;
|
||||
|
||||
|
@ -53,12 +56,20 @@ public class TokenTool {
|
|||
|
||||
public static final String LEXER_RULE_PREFIX = "RULE_";
|
||||
|
||||
private static final Pattern superRulePattern = Pattern.compile("^(SUPER_(\\d+_)?).*$");
|
||||
|
||||
public static boolean isLexerRule(String antlrTokenDef) {
|
||||
return antlrTokenDef.startsWith(LEXER_RULE_PREFIX);
|
||||
}
|
||||
|
||||
public static String getLexerRuleName(String antlrTokenDef) {
|
||||
return antlrTokenDef.substring(LEXER_RULE_PREFIX.length());
|
||||
if (antlrTokenDef.startsWith(LEXER_RULE_PREFIX))
|
||||
return antlrTokenDef.substring(LEXER_RULE_PREFIX.length());
|
||||
Matcher matcher = superRulePattern.matcher(antlrTokenDef);
|
||||
if (matcher.matches()) {
|
||||
return antlrTokenDef.substring(matcher.group(1).length());
|
||||
}
|
||||
return antlrTokenDef;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -281,9 +281,13 @@ public class PartialParsingHelper implements IPartialParsingHelper {
|
|||
return true;
|
||||
if (candidate.getGrammarElement() instanceof RuleCall) {
|
||||
AbstractRule rule = ((RuleCall) candidate.getGrammarElement()).getRule();
|
||||
if (!(rule instanceof ParserRule) || GrammarUtil.isDatatypeRule((ParserRule) rule))
|
||||
if (!(rule instanceof ParserRule))
|
||||
return true;
|
||||
else if (isInvalidDueToPredicates((AbstractElement) candidate.getGrammarElement()))
|
||||
ParserRule casted = (ParserRule) rule;
|
||||
if (GrammarUtil.isDatatypeRule(casted) || casted.isFragment() || !casted.getParameters().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (isInvalidDueToPredicates((AbstractElement) candidate.getGrammarElement()))
|
||||
return true;
|
||||
}
|
||||
if (candidate.getGrammarElement() instanceof Action) {
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
package org.eclipse.xtext.parsetree.reconstr.impl;
|
||||
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleNames;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
|
@ -47,8 +47,8 @@ public class DefaultHiddenTokenHelper extends AbstractHiddenTokenHelper {
|
|||
}
|
||||
|
||||
@Inject
|
||||
private void setGrammar(IGrammarAccess grammar) {
|
||||
wsRule = GrammarUtil.findRuleForName(grammar.getGrammar(), "WS");
|
||||
private void setGrammar(RuleNames names) {
|
||||
wsRule = Iterables.getFirst(names.getRulesBySimpleName("WS"), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,13 +20,11 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EClass;
|
||||
import org.eclipse.emf.ecore.EClassifier;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.Assignment;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.TypeRef;
|
||||
import org.eclipse.xtext.grammaranalysis.IGrammarNFAProvider.NFABuilder;
|
||||
import org.eclipse.xtext.grammaranalysis.impl.AbstractNFAState;
|
||||
|
@ -272,7 +270,7 @@ public class TreeConstState extends AbstractNFAState<TreeConstState, TreeConstTr
|
|||
|
||||
protected boolean isConsumingElement() {
|
||||
return element instanceof Assignment
|
||||
|| (element instanceof RuleCall && ((RuleCall) element).getRule().getType().getClassifier() instanceof EClass)
|
||||
|| GrammarUtil.isEObjectRuleCall(element)
|
||||
|| element instanceof Action;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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
|
||||
|
||||
import com.google.common.collect.ForwardingObject
|
||||
import org.eclipse.xtend.lib.annotations.Delegate
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
|
||||
/**
|
||||
* An abstract implementation of {@link IEObjectDescription} that delegates all
|
||||
* method invocations to another instance. Suitable to override and specialize
|
||||
* behavior.
|
||||
*
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
abstract class ForwardingEObjectDescription extends ForwardingObject implements IEObjectDescription {
|
||||
|
||||
@Delegate
|
||||
val IEObjectDescription delegate;
|
||||
|
||||
override protected delegate() {
|
||||
return this.delegate
|
||||
}
|
||||
|
||||
override toString() {
|
||||
return 'ForwardingEObjectDescription[' + delegate + ']'
|
||||
}
|
||||
|
||||
}
|
|
@ -12,6 +12,7 @@ import java.io.IOException;
|
|||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.Keyword;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
|
@ -32,8 +33,11 @@ public class TokenStreamSequenceAdapter implements ISequenceAcceptor {
|
|||
|
||||
protected ITokenStream out;
|
||||
|
||||
public TokenStreamSequenceAdapter(ITokenStream out, ISerializationDiagnostic.Acceptor errorAcceptor) {
|
||||
protected Grammar grammar;
|
||||
|
||||
public TokenStreamSequenceAdapter(ITokenStream out, Grammar grammar, ISerializationDiagnostic.Acceptor errorAcceptor) {
|
||||
this.out = out;
|
||||
this.grammar = grammar;
|
||||
this.errorAcceptor = errorAcceptor;
|
||||
}
|
||||
|
||||
|
@ -134,7 +138,7 @@ public class TokenStreamSequenceAdapter implements ISequenceAcceptor {
|
|||
out.flush();
|
||||
} catch (IOException e) {
|
||||
if (errorAcceptor != null)
|
||||
errorAcceptor.accept(new ExceptionDiagnostic(e));
|
||||
errorAcceptor.accept(new ExceptionDiagnostic(grammar, e));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +169,7 @@ public class TokenStreamSequenceAdapter implements ISequenceAcceptor {
|
|||
// System.out.println("H:" + value);
|
||||
} catch (IOException e) {
|
||||
if (errorAcceptor != null)
|
||||
errorAcceptor.accept(new ExceptionDiagnostic(e));
|
||||
errorAcceptor.accept(new ExceptionDiagnostic(grammar, e));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +179,7 @@ public class TokenStreamSequenceAdapter implements ISequenceAcceptor {
|
|||
out.writeSemantic(grammarElement, value);
|
||||
} catch (IOException e) {
|
||||
if (errorAcceptor != null)
|
||||
errorAcceptor.accept(new ExceptionDiagnostic(e));
|
||||
errorAcceptor.accept(new ExceptionDiagnostic(grammar, e));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,8 +14,10 @@ import org.eclipse.emf.ecore.EObject;
|
|||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.EcoreUtil2;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleNames;
|
||||
import org.eclipse.xtext.util.EmfFormatter;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
@ -25,28 +27,35 @@ import com.google.common.collect.Lists;
|
|||
/**
|
||||
* @author Moritz Eysholdt - Initial contribution and API
|
||||
*/
|
||||
public class Context2NameFunction implements Function<EObject, String> {
|
||||
public class Context2NameFunction {
|
||||
|
||||
@Override
|
||||
public String apply(EObject from) {
|
||||
return getContextName(from);
|
||||
public Function<EObject, String> toFunction(final Grammar grammar) {
|
||||
return new Function<EObject, String>() {
|
||||
@Override
|
||||
public String apply(EObject from) {
|
||||
return getContextName(grammar, from);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public String getContextName(Action ctx) {
|
||||
|
||||
public String getContextName(Grammar grammar, Action ctx) {
|
||||
ParserRule rule = EcoreUtil2.getContainerOfType(ctx, ParserRule.class);
|
||||
return rule.getName() + "_" + getUniqueActionName(ctx);
|
||||
return getContextName(grammar, rule) + "_" + getUniqueActionName(ctx);
|
||||
}
|
||||
|
||||
public String getContextName(EObject ctx) {
|
||||
public String getContextName(Grammar grammar, EObject ctx) {
|
||||
if (GrammarUtil.isEObjectRule(ctx))
|
||||
return getContextName((ParserRule) ctx);
|
||||
return getContextName(grammar, (ParserRule) ctx);
|
||||
if (GrammarUtil.isAssignedAction(ctx))
|
||||
return getContextName((Action) ctx);
|
||||
return getContextName(grammar, (Action) ctx);
|
||||
throw new RuntimeException("Invalid Context: " + EmfFormatter.objPath(ctx));
|
||||
}
|
||||
|
||||
public String getContextName(ParserRule ctx) {
|
||||
return ctx.getName();
|
||||
public String getContextName(Grammar grammar, ParserRule ctx) {
|
||||
if (grammar == null) {
|
||||
return ctx.getName();
|
||||
}
|
||||
return RuleNames.getRuleNames(grammar, false).getUniqueRuleName(ctx);
|
||||
}
|
||||
|
||||
public String getUniqueActionName(Action action) {
|
||||
|
|
|
@ -10,7 +10,6 @@ package org.eclipse.xtext.serializer.analysis;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EClass;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.Action;
|
||||
|
@ -116,7 +115,7 @@ public class ContextPDAProvider implements IContextPDAProvider {
|
|||
@Override
|
||||
public AbstractElement getCall(AbstractElement ele) {
|
||||
if (ele instanceof RuleCall && !GrammarUtil.isAssigned(ele)
|
||||
&& ((RuleCall) ele).getRule().getType().getClassifier() instanceof EClass)
|
||||
&& GrammarUtil.isEObjectRuleCall(ele))
|
||||
return ((RuleCall) ele).getRule().getAlternatives();
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public class ContextProvider implements IContextProvider {
|
|||
|
||||
protected void collectTypesForContext(TypeFinderState state, Set<EClass> types, boolean allowLocal,
|
||||
boolean hasAssignment, Set<Object> visited) {
|
||||
hasAssignment = hasAssignment || state.getGrammarElement() instanceof Assignment;
|
||||
hasAssignment = hasAssignment || state.getGrammarElement() instanceof Assignment || GrammarUtil.isEObjectFragmentRuleCall(state.getGrammarElement());
|
||||
if (allowLocal) {
|
||||
if (state.getGrammarElement() instanceof Action) {
|
||||
types.add((EClass) ((Action) state.getGrammarElement()).getType().getClassifier());
|
||||
|
@ -47,10 +47,14 @@ public class ContextProvider implements IContextProvider {
|
|||
}
|
||||
}
|
||||
if (state.isEndState() && !GrammarUtil.isUnassignedEObjectRuleCall(state.getGrammarElement())) {
|
||||
if (hasAssignment)
|
||||
types.add((EClass) GrammarUtil.containingRule(state.getGrammarElement()).getType().getClassifier());
|
||||
else
|
||||
if (hasAssignment) {
|
||||
ParserRule rule = (ParserRule) GrammarUtil.containingRule(state.getGrammarElement());
|
||||
if (!rule.isFragment()) {
|
||||
types.add((EClass) rule.getType().getClassifier());
|
||||
}
|
||||
} else {
|
||||
types.add(null);
|
||||
}
|
||||
}
|
||||
if (!visited.add(state))
|
||||
return;
|
||||
|
|
|
@ -32,7 +32,9 @@ import org.eclipse.xtext.Group;
|
|||
import org.eclipse.xtext.Keyword;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.RuleNames;
|
||||
import org.eclipse.xtext.TerminalRule;
|
||||
import org.eclipse.xtext.TypeRef;
|
||||
import org.eclipse.xtext.UnorderedGroup;
|
||||
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
|
||||
import org.eclipse.xtext.serializer.analysis.ActionFilterNFAProvider.ActionFilterState;
|
||||
|
@ -185,17 +187,20 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
case ASSIGNED_TERMINAL_RULE_CALL:
|
||||
EClass type = ele.getContainingConstraint().getType();
|
||||
EStructuralFeature feature = type.getEStructuralFeature(ele.getFeatureName());
|
||||
if (feature == null)
|
||||
throw new RuntimeException("Feature " + ele.getFeatureName() + " not found in "
|
||||
if (feature == null) {
|
||||
// TODO find a meaningful way to handle this
|
||||
System.err.println("Feature " + ele.getFeatureName() + " not found in "
|
||||
+ type.getName());
|
||||
int featureID = type.getFeatureID(feature);
|
||||
List<IConstraintElement> assignmentByFeature = assignmentsByFeature[featureID];
|
||||
if (assignmentByFeature == null)
|
||||
assignmentsByFeature[featureID] = assignmentByFeature = Lists.newArrayList();
|
||||
ele.setFeatureAssignmentId(assignmentByFeature.size());
|
||||
assignmentByFeature.add(ele);
|
||||
ele.setAssignmentId(assignments.size());
|
||||
assignments.add(ele);
|
||||
} else {
|
||||
int featureID = type.getFeatureID(feature);
|
||||
List<IConstraintElement> assignmentByFeature = assignmentsByFeature[featureID];
|
||||
if (assignmentByFeature == null)
|
||||
assignmentsByFeature[featureID] = assignmentByFeature = Lists.newArrayList();
|
||||
ele.setFeatureAssignmentId(assignmentByFeature.size());
|
||||
assignmentByFeature.add(ele);
|
||||
ele.setAssignmentId(assignments.size());
|
||||
assignments.add(ele);
|
||||
}
|
||||
return;
|
||||
case ALTERNATIVE:
|
||||
case GROUP:
|
||||
|
@ -490,10 +495,6 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected String context2Name(EObject context) {
|
||||
return ((Constraint) getContainingConstraint()).provider.context2Name.apply(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ConstraintElement))
|
||||
|
@ -1016,6 +1017,9 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
|
||||
@Inject
|
||||
protected Context2NameFunction context2Name;
|
||||
|
||||
@Inject
|
||||
protected RuleNames ruleNames;
|
||||
|
||||
@Inject
|
||||
protected IContextProvider contextProvider;
|
||||
|
@ -1040,20 +1044,32 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
} else if (ele instanceof RuleCall) {
|
||||
RuleCall rc = (RuleCall) ele;
|
||||
if (GrammarUtil.isUnassignedEObjectRuleCall(rc)) {
|
||||
if (!visited.add(rc))
|
||||
return null;
|
||||
ConstraintElement result = createConstraintElement((ParserRule) rc.getRule(), requiredType, visited);
|
||||
if (result != null && result != INVALID) {
|
||||
if (rc.getRule().getType().getClassifier() == requiredType)
|
||||
result.typeMatch();
|
||||
if (result.isTypeMatch())
|
||||
return result;
|
||||
ParserRule rule = (ParserRule) rc.getRule();
|
||||
if (!rule.isFragment()) {
|
||||
if (!visited.add(rc))
|
||||
return null;
|
||||
ConstraintElement result = createConstraintElement(rule, requiredType, visited);
|
||||
if (result != null && result != INVALID) {
|
||||
TypeRef returnType = rc.getRule().getType();
|
||||
if (returnType.getClassifier() == requiredType)
|
||||
result.typeMatch();
|
||||
if (result.isTypeMatch())
|
||||
return result;
|
||||
}
|
||||
return isOptional ? null : INVALID;
|
||||
} else {
|
||||
ConstraintElement result = createConstraintElement(context, rule.getAlternatives(), requiredType, visited);
|
||||
if (result != null && result != INVALID) {
|
||||
result.setMany(result.isMany() || GrammarUtil.isMultipleCardinality(ele));
|
||||
result.setOptional(result.isOptional() || GrammarUtil.isOptionalCardinality(ele));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return isOptional ? null : INVALID;
|
||||
} else if (GrammarUtil.containingAssignment(ele) != null)
|
||||
} else if (GrammarUtil.containingAssignment(ele) != null) {
|
||||
return new ConstraintElement(context, getConstraintElementType(ele), ele);
|
||||
else
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (ele instanceof Keyword) {
|
||||
if (GrammarUtil.containingAssignment(ele) != null)
|
||||
return new ConstraintElement(context, getConstraintElementType(ele), ele);
|
||||
|
@ -1235,7 +1251,7 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
protected ConstraintElement createConstraintElement(ParserRule rule, EClass requiredType, Set<Object> visited) {
|
||||
if (!visited.add(rule))
|
||||
return INVALID;
|
||||
if (GrammarUtil.containsAssignedAction(rule)) {
|
||||
if (GrammarUtil.containsAssignedAction(rule)) { // also check actions in used fragments
|
||||
ActionFilterState start = nfaProvider.getNFA(rule.getAlternatives());
|
||||
return createConstraintElement(rule, start, requiredType, false, visited);
|
||||
} else {
|
||||
|
@ -1256,7 +1272,7 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
for (Collection<IConstraint> equal : equalConstraints.values()) {
|
||||
// Collection<IConstraint> equal = filterConstraintsFromSubGrammars(grammar, allEqual);
|
||||
IConstraint representative = findRepresentativeConstraint(equal);
|
||||
((Constraint) representative).setName(findBestConstraintName(equal));
|
||||
((Constraint) representative).setName(findBestConstraintName(grammar, equal));
|
||||
for (IConstraint constraint : equal)
|
||||
allConstraints.put(constraint, representative);
|
||||
}
|
||||
|
@ -1320,7 +1336,7 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
collectElements(e, result);
|
||||
}
|
||||
|
||||
protected String findBestConstraintName(Collection<IConstraint> equalConstraints) {
|
||||
protected String findBestConstraintName(Grammar grammar, Collection<IConstraint> equalConstraints) {
|
||||
Set<ParserRule> relevantRules = Sets.newLinkedHashSet();
|
||||
Set<Action> relevantActions = Sets.newLinkedHashSet();
|
||||
Set<ParserRule> contextRules = Sets.newLinkedHashSet();
|
||||
|
@ -1366,7 +1382,7 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
for (Action a : relevantActions)
|
||||
actions.add(context2Name.getUniqueActionName(a));
|
||||
for (ParserRule a : relevantRules)
|
||||
rules.add(context2Name.getContextName(a));
|
||||
rules.add(context2Name.getContextName(grammar, a));
|
||||
Collections.sort(rules);
|
||||
String result = Joiner.on("_").join(rules);
|
||||
if (!actions.isEmpty()) {
|
||||
|
@ -1422,9 +1438,9 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
throw new RuntimeException("Unknown Grammar Element: " + EmfFormatter.objPath(ele));
|
||||
}
|
||||
|
||||
protected IConstraintContext getConstraints(Action context) {
|
||||
protected IConstraintContext getConstraints(Grammar grammar, Action context) {
|
||||
AssignedActionConstraintContext result = new AssignedActionConstraintContext(context,
|
||||
context2Name.getContextName(context));
|
||||
context2Name.getContextName(grammar, context));
|
||||
ActionFilterState start = nfaProvider.getNFA(context);
|
||||
Set<EClass> types = contextProvider.getTypesForContext(context);
|
||||
for (EClass type : types) {
|
||||
|
@ -1440,7 +1456,8 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
Constraint constraint = new ActionConstraint(context, type, ce, this);
|
||||
result.addConstraint(constraint);
|
||||
} else
|
||||
System.err.println("constraint is " + ce + " for context " + context2Name.getContextName(context)
|
||||
// TODO find a meaningful way to handle this
|
||||
System.err.println("constraint is " + ce + " for context " + context2Name.getContextName(grammar, context)
|
||||
+ " and type " + type.getName());
|
||||
}
|
||||
}
|
||||
|
@ -1452,22 +1469,23 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
List<IConstraintContext> result = cache.get(context);
|
||||
if (result == null) {
|
||||
result = Lists.newArrayList();
|
||||
for (ParserRule parserRule : GrammarUtil.allParserRules(context))
|
||||
if (parserRule.getType().getClassifier() instanceof EClass) {
|
||||
result.add(getConstraints(parserRule));
|
||||
for (ParserRule parserRule : GrammarUtil.allParserRules(context)) {
|
||||
if (parserRule.getType() != null && parserRule.getType().getClassifier() instanceof EClass) {
|
||||
result.add(getConstraints(context, parserRule));
|
||||
for (Action action : GrammarUtil.containedActions(parserRule))
|
||||
if (action.getFeature() != null)
|
||||
result.add(getConstraints(action));
|
||||
result.add(getConstraints(context, action));
|
||||
}
|
||||
}
|
||||
filterDuplicateConstraintsAndSetNames(context, result);
|
||||
cache.put(context, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected IConstraintContext getConstraints(ParserRule context) {
|
||||
protected IConstraintContext getConstraints(Grammar grammar, ParserRule context) {
|
||||
ParserRuleConstraintContext result = new ParserRuleConstraintContext(context,
|
||||
context2Name.getContextName(context));
|
||||
context2Name.getContextName(grammar, context));
|
||||
Set<EClass> types = contextProvider.getTypesForContext(context);
|
||||
for (EClass type : types) {
|
||||
if (type == null) {
|
||||
|
@ -1482,7 +1500,8 @@ public class GrammarConstraintProvider implements IGrammarConstraintProvider {
|
|||
Constraint constraint = new RuleConstraint(context, type, ce, this);
|
||||
result.addConstraint(constraint);
|
||||
} else
|
||||
System.err.println("constraint is " + ce + " for context " + context2Name.getContextName(context)
|
||||
// TODO find a meaningful way to handle this
|
||||
System.err.println("constraint is " + ce + " for context " + context2Name.getContextName(grammar, context)
|
||||
+ " and type " + type.getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import org.eclipse.xtext.Assignment;
|
|||
import org.eclipse.xtext.CrossReference;
|
||||
import org.eclipse.xtext.EcoreUtil2;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleNames;
|
||||
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
|
||||
import org.eclipse.xtext.serializer.analysis.ISyntacticSequencerPDAProvider.ISynAbsorberState;
|
||||
import org.eclipse.xtext.serializer.analysis.ISyntacticSequencerPDAProvider.SynAbsorberNfaAdapter;
|
||||
|
@ -179,7 +179,7 @@ public class SemanticSequencerNfaProvider implements ISemanticSequencerNfaProvid
|
|||
protected Map<AbstractElement, Integer> elementIDCache;
|
||||
|
||||
@Inject
|
||||
protected IGrammarAccess grammar;
|
||||
protected RuleNames ruleNames;
|
||||
|
||||
@Inject
|
||||
protected ISyntacticSequencerPDAProvider pdaProvider;
|
||||
|
@ -200,7 +200,7 @@ public class SemanticSequencerNfaProvider implements ISemanticSequencerNfaProvid
|
|||
if (elementIDCache == null) {
|
||||
elementIDCache = Maps.newHashMap();
|
||||
int counter = 0;
|
||||
for (ParserRule pr : GrammarUtil.allParserRules(grammar.getGrammar()))
|
||||
for (ParserRule pr : ruleNames.getAllParserRules())
|
||||
for (AbstractElement e : EcoreUtil2.getAllContentsOfType(pr, AbstractElement.class))
|
||||
elementIDCache.put(e, counter++);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.List;
|
|||
import org.eclipse.emf.ecore.EClass;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.EStructuralFeature;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.serializer.analysis.Context2NameFunction;
|
||||
import org.eclipse.xtext.util.EmfFormatter;
|
||||
|
||||
|
@ -33,9 +34,12 @@ public interface ISerializationDiagnostic {
|
|||
public class ExceptionDiagnostic implements ISerializationDiagnostic {
|
||||
|
||||
protected Throwable exception;
|
||||
|
||||
protected Grammar grammar;
|
||||
|
||||
public ExceptionDiagnostic(Throwable exception) {
|
||||
public ExceptionDiagnostic(Grammar grammar, Throwable exception) {
|
||||
this.exception = exception;
|
||||
this.grammar = grammar;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,6 +66,11 @@ public interface ISerializationDiagnostic {
|
|||
public EObject getContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Grammar getGrammar() {
|
||||
return grammar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
|
@ -90,7 +99,7 @@ public interface ISerializationDiagnostic {
|
|||
result.add("URI: " + eObject.eResource().getURI());
|
||||
}
|
||||
if (diagnostic.getContext() != null)
|
||||
result.add("Context: " + new Context2NameFunction().getContextName(diagnostic.getContext()));
|
||||
result.add("Context: " + new Context2NameFunction().getContextName(diagnostic.getGrammar(), diagnostic.getContext()));
|
||||
if (diagnostic.getEStructuralFeature() != null) {
|
||||
EStructuralFeature feature = diagnostic.getEStructuralFeature();
|
||||
EClass eClass = feature.getEContainingClass();
|
||||
|
@ -140,6 +149,8 @@ public interface ISerializationDiagnostic {
|
|||
EObject getSemanticObject();
|
||||
|
||||
EObject getContext();
|
||||
|
||||
Grammar getGrammar();
|
||||
|
||||
String getId();
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ public class SequencerDiagnosticProvider implements ISemanticSequencerDiagnostic
|
|||
@Override
|
||||
public ISerializationDiagnostic createFeatureValueMissing(EObject semanticObject, EStructuralFeature feature) {
|
||||
String msg = "A value for feature '" + feature.getName() + "' is missing but required.";
|
||||
return new SerializationDiagnostic(FEATURE_VALUE_MISSING, semanticObject, msg);
|
||||
return new SerializationDiagnostic(FEATURE_VALUE_MISSING, semanticObject, grammarAccess.getGrammar(), msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,18 +89,18 @@ public class SequencerDiagnosticProvider implements ISemanticSequencerDiagnostic
|
|||
else
|
||||
otherValidCtxs.add(ctx);
|
||||
}
|
||||
String contextName = context2Name.apply(context);
|
||||
String contextName = context2Name.getContextName(grammarAccess.getGrammar(), context);
|
||||
String semanticType = semanticObject.eClass().getName();
|
||||
String recommendCtxNames = Joiner.on(", ").join(Iterables.transform(recommendedCtxs, context2Name));
|
||||
String recommendCtxNames = Joiner.on(", ").join(Iterables.transform(recommendedCtxs, context2Name.toFunction(grammarAccess.getGrammar())));
|
||||
String validTypeNames = Joiner.on(", ").join(Iterables.transform(validTypes, new NamedElement2Name()));
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("The context '" + contextName + "' is not valid for type '" + semanticType + "'\n");
|
||||
msg.append("Recommended contexts for type '" + semanticType + "': " + recommendCtxNames + "\n");
|
||||
if (!otherValidCtxs.isEmpty())
|
||||
msg.append("Other valid contexts for type '" + semanticType + "': "
|
||||
+ Joiner.on(", ").join(Iterables.transform(otherValidCtxs, context2Name)));
|
||||
+ Joiner.on(", ").join(Iterables.transform(otherValidCtxs, context2Name.toFunction(grammarAccess.getGrammar()))));
|
||||
msg.append("The context '" + contextName + "' is valid for types: " + validTypeNames + "\n");
|
||||
return new SerializationDiagnostic(INVALID_CONTEXT_OR_TYPE, semanticObject, msg.toString());
|
||||
return new SerializationDiagnostic(INVALID_CONTEXT_OR_TYPE, semanticObject, grammarAccess.getGrammar(), msg.toString());
|
||||
}
|
||||
|
||||
protected List<EObject> getValidContexts(EClass clazz) {
|
||||
|
@ -135,7 +135,7 @@ public class SequencerDiagnosticProvider implements ISemanticSequencerDiagnostic
|
|||
msg.append("Could not serialize EObject via backtracking.\n");
|
||||
msg.append("Constraint: " + grammar + "\n");
|
||||
msg.append(semanticObject.getValuesString());
|
||||
return new SerializationDiagnostic(BACKTRACKING_FAILED, semanticObject.getEObject(), context, msg.toString());
|
||||
return new SerializationDiagnostic(BACKTRACKING_FAILED, semanticObject.getEObject(), context, grammarAccess.getGrammar(), msg.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import static org.eclipse.xtext.serializer.impl.FeatureFinderUtil.*;
|
|||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.EStructuralFeature;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
|
||||
/**
|
||||
* @author Moritz Eysholdt - Initial contribution and API
|
||||
|
@ -23,6 +24,8 @@ public class SerializationDiagnostic implements ISerializationDiagnostic {
|
|||
protected String message;
|
||||
|
||||
protected EObject semanticObject;
|
||||
|
||||
protected Grammar grammar;
|
||||
|
||||
protected EObject context;
|
||||
|
||||
|
@ -30,41 +33,44 @@ public class SerializationDiagnostic implements ISerializationDiagnostic {
|
|||
|
||||
private Throwable throwable;
|
||||
|
||||
public SerializationDiagnostic(String id, EObject semantic, AbstractElement element, String msg, Throwable exc) {
|
||||
this(id, semantic, semantic != null ? getFeature(element, semantic.eClass()) : null, msg, exc);
|
||||
public SerializationDiagnostic(String id, EObject semantic, AbstractElement element, Grammar grammar, String msg, Throwable exc) {
|
||||
this(id, semantic, semantic != null ? getFeature(element, semantic.eClass()) : null, grammar, msg, exc);
|
||||
}
|
||||
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, AbstractElement element, String message) {
|
||||
this(id, semanticObject, semanticObject != null ? getFeature(element, semanticObject.eClass()) : null, message);
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, AbstractElement element, Grammar grammar, String message) {
|
||||
this(id, semanticObject, semanticObject != null ? getFeature(element, semanticObject.eClass()) : null, grammar, message);
|
||||
}
|
||||
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, EStructuralFeature feature, String message) {
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, EStructuralFeature feature, Grammar grammar, String message) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.semanticObject = semanticObject;
|
||||
this.grammar = grammar;
|
||||
this.message = message;
|
||||
this.feature = feature;
|
||||
}
|
||||
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, EStructuralFeature feature, String message, Throwable throwable) {
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, EStructuralFeature feature, Grammar grammar, String message, Throwable throwable) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.semanticObject = semanticObject;
|
||||
this.grammar = grammar;
|
||||
this.throwable = throwable;
|
||||
this.feature = feature;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, EObject context, String message) {
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, EObject context, Grammar grammar, String message) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.semanticObject = semanticObject;
|
||||
this.grammar = grammar;
|
||||
this.message = message;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, String message) {
|
||||
this(id, semanticObject, (EStructuralFeature) null, message);
|
||||
public SerializationDiagnostic(String id, EObject semanticObject, Grammar grammar, String message) {
|
||||
this(id, semanticObject, (EStructuralFeature) null, grammar, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,6 +97,11 @@ public class SerializationDiagnostic implements ISerializationDiagnostic {
|
|||
public EObject getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Grammar getGrammar() {
|
||||
return grammar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
|
||||
import org.eclipse.xtext.serializer.analysis.ISyntacticSequencerPDAProvider.ISynAbsorberState;
|
||||
|
@ -21,12 +22,16 @@ import org.eclipse.xtext.serializer.sequencer.RuleCallStack;
|
|||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* @author Moritz Eysholdt - Initial contribution and API
|
||||
*/
|
||||
public class SyntacticSequencerDiagnosticProvider implements ISyntacticSequencerDiagnosticProvider {
|
||||
|
||||
@Inject
|
||||
private IGrammarAccess grammarAccess;
|
||||
|
||||
@Override
|
||||
public ISerializationDiagnostic createInvalidFollowingAbsorberDiagnostic(EObject context, EObject semanticObject,
|
||||
ISynAbsorberState from, AbstractElement to) {
|
||||
|
@ -42,7 +47,7 @@ public class SyntacticSequencerDiagnosticProvider implements ISyntacticSequencer
|
|||
msg.append("State '" + toName + "' may not follow '" + fromName + "'.\n");
|
||||
msg.append("Valid followers are: " + Joiner.on(", ").join(targets));
|
||||
|
||||
return new SerializationDiagnostic(INVALID_FOLLOWING_ABSORBER, semanticObject, context, msg.toString());
|
||||
return new SerializationDiagnostic(INVALID_FOLLOWING_ABSORBER, semanticObject, context, grammarAccess.getGrammar(), msg.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,6 +65,6 @@ public class SyntacticSequencerDiagnosticProvider implements ISyntacticSequencer
|
|||
buf.append("Found on top of the stack: " + poppedStr + "\n");
|
||||
buf.append("Expected: " + toConsume + "\n");
|
||||
buf.append("Rest of the stack: " + stack + "\n");
|
||||
return new SerializationDiagnostic(UNEXPECTED_STACK_TRACE, semanticObject, toConsume.getContext(), buf.toString());
|
||||
return new SerializationDiagnostic(UNEXPECTED_STACK_TRACE, semanticObject, toConsume.getContext(), grammarAccess.getGrammar(), buf.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.eclipse.xtext.AbstractElement;
|
|||
import org.eclipse.xtext.CrossReference;
|
||||
import org.eclipse.xtext.EnumLiteralDeclaration;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.linking.impl.LinkingHelper;
|
||||
import org.eclipse.xtext.scoping.IScope;
|
||||
|
@ -31,6 +32,9 @@ public class TokenDiagnosticProvider implements ITokenDiagnosticProvider {
|
|||
|
||||
@Inject
|
||||
private LinkingHelper linkingHelper;
|
||||
|
||||
@Inject
|
||||
private IGrammarAccess grammarAccess;
|
||||
|
||||
protected String getFullReferenceName(EObject semanticObject, CrossReference reference) {
|
||||
EReference ref = GrammarUtil.getReference(reference);
|
||||
|
@ -49,7 +53,7 @@ public class TokenDiagnosticProvider implements ITokenDiagnosticProvider {
|
|||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("The value '" + value + "' is invalid for enum " + rc.getRule().getName() + "\n");
|
||||
msg.append("Valid values are: " + Joiner.on(", ").join(valid));
|
||||
return new SerializationDiagnostic(INVALID_ENUM_VALUE, semanticObject, rc, msg.toString());
|
||||
return new SerializationDiagnostic(INVALID_ENUM_VALUE, semanticObject, rc, grammarAccess.getGrammar(), msg.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,19 +61,19 @@ public class TokenDiagnosticProvider implements ITokenDiagnosticProvider {
|
|||
CrossReference element, EObject target, IScope scope) {
|
||||
String msg = "No EObjectDescription could be found in Scope " + getFullReferenceName(semanticObject, element)
|
||||
+ " for " + EmfFormatter.objPath(target);
|
||||
return new SerializationDiagnostic(NO_EOBJECT_DESCRIPTION_FOUND, semanticObject, element, msg);
|
||||
return new SerializationDiagnostic(NO_EOBJECT_DESCRIPTION_FOUND, semanticObject, element, grammarAccess.getGrammar(), msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISerializationDiagnostic getNoScopeFoundDiagnostic(EObject semanticObject, CrossReference element,
|
||||
EObject target) {
|
||||
String msg = "Could not create Scope for EReference " + getFullReferenceName(semanticObject, element);
|
||||
return new SerializationDiagnostic(NO_SCOPE_FOUND, semanticObject, element, msg);
|
||||
return new SerializationDiagnostic(NO_SCOPE_FOUND, semanticObject, element, grammarAccess.getGrammar(), msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISerializationDiagnostic getNullNotAllowedDiagnostic(EObject semanticObject, AbstractElement ele) {
|
||||
return new SerializationDiagnostic(NULL_NOT_ALLOWED, semanticObject, ele, "Must not be null");
|
||||
return new SerializationDiagnostic(NULL_NOT_ALLOWED, semanticObject, ele, grammarAccess.getGrammar(), "Must not be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,7 +86,7 @@ public class TokenDiagnosticProvider implements ITokenDiagnosticProvider {
|
|||
msg.append("' for grammar rule '");
|
||||
msg.append(ruleName);
|
||||
msg.append("' to string via ValueConverter.");
|
||||
return new SerializationDiagnostic(VALUE_CONVERSION_EXCEPTION, semantic, element, msg.toString(), exception);
|
||||
return new SerializationDiagnostic(VALUE_CONVERSION_EXCEPTION, semantic, element, grammarAccess.getGrammar(), msg.toString(), exception);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ public class Serializer implements ISerializer {
|
|||
else
|
||||
formatterTokenStream = formatter.createFormatterStream(null, tokenStream, !options.isFormatting());
|
||||
EObject context = getContext(obj);
|
||||
ISequenceAcceptor acceptor = new TokenStreamSequenceAdapter(formatterTokenStream, errors);
|
||||
ISequenceAcceptor acceptor = new TokenStreamSequenceAdapter(formatterTokenStream, grammar.getGrammar(), errors);
|
||||
serialize(obj, context, acceptor, errors);
|
||||
formatterTokenStream.flush();
|
||||
}
|
||||
|
|
|
@ -444,8 +444,10 @@ public abstract class AbstractSyntacticSequencer implements ISyntacticSequencer,
|
|||
if (fromState instanceof ISynNavigable) {
|
||||
ISynNavigable fromEmitter = (ISynNavigable) fromState;
|
||||
// RCStack back = stack.clone();
|
||||
if (fromEmitter.hasEmitters())
|
||||
accept(fromNode, fromEmitter.getShortestStackpruningPathToAbsorber(stack), stack);
|
||||
if (fromEmitter.hasEmitters()) {
|
||||
List<ISynState> path = fromEmitter.getShortestStackpruningPathToAbsorber(stack);
|
||||
accept(fromNode, path, stack);
|
||||
}
|
||||
return fromEmitter.getTarget();
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.eclipse.emf.ecore.EStructuralFeature;
|
|||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.RuleNames;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
import org.eclipse.xtext.serializer.analysis.IGrammarConstraintProvider;
|
||||
import org.eclipse.xtext.serializer.analysis.IGrammarConstraintProvider.IConstraint;
|
||||
|
@ -55,7 +55,7 @@ public class ContextFinder implements IContextFinder {
|
|||
protected Map<Pair<EObject, EClass>, IConstraint> constraints;
|
||||
|
||||
@Inject
|
||||
protected IGrammarAccess grammar;
|
||||
protected RuleNames ruleNames;
|
||||
|
||||
@Inject
|
||||
protected IGrammarConstraintProvider grammarConstraintProvider;
|
||||
|
@ -223,7 +223,7 @@ public class ContextFinder implements IContextFinder {
|
|||
}
|
||||
|
||||
protected EObject getRootContext() {
|
||||
for (AbstractRule rule : grammar.getGrammar().getRules())
|
||||
for (AbstractRule rule : ruleNames.getAllRules())
|
||||
if (GrammarUtil.isEObjectRule(rule))
|
||||
return rule;
|
||||
throw new RuntimeException("There is no parser rule in the grammar.");
|
||||
|
@ -232,7 +232,7 @@ public class ContextFinder implements IContextFinder {
|
|||
protected void initConstraints() {
|
||||
if (constraintContexts == null) {
|
||||
constraints = Maps.newLinkedHashMap();
|
||||
constraintContexts = grammarConstraintProvider.getConstraints(grammar.getGrammar());
|
||||
constraintContexts = grammarConstraintProvider.getConstraints(ruleNames.getContextGrammar());
|
||||
// System.out.println(Joiner.on("\n").join(constraintContexts));
|
||||
for (IConstraintContext ctx : constraintContexts)
|
||||
for (IConstraint constraint : ctx.getConstraints())
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.eclipse.xtext.GrammarUtil;
|
|||
import org.eclipse.xtext.Keyword;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.RuleNames;
|
||||
import org.eclipse.xtext.TerminalRule;
|
||||
import org.eclipse.xtext.conversion.IValueConverterService;
|
||||
import org.eclipse.xtext.nodemodel.BidiIterator;
|
||||
|
@ -30,6 +31,9 @@ public class NodeModelSemanticSequencer extends AbstractSemanticSequencer {
|
|||
|
||||
@Inject
|
||||
protected IValueConverterService valueConverter;
|
||||
|
||||
@Inject
|
||||
protected RuleNames ruleNames;
|
||||
|
||||
@Override
|
||||
public void createSequence(EObject context, EObject semanticObject) {
|
||||
|
@ -46,7 +50,7 @@ public class NodeModelSemanticSequencer extends AbstractSemanticSequencer {
|
|||
acceptSemantic(semanticObject, rc, semanticObject.eGet(feature), node.getFirst());
|
||||
} else {
|
||||
String strVal = NodeModelUtils.getTokenText(node.getFirst());
|
||||
Object val = valueConverter.toValue(strVal, rc.getRule().getName(), node.getFirst());
|
||||
Object val = valueConverter.toValue(strVal, ruleNames.getQualifiedName(rc.getRule()), node.getFirst());
|
||||
acceptSemantic(semanticObject, rc, val, node.getFirst());
|
||||
}
|
||||
} else if (node.getSecond() instanceof Keyword)
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.eclipse.xtext.serializer.tokens;
|
|||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.RuleNames;
|
||||
import org.eclipse.xtext.conversion.IValueConverterService;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
|
||||
|
@ -25,6 +26,9 @@ public class ValueSerializer implements IValueSerializer {
|
|||
|
||||
@Inject
|
||||
private IValueConverterService converter;
|
||||
|
||||
@Inject
|
||||
private RuleNames ruleNames;
|
||||
|
||||
@Inject
|
||||
protected ITokenDiagnosticProvider diagnostics;
|
||||
|
@ -35,7 +39,7 @@ public class ValueSerializer implements IValueSerializer {
|
|||
@Override
|
||||
public boolean isValid(EObject context, RuleCall ruleCall, Object value, Acceptor errors) {
|
||||
try {
|
||||
String str = converter.toString(value, ruleCall.getRule().getName());
|
||||
String str = converter.toString(value, ruleNames.getQualifiedName(ruleCall.getRule()));
|
||||
if (str != null)
|
||||
return true;
|
||||
if (errors != null)
|
||||
|
@ -51,12 +55,12 @@ public class ValueSerializer implements IValueSerializer {
|
|||
@Override
|
||||
public String serializeAssignedValue(EObject context, RuleCall ruleCall, Object value, INode node, Acceptor errors) {
|
||||
if (node != null) {
|
||||
Object converted = converter.toValue(NodeModelUtils.getTokenText(node), ruleCall.getRule().getName(), node);
|
||||
Object converted = converter.toValue(NodeModelUtils.getTokenText(node), ruleNames.getQualifiedName(ruleCall.getRule()), node);
|
||||
if (converted != null && converted.equals(value))
|
||||
return tokenUtil.serializeNode(node);
|
||||
}
|
||||
try {
|
||||
String str = converter.toString(value, ruleCall.getRule().getName());
|
||||
String str = converter.toString(value, ruleNames.getQualifiedName(ruleCall.getRule()));
|
||||
if (str != null)
|
||||
return str;
|
||||
if (errors != null)
|
||||
|
|
|
@ -125,12 +125,25 @@ public class CurrentTypeFinder {
|
|||
@Override
|
||||
public Boolean caseRuleCall(RuleCall object) {
|
||||
EClassifier wasType = currentType;
|
||||
AbstractRule calledRule = object.getRule();
|
||||
if (currentType == null) {
|
||||
if (object.getRule() instanceof ParserRule && !GrammarUtil.isDatatypeRule((ParserRule) object.getRule())) {
|
||||
TypeRef returnType = object.getRule().getType();
|
||||
if (returnType != null)
|
||||
currentType = returnType.getClassifier();
|
||||
if (calledRule instanceof ParserRule && !GrammarUtil.isDatatypeRule((ParserRule) calledRule)) {
|
||||
ParserRule parserRule = (ParserRule) calledRule;
|
||||
if (parserRule.isFragment()) {
|
||||
if (context.getType() != null)
|
||||
currentType = context.getType().getClassifier();
|
||||
if (!parserRule.isWildcard()) {
|
||||
doSwitch(parserRule.getAlternatives());
|
||||
}
|
||||
} else {
|
||||
TypeRef returnType = calledRule.getType();
|
||||
if (returnType != null) {
|
||||
currentType = returnType.getClassifier();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isFragmentButNotWildcard(calledRule)) {
|
||||
doSwitch(calledRule.getAlternatives());
|
||||
}
|
||||
if (object == stopElement)
|
||||
return true;
|
||||
|
@ -139,6 +152,14 @@ public class CurrentTypeFinder {
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean isFragmentButNotWildcard(AbstractRule calledRule) {
|
||||
if (calledRule instanceof ParserRule) {
|
||||
ParserRule casted = (ParserRule) calledRule;
|
||||
return casted.isFragment() && !casted.isWildcard();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected EClassifier getCompatibleType(EClassifier a, EClassifier b, EObject context) {
|
||||
if (a == null)
|
||||
return b;
|
||||
|
|
|
@ -45,7 +45,7 @@ public class KeywordInspector {
|
|||
List<TerminalRule> rules = GrammarUtil.allTerminalRules(grammar);
|
||||
for(TerminalRule rule: rules) {
|
||||
if (!rule.isFragment()) {
|
||||
AbstractElement element = rule.getAlternatives();
|
||||
AbstractElement element = rule.getAlternatives();
|
||||
if (element instanceof Keyword && Strings.isEmpty(element.getCardinality())) {
|
||||
String value = ((Keyword) element).getValue();
|
||||
if (value.equals(keyword.getValue()))
|
||||
|
|
|
@ -44,10 +44,13 @@ public class OverriddenValueInspector extends XtextRuleInspector<Boolean, Parser
|
|||
*/
|
||||
private Set<AbstractRule> permanentlyVisited;
|
||||
|
||||
private Set<RuleCall> fragmentStack;
|
||||
|
||||
public OverriddenValueInspector(ValidationMessageAcceptor acceptor) {
|
||||
super(acceptor);
|
||||
assignedFeatures = newMultimap();
|
||||
permanentlyVisited = Sets.newHashSet();
|
||||
fragmentStack = Sets.newHashSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,20 +105,34 @@ public class OverriddenValueInspector extends XtextRuleInspector<Boolean, Parser
|
|||
Collection<AbstractElement> sources = Lists.newArrayList(assignedFeatures.get(feature));
|
||||
assignedFeatures.replaceValues(feature, Collections.<AbstractElement> emptyList());
|
||||
if (sources != null && sources.equals(Collections.singletonList(object))) {
|
||||
if (getNestingLevel() == 0)
|
||||
acceptWarning("The assigned value of feature '" + feature
|
||||
+ "' will possibly override itself because it is used inside of a loop.", object, null);
|
||||
if (getNestingLevel() == 0 && fragmentStack.isEmpty()) {
|
||||
if (object instanceof RuleCall) {
|
||||
acceptWarning("The fragment will possibly override the assigned value of feature '" + feature
|
||||
+ "' it is used inside of a loop.", object, null);
|
||||
} else {
|
||||
acceptWarning("The assigned value of feature '" + feature
|
||||
+ "' will possibly override itself because it is used inside of a loop.", object, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sources != null) {
|
||||
if (getNestingLevel() == 0)
|
||||
for (AbstractElement source : sources)
|
||||
if (getNestingLevel() == 0 && fragmentStack.isEmpty()) {
|
||||
for (AbstractElement source : sources) {
|
||||
acceptWarning("The possibly assigned value of feature '" + feature
|
||||
+ "' may be overridden by subsequent assignments.", source, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getNestingLevel() == 0 && fragmentStack.isEmpty()) {
|
||||
if (object instanceof RuleCall) {
|
||||
acceptWarning("The fragment will potentially override the possibly assigned value of feature '"
|
||||
+ feature + "'.", object, null);
|
||||
} else {
|
||||
acceptWarning("This assignment will override the possibly assigned value of feature '"
|
||||
+ feature + "'.", object, null);
|
||||
}
|
||||
}
|
||||
if (getNestingLevel() == 0)
|
||||
acceptWarning("This assignment will override the possibly assigned value of feature '"
|
||||
+ feature + "'.", object, null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -131,6 +148,11 @@ public class OverriddenValueInspector extends XtextRuleInspector<Boolean, Parser
|
|||
ParserRule parserRule = (ParserRule) calledRule;
|
||||
if (GrammarUtil.isDatatypeRule(parserRule))
|
||||
return Boolean.FALSE;
|
||||
if (parserRule.isFragment()) {
|
||||
visitFragment(object);
|
||||
if (GrammarUtil.isMultipleCardinality(object))
|
||||
visitFragment(object);
|
||||
}
|
||||
if (!addVisited(parserRule))
|
||||
return Boolean.FALSE;
|
||||
Multimap<String, AbstractElement> prevAssignedFeatures = assignedFeatures;
|
||||
|
@ -143,6 +165,22 @@ public class OverriddenValueInspector extends XtextRuleInspector<Boolean, Parser
|
|||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
private void visitFragment(RuleCall object) {
|
||||
Multimap<String, AbstractElement> prevAssignedFeatures = assignedFeatures;
|
||||
assignedFeatures = newMultimap();
|
||||
if (fragmentStack.add(object)) {
|
||||
try {
|
||||
doSwitch(object.getRule().getAlternatives());
|
||||
} finally {
|
||||
fragmentStack.remove(object);
|
||||
}
|
||||
}
|
||||
Multimap<String, AbstractElement> assignedByFragment = assignedFeatures;
|
||||
assignedFeatures = prevAssignedFeatures;
|
||||
for (String feature : assignedByFragment.keySet())
|
||||
checkAssignment(object, feature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean caseAlternatives(Alternatives object) {
|
||||
Multimap<String, AbstractElement> prevAssignedFeatures = assignedFeatures;
|
||||
|
|
|
@ -43,7 +43,7 @@ public class RuleWithoutInstantiationInspector extends XtextRuleInspector<Boolea
|
|||
// special treatment of first rule
|
||||
if (GrammarUtil.getGrammar(rule).getRules().get(0) == rule)
|
||||
return false;
|
||||
if (GrammarUtil.isDatatypeRule(rule) || rule.getAlternatives() == null)
|
||||
if (GrammarUtil.isDatatypeRule(rule) || rule.getAlternatives() == null || rule.isFragment())
|
||||
return false;
|
||||
return super.canInspect(rule);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.xtext;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.naming.QualifiedName;
|
||||
import org.eclipse.xtext.resource.EObjectDescription;
|
||||
import org.eclipse.xtext.resource.ForwardingEObjectDescription;
|
||||
import org.eclipse.xtext.resource.IEObjectDescription;
|
||||
import org.eclipse.xtext.scoping.IScope;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
*/
|
||||
public class SuperCallScope implements IScope {
|
||||
|
||||
private static final String SUPER = "super";
|
||||
|
||||
/**
|
||||
* Used during linking to set the {@link RuleCall#isExplicitlyCalled() flag}
|
||||
* which keeps track of explicitly chosen rules.
|
||||
* @author zarnekow - Initial contribution and API
|
||||
*/
|
||||
public static class ExplicitCallDescription extends ForwardingEObjectDescription {
|
||||
|
||||
private RuleCall ruleCall;
|
||||
|
||||
public ExplicitCallDescription(IEObjectDescription delegate, RuleCall ruleCall) {
|
||||
super(delegate);
|
||||
this.ruleCall = ruleCall;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EObject getEObjectOrProxy() {
|
||||
ruleCall.setExplicitlyCalled(true);
|
||||
return super.getEObjectOrProxy();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private EObject context;
|
||||
|
||||
public SuperCallScope(EObject context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IEObjectDescription getSingleElement(QualifiedName name) {
|
||||
IEObjectDescription result = doGetSingleElement(name);
|
||||
if (result != null && context instanceof RuleCall) {
|
||||
return new ExplicitCallDescription(result, (RuleCall) context);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private IEObjectDescription doGetSingleElement(QualifiedName qn) {
|
||||
if (qn.getSegmentCount() == 1) {
|
||||
if (SUPER.equals(qn.getFirstSegment())) {
|
||||
AbstractRule containingRule = GrammarUtil.containingRule(context);
|
||||
if (containingRule != null) {
|
||||
Grammar grammar = GrammarUtil.getGrammar(containingRule);
|
||||
for(Grammar parent: grammar.getUsedGrammars()) {
|
||||
AbstractRule superRule = GrammarUtil.findRuleForName(parent, containingRule.getName());
|
||||
if (superRule != null) {
|
||||
return EObjectDescription.create(qn, superRule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (qn.getSegmentCount() > 1) {
|
||||
Grammar grammar = GrammarUtil.getGrammar(context);
|
||||
if (grammar != null) {
|
||||
String firstSegment = qn.getFirstSegment();
|
||||
if (qn.getSegmentCount() == 2) {
|
||||
String ruleName = qn.getLastSegment();
|
||||
if (SUPER.equals(firstSegment)) {
|
||||
for(Grammar parent: grammar.getUsedGrammars()) {
|
||||
AbstractRule superRule = GrammarUtil.findRuleForName(parent, ruleName);
|
||||
if (superRule != null) {
|
||||
return EObjectDescription.create(qn, superRule);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (firstSegment.equals(GrammarUtil.getName(grammar))) {
|
||||
AbstractRule rule = GrammarUtil.findRuleForName(grammar, grammar.getName() + "." + ruleName);
|
||||
if (rule != null) {
|
||||
return EObjectDescription.create(qn, rule);
|
||||
}
|
||||
}
|
||||
for(Grammar usedGrammar: GrammarUtil.allUsedGrammars(grammar)) {
|
||||
if (firstSegment.equals(GrammarUtil.getName(usedGrammar))) {
|
||||
AbstractRule rule = GrammarUtil.findRuleForName(usedGrammar, usedGrammar.getName() + "." + ruleName);
|
||||
if (rule != null) {
|
||||
return EObjectDescription.create(qn, rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AbstractRule result = GrammarUtil.findRuleForName(grammar, qn.toString());
|
||||
if (result != null) {
|
||||
return EObjectDescription.create(qn, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<IEObjectDescription> getElements(QualifiedName name) {
|
||||
IEObjectDescription result = doGetSingleElement(name);
|
||||
if (result != null) {
|
||||
return Collections.singletonList(result);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IEObjectDescription getSingleElement(EObject object) {
|
||||
return Iterables.getFirst(getElements(object), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<IEObjectDescription> getElements(EObject object) {
|
||||
if (object instanceof AbstractRule) {
|
||||
Grammar grammar = GrammarUtil.getGrammar(context);
|
||||
AbstractRule rule = (AbstractRule) object;
|
||||
if (GrammarUtil.getGrammar(rule) == grammar) {
|
||||
return Lists.newArrayList(
|
||||
EObjectDescription.create(GrammarUtil.getName(grammar) + "." + rule.getName(), rule),
|
||||
EObjectDescription.create(grammar.getName() + "." + rule.getName(), rule));
|
||||
}
|
||||
List<IEObjectDescription> result = Lists.newArrayList(
|
||||
EObjectDescription.create(SUPER + "." + rule.getName(), rule),
|
||||
EObjectDescription.create(GrammarUtil.getName(grammar) + "." + rule.getName(), rule),
|
||||
EObjectDescription.create(grammar.getName() + "." + rule.getName(), rule));
|
||||
AbstractRule contextRule = GrammarUtil.containingRule(context);
|
||||
if (contextRule != null && contextRule.getName().equals(rule.getName())) {
|
||||
result.add(0, EObjectDescription.create(SUPER, rule));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<IEObjectDescription> getAllElements() {
|
||||
AbstractRule contextRule = GrammarUtil.containingRule(context);
|
||||
Grammar grammar = contextRule != null ? GrammarUtil.getGrammar(contextRule) : GrammarUtil.getGrammar(context);
|
||||
Map<QualifiedName, IEObjectDescription> result = Maps.newLinkedHashMap();
|
||||
if (grammar != null) {
|
||||
String shortName = GrammarUtil.getName(grammar) + ".";
|
||||
String longName = grammar.getName() + ".";
|
||||
for(AbstractRule rule: grammar.getRules()) {
|
||||
putIfAbsent(EObjectDescription.create(shortName + rule.getName(), rule), result);
|
||||
putIfAbsent(EObjectDescription.create(longName + rule.getName(), rule), result);
|
||||
}
|
||||
boolean waitingForSuper = contextRule != null;
|
||||
for(Grammar usedGrammar: GrammarUtil.allUsedGrammars(grammar)) {
|
||||
shortName = GrammarUtil.getName(usedGrammar) + ".";
|
||||
longName = usedGrammar.getName() + ".";
|
||||
for(AbstractRule rule: usedGrammar.getRules()) {
|
||||
if (waitingForSuper) {
|
||||
assert contextRule != null;
|
||||
if (rule.getName().equals(contextRule.getName())) {
|
||||
putIfAbsent(EObjectDescription.create(SUPER, rule), result);
|
||||
waitingForSuper = false;
|
||||
}
|
||||
}
|
||||
putIfAbsent(EObjectDescription.create(SUPER + "." + rule.getName(), rule), result);
|
||||
putIfAbsent(EObjectDescription.create(shortName + rule.getName(), rule), result);
|
||||
putIfAbsent(EObjectDescription.create(longName + rule.getName(), rule), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Lists.newArrayList(result.values());
|
||||
}
|
||||
|
||||
private void putIfAbsent(IEObjectDescription desc, Map<QualifiedName, IEObjectDescription> result) {
|
||||
if (!result.containsKey(desc.getName())) {
|
||||
result.put(desc.getName(), desc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -10,34 +10,36 @@ package org.eclipse.xtext.xtext;
|
|||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.EPackage;
|
||||
import org.eclipse.emf.ecore.EReference;
|
||||
import org.eclipse.xtext.AbstractMetamodelDeclaration;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.XtextPackage;
|
||||
import org.eclipse.xtext.parsetree.reconstr.impl.CrossReferenceSerializer;
|
||||
import org.eclipse.xtext.util.SimpleAttributeResolver;
|
||||
|
||||
/**
|
||||
* @author Moritz Eysholdt - Initial contribution and API
|
||||
*/
|
||||
public class XtextCrossReferenceSerializer extends CrossReferenceSerializer {
|
||||
|
||||
private final SimpleAttributeResolver<EObject, String> aliasResolver;
|
||||
|
||||
public XtextCrossReferenceSerializer() {
|
||||
super();
|
||||
aliasResolver = SimpleAttributeResolver.newResolver(String.class, "alias");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUnconvertedLinkText(EObject object, EReference reference, EObject context) {
|
||||
if (reference == XtextPackage.eINSTANCE.getGrammar_UsedGrammars())
|
||||
return ((Grammar) object).getName();
|
||||
if (reference == XtextPackage.eINSTANCE.getTypeRef_Metamodel())
|
||||
return aliasResolver.getValue(object);
|
||||
if (reference == XtextPackage.eINSTANCE.getTypeRef_Metamodel()) {
|
||||
AbstractMetamodelDeclaration casted = (AbstractMetamodelDeclaration) object;
|
||||
return casted.getAlias();
|
||||
}
|
||||
if (reference == XtextPackage.eINSTANCE.getAbstractMetamodelDeclaration_EPackage())
|
||||
return ((EPackage) object).getNsURI();
|
||||
if (object instanceof AbstractRule)
|
||||
if (object instanceof AbstractRule) {
|
||||
if (reference == XtextPackage.eINSTANCE.getRuleCall_Rule()) {
|
||||
if (((RuleCall)context).isExplicitlyCalled()) {
|
||||
return super.getUnconvertedLinkText(object, reference, context);
|
||||
}
|
||||
}
|
||||
return ((AbstractRule) object).getName();
|
||||
}
|
||||
return super.getUnconvertedLinkText(object, reference, context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,11 @@ import org.eclipse.xtext.services.XtextGrammarAccess.CharacterRangeElements;
|
|||
import org.eclipse.xtext.services.XtextGrammarAccess.CrossReferenceElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.EnumLiteralDeclarationElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.GrammarElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.NamedArgumentElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.NegatedTokenElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.NegationElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.ParserRuleElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.RuleCallElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.TerminalTokenElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.TypeRefElements;
|
||||
import org.eclipse.xtext.services.XtextGrammarAccess.UnorderedGroupElements;
|
||||
|
@ -47,6 +50,14 @@ public class XtextFormatter extends AbstractDeclarativeFormatter {
|
|||
cfg.setNoSpace().after(pair.getFirst());
|
||||
cfg.setNoSpace().before(pair.getSecond());
|
||||
}
|
||||
for (Pair<Keyword, Keyword> pair : g.findKeywordPairs("[", "]")) {
|
||||
cfg.setNoSpace().after(pair.getFirst());
|
||||
cfg.setNoSpace().before(pair.getSecond());
|
||||
}
|
||||
for (Pair<Keyword, Keyword> pair : g.findKeywordPairs("<", ">")) {
|
||||
cfg.setNoSpace().after(pair.getFirst());
|
||||
cfg.setNoSpace().before(pair.getSecond());
|
||||
}
|
||||
for (Keyword comma : g.findKeywords(",")) {
|
||||
cfg.setNoSpace().before(comma);
|
||||
}
|
||||
|
@ -72,7 +83,7 @@ public class XtextFormatter extends AbstractDeclarativeFormatter {
|
|||
|
||||
// ParserRule
|
||||
ParserRuleElements pr = g.getParserRuleAccess();
|
||||
cfg.setNoSpace().before(pr.getLeftParenthesisKeyword_2_1());
|
||||
cfg.setNoSpace().before(pr.getLeftParenthesisKeyword_1_1());
|
||||
|
||||
// TypeRef
|
||||
TypeRefElements typeRef = g.getTypeRefAccess();
|
||||
|
@ -101,8 +112,6 @@ public class XtextFormatter extends AbstractDeclarativeFormatter {
|
|||
|
||||
// CrossReference
|
||||
CrossReferenceElements cr = g.getCrossReferenceAccess();
|
||||
cfg.setNoSpace().after(cr.getLeftSquareBracketKeyword_0());
|
||||
cfg.setNoSpace().before(cr.getRightSquareBracketKeyword_3());
|
||||
cfg.setNoSpace().around(cr.getVerticalLineKeyword_2_0());
|
||||
|
||||
// TerminalToken
|
||||
|
@ -124,6 +133,20 @@ public class XtextFormatter extends AbstractDeclarativeFormatter {
|
|||
// EnumLiteralDeclaration
|
||||
EnumLiteralDeclarationElements eld = g.getEnumLiteralDeclarationAccess();
|
||||
cfg.setNoSpace().around(eld.getEqualsSignKeyword_1_0());
|
||||
|
||||
// GuardCondition
|
||||
NegationElements na = g.getNegationAccess();
|
||||
cfg.setNoSpace().after(na.getExclamationMarkKeyword_1_1());
|
||||
|
||||
// RuleCall
|
||||
RuleCallElements rca = g.getRuleCallAccess();
|
||||
cfg.setNoSpace().before(rca.getLessThanSignKeyword_1_0());
|
||||
|
||||
// NamedArgument
|
||||
NamedArgumentElements naa = g.getNamedArgumentAccess();
|
||||
cfg.setNoSpace().around(naa.getCalledByNameAssignment_0_1());
|
||||
cfg.setNoSpace().around(naa.getValueAssignment_1());
|
||||
cfg.setNoSpace().around(naa.getParameterAssignment_0_0());
|
||||
|
||||
//saveDebugGraphvizDiagram("XtextFormatting.dot");
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.eclipse.xtext.EnumRule;
|
|||
import org.eclipse.xtext.GeneratedMetamodel;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.NamedArgument;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.ReferencedMetamodel;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
|
@ -40,10 +41,10 @@ import org.eclipse.xtext.XtextFactory;
|
|||
import org.eclipse.xtext.XtextPackage;
|
||||
import org.eclipse.xtext.diagnostics.AbstractDiagnosticProducerDecorator;
|
||||
import org.eclipse.xtext.diagnostics.DiagnosticMessage;
|
||||
import org.eclipse.xtext.diagnostics.Severity;
|
||||
import org.eclipse.xtext.diagnostics.ExceptionDiagnostic;
|
||||
import org.eclipse.xtext.diagnostics.IDiagnosticConsumer;
|
||||
import org.eclipse.xtext.diagnostics.IDiagnosticProducer;
|
||||
import org.eclipse.xtext.diagnostics.Severity;
|
||||
import org.eclipse.xtext.linking.impl.Linker;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
|
||||
|
@ -132,7 +133,8 @@ public class XtextLinker extends Linker {
|
|||
|
||||
@Override
|
||||
protected boolean canSetDefaultValues(EReference ref) {
|
||||
return super.canSetDefaultValues(ref) || ref == XtextPackage.Literals.CROSS_REFERENCE__TERMINAL;
|
||||
return super.canSetDefaultValues(ref)
|
||||
|| ref == XtextPackage.Literals.CROSS_REFERENCE__TERMINAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -155,6 +157,20 @@ public class XtextLinker extends Linker {
|
|||
call.setRule(rule);
|
||||
((CrossReference) obj).setTerminal(call);
|
||||
}
|
||||
} else if (XtextPackage.eINSTANCE.getNamedArgument_Parameter() == ref) {
|
||||
final NamedArgument argument = (NamedArgument) obj;
|
||||
if (!argument.isCalledByName()) {
|
||||
RuleCall ruleCall = EcoreUtil2.getContainerOfType(argument, RuleCall.class);
|
||||
AbstractRule calledRule = ruleCall.getRule();
|
||||
if (calledRule instanceof ParserRule && !calledRule.eIsProxy()) {
|
||||
ParserRule casted = (ParserRule) calledRule;
|
||||
int idx = ruleCall.getArguments().indexOf(argument);
|
||||
if (idx < casted.getParameters().size()) {
|
||||
argument.setParameter(casted.getParameters().get(idx));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.setDefaultValueImpl(obj, ref, producer);
|
||||
}
|
||||
|
@ -393,7 +409,7 @@ public class XtextLinker extends Linker {
|
|||
}
|
||||
final List<RuleCall> allRuleCalls = EcoreUtil2.getAllContentsOfType(grammar, RuleCall.class);
|
||||
for (RuleCall call : allRuleCalls) {
|
||||
if (call.getRule() != null) {
|
||||
if (call.getRule() != null && !call.isExplicitlyCalled()) {
|
||||
AbstractRule rule = rulePerName.get(call.getRule().getName());
|
||||
if (rule != null)
|
||||
call.setRule(rule);
|
||||
|
@ -426,6 +442,9 @@ public class XtextLinker extends Linker {
|
|||
if (node == null)
|
||||
obj.eUnset(ref);
|
||||
}
|
||||
if (ref == XtextPackage.Literals.RULE_CALL__RULE) {
|
||||
obj.eUnset(XtextPackage.Literals.RULE_CALL__EXPLICITLY_CALLED);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPackageRemover(PackageRemover packageRemover) {
|
||||
|
|
|
@ -23,7 +23,7 @@ import com.google.common.collect.Sets;
|
|||
/**
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
*/
|
||||
public class XtextRuleInspector<Result, RuleType extends AbstractRule> extends XtextSwitch<Result> {
|
||||
public abstract class XtextRuleInspector<Result, RuleType extends AbstractRule> extends XtextSwitch<Result> {
|
||||
|
||||
private final ValidationMessageAcceptor acceptor;
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ package org.eclipse.xtext.xtext;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
|
@ -27,9 +26,13 @@ import org.eclipse.emf.ecore.InternalEObject;
|
|||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
import org.eclipse.xtext.AbstractMetamodelDeclaration;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.EcoreUtil2;
|
||||
import org.eclipse.xtext.EnumRule;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.TypeRef;
|
||||
import org.eclipse.xtext.XtextPackage;
|
||||
import org.eclipse.xtext.naming.QualifiedName;
|
||||
|
@ -38,6 +41,7 @@ import org.eclipse.xtext.resource.IEObjectDescription;
|
|||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.scoping.IGlobalScopeProvider;
|
||||
import org.eclipse.xtext.scoping.IScope;
|
||||
import org.eclipse.xtext.scoping.Scopes;
|
||||
import org.eclipse.xtext.scoping.impl.AbstractScopeProvider;
|
||||
import org.eclipse.xtext.scoping.impl.SelectableBasedScope;
|
||||
import org.eclipse.xtext.scoping.impl.SimpleScope;
|
||||
|
@ -45,6 +49,7 @@ import org.eclipse.xtext.scoping.impl.SimpleScope;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
|
@ -92,7 +97,28 @@ public class XtextScopeProvider extends AbstractScopeProvider {
|
|||
}
|
||||
});
|
||||
}
|
||||
return createScope(context.eResource(), reference.getEReferenceType());
|
||||
if(reference == XtextPackage.eINSTANCE.getRuleCall_Rule()) {
|
||||
return createScope(context.eResource(), reference.getEReferenceType(), new SuperCallScope(context));
|
||||
}
|
||||
if (reference == XtextPackage.eINSTANCE.getParameterReference_Parameter()) {
|
||||
ParserRule rule = GrammarUtil.containingParserRule(context);
|
||||
if (rule == null) {
|
||||
return IScope.NULLSCOPE;
|
||||
}
|
||||
return Scopes.scopeFor(rule.getParameters());
|
||||
}
|
||||
if (reference == XtextPackage.eINSTANCE.getNamedArgument_Parameter()) {
|
||||
RuleCall ruleCall = EcoreUtil2.getContainerOfType(context, RuleCall.class);
|
||||
if (ruleCall == null) {
|
||||
return IScope.NULLSCOPE;
|
||||
}
|
||||
AbstractRule referencedRule = ruleCall.getRule();
|
||||
if (referencedRule instanceof ParserRule) {
|
||||
return Scopes.scopeFor(((ParserRule) referencedRule).getParameters());
|
||||
}
|
||||
return IScope.NULLSCOPE;
|
||||
}
|
||||
return createScope(context.eResource(), reference.getEReferenceType(), IScope.NULLSCOPE);
|
||||
}
|
||||
|
||||
protected IScope createEnumLiteralsScope(EEnum eEnum) {
|
||||
|
@ -123,17 +149,17 @@ public class XtextScopeProvider extends AbstractScopeProvider {
|
|||
return createClassifierScope(allClassifiers);
|
||||
}
|
||||
|
||||
protected IScope createScope(Resource resource, EClass type) {
|
||||
protected IScope createScope(Resource resource, EClass type, IScope parent) {
|
||||
if (resource.getContents().size() < 1)
|
||||
throw new IllegalArgumentException("resource is not as expected: contents.size == "
|
||||
+ resource.getContents().size() + " but expected: >= 1");
|
||||
final EObject firstContent = resource.getContents().get(0);
|
||||
if (!(firstContent instanceof Grammar))
|
||||
return IScope.NULLSCOPE;
|
||||
return createScope((Grammar) firstContent, type);
|
||||
return parent;
|
||||
return createScope((Grammar) firstContent, type, parent);
|
||||
}
|
||||
|
||||
protected IScope createScope(final Grammar grammar, EClass type) {
|
||||
protected IScope createScope(final Grammar grammar, EClass type, IScope current) {
|
||||
if (EcorePackage.Literals.EPACKAGE == type) {
|
||||
return createEPackageScope(grammar);
|
||||
} else if (AbstractMetamodelDeclaration.class.isAssignableFrom(type.getInstanceClass())) {
|
||||
|
@ -147,30 +173,22 @@ public class XtextScopeProvider extends AbstractScopeProvider {
|
|||
}));
|
||||
}
|
||||
final List<Grammar> allGrammars = getAllGrammars(grammar);
|
||||
IScope current = IScope.NULLSCOPE;
|
||||
for (int i = allGrammars.size() - 1; i >= 0; i--) {
|
||||
current = createScope(allGrammars.get(i), type, current);
|
||||
current = doCreateScope(allGrammars.get(i), type, current);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
protected IScope createScope(final Grammar grammar, final EClass type, IScope parent) {
|
||||
|
||||
protected IScope doCreateScope(final Grammar grammar, final EClass type, IScope parent) {
|
||||
final IResourceDescription resourceDescription = resourceDescriptionManager.getResourceDescription(grammar.eResource());
|
||||
return SelectableBasedScope.createScope(parent, resourceDescription, type, false);
|
||||
}
|
||||
|
||||
protected List<Grammar> getAllGrammars(Grammar grammar) {
|
||||
Collection<Grammar> visitedGrammars = new LinkedHashSet<Grammar>();
|
||||
collectAllUsedGrammars(grammar, visitedGrammars);
|
||||
return new ArrayList<Grammar>(visitedGrammars);
|
||||
}
|
||||
|
||||
protected void collectAllUsedGrammars(Grammar grammar, Collection<Grammar> visited) {
|
||||
if (!visited.add(grammar))
|
||||
return;
|
||||
for(Grammar usedGrammar: grammar.getUsedGrammars()) {
|
||||
collectAllUsedGrammars(usedGrammar, visited);
|
||||
}
|
||||
List<Grammar> result = Lists.newArrayList(grammar);
|
||||
result.addAll(GrammarUtil.allUsedGrammars(grammar));
|
||||
return result;
|
||||
}
|
||||
|
||||
protected IScope createEPackageScope(final Grammar grammar, IScope parent) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.eclipse.xtext.CrossReference;
|
|||
import org.eclipse.xtext.EnumLiteralDeclaration;
|
||||
import org.eclipse.xtext.EnumRule;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.NamedArgument;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.TerminalRule;
|
||||
|
@ -67,6 +68,12 @@ public class XtextTransientValueService extends DefaultTransientValueService {
|
|||
return decl.getEnumLiteral() != null && decl.getLiteral() != null &&
|
||||
Strings.equal(decl.getLiteral().getValue(), decl.getEnumLiteral().getName());
|
||||
}
|
||||
else if (feature == XtextPackage.eINSTANCE.getRuleCall_ExplicitlyCalled()) {
|
||||
return true;
|
||||
}
|
||||
else if (feature == XtextPackage.eINSTANCE.getNamedArgument_Parameter()) {
|
||||
return !((NamedArgument)owner).isCalledByName();
|
||||
}
|
||||
return super.isTransient(owner, feature, index);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.eclipse.xtext.CrossReference;
|
|||
import org.eclipse.xtext.EnumLiteralDeclaration;
|
||||
import org.eclipse.xtext.EnumRule;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.NamedArgument;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.TerminalRule;
|
||||
|
@ -80,6 +81,13 @@ public class XtextTransientValueService2 extends TransientValueService {
|
|||
return NO;
|
||||
}
|
||||
return YES;
|
||||
} else if (feature == XtextPackage.eINSTANCE.getRuleCall_ExplicitlyCalled()) {
|
||||
return YES;
|
||||
} else if (feature == XtextPackage.eINSTANCE.getNamedArgument_Parameter()) {
|
||||
if (((NamedArgument)owner).isCalledByName()) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
return super.isValueTransient(owner, feature);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ import org.eclipse.xtext.Grammar;
|
|||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.Group;
|
||||
import org.eclipse.xtext.Keyword;
|
||||
import org.eclipse.xtext.NamedArgument;
|
||||
import org.eclipse.xtext.Parameter;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.ReferencedMetamodel;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
|
@ -78,7 +80,6 @@ import org.eclipse.xtext.util.XtextSwitch;
|
|||
import org.eclipse.xtext.validation.AbstractDeclarativeValidator;
|
||||
import org.eclipse.xtext.validation.AbstractValidationMessageAcceptor;
|
||||
import org.eclipse.xtext.validation.Check;
|
||||
import org.eclipse.xtext.validation.CheckType;
|
||||
import org.eclipse.xtext.validation.ValidationMessageAcceptor;
|
||||
import org.eclipse.xtext.xtext.ecoreInference.SourceAdapter;
|
||||
|
||||
|
@ -109,8 +110,74 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
protected List<EPackage> getEPackages() {
|
||||
return Collections.<EPackage>singletonList(XtextPackage.eINSTANCE);
|
||||
}
|
||||
|
||||
@Check
|
||||
public void checkOrderOfArguments(RuleCall call) {
|
||||
AbstractRule rule = call.getRule();
|
||||
if (rule instanceof ParserRule) {
|
||||
Set<Parameter> usedParameters = Sets.newHashSet();
|
||||
boolean hasError = false;
|
||||
boolean hasPositionalArgument = false;
|
||||
boolean hasNamedArgument = false;
|
||||
for(NamedArgument argument: call.getArguments()) {
|
||||
Parameter parameter = argument.getParameter();
|
||||
if (parameter == null || parameter.eIsProxy()) {
|
||||
hasError = true;
|
||||
} else if (!usedParameters.add(parameter)) {
|
||||
hasError = true;
|
||||
error("Duplicate value for parameter " + parameter.getName(),
|
||||
argument, XtextPackage.Literals.NAMED_ARGUMENT__PARAMETER);
|
||||
}
|
||||
if (!argument.isCalledByName()) {
|
||||
hasPositionalArgument = true;
|
||||
} else {
|
||||
hasNamedArgument = true;
|
||||
}
|
||||
}
|
||||
if (hasError) {
|
||||
return;
|
||||
}
|
||||
List<Parameter> parameters = ((ParserRule) rule).getParameters();
|
||||
if (!hasPositionalArgument) {
|
||||
if (usedParameters.size() != parameters.size()) {
|
||||
StringBuilder missing = new StringBuilder();
|
||||
int count = 0;
|
||||
for(Parameter parameter: parameters) {
|
||||
if (!usedParameters.contains(parameter)) {
|
||||
if (count > 0) {
|
||||
missing.append(", ");
|
||||
}
|
||||
missing.append(parameter.getName());
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 1) {
|
||||
error("Missing argument for parameter " + missing,
|
||||
call, XtextPackage.Literals.RULE_CALL__RULE);
|
||||
} else {
|
||||
error(count + " missing arguments for the following parameters: " + missing,
|
||||
call, XtextPackage.Literals.RULE_CALL__RULE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (usedParameters.size() != parameters.size()) {
|
||||
error(String.format("Expected %d arguments but got %d", parameters.size(), usedParameters.size()),
|
||||
call, XtextPackage.Literals.RULE_CALL__RULE);
|
||||
} else if (hasNamedArgument) {
|
||||
for(int i = 0, max = Math.min(usedParameters.size(), parameters.size()); i < max; i++) {
|
||||
NamedArgument argument = call.getArguments().get(i);
|
||||
Parameter param = parameters.get(i);
|
||||
if (argument.isCalledByName() && argument.getParameter() != param) {
|
||||
error("Out of sequence named argument. Expected value for " + param.getName(),
|
||||
argument, XtextPackage.Literals.NAMED_ARGUMENT__PARAMETER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Check(CheckType.FAST)
|
||||
@Check
|
||||
public void checkGrammarUsesMaxOneOther(Grammar grammar) {
|
||||
if (grammar.getUsedGrammars().size() > 1) {
|
||||
for(int i = 1; i < grammar.getUsedGrammars().size(); i++) {
|
||||
|
@ -122,7 +189,7 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
}
|
||||
}
|
||||
|
||||
@Check(CheckType.FAST)
|
||||
@Check
|
||||
public void checkGrammarRecursiveReference(Grammar grammar) {
|
||||
Set<Grammar> visitedGrammars = Sets.newHashSet(grammar);
|
||||
for (int i = 0; i < grammar.getUsedGrammars().size(); i++) {
|
||||
|
@ -684,7 +751,7 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
@Check
|
||||
public void checkUnassignedRuleCallAllowed(final RuleCall call) {
|
||||
if (call.getRule() != null && !call.getRule().eIsProxy() && GrammarUtil.containingAssignment(call) == null) {
|
||||
AbstractRule container = EcoreUtil2.getContainerOfType(call, AbstractRule.class);
|
||||
AbstractRule container = GrammarUtil.containingRule(call);
|
||||
if (call.getRule() instanceof ParserRule) {
|
||||
if (container instanceof TerminalRule) {
|
||||
getMessageAcceptor().acceptError(
|
||||
|
@ -693,9 +760,12 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
XtextPackage.Literals.RULE_CALL__RULE,
|
||||
ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
|
||||
null);
|
||||
} else {
|
||||
ParserRule parserRule = (ParserRule) call.getRule();
|
||||
if (!GrammarUtil.isDatatypeRule(parserRule) && !parserRule.isFragment()) {
|
||||
checkCurrentMustBeUnassigned(call);
|
||||
}
|
||||
}
|
||||
else if (!GrammarUtil.isDatatypeRule((ParserRule) call.getRule()))
|
||||
checkCurrentMustBeUnassigned(call);
|
||||
}
|
||||
if (call.getRule() instanceof EnumRule) {
|
||||
if (container instanceof TerminalRule) {
|
||||
|
@ -714,7 +784,7 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
public void checkTerminalFragmentCalledFromTerminalRule(final RuleCall call) {
|
||||
if (call.getRule() != null && !call.getRule().eIsProxy()) {
|
||||
if (call.getRule() instanceof TerminalRule && ((TerminalRule) call.getRule()).isFragment()) {
|
||||
AbstractRule container = EcoreUtil2.getContainerOfType(call, AbstractRule.class);
|
||||
AbstractRule container = GrammarUtil.containingRule(call);
|
||||
if (!(container instanceof TerminalRule)) {
|
||||
getMessageAcceptor().acceptError(
|
||||
"Only terminal rules may use terminal fragments.",
|
||||
|
@ -728,12 +798,11 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
}
|
||||
|
||||
private void checkCurrentMustBeUnassigned(final AbstractElement element) {
|
||||
ParserRule rule = GrammarUtil.containingParserRule(element);
|
||||
final ParserRule rule = GrammarUtil.containingParserRule(element);
|
||||
if (GrammarUtil.isDatatypeRule(rule))
|
||||
return;
|
||||
|
||||
XtextSwitch<Boolean> visitor = new XtextSwitch<Boolean>() {
|
||||
private boolean isNull = true;
|
||||
private boolean isNull = !rule.isFragment();
|
||||
|
||||
@Override
|
||||
public Boolean caseAbstractElement(AbstractElement object) {
|
||||
|
@ -781,7 +850,7 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
public Boolean caseAction(Action object) {
|
||||
if (object == element) {
|
||||
if (!(isNull && !isMany(object))) {
|
||||
error("An unassigned action is not allowed, when the 'current' was already created.", null);
|
||||
error("An unassigned action is not allowed, when the 'current' was already created.", object, null);
|
||||
checkDone();
|
||||
}
|
||||
}
|
||||
|
@ -792,8 +861,13 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
@Override
|
||||
public Boolean caseRuleCall(RuleCall object) {
|
||||
if (object == element) {
|
||||
AbstractRule calledRule = object.getRule();
|
||||
if (calledRule instanceof ParserRule && ((ParserRule) calledRule).isFragment()) {
|
||||
isNull = false;
|
||||
return isNull;
|
||||
}
|
||||
if (!(isNull && !isMany(object))) {
|
||||
error("An unassigned rule call is not allowed, when the 'current' was already created.", null);
|
||||
error("An unassigned rule call is not allowed, when the 'current' was already created.", object, null);
|
||||
checkDone();
|
||||
}
|
||||
}
|
||||
|
@ -826,6 +900,9 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
public void checkAssignedActionAfterAssignment(final Action action) {
|
||||
if (action.getFeature() != null) {
|
||||
ParserRule rule = GrammarUtil.containingParserRule(action);
|
||||
if (rule.isFragment() && !rule.isWildcard()) {
|
||||
return;
|
||||
}
|
||||
XtextSwitch<Boolean> visitor = new XtextSwitch<Boolean>() {
|
||||
private boolean assignedActionAllowed = false;
|
||||
|
||||
|
@ -880,7 +957,7 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
public Boolean caseAction(Action object) {
|
||||
if (object == action) {
|
||||
if (!assignedActionAllowed) {
|
||||
error("An action is not allowed, when the current may still be unassigned.", null);
|
||||
error("An action is not allowed in wildcard fragments and when the current may still be unassigned.", null);
|
||||
checkDone();
|
||||
}
|
||||
}
|
||||
|
@ -899,7 +976,7 @@ public class XtextValidator extends AbstractDeclarativeValidator {
|
|||
|
||||
@Override
|
||||
public Boolean caseParserRule(ParserRule object) {
|
||||
assignedActionAllowed = !GrammarUtil.isDatatypeRule(object);
|
||||
assignedActionAllowed = !GrammarUtil.isDatatypeRule(object) && !(object.isFragment() && object.isWildcard());
|
||||
return assignedActionAllowed;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,14 +13,28 @@ import org.eclipse.xtext.conversion.IValueConverter;
|
|||
import org.eclipse.xtext.conversion.ValueConverter;
|
||||
import org.eclipse.xtext.conversion.ValueConverterException;
|
||||
import org.eclipse.xtext.conversion.impl.AbstractNullSafeConverter;
|
||||
import org.eclipse.xtext.conversion.impl.KeywordAlternativeConverter;
|
||||
import org.eclipse.xtext.nodemodel.ILeafNode;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
/**
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
*/
|
||||
@Singleton
|
||||
public class XtextValueConverters extends DefaultTerminalConverters {
|
||||
|
||||
@Inject
|
||||
private Provider<KeywordAlternativeConverter> validIDConverter;
|
||||
|
||||
@ValueConverter(rule = "ValidID")
|
||||
public IValueConverter<String> ValidID() {
|
||||
return validIDConverter.get();
|
||||
}
|
||||
|
||||
@ValueConverter(rule = "GrammarID")
|
||||
public IValueConverter<String> GrammarID() {
|
||||
return new AbstractNullSafeConverter<String>() {
|
||||
|
@ -51,5 +65,51 @@ public class XtextValueConverters extends DefaultTerminalConverters {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ValueConverter(rule = "RuleID")
|
||||
public IValueConverter<String> RuleID() {
|
||||
return new AbstractNullSafeConverter<String>() {
|
||||
@Override
|
||||
protected String internalToValue(String string, INode node) throws ValueConverterException {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for(ILeafNode leaf: node.getLeafNodes()) {
|
||||
if (!leaf.isHidden()) {
|
||||
if (leaf.getGrammarElement() instanceof Keyword)
|
||||
result.append(".");
|
||||
else
|
||||
result.append(ID().toValue(leaf.getText(), leaf));
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String internalToString(String value) {
|
||||
String[] splitted = value.split("\\.");
|
||||
StringBuilder result = new StringBuilder(value.length());
|
||||
for(int i = 0; i < splitted.length; i++) {
|
||||
if (i != 0)
|
||||
result.append("::");
|
||||
result.append(ID().toString(splitted[i]));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ValueConverter(rule = "LiteralValue")
|
||||
public IValueConverter<Boolean> LiteralValue() {
|
||||
return new AbstractNullSafeConverter<Boolean>() {
|
||||
@Override
|
||||
protected Boolean internalToValue(String string, INode node) throws ValueConverterException {
|
||||
return "+".equals(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String internalToString(Boolean value) {
|
||||
return value.booleanValue() ? "+" : "!";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@ public enum TransformationErrorCode {
|
|||
UnknownMetaModelAlias,
|
||||
InvalidDatatypeRule,
|
||||
InvalidSupertype,
|
||||
InvalidFeature;
|
||||
InvalidFeature,
|
||||
InvalidFragmentOverride,
|
||||
InvalidRuleOverride;
|
||||
|
||||
public String getFullyQualifiedCode() {
|
||||
return getClass().getCanonicalName() + "." + name();
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.common.util.EList;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.EClass;
|
||||
import org.eclipse.emf.ecore.EClassifier;
|
||||
|
@ -204,31 +203,33 @@ public class Xtext2EcoreTransformer {
|
|||
for (AbstractRule rule : grammar.getRules()) {
|
||||
try {
|
||||
EClassifierInfo generatedEClass = findOrCreateEClassifierInfo(rule);
|
||||
if (rule instanceof ParserRule) {
|
||||
ParserRule parserRule = (ParserRule) rule;
|
||||
if (parserRule.getAlternatives() != null) {
|
||||
if (!GrammarUtil.isDatatypeRule(parserRule)) {
|
||||
deriveTypesAndHierarchy(parserRule, generatedEClass, parserRule.getAlternatives());
|
||||
} else {
|
||||
if (generatedEClass != null || !isWildcardFragment(rule)) {
|
||||
if (rule instanceof ParserRule) {
|
||||
ParserRule parserRule = (ParserRule) rule;
|
||||
if (parserRule.getAlternatives() != null) {
|
||||
if (!GrammarUtil.isDatatypeRule(parserRule)) {
|
||||
deriveTypesAndHierarchy(parserRule, generatedEClass, parserRule.getAlternatives());
|
||||
} else {
|
||||
checkSupertypeOfOverriddenDatatypeRule(rule);
|
||||
}
|
||||
}
|
||||
} else if (rule instanceof TerminalRule) {
|
||||
if (rule.getType() != null) {
|
||||
if (!(rule.getType().getClassifier() instanceof EDataType))
|
||||
throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable,
|
||||
"Return type of a terminal rule must be an EDataType.", rule.getType());
|
||||
checkSupertypeOfOverriddenDatatypeRule(rule);
|
||||
}
|
||||
} else if (rule instanceof EnumRule) {
|
||||
if (rule.getType() != null) {
|
||||
if (!(rule.getType().getClassifier() instanceof EEnum))
|
||||
throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable,
|
||||
"Return type of an enum rule must be an EEnum.", rule.getType());
|
||||
checkSupertypeOfOverriddenDatatypeRule(rule);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown rule type: " + rule.eClass().getName());
|
||||
}
|
||||
} else if (rule instanceof TerminalRule) {
|
||||
if (rule.getType() != null) {
|
||||
if (!(rule.getType().getClassifier() instanceof EDataType))
|
||||
throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable,
|
||||
"Return type of a terminal rule must be an EDataType.", rule.getType());
|
||||
checkSupertypeOfOverriddenDatatypeRule(rule);
|
||||
}
|
||||
} else if (rule instanceof EnumRule) {
|
||||
if (rule.getType() != null) {
|
||||
if (!(rule.getType().getClassifier() instanceof EEnum))
|
||||
throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable,
|
||||
"Return type of an enum rule must be an EEnum.", rule.getType());
|
||||
checkSupertypeOfOverriddenDatatypeRule(rule);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown rule type: " + rule.eClass().getName());
|
||||
}
|
||||
}
|
||||
catch (TransformationException e) {
|
||||
|
@ -320,7 +321,7 @@ public class Xtext2EcoreTransformer {
|
|||
boolean result = true;
|
||||
for (AbstractRule rule : grammar.getRules()) {
|
||||
try {
|
||||
if (rule instanceof ParserRule && !GrammarUtil.isDatatypeRule((ParserRule) rule)) {
|
||||
if (rule instanceof ParserRule && !GrammarUtil.isDatatypeRule((ParserRule) rule) && !isWildcardFragment(rule)) {
|
||||
deriveFeatures((ParserRule) rule);
|
||||
} else if (rule instanceof EnumRule) {
|
||||
deriveEnums((EnumRule) rule);
|
||||
|
@ -420,11 +421,15 @@ public class Xtext2EcoreTransformer {
|
|||
|
||||
@Override
|
||||
public Xtext2EcoreInterpretationContext caseGroup(Group object) {
|
||||
Xtext2EcoreInterpretationContext result = deriveFeatures(context.spawnContextForGroup(), object.getElements());
|
||||
if (GrammarUtil.isMultipleCardinality(object)) {
|
||||
result = deriveFeatures(result.spawnContextForGroup(), object.getElements());
|
||||
return visitElements(object, object.getElements());
|
||||
}
|
||||
|
||||
private Xtext2EcoreInterpretationContext visitElements(AbstractElement caller, List<AbstractElement> elementsToProcess) {
|
||||
Xtext2EcoreInterpretationContext result = deriveFeatures(context.spawnContextForGroup(), elementsToProcess);
|
||||
if (GrammarUtil.isMultipleCardinality(caller)) {
|
||||
result = deriveFeatures(result.spawnContextForGroup(), elementsToProcess);
|
||||
}
|
||||
if (GrammarUtil.isOptionalCardinality(object)) {
|
||||
if (GrammarUtil.isOptionalCardinality(caller)) {
|
||||
result = result.mergeSpawnedContexts(Arrays.asList(context, result));
|
||||
}
|
||||
return result;
|
||||
|
@ -450,8 +455,14 @@ public class Xtext2EcoreTransformer {
|
|||
|
||||
@Override
|
||||
public Xtext2EcoreInterpretationContext caseRuleCall(RuleCall object) {
|
||||
AbstractRule calledRule = object.getRule();
|
||||
if (isWildcardFragment(calledRule)) {
|
||||
return visitElements(object, Collections.singletonList(calledRule.getAlternatives()));
|
||||
}
|
||||
if (isParserRuleFragment(calledRule)) {
|
||||
return context;
|
||||
}
|
||||
if (!GrammarUtil.isOptionalCardinality(object)) {
|
||||
AbstractRule calledRule = object.getRule();
|
||||
// do not throw an exception for missing rules, these have been
|
||||
// announced during the first iteration
|
||||
if (calledRule != null && calledRule instanceof ParserRule && !GrammarUtil.isDatatypeRule((ParserRule) calledRule)) {
|
||||
|
@ -495,7 +506,7 @@ public class Xtext2EcoreTransformer {
|
|||
}
|
||||
|
||||
private Xtext2EcoreInterpretationContext deriveFeatures(Xtext2EcoreInterpretationContext context,
|
||||
EList<AbstractElement> elements) {
|
||||
List<AbstractElement> elements) {
|
||||
Xtext2EcoreInterpretationContext result = context;
|
||||
for (AbstractElement element : elements) {
|
||||
result = deriveFeatures(result, element);
|
||||
|
@ -605,19 +616,14 @@ public class Xtext2EcoreTransformer {
|
|||
final TypeHierarchyHelper helper = new TypeHierarchyHelper(grammar, this.eClassifierInfos, this.errorAcceptor);
|
||||
helper.liftUpFeaturesRecursively();
|
||||
helper.removeDuplicateDerivedFeatures();
|
||||
// helper.detectEClassesWithCyclesInTypeHierachy();
|
||||
|
||||
// duplicated features can occur in rare cases when alternatives produce
|
||||
// different types of a feature
|
||||
// If the internal structure (Set) of the underlying algorithm
|
||||
// produces the features for the subtype first the implementation of EClassInfo
|
||||
// wont find a conflict
|
||||
// helper.detectDuplicatedFeatures();
|
||||
}
|
||||
|
||||
private void deriveTypesAndHierarchy(final ParserRule rule, final EClassifierInfo ruleReturnType,
|
||||
AbstractElement element) throws TransformationException {
|
||||
TransformationException ex = new XtextSwitch<TransformationException>() {
|
||||
|
||||
Set<AbstractRule> visiting = Sets.newHashSet();
|
||||
|
||||
@Override
|
||||
public TransformationException caseAction(Action action) {
|
||||
final TypeRef actionTypeRef = action.getType();
|
||||
|
@ -633,10 +639,8 @@ public class Xtext2EcoreTransformer {
|
|||
@Override
|
||||
public TransformationException caseCompoundElement(CompoundElement object) {
|
||||
for (AbstractElement ele : object.getElements()) {
|
||||
try {
|
||||
deriveTypesAndHierarchy(rule, ruleReturnType, ele);
|
||||
}
|
||||
catch (TransformationException ex) {
|
||||
TransformationException ex = doSwitch(ele);
|
||||
if (ex != null) {
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
@ -656,21 +660,40 @@ public class Xtext2EcoreTransformer {
|
|||
"Cannot find called rule.", ruleCall);
|
||||
}
|
||||
if (calledRule instanceof TerminalRule ||
|
||||
calledRule instanceof ParserRule && (GrammarUtil.isDatatypeRule((ParserRule) calledRule)))
|
||||
calledRule instanceof ParserRule && (GrammarUtil.isDatatypeRule((ParserRule) calledRule))
|
||||
|| isWildcardFragment(calledRule))
|
||||
return null;
|
||||
if (calledRule instanceof EnumRule) {
|
||||
return new TransformationException(TransformationErrorCode.NoSuchRuleAvailable,
|
||||
"Cannot call enum rule without assignment.", ruleCall);
|
||||
}
|
||||
final TypeRef calledRuleReturnTypeRef = getOrComputeReturnType(calledRule);
|
||||
try {
|
||||
addSuperType(rule, calledRuleReturnTypeRef, ruleReturnType);
|
||||
}
|
||||
catch (TransformationException ex) {
|
||||
if (isParserRuleFragment(calledRule)) {
|
||||
TypeRef subTypeRef = getOrComputeReturnType(rule);
|
||||
addSuperType(rule, subTypeRef, findOrCreateEClassifierInfo(calledRule));
|
||||
if (visiting.add(calledRule)) {
|
||||
try {
|
||||
AbstractElement fragment = calledRule.getAlternatives();
|
||||
doSwitch(fragment);
|
||||
} finally {
|
||||
visiting.remove(calledRule);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final TypeRef calledRuleReturnTypeRef = getOrComputeReturnType(calledRule);
|
||||
addSuperType(rule, calledRuleReturnTypeRef, ruleReturnType);
|
||||
}
|
||||
} catch (TransformationException ex) {
|
||||
return ex;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformationException defaultCase(EObject object) {
|
||||
// ignore
|
||||
return null;
|
||||
}
|
||||
|
||||
}.doSwitch(element);
|
||||
if (ex != null)
|
||||
|
@ -684,20 +707,80 @@ public class Xtext2EcoreTransformer {
|
|||
|
||||
private boolean deriveTypeHierarchyFromOverridden(ParserRule rule, Grammar grammar) throws TransformationException {
|
||||
AbstractRule parentRule = GrammarUtil.findRuleForName(grammar, rule.getName());
|
||||
if (parentRule != null && parentRule.getType() != null && parentRule != rule) {
|
||||
if (parentRule.getType().getClassifier() instanceof EDataType)
|
||||
throw new TransformationException(TransformationErrorCode.InvalidSupertype,
|
||||
"Cannot inherit from datatype rule and return another type.", rule.getType());
|
||||
EClassifierInfo parentTypeInfo = eClassifierInfos.getInfoOrNull(parentRule.getType());
|
||||
if (parentTypeInfo == null)
|
||||
throw new TransformationException(TransformationErrorCode.InvalidSupertype,
|
||||
"Cannot determine return type of overridden rule.", rule.getType());
|
||||
addSuperType(rule, rule.getType(), parentTypeInfo);
|
||||
return true;
|
||||
if (parentRule != null) {
|
||||
if (parentRule != rule && parentRule instanceof ParserRule) {
|
||||
ParserRule casted = (ParserRule) parentRule;
|
||||
if (casted.isFragment() != rule.isFragment()) {
|
||||
if (rule.isFragment()) {
|
||||
throw new TransformationException(TransformationErrorCode.InvalidFragmentOverride,
|
||||
"A fragment rule cannot override a production rule.", rule);
|
||||
} else {
|
||||
throw new TransformationException(TransformationErrorCode.InvalidFragmentOverride,
|
||||
"Only fragment rule can override other fragment rules.", rule);
|
||||
}
|
||||
}
|
||||
if (casted.isWildcard() != rule.isWildcard()) {
|
||||
if (rule.isWildcard()) {
|
||||
throw new TransformationException(TransformationErrorCode.InvalidFragmentOverride,
|
||||
"A wildcard fragment rule cannot override a typed fragment rule.", rule);
|
||||
} else {
|
||||
throw new TransformationException(TransformationErrorCode.InvalidFragmentOverride,
|
||||
"Only wildcard fragment rules can override other wildcard fragments.", rule);
|
||||
}
|
||||
}
|
||||
if (rule.isFragment() && !rule.isWildcard() && parentRule.getType() != null) {
|
||||
if (rule.getType().getClassifier() != parentRule.getType().getClassifier()) {
|
||||
throw new TransformationException(TransformationErrorCode.InvalidFragmentOverride,
|
||||
"Overriding fragment rules cannot redeclare their type.", rule.getType());
|
||||
}
|
||||
}
|
||||
checkParameterLists(rule, casted);
|
||||
}
|
||||
if (parentRule.getType() != null && parentRule != rule) {
|
||||
if (parentRule.getType().getClassifier() instanceof EDataType)
|
||||
throw new TransformationException(TransformationErrorCode.InvalidSupertype,
|
||||
"Cannot inherit from datatype rule and return another type.", rule.getType());
|
||||
EClassifierInfo parentTypeInfo = eClassifierInfos.getInfoOrNull(parentRule.getType());
|
||||
if (parentTypeInfo == null)
|
||||
throw new TransformationException(TransformationErrorCode.InvalidSupertype,
|
||||
"Cannot determine return type of overridden rule.", rule.getType());
|
||||
addSuperType(rule, rule.getType(), parentTypeInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkParameterLists(ParserRule rule, ParserRule overridden) throws TransformationException {
|
||||
int inherited = overridden.getParameters().size();
|
||||
if (inherited == rule.getParameters().size()) {
|
||||
boolean ok = true;
|
||||
for(int i = 0; ok && i < inherited; i++) {
|
||||
if (!Strings.equal(rule.getParameters().get(i).getName(), overridden.getParameters().get(i).getName())) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (inherited == 0) {
|
||||
throw new TransformationException(TransformationErrorCode.InvalidRuleOverride,
|
||||
"Overridden rule " + rule.getName() + " does not declare any parameters", rule);
|
||||
}
|
||||
StringBuilder message = new StringBuilder("Parameter list is incompatible with inherited ");
|
||||
message.append(rule.getName()).append("[");
|
||||
for(int i = 0; i < overridden.getParameters().size(); i++) {
|
||||
if (i != 0) {
|
||||
message.append(", ");
|
||||
}
|
||||
message.append(overridden.getParameters().get(i).getName());
|
||||
}
|
||||
message.append("]");
|
||||
throw new TransformationException(TransformationErrorCode.InvalidRuleOverride,
|
||||
message.toString(), rule);
|
||||
}
|
||||
|
||||
private void addSuperType(ParserRule rule, TypeRef subTypeRef, EClassifierInfo superTypeInfo) throws TransformationException {
|
||||
final EClassifier subType = subTypeRef.getClassifier();
|
||||
final EClassifierInfo subTypeInfo = subType == null
|
||||
|
@ -841,14 +924,34 @@ public class Xtext2EcoreTransformer {
|
|||
}
|
||||
|
||||
private EClassifierInfo findOrCreateEClassifierInfo(AbstractRule rule) throws TransformationException {
|
||||
if (isWildcardFragment(rule)) {
|
||||
return null;
|
||||
}
|
||||
final TypeRef typeRef = getOrComputeReturnType(rule);
|
||||
if (typeRef == null)
|
||||
if (typeRef == null) {
|
||||
throw new TransformationException(TransformationErrorCode.NoSuchTypeAvailable, "Cannot create type for unnamed rule.", rule);
|
||||
}
|
||||
if (typeRef.getMetamodel() != null && typeRef.getMetamodel().getEPackage() == null)
|
||||
throw new TransformationException(TransformationErrorCode.UnknownMetaModelAlias, "Cannot create type without declared package.", typeRef);
|
||||
return findOrCreateEClassifierInfo(typeRef, rule.getName(), grammar.getRules().contains(rule));
|
||||
}
|
||||
|
||||
private boolean isWildcardFragment(AbstractRule rule) {
|
||||
if (rule instanceof ParserRule) {
|
||||
ParserRule casted = (ParserRule) rule;
|
||||
return casted.isFragment() && casted.isWildcard();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isParserRuleFragment(AbstractRule rule) {
|
||||
if (rule instanceof ParserRule) {
|
||||
ParserRule casted = (ParserRule) rule;
|
||||
return casted.isFragment() && !casted.isWildcard();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private EClassifierInfo findEClassifierInfo(AbstractRule rule) {
|
||||
final TypeRef typeRef = getOrComputeReturnType(rule);
|
||||
if (typeRef == null)
|
||||
|
@ -884,8 +987,7 @@ public class Xtext2EcoreTransformer {
|
|||
+ typeRef.getClassifier().getName());
|
||||
// + GrammarUtil.getQualifiedName(typeRef));
|
||||
|
||||
String classifierName = null;
|
||||
classifierName = GrammarUtil.getTypeRefName(typeRef);
|
||||
String classifierName = GrammarUtil.getTypeRefName(typeRef);
|
||||
if (classifierName == null)
|
||||
classifierName = name;
|
||||
if (classifierName == null)
|
||||
|
|
Loading…
Reference in a new issue