Bug Involving Modified #to:by:do:
Tim Olson
tim at jumpnet.com
Sat Jan 30 15:08:35 UTC 1999
Richard Harmon wrote:
>I modified Number 'intervals' #to:by:do: method by adding at the beginning:
>
> step = 0 ifTrue: [
> ^self error: 'step must be non-zero.'
> ].
>
>
>then evaluated:
>
> 5 to: 1 by: 0 do: [ :n | ^#bogus].
>
>it returns bogus.
Ralph Johnson replied:
>Traditionally to:do: is optimized by the compiler when you send
>it to a number, so the to:do: method is never called. I bet that
>Squeak does the same thing with to:by:do:. The problem is that
>you are catching the compiler cheating.
Yep; there is a hint in the beginning of the method that Richard modified
that states this. Richard, the compiler macro-expansions (inlined code)
are in the MessageNode class (macro transformations category). If you
want to continue to play with this, here is a change to the to:by:do
transformation that causes it to not in-line if the step amount is zero.
'From Squeak 2.3 of January 14, 1999 on 30 January 1999 at 8:59:33 am'!
!MessageNode methodsFor: 'macro transformations' stamp: 'tao 1/30/1999
08:56'!
transformToDo: encoder
" var _ rcvr. L1: [var <= arg1] Bfp(L2) [block body. var _ var + inc]
Jmp(L1) L2: "
| limit increment block initStmt test incStmt limitInit blockVar |
"First check for valid arguments"
((arguments last isMemberOf: BlockNode)
and: [arguments last numberOfArguments = 1])
ifFalse: [^ false].
arguments last firstArgument isVariableReference
ifFalse: [^ false]. "As with debugger remote vars"
arguments size = 3
ifTrue: [increment _ arguments at: 2.
(increment isConstantNumber and:
[increment literalValue ~= 0]) ifFalse: [^ false]]
ifFalse: [increment _ encoder encodeLiteral: 1].
arguments size < 3 ifTrue: "transform to full form"
[selector _ SelectorNode new key: #to:by:do: code: #macro].
"Now generate auxiliary structures"
block _ arguments last.
blockVar _ block firstArgument.
initStmt _ AssignmentNode new variable: blockVar value: receiver.
limit _ arguments at: 1.
limit isVariableReference | limit isConstantNumber
ifTrue: [limitInit _ nil]
ifFalse: "Need to store limit in a var"
[limit _ encoder autoBind: blockVar key , 'LimiT'.
limit scope: -2. "Already done parsing block"
limitInit _ AssignmentNode new
variable: limit
value: (arguments at: 1)].
test _ MessageNode new receiver: blockVar
selector: (increment key > 0 ifTrue: [#<=] ifFalse: [#>=])
arguments: (Array with: limit)
precedence: precedence from: encoder.
incStmt _ AssignmentNode new
variable: blockVar
value: (MessageNode new
receiver: blockVar selector: #+
arguments: (Array with: increment)
precedence: precedence from: encoder).
arguments _ (Array with: limit with: increment with: block)
, (Array with: initStmt with: test with: incStmt with: limitInit).
^ true! !
!Number methodsFor: 'intervals' stamp: 'tao 1/30/1999 08:58'!
to: stop by: step do: aBlock
"Normally compiled in-line, and therefore not overridable.
Evaluate aBlock for each element of the interval (self to: stop by:
step)."
| nextValue |
nextValue _ self.
step = 0 ifTrue: [self error: 'step must be non-zero'].
step < 0
ifTrue: [[stop <= nextValue]
whileTrue:
[aBlock value: nextValue.
nextValue _ nextValue + step]]
ifFalse: [[stop >= nextValue]
whileTrue:
[aBlock value: nextValue.
nextValue _ nextValue + step]]! !
-- tim
More information about the Squeak-dev
mailing list
|