在 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
我正在开发一个函数,它为 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