嵌套后代模式匹配

Nested descendant pattern matches

我正在尝试查找所有方法调用和包含它们的 classes。如果我没理解错的话,模式匹配执行回溯,以所有可能的方式进行匹配。

采取以下java代码。

package main;
public class Main {
    public static void main(String[] args) {
        System.out.println("hello world");
        System.out.println("hello again");
    }
}

我正在使用 createAstsFromDirectory 加载代码。

rascal>ast = createAstsFromDirectory(|home:///multiple-method-calls|, false);

我试图找到对 println 的两个调用。以下代码匹配一次:

void findCalls(set[Declaration] ast)
{
  visit(ast)
  {
    case \class(_,_,_,/\methodCall(_,_,str methodName,_)):
      println("<methodName>");
  }
}
rascal>findCalls(ast);
println
ok

这段代码匹配四次:

void findCalls(set[Declaration] ast)
{
  visit(ast)
  {
    case /\class(_,_,_,/\methodCall(_,_,str methodName,_)):
      println("<methodName>");
  }
}
rascal>findCalls(ast);
println
println
println
println
ok

模式必须如何才能恰好匹配两次?

相关问题,如何获取class名字?尝试访问 class 名称时出现错误消息。

void findCalls(set[Declaration] ast)
{
  visit(ast)
  {
    case /\class(str className,_,_,/\methodCall(_,_,str methodName,_)):
      println("<className> <methodName>");
  }
}
findCalls(ast);
Main println
|project://personal-prof/src/Assignment13Rules.rsc|(3177,9,<141,16>,<141,25>): Undeclared variable: className

看起来第一个匹配项 className 正确绑定到 "Main",但第二个匹配项没有。

我想我会这样写:

void findCalls(set[Declaration] ast) {
  for(/class(_, _, _, /methodCall(_,_,str methodName,_)) <- ast) {
      println("<methodName>");
  }
}

for 循环遍历它可以找到的每个 class,通过它可以在内部找到的每个 methodCall,因此对于您给出的示例两次。

你的第二次尝试出错并且匹配太频繁:如果你在一个访问的情况的顶部嵌套一个/,你访问树中的每个位置一次,并遍历整个子 -再次包含根节点的树。所以你每次都会接到两次电话。

您的第一次尝试出错了,因为访问的案例模式的顶级不会自行回溯,它会找到整个模式的第一个匹配项,然后停止。所以嵌套的/只匹配一次然后body被执行

在 for 循环解决方案中,for 循环(与访问不同)将尝试所有可能的匹配直到它停止,所以这就是要走的路。还有一个更接近你原计划的解决方案:

void findCalls(set[Declaration] ast) {
      visit (ast) {
        case class(_, _, _, body) : 
          for (/methodCall(_,_,str methodName,_) <- body) {
            println("<methodName>");
          }
      }
}   

这也像 for 循环一样工作,它首先通过访问一个一个地找到所有 classes,然后通过 for 循环遍历所有嵌套匹配。

最后,您还可以嵌套访问本身以获得正确答案:

void findCalls(set[Declaration] ast) {
      visit (ast) {
        case class(_, _, _, body) : 
          visit(body) {
            case methodCall(_,_,str methodName,_): {
            println("<methodName>");
          }
        }
      }
}

WRT 到 className 东西,似乎 visit 和顶级深度匹配的组合在这样的情况下:case /<pattern> 中有一个错误Rasca 解释器在深层模式中丢失了变量绑定。所以请避免这种模式(我认为您不需要它),如果您愿意,请在 github?

上提交问题报告

在 for 循环的情况下,这将按预期简单地工作:

for(/class(str className, _, _, /methodCall(_,_,str methodName,_)) <- ast) {
   println("<className>::<methodName>");
}