Index: lib/dom/scripts/generator.py |
diff --git a/lib/dom/scripts/generator.py b/lib/dom/scripts/generator.py |
index 8d72a6c024459201352f46a8d717b078d2417b26..25cfd43f28129ec0d6039b99b58dafb54af963dc 100644 |
--- a/lib/dom/scripts/generator.py |
+++ b/lib/dom/scripts/generator.py |
@@ -721,3 +721,121 @@ def GetIDLTypeInfo(idl_type_name): |
if match: |
return SequenceIDLTypeInfo(idl_type_name, GetIDLTypeInfo(match.group(1))) |
return _idl_type_registry.get(idl_type_name, IDLTypeInfo(idl_type_name)) |
+ |
+def GenerateDispatch(generator, emitter, info, indent, position, overloads): |
podivilov
2012/05/05 16:44:12
I don't think it's a good idea to move this method
sra1
2012/05/05 18:02:06
Pavel, could you say why?
My concern is that nati
podivilov
2012/05/10 10:51:43
We currently use this method in two systems - nati
Anton Muhin
2012/05/10 11:30:13
I am not sure we should be that picky about how ma
Anton Muhin
2012/05/10 11:30:13
Stephen, this CL just gets rid of code duplication
podivilov
2012/05/10 15:57:13
Why is it needed? We are going to get rid of dupli
Anton Muhin
2012/05/10 16:11:55
What do you suggest? Wait until we get rid of it?
podivilov
2012/05/10 16:20:36
Personally, I prefer that you wait until migration
Anton Muhin
2012/05/10 16:24:08
What's ETA? If it's a day or two, I'd better wait
|
+ """Generates a dispatch to one of the overloads. |
+ |
+ Arguments: |
+ emitter: an Emitter for the body of a block of code. |
+ info: the compound information about the operation and its overloads. |
+ indent: an indentation string for generated code. |
+ position: the index of the parameter to dispatch on. |
+ overloads: a list of the remaining IDLOperations to dispatch. |
+ |
+ Returns True if the dispatch can fall through on failure, False if the code |
+ always dispatches. |
+ """ |
+ |
+ def NullCheck(name): |
+ return '%s === null' % name |
+ |
+ def TypeCheck(name, type): |
+ return '%s is %s' % (name, type) |
+ |
+ def ShouldGenerateSingleOperation(): |
+ if position == len(info.param_infos): |
+ if len(overloads) > 1: |
+ raise Exception('Duplicate operations ' + str(overloads)) |
+ return True |
+ |
+ # Check if we dispatch on RequiredCppParameter arguments. In this |
+ # case all trailing arguments must be RequiredCppParameter and there |
+ # is no need in dispatch. |
+ # TODO(antonm): better diagnositics. |
+ if position >= len(overloads[0].arguments): |
+ def IsRequiredCppParameter(arg): |
+ return 'RequiredCppParameter' in arg.ext_attrs |
+ last_overload = overloads[-1] |
+ if (len(last_overload.arguments) > position and |
+ IsRequiredCppParameter(last_overload.arguments[position])): |
+ for overload in overloads: |
+ args = overload.arguments[position:] |
+ if not all([IsRequiredCppParameter(arg) for arg in args]): |
+ raise Exception('Invalid overload for RequiredCppParameter') |
+ return True |
+ |
+ return False |
+ |
+ if ShouldGenerateSingleOperation(): |
+ generator.GenerateSingleOperation(emitter, info, indent, overloads[-1]) |
+ return False |
+ |
+ # FIXME: Consider a simpler dispatch that iterates over the |
+ # overloads and generates an overload specific check. Revisit |
+ # when we move to named optional arguments. |
+ |
+ # Partition the overloads to divide and conquer on the dispatch. |
+ positive = [] |
+ negative = [] |
+ first_overload = overloads[0] |
+ param = info.param_infos[position] |
+ |
+ if position < len(first_overload.arguments): |
+ # FIXME: This will not work if the second overload has a more |
+ # precise type than the first. E.g., |
+ # void foo(Node x); |
+ # void foo(Element x); |
+ type = DartType(first_overload.arguments[position].type.id) |
+ test = TypeCheck(param.name, type) |
+ pred = lambda op: len(op.arguments) > position and DartType(op.arguments[position].type.id) == type |
+ else: |
+ type = None |
+ test = NullCheck(param.name) |
+ pred = lambda op: position >= len(op.arguments) |
+ |
+ for overload in overloads: |
+ if pred(overload): |
+ positive.append(overload) |
+ else: |
+ negative.append(overload) |
+ |
+ if positive and negative: |
+ (true_code, false_code) = emitter.Emit( |
+ '$(INDENT)if ($COND) {\n' |
+ '$!TRUE' |
+ '$(INDENT)} else {\n' |
+ '$!FALSE' |
+ '$(INDENT)}\n', |
+ COND=test, INDENT=indent) |
+ fallthrough1 = GenerateDispatch(generator, |
+ true_code, info, indent + ' ', position + 1, positive) |
+ fallthrough2 = GenerateDispatch(generator, |
+ false_code, info, indent + ' ', position, negative) |
+ return fallthrough1 or fallthrough2 |
+ |
+ if negative: |
+ raise Exception('Internal error, must be all positive') |
+ |
+ # All overloads require the same test. Do we bother? |
+ |
+ # If the test is the same as the method's formal parameter then checked mode |
+ # will have done the test already. (It could be null too but we ignore that |
+ # case since all the overload behave the same and we don't know which types |
+ # in the IDL are not nullable.) |
+ if type == param.dart_type: |
+ return GenerateDispatch(generator, |
+ emitter, info, indent, position + 1, positive) |
+ |
+ # Otherwise the overloads have the same type but the type is a subtype of |
+ # the method's synthesized formal parameter. e.g we have overloads f(X) and |
+ # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The |
+ # dispatch has removed f(X), leaving only f(Y), but there is no guarantee |
+ # that Y = Z-X, so we need to check for Y. |
+ true_code = emitter.Emit( |
+ '$(INDENT)if ($COND) {\n' |
+ '$!TRUE' |
+ '$(INDENT)}\n', |
+ COND=test, INDENT=indent) |
+ GenerateDispatch(generator, |
+ true_code, info, indent + ' ', position + 1, positive) |
+ return True |