在 Java 包上使用 "ls" 命令时出现不支持的方案错误

Unsupported scheme error when using "ls" command on a Java package

我正在开发一个函数,它为 Java M3 提供每个包的代码量列表。这个函数看起来像这样:

public list[int] calculateSizePerComponent(M3 model){
    set[loc] packages = packages(model);
    list[int] componentSizes = [];
    for(package <- packages){
        list[loc] classFiles = [x | x <- package.ls, endsWith(x.file, ".java")];
        if(size(classFiles)>0){
            int sourceSize = 0;
            for(classFile <- classFiles){
                sourceSize+=getLinesOfCode(classFile).linesOfCode;
            }
            componentSizes += sourceSize;
        }
    }
    return componentSizes;
}

我使用以下函数来计算 Java 编译单元(适用于其他示例)中的代码行数(体积):

public tuple[int linesOfCode,int blankLines,int commentLines] getLinesOfCode(loc location) {
    int linesOfCode = 0;
    int blankLines = 0;
    int commentLines = 0;
    bool incomment = false; 

    srcLines = readFileLines(location);     
    for (line <- srcLines) {
        switch(line){
            case /^\s*\/\/\s*\w*/: commentLines += 1; // Line preceded by '//'
            case /((\s*\/\*[\w\s]+\*\/)+[\s\w]+(\/\/[\s\w]+$)*)+/: linesOfCode += 1; // Line containing Java code containing any amount of comments. Example: code /**comment*/ code /**comment*/ code
            case /^\s*\/\*?[\w\s\?\@]*\*\/$/: commentLines += 1; // Line containing single line comment: /*comment*/
            case /\s*\/\*[\w\s]*\*\/[\s\w]+/: linesOfCode += 1; // Line containing a comment, but also code. Example: /**comment*/ code
            case /^[\s\w]*\*\/\s*\w+[\s\w]*/: {incomment = false; linesOfCode += 1;} // Line closing a multi-line comment, but also containing code. Example: comment*/ code
            case /^\s*\/\*\*?[^\*\/]*$/: {incomment = true; commentLines += 1;} // Line opening a multi-line comment, Example: /**comment
            case /\s*\*\/\s*$/: {commentLines += 1; incomment = false;} // Line closing a multi-line comment, Example: comment*/
            case /^\s*$/: blankLines += 1; // Blank line
            default: if (incomment) commentLines += 1; else linesOfCode += 1;
        }
    }
    return <linesOfCode,blankLines,commentLines>;
}

不过,package.ls好像return的结果是有错误的方案。因此,我在 readFileLines 调用中收到以下错误:

|std:///IO.rsc|(14565,775,<583,0>,<603,43>): IO("Unsupported scheme java+package")
        at *** somewhere ***(|std:///IO.rsc|(14565,775,<583,0>,<603,43>))
        at readFileLines(|project://Software_Evolution/src/metrics/volume.rsc|(1911,8,<49,26>,<49,34>))
        at calculateSizePerComponent(|project://Software_Evolution/src/metrics/componentsize.rsc|(1996,38,<64,16>,<64,54>))
        at getComponentSize(|project://Software_Evolution/src/metrics/componentsize.rsc|(267,1112,<15,0>,<42,1>))
        at $root$(|prompt:///|(0,30,<1,0>,<1,30>))

当我打印位置时,我得到以下信息:

|java+package:///smallsql/database/language/Language.java|

这是不正确的,因为这是一个 java 编译单元而不是包。如何获取此文件中的代码行?

分步分析:

  • package.ls 之所以有效,是因为首先逻辑 URI 由注册表 "name server" 解析为磁盘上的实际物理文件夹。如果那确实是一个目录,那么 .ls 具有正确的语义,你会得到该文件夹​​中的文件列表。
  • loc |java+package:///smallsql/database/language/Language.java| 实际上指向一个文件,甚至不是一个 compilationUnit。
  • 子位置的构造发生了意外,它采用文件夹的旧逻辑位置并简单地连接子文件的名称 "Language.java",但这没有意义。
  • 我在当前的 master 中修复了这个错误,几分钟后就会发布一个不稳定的版本
  • 但您也可以通过首先将包位置解析为物理位置来解决此问题:resolve(package).ls 应该做得更好。

PS:正则表达式很容易出错,你可能不得不处理很多极端情况。我会使用从 Java 的语法定义生成的真实解析器,或者使用 M3 已经通过 Eclipse 编译器生成的语法树来计算 SLOC。

Rascal 函数 resolveLocation 最终解决了问题。所以我不得不使用 resolveLocation(package).ls.

而不是 package.ls