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