[squeak-dev] The Trunk: Kernel-ct.1419.mcz
Nicolas Cellier
nicolas.cellier.aka.nice at gmail.com
Thu Dec 2 00:44:22 UTC 2021
Le jeu. 2 déc. 2021 à 01:41, Nicolas Cellier <
nicolas.cellier.aka.nice at gmail.com> a écrit :
> Hi Christoph,
> yes sorry for the noise, old behavior is indeed unchanged.
>
> My understanding was that defaultBase utility would have been to avoid
> using an explicit radix
> For example for reinterpreting numbers printed via printStringBase:,
> because printStringBase: also omits the explicit radix.
> However, I would not expect the defaultBase to change the interpretation
> of radix, nor of exponent, because I'm not used to it, and that's not how
> Smalltalk reads Numbers traditionally.
>
> Example:
> (20 exp printStringBase: 8)
> -> '3.47260421332164004e9'
>
> ((ExtendedNumberParser on: (20 exp printStringBase: 8))
> defaultBase: 8;
> nextNumber)
> -> 3.614762391222941
>
> does not feel completely right IMO.
>
> But you seem to have over plans for defaultBase.
>
err... other plans.
What is its utility exactly ?
>
> Le jeu. 2 déc. 2021 à 01:07, Thiede, Christoph <
> Christoph.Thiede at student.hpi.uni-potsdam.de> a écrit :
>
>> Hi Nicolas,
>>
>>
>> could you please elaborate what breaking change you are referring to? :-)
>> After installing this update, 2r1e53 still evaluates to the same value
>> for me.
>>
>>
>> The old behavior seems to have been: The radix of the string, if any, is
>> parsed to base 10. The significand is parsed based to that radix, if any,
>> otherwise, to 10. The exponent, if any, is parsed to 10.
>>
>> The new behavior is: The radix of the string, if any parsed to the new
>> default base in the number parsed, which defaults to 10. The significand
>> is parsed based to that radix, if any, otherwise, to the default base.
>> The exponent, if any, is parsed to the default base.
>>
>>
>> Here is another example:
>>
>>
>> (ExtendedNumberParser on: '11r1e10')
>> defaultBase: 2;
>> nextNumber. "9"
>>
>>
>> The only questionable hick-up I could find is this:
>>
>>
>> (ExtendedNumberParser on: '1e3')
>> defaultBase: 2;
>> nextNumber. "1"
>>
>> (One might expect a NumberParserError instead.)
>>
>>
>> But this is not something new; in an older image, the following has the
>> same result:
>>
>>
>> (ExtendedNumberParser on: '1ea') nextNumber. "1"
>>
>>
>> Best,
>>
>> Christoph
>> ------------------------------
>> *Von:* Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im
>> Auftrag von Nicolas Cellier <nicolas.cellier.aka.nice at gmail.com>
>> *Gesendet:* Donnerstag, 2. Dezember 2021 00:37:34
>> *An:* The general-purpose Squeak developers list
>> *Betreff:* Re: [squeak-dev] The Trunk: Kernel-ct.1419.mcz
>>
>> Reminder: until now, the exponent has always been read in base 10,
>> whatever the radix of the significand.
>>
>> For example:
>> 1 << 53 = 2r1e53
>>
>> This commit is changing the interpretation of such numbers...
>>
>> Le mer. 1 déc. 2021 à 16:34, <commits at source.squeak.org> a écrit :
>>
>>> Marcel Taeumel uploaded a new version of Kernel to project The Trunk:
>>> http://source.squeak.org/trunk/Kernel-ct.1419.mcz
>>>
>>> ==================== Summary ====================
>>>
>>> Name: Kernel-ct.1419
>>> Author: ct
>>> Time: 27 October 2021, 10:21:05.275233 pm
>>> UUID: ecfac90e-ea85-774f-b13d-0ecad50c894a
>>> Ancestors: Kernel-eem.1418
>>>
>>> Makes it possible to specify a different default base in number parsers.
>>> There is no need to hard-code the 10 and I am actually building something
>>> with a different default number system. Clients can still change the base
>>> via the radix notation.
>>>
>>> (ExtendedNumberParser on: '10')
>>> defaultBase: 16;
>>> nextNumber. "16"
>>> (ExtendedNumberParser on: '2r10')
>>> defaultBase: 16;
>>> nextNumber. "2"
>>> (ExtendedNumberParser on: 'ar10')
>>> defaultBase: 16;
>>> nextNumber. "10".
>>>
>>> Also adds Integer class >> #readFrom:base:ifFail: for convenience.
>>> Removes redundant class-side overrides on SqNumberParser.
>>>
>>> =============== Diff against Kernel-eem.1418 ===============
>>>
>>> Item was changed:
>>> ----- Method: ExtendedNumberParser>>nextFraction (in category
>>> 'parsing-public') -----
>>> nextFraction
>>> | numerator denominator numberOfTrailingZeroInIntegerPart |
>>> + base := self defaultBase.
>>> - base := 10.
>>> neg := self peekSignIsMinus.
>>> (integerPart := self nextUnsignedIntegerOrNilBase: base)
>>> ifNil: [numberOfTrailingZeroInIntegerPart := 0]
>>> ifNotNil: [
>>> numberOfTrailingZeroInIntegerPart := nDigits -
>>> lastNonZero.
>>> (sourceStream peekFor: $r)
>>> ifTrue: ["<base>r<integer>"
>>> (base := integerPart) < 2
>>> ifTrue: [
>>> sourceStream
>>> skip: -1.
>>> ^ self expected:
>>> 'an integer greater than 1 as valid radix'].
>>> self peekSignIsMinus
>>> ifTrue: [neg := neg not].
>>> integerPart := self
>>> nextUnsignedIntegerBase: base.
>>>
>>> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero]].
>>> (sourceStream peekFor: $.)
>>> ifTrue:
>>> [^self
>>> readFractionPartNumberOfTrailingZeroInIntegerPart:
>>> numberOfTrailingZeroInIntegerPart].
>>> integerPart
>>> ifNil:
>>> ["No integerPart, raise an error"
>>> ^ self expected: 'a digit'].
>>> numerator := neg
>>> ifTrue: [integerPart negated]
>>> ifFalse: [integerPart].
>>> self readExponent ifTrue: [numerator := numerator * (base
>>> raisedToInteger: exponent)].
>>> (sourceStream peekFor: $/) ifFalse: [^numerator].
>>> base := 10.
>>> + base := self defaultBase.
>>> (denominator := self nextUnsignedIntegerOrNilBase: base)
>>> ifNil:
>>> [sourceStream skip: -1. "Not a valid
>>> denominator, ungobble / and return numerator"
>>> ^numerator].
>>> (sourceStream peekFor: $r)
>>> ifTrue: ["<base>r<integer>"
>>> (base := denominator) < 2
>>> ifTrue: [
>>> sourceStream skip: -1.
>>> ^ self expected: 'an integer
>>> greater than 1 as valid radix'].
>>> denominator := self nextUnsignedIntegerBase:
>>> base].
>>> self readExponent ifTrue: [denominator := denominator * (base
>>> raisedToInteger: exponent)].
>>> ^numerator / denominator!
>>>
>>> Item was changed:
>>> ----- Method: ExtendedNumberParser>>nextNumber (in category
>>> 'parsing-public') -----
>>> nextNumber
>>> "main method for reading a number.
>>> This one can read Float Integer and ScaledDecimal"
>>>
>>> | numberOfTrailingZeroInIntegerPart |
>>> + base := self defaultBase.
>>> - base := 10.
>>> neg := self peekSignIsMinus.
>>> integerPart := self nextUnsignedIntegerOrNilBase: base.
>>> integerPart ifNil: [(sourceStream peekFor: $.)
>>> ifTrue: [
>>> "Try .1 syntax"
>>> ^self readNumberWithoutIntegerPart]
>>> ifFalse: [
>>> "This is not a regular number beginning with a
>>> digit
>>> It is time to check for exceptional condition
>>> NaN and Infinity"
>>> ^self readNamedFloatOrFail]].
>>> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.
>>> (sourceStream peekFor: $r)
>>> ifTrue: ["<base>r<integer>"
>>> | oldNeg pos |
>>> pos := sourceStream position - 1.
>>> (base := integerPart) < 2
>>> ifTrue: ["A radix currently need to be
>>> greater than 1, ungobble the r and return the integer part"
>>> sourceStream skip: -1.
>>> ^neg
>>> ifTrue: [base negated]
>>> ifFalse: [base]].
>>> oldNeg := neg.
>>> self peekSignIsMinus ifTrue: [neg := neg not].
>>> integerPart := self
>>> nextUnsignedIntegerOrNilBase: base.
>>> integerPart ifNil: [
>>> (sourceStream peekFor: $.) ifTrue: [self
>>> readNumberWithoutIntegerPartOrNil ifNotNil: [:aNumber | ^aNumber]].
>>> sourceStream position: pos.
>>> ^oldNeg
>>> ifTrue: [base negated]
>>> ifFalse: [base]].
>>> numberOfTrailingZeroInIntegerPart := nDigits -
>>> lastNonZero].
>>> ^ (sourceStream peekFor: $.)
>>> ifTrue: [self
>>> readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart:
>>> numberOfTrailingZeroInIntegerPart]
>>> ifFalse: [self makeIntegerOrScaledInteger]!
>>>
>>> Item was changed:
>>> ----- Method: FORTRANNumberParser>>nextNumber (in category
>>> 'parsing-public') -----
>>> nextNumber
>>> "main method for reading a number with FORTRAN syntax.
>>> This one can read Real and Integer (not complex)"
>>>
>>> | numberOfTrailingZeroInIntegerPart
>>> numberOfNonZeroFractionDigits mantissa value
>>> numberOfTrailingZeroInFractionPart noInt |
>>> + base := self defaultBase..
>>> - base := 10.
>>> (self nextMatchAll: 'NaN') ifTrue: [^Float nan].
>>> neg := self peekSignIsMinus.
>>> (self nextMatchAll: 'Infinity')
>>> ifTrue: [^neg ifTrue: [Float negativeInfinity] ifFalse:
>>> [Float infinity]].
>>> (noInt := sourceStream peekFor: $.)
>>> ifTrue:
>>> [integerPart := 0.
>>> numberOfTrailingZeroInIntegerPart := 0]
>>> ifFalse:
>>> [integerPart := self nextUnsignedIntegerBase:
>>> base.
>>> numberOfTrailingZeroInIntegerPart := nDigits -
>>> lastNonZero].
>>> (noInt or: [sourceStream peekFor: $.])
>>> ifTrue:
>>> [fractionPart := self nextUnsignedIntegerBase:
>>> base ifFail: [nil].
>>> fractionPart isNil
>>> ifTrue:
>>> [noInt
>>> ifTrue:
>>> ["no interger
>>> part, no fraction part..."
>>> self expected:
>>> 'a digit 0 to 9'.
>>> ^nil].
>>> fractionPart := 0]
>>> ifFalse:
>>> [numberOfNonZeroFractionDigits
>>> := lastNonZero.
>>>
>>> numberOfTrailingZeroInFractionPart := nDigits - lastNonZero].
>>> self readExponent]
>>> ifFalse:
>>> [self readExponent ifFalse: [^neg ifTrue:
>>> [integerPart negated] ifFalse: [integerPart]].
>>> fractionPart := 0].
>>> fractionPart isZero
>>> ifTrue:
>>> [mantissa := integerPart // (base raisedTo:
>>> numberOfTrailingZeroInIntegerPart).
>>> exponent := exponent +
>>> numberOfTrailingZeroInIntegerPart]
>>> ifFalse:
>>> [mantissa := integerPart * (base raisedTo:
>>> numberOfNonZeroFractionDigits)
>>> + (fractionPart // (base
>>> raisedTo: numberOfTrailingZeroInFractionPart)).
>>> exponent := exponent -
>>> numberOfNonZeroFractionDigits].
>>> value := self
>>> makeFloatFromMantissa: mantissa
>>> exponent: exponent
>>> base: base.
>>> ^neg ifTrue: [value isZero ifTrue: [Float negativeZero] ifFalse:
>>> [value negated]] ifFalse: [value]!
>>>
>>> Item was added:
>>> + ----- Method: Integer class>>readFrom:base:ifFail: (in category
>>> 'instance creation') -----
>>> + readFrom: aStringOrStream base: base ifFail: aBlock
>>> + "Answer an instance of one of the concrete subclasses if
>>> Integer.
>>> + Initial plus or minus sign accepted, and bases > 10 use letters
>>> A-Z.
>>> + Imbedded radix specifiers not allowed; use Number class
>>> readFrom: for that.
>>> + Execute aBlock if there are no digits."
>>> +
>>> + ^(ExtendedNumberParser on: aStringOrStream) nextIntegerBase:
>>> base ifFail: aBlock!
>>>
>>> Item was changed:
>>> Object subclass: #NumberParser
>>> + instanceVariableNames: 'sourceStream base neg integerPart
>>> fractionPart exponent scale nDigits lastNonZero requestor failBlock
>>> defaultBase'
>>> - instanceVariableNames: 'sourceStream base neg integerPart
>>> fractionPart exponent scale nDigits lastNonZero requestor failBlock'
>>> classVariableNames: ''
>>> poolDictionaries: ''
>>> category: 'Kernel-Numbers'!
>>>
>>> + !NumberParser commentStamp: 'ct 10/27/2021 22:04' prior: 0!
>>> - !NumberParser commentStamp: 'nice 3/15/2010 00:16' prior: 0!
>>> NumberParser is an abstract class for parsing and building numbers
>>> from string/stream.
>>> It offers a framework with utility methods and exception handling.
>>>
>>> Number syntax is not defined and should be subclassResponsibility.
>>>
>>> Instance variables:
>>> sourceStream <Stream> the stream of characters from which the number
>>> is read
>>> base <Integer> the radix in which to interpret digits
>>> neg <Boolean> true in case of minus sign
>>> integerPart <Integer> the integer part of the number
>>> fractionPart <Integer> the fraction part of the number if any
>>> exponent <Integer> the exponent used in scientific notation if any
>>> scale <Integer> the scale used in case of ScaledDecimal number if any
>>> nDigits <Integer> number of digits read to form an Integer
>>> lasNonZero <Integer> position of last non zero digit, starting at 1
>>> from left, 0 if all digits are zero
>>> requestor <TextEditor | nil> can be used to insert an error message in
>>> the requestor
>>> failBlock <BlockClosure> Block to execute whenever an error occurs.
>>> The fail block can have 0, 1 or 2 arguments (errorString and
>>> source position)
>>> + defaultBase <Integer> the default radix in which to interpret digits,
>>> unless specified differently via radix notation!
>>> - !
>>>
>>> Item was added:
>>> + ----- Method: NumberParser>>defaultBase (in category 'accessing') -----
>>> + defaultBase
>>> +
>>> + ^ defaultBase!
>>>
>>> Item was added:
>>> + ----- Method: NumberParser>>defaultBase: (in category 'accessing')
>>> -----
>>> + defaultBase: anInteger
>>> +
>>> + self assert: anInteger < 28 description: 'Default base must be
>>> lower than 28 to keep radix r distinguishable from digits. For higher
>>> bases, pass the base manually to #nextNumberBase: autc.'.
>>> + defaultBase := anInteger!
>>>
>>> Item was added:
>>> + ----- Method: NumberParser>>defaultRadixBase (in category 'accessing')
>>> -----
>>> + defaultRadixBase
>>> +
>>> + ^ 10!
>>>
>>> Item was added:
>>> + ----- Method: NumberParser>>initialize (in category
>>> 'initialize-release') -----
>>> + initialize
>>> +
>>> + defaultBase := 10!
>>>
>>> Item was changed:
>>> ----- Method: NumberParser>>nextInteger (in category 'parsing-public')
>>> -----
>>> nextInteger
>>> "Read an Integer from sourceStream, asnwser that Integer.
>>> This is a generic version dealing with an optional sign and a
>>> simple sequence of decimal digits.
>>> Subclass might define extended syntax."
>>>
>>> + base := self defaultBase.
>>> - base := 10.
>>> ^self nextIntegerBase: base ifFail: [^self expected: ('a digit
>>> between 0 and ' copyWith: (Character digitValue: base - 1))]!
>>>
>>> Item was changed:
>>> ----- Method: NumberParser>>nextUnsignedInteger (in category
>>> 'parsing-public') -----
>>> nextUnsignedInteger
>>> "Read an Integer from sourceStream, asnwser that Integer.
>>> This is a generic version dealing with a simple sequence of
>>> decimal digits.
>>> Subclass might define extended syntax."
>>> +
>>> + base := self defaultBase.
>>> -
>>> - base := 10.
>>> ^self nextUnsignedIntegerBase: base ifFail: [^self expected: ('a
>>> digit between 0 and ' copyWith: (Character digitValue: base - 1))]!
>>>
>>> Item was changed:
>>> ----- Method: NumberParser>>on: (in category 'initialize-release')
>>> -----
>>> on: aStringOrStream
>>> sourceStream := aStringOrStream isString
>>> ifTrue: [ aStringOrStream readStream ]
>>> ifFalse: [ aStringOrStream ].
>>> + base := self defaultBase.
>>> - base := 10.
>>> neg := false.
>>> integerPart := fractionPart := exponent := scale := 0.
>>> requestor := failBlock := nil!
>>>
>>> Item was changed:
>>> ----- Method: NumberParser>>readExponent (in category
>>> 'parsing-private') -----
>>> readExponent
>>> "read the exponent if any (stored in instVar).
>>> Answer true if found, answer false if none.
>>> If exponent letter is not followed by a digit,
>>> this is not considered as an error.
>>> Exponent are always read in base 10."
>>>
>>> | eneg epos |
>>> exponent := 0.
>>> (self isExponentLetter: sourceStream peek) ifFalse: [^ false].
>>> sourceStream next.
>>> eneg := sourceStream peekFor: $-.
>>> epos := eneg not and: [self allowPlusSignInExponent and:
>>> [sourceStream peekFor: $+]].
>>> + exponent := self nextUnsignedIntegerOrNilBase: self defaultBase.
>>> - exponent := self nextUnsignedIntegerOrNilBase: 10.
>>>
>> Above is the questionable change for reading the exponent...
>>
>> exponent ifNil: ["Oops, there was no digit after the exponent
>>> letter.Ungobble the letter"
>>> exponent := 0.
>>> sourceStream
>>> skip: ((eneg or: [epos])
>>> ifTrue:
>>> [-2]
>>> ifFalse:
>>> [-1]).
>>> ^ false].
>>> eneg ifTrue: [exponent := exponent negated].
>>> ^true!
>>>
>>> Item was removed:
>>> - ----- Method: SqNumberParser class>>on: (in category 'instance
>>> creation') -----
>>> - on: aStringOrStream
>>> - ^self new on: aStringOrStream!
>>>
>>> Item was removed:
>>> - ----- Method: SqNumberParser class>>parse: (in category 'instance
>>> creation') -----
>>> - parse: aStringOrStream
>>> - ^(self new)
>>> - on: aStringOrStream;
>>> - nextNumber!
>>>
>>> Item was removed:
>>> - ----- Method: SqNumberParser class>>parse:onError: (in category
>>> 'instance creation') -----
>>> - parse: aStringOrStream onError: failBlock
>>> - ^(self new)
>>> - on: aStringOrStream;
>>> - failBlock: failBlock;
>>> - nextNumber!
>>>
>>> Item was changed:
>>> ----- Method: SqNumberParser>>nextFraction (in category
>>> 'parsing-public') -----
>>> nextFraction
>>> | numerator denominator numberOfTrailingZeroInIntegerPart |
>>> + base := self defaultBase.
>>> - base := 10.
>>> neg := self peekSignIsMinus.
>>> (integerPart := self nextUnsignedIntegerOrNilBase: base)
>>> ifNil: ["No integerPart, raise an error"
>>> ^ self expected: 'a digit'].
>>> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.
>>> (sourceStream peekFor: $r)
>>> ifTrue: ["<base>r<integer>"
>>> (base := integerPart) < 2
>>> ifTrue: [
>>> sourceStream skip: -1.
>>> ^ self expected: 'an integer
>>> greater than 1 as valid radix'].
>>> self peekSignIsMinus
>>> ifTrue: [neg := neg not].
>>> integerPart := self nextUnsignedIntegerBase:
>>> base.
>>> numberOfTrailingZeroInIntegerPart := nDigits -
>>> lastNonZero].
>>> (sourceStream peekFor: $.)
>>> ifTrue:
>>> [^self
>>> readFractionPartNumberOfTrailingZeroInIntegerPart:
>>> numberOfTrailingZeroInIntegerPart].
>>> numerator := neg
>>> ifTrue: [integerPart negated]
>>> ifFalse: [integerPart].
>>> self readExponent ifTrue: [numerator := numerator * (base
>>> raisedToInteger: exponent)].
>>> (sourceStream peekFor: $/) ifFalse: [^numerator].
>>> + base := self defaultBase.
>>> - base := 10.
>>> (denominator := self nextUnsignedIntegerOrNilBase: base)
>>> ifNil:
>>> [sourceStream skip: -1. "Not a valid
>>> denominator, ungobble / and return numerator"
>>> ^numerator].
>>> (sourceStream peekFor: $r)
>>> ifTrue: ["<base>r<integer>"
>>> (base := denominator) < 2
>>> ifTrue: [
>>> sourceStream skip: -1.
>>> ^ self expected: 'an integer
>>> greater than 1 as valid radix'].
>>> denominator := self nextUnsignedIntegerBase:
>>> base].
>>> self readExponent ifTrue: [denominator := denominator * (base
>>> raisedToInteger: exponent)].
>>> ^numerator / denominator!
>>>
>>> Item was changed:
>>> ----- Method: SqNumberParser>>nextInteger (in category
>>> 'parsing-public') -----
>>> nextInteger
>>> "Read an Integer from sourceStream, asnwser that Integer.
>>> In Smalltalk syntax, a radix can be specified, and an exponent
>>> too."
>>>
>>> | numberOfTrailingZeroInIntegerPart |
>>> + base := self defaultBase.
>>> - base := 10.
>>> neg := self peekSignIsMinus.
>>> integerPart := self nextUnsignedIntegerOrNilBase: base.
>>> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.
>>> (sourceStream peekFor: $r)
>>> ifTrue: ["<base>r<integer>"
>>> (base := integerPart) < 2
>>> ifTrue: [
>>> sourceStream skip: -1.
>>> ^ self expected: 'an integer
>>> greater than 1 as valid radix'].
>>> self peekSignIsMinus
>>> ifTrue: [neg := neg not].
>>> integerPart := self nextUnsignedIntegerBase:
>>> base.
>>> numberOfTrailingZeroInIntegerPart := nDigits -
>>> lastNonZero].
>>> ^ self makeIntegerOrScaledInteger!
>>>
>>> Item was changed:
>>> ----- Method: SqNumberParser>>nextNumber (in category
>>> 'parsing-public') -----
>>> nextNumber
>>> "main method for reading a number.
>>> This one can read Float Integer and ScaledDecimal"
>>>
>>> | numberOfTrailingZeroInIntegerPart |
>>> + base := self defaultBase.
>>> - base := 10.
>>> neg := self peekSignIsMinus.
>>> integerPart := self nextUnsignedIntegerOrNilBase: base.
>>> integerPart ifNil: [
>>> "This is not a regular number beginning with a digit
>>> It is time to check for exceptional condition NaN and
>>> Infinity"
>>> ^self readNamedFloatOrFail].
>>> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.
>>> (sourceStream peekFor: $r)
>>> ifTrue: ["<base>r<integer>"
>>> (base := integerPart) < 2
>>> ifTrue: [
>>> sourceStream skip: -1.
>>> ^ self expected: 'an integer
>>> greater than 1 as valid radix'].
>>> self peekSignIsMinus
>>> ifTrue: [neg := neg not].
>>> integerPart := self nextUnsignedIntegerBase:
>>> base.
>>> numberOfTrailingZeroInIntegerPart := nDigits -
>>> lastNonZero].
>>> ^ (sourceStream peekFor: $.)
>>> ifTrue: [self
>>> readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart:
>>> numberOfTrailingZeroInIntegerPart]
>>> ifFalse: [self makeIntegerOrScaledInteger]!
>>>
>>> Item was changed:
>>> ----- Method: SqNumberParser>>nextScaledDecimal (in category
>>> 'parsing-public') -----
>>> nextScaledDecimal
>>> "Main method for reading a (scaled) decimal number.
>>> Good Gracious, do not accept a decimal in another base than 10!!
>>> In other words, do not accept radix notation like 2r1.1, even
>>> not 10r5.3
>>> Do not accept exponent notation neither, like 1.0e-3"
>>>
>>> | numberOfNonZeroFractionDigits
>>> numberOfTrailingZeroInFractionPart |
>>> + base := self defaultBase.
>>> - base := 10.
>>> neg := sourceStream peekFor: $-.
>>> integerPart := self nextUnsignedIntegerBase: base.
>>> (sourceStream peekFor: $.)
>>> ifTrue: [fractionPart := self
>>> nextUnsignedIntegerOrNilBase: base.
>>> fractionPart ifNil: ["Oops, the decimal point
>>> seems not part of this number"
>>> sourceStream
>>> skip: -1.
>>> ^ neg
>>> ifTrue:
>>> [integerPart negated asScaledDecimal: 0]
>>> ifFalse:
>>> [integerPart asScaledDecimal: 0]].
>>> numberOfNonZeroFractionDigits := lastNonZero.
>>> numberOfTrailingZeroInFractionPart := nDigits -
>>> lastNonZero.
>>> (self readScaleWithDefaultNumberOfDigits:
>>> nDigits)
>>> ifFalse: ["No scale were provided. use
>>> number of digits after decimal point as scale"
>>> scale := nDigits].
>>> ^self
>>> makeScaledDecimalWithNumberOfNonZeroFractionDigits:
>>> numberOfNonZeroFractionDigits andNumberOfTrailingZeroInFractionPart:
>>> numberOfTrailingZeroInFractionPart].
>>> self readScaleWithDefaultNumberOfDigits: 0.
>>> neg ifTrue: [integerPart := integerPart negated].
>>> ^integerPart asScaledDecimal: scale!
>>>
>>> Item was changed:
>>> ----- Method: SqNumberParser>>nextUnsignedInteger (in category
>>> 'parsing-public') -----
>>> nextUnsignedInteger
>>> "Read an unsigned Integer from sourceStream, asnwser that
>>> Integer.
>>> In Smalltalk syntax, a radix can be specified, and an exponent
>>> too."
>>>
>>> + base := self defaultBase.
>>> - base := 10.
>>> neg := false.
>>> integerPart := self nextUnsignedIntegerOrNilBase: base.
>>> (sourceStream peekFor: $r)
>>> ifTrue: ["<base>r<integer>"
>>> (base := integerPart) < 2
>>> ifTrue: [
>>> sourceStream skip: -1.
>>> ^ self expected: 'an integer
>>> greater than 1 as valid radix'].
>>> integerPart := self nextUnsignedIntegerBase:
>>> base].
>>> ^ self makeIntegerOrScaledInteger!
>>>
>>> Item was changed:
>>> ----- Method: SqNumberParser>>readScaleWithDefaultNumberOfDigits: (in
>>> category 'parsing-private') -----
>>> readScaleWithDefaultNumberOfDigits: anInteger
>>> "Read the scale if any and store it into scale instance Variable.
>>> Answer true if found, answer false if none.
>>> The scale is specified by letter s, optionnally followed by a
>>> positive integer in base 10.
>>> If no integer is specified, that means using as many digits as
>>> provided after the fraction separator, as provided by parameter anInteger.
>>> A letter s followed by another letter is not considered as a
>>> scale specification, because it could be part of a message."
>>>
>>> scale := 0.
>>> sourceStream atEnd
>>> ifTrue: [ ^ false ].
>>> (sourceStream peekFor: $s)
>>> ifFalse: [ ^ false ].
>>> + scale := self nextUnsignedIntegerOrNilBase: self defaultBase.
>>> - scale := self nextUnsignedIntegerOrNilBase: 10.
>>> scale
>>> ifNil: [
>>> scale := anInteger.
>>> (sourceStream peek ifNil: [ false ] ifNotNil: [
>>> :nextChar | nextChar isLetter ])
>>> ifTrue: [
>>> sourceStream skip: -1.
>>> "ungobble the s"
>>> ^ false ]
>>> ifFalse: [ ^ true ] ].
>>> ^ true!
>>>
>>>
>>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20211202/ea1d6868/attachment.html>
More information about the Squeak-dev
mailing list
|