lengthToLen() is called when the selection pattern doesn't fully match
So part of tracking down the length issue (since I'm seeing that currently), I noticed that the call transforms.lengthToLen() got called repeatedly for transforms that weren't related to the selection definition for that function.
Breaking in with the python debugger gave me the following:
In compiler/__init__.py(38):transformAST()
-> import pdb; pdb.set_trace()
(Pdb) print selector
Child(Type(DOT:15) > Type(IDENT=length:164))
There should be a METHOD_CALL in front of that according to what's in config/default.py:
(Type('METHOD_CALL') > Type('DOT') > Type('IDENT', 'length'), transform.lengthToLen)
Further tracing shows the problem to be in the Selector.gt() function in lang/selector.py:
def __gt__(self, other):
""" E > F
Like CSS: "E > F": an F element child of an E element
"""
return Child(self, other)
In the case of Type(A) > Type(B) > Type(C), the interpreter is evaluating Type(A) > Type(B) as True first and then returns the value of Type(B) > Type(C).
I'm thinking that one option might be to override the >> op instead, but I'm trying to think if there's a left to right issue.
Ideally, for Type(A) >> Type(B) >> Type(C) I think I'd want:
Child(Type(A), Child(Type(B), Type(C)))
But right now, I'd get:
Child(Child(Type(A), Type(B)), Type(C))
Are those equivalent selections?
Thanks for the detailed analysis and ticket. That's truly appreciated.
I think the selector is wrong; the Type('METHOD_CALL') doesn't need to be in there at all.
I checked the __gt__ issue, and it works like I expect in a test case that's outside of j2py, so I'll revisit that when I'm wrapping this up.
Here's the source file I was concentrating on, and it could serve as a good test case for the conversion of length to len():
http://code.google.com/p/zxing/source/browse/trunk/core/src/com/google/zxing/common/reedsolomon/GenericGFPoly.java
When I ran j2py against that, j2py crashed.
The AST being passed into lengthToLen didn't resemble the AST lengthToLen is expecting in it's docstring.
This is the code I tested to test the gt()
class A(object):
def __gt__(self, other):
print str(self.__class__) + "__gt__() called"
return self
class B(A):
pass
class C(A):
pass
class D(A):
pass
result = A() > B() > C() > D()
print "Output: " + str(result.__class__)
result = A() > ( B() > ( C() > D() ) )
print "Output: " + str(result.__class__)
The output looks like this:
<class '__main__.A'>__gt__() called
<class '__main__.B'>__gt__() called
<class '__main__.C'>__gt__() called
Output: <class '__main__.C'>
<class '__main__.C'>__gt__() called
<class '__main__.B'>__gt__() called
<class '__main__.A'>__gt__() called
Output: <class '__main__.A'>
This the exact behavior I saw with the selector. In the first case, whatever A and B returns are tossed. Parens are added to force the correct behavior in the second case.