Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: Source/bindings/scripts/unstable/idl_definitions.py

Issue 181513006: IDL compiler: delete Perl compiler, remove unstable/ directory (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 """Blink IDL Intermediate Representation (IR) classes.
30
31 Also JSON export, using legacy Perl terms and format, to ensure that both
32 parsers produce the same output.
33 FIXME: remove BaseIdl, JSON export (json_serializable and to_json), and Perl
34 compatibility functions and hacks once Perl compiler gone.
35 """
36
37 # Disable attribute hiding check (else JSONEncoder default raises an error)
38 # pylint: disable=E0202
39 # pylint doesn't understand ABCs.
40 # pylint: disable=W0232, E0203, W0201
41
42 import abc
43 import json
44 import re
45
46
47 # Base classes
48
49
50 class BaseIdl(object):
51 """Abstract base class, used for JSON serialization."""
52 __metaclass__ = abc.ABCMeta
53
54 @abc.abstractmethod
55 def json_serializable(self):
56 """Returns a JSON serializable form of the object.
57
58 This should be a dictionary, with keys scoped names of the form
59 Class::key, where the scope is the class name.
60 This is so we produce identical output to the Perl code, which uses
61 the Perl module JSON.pm, which uses this format.
62 """
63 pass
64
65
66 class TypedObject(object):
67 """Object with a type, such as an Attribute or Operation (return value).
68
69 The type can be an actual type, or can be a typedef, which must be resolved
70 before passing data to the code generator.
71 """
72 __metaclass__ = abc.ABCMeta
73 idl_type = None
74 extended_attributes = None
75
76 def resolve_typedefs(self, typedefs):
77 """Resolve typedefs to actual types in the object."""
78 # Constructors don't have their own return type, because it's the
79 # interface itself.
80 if not self.idl_type:
81 return
82 # (Types are represented either as strings or as IdlUnionType objects.)
83 # Union types are objects, which have a member function for this
84 if isinstance(self.idl_type, IdlUnionType):
85 # Method 'resolve_typedefs' call is ok, but pylint can't infer this
86 # pylint: disable=E1101
87 self.idl_type.resolve_typedefs(typedefs)
88 return
89 # Otherwise, IDL type is represented as string, so use a function
90 self.idl_type = resolve_typedefs(self.idl_type, typedefs)
91
92
93 # IDL classes
94
95
96 class IdlDefinitions(BaseIdl):
97 def __init__(self, callback_functions=None, enumerations=None, file_name=Non e, interfaces=None, typedefs=None):
98 self.callback_functions = callback_functions or {}
99 self.enumerations = enumerations or {}
100 self.file_name = file_name or None
101 self.interfaces = interfaces or {}
102 # Typedefs are not exposed by bindings; resolve typedefs with the
103 # actual types and then discard the Typedefs.
104 # http://www.w3.org/TR/WebIDL/#idl-typedefs
105 if typedefs:
106 self.resolve_typedefs(typedefs)
107
108 def resolve_typedefs(self, typedefs):
109 for callback_function in self.callback_functions.itervalues():
110 callback_function.resolve_typedefs(typedefs)
111 for interface in self.interfaces.itervalues():
112 interface.resolve_typedefs(typedefs)
113
114 def json_serializable(self):
115 return {
116 'idlDocument::callbackFunctions': self.callback_functions.values (),
117 'idlDocument::enumerations': self.enumerations.values(),
118 'idlDocument::fileName': self.file_name,
119 'idlDocument::interfaces': sorted(self.interfaces.values()),
120 }
121
122 def to_json(self, debug=False):
123 """Returns a JSON string representing the Definitions.
124
125 The JSON output should be identical with the output of the Perl parser,
126 specifically the function serializeJSON in idl_serializer.pm,
127 which takes a Perl object created by idl_parser.pm.
128 """
129 # Sort so order consistent, allowing comparison of output
130 if debug:
131 # indent turns on pretty-printing for legibility
132 return json.dumps(self, cls=IdlEncoder, sort_keys=True, indent=4)
133 # Use compact separators so output identical to Perl
134 return json.dumps(self, cls=IdlEncoder, sort_keys=True, separators=(',', ':'))
135
136
137 class IdlCallbackFunction(BaseIdl, TypedObject):
138 def __init__(self, name=None, idl_type=None, arguments=None):
139 self.idl_type = idl_type
140 self.name = name
141 self.arguments = arguments or []
142
143 def resolve_typedefs(self, typedefs):
144 TypedObject.resolve_typedefs(self, typedefs)
145 for argument in self.arguments:
146 argument.resolve_typedefs(typedefs)
147
148 def json_serializable(self):
149 return {
150 'callbackFunction::name': self.name,
151 'callbackFunction::type': self.idl_type,
152 'callbackFunction::parameters': self.arguments,
153 }
154
155
156 class IdlEnum(BaseIdl):
157 def __init__(self, name=None, values=None):
158 self.name = name
159 self.values = values or []
160
161 def json_serializable(self):
162 return {
163 'domEnum::name': self.name,
164 'domEnum::values': self.values,
165 }
166
167
168 class IdlInterface(BaseIdl):
169 def __init__(self, attributes=None, constants=None, constructors=None, custo m_constructors=None, extended_attributes=None, operations=None, is_callback=Fals e, is_partial=False, name=None, parent=None):
170 self.attributes = attributes or []
171 self.constants = constants or []
172 self.constructors = constructors or []
173 self.custom_constructors = custom_constructors or []
174 self.extended_attributes = extended_attributes or {}
175 self.operations = operations or []
176 self.is_callback = is_callback
177 self.is_partial = is_partial
178 self.is_exception = False
179 self.name = name
180 self.parent = parent
181
182 def resolve_typedefs(self, typedefs):
183 for attribute in self.attributes:
184 attribute.resolve_typedefs(typedefs)
185 for constant in self.constants:
186 constant.resolve_typedefs(typedefs)
187 for constructor in self.constructors:
188 constructor.resolve_typedefs(typedefs)
189 for custom_constructor in self.custom_constructors:
190 custom_constructor.resolve_typedefs(typedefs)
191 for operation in self.operations:
192 operation.resolve_typedefs(typedefs)
193
194 def json_serializable(self):
195 return {
196 'domInterface::attributes': self.attributes,
197 'domInterface::constants': self.constants,
198 'domInterface::constructors': self.constructors,
199 'domInterface::customConstructors': self.custom_constructors,
200 'domInterface::extendedAttributes': none_to_value_is_missing(self.ex tended_attributes),
201 'domInterface::functions': self.operations,
202 'domInterface::isException': false_to_none(self.is_exception),
203 'domInterface::isCallback': boolean_to_perl(false_to_none(self.is_ca llback)),
204 'domInterface::isPartial': false_to_none(self.is_partial),
205 'domInterface::name': self.name,
206 'domInterface::parent': self.parent,
207 }
208
209
210 class IdlException(IdlInterface):
211 # Properly exceptions and interfaces are distinct, and thus should inherit a
212 # common base class (say, "IdlExceptionOrInterface").
213 # However, there is only one exception (DOMException), and new exceptions
214 # are not expected. Thus it is easier to implement exceptions as a
215 # restricted subclass of interfaces.
216 # http://www.w3.org/TR/WebIDL/#idl-exceptions
217 def __init__(self, name=None, constants=None, operations=None, attributes=No ne, extended_attributes=None):
218 IdlInterface.__init__(self, name=name, constants=constants, operations=o perations, attributes=attributes, extended_attributes=extended_attributes)
219 self.is_exception = True
220
221
222 class IdlAttribute(BaseIdl, TypedObject):
223 def __init__(self, idl_type=None, extended_attributes=None, getter_exception s=None, is_nullable=False, is_static=False, is_read_only=False, name=None, sette r_exceptions=None):
224 self.idl_type = idl_type
225 self.extended_attributes = extended_attributes or {}
226 self.getter_exceptions = getter_exceptions or []
227 self.is_nullable = is_nullable
228 self.is_static = is_static
229 self.is_read_only = is_read_only
230 self.name = name
231 self.setter_exceptions = setter_exceptions or []
232
233 def json_serializable(self):
234 return {
235 'domAttribute::extendedAttributes': none_to_value_is_missing(self.ex tended_attributes),
236 'domAttribute::getterExceptions': self.getter_exceptions,
237 'domAttribute::isNullable': boolean_to_perl_quoted(false_to_none(sel f.is_nullable)),
238 'domAttribute::isReadOnly': boolean_to_perl(false_to_none(self.is_re ad_only)),
239 'domAttribute::isStatic': boolean_to_perl(false_to_none(self.is_stat ic)),
240 'domAttribute::name': self.name,
241 'domAttribute::setterExceptions': self.setter_exceptions,
242 'domAttribute::type': self.idl_type,
243 }
244
245
246 class IdlConstant(BaseIdl, TypedObject):
247 def __init__(self, name=None, idl_type=None, value=None, extended_attributes =None):
248 self.idl_type = idl_type
249 self.extended_attributes = extended_attributes or {}
250 self.name = name
251 self.value = value
252
253 def json_serializable(self):
254 return {
255 'domConstant::extendedAttributes': none_to_value_is_missing(self.ext ended_attributes),
256 'domConstant::name': self.name,
257 'domConstant::type': self.idl_type,
258 'domConstant::value': self.value,
259 }
260
261
262 class IdlOperation(BaseIdl, TypedObject):
263 def __init__(self, is_static=False, name=None, idl_type=None, extended_attri butes=None, specials=None, arguments=None, overloaded_index=None):
264 self.is_static = is_static
265 self.name = name or ''
266 self.idl_type = idl_type
267 self.extended_attributes = extended_attributes or {}
268 self.specials = specials or []
269 self.arguments = arguments or []
270 # FIXME: remove overloaded_index (only here for Perl compatibility),
271 # as overloading is handled in code generator (v8_interface.py).
272 self.overloaded_index = overloaded_index
273
274 def resolve_typedefs(self, typedefs):
275 TypedObject.resolve_typedefs(self, typedefs)
276 for argument in self.arguments:
277 argument.resolve_typedefs(typedefs)
278
279 def json_serializable(self):
280 return {
281 'domFunction::extendedAttributes': none_to_value_is_missing(self.ext ended_attributes),
282 'domFunction::isStatic': boolean_to_perl(false_to_none(self.is_stati c)),
283 'domFunction::name': self.name,
284 'domFunction::overloadedIndex': self.overloaded_index,
285 'domFunction::parameters': self.arguments,
286 'domFunction::specials': self.specials,
287 'domFunction::type': self.idl_type,
288 }
289
290
291 class IdlArgument(BaseIdl, TypedObject):
292 def __init__(self, name=None, idl_type=None, extended_attributes=None, is_op tional=False, is_nullable=None, is_variadic=False):
293 self.idl_type = idl_type
294 self.extended_attributes = extended_attributes or {}
295 # FIXME: boolean values are inconsistent.
296 # The below hack is so that generated JSON is identical to
297 # Perl-generated JSON, where the exact values depend on the code path.
298 # False and None (Perl: 0 and undef) are semantically interchangeable,
299 # but yield different JSON.
300 # Once Perl removed, have all default to False.
301 if is_optional is None:
302 is_optional = False
303 if is_variadic is None:
304 is_variadic = False
305 self.is_nullable = is_nullable # (T?)
306 self.is_optional = is_optional # (optional T)
307 self.is_variadic = is_variadic # (T...)
308 self.name = name
309
310 def json_serializable(self):
311 return {
312 'domParameter::extendedAttributes': none_to_value_is_missing(self.ex tended_attributes),
313 'domParameter::isNullable': boolean_to_perl_quoted(self.is_nullable) ,
314 'domParameter::isOptional': boolean_to_perl(self.is_optional),
315 'domParameter::isVariadic': boolean_to_perl(self.is_variadic),
316 'domParameter::name': self.name,
317 'domParameter::type': self.idl_type,
318 }
319
320 # Type classes
321
322
323 def resolve_typedefs(idl_type, typedefs):
324 """Return an IDL type (as string) with typedefs resolved."""
325 # Converts a string representation to and from an IdlType object to handle
326 # parsing of composite types (arrays and sequences) and encapsulate typedef
327 # resolution, e.g., GLint[] -> unsigned long[] requires parsing the '[]'.
328 # Use fluent interface to avoid auxiliary variable.
329 return str(IdlType.from_string(idl_type).resolve_typedefs(typedefs))
330
331
332 class IdlType(object):
333 # FIXME: replace type strings with these objects,
334 # so don't need to parse everywhere types are used.
335 # Types are stored internally as strings, not objects,
336 # e.g., as 'sequence<Foo>' or 'Foo[]',
337 # hence need to parse the string whenever a type is used.
338 # FIXME: incorporate Nullable, Variadic, etc.
339 # FIXME: properly should nest types
340 # Formally types are nested, e.g., short?[] vs. short[]?,
341 # but in practice these complex types aren't used and can treat
342 # as orthogonal properties.
343 def __init__(self, base_type, is_array=False, is_sequence=False):
344 if is_array and is_sequence:
345 raise ValueError('Array of Sequences are not allowed.')
346 self.base_type = base_type
347 self.is_array = is_array
348 self.is_sequence = is_sequence
349
350 def __str__(self):
351 type_string = self.base_type
352 if self.is_array:
353 return type_string + '[]'
354 if self.is_sequence:
355 return 'sequence<%s>' % type_string
356 return type_string
357
358 @classmethod
359 def from_string(cls, type_string):
360 sequence_re = r'^sequence<([^>]*)>$'
361 if type_string.endswith('[]'):
362 type_string = type_string[:-2]
363 sequence_match = re.match(sequence_re, type_string)
364 if sequence_match:
365 raise ValueError('Array of Sequences are not allowed.')
366 return cls(type_string, is_array=True)
367 sequence_match = re.match(sequence_re, type_string)
368 if sequence_match:
369 base_type = sequence_match.group(1)
370 return cls(base_type, is_sequence=True)
371 return cls(type_string)
372
373 def resolve_typedefs(self, typedefs):
374 if self.base_type in typedefs:
375 self.base_type = typedefs[self.base_type]
376 return self # Fluent interface
377
378
379 class IdlUnionType(BaseIdl):
380 def __init__(self, union_member_types=None):
381 self.union_member_types = union_member_types or []
382
383 def resolve_typedefs(self, typedefs):
384 self.union_member_types = [
385 typedefs.get(union_member_type, union_member_type)
386 for union_member_type in self.union_member_types]
387
388 def json_serializable(self):
389 return {
390 'UnionType::unionMemberTypes': self.union_member_types,
391 }
392
393
394 # Perl JSON compatibility functions
395
396 def none_to_value_is_missing(extended_attributes):
397 # Perl IDL Parser uses 'VALUE_IS_MISSING' for null values in
398 # extended attributes, so add this as a filter when exporting to JSON.
399 new_extended_attributes = {}
400 for key, value in extended_attributes.iteritems():
401 if value is None:
402 new_extended_attributes[key] = 'VALUE_IS_MISSING'
403 else:
404 new_extended_attributes[key] = value
405 return new_extended_attributes
406
407
408 def boolean_to_perl(value):
409 # Perl stores booleans as 1, 0, or undefined (JSON null);
410 # convert to this format.
411 if value is None:
412 return None
413 return int(value)
414
415
416 def boolean_to_perl_quoted(value):
417 # Bug-for-bug compatibility with Perl.
418 # The value of isNullable is quoted ('1', '0', or undefined), rather than
419 # an integer, so add quotes.
420 if value is None:
421 return None
422 return str(int(value))
423
424
425 def false_to_none(value):
426 # The Perl parser generally uses undefined (Python None) rather than False
427 # for boolean flags, because the value is simply left undefined, rather than
428 # explicitly set to False.
429 if value is False:
430 return None
431 return value
432
433
434 # JSON export
435
436
437 class IdlEncoder(json.JSONEncoder):
438 def default(self, obj):
439 if isinstance(obj, BaseIdl):
440 return obj.json_serializable()
441 return json.JSONEncoder.default(self, obj)
OLDNEW
« no previous file with comments | « Source/bindings/scripts/unstable/idl_compiler.py ('k') | Source/bindings/scripts/unstable/idl_definitions_builder.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698