4444
4545
4646def simple_replace (contents , match , replacement , assignment ):
47- "replaces the indexes in 'contents' described by the tuple 'group' with replacement"
48-
47+ "replaces the indexes in 'contents' described by the tuple 'group' with replacement, which may have backrefs "
48+
4949 start , end = match .span (1 )
50- return contents [:start ] + replacement + contents [end :]
50+ return contents [:start ] + match . expand ( replacement ) + contents [end :]
5151
5252
5353def replace_pre (contents , match , replacement , assignment ):
5454 "replaces a pre-increment/decrement"
55-
55+
5656 start , end = match .span (1 )
5757 replacement = replacement .replace ('%receiver' , contents [start : end ])
5858 start , end = match .span ()
@@ -61,24 +61,24 @@ def replace_pre(contents, match, replacement, assignment):
6161
6262def replace_field_access (contents , match , replacement , assignment ):
6363 "replaces a field access, scanning backwards to determine the receiver"
64-
64+
6565 start , end = match .span (1 )
6666 level = 0
67-
67+
6868 def consume_whitespace_backwards (idx ):
6969 while idx > 0 and contents [idx ].isspace ():
7070 idx -= 1
7171 return idx
72-
72+
7373 def consume_whitespace_forward (idx ):
7474 while idx < len (contents ) and contents [idx ].isspace ():
7575 idx += 1
7676 return idx
77-
77+
7878 start = consume_whitespace_backwards (start - 1 )
7979 if start < 1 or contents [start - 1 : start + 1 ] != '->' :
8080 return contents
81-
81+
8282 # scan backwards to capture the whole receiver
8383 idx = consume_whitespace_backwards (start - 2 )
8484 empty = True
@@ -110,12 +110,12 @@ def consume_whitespace_forward(idx):
110110 else :
111111 idx += 1
112112 break
113-
113+
114114 receiver_start = consume_whitespace_forward (idx )
115115 receiver_string = contents [receiver_start : start - 1 ]
116-
116+
117117 if assignment is not None :
118-
118+
119119 # scan forwards to see if there's an assignment
120120 idx = consume_whitespace_forward (end )
121121 if contents [idx ] == '=' and contents [idx + 1 ] != '=' :
@@ -139,11 +139,11 @@ def consume_whitespace_forward(idx):
139139 idx += 2
140140 else :
141141 idx += 1
142-
142+
143143 value_string = contents [value_start :idx ]
144-
144+
145145 return contents [:receiver_start ] + assignment .replace ('%receiver' , receiver_string ).replace ("%value" , value_string ) + contents [idx :]
146-
146+
147147 return contents [:receiver_start ] + replacement .replace ('%receiver' , receiver_string ) + contents [end :]
148148
149149
@@ -157,13 +157,16 @@ def consume_whitespace_forward(idx):
157157 r'\W(ob_item)\W' : (replace_field_access , 'PySequence_Fast_ITEMS((PyObject*)%receiver)' ),
158158 r'^\s*()(std::)?free\((const_cast<char \*>)?\(?\w+->m_ml->ml_doc\)?\);' : (simple_replace , '//' ),
159159 r'\W(m_ml\s*->\s*ml_doc)\W' : (replace_field_access , 'PyObject_GetDoc((PyObject*)(%receiver))' , 'PyObject_SetDoc((PyObject*)(%receiver), %value)' ),
160+ r'\W(m_ml)\W' : (replace_field_access , '_PyCFunction_GetMethodDef((PyObject*)(%receiver))' ),
161+ r'\W(m_module)\W' : (replace_field_access , '_PyCFunction_GetModule((PyObject*)(%receiver))' ),
162+ r'(&PyTuple_GET_ITEM\(([\(\w](?:\w|->|\.|\(|\))*), 0\))' : (simple_replace , r'PySequence_Fast_ITEMS(\2)' ),
160163 # already defined by GraalPy:
161164 r'^\s*()#\s*define\s+Py_SET_TYPE\W' : (simple_replace , '//' ),
162165 r'^\s*()#\s*define\s+Py_SET_SIZE\W' : (simple_replace , '//' ),
163166 r'^\s*()#\s*define\s+Py_SET_REFCNT\W' : (simple_replace , '//' ),
164167}
165168
166-
169+
167170def auto_patch (path , dryrun ):
168171 "reads the given file, applies all replacements, and writes back the result if there were changes"
169172
@@ -172,7 +175,7 @@ def auto_patch(path, dryrun):
172175 contents = f .read ()
173176 except UnicodeDecodeError :
174177 return # may happen for binary files
175-
178+
176179 original = contents
177180 import re
178181 for pattern , (* ops ,) in auto_replacements .items ():
0 commit comments