]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexGen.py
2 # LexGen.py - implemented 2002 by Neil Hodgson neilh@scintilla.org
3 # Released to the public domain.
5 # Regenerate the Scintilla and SciTE source files that list
6 # all the lexers and all the properties files.
7 # Should be run whenever a new lexer is added or removed.
8 # Requires Python 2.4 or later
9 # Most files are regenerated in place with templates stored in comments.
10 # The VS .NET project file is generated into a different file as the
11 # VS .NET environment will not retain comments when modifying the file.
12 # The files are copied to a string apart from sections between a
13 # ++Autogenerated comment and a --Autogenerated comment which is
14 # generated by the CopyWithInsertion function. After the whole
15 # string is instantiated, it is compared with the target file and
16 # if different the file is rewritten.
17 # Does not regenerate the Visual C++ 6 project files but does the VS .NET
29 if sys
.platform
== "win32":
32 # Yes, LF is the native EOL even on Mac OS X. CR is just for
33 # Mac OS <=9 (a.k.a. "Mac Classic")
36 # Automatically generated sections contain start and end comments,
37 # a definition line and the results.
38 # The results are replaced by regenerating based on the definition line.
39 # The definition line is a comment prefix followed by "**".
40 # If there is a digit after the ** then this indicates which list to use
41 # and the digit and next character are not part of the definition
42 # Backslash is used as an escape within the definition line.
43 # The part between \( and \) is repeated for each item in the list.
44 # \* is replaced by each list item. \t, and \n are tab and newline.
45 def CopyWithInsertion(input, commentPrefix
, retainDefs
, eolType
, *lists
):
49 for line
in input.splitlines(0):
50 isStartGenerated
= line
.startswith(commentPrefix
+ "++Autogenerated")
51 if copying
and not isStartGenerated
:
58 elif not copying
and line
.startswith(commentPrefix
+ "**"):
61 definition
= line
[len(commentPrefix
+ "**"):]
62 if (commentPrefix
== "<!--") and (" -->" in definition
):
63 definition
= definition
.replace(" -->", "")
65 if definition
[0] in string
.digits
:
66 listid
= int(definition
[:1])
67 definition
= definition
[2:]
68 # Hide double slashes as a control character
69 definition
= definition
.replace("\\\\", "\001")
70 # Do some normal C style transforms
71 definition
= definition
.replace("\\n", "\n")
72 definition
= definition
.replace("\\t", "\t")
73 # Get the doubled backslashes back as single backslashes
74 definition
= definition
.replace("\001", "\\")
75 startRepeat
= definition
.find("\\(")
76 endRepeat
= definition
.find("\\)")
77 intro
= definition
[:startRepeat
]
79 if intro
.endswith("\n"):
84 middle
= definition
[startRepeat
+2:endRepeat
]
85 for i
in lists
[listid
]:
86 item
= middle
.replace("\\*", i
)
87 if pos
and (pos
+ len(item
) >= 80):
92 if item
.endswith("\n"):
94 outro
= definition
[endRepeat
+2:]
96 out
= out
.replace("\n", eolType
) # correct EOLs in generated content
98 elif line
.startswith(commentPrefix
+ "--Autogenerated"):
102 output
= [line
.rstrip(" \t") for line
in output
] # trim trailing whitespace
103 return eolType
.join(output
) + eolType
105 def UpdateFile(filename
, updated
):
106 """ If the file is different to updated then copy updated
107 into the file else leave alone so CVS and make don't treat
110 infile
= open(filename
, "rb")
111 except IOError: # File is not there yet
112 out
= open(filename
, "wb")
113 out
.write(updated
.encode('utf-8'))
115 print("New %s" % filename
)
117 original
= infile
.read()
119 original
= original
.decode('utf-8')
120 if updated
!= original
:
122 out
= open(filename
, "wb")
123 out
.write(updated
.encode('utf-8'))
125 print("Changed %s " % filename
)
127 #~ print "Unchanged", filename
129 def Generate(inpath
, outpath
, commentPrefix
, eolType
, *lists
):
130 """Generate 'outpath' from 'inpath'.
132 "eolType" indicates the type of EOLs to use in the generated
133 file. It should be one of following constants: LF, CRLF,
136 #print "generate '%s' -> '%s' (comment prefix: %r, eols: %r)"\
137 # % (inpath, outpath, commentPrefix, eolType)
139 infile
= open(inpath
, "rb")
141 print("Can not open %s" % inpath
)
143 original
= infile
.read()
145 original
= original
.decode('utf-8')
146 updated
= CopyWithInsertion(original
, commentPrefix
,
147 inpath
== outpath
, eolType
, *lists
)
148 UpdateFile(outpath
, updated
)
150 def Regenerate(filename
, commentPrefix
, eolType
, *lists
):
151 """Regenerate the given file.
153 "eolType" indicates the type of EOLs to use in the generated
154 file. It should be one of following constants: LF, CRLF,
157 Generate(filename
, filename
, commentPrefix
, eolType
, *lists
)
159 def FindModules(lexFile
):
162 for l
in f
.readlines():
163 if l
.startswith("LexerModule"):
164 l
= l
.replace("(", " ")
165 modules
.append(l
.split()[1])
168 # Properties that start with lexer. or fold. are automatically found but there are some
169 # older properties that don't follow this pattern so must be explicitly listed.
170 knownIrregularProperties
= [
172 "styling.within.preprocessor",
173 "tab.timmy.whinge.level",
174 "asp.default.language",
175 "html.tags.case.sensitive",
178 "sql.backslash.escapes",
183 def FindProperties(lexFile
):
186 for l
in f
.readlines():
187 if ("GetProperty" in l
or "DefineProperty" in l
) and "\"" in l
:
189 if not l
.startswith("//"): # Drop comments
190 propertyName
= l
.split("\"")[1]
191 if propertyName
.lower() == propertyName
:
192 # Only allow lower case property names
193 if propertyName
in knownIrregularProperties
or \
194 propertyName
.startswith("fold.") or \
195 propertyName
.startswith("lexer."):
196 properties
[propertyName
] = 1
199 def FindPropertyDocumentation(lexFile
):
203 for l
in f
.readlines():
205 if "// property " in l
:
206 propertyName
= l
.split()[2]
207 if propertyName
.lower() == propertyName
:
208 # Only allow lower case property names
211 elif "DefineProperty" in l
and "\"" in l
:
212 propertyName
= l
.split("\"")[1]
213 if propertyName
.lower() == propertyName
:
214 # Only allow lower case property names
218 if l
.startswith("//"):
220 documents
[name
] += " "
221 documents
[name
] += l
[2:].strip()
222 elif l
.startswith("\""):
230 # Fix escaped double quotes
231 l
= l
.replace("\\\"", "\"")
235 for name
in list(documents
.keys()):
236 if documents
[name
] == "":
241 return cmp(a
.lower(), b
.lower())
246 def sortListInsensitive(l
):
247 try: # Try key function
249 except TypeError: # Earlier version of Python, so use comparison function
252 def UpdateLineInFile(path
, linePrefix
, lineReplace
):
254 with open(path
, "r") as f
:
255 for l
in f
.readlines():
257 if l
.startswith(linePrefix
):
258 lines
.append(lineReplace
)
261 contents
= NATIVE
.join(lines
) + NATIVE
262 UpdateFile(path
, contents
)
264 def UpdateVersionNumbers(root
):
265 with open(root
+ "scintilla/version.txt") as f
:
267 versionDotted
= version
[0] + '.' + version
[1] + '.' + version
[2]
268 versionCommad
= version
[0] + ', ' + version
[1] + ', ' + version
[2] + ', 0'
270 UpdateLineInFile(root
+ "scintilla/win32/ScintRes.rc", "#define VERSION_SCINTILLA",
271 "#define VERSION_SCINTILLA \"" + versionDotted
+ "\"")
272 UpdateLineInFile(root
+ "scintilla/win32/ScintRes.rc", "#define VERSION_WORDS",
273 "#define VERSION_WORDS " + versionCommad
)
274 UpdateLineInFile(root
+ "scintilla/qt/ScintillaEditBase/ScintillaEditBase.pro",
276 "VERSION = " + versionDotted
)
277 UpdateLineInFile(root
+ "scintilla/qt/ScintillaEdit/ScintillaEdit.pro",
279 "VERSION = " + versionDotted
)
280 UpdateLineInFile(root
+ "scintilla/doc/ScintillaDownload.html", " Release",
281 " Release " + versionDotted
)
282 UpdateLineInFile(root
+ "scintilla/doc/index.html",
283 ' <font color="#FFCC99" size="3"> Release version',
284 ' <font color="#FFCC99" size="3"> Release version ' + versionDotted
+ '<br />')
286 if os
.path
.exists(root
+ "scite"):
287 UpdateLineInFile(root
+ "scite/src/SciTE.h", "#define VERSION_SCITE",
288 "#define VERSION_SCITE \"" + versionDotted
+ "\"")
289 UpdateLineInFile(root
+ "scite/src/SciTE.h", "#define VERSION_WORDS",
290 "#define VERSION_WORDS " + versionCommad
)
291 UpdateLineInFile(root
+ "scite/doc/SciTEDownload.html", " Release",
292 " Release " + versionDotted
)
293 UpdateLineInFile(root
+ "scite/doc/SciTE.html",
294 ' <font color="#FFCC99" size="3"> Release version',
295 ' <font color="#FFCC99" size="3"> Release version ' + versionDotted
+ '<br />')
300 # Find all the lexer source code files
301 lexFilePaths
= glob
.glob(root
+ "scintilla/lexers/Lex*.cxx")
302 sortListInsensitive(lexFilePaths
)
303 lexFiles
= [os
.path
.basename(f
)[:-4] for f
in lexFilePaths
]
307 propertyDocuments
= {}
308 for lexFile
in lexFilePaths
:
309 lexerModules
.extend(FindModules(lexFile
))
310 for k
in FindProperties(lexFile
).keys():
311 lexerProperties
[k
] = 1
312 documents
= FindPropertyDocumentation(lexFile
)
313 for k
in documents
.keys():
314 propertyDocuments
[k
] = documents
[k
]
315 sortListInsensitive(lexerModules
)
316 lexerProperties
= list(lexerProperties
.keys())
317 sortListInsensitive(lexerProperties
)
319 # Generate HTML to document each property
320 # This is done because tags can not be safely put inside comments in HTML
321 documentProperties
= list(propertyDocuments
.keys())
322 sortListInsensitive(documentProperties
)
324 for k
in documentProperties
:
325 propertiesHTML
.append("\t<tr id='property-%s'>\n\t<td>%s</td>\n\t<td>%s</td>\n\t</tr>" %
326 (k
, k
, propertyDocuments
[k
]))
328 # Find all the SciTE properties files
329 otherProps
= ["abbrev.properties", "Embedded.properties", "SciTEGlobal.properties", "SciTE.properties"]
330 if os
.path
.exists(root
+ "scite"):
331 propFilePaths
= glob
.glob(root
+ "scite/src/*.properties")
332 sortListInsensitive(propFilePaths
)
333 propFiles
= [os
.path
.basename(f
) for f
in propFilePaths
if os
.path
.basename(f
) not in otherProps
]
334 sortListInsensitive(propFiles
)
337 Regenerate(root
+ "scintilla/src/Catalogue.cxx", "//", NATIVE
, lexerModules
)
338 Regenerate(root
+ "scintilla/win32/scintilla.mak", "#", NATIVE
, lexFiles
)
339 Regenerate(root
+ "scintilla/win32/scintilla_vc6.mak", "#", NATIVE
, lexFiles
)
340 if os
.path
.exists(root
+ "scite"):
341 Regenerate(root
+ "scite/win32/makefile", "#", NATIVE
, propFiles
)
342 Regenerate(root
+ "scite/win32/scite.mak", "#", NATIVE
, propFiles
)
343 Regenerate(root
+ "scite/src/SciTEProps.cxx", "//", NATIVE
, lexerProperties
)
344 Regenerate(root
+ "scite/doc/SciTEDoc.html", "<!--", NATIVE
, propertiesHTML
)
345 Generate(root
+ "scite/boundscheck/vcproj.gen",
346 root
+ "scite/boundscheck/SciTE.vcproj", "#", NATIVE
, lexFiles
)
348 UpdateVersionNumbers(root
)