現在、Xtext DSL の相互参照を実装しています。dsl ファイルには複数の XImportSection を含めることができ、特殊なケースでは XImportSection にすべての import ステートメントが含まれているとは限りません。これは、正しい XimportSection を見つけてビルドするには、「XImportSectionNamespaceScopeProvider」をカスタマイズする必要があることを意味します。実装中に、エディターや検証の予期しない動作を見つけました。
実装をテストするために切り取った次の 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)
、ソース ファイルにクラスのような要素が 1 つしかないことを前提としています。しかし、私の言語では、複数存在する可能性があります。このため、カスタマイズする必要があります。
私の考えは、次の実装です (Xtend プログラミング言語を使用):
override List<ImportNormalizer> internalGetImportedNamespaceResolvers(EObject context, boolean ignoreCase) {
switch (context) {
ModifiesUnit: context.buildImportSection
default: // ... anything else
}
}
この作業を開始する前に、参照は正常に機能し、予期しないことは何も起こりませんでした。ModifiesUnit
私の目標は、JVM タイプへの参照を解決するために Xbase によって使用される、カスタマイズされた XImportSection を構築することです。そのためには、参照先の XImportSection のコピーが必要ですClassOrInterface
。XImportSection にアクセスするには、まず を呼び出しますModifiesUnit.getUnit()
。この呼び出しが実行された直後に、エディターは予期しない動作を示します。エラーにつながる最小限の実装は次のようになります。
def XImportSection buildImportSection(ModifiesUnit u) {
val ci = u.unit // Since this expression is executed, the error occurs!
// ...
}
ここで、私は内部で何が起こっているのかわかりません!しかし、それは誤差を計算します。エディターは、(1) の修飾名に次のエラーを表示します: 「Cyclic linking detected : ModifiesUnit.unit->ModifiesUnit.unit」。
私の質問は次のとおりです。それはどういう意味ですか? Xtext でこのエラーが表示されるのはなぜですか? 参照されたオブジェクトにアクセスすると表示されるのはなぜですか?
私はそこで奇妙なことも考え出しました: 私の最初のアプローチでは、私のコードはNullPointerException
. わかりました、オブジェクトを印刷して理由を理解しようとしました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)
このメソッドは 2 回実行され、Xtext は 1 回目と 2 回目の実行の間でプロキシを解決しているようです。一度受け取ったオブジェクトが正しいものであれば、私にとっては問題ありません。if-instanceof ステートメントで処理します。
しかし、なぜそこに 2 つの参照があるのでしょうか。ClassDeclaration (2b) の抽象的なスーパールールのみである ParserRule ClassOrInterface (2a) に依存していますか? しかし、Xtext が ClassOrInterface の参照を解決できないのはなぜですか?