| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 3 # for details. All rights reserved. Use of this source code is governed by a |
| 4 # BSD-style license that can be found in the LICENSE file. |
| 5 |
| 6 import os |
| 7 import sys |
| 8 |
| 9 import idl_definitions |
| 10 from idl_types import IdlType, IdlUnionType, IdlArrayOrSequenceType |
| 11 |
| 12 from compute_interfaces_info_overall import interfaces_info |
| 13 |
| 14 |
| 15 new_asts = {} |
| 16 |
| 17 |
| 18 _operation_suffix_map = { |
| 19 '__getter__': "Getter", |
| 20 '__setter__': "Setter", |
| 21 '__delete__': "Deleter", |
| 22 } |
| 23 |
| 24 class IDLNode(object): |
| 25 """Base class for all IDL elements. |
| 26 IDLNode may contain various child nodes, and have properties. Examples |
| 27 of IDLNode are interfaces, interface members, function arguments, |
| 28 etc. |
| 29 """ |
| 30 |
| 31 def __init__(self, ast): |
| 32 """Initializes an IDLNode from a PegParser AST output.""" |
| 33 self.id = self._find_first(ast, 'Id') if ast is not None else None |
| 34 |
| 35 |
| 36 def __repr__(self): |
| 37 """Generates string of the form <class id extra extra ... 0x12345678>.""" |
| 38 extras = self._extra_repr() |
| 39 if isinstance(extras, list): |
| 40 extras = ' '.join([str(e) for e in extras]) |
| 41 try: |
| 42 if self.id: |
| 43 return '<%s %s 0x%x>' % ( |
| 44 type(self).__name__, |
| 45 ('%s %s' % (self.id, extras)).strip(), |
| 46 hash(self)) |
| 47 return '<%s %s 0x%x>' % ( |
| 48 type(self).__name__, |
| 49 extras, |
| 50 hash(self)) |
| 51 except Exception, e: |
| 52 return "can't convert to string: %s" % e |
| 53 |
| 54 def _extra_repr(self): |
| 55 """Returns string of extra info for __repr__().""" |
| 56 return '' |
| 57 |
| 58 def __cmp__(self, other): |
| 59 """Override default compare operation. |
| 60 IDLNodes are equal if all their properties are equal.""" |
| 61 if other is None or not isinstance(other, IDLNode): |
| 62 return 1 |
| 63 return self.__dict__.__cmp__(other.__dict__) |
| 64 |
| 65 def reset_id(self, newId): |
| 66 """Reset the id of the Node. This is typically done during a normalization |
| 67 phase (e.g., "DOMWindow" -> "Window").""" |
| 68 self.id = newId |
| 69 |
| 70 def all(self, type_filter=None): |
| 71 """Returns a list containing this node and all it child nodes |
| 72 (recursive). |
| 73 |
| 74 Args: |
| 75 type_filter -- can be used to limit the results to a specific |
| 76 node type (e.g. IDLOperation). |
| 77 """ |
| 78 res = [] |
| 79 if type_filter is None or isinstance(self, type_filter): |
| 80 res.append(self) |
| 81 for v in self._all_subnodes(): |
| 82 if isinstance(v, IDLNode): |
| 83 res.extend(v.all(type_filter)) |
| 84 elif isinstance(v, list): |
| 85 for item in v: |
| 86 if isinstance(item, IDLNode): |
| 87 res.extend(item.all(type_filter)) |
| 88 return res |
| 89 |
| 90 def _all_subnodes(self): |
| 91 """Accessor used by all() to find subnodes.""" |
| 92 return self.__dict__.values() |
| 93 |
| 94 def to_dict(self): |
| 95 """Converts the IDLNode and its children into a dictionary. |
| 96 This method is useful mostly for debugging and pretty printing. |
| 97 """ |
| 98 res = {} |
| 99 for (k, v) in self.__dict__.items(): |
| 100 if v == None or v == False or v == [] or v == {}: |
| 101 # Skip empty/false members. |
| 102 continue |
| 103 elif isinstance(v, IDLDictNode) and not len(v): |
| 104 # Skip empty dict sub-nodes. |
| 105 continue |
| 106 elif isinstance(v, list): |
| 107 # Convert lists: |
| 108 new_v = [] |
| 109 for sub_node in v: |
| 110 if isinstance(sub_node, IDLNode): |
| 111 # Convert sub-node: |
| 112 new_v.append(sub_node.to_dict()) |
| 113 else: |
| 114 new_v.append(sub_node) |
| 115 v = new_v |
| 116 elif isinstance(v, IDLNode): |
| 117 # Convert sub-node: |
| 118 v = v.to_dict() |
| 119 res[k] = v |
| 120 return res |
| 121 |
| 122 def _find_all(self, ast, label, max_results=sys.maxint): |
| 123 """Searches the AST for tuples with a given label. The PegParser |
| 124 output is composed of lists and tuples, where the tuple 1st argument |
| 125 is a label. If ast root is a list, will search recursively inside each |
| 126 member in the list. |
| 127 |
| 128 Args: |
| 129 ast -- the AST to search. |
| 130 label -- the label to look for. |
| 131 res -- results are put into this list. |
| 132 max_results -- maximum number of results. |
| 133 """ |
| 134 res = [] |
| 135 if max_results <= 0: |
| 136 return res |
| 137 |
| 138 if isinstance(ast, list): |
| 139 for childAst in ast: |
| 140 if childAst and \ |
| 141 not(isinstance(childAst, dict)) and \ |
| 142 not(isinstance(childAst, str)) and \ |
| 143 not(isinstance(childAst, tuple)) and \ |
| 144 childAst.__module__ == "idl_definitions": |
| 145 field_name = self._convert_label_to_field(label) |
| 146 if hasattr(childAst, field_name): |
| 147 field_value = getattr(childAst, field_name) |
| 148 # It's an IdlType we need the string name of the type. |
| 149 if field_name == 'idl_type': |
| 150 field_value = getattr(field_value, 'base_type') |
| 151 res.append(field_value) |
| 152 else: |
| 153 sub_res = self._find_all(childAst, label, |
| 154 max_results - len(res)) |
| 155 res.extend(sub_res) |
| 156 elif isinstance(ast, tuple): |
| 157 (nodeLabel, value) = ast |
| 158 if nodeLabel == label: |
| 159 res.append(value) |
| 160 # TODO(terry): Seems bogus to check for so many things probably better to ju
st |
| 161 # pass in blink_compile and drive it off from that... |
| 162 elif (ast and not(isinstance(ast, dict)) and |
| 163 not(isinstance(ast, str)) and |
| 164 (ast.__module__ == "idl_definitions" or ast.__module__ == "idl_types")
): |
| 165 field_name = self._convert_label_to_field(label) |
| 166 if hasattr(ast, field_name): |
| 167 field_value = getattr(ast, field_name) |
| 168 if field_value: |
| 169 if label == 'Interface' or label == 'Enum': |
| 170 for key in field_value: |
| 171 value = field_value[key] |
| 172 res.append(value) |
| 173 elif isinstance(field_value, list): |
| 174 for item in field_value: |
| 175 res.append(item) |
| 176 elif label == 'ParentInterface' or label == 'InterfaceType': |
| 177 # Fetch the AST for the parent interface. |
| 178 parent_idlnode = new_asts[field_value] |
| 179 res.append(parent_idlnode.interfaces[field_value]) |
| 180 else: |
| 181 res.append(field_value) |
| 182 |
| 183 return res |
| 184 |
| 185 def _find_first(self, ast, label): |
| 186 """Convenience method for _find_all(..., max_results=1). |
| 187 Returns a single element instead of a list, or None if nothing |
| 188 is found.""" |
| 189 res = self._find_all(ast, label, max_results=1) |
| 190 if len(res): |
| 191 return res[0] |
| 192 return None |
| 193 |
| 194 def _has(self, ast, label): |
| 195 """Returns true if an element with the given label is |
| 196 in the AST by searching for it.""" |
| 197 return len(self._find_all(ast, label, max_results=1)) == 1 |
| 198 |
| 199 # Mapping from original AST tuple names to new AST field names idl_definitions
.Idl*. |
| 200 def _convert_label_to_field(self, label): |
| 201 label_field = { |
| 202 # Keys old AST names, Values Blink IdlInterface names. |
| 203 'ParentInterface': 'parent', |
| 204 'Id': 'name', |
| 205 'Interface': 'interfaces', |
| 206 'Callback': 'is_callback', |
| 207 'Partial': 'is_partial', |
| 208 'Operation': 'operations', |
| 209 'Attribute': 'attributes', |
| 210 'Const': 'constants', |
| 211 'Type': 'idl_type', |
| 212 'ExtAttrs': 'extended_attributes', |
| 213 'Special': 'specials', |
| 214 'ReturnType': 'idl_type', |
| 215 'Argument': 'arguments', |
| 216 'InterfaceType': 'name', |
| 217 'ConstExpr': 'value', |
| 218 'Static': 'is_static', |
| 219 'ReadOnly': 'is_read_only', |
| 220 'Optional': 'is_optional', |
| 221 'Nullable': 'is_nullable', |
| 222 'Enum': 'enumerations', |
| 223 'Annotation': '', # TODO(terry): Ignore annotation used for databa
se cache. |
| 224 'TypeDef': '', # typedef in an IDL are already resolved. |
| 225 } |
| 226 result = label_field.get(label) |
| 227 if result != '' and not(result): |
| 228 print 'FATAL ERROR: AST mapping name not found %s.' % label |
| 229 return result if result else '' |
| 230 |
| 231 def _convert_all(self, ast, label, idlnode_ctor): |
| 232 """Converts AST elements into IDLNode elements. |
| 233 Uses _find_all to find elements with a given label and converts |
| 234 them into IDLNodes with a given constructor. |
| 235 Returns: |
| 236 A list of the converted nodes. |
| 237 Args: |
| 238 ast -- the ast element to start a search at. |
| 239 label -- the element label to look for. |
| 240 idlnode_ctor -- a constructor function of one of the IDLNode |
| 241 sub-classes. |
| 242 """ |
| 243 res = [] |
| 244 found = self._find_all(ast, label) |
| 245 if not found: |
| 246 return res |
| 247 if not isinstance(found, list): |
| 248 raise RuntimeError("Expected list but %s found" % type(found)) |
| 249 for childAst in found: |
| 250 converted = idlnode_ctor(childAst) |
| 251 res.append(converted) |
| 252 return res |
| 253 |
| 254 def _convert_first(self, ast, label, idlnode_ctor): |
| 255 """Like _convert_all, but only converts the first found results.""" |
| 256 childAst = self._find_first(ast, label) |
| 257 if not childAst: |
| 258 return None |
| 259 return idlnode_ctor(childAst) |
| 260 |
| 261 def _convert_ext_attrs(self, ast): |
| 262 """Helper method for uniform conversion of extended attributes.""" |
| 263 self.ext_attrs = IDLExtAttrs(ast) |
| 264 |
| 265 def _convert_annotations(self, ast): |
| 266 """Helper method for uniform conversion of annotations.""" |
| 267 self.annotations = IDLAnnotations(ast) |
| 268 |
| 269 |
| 270 class IDLDictNode(IDLNode): |
| 271 """Base class for dictionary-like IDL nodes such as extended attributes |
| 272 and annotations. The base class implements various dict interfaces.""" |
| 273 |
| 274 def __init__(self, ast): |
| 275 IDLNode.__init__(self, None) |
| 276 if ast is not None and isinstance(ast, dict): |
| 277 self.__map = ast |
| 278 else: |
| 279 self.__map = {} |
| 280 |
| 281 def __len__(self): |
| 282 return len(self.__map) |
| 283 |
| 284 def __getitem__(self, key): |
| 285 return self.__map[key] |
| 286 |
| 287 def __setitem__(self, key, value): |
| 288 self.__map[key] = value |
| 289 |
| 290 def __delitem__(self, key): |
| 291 del self.__map[key] |
| 292 |
| 293 def __contains__(self, key): |
| 294 return key in self.__map |
| 295 |
| 296 def __iter__(self): |
| 297 return self.__map.__iter__() |
| 298 |
| 299 def get(self, key, default=None): |
| 300 return self.__map.get(key, default) |
| 301 |
| 302 def setdefault(self, key, value=None): |
| 303 return self.__map.setdefault(key, value) |
| 304 |
| 305 def items(self): |
| 306 return self.__map.items() |
| 307 |
| 308 def keys(self): |
| 309 return self.__map.keys() |
| 310 |
| 311 def values(self): |
| 312 return self.__map.values() |
| 313 |
| 314 def clear(self): |
| 315 self.__map = {} |
| 316 |
| 317 def to_dict(self): |
| 318 """Overrides the default IDLNode.to_dict behavior. |
| 319 The IDLDictNode members are copied into a new dictionary, and |
| 320 IDLNode members are recursively converted into dicts as well. |
| 321 """ |
| 322 res = {} |
| 323 for (k, v) in self.__map.items(): |
| 324 if isinstance(v, IDLNode): |
| 325 v = v.to_dict() |
| 326 res[k] = v |
| 327 return res |
| 328 |
| 329 def _all_subnodes(self): |
| 330 # Usually an IDLDictNode does not contain further IDLNodes. |
| 331 return [] |
| 332 |
| 333 |
| 334 class IDLFile(IDLNode): |
| 335 """IDLFile is the top-level node in each IDL file. It may contain interfaces."
"" |
| 336 |
| 337 DART_IDL = 'dart.idl' |
| 338 |
| 339 def __init__(self, ast, filename=None): |
| 340 IDLNode.__init__(self, ast) |
| 341 self.filename = filename |
| 342 |
| 343 filename_basename = os.path.basename(filename) |
| 344 |
| 345 self.interfaces = self._convert_all(ast, 'Interface', IDLInterface) |
| 346 |
| 347 is_blink = not(isinstance(ast, list)) and ast.__module__ == 'idl_definitions
' |
| 348 |
| 349 if is_blink: |
| 350 # implements is handled by the interface merging step (see the function |
| 351 # merge_interface_dependencies). |
| 352 for interface in self.interfaces: |
| 353 blink_interface = ast.interfaces.get(interface.id) |
| 354 if filename_basename == self.DART_IDL: |
| 355 # Special handling for dart.idl we need to remember the interface, |
| 356 # since we could have many (not one interface / file). Then build up |
| 357 # the IDLImplementsStatement for any implements in dart.idl. |
| 358 interface_info = interfaces_info['__dart_idl___']; |
| 359 |
| 360 self.implementsStatements = [] |
| 361 |
| 362 implement_pairs = interface_info['implement_pairs'] |
| 363 for implement_pair in implement_pairs: |
| 364 interface_name = implement_pair[0] |
| 365 implemented_name = implement_pair[1] |
| 366 |
| 367 implementor = new_asts[interface_name].interfaces.get(interface_name
) |
| 368 implement_statement = self._createImplementsStatement(implementor, |
| 369 implemented_na
me) |
| 370 |
| 371 self.implementsStatements.append(implement_statement) |
| 372 else: |
| 373 interface_info = interfaces_info[interface.id] |
| 374 |
| 375 implements = interface_info['implements_interfaces'] |
| 376 if not(blink_interface.is_partial) and len(implements) > 0: |
| 377 implementor = new_asts[interface.id].interfaces.get(interface.id) |
| 378 |
| 379 self.implementsStatements = [] |
| 380 |
| 381 # TODO(terry): Need to handle more than one implements. |
| 382 for implemented_name in implements: |
| 383 implement_statement = self._createImplementsStatement(implementor, |
| 384 implemented_
name) |
| 385 self.implementsStatements.append(implement_statement) |
| 386 else: |
| 387 self.implementsStatements = [] |
| 388 else: |
| 389 self.implementsStatements = self._convert_all(ast, 'ImplStmt', |
| 390 IDLImplementsStatement) |
| 391 |
| 392 # No reason to handle typedef they're already aliased in Blink's AST. |
| 393 self.typeDefs = [] if is_blink else self._convert_all(ast, 'TypeDef', IDLTyp
eDef) |
| 394 |
| 395 self.enums = self._convert_all(ast, 'Enum', IDLEnum) |
| 396 |
| 397 def _createImplementsStatement(self, implementor, implemented_name): |
| 398 implemented = new_asts[implemented_name].interfaces.get(implemented_name) |
| 399 |
| 400 implement_statement = IDLImplementsStatement(implemented) |
| 401 |
| 402 implement_statement.implementor = IDLType(implementor) |
| 403 implement_statement.implemented = IDLType(implemented) |
| 404 |
| 405 return implement_statement |
| 406 |
| 407 |
| 408 class IDLModule(IDLNode): |
| 409 """IDLModule has an id, and may contain interfaces, type defs and |
| 410 implements statements.""" |
| 411 def __init__(self, ast): |
| 412 IDLNode.__init__(self, ast) |
| 413 self._convert_ext_attrs(ast) |
| 414 self._convert_annotations(ast) |
| 415 self.interfaces = self._convert_all(ast, 'Interface', IDLInterface) |
| 416 |
| 417 is_blink = ast.__module__ == 'idl_definitions' |
| 418 |
| 419 # No reason to handle typedef they're already aliased in Blink's AST. |
| 420 self.typeDefs = [] if is_blink else self._convert_all(ast, 'TypeDef', IDLTyp
eDef) |
| 421 |
| 422 self.enums = self._convert_all(ast, 'Enum', IDLNode) |
| 423 |
| 424 if is_blink: |
| 425 # implements is handled by the interface merging step (see the function |
| 426 # merge_interface_dependencies). |
| 427 for interface in self.interfaces: |
| 428 interface_info = interfaces_info[interface.id] |
| 429 # TODO(terry): Same handling for implementsStatements as in IDLFile? |
| 430 self.implementsStatements = interface_info['implements_interfaces'] |
| 431 else: |
| 432 self.implementsStatements = self._convert_all(ast, 'ImplStmt', |
| 433 IDLImplementsStatement) |
| 434 |
| 435 |
| 436 class IDLExtAttrs(IDLDictNode): |
| 437 """IDLExtAttrs is an IDLDictNode that stores IDL Extended Attributes. |
| 438 Modules, interfaces, members and arguments can all own IDLExtAttrs.""" |
| 439 def __init__(self, ast=None): |
| 440 IDLDictNode.__init__(self, None) |
| 441 if not ast: |
| 442 return |
| 443 if not(isinstance(ast, list)) and ast.__module__ == "idl_definitions": |
| 444 # Pull out extended attributes from Blink AST. |
| 445 for name, value in ast.extended_attributes.items(): |
| 446 # TODO(terry): Handle constructors... |
| 447 if name == 'NamedConstructor' or name == 'Constructor': |
| 448 for constructor in ast.constructors: |
| 449 if constructor.name == 'NamedConstructor': |
| 450 constructor_name = ast.extended_attributes['NamedConstructor'] |
| 451 else: |
| 452 constructor_name = None |
| 453 func_value = IDLExtAttrFunctionValue(constructor_name, constructor.a
rguments, True) |
| 454 if name == 'Constructor': |
| 455 self.setdefault('Constructor', []).append(func_value) |
| 456 else: |
| 457 self[name] = func_value |
| 458 else: |
| 459 self[name] = value |
| 460 else: |
| 461 ext_attrs_ast = self._find_first(ast, 'ExtAttrs') |
| 462 if not ext_attrs_ast: |
| 463 return |
| 464 for ext_attr in self._find_all(ext_attrs_ast, 'ExtAttr'): |
| 465 name = self._find_first(ext_attr, 'Id') |
| 466 value = self._find_first(ext_attr, 'ExtAttrValue') |
| 467 |
| 468 if name == 'Constructor': |
| 469 # There might be multiple constructor attributes, collect them |
| 470 # as a list. Represent plain Constructor attribute |
| 471 # (without any signature) as None. |
| 472 assert value is None |
| 473 func_value = None |
| 474 ctor_args = self._find_first(ext_attr, 'ExtAttrArgList') |
| 475 if ctor_args: |
| 476 func_value = IDLExtAttrFunctionValue(None, ctor_args) |
| 477 self.setdefault('Constructor', []).append(func_value) |
| 478 continue |
| 479 |
| 480 func_value = self._find_first(value, 'ExtAttrFunctionValue') |
| 481 if func_value: |
| 482 # E.g. NamedConstructor=Audio(optional DOMString src) |
| 483 self[name] = IDLExtAttrFunctionValue( |
| 484 func_value, |
| 485 self._find_first(func_value, 'ExtAttrArgList')) |
| 486 continue |
| 487 |
| 488 self[name] = value |
| 489 |
| 490 def _all_subnodes(self): |
| 491 # Extended attributes may contain IDLNodes, e.g. IDLExtAttrFunctionValue |
| 492 return self.values() |
| 493 |
| 494 |
| 495 class IDLExtAttrFunctionValue(IDLNode): |
| 496 """IDLExtAttrFunctionValue.""" |
| 497 def __init__(self, func_value_ast, arg_list_ast, is_blink=False): |
| 498 IDLNode.__init__(self, func_value_ast) |
| 499 if is_blink: |
| 500 # Blink path |
| 501 self.id = func_value_ast # func_value_ast is the function name for Blink
. |
| 502 self.arguments = [] |
| 503 for argument in arg_list_ast: |
| 504 self.arguments.append(IDLArgument(argument)) |
| 505 else: |
| 506 self.arguments = self._convert_all(arg_list_ast, 'Argument', IDLArgument) |
| 507 |
| 508 |
| 509 class IDLType(IDLNode): |
| 510 """IDLType is used to describe constants, attributes and operations' |
| 511 return and input types. IDLType matches AST labels such as ScopedName, |
| 512 StringType, VoidType, IntegerType, etc.""" |
| 513 |
| 514 def __init__(self, ast): |
| 515 IDLNode.__init__(self, ast) |
| 516 |
| 517 self.nullable = self._has(ast, 'Nullable') |
| 518 # Search for a 'ScopedName' or any label ending with 'Type'. |
| 519 if isinstance(ast, list): |
| 520 self.id = self._find_first(ast, 'ScopedName') |
| 521 if not self.id: |
| 522 # FIXME: use regexp search instead |
| 523 def findType(ast): |
| 524 for label, childAst in ast: |
| 525 if label.endswith('Type'): |
| 526 type = self._label_to_type(label, ast) |
| 527 if type != 'sequence': |
| 528 return type |
| 529 type_ast = self._find_first(childAst, 'Type') |
| 530 if not type_ast: |
| 531 return type |
| 532 return 'sequence<%s>' % findType(type_ast) |
| 533 raise Exception('No type declaration found in %s' % ast) |
| 534 self.id = findType(ast) |
| 535 # TODO(terry): Remove array_modifiers id has [] appended, keep for old |
| 536 # parsing. |
| 537 array_modifiers = self._find_first(ast, 'ArrayModifiers') |
| 538 if array_modifiers: |
| 539 self.id += array_modifiers |
| 540 elif isinstance(ast, tuple): |
| 541 (label, value) = ast |
| 542 if label == 'ScopedName': |
| 543 self.id = value |
| 544 else: |
| 545 self.id = self._label_to_type(label, ast) |
| 546 elif isinstance(ast, str): |
| 547 self.id = ast |
| 548 # New blink handling. |
| 549 elif ast.__module__ == "idl_types": |
| 550 if isinstance(ast, IdlType) or isinstance(ast, IdlArrayOrSequenceType): |
| 551 type_name = str(ast) |
| 552 |
| 553 # TODO(terry): For now don't handle unrestricted types see |
| 554 # https://code.google.com/p/chromium/issues/detail?id=35429
8 |
| 555 type_name = type_name.replace('unrestricted ', '', 1); |
| 556 |
| 557 # TODO(terry): Handled ScalarValueString as a DOMString. |
| 558 type_name = type_name.replace('ScalarValueString', 'DOMString', 1) |
| 559 |
| 560 self.id = type_name |
| 561 else: |
| 562 # IdlUnionType |
| 563 if ast.is_union_type: |
| 564 print 'WARNING type %s is union mapped to \'any\'' % self.id |
| 565 # TODO(terry): For union types use any otherwise type is unionType is |
| 566 # not found and is removed during merging. |
| 567 self.id = 'any' |
| 568 # TODO(terry): Any union type e.g. 'type1 or type2 or type2', |
| 569 # 'typedef (Type1 or Type2) UnionType' |
| 570 # Is a problem we need to extend IDLType and IDLTypeDef to handle more |
| 571 # than one type. |
| 572 # |
| 573 # Also for typedef's e.g., |
| 574 # typedef (Type1 or Type2) UnionType |
| 575 # should consider synthesizing a new interface (e.g., UnionType) that's |
| 576 # both Type1 and Type2. |
| 577 if not self.id: |
| 578 print '>>>> __module__ %s' % ast.__module__ |
| 579 raise SyntaxError('Could not parse type %s' % (ast)) |
| 580 |
| 581 def _label_to_type(self, label, ast): |
| 582 if label == 'LongLongType': |
| 583 label = 'long long' |
| 584 elif label.endswith('Type'): |
| 585 # Omit 'Type' suffix and lowercase the rest. |
| 586 label = '%s%s' % (label[0].lower(), label[1:-4]) |
| 587 |
| 588 # Add unsigned qualifier. |
| 589 if self._has(ast, 'Unsigned'): |
| 590 label = 'unsigned %s' % label |
| 591 return label |
| 592 |
| 593 |
| 594 class IDLEnum(IDLNode): |
| 595 """IDLNode for 'enum [id] { [string]+ }'""" |
| 596 def __init__(self, ast): |
| 597 IDLNode.__init__(self, ast) |
| 598 self._convert_annotations(ast) |
| 599 if not(isinstance(ast, list)) and ast.__module__ == "idl_definitions": |
| 600 # Blink AST |
| 601 self.values = ast.values |
| 602 else: |
| 603 self.values = self._find_all(ast, 'StringLiteral') |
| 604 |
| 605 # TODO(terry): Need to handle emitting of enums for dart:html |
| 606 |
| 607 |
| 608 class IDLTypeDef(IDLNode): |
| 609 """IDLNode for 'typedef [type] [id]' declarations.""" |
| 610 def __init__(self, ast): |
| 611 IDLNode.__init__(self, ast) |
| 612 self._convert_annotations(ast) |
| 613 self.type = self._convert_first(ast, 'Type', IDLType) |
| 614 |
| 615 |
| 616 class IDLInterface(IDLNode): |
| 617 """IDLInterface node contains operations, attributes, constants, |
| 618 as well as parent references.""" |
| 619 |
| 620 def __init__(self, ast): |
| 621 IDLNode.__init__(self, ast) |
| 622 self._convert_ext_attrs(ast) |
| 623 self._convert_annotations(ast) |
| 624 |
| 625 self.parents = self._convert_all(ast, 'ParentInterface', |
| 626 IDLParentInterface) |
| 627 |
| 628 javascript_interface_name = self.ext_attrs.get('InterfaceName', self.id) |
| 629 self.javascript_binding_name = javascript_interface_name |
| 630 self.doc_js_name = javascript_interface_name |
| 631 |
| 632 if not (self._find_first(ast, 'Callback') is None): |
| 633 self.ext_attrs['Callback'] = None |
| 634 if not (self._find_first(ast, 'Partial') is None): |
| 635 self.is_supplemental = True |
| 636 self.ext_attrs['DartSupplemental'] = None |
| 637 |
| 638 self.operations = self._convert_all(ast, 'Operation', |
| 639 lambda ast: IDLOperation(ast, self.doc_js_name)) |
| 640 self.attributes = self._convert_all(ast, 'Attribute', |
| 641 lambda ast: IDLAttribute(ast, self.doc_js_name)) |
| 642 self.constants = self._convert_all(ast, 'Const', |
| 643 lambda ast: IDLConstant(ast, self.doc_js_name)) |
| 644 self.is_supplemental = 'DartSupplemental' in self.ext_attrs |
| 645 self.is_no_interface_object = 'NoInterfaceObject' in self.ext_attrs |
| 646 |
| 647 |
| 648 def reset_id(self, new_id): |
| 649 """Reset the id of the Interface and corresponding the JS names.""" |
| 650 if self.id != new_id: |
| 651 self.id = new_id |
| 652 self.doc_js_name = new_id |
| 653 self.javascript_binding_name = new_id |
| 654 for member in self.operations: |
| 655 member.doc_js_interface_name = new_id |
| 656 for member in self.attributes: |
| 657 member.doc_js_interface_name = new_id |
| 658 for member in self.constants: |
| 659 member.doc_js_interface_name = new_id |
| 660 |
| 661 def has_attribute(self, candidate): |
| 662 for attribute in self.attributes: |
| 663 if (attribute.id == candidate.id and |
| 664 attribute.is_read_only == candidate.is_read_only): |
| 665 return True |
| 666 return False |
| 667 |
| 668 |
| 669 class IDLParentInterface(IDLNode): |
| 670 """This IDLNode specialization is for 'Interface Child : Parent {}' |
| 671 declarations.""" |
| 672 def __init__(self, ast): |
| 673 IDLNode.__init__(self, ast) |
| 674 self._convert_annotations(ast) |
| 675 self.type = self._convert_first(ast, 'InterfaceType', IDLType) |
| 676 |
| 677 |
| 678 class IDLMember(IDLNode): |
| 679 """A base class for constants, attributes and operations.""" |
| 680 |
| 681 def __init__(self, ast, doc_js_interface_name): |
| 682 IDLNode.__init__(self, ast) |
| 683 |
| 684 self.type = self._convert_first(ast, 'Type', IDLType) |
| 685 self._convert_ext_attrs(ast) |
| 686 self._convert_annotations(ast) |
| 687 self.doc_js_interface_name = doc_js_interface_name |
| 688 self.is_static = self._has(ast, 'Static') |
| 689 |
| 690 |
| 691 class IDLOperation(IDLMember): |
| 692 """IDLNode specialization for 'type name(args)' declarations.""" |
| 693 def __init__(self, ast, doc_js_interface_name): |
| 694 IDLMember.__init__(self, ast, doc_js_interface_name) |
| 695 |
| 696 self.type = self._convert_first(ast, 'ReturnType', IDLType) |
| 697 self.arguments = self._convert_all(ast, 'Argument', IDLArgument) |
| 698 self.specials = self._find_all(ast, 'Special') |
| 699 # Special case: there are getters of the form |
| 700 # getter <ReturnType>(args). For now force the name to be __getter__, |
| 701 # but it should be operator[] later. |
| 702 if self.id is None: |
| 703 if self.specials == ['getter']: |
| 704 if self.ext_attrs.get('Custom') == 'PropertyQuery': |
| 705 # Handling __propertyQuery__ the extended attribute is: |
| 706 # [Custom=PropertyQuery] getter boolean (DOMString name); |
| 707 self.id = '__propertyQuery__' |
| 708 else: |
| 709 self.id = '__getter__' |
| 710 elif self.specials == ['setter']: |
| 711 self.id = '__setter__' |
| 712 # Special case: if it's a setter, ignore 'declared' return type |
| 713 self.type = IDLType([('VoidType', None)]) |
| 714 elif self.specials == ['deleter']: |
| 715 self.id = '__delete__' |
| 716 else: |
| 717 raise Exception('Cannot handle %s: operation has no id' % ast) |
| 718 |
| 719 if len(self.arguments) >= 1 and (self.id in _operation_suffix_map) and not
self.ext_attrs.get('ImplementedAs'): |
| 720 arg = self.arguments[0] |
| 721 operation_category = 'Named' if arg.type.id == 'DOMString' else 'Indexed
' |
| 722 self.ext_attrs.setdefault('ImplementedAs', 'anonymous%s%s' % (operation_
category, _operation_suffix_map[self.id])) |
| 723 |
| 724 def _extra_repr(self): |
| 725 return [self.arguments] |
| 726 |
| 727 def SameSignatureAs(self, operation): |
| 728 if self.type != operation.type: |
| 729 return False |
| 730 return [a.type for a in self.arguments] == [a.type for a in operation.argume
nts] |
| 731 |
| 732 class IDLAttribute(IDLMember): |
| 733 """IDLNode specialization for 'attribute type name' declarations.""" |
| 734 def __init__(self, ast, doc_js_interface_name): |
| 735 IDLMember.__init__(self, ast, doc_js_interface_name) |
| 736 self.is_read_only = self._has(ast, 'ReadOnly') |
| 737 # There are various ways to define exceptions for attributes: |
| 738 |
| 739 def _extra_repr(self): |
| 740 extra = [] |
| 741 if self.is_read_only: extra.append('readonly') |
| 742 return extra |
| 743 |
| 744 |
| 745 class IDLConstant(IDLMember): |
| 746 """IDLNode specialization for 'const type name = value' declarations.""" |
| 747 def __init__(self, ast, doc_js_interface_name): |
| 748 IDLMember.__init__(self, ast, doc_js_interface_name) |
| 749 self.value = self._find_first(ast, 'ConstExpr') |
| 750 |
| 751 |
| 752 class IDLArgument(IDLNode): |
| 753 """IDLNode specialization for operation arguments.""" |
| 754 def __init__(self, ast): |
| 755 IDLNode.__init__(self, ast) |
| 756 |
| 757 self.default_value = None |
| 758 self.default_value_is_null = False |
| 759 # Handle the 'argType arg = default'. IDL syntax changed from |
| 760 # [default=NullString]. |
| 761 if not isinstance(ast, list): |
| 762 if isinstance(ast.default_value, idl_definitions.IdlLiteral) and ast.defau
lt_value: |
| 763 self.default_value = ast.default_value.value |
| 764 self.default_value_is_null = ast.default_value.is_null |
| 765 elif 'Default' in ast.extended_attributes: |
| 766 # Work around [Default=Undefined] for arguments - only look in the model
's |
| 767 # default_value |
| 768 self.default_value = ast.extended_attributes.get('Default') |
| 769 self.default_value_is_null = False |
| 770 |
| 771 self.type = self._convert_first(ast, 'Type', IDLType) |
| 772 self.optional = self._has(ast, 'Optional') |
| 773 self._convert_ext_attrs(ast) |
| 774 # TODO(vsm): Recover this from the type instead. |
| 775 if 'Callback' in self.type.id: |
| 776 self.ext_attrs['Callback'] = None |
| 777 |
| 778 def __repr__(self): |
| 779 return '<IDLArgument(type = %s, id = %s)>' % (self.type, self.id) |
| 780 |
| 781 |
| 782 class IDLImplementsStatement(IDLNode): |
| 783 """IDLNode specialization for 'IMPLEMENTOR implements IMPLEMENTED' declaration
s.""" |
| 784 def __init__(self, ast): |
| 785 IDLNode.__init__(self, ast) |
| 786 if isinstance(ast, list) or ast.__module__ != 'idl_definitions': |
| 787 self.implementor = self._convert_first(ast, 'ImplStmtImplementor', IDLType
) |
| 788 self.implemented = self._convert_first(ast, 'ImplStmtImplemented', IDLType
) |
| 789 |
| 790 |
| 791 class IDLAnnotations(IDLDictNode): |
| 792 """IDLDictNode specialization for a list of FremontCut annotations.""" |
| 793 def __init__(self, ast=None): |
| 794 IDLDictNode.__init__(self, ast) |
| 795 self.id = None |
| 796 if not ast: |
| 797 return |
| 798 for annotation in self._find_all(ast, 'Annotation'): |
| 799 name = self._find_first(annotation, 'Id') |
| 800 value = IDLAnnotation(annotation) |
| 801 self[name] = value |
| 802 |
| 803 |
| 804 class IDLAnnotation(IDLDictNode): |
| 805 """IDLDictNode specialization for one annotation.""" |
| 806 def __init__(self, ast=None): |
| 807 IDLDictNode.__init__(self, ast) |
| 808 self.id = None |
| 809 if not ast: |
| 810 return |
| 811 for arg in self._find_all(ast, 'AnnotationArg'): |
| 812 name = self._find_first(arg, 'Id') |
| 813 value = self._find_first(arg, 'AnnotationArgValue') |
| 814 self[name] = value |
| OLD | NEW |