]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - generate-js-builtins
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / generate-js-builtins
diff --git a/generate-js-builtins b/generate-js-builtins
new file mode 100644 (file)
index 0000000..613a207
--- /dev/null
@@ -0,0 +1,304 @@
+#!/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")