'From Squeak3.10beta of 22 July 2007 [latest update: #7159] on 31 August 2008 at 2:32:37 am'!
"Change Set: Float-readFromManyDigits-Patch-M6982-nice
Date: 15 March 2008
Author: nice
This is a patch for http://bugs.squeak.org/view.php?id=6982
A naive Float>>readFrom: does interpret numbers with many digits as Infinity or NaN.
Solution is simply to use SqNumberParser.
This has another advantage: nearest floating point value will be returned.
The old behaviour consisting in answering zero when no valid number, has been abandonned.
Anyone wishing such a behaviour has to rewrite its code with an explicit:
(Number readFrom: aStream ifFail: [0])
Another un-maintained feature is un-documented behaviour of:
Number readFrom: '1.e-3'.
Number readFrom: '.1e2'.
These are not valid Smalltalk literals.
Subclass SqNumberParser if really interested"!
!Number class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 00:14'!
readFrom: stringOrStream
"Answer a number as described on aStream. The number may
be any accepted Smalltalk literal Number format.
It can include a leading radix specification, as in 16rFADE.
It can as well be NaN, Infinity or -Infinity for conveniency."
^(SqNumberParser on: stringOrStream) nextNumber! !
!Number class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 00:27'!
readFrom: stringOrStream base: base
"Answer a number as described on aStream in the given number base."
^(SqNumberParser on: stringOrStream) nextNumberBase: base! !
!Number class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 00:42'!
readFrom: stringOrStream ifFail: aBlock
"Answer a number as described on aStream. The number may
be any accepted Smalltalk literal Number format.
It can include a leading radix specification, as in 16rFADE.
It can as well be NaN, Infinity or -Infinity for conveniency.
If input does not represent a valid number, then execute fail block
and leave the stream positioned before offending character"
^(SqNumberParser on: stringOrStream) failBlock: aBlock; nextNumber! !
!Float class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 00:54'!
readFrom: aStream ifFail: aBlock
"Answer a new Float as described on the stream, aStream."
^(super readFrom: aStream ifFail: [^aBlock value]) asFloat! !
!Integer class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 00:36'!
readFrom: aStringOrStream
"Answer a new Integer as described on the stream, aStream.
Embedded radix specifiers not allowed - use Number readFrom: for that."
^self readFrom: aStringOrStream base: 10! !
!Integer class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 01:09'!
readFrom: aStringOrStream base: base
"Answer an instance of one of the concrete subclasses if Integer.
Initial minus sign accepted, and bases > 10 use letters A-Z.
Imbedded radix specifiers not allowed; use Number
class readFrom: for that.
Raise an Error if there are no digits."
^(SqNumberParser on: aStringOrStream) nextIntegerBase: base! !
!Integer class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 01:09'!
readFrom: aStringOrStream ifFail: aBlock
"Answer an instance of one of the concrete subclasses if Integer.
Initial minus sign accepted.
Imbedded radix specifiers not allowed; use Number
class readFrom: for that.
Execute aBlock if there are no digits."
^(SqNumberParser on: aStringOrStream) nextIntegerBase: 10 ifFail: aBlock! !
!SqNumberParser methodsFor: 'parsing-public' stamp: 'nice 8/31/2008 00:51'!
nextNumberBase: b
"Method for reading a number without radix prefix.
This one can read Float Integer and ScaledDecimal"
| numberOfTrailingZeroInIntegerPart |
base := b.
neg := sourceStream peekFor: $-.
integerPart := self nextUnsignedIntegerBase: base ifFail: [
"This is not a regular number beginning with a digit
It is time to check for exceptional condition NaN and Infinity"
^self readNamedFloatIfFail: [self expected: ['a digit between 0 and ' , (Character digitValue: base - 1)]]].
numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.
^ (sourceStream peekFor: $.)
ifTrue: [self readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart]
ifFalse: [self makeIntegerOrScaledInteger]! !
Number class removeSelector: #readExponent:base:from:!
Number class removeSelector: #readRemainderOf:from:base:withSign:!
Number class removeSelector: #readScaledDecimal:fractionPart:digits:base:sign:from:!
!Number class reorganize!
('instance creation' readExactlyFrom: readFrom: readFrom:base: readFrom:ifFail:)
!