Home | History | Annotate | Download | only in scripts
      1 # Copyright (C) 2013 Google Inc. All rights reserved.
      2 #
      3 # Redistribution and use in source and binary forms, with or without
      4 # modification, are permitted provided that the following conditions are
      5 # met:
      6 #
      7 #     * Redistributions of source code must retain the above copyright
      8 # notice, this list of conditions and the following disclaimer.
      9 #     * Redistributions in binary form must reproduce the above
     10 # copyright notice, this list of conditions and the following disclaimer
     11 # in the documentation and/or other materials provided with the
     12 # distribution.
     13 #     * Neither the name of Google Inc. nor the names of its
     14 # contributors may be used to endorse or promote products derived from
     15 # this software without specific prior written permission.
     16 #
     17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 """Functions shared by various parts of the code generator.
     30 
     31 Extends IdlTypeBase type with |enum_validation_expression| property.
     32 
     33 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
     34 """
     35 
     36 import re
     37 
     38 from idl_types import IdlTypeBase
     39 import idl_types
     40 from v8_globals import includes
     41 import v8_types
     42 
     43 ACRONYMS = [
     44     'CSSOM',  # must come *before* CSS to match full acronym
     45     'CSS',
     46     'HTML',
     47     'IME',
     48     'JS',
     49     'SVG',
     50     'URL',
     51     'WOFF',
     52     'XML',
     53     'XSLT',
     54 ]
     55 
     56 
     57 ################################################################################
     58 # Extended attribute parsing
     59 ################################################################################
     60 
     61 def extended_attribute_value_contains(extended_attribute_value, key):
     62     return (extended_attribute_value == key or
     63             (isinstance(extended_attribute_value, list) and
     64              key in extended_attribute_value))
     65 
     66 
     67 def has_extended_attribute(definition_or_member, extended_attribute_list):
     68     return any(extended_attribute in definition_or_member.extended_attributes
     69                for extended_attribute in extended_attribute_list)
     70 
     71 
     72 def has_extended_attribute_value(definition_or_member, name, value):
     73     extended_attributes = definition_or_member.extended_attributes
     74     return (name in extended_attributes and
     75             extended_attribute_value_contains(extended_attributes[name], value))
     76 
     77 
     78 def extended_attribute_value_as_list(definition_or_member, name):
     79     extended_attributes = definition_or_member.extended_attributes
     80     if name not in extended_attributes:
     81         return None
     82     value = extended_attributes[name]
     83     if isinstance(value, list):
     84         return value
     85     return [value]
     86 
     87 
     88 ################################################################################
     89 # String handling
     90 ################################################################################
     91 
     92 def capitalize(name):
     93     """Capitalize first letter or initial acronym (used in setter names)."""
     94     for acronym in ACRONYMS:
     95         if name.startswith(acronym.lower()):
     96             return name.replace(acronym.lower(), acronym)
     97     return name[0].upper() + name[1:]
     98 
     99 
    100 def strip_suffix(string, suffix):
    101     if not suffix or not string.endswith(suffix):
    102         return string
    103     return string[:-len(suffix)]
    104 
    105 
    106 def uncapitalize(name):
    107     """Uncapitalizes first letter or initial acronym (used in method names).
    108 
    109     E.g., 'SetURL' becomes 'setURL', but 'URLFoo' becomes 'urlFoo'.
    110     """
    111     for acronym in ACRONYMS:
    112         if name.startswith(acronym):
    113             return name.replace(acronym, acronym.lower())
    114     return name[0].lower() + name[1:]
    115 
    116 
    117 ################################################################################
    118 # C++
    119 ################################################################################
    120 
    121 def enum_validation_expression(idl_type):
    122     # FIXME: Add IdlEnumType, move property to derived type, and remove this check
    123     if not idl_type.is_enum:
    124         return None
    125     return ' || '.join(['string == "%s"' % enum_value
    126                         for enum_value in idl_type.enum_values])
    127 IdlTypeBase.enum_validation_expression = property(enum_validation_expression)
    128 
    129 
    130 def scoped_name(interface, definition, base_name):
    131     if 'ImplementedInPrivateScript' in definition.extended_attributes:
    132         return '%s::PrivateScript::%s' % (v8_class_name(interface), base_name)
    133     # partial interfaces are implemented as separate classes, with their members
    134     # implemented as static member functions
    135     partial_interface_implemented_as = definition.extended_attributes.get('PartialInterfaceImplementedAs')
    136     if partial_interface_implemented_as:
    137         return '%s::%s' % (partial_interface_implemented_as, base_name)
    138     if (definition.is_static or
    139         definition.name in ('Constructor', 'NamedConstructor')):
    140         return '%s::%s' % (cpp_name(interface), base_name)
    141     return 'impl->%s' % base_name
    142 
    143 
    144 def v8_class_name(interface):
    145     return v8_types.v8_type(interface.name)
    146 
    147 
    148 ################################################################################
    149 # Specific extended attributes
    150 ################################################################################
    151 
    152 # [ActivityLogging]
    153 def activity_logging_world_list(member, access_type=''):
    154     """Returns a set of world suffixes for which a definition member has activity logging, for specified access type.
    155 
    156     access_type can be 'Getter' or 'Setter' if only checking getting or setting.
    157     """
    158     extended_attributes = member.extended_attributes
    159     if 'LogActivity' not in extended_attributes:
    160         return set()
    161     log_activity = extended_attributes['LogActivity']
    162     if log_activity and not log_activity.startswith(access_type):
    163         return set()
    164 
    165     includes.add('bindings/core/v8/V8DOMActivityLogger.h')
    166     if 'LogAllWorlds' in extended_attributes:
    167         return set(['', 'ForMainWorld'])
    168     return set([''])  # At minimum, include isolated worlds.
    169 
    170 
    171 # [ActivityLogging]
    172 def activity_logging_world_check(member):
    173     """Returns if an isolated world check is required when generating activity
    174     logging code.
    175 
    176     The check is required when there is no per-world binding code and logging is
    177     required only for isolated world.
    178     """
    179     extended_attributes = member.extended_attributes
    180     if 'LogActivity' not in extended_attributes:
    181         return False
    182     if ('PerWorldBindings' not in extended_attributes and
    183         'LogAllWorlds' not in extended_attributes):
    184         return True
    185     return False
    186 
    187 
    188 # [CallWith]
    189 CALL_WITH_ARGUMENTS = {
    190     'ScriptState': 'scriptState',
    191     'ExecutionContext': 'executionContext',
    192     'ScriptArguments': 'scriptArguments.release()',
    193     'ActiveWindow': 'callingDOMWindow(info.GetIsolate())',
    194     'FirstWindow': 'enteredDOMWindow(info.GetIsolate())',
    195     'Document': 'document',
    196 }
    197 # List because key order matters, as we want arguments in deterministic order
    198 CALL_WITH_VALUES = [
    199     'ScriptState',
    200     'ExecutionContext',
    201     'ScriptArguments',
    202     'ActiveWindow',
    203     'FirstWindow',
    204     'Document',
    205 ]
    206 
    207 
    208 def call_with_arguments(call_with_values):
    209     if not call_with_values:
    210         return []
    211     return [CALL_WITH_ARGUMENTS[value]
    212             for value in CALL_WITH_VALUES
    213             if extended_attribute_value_contains(call_with_values, value)]
    214 
    215 
    216 # [Conditional]
    217 DELIMITER_TO_OPERATOR = {
    218     '|': '||',
    219     ',': '&&',
    220 }
    221 
    222 
    223 def conditional_string(definition_or_member):
    224     extended_attributes = definition_or_member.extended_attributes
    225     if 'Conditional' not in extended_attributes:
    226         return None
    227     return 'ENABLE(%s)' % extended_attributes['Conditional']
    228 
    229 
    230 # [DeprecateAs]
    231 def deprecate_as(member):
    232     extended_attributes = member.extended_attributes
    233     if 'DeprecateAs' not in extended_attributes:
    234         return None
    235     includes.add('core/frame/UseCounter.h')
    236     return extended_attributes['DeprecateAs']
    237 
    238 
    239 # [Exposed]
    240 EXPOSED_EXECUTION_CONTEXT_METHOD = {
    241     'DedicatedWorker': 'isDedicatedWorkerGlobalScope',
    242     'ServiceWorker': 'isServiceWorkerGlobalScope',
    243     'SharedWorker': 'isSharedWorkerGlobalScope',
    244     'Window': 'isDocument',
    245     'Worker': 'isWorkerGlobalScope',
    246 }
    247 
    248 
    249 def exposed(definition_or_member, interface):
    250     exposure_set = extended_attribute_value_as_list(definition_or_member, 'Exposed')
    251     if not exposure_set:
    252         return None
    253 
    254     interface_exposure_set = expanded_exposure_set_for_interface(interface)
    255 
    256     # Methods must not be exposed to a broader scope than their interface.
    257     if not set(exposure_set).issubset(interface_exposure_set):
    258         raise ValueError('Interface members\' exposure sets must be a subset of the interface\'s.')
    259 
    260     exposure_checks = []
    261     for environment in exposure_set:
    262         # Methods must be exposed on one of the scopes known to Blink.
    263         if environment not in EXPOSED_EXECUTION_CONTEXT_METHOD:
    264             raise ValueError('Values for the [Exposed] annotation must reflect to a valid exposure scope.')
    265 
    266         exposure_checks.append('context->%s()' % EXPOSED_EXECUTION_CONTEXT_METHOD[environment])
    267 
    268     return ' || '.join(exposure_checks)
    269 
    270 
    271 def expanded_exposure_set_for_interface(interface):
    272     exposure_set = extended_attribute_value_as_list(interface, 'Exposed')
    273 
    274     # "Worker" is an aggregation for the different kinds of workers.
    275     if 'Worker' in exposure_set:
    276         exposure_set.extend(('DedicatedWorker', 'SharedWorker', 'ServiceWorker'))
    277 
    278     return sorted(set(exposure_set))
    279 
    280 
    281 # [GarbageCollected], [WillBeGarbageCollected]
    282 def gc_type(definition):
    283     extended_attributes = definition.extended_attributes
    284     if 'GarbageCollected' in extended_attributes:
    285         return 'GarbageCollectedObject'
    286     elif 'WillBeGarbageCollected' in extended_attributes:
    287         return 'WillBeGarbageCollectedObject'
    288     return 'RefCountedObject'
    289 
    290 
    291 # [ImplementedAs]
    292 def cpp_name(definition_or_member):
    293     extended_attributes = definition_or_member.extended_attributes
    294     if 'ImplementedAs' not in extended_attributes:
    295         return definition_or_member.name
    296     return extended_attributes['ImplementedAs']
    297 
    298 
    299 # [MeasureAs]
    300 def measure_as(definition_or_member):
    301     extended_attributes = definition_or_member.extended_attributes
    302     if 'MeasureAs' not in extended_attributes:
    303         return None
    304     includes.add('core/frame/UseCounter.h')
    305     return extended_attributes['MeasureAs']
    306 
    307 
    308 # [PerContextEnabled]
    309 def per_context_enabled_function_name(definition_or_member):
    310     extended_attributes = definition_or_member.extended_attributes
    311     if 'PerContextEnabled' not in extended_attributes:
    312         return None
    313     feature_name = extended_attributes['PerContextEnabled']
    314     return 'ContextFeatures::%sEnabled' % uncapitalize(feature_name)
    315 
    316 
    317 # [RuntimeEnabled]
    318 def runtime_enabled_function_name(definition_or_member):
    319     """Returns the name of the RuntimeEnabledFeatures function.
    320 
    321     The returned function checks if a method/attribute is enabled.
    322     Given extended attribute RuntimeEnabled=FeatureName, return:
    323         RuntimeEnabledFeatures::{featureName}Enabled
    324     """
    325     extended_attributes = definition_or_member.extended_attributes
    326     if 'RuntimeEnabled' not in extended_attributes:
    327         return None
    328     feature_name = extended_attributes['RuntimeEnabled']
    329     return 'RuntimeEnabledFeatures::%sEnabled' % uncapitalize(feature_name)
    330