Your example does not seem to be right to me.
Here’s the overview of how filters are supposed to work from the spec:
> Overview
> When the left operand evaluates to an XML object, the filtering predicate
> adds the left operand to the front of the scope chain of the current
> execution context, evaluates the Expression with the augmented scope chain,
> converts the result to a Boolean value, then restores the scope chain. If the
> result is true, the filtering predicate returns an XMLList containing the
> left operand. Otherwise it returns an empty XMLList.
> When the left operand is an XMLList, the filtering predicate is applied to
> each XML object in the XMLList in order using the XML object as the left
> operand and the Expression as the right operand. It concatenates the results
> and returns them as a single XMLList containing all the XML properties for
> which the result was true. For example,
>
> var john = e.employee.(name == "John"); // employees with name John
> var twoemployees = e.employee.(@id == 0 || @id == 1); // employees with id's
> 0 & 1
> var emp = e.employee.(@id == 1).name; // name of employee with id 1
>
> The effect of the filtering predicate is similar to SQL’s WHERE clause or
> XPath’s filtering predicates.
> For example, the statement:
>
> // get the two employees with ids 0 and 1 using a predicate
> var twoEmployees = e..employee.(@id == 0 || @id == 1);
>
> produces the same result as the following set of statements:
> // get the two employees with the ids 0 and 1 using a for loop
> var i = 0;
> var twoEmployees = new XMLList();
> for each (var p in e..employee) {
> with (p) {
> if (@id == 0 || @id == 1) {
> twoEmployees[i++] = p;
> }
> }
> }
The question is what is "the front of the scope chain of the current execution
context”? I’m pretty sure that means the start of sub-expressions. I don’t see
how that can apply to the right-hand of comparison expressions. There is
nothing in the spec about figuring out if a part of an expression is referring
to XML or XMLList.
> On Aug 7, 2018, at 9:45 AM, Alex Harui <[email protected]> wrote:
>
> I don't get what portion of the spec has to do with whether we append "node"
> to various expressions. IMO, the changes I made only affect 6b. 6a is
> handled by generating a function with "node" as the parameter (because node
> is list[i] in the spec). The task in 6b is to correctly evaluate any e4x
> filter expression. I'm not sure what the limits are on what you can have in
> a filter expression, but if you can have just plain "@app" anywhere in the
> filter expression, I don't believe scoping rules would know to apply that to
> the "node" parameter without generating the "node" before "@app".
>
> There is a chance that the Flex Compiler was using "magic" to generate the
> "node" and really should have reported an error. I do remember being told
> that the filter function can be "anything". Even:
> (var foo:int = @app.length(); foo > @bar.length())
>
> If there are actual rules in the spec about evaluating the expression, that
> might apply to how we handle these expressions, otherwise I think the right
> thing is to resolve each expression and if the expression does not resolve to
> anything else, assume that it applies to the node. I know the logic in
> EmitterUtils.writeE4xFilterNode isn't covering all cases. It is trying to
> see what the expression resolves to, and returns false for known conditions
> (like a member of a class). Just make it return false for your case (and
> feel free to add that case to the tests). Eventually we'll have enough cases
> to either call it "good enough" or figure out a better way to determine when
> the expression applies to "node".
>
> My 2 cents,
> -Alex
>
> On 8/6/18, 11:20 PM, "Harbs" <[email protected]> wrote:
>
> I just looked at the spec. I think it’s correct to append “node” to the
> first statement of the expression only. The only exception seems to be
> expressions which use boolean expressions (i.e. || or &&) in which case each
> piece of the boolean expression should be considered a self-contained
> expression. So in your example, there are really two filter expressions:
> 1. hasOwnProperty("@app”)
> 2. @app.length() > 0
>
> Both of those should have node appended to the front, but nothing else.
>
> Here’s the relevant semantics in the spec (the important bit being 6a):
>
>> 6. For i = 0 to list.[[Length]]-1
>> a. Add list[i] to the front of the scope chain
>> b. Let ref be the result of evaluating Expression using the augmented scope
>> chain of step 6a
>> c. Let match = ToBoolean(GetValue(ref))
>> d. Remove list[i] from the front of the scope chain
>> e. If (match == true), call the [[Append]] method of r with argument list[i]
>> 7. Return r
>
> Makes sense?
>
> Harbs
>
>> On Aug 7, 2018, at 1:39 AM, Alex Harui <[email protected]> wrote:
>>
>> In porting Tour De Flex, there were patterns like this (explorerTree is XML):
>>
>> explorerTree..node.(hasOwnProperty("@app") && @app.length() > 0)
>>
>> The compiler logic before I made any changes yesterday just assumed that the
>> first expression was a reference to the node parameter but other expressions
>> were not, but it looks like the expression "@app.length()" was allowed in
>> Flex as a reference to the node. So I think the compiler has to determine
>> what expressions evaluate to "nothing" which implies they are references to
>> the node, and what did resolve to something. This is all new logic and I
>> don't know how to determine all of the test cases up front, so we'll have to
>> keep tuning it as we find patterns that don't work as we want them to.
>>
>> In your case, if the expression resolves to a VariableDefinition, that
>> probably means that isn't a reference to node. Not exactly sure, so you
>> should debug into it to see what the node pattern is and return false.
>>
>> Thanks,
>> -Alex
>>
>> On 8/6/18, 3:28 PM, "Harbs" <[email protected]> wrote:
>>
>> Doesn’t it always need to be a method for it to reference the node?
>>
>> I.e. child() should be node.child(), but foo.baz would not.
>>
>>> On Aug 7, 2018, at 1:12 AM, Alex Harui <[email protected]> wrote:
>>>
>>> Yep, we need more intelligent understanding of when a reference is to the
>>> node or not.
>>>
>>> Debug into EmitterUtils.writeE4xFilterNode and figure out the node pattern
>>> you need.
>>>
>>> -Alex
>>>
>>> On 8/6/18, 3:09 PM, "Harbs" <[email protected]> wrote:
>>>
>>> var folderFolders:XMLList =
>>> assetXML.folder.(child('key').indexOf(folder.key) == 0);
>>> var folderImages:XMLList =
>>> assetXML.image.(child('key').indexOf(folder.key) == 0);
>>>
>>> Is now compiled as:
>>>
>>> var /** @type {XMLList} */ folderFolders =
>>> this.assetXML.child('folder').filter(function(node){return
>>> (node.child('key').indexOf(node.folder.key) == 0)});
>>> var /** @type {XMLList} */ folderImages =
>>> this.assetXML.child('image').filter(function(node){return
>>> (node.child('key').indexOf(node.folder.key) == 0)});
>>>
>>> “node.folder.key” is not correct. “folder” is a local variable of an un
>>> related object type.
>>>
>>> I assume this broke with the recent XML filter changes.
>>>
>>> Harbs
>>>
>>
>>
>>
>
>
>