【问题标题】:Match root element of partial AST匹配部分 AST 的根元素
【发布时间】:2019-07-08 07:54:31
【问题描述】:

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

如何只匹配根元素?

【问题讨论】:

  • 首先我尝试使用 if 语句进行匹配。喜欢:if (args[0] == \equals(_, _) ...,但这不起作用。我让它与 switch 语句一起使用。

标签: match rascal clair


【解决方案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 应该在内部考虑到常见的东西以提高效率。两种模式非常相似的事实并不是 Rascal 恕我直言的代码异味,因为这就是这段代码的全部意义所在,您希望稍微不同地对待两种相似的模式,第一个示例文档明确地没有嵌套控制流。换句话说:嵌套模式比嵌套控制流更清晰?

【讨论】:

    【解决方案2】:

    我使用这个字段,因为评论字段的空间有限。

    我喜欢嵌套模式的这一特性,但我无法匹配简单的大小写。我尝试了以下模式:

        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 匹配的模式?

    【讨论】:

    • 最好从示例(打印出来的树)中复制/粘贴模式。表达式语法与模式语法相同。在示例中,我看到idExpression(...) 带有小写i,在模式中我看到IdExpression。这就是模式不匹配的原因。
    • 更好:该示例有idExpression(name("patternA"))),因此还应该嵌套一个name 构造函数!
    • src 字段可以被忽略并从模式中删除(如果值中的关键字字段未明确包含在匹配模式中,则模式匹配将忽略它们)
    • idExpression 和 name 都是必需的。
    • 是的。该模式应该与您打印的示例完全相同。格罗耶斯
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 2011-11-02
    • 2021-09-16
    • 2018-02-03
    • 1970-01-01
    • 2021-09-14
    相关资源
    最近更新 更多