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
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>
>>
>