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