简体   繁体   中英

Match root element of partial AST

I want to refactor some C code using Clair and Rascal. I search for a function with a certain name. If I find such a function, I want to replace it with another function. I need to choose between four functions. The function to choose depends on the argument of the function found. I need to match the root element of an expression.

I can match using the visit pattern. I tried

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

This does not guarantee I match the root element. In (A != B) == CI only want to match the ==

How can I match only the root element?

You can nest patterns arbitrarily and use this to match a function call including the name of your function and the shape of the first argument you want to match.

For example:

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

Note the list pattern [..] which matches argument lists of arbitrary length here as long as the first argument is an equals or nonEquals expression.

So you could repeat a top-level case for each case of the first parameter, like above, or nest a switch and use "insert", like below:

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

I prefer the first case because it's more declarative. Rascal should factor the common stuff for efficiency sake internally. The fact that both patterns are very similar is not a code smell in Rascal IMHO, because that's the whole point of this code, you want to treat two similar patterns slightly differently and the first example documents that explicitly without nesting control flow. In other words: It's clearer to nest a pattern than to nest control flow 😁

I use this field, because space is limited in the comment field.

I like this feature of nested patterns, but I do not get the simple case to match. I tried the following patterns:

    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) gives the following results:

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

How can I make a pattern that does match MethodA?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM