[squeak-dev] The Trunk: Kernel-ct.1419.mcz
Nicolas Cellier
nicolas.cellier.aka.nice at gmail.com
Wed Dec 1 23:37:34 UTC 2021
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/74bdec8a/attachment-0001.html>
More information about the Squeak-dev
mailing list
|