Xtext 链接服务和派生状态

Xtext linking service and derived state

我有这个语法:

Feature returns ecore::EStructuralFeature:
{Feature} name=ID ':' (fp_many?='*')? eType=[ecore::EClassifier];

还有 EClass:

Class returns ecore::EClass:
{EClassClass}
name=ID (interface?=':Api')?
(BEGIN
(eStructuralFeatures+=Feature)*
(eOperations+=Operation)*
END)?;

我的目标是使用类似于 YAML 的语法为文本 Ecore mm 提供 DSL,因此我需要根据其 EType 将 Feature 对象转换为 EAttribute 或 EReference。

我试过像这样在 LazyLinker 中挂钩 afterModelLinked

Queue<Feature> ftrs = Queues.newArrayDeque(features);
Feature f = null;
while ((f = ftrs.poll()) != null) {
    if (f.getEType() == null)
     continue;
    if (f.getEType() instanceof EDataType) {
    createEAttribute(eClazz, f);
    } else if (f.getEType() instanceof EClass) {
    createEReference(eClazz, f);
    }
    eClazz.getEStructuralFeatures().remove(f);
}

此代码确实将功能转换为适当的类型,但我在验证服务中收到错误堆栈跟踪:

org.eclipse.emf.common.util.WrappedException: java.lang.NullPointerException
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:233)
at org.eclipse.xtext.resource.persistence.StorageAwareResource.getEObject(StorageAwareResource.java:124)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doResolveLazyCrossReference(LazyLinkingResource.java:192)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReference(LazyLinkingResource.java:151)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.resolveLazyCrossReferences(LazyLinkingResource.java:137)
at org.eclipse.xtext.EcoreUtil2.resolveLazyCrossReferences(EcoreUtil2.java:528)
at org.eclipse.xtext.validation.ResourceValidatorImpl.resolveProxies(ResourceValidatorImpl.java:163)
at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:75)
at org.eclipse.xtext.ui.editor.validation.ValidationJob.exec(ValidationJob.java:91)
at org.eclipse.xtext.ui.editor.validation.ValidationJob.exec(ValidationJob.java:1)
at org.eclipse.xtext.util.concurrent.CancelableUnitOfWork.exec(CancelableUnitOfWork.java:26)
at org.eclipse.xtext.resource.OutdatedStateManager.exec(OutdatedStateManager.java:121)
at org.eclipse.xtext.ui.editor.model.XtextDocument$XtextDocumentLocker.internalReadOnly(XtextDocument.java:520)
at org.eclipse.xtext.ui.editor.model.XtextDocument$XtextDocumentLocker.readOnly(XtextDocument.java:492)
at org.eclipse.xtext.ui.editor.model.XtextDocument.readOnly(XtextDocument.java:133)
at org.eclipse.xtext.ui.editor.validation.ValidationJob.createIssues(ValidationJob.java:86)
at org.eclipse.xtext.ui.editor.validation.ValidationJob.run(ValidationJob.java:67)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
Caused by: java.lang.NullPointerException
at org.eclipse.xtext.linking.impl.ImportedNamesAdapter.find(ImportedNamesAdapter.java:34)
at org.eclipse.xtext.linking.impl.DefaultLinkingService.getImportedNamesAdapter(DefaultLinkingService.java:95)
at com.eacg.dsl.faml.linker.FamlLinkingService.getImportedNamesAdapter(FamlLinkingService.java:53)
at org.eclipse.xtext.linking.impl.DefaultLinkingService.registerImportedNamesAdapter(DefaultLinkingService.java:86)
at org.eclipse.xtext.linking.impl.DefaultLinkingService.registerImportedNamesAdapter(DefaultLinkingService.java:90)
at org.eclipse.xtext.linking.impl.DefaultLinkingService.registerImportedNamesAdapter(DefaultLinkingService.java:80)
at org.eclipse.xtext.linking.impl.DefaultLinkingService.getScope(DefaultLinkingService.java:58)
at com.eacg.dsl.faml.linker.FamlLinkingService.getScope(FamlLinkingService.java:47)
at org.eclipse.xtext.linking.impl.DefaultLinkingService.getLinkedObjects(DefaultLinkingService.java:119)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:250)
at org.eclipse.xtext.linking.lazy.LazyLinkingResource.getEObject(LazyLinkingResource.java:225)

调试时,我发现它仍在上下文中使用对象 Feature,即使我在创建映射时已将其删除。

我的问题是:如何在不破坏我的模型的情况下安全地替换对象Feature。我也尝试过实现 IDerivedStateComputer 但出现了一些错误。

我认为这里的根本问题是 EMF 是一种基于图形的格式; 类 可以是其他 类 的特征、操作的参数等。通常,此关系图可以包含环、圈和结。因此,任何试图就地修改的东西都会很棘手,需要一个成熟的图遍历算法来确保你不会改变依赖于你尚未处理的东西的东西。

另一种方法是让模型加载并 link 以其原始形式,然后将其转换为单通道。这就是 xcore 实现事物的方式;等效的声明是:

XClass:
{XClass}
(annotations+=XAnnotation)*
((abstract?='abstract'? 'class') | interface?= 'interface') name = ID
('<' typeParameters+=XTypeParameter (',' typeParameters+=XTypeParameter)* '>')?
('extends' superTypes+=XGenericType (',' superTypes+=XGenericType)*)?
('wraps' instanceType=JvmTypeReference) ?
'{'
   (members+=XMember)*
'}'

;

注意所有 X,它们是本地模型 类。然后后来,只有一个功能:

protected EClass getEClass(final XClass xClass)