Modify AST to send a message on Character nodes
Hi everyone, I would like to modify the AST of a smalltalk expression compiled to automatically send a certain message when a node represents a Character (so the user does not have to write the message sending explicitly). I would of course add a special button in the menu you get when right clicking in a playground so the user knows it is a "special" do-it... For example: $a. would transform into an ast that the source code looks like $a aMessage How can I do this? :) Julien
If you don't want to manually operate on AST, you can use Mark's Rewrite Tool ( http://screencast.com/t/LCEl0hFl , https://medium.com/@peteruhnak/using-rewrite-tool-for-fixing-deprecated-code... ) As for ASTs I would be also curious about the answer, as this seems like it should be a simple task. Peter On Sat, Sep 12, 2015 at 2:24 PM, Julien Delplanque <julien@tamere.eu> wrote:
Hi everyone,
I would like to modify the AST of a smalltalk expression compiled to automatically send a certain message when a node represents a Character (so the user does not have to write the message sending explicitly). I would of course add a special button in the menu you get when right clicking in a playground so the user knows it is a "special" do-it...
For example: $a. would transform into an ast that the source code looks like $a aMessage
How can I do this? :)
Julien
Hi everyone, I believe you should be able to do this transformation with Rewrite Tool. The only problem I see is that you want to do this only with single symbol. Because, in my tool you can do: transform: *`#literal* into: *`#literal aMessage*. In this case `#literal means any literal, not only symbols. In other words it will transform $a into $a aMessage Also, this rule will transform, for instance 123 into 123 aMessage If I understand right, you would like to do this programatically, so you don't need RewriteTool in that case. Mark 2015-09-12 16:46 GMT+03:00 Peter Uhnák <i.uhnak@gmail.com>:
If you don't want to manually operate on AST, you can use Mark's Rewrite Tool ( http://screencast.com/t/LCEl0hFl , https://medium.com/@peteruhnak/using-rewrite-tool-for-fixing-deprecated-code... )
As for ASTs I would be also curious about the answer, as this seems like it should be a simple task.
Peter
On Sat, Sep 12, 2015 at 2:24 PM, Julien Delplanque <julien@tamere.eu> wrote:
Hi everyone,
I would like to modify the AST of a smalltalk expression compiled to automatically send a certain message when a node represents a Character (so the user does not have to write the message sending explicitly). I would of course add a special button in the menu you get when right clicking in a playground so the user knows it is a "special" do-it...
For example: $a. would transform into an ast that the source code looks like $a aMessage
How can I do this? :)
Julien
Hi Julien, Mark and Peter, here is a RB approach: | rewriter | rewriter := RBParseTreeRewriter new replace: ' `#aLiteral `{:node | node value isCharacter}' with: '`#aLiteral aMessage'; yourself. rewriter executeTree: (RBParser parseExpression: 'Array with: $a asciiValue with: $b with: #c with: d'). rewriter tree formattedCode And the result is: 'Array with: $a aMessage asciiValue with: $b aMessage with: #c with: d' Need to keep all those snipets somewhere. And I think the chapter in Pharo for the enterprise does not explain well the conditional stuff in { }. Thierry Le 12/09/2015 16:03, Mark Rizun a écrit :
Hi everyone,
I believe you should be able to do this transformation with Rewrite Tool. The only problem I see is that you want to do this only with single symbol. Because, in my tool you can do:
transform: *`#literal* into: *`#literal aMessage*. In this case `#literal**means any literal, not only symbols. In other words it will transform
$a into $a aMessage
Also, this rule will transform, for instance 123 into 123 aMessage
If I understand right, you would like to do this programatically, so you don't need RewriteTool in that case.
Mark
2015-09-12 16:46 GMT+03:00 Peter Uhnák <i.uhnak@gmail.com <mailto:i.uhnak@gmail.com>>:
If you don't want to manually operate on AST, you can use Mark's Rewrite Tool ( http://screencast.com/t/LCEl0hFl , https://medium.com/@peteruhnak/using-rewrite-tool-for-fixing-deprecated-code... )
As for ASTs I would be also curious about the answer, as this seems like it should be a simple task.
Peter
On Sat, Sep 12, 2015 at 2:24 PM, Julien Delplanque <julien@tamere.eu <mailto:julien@tamere.eu>> wrote:
Hi everyone,
I would like to modify the AST of a smalltalk expression compiled to automatically send a certain message when a node represents a Character (so the user does not have to write the message sending explicitly). I would of course add a special button in the menu you get when right clicking in a playground so the user knows it is a "special" do-it...
For example: $a. would transform into an ast that the source code looks like $a aMessage
How can I do this? :)
Julien
Le 12/09/2015 18:20, Mark Rizun a écrit :
Need to keep all those snipets somewhere. And I think the chapter in Pharo for the enterprise does not explain well the conditional stuff in { }.
I always forget the syntax of writing condition on nodes :)
I was missing the fact that the condition apply to the previous pattern variable? Conditions are very convenient, however, to execute code during the matching part of the rewrite. Especially code with side effects ;) Thierry
| rewriter | rewriter := RBParseTreeRewriter new replace: ' `#aLiteral `{:node | node value isCharacter}' with: '`#aLiteral aMessage'; yourself. rewriter executeTree: (RBParser parseExpression: 'Array with: $a asciiValue with: $b with: #c with: d'). rewriter tree formattedCode
This is cool! And so simple! Need to keep all those snipets somewhere. And I think the chapter in Pharo
for the enterprise does not explain well the conditional stuff in { }.
P4E is still work-in-progress, no? So it still can be added there. I think we need some better way to present the content of the books than just a "book"... like with side menu showing topics within a chapter, search, or whatever. Maybe it could be made available somewhere with Guille's Ecstatic generator. Peter
On 12 Sep 2015, at 19:23, Peter Uhnák <i.uhnak@gmail.com> wrote:
| rewriter | rewriter := RBParseTreeRewriter new replace: ' `#aLiteral `{:node | node value isCharacter}' with: '`#aLiteral aMessage'; yourself. rewriter executeTree: (RBParser parseExpression: 'Array with: $a asciiValue with: $b with: #c with: d'). rewriter tree formattedCode
This is cool! And so simple!
This can be combined with the compiler transform plugins of Opal: -> make subclass of OCCompilerASTPlugin -> put your code in a method called #transform now when you override #compiler on the class side of a class like this: compiler ^super compiler addPlugin: ASTPluginMeaningOfLife. the plugin will be active for the hierarchy, which means that all code compiled will be transformed. There is a simple example ASTPluginMeaningOfLife in the image. Marcus
Le 13/09/2015 08:56, Marcus Denker a écrit :
On 12 Sep 2015, at 19:23, Peter Uhnák <i.uhnak@gmail.com <mailto:i.uhnak@gmail.com>> wrote:
| rewriter | rewriter := RBParseTreeRewriter new replace: ' `#aLiteral `{:node | node value isCharacter}' with: '`#aLiteral aMessage'; yourself. rewriter executeTree: (RBParser parseExpression: 'Array with: $a asciiValue with: $b with: #c with: d'). rewriter tree formattedCode
This is cool! And so simple!
This can be combined with the compiler transform plugins of Opal:
-> make subclass of OCCompilerASTPlugin -> put your code in a method called #transform
now when you override #compiler on the class side of a class like this:
compiler ^super compiler addPlugin: ASTPluginMeaningOfLife.
the plugin will be active for the hierarchy, which means that all code compiled will be transformed.
There is a simple example ASTPluginMeaningOfLife in the image.
Cool. Intriguing. I'm sure I can use it to: - patch problematic code on the fly without registering an override - change the semantics of some smalltalk statement (so that a := becomes self a: or anything else) Would it be possible to couple it with Clement work to have some ability to pre-compile some code in specific classes (strength reduction, once literals) where we know that this is valuable? It would also be nice to have a way not to write bytecode by hand, like, say, in the slots example of a few days back. Oh, ok, for the literal stuff, I think I know how to do it: In a method: - replace target expression with symbol literal. - evaluate target expression in isolation, store value. - compile method with symbol literal. - in compiled method, replace symbol literal with value stored above. Would that work? Thierry
Marcus
Cool. Intriguing.
I'm sure I can use it to: - patch problematic code on the fly without registering an override - change the semantics of some smalltalk statement (so that a := becomes self a: or anything else)
Yes, it is for âevilâ experiments that can not be done else (short of changing the compiler itself). e.g. last week for an experiment, I wanted a form of âsuperâ where it is not âself, but start lookup in superclassâ, but instead âthis object, do a send to it but start lookup in the superclassâ. There are no messages called #super in the image, so you can so that by transforming all myObject super doSomething into myObject perform: #doSomething withArguments: #() inSuperclass: myObject class superclass. The needed Opal plugin has this #transform method: transform | superSends new | superSends := ast sendNodes select: [ :each | each selector = #super ]. superSends do: [ :spnode | new := RBMessageNode receiver: spnode receiver copy selector: #perform:withArguments:inSuperclass: arguments: {RBLiteralNode value: spnode parent selector copy . RBArrayNode statements: spnode parent arguments . RBMessageNode receiver: (RBMessageNode receiver: spnode receiver copy selector: #class) selector: #superclass}. spnode parent replaceWith: new ]. ^ast
Would it be possible to couple it with Clement work to have some ability to pre-compile some code in specific classes (strength reduction, once literals) where we know that this is valuable?
Good questionâ¦.
It would also be nice to have a way not to write bytecode by hand, like, say, in the slots example of a few days back.
Yes, the byte code writing for Slots is just a solution that works *today*. With a runtime optimizer you could instead always generate the reflective slow version and let Sista optimise it.
Oh, ok, for the literal stuff, I think I know how to do it:
In a method: - replace target expression with symbol literal. - evaluate target expression in isolation, store value. - compile method with symbol literal. - in compiled method, replace symbol literal with value stored above.
Would that work?
Hmm⦠messages to known objects without side effect could be evaluated by the compiler. What makes it hard ist mostly debugging: mapping the generated code back to the original sourceâ¦. Marcus
Great! Thats what I was looking for. On 12/09/15 18:12, Thierry Goubier wrote:
Hi Julien, Mark and Peter,
here is a RB approach:
| rewriter | rewriter := RBParseTreeRewriter new replace: ' `#aLiteral `{:node | node value isCharacter}' with: '`#aLiteral aMessage'; yourself. rewriter executeTree: (RBParser parseExpression: 'Array with: $a asciiValue with: $b with: #c with: d'). rewriter tree formattedCode
And the result is:
'Array with: $a aMessage asciiValue with: $b aMessage with: #c with: d'
Need to keep all those snipets somewhere. And I think the chapter in Pharo for the enterprise does not explain well the conditional stuff in { }.
Thierry
Le 12/09/2015 16:03, Mark Rizun a écrit :
Hi everyone,
I believe you should be able to do this transformation with Rewrite Tool. The only problem I see is that you want to do this only with single symbol. Because, in my tool you can do:
transform: *`#literal* into: *`#literal aMessage*. In this case `#literal**means any literal, not only symbols. In other words it will transform
$a into $a aMessage
Also, this rule will transform, for instance 123 into 123 aMessage
If I understand right, you would like to do this programatically, so you don't need RewriteTool in that case.
Mark
2015-09-12 16:46 GMT+03:00 Peter Uhnák <i.uhnak@gmail.com <mailto:i.uhnak@gmail.com>>:
If you don't want to manually operate on AST, you can use Mark's Rewrite Tool ( http://screencast.com/t/LCEl0hFl , https://medium.com/@peteruhnak/using-rewrite-tool-for-fixing-deprecated-code... )
As for ASTs I would be also curious about the answer, as this seems like it should be a simple task.
Peter
On Sat, Sep 12, 2015 at 2:24 PM, Julien Delplanque <julien@tamere.eu <mailto:julien@tamere.eu>> wrote:
Hi everyone,
I would like to modify the AST of a smalltalk expression compiled to automatically send a certain message when a node represents a Character (so the user does not have to write the message sending explicitly). I would of course add a special button in the menu you get when right clicking in a playground so the user knows it is a "special" do-it...
For example: $a. would transform into an ast that the source code looks like $a aMessage
How can I do this? :)
Julien
Le 12/09/2015 15:46, Peter Uhnák a écrit :
If you don't want to manually operate on AST, you can use Mark's Rewrite Tool ( http://screencast.com/t/LCEl0hFl , https://medium.com/@peteruhnak/using-rewrite-tool-for-fixing-deprecated-code... )
As for ASTs I would be also curious about the answer, as this seems like it should be a simple task.
It is fairly easy if you write a RB AST visitor subclass, with a single method / case to handle character literal. Now, I'm sure you can use RBParseTreeRewriter to do it with a single call... Thierry
Peter
On Sat, Sep 12, 2015 at 2:24 PM, Julien Delplanque <julien@tamere.eu <mailto:julien@tamere.eu>> wrote:
Hi everyone,
I would like to modify the AST of a smalltalk expression compiled to automatically send a certain message when a node represents a Character (so the user does not have to write the message sending explicitly). I would of course add a special button in the menu you get when right clicking in a playground so the user knows it is a "special" do-it...
For example: $a. would transform into an ast that the source code looks like $a aMessage
How can I do this? :)
Julien
participants (5)
-
Julien Delplanque -
Marcus Denker -
Mark Rizun -
Peter Uhnák -
Thierry Goubier