1 # Copyright (C) 2013 Google Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
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
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.
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.
29 """Functions shared by various parts of the code generator.
31 Extends IdlTypeBase type with |enum_validation_expression| property.
33 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
38 from idl_types import IdlTypeBase
40 from v8_globals import includes
44 'CSSOM', # must come *before* CSS to match full acronym
57 ################################################################################
58 # Extended attribute parsing
59 ################################################################################
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))
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)
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))
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:
82 value = extended_attributes[name]
83 if isinstance(value, list):
88 ################################################################################
90 ################################################################################
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:]
100 def strip_suffix(string, suffix):
101 if not suffix or not string.endswith(suffix):
103 return string[:-len(suffix)]
106 def uncapitalize(name):
107 """Uncapitalizes first letter or initial acronym (used in method names).
109 E.g., 'SetURL' becomes 'setURL', but 'URLFoo' becomes 'urlFoo'.
111 for acronym in ACRONYMS:
112 if name.startswith(acronym):
113 return name.replace(acronym, acronym.lower())
114 return name[0].lower() + name[1:]
117 ################################################################################
119 ################################################################################
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:
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)
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
144 def v8_class_name(interface):
145 return v8_types.v8_type(interface.name)
148 def v8_class_name_or_partial(interface):
149 class_name = v8_class_name(interface)
150 if interface.is_partial:
151 return ''.join([class_name, 'Partial'])
155 ################################################################################
156 # Specific extended attributes
157 ################################################################################
160 def activity_logging_world_list(member, access_type=''):
161 """Returns a set of world suffixes for which a definition member has activity logging, for specified access type.
163 access_type can be 'Getter' or 'Setter' if only checking getting or setting.
165 extended_attributes = member.extended_attributes
166 if 'LogActivity' not in extended_attributes:
168 log_activity = extended_attributes['LogActivity']
169 if log_activity and not log_activity.startswith(access_type):
172 includes.add('bindings/core/v8/V8DOMActivityLogger.h')
173 if 'LogAllWorlds' in extended_attributes:
174 return set(['', 'ForMainWorld'])
175 return set(['']) # At minimum, include isolated worlds.
179 def activity_logging_world_check(member):
180 """Returns if an isolated world check is required when generating activity
183 The check is required when there is no per-world binding code and logging is
184 required only for isolated world.
186 extended_attributes = member.extended_attributes
187 if 'LogActivity' not in extended_attributes:
189 if ('PerWorldBindings' not in extended_attributes and
190 'LogAllWorlds' not in extended_attributes):
196 CALL_WITH_ARGUMENTS = {
197 'ScriptState': 'scriptState',
198 'ExecutionContext': 'executionContext',
199 'ScriptArguments': 'scriptArguments.release()',
200 'ActiveWindow': 'callingDOMWindow(info.GetIsolate())',
201 'FirstWindow': 'enteredDOMWindow(info.GetIsolate())',
202 'Document': 'document',
204 # List because key order matters, as we want arguments in deterministic order
215 def call_with_arguments(call_with_values):
216 if not call_with_values:
218 return [CALL_WITH_ARGUMENTS[value]
219 for value in CALL_WITH_VALUES
220 if extended_attribute_value_contains(call_with_values, value)]
224 DELIMITER_TO_OPERATOR = {
230 def conditional_string(definition_or_member):
231 extended_attributes = definition_or_member.extended_attributes
232 if 'Conditional' not in extended_attributes:
234 return 'ENABLE(%s)' % extended_attributes['Conditional']
238 def deprecate_as(member):
239 extended_attributes = member.extended_attributes
240 if 'DeprecateAs' not in extended_attributes:
242 includes.add('core/frame/UseCounter.h')
243 return extended_attributes['DeprecateAs']
247 EXPOSED_EXECUTION_CONTEXT_METHOD = {
248 'DedicatedWorker': 'isDedicatedWorkerGlobalScope',
249 'ServiceWorker': 'isServiceWorkerGlobalScope',
250 'SharedWorker': 'isSharedWorkerGlobalScope',
251 'Window': 'isDocument',
252 'Worker': 'isWorkerGlobalScope',
256 def exposed(definition_or_member, interface):
257 exposure_set = extended_attribute_value_as_list(definition_or_member, 'Exposed')
261 interface_exposure_set = expanded_exposure_set_for_interface(interface)
263 # Methods must not be exposed to a broader scope than their interface.
264 if not set(exposure_set).issubset(interface_exposure_set):
265 raise ValueError('Interface members\' exposure sets must be a subset of the interface\'s.')
268 for environment in exposure_set:
269 # Methods must be exposed on one of the scopes known to Blink.
270 if environment not in EXPOSED_EXECUTION_CONTEXT_METHOD:
271 raise ValueError('Values for the [Exposed] annotation must reflect to a valid exposure scope.')
273 exposure_checks.append('context->%s()' % EXPOSED_EXECUTION_CONTEXT_METHOD[environment])
275 return ' || '.join(exposure_checks)
278 def expanded_exposure_set_for_interface(interface):
279 exposure_set = extended_attribute_value_as_list(interface, 'Exposed')
281 # "Worker" is an aggregation for the different kinds of workers.
282 if 'Worker' in exposure_set:
283 exposure_set.extend(('DedicatedWorker', 'SharedWorker', 'ServiceWorker'))
285 return sorted(set(exposure_set))
288 # [GarbageCollected], [WillBeGarbageCollected]
289 def gc_type(definition):
290 extended_attributes = definition.extended_attributes
291 if 'GarbageCollected' in extended_attributes:
292 return 'GarbageCollectedObject'
293 elif 'WillBeGarbageCollected' in extended_attributes:
294 return 'WillBeGarbageCollectedObject'
295 return 'RefCountedObject'
299 def cpp_name(definition_or_member):
300 extended_attributes = definition_or_member.extended_attributes
301 if 'ImplementedAs' not in extended_attributes:
302 return definition_or_member.name
303 return extended_attributes['ImplementedAs']
306 def cpp_name_or_partial(interface):
307 cpp_class_name = cpp_name(interface)
308 if interface.is_partial:
309 return ''.join([cpp_class_name, 'Partial'])
310 return cpp_class_name
314 def measure_as(definition_or_member):
315 extended_attributes = definition_or_member.extended_attributes
316 if 'MeasureAs' not in extended_attributes:
318 includes.add('core/frame/UseCounter.h')
319 return extended_attributes['MeasureAs']
322 # [PerContextEnabled]
323 def per_context_enabled_function_name(definition_or_member):
324 extended_attributes = definition_or_member.extended_attributes
325 if 'PerContextEnabled' not in extended_attributes:
327 feature_name = extended_attributes['PerContextEnabled']
328 return 'ContextFeatures::%sEnabled' % uncapitalize(feature_name)
332 def runtime_enabled_function_name(definition_or_member):
333 """Returns the name of the RuntimeEnabledFeatures function.
335 The returned function checks if a method/attribute is enabled.
336 Given extended attribute RuntimeEnabled=FeatureName, return:
337 RuntimeEnabledFeatures::{featureName}Enabled
339 extended_attributes = definition_or_member.extended_attributes
340 if 'RuntimeEnabled' not in extended_attributes:
342 feature_name = extended_attributes['RuntimeEnabled']
343 return 'RuntimeEnabledFeatures::%sEnabled' % uncapitalize(feature_name)