• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 for type handling and type conversion (Blink/C++ <-> V8/JS).
30
31Extends IdlType and IdlUnionType with V8-specific properties, methods, and
32class methods.
33
34Spec:
35http://www.w3.org/TR/WebIDL/#es-type-mapping
36
37Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
38"""
39
40import posixpath
41
42from idl_types import IdlTypeBase, IdlType, IdlUnionType, IdlArrayOrSequenceType, IdlNullableType
43import v8_attributes  # for IdlType.constructor_type_name
44from v8_globals import includes
45
46
47################################################################################
48# V8-specific handling of IDL types
49################################################################################
50
51NON_WRAPPER_TYPES = frozenset([
52    'Dictionary',
53    'EventHandler',
54    'EventListener',
55    'NodeFilter',
56    'SerializedScriptValue',
57])
58TYPED_ARRAYS = {
59    # (cpp_type, v8_type), used by constructor templates
60    'ArrayBuffer': None,
61    'ArrayBufferView': None,
62    'Float32Array': ('float', 'v8::kExternalFloatArray'),
63    'Float64Array': ('double', 'v8::kExternalDoubleArray'),
64    'Int8Array': ('signed char', 'v8::kExternalByteArray'),
65    'Int16Array': ('short', 'v8::kExternalShortArray'),
66    'Int32Array': ('int', 'v8::kExternalIntArray'),
67    'Uint8Array': ('unsigned char', 'v8::kExternalUnsignedByteArray'),
68    'Uint8ClampedArray': ('unsigned char', 'v8::kExternalPixelArray'),
69    'Uint16Array': ('unsigned short', 'v8::kExternalUnsignedShortArray'),
70    'Uint32Array': ('unsigned int', 'v8::kExternalUnsignedIntArray'),
71}
72
73IdlType.is_typed_array_element_type = property(
74    lambda self: self.base_type in TYPED_ARRAYS)
75
76IdlType.is_wrapper_type = property(
77    lambda self: (self.is_interface_type and
78                  self.base_type not in NON_WRAPPER_TYPES))
79
80
81################################################################################
82# C++ types
83################################################################################
84
85CPP_TYPE_SAME_AS_IDL_TYPE = set([
86    'double',
87    'float',
88    'long long',
89    'unsigned long long',
90])
91CPP_INT_TYPES = set([
92    'byte',
93    'long',
94    'short',
95])
96CPP_UNSIGNED_TYPES = set([
97    'octet',
98    'unsigned int',
99    'unsigned long',
100    'unsigned short',
101])
102CPP_SPECIAL_CONVERSION_RULES = {
103    'Date': 'double',
104    'Dictionary': 'Dictionary',
105    'EventHandler': 'EventListener*',
106    'NodeFilter': 'RefPtrWillBeRawPtr<NodeFilter>',
107    'Promise': 'ScriptPromise',
108    'ScriptValue': 'ScriptValue',
109    # FIXME: Eliminate custom bindings for XPathNSResolver  http://crbug.com/345529
110    'XPathNSResolver': 'RefPtrWillBeRawPtr<XPathNSResolver>',
111    'boolean': 'bool',
112    'unrestricted double': 'double',
113    'unrestricted float': 'float',
114}
115
116
117def cpp_type(idl_type, extended_attributes=None, raw_type=False, used_as_rvalue_type=False, used_as_variadic_argument=False, used_in_cpp_sequence=False):
118    """Returns C++ type corresponding to IDL type.
119
120    |idl_type| argument is of type IdlType, while return value is a string
121
122    Args:
123        idl_type:
124            IdlType
125        raw_type:
126            bool, True if idl_type's raw/primitive C++ type should be returned.
127        used_as_rvalue_type:
128            bool, True if the C++ type is used as an argument or the return
129            type of a method.
130        used_as_variadic_argument:
131            bool, True if the C++ type is used as a variadic argument of a method.
132        used_in_cpp_sequence:
133            bool, True if the C++ type is used as an element of a container.
134            Containers can be an array, a sequence or a dictionary.
135    """
136    def string_mode():
137        if extended_attributes.get('TreatNullAs') == 'EmptyString':
138            return 'TreatNullAsEmptyString'
139        if idl_type.is_nullable or extended_attributes.get('TreatNullAs') == 'NullString':
140            if extended_attributes.get('TreatUndefinedAs') == 'NullString':
141                return 'TreatNullAndUndefinedAsNullString'
142            return 'TreatNullAsNullString'
143        return ''
144
145    extended_attributes = extended_attributes or {}
146    idl_type = idl_type.preprocessed_type
147
148    # Array or sequence types
149    if used_as_variadic_argument:
150        native_array_element_type = idl_type
151    else:
152        native_array_element_type = idl_type.native_array_element_type
153    if native_array_element_type:
154        vector_type = cpp_ptr_type('Vector', 'HeapVector', native_array_element_type.gc_type)
155        vector_template_type = cpp_template_type(vector_type, native_array_element_type.cpp_type_args(used_in_cpp_sequence=True))
156        if used_as_rvalue_type:
157            return 'const %s&' % vector_template_type
158        return vector_template_type
159
160    # Simple types
161    base_idl_type = idl_type.base_type
162
163    if base_idl_type in CPP_TYPE_SAME_AS_IDL_TYPE:
164        return base_idl_type
165    if base_idl_type in CPP_INT_TYPES:
166        return 'int'
167    if base_idl_type in CPP_UNSIGNED_TYPES:
168        return 'unsigned'
169    if base_idl_type in CPP_SPECIAL_CONVERSION_RULES:
170        return CPP_SPECIAL_CONVERSION_RULES[base_idl_type]
171
172    if base_idl_type in NON_WRAPPER_TYPES:
173        return ('PassRefPtr<%s>' if used_as_rvalue_type else 'RefPtr<%s>') % base_idl_type
174    if idl_type.is_string_type:
175        if not raw_type:
176            return 'String'
177        return 'V8StringResource<%s>' % string_mode()
178
179    if idl_type.is_typed_array_element_type and raw_type:
180        return base_idl_type + '*'
181    if idl_type.is_interface_type:
182        implemented_as_class = idl_type.implemented_as
183        if raw_type:
184            return implemented_as_class + '*'
185        new_type = 'Member' if used_in_cpp_sequence else 'RawPtr'
186        ptr_type = cpp_ptr_type(('PassRefPtr' if used_as_rvalue_type else 'RefPtr'), new_type, idl_type.gc_type)
187        return cpp_template_type(ptr_type, implemented_as_class)
188    # Default, assume native type is a pointer with same type name as idl type
189    return base_idl_type + '*'
190
191
192def cpp_type_initializer(idl_type):
193    """Returns a string containing a C++ initialization statement for the
194    corresponding type.
195
196    |idl_type| argument is of type IdlType.
197    """
198
199    base_idl_type = idl_type.base_type
200
201    if idl_type.native_array_element_type:
202        return ''
203    if idl_type.is_numeric_type:
204        return ' = 0'
205    if base_idl_type == 'boolean':
206        return ' = false'
207    if (base_idl_type in NON_WRAPPER_TYPES or
208        base_idl_type in CPP_SPECIAL_CONVERSION_RULES or
209        base_idl_type == 'any' or
210        idl_type.is_string_type or
211        idl_type.is_enum):
212        return ''
213    return ' = nullptr'
214
215
216def cpp_type_union(idl_type, extended_attributes=None, raw_type=False):
217    # FIXME: Need to revisit the design of union support.
218    # http://crbug.com/240176
219    return None
220
221
222def cpp_type_initializer_union(idl_type):
223    return (member_type.cpp_type_initializer for member_type in idl_type.member_types)
224
225
226# Allow access as idl_type.cpp_type if no arguments
227IdlTypeBase.cpp_type = property(cpp_type)
228IdlTypeBase.cpp_type_initializer = property(cpp_type_initializer)
229IdlTypeBase.cpp_type_args = cpp_type
230IdlUnionType.cpp_type = property(cpp_type_union)
231IdlUnionType.cpp_type_initializer = property(cpp_type_initializer_union)
232IdlUnionType.cpp_type_args = cpp_type_union
233
234
235IdlArrayOrSequenceType.native_array_element_type = property(
236    lambda self: self.element_type)
237
238
239def cpp_template_type(template, inner_type):
240    """Returns C++ template specialized to type, with space added if needed."""
241    if inner_type.endswith('>'):
242        format_string = '{template}<{inner_type} >'
243    else:
244        format_string = '{template}<{inner_type}>'
245    return format_string.format(template=template, inner_type=inner_type)
246
247
248def cpp_ptr_type(old_type, new_type, gc_type):
249    if gc_type == 'GarbageCollectedObject':
250        return new_type
251    if gc_type == 'WillBeGarbageCollectedObject':
252        if old_type == 'Vector':
253            return 'WillBe' + new_type
254        return old_type + 'WillBe' + new_type
255    return old_type
256
257
258def v8_type(interface_name):
259    return 'V8' + interface_name
260
261
262# [ImplementedAs]
263# This handles [ImplementedAs] on interface types, not [ImplementedAs] in the
264# interface being generated. e.g., given:
265#   Foo.idl: interface Foo {attribute Bar bar};
266#   Bar.idl: [ImplementedAs=Zork] interface Bar {};
267# when generating bindings for Foo, the [ImplementedAs] on Bar is needed.
268# This data is external to Foo.idl, and hence computed as global information in
269# compute_interfaces_info.py to avoid having to parse IDLs of all used interfaces.
270IdlType.implemented_as_interfaces = {}
271
272
273def implemented_as(idl_type):
274    base_idl_type = idl_type.base_type
275    if base_idl_type in IdlType.implemented_as_interfaces:
276        return IdlType.implemented_as_interfaces[base_idl_type]
277    return base_idl_type
278
279
280IdlType.implemented_as = property(implemented_as)
281
282IdlType.set_implemented_as_interfaces = classmethod(
283    lambda cls, new_implemented_as_interfaces:
284        cls.implemented_as_interfaces.update(new_implemented_as_interfaces))
285
286
287# [GarbageCollected]
288IdlType.garbage_collected_types = set()
289
290IdlType.is_garbage_collected = property(
291    lambda self: self.base_type in IdlType.garbage_collected_types)
292
293IdlType.set_garbage_collected_types = classmethod(
294    lambda cls, new_garbage_collected_types:
295        cls.garbage_collected_types.update(new_garbage_collected_types))
296
297
298# [WillBeGarbageCollected]
299IdlType.will_be_garbage_collected_types = set()
300
301IdlType.is_will_be_garbage_collected = property(
302    lambda self: self.base_type in IdlType.will_be_garbage_collected_types)
303
304IdlType.set_will_be_garbage_collected_types = classmethod(
305    lambda cls, new_will_be_garbage_collected_types:
306        cls.will_be_garbage_collected_types.update(new_will_be_garbage_collected_types))
307
308
309def gc_type(idl_type):
310    if idl_type.is_garbage_collected:
311        return 'GarbageCollectedObject'
312    if idl_type.is_will_be_garbage_collected:
313        return 'WillBeGarbageCollectedObject'
314    return 'RefCountedObject'
315
316IdlTypeBase.gc_type = property(gc_type)
317
318
319################################################################################
320# Includes
321################################################################################
322
323def includes_for_cpp_class(class_name, relative_dir_posix):
324    return set([posixpath.join('bindings', relative_dir_posix, class_name + '.h')])
325
326
327INCLUDES_FOR_TYPE = {
328    'object': set(),
329    'Dictionary': set(['bindings/core/v8/Dictionary.h']),
330    'EventHandler': set(['bindings/core/v8/V8AbstractEventListener.h',
331                         'bindings/core/v8/V8EventListenerList.h']),
332    'EventListener': set(['bindings/core/v8/BindingSecurity.h',
333                          'bindings/core/v8/V8EventListenerList.h',
334                          'core/frame/LocalDOMWindow.h']),
335    'HTMLCollection': set(['bindings/core/v8/V8HTMLCollection.h',
336                           'core/dom/ClassCollection.h',
337                           'core/dom/TagCollection.h',
338                           'core/html/HTMLCollection.h',
339                           'core/html/HTMLDataListOptionsCollection.h',
340                           'core/html/HTMLFormControlsCollection.h',
341                           'core/html/HTMLTableRowsCollection.h']),
342    'NodeList': set(['bindings/core/v8/V8NodeList.h',
343                     'core/dom/NameNodeList.h',
344                     'core/dom/NodeList.h',
345                     'core/dom/StaticNodeList.h',
346                     'core/html/LabelsNodeList.h']),
347    'Promise': set(['bindings/core/v8/ScriptPromise.h']),
348    'SerializedScriptValue': set(['bindings/core/v8/SerializedScriptValue.h']),
349    'ScriptValue': set(['bindings/core/v8/ScriptValue.h']),
350}
351
352
353def includes_for_type(idl_type):
354    idl_type = idl_type.preprocessed_type
355
356    # Simple types
357    base_idl_type = idl_type.base_type
358    if base_idl_type in INCLUDES_FOR_TYPE:
359        return INCLUDES_FOR_TYPE[base_idl_type]
360    if idl_type.is_basic_type:
361        return set()
362    if idl_type.is_typed_array_element_type:
363        return set(['bindings/core/v8/custom/V8%sCustom.h' % base_idl_type])
364    if base_idl_type.endswith('ConstructorConstructor'):
365        # FIXME: rename to NamedConstructor
366        # FIXME: replace with a [NamedConstructorAttribute] extended attribute
367        # Ending with 'ConstructorConstructor' indicates a named constructor,
368        # and these do not have header files, as they are part of the generated
369        # bindings for the interface
370        return set()
371    if base_idl_type.endswith('Constructor'):
372        # FIXME: replace with a [ConstructorAttribute] extended attribute
373        base_idl_type = idl_type.constructor_type_name
374    if base_idl_type not in component_dir:
375        return set()
376    return set(['bindings/%s/v8/V8%s.h' % (component_dir[base_idl_type],
377                                           base_idl_type)])
378
379IdlType.includes_for_type = property(includes_for_type)
380IdlUnionType.includes_for_type = property(
381    lambda self: set.union(*[member_type.includes_for_type
382                             for member_type in self.member_types]))
383IdlArrayOrSequenceType.includes_for_type = property(
384    lambda self: self.element_type.includes_for_type)
385
386
387def add_includes_for_type(idl_type):
388    includes.update(idl_type.includes_for_type)
389
390IdlTypeBase.add_includes_for_type = add_includes_for_type
391
392
393def includes_for_interface(interface_name):
394    return IdlType(interface_name).includes_for_type
395
396
397def add_includes_for_interface(interface_name):
398    includes.update(includes_for_interface(interface_name))
399
400
401def impl_should_use_nullable_container(idl_type):
402    return not(idl_type.cpp_type_has_null_value)
403
404IdlTypeBase.impl_should_use_nullable_container = property(
405    impl_should_use_nullable_container)
406
407
408def impl_includes_for_type(idl_type, interfaces_info):
409    includes_for_type = set()
410    if idl_type.impl_should_use_nullable_container:
411        includes_for_type.add('bindings/core/v8/Nullable.h')
412
413    idl_type = idl_type.preprocessed_type
414    native_array_element_type = idl_type.native_array_element_type
415    if native_array_element_type:
416        includes_for_type.update(impl_includes_for_type(
417                native_array_element_type, interfaces_info))
418        includes_for_type.add('wtf/Vector.h')
419
420    base_idl_type = idl_type.base_type
421    if idl_type.is_string_type:
422        includes_for_type.add('wtf/text/WTFString.h')
423    if base_idl_type in interfaces_info:
424        interface_info = interfaces_info[idl_type.base_type]
425        includes_for_type.add(interface_info['include_path'])
426    if base_idl_type in INCLUDES_FOR_TYPE:
427        includes_for_type.update(INCLUDES_FOR_TYPE[base_idl_type])
428    return includes_for_type
429
430IdlTypeBase.impl_includes_for_type = impl_includes_for_type
431
432
433component_dir = {}
434
435
436def set_component_dirs(new_component_dirs):
437    component_dir.update(new_component_dirs)
438
439
440################################################################################
441# V8 -> C++
442################################################################################
443
444V8_VALUE_TO_CPP_VALUE = {
445    # Basic
446    'Date': 'toCoreDate({v8_value})',
447    'DOMString': '{v8_value}',
448    'ByteString': 'toByteString({arguments})',
449    'ScalarValueString': 'toScalarValueString({arguments})',
450    'boolean': '{v8_value}->BooleanValue()',
451    'float': 'toFloat({arguments})',
452    'unrestricted float': 'toFloat({arguments})',
453    'double': 'toDouble({arguments})',
454    'unrestricted double': 'toDouble({arguments})',
455    'byte': 'toInt8({arguments})',
456    'octet': 'toUInt8({arguments})',
457    'short': 'toInt16({arguments})',
458    'unsigned short': 'toUInt16({arguments})',
459    'long': 'toInt32({arguments})',
460    'unsigned long': 'toUInt32({arguments})',
461    'long long': 'toInt64({arguments})',
462    'unsigned long long': 'toUInt64({arguments})',
463    # Interface types
464    'Dictionary': 'Dictionary({v8_value}, {isolate})',
465    'EventTarget': 'V8DOMWrapper::isDOMWrapper({v8_value}) ? toWrapperTypeInfo(v8::Handle<v8::Object>::Cast({v8_value}))->toEventTarget(v8::Handle<v8::Object>::Cast({v8_value})) : 0',
466    'NodeFilter': 'toNodeFilter({v8_value}, info.Holder(), ScriptState::current({isolate}))',
467    'Promise': 'ScriptPromise::cast(ScriptState::current({isolate}), {v8_value})',
468    'SerializedScriptValue': 'SerializedScriptValue::create({v8_value}, 0, 0, exceptionState, {isolate})',
469    'ScriptValue': 'ScriptValue(ScriptState::current({isolate}), {v8_value})',
470    'Window': 'toDOMWindow({v8_value}, {isolate})',
471    'XPathNSResolver': 'toXPathNSResolver({v8_value}, {isolate})',
472}
473
474
475def v8_conversion_needs_exception_state(idl_type):
476    return (idl_type.is_numeric_type or
477            idl_type.is_dictionary or
478            idl_type.name in ('ByteString', 'ScalarValueString', 'SerializedScriptValue'))
479
480IdlType.v8_conversion_needs_exception_state = property(v8_conversion_needs_exception_state)
481IdlArrayOrSequenceType.v8_conversion_needs_exception_state = True
482
483
484TRIVIAL_CONVERSIONS = frozenset([
485    'any',
486    'boolean',
487    'Date',
488    'Dictionary',
489    'NodeFilter',
490    'XPathNSResolver',
491    'Promise'
492])
493
494
495def v8_conversion_is_trivial(idl_type):
496    # The conversion is a simple expression that returns the converted value and
497    # cannot raise an exception.
498    return (idl_type.base_type in TRIVIAL_CONVERSIONS or
499            idl_type.is_wrapper_type)
500
501IdlType.v8_conversion_is_trivial = property(v8_conversion_is_trivial)
502
503
504def v8_value_to_cpp_value(idl_type, extended_attributes, v8_value, index, isolate):
505    if idl_type.name == 'void':
506        return ''
507
508    # Array or sequence types
509    native_array_element_type = idl_type.native_array_element_type
510    if native_array_element_type:
511        return v8_value_to_cpp_value_array_or_sequence(native_array_element_type, v8_value, index)
512
513    # Simple types
514    idl_type = idl_type.preprocessed_type
515    add_includes_for_type(idl_type)
516    base_idl_type = idl_type.base_type
517
518    if 'EnforceRange' in extended_attributes:
519        arguments = ', '.join([v8_value, 'EnforceRange', 'exceptionState'])
520    elif 'Clamp' in extended_attributes:
521        arguments = ', '.join([v8_value, 'Clamp', 'exceptionState'])
522    elif idl_type.v8_conversion_needs_exception_state:
523        arguments = ', '.join([v8_value, 'exceptionState'])
524    else:
525        arguments = v8_value
526
527    if base_idl_type in V8_VALUE_TO_CPP_VALUE:
528        cpp_expression_format = V8_VALUE_TO_CPP_VALUE[base_idl_type]
529    elif idl_type.is_typed_array_element_type:
530        cpp_expression_format = (
531            '{v8_value}->Is{idl_type}() ? '
532            'V8{idl_type}::toImpl(v8::Handle<v8::{idl_type}>::Cast({v8_value})) : 0')
533    elif idl_type.is_dictionary:
534        cpp_expression_format = 'V8{idl_type}::toImpl({isolate}, {v8_value}, exceptionState)'
535    else:
536        cpp_expression_format = (
537            'V8{idl_type}::toImplWithTypeCheck({isolate}, {v8_value})')
538
539    return cpp_expression_format.format(arguments=arguments, idl_type=base_idl_type, v8_value=v8_value, isolate=isolate)
540
541
542def v8_value_to_cpp_value_array_or_sequence(native_array_element_type, v8_value, index, isolate='info.GetIsolate()'):
543    # Index is None for setters, index (starting at 0) for method arguments,
544    # and is used to provide a human-readable exception message
545    if index is None:
546        index = 0  # special case, meaning "setter"
547    else:
548        index += 1  # human-readable index
549    if (native_array_element_type.is_interface_type and
550        native_array_element_type.name != 'Dictionary'):
551        this_cpp_type = None
552        ref_ptr_type = cpp_ptr_type('RefPtr', 'Member', native_array_element_type.gc_type)
553        expression_format = '(to{ref_ptr_type}NativeArray<{native_array_element_type}, V8{native_array_element_type}>({v8_value}, {index}, {isolate}, exceptionState))'
554        add_includes_for_type(native_array_element_type)
555    else:
556        ref_ptr_type = None
557        this_cpp_type = native_array_element_type.cpp_type
558        expression_format = 'toImplArray<{cpp_type}>({v8_value}, {index}, {isolate}, exceptionState)'
559    expression = expression_format.format(native_array_element_type=native_array_element_type.name, cpp_type=this_cpp_type, index=index, ref_ptr_type=ref_ptr_type, v8_value=v8_value, isolate=isolate)
560    return expression
561
562
563def v8_value_to_local_cpp_value(idl_type, extended_attributes, v8_value, variable_name, index=None, declare_variable=True, isolate='info.GetIsolate()', used_in_private_script=False, return_promise=False):
564    """Returns an expression that converts a V8 value to a C++ value and stores it as a local value."""
565
566    # FIXME: Support union type.
567    if idl_type.is_union_type:
568        return '/* no V8 -> C++ conversion for IDL union type: %s */' % idl_type.name
569
570    this_cpp_type = idl_type.cpp_type_args(extended_attributes=extended_attributes, raw_type=True)
571    idl_type = idl_type.preprocessed_type
572
573    if idl_type.base_type in ('void', 'object', 'EventHandler', 'EventListener'):
574        return '/* no V8 -> C++ conversion for IDL type: %s */' % idl_type.name
575
576    cpp_value = v8_value_to_cpp_value(idl_type, extended_attributes, v8_value, index, isolate)
577    if idl_type.is_string_type or idl_type.v8_conversion_needs_exception_state:
578        # Types that need error handling and use one of a group of (C++) macros
579        # to take care of this.
580
581        args = [variable_name, cpp_value]
582
583        if idl_type.v8_conversion_needs_exception_state:
584            macro = 'TONATIVE_DEFAULT_EXCEPTIONSTATE' if used_in_private_script else 'TONATIVE_VOID_EXCEPTIONSTATE'
585        elif return_promise:
586            macro = 'TOSTRING_VOID_EXCEPTIONSTATE'
587        else:
588            macro = 'TOSTRING_DEFAULT' if used_in_private_script else 'TOSTRING_VOID'
589
590        if macro.endswith('_EXCEPTIONSTATE'):
591            args.append('exceptionState')
592
593        if used_in_private_script:
594            args.append('false')
595
596        suffix = ''
597
598        if return_promise:
599            suffix += '_PROMISE'
600            args.append('info')
601            if macro.endswith('_EXCEPTIONSTATE'):
602                args.append('ScriptState::current(%s)' % isolate)
603
604        if declare_variable:
605            args.insert(0, this_cpp_type)
606        else:
607            suffix += '_INTERNAL'
608
609        return '%s(%s)' % (macro + suffix, ', '.join(args))
610
611    # Types that don't need error handling, and simply assign a value to the
612    # local variable.
613
614    if not idl_type.v8_conversion_is_trivial:
615        raise Exception('unclassified V8 -> C++ conversion for IDL type: %s' % idl_type.name)
616
617    assignment = '%s = %s' % (variable_name, cpp_value)
618    if declare_variable:
619        return '%s %s' % (this_cpp_type, assignment)
620    return assignment
621
622
623IdlTypeBase.v8_value_to_local_cpp_value = v8_value_to_local_cpp_value
624
625
626################################################################################
627# C++ -> V8
628################################################################################
629
630def preprocess_idl_type(idl_type):
631    if idl_type.is_enum:
632        # Enumerations are internally DOMStrings
633        return IdlType('DOMString')
634    if (idl_type.name in ['Any', 'Object'] or idl_type.is_callback_function):
635        return IdlType('ScriptValue')
636    return idl_type
637
638IdlTypeBase.preprocessed_type = property(preprocess_idl_type)
639
640
641def preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes):
642    """Returns IDL type and value, with preliminary type conversions applied."""
643    idl_type = idl_type.preprocessed_type
644    if idl_type.name == 'Promise':
645        idl_type = IdlType('ScriptValue')
646    if idl_type.base_type in ['long long', 'unsigned long long']:
647        # long long and unsigned long long are not representable in ECMAScript;
648        # we represent them as doubles.
649        is_nullable = idl_type.is_nullable
650        idl_type = IdlType('double')
651        if is_nullable:
652            idl_type = IdlNullableType(idl_type)
653        cpp_value = 'static_cast<double>(%s)' % cpp_value
654    # HTML5 says that unsigned reflected attributes should be in the range
655    # [0, 2^31). When a value isn't in this range, a default value (or 0)
656    # should be returned instead.
657    extended_attributes = extended_attributes or {}
658    if ('Reflect' in extended_attributes and
659        idl_type.base_type in ['unsigned long', 'unsigned short']):
660        cpp_value = cpp_value.replace('getUnsignedIntegralAttribute',
661                                      'getIntegralAttribute')
662        cpp_value = 'std::max(0, static_cast<int>(%s))' % cpp_value
663    return idl_type, cpp_value
664
665
666def v8_conversion_type(idl_type, extended_attributes):
667    """Returns V8 conversion type, adding any additional includes.
668
669    The V8 conversion type is used to select the C++ -> V8 conversion function
670    or v8SetReturnValue* function; it can be an idl_type, a cpp_type, or a
671    separate name for the type of conversion (e.g., 'DOMWrapper').
672    """
673    extended_attributes = extended_attributes or {}
674
675    # FIXME: Support union type.
676    if idl_type.is_union_type:
677        return ''
678
679    # Array or sequence types
680    native_array_element_type = idl_type.native_array_element_type
681    if native_array_element_type:
682        if native_array_element_type.is_interface_type:
683            add_includes_for_type(native_array_element_type)
684        return 'array'
685
686    # Simple types
687    base_idl_type = idl_type.base_type
688    # Basic types, without additional includes
689    if base_idl_type in CPP_INT_TYPES:
690        return 'int'
691    if base_idl_type in CPP_UNSIGNED_TYPES:
692        return 'unsigned'
693    if idl_type.is_string_type:
694        if idl_type.is_nullable:
695            return 'StringOrNull'
696        if 'TreatReturnedNullStringAs' not in extended_attributes:
697            return base_idl_type
698        treat_returned_null_string_as = extended_attributes['TreatReturnedNullStringAs']
699        if treat_returned_null_string_as == 'Null':
700            return 'StringOrNull'
701        if treat_returned_null_string_as == 'Undefined':
702            return 'StringOrUndefined'
703        raise 'Unrecognized TreatReturnedNullStringAs value: "%s"' % treat_returned_null_string_as
704    if idl_type.is_basic_type or base_idl_type == 'ScriptValue':
705        return base_idl_type
706
707    # Data type with potential additional includes
708    add_includes_for_type(idl_type)
709    if base_idl_type in V8_SET_RETURN_VALUE:  # Special v8SetReturnValue treatment
710        return base_idl_type
711
712    # Pointer type
713    return 'DOMWrapper'
714
715IdlTypeBase.v8_conversion_type = v8_conversion_type
716
717
718V8_SET_RETURN_VALUE = {
719    'boolean': 'v8SetReturnValueBool(info, {cpp_value})',
720    'int': 'v8SetReturnValueInt(info, {cpp_value})',
721    'unsigned': 'v8SetReturnValueUnsigned(info, {cpp_value})',
722    'DOMString': 'v8SetReturnValueString(info, {cpp_value}, info.GetIsolate())',
723    'ByteString': 'v8SetReturnValueString(info, {cpp_value}, info.GetIsolate())',
724    'ScalarValueString': 'v8SetReturnValueString(info, {cpp_value}, info.GetIsolate())',
725    # [TreatReturnedNullStringAs]
726    'StringOrNull': 'v8SetReturnValueStringOrNull(info, {cpp_value}, info.GetIsolate())',
727    'StringOrUndefined': 'v8SetReturnValueStringOrUndefined(info, {cpp_value}, info.GetIsolate())',
728    'void': '',
729    # No special v8SetReturnValue* function (set value directly)
730    'float': 'v8SetReturnValue(info, {cpp_value})',
731    'unrestricted float': 'v8SetReturnValue(info, {cpp_value})',
732    'double': 'v8SetReturnValue(info, {cpp_value})',
733    'unrestricted double': 'v8SetReturnValue(info, {cpp_value})',
734    # No special v8SetReturnValue* function, but instead convert value to V8
735    # and then use general v8SetReturnValue.
736    'array': 'v8SetReturnValue(info, {cpp_value})',
737    'Date': 'v8SetReturnValue(info, {cpp_value})',
738    'EventHandler': 'v8SetReturnValue(info, {cpp_value})',
739    'ScriptValue': 'v8SetReturnValue(info, {cpp_value})',
740    'SerializedScriptValue': 'v8SetReturnValue(info, {cpp_value})',
741    # DOMWrapper
742    'DOMWrapperForMainWorld': 'v8SetReturnValueForMainWorld(info, WTF::getPtr({cpp_value}))',
743    'DOMWrapperFast': 'v8SetReturnValueFast(info, WTF::getPtr({cpp_value}), {script_wrappable})',
744    'DOMWrapperDefault': 'v8SetReturnValue(info, {cpp_value})',
745}
746
747
748def v8_set_return_value(idl_type, cpp_value, extended_attributes=None, script_wrappable='', release=False, for_main_world=False):
749    """Returns a statement that converts a C++ value to a V8 value and sets it as a return value.
750
751    """
752    def dom_wrapper_conversion_type():
753        if not script_wrappable:
754            return 'DOMWrapperDefault'
755        if for_main_world:
756            return 'DOMWrapperForMainWorld'
757        return 'DOMWrapperFast'
758
759    idl_type, cpp_value = preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes)
760    this_v8_conversion_type = idl_type.v8_conversion_type(extended_attributes)
761    # SetReturn-specific overrides
762    if this_v8_conversion_type in ['Date', 'EventHandler', 'ScriptValue', 'SerializedScriptValue', 'array']:
763        # Convert value to V8 and then use general v8SetReturnValue
764        cpp_value = idl_type.cpp_value_to_v8_value(cpp_value, extended_attributes=extended_attributes)
765    if this_v8_conversion_type == 'DOMWrapper':
766        this_v8_conversion_type = dom_wrapper_conversion_type()
767
768    format_string = V8_SET_RETURN_VALUE[this_v8_conversion_type]
769    # FIXME: oilpan: Remove .release() once we remove all RefPtrs from generated code.
770    if release:
771        cpp_value = '%s.release()' % cpp_value
772    statement = format_string.format(cpp_value=cpp_value, script_wrappable=script_wrappable)
773    return statement
774
775
776def v8_set_return_value_union(idl_type, cpp_value, extended_attributes=None, script_wrappable='', release=False, for_main_world=False):
777    # FIXME: Need to revisit the design of union support.
778    # http://crbug.com/240176
779    return None
780
781
782IdlTypeBase.v8_set_return_value = v8_set_return_value
783IdlUnionType.v8_set_return_value = v8_set_return_value_union
784
785IdlType.release = property(lambda self: self.is_interface_type)
786IdlUnionType.release = property(
787    lambda self: [member_type.is_interface_type
788                  for member_type in self.member_types])
789
790
791CPP_VALUE_TO_V8_VALUE = {
792    # Built-in types
793    'Date': 'v8DateOrNaN({cpp_value}, {isolate})',
794    'DOMString': 'v8String({isolate}, {cpp_value})',
795    'ByteString': 'v8String({isolate}, {cpp_value})',
796    'ScalarValueString': 'v8String({isolate}, {cpp_value})',
797    'boolean': 'v8Boolean({cpp_value}, {isolate})',
798    'int': 'v8::Integer::New({isolate}, {cpp_value})',
799    'unsigned': 'v8::Integer::NewFromUnsigned({isolate}, {cpp_value})',
800    'float': 'v8::Number::New({isolate}, {cpp_value})',
801    'unrestricted float': 'v8::Number::New({isolate}, {cpp_value})',
802    'double': 'v8::Number::New({isolate}, {cpp_value})',
803    'unrestricted double': 'v8::Number::New({isolate}, {cpp_value})',
804    'void': 'v8Undefined()',
805    # [TreatReturnedNullStringAs]
806    'StringOrNull': '{cpp_value}.isNull() ? v8::Handle<v8::Value>(v8::Null({isolate})) : v8String({isolate}, {cpp_value})',
807    'StringOrUndefined': '{cpp_value}.isNull() ? v8Undefined() : v8String({isolate}, {cpp_value})',
808    # Special cases
809    'EventHandler': '{cpp_value} ? v8::Handle<v8::Value>(V8AbstractEventListener::cast({cpp_value})->getListenerObject(impl->executionContext())) : v8::Handle<v8::Value>(v8::Null({isolate}))',
810    'ScriptValue': '{cpp_value}.v8Value()',
811    'SerializedScriptValue': '{cpp_value} ? {cpp_value}->deserialize() : v8::Handle<v8::Value>(v8::Null({isolate}))',
812    # General
813    'array': 'v8Array({cpp_value}, {creation_context}, {isolate})',
814    'DOMWrapper': 'toV8({cpp_value}, {creation_context}, {isolate})',
815}
816
817
818def cpp_value_to_v8_value(idl_type, cpp_value, isolate='info.GetIsolate()', creation_context='info.Holder()', extended_attributes=None):
819    """Returns an expression that converts a C++ value to a V8 value."""
820    # the isolate parameter is needed for callback interfaces
821    idl_type, cpp_value = preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes)
822    this_v8_conversion_type = idl_type.v8_conversion_type(extended_attributes)
823    format_string = CPP_VALUE_TO_V8_VALUE[this_v8_conversion_type]
824    statement = format_string.format(cpp_value=cpp_value, isolate=isolate, creation_context=creation_context)
825    return statement
826
827IdlTypeBase.cpp_value_to_v8_value = cpp_value_to_v8_value
828
829
830def literal_cpp_value(idl_type, idl_literal):
831    """Converts an expression that is a valid C++ literal for this type."""
832    # FIXME: add validation that idl_type and idl_literal are compatible
833    literal_value = str(idl_literal)
834    if idl_type.base_type in CPP_UNSIGNED_TYPES:
835        return literal_value + 'u'
836    return literal_value
837
838IdlType.literal_cpp_value = literal_cpp_value
839
840
841################################################################################
842# Utility properties for nullable types
843################################################################################
844
845
846def cpp_type_has_null_value(idl_type):
847    # - String types (String/AtomicString) represent null as a null string,
848    #   i.e. one for which String::isNull() returns true.
849    # - Enum types, as they are implemented as Strings.
850    # - Wrapper types (raw pointer or RefPtr/PassRefPtr) represent null as
851    #   a null pointer.
852    # - Dictionary types represent null as a null pointer. They are garbage
853    #   collected so their type is raw pointer.
854    # - 'Object' type. We use ScriptValue for object type.
855    return (idl_type.is_string_type or idl_type.is_wrapper_type or
856            idl_type.is_enum or idl_type.is_dictionary or idl_type.base_type == 'object')
857
858IdlTypeBase.cpp_type_has_null_value = property(cpp_type_has_null_value)
859
860
861def is_implicit_nullable(idl_type):
862    # Nullable type where the corresponding C++ type supports a null value.
863    return idl_type.is_nullable and idl_type.cpp_type_has_null_value
864
865
866def is_explicit_nullable(idl_type):
867    # Nullable type that isn't implicit nullable (see above.) For such types,
868    # we use Nullable<T> or similar explicit ways to represent a null value.
869    return idl_type.is_nullable and not idl_type.is_implicit_nullable
870
871IdlTypeBase.is_implicit_nullable = property(is_implicit_nullable)
872IdlUnionType.is_implicit_nullable = False
873IdlTypeBase.is_explicit_nullable = property(is_explicit_nullable)
874