]>
Commit | Line | Data |
---|---|---|
81345200 A |
1 | #!/usr/bin/python |
2 | # Copyright (C) 2014 Apple Inc. All rights reserved. | |
3 | # | |
4 | # Redistribution and use in source and binary forms, with or without | |
5 | # modification, are permitted provided that the following conditions | |
6 | # are met: | |
7 | # 1. Redistributions of source code must retain the above copyright | |
8 | # notice, this list of conditions and the following disclaimer. | |
9 | # 2. Redistributions in binary form must reproduce the above copyright | |
10 | # notice, this list of conditions and the following disclaimer in the | |
11 | # documentation and/or other materials provided with the distribution. | |
12 | # | |
13 | # THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
14 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
17 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 | # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | ||
25 | import filecmp | |
26 | import fnmatch | |
27 | import os | |
28 | import re | |
29 | import shutil | |
30 | import sys | |
31 | import datetime | |
32 | import json | |
33 | ||
34 | copyrightText = """ * | |
35 | * Redistribution and use in source and binary forms, with or without | |
36 | * modification, are permitted provided that the following conditions | |
37 | * are met: | |
38 | * 1. Redistributions of source code must retain the above copyright | |
39 | * notice, this list of conditions and the following disclaimer. | |
40 | * 2. Redistributions in binary form must reproduce the above copyright | |
41 | * notice, this list of conditions and the following disclaimer in the | |
42 | * documentation and/or other materials provided with the distribution. | |
43 | * | |
44 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
45 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
46 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
47 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
48 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
49 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
50 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
51 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
52 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
53 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
54 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
55 | */\n | |
56 | """ | |
57 | ||
58 | generatorString = "/* Generated by %s do not hand edit. */\n" % os.path.basename(__file__) | |
59 | ||
60 | functionHeadRegExp = re.compile(r"function\s+\w+\s*\(.*?\)", re.MULTILINE | re.S) | |
61 | functionNameRegExp = re.compile(r"function\s+(\w+)\s*\(", re.MULTILINE | re.S) | |
62 | functionParameterFinder = re.compile(r"^function\s+(?:\w+)\s*\(((?:\s*\w+)?\s*(?:\s*,\s*\w+)*)?\)", re.MULTILINE | re.S) | |
63 | ||
64 | multilineCommentRegExp = re.compile(r"\/\*.*?\*\/", re.MULTILINE | re.S) | |
65 | singleLineCommentRegExp = re.compile(r"\/\/.*?\n", re.MULTILINE | re.S) | |
66 | ||
67 | def getCopyright(source): | |
68 | copyrightBlock = multilineCommentRegExp.findall(source)[0] | |
69 | copyrightBlock = copyrightBlock[:copyrightBlock.index("Redistribution")] | |
70 | copyRightLines = [] | |
71 | ||
72 | for line in copyrightBlock.split("\n"): | |
73 | line = line.replace("/*", "") | |
74 | line = line.replace("*/", "") | |
75 | line = line.replace("*", "") | |
76 | line = line.replace("Copyright", "") | |
77 | line = line.replace("copyright", "") | |
78 | line = line.replace("(C)", "") | |
79 | line = line.replace("(c)", "") | |
80 | line = line.strip() | |
81 | if len(line) == 0: | |
82 | continue | |
83 | ||
84 | copyRightLines.append(line) | |
85 | ||
86 | return list(set(copyRightLines)) | |
87 | ||
88 | ||
89 | ||
90 | def getFunctions(source): | |
91 | ||
92 | source = multilineCommentRegExp.sub("/**/", singleLineCommentRegExp.sub("//\n", source)) | |
93 | ||
94 | matches = [ f for f in functionHeadRegExp.finditer(source)] | |
95 | functionBounds = [] | |
96 | start = 0 | |
97 | end = 0 | |
98 | for match in matches: | |
99 | start = match.start() | |
100 | if start < end: | |
101 | continue | |
102 | end = match.end() | |
103 | while source[end] != '{': | |
104 | end = end + 1 | |
105 | depth = 1 | |
106 | end = end + 1 | |
107 | while depth > 0: | |
108 | if source[end] == '{': | |
109 | depth = depth + 1 | |
110 | elif source[end] == '}': | |
111 | depth = depth - 1 | |
112 | end = end + 1 | |
113 | functionBounds.append((start, end)) | |
114 | ||
115 | functions = [source[start:end].strip() for (start, end) in functionBounds] | |
116 | result = [] | |
117 | for function in functions: | |
118 | function = multilineCommentRegExp.sub("", function) | |
119 | functionName = functionNameRegExp.findall(function)[0] | |
120 | functionParameters = functionParameterFinder.findall(function)[0].split(',') | |
121 | if len(functionParameters[0]) == 0: | |
122 | functionParameters = [] | |
123 | ||
124 | result.append((functionName, function, functionParameters)) | |
125 | return result | |
126 | ||
127 | ||
128 | def generateCode(source): | |
129 | inputFile = open(source, "r") | |
130 | baseName = os.path.basename(source).replace(".js", "") | |
131 | ||
132 | source = "" | |
133 | for line in inputFile: | |
134 | source = source + line | |
135 | ||
136 | if sys.platform == "cygwin": | |
137 | source = source.replace("\r\n", "\n") | |
138 | return (baseName, getFunctions(source), getCopyright(source)) | |
139 | ||
140 | def mangleName(object, name): | |
141 | qName = object + "." + name | |
142 | mangledName = "" | |
143 | i = 0 | |
144 | while i < len(qName): | |
145 | if qName[i] == '.': | |
146 | mangledName = mangledName + qName[i + 1].upper() | |
147 | i = i + 1 | |
148 | else: | |
149 | mangledName = mangledName + qName[i] | |
150 | i = i + 1 | |
151 | return mangledName | |
152 | ||
153 | builtins = [] | |
154 | ||
155 | baseName = sys.argv[-1] | |
156 | builtin_definitions = sys.argv[1:-1] | |
157 | (output_base, _) = os.path.splitext(sys.argv[-1]) | |
158 | ||
159 | copyrights = [] | |
160 | for file in builtin_definitions: | |
161 | if fnmatch.fnmatch(file, '*.js'): | |
162 | (baseName, functions, objectCopyrights) = generateCode(file) | |
163 | copyrights.extend(objectCopyrights) | |
164 | builtins.append((baseName, functions)) | |
165 | ||
166 | copyrights = list(set(copyrights)) | |
167 | ||
168 | copyrightBody = "" | |
169 | for copyright in copyrights: | |
170 | copyrightBody = copyrightBody +" * Copyright (C) " + copyright + "\n" | |
171 | ||
172 | builtinsHeader = open(output_base + ".h.tmp", "w") | |
173 | builtinsImplementation = open(output_base + ".cpp.tmp", "w") | |
174 | copyrightText = "/*\n" + copyrightBody + copyrightText | |
175 | builtinsHeader.write("""%s | |
176 | %s | |
177 | ||
178 | #ifndef JSCBuiltins_H | |
179 | #define JSCBuiltins_H | |
180 | ||
181 | namespace JSC { | |
182 | ||
183 | class FunctionExecutable; | |
184 | class Identifier; | |
185 | class JSGlobalObject; | |
186 | class SourceCode; | |
187 | class UnlinkedFunctionExecutable; | |
188 | class VM; | |
189 | ||
190 | FunctionExecutable* createBuiltinExecutable(VM&, UnlinkedFunctionExecutable*, const SourceCode&); | |
191 | ||
192 | """ % (generatorString, copyrightText)) | |
193 | ||
194 | codeReferences = [] | |
195 | ||
196 | for (objectName, functions) in builtins: | |
197 | print("Generating bindings for the %s builtin." % objectName) | |
198 | builtinsHeader.write("/* %s functions */\n" % objectName) | |
199 | for (name, implementation, _) in functions: | |
200 | mangledName = mangleName(objectName, name) | |
201 | mangledName = mangledName[0].lower() + mangledName[1:] + "Code" | |
202 | codeReferences.append((mangledName, name, implementation)) | |
203 | builtinsHeader.write("extern const char* s_%s;\n" % mangledName) | |
204 | builtinsHeader.write("extern const int s_%sLength;\n" % mangledName) | |
205 | builtinsHeader.write("\n") | |
206 | builtinsHeader.write("#define JSC_FOREACH_%s_BUILTIN(macro) \\\n" % objectName.replace(".", "_").upper()) | |
207 | for (name, implementation, arguments) in functions: | |
208 | mangledName = mangleName(objectName, name) | |
209 | builtinsHeader.write(" macro(%s, %s, %d) \\\n" % (name, mangledName, len(arguments))) | |
210 | builtinsHeader.write("\n") | |
211 | for (name, implementation, arguments) in functions: | |
212 | builtinsHeader.write("#define JSC_BUILTIN_%s 1\n" % mangleName(objectName, name).upper()) | |
213 | builtinsHeader.write("\n\n") | |
214 | names = [] | |
215 | builtinsHeader.write("#define JSC_FOREACH_BUILTIN(macro)\\\n") | |
216 | for (codeReference, functionName, source) in codeReferences: | |
217 | builtinsHeader.write(" macro(%s, %s, s_%sLength) \\\n" % (codeReference, functionName, codeReference)) | |
218 | names.append(functionName) | |
219 | ||
220 | builtinsHeader.write("\n\n") | |
221 | builtinsHeader.write("#define JSC_FOREACH_BUILTIN_FUNCTION_NAME(macro) \\\n") | |
222 | for name in sorted(set(names)): | |
223 | builtinsHeader.write(" macro(%s) \\\n" % name) | |
224 | builtinsHeader.write(""" | |
225 | ||
226 | #define JSC_DECLARE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\ | |
227 | FunctionExecutable* codeName##Generator(VM&); | |
228 | ||
229 | JSC_FOREACH_BUILTIN(JSC_DECLARE_BUILTIN_GENERATOR) | |
230 | #undef JSC_DECLARE_BUILTIN_GENERATOR | |
231 | ||
232 | #define JSC_BUILTIN_EXISTS(name) defined JSC_BUILTIN_ ## name | |
233 | ||
234 | } | |
235 | ||
236 | #endif | |
237 | ||
238 | """) | |
239 | ||
240 | builtinsImplementation.write("""%s | |
241 | %s | |
242 | ||
243 | #include "config.h" | |
244 | ||
245 | #include "JSCBuiltins.h" | |
246 | ||
247 | #include "BuiltinExecutables.h" | |
248 | #include "Executable.h" | |
249 | #include "JSCellInlines.h" | |
250 | #include "VM.h" | |
251 | ||
252 | namespace JSC { | |
253 | ||
254 | """ % (generatorString, copyrightText)) | |
255 | ||
256 | for (codeReference, name, source) in codeReferences: | |
257 | source = "(function " + source[source.index("("):] + ")" | |
258 | lines = json.dumps(source)[1:-1].split("\\n") | |
259 | sourceLength = len(source) | |
260 | source = "" | |
261 | for line in lines: | |
262 | source = source + (" \"%s\\n\" \\\n" % line) | |
263 | builtinsImplementation.write("const char* s_%s =\n%s;\n\n" % (codeReference, source)) | |
264 | builtinsImplementation.write("const int s_%sLength = %d;\n\n" % (codeReference, sourceLength + 1)) # + 1 for \n | |
265 | ||
266 | builtinsImplementation.write(""" | |
267 | FunctionExecutable* createBuiltinExecutable(VM& vm, UnlinkedFunctionExecutable* unlinkedExecutable, const SourceCode& source) | |
268 | { | |
269 | unsigned lineCount = unlinkedExecutable->lineCount(); | |
270 | unsigned startColumn = 1; | |
271 | unsigned sourceLength = unlinkedExecutable->sourceLength(); | |
272 | bool endColumnIsOnStartLine = !lineCount; | |
273 | unsigned endColumnExcludingBraces = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? 0 : 1); | |
274 | unsigned startOffset = unlinkedExecutable->startOffset(); | |
275 | unsigned startOffsetExcludingOpenBrace = startOffset + 1; | |
276 | unsigned endOffsetExcludingCloseBrace = startOffset + sourceLength - 1; | |
277 | SourceCode bodySource(source.provider(), startOffsetExcludingOpenBrace, endOffsetExcludingCloseBrace, 0, startColumn); | |
278 | return FunctionExecutable::create(vm, bodySource, unlinkedExecutable, 0, lineCount, startColumn, endColumnExcludingBraces, false); | |
279 | } | |
280 | ||
281 | #define JSC_DEFINE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\ | |
282 | FunctionExecutable* codeName##Generator(VM& vm) \\ | |
283 | { \\ | |
284 | return createBuiltinExecutable(vm, vm.builtinExecutables()->codeName##Executable(), vm.builtinExecutables()->codeName##Source()); \\ | |
285 | } | |
286 | ||
287 | JSC_FOREACH_BUILTIN(JSC_DEFINE_BUILTIN_GENERATOR) | |
288 | #undef JSC_DEFINE_BUILTIN_GENERATOR | |
289 | } | |
290 | ||
291 | """) | |
292 | ||
293 | builtinsHeader.close() | |
294 | builtinsImplementation.close() | |
295 | ||
296 | if (not os.path.exists(output_base + ".h")) or (not filecmp.cmp(output_base + ".h.tmp", output_base + ".h", shallow=False)): | |
297 | os.rename(output_base + ".h.tmp", output_base + ".h") | |
298 | else: | |
299 | os.remove(output_base + ".h.tmp") | |
300 | ||
301 | if (not os.path.exists(output_base + ".cpp")) or (not filecmp.cmp(output_base + ".cpp.tmp", output_base + ".cpp", shallow=False)): | |
302 | os.rename(output_base + ".cpp.tmp", output_base + ".cpp") | |
303 | else: | |
304 | os.remove(output_base + ".cpp.tmp") |