我目前正在为我的 Xtext dsl 实现交叉引用。一个 dsl 文件可以包含多个 XImportSection,在某些特殊情况下,一个 XImportSection 不一定包含所有导入语句。这意味着我需要自定义“XImportSectionNamespaceScopeProvider”来查找/构建正确的 XimportSection。在实施过程中,我发现了编辑器的意外行为和/或一些验证。
我使用以下 dsl 代码来测试我的实现:
delta MyDelta {
adds {
package my.pkg;
import java.util.List;
public class MyClass
implements List
{
}
}
modifies my.pkg.MyClass { // (1)
adds import java.util.ArrayList;
adds superclass ArrayList<String>;
}
}
dsl源代码由以下语法规则描述(不完整!):
AddsUnit:
{AddsUnit} 'adds' '{' unit=JavaCompilationUnit? '}';
ModifiesUnit:
'modifies' unit=[ClassOrInterface|QualifiedName] '{'
modifiesPackage=ModifiesPackage?
modifiesImports+=ModifiesImport*
modifiesSuperclass=ModifiesInheritance?
'}';
JavaCompilationUnit:
=> (annotations+=Annotation*
'package' name=QualifiedName EOL)?
importSection=XImportSection?
typeDeclarations+=ClassOrInterfaceDeclaration;
ClassOrInterfaceDeclaration:
annotations+=Annotation* modifiers+=Modifier* classOrInterface=ClassOrInterface;
ClassOrInterface: // (2a)
ClassDeclaration | InterfaceDeclaration | EnumDeclaration | AnnotationTypeDeclaration;
ClassDeclaration: // (2b)
'class' name=QualifiedName typeParameters=TypeParameters?
('extends' superClass=JvmTypeReference)?
('implements' interfaces=Typelist)?
body=ClassBody;
为了提供更好的工具支持,aModifiesUnit
引用了被修改的类。这个 Xtext 特定的实现支持到类的超链接。
我目前正在开发定制的 XImportSectionScopeProvider,它为ModifiesUnit
. 默认实现包含一个方法protected List<ImportNormalizer> internalGetImportedNamespaceResolvers(EObject context, boolean ignoreCase)
,假设源文件中只有一个类元素。但是对于我的语言来说,可能不止一种。出于这个原因,我必须自定义它。
我现在的想法是以下实现(使用 Xtend 编程语言):
override List<ImportNormalizer> internalGetImportedNamespaceResolvers(EObject context, boolean ignoreCase) {
switch (context) {
ModifiesUnit: context.buildImportSection
default: // ... anything else
}
}
在我开始这项工作之前,参考工作正常,没有发生任何意外。我现在的目标是构建一个定制的 XImportSection,ModifiesUnit
Xbase 使用它来解析对 JVM 类型的引用。为此,我需要引用的 XImportSection 的副本ClassOrInterface
。要访问 XImportSection,我首先调用ModifiesUnit.getUnit()
. 执行此调用后,编辑器立即显示意外行为。导致错误的最小实现如下所示:
def XImportSection buildImportSection(ModifiesUnit u) {
val ci = u.unit // Since this expression is executed, the error occurs!
// ...
}
在这里,我不知道内部发生了什么!但它计算一个错误。编辑器在 (1) 处的限定名称上显示以下错误:“检测到循环链接:ModifiesUnit.unit->ModifiesUnit.unit”。
我的问题是:这是什么意思?为什么 Xtext 会显示此错误?如果我访问引用的对象,为什么会出现?
我还在那里发现了一件奇怪的事情:在我的第一种方法中,我的代码抛出了一个NullPointerException
. 好的,我试图通过打印 object 来找出原因ci
。结果是:
org.deltaj.scoping.deltaJ.impl.ClassOrInterfaceImpl@4642f064 (eProxyURI: platform:/resource/Test/src/My.dj#xtextLink_::0.0.0.1.1::0::/2)
org.deltaj.scoping.deltaJ.impl.ClassDeclarationImpl@1c70366 (name: MyClass)
好吧,好像是这个方法执行了两次,Xtext解析了第一次和第二次执行之间的代理。只要收到的对象是正确的,对我来说就可以了。我用 if-instanceof 语句处理它。
但是为什么我在那里得到两个参考?它是否依赖于仅是 ClassDeclaration (2b) 的抽象超级规则的 ParserRule ClassOrInterface (2a)?但是为什么 Xtext 不能解析 ClassOrInterface 的引用呢?