[squeak-dev] MessageNodes are modified when printed

Levente Uzonyi leves at elte.hu
Sun Feb 20 05:28:44 UTC 2011


Hi,

I was looking for loop patterns that can be rewritten to use #repeat:, 
because it became an inlined message (thanks Nicolas). I decided to use 
ParseNodeEnumerator, the swiss army knife, suitable for these kind of 
tasks. As a first step I tried to find method with the following pattern:
[ ... true ] whileTrue.
To my surprise, my code didn't find any methods with it. Since I knew 
that there are methods with this pattern, I created the following "test 
case" which shows the problem:

| shouldSelect visitor |
shouldSelect := false.
visitor := ParseNodeEnumerator ofBlock: [ :node |
 	shouldSelect := shouldSelect or: [
 		node isMessageNode and: [
 		node selector key == #whileTrue and: [
 		node receiver isBlockNode and: [
 		node receiver statements last isVariableNode and: [
 			node receiver statements last key = 'true' ] ] ] ] ] ].
shouldSelect := false.
[ [ true ] whileTrue ] decompile accept: visitor.
shouldSelect.

It should return true, but it returns false. What's even worse is that if 
you insert a #halt, like in the following example and press proceed when 
the debugger shows up, then the result will be true.

...
 		node isMessageNode and: [
 		self halt.
 		node selector key == #whileTrue and: [
...

The cause of the problem is that the decompiler creates the MessageNode 
with #whileTrue: as selector instead of #whileTrue, but MessageNode >> 
#printWhileOn:indent: or MessageNode >> 
#printWithClosureAnalysisWhileOn:indent: replaces the selector to 
#whileTrue. Since the debugger triggers one of these methods, 
the code will pass in the second case (#halt). The same happens if you 
open an explorer on the MessageNode.

Shouldn't the change be done by the decompiler, instead of some method 
used for printing?


Cheers,
Levente

P.S.: I finished the script and rewrote most methods with these patterns 
in the Trunk. I'll push them soon. Here's the final snippet in case you 
would like to check your own code:

| shouldSelect |
shouldSelect := false.
visitor := ParseNodeEnumerator ofBlock: [ :node |
 	shouldSelect := shouldSelect or: [
 		node isMessageNode and: [
 			(#(whileTrue whileTrue: whileFalse whileFalse:) instVarsInclude: node selector key) and: [
 				| receiver |
 				(receiver := node receiver) isBlockNode and: [
 					| lastStatement |
 					(lastStatement := receiver statements last) isVariableNode and: [
 						#('true' 'false') includes: lastStatement key ] ] ] ] ] ].
SystemNavigation default browseAllSelect: [ :method |
 	shouldSelect := false.
 	method decompile accept: visitor.
 	shouldSelect ]



More information about the Squeak-dev mailing list