| #!/usr/bin/env python3 | |
| # | |
| # Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| # for details. All rights reserved. Use of this source code is governed by a | |
| # BSD-style license that can be found in the LICENSE file. | |
| """Generates sdk/lib/_blink/dartium/_blink_dartium.dart file.""" | |
| import os | |
| from generator import AnalyzeOperation, AnalyzeConstructor, ConstantOutputOrder | |
| # This is list of all methods with native c++ implementations | |
| # If performing a dartium merge, the best practice is to comment out this list, | |
| # ensure everything runs, and then uncomment this list which might possibly | |
| # introduce breaking changes due to changes to these method signatures. | |
| _js_custom_members = set([ | |
| 'Document.createElement', | |
| 'Element.id', | |
| 'Element.tagName', | |
| 'Element.className', | |
| 'Element.setAttribute', | |
| 'Element.getAttribute', | |
| # Consider adding this method so there is a fast path to access only | |
| # element children. | |
| # 'NonDocumentTypeChildNode.nextElementSibling', | |
| 'Node.appendChild', # actually not removed, just native implementation. | |
| 'Node.cloneNode', | |
| 'Node.insertBefore', | |
| 'Node.lastChild', | |
| 'Node.firstChild', | |
| 'Node.parentElement', | |
| 'Node.parentNode', | |
| 'Node.childNodes', | |
| 'Node.removeChild', | |
| 'Node.contains', | |
| 'Node.nextSibling', | |
| 'Node.previousSibling', | |
| 'ChildNode.remove', | |
| 'Document.createTextNode', | |
| 'Window.location', | |
| 'Location.href', | |
| 'Location.hash', | |
| 'Node.querySelector', | |
| 'HTMLElement.hidden', | |
| 'HTMLElement.style', | |
| 'Element.attributes', | |
| 'Window.innerWidth', | |
| 'NodeList.length', | |
| 'NodeList.item', | |
| 'ParentNode.children', | |
| 'ParentNode.firstElementChild', | |
| 'ParentNode.lastElementChild', | |
| 'Event.target', | |
| 'MouseEvent.clientY', | |
| 'MouseEvent.clientX', | |
| 'Node.nodeType', | |
| 'Node.textContent', | |
| 'HTMLCollection.length', | |
| 'HTMLCollection.item', | |
| 'Node.lastElementChild', | |
| 'Node.firstElementChild', | |
| 'HTMLElement_tabIndex', | |
| 'Element.clientWidth', | |
| 'Element.clientHeight', | |
| 'Document.body', | |
| 'Element.removeAttribute', | |
| 'Element.getBoundingClientRect', | |
| 'CSSStyleDeclaration.getPropertyValue', | |
| 'CSSStyleDeclaration.setProperty', | |
| 'CSSStyleDeclaration.__propertyQuery__', | |
| # TODO(jacobr): consider implementing these methods as well as they show | |
| # up in benchmarks for some sample applications. | |
| #'Document.createEvent', | |
| #'Document.initEvent', | |
| #'EventTarget.dispatchEvent', | |
| ]) | |
| # Uncomment out this line to short circuited native methods and run all of | |
| # dart:html through JS interop except for createElement which is slightly more | |
| # tightly natively wired. | |
| # _js_custom_members = set() | |
| # Expose built-in methods support by an instance that is not shown in the IDL. | |
| _additional_methods = { | |
| # Support propertyIsEnumerable (available on all objects only needed by | |
| # CSSStyleDeclaration decides if style property is supported (handling | |
| # camelcase and inject hyphens between camelcase). | |
| # Format of dictionary is 'operation name', arguments, returns value (True or False) | |
| 'CSSStyleDeclaration': ('propertyIsEnumerable', 1, True), | |
| } | |
| HEADER = """/* Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| * for details. All rights reserved. Use of this source code is governed by a | |
| * BSD-style license that can be found in the LICENSE file. | |
| * | |
| * DO NOT EDIT | |
| * Auto-generated _blink library. | |
| */ | |
| library dart.dom._blink; | |
| import 'dart:async'; | |
| import 'dart:js' as js; | |
| import 'dart:html' show DomException; | |
| import 'dart:_internal' as internal; | |
| // This is a place to put custom renames if we need them. | |
| final resolverMap = { | |
| }; | |
| dynamic resolver(String s) { | |
| """ | |
| END_RESOLVER = """ | |
| // Failed to find it, check for custom renames | |
| dynamic obj = resolverMap[s]; | |
| if (obj != null) return obj; | |
| throw("No such interface exposed in blink: ${s}"); | |
| } | |
| """ | |
| BLINK_UTILS = """ | |
| // _Utils native entry points | |
| class Blink_Utils { | |
| static window() native "Utils_window"; | |
| static forwardingPrint(message) native "Utils_forwardingPrint"; | |
| static spawnDomUri(uri) native "Utils_spawnDomUri"; | |
| static void spawnDomHelper(Function f, int replyTo) native "Utils_spawnDomHelper"; | |
| static register(document, tag, customType, extendsTagName) native "Utils_register"; | |
| // Below code sets up VMLibraryHooks for resolvePackageUri. | |
| static Uri resolvePackageUri(Uri packageUri) native "Utils_resolvePackageUri"; | |
| static Future<Uri> _resolvePackageUriFuture(Uri packageUri) async { | |
| return resolvePackageUri(packageUri); | |
| } | |
| static void _setupHooks() { | |
| internal.VMLibraryHooks.resolvePackageUriFuture = _resolvePackageUriFuture; | |
| } | |
| // Defines an interceptor if there is an appropriate JavaScript prototype to define it on. | |
| // In any case, returns a typed JS wrapper compatible with dart:html and the new | |
| // typed JS Interop. | |
| static defineInterceptorCustomElement(jsObject, Type type) native "Utils_defineInterceptorCustomElement"; | |
| static defineInterceptor(jsObject, Type type) native "Utils_defineInterceptor"; | |
| static setInstanceInterceptor(o, Type type, {bool customElement: false}) native "Utils_setInstanceInterceptor"; | |
| static setInstanceInterceptorCustomUpgrade(o) native "Utils_setInstanceInterceptorCustomUpgrade"; | |
| // This method will throw if the element isn't actually a real Element. | |
| static initializeCustomElement(element) native "Utils_initializeCustomElement"; | |
| } | |
| class Blink_DOMStringMap { | |
| // _DOMStringMap native entry points | |
| static containsKey(_DOMStringMap, key) native "DOMStringMap_containsKey_Callback"; | |
| static item(_DOMStringMap, key) native "DOMStringMap_item_Callback"; | |
| static setItem(_DOMStringMap, key, value) native "DOMStringMap_setItem_Callback"; | |
| static remove(_DOMStringMap, key) native "DOMStringMap_remove_Callback"; | |
| static get_keys(_DOMStringMap) native "DOMStringMap_getKeys_Callback"; | |
| } | |
| // Calls through JsNative but returns DomException instead of error strings. | |
| class Stats { | |
| Stats(this.name) { | |
| counts = new Map<String, int>(); | |
| } | |
| String name; | |
| Map<String, int> counts; | |
| clear() { | |
| counts.clear(); | |
| } | |
| track(String v) { | |
| counts[v] = counts.putIfAbsent(v, ()=> 0) + 1; | |
| } | |
| toString() { | |
| StringBuffer sb = new StringBuffer(); | |
| sb.write('================'); | |
| sb.write('$name ${counts.length}'); | |
| var keys = counts.keys.toList(); | |
| keys.sort((a,b) => counts[b].compareTo(counts[a])); | |
| for (var key in keys) { | |
| print("$key => ${counts[key]}"); | |
| } | |
| sb.write('---------------'); | |
| sb.write('================'); | |
| return sb; | |
| } | |
| } | |
| bool TRACK_STATS = true; | |
| dumpStats() { | |
| print("------------ STATS ----------------"); | |
| print(Blink_JsNative_DomException.getPropertyStats.toString()); | |
| print(Blink_JsNative_DomException.setPropertyStats.toString()); | |
| print(Blink_JsNative_DomException.callMethodStats.toString()); | |
| print(Blink_JsNative_DomException.constructorStats.toString()); | |
| print("-----------------------------------"); | |
| } | |
| clearStats() { | |
| Blink_JsNative_DomException.getPropertyStats.clear(); | |
| Blink_JsNative_DomException.setPropertyStats.clear(); | |
| Blink_JsNative_DomException.callMethodStats.clear(); | |
| Blink_JsNative_DomException.constructorStats.clear(); | |
| } | |
| class Blink_JsNative_DomException { | |
| static var getPropertyStats = new Stats('get property'); | |
| static var setPropertyStats = new Stats('set property'); | |
| static var callMethodStats = new Stats('call method'); | |
| static var constructorStats = new Stats('constructor'); | |
| static var constructors = new Map<String, dynamic>(); | |
| static getProperty(o, String name) { | |
| try { | |
| if (TRACK_STATS) getPropertyStats.track(name); | |
| return js.JsNative.getProperty(o, name); | |
| } catch (e) { | |
| // Re-throw any errors (returned as a string) as a DomException. | |
| throw new DomException.jsInterop(e); | |
| } | |
| } | |
| static propertyQuery(o, String name) { | |
| try { | |
| if (TRACK_STATS) getPropertyStats.track('__propertyQuery__'); | |
| return js.JsNative.getProperty(o, name); | |
| } catch (e) { | |
| // Re-throw any errors (returned as a string) as a DomException. | |
| throw new DomException.jsInterop(e); | |
| } | |
| } | |
| static callConstructor0(String name) { | |
| try { | |
| if (TRACK_STATS) constructorStats.track(name); | |
| var constructor = constructors.putIfAbsent(name, () => js.context[name]); | |
| return js.JsNative.callConstructor0(constructor); | |
| } catch (e) { | |
| // Re-throw any errors (returned as a string) as a DomException. | |
| throw new DomException.jsInterop(e); | |
| } | |
| } | |
| static callConstructor(String name, List args) { | |
| try { | |
| if (TRACK_STATS) constructorStats.track(name); | |
| var constructor = constructors.putIfAbsent(name, () => js.context[name]); | |
| return js.JsNative.callConstructor(constructor, args); | |
| } catch (e) { | |
| // Re-throw any errors (returned as a string) as a DomException. | |
| throw new DomException.jsInterop(e); | |
| } | |
| } | |
| static setProperty(o, String name, value) { | |
| try { | |
| if (TRACK_STATS) setPropertyStats.track(name); | |
| return js.JsNative.setProperty(o, name, value); | |
| } catch (e) { | |
| // Re-throw any errors (returned as a string) as a DomException. | |
| throw new DomException.jsInterop(e); | |
| } | |
| } | |
| static callMethod(o, String method, List args) { | |
| try { | |
| if (TRACK_STATS) callMethodStats.track(method); | |
| return js.JsNative.callMethod(o, method, args); | |
| } catch (e) { | |
| // Re-throw any errors (returned as a string) as a DomException. | |
| throw new DomException.jsInterop(e); | |
| } | |
| } | |
| }""" | |
| CLASS_DEFINITION = """class Blink%s { | |
| static final instance = new Blink%s(); | |
| """ | |
| CLASS_DEFINITION_EXTENDS = """class Blink%s extends Blink%s { | |
| static final instance = new Blink%s(); | |
| """ | |
| #(interface_name) | |
| # | |
| CONSTRUCTOR_0 = [ | |
| ' constructorCallback_0_()', | |
| ' => Blink_JsNative_DomException.callConstructor0("%s");\n\n', | |
| ' native "Blink_Constructor_%s";\n\n' | |
| ] | |
| #(argument_count, arguments, interface_name, arguments) | |
| CONSTRUCTOR_ARGS = [ | |
| ' constructorCallback_%s_(%s)', | |
| ' => Blink_JsNative_DomException.callConstructor("%s", [%s]);\n\n', | |
| ' native "Blink_Constructor_Args_%s" /* %s */;\n\n' | |
| ] | |
| #(attribute_name, attribute_name) | |
| ATTRIBUTE_GETTER = [ | |
| ' %s_Getter_(mthis)', | |
| ' => Blink_JsNative_DomException.getProperty(mthis /* %s */, "%s");\n\n', | |
| ' native "Blink_Getter_%s_%s";\n\n' | |
| ] | |
| ATTRIBUTE_SETTER = [ | |
| ' %s_Setter_(mthis, __arg_0)', | |
| ' => Blink_JsNative_DomException.setProperty(mthis /* %s */, "%s", __arg_0);\n\n', | |
| ' native "Blink_Setter_%s_%s";\n\n' | |
| ] | |
| #(operation_name, operationName) | |
| OPERATION_0 = [ | |
| ' %s_Callback_0_(mthis)', | |
| ' => Blink_JsNative_DomException.callMethod(mthis /* %s */, "%s", []);\n\n', | |
| ' native "Blink_Operation_0_%s_%s";\n\n' | |
| ] | |
| # getter, setter, deleter, propertyQuery code, and propertyIsEnumerable | |
| OPERATION_1 = [ | |
| ' $%s_Callback_1_(mthis, __arg_0)', | |
| ' => Blink_JsNative_DomException.callMethod(mthis /* %s */, "%s", [__arg_0]);\n\n', | |
| ' native "Blink_Operation_1_%s_%s";\n\n' | |
| ] | |
| OPERATION_2 = [ | |
| ' $%s_Callback_2_(mthis, __arg_0, __arg_1)', | |
| ' => Blink_JsNative_DomException.callMethod(mthis /* %s */, "%s", [__arg_0, __arg_1]);\n\n', | |
| ' native "Blink_Operation_2_%s_%s";\n\n' | |
| ] | |
| OPERATION_PQ = [ | |
| ' $%s_Callback_1_(mthis, __arg_0)', | |
| ' => Blink_JsNative_DomException.propertyQuery(mthis, __arg_0); /* %s */ \n\n', | |
| ' native "Blink_Operation_PQ_%s";\n\n' | |
| ] | |
| #(operation_name, argument_count, arguments, operation_name, arguments) | |
| ARGUMENT_NUM = "__arg_%s" | |
| OPERATION_ARGS = [ | |
| ' %s_Callback_%s_(mthis, %s)', | |
| ' => Blink_JsNative_DomException.callMethod(mthis /* %s */, "%s", [%s]);\n\n', | |
| ' native "Blink_Operation_%s_%s"; /* %s */\n\n' | |
| ] | |
| # get class property to make static call. | |
| CLASS_STATIC = 'Blink_JsNative_DomException.getProperty(js.context, "%s")' | |
| # name, classname_getproperty, name | |
| STATIC_ATTRIBUTE_GETTER = [ | |
| ' %s_Getter_()', | |
| ' => Blink_JsNative_DomException.getProperty(%s /* %s */, "%s");\n\n', | |
| ' /* %s */ native "Blink_Static_getter_%s_%s"' | |
| ] | |
| # name, classname_getproperty, name | |
| STATIC_OPERATION_0 = [ | |
| ' %s_Callback_0_()', | |
| ' => Blink_JsNative_DomException.callMethod(%s /* %s */, "%s", []);\n\n', | |
| ' /* %s */ native "Blink_Static_Operation_0_%s_%s' | |
| ] | |
| # name, argsCount, args, classname_getproperty, name, args | |
| STATIC_OPERATION_ARGS = [ | |
| ' %s_Callback_%s_(%s)', | |
| ' => Blink_JsNative_DomException.callMethod(%s /* %s */, "%s", [%s]);\n\n', | |
| ' /* %s */ native "Blink_Static_Operations_%s_%s" /* %s */ \n\n' | |
| ] | |
| CLASS_DEFINITION_END = """} | |
| """ | |
| def generate_parameter_entries(param_infos): | |
| optional_default_args = 0 | |
| for argument in param_infos: | |
| if argument.is_optional: | |
| optional_default_args += 1 | |
| arg_count = len(param_infos) | |
| min_arg_count = arg_count - optional_default_args | |
| lb = min_arg_count - 2 if min_arg_count > 2 else 0 | |
| return (lb, arg_count + 1) | |
| constructor_renames = { | |
| 'RTCPeerConnection': 'webkitRTCPeerConnection', | |
| 'SpeechRecognition': 'webkitSpeechRecognition', | |
| } | |
| def rename_constructor(name): | |
| return constructor_renames[name] if name in constructor_renames else name | |
| def _Find_Match(interface_id, member, member_prefix, candidates): | |
| member_name = interface_id + '.' + member | |
| if member_name in candidates: | |
| return member_name | |
| member_name = interface_id + '.' + member_prefix + member | |
| if member_name in candidates: | |
| return member_name | |
| member_name = interface_id + '.*' | |
| if member_name in candidates: | |
| return member_name | |
| def _Is_Native(interface, member): | |
| return _Find_Match(interface, member, '', _js_custom_members) | |
| def Select_Stub(template, is_native): | |
| if is_native: | |
| return template[0] + template[2] | |
| else: | |
| return template[0] + template[1] | |
| def Generate_Blink(output_dir, database, type_registry): | |
| blink_filename = os.path.join(output_dir, '_blink_dartium.dart') | |
| blink_file = open(blink_filename, 'w') | |
| blink_file.write(HEADER) | |
| interfaces = database.GetInterfaces() | |
| for interface in interfaces: | |
| name = interface.id | |
| resolver_entry = ' if (s == "%s") return Blink%s.instance;\n' % (name, | |
| name) | |
| blink_file.write(resolver_entry) | |
| blink_file.write(END_RESOLVER) | |
| for interface in interfaces: | |
| name = interface.id | |
| if interface.parents and len( | |
| interface.parents) > 0 and interface.parents[0].id: | |
| extends = interface.parents[0].id | |
| class_def = CLASS_DEFINITION_EXTENDS % (name, extends, name) | |
| else: | |
| class_def = CLASS_DEFINITION % (name, name) | |
| blink_file.write(class_def) | |
| analyzed_constructors = AnalyzeConstructor(interface) | |
| if analyzed_constructors: | |
| _Emit_Blink_Constructors(blink_file, analyzed_constructors) | |
| elif 'Constructor' in interface.ext_attrs: | |
| # Zero parameter constructor. | |
| blink_file.write( | |
| Select_Stub(CONSTRUCTOR_0, _Is_Native(name, 'constructor')) % | |
| rename_constructor(name)) | |
| _Process_Attributes(blink_file, interface, interface.attributes) | |
| _Process_Operations(blink_file, interface, interface.operations, True) | |
| _Emit_Extra_Operations(blink_file, name) | |
| secondary_parents = database.TransitiveSecondaryParents( | |
| interface, False) | |
| for secondary in secondary_parents: | |
| _Process_Attributes(blink_file, secondary, secondary.attributes) | |
| _Process_Operations(blink_file, secondary, secondary.operations, | |
| False) | |
| blink_file.write(CLASS_DEFINITION_END) | |
| blink_file.write(BLINK_UTILS) | |
| blink_file.close() | |
| def _Emit_Extra_Operations(blink_file, interface_name): | |
| if (interface_name in _additional_methods): | |
| (name, arg_count, return_value) = _additional_methods[interface_name] | |
| exposed_name = ''.join(['__get', '___', name]) if return_value else name | |
| blink_file.write( | |
| Select_Stub(OPERATION_1, False) % (exposed_name, interface_name, | |
| name)) | |
| def _Emit_Blink_Constructors(blink_file, analyzed_constructors): | |
| (arg_min_count, arg_max_count) = generate_parameter_entries( | |
| analyzed_constructors.param_infos) | |
| name = analyzed_constructors.js_name | |
| if not (name): | |
| name = analyzed_constructors.type_name | |
| for callback_index in range(arg_min_count, arg_max_count): | |
| if callback_index == 0: | |
| blink_file.write( | |
| Select_Stub(CONSTRUCTOR_0, _Is_Native(name, 'constructor')) % | |
| (rename_constructor(name))) | |
| else: | |
| arguments = [] | |
| for i in range(0, callback_index): | |
| arguments.append(ARGUMENT_NUM % i) | |
| argument_list = ', '.join(arguments) | |
| blink_file.write( | |
| Select_Stub(CONSTRUCTOR_ARGS, _Is_Native(name, 'constructor')) % | |
| (callback_index, argument_list, rename_constructor(name), | |
| argument_list)) | |
| def _Process_Attributes(blink_file, interface, attributes): | |
| # Emit an interface's attributes and operations. | |
| for attribute in sorted(attributes, key=ConstantOutputOrder): | |
| name = attribute.id | |
| is_native = _Is_Native(interface.id, name) | |
| if attribute.is_read_only: | |
| if attribute.is_static: | |
| class_property = CLASS_STATIC % interface.id | |
| blink_file.write( | |
| Select_Stub(STATIC_ATTRIBUTE_GETTER, is_native) % | |
| (name, class_property, interface.id, name)) | |
| else: | |
| blink_file.write( | |
| Select_Stub(ATTRIBUTE_GETTER, is_native) % | |
| (name, interface.id, name)) | |
| else: | |
| blink_file.write( | |
| Select_Stub(ATTRIBUTE_GETTER, is_native) % (name, interface.id, | |
| name)) | |
| blink_file.write( | |
| Select_Stub(ATTRIBUTE_SETTER, is_native) % (name, interface.id, | |
| name)) | |
| def _Process_Operations(blink_file, | |
| interface, | |
| operations, | |
| primary_interface=False): | |
| analyzeOperations = [] | |
| for operation in sorted(operations, key=ConstantOutputOrder): | |
| if len(analyzeOperations) == 0: | |
| analyzeOperations.append(operation) | |
| else: | |
| if analyzeOperations[0].id == operation.id: | |
| # Handle overloads | |
| analyzeOperations.append(operation) | |
| else: | |
| _Emit_Blink_Operation(blink_file, interface, analyzeOperations, | |
| primary_interface) | |
| analyzeOperations = [operation] | |
| if len(analyzeOperations) > 0: | |
| _Emit_Blink_Operation(blink_file, interface, analyzeOperations, | |
| primary_interface) | |
| # List of DartName operations to not emit (e.g., For now only WebGL2RenderingContextBase | |
| # has readPixels in both WebGLRenderingContextBase and WebGL2RenderingContextBase. | |
| # Furthermore, readPixels has the exact same number of arguments - in JavaScript | |
| # there is no typing so they're the same. | |
| suppressed_operations = { | |
| 'WebGL2RenderingContextBase': ['readPixels2', 'texImage2D2'], | |
| } | |
| def _Suppress_Secondary_Interface_Operation(interface, analyzed): | |
| if interface.id in suppressed_operations: | |
| # Should this DartName (name property) be suppressed on this interface? | |
| return analyzed.name in suppressed_operations[interface.id] | |
| return False | |
| def _Emit_Blink_Operation(blink_file, interface, analyzeOperations, | |
| primary_interface): | |
| analyzed = AnalyzeOperation(interface, analyzeOperations) | |
| if not (primary_interface) and _Suppress_Secondary_Interface_Operation( | |
| interface, analyzed): | |
| return | |
| (arg_min_count, | |
| arg_max_count) = generate_parameter_entries(analyzed.param_infos) | |
| name = analyzed.js_name | |
| is_native = _Is_Native(interface.id, name) | |
| operation = analyzeOperations[0] | |
| if (name.startswith('__') and \ | |
| ('getter' in operation.specials or \ | |
| 'setter' in operation.specials or \ | |
| 'deleter' in operation.specials)): | |
| if name == '__propertyQuery__': | |
| blink_file.write( | |
| Select_Stub(OPERATION_PQ, is_native) % (name, interface.id)) | |
| else: | |
| arg_min_count = arg_max_count | |
| if arg_max_count == 2: | |
| blink_file.write( | |
| Select_Stub(OPERATION_1, is_native) % (name, interface.id, | |
| name)) | |
| elif arg_max_count == 3: | |
| blink_file.write( | |
| Select_Stub(OPERATION_2, is_native) % (name, interface.id, | |
| name)) | |
| else: | |
| print("FATAL ERROR: _blink emitter operator %s.%s" % | |
| (interface.id, name)) | |
| exit | |
| return | |
| for callback_index in range(arg_min_count, arg_max_count): | |
| if callback_index == 0: | |
| if operation.is_static: | |
| class_property = CLASS_STATIC % interface.id | |
| blink_file.write( | |
| Select_Stub(STATIC_OPERATION_0, is_native) % | |
| (name, class_property, interface.id, name)) | |
| else: | |
| blink_file.write( | |
| Select_Stub(OPERATION_0, is_native) % (name, interface.id, | |
| name)) | |
| else: | |
| arguments = [] | |
| for i in range(0, callback_index): | |
| arguments.append(ARGUMENT_NUM % i) | |
| argument_list = ', '.join(arguments) | |
| if operation.is_static: | |
| class_property = CLASS_STATIC % interface.id | |
| blink_file.write( | |
| Select_Stub(STATIC_OPERATION_ARGS, is_native) % | |
| (name, callback_index, argument_list, class_property, | |
| interface.id, name, argument_list)) | |
| else: | |
| blink_file.write( | |
| Select_Stub(OPERATION_ARGS, is_native) % | |
| (name, callback_index, argument_list, interface.id, name, | |
| argument_list)) |