• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4"""IDL type handling.
5
6Classes:
7IdlType
8IdlUnionType
9"""
10
11from collections import defaultdict
12
13
14################################################################################
15# IDL types
16################################################################################
17
18INTEGER_TYPES = frozenset([
19    # http://www.w3.org/TR/WebIDL/#dfn-integer-type
20    'byte',
21    'octet',
22    'short',
23    'unsigned short',
24    # int and unsigned are not IDL types
25    'long',
26    'unsigned long',
27    'long long',
28    'unsigned long long',
29])
30NUMERIC_TYPES = (INTEGER_TYPES | frozenset([
31    # http://www.w3.org/TR/WebIDL/#dfn-numeric-type
32    'float',
33    'unrestricted float',
34    'double',
35    'unrestricted double',
36]))
37# http://www.w3.org/TR/WebIDL/#dfn-primitive-type
38PRIMITIVE_TYPES = (frozenset(['boolean']) | NUMERIC_TYPES)
39BASIC_TYPES = (PRIMITIVE_TYPES | frozenset([
40    # Built-in, non-composite, non-object data types
41    # http://heycam.github.io/webidl/#idl-types
42    'DOMString',
43    'ByteString',
44    'Date',
45    # http://heycam.github.io/webidl/#es-type-mapping
46    'void',
47    # http://encoding.spec.whatwg.org/#type-scalarvaluestring
48    'ScalarValueString',
49]))
50TYPE_NAMES = {
51    # http://heycam.github.io/webidl/#dfn-type-name
52    'any': 'Any',
53    'boolean': 'Boolean',
54    'byte': 'Byte',
55    'octet': 'Octet',
56    'short': 'Short',
57    'unsigned short': 'UnsignedShort',
58    'long': 'Long',
59    'unsigned long': 'UnsignedLong',
60    'long long': 'LongLong',
61    'unsigned long long': 'UnsignedLongLong',
62    'float': 'Float',
63    'unrestricted float': 'UnrestrictedFloat',
64    'double': 'Double',
65    'unrestricted double': 'UnrestrictedDouble',
66    'DOMString': 'String',
67    'ByteString': 'ByteString',
68    'ScalarValueString': 'ScalarValueString',
69    'object': 'Object',
70    'Date': 'Date',
71}
72
73
74################################################################################
75# Inheritance
76################################################################################
77
78ancestors = defaultdict(list)  # interface_name -> ancestors
79
80def inherits_interface(interface_name, ancestor_name):
81    return (interface_name == ancestor_name or
82            ancestor_name in ancestors[interface_name])
83
84
85def set_ancestors(new_ancestors):
86    ancestors.update(new_ancestors)
87
88
89################################################################################
90# IdlType
91################################################################################
92
93class IdlType(object):
94    # FIXME: incorporate Nullable, etc.
95    # FIXME: use nested types: IdlArrayType, IdlNullableType, IdlSequenceType
96    # to support types like short?[] vs. short[]?, instead of treating these
97    # as orthogonal properties (via flags).
98    callback_functions = set()
99    callback_interfaces = set()
100    enums = {}  # name -> values
101
102    def __init__(self, base_type, is_array=False, is_sequence=False, is_nullable=False, is_unrestricted=False):
103        if is_array and is_sequence:
104            raise ValueError('Array of Sequences are not allowed.')
105        if is_unrestricted:
106            self.base_type = 'unrestricted %s' % base_type
107        else:
108            self.base_type = base_type
109        self.is_array = is_array
110        self.is_sequence = is_sequence
111        self.is_nullable = is_nullable
112
113    def __str__(self):
114        type_string = self.base_type
115        if self.is_array:
116            return type_string + '[]'
117        if self.is_sequence:
118            return 'sequence<%s>' % type_string
119        if self.is_nullable:
120            # FIXME: Dictionary::ConversionContext::setConversionType can't
121            # handle the '?' in nullable types (passes nullability separately).
122            # Update that function to handle nullability from the type name,
123            # simplifying its signature.
124            # return type_string + '?'
125            return type_string
126        return type_string
127
128    # FIXME: rename to native_array_element_type and move to v8_types.py
129    @property
130    def array_or_sequence_type(self):
131        return self.array_type or self.sequence_type
132
133    # FIXME: rename to array_element_type
134    @property
135    def array_type(self):
136        return self.is_array and IdlType(self.base_type)
137
138    # FIXME: rename to sequence_element_type
139    @property
140    def sequence_type(self):
141        return self.is_sequence and IdlType(self.base_type)
142
143    @property
144    def is_basic_type(self):
145        return self.base_type in BASIC_TYPES and not self.array_or_sequence_type
146
147    @property
148    def is_callback_function(self):
149        return self.base_type in IdlType.callback_functions
150
151    @property
152    def is_callback_interface(self):
153        return self.base_type in IdlType.callback_interfaces
154
155    @property
156    def is_composite_type(self):
157        return (self.name == 'Any' or
158                self.array_type or
159                self.sequence_type or
160                self.is_union_type)
161
162    @property
163    def is_enum(self):
164        # FIXME: add an IdlEnumType class and a resolve_enums step at end of
165        # IdlDefinitions constructor
166        return self.name in IdlType.enums
167
168    @property
169    def enum_values(self):
170        return IdlType.enums[self.name]
171
172    @property
173    def is_integer_type(self):
174        return self.base_type in INTEGER_TYPES and not self.array_or_sequence_type
175
176    @property
177    def is_numeric_type(self):
178        return self.base_type in NUMERIC_TYPES and not self.array_or_sequence_type
179
180    @property
181    def is_primitive_type(self):
182        return self.base_type in PRIMITIVE_TYPES and not self.array_or_sequence_type
183
184    @property
185    def is_interface_type(self):
186        # Anything that is not another type is an interface type.
187        # http://www.w3.org/TR/WebIDL/#idl-types
188        # http://www.w3.org/TR/WebIDL/#idl-interface
189        # In C++ these are RefPtr or PassRefPtr types.
190        return not(self.is_basic_type or
191                   self.is_composite_type or
192                   self.is_callback_function or
193                   self.is_enum or
194                   self.name == 'Object' or
195                   self.name == 'Promise')  # Promise will be basic in future
196
197    @property
198    def is_union_type(self):
199        return isinstance(self, IdlUnionType)
200
201    @property
202    def name(self):
203        """Return type name.
204
205        http://heycam.github.io/webidl/#dfn-type-name
206        """
207        base_type = self.base_type
208        base_type_name = TYPE_NAMES.get(base_type, base_type)
209        if self.is_array:
210            return base_type_name + 'Array'
211        if self.is_sequence:
212            return base_type_name + 'Sequence'
213        if self.is_nullable:
214            return base_type_name + 'OrNull'
215        return base_type_name
216
217    @classmethod
218    def set_callback_functions(cls, new_callback_functions):
219        cls.callback_functions.update(new_callback_functions)
220
221    @classmethod
222    def set_callback_interfaces(cls, new_callback_interfaces):
223        cls.callback_interfaces.update(new_callback_interfaces)
224
225    @classmethod
226    def set_enums(cls, new_enums):
227        cls.enums.update(new_enums)
228
229    def resolve_typedefs(self, typedefs):
230        if self.base_type not in typedefs:
231            return self
232        new_type = typedefs[self.base_type]
233        if type(new_type) != type(self):
234            # If type changes, need to return a different object,
235            # since can't change type(self)
236            return new_type
237        # If type doesn't change, just mutate self to avoid a new object
238        # FIXME: a bit ugly; use __init__ instead of setting flags
239        self.base_type = new_type.base_type
240        # handle array both in use and in typedef itself:
241        # typedef Type TypeDef;
242        # TypeDef[] ...
243        # and:
244        # typedef Type[] TypeArray
245        # TypeArray ...
246        self.is_array |= new_type.is_array
247        self.is_sequence |= new_type.is_sequence
248        return self
249
250
251################################################################################
252# IdlUnionType
253################################################################################
254
255class IdlUnionType(object):
256    # http://heycam.github.io/webidl/#idl-union
257    # FIXME: derive from IdlType, instead of stand-alone class, to reduce
258    # duplication.
259    def __init__(self, member_types, is_nullable=False):
260        self.member_types = member_types
261        self.is_nullable = is_nullable
262
263    @property
264    def array_or_sequence_type(self):
265        return False
266
267    @property
268    def array_type(self):
269        return False
270
271    @property
272    def is_array(self):
273        # We do not support arrays of union types
274        return False
275
276    @property
277    def base_type(self):
278        return None
279
280    @property
281    def is_basic_type(self):
282        return False
283
284    @property
285    def is_callback_function(self):
286        return False
287
288    @property
289    def is_enum(self):
290        return False
291
292    @property
293    def is_integer_type(self):
294        return False
295
296    @property
297    def is_numeric_type(self):
298        return False
299
300    @property
301    def is_primitivee_type(self):
302        return False
303
304    @property
305    def is_sequence(self):
306        # We do not support sequences of union types
307        return False
308
309    @property
310    def is_union_type(self):
311        return True
312
313    @property
314    def name(self):
315        return 'Or'.join(member_type.name for member_type in self.member_types)
316
317    def resolve_typedefs(self, typedefs):
318        self.member_types = [
319            typedefs.get(member_type, member_type)
320            for member_type in self.member_types]
321        return self
322