Coverage for src/rejuvenation/refactor_with_nested_compositions.py: 94%
50 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-02 13:12 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-02 13:12 +0000
1"""AI: Example script demonstrating nested pattern replacements when rewriting C source."""
3# This script demonstrates the use of the syntax_tree library to parse and rewrite C code.
4# It specifically showcases nested replacements and multiple patterns.
5import textwrap
7from renaissance.integrations.clang import ClangASTNode, CPatternFactory
8from renaissance.syntax_tree import ASTFactory, ASTRewriter, ASTShower
9from renaissance.syntax_tree.ast_finder import find_semantic_kind
10from renaissance.syntax_tree.match_finder import find_all
11from renaissance.syntax_tree.semantic_kind import SemanticKind
13example_code = """
14void f1(int a, int b, int c);
15void f2(int a, int c);
16void f(){
17 const int a = 1;
18 const int b = 2;
19 int isAOne = a==1;
20 int c = 0, d=0;
21 if (a==1) {
22 d++;
23 if(a==1){
24 d++;
25 c=d;
26 f1(a,b,c);
27 }
28 }
29 if (a==2) {
30 c++;
31 f1(a,b,c);
32 }
33 f1(a,b,c);
34}
35""".strip()
37expected_result = """
38void f1(int a, int b, int c);
39void f2(int a, int c);
40void f(){
41 const int a = 1;
42 const int b = 2;
43 int isAOne = a==1;
44 int c = 0, d=0;
45 //changed if expr to const
46 if(isAOne){
47 d++;
48 //changed if expr to const
49 if(isAOne){
50 d++;
51 c=d;
52 //changed function f1 to f2
53 f2(a,c);
54 }
55 }
56 if (a==2) {
57 c++;
58 //changed function f1 to f2
59 f2(a,c);
60 }
61 //changed function f1 to f2
62 f2(a,c);
63}
64""".strip()
67def refactor_with_nested_compositions(args):
68 """AI: Demonstrate nested pattern composition by rewriting calls inside matched if-statement bodies."""
69 # the first argument is the code to be parsed
70 code = args[1] if len(args) > 1 else ""
72 # Create a factory args from the command line are passed to the factory for example -I/usr/include
73 factory = ASTFactory(ClangASTNode, args if not code else args[1:])
74 # Create a pattern factory (using the factory (hence also its args)
75 # create translation unit
76 atu = factory.create(code) if code else factory.create_from_text(example_code, "example.c")
77 # create a pattern factory atu is passed to the pattern factory for use of all # includes, #defines and declarations
78 pattern_factory = CPatternFactory(factory, atu)
79 # create a pattern that matches an if statement with a==1 as the condition and a block of statements as the body
80 # the type is important so it's declared as const int a
81 pattern1 = pattern_factory.create_statements("if(a==1){$$stmts;}", extra_declarations=["const int a;"])
82 # for pattern 2 we create a fully functional c snippet with a call to f1
83 # note that the f1 declaration is derived from the atu
84 pattern2 = pattern_factory.create("int $a,$b,$c; void fff() {f1($a,$b,$c);}")
85 ASTShower.show_node(pattern1[0], include_properties=True)
87 # we only want to search the call expression as a pattern so it's searched using the kind
88 pattern2 = find_semantic_kind(pattern2, SemanticKind.CALL)
90 # the replacement code strip indent is used to be agnostic to the indentation of the replacement
91 pattern1replacement = textwrap.dedent("""
92 //changed if expr to const
93 if(isAOne){
94 $$stmts;
95 }""")
97 pattern2replacement = "\n//changed function f1 to f2\nf2($a,$c);"
99 # show node and patterns enable include properties to show the properties of the nodes
100 include_properties = True
101 ASTShower.show_node(atu, include_properties)
102 ASTShower.show_node(pattern1[0], include_properties)
103 ASTShower.show_node(pattern2[0], include_properties)
105 result1 = None
106 while atu:
107 # create an ASTRewriter
108 rewriter = ASTRewriter(atu)
110 def raw(nodes):
111 res = ""
112 for node in nodes:
113 res += node.text
114 return res + "\n"
116 # create a refactoring that use different replacement code for different patterns
117 def refactor(match1):
118 print(f"peek: f{match1.signature}")
119 if match1.patterns == pattern1:
120 replacement_text = pattern1replacement
121 for repl_snippet in match1.expansions:
122 replacement_text = replacement_text.replace(repl_snippet, raw(match1.expansions[repl_snippet]))
123 else:
124 replacement_text = pattern2replacement
125 for repl_snippet in match1.expansions:
126 replacement_text = replacement_text.replace(repl_snippet, match1.expansions[repl_snippet][0].signature)
127 return rewriter.replace(replacement_text, match1.nodes)
129 # search matches for pattern1 and pattern2 and replace them using the refactor function
130 for match in find_all(atu.children, pattern1, pattern2):
131 refactor(match)
133 # print the rewritten code
134 result1 = rewriter.apply_to_string()
135 atu = factory.create_from_text(result1, "example.c") if rewriter.has_changed() else None
136 return result1
139if __name__ == "__main__":
140 import sys
142 result = refactor_with_nested_compositions(sys.argv)
143 print(result)