当前位置: 首页 > 知识库问答 >
问题:

Xtext导入命名空间验证

诸经略
2023-03-14

我试图通过定义类似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,我可以使用“导入[包名]。[*|类名]”从其他文件导入类。(在引用者的同一个包中的类的自动导入仍然是半成品,但目前我可以通过显式导入来管理)

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

一个可能的想法可能是以某种方式获取项目的每个类路径目录的URI,并从那里开始工作,但我还没有弄清楚如何做到这一点。

知道我应该如何验证我的包和导入声明吗?我一直觉得我离得很近,但还很远。

编辑:删除了对DefaultGlobalScopeProvider行为的错误思考。这与文件层次结构无关,只与限定名有关。我还可以自动导入自己的软件包。

更新:考虑到这一点,我应该通过列举可用资源并检查它们的限定名称来验证导入。然后,只有包声明验证才需要文件层次结构检查。

Update2:在eclipse中,资源URI的格式似乎总是“平台:/资源/[项目]/[src文件夹]/...”。假设这意味着我可以对此进行硬检查,但是在语法项目验证器中这样做会在Eclipse上创建一个语法级别的依赖,这对于任何严肃的DSL项目来说可能都不是一个好主意。然而,这篇文章中的一条评论让我想到,也许我应该考虑在语法级别根本不做包位置验证,而只在用户界面项目中(我还没有修改)。这个想法是,资源的位置可能应该以更抽象的形式保留,而不是期望传统的文件系统层次结构。

共有1个答案

方献
2023-03-14

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

@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
    );
}

简而言之,它只是循环遍历所有资源,并比较导入的限定名称和资源的顶级类,忽略任何文件名。限定名称提供程序是我自己的,它将包名附加到类名中。像这样,它只能验证顶级类级别的导入,但我可以在以后更进一步。不知道这是否足以导入外部库,但这是我目前不感兴趣的另一个话题。

此外,我决定不根据文件名验证包名。虽然Java做到了这一点,但我想在当今世界,最好将其作为编辑器级别的约束,而忽略语法级别的约束。

 类似资料:
  • 问题内容: 尽管我已经学习Python大约一年了,但我正在学习Python并仍然是一个初学者。我正在尝试编写一个在主模块中调用的功能模块。被调用模块中的每个函数都需要math模块才能运行。我想知道是否有一种方法可以在不将数学模块导入被调用模块内部的情况下进行操作。这是我所拥有的: : : 运行时,我得到: 我很难理解的是为什么在运行时出现名称错误。我知道该变量在导入时对主模块变为全局,因为可以访问

  • Spring Security中主要的提高验证服务的接口是AuthenticationManager,这通常是一个Spring Security的ProviderManager 类的实例。如果你以前用过框架你可能已经熟悉了。如果不是后面的技术预览章节会讲到。这个bean是通过authentication-manager命名空间来注册。你不能使用自定义的AuthenticationManager如果

  • 当我挂载$docker时,为使用主机文件系统的正在运行的容器运行-v/tmp:/tmp-ti ubuntu/bin/bash。当我从exit命令关闭上述容器并将上述容器id与新的$docker运行链接--volumes-from=“closed container id”-ti ubuntu/bin/bash时,这也使用了新运行的容器中的/tmp文件。

  • 关于术语的一点说明: 请务必注意一点,TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与ECMAScript 2015里的术语保持一致,(也就是说 module X { 相当于现在推荐的写法 namespace X {)。 这篇文章描述了如何在TypeScript里使用命名空间(之前叫做“内部模块”)来组织你的代码

  • Let the word of Christ dwell in you richly in all wisdom; teaching and admonishing one another in psalms and hymns and spiritual songs, singing with grrace in your hearts tto the Lord. And whatsoever

  • 客户端有许多“命名空间”,通常是一些公开的可管理功能。命名空间对应 Elasticsearch 中各种可管理的 endpoint。下面是全部的命名空间: **命名空间** **功能** `indices()` 索引数据统计和显示索引信息 `nodes()` 节点数据统计和显示节点信息 `cluster()` 集群数据统计和显示集群信息 `snapshot()` 对集群和索引进行拍摄快照或恢复数据