Re: Change Set: tallyLiterals.1.cs

Eliot Miranda <[email protected]>
Newsgroups gmane.comp.lang.smalltalk.squeak.general
Message-ID <CAC20JE0Po+nNO1KfFQxmjpPWE2W8EyXBQ=yTgGGUizt4qWGptA@mail.gmail.com>
On Mon, Jun 1, 2026 at 2:02 PM Christoph Thiede via Squeak-dev <
[email protected]> wrote:

> *=============== Summary ===============*
>
> Change Set:        tallyLiterals
> Date:            1 June 2026
> Author:            Christoph Thiede
>
> Adds support for tally bases and radix 1 to number parser. Also updates
> Shout and tests.
>

!!

At first I considered making 1r111 = 3 as supposed earlier on the mailing
> list but then I found the following more consistent:
>
> 1r000 = 0.
> 1t = 0.
> 1t1 = 1.
> 1t111 = 3.
>
> *=============== Diff ===============*
>
> *ExtendedNumberParser>>nextFraction {parsing-public} · ct 6/1/2026 21:45
> (changed)*
> nextFraction
>     | numerator denominator numberOfTrailingZeroInIntegerPart |
>     base := self defaultBase.
>     neg := self peekSignIsMinus.
>     (integerPart := self nextUnsignedIntegerOrNilBase: base)
>         ifNil: [numberOfTrailingZeroInIntegerPart := 0]
>         ifNotNil: [
>             numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.
>             (sourceStream peekFor: $r)
>                 ifTrue: ["<base>r<integer>"
> -                     (base := integerPart) < 2
> +                     (base := integerPart) < 1
>                         ifTrue: [
>                             sourceStream skip: -1.
> -                             ^ self expected: 'an integer greater than 1
> as valid radix'].
> +                             ^ self expected: 'an integer greater than 0
> 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
> +             (base := denominator) < 1
>                 ifTrue: [
>                     sourceStream skip: -1.
> -                     ^ self expected: 'an integer greater than 1 as valid
> radix'].
> +                     ^ self expected: 'an integer greater than 0 as valid
> radix'].
>             denominator := self nextUnsignedIntegerBase: base].
>     self readExponent ifTrue: [denominator := denominator * (base
> raisedToInteger: exponent)].
>     ^numerator / denominator
>
> *ExtendedNumberParser>>nextNumber {parsing-public} · ct 6/1/2026 22:52
> (changed)*
> nextNumber
>     "main method for reading a number.
>     This one can read Float Integer and ScaledDecimal"
>
>     | numberOfTrailingZeroInIntegerPart |
>     base := self defaultBase.
>     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"
> +             (base := integerPart) < 1
> +                 ifTrue: ["A radix currently need to be greater than 0,
> 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: $t)
> +         ifTrue: ["1t<integer>"
> +             integerPart = 1t1
> +                 ifTrue: [
> +                     | char |
> +                     nDigits := lastNonZero := 0.
> +                     [(char := sourceStream next) = $1 ifFalse: [
> +                         char ifNotNil: [sourceStream skip: -1].
> +                         ^ neg ifTrue: [nDigits negated] ifFalse:
> [nDigits]].
> +                     nDigits := nDigits + 1] repeat]
> +                 ifFalse: [
> +                     sourceStream skip: -1]].
>     ^ (sourceStream peekFor: $.)
>         ifTrue: [self
> readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart:
> numberOfTrailingZeroInIntegerPart]
>         ifFalse: [self makeIntegerOrScaledInteger]
>
> *NumberParser>>nextElementaryLargeIntegerBase: {parsing-large int} · ct
> 6/1/2026 22:14 (changed)*
> nextElementaryLargeIntegerBase: aRadix
>     "Form an unsigned integer with incoming digits from sourceStream.
>     Return this integer, or zero if no digits found.
>     Stop reading if end of digits or if a LargeInteger is formed.
>     Count the number of digits and the position of lastNonZero digit and
> store them in instVar."
>
>     | value digit char |
> -     value := 0.
>     nDigits := 0.
>     lastNonZero := 0.
> +     value := 0.
>     [
>         value isLarge ifTrue: [ ^value ].
>         char := sourceStream next ifNil: [ ^value ].
>         ((digit := char digitValue) < 0 or: [digit >= aRadix]) ifTrue: [
>             sourceStream skip: -1.
>             ^value ].
>         nDigits := nDigits + 1.
>         digit = 0
>             ifFalse: [
>                 lastNonZero := nDigits.
>                 value := value * aRadix + digit ]
>             ifTrue: [ value := value * aRadix ] ] repeat
>
> *SHParserST80>>scanNumber {scan} · ct 6/1/2026 22:34 (changed)*
> scanNumber
>
>     | c |
>     currentTokenSourcePosition := sourcePosition.
>     self skipDigits.
>     (c := self currentChar) == $r
>         ifTrue: [
>             | base |
>             base := (source copyFrom: currentTokenSourcePosition to:
> sourcePosition - 1) asUnsignedInteger.
> -             base < 2 ifTrue: [ self fail ": radix must be greater than
> 1" ].
> +             base < 1 ifTrue: [ self fail ": radix must be greater than
> 1" ].
>             self peekChar == $- ifTrue: [ self nextChar ].
>             self skipDigitsBase: base.
>             (c := self currentChar) == $. ifTrue: [
>                 (self isDigit: self peekChar base: base) ifTrue: [
>                     self skipDigitsBase: base].
>                 c := self currentChar ] ]
>         ifFalse: [
> +             c == $t ifTrue: [
> +                 | base |
> +                 base := (source copyFrom: currentTokenSourcePosition to:
> sourcePosition - 1) asUnsignedInteger.
> +                 base = 1t1 ifTrue: [
> +                     self peekChar == $- ifTrue: [ self nextChar ].
> +                     [ self nextChar = $1 ] whileTrue]].
>             c == $. ifTrue: [
>                 self peekChar isDigit ifFalse: [
>                     ^currentToken := source copyFrom:
> currentTokenSourcePosition to: sourcePosition - 1 ].
>                 self skipDigits.
>                 c := self currentChar ] ].
>     c == $s
>         ifTrue: [
>             (c := self nextChar) isDigit
>                 ifFalse: [ c isLetter ifTrue: [sourcePosition :=
> sourcePosition - 1 ] ]
>                 ifTrue: [ self skipDigits ] ]
>         ifFalse: [
>             (c == $d
>                 or: [ c == $e
>                 or: [ c == $q ] ])
>                 ifTrue: [
>                     ((c := self nextChar) isDigit or: [ c == $- and: [
> self peekChar isDigit ] ])
>                         ifFalse: [ sourcePosition := sourcePosition - 1 ]
>                         ifTrue: [ self skipDigits ] ] ].
>     currentToken := source copyFrom: currentTokenSourcePosition to:
> sourcePosition - 1
>
> *SqNumberParser>>nextFraction {parsing-public} · ct 6/1/2026 21:45
> (changed)*
> nextFraction
>     | numerator denominator numberOfTrailingZeroInIntegerPart |
>     base := self defaultBase.
>     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
> +             (base := integerPart) < 1
>                 ifTrue: [
>                     sourceStream skip: -1.
> -                     ^ self expected: 'an integer greater than 1 as valid
> radix'].
> +                     ^ self expected: 'an integer greater than 0 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.
>     (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
> +             (base := denominator) < 1
>                 ifTrue: [
>                     sourceStream skip: -1.
> -                     ^ self expected: 'an integer greater than 1 as valid
> radix'].
> +                     ^ self expected: 'an integer greater than 0 as valid
> radix'].
>             denominator := self nextUnsignedIntegerBase: base].
>     self readExponent ifTrue: [denominator := denominator * (base
> raisedToInteger: exponent)].
>     ^numerator / denominator
>
> *SqNumberParser>>nextInteger {parsing-public} · ct 6/1/2026 21:45
> (changed)*
> 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.
>     neg := self peekSignIsMinus.
>     integerPart := self nextUnsignedIntegerOrNilBase: base.
>     numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.
>     (sourceStream peekFor: $r)
>         ifTrue: ["<base>r<integer>"
> -             (base := integerPart) < 2
> +             (base := integerPart) < 1
>                 ifTrue: [
>                     sourceStream skip: -1.
> -                     ^ self expected: 'an integer greater than 1 as valid
> radix'].
> +                     ^ self expected: 'an integer greater than 0 as valid
> radix'].
>             self peekSignIsMinus
>                 ifTrue: [neg := neg not].
>             integerPart := self nextUnsignedIntegerBase: base.
>             numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].
>     ^ self makeIntegerOrScaledInteger
>
> *SqNumberParser>>nextNumber {parsing-public} · ct 6/1/2026 22:51 (changed)*
> nextNumber
>     "main method for reading a number.
>     This one can read Float Integer and ScaledDecimal"
>
>     | numberOfTrailingZeroInIntegerPart |
>     base := self defaultBase.
>     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
> +             (base := integerPart) < 1
>                 ifTrue: [
>                     sourceStream skip: -1.
> -                     ^ self expected: 'an integer greater than 1 as valid
> radix'].
> +                     ^ self expected: 'an integer greater than 0 as valid
> radix'].
>             self peekSignIsMinus
>                 ifTrue: [neg := neg not].
>             integerPart := self nextUnsignedIntegerBase: base.
> -             numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].
> +             numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero]
> +         ifFalse: [
> +             (sourceStream peekFor: $t)
> +                 ifTrue: ["1t<integer>"
> +                     integerPart = 1t1
> +                         ifTrue: [
> +                             | char |
> +                             nDigits := lastNonZero := 0.
> +                             [(char := sourceStream next) = $1 ifFalse: [
> +                                 char ifNotNil: [sourceStream skip: -1].
> +                                 ^ neg ifTrue: [nDigits negated] ifFalse:
> [nDigits]].
> +                             nDigits := nDigits + 1] repeat]
> +                         ifFalse: [
> +                             sourceStream skip: -1]]].
>     ^ (sourceStream peekFor: $.)
>         ifTrue: [self
> readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart:
> numberOfTrailingZeroInIntegerPart]
>         ifFalse: [self makeIntegerOrScaledInteger]
>
> *SqNumberParser>>nextUnsignedInteger {parsing-public} · ct 6/1/2026 21:45
> (changed)*
> 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.
>     neg := false.
>     integerPart := self nextUnsignedIntegerOrNilBase: base.
>     (sourceStream peekFor: $r)
>         ifTrue: ["<base>r<integer>"
> -             (base := integerPart) < 2
> +             (base := integerPart) < 1
>                 ifTrue: [
>                     sourceStream skip: -1.
> -                     ^ self expected: 'an integer greater than 1 as valid
> radix'].
> +                     ^ self expected: 'an integer greater than 0 as valid
> radix'].
>             integerPart := self nextUnsignedIntegerBase: base].
>     ^ self makeIntegerOrScaledInteger
>
> *SqNumberParserTest>>testBases {tests - fail} · ct 6/1/2026 22:51
> (changed)*
> testBases
>
>     self assert: (SqNumberParser parse: '16r20') equals: 32.
>     self assert: (SqNumberParser parse: '2r10') equals: 2.
> +     self assert: (SqNumberParser parse: '1r000') equals: 0.
>     self assert: ((SqNumberParser on: '10')
>         nextIntegerBase: 2) equals: 2.
>     self assert: ((SqNumberParser on: '10')
>         defaultBase: 2;
>         nextNumber) equals: 2.
>     self assert: ((SqNumberParser on: '1000r10')
>         defaultBase: 2;
>         nextNumber) equals: 8.
>
> *SqNumberParserTest>>testTally {tests - fail} · ct 6/1/2026 22:49*
> + testTally
> +
> +     | rs |
> +     self assert: (SqNumberParser parse: '1t') equals: 0.
> +     self assert: (SqNumberParser parse: '1t1') equals: 1.
> +     self assert: (SqNumberParser parse: '1t111') equals: 3.
> +     self assert: (SqNumberParser parse: '-1t11') equals: -2.
> +
> +     rs := '1t11e1' readStream.
> +     self assert: (SqNumberParser parse: rs) equals: 2.
> +     self assert: rs upToEnd equals: 'e1'.
> +
> +     rs := '2t1' readStream.
> +     self assert: (SqNumberParser parse: rs) equals: 2.
> +     self assert: rs upToEnd equals: 't1'.
> +
> +     rs := '1t0' readStream.
> +     self assert: (SqNumberParser parse: rs) equals: 0.
> +     self assert: rs upToEnd equals: '0'.
> +
> +     rs := '1t22' readStream.
> +     self assert: (SqNumberParser parse: rs) equals: 0.
> +     self assert: rs upToEnd equals: '22'.
>
> --
> *Sent from **Squeak Inbox Talk
> <https://github.com/hpi-swa-lab/squeak-inbox-talk>*Squeak-dev mailing
> list -- [email protected]
> To unsubscribe send an email to
> [email protected]



-- 
_,,,^..^,,,_
best, Eliot

Squeak-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.