Tirasz / transpy

(Thesis) Transforming conditions into structural patterns with Python AST
1 stars 2 forks source link

Visit branches instead of If-nodes. #2

Closed Tirasz closed 3 years ago

Tirasz commented 3 years ago

Make plugins visit the branches instead of the main If-node. The plugins should return with a list of subjects for the given branch. In the main analyzer, construct a dictionary of branch -> [ (plugin, [subjects]) ] (A list of tuples saying: PluginXY can transform this branch using these subjects) By going over and intersecting the returned subjects, determine if it can be transformed into a pattern match. For example, given the code:

if isinstance(x, SomeClass) and x.prop = "something" and x.other_prop = 42 and something_else():
    ...
elif (x == None or x == "") and (y == "Error" or y ==404) and something_else():
    ...

For the first branch, LiteralCase would return nothing, while ClassCase would return a list: ["x"] For the second branch, ClassCase would return nothing, while LiteralCase would return a list: ["x", "y"] In the main analyzer this would look like: branch1 -> [(ClassCase(), ["x"])] branch2 -> [(LiteralCase(), ["x", "y"])] After somehow making sense of the above, we can conclude that: The whole If-node can be transformed into a pattern match, using the subject x. Like so:

match x:
    case SomeClass(prop = "something", other_prop=42) if something_else():
        ...
    case None | "" if (y == "Error" or y == 404) and something_else():
        ...

Reworking the one (1!) already existing plugin to work this way shouldn't be too hard. But implementing this in the main analyzer is going to be bit more difficult.

Even though this solution smells, in practice i dont think many (if any) branches are gonna have more than one plugin that can transform them.