| #!/usr/bin/python | 
 | # Copyright (C) 2014 Apple Inc. All rights reserved. | 
 | # | 
 | # Redistribution and use in source and binary forms, with or without | 
 | # modification, are permitted provided that the following conditions | 
 | # are met: | 
 | # 1. Redistributions of source code must retain the above copyright | 
 | #    notice, this list of conditions and the following disclaimer. | 
 | # 2. Redistributions in binary form must reproduce the above copyright | 
 | #    notice, this list of conditions and the following disclaimer in the | 
 | #    documentation and/or other materials provided with the distribution. | 
 | # | 
 | # THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
 | # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
 | # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 | import filecmp | 
 | import fnmatch | 
 | import os | 
 | import re | 
 | import shutil | 
 | import sys | 
 | import datetime | 
 | import json | 
 |  | 
 | copyrightText = """ * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer in the | 
 |  *    documentation and/or other materials provided with the distribution. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
 |  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
 |  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
 |  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
 |  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
 |  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
 |  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
 |  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
 |  */\n | 
 | """ | 
 |  | 
 | generatorString = "/* Generated by %s do not hand edit. */\n" % os.path.basename(__file__) | 
 |  | 
 | functionHeadRegExp = re.compile(r"function\s+\w+\s*\(.*?\)", re.MULTILINE | re.S) | 
 | functionNameRegExp = re.compile(r"function\s+(\w+)\s*\(", re.MULTILINE | re.S) | 
 | functionParameterFinder = re.compile(r"^function\s+(?:\w+)\s*\(((?:\s*\w+)?\s*(?:\s*,\s*\w+)*)?\)", re.MULTILINE | re.S) | 
 |  | 
 | multilineCommentRegExp = re.compile(r"\/\*.*?\*\/", re.MULTILINE | re.S) | 
 | singleLineCommentRegExp = re.compile(r"\/\/.*?\n", re.MULTILINE | re.S) | 
 |  | 
 | def getCopyright(source): | 
 |     copyrightBlock = multilineCommentRegExp.findall(source)[0] | 
 |     copyrightBlock = copyrightBlock[:copyrightBlock.index("Redistribution")] | 
 |     copyRightLines = [] | 
 |  | 
 |     for line in copyrightBlock.split("\n"): | 
 |         line = line.replace("/*", "") | 
 |         line = line.replace("*/", "") | 
 |         line = line.replace("*", "") | 
 |         line = line.replace("Copyright", "") | 
 |         line = line.replace("copyright", "") | 
 |         line = line.replace("(C)", "") | 
 |         line = line.replace("(c)", "") | 
 |         line = line.strip() | 
 |         if len(line) == 0: | 
 |             continue | 
 |  | 
 |         copyRightLines.append(line) | 
 |      | 
 |     return list(set(copyRightLines)) | 
 |  | 
 |  | 
 |  | 
 | def getFunctions(source): | 
 |  | 
 |     source = multilineCommentRegExp.sub("/**/", singleLineCommentRegExp.sub("//\n", source)) | 
 |  | 
 |     matches = [ f for f in functionHeadRegExp.finditer(source)] | 
 |     functionBounds = [] | 
 |     start = 0 | 
 |     end = 0 | 
 |     for match in matches: | 
 |         start = match.start() | 
 |         if start < end: | 
 |             continue | 
 |         end = match.end() | 
 |         while source[end] != '{': | 
 |             end = end + 1 | 
 |         depth = 1 | 
 |         end = end + 1 | 
 |         while depth > 0: | 
 |             if source[end] == '{': | 
 |                 depth = depth + 1 | 
 |             elif source[end] == '}': | 
 |                 depth = depth - 1 | 
 |             end = end + 1 | 
 |         functionBounds.append((start, end)) | 
 |  | 
 |     functions = [source[start:end].strip() for (start, end) in functionBounds] | 
 |     result = [] | 
 |     for function in functions: | 
 |         function = multilineCommentRegExp.sub("", function) | 
 |         functionName = functionNameRegExp.findall(function)[0] | 
 |         functionParameters = functionParameterFinder.findall(function)[0].split(',') | 
 |         if len(functionParameters[0]) == 0: | 
 |             functionParameters = [] | 
 |              | 
 |         result.append((functionName, function, functionParameters)) | 
 |     return result | 
 |          | 
 |  | 
 | def generateCode(source): | 
 |     inputFile = open(source, "r") | 
 |     baseName = os.path.basename(source).replace(".js", "") | 
 |      | 
 |     source = "" | 
 |     for line in inputFile: | 
 |         source = source + line | 
 |      | 
 |     if sys.platform == "cygwin": | 
 |         source = source.replace("\r\n", "\n") | 
 |     return (baseName, getFunctions(source), getCopyright(source)) | 
 |  | 
 | def mangleName(object, name): | 
 |     qName = object + "." + name | 
 |     mangledName = "" | 
 |     i = 0 | 
 |     while i < len(qName): | 
 |         if qName[i] == '.': | 
 |             mangledName = mangledName + qName[i + 1].upper() | 
 |             i = i + 1 | 
 |         else: | 
 |             mangledName = mangledName + qName[i] | 
 |         i = i + 1 | 
 |     return mangledName | 
 |  | 
 | builtins = [] | 
 |  | 
 | baseName = sys.argv[-1] | 
 | builtin_definitions = sys.argv[1:-1] | 
 | (output_base, _) = os.path.splitext(sys.argv[-1]) | 
 |  | 
 | copyrights = [] | 
 | for file in builtin_definitions: | 
 |     if fnmatch.fnmatch(file, '*.js'): | 
 |         (baseName, functions, objectCopyrights) = generateCode(file) | 
 |         copyrights.extend(objectCopyrights) | 
 |         builtins.append((baseName, functions)) | 
 |  | 
 | copyrights = list(set(copyrights)) | 
 |  | 
 | copyrightBody = "" | 
 | for copyright in copyrights: | 
 |     copyrightBody = copyrightBody +" * Copyright (C) " + copyright + "\n" | 
 |  | 
 | builtinsHeader = open(output_base + ".h.tmp", "w") | 
 | builtinsImplementation = open(output_base + ".cpp.tmp", "w") | 
 | copyrightText = "/*\n" + copyrightBody + copyrightText | 
 | builtinsHeader.write("""%s | 
 | %s | 
 |  | 
 | #ifndef JSCBuiltins_H | 
 | #define JSCBuiltins_H | 
 |  | 
 | namespace JSC { | 
 |  | 
 | class FunctionExecutable; | 
 | class Identifier; | 
 | class JSGlobalObject; | 
 | class SourceCode; | 
 | class UnlinkedFunctionExecutable; | 
 | class VM; | 
 |  | 
 | FunctionExecutable* createBuiltinExecutable(VM&, UnlinkedFunctionExecutable*, const SourceCode&); | 
 |  | 
 | """ % (generatorString, copyrightText)) | 
 |  | 
 | codeReferences = [] | 
 |  | 
 | for (objectName, functions) in builtins: | 
 |     print("Generating bindings for the %s builtin." % objectName) | 
 |     builtinsHeader.write("/* %s functions */\n" % objectName) | 
 |     for (name, implementation, _) in functions: | 
 |         mangledName = mangleName(objectName, name) | 
 |         mangledName = mangledName[0].lower() + mangledName[1:] + "Code" | 
 |         codeReferences.append((mangledName, name, implementation)) | 
 |         builtinsHeader.write("extern const char* s_%s;\n" % mangledName) | 
 |         builtinsHeader.write("extern const int s_%sLength;\n" % mangledName) | 
 |     builtinsHeader.write("\n") | 
 |     builtinsHeader.write("#define JSC_FOREACH_%s_BUILTIN(macro) \\\n" % objectName.replace(".", "_").upper()) | 
 |     for (name, implementation, arguments) in functions: | 
 |         mangledName = mangleName(objectName, name) | 
 |         builtinsHeader.write("    macro(%s, %s, %d) \\\n" % (name, mangledName, len(arguments))) | 
 |     builtinsHeader.write("\n") | 
 |     for (name, implementation, arguments) in functions: | 
 |         builtinsHeader.write("#define JSC_BUILTIN_%s 1\n" % mangleName(objectName, name).upper()) | 
 |     builtinsHeader.write("\n\n") | 
 | names = [] | 
 | builtinsHeader.write("#define JSC_FOREACH_BUILTIN(macro)\\\n") | 
 | for (codeReference, functionName, source) in codeReferences: | 
 |     builtinsHeader.write("    macro(%s, %s, s_%sLength) \\\n" % (codeReference, functionName, codeReference)) | 
 |     names.append(functionName) | 
 |  | 
 | builtinsHeader.write("\n\n") | 
 | builtinsHeader.write("#define JSC_FOREACH_BUILTIN_FUNCTION_NAME(macro) \\\n") | 
 | for name in sorted(set(names)): | 
 |     builtinsHeader.write("    macro(%s) \\\n" % name) | 
 | builtinsHeader.write(""" | 
 |  | 
 | #define JSC_DECLARE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\ | 
 |     FunctionExecutable* codeName##Generator(VM&); | 
 |  | 
 | JSC_FOREACH_BUILTIN(JSC_DECLARE_BUILTIN_GENERATOR) | 
 | #undef JSC_DECLARE_BUILTIN_GENERATOR | 
 |  | 
 | #define JSC_BUILTIN_EXISTS(name) defined JSC_BUILTIN_ ## name | 
 |  | 
 | } | 
 |  | 
 | #endif | 
 |  | 
 | """) | 
 |  | 
 | builtinsImplementation.write("""%s | 
 | %s | 
 |  | 
 | #include "config.h" | 
 |  | 
 | #include "JSCBuiltins.h" | 
 |  | 
 | #include "BuiltinExecutables.h" | 
 | #include "Executable.h" | 
 | #include "JSCellInlines.h" | 
 | #include "VM.h" | 
 |  | 
 | namespace JSC { | 
 |  | 
 | """  % (generatorString, copyrightText)) | 
 |  | 
 | for (codeReference, name, source) in codeReferences: | 
 |     source = "(function " + source[source.index("("):] + ")" | 
 |     lines = json.dumps(source)[1:-1].split("\\n") | 
 |     sourceLength = len(source) | 
 |     source = "" | 
 |     for line in lines: | 
 |         source = source + ("    \"%s\\n\" \\\n" % line) | 
 |     builtinsImplementation.write("const char* s_%s =\n%s;\n\n" % (codeReference, source)) | 
 |     builtinsImplementation.write("const int s_%sLength = %d;\n\n" % (codeReference, sourceLength + 1)) # + 1 for \n | 
 |  | 
 | builtinsImplementation.write(""" | 
 | FunctionExecutable* createBuiltinExecutable(VM& vm, UnlinkedFunctionExecutable* unlinkedExecutable, const SourceCode& source) | 
 | { | 
 |     unsigned lineCount = unlinkedExecutable->lineCount(); | 
 |     unsigned startColumn = 1; | 
 |     unsigned sourceLength = unlinkedExecutable->sourceLength(); | 
 |     bool endColumnIsOnStartLine = !lineCount; | 
 |     unsigned endColumnExcludingBraces = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? 0 : 1); | 
 |     unsigned startOffset = unlinkedExecutable->startOffset(); | 
 |     unsigned startOffsetExcludingOpenBrace = startOffset + 1; | 
 |     unsigned endOffsetExcludingCloseBrace = startOffset + sourceLength - 1; | 
 |     SourceCode bodySource(source.provider(), startOffsetExcludingOpenBrace, endOffsetExcludingCloseBrace, 0, startColumn); | 
 |     return FunctionExecutable::create(vm, bodySource, unlinkedExecutable, 0, lineCount, startColumn, endColumnExcludingBraces, false); | 
 | } | 
 |  | 
 | #define JSC_DEFINE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\ | 
 | FunctionExecutable* codeName##Generator(VM& vm) \\ | 
 | { \\ | 
 |     return createBuiltinExecutable(vm, vm.builtinExecutables()->codeName##Executable(), vm.builtinExecutables()->codeName##Source()); \\ | 
 | } | 
 |  | 
 | JSC_FOREACH_BUILTIN(JSC_DEFINE_BUILTIN_GENERATOR) | 
 | #undef JSC_DEFINE_BUILTIN_GENERATOR | 
 | } | 
 |  | 
 | """) | 
 |  | 
 | builtinsHeader.close() | 
 | builtinsImplementation.close() | 
 |  | 
 | if (not os.path.exists(output_base + ".h")) or (not filecmp.cmp(output_base + ".h.tmp", output_base + ".h", shallow=False)): | 
 |     os.rename(output_base + ".h.tmp", output_base + ".h") | 
 | else: | 
 |     os.remove(output_base + ".h.tmp") | 
 |  | 
 | if (not os.path.exists(output_base + ".cpp")) or (not filecmp.cmp(output_base + ".cpp.tmp", output_base + ".cpp", shallow=False)): | 
 |     os.rename(output_base + ".cpp.tmp", output_base + ".cpp") | 
 | else: | 
 |     os.remove(output_base + ".cpp.tmp") |