| # Copyright (C) 2013 Google Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: |
| # |
| # * Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # * 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. |
| # * Neither the name of Google Inc. nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT |
| # OWNER OR 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. |
| |
| """Functions for type handling and type conversion (Blink/C++ <-> V8/JS). |
| |
| Extends IdlType and IdlUnionType with V8-specific properties, methods, and |
| class methods. |
| |
| Spec: |
| http://www.w3.org/TR/WebIDL/#es-type-mapping |
| |
| Design doc: http://www.chromium.org/developers/design-documents/idl-compiler |
| """ |
| |
| import posixpath |
| |
| from idl_types import IdlTypeBase, IdlType, IdlUnionType, IdlArrayOrSequenceType, IdlNullableType |
| import v8_attributes # for IdlType.constructor_type_name |
| from v8_globals import includes |
| |
| |
| ################################################################################ |
| # V8-specific handling of IDL types |
| ################################################################################ |
| |
| NON_WRAPPER_TYPES = frozenset([ |
| 'CompareHow', |
| 'NodeFilter', |
| 'SerializedScriptValue', |
| ]) |
| TYPED_ARRAYS = { |
| # (cpp_type, v8_type), used by constructor templates |
| 'ArrayBuffer': None, |
| 'ArrayBufferView': None, |
| 'Float32Array': ('float', 'v8::kExternalFloatArray'), |
| 'Float64Array': ('double', 'v8::kExternalDoubleArray'), |
| 'Int8Array': ('signed char', 'v8::kExternalByteArray'), |
| 'Int16Array': ('short', 'v8::kExternalShortArray'), |
| 'Int32Array': ('int', 'v8::kExternalIntArray'), |
| 'Uint8Array': ('unsigned char', 'v8::kExternalUnsignedByteArray'), |
| 'Uint8ClampedArray': ('unsigned char', 'v8::kExternalPixelArray'), |
| 'Uint16Array': ('unsigned short', 'v8::kExternalUnsignedShortArray'), |
| 'Uint32Array': ('unsigned int', 'v8::kExternalUnsignedIntArray'), |
| } |
| |
| IdlType.is_typed_array_element_type = property( |
| lambda self: self.base_type in TYPED_ARRAYS) |
| |
| IdlType.is_wrapper_type = property( |
| lambda self: (self.is_interface_type and |
| self.base_type not in NON_WRAPPER_TYPES)) |
| |
| |
| ################################################################################ |
| # C++ types |
| ################################################################################ |
| |
| CPP_TYPE_SAME_AS_IDL_TYPE = set([ |
| 'double', |
| 'float', |
| 'long long', |
| 'unsigned long long', |
| ]) |
| CPP_INT_TYPES = set([ |
| 'byte', |
| 'long', |
| 'short', |
| ]) |
| CPP_UNSIGNED_TYPES = set([ |
| 'octet', |
| 'unsigned int', |
| 'unsigned long', |
| 'unsigned short', |
| ]) |
| CPP_SPECIAL_CONVERSION_RULES = { |
| 'CompareHow': 'Range::CompareHow', |
| 'Date': 'double', |
| 'Promise': 'ScriptPromise', |
| 'ScriptValue': 'ScriptValue', |
| 'boolean': 'bool', |
| 'unrestricted double': 'double', |
| 'unrestricted float': 'float', |
| } |
| |
| |
| def cpp_type_initializer(idl_type): |
| """Returns a string containing a C++ initialization statement for the |
| corresponding type. |
| |
| |idl_type| argument is of type IdlType. |
| """ |
| |
| base_idl_type = idl_type.base_type |
| |
| if idl_type.native_array_element_type: |
| return '' |
| if idl_type.is_numeric_type: |
| return ' = 0' |
| if base_idl_type == 'boolean': |
| return ' = false' |
| if (base_idl_type in NON_WRAPPER_TYPES or |
| base_idl_type in CPP_SPECIAL_CONVERSION_RULES or |
| base_idl_type == 'any' or |
| idl_type.is_string_type or |
| idl_type.is_enum): |
| return '' |
| return ' = nullptr' |
| |
| |
| def cpp_type_union(idl_type, extended_attributes=None, raw_type=False): |
| # FIXME: Need to revisit the design of union support. |
| # http://crbug.com/240176 |
| return None |
| |
| |
| def cpp_type_initializer_union(idl_type): |
| return (member_type.cpp_type_initializer for member_type in idl_type.member_types) |
| |
| |
| # Allow access as idl_type.cpp_type if no arguments |
| IdlTypeBase.cpp_type_initializer = property(cpp_type_initializer) |
| IdlUnionType.cpp_type = property(cpp_type_union) |
| IdlUnionType.cpp_type_initializer = property(cpp_type_initializer_union) |
| IdlUnionType.cpp_type_args = cpp_type_union |
| |
| |
| IdlArrayOrSequenceType.native_array_element_type = property( |
| lambda self: self.element_type) |
| |
| |
| def cpp_template_type(template, inner_type): |
| """Returns C++ template specialized to type, with space added if needed.""" |
| if inner_type.endswith('>'): |
| format_string = '{template}<{inner_type} >' |
| else: |
| format_string = '{template}<{inner_type}>' |
| return format_string.format(template=template, inner_type=inner_type) |
| |
| |
| # [ImplementedAs] |
| # This handles [ImplementedAs] on interface types, not [ImplementedAs] in the |
| # interface being generated. e.g., given: |
| # Foo.idl: interface Foo {attribute Bar bar}; |
| # Bar.idl: [ImplementedAs=Zork] interface Bar {}; |
| # when generating bindings for Foo, the [ImplementedAs] on Bar is needed. |
| # This data is external to Foo.idl, and hence computed as global information in |
| # compute_interfaces_info.py to avoid having to parse IDLs of all used interfaces. |
| IdlType.implemented_as_interfaces = {} |
| |
| |
| def implemented_as(idl_type): |
| base_idl_type = idl_type.base_type |
| if base_idl_type in IdlType.implemented_as_interfaces: |
| return IdlType.implemented_as_interfaces[base_idl_type] |
| return base_idl_type |
| |
| |
| IdlType.implemented_as = property(implemented_as) |
| |
| IdlType.set_implemented_as_interfaces = classmethod( |
| lambda cls, new_implemented_as_interfaces: |
| cls.implemented_as_interfaces.update(new_implemented_as_interfaces)) |
| |
| |
| ################################################################################ |
| # Includes |
| ################################################################################ |
| |
| def includes_for_cpp_class(class_name, relative_dir_posix): |
| return set([posixpath.join('bindings', relative_dir_posix, class_name + '.h')]) |
| |
| |
| INCLUDES_FOR_TYPE = { |
| 'object': set(), |
| 'CompareHow': set(), |
| 'NodeList': set(['bindings/core/v8/V8NodeList.h', |
| 'core/dom/NodeList.h', |
| 'core/dom/StaticNodeList.h']), |
| 'Promise': set(['bindings/core/v8/ScriptPromise.h']), |
| 'SerializedScriptValue': set(['bindings/core/v8/SerializedScriptValue.h']), |
| 'ScriptValue': set(['bindings/core/v8/ScriptValue.h']), |
| } |
| |
| |
| def includes_for_type(idl_type): |
| idl_type = idl_type.preprocessed_type |
| |
| # Simple types |
| base_idl_type = idl_type.base_type |
| if base_idl_type in INCLUDES_FOR_TYPE: |
| return INCLUDES_FOR_TYPE[base_idl_type] |
| if idl_type.is_basic_type: |
| return set() |
| if idl_type.is_typed_array_element_type: |
| return set(['bindings/core/v8/custom/V8%sCustom.h' % base_idl_type]) |
| if base_idl_type.endswith('ConstructorConstructor'): |
| # FIXME: rename to NamedConstructor |
| # FIXME: replace with a [NamedConstructorAttribute] extended attribute |
| # Ending with 'ConstructorConstructor' indicates a named constructor, |
| # and these do not have header files, as they are part of the generated |
| # bindings for the interface |
| return set() |
| if base_idl_type.endswith('Constructor'): |
| # FIXME: replace with a [ConstructorAttribute] extended attribute |
| base_idl_type = idl_type.constructor_type_name |
| if base_idl_type not in component_dir: |
| return set() |
| return set(['bindings/%s/v8/V8%s.h' % (component_dir[base_idl_type], |
| base_idl_type)]) |
| |
| IdlType.includes_for_type = property(includes_for_type) |
| IdlUnionType.includes_for_type = property( |
| lambda self: set.union(*[member_type.includes_for_type |
| for member_type in self.member_types])) |
| IdlArrayOrSequenceType.includes_for_type = property( |
| lambda self: self.element_type.includes_for_type) |
| |
| |
| def add_includes_for_type(idl_type): |
| includes.update(idl_type.includes_for_type) |
| |
| IdlTypeBase.add_includes_for_type = add_includes_for_type |
| |
| |
| def includes_for_interface(interface_name): |
| return IdlType(interface_name).includes_for_type |
| |
| |
| def add_includes_for_interface(interface_name): |
| includes.update(includes_for_interface(interface_name)) |
| |
| |
| def impl_should_use_nullable_container(idl_type): |
| return not(idl_type.cpp_type_has_null_value) |
| |
| IdlTypeBase.impl_should_use_nullable_container = property( |
| impl_should_use_nullable_container) |
| |
| |
| def impl_includes_for_type(idl_type, interfaces_info): |
| includes_for_type = set() |
| if idl_type.impl_should_use_nullable_container: |
| includes_for_type.add('bindings/nullable.h') |
| |
| idl_type = idl_type.preprocessed_type |
| native_array_element_type = idl_type.native_array_element_type |
| if native_array_element_type: |
| includes_for_type.update(impl_includes_for_type( |
| native_array_element_type, interfaces_info)) |
| includes_for_type.add('wtf/Vector.h') |
| |
| if idl_type.is_string_type: |
| includes_for_type.add('wtf/text/WTFString.h') |
| if idl_type.name in interfaces_info: |
| interface_info = interfaces_info[idl_type.name] |
| includes_for_type.add(interface_info['include_path']) |
| return includes_for_type |
| |
| IdlTypeBase.impl_includes_for_type = impl_includes_for_type |
| |
| |
| component_dir = {} |
| |
| |
| def set_component_dirs(new_component_dirs): |
| component_dir.update(new_component_dirs) |
| |
| |
| ################################################################################ |
| # C++ -> V8 |
| ################################################################################ |
| |
| def preprocess_idl_type(idl_type): |
| if idl_type.is_enum: |
| # Enumerations are internally DOMStrings |
| return IdlType('DOMString') |
| if (idl_type.name == 'Any' or idl_type.is_callback_function): |
| return IdlType('ScriptValue') |
| return idl_type |
| |
| IdlTypeBase.preprocessed_type = property(preprocess_idl_type) |
| |
| |
| def preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes): |
| """Returns IDL type and value, with preliminary type conversions applied.""" |
| idl_type = idl_type.preprocessed_type |
| if idl_type.name == 'Promise': |
| idl_type = IdlType('ScriptValue') |
| if idl_type.base_type in ['long long', 'unsigned long long']: |
| # long long and unsigned long long are not representable in ECMAScript; |
| # we represent them as doubles. |
| is_nullable = idl_type.is_nullable |
| idl_type = IdlType('double') |
| if is_nullable: |
| idl_type = IdlNullableType(idl_type) |
| cpp_value = 'static_cast<double>(%s)' % cpp_value |
| return idl_type, cpp_value |
| |
| |
| IdlType.release = property(lambda self: self.is_interface_type) |
| IdlUnionType.release = property( |
| lambda self: [member_type.is_interface_type |
| for member_type in self.member_types]) |
| |
| |
| def literal_cpp_value(idl_type, idl_literal): |
| """Converts an expression that is a valid C++ literal for this type.""" |
| # FIXME: add validation that idl_type and idl_literal are compatible |
| literal_value = str(idl_literal) |
| if idl_type.base_type in CPP_UNSIGNED_TYPES: |
| return literal_value + 'u' |
| return literal_value |
| |
| IdlType.literal_cpp_value = literal_cpp_value |
| |
| |
| ################################################################################ |
| # Utility properties for nullable types |
| ################################################################################ |
| |
| |
| def cpp_type_has_null_value(idl_type): |
| # - String types (String/AtomicString) represent null as a null string, |
| # i.e. one for which String::isNull() returns true. |
| # - Wrapper types (raw pointer or RefPtr/PassRefPtr) represent null as |
| # a null pointer. |
| return (idl_type.is_string_type or idl_type.is_wrapper_type) |
| |
| IdlTypeBase.cpp_type_has_null_value = property(cpp_type_has_null_value) |
| |
| |
| def is_implicit_nullable(idl_type): |
| # Nullable type where the corresponding C++ type supports a null value. |
| return idl_type.is_nullable and idl_type.cpp_type_has_null_value |
| |
| |
| def is_explicit_nullable(idl_type): |
| # Nullable type that isn't implicit nullable (see above.) For such types, |
| # we use Nullable<T> or similar explicit ways to represent a null value. |
| return idl_type.is_nullable and not idl_type.is_implicit_nullable |
| |
| IdlTypeBase.is_implicit_nullable = property(is_implicit_nullable) |
| IdlUnionType.is_implicit_nullable = False |
| IdlTypeBase.is_explicit_nullable = property(is_explicit_nullable) |