Rename Mutex to DeprecatedMutex
[WebKit-https.git] / Source / JavaScriptCore / 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|constructor)\s+\w+\s*\(.*?\)", re.MULTILINE | re.S)
68 functionNameRegExp = re.compile(r"(?:function|constructor)\s+(\w+)\s*\(", re.MULTILINE | re.S)
69 functionIsConstructorRegExp = re.compile(r"^constructor", re.MULTILINE | re.S)
70 functionParameterFinder = re.compile(r"^(?:function|constructor)\s+(?:\w+)\s*\(((?:\s*\w+)?\s*(?:\s*,\s*\w+)*)?\s*\)", re.MULTILINE | re.S)
71
72 multilineCommentRegExp = re.compile(r"\/\*.*?\*\/", re.MULTILINE | re.S)
73 singleLineCommentRegExp = re.compile(r"\/\/.*?\n", re.MULTILINE | re.S)
74
75 def getCopyright(source):
76     copyrightBlock = multilineCommentRegExp.findall(source)[0]
77     copyrightBlock = copyrightBlock[:copyrightBlock.index("Redistribution")]
78     copyRightLines = []
79
80     for line in copyrightBlock.split("\n"):
81         line = line.replace("/*", "")
82         line = line.replace("*/", "")
83         line = line.replace("*", "")
84         line = line.replace("Copyright", "")
85         line = line.replace("copyright", "")
86         line = line.replace("(C)", "")
87         line = line.replace("(c)", "")
88         line = line.strip()
89         if len(line) == 0:
90             continue
91
92         copyRightLines.append(line)
93     
94     return list(set(copyRightLines))
95
96 class Function(object):
97     def __init__(self, name, source, isConstructor, parameters):
98         self.name = name
99         self.source = source
100         self.isConstructor = isConstructor
101         self.parameters = parameters
102
103     def mangleName(self, object):
104         qName = object + "." + self.name
105         mangledName = ""
106         i = 0
107         while i < len(qName):
108             if qName[i] == '.':
109                 mangledName = mangledName + qName[i + 1].upper()
110                 i = i + 1
111             else:
112                 mangledName = mangledName + qName[i]
113             i = i + 1
114         if self.isConstructor:
115             mangledName = mangledName + "Constructor"
116         return mangledName
117
118 def getFunctions(source):
119
120     source = multilineCommentRegExp.sub("/**/", singleLineCommentRegExp.sub("//\n", source))
121
122     matches = [ f for f in functionHeadRegExp.finditer(source)]
123     functionBounds = []
124     start = 0
125     end = 0
126     for match in matches:
127         start = match.start()
128         if start < end:
129             continue
130         end = match.end()
131         while source[end] != '{':
132             end = end + 1
133         depth = 1
134         end = end + 1
135         while depth > 0:
136             if source[end] == '{':
137                 depth = depth + 1
138             elif source[end] == '}':
139                 depth = depth - 1
140             end = end + 1
141         functionBounds.append((start, end))
142
143     functions = [source[start:end].strip() for (start, end) in functionBounds]
144     result = []
145     for function in functions:
146         function = multilineCommentRegExp.sub("", function)
147         functionName = functionNameRegExp.findall(function)[0]
148         functionIsConstructor = functionIsConstructorRegExp.match(function) != None
149         functionParameters = functionParameterFinder.findall(function)[0].split(',')
150         if len(functionParameters[0]) == 0:
151             functionParameters = []
152
153         result.append(Function(functionName, function, functionIsConstructor, functionParameters))
154     return result
155
156
157 def generateCode(source):
158     inputFile = open(source, "r")
159     baseName = os.path.basename(source).replace(".js", "")
160     
161     source = ""
162     for line in inputFile:
163         source = source + line
164     
165     if sys.platform == "cygwin":
166         source = source.replace("\r\n", "\n")
167     return (baseName, getFunctions(source), getCopyright(source))
168
169 builtins = []
170 copyrights = []
171 (output_base, _) = os.path.splitext(args.output)
172
173 if args.input_directory:
174     for file in os.listdir(args.input_directory):
175         args.input_file.append(os.path.join(args.input_directory, file))
176
177 for file in args.input_file:
178     if fnmatch.fnmatch(file, '*.js'):
179         (baseName, functions, objectCopyrights) = generateCode(file)
180         copyrights.extend(objectCopyrights)
181         builtins.append((baseName, functions))
182
183 copyrights = list(set(copyrights))
184
185 copyrightBody = ""
186 for copyright in copyrights:
187     copyrightBody = copyrightBody +" * Copyright (C) " + copyright + "\n"
188
189 builtinsHeader = open(output_base + ".h.tmp", "w")
190 builtinsImplementation = open(output_base + ".cpp.tmp", "w")
191 copyrightText = "/*\n" + copyrightBody + copyrightText
192 builtinsHeader.write("""%s
193 %s
194
195 #ifndef JSCBuiltins_H
196 #define JSCBuiltins_H
197
198 #include "ConstructAbility.h"
199
200 namespace JSC {
201
202 class FunctionExecutable;
203 class Identifier;
204 class JSGlobalObject;
205 class SourceCode;
206 class UnlinkedFunctionExecutable;
207 class VM;
208
209 FunctionExecutable* createBuiltinExecutable(VM&, UnlinkedFunctionExecutable*, const SourceCode&);
210
211 """ % (generatorString, copyrightText))
212
213 codeReferences = []
214
215 for (objectName, functions) in builtins:
216     print("Generating bindings for the %s builtin." % objectName)
217     builtinsHeader.write("/* %s functions */\n" % objectName)
218     for function in functions:
219         name = function.name
220         mangledName = function.mangleName(objectName)
221         mangledName = mangledName[0].lower() + mangledName[1:] + "Code"
222         codeReferences.append((mangledName, function))
223         builtinsHeader.write("extern const char* s_%s;\n" % mangledName)
224         builtinsHeader.write("extern const int s_%sLength;\n" % mangledName)
225         builtinsHeader.write("extern const ConstructAbility s_%sConstructAbility;\n" % mangledName)
226     builtinsHeader.write("\n")
227     builtinsHeader.write("#define JSC_FOREACH_%s_BUILTIN(macro) \\\n" % objectName.replace(".", "_").upper())
228     for function in functions:
229         mangledName = function.mangleName(objectName)
230         builtinsHeader.write("    macro(%s, %s, %d) \\\n" % (function.name, mangledName, len(function.parameters)))
231     builtinsHeader.write("\n")
232     for function in functions:
233         builtinsHeader.write("#define JSC_BUILTIN_%s 1\n" % function.mangleName(objectName).upper())
234     builtinsHeader.write("\n\n")
235 names = []
236 builtinsHeader.write("#define JSC_FOREACH_BUILTIN(macro)\\\n")
237 for (codeReference, function) in codeReferences:
238     builtinsHeader.write("    macro(%s, %s, s_%sLength) \\\n" % (codeReference, function.name, codeReference))
239     names.append(function.name)
240
241 builtinsHeader.write("\n\n")
242 builtinsHeader.write("#define JSC_FOREACH_BUILTIN_FUNCTION_NAME(macro) \\\n")
243 for name in sorted(set(names)):
244     builtinsHeader.write("    macro(%s) \\\n" % name)
245 builtinsHeader.write("""
246
247 #define JSC_DECLARE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\
248     FunctionExecutable* codeName##Generator(VM&);
249
250 JSC_FOREACH_BUILTIN(JSC_DECLARE_BUILTIN_GENERATOR)
251 #undef JSC_DECLARE_BUILTIN_GENERATOR
252
253 #define JSC_BUILTIN_EXISTS(name) defined JSC_BUILTIN_ ## name
254
255 }
256
257 #endif
258
259 """)
260
261 builtinsImplementation.write("""%s
262 %s
263
264 #include "config.h"
265
266 #include "JSCBuiltins.h"
267
268 #include "BuiltinExecutables.h"
269 #include "ConstructAbility.h"
270 #include "Executable.h"
271 #include "JSCellInlines.h"
272 #include "VM.h"
273
274 namespace JSC {
275
276 """  % (generatorString, copyrightText))
277
278 for (codeReference, function) in codeReferences:
279     source = function.source
280     source = "(function " + source[source.index("("):] + ")"
281     lines = json.dumps(source)[1:-1].split("\\n")
282     sourceLength = len(source)
283     source = ""
284     for line in lines:
285         source = source + ("    \"%s\\n\" \\\n" % line)
286     builtinsImplementation.write("const char* s_%s =\n%s;\n\n" % (codeReference, source))
287     builtinsImplementation.write("const int s_%sLength = %d;\n\n" % (codeReference, sourceLength + 1)) # + 1 for \n
288     constructAbility = "ConstructAbility::CannotConstruct"
289     if function.isConstructor:
290         constructAbility = "ConstructAbility::CanConstruct"
291     builtinsImplementation.write("const ConstructAbility s_%sConstructAbility = %s;\n\n" % (codeReference, constructAbility)) # + 1 for \n
292
293 builtinsImplementation.write("""
294 #define JSC_DEFINE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\
295 FunctionExecutable* codeName##Generator(VM& vm) \\
296 { \\
297     return vm.builtinExecutables()->codeName##Executable()->link(vm, vm.builtinExecutables()->codeName##Source()); \\
298 }
299
300 JSC_FOREACH_BUILTIN(JSC_DEFINE_BUILTIN_GENERATOR)
301 #undef JSC_DEFINE_BUILTIN_GENERATOR
302 }
303
304 """)
305
306 builtinsHeader.close()
307 builtinsImplementation.close()
308
309 if (not os.path.exists(output_base + ".h")) or (not filecmp.cmp(output_base + ".h.tmp", output_base + ".h", shallow=False)):
310     if (os.path.exists(output_base + ".h")):
311         os.remove(output_base + ".h")
312     os.rename(output_base + ".h.tmp", output_base + ".h")
313 else:
314     os.remove(output_base + ".h.tmp")
315
316 if (not os.path.exists(output_base + ".cpp")) or (not filecmp.cmp(output_base + ".cpp.tmp", output_base + ".cpp", shallow=False)):
317     if (os.path.exists(output_base + ".cpp")):
318         os.remove(output_base + ".cpp")
319     os.rename(output_base + ".cpp.tmp", output_base + ".cpp")
320 else:
321     os.remove(output_base + ".cpp.tmp")