import os
import re
import sys
class Filter:
def __init__(self):
pass
def transform(self, s):
return s
class CompoundFilt(Filter):
def __init__(self, items=()):
super().__init__()
self._filters = list(items)
def add(self, filt):
self._filters.append(filt)
return self
def transform(self, s):
for f in self._filters:
s = f.transform(s)
return s
class SplitError(Exception):
pass
def split_comments(s):
PAT_CODE = re.compile(r'''^(?: [^/"']+ |
"(?:[^\\"]+|\\.)*" |
'(?:[^\\']+|\\.)*' |
/[^/*]
)*''', re.VERBOSE|re.DOTALL)
PAT_C99_COMMENT = re.compile(r'^//.*$', re.MULTILINE)
PAT_C_COMMENT = re.compile(r'^/\*(?:[^*]|\*+[^*/])*\*+/', re.DOTALL)
while True:
m = PAT_CODE.match(s)
if m:
code = m.group(0)
s = s[m.end():]
else:
code = ""
if s.startswith("//"):
m = PAT_C99_COMMENT.match(s)
else:
m = PAT_C_COMMENT.match(s)
if m:
comment = m.group(0)
s = s[m.end():]
else:
comment = ""
if code == "" and comment == "":
if s:
raise SplitError()
return
yield (code, comment)
class IgnoreCommentsFilt(Filter):
def __init__(self, filt):
super().__init__()
self._filt = filt
def transform(self, s):
result = []
for code, comment in split_comments(s):
result.append(self._filt.transform(code))
result.append(comment)
return "".join(result)
class RegexFilt(Filter):
def __init__(self, pat, replacement, flags=0):
super().__init__()
self._pat = re.compile(pat, flags)
self._replacement = replacement
def transform(self, s):
s, _ = self._pat.subn(self._replacement, s)
return s
def revise(fname, filt):
contents = open(fname, 'r').read()
result = filt.transform(contents)
if result == contents:
return
tmpname = "{}_codetool_tmp".format(fname)
try:
with open(tmpname, 'w') as f:
f.write(result)
os.rename(tmpname, fname)
except:
os.unlink(tmpname)
raise
BREAK_MOCK_IMPL = RegexFilt(
r'^MOCK_IMPL\(([^,]+),\s*(\S+)',
r'MOCK_IMPL(\1,\n\2',
re.MULTILINE)
RESTORE_SMARTLIST_END = RegexFilt(
r'}\s*(SMARTLIST|DIGESTMAP|DIGEST256MAP|STRMAP|MAP)_FOREACH_END\s*\(',
r'} \1_FOREACH_END (',
re.MULTILINE)
F = CompoundFilt()
F.add(IgnoreCommentsFilt(CompoundFilt([
RESTORE_SMARTLIST_END,
BREAK_MOCK_IMPL])))
if __name__ == '__main__':
for fname in sys.argv[1:]:
revise(fname, F)