| 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 wrapping binding from the IDL database.""" | |
| 8 | |
| 9 import os | |
| 10 from generator import * | |
| 11 from systembase import * | |
| 12 | |
| 13 class WrappingImplementationSystem(System): | |
| 14 | |
| 15 def __init__(self, templates, database, emitters, output_dir): | |
| 16 """Prepared for generating wrapping implementation. | |
| 17 | |
| 18 - Creates emitter for JS code. | |
| 19 - Creates emitter for Dart code. | |
| 20 """ | |
| 21 super(WrappingImplementationSystem, self).__init__( | |
| 22 templates, database, emitters, output_dir) | |
| 23 self._dart_wrapping_file_paths = [] | |
| 24 | |
| 25 | |
| 26 def InterfaceGenerator(self, | |
| 27 interface, | |
| 28 common_prefix, | |
| 29 super_interface_name, | |
| 30 source_filter): | |
| 31 """.""" | |
| 32 interface_name = interface.id | |
| 33 dart_wrapping_file_path = self._FilePathForDartWrappingImpl(interface_name) | |
| 34 | |
| 35 self._dart_wrapping_file_paths.append(dart_wrapping_file_path) | |
| 36 | |
| 37 dart_code = self._emitters.FileEmitter(dart_wrapping_file_path) | |
| 38 dart_code.Emit(self._templates.Load('wrapping_impl.darttemplate')) | |
| 39 return WrappingInterfaceGenerator(interface, super_interface_name, | |
| 40 dart_code, | |
| 41 self._BaseDefines(interface)) | |
| 42 | |
| 43 def ProcessCallback(self, interface, info): | |
| 44 pass | |
| 45 | |
| 46 def GenerateLibraries(self, lib_dir): | |
| 47 # Library generated for implementation. | |
| 48 self._GenerateLibFile( | |
| 49 'wrapping_dom.darttemplate', | |
| 50 os.path.join(lib_dir, 'wrapping_dom.dart'), | |
| 51 (self._interface_system._dart_interface_file_paths + | |
| 52 self._interface_system._dart_callback_file_paths + | |
| 53 # FIXME: Move the implementation to a separate library. | |
| 54 self._dart_wrapping_file_paths | |
| 55 )) | |
| 56 | |
| 57 | |
| 58 def Finish(self): | |
| 59 pass | |
| 60 | |
| 61 | |
| 62 def _FilePathForDartWrappingImpl(self, interface_name): | |
| 63 """Returns the file path of the Dart wrapping implementation.""" | |
| 64 return os.path.join(self._output_dir, 'src', 'wrapping', | |
| 65 '_%sWrappingImplementation.dart' % interface_name) | |
| 66 | |
| 67 class WrappingInterfaceGenerator(object): | |
| 68 """Generates Dart and JS implementation for one DOM IDL interface.""" | |
| 69 | |
| 70 def __init__(self, interface, super_interface, dart_code, base_members): | |
| 71 """Generates Dart and JS code for the given interface. | |
| 72 | |
| 73 Args: | |
| 74 | |
| 75 interface: an IDLInterface instance. It is assumed that all types have | |
| 76 been converted to Dart types (e.g. int, String), unless they are in | |
| 77 the same package as the interface. | |
| 78 super_interface: A string or None, the name of the common interface that | |
| 79 this interface implements, if any. | |
| 80 dart_code: an Emitter for the file containing the Dart implementation | |
| 81 class. | |
| 82 base_members: a set of names of members defined in a base class. This is | |
| 83 used to avoid static member 'overriding' in the generated Dart code. | |
| 84 """ | |
| 85 self._interface = interface | |
| 86 self._super_interface = super_interface | |
| 87 self._dart_code = dart_code | |
| 88 self._base_members = base_members | |
| 89 self._current_secondary_parent = None | |
| 90 | |
| 91 | |
| 92 def StartInterface(self): | |
| 93 interface = self._interface | |
| 94 interface_name = interface.id | |
| 95 | |
| 96 self._class_name = self._ImplClassName(interface_name) | |
| 97 | |
| 98 base = self._BaseClassName(interface) | |
| 99 | |
| 100 (self._members_emitter, | |
| 101 self._top_level_emitter) = self._dart_code.Emit( | |
| 102 '\n' | |
| 103 'class $CLASS extends $BASE implements $INTERFACE {\n' | |
| 104 ' $CLASS() : super() {}\n' | |
| 105 '\n' | |
| 106 ' static create_$CLASS() native {\n' | |
| 107 ' return new $CLASS();\n' | |
| 108 ' }\n' | |
| 109 '$!MEMBERS' | |
| 110 '\n' | |
| 111 ' String get typeName() { return "$INTERFACE"; }\n' | |
| 112 '}\n' | |
| 113 '$!TOP_LEVEL', | |
| 114 CLASS=self._class_name, BASE=base, INTERFACE=interface_name) | |
| 115 | |
| 116 def _ImplClassName(self, type_name): | |
| 117 return '_' + type_name + 'WrappingImplementation' | |
| 118 | |
| 119 def _BaseClassName(self, interface): | |
| 120 if not interface.parents: | |
| 121 return 'DOMWrapperBase' | |
| 122 | |
| 123 supertype = interface.parents[0].type.id | |
| 124 | |
| 125 # FIXME: We're currently injecting List<..> and EventTarget as | |
| 126 # supertypes in dart.idl. We should annotate/preserve as | |
| 127 # attributes instead. For now, this hack lets the interfaces | |
| 128 # inherit, but not the classes. | |
| 129 # List methods are injected in AddIndexer. | |
| 130 if IsDartListType(supertype) or IsDartCollectionType(supertype): | |
| 131 return 'DOMWrapperBase' | |
| 132 | |
| 133 if supertype == 'EventTarget': | |
| 134 # Most implementors of EventTarget specify the EventListener operations | |
| 135 # again. If the operations are not specified, try to inherit from the | |
| 136 # EventTarget implementation. | |
| 137 # | |
| 138 # Applies to MessagePort. | |
| 139 if not [op for op in interface.operations if op.id == 'addEventListener']: | |
| 140 return self._ImplClassName(supertype) | |
| 141 return 'DOMWrapperBase' | |
| 142 | |
| 143 return self._ImplClassName(supertype) | |
| 144 | |
| 145 def FinishInterface(self): | |
| 146 """.""" | |
| 147 pass | |
| 148 | |
| 149 def AddConstant(self, constant): | |
| 150 # Constants are already defined on the interface. | |
| 151 pass | |
| 152 | |
| 153 def _MethodName(self, prefix, name): | |
| 154 method_name = prefix + name | |
| 155 if name in self._base_members: # Avoid illegal Dart 'static override'. | |
| 156 method_name = method_name + '_' + self._interface.id | |
| 157 return method_name | |
| 158 | |
| 159 def AddAttribute(self, getter, setter): | |
| 160 if getter: | |
| 161 self._AddGetter(getter) | |
| 162 if setter: | |
| 163 self._AddSetter(setter) | |
| 164 | |
| 165 def _AddGetter(self, attr): | |
| 166 # FIXME: Instead of injecting the interface name into the method when it is | |
| 167 # also implemented in the base class, suppress the method altogether if it | |
| 168 # has the same signature. I.e., let the JS do the virtual dispatch instead. | |
| 169 method_name = self._MethodName('_get_', attr.id) | |
| 170 self._members_emitter.Emit( | |
| 171 '\n' | |
| 172 ' $TYPE get $NAME() { return $METHOD(this); }\n' | |
| 173 ' static $TYPE $METHOD(var _this) native;\n', | |
| 174 NAME=DartDomNameOfAttribute(attr), | |
| 175 TYPE=DartType(attr.type.id), | |
| 176 METHOD=method_name) | |
| 177 | |
| 178 def _AddSetter(self, attr): | |
| 179 # FIXME: See comment on getter. | |
| 180 method_name = self._MethodName('_set_', attr.id) | |
| 181 self._members_emitter.Emit( | |
| 182 '\n' | |
| 183 ' void set $NAME($TYPE value) { $METHOD(this, value); }\n' | |
| 184 ' static void $METHOD(var _this, $TYPE value) native;\n', | |
| 185 NAME=DartDomNameOfAttribute(attr), | |
| 186 TYPE=DartType(attr.type.id), | |
| 187 METHOD=method_name) | |
| 188 | |
| 189 def AddSecondaryAttribute(self, interface, getter, setter): | |
| 190 self._SecondaryContext(interface) | |
| 191 self.AddAttribute(getter, setter) | |
| 192 | |
| 193 def AddSecondaryOperation(self, interface, info): | |
| 194 self._SecondaryContext(interface) | |
| 195 self.AddOperation(info) | |
| 196 | |
| 197 def _SecondaryContext(self, interface): | |
| 198 if interface is not self._current_secondary_parent: | |
| 199 self._current_secondary_parent = interface | |
| 200 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id) | |
| 201 | |
| 202 def AddIndexer(self, element_type): | |
| 203 """Adds all the methods required to complete implementation of List.""" | |
| 204 # We would like to simply inherit the implementation of everything except | |
| 205 # get length(), [], and maybe []=. It is possible to extend from a base | |
| 206 # array implementation class only when there is no other implementation | |
| 207 # inheritance. There might be no implementation inheritance other than | |
| 208 # DOMBaseWrapper for many classes, but there might be some where the | |
| 209 # array-ness is introduced by a non-root interface: | |
| 210 # | |
| 211 # interface Y extends X, List<T> ... | |
| 212 # | |
| 213 # In the non-root case we have to choose between: | |
| 214 # | |
| 215 # class YImpl extends XImpl { add List<T> methods; } | |
| 216 # | |
| 217 # and | |
| 218 # | |
| 219 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | |
| 220 # | |
| 221 dart_element_type = DartType(element_type) | |
| 222 if self._HasNativeIndexGetter(self._interface): | |
| 223 self._EmitNativeIndexGetter(self._interface, dart_element_type) | |
| 224 else: | |
| 225 self._members_emitter.Emit( | |
| 226 '\n' | |
| 227 ' $TYPE operator[](int index) {\n' | |
| 228 ' return item(index);\n' | |
| 229 ' }\n', | |
| 230 TYPE=dart_element_type) | |
| 231 | |
| 232 if self._HasNativeIndexSetter(self._interface): | |
| 233 self._EmitNativeIndexSetter(self._interface, dart_element_type) | |
| 234 else: | |
| 235 self._members_emitter.Emit( | |
| 236 '\n' | |
| 237 ' void operator[]=(int index, $TYPE value) {\n' | |
| 238 ' throw new UnsupportedOperationException("Cannot assign element of
immutable List.");\n' | |
| 239 ' }\n', | |
| 240 TYPE=dart_element_type) | |
| 241 | |
| 242 self._members_emitter.Emit( | |
| 243 '\n' | |
| 244 ' void add($TYPE value) {\n' | |
| 245 ' throw new UnsupportedOperationException("Cannot add to immutable Li
st.");\n' | |
| 246 ' }\n' | |
| 247 '\n' | |
| 248 ' void addLast($TYPE value) {\n' | |
| 249 ' throw new UnsupportedOperationException("Cannot add to immutable Li
st.");\n' | |
| 250 ' }\n' | |
| 251 '\n' | |
| 252 ' void addAll(Collection<$TYPE> collection) {\n' | |
| 253 ' throw new UnsupportedOperationException("Cannot add to immutable Li
st.");\n' | |
| 254 ' }\n' | |
| 255 '\n' | |
| 256 ' void sort(int compare($TYPE a, $TYPE b)) {\n' | |
| 257 ' throw new UnsupportedOperationException("Cannot sort immutable List
.");\n' | |
| 258 ' }\n' | |
| 259 '\n' | |
| 260 ' void copyFrom(List<Object> src, int srcStart, ' | |
| 261 'int dstStart, int count) {\n' | |
| 262 ' throw new UnsupportedOperationException("This object is immutable."
);\n' | |
| 263 ' }\n' | |
| 264 '\n' | |
| 265 ' int indexOf($TYPE element, [int start = 0]) {\n' | |
| 266 ' return _Lists.indexOf(this, element, start, this.length);\n' | |
| 267 ' }\n' | |
| 268 '\n' | |
| 269 ' int lastIndexOf($TYPE element, [int start = null]) {\n' | |
| 270 ' if (start === null) start = length - 1;\n' | |
| 271 ' return _Lists.lastIndexOf(this, element, start);\n' | |
| 272 ' }\n' | |
| 273 '\n' | |
| 274 ' int clear() {\n' | |
| 275 ' throw new UnsupportedOperationException("Cannot clear immutable Lis
t.");\n' | |
| 276 ' }\n' | |
| 277 '\n' | |
| 278 ' $TYPE removeLast() {\n' | |
| 279 ' throw new UnsupportedOperationException("Cannot removeLast on immut
able List.");\n' | |
| 280 ' }\n' | |
| 281 '\n' | |
| 282 ' $TYPE last() {\n' | |
| 283 ' return this[length - 1];\n' | |
| 284 ' }\n' | |
| 285 '\n' | |
| 286 ' void forEach(void f($TYPE element)) {\n' | |
| 287 ' _Collections.forEach(this, f);\n' | |
| 288 ' }\n' | |
| 289 '\n' | |
| 290 ' Collection map(f($TYPE element)) {\n' | |
| 291 ' return _Collections.map(this, [], f);\n' | |
| 292 ' }\n' | |
| 293 '\n' | |
| 294 ' Collection<$TYPE> filter(bool f($TYPE element)) {\n' | |
| 295 ' return _Collections.filter(this, new List<$TYPE>(), f);\n' | |
| 296 ' }\n' | |
| 297 '\n' | |
| 298 ' bool every(bool f($TYPE element)) {\n' | |
| 299 ' return _Collections.every(this, f);\n' | |
| 300 ' }\n' | |
| 301 '\n' | |
| 302 ' bool some(bool f($TYPE element)) {\n' | |
| 303 ' return _Collections.some(this, f);\n' | |
| 304 ' }\n' | |
| 305 '\n' | |
| 306 ' void setRange(int start, int length, List<$TYPE> from, [int startFrom
]) {\n' | |
| 307 ' throw new UnsupportedOperationException("Cannot setRange on immutab
le List.");\n' | |
| 308 ' }\n' | |
| 309 '\n' | |
| 310 ' void removeRange(int start, int length) {\n' | |
| 311 ' throw new UnsupportedOperationException("Cannot removeRange on immu
table List.");\n' | |
| 312 ' }\n' | |
| 313 '\n' | |
| 314 ' void insertRange(int start, int length, [$TYPE initialValue]) {\n' | |
| 315 ' throw new UnsupportedOperationException("Cannot insertRange on immu
table List.");\n' | |
| 316 ' }\n' | |
| 317 '\n' | |
| 318 ' List<$TYPE> getRange(int start, int length) {\n' | |
| 319 ' throw new NotImplementedException();\n' | |
| 320 ' }\n' | |
| 321 '\n' | |
| 322 ' bool isEmpty() {\n' | |
| 323 ' return length == 0;\n' | |
| 324 ' }\n' | |
| 325 '\n' | |
| 326 ' Iterator<$TYPE> iterator() {\n' | |
| 327 ' return new _FixedSizeListIterator<$TYPE>(this);\n' | |
| 328 ' }\n', | |
| 329 TYPE=dart_element_type) | |
| 330 | |
| 331 def _HasNativeIndexGetter(self, interface): | |
| 332 return ('IndexedGetter' in interface.ext_attrs or | |
| 333 'NumericIndexedGetter' in interface.ext_attrs) | |
| 334 | |
| 335 def _EmitNativeIndexGetter(self, interface, dart_element_type): | |
| 336 method_name = '_index' | |
| 337 self._members_emitter.Emit( | |
| 338 '\n' | |
| 339 ' $TYPE operator[](int index) { return $METHOD(this, index); }\n' | |
| 340 ' static $TYPE $METHOD(var _this, int index) native;\n', | |
| 341 TYPE=dart_element_type, METHOD=method_name) | |
| 342 | |
| 343 def _HasNativeIndexSetter(self, interface): | |
| 344 return 'CustomIndexedSetter' in interface.ext_attrs | |
| 345 | |
| 346 def _EmitNativeIndexSetter(self, interface, dart_element_type): | |
| 347 method_name = '_set_index' | |
| 348 self._members_emitter.Emit( | |
| 349 '\n' | |
| 350 ' void operator[]=(int index, $TYPE value) {\n' | |
| 351 ' return $METHOD(this, index, value);\n' | |
| 352 ' }\n' | |
| 353 ' static $METHOD(_this, index, value) native;\n', | |
| 354 TYPE=dart_element_type, METHOD=method_name) | |
| 355 | |
| 356 def AddOperation(self, info): | |
| 357 """ | |
| 358 Arguments: | |
| 359 info: An OperationInfo object. | |
| 360 """ | |
| 361 body = self._members_emitter.Emit( | |
| 362 '\n' | |
| 363 ' $TYPE $NAME($PARAMS) {\n' | |
| 364 '$!BODY' | |
| 365 ' }\n', | |
| 366 TYPE=info.type_name, | |
| 367 NAME=info.name, | |
| 368 PARAMS=info.ParametersImplementationDeclaration()) | |
| 369 | |
| 370 # Process in order of ascending number of arguments to ensure missing | |
| 371 # optional arguments are processed early. | |
| 372 overloads = sorted(info.overloads, | |
| 373 key=lambda overload: len(overload.arguments)) | |
| 374 self._native_version = 0 | |
| 375 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | |
| 376 if fallthrough: | |
| 377 body.Emit(' throw "Incorrect number or type of arguments";\n'); | |
| 378 | |
| 379 def AddStaticOperation(self, info): | |
| 380 pass | |
| 381 | |
| 382 def GenerateSingleOperation(self, emitter, info, indent, operation): | |
| 383 """Generates a call to a single operation. | |
| 384 | |
| 385 Arguments: | |
| 386 emitter: an Emitter for the body of a block of code. | |
| 387 info: the compound information about the operation and its overloads. | |
| 388 indent: an indentation string for generated code. | |
| 389 operation: the IDLOperation to call. | |
| 390 """ | |
| 391 # TODO(sra): Do we need to distinguish calling with missing optional | |
| 392 # arguments from passing 'null' which is represented as 'undefined'? | |
| 393 def UnwrapArgExpression(name, type): | |
| 394 # TODO: Type specific unwrapping. | |
| 395 return '__dom_unwrap(%s)' % (name) | |
| 396 | |
| 397 def ArgNameAndUnwrapper(param_info, overload_arg): | |
| 398 return (param_info.name, | |
| 399 UnwrapArgExpression(param_info.name, param_info.dart_type)) | |
| 400 | |
| 401 names_and_unwrappers = [ArgNameAndUnwrapper(info.param_infos[i], arg) | |
| 402 for (i, arg) in enumerate(operation.arguments)] | |
| 403 unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers] | |
| 404 arg_names = [name for (name, _) in names_and_unwrappers] | |
| 405 | |
| 406 self._native_version += 1 | |
| 407 native_name = self._MethodName('_', info.name) | |
| 408 if self._native_version > 1: | |
| 409 native_name = '%s_%s' % (native_name, self._native_version) | |
| 410 | |
| 411 argument_expressions = ', '.join(['this'] + arg_names) | |
| 412 if info.type_name != 'void': | |
| 413 emitter.Emit('$(INDENT)return $NATIVENAME($ARGS);\n', | |
| 414 INDENT=indent, | |
| 415 NATIVENAME=native_name, | |
| 416 ARGS=argument_expressions) | |
| 417 else: | |
| 418 emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n' | |
| 419 '$(INDENT)return;\n', | |
| 420 INDENT=indent, | |
| 421 NATIVENAME=native_name, | |
| 422 ARGS=argument_expressions) | |
| 423 | |
| 424 self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n', | |
| 425 NAME=native_name, | |
| 426 TYPE=info.type_name, | |
| 427 PARAMS=', '.join(['receiver'] + arg_names) ) | |
| 428 | |
| 429 | |
| 430 def GenerateDispatch(self, emitter, info, indent, position, overloads): | |
| 431 """Generates a dispatch to one of the overloads. | |
| 432 | |
| 433 Arguments: | |
| 434 emitter: an Emitter for the body of a block of code. | |
| 435 info: the compound information about the operation and its overloads. | |
| 436 indent: an indentation string for generated code. | |
| 437 position: the index of the parameter to dispatch on. | |
| 438 overloads: a list of the remaining IDLOperations to dispatch. | |
| 439 | |
| 440 Returns True if the dispatch can fall through on failure, False if the code | |
| 441 always dispatches. | |
| 442 """ | |
| 443 | |
| 444 def NullCheck(name): | |
| 445 return '%s === null' % name | |
| 446 | |
| 447 def TypeCheck(name, type): | |
| 448 return '%s is %s' % (name, type) | |
| 449 | |
| 450 def ShouldGenerateSingleOperation(): | |
| 451 if position == len(info.param_infos): | |
| 452 if len(overloads) > 1: | |
| 453 raise Exception('Duplicate operations ' + str(overloads)) | |
| 454 return True | |
| 455 | |
| 456 # Check if we dispatch on RequiredCppParameter arguments. In this | |
| 457 # case all trailing arguments must be RequiredCppParameter and there | |
| 458 # is no need in dispatch. | |
| 459 # TODO(antonm): better diagnositics. | |
| 460 if position >= len(overloads[0].arguments): | |
| 461 def IsRequiredCppParameter(arg): | |
| 462 return 'RequiredCppParameter' in arg.ext_attrs | |
| 463 last_overload = overloads[-1] | |
| 464 if (len(last_overload.arguments) > position and | |
| 465 IsRequiredCppParameter(last_overload.arguments[position])): | |
| 466 for overload in overloads: | |
| 467 args = overload.arguments[position:] | |
| 468 if not all([IsRequiredCppParameter(arg) for arg in args]): | |
| 469 raise Exception('Invalid overload for RequiredCppParameter') | |
| 470 return True | |
| 471 | |
| 472 return False | |
| 473 | |
| 474 if ShouldGenerateSingleOperation(): | |
| 475 self.GenerateSingleOperation(emitter, info, indent, overloads[-1]) | |
| 476 return False | |
| 477 | |
| 478 # FIXME: Consider a simpler dispatch that iterates over the | |
| 479 # overloads and generates an overload specific check. Revisit | |
| 480 # when we move to named optional arguments. | |
| 481 | |
| 482 # Partition the overloads to divide and conquer on the dispatch. | |
| 483 positive = [] | |
| 484 negative = [] | |
| 485 first_overload = overloads[0] | |
| 486 param = info.param_infos[position] | |
| 487 | |
| 488 if position < len(first_overload.arguments): | |
| 489 # FIXME: This will not work if the second overload has a more | |
| 490 # precise type than the first. E.g., | |
| 491 # void foo(Node x); | |
| 492 # void foo(Element x); | |
| 493 type = DartType(first_overload.arguments[position].type.id) | |
| 494 test = TypeCheck(param.name, type) | |
| 495 pred = lambda op: len(op.arguments) > position and DartType(op.arguments[p
osition].type.id) == type | |
| 496 else: | |
| 497 type = None | |
| 498 test = NullCheck(param.name) | |
| 499 pred = lambda op: position >= len(op.arguments) | |
| 500 | |
| 501 for overload in overloads: | |
| 502 if pred(overload): | |
| 503 positive.append(overload) | |
| 504 else: | |
| 505 negative.append(overload) | |
| 506 | |
| 507 if positive and negative: | |
| 508 (true_code, false_code) = emitter.Emit( | |
| 509 '$(INDENT)if ($COND) {\n' | |
| 510 '$!TRUE' | |
| 511 '$(INDENT)} else {\n' | |
| 512 '$!FALSE' | |
| 513 '$(INDENT)}\n', | |
| 514 COND=test, INDENT=indent) | |
| 515 fallthrough1 = self.GenerateDispatch( | |
| 516 true_code, info, indent + ' ', position + 1, positive) | |
| 517 fallthrough2 = self.GenerateDispatch( | |
| 518 false_code, info, indent + ' ', position, negative) | |
| 519 return fallthrough1 or fallthrough2 | |
| 520 | |
| 521 if negative: | |
| 522 raise Exception('Internal error, must be all positive') | |
| 523 | |
| 524 # All overloads require the same test. Do we bother? | |
| 525 | |
| 526 # If the test is the same as the method's formal parameter then checked mode | |
| 527 # will have done the test already. (It could be null too but we ignore that | |
| 528 # case since all the overload behave the same and we don't know which types | |
| 529 # in the IDL are not nullable.) | |
| 530 if type == param.dart_type: | |
| 531 return self.GenerateDispatch( | |
| 532 emitter, info, indent, position + 1, positive) | |
| 533 | |
| 534 # Otherwise the overloads have the same type but the type is a subtype of | |
| 535 # the method's synthesized formal parameter. e.g we have overloads f(X) and | |
| 536 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The | |
| 537 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee | |
| 538 # that Y = Z-X, so we need to check for Y. | |
| 539 true_code = emitter.Emit( | |
| 540 '$(INDENT)if ($COND) {\n' | |
| 541 '$!TRUE' | |
| 542 '$(INDENT)}\n', | |
| 543 COND=test, INDENT=indent) | |
| 544 self.GenerateDispatch( | |
| 545 true_code, info, indent + ' ', position + 1, positive) | |
| 546 return True | |
| OLD | NEW |