匹配部分AST的根元素

时间:2019-07-08 07:54:31

标签: match rascal clair

我想使用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)== C中,我只想匹配==

我怎么只匹配根元素?

2 个答案:

答案 0 :(得分:1)

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

例如:

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 IMHO中并不是代码异味,因为这就是这段代码的全部重点,您想要略微不同地对待两种相似的模式,并且第一个示例文档明确地不嵌套控制流。换句话说:嵌套模式比嵌套控制流?

更清晰

答案 1 :(得分:0)

我使用此字段,因为注释字段中的空间有限。

我喜欢嵌套模式的此功能,但是我没有找到匹配的简单案例。我尝试了以下模式:

    visit(body) {
        case \functionCall("methodA", [arg, *_]): println("match");
        case \functionCall(SomeId("methodA", [arg, *_])): println("match");
        case \functionCall(SomeId("methodA"), [arg, *_]): println("match");
        case \functionCall(IdExpresssion("methodA", [arg, *_])): println("match");
        case \functionCall(IdExpresssion("methodA"), [arg, *_]): println("match");
        case \functionCall(name("methodA", [arg, *_])): println("match");
        case \functionCall(name("methodA"), [arg, *_]): println("match");
    }

iprint(body)给出以下结果:

compoundStatement(
  [
    compoundStatement(
      [
        expressionStatement(
.... some expressions and declarations
        for(
... for statement
          compoundStatement(
            [
... inside for loop
              expressionStatement(
                functionCall(
                  idExpression(
                    name(
                      "methodA",
                      src=|project://Instrumentation/example.c|(11195,10)),
                    src=|project://Instrumentation/example.c|(11195,10),
                    decl=|cpp+problem://Attempt%20to%20use%20symbol%20failed:%20methodA|,
                    typ=problemType("Failure to determine type of expression")),
                  [equals(
                      idExpression(
                        name(
                          "beforeTest",
                          src=|project://Instrumentation/example.c|(11207,20)),
                        src=|project://Instrumentation/example.c|(11207,20),
                        decl=|cpp+variable:///test1()/beforeTest|,
                        typ=problemType("Type depends on an unresolved name")),
                      idExpression(
                        name(
                          "afterTest",
                          src=|project://Instrumentation/example.c|(11231,19)),
                        src=|project://Instrumentation/example.c|(11231,19),
                        decl=|cpp+variable:///test1()/afterTest|,
                        typ=problemType("Type depends on an unresolved name")),
                      src=|project://Instrumentation/example.c|(11207,43),
                      typ=problemType("Type depends on an unresolved name"))],
                  src=|project://Instrumentation/example.c|(11195,57),
                  typ=problemBinding()),
                src=|project://Instrumentation/example.c|(11195,58)),
              expressionStatement(
... more expressions and declaratios in for loop              
  ],
  src=|project://Instrumentation/example.c|(10148,1349))ok

如何制作与MethodA匹配的模式?