Home | History | Annotate | Download | only in unstable
      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 FIXME: Not currently used in build.
     32 This is a rewrite of the Perl IDL compiler in Python, but is not complete.
     33 Once it is complete, we will switch all IDL files over to Python at once.
     34 Until then, please work on the Perl IDL compiler.
     35 For details, see bug http://crbug.com/239771
     36 """
     37 
     38 # FIXME: eliminate this file if possible
     39 
     40 import re
     41 
     42 from v8_globals import includes
     43 import v8_types
     44 
     45 ACRONYMS = ['CSS', 'HTML', 'IME', 'JS', 'SVG', 'URL', 'WOFF', 'XML', 'XSLT']
     46 
     47 
     48 # Extended attributes
     49 def extended_attribute_value_contains(extended_attribute_value, value):
     50     return (extended_attribute_value and
     51             value in re.split('[|&]', extended_attribute_value))
     52 
     53 
     54 def has_extended_attribute(definition_or_member, extended_attribute_list):
     55     return any(extended_attribute in definition_or_member.extended_attributes
     56                for extended_attribute in extended_attribute_list)
     57 
     58 
     59 def has_extended_attribute_value(definition_or_member, name, value):
     60     extended_attributes = definition_or_member.extended_attributes
     61     return (name in extended_attributes and
     62             extended_attribute_value_contains(extended_attributes[name], value))
     63 
     64 
     65 # String handling
     66 def capitalize(name):
     67     """Capitalize first letter or initial acronym (used in setter names)."""
     68     for acronym in ACRONYMS:
     69         if name.startswith(acronym.lower()):
     70             return name.replace(acronym.lower(), acronym)
     71     return name[0].upper() + name[1:]
     72 
     73 
     74 def strip_suffix(string, suffix):
     75     if not suffix or not string.endswith(suffix):
     76         return string
     77     return string[:-len(suffix)]
     78 
     79 
     80 def uncapitalize(name):
     81     """Uncapitalizes first letter or initial acronym (used in method names).
     82 
     83     E.g., 'SetURL' becomes 'setURL', but 'URLFoo' becomes 'urlFoo'.
     84     """
     85     for acronym in ACRONYMS:
     86         if name.startswith(acronym):
     87             name.replace(acronym, acronym.lower())
     88             return name
     89     return name[0].lower() + name[1:]
     90 
     91 
     92 # C++
     93 def enum_validation_expression(idl_type):
     94     if not v8_types.is_enum_type(idl_type):
     95         return None
     96     return ' || '.join(['string == "%s"' % enum_value
     97                         for enum_value in v8_types.enum_values(idl_type)])
     98 
     99 
    100 def scoped_name(interface, definition, base_name):
    101     if definition.is_static:
    102         return '%s::%s' % (interface.name, base_name)
    103     return 'imp->%s' % base_name
    104 
    105 
    106 def v8_class_name(interface):
    107     return v8_types.v8_type(interface.name)
    108 
    109 
    110 # [ActivityLogging]
    111 def activity_logging_world_list(member, access_type=None):
    112     """Returns a set of world suffixes for which a definition member has activity logging, for specified access type.
    113 
    114     access_type can be 'Getter' or 'Setter' if only checking getting or setting.
    115     """
    116     if 'ActivityLogging' not in member.extended_attributes:
    117         return set()
    118     activity_logging = member.extended_attributes['ActivityLogging']
    119     # [ActivityLogging=For*] (no prefix, starts with the worlds suffix) means
    120     # "log for all use (method)/access (attribute)", otherwise check that value
    121     # agrees with specified access_type (Getter/Setter).
    122     has_logging = (activity_logging.startswith('For') or
    123                    (access_type and activity_logging.startswith(access_type)))
    124     if not has_logging:
    125         return set()
    126     includes.add('bindings/v8/V8DOMActivityLogger.h')
    127     if activity_logging.endswith('ForIsolatedWorlds'):
    128         return set([''])
    129     return set(['', 'ForMainWorld'])  # endswith('ForAllWorlds')
    130 
    131 
    132 # [CallWith]
    133 CALL_WITH_ARGUMENTS = {
    134     'ScriptState': '&state',
    135     'ExecutionContext': 'scriptContext',
    136     'ScriptArguments': 'scriptArguments.release()',
    137     'ActiveWindow': 'activeDOMWindow()',
    138     'FirstWindow': 'firstDOMWindow()',
    139 }
    140 # List because key order matters, as we want arguments in deterministic order
    141 CALL_WITH_VALUES = [
    142     'ScriptState',
    143     'ExecutionContext',
    144     'ScriptArguments',
    145     'ActiveWindow',
    146     'FirstWindow',
    147 ]
    148 
    149 
    150 def call_with_arguments(member, call_with_values=None):
    151     # Optional parameter so setter can override with [SetterCallWith]
    152     call_with_values = call_with_values or member.extended_attributes.get('CallWith')
    153     if not call_with_values:
    154         return []
    155     return [CALL_WITH_ARGUMENTS[value]
    156             for value in CALL_WITH_VALUES
    157             if extended_attribute_value_contains(call_with_values, value)]
    158 
    159 
    160 # [Conditional]
    161 def conditional_string(definition_or_member):
    162     extended_attributes = definition_or_member.extended_attributes
    163     if 'Conditional' not in extended_attributes:
    164         return None
    165     conditional = extended_attributes['Conditional']
    166     for operator in '&|':
    167         if operator in conditional:
    168             conditions = conditional.split(operator)
    169             operator_separator = ' %s%s ' % (operator, operator)
    170             return operator_separator.join('ENABLE(%s)' % expression for expression in sorted(conditions))
    171     return 'ENABLE(%s)' % conditional
    172 
    173 
    174 # [DeprecateAs]
    175 def deprecate_as(member):
    176     extended_attributes = member.extended_attributes
    177     if 'DeprecateAs' not in extended_attributes:
    178         return None
    179     includes.add('core/frame/UseCounter.h')
    180     return extended_attributes['DeprecateAs']
    181 
    182 
    183 # [ImplementedAs]
    184 def cpp_name(definition_or_member):
    185     extended_attributes = definition_or_member.extended_attributes
    186     if 'ImplementedAs' not in extended_attributes:
    187         return definition_or_member.name
    188     return extended_attributes['ImplementedAs']
    189 
    190 
    191 # [MeasureAs]
    192 def measure_as(definition_or_member):
    193     extended_attributes = definition_or_member.extended_attributes
    194     if 'MeasureAs' not in extended_attributes:
    195         return None
    196     includes.add('core/frame/UseCounter.h')
    197     return extended_attributes['MeasureAs']
    198 
    199 
    200 # [PerContextEnabled]
    201 def per_context_enabled_function_name(definition_or_member):
    202     extended_attributes = definition_or_member.extended_attributes
    203     if 'PerContextEnabled' not in extended_attributes:
    204         return None
    205     feature_name = extended_attributes['PerContextEnabled']
    206     return 'ContextFeatures::%sEnabled' % uncapitalize(feature_name)
    207 
    208 
    209 # [RuntimeEnabled]
    210 def runtime_enabled_function_name(definition_or_member):
    211     """Returns the name of the RuntimeEnabledFeatures function.
    212 
    213     The returned function checks if a method/attribute is enabled.
    214     Given extended attribute RuntimeEnabled=FeatureName, return:
    215         RuntimeEnabledFeatures::{featureName}Enabled
    216     """
    217     extended_attributes = definition_or_member.extended_attributes
    218     if 'RuntimeEnabled' not in extended_attributes:
    219         return None
    220     feature_name = extended_attributes['RuntimeEnabled']
    221     return 'RuntimeEnabledFeatures::%sEnabled' % uncapitalize(feature_name)
    222