bburg@apple.com | a95212f | 2015-10-22 04:39:01 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # |
| 3 | # Copyright (c) 2014, 2015 Apple Inc. All rights reserved. |
| 4 | # Copyright (c) 2014 University of Washington. All rights reserved. |
| 5 | # |
| 6 | # Redistribution and use in source and binary forms, with or without |
| 7 | # modification, are permitted provided that the following conditions |
| 8 | # are met: |
| 9 | # 1. Redistributions of source code must retain the above copyright |
| 10 | # notice, this list of conditions and the following disclaimer. |
| 11 | # 2. Redistributions in binary form must reproduce the above copyright |
| 12 | # notice, this list of conditions and the following disclaimer in the |
| 13 | # documentation and/or other materials provided with the distribution. |
| 14 | # |
| 15 | # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| 17 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 18 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| 19 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 20 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 21 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 22 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 23 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 24 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| 25 | # THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | |
| 27 | import logging |
| 28 | import os.path |
| 29 | import re |
| 30 | from string import Template |
| 31 | import json |
| 32 | |
| 33 | from builtins_model import BuiltinFunction, BuiltinObject |
| 34 | from builtins_templates import BuiltinsGeneratorTemplates as Templates |
| 35 | |
| 36 | log = logging.getLogger('global') |
| 37 | |
| 38 | # These match WK_lcfirst and WK_ucfirst defined in CodeGenerator.pm. |
| 39 | def WK_lcfirst(str): |
| 40 | str = str[:1].lower() + str[1:] |
commit-queue@webkit.org | ac1e56e | 2016-07-25 06:28:35 +0000 | [diff] [blame] | 41 | str = str.replace('dOM', 'dom') |
bburg@apple.com | a95212f | 2015-10-22 04:39:01 +0000 | [diff] [blame] | 42 | str = str.replace('uRL', 'url') |
| 43 | str = str.replace('jS', 'js') |
| 44 | str = str.replace('xML', 'xml') |
| 45 | str = str.replace('xSLT', 'xslt') |
| 46 | str = str.replace('cSS', 'css') |
youenn.fablet@crf.canon.fr | 2f74c97 | 2015-12-11 07:45:09 +0000 | [diff] [blame] | 47 | str = str.replace('rTC', 'rtc') |
bburg@apple.com | a95212f | 2015-10-22 04:39:01 +0000 | [diff] [blame] | 48 | return str |
| 49 | |
| 50 | def WK_ucfirst(str): |
| 51 | str = str[:1].upper() + str[1:] |
| 52 | str = str.replace('Xml', 'XML') |
| 53 | str = str.replace('Svg', 'SVG') |
| 54 | return str |
| 55 | |
| 56 | class BuiltinsGenerator: |
| 57 | def __init__(self, model): |
| 58 | self._model = model |
| 59 | |
| 60 | def model(self): |
| 61 | return self._model |
| 62 | |
| 63 | # These methods are overridden by subclasses. |
| 64 | |
| 65 | def generate_output(self): |
| 66 | pass |
| 67 | |
| 68 | def output_filename(self): |
| 69 | pass |
| 70 | |
| 71 | |
| 72 | # Shared code generation methods. |
| 73 | def generate_license(self): |
| 74 | raw_license = Template(Templates.LicenseText).substitute(None) |
| 75 | copyrights = self._model.copyrights() |
| 76 | copyrights.sort() |
| 77 | |
| 78 | license_block = [] |
| 79 | license_block.append("/*") |
| 80 | for copyright in copyrights: |
| 81 | license_block.append(" * Copyright (c) %s" % copyright) |
| 82 | if len(copyrights) > 0: |
| 83 | license_block.append(" * ") |
| 84 | |
| 85 | for line in raw_license.split('\n'): |
| 86 | license_block.append(" * " + line) |
| 87 | |
| 88 | license_block.append(" */") |
| 89 | |
| 90 | return '\n'.join(license_block) |
| 91 | |
| 92 | def generate_includes_from_entries(self, entries): |
| 93 | includes = set() |
| 94 | for entry in entries: |
| 95 | (allowed_framework_names, data) = entry |
| 96 | (framework_name, header_path) = data |
| 97 | |
| 98 | if self.model().framework.name not in allowed_framework_names: |
| 99 | continue |
| 100 | if self.model().framework.name != framework_name: |
| 101 | includes.add("#include <%s>" % header_path) |
| 102 | else: |
| 103 | includes.add("#include \"%s\"" % os.path.basename(header_path)) |
| 104 | |
bburg@apple.com | 3e82ff0 | 2015-10-28 20:00:36 +0000 | [diff] [blame] | 105 | return sorted(list(includes)) |
bburg@apple.com | a95212f | 2015-10-22 04:39:01 +0000 | [diff] [blame] | 106 | |
bburg@apple.com | 3e82ff0 | 2015-10-28 20:00:36 +0000 | [diff] [blame] | 107 | def generate_primary_header_includes(self): |
| 108 | name, _ = os.path.splitext(self.output_filename()) |
| 109 | return '\n'.join([ |
| 110 | "#include \"config.h\"", |
| 111 | "#include \"%s.h\"" % name, |
| 112 | ]) |
bburg@apple.com | a95212f | 2015-10-22 04:39:01 +0000 | [diff] [blame] | 113 | |
| 114 | def generate_embedded_code_string_section_for_function(self, function): |
| 115 | text = function.function_source |
| 116 | # Wrap it in parens to avoid adding to global scope. |
| 117 | text = "(function " + text[text.index("("):] + ")" |
| 118 | embeddedSourceLength = len(text) + 1 # For extra \n. |
| 119 | # Lazy way to escape quotes, I think? |
| 120 | textLines = json.dumps(text)[1:-1].split("\\n") |
| 121 | # This looks scary because we need the JS source itself to have newlines. |
| 122 | embeddedSource = '\n'.join([' "%s\\n" \\' % line for line in textLines]) |
| 123 | |
| 124 | constructAbility = "CannotConstruct" |
| 125 | if function.is_constructor: |
| 126 | constructAbility = "CanConstruct" |
| 127 | |
| 128 | args = { |
| 129 | 'codeName': BuiltinsGenerator.mangledNameForFunction(function) + 'Code', |
| 130 | 'embeddedSource': embeddedSource, |
| 131 | 'embeddedSourceLength': embeddedSourceLength, |
sbarati@apple.com | 50b2572 | 2016-03-29 21:04:21 +0000 | [diff] [blame] | 132 | 'canConstruct': constructAbility, |
| 133 | 'intrinsic': function.intrinsic |
bburg@apple.com | a95212f | 2015-10-22 04:39:01 +0000 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | lines = [] |
| 137 | lines.append("const JSC::ConstructAbility s_%(codeName)sConstructAbility = JSC::ConstructAbility::%(canConstruct)s;" % args); |
| 138 | lines.append("const int s_%(codeName)sLength = %(embeddedSourceLength)d;" % args); |
sbarati@apple.com | 50b2572 | 2016-03-29 21:04:21 +0000 | [diff] [blame] | 139 | lines.append("static const JSC::Intrinsic s_%(codeName)sIntrinsic = JSC::%(intrinsic)s;" % args); |
bburg@apple.com | a95212f | 2015-10-22 04:39:01 +0000 | [diff] [blame] | 140 | lines.append("const char* s_%(codeName)s =\n%(embeddedSource)s\n;" % args); |
| 141 | return '\n'.join(lines) |
| 142 | |
| 143 | # Helper methods. |
| 144 | |
| 145 | @staticmethod |
commit-queue@webkit.org | d1ae659 | 2016-07-08 10:42:25 +0000 | [diff] [blame] | 146 | def wrap_with_guard(guard, text): |
| 147 | if not guard: |
| 148 | return text |
| 149 | return '\n'.join([ |
| 150 | '#if %s' % guard, |
| 151 | text, |
| 152 | '#endif // %s' % guard, |
| 153 | ]) |
| 154 | |
| 155 | @staticmethod |
bburg@apple.com | a95212f | 2015-10-22 04:39:01 +0000 | [diff] [blame] | 156 | def mangledNameForObject(object): |
| 157 | if not isinstance(object, BuiltinObject): |
| 158 | raise Exception("Invalid argument passed to mangledNameForObject()") |
| 159 | |
| 160 | def toCamel(match): |
| 161 | str = match.group(0) |
| 162 | return str[1].upper() |
| 163 | return re.sub(r'\.[a-z]', toCamel, object.object_name, flags=re.IGNORECASE) |
| 164 | |
| 165 | |
| 166 | @staticmethod |
| 167 | def mangledNameForFunction(function): |
| 168 | if not isinstance(function, BuiltinFunction): |
| 169 | raise Exception("Invalid argument passed to mangledNameForFunction()") |
| 170 | |
| 171 | function_name = WK_ucfirst(function.function_name) |
| 172 | |
| 173 | def toCamel(match): |
| 174 | str = match.group(0) |
| 175 | return str[1].upper() |
| 176 | function_name = re.sub(r'\.[a-z]', toCamel, function_name, flags=re.IGNORECASE) |
| 177 | if function.is_constructor: |
| 178 | function_name = function_name + "Constructor" |
| 179 | |
| 180 | object_name = BuiltinsGenerator.mangledNameForObject(function.object) |
| 181 | return WK_lcfirst(object_name + function_name) |