[Pharo-project] How to get the AST Node for a Context
Hi, We implemented this today: #sourceNode for MethodContext. It returns the AST node of context, as part of the whole AST of the method. thisContext sourceNode Returns: DoIt ^ thisContext sourceNode ------------ [ thisContext sourceNode ] value ==> RBBlockNode([ thisContext sourceNode ]) --------------- But even for optimized blocks it works: [ true ifTrue:[thisContext sourceNode ]] value RBBlockNode([ thisContext sourceNode ]) The AST is the one used for code generation, with all information of Semantic Analysis *and* the possibility to get the IR with all information, too. So: [ true ifTrue:[|a|thisContext sourceNode ]] value scope ===> an OCOptimizedBlockScope 4 Marcus
Yeah this is really cool. Especially now BlockClosure and optimized BlockClosure (to:do:, ifTrue:ifFalse:, ifNil:ifNotNil:, and:, or:) have the same behavior for debugger byte code to source code mapping, for decompilation, ... 2013/4/17 Marcus Denker <marcus.denker@inria.fr>
Hi,
We implemented this today:
#sourceNode for MethodContext. It returns the AST node of context, as part of the whole AST of the method.
thisContext sourceNode
Returns:
DoIt ^ thisContext sourceNode
------------
[ thisContext sourceNode ] value
==>
RBBlockNode([ thisContext sourceNode ])
--------------- But even for optimized blocks it works:
[ true ifTrue:[thisContext sourceNode ]] value
RBBlockNode([ thisContext sourceNode ])
The AST is the one used for code generation, with all information of Semantic Analysis *and* the possibility to get the IR with all information, too.
So:
[ true ifTrue:[|a|thisContext sourceNode ]] value scope
===> an OCOptimizedBlockScope 4
Marcus
-- Clément Béra Mate Virtual Machine Engineer Bâtiment B 40, avenue Halley 59650 *Villeneuve d'Ascq*
I really really like this :) very simple yet powerful! On 2013-04-17, at 21:28, Clément Bera <bera.clement@gmail.com> wrote:
Yeah this is really cool. Especially now BlockClosure and optimized BlockClosure (to:do:, ifTrue:ifFalse:, ifNil:ifNotNil:, and:, or:) have the same behavior for debugger byte code to source code mapping, for decompilation, ...
2013/4/17 Marcus Denker <marcus.denker@inria.fr>
Hi,
We implemented this today:
#sourceNode for MethodContext. It returns the AST node of context, as part of the whole AST of the method.
thisContext sourceNode
Returns:
DoIt ^ thisContext sourceNode
------------
[ thisContext sourceNode ] value
==>
RBBlockNode([ thisContext sourceNode ])
--------------- But even for optimized blocks it works:
[ true ifTrue:[thisContext sourceNode ]] value
RBBlockNode([ thisContext sourceNode ])
The AST is the one used for code generation, with all information of Semantic Analysis *and* the possibility to get the IR with all information, too.
So:
[ true ifTrue:[|a|thisContext sourceNode ]] value scope
===> an OCOptimizedBlockScope 4
Marcus
-- Clément Béra Mate Virtual Machine Engineer Bâtiment B 40, avenue Halley 59650 *Villeneuve d'Ascq*
On Apr 17, 2013, at 10:29 PM, Camillo Bruni <camillobruni@gmail.com> wrote:
I really really like this :)
very simple yet powerful!
Yes this will massively simplify the debugger :) So we will be able to get a debugger really working without needing an magician to fix its bugs. Stef
On Apr 17, 2013, at 10:44 PM, stephane ducasse <stephane.ducasse@free.fr> wrote:
On Apr 17, 2013, at 10:29 PM, Camillo Bruni <camillobruni@gmail.com> wrote:
I really really like this :)
very simple yet powerful!
Yes this will massively simplify the debugger :) So we will be able to get a debugger really working without needing an magician to fix its bugs.
Yes, just the AST with Semantic Analysis information (Scope and Semantic Variables), plus bytecodelevel IR that provides the bridge to the low-level pc (bytecode mapping) data⦠e.g. to get the highlight in the debugger, this is now just this in DebuggerMethodMapOpal: rangeForPC: aPC contextIsActiveContext: contextIsActive "return the debug highlight for aPC" | pc | "When on the top of the stack the pc is pointing to right instruction, but deeper in the stack the pc was already advanced one bytecode, so we need to go back this one bytecode, which can consist of multiple bytes. But on IR, we record the *last* bytecode offset as the offset of the IR instruction, which means we can just go back one" pc := contextIsActive ifTrue: [aPC] ifFalse: [aPC - 1]. ^(methodNode ir instructionForPC: pc) sourceNode debugHighlightRange more helper methods will simplify this even more, e.g. we should have a method on RBMethodNode like #nodeForPC: rangeForPC: aPC contextIsActiveContext: contextIsActive "return the debug highlight for aPC" | pc | "When on the top of the stack the pc is pointing to right instruction, but deeper in the stack the pc was already advanced one bytecode, so we need to go back this one bytecode, which can consist of multiple bytes. But on IR, we record the *last* bytecode offset as the offset of the IR instruction, which means we can just go back one" pc := contextIsActive ifTrue: [aPC] ifFalse: [aPC - 1]. ^(methodNode nodeForPC: pc) debugHighlightRange And this method one then can just implement on MethodContext itself. (Caching is handled by ASTCache). Marcus
I should say that I LOVVVVVVVEEEEE the comments in the method. Yes Yes Yes. Stef
Yes, just the AST with Semantic Analysis information (Scope and Semantic Variables), plus bytecodelevel IR that provides the bridge to the low-level pc (bytecode mapping) dataâ¦
e.g. to get the highlight in the debugger, this is now just this in DebuggerMethodMapOpal:
rangeForPC: aPC contextIsActiveContext: contextIsActive "return the debug highlight for aPC" | pc |
"When on the top of the stack the pc is pointing to right instruction, but deeper in the stack the pc was already advanced one bytecode, so we need to go back this one bytecode, which can consist of multiple bytes. But on IR, we record the *last* bytecode offset as the offset of the IR instruction, which means we can just go back one"
pc := contextIsActive ifTrue: [aPC] ifFalse: [aPC - 1]. ^(methodNode ir instructionForPC: pc) sourceNode debugHighlightRange
more helper methods will simplify this even more, e.g. we should have a method on RBMethodNode like #nodeForPC:
rangeForPC: aPC contextIsActiveContext: contextIsActive "return the debug highlight for aPC" | pc |
"When on the top of the stack the pc is pointing to right instruction, but deeper in the stack the pc was already advanced one bytecode, so we need to go back this one bytecode, which can consist of multiple bytes. But on IR, we record the *last* bytecode offset as the offset of the IR instruction, which means we can just go back one"
pc := contextIsActive ifTrue: [aPC] ifFalse: [aPC - 1]. ^(methodNode nodeForPC: pc) debugHighlightRange
And this method one then can just implement on MethodContext itself. (Caching is handled by ASTCache).
Marcus
+1, the comments helps to understand, but this kind of stateful behavior sucks in the first place 2013/4/18 stephane ducasse <stephane.ducasse@free.fr>
I should say that I LOVVVVVVVEEEEE the comments in the method. Yes Yes Yes.
Stef
Yes, just the AST with Semantic Analysis information (Scope and Semantic
Variables), plus
bytecodelevel IR that provides the bridge to the low-level pc (bytecode mapping) dataâ¦
e.g. to get the highlight in the debugger, this is now just this in DebuggerMethodMapOpal:
rangeForPC: aPC contextIsActiveContext: contextIsActive "return the debug highlight for aPC" | pc |
"When on the top of the stack the pc is pointing to right instruction, but deeper in the stack the pc was already advanced one bytecode, so we need to go back this one bytecode, which can consist of multiple bytes. But on IR, we record the *last* bytecode offset as the offset of the IR instruction, which means we can just go back one"
pc := contextIsActive ifTrue: [aPC] ifFalse: [aPC - 1]. ^(methodNode ir instructionForPC: pc) sourceNode debugHighlightRange
more helper methods will simplify this even more, e.g. we should have a method on RBMethodNode like #nodeForPC:
rangeForPC: aPC contextIsActiveContext: contextIsActive "return the debug highlight for aPC" | pc |
"When on the top of the stack the pc is pointing to right instruction, but deeper in the stack the pc was already advanced one bytecode, so we need to go back this one bytecode, which can consist of multiple bytes. But on IR, we record the *last* bytecode offset as the offset of the IR instruction, which means we can just go back one"
pc := contextIsActive ifTrue: [aPC] ifFalse: [aPC - 1]. ^(methodNode nodeForPC: pc) debugHighlightRange
And this method one then can just implement on MethodContext itself. (Caching is handled by ASTCache).
Marcus
Sure, typical refactoring process. Code is convoluted and hard to follow, so you first document and explicit most obscure steps. In a second time, you realize how simpler it could be... Pharo is quite fast and still accelerating these days, so I understand the "satisfecit", it's already huge progress. My unsatisfied nature just tell to not stop in the middle of the bridge, and to not let un-necessarily complex code, even if well commented :) 2013/4/18 Marcus Denker <marcus.denker@inria.fr>
On Apr 18, 2013, at 12:54 PM, Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com> wrote:
+1, the comments helps to understand, but this kind of stateful behavior sucks in the first place
It does, but one step at a time.
Marcus
On 18 April 2013 19:17, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Sure, typical refactoring process. Code is convoluted and hard to follow, so you first document and explicit most obscure steps. In a second time, you realize how simpler it could be...
Pharo is quite fast and still accelerating these days, so I understand the "satisfecit", it's already huge progress. My unsatisfied nature just tell to not stop in the middle of the bridge, and to not let un-necessarily complex code, even if well commented :)
Opal is there we all can start contributing. I, for instance, have plans for replacing parsing.. to make modular parser & encoder -- Best regards, Igor Stasenko.
On Apr 18, 2013, at 8:19 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 18 April 2013 19:17, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Sure, typical refactoring process. Code is convoluted and hard to follow, so you first document and explicit most obscure steps. In a second time, you realize how simpler it could be...
Pharo is quite fast and still accelerating these days, so I understand the "satisfecit", it's already huge progress. My unsatisfied nature just tell to not stop in the middle of the bridge, and to not let un-necessarily complex code, even if well commented :)
Opal is there we all can start contributing. I, for instance, have plans for replacing parsing.. to make modular parser & encoder
Yes :) I would like to have a compilationContext instead of this ugly full of parameter methods and â¦. I would like to be able to specify an environment (class binding + literal binding) as input and an environment as output so that we can bootstrap the compiler nicely and do a lot fun stuff. Stef
On 18 April 2013 20:35, stephane ducasse <stephane.ducasse@free.fr> wrote:
On Apr 18, 2013, at 8:19 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 18 April 2013 19:17, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Sure, typical refactoring process. Code is convoluted and hard to follow, so you first document and explicit most obscure steps. In a second time, you realize how simpler it could be...
Pharo is quite fast and still accelerating these days, so I understand the "satisfecit", it's already huge progress. My unsatisfied nature just tell to not stop in the middle of the bridge, and to not let un-necessarily complex code, even if well commented :)
Opal is there we all can start contributing. I, for instance, have plans for replacing parsing.. to make modular parser & encoder
Yes :) I would like to have a compilationContext instead of this ugly full of parameter methods and â¦.
I would like to be able to specify an environment (class binding + literal binding) as input and an environment as output so that we can bootstrap the compiler nicely and do a lot fun stuff.
Take a look at Colin Putney's Environments stuff. Seriously. It's all there. Compilation contexts, class bindings, various policies for importing/exporting definitions. It just needs forging in the hands of users. frank
Stef
Sure, typical refactoring process. Code is convoluted and hard to follow, so you first document and explicit most obscure steps. In a second time, you realize how simpler it could be...
Pharo is quite fast and still accelerating these days, so I understand the "satisfecit", it's already huge progress. My unsatisfied nature just tell to not stop in the middle of the bridge, and to not let un-necessarily complex code, even if well commented :)
do not worry for that we have a long list of tasks for the compiler and even more for other components. :) Stef
... and people asking , why it has huge impact on our future :) that's why. On 17 April 2013 23:06, Marcus Denker <marcus.denker@inria.fr> wrote:
On Apr 17, 2013, at 10:44 PM, stephane ducasse <stephane.ducasse@free.fr> wrote:
On Apr 17, 2013, at 10:29 PM, Camillo Bruni <camillobruni@gmail.com> wrote:
I really really like this :)
very simple yet powerful!
Yes this will massively simplify the debugger :) So we will be able to get a debugger really working without needing an magician to fix its bugs.
Yes, just the AST with Semantic Analysis information (Scope and Semantic Variables), plus bytecodelevel IR that provides the bridge to the low-level pc (bytecode mapping) dataâ¦
e.g. to get the highlight in the debugger, this is now just this in DebuggerMethodMapOpal:
rangeForPC: aPC contextIsActiveContext: contextIsActive "return the debug highlight for aPC" | pc |
"When on the top of the stack the pc is pointing to right instruction, but deeper in the stack the pc was already advanced one bytecode, so we need to go back this one bytecode, which can consist of multiple bytes. But on IR, we record the *last* bytecode offset as the offset of the IR instruction, which means we can just go back one"
pc := contextIsActive ifTrue: [aPC] ifFalse: [aPC - 1]. ^(methodNode ir instructionForPC: pc) sourceNode debugHighlightRange
more helper methods will simplify this even more, e.g. we should have a method on RBMethodNode like #nodeForPC:
rangeForPC: aPC contextIsActiveContext: contextIsActive "return the debug highlight for aPC" | pc |
"When on the top of the stack the pc is pointing to right instruction, but deeper in the stack the pc was already advanced one bytecode, so we need to go back this one bytecode, which can consist of multiple bytes. But on IR, we record the *last* bytecode offset as the offset of the IR instruction, which means we can just go back one"
pc := contextIsActive ifTrue: [aPC] ifFalse: [aPC - 1]. ^(methodNode nodeForPC: pc) debugHighlightRange
And this method one then can just implement on MethodContext itself. (Caching is handled by ASTCache).
Marcus
-- Best regards, Igor Stasenko.
stephane ducasse wrote:
On Apr 17, 2013, at 10:29 PM, Camillo Bruni <camillobruni@gmail.com> wrote:
I really really like this :)
very simple yet powerful!
Yes this will massively simplify the debugger :) So we will be able to get a debugger really working without needing an magician to fix its bugs.
Stef
Along the lines of a good engineering principle I like... If you can't solve a problem, change the problem to one you can solve. cheers -ben
On Apr 17, 2013, at 5:51 PM, Marcus Denker <marcus.denker@inria.fr> wrote:
Hi,
We implemented this today:
#sourceNode for MethodContext. It returns the AST node of context, as part of the whole AST of the method.
today we added: [ 1 + 2 ] sourceNode. ==> RBBlockNode([ 1 + 2 ]) (Object>>#halt) sourceNodeForPC: 22. ==> RBMessageNode(Halt now) And (of course): |block blockNodeViaContext blockNodeViaClosure | block := [blockNodeViaContext := thisContext sourceNode]. block value. blockNodeViaClosure := block sourceNode. blockNodeViaContext == blockNodeViaClosure ==> true Marcus
participants (8)
-
Ben Coman -
Camillo Bruni -
Clément Bera -
Frank Shearar -
Igor Stasenko -
Marcus Denker -
Nicolas Cellier -
stephane ducasse