#!/usr/bin/env python # # Copyright (c) 2014, 2015 Apple Inc. All rights reserved. # Copyright (c) 2014 University of Washington. 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. AND ITS CONTRIBUTORS ``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 ITS 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 logging import os.path import re from string import Template import json from builtins_model import BuiltinFunction, BuiltinObject from builtins_templates import BuiltinsGeneratorTemplates as Templates log = logging.getLogger('global') # These match WK_lcfirst and WK_ucfirst defined in CodeGenerator.pm. def WK_lcfirst(str): str = str[:1].lower() + str[1:] str = str.replace('dOM', 'dom') str = str.replace('uRL', 'url') str = str.replace('jS', 'js') str = str.replace('xML', 'xml') str = str.replace('xSLT', 'xslt') str = str.replace('cSS', 'css') str = str.replace('rTC', 'rtc') return str def WK_ucfirst(str): str = str[:1].upper() + str[1:] str = str.replace('Xml', 'XML') str = str.replace('Svg', 'SVG') return str class BuiltinsGenerator: def __init__(self, model): self._model = model def model(self): return self._model # These methods are overridden by subclasses. def generate_output(self): pass def output_filename(self): pass # Shared code generation methods. def generate_license(self): raw_license = Template(Templates.LicenseText).substitute(None) copyrights = self._model.copyrights() copyrights.sort() license_block = [] license_block.append("/*") for copyright in copyrights: license_block.append(" * Copyright (c) %s" % copyright) if len(copyrights) > 0: license_block.append(" * ") for line in raw_license.split('\n'): license_block.append(" * " + line) license_block.append(" */") return '\n'.join(license_block) def generate_includes_from_entries(self, entries): includes = set() for entry in entries: (allowed_framework_names, data) = entry (framework_name, header_path) = data if self.model().framework.name not in allowed_framework_names: continue if self.model().framework.name != framework_name: includes.add("#include <%s/%s>" % (framework_name, os.path.basename(header_path))) else: includes.add("#include \"%s\"" % os.path.basename(header_path)) return sorted(list(includes)) def generate_primary_header_includes(self): name, _ = os.path.splitext(self.output_filename()) return '\n'.join([ "#include \"config.h\"", "#include \"%s.h\"" % name, ]) def generate_embedded_code_string_section_for_function(self, function): text = function.function_source # Wrap it in parens to avoid adding to global scope. text = "(function " + text[text.index("("):] + ")" embeddedSourceLength = len(text) + 1 # For extra \n. # Lazy way to escape quotes, I think? textLines = json.dumps(text)[1:-1].split("\\n") # This looks scary because we need the JS source itself to have newlines. embeddedSource = '\n'.join([' "%s\\n" \\' % line for line in textLines]) constructAbility = "CannotConstruct" if function.is_constructor: constructAbility = "CanConstruct" args = { 'codeName': BuiltinsGenerator.mangledNameForFunction(function) + 'Code', 'embeddedSource': embeddedSource, 'embeddedSourceLength': embeddedSourceLength, 'canConstruct': constructAbility, 'intrinsic': function.intrinsic } lines = [] lines.append("const JSC::ConstructAbility s_%(codeName)sConstructAbility = JSC::ConstructAbility::%(canConstruct)s;" % args); lines.append("const int s_%(codeName)sLength = %(embeddedSourceLength)d;" % args); lines.append("static const JSC::Intrinsic s_%(codeName)sIntrinsic = JSC::%(intrinsic)s;" % args); lines.append("const char* s_%(codeName)s =\n%(embeddedSource)s\n;" % args); return '\n'.join(lines) # Helper methods. @staticmethod def wrap_with_guard(guard, text): if not guard: return text return '\n'.join([ '#if %s' % guard, text, '#endif // %s' % guard, ]) @staticmethod def mangledNameForObject(object): if not isinstance(object, BuiltinObject): raise Exception("Invalid argument passed to mangledNameForObject()") def toCamel(match): str = match.group(0) return str[1].upper() return re.sub(r'\.[a-z]', toCamel, object.object_name, flags=re.IGNORECASE) @staticmethod def mangledNameForFunction(function): if not isinstance(function, BuiltinFunction): raise Exception("Invalid argument passed to mangledNameForFunction()") function_name = WK_ucfirst(function.function_name) def toCamel(match): str = match.group(0) return str[1].upper() function_name = re.sub(r'\.[a-z]', toCamel, function_name, flags=re.IGNORECASE) if function.is_constructor: function_name = function_name + "Constructor" object_name = BuiltinsGenerator.mangledNameForObject(function.object) return WK_lcfirst(object_name + function_name)