whileTrue: & whileFalse: всегда возвращать ноль.
например если есть нормальное рекурсивное определение:
whileTrue: aBlock
^self value ifTrue: [self whileTrue: aBlock]
ifTrue: вернет nil, если self value равно false, поэтому значение всегда должно быть nil. Это отражено в оптимизации компилятора. Оригинальная синяя книга Smalltalk-80 V2 имеет определение
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]
Так что просто поменяйте свой на
BlockContext>>myWhileTrue: aBlock
| start |
start := thisContext pc.
self value ifFalse: [ ^ nil ].
aBlock value.
thisContext pc: start
или ??
BlockContext>>myWhileTrue: aBlock
| start |
start := thisContext pc.
^self value ifTrue:
[aBlock value.
thisContext pc: start]
Но, увы, оба из них приводят к аварийному завершению работы виртуальной машины через некоторое время после второй итерации, поскольку этот компьютер с контекстами не отвечает на ПК на следующей итерации, а вместо этого независимо от того, какой версией является стек:)
Однако работает следующее:
ContextPart methods for controlling
label
^{ pc. stackp }
goto: aLabel
"N.B. 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]