| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 4 # BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 """This module generates Dart APIs from the IDL database.""" | 6 """This module generates Dart APIs from the IDL database.""" |
| 7 | 7 |
| 8 import emitter | 8 import emitter |
| 9 import idlnode | 9 import idlnode |
| 10 import logging | 10 import logging |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 'FileReader': '', | 74 'FileReader': '', |
| 75 'XMLHttpRequest': '', | 75 'XMLHttpRequest': '', |
| 76 'WebKitCSSMatrix': '[String spec]', | 76 'WebKitCSSMatrix': '[String spec]', |
| 77 'WebKitPoint': 'num x, num y', | 77 'WebKitPoint': 'num x, num y', |
| 78 # dart:html types | 78 # dart:html types |
| 79 'CSSMatrix': '[String spec]', | 79 'CSSMatrix': '[String spec]', |
| 80 'Point': 'num x, num y', | 80 'Point': 'num x, num y', |
| 81 } | 81 } |
| 82 | 82 |
| 83 # | 83 # |
| 84 # Interface version of the DOM needs to delegate typed array constructors to a | |
| 85 # factory provider. | |
| 86 # | |
| 87 _interface_factories = { | |
| 88 'Float32Array': '_TypedArrayFactoryProvider', | |
| 89 'Float64Array': '_TypedArrayFactoryProvider', | |
| 90 'Int8Array': '_TypedArrayFactoryProvider', | |
| 91 'Int16Array': '_TypedArrayFactoryProvider', | |
| 92 'Int32Array': '_TypedArrayFactoryProvider', | |
| 93 'Uint8Array': '_TypedArrayFactoryProvider', | |
| 94 'Uint16Array': '_TypedArrayFactoryProvider', | |
| 95 'Uint32Array': '_TypedArrayFactoryProvider', | |
| 96 } | |
| 97 | |
| 98 # | |
| 99 # Custom methods that must be implemented by hand. | 84 # Custom methods that must be implemented by hand. |
| 100 # | 85 # |
| 101 _custom_methods = set([ | 86 _custom_methods = set([ |
| 102 ('DOMWindow', 'setInterval'), | 87 ('DOMWindow', 'setInterval'), |
| 103 ('DOMWindow', 'setTimeout'), | 88 ('DOMWindow', 'setTimeout'), |
| 104 ('WorkerContext', 'setInterval'), | 89 ('WorkerContext', 'setInterval'), |
| 105 ('WorkerContext', 'setTimeout'), | 90 ('WorkerContext', 'setTimeout'), |
| 106 ('CanvasRenderingContext2D', 'setFillStyle'), | 91 ('CanvasRenderingContext2D', 'setFillStyle'), |
| 107 ('CanvasRenderingContext2D', 'setStrokeStyle'), | 92 ('CanvasRenderingContext2D', 'setStrokeStyle'), |
| 108 ('CanvasRenderingContext2D', 'setFillStyle'), | 93 ('CanvasRenderingContext2D', 'setFillStyle'), |
| 109 ]) | 94 ]) |
| 110 | 95 |
| 111 # | 96 # |
| 112 # Custom getters that must be implemented by hand. | 97 # Custom getters that must be implemented by hand. |
| 113 # | 98 # |
| 114 _custom_getters = set([ | 99 _custom_getters = set([ |
| 115 ('DOMWindow', 'localStorage'), | 100 ('DOMWindow', 'localStorage'), |
| 116 ]) | 101 ]) |
| 117 | 102 |
| 118 # | 103 # |
| 119 # Custom native specs for the Frog dom. | 104 # Custom native specs for the Frog dom. |
| 120 # | 105 # |
| 121 _frog_dom_custom_native_specs = { | 106 _frog_dom_custom_native_specs = { |
| 122 'Console': '=console', # Decorate the singleton Console object. | 107 'Console': '=console', # Decorate the singleton Console object. |
| 123 'DOMWindow': '@*DOMWindow', # DOMWindow aliased with global scope. | 108 'DOMWindow': '@*DOMWindow', # DOMWindow aliased with global scope. |
| 124 | |
| 125 # Temporary hack: make these not be 'hidden'. Will not work on IE9. | |
| 126 'Float32Array': 'Float32Array', | |
| 127 'Float64Array': 'Float64Array', | |
| 128 'Int8Array': 'Int8Array', | |
| 129 'Int16Array': 'Int16Array', | |
| 130 'Int32Array': 'Int32Array', | |
| 131 'Uint8Array': 'Uint8Array', | |
| 132 'Uint16Array': 'Uint16Array', | |
| 133 'Uint32Array': 'Uint32Array', | |
| 134 } | 109 } |
| 135 | 110 |
| 136 # | 111 # |
| 137 # Publically visible types common across all supported browsers. | 112 # Publically visible types common across all supported browsers. |
| 138 # | 113 # |
| 139 _BROWSER_SHARED_TYPES = [ | 114 _BROWSER_SHARED_TYPES = [ |
| 140 'Attr', | 115 'Attr', |
| 141 'CDATASection', | 116 'CDATASection', |
| 142 'CSSFontFaceRule', | 117 'CSSFontFaceRule', |
| 143 'CSSImportRule', | 118 'CSSImportRule', |
| (...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 if attr.type.id == 'EventListener': continue | 703 if attr.type.id == 'EventListener': continue |
| 729 if attr.is_fc_getter: | 704 if attr.is_fc_getter: |
| 730 for generator in generators: | 705 for generator in generators: |
| 731 generator.AddGetter(attr) | 706 generator.AddGetter(attr) |
| 732 elif attr.is_fc_setter: | 707 elif attr.is_fc_setter: |
| 733 for generator in generators: | 708 for generator in generators: |
| 734 generator.AddSetter(attr) | 709 generator.AddSetter(attr) |
| 735 | 710 |
| 736 # The implementation should define an indexer if the interface directly | 711 # The implementation should define an indexer if the interface directly |
| 737 # extends List. | 712 # extends List. |
| 738 element_type = MaybeListElementType(interface) | 713 for parent in interface.parents: |
| 739 if element_type: | 714 match = re.match(r'List<(\w*)>$', parent.type.id) |
| 740 for generator in generators: | 715 if match: |
| 741 generator.AddIndexer(element_type) | 716 element_type = match.group(1) |
| 717 for generator in generators: |
| 718 generator.AddIndexer(element_type) |
| 719 break |
| 742 | 720 |
| 743 # Group overloaded operations by id | 721 # Group overloaded operations by id |
| 744 operationsById = {} | 722 operationsById = {} |
| 745 for operation in interface.operations: | 723 for operation in interface.operations: |
| 746 if operation.id not in operationsById: | 724 if operation.id not in operationsById: |
| 747 operationsById[operation.id] = [] | 725 operationsById[operation.id] = [] |
| 748 operationsById[operation.id].append(operation) | 726 operationsById[operation.id].append(operation) |
| 749 | 727 |
| 750 # Generate operations | 728 # Generate operations |
| 751 for id in sorted(operationsById.keys()): | 729 for id in sorted(operationsById.keys()): |
| 752 operations = operationsById[id] | 730 operations = operationsById[id] |
| 753 info = self._AnalyzeOperation(interface, operations) | 731 info = self._AnalyzeOperation(interface, operations) |
| 754 for generator in generators: | 732 for generator in generators: |
| 755 generator.AddOperation(info) | 733 generator.AddOperation(info) |
| 756 | 734 |
| 757 # With multiple inheritance, attributes and operations of non-first | 735 # With multiple inheritance, attributes and operations of non-first |
| 758 # interfaces need to be added. Sometimes the attribute or operation is | 736 # interfaces need to be added. Sometimes the attribute or operation is |
| 759 # defined in the current interface as well as a parent. In that case we | 737 # defined in the current interface as well as a parent. In that case we |
| 760 # avoid making a duplicate definition and pray that the signatures match. | 738 # avoid making a duplicate definition and pray that the signatures match. |
| 761 | 739 |
| 762 for parent_interface in self._TransitiveSecondaryParents(interface): | 740 for parent_interface in self._TransitiveSecondaryParents(interface): |
| 763 if isinstance(parent_interface, str): # _IsDartCollectionType(parent_inte
rface) | 741 if isinstance(interface, str): # _IsDartCollectionType(parent_interface) |
| 764 continue | 742 continue |
| 765 attributes = sorted(parent_interface.attributes, | 743 attributes = sorted(parent_interface.attributes, |
| 766 AttributeOutputOrder) | 744 AttributeOutputOrder) |
| 767 for attr in attributes: | 745 for attr in attributes: |
| 768 if not self._DefinesSameAttribute(interface, attr): | 746 if not self._DefinesSameAttribute(interface, attr): |
| 769 if attr.is_fc_getter: | 747 if attr.is_fc_getter: |
| 770 for generator in generators: | 748 for generator in generators: |
| 771 generator.AddSecondaryGetter(parent_interface, attr) | 749 generator.AddSecondaryGetter(parent_interface, attr) |
| 772 elif attr.is_fc_setter: | 750 elif attr.is_fc_setter: |
| 773 for generator in generators: | 751 for generator in generators: |
| (...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1314 type_name: A string, the name of the return type of the operation. | 1292 type_name: A string, the name of the return type of the operation. |
| 1315 arg_declarations: A list of strings, Dart argument declarations for the | 1293 arg_declarations: A list of strings, Dart argument declarations for the |
| 1316 member that implements the set of overloads. Each string is of the form | 1294 member that implements the set of overloads. Each string is of the form |
| 1317 "T arg" or "T arg = null". | 1295 "T arg" or "T arg = null". |
| 1318 arg_infos: A list of (name, type, default_value) tuples. | 1296 arg_infos: A list of (name, type, default_value) tuples. |
| 1319 default_value is None for mandatory arguments. | 1297 default_value is None for mandatory arguments. |
| 1320 """ | 1298 """ |
| 1321 pass | 1299 pass |
| 1322 | 1300 |
| 1323 | 1301 |
| 1324 def MaybeListElementType(interface): | |
| 1325 """Returns the List element type T, or None in interface does not implement | |
| 1326 List<T>. | |
| 1327 """ | |
| 1328 for parent in interface.parents: | |
| 1329 match = re.match(r'List<(\w*)>$', parent.type.id) | |
| 1330 if match: | |
| 1331 return match.group(1) | |
| 1332 return None | |
| 1333 | |
| 1334 def MaybeTypedArrayElementType(interface): | |
| 1335 """Returns the typed array element type, or None in interface is not a | |
| 1336 TypedArray. | |
| 1337 """ | |
| 1338 # Typed arrays implement ArrayBufferView and List<T>. | |
| 1339 for parent in interface.parents: | |
| 1340 if parent.type.id == 'ArrayBufferView': | |
| 1341 return MaybeListElementType(interface) | |
| 1342 return None | |
| 1343 | |
| 1344 | |
| 1345 def AttributeOutputOrder(a, b): | 1302 def AttributeOutputOrder(a, b): |
| 1346 """Canonical output ordering for attributes.""" | 1303 """Canonical output ordering for attributes.""" |
| 1347 # Getters before setters: | 1304 # Getters before setters: |
| 1348 if a.id < b.id: return -1 | 1305 if a.id < b.id: return -1 |
| 1349 if a.id > b.id: return 1 | 1306 if a.id > b.id: return 1 |
| 1350 if a.is_fc_setter < b.is_fc_setter: return -1 | 1307 if a.is_fc_setter < b.is_fc_setter: return -1 |
| 1351 if a.is_fc_setter > b.is_fc_setter: return 1 | 1308 if a.is_fc_setter > b.is_fc_setter: return 1 |
| 1352 return 0 | 1309 return 0 |
| 1353 | 1310 |
| 1354 def ConstantOutputOrder(a, b): | 1311 def ConstantOutputOrder(a, b): |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1439 | 1396 |
| 1440 comment = ' extends' | 1397 comment = ' extends' |
| 1441 if extends: | 1398 if extends: |
| 1442 extends_emitter.Emit(' extends $SUPERS', SUPERS=', '.join(extends)) | 1399 extends_emitter.Emit(' extends $SUPERS', SUPERS=', '.join(extends)) |
| 1443 comment = ',' | 1400 comment = ',' |
| 1444 if suppressed_extends: | 1401 if suppressed_extends: |
| 1445 extends_emitter.Emit(' /*$COMMENT $SUPERS */', | 1402 extends_emitter.Emit(' /*$COMMENT $SUPERS */', |
| 1446 COMMENT=comment, | 1403 COMMENT=comment, |
| 1447 SUPERS=', '.join(suppressed_extends)) | 1404 SUPERS=', '.join(suppressed_extends)) |
| 1448 | 1405 |
| 1449 if typename in _interface_factories: | |
| 1450 extends_emitter.Emit(' factory $F', F=_interface_factories[typename]) | |
| 1451 | |
| 1452 element_type = MaybeTypedArrayElementType(self._interface) | |
| 1453 if element_type: | |
| 1454 self._members_emitter.Emit( | |
| 1455 '\n' | |
| 1456 ' $CTOR(int length);\n' | |
| 1457 '\n' | |
| 1458 ' $CTOR.fromList(List<$TYPE> list);\n' | |
| 1459 '\n' | |
| 1460 ' $CTOR.fromBuffer(ArrayBuffer buffer);\n', | |
| 1461 CTOR=self._interface.id, | |
| 1462 TYPE=element_type) | |
| 1463 | |
| 1464 | |
| 1465 def FinishInterface(self): | 1406 def FinishInterface(self): |
| 1466 # Write snippet text that was inlined in the IDL. | 1407 # Write snippet text that was inlined in the IDL. |
| 1467 for snippet in self._interface.snippets: | 1408 for snippet in self._interface.snippets: |
| 1468 self._members_emitter.Emit('\n$LINES', | 1409 self._members_emitter.Emit('\n$LINES', |
| 1469 LINES=IndentText(snippets.text, ' ')) | 1410 LINES=IndentText(snippets.text, ' ')) |
| 1470 | 1411 |
| 1471 # TODO(vsm): Test if snippets are extra methods or extra types. | 1412 # TODO(vsm): Test if snippets are extra methods or extra types. |
| 1472 # Since Dart doesn't permit inner types, append after the interface. | 1413 # Since Dart doesn't permit inner types, append after the interface. |
| 1473 # Consider moving these types to auxilary classes instead. | 1414 # Consider moving these types to auxilary classes instead. |
| 1474 if self._extra_snippets is not None: | 1415 if self._extra_snippets is not None: |
| (...skipping 849 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2324 if not [op for op in interface.operations if op.id == 'addEventListener'
]: | 2265 if not [op for op in interface.operations if op.id == 'addEventListener'
]: |
| 2325 base = self._ImplClassName(supertype) | 2266 base = self._ImplClassName(supertype) |
| 2326 else: | 2267 else: |
| 2327 base = self._ImplClassName(supertype) | 2268 base = self._ImplClassName(supertype) |
| 2328 | 2269 |
| 2329 if base: | 2270 if base: |
| 2330 extends = " extends " + base | 2271 extends = " extends " + base |
| 2331 else: | 2272 else: |
| 2332 extends = "" | 2273 extends = "" |
| 2333 | 2274 |
| 2275 if interface_name in _constructable_types.keys(): |
| 2276 parameters = _constructable_types[interface_name] |
| 2277 constructor = ' %s(%s) native;\n\n' % (interface_name, parameters) |
| 2278 else: |
| 2279 constructor = '' |
| 2280 |
| 2334 if interface_name in _frog_dom_custom_native_specs: | 2281 if interface_name in _frog_dom_custom_native_specs: |
| 2335 native_spec = _frog_dom_custom_native_specs[interface_name] | 2282 native_spec = _frog_dom_custom_native_specs[interface_name] |
| 2336 else: | 2283 else: |
| 2337 # Is the type's JavaScript constructor accessible from the global scope? | 2284 # Is the type's constructor accessible from the global scope? If so, we |
| 2338 # If so, we can directly patch the prototype. We don't really want to do | 2285 # can directly patch the prototype. We don't really want to do this yet |
| 2339 # this yet because the dynamic patching mechanism is tricky and we want to | 2286 # because the dynamic patching mechanism is tricky and we want to test it |
| 2340 # test it a lot. But patching is currently broken on FireFox for non-leaf | 2287 # a lot. But patching is currently broken on FireFox for non-leaf types, |
| 2341 # types, so 'hide' only the leaf types. | 2288 # so 'hide' only the leaf types. |
| 2342 is_hidden = interface_name not in _BROWSER_SHARED_TYPES | 2289 is_hidden = interface_name not in _BROWSER_SHARED_TYPES |
| 2343 if interface_name not in self._interfaces_with_subtypes: | 2290 if interface_name not in self._interfaces_with_subtypes: |
| 2344 is_hidden = True | 2291 is_hidden = True |
| 2345 | 2292 |
| 2346 native_spec = '*' if is_hidden else '' | 2293 native_spec = '*' if is_hidden else '' |
| 2347 native_spec += interface_name | 2294 native_spec += interface_name |
| 2348 | 2295 |
| 2349 # TODO: Include all implemented interfaces, including other Lists. | |
| 2350 implements = '' | |
| 2351 element_type = MaybeTypedArrayElementType(self._interface) | |
| 2352 if element_type: | |
| 2353 implements = ' implements List<' + element_type + '>' | |
| 2354 | |
| 2355 (self._members_emitter, self._base_emitter) = self._dart_code.Emit( | 2296 (self._members_emitter, self._base_emitter) = self._dart_code.Emit( |
| 2356 '\n' | 2297 '\n' |
| 2357 'class $CLASS$BASE$IMPLEMENTS native "$NATIVE" {\n' | 2298 'class $CLASS$BASE native "$NATIVE" {\n' |
| 2358 '$!MEMBERS' | 2299 '$CONSTRUCTOR$!MEMBERS' |
| 2359 '$!ADDITIONS' | 2300 '$!ADDITIONS' |
| 2360 '}\n', | 2301 '}\n', |
| 2361 CLASS=self._class_name, BASE=extends, | 2302 CLASS=self._class_name, BASE=extends, |
| 2362 INTERFACE=interface_name, | 2303 INTERFACE=interface_name, CONSTRUCTOR=constructor, |
| 2363 IMPLEMENTS=implements, | |
| 2364 NATIVE=native_spec) | 2304 NATIVE=native_spec) |
| 2365 | 2305 |
| 2366 if interface_name in _constructable_types.keys(): | |
| 2367 self._members_emitter.Emit( | |
| 2368 ' $NAME($PARAMS) native;\n\n', | |
| 2369 NAME=interface_name, | |
| 2370 PARAMS=_constructable_types[interface_name]) | |
| 2371 | |
| 2372 element_type = MaybeTypedArrayElementType(interface) | |
| 2373 if element_type: | |
| 2374 self.AddTypedArrayConstructors(element_type) | |
| 2375 | |
| 2376 if not base: | 2306 if not base: |
| 2377 # Emit shared base functionality here as we have no common base type. | 2307 # Emit shared base functionality here as we have no common base type. |
| 2378 self._base_emitter.Emit( | 2308 self._base_emitter.Emit( |
| 2379 '\n' | 2309 '\n' |
| 2380 ' var dartObjectLocalStorage;\n' | 2310 ' var dartObjectLocalStorage;\n' |
| 2381 '\n' | 2311 '\n' |
| 2382 ' String get typeName() native;\n') | 2312 ' String get typeName() native;\n') |
| 2383 | 2313 |
| 2384 def _ImplClassName(self, type_name): | 2314 def _ImplClassName(self, type_name): |
| 2385 return type_name | 2315 return type_name |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2445 # | 2375 # |
| 2446 # and | 2376 # and |
| 2447 # | 2377 # |
| 2448 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | 2378 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } |
| 2449 # | 2379 # |
| 2450 self._members_emitter.Emit( | 2380 self._members_emitter.Emit( |
| 2451 '\n' | 2381 '\n' |
| 2452 ' $TYPE operator[](int index) native;\n', | 2382 ' $TYPE operator[](int index) native;\n', |
| 2453 TYPE=element_type) | 2383 TYPE=element_type) |
| 2454 | 2384 |
| 2455 if 'HasCustomIndexSetter' in self._interface.ext_attrs: | |
| 2456 self._members_emitter.Emit( | |
| 2457 '\n' | |
| 2458 ' void operator[]=(int index, $TYPE value) native;\n', | |
| 2459 TYPE=element_type) | |
| 2460 else: | |
| 2461 self._members_emitter.Emit( | |
| 2462 '\n' | |
| 2463 ' void operator[]=(int index, $TYPE value) {\n' | |
| 2464 ' throw new UnsupportedOperationException("Cannot assign element of
immutable List.");\n' | |
| 2465 ' }\n', | |
| 2466 TYPE=element_type) | |
| 2467 | |
| 2468 | |
| 2469 def AddTypedArrayConstructors(self, element_type): | |
| 2470 self._members_emitter.Emit( | |
| 2471 '\n' | |
| 2472 ' factory $CTOR(int length) => _construct(length);\n' | |
| 2473 '\n' | |
| 2474 ' factory $CTOR.fromList(List<$TYPE> list) => _construct(list);\n' | |
| 2475 '\n' | |
| 2476 ' factory $CTOR.fromBuffer(ArrayBuffer buffer) => _construct(buffer);\n
' | |
| 2477 '\n' | |
| 2478 ' static _construct(arg) native \'return new $CTOR(arg);\';\n', | |
| 2479 CTOR=self._interface.id, | |
| 2480 TYPE=element_type) | |
| 2481 | |
| 2482 | |
| 2483 def AddOperation(self, info): | 2385 def AddOperation(self, info): |
| 2484 """ | 2386 """ |
| 2485 Arguments: | 2387 Arguments: |
| 2486 info: An OperationInfo object. | 2388 info: An OperationInfo object. |
| 2487 """ | 2389 """ |
| 2488 # TODO(vsm): Handle overloads. | 2390 # TODO(vsm): Handle overloads. |
| 2489 self._members_emitter.Emit( | 2391 self._members_emitter.Emit( |
| 2490 '\n' | 2392 '\n' |
| 2491 ' $TYPE $NAME($ARGS) native;\n', | 2393 ' $TYPE $NAME($ARGS) native;\n', |
| 2492 TYPE=info.type_name, | 2394 TYPE=info.type_name, |
| 2493 NAME=info.name, | 2395 NAME=info.name, |
| 2494 ARGS=info.arg_implementation_declaration) | 2396 ARGS=info.arg_implementation_declaration) |
| OLD | NEW |