On Sat, Nov 21, 2015 at 7:07 AM, Thierry Goubier <thierry.goubier@gmail.com> wrote:
Hi Mariano,

Le 20/11/2015 20:58, Mariano Martinez Peck a ��crit :
Thierry,

Sorry to bother again. Unfortunately, RB does not work out of the box in
GemStone .... only the formatter part. grrr.

There is maybe a message to send to the maintainer of RB in Gemstone :)


Thanks Thierry. Yes, I talked with Dale and the only "official" usage/port of RB is actually the formatter ;)
��
Anyway, I am trying to make it work, and it's failing in this easy example:

/| tree rewriter |/
/tree := RBParser parseMethod: 'DoIt ^ [:proxy | proxy at: #oldSelector.
]'./
/rewriter := RBParseTreeRewriter new./
/rewriter /
/replace: ('`#oldSelector `{:node | node value isSymbol and: [node value
matchesRegex: ''.*oldSelector.*''] }')/
/with: ('`{RBLiteralNode value: (`#oldSelector value copyReplaceAll:
''oldSelector'' with: ''newSelector'') asSymbol }')./
/rewriter executeTree: tree./
/rewriter tree newSource/
And the problem is the line:

/with: ('`{RBLiteralNode value: (`#oldSelector value copyReplaceAll:
''oldSelector'' with: ''newSelector'') asSymbol }')./

which gets translated to:

[ :aDictionary |
RBLiteralNode
�� ��value:
�� �� ��((*self* lookupMatchFor: '`#oldSelector' in: aDictionary) value
�� �� �� ��copyReplaceAll: 'oldSelector'
�� �� �� ��with: 'newSelector') asSymbol ]

The problem in GemStone is that that "self" is binded to nil and not to
the receiver instance (RBPatternBlockNode). And so I get a Nil dnu..
*And I don't know how that closure is finally generated.*

The message node:

/(*self* lookupMatchFor: '`#oldSelector' in: aDictionary) /

Its generated in:

RBPatternBlockNode >> constructLookupNodeFor: aString in: aRBBlockNode
| argumentNode |
argumentNode := RBLiteralNode value: aString.

^RBMessageNode
receiver:* (RBVariableNode named: 'self')*
selector: #lookupMatchFor:in:
arguments: (Array with: argumentNode with: aRBBlockNode arguments last)

Any ideas?

Yes. I think it is possible to work around it by using the dictionary itself, storing the node selector in it in the replace: pattern and retrieving it in the with: pattern.

rewriter
�� �� �� �� �� �� �� �� replace: ('`#oldSelector `{:node :dic | (node value isSymbol and: [node value matchesRegex: ''.*oldSelector.*'']) ifTrue: [dic at: #selector put: node value. true] ifFalse: [false] }')
�� �� �� �� �� �� �� �� with: ('`{:dic | RBLiteralNode value: ((dic at: #selector) copyReplaceAll: ''oldSelector'' with: ''newSelector'') asSymbol }').


Wow, that's very cool. I wasn't aware that I could pass arguments (like the dict in this case). This is powerful.
Thank you RB Jedi.��
��
Now, maybe correcting RB in Gemstone is something to do, as well.


Yes. So with the dict workaround you said, it DID work, but when I continue a little more and I found out where was the closure being generated, and that is��RBPatternBlockNode >> #createBlockFor:��
And yeah, the way it was being generated the closure ("source evalauted") was binding "self" to nil.�� I found a way to make it bind the real self and that worked too. So...time to fork RB for GemStone and commit the fix :)

BTW, do you image other cases like this?
��
Thanks!

Regards,

Thierry

thanks in advance,


On Mon, Nov 9, 2015 at 2:39 PM, Thierry Goubier
<thierry.goubier@gmail.com <mailto:thierry.goubier@gmail.com>> wrote:

�� �� Le 09/11/2015 17:38, Mariano Martinez Peck a ��crit :

�� �� �� �� Thierry, I have a last question. My last requirement will
�� �� �� �� basically be
�� �� �� �� to find ANY node that would match the regex *oldSelector* and
�� �� �� �� rename it
�� �� �� �� to *newSelector* being that.. a literal string, a literal symbol, a
�� �� �� �� message send, a tempVar name, a comment, etc... I guess there is a
�� �� �� �� simpler way that defining rewrite for each type of node right?
�� �� �� �� I can always do a "(methodSource substrings detect: [:each | each
�� �� �� �� matches: '*oldSelector'] ifNone: [#()] )�� ��each2: [:each2 |
�� �� �� �� copReplace.
�� �� �� �� .... ]


�� �� I think that if it is really everywhere, then it may works better to
�� �� just do text replace (methodSource copyReplaceAll: 'oldSelector'
�� �� with: 'newSelector').

�� �� But remember that it will touch everything (pragmas, varNames,
�� �� comments, etc.)

�� �� �� �� but RB is probably better.


�� �� It gives you more control to what you will change. But then you will
�� �� have to write rewrites for all types of nodes (around 6 or 7?).

�� �� �� �� Any clues in this last requirement?


�� �� Well, one thing which may be interesting would be to consider
�� �� encapsulating the rewrites in refactoring commands, and bring them
�� �� as a composite change, so that you could launch a rewrite, recover
�� �� all those method changes, apply (execute) them, check the result
�� �� with the possibility of undoing them.

�� �� But I'm not familiar with that part of RB. I do consider it could
�� �� become significant with EPICEA. It has been a long term project to
�� �� have AltBrowser make all coding actions as refactoring commands so
�� �� that EPICEA could log them properly, but its only partly there (and
�� �� has been for years now)... and EPICEA is not yet here as well (but
�� �� could be soon).

�� �� Thierry




--
Mariano
http://marianopeck.wordpress.com





--