plugins/zap-transformation/__main__.py (69 lines of code) (raw):

import re from polyglot_piranha import OutgoingEdges, Rule, RuleGraph, execute_piranha, PiranhaArguments mapping = { "Bool": ["true", "false"], "Complex128": ["complex128(:[x])"], "Float64": ["float64(:[x])"], } def convert_hole_style(s): pattern = re.compile(r':\[(\w+)\]') return pattern.sub(r'@\1', s) # This function creates a list of simple rules for the following scenario: # - zap.Any is used with a pattern from the mapping def get_simple_rule(mapping): return [ Rule( f"simple_{api}_usage_{pattern}", # Create a unique name for the rule query=f"cs logger.With(zap.Any(:[f], {pattern})).Info(:[i])", # The query to match replace_node="*", replace="logger.With(zap.{}(@f, {})).Info(@i)".format(api, convert_hole_style(pattern)), # The replacement (the replacement is a bit awkward because we need to convert the hole style) holes = {"zap"} ) for api, patterns in mapping.items() for pattern in patterns ] # This function creates a rule graph for the following scenario: # - zap.Any is used with a variable (e.g., zap.Any("key", &value)) # - The variable is declared within the enclosing function # - The variable is initialized to a pattern from the mapping def rule_graph_for_usage_with_variables(mapping): # Matches the usage of zap.Any with a variable usage_with_var = Rule( f"usage_of_zap_any_with_var", query=f"cs logger.With(zap.Any(:[f], &:[var_name])).Info(:[i])", holes = {"zap"} ) rules =[usage_with_var] edges = [] for api, patterns in mapping.items(): for pattern in patterns: # Matches the declaration of a variable initialized to the pattern var_decl_pattern = Rule( name=f"var_decl_{api}_usage_{pattern}", query=f"cs :[var_name] = {pattern}", holes = {"var_name"}, is_seed_rule=False ) # Update the zap any usage update_zap_usage = Rule( name=f"update_zap_usage_{api}_usage_{pattern}", query=f"cs logger.With(zap.Any(:[f], &:[var_name])).Info(:[i])", replace_node="*", replace=f"logger.With(zap.{api}(@f, &@var_name)).Info(@i)", holes = {"var_name"}, is_seed_rule=False ) # When zap usage with a variable is found, we find the declaration of the variable within the enclosing function edges.append(OutgoingEdges( usage_with_var.name, to = [ var_decl_pattern.name ], scope= "Function-Method" )) # If the variable declaration is found for that variable, and it is initialized to the pattern, we update the zap usage edges.append(OutgoingEdges( var_decl_pattern.name, to = [ update_zap_usage.name ], scope= "Function-Method" )) rules.extend([var_decl_pattern, update_zap_usage]) return rules, edges simple_rules = get_simple_rule(mapping) complex_rules, edges = rule_graph_for_usage_with_variables(mapping) rule_graph = RuleGraph(rules=simple_rules + complex_rules, edges=edges) args = PiranhaArguments( "go", paths_to_codebase=["/Users/ketkara/repositories/open-source/piranha/plugins/zap-transformation/resource"], substitutions={"zap": "zap"}, rule_graph=rule_graph, ) summary = execute_piranha(args) print(summary)