]>
git.saurik.com Git - apple/javascriptcore.git/blob - generate-js-builtins
2 # Copyright (C) 2014 Apple Inc. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
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.
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.
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()
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
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.
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.
65 generatorString
= "/* Generated by %s do not hand edit. */\n" % os
.path
.basename(__file__
)
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
)
71 multilineCommentRegExp
= re
.compile(r
"\/\*.*?\*\/", re
.MULTILINE | re
.S
)
72 singleLineCommentRegExp
= re
.compile(r
"\/\/.*?\n", re
.MULTILINE | re
.S
)
74 def getCopyright(source
):
75 copyrightBlock
= multilineCommentRegExp
.findall(source
)[0]
76 copyrightBlock
= copyrightBlock
[:copyrightBlock
.index("Redistribution")]
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)", "")
91 copyRightLines
.append(line
)
93 return list(set(copyRightLines
))
97 def getFunctions(source
):
99 source
= multilineCommentRegExp
.sub("/**/", singleLineCommentRegExp
.sub("//\n", source
))
101 matches
= [ f
for f
in functionHeadRegExp
.finditer(source
)]
105 for match
in matches
:
106 start
= match
.start()
110 while source
[end
] != '{':
115 if source
[end
] == '{':
117 elif source
[end
] == '}':
120 functionBounds
.append((start
, end
))
122 functions
= [source
[start
:end
].strip() for (start
, end
) in functionBounds
]
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
= []
131 result
.append((functionName
, function
, functionParameters
))
135 def generateCode(source
):
136 inputFile
= open(source
, "r")
137 baseName
= os
.path
.basename(source
).replace(".js", "")
140 for line
in inputFile
:
141 source
= source
+ line
143 if sys
.platform
== "cygwin":
144 source
= source
.replace("\r\n", "\n")
145 return (baseName
, getFunctions(source
), getCopyright(source
))
147 def mangleName(object, name
):
148 qName
= object + "." + name
151 while i
< len(qName
):
153 mangledName
= mangledName
+ qName
[i
+ 1].upper()
156 mangledName
= mangledName
+ qName
[i
]
162 (output_base
, _
) = os
.path
.splitext(args
.output
)
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))
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
))
174 copyrights
= list(set(copyrights
))
177 for copyright
in copyrights
:
178 copyrightBody
= copyrightBody
+" * Copyright (C) " + copyright
+ "\n"
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
186 #ifndef JSCBuiltins_H
187 #define JSCBuiltins_H
191 class FunctionExecutable;
193 class JSGlobalObject;
195 class UnlinkedFunctionExecutable;
198 FunctionExecutable* createBuiltinExecutable(VM&, UnlinkedFunctionExecutable*, const SourceCode&);
200 """ % (generatorString
, copyrightText
))
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")
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
)
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("""
234 #define JSC_DECLARE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\
235 FunctionExecutable* codeName##Generator(VM&);
237 JSC_FOREACH_BUILTIN(JSC_DECLARE_BUILTIN_GENERATOR)
238 #undef JSC_DECLARE_BUILTIN_GENERATOR
240 #define JSC_BUILTIN_EXISTS(name) defined JSC_BUILTIN_ ## name
248 builtinsImplementation
.write("""%s
253 #include "JSCBuiltins.h"
255 #include "BuiltinExecutables.h"
256 #include "Executable.h"
257 #include "JSCellInlines.h"
262 """ % (generatorString
, copyrightText
))
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
)
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
274 builtinsImplementation
.write("""
275 #define JSC_DEFINE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\
276 FunctionExecutable* codeName##Generator(VM& vm) \\
278 return vm.builtinExecutables()->codeName##Executable()->link(vm, vm.builtinExecutables()->codeName##Source()); \\
281 JSC_FOREACH_BUILTIN(JSC_DEFINE_BUILTIN_GENERATOR)
282 #undef JSC_DEFINE_BUILTIN_GENERATOR
287 builtinsHeader
.close()
288 builtinsImplementation
.close()
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")
295 os
.remove(output_base
+ ".h.tmp")
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")
302 os
.remove(output_base
+ ".cpp.tmp")