Marcel Taeumel uploaded a new version of KernelTests to project The Trunk:
http://source.squeak.org/trunk/KernelTests-mt.365.mcz
==================== Summary ====================
Name: KernelTests-mt.365
Author: mt
Time: 31 May 2019, 11:49:30.444936 am
UUID: 4087706d-1610-504e-9930-d0ab9de30dd5
Ancestors: KernelTests-nice.364, KernelTests-cmfcmf.357
merge cmfcmf.357
=============== Diff against KernelTests-nice.364 ===============
Item was added:
+ ----- Method: RandomTest>>testRoll (in category 'tests') -----
+ testRoll
+
+ | random result |
+ random := Random seed: 14482.
+
+ "Roll the default die (d6)"
+ 100 timesRepeat: [
+ result := random roll: 'd'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 6 description: [ 'Rolled value ', result asString, ' should be 6 or less.' ] ].
+ 100 timesRepeat: [
+ result := random roll: '1d'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 6 description: [ 'Rolled value ', result asString, ' should be 6 or less.' ] ].
+
+ "Roll a d20"
+ 100 timesRepeat: [
+ result := random roll: '1d20'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 20 description: [ 'Rolled value ', result asString, ' should be 20 or less.' ] ].
+
+ "Roll a d% (d100)"
+ 1000 timesRepeat: [
+ result := random roll: '1d%'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 100 description: [ 'Rolled value ', result asString, ' should be 100 or less.' ] ].
+ 1000 timesRepeat: [
+ result := random roll: 'd%'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 100 description: [ 'Rolled value ', result asString, ' should be 100 or less.' ] ].
+
+ "Roll multiple dice"
+ 100 timesRepeat: [
+ result := random roll: '2d2'.
+ self assert: result >= 2 description: [ 'Rolled value ', result asString, ' should be 2 or more.' ].
+ self assert: result <= 4 description: [ 'Rolled value ', result asString, ' should be 4 or less.' ] ].
+ 100 timesRepeat: [
+ result := random roll: '1d2+1d2'.
+ self assert: result >= 2 description: [ 'Rolled value ', result asString, ' should be 2 or more.' ].
+ self assert: result <= 4 description: [ 'Rolled value ', result asString, ' should be 4 or less.' ] ].
+
+ "Roll some d1s"
+ result := random roll: '10d1'.
+ self assert: result = 10 description: [ 'Rolled value ', result asString, 'should be 10.' ].
+ result := random roll: '10d1-5d1'.
+ self assert: result = 5 description: [ 'Rolled value ', result asString, 'should be 5.' ].
+
+ "Roll a constant value"
+ result := random roll: '5'.
+ self assert: result = 5 description: [ 'Rolled value ', result asString, 'should be 5.' ].
+ result := random roll: '5+3+2'.
+ self assert: result = 10 description: [ 'Rolled value ', result asString, 'should be 10.' ].
+
+ "Roll die and add constant value"
+ result := random roll: '1d1+3'.
+ self assert: result = 4 description: [ 'Rolled value ', result asString, 'should be 4.' ].!
Marcel Taeumel uploaded a new version of KernelTests to project The Trunk:
http://source.squeak.org/trunk/KernelTests-cmfcmf.357.mcz
==================== Summary ====================
Name: KernelTests-cmfcmf.357
Author: cmfcmf
Time: 29 May 2019, 10:11:48.378802 pm
UUID: f67037ad-f5fe-4145-8efa-3845d0494ace
Ancestors: KernelTests-fn.356
Test Random>>roll:
=============== Diff against KernelTests-fn.356 ===============
Item was added:
+ ----- Method: RandomTest>>testRoll (in category 'tests') -----
+ testRoll
+
+ | random result |
+ random := Random seed: 14482.
+
+ "Roll the default die (d6)"
+ 100 timesRepeat: [
+ result := random roll: 'd'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 6 description: [ 'Rolled value ', result asString, ' should be 6 or less.' ] ].
+ 100 timesRepeat: [
+ result := random roll: '1d'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 6 description: [ 'Rolled value ', result asString, ' should be 6 or less.' ] ].
+
+ "Roll a d20"
+ 100 timesRepeat: [
+ result := random roll: '1d20'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 20 description: [ 'Rolled value ', result asString, ' should be 20 or less.' ] ].
+
+ "Roll a d% (d100)"
+ 1000 timesRepeat: [
+ result := random roll: '1d%'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 100 description: [ 'Rolled value ', result asString, ' should be 100 or less.' ] ].
+ 1000 timesRepeat: [
+ result := random roll: 'd%'.
+ self assert: result >= 1 description: [ 'Rolled value ', result asString, ' should be 1 or more.' ].
+ self assert: result <= 100 description: [ 'Rolled value ', result asString, ' should be 100 or less.' ] ].
+
+ "Roll multiple dice"
+ 100 timesRepeat: [
+ result := random roll: '2d2'.
+ self assert: result >= 2 description: [ 'Rolled value ', result asString, ' should be 2 or more.' ].
+ self assert: result <= 4 description: [ 'Rolled value ', result asString, ' should be 4 or less.' ] ].
+ 100 timesRepeat: [
+ result := random roll: '1d2+1d2'.
+ self assert: result >= 2 description: [ 'Rolled value ', result asString, ' should be 2 or more.' ].
+ self assert: result <= 4 description: [ 'Rolled value ', result asString, ' should be 4 or less.' ] ].
+
+ "Roll some d1s"
+ result := random roll: '10d1'.
+ self assert: result = 10 description: [ 'Rolled value ', result asString, 'should be 10.' ].
+ result := random roll: '10d1-5d1'.
+ self assert: result = 5 description: [ 'Rolled value ', result asString, 'should be 5.' ].
+
+ "Roll a constant value"
+ result := random roll: '5'.
+ self assert: result = 5 description: [ 'Rolled value ', result asString, 'should be 5.' ].
+ result := random roll: '5+3+2'.
+ self assert: result = 10 description: [ 'Rolled value ', result asString, 'should be 10.' ].
+
+ "Roll die and add constant value"
+ result := random roll: '1d1+3'.
+ self assert: result = 4 description: [ 'Rolled value ', result asString, 'should be 4.' ].!
Marcel Taeumel uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-cmfcmf.1216.mcz
==================== Summary ====================
Name: Kernel-cmfcmf.1216
Author: cmfcmf
Time: 29 May 2019, 10:09:51.240802 pm
UUID: 3c20ffc1-89f8-474e-95a7-05fab06c9f9b
Ancestors: Kernel-eem.1215
Make Random>>roll: work again and add support for constant operands
This version fixes three issues:
1. Random>>roll: was not working anymore. The following code only produced an error:
Random new roll: '1d20'
This happened due to an issue with Random>>diceToken: which used Number>>readFrom: to extract numbers from the string. Calling Number readFrom: '1d20' results in 100000000000000000000 instead of the expected 1, because $d is seen as an exponent letter by the ExtendedNumberParser used by Number>>readFrom: (see ExtendedNumberParser>>exponentLetters).
I therefore replaced Number>>readFrom: by Integer>>readFrom:, which doesn't use the exponent letters.
2. I also fixed a minor issue with the mini-grammar's 'dice' rule. Before this version, it read as if it only supported one or two operands, when it really supported an unlimited number of operands.
3. The mini-grammer's 'expr' rule read as if it supported constant operands (e.g., '1d20+5' or '42'), because 'expr' was allowed to be just 'num'. As far as I can gather, this has never worked (but I might be wrong). This is now also fixed by always setting res to the token read if the token is a number. If the token is neither a number nor $d, an error is now signalled.
=============== Diff against Kernel-eem.1215 ===============
Item was changed:
----- Method: Random>>diceToken: (in category 'die rolling') -----
diceToken: stream
"Private. Mini scanner, see #roll:"
stream atEnd ifTrue: [^ nil].
+ stream peek isDigit ifTrue: [^ Integer readFrom: stream].
- stream peek isDigit ifTrue: [^ Number readFrom: stream].
^ stream next asLowercase!
Item was changed:
----- Method: Random>>roll: (in category 'die rolling') -----
roll: diceString
"Roll some dice, DnD-style, according to this mini-grammar:
+ dice := epxr {pm dice}
- dice := epxr {pm expr}
pm := '+' | '-'
expr := num | num dD | dD numP | num dD numP
dD := 'd' | 'D'
num := digit+
numP := num | '%'"
| stream op result |
stream := diceString readStream.
result := 0.
op := #+.
[ | res range dice token |
token := self diceToken: stream.
token isNumber
ifTrue: [dice := token.
+ res := token.
token := self diceToken: stream]
ifFalse: [token == $d
ifTrue: [dice := 1]
+ ifFalse: [self error: 'unknown token' , token]].
- ifFalse: [res := 0]].
token == $d
ifTrue: [token := self diceToken: stream.
token isNumber
ifTrue: [range := token.
token := self diceToken: stream]
ifFalse: [token == $%
ifTrue: [range := 100.
token := self diceToken: stream]
ifFalse: [range := 6]].
res := 0.
dice timesRepeat: [res := res + (self nextInt: range)]].
result := result perform: op with: res.
token ifNil: [^ result].
(token == $+ or: [token == $-])
ifFalse: [self error: 'unknown token ' , token].
op := token asSymbol] repeat!
Chris Muller uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-cmm.848.mcz
==================== Summary ====================
Name: Tools-cmm.848
Author: cmm
Time: 25 May 2019, 5:42:37.546478 pm
UUID: dd37c4dd-789f-47d8-a059-2595ee4eb451
Ancestors: Tools-nice.847
- Fix from Tim Johnson prevents a DNU from ChangeSorter under certain conditions.
- Add ability to filter methods from a MessageSet based on package they're NOT in (helpful for filtering test methods, or identifying methods in the wrong package).
=============== Diff against Tools-nice.847 ===============
Item was changed:
----- Method: ChangeSorter>>setContents (in category 'code pane') -----
setContents
"return the source code that shows in the bottom pane"
| sel class strm changeType |
self clearUserEditFlag.
+ myChangeSet ifNil: [^ contents := String empty]. "should not happen but can"
currentClassName ifNil: [^ contents := myChangeSet preambleString ifNil: ['']].
class := self selectedClassOrMetaClass.
(sel := self selectedMessageName) == nil
ifFalse: [changeType := (myChangeSet atSelector: (sel := sel asSymbol) class: class).
changeType == #remove
ifTrue: [^ contents := 'Method has been removed (see versions)'].
changeType == #addedThenRemoved
ifTrue: [^ contents := 'Added then removed (see versions)'].
class ifNil: [^ contents := 'Method was added, but cannot be found!!'].
(class includesSelector: sel)
ifFalse: [^ contents := 'Method was added, but cannot be found!!'].
contents := class sourceCodeAt: sel.
(#(prettyPrint prettyDiffs) includes: contentsSymbol) ifTrue:
[contents := class prettyPrinterClass
format: contents in: class notifying: nil].
self showingAnyKindOfDiffs
ifTrue: [contents := self diffFromPriorSourceFor: contents].
^ contents := contents asText makeSelectorBoldIn: class]
ifTrue: [strm := WriteStream on: (String new: 100).
(myChangeSet classChangeAt: (self withoutItemAnnotation: currentClassName)) do:
[:each |
each = #remove ifTrue: [strm nextPutAll: 'Entire class was removed.'; cr].
each = #addedThenRemoved ifTrue: [strm nextPutAll: 'Class was added then removed.'].
each = #rename ifTrue: [strm nextPutAll: 'Class name was changed.'; cr].
each = #add ifTrue: [strm nextPutAll: 'Class definition was added.'; cr].
each = #change ifTrue: [strm nextPutAll: 'Class definition was changed.'; cr].
each = #reorganize ifTrue: [strm nextPutAll: 'Class organization was changed.'; cr].
each = #comment ifTrue: [strm nextPutAll: 'New class comment.'; cr.
]].
^ contents := strm contents].!
Item was changed:
----- Method: MessageSet>>filterMessageList (in category 'filtering') -----
filterMessageList
"Allow the user to refine the list of messages."
| builder menuSpec |
builder := ToolBuilder default.
menuSpec := builder pluggableMenuSpec new
model: self;
yourself.
menuSpec addList:
#(
('unsent messages' filterToUnsentMessages 'filter to show only messages that have no senders')
-
('messages that send...' filterToSendersOf 'filter to show only messages that send a selector I specify')
('messages that do not send...' filterToNotSendersOf 'filter to show only messages that do not send a selector I specify')
-
('messages whose selector is...' filterToImplementorsOf 'filter to show only messages with a given selector I specify')
('messages whose selector is NOT...' filterToNotImplementorsOf 'filter to show only messages whose selector is NOT a seletor I specify')
-
('messages in current change set' filterToCurrentChangeSet 'filter to show only messages that are in the current change set')
('messages not in current change set' filterToNotCurrentChangeSet 'filter to show only messages that are not in the current change set')
-
('messages in any change set' filterToAnyChangeSet 'filter to show only messages that occur in at least one change set')
('messages not in any change set' filterToNotAnyChangeSet 'filter to show only messages that do not occur in any change set in the system')
-
('messages authored by me' filterToCurrentAuthor 'filter to show only messages whose authoring stamp has my initials')
('messages not authored by me' filterToNotCurrentAuthor 'filter to show only messages whose authoring stamp does not have my initials')
-
('messages logged in .changes file' filterToMessagesInChangesFile 'filter to show only messages whose latest source code is logged in the .changes file')
('messages only in .sources file' filterToMessagesInSourcesFile 'filter to show only messages whose latest source code is logged in the .sources file')
-
('messages with prior versions' filterToMessagesWithPriorVersions 'filter to show only messages that have at least one prior version')
('messages without prior versions' filterToMessagesWithoutPriorVersions 'filter to show only messages that have no prior versions')
-
('uncommented messages' filterToUncommentedMethods 'filter to show only messages that do not have comments at the beginning')
('commented messages' filterToCommentedMethods 'filter to show only messages that have comments at the beginning')
-
('messages in hardened classes' filterToMessagesWithHardenedClasses 'filter to show only messages of established classes (as opposed to Uniclasses such as Player23)') -
('methods in classes with matching names' filterToMatchingClassesNames 'filter to show only methods of classes with names that match the given criteria (wildcards are allowed)')
('methods in package...' filterToPackage 'filter to show only methods of a given package')
+ ('methods not in package...' filterToNotPackage 'filter to show only methods of a given package')
-
('messages that...' filterToMessagesThat 'let me type in a block taking a class and a selector, which will specify yea or nay concerning which elements should remain in the list')).
builder runModal: (builder open: menuSpec).!
Item was added:
+ ----- Method: MessageSet>>filterToNotPackage (in category 'filtering') -----
+ filterToNotPackage
+ self requestPackageSelection ifNotNil:
+ [ : selectedPackage | self filterFrom:
+ [ : aClass : aSelector | (selectedPackage
+ includesMethod: aSelector
+ ofClass: aClass) not ] ]!
Item was changed:
----- Method: MessageSet>>filterToPackage (in category 'filtering') -----
filterToPackage
+ self requestPackageSelection ifNotNil:
+ [ : selectedPackage | self filterFrom:
+ [ : aClass : aSelector | selectedPackage
+ includesMethod: aSelector
+ ofClass: aClass ] ]!
-
- | packages selectedIndex selectedPackage |
-
- packages := (PackageOrganizer default packages sort: [ :a :b |
- a packageName <= b packageName ]).
-
- selectedIndex := UIManager default chooseFrom: (packages collect:[:each | each packageName]) lines: #() title: 'Select a package...'.
- selectedIndex isZero ifTrue:[^ self].
-
- selectedPackage := packages at: selectedIndex.
- self filterFrom: [:aClass :aSelector | selectedPackage includesMethod: aSelector ofClass: aClass ]
- !
Item was added:
+ ----- Method: MessageSet>>requestPackageSelection (in category 'private') -----
+ requestPackageSelection
+ | packages selectedIndex |
+ packages := PackageOrganizer default packages sort:
+ [ : a : b | a packageName <= b packageName ].
+ selectedIndex := UIManager default
+ chooseFrom: (packages collect: [ : each | each packageName ])
+ lines: Array empty
+ title: 'Select a package...'.
+ ^ packages at: selectedIndex ifAbsent: [ nil ]!
Chris Muller uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-cmm.835.mcz
==================== Summary ====================
Name: Collections-cmm.835
Author: cmm
Time: 25 May 2019, 5:37:43.260101 pm
UUID: 691806ad-7981-4e23-aad9-864eaf710a5a
Ancestors: Collections-mt.834
- Moved three methods belonging to Chronology to that package.
=============== Diff against Collections-mt.834 ===============
Item was removed:
- ----- Method: String>>asDate (in category 'converting') -----
- asDate
- "Many allowed forms, see Date>>#readFrom:"
-
- ^ Date fromString: self!
Item was removed:
- ----- Method: String>>asDateAndTime (in category 'converting') -----
- asDateAndTime
-
- "Convert from UTC format" ^ DateAndTime fromString: self!
Item was removed:
- ----- Method: String>>asDuration (in category 'converting') -----
- asDuration
- "convert from [nnnd]hh:mm:ss[.nanos] format. [] implies optional elements"
-
- ^ Duration fromString: self
- !
Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.1237.mcz
==================== Summary ====================
Name: Kernel-nice.1237
Author: nice
Time: 23 May 2019, 9:17:06.927326 pm
UUID: 11d57971-88b6-4078-8ac6-91ba023d2ba6
Ancestors: Kernel-nice.1236
Fix sqrtRem in 32bits Squeak.
Since SmallInteger maxVal + 1 has only 4 bytes, self highBit bitShift: -5 may equal 0: we split in a single whole part and engage into an infinite loop.
=============== Diff against Kernel-nice.1236 ===============
Item was changed:
----- Method: LargePositiveInteger>>sqrtRem (in category 'mathematical functions') -----
sqrtRem
"See super. Use a divide and conquer method to perform this operation.
See Paul Zimmermann. Karatsuba Square Root. [Research Report] RR-3805, INRIA. 1999, pp.8. <inria-00072854>
https://hal.inria.fr/inria-00072854/PDF/RR-3805.pdf"
| n qr q s r sr a3a2 a1 a0 |
"Split self in 4 digits a3,a2,a1,a0 in base b,
such that most significant digit a3 >= b/4
It is not a problem to have a3 >= b,
so we can round b down to a whole number of bytes n"
+ n := (self highBit bitShift: -5) max: 1. "bitShift: -2 divide in 4 parts, bitShift: -3 round down in bytes"
- n := self highBit bitShift: -5. "bitShift: -2 divide in 4 parts, bitShift: -3 round down in bytes"
a3a2 := self butLowestNDigits: n * 2.
a1 := self copyDigitsFrom: n + 1 to: n * 2.
a0 := self lowestNDigits: n.
sr := a3a2 sqrtRem.
qr := (sr last bitShift: 8 * n) + a1 divideByInteger: (sr first bitShift: 1).
q := qr first normalize.
s := (sr first bitShift: 8 * n) + q.
r := (qr last normalize bitShift: 8 * n) + a0 - q squared.
r negative
ifTrue:
[r := (s bitShift: 1) + r - 1.
s := s - 1].
sr at: 1 put: s; at: 2 put: r.
^sr
!