首页 > 解决方案 > 匹配部分 AST 的根元素

问题描述

我想使用 Clair 和 Rascal 重构一些 C 代码。我搜索具有特定名称的函数。如果我找到这样的功能,我想用另一个功能替换它。我需要在四个功能之间进行选择。要选择的函数取决于找到的函数的参数。我需要匹配表达式的根元素。

我可以使用访问模式进行匹配。我试过了

visit(body) {
  case \functionCall(func, args): {
    if ("myName" == func.name.\value) {
      visit(args[0]) {
        case \equals(_, _): println("Equals");
        case \notEquals(_, _): println("Not equals");
      }             
    }
  }
}

这并不能保证我匹配根元素。在 (A != B) == CI 只想匹配 ==

我怎样才能只匹配根元素?

标签: matchrascalclair

解决方案


您可以任意嵌套模式并使用它来匹配函数调用,包括函数名称和要匹配的第一个参数的形状。

例如:

case functionCall(someId("my name", [e:\equals(_, _), *_]) => newFunctionCall(e)
case functionCall(someId("my name", [e:\notEquals(_, _), *_]) => newFunctionCall(e)

[..]请注意,只要第一个参数是 equals 或 nonEquals 表达式,这里匹配任意长度的参数列表的列表模式。

因此,您可以为第一个参数的每个案例重复一个顶级案例,如上,或嵌套一个开关并使用“插入”,如下所示:

  case functionCall(someId("my name", [arg, *_]) : 
               switch(arg) {
                  case equals(_, _) : insert newFunctionCall(arg);
                  ...
               }

我更喜欢第一种情况,因为它更具声明性。Rascal 应该在内部考虑到常见的东西以提高效率。两种模式非常相似的事实并不是 Rascal 恕我直言的代码异味,因为这就是这段代码的全部意义所在,您希望稍微不同地对待两种相似的模式,第一个示例文档明确地没有嵌套控制流。换句话说:嵌套模式比嵌套控制流更清晰


推荐阅读