Xtext导入名称空间验证

时间:2018-07-04 06:29:42

标签: xtext

我正在尝试通过使用类似Java的包,类和导入定义语法来学习Xtext。我的语法片段看起来像这样,其中CompilationUnit是根对象。

CompilationUnit:
  packageDeclaration=PackageDeclaration?
  imports+=ImportDeclaration*
  topClass=Class
;

packageDeclaration:
  'package' path=QualifiedName ';'
;

ImportDeclaration:
  'import' importedNamespace=QualifiedNameWithWildCard ';'
;

Class:
  {Class} visibility=Visibility isStatic?='static' 'class' name=ID ('extends' superClass=[Class|QualifiedName])? body=ClassBody
;

对于导入交叉引用,我使用DefaultGlobalScopeProvider,并且已经用自己的版本覆盖了QualifiedNameProvider,该版本将程序包名称附加为topClass QualifiedName的前缀。为了自动化自己的包导入,我编辑了项目特定的ScopeProvider。所有这些似乎都可以正常工作,并且使用生成的Eclipse IDE,我可以使用“ import [packageName]。[* | ClassName]”从其他文件中导入类。 (仍在与引荐来源网址相同的程序包中自动进行类的自动导入工作,但目前我可以通过显式导入进行管理)

我要尝试的下一步是验证导入和包声明。我想实现与Java相同的限制,即文件的包声明应等于文件的相对路径,另一方面,我想验证导入的类或包的存在。问题是,通过EObject的eResource,我只能访问资源的完整URI(例如platform:/resource/Sample/src/mypack/Sample.myjava),而相对于源文件夹的路径名会更短( mypack / Sample.myjava)。我还没有弄清楚是否应该使用某种逻辑来裁剪URI或采用完全不同的方法。

一个可能的想法可能是以某种方式获取项目的每个类路径目录的URI,然后从那里开始工作,但是我还没有弄清楚该怎么做。

有什么主意,我应该如何验证我的包裹和进口声明?我一直觉得自己很亲近,但到目前为止。

编辑:删除了对DefaultGlobalScopeProvider行为的误解。这与文件层次结构无关,而仅与限定名称有关。另外,我还可以自动导入自己的软件包。

更新:考虑到这一点,我应该适当地通过枚举可用资源并检查其合格名称来验证导入。然后,只有程序包声明验证才需要文件层次结构检查。

Update2:似乎在Eclipse中,资源URI的格式始终为“ platform:/ resource / [Project] / [src文件夹] / ...”。假设这意味着我可以对此进行严格检查,但是在语法项目验证器中执行此操作将在Eclipse上创建语法级别的依赖项,这对于任何严肃的DSL项目而言都不是一个好主意。但是,这篇文章中的评论使我认为也许我不应该考虑完全不在语法级别上进行包位置验证,而应该仅在UI项目中进行(我尚未更改)。想法是,应该比预期的传统文件系统层次结构更抽象地保留资源的位置。

1 个答案:

答案 0 :(得分:0)

我能够创建一个解决方案。以下代码是验证导入声明的粗略实现,可能需要进行一些清理,但基本上可以做到这一点。

@Check
def checkImportSanity(ImportDeclaration imp) {

    val importQN = qualifiedNameConverter.toQualifiedName(imp.importedNamespace)
    val hasWildcard = isImportWildcard(importQN.getLastSegment)

    for (r:imp.eContainer.eResource.resourceSet.resources) {
        val classQN = qualifiedNameProvider.getFullyQualifiedName((r.getContents().get(0) as CompilationUnit).topClass)
        if (hasWildcard && classQN.skipLast(1).equals(importQN.skipLast(1))) {
            return
        }
        else if (classQN.equals(importQN)) {
            return
        }
    }

    error("This import doesn't match any class!",
        imp, MyJavaPackage.Literals.IMPORT_DECLARATION__IMPORTED_NAMESPACE
    );
}
简而言之,它只是循环浏览所有资源,并比较导入的限定名称和资源的顶级类,而忽略任何文件名。 qualifiedNameProvider是我自己的,它将包名附加到类名之后。这样,它只能验证顶级导入,但我可以在以后进行进一步介绍。不知道这是否足以导入外部库,但这是我目前不感兴趣的另一个主题。

此外,我决定不根据文件名验证软件包名称。在Java做到这一点的同时,我想在当今世界,最好将其保留为编辑器级别的约束,而在语法级别上将其忽略。