I’m also pretty sure that the following from Mozilla’s page[1] will not work 
correctly:

var people = <people>
  <person>
    <name>Bob</name>
    <age>32</age>
  </person>
  <person>
    <name>Joe</name>
    <age>46</age>
  </person>
</people>;

function over40(i) {
    return i > 40;
}

alert(people.person.(over40(parseInt(age))).name); // Alerts Joe

https://developer.mozilla.org/en-US/docs/Archive/Web/E4X/Processing_XML_with_E4X
 
<https://developer.mozilla.org/en-US/docs/Archive/Web/E4X/Processing_XML_with_E4X>

> On Aug 7, 2018, at 1:41 PM, Harbs <[email protected]> wrote:
> 
> OK. I fixed the issue, but there’s a couple of loose ends:
> 
> 1. I don’t know how to add unit tests for these cases. In the current unit 
> tests, I see “getNode” and “getVariable” being used. I don’t know the logic 
> in setting up tests.
> 2. I’m not quite sure what "parentNode.getChild(0)” does. What is the parent 
> node and will this cause my second case of e.employee.(1 == @id) to fail? 
> Removing the check against firstChild caused the testXMLFilterWithAttribute 
> test to fail because it prepended “node.” to “length()”.
> 
> P.S. I finally got debugging from Eclipse working on the compiler, so 
> hopefully I’ll have a much easier time fixing compiler issues in the future. 
> :-)
> 
> Thanks,
> Harbs
> 
>> On Aug 7, 2018, at 10:51 AM, Harbs <[email protected]> wrote:
>> 
>> Well, it looks like I was wrong.
>> 
>> I just tested the following in Flash, and then both give the same results 
>> (i.e. return the attribute):
>> 
>> var emp = e.employee.(@id == 1).@name; // name of employee with id 1
>> var foo = e.employee.(1 == @id).@name; // name of employee with id 1
>> 
>>> On Aug 7, 2018, at 10:27 AM, Harbs <[email protected]> wrote:
>>> 
>>> 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
>>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>> 
>>>> 
>>>> 
>>> 
>> 
> 

Reply via email to