| 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 # |
| 84 # Custom methods that must be implemented by hand. | 99 # Custom methods that must be implemented by hand. |
| 85 # | 100 # |
| 86 _custom_methods = set([ | 101 _custom_methods = set([ |
| 87 ('DOMWindow', 'setInterval'), | 102 ('DOMWindow', 'setInterval'), |
| 88 ('DOMWindow', 'setTimeout'), | 103 ('DOMWindow', 'setTimeout'), |
| 89 ('WorkerContext', 'setInterval'), | 104 ('WorkerContext', 'setInterval'), |
| 90 ('WorkerContext', 'setTimeout'), | 105 ('WorkerContext', 'setTimeout'), |
| 91 ('CanvasRenderingContext2D', 'setFillStyle'), | 106 ('CanvasRenderingContext2D', 'setFillStyle'), |
| 92 ('CanvasRenderingContext2D', 'setStrokeStyle'), | 107 ('CanvasRenderingContext2D', 'setStrokeStyle'), |
| 93 ('CanvasRenderingContext2D', 'setFillStyle'), | 108 ('CanvasRenderingContext2D', 'setFillStyle'), |
| 94 ]) | 109 ]) |
| 95 | 110 |
| 96 # | 111 # |
| 97 # Custom getters that must be implemented by hand. | 112 # Custom getters that must be implemented by hand. |
| 98 # | 113 # |
| 99 _custom_getters = set([ | 114 _custom_getters = set([ |
| 100 ('DOMWindow', 'localStorage'), | 115 ('DOMWindow', 'localStorage'), |
| 101 ]) | 116 ]) |
| 102 | 117 |
| 103 # | 118 # |
| 104 # Custom native specs for the Frog dom. | 119 # Custom native specs for the Frog dom. |
| 105 # | 120 # |
| 106 _frog_dom_custom_native_specs = { | 121 _frog_dom_custom_native_specs = { |
| 107 'Console': '=console', # Decorate the singleton Console object. | 122 'Console': '=console', # Decorate the singleton Console object. |
| 108 'DOMWindow': '@*DOMWindow', # DOMWindow aliased with global scope. | 123 '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', |
| 109 } | 134 } |
| 110 | 135 |
| 111 # | 136 # |
| 112 # Publically visible types common across all supported browsers. | 137 # Publically visible types common across all supported browsers. |
| 113 # | 138 # |
| 114 _BROWSER_SHARED_TYPES = [ | 139 _BROWSER_SHARED_TYPES = [ |
| 115 'Attr', | 140 'Attr', |
| 116 'CDATASection', | 141 'CDATASection', |
| 117 'CSSFontFaceRule', | 142 'CSSFontFaceRule', |
| 118 'CSSImportRule', | 143 'CSSImportRule', |
| (...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 if attr.type.id == 'EventListener': continue | 728 if attr.type.id == 'EventListener': continue |
| 704 if attr.is_fc_getter: | 729 if attr.is_fc_getter: |
| 705 for generator in generators: | 730 for generator in generators: |
| 706 generator.AddGetter(attr) | 731 generator.AddGetter(attr) |
| 707 elif attr.is_fc_setter: | 732 elif attr.is_fc_setter: |
| 708 for generator in generators: | 733 for generator in generators: |
| 709 generator.AddSetter(attr) | 734 generator.AddSetter(attr) |
| 710 | 735 |
| 711 # The implementation should define an indexer if the interface directly | 736 # The implementation should define an indexer if the interface directly |
| 712 # extends List. | 737 # extends List. |
| 713 for parent in interface.parents: | 738 element_type = MaybeListElementType(interface) |
| 714 match = re.match(r'List<(\w*)>$', parent.type.id) | 739 if element_type: |
| 715 if match: | 740 for generator in generators: |
| 716 element_type = match.group(1) | 741 generator.AddIndexer(element_type) |
| 717 for generator in generators: | |
| 718 generator.AddIndexer(element_type) | |
| 719 break | |
| 720 | 742 |
| 721 # Group overloaded operations by id | 743 # Group overloaded operations by id |
| 722 operationsById = {} | 744 operationsById = {} |
| 723 for operation in interface.operations: | 745 for operation in interface.operations: |
| 724 if operation.id not in operationsById: | 746 if operation.id not in operationsById: |
| 725 operationsById[operation.id] = [] | 747 operationsById[operation.id] = [] |
| 726 operationsById[operation.id].append(operation) | 748 operationsById[operation.id].append(operation) |
| 727 | 749 |
| 728 # Generate operations | 750 # Generate operations |
| 729 for id in sorted(operationsById.keys()): | 751 for id in sorted(operationsById.keys()): |
| 730 operations = operationsById[id] | 752 operations = operationsById[id] |
| 731 info = self._AnalyzeOperation(interface, operations) | 753 info = self._AnalyzeOperation(interface, operations) |
| 732 for generator in generators: | 754 for generator in generators: |
| 733 generator.AddOperation(info) | 755 generator.AddOperation(info) |
| 734 | 756 |
| 735 # With multiple inheritance, attributes and operations of non-first | 757 # With multiple inheritance, attributes and operations of non-first |
| 736 # interfaces need to be added. Sometimes the attribute or operation is | 758 # interfaces need to be added. Sometimes the attribute or operation is |
| 737 # defined in the current interface as well as a parent. In that case we | 759 # defined in the current interface as well as a parent. In that case we |
| 738 # avoid making a duplicate definition and pray that the signatures match. | 760 # avoid making a duplicate definition and pray that the signatures match. |
| 739 | 761 |
| 740 for parent_interface in self._TransitiveSecondaryParents(interface): | 762 for parent_interface in self._TransitiveSecondaryParents(interface): |
| 741 if isinstance(interface, str): # _IsDartCollectionType(parent_interface) | 763 if isinstance(parent_interface, str): # _IsDartCollectionType(parent_inte
rface) |
| 742 continue | 764 continue |
| 743 attributes = sorted(parent_interface.attributes, | 765 attributes = sorted(parent_interface.attributes, |
| 744 AttributeOutputOrder) | 766 AttributeOutputOrder) |
| 745 for attr in attributes: | 767 for attr in attributes: |
| 746 if not self._DefinesSameAttribute(interface, attr): | 768 if not self._DefinesSameAttribute(interface, attr): |
| 747 if attr.is_fc_getter: | 769 if attr.is_fc_getter: |
| 748 for generator in generators: | 770 for generator in generators: |
| 749 generator.AddSecondaryGetter(parent_interface, attr) | 771 generator.AddSecondaryGetter(parent_interface, attr) |
| 750 elif attr.is_fc_setter: | 772 elif attr.is_fc_setter: |
| 751 for generator in generators: | 773 for generator in generators: |
| (...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1292 type_name: A string, the name of the return type of the operation. | 1314 type_name: A string, the name of the return type of the operation. |
| 1293 arg_declarations: A list of strings, Dart argument declarations for the | 1315 arg_declarations: A list of strings, Dart argument declarations for the |
| 1294 member that implements the set of overloads. Each string is of the form | 1316 member that implements the set of overloads. Each string is of the form |
| 1295 "T arg" or "T arg = null". | 1317 "T arg" or "T arg = null". |
| 1296 arg_infos: A list of (name, type, default_value) tuples. | 1318 arg_infos: A list of (name, type, default_value) tuples. |
| 1297 default_value is None for mandatory arguments. | 1319 default_value is None for mandatory arguments. |
| 1298 """ | 1320 """ |
| 1299 pass | 1321 pass |
| 1300 | 1322 |
| 1301 | 1323 |
| 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 |
| 1302 def AttributeOutputOrder(a, b): | 1345 def AttributeOutputOrder(a, b): |
| 1303 """Canonical output ordering for attributes.""" | 1346 """Canonical output ordering for attributes.""" |
| 1304 # Getters before setters: | 1347 # Getters before setters: |
| 1305 if a.id < b.id: return -1 | 1348 if a.id < b.id: return -1 |
| 1306 if a.id > b.id: return 1 | 1349 if a.id > b.id: return 1 |
| 1307 if a.is_fc_setter < b.is_fc_setter: return -1 | 1350 if a.is_fc_setter < b.is_fc_setter: return -1 |
| 1308 if a.is_fc_setter > b.is_fc_setter: return 1 | 1351 if a.is_fc_setter > b.is_fc_setter: return 1 |
| 1309 return 0 | 1352 return 0 |
| 1310 | 1353 |
| 1311 def ConstantOutputOrder(a, b): | 1354 def ConstantOutputOrder(a, b): |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1396 | 1439 |
| 1397 comment = ' extends' | 1440 comment = ' extends' |
| 1398 if extends: | 1441 if extends: |
| 1399 extends_emitter.Emit(' extends $SUPERS', SUPERS=', '.join(extends)) | 1442 extends_emitter.Emit(' extends $SUPERS', SUPERS=', '.join(extends)) |
| 1400 comment = ',' | 1443 comment = ',' |
| 1401 if suppressed_extends: | 1444 if suppressed_extends: |
| 1402 extends_emitter.Emit(' /*$COMMENT $SUPERS */', | 1445 extends_emitter.Emit(' /*$COMMENT $SUPERS */', |
| 1403 COMMENT=comment, | 1446 COMMENT=comment, |
| 1404 SUPERS=', '.join(suppressed_extends)) | 1447 SUPERS=', '.join(suppressed_extends)) |
| 1405 | 1448 |
| 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 |
| 1406 def FinishInterface(self): | 1465 def FinishInterface(self): |
| 1407 # Write snippet text that was inlined in the IDL. | 1466 # Write snippet text that was inlined in the IDL. |
| 1408 for snippet in self._interface.snippets: | 1467 for snippet in self._interface.snippets: |
| 1409 self._members_emitter.Emit('\n$LINES', | 1468 self._members_emitter.Emit('\n$LINES', |
| 1410 LINES=IndentText(snippets.text, ' ')) | 1469 LINES=IndentText(snippets.text, ' ')) |
| 1411 | 1470 |
| 1412 # TODO(vsm): Test if snippets are extra methods or extra types. | 1471 # TODO(vsm): Test if snippets are extra methods or extra types. |
| 1413 # Since Dart doesn't permit inner types, append after the interface. | 1472 # Since Dart doesn't permit inner types, append after the interface. |
| 1414 # Consider moving these types to auxilary classes instead. | 1473 # Consider moving these types to auxilary classes instead. |
| 1415 if self._extra_snippets is not None: | 1474 if self._extra_snippets is not None: |
| (...skipping 849 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2265 if not [op for op in interface.operations if op.id == 'addEventListener'
]: | 2324 if not [op for op in interface.operations if op.id == 'addEventListener'
]: |
| 2266 base = self._ImplClassName(supertype) | 2325 base = self._ImplClassName(supertype) |
| 2267 else: | 2326 else: |
| 2268 base = self._ImplClassName(supertype) | 2327 base = self._ImplClassName(supertype) |
| 2269 | 2328 |
| 2270 if base: | 2329 if base: |
| 2271 extends = " extends " + base | 2330 extends = " extends " + base |
| 2272 else: | 2331 else: |
| 2273 extends = "" | 2332 extends = "" |
| 2274 | 2333 |
| 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 | |
| 2281 if interface_name in _frog_dom_custom_native_specs: | 2334 if interface_name in _frog_dom_custom_native_specs: |
| 2282 native_spec = _frog_dom_custom_native_specs[interface_name] | 2335 native_spec = _frog_dom_custom_native_specs[interface_name] |
| 2283 else: | 2336 else: |
| 2284 # Is the type's constructor accessible from the global scope? If so, we | 2337 # Is the type's JavaScript constructor accessible from the global scope? |
| 2285 # can directly patch the prototype. We don't really want to do this yet | 2338 # If so, we can directly patch the prototype. We don't really want to do |
| 2286 # because the dynamic patching mechanism is tricky and we want to test it | 2339 # this yet because the dynamic patching mechanism is tricky and we want to |
| 2287 # a lot. But patching is currently broken on FireFox for non-leaf types, | 2340 # test it a lot. But patching is currently broken on FireFox for non-leaf |
| 2288 # so 'hide' only the leaf types. | 2341 # types, so 'hide' only the leaf types. |
| 2289 is_hidden = interface_name not in _BROWSER_SHARED_TYPES | 2342 is_hidden = interface_name not in _BROWSER_SHARED_TYPES |
| 2290 if interface_name not in self._interfaces_with_subtypes: | 2343 if interface_name not in self._interfaces_with_subtypes: |
| 2291 is_hidden = True | 2344 is_hidden = True |
| 2292 | 2345 |
| 2293 native_spec = '*' if is_hidden else '' | 2346 native_spec = '*' if is_hidden else '' |
| 2294 native_spec += interface_name | 2347 native_spec += interface_name |
| 2295 | 2348 |
| 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 |
| 2296 (self._members_emitter, self._base_emitter) = self._dart_code.Emit( | 2355 (self._members_emitter, self._base_emitter) = self._dart_code.Emit( |
| 2297 '\n' | 2356 '\n' |
| 2298 'class $CLASS$BASE native "$NATIVE" {\n' | 2357 'class $CLASS$BASE$IMPLEMENTS native "$NATIVE" {\n' |
| 2299 '$CONSTRUCTOR$!MEMBERS' | 2358 '$!MEMBERS' |
| 2300 '$!ADDITIONS' | 2359 '$!ADDITIONS' |
| 2301 '}\n', | 2360 '}\n', |
| 2302 CLASS=self._class_name, BASE=extends, | 2361 CLASS=self._class_name, BASE=extends, |
| 2303 INTERFACE=interface_name, CONSTRUCTOR=constructor, | 2362 INTERFACE=interface_name, |
| 2363 IMPLEMENTS=implements, |
| 2304 NATIVE=native_spec) | 2364 NATIVE=native_spec) |
| 2305 | 2365 |
| 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 |
| 2306 if not base: | 2376 if not base: |
| 2307 # Emit shared base functionality here as we have no common base type. | 2377 # Emit shared base functionality here as we have no common base type. |
| 2308 self._base_emitter.Emit( | 2378 self._base_emitter.Emit( |
| 2309 '\n' | 2379 '\n' |
| 2310 ' var dartObjectLocalStorage;\n' | 2380 ' var dartObjectLocalStorage;\n' |
| 2311 '\n' | 2381 '\n' |
| 2312 ' String get typeName() native;\n') | 2382 ' String get typeName() native;\n') |
| 2313 | 2383 |
| 2314 def _ImplClassName(self, type_name): | 2384 def _ImplClassName(self, type_name): |
| 2315 return type_name | 2385 return type_name |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2375 # | 2445 # |
| 2376 # and | 2446 # and |
| 2377 # | 2447 # |
| 2378 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | 2448 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } |
| 2379 # | 2449 # |
| 2380 self._members_emitter.Emit( | 2450 self._members_emitter.Emit( |
| 2381 '\n' | 2451 '\n' |
| 2382 ' $TYPE operator[](int index) native;\n', | 2452 ' $TYPE operator[](int index) native;\n', |
| 2383 TYPE=element_type) | 2453 TYPE=element_type) |
| 2384 | 2454 |
| 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 |
| 2385 def AddOperation(self, info): | 2483 def AddOperation(self, info): |
| 2386 """ | 2484 """ |
| 2387 Arguments: | 2485 Arguments: |
| 2388 info: An OperationInfo object. | 2486 info: An OperationInfo object. |
| 2389 """ | 2487 """ |
| 2390 # TODO(vsm): Handle overloads. | 2488 # TODO(vsm): Handle overloads. |
| 2391 self._members_emitter.Emit( | 2489 self._members_emitter.Emit( |
| 2392 '\n' | 2490 '\n' |
| 2393 ' $TYPE $NAME($ARGS) native;\n', | 2491 ' $TYPE $NAME($ARGS) native;\n', |
| 2394 TYPE=info.type_name, | 2492 TYPE=info.type_name, |
| 2395 NAME=info.name, | 2493 NAME=info.name, |
| 2396 ARGS=info.arg_implementation_declaration) | 2494 ARGS=info.arg_implementation_declaration) |
| OLD | NEW |