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) == C I 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:
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:
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