-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaddFunctionWrappers.py
172 lines (153 loc) · 8.04 KB
/
addFunctionWrappers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import os
import sys
import re
import fileUtils
import subprocess
import time
functionDeclPattern = re.compile(r'[a-zA-Z_]+?\s*?::\s*?~?[a-zA-Z_]+?\s*?\(')
commentPattern = re.compile(r'\s*?//\s*?\*+?')
commentLine = '// ' + ('*' * 97)
def runClangFormat(filePath):
if 'CLANG_FORMAT_PATH' not in os.environ or not os.path.exists(os.environ['CLANG_FORMAT_PATH']):
print('Could not find clang format executable.')
return
result = subprocess.run([os.environ['CLANG_FORMAT_PATH'], '-style=file', filePath], capture_output=True, text=True)
result.check_returncode()
fileUtils.writeFile(filePath, result.stdout)
def lineHasNamespaceBegin(line):
namespaceIndex = line.find('namespace')
if namespaceIndex > -1:
commentIndex = line.find('//')
usingIndex = line.find('using')
isBeforeComment = commentIndex == -1 or namespaceIndex < commentIndex
isBeforeUsing = usingIndex == -1 or namespaceIndex < usingIndex
return isBeforeComment and isBeforeUsing
return False
def braceBalance(line):
opening = line.count('{')
closing = line.count('}')
balance = opening - closing
if lineHasNamespaceBegin(line):
balance -= 1
return balance
class FileChanger(fileUtils.FileChanger):
def changeContents(self, contents):
lines = contents.split('\n')
newContents = []
lineIndex = 0
currentBraceBalance = 0
currentNamespaceBalance = 0
isInFunctionDecl = False
foundEndingWrapper = False
skipNextLine = False
for line in lines:
addition = line
currentBraceBalance += braceBalance(line)
if lineHasNamespaceBegin(line):
currentNamespaceBalance += 1
if currentBraceBalance < 0:
currentNamespaceBalance += currentBraceBalance
currentBraceBalance = 0
if skipNextLine:
skipNextLine = False
else:
newContents, skipNextLine, isInFunctionDecl, foundEndingWrapper = self.treatLine(addition,
currentBraceBalance,
foundEndingWrapper,
isInFunctionDecl, line,
lineIndex, lines,
newContents,
skipNextLine)
lineIndex += 1
return ''.join(newContents)
def treatLine(self, addition, currentBraceBalance, foundEndingWrapper, isInFunctionDecl, line, lineIndex, lines,
newContents, skipNextLine):
addition, newContents, skipNextLine, isInFunctionDecl, foundEndingWrapper = self.matchLine(addition,
currentBraceBalance,
foundEndingWrapper,
isInFunctionDecl,
line, lineIndex,
lines, newContents,
skipNextLine)
if lineIndex < len(lines) - 1:
addition += '\n'
newContents.append(addition)
return newContents, skipNextLine, isInFunctionDecl, foundEndingWrapper
def matchLine(self, addition, currentBraceBalance, foundEndingWrapper, isInFunctionDecl, line, lineIndex, lines,
newContents, skipNextLine):
if not isInFunctionDecl and (currentBraceBalance == 0 or (
currentBraceBalance == 1 and braceBalance(
line) == 1)) and '#include' not in line and 'using ' not in line and line.strip() != '':
foundEndingWrapper, isInFunctionDecl, newContents = self.matchFunctionDecl(foundEndingWrapper,
isInFunctionDecl, line,
lineIndex, lines,
newContents)
if isInFunctionDecl:
addition, foundEndingWrapper, isInFunctionDecl, skipNextLine = self.matchEndingWrapper(
addition, foundEndingWrapper, isInFunctionDecl, line, lineIndex, lines, newContents,
skipNextLine)
return addition, newContents, skipNextLine, isInFunctionDecl, foundEndingWrapper
def matchEndingWrapper(self, addition, foundEndingWrapper, isInFunctionDecl, line, lineIndex, lines, newContents,
skipNextLine):
if commentPattern.match(line) is not None:
addition = commentLine
foundEndingWrapper = True
else:
braceIndex = line.find('{')
if braceIndex > -1:
isInFunctionDecl = False
if not foundEndingWrapper:
if braceIndex == 0:
if not foundEndingWrapper:
newContents.append(commentLine + '\n')
else:
if len(lines) > lineIndex + 1 and commentPattern.match(lines[lineIndex + 1]):
skipNextLine = True
substringBeforeBrace = line[0:braceIndex]
if substringBeforeBrace.strip() == '':
newContents.append(commentLine + '\n')
else:
newContents.append(substringBeforeBrace + '\n')
newContents.append(commentLine + '\n')
addition = line[braceIndex:]
return addition, foundEndingWrapper, isInFunctionDecl, skipNextLine
def matchFunctionDecl(self, foundEndingWrapper, isInFunctionDecl, line, lineIndex, lines, newContents):
functionDeclMatch = functionDeclPattern.search(line)
if functionDeclMatch is not None:
previousLine = lines[lineIndex - 1]
if commentPattern.match(previousLine) is not None:
newContents[-1] = commentLine + '\n'
elif previousLine.strip() == '':
newContents.append(commentLine + '\n')
else:
previousLine = lines[lineIndex - 2]
if commentPattern.match(previousLine) is not None:
newContents[-2] = commentLine + '\n'
elif previousLine.strip() == '':
newContents = newContents[:-2] + [commentLine + '\n'] + newContents[-2:]
isInFunctionDecl = True
foundEndingWrapper = False
return foundEndingWrapper, isInFunctionDecl, newContents
def treatFile(filePath):
print('Formatting ' + filePath)
if not os.path.exists(filePath):
print(f'Error: file {filePath} does not exist')
return
if not os.path.isfile(filePath):
print(f'Error: path {filePath} is not a file')
return
if filePath.endswith('.cc'):
fileChanger = FileChanger()
fileChanger.run(filePath)
if filePath.endswith('.cc') or filePath.endswith('.h'):
runClangFormat(filePath)
def add(inputPath):
if os.path.isdir(inputPath):
for dirname, _, filenames in os.walk(inputPath):
for filename in filenames:
filePath = os.path.join(dirname, filename)
treatFile(filePath)
else:
treatFile(inputPath)
if __name__ == '__main__':
add(sys.argv[1])