| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/python | |
| 2 # Copyright (c) 2012, 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 """This module provides shared functionality for the systems to generate | |
| 7 native binding from the IDL database.""" | |
| 8 | |
| 9 import emitter | |
| 10 import os | |
| 11 from generator import * | |
| 12 from htmldartgenerator import * | |
| 13 | |
| 14 class DartiumBackend(HtmlDartGenerator): | |
| 15 """Generates Dart implementation for one DOM IDL interface.""" | |
| 16 | |
| 17 def __init__(self, interface, cpp_library_emitter, options): | |
| 18 super(DartiumBackend, self).__init__(interface, options) | |
| 19 | |
| 20 self._interface = interface | |
| 21 self._cpp_library_emitter = cpp_library_emitter | |
| 22 self._database = options.database | |
| 23 self._template_loader = options.templates | |
| 24 self._type_registry = options.type_registry | |
| 25 self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) | |
| 26 | |
| 27 def ImplementsMergedMembers(self): | |
| 28 # We could not add merged functions to implementation class because | |
| 29 # underlying c++ object doesn't implement them. Merged functions are | |
| 30 # generated on merged interface implementation instead. | |
| 31 return False | |
| 32 | |
| 33 def CustomJSMembers(self): | |
| 34 return {} | |
| 35 | |
| 36 def GenerateCallback(self, info): | |
| 37 if IsPureInterface(self._interface.id): | |
| 38 return | |
| 39 | |
| 40 cpp_impl_includes = set() | |
| 41 cpp_header_handlers_emitter = emitter.Emitter() | |
| 42 cpp_impl_handlers_emitter = emitter.Emitter() | |
| 43 class_name = 'Dart%s' % self._interface.id | |
| 44 for operation in self._interface.operations: | |
| 45 parameters = [] | |
| 46 arguments = [] | |
| 47 conversion_includes = [] | |
| 48 for argument in operation.arguments: | |
| 49 argument_type_info = self._TypeInfo(argument.type.id) | |
| 50 parameters.append('%s %s' % (argument_type_info.parameter_type(), | |
| 51 argument.id)) | |
| 52 arguments.append(argument_type_info.to_dart_conversion(argument.id)) | |
| 53 conversion_includes.extend(argument_type_info.conversion_includes()) | |
| 54 | |
| 55 cpp_header_handlers_emitter.Emit( | |
| 56 '\n' | |
| 57 ' virtual bool handleEvent($PARAMETERS);\n', | |
| 58 PARAMETERS=', '.join(parameters)) | |
| 59 | |
| 60 if 'Custom' in operation.ext_attrs: | |
| 61 continue | |
| 62 | |
| 63 cpp_impl_includes |= set(conversion_includes) | |
| 64 arguments_declaration = 'Dart_Handle arguments[] = { %s }' % ', '.join(arg
uments) | |
| 65 if not len(arguments): | |
| 66 arguments_declaration = 'Dart_Handle* arguments = 0' | |
| 67 cpp_impl_handlers_emitter.Emit( | |
| 68 '\n' | |
| 69 'bool $CLASS_NAME::handleEvent($PARAMETERS)\n' | |
| 70 '{\n' | |
| 71 ' if (!m_callback.isIsolateAlive())\n' | |
| 72 ' return false;\n' | |
| 73 ' DartIsolateScope scope(m_callback.isolate());\n' | |
| 74 ' DartApiScope apiScope;\n' | |
| 75 ' $ARGUMENTS_DECLARATION;\n' | |
| 76 ' return m_callback.handleEvent($ARGUMENT_COUNT, arguments);\n' | |
| 77 '}\n', | |
| 78 CLASS_NAME=class_name, | |
| 79 PARAMETERS=', '.join(parameters), | |
| 80 ARGUMENTS_DECLARATION=arguments_declaration, | |
| 81 ARGUMENT_COUNT=len(arguments)) | |
| 82 | |
| 83 cpp_header_emitter = self._cpp_library_emitter.CreateHeaderEmitter( | |
| 84 self._interface.id, | |
| 85 self._renamer.GetLibraryName(self._interface), | |
| 86 True) | |
| 87 cpp_header_emitter.Emit( | |
| 88 self._template_loader.Load('cpp_callback_header.template'), | |
| 89 INTERFACE=self._interface.id, | |
| 90 HANDLERS=cpp_header_handlers_emitter.Fragments()) | |
| 91 | |
| 92 cpp_impl_emitter = self._cpp_library_emitter.CreateSourceEmitter(self._inter
face.id) | |
| 93 cpp_impl_emitter.Emit( | |
| 94 self._template_loader.Load('cpp_callback_implementation.template'), | |
| 95 INCLUDES=self._GenerateCPPIncludes(cpp_impl_includes), | |
| 96 INTERFACE=self._interface.id, | |
| 97 HANDLERS=cpp_impl_handlers_emitter.Fragments()) | |
| 98 | |
| 99 def ImplementationTemplate(self): | |
| 100 template = None | |
| 101 interface_name = self._interface.doc_js_name | |
| 102 if interface_name == self._interface.id or not self._database.HasInterface(i
nterface_name): | |
| 103 template_file = 'impl_%s.darttemplate' % interface_name | |
| 104 template = self._template_loader.TryLoad(template_file) | |
| 105 if not template: | |
| 106 template = self._template_loader.Load('dart_implementation.darttemplate') | |
| 107 return template | |
| 108 | |
| 109 def RootClassName(self): | |
| 110 return 'NativeFieldWrapperClass1' | |
| 111 | |
| 112 def NativeSpec(self): | |
| 113 return '' | |
| 114 | |
| 115 def StartInterface(self, memebers_emitter): | |
| 116 # Create emitters for c++ implementation. | |
| 117 if not IsPureInterface(self._interface.id): | |
| 118 self._cpp_header_emitter = self._cpp_library_emitter.CreateHeaderEmitter( | |
| 119 self._interface.id, | |
| 120 self._renamer.GetLibraryName(self._interface)) | |
| 121 self._cpp_impl_emitter = self._cpp_library_emitter.CreateSourceEmitter(sel
f._interface.id) | |
| 122 else: | |
| 123 self._cpp_header_emitter = emitter.Emitter() | |
| 124 self._cpp_impl_emitter = emitter.Emitter() | |
| 125 | |
| 126 self._interface_type_info = self._TypeInfo(self._interface.id) | |
| 127 self._members_emitter = memebers_emitter | |
| 128 self._cpp_declarations_emitter = emitter.Emitter() | |
| 129 self._cpp_impl_includes = set() | |
| 130 self._cpp_definitions_emitter = emitter.Emitter() | |
| 131 self._cpp_resolver_emitter = emitter.Emitter() | |
| 132 | |
| 133 # We need to revisit our treatment of typed arrays, right now | |
| 134 # it is full of hacks. | |
| 135 if self._interface.ext_attrs.get('ConstructorTemplate') == 'TypedArray': | |
| 136 self._cpp_resolver_emitter.Emit( | |
| 137 ' if (name == "$(INTERFACE_NAME)_constructor_Callback")\n' | |
| 138 ' return Dart$(INTERFACE_NAME)Internal::constructorCallback;\n'
, | |
| 139 INTERFACE_NAME=self._interface.id) | |
| 140 | |
| 141 self._cpp_impl_includes.add('"DartArrayBufferViewCustom.h"'); | |
| 142 self._cpp_definitions_emitter.Emit( | |
| 143 '\n' | |
| 144 'static void constructorCallback(Dart_NativeArguments args)\n' | |
| 145 '{\n' | |
| 146 ' WebCore::DartArrayBufferViewInternal::constructWebGLArray<Dart$(INT
ERFACE_NAME)>(args);\n' | |
| 147 '}\n', | |
| 148 INTERFACE_NAME=self._interface.id); | |
| 149 | |
| 150 def EmitHelpers(self, base_class): | |
| 151 # Emit internal constructor which is necessary for Dartium bindings | |
| 152 # to construct wrappers from C++. Eventually it should go away | |
| 153 # once it is possible to construct such an instance directly. | |
| 154 super_constructor = '' | |
| 155 if base_class and base_class != 'NativeFieldWrapperClass1': | |
| 156 super_constructor = ' : super.internal()' | |
| 157 self._members_emitter.Emit( | |
| 158 ' $CLASSNAME.internal()$SUPERCONSTRUCTOR;\n', | |
| 159 CLASSNAME=self._interface_type_info.implementation_name(), | |
| 160 SUPERCONSTRUCTOR=super_constructor) | |
| 161 | |
| 162 def EmitStaticFactory(self, constructor_info): | |
| 163 constructor_callback_id = self._interface.id + '_constructor_Callback' | |
| 164 | |
| 165 self._members_emitter.Emit( | |
| 166 ' static $INTERFACE_NAME _create($PARAMETERS_DECLARATION) ' | |
| 167 'native "$CONSTRUCTOR_CALLBACK_ID";\n', | |
| 168 INTERFACE_NAME=self._interface_type_info.interface_name(), | |
| 169 PARAMETERS_DECLARATION=constructor_info.ParametersDeclaration( | |
| 170 self._DartType), | |
| 171 CONSTRUCTOR_CALLBACK_ID=constructor_callback_id) | |
| 172 | |
| 173 # TODO(antonm): currently we don't have information about number of argument
s expected by | |
| 174 # the constructor, so name only dispatch. | |
| 175 self._cpp_resolver_emitter.Emit( | |
| 176 ' if (name == "$CONSTRUCTOR_CALLBACK_ID")\n' | |
| 177 ' return Dart$(WEBKIT_INTERFACE_NAME)Internal::constructorCallbac
k;\n', | |
| 178 CONSTRUCTOR_CALLBACK_ID=constructor_callback_id, | |
| 179 WEBKIT_INTERFACE_NAME=self._interface.id) | |
| 180 | |
| 181 ext_attrs = self._interface.ext_attrs | |
| 182 | |
| 183 if 'CustomConstructor' in ext_attrs: | |
| 184 # We have a custom implementation for it. | |
| 185 self._cpp_declarations_emitter.Emit( | |
| 186 '\n' | |
| 187 'void constructorCallback(Dart_NativeArguments);\n') | |
| 188 return | |
| 189 | |
| 190 create_function = 'create' | |
| 191 if 'NamedConstructor' in ext_attrs: | |
| 192 create_function = 'createForJSConstructor' | |
| 193 function_expression = '%s::%s' % (self._interface_type_info.native_type(), c
reate_function) | |
| 194 self._GenerateNativeCallback( | |
| 195 'constructorCallback', | |
| 196 False, | |
| 197 function_expression, | |
| 198 self._interface, | |
| 199 constructor_info.idl_args, | |
| 200 self._interface.id, | |
| 201 'ConstructorRaisesException' in ext_attrs) | |
| 202 | |
| 203 def FinishInterface(self): | |
| 204 self._GenerateCPPHeader() | |
| 205 | |
| 206 self._cpp_impl_emitter.Emit( | |
| 207 self._template_loader.Load('cpp_implementation.template'), | |
| 208 INTERFACE=self._interface.id, | |
| 209 INCLUDES=self._GenerateCPPIncludes(self._cpp_impl_includes), | |
| 210 CALLBACKS=self._cpp_definitions_emitter.Fragments(), | |
| 211 RESOLVER=self._cpp_resolver_emitter.Fragments(), | |
| 212 DART_IMPLEMENTATION_CLASS=self._interface_type_info.implementation_name(
), | |
| 213 DART_IMPLEMENTATION_LIBRARY='dart:%s' % self._renamer.GetLibraryName(sel
f._interface)) | |
| 214 | |
| 215 def _GenerateCPPHeader(self): | |
| 216 to_native_emitter = emitter.Emitter() | |
| 217 if self._interface_type_info.custom_to_native(): | |
| 218 to_native_emitter.Emit( | |
| 219 ' static PassRefPtr<NativeType> toNative(Dart_Handle handle, Dart_H
andle& exception);\n') | |
| 220 else: | |
| 221 to_native_emitter.Emit( | |
| 222 ' static NativeType* toNative(Dart_Handle handle, Dart_Handle& exce
ption)\n' | |
| 223 ' {\n' | |
| 224 ' return DartDOMWrapper::unwrapDartWrapper<Dart$INTERFACE>(hand
le, exception);\n' | |
| 225 ' }\n', | |
| 226 INTERFACE=self._interface.id) | |
| 227 | |
| 228 to_dart_emitter = emitter.Emitter() | |
| 229 | |
| 230 ext_attrs = self._interface.ext_attrs | |
| 231 | |
| 232 if ('CustomToJS' in ext_attrs or | |
| 233 ('CustomToJSObject' in ext_attrs and 'TypedArray' not in ext_attrs) or | |
| 234 'PureInterface' in ext_attrs or | |
| 235 'CPPPureInterface' in ext_attrs or | |
| 236 self._interface_type_info.custom_to_dart()): | |
| 237 to_dart_emitter.Emit( | |
| 238 ' static Dart_Handle toDart(NativeType* value);\n') | |
| 239 else: | |
| 240 to_dart_emitter.Emit( | |
| 241 ' static Dart_Handle toDart(NativeType* value)\n' | |
| 242 ' {\n' | |
| 243 ' return DartDOMWrapper::toDart<Dart$(INTERFACE)>(value);\n' | |
| 244 ' }\n', | |
| 245 INTERFACE=self._interface.id) | |
| 246 | |
| 247 webcore_includes = self._GenerateCPPIncludes( | |
| 248 self._interface_type_info.webcore_includes()) | |
| 249 | |
| 250 is_node_test = lambda interface: interface.id == 'Node' | |
| 251 is_active_test = lambda interface: 'ActiveDOMObject' in interface.ext_attrs | |
| 252 is_event_target_test = lambda interface: 'EventTarget' in interface.ext_attr
s | |
| 253 def TypeCheckHelper(test): | |
| 254 return 'true' if any(map(test, self._database.Hierarchy(self._interface)))
else 'false' | |
| 255 | |
| 256 self._cpp_header_emitter.Emit( | |
| 257 self._template_loader.Load('cpp_header.template'), | |
| 258 INTERFACE=self._interface.id, | |
| 259 WEBCORE_INCLUDES=webcore_includes, | |
| 260 WEBCORE_CLASS_NAME=self._interface_type_info.native_type(), | |
| 261 DECLARATIONS=self._cpp_declarations_emitter.Fragments(), | |
| 262 IS_NODE=TypeCheckHelper(is_node_test), | |
| 263 IS_ACTIVE=TypeCheckHelper(is_active_test), | |
| 264 IS_EVENT_TARGET=TypeCheckHelper(is_event_target_test), | |
| 265 TO_NATIVE=to_native_emitter.Fragments(), | |
| 266 TO_DART=to_dart_emitter.Fragments()) | |
| 267 | |
| 268 def EmitAttribute(self, attribute, html_name, read_only): | |
| 269 self._AddGetter(attribute, html_name) | |
| 270 if not read_only: | |
| 271 self._AddSetter(attribute, html_name) | |
| 272 | |
| 273 def _AddGetter(self, attr, html_name): | |
| 274 type_info = self._TypeInfo(attr.type.id) | |
| 275 dart_declaration = '%s get %s' % ( | |
| 276 self.SecureOutputType(attr.type.id), html_name) | |
| 277 is_custom = 'Custom' in attr.ext_attrs or 'CustomGetter' in attr.ext_attrs | |
| 278 cpp_callback_name = self._GenerateNativeBinding(attr.id, 1, | |
| 279 dart_declaration, 'Getter', is_custom) | |
| 280 if is_custom: | |
| 281 return | |
| 282 | |
| 283 if 'Reflect' in attr.ext_attrs: | |
| 284 webcore_function_name = self._TypeInfo(attr.type.id).webcore_getter_name() | |
| 285 if 'URL' in attr.ext_attrs: | |
| 286 if 'NonEmpty' in attr.ext_attrs: | |
| 287 webcore_function_name = 'getNonEmptyURLAttribute' | |
| 288 else: | |
| 289 webcore_function_name = 'getURLAttribute' | |
| 290 elif 'ImplementedAs' in attr.ext_attrs: | |
| 291 webcore_function_name = attr.ext_attrs['ImplementedAs'] | |
| 292 else: | |
| 293 if attr.id == 'operator': | |
| 294 webcore_function_name = '_operator' | |
| 295 elif attr.id == 'target' and attr.type.id == 'SVGAnimatedString': | |
| 296 webcore_function_name = 'svgTarget' | |
| 297 else: | |
| 298 webcore_function_name = self._ToWebKitName(attr.id) | |
| 299 if attr.type.id.startswith('SVGAnimated'): | |
| 300 webcore_function_name += 'Animated' | |
| 301 | |
| 302 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi
on_name, attr) | |
| 303 self._GenerateNativeCallback( | |
| 304 cpp_callback_name, | |
| 305 True, | |
| 306 function_expression, | |
| 307 attr, | |
| 308 [], | |
| 309 attr.type.id, | |
| 310 attr.get_raises) | |
| 311 | |
| 312 def _AddSetter(self, attr, html_name): | |
| 313 type_info = self._TypeInfo(attr.type.id) | |
| 314 dart_declaration = 'void set %s(%s value)' % (html_name, self._DartType(attr
.type.id)) | |
| 315 is_custom = set(['Custom', 'CustomSetter', 'V8CustomSetter']) & set(attr.ext
_attrs) | |
| 316 cpp_callback_name = self._GenerateNativeBinding(attr.id, 2, | |
| 317 dart_declaration, 'Setter', is_custom) | |
| 318 if is_custom: | |
| 319 return | |
| 320 | |
| 321 if 'Reflect' in attr.ext_attrs: | |
| 322 webcore_function_name = self._TypeInfo(attr.type.id).webcore_setter_name() | |
| 323 else: | |
| 324 webcore_function_name = re.sub(r'^(xml(?=[A-Z])|\w)', | |
| 325 lambda s: s.group(1).upper(), | |
| 326 attr.id) | |
| 327 webcore_function_name = 'set%s' % webcore_function_name | |
| 328 if attr.type.id.startswith('SVGAnimated'): | |
| 329 webcore_function_name += 'Animated' | |
| 330 | |
| 331 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi
on_name, attr) | |
| 332 self._GenerateNativeCallback( | |
| 333 cpp_callback_name, | |
| 334 True, | |
| 335 function_expression, | |
| 336 attr, | |
| 337 [attr], | |
| 338 'void', | |
| 339 attr.set_raises) | |
| 340 | |
| 341 def AddIndexer(self, element_type): | |
| 342 """Adds all the methods required to complete implementation of List.""" | |
| 343 # We would like to simply inherit the implementation of everything except | |
| 344 # length, [], and maybe []=. It is possible to extend from a base | |
| 345 # array implementation class only when there is no other implementation | |
| 346 # inheritance. There might be no implementation inheritance other than | |
| 347 # DOMBaseWrapper for many classes, but there might be some where the | |
| 348 # array-ness is introduced by a non-root interface: | |
| 349 # | |
| 350 # interface Y extends X, List<T> ... | |
| 351 # | |
| 352 # In the non-root case we have to choose between: | |
| 353 # | |
| 354 # class YImpl extends XImpl { add List<T> methods; } | |
| 355 # | |
| 356 # and | |
| 357 # | |
| 358 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | |
| 359 # | |
| 360 dart_element_type = self._DartType(element_type) | |
| 361 if self._HasNativeIndexGetter(): | |
| 362 self._EmitNativeIndexGetter(dart_element_type) | |
| 363 else: | |
| 364 self._members_emitter.Emit( | |
| 365 '\n' | |
| 366 ' $TYPE operator[](int index) native "$(INTERFACE)_item_Callback";\n'
, | |
| 367 TYPE=self.SecureOutputType(element_type), | |
| 368 INTERFACE=self._interface.id) | |
| 369 | |
| 370 if self._HasNativeIndexSetter(): | |
| 371 self._EmitNativeIndexSetter(dart_element_type) | |
| 372 else: | |
| 373 self._members_emitter.Emit( | |
| 374 '\n' | |
| 375 ' void operator[]=(int index, $TYPE value) {\n' | |
| 376 ' throw new UnsupportedError("Cannot assign element of immutable Li
st.");\n' | |
| 377 ' }\n', | |
| 378 TYPE=dart_element_type) | |
| 379 | |
| 380 self.EmitListMixin(dart_element_type) | |
| 381 | |
| 382 def AmendIndexer(self, element_type): | |
| 383 # If interface is marked as having native indexed | |
| 384 # getter or setter, we must emit overrides as it's not | |
| 385 # guaranteed that the corresponding methods in C++ would be | |
| 386 # virtual. For example, as of time of writing, even though | |
| 387 # Uint8ClampedArray inherits from Uint8Array, ::set method | |
| 388 # is not virtual and accessing it through Uint8Array pointer | |
| 389 # would lead to wrong semantics (modulo vs. clamping.) | |
| 390 dart_element_type = self._DartType(element_type) | |
| 391 | |
| 392 if self._HasNativeIndexGetter(): | |
| 393 self._EmitNativeIndexGetter(dart_element_type) | |
| 394 if self._HasNativeIndexSetter(): | |
| 395 self._EmitNativeIndexSetter(dart_element_type) | |
| 396 | |
| 397 def _HasNativeIndexGetter(self): | |
| 398 ext_attrs = self._interface.ext_attrs | |
| 399 return ('CustomIndexedGetter' in ext_attrs or | |
| 400 'NumericIndexedGetter' in ext_attrs) | |
| 401 | |
| 402 def _EmitNativeIndexGetter(self, element_type): | |
| 403 dart_declaration = '%s operator[](int index)' % \ | |
| 404 self.SecureOutputType(element_type, True) | |
| 405 self._GenerateNativeBinding('numericIndexGetter', 2, dart_declaration, | |
| 406 'Callback', True) | |
| 407 | |
| 408 def _HasNativeIndexSetter(self): | |
| 409 return 'CustomIndexedSetter' in self._interface.ext_attrs | |
| 410 | |
| 411 def _EmitNativeIndexSetter(self, element_type): | |
| 412 dart_declaration = 'void operator[]=(int index, %s value)' % element_type | |
| 413 self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration, | |
| 414 'Callback', True) | |
| 415 | |
| 416 def EmitOperation(self, info, html_name): | |
| 417 """ | |
| 418 Arguments: | |
| 419 info: An OperationInfo object. | |
| 420 """ | |
| 421 | |
| 422 operation = info.operations[0] | |
| 423 | |
| 424 is_custom = 'Custom' in operation.ext_attrs | |
| 425 has_optional_arguments = any(self._IsArgumentOptionalInWebCore(operation, ar
gument) for argument in operation.arguments) | |
| 426 needs_dispatcher = not is_custom and (len(info.operations) > 1 or has_option
al_arguments) | |
| 427 | |
| 428 dart_declaration = '%s%s %s(%s)' % ( | |
| 429 'static ' if info.IsStatic() else '', | |
| 430 self.SecureOutputType(info.type_name), | |
| 431 html_name, | |
| 432 info.ParametersDeclaration( | |
| 433 (lambda x: 'dynamic') if needs_dispatcher else self._DartType)) | |
| 434 | |
| 435 if not needs_dispatcher: | |
| 436 # Bind directly to native implementation | |
| 437 argument_count = (0 if info.IsStatic() else 1) + len(info.param_infos) | |
| 438 cpp_callback_name = self._GenerateNativeBinding( | |
| 439 info.name, argument_count, dart_declaration, 'Callback', is_custom) | |
| 440 if not is_custom: | |
| 441 self._GenerateOperationNativeCallback(operation, operation.arguments, cp
p_callback_name) | |
| 442 else: | |
| 443 self._GenerateDispatcher(info.operations, dart_declaration, [info.name for
info in info.param_infos]) | |
| 444 | |
| 445 def _GenerateDispatcher(self, operations, dart_declaration, argument_names): | |
| 446 | |
| 447 body = self._members_emitter.Emit( | |
| 448 '\n' | |
| 449 ' $DECLARATION {\n' | |
| 450 '$!BODY' | |
| 451 ' }\n', | |
| 452 DECLARATION=dart_declaration) | |
| 453 | |
| 454 version = [1] | |
| 455 def GenerateCall(operation, argument_count, checks): | |
| 456 if checks: | |
| 457 if operation.type.id != 'void': | |
| 458 template = ' if ($CHECKS) {\n return $CALL;\n }\n' | |
| 459 else: | |
| 460 template = ' if ($CHECKS) {\n $CALL;\n return;\n }\n' | |
| 461 else: | |
| 462 if operation.type.id != 'void': | |
| 463 template = ' return $CALL;\n' | |
| 464 else: | |
| 465 template = ' $CALL;\n' | |
| 466 | |
| 467 overload_name = '%s_%s' % (operation.id, version[0]) | |
| 468 version[0] += 1 | |
| 469 argument_list = ', '.join(argument_names[:argument_count]) | |
| 470 call = '_%s(%s)' % (overload_name, argument_list) | |
| 471 body.Emit(template, CHECKS=' && '.join(checks), CALL=call) | |
| 472 | |
| 473 dart_declaration = '%s%s _%s(%s)' % ( | |
| 474 'static ' if operation.is_static else '', | |
| 475 self.SecureOutputType(operation.type.id), | |
| 476 overload_name, argument_list) | |
| 477 cpp_callback_name = self._GenerateNativeBinding( | |
| 478 overload_name, (0 if operation.is_static else 1) + argument_count, | |
| 479 dart_declaration, 'Callback', False) | |
| 480 self._GenerateOperationNativeCallback(operation, operation.arguments[:argu
ment_count], cpp_callback_name) | |
| 481 | |
| 482 def GenerateChecksAndCall(operation, argument_count): | |
| 483 checks = [] | |
| 484 for i in range(0, argument_count): | |
| 485 argument = operation.arguments[i] | |
| 486 argument_name = argument_names[i] | |
| 487 type = self._DartType(argument.type.id) | |
| 488 if type not in ['dynamic', 'Object']: | |
| 489 checks.append('(%s is %s || %s == null)' % (argument_name, type, argum
ent_name)) | |
| 490 checks.extend(['!?%s' % name for name in argument_names[argument_count:]]) | |
| 491 GenerateCall(operation, argument_count, checks) | |
| 492 | |
| 493 # TODO: Optimize the dispatch to avoid repeated checks. | |
| 494 if len(operations) > 1: | |
| 495 for operation in operations: | |
| 496 for position, argument in enumerate(operation.arguments): | |
| 497 if self._IsArgumentOptionalInWebCore(operation, argument): | |
| 498 GenerateChecksAndCall(operation, position) | |
| 499 GenerateChecksAndCall(operation, len(operation.arguments)) | |
| 500 body.Emit(' throw "Incorrect number or type of arguments";\n'); | |
| 501 else: | |
| 502 operation = operations[0] | |
| 503 argument_count = len(operation.arguments) | |
| 504 for position, argument in list(enumerate(operation.arguments))[::-1]: | |
| 505 if self._IsArgumentOptionalInWebCore(operation, argument): | |
| 506 check = '?%s' % argument_names[position] | |
| 507 # argument_count instead of position + 1 is used here to cover one | |
| 508 # complicated case with the effectively optional argument in the middl
e. | |
| 509 # Consider foo(x, [Optional] y, [Optional=DefaultIsNullString] z) | |
| 510 # (as of now it's modelled after HTMLMediaElement.webkitAddKey). | |
| 511 # y is optional in WebCore, while z is not. | |
| 512 # In this case, if y was actually passed, we'd like to emit foo(x, y,
z) invocation, | |
| 513 # not foo(x, y). | |
| 514 GenerateCall(operation, argument_count, [check]) | |
| 515 argument_count = position | |
| 516 GenerateCall(operation, argument_count, []) | |
| 517 | |
| 518 def SecondaryContext(self, interface): | |
| 519 pass | |
| 520 | |
| 521 def _GenerateOperationNativeCallback(self, operation, arguments, cpp_callback_
name): | |
| 522 webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.i
d) | |
| 523 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi
on_name, operation) | |
| 524 self._GenerateNativeCallback( | |
| 525 cpp_callback_name, | |
| 526 not operation.is_static, | |
| 527 function_expression, | |
| 528 operation, | |
| 529 arguments, | |
| 530 operation.type.id, | |
| 531 operation.raises) | |
| 532 | |
| 533 def _GenerateNativeCallback(self, | |
| 534 callback_name, | |
| 535 needs_receiver, | |
| 536 function_expression, | |
| 537 node, | |
| 538 arguments, | |
| 539 return_type, | |
| 540 raises_dom_exception): | |
| 541 ext_attrs = node.ext_attrs | |
| 542 | |
| 543 cpp_arguments = [] | |
| 544 requires_v8_scope = \ | |
| 545 any((self._TypeInfo(argument.type.id).requires_v8_scope() for argument i
n arguments)) or\ | |
| 546 self._interface.id.startswith('IDB') | |
| 547 runtime_check = None | |
| 548 raises_exceptions = raises_dom_exception or arguments | |
| 549 | |
| 550 # TODO(antonm): unify with ScriptState below. | |
| 551 requires_stack_info = ext_attrs.get('CallWith') == 'ScriptArguments|ScriptSt
ate' | |
| 552 if requires_stack_info: | |
| 553 raises_exceptions = True | |
| 554 requires_v8_scope = True | |
| 555 cpp_arguments = ['&state', 'scriptArguments.release()'] | |
| 556 # WebKit uses scriptArguments to reconstruct last argument, so | |
| 557 # it's not needed and should be just removed. | |
| 558 arguments = arguments[:-1] | |
| 559 | |
| 560 # TODO(antonm): unify with ScriptState below. | |
| 561 requires_script_arguments = ext_attrs.get('CallWith') == 'ScriptArguments' | |
| 562 if requires_script_arguments: | |
| 563 raises_exceptions = True | |
| 564 requires_v8_scope = True | |
| 565 cpp_arguments = ['scriptArguments.release()'] | |
| 566 # WebKit uses scriptArguments to reconstruct last argument, so | |
| 567 # it's not needed and should be just removed. | |
| 568 arguments = arguments[:-1] | |
| 569 | |
| 570 requires_script_execution_context = ext_attrs.get('CallWith') == 'ScriptExec
utionContext' | |
| 571 if requires_script_execution_context: | |
| 572 raises_exceptions = True | |
| 573 cpp_arguments = ['context'] | |
| 574 | |
| 575 requires_script_state = ext_attrs.get('CallWith') == 'ScriptState' | |
| 576 if requires_script_state: | |
| 577 raises_exceptions = True | |
| 578 cpp_arguments = ['&state'] | |
| 579 | |
| 580 requires_dom_window = 'NamedConstructor' in ext_attrs | |
| 581 if requires_dom_window: | |
| 582 raises_exceptions = True | |
| 583 cpp_arguments = ['document'] | |
| 584 | |
| 585 if 'ImplementedBy' in ext_attrs: | |
| 586 assert needs_receiver | |
| 587 self._cpp_impl_includes.add('"%s.h"' % ext_attrs['ImplementedBy']) | |
| 588 cpp_arguments.append('receiver') | |
| 589 | |
| 590 if 'Reflect' in ext_attrs: | |
| 591 cpp_arguments = [self._GenerateWebCoreReflectionAttributeName(node)] | |
| 592 | |
| 593 v8EnabledPerContext = ext_attrs.get('synthesizedV8EnabledPerContext', ext_at
trs.get('V8EnabledPerContext')) | |
| 594 v8EnabledAtRuntime = ext_attrs.get('synthesizedV8EnabledAtRuntime', ext_attr
s.get('V8EnabledAtRuntime')) | |
| 595 assert(not (v8EnabledPerContext and v8EnabledAtRuntime)) | |
| 596 | |
| 597 if v8EnabledPerContext: | |
| 598 raises_exceptions = True | |
| 599 self._cpp_impl_includes.add('"ContextFeatures.h"') | |
| 600 self._cpp_impl_includes.add('"DOMWindow.h"') | |
| 601 runtime_check = emitter.Format( | |
| 602 ' if (!ContextFeatures::$(FEATURE)Enabled(DartUtilities::domWin
dowForCurrentIsolate()->document())) {\n' | |
| 603 ' exception = Dart_NewStringFromCString("Feature $FEATURE i
s not enabled");\n' | |
| 604 ' goto fail;\n' | |
| 605 ' }', | |
| 606 FEATURE=v8EnabledPerContext) | |
| 607 | |
| 608 if v8EnabledAtRuntime: | |
| 609 raises_exceptions = True | |
| 610 self._cpp_impl_includes.add('"RuntimeEnabledFeatures.h"') | |
| 611 runtime_check = emitter.Format( | |
| 612 ' if (!RuntimeEnabledFeatures::$(FEATURE)Enabled()) {\n' | |
| 613 ' exception = Dart_NewStringFromCString("Feature $FEATURE i
s not enabled");\n' | |
| 614 ' goto fail;\n' | |
| 615 ' }', | |
| 616 FEATURE=self._ToWebKitName(v8EnabledAtRuntime)) | |
| 617 | |
| 618 body_emitter = self._cpp_definitions_emitter.Emit( | |
| 619 '\n' | |
| 620 'static void $CALLBACK_NAME(Dart_NativeArguments args)\n' | |
| 621 '{\n' | |
| 622 ' DartApiScope dartApiScope;\n' | |
| 623 '$!BODY' | |
| 624 '}\n', | |
| 625 CALLBACK_NAME=callback_name) | |
| 626 | |
| 627 if raises_exceptions: | |
| 628 body_emitter = body_emitter.Emit( | |
| 629 ' Dart_Handle exception = 0;\n' | |
| 630 '$!BODY' | |
| 631 '\n' | |
| 632 'fail:\n' | |
| 633 ' Dart_ThrowException(exception);\n' | |
| 634 ' ASSERT_NOT_REACHED();\n') | |
| 635 | |
| 636 body_emitter = body_emitter.Emit( | |
| 637 ' {\n' | |
| 638 '$!BODY' | |
| 639 ' return;\n' | |
| 640 ' }\n') | |
| 641 | |
| 642 if requires_v8_scope: | |
| 643 body_emitter.Emit( | |
| 644 ' V8Scope v8scope;\n\n') | |
| 645 | |
| 646 if runtime_check: | |
| 647 body_emitter.Emit( | |
| 648 '$RUNTIME_CHECK\n', | |
| 649 RUNTIME_CHECK=runtime_check) | |
| 650 | |
| 651 if requires_script_execution_context: | |
| 652 body_emitter.Emit( | |
| 653 ' ScriptExecutionContext* context = DartUtilities::scriptExecut
ionContext();\n' | |
| 654 ' if (!context) {\n' | |
| 655 ' exception = Dart_NewStringFromCString("Failed to retrieve
a context");\n' | |
| 656 ' goto fail;\n' | |
| 657 ' }\n\n') | |
| 658 | |
| 659 if requires_script_state: | |
| 660 body_emitter.Emit( | |
| 661 ' ScriptState* currentState = ScriptState::current();\n' | |
| 662 ' if (!currentState) {\n' | |
| 663 ' exception = Dart_NewStringFromCString("Failed to retrieve
a script state");\n' | |
| 664 ' goto fail;\n' | |
| 665 ' }\n' | |
| 666 ' ScriptState& state = *currentState;\n\n') | |
| 667 | |
| 668 if requires_dom_window: | |
| 669 self._cpp_impl_includes.add('"DOMWindow.h"') | |
| 670 body_emitter.Emit( | |
| 671 ' DOMWindow* domWindow = DartUtilities::domWindowForCurrentIsol
ate();\n' | |
| 672 ' if (!domWindow) {\n' | |
| 673 ' exception = Dart_NewStringFromCString("Failed to fetch do
mWindow");\n' | |
| 674 ' goto fail;\n' | |
| 675 ' }\n' | |
| 676 ' Document* document = domWindow->document();\n') | |
| 677 | |
| 678 if needs_receiver: | |
| 679 body_emitter.Emit( | |
| 680 ' $WEBCORE_CLASS_NAME* receiver = DartDOMWrapper::receiver< $WE
BCORE_CLASS_NAME >(args);\n', | |
| 681 WEBCORE_CLASS_NAME=self._interface_type_info.native_type()) | |
| 682 | |
| 683 if requires_stack_info: | |
| 684 self._cpp_impl_includes.add('"ScriptArguments.h"') | |
| 685 body_emitter.Emit( | |
| 686 '\n' | |
| 687 ' ScriptState* currentState = ScriptState::current();\n' | |
| 688 ' if (!currentState) {\n' | |
| 689 ' exception = Dart_NewStringFromCString("Failed to retrieve
a script state");\n' | |
| 690 ' goto fail;\n' | |
| 691 ' }\n' | |
| 692 ' ScriptState& state = *currentState;\n' | |
| 693 '\n' | |
| 694 ' Dart_Handle customArgument = Dart_GetNativeArgument(args, $IN
DEX);\n' | |
| 695 ' RefPtr<ScriptArguments> scriptArguments(DartUtilities::create
ScriptArguments(customArgument, exception));\n' | |
| 696 ' if (!scriptArguments)\n' | |
| 697 ' goto fail;\n' | |
| 698 ' RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::create
ScriptCallStack());\n' | |
| 699 ' if (!scriptCallStack->size())\n' | |
| 700 ' return;\n', | |
| 701 INDEX=len(arguments) + 1) | |
| 702 | |
| 703 if requires_script_arguments: | |
| 704 self._cpp_impl_includes.add('"ScriptArguments.h"') | |
| 705 body_emitter.Emit( | |
| 706 '\n' | |
| 707 ' Dart_Handle customArgument = Dart_GetNativeArgument(args, $IN
DEX);\n' | |
| 708 ' RefPtr<ScriptArguments> scriptArguments(DartUtilities::create
ScriptArguments(customArgument, exception));\n' | |
| 709 ' if (!scriptArguments)\n' | |
| 710 ' goto fail;\n' | |
| 711 ' RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::create
ScriptCallStack());\n' | |
| 712 ' if (!scriptCallStack->size())\n' | |
| 713 ' return;\n', | |
| 714 INDEX=len(arguments) + 1) | |
| 715 | |
| 716 # Emit arguments. | |
| 717 start_index = 1 if needs_receiver else 0 | |
| 718 for i, argument in enumerate(arguments): | |
| 719 type_info = self._TypeInfo(argument.type.id) | |
| 720 argument_expression_template, type, cls, function = \ | |
| 721 type_info.to_native_info(argument, self._interface.id) | |
| 722 | |
| 723 if ((IsOptional(argument) and not self._IsArgumentOptionalInWebCore(node,
argument)) or | |
| 724 (argument.ext_attrs.get('Optional') == 'DefaultIsNullString')): | |
| 725 function += 'WithNullCheck' | |
| 726 | |
| 727 argument_name = DartDomNameOfAttribute(argument) | |
| 728 if type_info.pass_native_by_ref(): | |
| 729 invocation_template =\ | |
| 730 ' $TYPE $ARGUMENT_NAME;\n'\ | |
| 731 ' $CLS::$FUNCTION(Dart_GetNativeArgument(args, $INDEX), $ARGU
MENT_NAME, exception);\n' | |
| 732 else: | |
| 733 invocation_template =\ | |
| 734 ' $TYPE $ARGUMENT_NAME = $CLS::$FUNCTION(Dart_GetNativeArgume
nt(args, $INDEX), exception);\n' | |
| 735 body_emitter.Emit( | |
| 736 '\n' + | |
| 737 invocation_template + | |
| 738 ' if (exception)\n' | |
| 739 ' goto fail;\n', | |
| 740 TYPE=type, | |
| 741 ARGUMENT_NAME=argument_name, | |
| 742 CLS=cls, | |
| 743 FUNCTION=function, | |
| 744 INDEX=start_index + i) | |
| 745 self._cpp_impl_includes.add('"%s.h"' % cls) | |
| 746 cpp_arguments.append(argument_expression_template % argument_name) | |
| 747 | |
| 748 body_emitter.Emit('\n') | |
| 749 | |
| 750 if 'NeedsUserGestureCheck' in ext_attrs: | |
| 751 cpp_arguments.append('DartUtilities::processingUserGesture') | |
| 752 | |
| 753 invocation_emitter = body_emitter | |
| 754 if raises_dom_exception: | |
| 755 cpp_arguments.append('ec') | |
| 756 invocation_emitter = body_emitter.Emit( | |
| 757 ' ExceptionCode ec = 0;\n' | |
| 758 '$!INVOCATION' | |
| 759 ' if (UNLIKELY(ec)) {\n' | |
| 760 ' exception = DartDOMWrapper::exceptionCodeToDartException(ec
);\n' | |
| 761 ' goto fail;\n' | |
| 762 ' }\n') | |
| 763 | |
| 764 function_call = '%s(%s)' % (function_expression, ', '.join(cpp_arguments)) | |
| 765 if return_type == 'void': | |
| 766 invocation_emitter.Emit( | |
| 767 ' $FUNCTION_CALL;\n', | |
| 768 FUNCTION_CALL=function_call) | |
| 769 else: | |
| 770 return_type_info = self._TypeInfo(return_type) | |
| 771 self._cpp_impl_includes |= set(return_type_info.conversion_includes()) | |
| 772 | |
| 773 # Generate to Dart conversion of C++ value. | |
| 774 to_dart_conversion = return_type_info.to_dart_conversion(function_call, se
lf._interface.id, ext_attrs) | |
| 775 invocation_emitter.Emit( | |
| 776 ' Dart_Handle returnValue = $TO_DART_CONVERSION;\n' | |
| 777 ' if (returnValue)\n' | |
| 778 ' Dart_SetReturnValue(args, returnValue);\n', | |
| 779 TO_DART_CONVERSION=to_dart_conversion) | |
| 780 | |
| 781 def _GenerateNativeBinding(self, idl_name, argument_count, dart_declaration, | |
| 782 native_suffix, is_custom): | |
| 783 annotations = FindCommonAnnotations(self._interface.id, idl_name) | |
| 784 if annotations: | |
| 785 annotation_str = '\n ' + '\n '.join(annotations) | |
| 786 else: | |
| 787 annotation_str = '' | |
| 788 | |
| 789 native_binding = '%s_%s_%s' % (self._interface.id, idl_name, native_suffix) | |
| 790 self._members_emitter.Emit( | |
| 791 '\n' | |
| 792 '\n /** @domName $DOMINTERFACE.$DOMNAME */' | |
| 793 '$ANNOTATIONS' | |
| 794 '\n $DART_DECLARATION native "$NATIVE_BINDING";\n', | |
| 795 DOMINTERFACE=self._interface.id, | |
| 796 DOMNAME=idl_name, | |
| 797 ANNOTATIONS=annotation_str, | |
| 798 DART_DECLARATION=dart_declaration, | |
| 799 NATIVE_BINDING=native_binding) | |
| 800 | |
| 801 cpp_callback_name = '%s%s' % (idl_name, native_suffix) | |
| 802 self._cpp_resolver_emitter.Emit( | |
| 803 ' if (argumentCount == $ARGC && name == "$NATIVE_BINDING")\n' | |
| 804 ' return Dart$(INTERFACE_NAME)Internal::$CPP_CALLBACK_NAME;\n', | |
| 805 ARGC=argument_count, | |
| 806 NATIVE_BINDING=native_binding, | |
| 807 INTERFACE_NAME=self._interface.id, | |
| 808 CPP_CALLBACK_NAME=cpp_callback_name) | |
| 809 | |
| 810 if is_custom: | |
| 811 self._cpp_declarations_emitter.Emit( | |
| 812 '\n' | |
| 813 'void $CPP_CALLBACK_NAME(Dart_NativeArguments);\n', | |
| 814 CPP_CALLBACK_NAME=cpp_callback_name) | |
| 815 | |
| 816 return cpp_callback_name | |
| 817 | |
| 818 def _GenerateWebCoreReflectionAttributeName(self, attr): | |
| 819 namespace = 'HTMLNames' | |
| 820 svg_exceptions = ['class', 'id', 'onabort', 'onclick', 'onerror', 'onload', | |
| 821 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', | |
| 822 'onmouseup', 'onresize', 'onscroll', 'onunload'] | |
| 823 if self._interface.id.startswith('SVG') and not attr.id in svg_exceptions: | |
| 824 namespace = 'SVGNames' | |
| 825 self._cpp_impl_includes.add('"%s.h"' % namespace) | |
| 826 | |
| 827 attribute_name = attr.ext_attrs['Reflect'] or attr.id.lower() | |
| 828 return 'WebCore::%s::%sAttr' % (namespace, attribute_name) | |
| 829 | |
| 830 def _GenerateWebCoreFunctionExpression(self, function_name, idl_node): | |
| 831 if 'ImplementedBy' in idl_node.ext_attrs: | |
| 832 return '%s::%s' % (idl_node.ext_attrs['ImplementedBy'], function_name) | |
| 833 if idl_node.is_static: | |
| 834 return '%s::%s' % (self._interface_type_info.idl_type(), function_name) | |
| 835 return '%s%s' % (self._interface_type_info.receiver(), function_name) | |
| 836 | |
| 837 def _IsArgumentOptionalInWebCore(self, operation, argument): | |
| 838 if not IsOptional(argument): | |
| 839 return False | |
| 840 if 'Callback' in argument.ext_attrs: | |
| 841 return False | |
| 842 if operation.id in ['addEventListener', 'removeEventListener'] and argument.
id == 'useCapture': | |
| 843 return False | |
| 844 # Another option would be to adjust in IDLs, but let's keep it here for now | |
| 845 # as it's a single instance. | |
| 846 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope
rty' and argument.id == 'priority': | |
| 847 return False | |
| 848 if argument.type.id == 'Dictionary': | |
| 849 return False | |
| 850 return True | |
| 851 | |
| 852 def _GenerateCPPIncludes(self, includes): | |
| 853 return ''.join(['#include %s\n' % include for include in sorted(includes)]) | |
| 854 | |
| 855 def _ToWebKitName(self, name): | |
| 856 name = name[0].lower() + name[1:] | |
| 857 name = re.sub(r'^(hTML|uRL|jS|xML|xSLT)', lambda s: s.group(1).lower(), | |
| 858 name) | |
| 859 return re.sub(r'^(create|exclusive)', | |
| 860 lambda s: 'is' + s.group(1).capitalize(), | |
| 861 name) | |
| 862 | |
| 863 def _TypeInfo(self, type_name): | |
| 864 return self._type_registry.TypeInfo(type_name) | |
| 865 | |
| 866 def _DartType(self, type_name): | |
| 867 return self._type_registry.DartType(type_name) | |
| 868 | |
| 869 | |
| 870 class CPPLibraryEmitter(): | |
| 871 def __init__(self, emitters, cpp_sources_dir): | |
| 872 self._emitters = emitters | |
| 873 self._cpp_sources_dir = cpp_sources_dir | |
| 874 self._library_headers = {} | |
| 875 self._sources_list = [] | |
| 876 | |
| 877 def CreateHeaderEmitter(self, interface_name, library_name, is_callback=False)
: | |
| 878 path = os.path.join(self._cpp_sources_dir, 'Dart%s.h' % interface_name) | |
| 879 if not is_callback: | |
| 880 if not library_name in self._library_headers: | |
| 881 self._library_headers[library_name] = [] | |
| 882 self._library_headers[library_name].append(path) | |
| 883 return self._emitters.FileEmitter(path) | |
| 884 | |
| 885 def CreateSourceEmitter(self, interface_name): | |
| 886 path = os.path.join(self._cpp_sources_dir, 'Dart%s.cpp' % interface_name) | |
| 887 self._sources_list.append(path) | |
| 888 return self._emitters.FileEmitter(path) | |
| 889 | |
| 890 def EmitDerivedSources(self, template, output_dir): | |
| 891 partitions = 20 # FIXME: this should be configurable. | |
| 892 sources_count = len(self._sources_list) | |
| 893 for i in range(0, partitions): | |
| 894 file_path = os.path.join(output_dir, 'DartDerivedSources%02i.cpp' % (i + 1
)) | |
| 895 includes_emitter = self._emitters.FileEmitter(file_path).Emit(template) | |
| 896 for source_file in self._sources_list[i::partitions]: | |
| 897 path = os.path.relpath(source_file, output_dir) | |
| 898 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
| 899 | |
| 900 def EmitResolver(self, template, output_dir): | |
| 901 for library_name in self._library_headers.keys(): | |
| 902 file_path = os.path.join(output_dir, '%s_DartResolver.cpp' % library_name) | |
| 903 includes_emitter, body_emitter = self._emitters.FileEmitter(file_path).Emi
t( | |
| 904 template, | |
| 905 LIBRARY_NAME=library_name) | |
| 906 | |
| 907 headers = self._library_headers[library_name] | |
| 908 for header_file in headers: | |
| 909 path = os.path.relpath(header_file, output_dir) | |
| 910 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
| 911 body_emitter.Emit( | |
| 912 ' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argu
mentCount))\n' | |
| 913 ' return func;\n', | |
| 914 CLASS_NAME=os.path.splitext(os.path.basename(path))[0]) | |
| OLD | NEW |