Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright (C) 2013 Google Inc. All rights reserved. | |
|
dominicc (has gone to gerrit)
2013/06/26 04:20:53
Your comments need work.
Fragments do not work we
Nils Barth (inactive)
2013/06/26 04:43:37
Will do.
| |
| 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 | |
|
dominicc (has gone to gerrit)
2013/06/26 04:20:53
End the first line of a docstring comment with a p
| |
| 30 | |
| 31 Also JSON export. | |
| 32 """ | |
| 33 | |
| 34 # Disable attribute hiding check (else JSONEncoder default raises an error) | |
| 35 # pylint: disable=E0202 | |
| 36 | |
| 37 import abc | |
| 38 import json | |
| 39 import os.path | |
| 40 import re | |
| 41 | |
| 42 | |
| 43 # Base classes | |
| 44 | |
| 45 | |
| 46 class BaseIdl(): | |
| 47 """Abstract base class, used for JSON serialization.""" | |
| 48 __metaclass__ = abc.ABCMeta | |
| 49 | |
| 50 @abc.abstractmethod | |
| 51 def to_json(self): | |
|
dominicc (has gone to gerrit)
2013/06/26 04:20:53
Is there a better name for this? It doesn't return
Nils Barth (inactive)
2013/06/26 04:43:37
"json_serializable" is more precise; will change.
| |
| 52 """Return a serializable form of the object. | |
|
dominicc (has gone to gerrit)
2013/06/26 04:20:53
Return -> Returns
| |
| 53 | |
| 54 Compatible with Perl IR and JSON import. | |
|
dominicc (has gone to gerrit)
2013/06/26 04:20:53
Wrap text; separate paragraphs with blank lines. Y
dominicc (has gone to gerrit)
2013/06/26 04:20:53
This documentation needs to be improved.
"Compati
| |
| 55 In practice a dictionary, whose keys specify the class.""" | |
| 56 pass | |
|
dominicc (has gone to gerrit)
2013/06/26 04:20:53
It would be better to raise an exception here. If
Nils Barth (inactive)
2013/06/26 04:43:37
The ABC (Abstract Base Class) library handles this
| |
| 57 | |
| 58 | |
| 59 class TypedIdlObject(BaseIdl): | |
|
dominicc (has gone to gerrit)
2013/06/26 04:20:53
If this class handles typedefs, maybe it should ha
| |
| 60 """Auxiliary class for handling typedefs.""" | |
|
dominicc (has gone to gerrit)
2013/06/26 04:20:53
Auxiliary is a meaningless word without more conte
| |
| 61 data_type = None | |
| 62 extended_attributes = {} | |
|
dominicc (has gone to gerrit)
2013/06/26 04:20:53
Won't this hash object be shared by all instances
Nils Barth (inactive)
2013/06/26 04:43:37
(Just added this to silence lint errors; probably
| |
| 63 | |
| 64 def apply_typedefs(self, typedefs): | |
| 65 """Applies typedefs to object itself (e.g., return type of function). | |
| 66 | |
| 67 Override if calling on parameters as well.""" | |
| 68 new_extended_attributes = {} | |
| 69 # Convert string representation to and from a Type object | |
| 70 # to handle parsing | |
| 71 data_type_object = Type.from_string(self.data_type) | |
| 72 base_type = data_type_object.base_type | |
| 73 if base_type in typedefs: | |
| 74 replacement_type = typedefs[base_type] | |
| 75 data_type_object.base_type = replacement_type.data_type | |
| 76 new_extended_attributes = replacement_type.extended_attributes | |
| 77 self.data_type = str(data_type_object) | |
| 78 self.extended_attributes.update(new_extended_attributes) | |
| 79 if new_extended_attributes: | |
| 80 raise ValueError('Extended attributes in a typedef are untested!') | |
| 81 | |
| 82 | |
| 83 # IDL classes | |
| 84 | |
| 85 | |
| 86 class IdlDocument(BaseIdl): | |
| 87 def __init__(self, callback_functions=None, enumerations=None, file_name=Non e, interfaces=None, typedefs=None): | |
| 88 self.callback_functions = callback_functions or [] | |
| 89 self.enumerations = enumerations or [] | |
| 90 if file_name: | |
| 91 self.file_name = os.path.abspath(file_name) | |
| 92 self.interfaces = interfaces or [] | |
| 93 if typedefs: | |
| 94 self.apply_typedefs(typedefs) | |
| 95 | |
| 96 def apply_typedefs(self, typedefs): | |
| 97 for callback_function in self.callback_functions: | |
| 98 callback_function.apply_typedefs(typedefs) | |
| 99 for interface in self.interfaces: | |
| 100 interface.apply_typedefs(typedefs) | |
| 101 | |
| 102 def to_json(self): | |
| 103 return { | |
| 104 'idlDocument::callbackFunctions': self.callback_functions, | |
| 105 'idlDocument::enumerations': self.enumerations, | |
| 106 'idlDocument::fileName': self.file_name, | |
| 107 'idlDocument::interfaces': self.interfaces, | |
| 108 } | |
| 109 | |
| 110 | |
| 111 class CallbackFunction(TypedIdlObject): | |
| 112 def __init__(self, name=None, data_type=None, parameters=None): | |
| 113 """parameters: List of DomParameters""" | |
| 114 self.data_type = data_type | |
| 115 self.name = name or "" # FIXME: is "" needed? | |
| 116 self.parameters = parameters or [] | |
| 117 | |
| 118 def apply_typedefs(self, typedefs): | |
| 119 TypedIdlObject.apply_typedefs(self, typedefs) | |
| 120 for parameter in self.parameters: | |
| 121 parameter.apply_typedefs(typedefs) | |
| 122 raise ValueError('Typedefs in CallbackFunctions are untested!') | |
| 123 | |
| 124 def to_json(self): | |
| 125 return { | |
| 126 'callbackFunction::name': self.name, | |
| 127 'callbackFunction::type': self.data_type, | |
| 128 'callbackFunction::parameters': self.parameters, | |
| 129 } | |
| 130 | |
| 131 | |
| 132 class DomEnum(BaseIdl): | |
| 133 def __init__(self, name=None, values=None): | |
| 134 """name: enumeration identifier | |
| 135 values: enumeration values, list of unique strings | |
| 136 """ | |
| 137 self.name = name | |
| 138 self.values = values or [] | |
| 139 | |
| 140 def to_json(self): | |
| 141 return { | |
| 142 'domEnum::name': self.name, | |
| 143 'domEnum::values': self.values, | |
| 144 } | |
| 145 | |
| 146 | |
| 147 class DomInterface(BaseIdl): | |
| 148 def __init__(self, name=None, parents=None, constants=None, functions=None, attributes=None, extended_attributes=None, constructors=None, custom_constructor s=None, is_exception=None, is_callback=None, is_partial=None): | |
| 149 """ | |
| 150 attributes: list of DomAttributes | |
| 151 constants: list of DomConstants | |
| 152 constructors: list of DomFunctions | |
| 153 custom_constructors: list of DomFunctions | |
| 154 functions: list of DomFunctions | |
| 155 is_exception: used for exceptions | |
| 156 parents: list of strings | |
| 157 """ | |
| 158 self.attributes = attributes or [] | |
| 159 self.constants = constants or [] | |
| 160 self.constructors = constructors or [] | |
| 161 self.custom_constructors = custom_constructors or [] | |
| 162 self.extended_attributes = extended_attributes or {} | |
| 163 self.functions = functions or [] | |
| 164 self.is_exception = is_exception | |
| 165 self.is_callback = is_callback | |
| 166 self.is_partial = is_partial | |
| 167 self.name = name | |
| 168 self.parents = parents or [] | |
| 169 | |
| 170 def apply_typedefs(self, typedefs): | |
| 171 for constant in self.constants: | |
| 172 constant.apply_typedefs(typedefs) | |
| 173 for attribute in self.attributes: | |
| 174 attribute.apply_typedefs(typedefs) | |
| 175 for function in self.functions: | |
| 176 function.apply_typedefs(typedefs) | |
| 177 for constructor in self.constructors: | |
| 178 constructor.apply_typedefs(typedefs) | |
| 179 for custom_constructor in self.custom_constructors: | |
| 180 custom_constructor.apply_typedefs(typedefs) | |
| 181 | |
| 182 def to_json(self): | |
| 183 return { | |
| 184 'domInterface::name': self.name, | |
| 185 'domInterface::parents': self.parents, | |
| 186 'domInterface::constants': self.constants, | |
| 187 'domInterface::functions': self.functions, | |
| 188 'domInterface::attributes': self.attributes, | |
| 189 'domInterface::extendedAttributes': none_to_value_is_missing(self.ex tended_attributes), | |
| 190 'domInterface::constructors': self.constructors, | |
| 191 'domInterface::customConstructors': self.custom_constructors, | |
| 192 'domInterface::isException': boolean_to_perl(self.is_exception), | |
| 193 'domInterface::isCallback': boolean_to_perl(self.is_callback), | |
| 194 'domInterface::isPartial': self.is_partial, | |
| 195 } | |
| 196 | |
| 197 | |
| 198 class DomAttribute(TypedIdlObject): | |
| 199 def __init__(self, data_type=None, name=None, is_nullable=None, is_static=No ne, is_read_only=None, getter_exceptions=None, setter_exceptions=None, extended_ attributes=None): | |
| 200 """data_type: Attribute type (including namespace), string or UnionType | |
| 201 is_nullable: (T?) | |
| 202 getter_exceptions: Possibly raised exceptions | |
| 203 setter_exceptions: Possibly raised exceptions | |
| 204 """ | |
| 205 self.data_type = data_type | |
| 206 self.extended_attributes = extended_attributes or {} | |
| 207 self.getter_exceptions = getter_exceptions or [] | |
| 208 self.is_nullable = is_nullable | |
| 209 self.is_static = is_static | |
| 210 self.is_read_only = is_read_only | |
| 211 self.name = name | |
| 212 self.setter_exceptions = setter_exceptions or [] | |
| 213 | |
| 214 def to_json(self): | |
| 215 return { | |
| 216 'domAttribute::extendedAttributes': none_to_value_is_missing(self.ex tended_attributes), | |
| 217 'domAttribute::getterExceptions': self.getter_exceptions, | |
| 218 'domAttribute::isNullable': self.is_nullable, | |
| 219 'domAttribute::isReadOnly': self.is_read_only, | |
| 220 'domAttribute::isStatic': self.is_static, | |
| 221 'domAttribute::name': self.name, | |
| 222 'domAttribute::setterExceptions': self.setter_exceptions, | |
| 223 'domAttribute::type': self.data_type, | |
| 224 } | |
| 225 | |
| 226 | |
| 227 class DomConstant(TypedIdlObject): | |
| 228 def __init__(self, name=None, data_type=None, value=None, extended_attribute s=None): | |
| 229 self.data_type = data_type | |
| 230 self.extended_attributes = extended_attributes or {} | |
| 231 self.name = name | |
| 232 self.value = value | |
| 233 | |
| 234 def to_json(self): | |
| 235 return { | |
| 236 'domConstant::extendedAttributes': none_to_value_is_missing(self.ext ended_attributes), | |
| 237 'domConstant::name': self.name, | |
| 238 'domConstant::type': self.data_type, | |
| 239 'domConstant::value': self.value, | |
| 240 } | |
| 241 | |
| 242 | |
| 243 class DomFunction(TypedIdlObject): | |
| 244 def __init__(self, is_static=None, name=None, data_type=None, extended_attri butes=None, specials=None, parameters=None, overloaded_index=None): | |
| 245 """parameters: List of DomParameters""" | |
| 246 self.is_static = is_static | |
| 247 self.name = name or "" | |
| 248 self.data_type = data_type | |
| 249 self.extended_attributes = extended_attributes or {} | |
| 250 self.specials = specials or [] | |
| 251 self.parameters = parameters or [] | |
| 252 self.overloaded_index = overloaded_index | |
| 253 | |
| 254 def apply_typedefs(self, typedefs): | |
| 255 TypedIdlObject.apply_typedefs(self, typedefs) | |
| 256 for parameter in self.parameters: | |
| 257 parameter.apply_typedefs(typedefs) | |
| 258 | |
| 259 def to_json(self): | |
| 260 return { | |
| 261 'domFunction::extendedAttributes': none_to_value_is_missing(self.ext ended_attributes), | |
| 262 'domFunction::isStatic': boolean_to_perl(self.is_static), | |
| 263 'domFunction::name': self.name, | |
| 264 'domFunction::overloadedIndex': self.overloaded_index, | |
| 265 'domFunction::parameters': self.parameters, | |
| 266 'domFunction::specials': self.specials, | |
| 267 'domFunction::type': self.data_type, | |
| 268 } | |
| 269 | |
| 270 | |
| 271 class DomParameter(TypedIdlObject): | |
| 272 def __init__(self, name=None, data_type=None, extended_attributes=None, is_o ptional=False, is_nullable=None, is_variadic=False): | |
| 273 """Used to represent a map of 'variable name' <-> 'variable type' | |
| 274 | |
| 275 data_type: string or UnionType | |
| 276 is_optional: (optional T) | |
| 277 is_nullable: (T?) | |
| 278 is_variadic: (long... numbers) | |
| 279 """ | |
| 280 self.data_type = data_type | |
| 281 self.extended_attributes = extended_attributes or {} | |
| 282 # FIXME: boolean values are inconsistent (due to Perl), | |
| 283 # being sometimes True, False, or None (Perl: 1, 0, undef) | |
| 284 # Should all default to False, and be either True or False | |
| 285 if is_optional is None: | |
| 286 is_optional = False | |
| 287 if is_variadic is None: | |
| 288 is_variadic = False | |
| 289 self.is_nullable = is_nullable | |
| 290 # FIXME: can these be in to_json instead? | |
| 291 self.is_optional = boolean_to_perl(is_optional) | |
| 292 self.is_variadic = boolean_to_perl(is_variadic) | |
| 293 self.name = name | |
| 294 | |
| 295 def to_json(self): | |
| 296 return { | |
| 297 'domParameter::extendedAttributes': none_to_value_is_missing(self.ex tended_attributes), | |
| 298 'domParameter::isNullable': self.is_nullable, | |
| 299 'domParameter::isOptional': self.is_optional, | |
| 300 'domParameter::isVariadic': self.is_variadic, | |
| 301 'domParameter::name': self.name, | |
| 302 'domParameter::type': self.data_type, | |
| 303 } | |
| 304 | |
| 305 # Type classes | |
| 306 | |
| 307 | |
| 308 class Type(): | |
| 309 # FIXME: replace Type strings with these objects, | |
| 310 # so don't need to parse everywhere types are used. | |
| 311 # Types are stored internally as strings, not objects, | |
| 312 # e.g., as 'sequence<Foo>' or 'Foo[]', | |
| 313 # hence need to parse the string whenever a type is used. | |
| 314 # FIXME: incorporate Nullable, Variadic, etc. | |
| 315 # FIXME: properly should nest types | |
| 316 # Formally types are nested, e.g., short?[] vs. short[]?, | |
| 317 # but in practice these complex types aren't used and can treat | |
| 318 # as orthogonal properties. | |
| 319 def __init__(self, base_type=None, is_array=False, is_sequence=False): | |
| 320 if is_array and is_sequence: | |
| 321 raise ValueError('Array of Sequences not allowed.') | |
| 322 self.base_type = base_type | |
| 323 self.is_array = is_array | |
| 324 self.is_sequence = is_sequence | |
| 325 | |
| 326 def __str__(self): | |
| 327 type_string = self.base_type | |
| 328 if self.is_array: | |
| 329 type_string += '[]' | |
| 330 if self.is_sequence: | |
| 331 type_string = 'sequence<%s>' % type_string | |
| 332 return type_string | |
| 333 | |
| 334 @classmethod | |
| 335 def from_string(cls, type_string): | |
| 336 is_array = False | |
| 337 if type_string.endswith('[]'): | |
| 338 is_array = True | |
| 339 type_string = type_string[:-2] | |
| 340 | |
| 341 is_sequence = False | |
| 342 sequence_re = r'^sequence<([^>]*)>$' | |
| 343 sequence_match = re.match(sequence_re, type_string) | |
| 344 if sequence_match: | |
| 345 is_sequence = True | |
| 346 type_string = sequence_match.group(1) | |
| 347 base_type = type_string | |
| 348 return cls(base_type=base_type, is_array=is_array, is_sequence=is_sequen ce) | |
| 349 | |
| 350 | |
| 351 class Typedef(): | |
| 352 # Not exposed in bindings, internal to IDL parsing | |
| 353 def __init__(self, extended_attributes=None, data_type=None): | |
| 354 self.extended_attributes = extended_attributes or {} | |
| 355 self.data_type = data_type | |
| 356 | |
| 357 | |
| 358 class UnionType(BaseIdl): | |
| 359 def __init__(self, union_member_types=None): | |
| 360 """union_member_types: list of string or UnionType""" | |
| 361 self.union_member_types = union_member_types or [] | |
| 362 | |
| 363 def to_json(self): | |
| 364 return { | |
| 365 'UnionType::unionMemberTypes': self.union_member_types, | |
| 366 } | |
| 367 | |
| 368 | |
| 369 # Perl JSON compatiblity functions | |
| 370 # FIXME: remove when Perl removed | |
| 371 | |
| 372 def none_to_value_is_missing(extended_attributes): | |
| 373 # Perl IDL Parser uses 'VALUE_IS_MISSING' for null values in | |
| 374 # extended attributes, so add this as a filter when exporting to JSON. | |
| 375 new_extended_attributes = {} | |
| 376 for key, value in extended_attributes.iteritems(): | |
| 377 if value is None: | |
| 378 new_extended_attributes[key] = 'VALUE_IS_MISSING' | |
| 379 else: | |
| 380 new_extended_attributes[key] = value | |
| 381 return new_extended_attributes | |
| 382 | |
| 383 | |
| 384 def boolean_to_perl(value): | |
| 385 # Perl stores booleans as 1, 0, or undefined (JSON null); | |
| 386 # convert to this format | |
| 387 if value is None: | |
| 388 return None | |
| 389 return int(value) | |
| 390 | |
| 391 # JSON export | |
| 392 # FIXME: remove when Perl removed | |
| 393 # (so no longer using JSON as intermediate format) | |
| 394 | |
| 395 | |
| 396 class IdlEncoder(json.JSONEncoder): | |
| 397 def default(self, obj): | |
| 398 if isinstance(obj, BaseIdl): | |
| 399 return obj.to_json() | |
| 400 return json.JSONEncoder.default(self, obj) | |
| 401 | |
| 402 | |
| 403 def ir_to_json(ir, debug=False): | |
| 404 if debug: | |
| 405 # More legible | |
| 406 return json.dumps(ir, cls=IdlEncoder, sort_keys=True, indent=4) | |
| 407 return json.dumps(ir, cls=IdlEncoder, sort_keys=True, separators=(',', ':')) | |
| OLD | NEW |