On Sat, Nov 21, 2015 at 7:07 AM, Thierry Goubier <[email protected]>
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
>> <[email protected] <mailto:[email protected]>> 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
>>
>
>
>


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

Reply via email to