|
|
Created:
6 years, 7 months ago by pavane Modified:
6 years, 6 months ago CC:
blink-reviews, arv+blink, jsbell+bindings_chromium.org, sof, kouhei+bindings_chromium.org, abarth-chromium, marja+watch_chromium.org, adamk+blink_chromium.org, haraken, Nate Chapin, Inactive Base URL:
https://chromium.googlesource.com/chromium/blink.git@master Visibility:
Public. |
DescriptionSupport WebIDL optional default value syntax
Currently default values are (in some cases) supported by the
non-standard [Default] extended attribute, namely as
[Default=Undefined] and [Default=NullString].
This is first patch in the effort to replace it with WebIDL
standard syntax.
BUG=258153
R=nbarth@chromium.org, haraken@chromium.org
Patch Set 1 #
Total comments: 3
Patch Set 2 : #
Total comments: 4
Messages
Total messages: 10 (0 generated)
Please have a look at this patch. There are still two problems which need to be handled. 1. From my observation, it looks like keywords like true and false are separately handled. For eg. it is able to resolve statements like below Node cloneNode(optional bool deep = "true"); Node cloneNode(optional bool deep = 1); whereas it is not able to resolve the below statement, Node cloneNode(optional bool deep = true); We may have to hack the script to handle these booleans. One way to handle this is like below: diff --git a/Source/bindings/scripts/idl_definitions.py b/Source/bindings/scripts/idl_definitions.py index 2ad1509..f49dc03 100644 --- a/Source/bindings/scripts/idl_definitions.py +++ b/Source/bindings/scripts/idl_definitions.py @@ -490,7 +490,12 @@ class IdlArgument(TypedObject): raise ValueError('Unrecognized Argument node; expected "...", got "%s"' % child_name) self.is_variadic = child.GetProperty('ELLIPSIS') or False elif child_class == 'Default': - self.default_value = child.GetName() + if child.GetProperty('VALUE') == True: + self.default_value = 'true' + elif child.GetProperty('VALUE') == False: + self.default_value = 'false' + else: + self.default_value = child.GetName() else: raise ValueError('Unrecognized node class: %s' % child_class) Need your opinion on this. 2. Other case is PassRefPtr. We cannot pass a default value as null to a PassRefPtr. For eg. below statement throws compilation errors NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter filter = null); where as this one works fine boolean isSameNode(optional Node other = null); I observed that there are two classes which are specially handled in the current script 'NodeFilter' and 'XPathNSResolver'. I want to know whether similar can be done in this case. Please suggest if you have better ideas to handle this case. Thanks in advance.
On 2014/05/15 14:33:06, pavane wrote: > Please have a look at this patch. Context: I had started on an implementation of this too, so I'll be talking about my alternative implementation (which is far from finished.) It would be helpful if you added tests to Source/bindings/tests/idls/TestObject.idl so that we can see your code in action directly in the CL. I had added this block of methods on my branch: // Optional arguments with defaults void voidMethodDefaultStringArg(optional DOMString defaultStringArg = "foo"); void voidMethodDefaultLongArg(optional long defaultLongArg = 10); void voidMethodDefaultDoubleArg(optional double defaultDoubleArg = 0.5); void voidMethodDefaultTrueBooleanArg(optional boolean defaultBooleanArg = true); void voidMethodDefaultFalseBooleanArg(optional boolean defaultBooleanArg = false); void voidMethodDefaultNullableStringArg(optional DOMString? defaultStringArg = null); void voidMethodDefaultNullableTestInterfaceArg(optional TestInterface? defaultTestInterfaceArg = null); Note: I'm not sure all of those make sense to test, but at least some of them ought to. > There are still two problems which need to be handled. > > 1. From my observation, it looks like keywords like true and false are > separately handled. > For eg. it is able to resolve statements like below > Node cloneNode(optional bool deep = "true"); > Node cloneNode(optional bool deep = 1); > whereas it is not able to resolve the below statement, > Node cloneNode(optional bool deep = true); > > We may have to hack the script to handle these booleans. One way to handle this > is like below: > diff --git a/Source/bindings/scripts/idl_definitions.py > b/Source/bindings/scripts/idl_definitions.py > index 2ad1509..f49dc03 100644 > --- a/Source/bindings/scripts/idl_definitions.py > +++ b/Source/bindings/scripts/idl_definitions.py > @@ -490,7 +490,12 @@ class IdlArgument(TypedObject): > raise ValueError('Unrecognized Argument node; expected > "...", got "%s"' % child_name) > self.is_variadic = child.GetProperty('ELLIPSIS') or False > elif child_class == 'Default': > - self.default_value = child.GetName() > + if child.GetProperty('VALUE') == True: > + self.default_value = 'true' > + elif child.GetProperty('VALUE') == False: > + self.default_value = 'false' > + else: > + self.default_value = child.GetName() > else: > raise ValueError('Unrecognized node class: %s' % child_class) > > Need your opinion on this. It's probably best that the experts weigh in on this. My next step, had I continued with my implementation, would have been to check if the base IDL parser in {chromium}/tools/idl_parser/ could be made a bit more uniform in how it represents literal values, so that the code here could be (ideally IMO) just self.default_value = child.GetProperty('VALUE') Using the 'NAME' property as the value for a literal is a bit awkward. You also need to look at the 'TYPE' property, I think. And why does "0.5" come out as a node with 'VALUE' == "0.5" and 'TYPE' == "float", but "10" come out as a node with 'NAME' == "10" and 'TYPE' == "integer". Crazy. :-) > 2. Other case is PassRefPtr. We cannot pass a default value as null to a > PassRefPtr. > For eg. below statement throws compilation errors > NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = > 0xFFFFFFFF, optional NodeFilter filter = null); > where as this one works fine > boolean isSameNode(optional Node other = null); > > I observed that there are two classes which are specially handled in the current > script 'NodeFilter' and 'XPathNSResolver'. I want to know whether similar can be > done in this case. Please suggest if you have better ideas to handle this case. I based my experience on the unfinished CL https://codereview.chromium.org/265293004/, where local variables for all arguments are declared first, before type checking and conversion is done for the arguments. Based on that, I used the declared default arguments to initialize the locals instead of passing them as arguments directly to the C++ implementation. IOW, the generated code for "void method(double A, optional double B = 0.5)" would look something like this: double requiredArg; double optionalArg = 0.5; do { requiredArg = ...; if (info.Length() < 2) break; optionalArg = ...; } while (false); impl->method(requiredArg, optionalArg); This approach is not necessarily ideal, either, but does reduce amount of (source and binary) code in some cases, and would work for RefPtr/PassRefPtr, I believe. The RefPtr local would just be left "uninitialized", i.e. null, but "optionalArg.release()" would still work fine as the value for a PassRefPtr argument (I assume.)
Hi Pavane, Thanks for doing this! not LGTM currently, but with revisions (addressing Jens's concerns) would be very welcome! Issues to address: 1. Test cases. Please add test cases only for examples that are actually used in real IDL files. 2. Update IDL files. As a rule we make changes to IDL files *in sync* with changes to the CG, so it's clear from the revision history how changes are related. Thus could you please change *all* cases of [Default=...] that are handled by this CL? Here's a quick bash file I use called |grep-idl|; you can call it with grep-idl Default ...to find all uses of the [Default] extended attribute in the Blink codebase: ######################################################## #!/bin/bash # Find IDL files with a particular extended attribute, # optionally with some following restriction (e.g., attribute, const, interface) cd "$BLINK_DIR" EXT_ATTR="$1" EXT_ATTR_RE="\[[^\]]*$EXT_ATTR[^\]]*\]" if [ $# -eq 2 ] then REST="$2" else REST='' fi REST_RE="[^{;]*$REST[^{;]*({|;)" RE="(?s)$EXT_ATTR_RE$REST_RE" # FIXME: add a filename list mode grep \ --color=auto \ -Pzo "$RE" \ $(git ls-files '*.idl') ######################################################## 3. Once you've handled all cases, please remove the existing [Default] extended attribute from the CG, IDLExtendedAttributes.txt, and the IDL extended attributes documentation at: http://www.chromium.org/blink/webidl/blink-idl-extended-attributes On 2014/05/15 14:33:06, pavane wrote: > Please have a look at this patch. > > There are still two problems which need to be handled. > > 1. From my observation, it looks like keywords like true and false are > separately handled. It's fine to not handle these for now: we work very incrementally in bindings, so you can just handle the easy cases first, and followup with handling these other cases. This also makes reviewing easier. > We may have to hack the script to handle these booleans. One way to handle this > is like below: > diff --git a/Source/bindings/scripts/idl_definitions.py > b/Source/bindings/scripts/idl_definitions.py > index 2ad1509..f49dc03 100644 > --- a/Source/bindings/scripts/idl_definitions.py > +++ b/Source/bindings/scripts/idl_definitions.py > @@ -490,7 +490,12 @@ class IdlArgument(TypedObject): > raise ValueError('Unrecognized Argument node; expected > "...", got "%s"' % child_name) > self.is_variadic = child.GetProperty('ELLIPSIS') or False > elif child_class == 'Default': > - self.default_value = child.GetName() > + if child.GetProperty('VALUE') == True: > + self.default_value = 'true' > + elif child.GetProperty('VALUE') == False: > + self.default_value = 'false' > + else: > + self.default_value = child.GetName() > else: > raise ValueError('Unrecognized node class: %s' % child_class) Have you considered using a function? ;) More seriously, parsing is very naturally recursive and factored as "one function per node type". Please follow the existing code, as per: self.default_value = default_node_to_default_value(child) This also means that the function can use |return| instead of elif and assignment, which is clearer. > 2. Other case is PassRefPtr. We cannot pass a default value as null to a > PassRefPtr. > For eg. below statement throws compilation errors > NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = > 0xFFFFFFFF, optional NodeFilter filter = null); > where as this one works fine > boolean isSameNode(optional Node other = null); > > I observed that there are two classes which are specially handled in the current > script 'NodeFilter' and 'XPathNSResolver'. I want to know whether similar can be > done in this case. Please suggest if you have better ideas to handle this case. Handle these in a followup. For PassRefPtr handling (I think this is for callback functions, right?), please ask haraken@ for advice.
Thanks for review Jens! As you note, covering all cases is a bit intricate. On 2014/05/15 15:52:36, Jens Lindström wrote: > Context: I had started on an implementation of this too, so I'll be talking > about my alternative implementation (which is far from finished.) Jens, it's fine to upload v. small and simple CLs (like this one, but with tests and actual use); no need to have it completely perfect for all cases before posting! (As a rule in bindings we're v. agile, and we're fine with refactoring and restructuring as we go: the churn is part of the review process around here ;) > It would be helpful if you added tests to > Source/bindings/tests/idls/TestObject.idl so that we can see your code in action > directly in the CL. I had added this block of methods on my branch: > > // Optional arguments with defaults <snip> > > Note: I'm not sure all of those make sense to test, but at least some of them > ought to. Thanks for the great examples! As noted, we add test cases based on actual code; I grep through .idl files or generated code to see what is actually used. > > There are still two problems which need to be handled. > > > > 1. From my observation, it looks like keywords like true and false are > > separately handled. <snip> > It's probably best that the experts weigh in on this. My next step, had I > continued with my implementation, would have been to check if the base IDL > parser in {chromium}/tools/idl_parser/ could be made a bit more uniform in how > it represents literal values, so that the code here could be (ideally IMO) just > > self.default_value = child.GetProperty('VALUE') Cleaning up the base parser will be much easier once Chromium and Blink repos are merged, as otherwise we have lots of 3-sided patches to handle transition. In this case that's not necessary since we're not yet using this. In general we're fine with adding compatibility layer and a FIXME, particularly for this case. (Parser is pretty stable and not where the action is, so technical debt in the idl_definitions compatibility layer is acceptable.) > Using the 'NAME' property as the value for a literal is a bit awkward. You also > need to look at the 'TYPE' property, I think. > > And why does "0.5" come out as a node with 'VALUE' == "0.5" and 'TYPE' == > "float", but "10" come out as a node with 'NAME' == "10" and 'TYPE' == > "integer". Crazy. :-) Could you file a bug for this? This level of inconsistency should be fixed. The contact for the base IDL parser is Noel Allen (noelallen@), and he's very helpful and open to fixes. > > 2. Other case is PassRefPtr. <snip: v. helpful response> haraken: is Jens's approach for RefPtr/PassRefPtr handling correct? See earlier: https://codereview.chromium.org/272213005/#msg2
Inline style points. https://codereview.chromium.org/272213005/diff/1/Source/bindings/scripts/v8_m... File Source/bindings/scripts/v8_methods.py (right): https://codereview.chromium.org/272213005/diff/1/Source/bindings/scripts/v8_m... Source/bindings/scripts/v8_methods.py:171: 'default_value': argument.default_value, Alphabetical order please. https://codereview.chromium.org/272213005/diff/1/Source/bindings/scripts/v8_m... Source/bindings/scripts/v8_methods.py:198: # Truncate omitted optional arguments Could you move these down to the cpp_arguments.extend() lines, and omit the auxiliary variables? (We tend to avoid these if possible.) https://codereview.chromium.org/272213005/diff/1/Source/bindings/scripts/v8_m... Source/bindings/scripts/v8_methods.py:208: cpp_arguments.extend(cpp_argument(argument) for argument in required_arguments) Line breaks please, here and next line: loop and condition both on separate lines.
Thanks Nils and Jens for your reviews. Nils, I thought of handling this issue in bits and pieces because of complexity involved but what you said makes sense. So, i will first solve the simpler cases and later go for complex cases one by one and in the end i will remove the syntax handling code for complete set of [Default] extended attributes. Regarding the below comment: > And why does "0.5" come out as a node with 'VALUE' == "0.5" and 'TYPE' == > "float", but "10" come out as a node with 'NAME' == "10" and 'TYPE' == > "integer". Crazy. :-) Yes, i too noted that this behavior is awkward. My personal feeling is that we should have everything coming into 'VALUE'. Then below statement will suffice for all cases self.default_value = child.GetProperty('VALUE') But problem is Types like String, Integer etc are coming into 'NAME' and Types like Boolean, Double, Float etc are coming into 'VALUE'. Yes, it is better to raise a bug for it. For now, i will put a hack for solving these cases till the time this issue is solved.
On 2014/05/16 13:11:30, pavane wrote: > Nils, I thought of handling this issue in bits and pieces because of complexity > involved but what you said makes sense. So, i will first solve the simpler cases > and later go for complex cases one by one and in the end i will remove the > syntax handling code for complete set of [Default] extended attributes. Sounds good! BTW, I'm OoO next week, so please direct reviews to haraken and Jens, but feel free to CC me; I'll be back the following week (May 26th) and can review again then.
Hi Pavane, Thanks for fixes! (I know you haven't sent it for another review, but added a few notes.) Assuming this works, please: * Add some test cases. * Fix current uses (that this covers). ...and I'll be happy to ok it! https://codereview.chromium.org/272213005/diff/40001/Source/bindings/scripts/... File Source/bindings/scripts/idl_definitions.py (right): https://codereview.chromium.org/272213005/diff/40001/Source/bindings/scripts/... Source/bindings/scripts/idl_definitions.py:514: # FIXME: IDL parser currently outputs literal values inconsistently(crbug.com/374178). Please use complete URLs (so syntax matching detects them). In fact, once it's consistent, you can remove this function, since it's just a single expression! So the comment should be something like: # FIXME: Should be: return node.GetProperty('VALUE') (inlined) # but IDL parser currently outputs literal values inconsistently # http://crbug.com/374178 https://codereview.chromium.org/272213005/diff/40001/Source/bindings/scripts/... Source/bindings/scripts/idl_definitions.py:516: if (node.GetProperty('TYPE') == "boolean" or Single quotes. https://codereview.chromium.org/272213005/diff/40001/Source/bindings/scripts/... Source/bindings/scripts/idl_definitions.py:517: node.GetProperty('TYPE') == "float"): You can use |in| for checking against a list: node.GetProperty('TYPE') in ('boolean', 'float') Slick, eh?
https://codereview.chromium.org/272213005/diff/40001/Source/bindings/scripts/... File Source/bindings/scripts/idl_definitions.py (right): https://codereview.chromium.org/272213005/diff/40001/Source/bindings/scripts/... Source/bindings/scripts/idl_definitions.py:517: node.GetProperty('TYPE') == "float"): On 2014/06/02 02:48:34, Nils Barth wrote: > You can use |in| for checking against a list: > node.GetProperty('TYPE') in ('boolean', 'float') > Slick, eh? BTW, since it's probably unfamiliar: You can also use |in| for substring testing! https://docs.python.org/2/library/stdtypes.html#index-22
Message was sent while issue was closed.
Closing, superseded by: https://codereview.chromium.org/312683005/ |