whileTrue: and whileFalse: always return zero. for example, if there is a normal recursive definition:
whileTrue: aBlock ^self value ifTrue: [self whileTrue: aBlock]
ifTrue: will return nil if self is false, so the value should always be nil. This affected compiler optimization. The Smalltalk-80 V2 source blue book defines
whileTrue: aBlock "Evaluate the argument, aBlock, as long as the value of the receiver is true. Ordinarily compiled in-line. But could also be done in Smalltalk as follows" ^self value ifTrue: [aBlock value. self whileTrue: aBlock]
So just change your style to
BlockContext>>myWhileTrue: aBlock | start | start := thisContext pc. self value ifFalse: [ ^ nil ]. aBlock value. thisContext pc: start
or??
BlockContext>>myWhileTrue: aBlock | start | start := thisContext pc. ^self value ifTrue: [aBlock value. thisContext pc: start]
But, alas, both of them crash the VM after the second iteration, because thisContext pc does not respond to pc at the next iteration, but instead of having the top of the stack :)
However, the following works:
ContextPart methods for controlling label ^{ pc. stackp } goto: aLabel "NB we *must* answer label so that the top of stack is aLabel as it is when we send label" pc := aLabel at: 1. self stackp: (aLabel at: 2). ^aLabel BlockContext>>myWhileTrue: aBlock | label | label := thisContext label. self value ifFalse: [^nil]. aBlock value. thisContext goto: label BlockClosure>>myWhileTrue: aBlock | label | label := thisContext label. ^self value ifTrue: [aBlock value. thisContext goto: label]
Eliot miranda
source share