<body><div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
+1<div class="mb_sig"></div><blockquote class='history_container' type='cite' style='border-left-style:solid;border-width:1px; margin-top:20px; margin-left:0px;padding-left:10px;'>
<p style='color: #AAAAAA; margin-top: 10px;'>Am 28.10.2021 11:07:31 schrieb commits@source.squeak.org <commits@source.squeak.org>:</p><div style='font-family:Arial,Helvetica,sans-serif'>A new version of Kernel was added to project The Inbox:<br>http://source.squeak.org/inbox/Kernel-ct.1419.mcz<br><br>==================== Summary ====================<br><br>Name: Kernel-ct.1419<br>Author: ct<br>Time: 27 October 2021, 10:21:05.275233 pm<br>UUID: ecfac90e-ea85-774f-b13d-0ecad50c894a<br>Ancestors: Kernel-eem.1418<br><br>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.<br><br> (ExtendedNumberParser on: '10')<br> defaultBase: 16;<br> nextNumber. "16"<br> (ExtendedNumberParser on: '2r10')<br> defaultBase: 16;<br> nextNumber. "2"<br> (ExtendedNumberParser on: 'ar10')<br> defaultBase: 16;<br> nextNumber. "10".<br><br>Also adds Integer class >> #readFrom:base:ifFail: for convenience. Removes redundant class-side overrides on SqNumberParser.<br><br>=============== Diff against Kernel-eem.1418 ===============<br><br>Item was changed:<br> ----- Method: ExtendedNumberParser>>nextFraction (in category 'parsing-public') -----<br> nextFraction<br> | numerator denominator numberOfTrailingZeroInIntegerPart |<br>+ base := self defaultBase.<br>- base := 10.<br> neg := self peekSignIsMinus.<br> (integerPart := self nextUnsignedIntegerOrNilBase: base)<br> ifNil: [numberOfTrailingZeroInIntegerPart := 0]<br> ifNotNil: [<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.<br> (sourceStream peekFor: $r)<br> ifTrue: ["<base>r<integer>"<br> (base := integerPart) < 2<br> ifTrue: [<br> sourceStream skip: -1.<br> ^ self expected: 'an integer greater than 1 as valid radix'].<br> self peekSignIsMinus<br> ifTrue: [neg := neg not].<br> integerPart := self nextUnsignedIntegerBase: base.<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero]].<br> (sourceStream peekFor: $.)<br> ifTrue:<br> [^self readFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart].<br> integerPart<br> ifNil:<br> ["No integerPart, raise an error"<br> ^ self expected: 'a digit'].<br> numerator := neg<br> ifTrue: [integerPart negated]<br> ifFalse: [integerPart].<br> self readExponent ifTrue: [numerator := numerator * (base raisedToInteger: exponent)].<br> (sourceStream peekFor: $/) ifFalse: [^numerator].<br> base := 10.<br>+ base := self defaultBase.<br> (denominator := self nextUnsignedIntegerOrNilBase: base)<br> ifNil:<br> [sourceStream skip: -1. "Not a valid denominator, ungobble / and return numerator"<br> ^numerator].<br> (sourceStream peekFor: $r)<br> ifTrue: ["<base>r<integer>"<br> (base := denominator) < 2<br> ifTrue: [<br> sourceStream skip: -1.<br> ^ self expected: 'an integer greater than 1 as valid radix'].<br> denominator := self nextUnsignedIntegerBase: base].<br> self readExponent ifTrue: [denominator := denominator * (base raisedToInteger: exponent)].<br> ^numerator / denominator!<br><br>Item was changed:<br> ----- Method: ExtendedNumberParser>>nextNumber (in category 'parsing-public') -----<br> nextNumber<br> "main method for reading a number.<br> This one can read Float Integer and ScaledDecimal"<br> <br> | numberOfTrailingZeroInIntegerPart |<br>+ base := self defaultBase.<br>- base := 10.<br> neg := self peekSignIsMinus.<br> integerPart := self nextUnsignedIntegerOrNilBase: base.<br> integerPart ifNil: [(sourceStream peekFor: $.)<br> ifTrue: [<br> "Try .1 syntax"<br> ^self readNumberWithoutIntegerPart]<br> ifFalse: [<br> "This is not a regular number beginning with a digit<br> It is time to check for exceptional condition NaN and Infinity"<br> ^self readNamedFloatOrFail]].<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.<br> (sourceStream peekFor: $r)<br> ifTrue: ["<base>r<integer>"<br> | oldNeg pos |<br> pos := sourceStream position - 1.<br> (base := integerPart) < 2<br> ifTrue: ["A radix currently need to be greater than 1, ungobble the r and return the integer part"<br> sourceStream skip: -1.<br> ^neg<br> ifTrue: [base negated]<br> ifFalse: [base]].<br> oldNeg := neg.<br> self peekSignIsMinus ifTrue: [neg := neg not].<br> integerPart := self nextUnsignedIntegerOrNilBase: base.<br> integerPart ifNil: [<br> (sourceStream peekFor: $.) ifTrue: [self readNumberWithoutIntegerPartOrNil ifNotNil: [:aNumber | ^aNumber]].<br> sourceStream position: pos.<br> ^oldNeg<br> ifTrue: [base negated]<br> ifFalse: [base]].<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].<br> ^ (sourceStream peekFor: $.)<br> ifTrue: [self readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart]<br> ifFalse: [self makeIntegerOrScaledInteger]!<br><br>Item was changed:<br> ----- Method: FORTRANNumberParser>>nextNumber (in category 'parsing-public') -----<br> nextNumber<br> "main method for reading a number with FORTRAN syntax.<br> This one can read Real and Integer (not complex)"<br> <br> | numberOfTrailingZeroInIntegerPart numberOfNonZeroFractionDigits mantissa value numberOfTrailingZeroInFractionPart noInt |<br>+ base := self defaultBase..<br>- base := 10.<br> (self nextMatchAll: 'NaN') ifTrue: [^Float nan].<br> neg := self peekSignIsMinus.<br> (self nextMatchAll: 'Infinity') <br> ifTrue: [^neg ifTrue: [Float negativeInfinity] ifFalse: [Float infinity]].<br> (noInt := sourceStream peekFor: $.) <br> ifTrue: <br> [integerPart := 0.<br> numberOfTrailingZeroInIntegerPart := 0]<br> ifFalse: <br> [integerPart := self nextUnsignedIntegerBase: base.<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].<br> (noInt or: [sourceStream peekFor: $.]) <br> ifTrue: <br> [fractionPart := self nextUnsignedIntegerBase: base ifFail: [nil].<br> fractionPart isNil <br> ifTrue: <br> [noInt <br> ifTrue: <br> ["no interger part, no fraction part..."<br> self expected: 'a digit 0 to 9'.<br> ^nil].<br> fractionPart := 0]<br> ifFalse: <br> [numberOfNonZeroFractionDigits := lastNonZero.<br> numberOfTrailingZeroInFractionPart := nDigits - lastNonZero].<br> self readExponent]<br> ifFalse: <br> [self readExponent ifFalse: [^neg ifTrue: [integerPart negated] ifFalse: [integerPart]].<br> fractionPart := 0].<br> fractionPart isZero <br> ifTrue: <br> [mantissa := integerPart // (base raisedTo: numberOfTrailingZeroInIntegerPart).<br> exponent := exponent + numberOfTrailingZeroInIntegerPart]<br> ifFalse: <br> [mantissa := integerPart * (base raisedTo: numberOfNonZeroFractionDigits) <br> + (fractionPart // (base raisedTo: numberOfTrailingZeroInFractionPart)).<br> exponent := exponent - numberOfNonZeroFractionDigits].<br> value := self <br> makeFloatFromMantissa: mantissa<br> exponent: exponent<br> base: base.<br> ^neg ifTrue: [value isZero ifTrue: [Float negativeZero] ifFalse: [value negated]] ifFalse: [value]!<br><br>Item was added:<br>+ ----- Method: Integer class>>readFrom:base:ifFail: (in category 'instance creation') -----<br>+ readFrom: aStringOrStream base: base ifFail: aBlock<br>+ "Answer an instance of one of the concrete subclasses if Integer. <br>+ Initial plus or minus sign accepted, and bases > 10 use letters A-Z.<br>+ Imbedded radix specifiers not allowed; use Number class readFrom: for that.<br>+ Execute aBlock if there are no digits."<br>+ <br>+ ^(ExtendedNumberParser on: aStringOrStream) nextIntegerBase: base ifFail: aBlock!<br><br>Item was changed:<br> Object subclass: #NumberParser<br>+ instanceVariableNames: 'sourceStream base neg integerPart fractionPart exponent scale nDigits lastNonZero requestor failBlock defaultBase'<br>- instanceVariableNames: 'sourceStream base neg integerPart fractionPart exponent scale nDigits lastNonZero requestor failBlock'<br> classVariableNames: ''<br> poolDictionaries: ''<br> category: 'Kernel-Numbers'!<br> <br>+ !NumberParser commentStamp: 'ct 10/27/2021 22:04' prior: 0!<br>- !NumberParser commentStamp: 'nice 3/15/2010 00:16' prior: 0!<br> NumberParser is an abstract class for parsing and building numbers from string/stream.<br> It offers a framework with utility methods and exception handling.<br> <br> Number syntax is not defined and should be subclassResponsibility.<br> <br> Instance variables:<br> sourceStream <stream> the stream of characters from which the number is read<br> base <integer> the radix in which to interpret digits<br> neg <boolean> true in case of minus sign<br> integerPart <integer> the integer part of the number<br> fractionPart <integer> the fraction part of the number if any<br> exponent <integer> the exponent used in scientific notation if any<br> scale <integer> the scale used in case of ScaledDecimal number if any<br> nDigits <integer> number of digits read to form an Integer<br> lasNonZero <integer> position of last non zero digit, starting at 1 from left, 0 if all digits are zero<br> requestor <texteditor |="" nil=""> can be used to insert an error message in the requestor<br> failBlock <blockclosure> Block to execute whenever an error occurs.<br> The fail block can have 0, 1 or 2 arguments (errorString and source position)<br>+ defaultBase <integer> the default radix in which to interpret digits, unless specified differently via radix notation!<br>- !<br><br>Item was added:<br>+ ----- Method: NumberParser>>defaultBase (in category 'accessing') -----<br>+ defaultBase<br>+ <br>+ ^ defaultBase!<br><br>Item was added:<br>+ ----- Method: NumberParser>>defaultBase: (in category 'accessing') -----<br>+ defaultBase: anInteger<br>+ <br>+ 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.'.<br>+ defaultBase := anInteger!<br><br>Item was added:<br>+ ----- Method: NumberParser>>defaultRadixBase (in category 'accessing') -----<br>+ defaultRadixBase<br>+ <br>+ ^ 10!<br><br>Item was added:<br>+ ----- Method: NumberParser>>initialize (in category 'initialize-release') -----<br>+ initialize<br>+ <br>+ defaultBase := 10!<br><br>Item was changed:<br> ----- Method: NumberParser>>nextInteger (in category 'parsing-public') -----<br> nextInteger<br> "Read an Integer from sourceStream, asnwser that Integer.<br> This is a generic version dealing with an optional sign and a simple sequence of decimal digits.<br> Subclass might define extended syntax."<br> <br>+ base := self defaultBase.<br>- base := 10.<br> ^self nextIntegerBase: base ifFail: [^self expected: ('a digit between 0 and ' copyWith: (Character digitValue: base - 1))]!<br><br>Item was changed:<br> ----- Method: NumberParser>>nextUnsignedInteger (in category 'parsing-public') -----<br> nextUnsignedInteger<br> "Read an Integer from sourceStream, asnwser that Integer.<br> This is a generic version dealing with a simple sequence of decimal digits.<br> Subclass might define extended syntax."<br>+ <br>+ base := self defaultBase.<br>- <br>- base := 10.<br> ^self nextUnsignedIntegerBase: base ifFail: [^self expected: ('a digit between 0 and ' copyWith: (Character digitValue: base - 1))]!<br><br>Item was changed:<br> ----- Method: NumberParser>>on: (in category 'initialize-release') -----<br> on: aStringOrStream <br> sourceStream := aStringOrStream isString <br> ifTrue: [ aStringOrStream readStream ]<br> ifFalse: [ aStringOrStream ].<br>+ base := self defaultBase.<br>- base := 10.<br> neg := false.<br> integerPart := fractionPart := exponent := scale := 0.<br> requestor := failBlock := nil!<br><br>Item was changed:<br> ----- Method: NumberParser>>readExponent (in category 'parsing-private') -----<br> readExponent<br> "read the exponent if any (stored in instVar).<br> Answer true if found, answer false if none.<br> If exponent letter is not followed by a digit,<br> this is not considered as an error.<br> Exponent are always read in base 10."<br> <br> | eneg epos |<br> exponent := 0.<br> (self isExponentLetter: sourceStream peek) ifFalse: [^ false].<br> sourceStream next.<br> eneg := sourceStream peekFor: $-.<br> epos := eneg not and: [self allowPlusSignInExponent and: [sourceStream peekFor: $+]].<br>+ exponent := self nextUnsignedIntegerOrNilBase: self defaultBase.<br>- exponent := self nextUnsignedIntegerOrNilBase: 10.<br> exponent ifNil: ["Oops, there was no digit after the exponent letter.Ungobble the letter"<br> exponent := 0.<br> sourceStream<br> skip: ((eneg or: [epos])<br> ifTrue: [-2]<br> ifFalse: [-1]).<br> ^ false].<br> eneg ifTrue: [exponent := exponent negated].<br> ^true!<br><br>Item was removed:<br>- ----- Method: SqNumberParser class>>on: (in category 'instance creation') -----<br>- on: aStringOrStream<br>- ^self new on: aStringOrStream!<br><br>Item was removed:<br>- ----- Method: SqNumberParser class>>parse: (in category 'instance creation') -----<br>- parse: aStringOrStream <br>- ^(self new)<br>- on: aStringOrStream;<br>- nextNumber!<br><br>Item was removed:<br>- ----- Method: SqNumberParser class>>parse:onError: (in category 'instance creation') -----<br>- parse: aStringOrStream onError: failBlock <br>- ^(self new)<br>- on: aStringOrStream;<br>- failBlock: failBlock;<br>- nextNumber!<br><br>Item was changed:<br> ----- Method: SqNumberParser>>nextFraction (in category 'parsing-public') -----<br> nextFraction<br> | numerator denominator numberOfTrailingZeroInIntegerPart |<br>+ base := self defaultBase.<br>- base := 10.<br> neg := self peekSignIsMinus.<br> (integerPart := self nextUnsignedIntegerOrNilBase: base)<br> ifNil: ["No integerPart, raise an error"<br> ^ self expected: 'a digit'].<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.<br> (sourceStream peekFor: $r)<br> ifTrue: ["<base>r<integer>"<br> (base := integerPart) < 2<br> ifTrue: [<br> sourceStream skip: -1.<br> ^ self expected: 'an integer greater than 1 as valid radix'].<br> self peekSignIsMinus<br> ifTrue: [neg := neg not].<br> integerPart := self nextUnsignedIntegerBase: base.<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].<br> (sourceStream peekFor: $.)<br> ifTrue:<br> [^self readFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart].<br> numerator := neg<br> ifTrue: [integerPart negated]<br> ifFalse: [integerPart].<br> self readExponent ifTrue: [numerator := numerator * (base raisedToInteger: exponent)].<br> (sourceStream peekFor: $/) ifFalse: [^numerator].<br>+ base := self defaultBase.<br>- base := 10.<br> (denominator := self nextUnsignedIntegerOrNilBase: base)<br> ifNil:<br> [sourceStream skip: -1. "Not a valid denominator, ungobble / and return numerator"<br> ^numerator].<br> (sourceStream peekFor: $r)<br> ifTrue: ["<base>r<integer>"<br> (base := denominator) < 2<br> ifTrue: [<br> sourceStream skip: -1.<br> ^ self expected: 'an integer greater than 1 as valid radix'].<br> denominator := self nextUnsignedIntegerBase: base].<br> self readExponent ifTrue: [denominator := denominator * (base raisedToInteger: exponent)].<br> ^numerator / denominator!<br><br>Item was changed:<br> ----- Method: SqNumberParser>>nextInteger (in category 'parsing-public') -----<br> nextInteger<br> "Read an Integer from sourceStream, asnwser that Integer.<br> In Smalltalk syntax, a radix can be specified, and an exponent too."<br> <br> | numberOfTrailingZeroInIntegerPart |<br>+ base := self defaultBase.<br>- base := 10.<br> neg := self peekSignIsMinus.<br> integerPart := self nextUnsignedIntegerOrNilBase: base.<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.<br> (sourceStream peekFor: $r)<br> ifTrue: ["<base>r<integer>"<br> (base := integerPart) < 2<br> ifTrue: [<br> sourceStream skip: -1.<br> ^ self expected: 'an integer greater than 1 as valid radix'].<br> self peekSignIsMinus<br> ifTrue: [neg := neg not].<br> integerPart := self nextUnsignedIntegerBase: base.<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].<br> ^ self makeIntegerOrScaledInteger!<br><br>Item was changed:<br> ----- Method: SqNumberParser>>nextNumber (in category 'parsing-public') -----<br> nextNumber<br> "main method for reading a number.<br> This one can read Float Integer and ScaledDecimal"<br> <br> | numberOfTrailingZeroInIntegerPart |<br>+ base := self defaultBase.<br>- base := 10.<br> neg := self peekSignIsMinus.<br> integerPart := self nextUnsignedIntegerOrNilBase: base.<br> integerPart ifNil: [<br> "This is not a regular number beginning with a digit<br> It is time to check for exceptional condition NaN and Infinity"<br> ^self readNamedFloatOrFail].<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.<br> (sourceStream peekFor: $r)<br> ifTrue: ["<base>r<integer>"<br> (base := integerPart) < 2<br> ifTrue: [<br> sourceStream skip: -1.<br> ^ self expected: 'an integer greater than 1 as valid radix'].<br> self peekSignIsMinus<br> ifTrue: [neg := neg not].<br> integerPart := self nextUnsignedIntegerBase: base.<br> numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].<br> ^ (sourceStream peekFor: $.)<br> ifTrue: [self readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart]<br> ifFalse: [self makeIntegerOrScaledInteger]!<br><br>Item was changed:<br> ----- Method: SqNumberParser>>nextScaledDecimal (in category 'parsing-public') -----<br> nextScaledDecimal<br> "Main method for reading a (scaled) decimal number.<br> Good Gracious, do not accept a decimal in another base than 10!!<br> In other words, do not accept radix notation like 2r1.1, even not 10r5.3<br> Do not accept exponent notation neither, like 1.0e-3"<br> <br> | numberOfNonZeroFractionDigits numberOfTrailingZeroInFractionPart |<br>+ base := self defaultBase.<br>- base := 10.<br> neg := sourceStream peekFor: $-.<br> integerPart := self nextUnsignedIntegerBase: base.<br> (sourceStream peekFor: $.)<br> ifTrue: [fractionPart := self nextUnsignedIntegerOrNilBase: base.<br> fractionPart ifNil: ["Oops, the decimal point seems not part of this number"<br> sourceStream skip: -1.<br> ^ neg<br> ifTrue: [integerPart negated asScaledDecimal: 0]<br> ifFalse: [integerPart asScaledDecimal: 0]].<br> numberOfNonZeroFractionDigits := lastNonZero.<br> numberOfTrailingZeroInFractionPart := nDigits - lastNonZero.<br> (self readScaleWithDefaultNumberOfDigits: nDigits)<br> ifFalse: ["No scale were provided. use number of digits after decimal point as scale"<br> scale := nDigits].<br> ^self makeScaledDecimalWithNumberOfNonZeroFractionDigits: numberOfNonZeroFractionDigits andNumberOfTrailingZeroInFractionPart: numberOfTrailingZeroInFractionPart].<br> self readScaleWithDefaultNumberOfDigits: 0.<br> neg ifTrue: [integerPart := integerPart negated].<br> ^integerPart asScaledDecimal: scale!<br><br>Item was changed:<br> ----- Method: SqNumberParser>>nextUnsignedInteger (in category 'parsing-public') -----<br> nextUnsignedInteger<br> "Read an unsigned Integer from sourceStream, asnwser that Integer.<br> In Smalltalk syntax, a radix can be specified, and an exponent too."<br> <br>+ base := self defaultBase.<br>- base := 10.<br> neg := false.<br> integerPart := self nextUnsignedIntegerOrNilBase: base.<br> (sourceStream peekFor: $r)<br> ifTrue: ["<base>r<integer>"<br> (base := integerPart) < 2<br> ifTrue: [<br> sourceStream skip: -1.<br> ^ self expected: 'an integer greater than 1 as valid radix'].<br> integerPart := self nextUnsignedIntegerBase: base].<br> ^ self makeIntegerOrScaledInteger!<br><br>Item was changed:<br> ----- Method: SqNumberParser>>readScaleWithDefaultNumberOfDigits: (in category 'parsing-private') -----<br> readScaleWithDefaultNumberOfDigits: anInteger<br> "Read the scale if any and store it into scale instance Variable.<br> Answer true if found, answer false if none.<br> The scale is specified by letter s, optionnally followed by a positive integer in base 10.<br> If no integer is specified, that means using as many digits as provided after the fraction separator, as provided by parameter anInteger.<br> A letter s followed by another letter is not considered as a scale specification, because it could be part of a message."<br> <br> scale := 0.<br> sourceStream atEnd<br> ifTrue: [ ^ false ].<br> (sourceStream peekFor: $s)<br> ifFalse: [ ^ false ].<br>+ scale := self nextUnsignedIntegerOrNilBase: self defaultBase.<br>- scale := self nextUnsignedIntegerOrNilBase: 10.<br> scale<br> ifNil: [ <br> scale := anInteger.<br> (sourceStream peek ifNil: [ false ] ifNotNil: [ :nextChar | nextChar isLetter ])<br> ifTrue: [ <br> sourceStream skip: -1. "ungobble the s"<br> ^ false ]<br> ifFalse: [ ^ true ] ].<br> ^ true!<br><br><br></integer></integer></integer></integer></integer></integer></blockclosure></texteditor></integer></integer></integer></integer></integer></integer></boolean></integer></stream></integer></integer></integer></div></blockquote>
</div></body>