Christoph Thiede uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-ct.1442.mcz
==================== Summary ====================
Name: Kernel-ct.1442
Author: ct
Time: 3 January 2022, 9:25:00.293397 pm
UUID: 1c8eb404-f420-9f48-99fa-32c965fb5491
Ancestors: Kernel-mt.1441
Improves multilingual support in common error messages on Object.
Uploaded to the inbox because I am not sure whether any of these places should NOT invoke Get-Text to avoid infinite recursions. I already excluded the error selectors in the private category and #primitiveFailed: for this reason. How far do we want to go with multilingual support in low-level Kernel?
=============== Diff against Kernel-mt.1441 ===============
Item was changed:
----- Method: AdditionalMethodState>>copyWith: (in category 'copying') -----
copyWith: aPropertyOrPragma "<Association|Pragma>"
"Answer a copy of the receiver which includes aPropertyOrPragma"
| bs copy |
(Association == aPropertyOrPragma class
or: [Pragma == aPropertyOrPragma class]) ifFalse:
+ [self error: ('{1} instances should hold only Associations or Pragmas.' translated format: {self class name})].
- [self error: self class name, ' instances should hold only Associations or Pragmas.'].
"no need to initialize here; we're copying all inst vars"
copy := self class basicNew: (bs := self basicSize) + 1.
1 to: bs do:
[:i|
copy basicAt: i put: (self basicAt: i) shallowCopy].
copy basicAt: bs + 1 put: aPropertyOrPragma.
1 to: self class instSize do:
[:i| copy instVarAt: i put: (self instVarAt: i)].
^copy!
Item was changed:
----- Method: Object>>assert: (in category 'error handling') -----
assert: aBlock
"Throw an assertion error if aBlock does not evaluates to true."
+ aBlock value ifFalse: [AssertionFailure signal: 'Assertion failed' translated]!
- aBlock value ifFalse: [AssertionFailure signal: 'Assertion failed']!
Item was changed:
----- Method: Object>>backwardCompatibilityOnly: (in category 'error handling') -----
backwardCompatibilityOnly: explanationString
"Warn that the sending method has been deprecated. Methods that are tagt with #backwardCompatibility:
are kept for compatibility."
Deprecation
signalForContext: thisContext sender
+ message: ' (but will be kept for compatibility)' translated
- message: ' (but will be kept for compatibility)'
explanation: explanationString!
Item was changed:
----- Method: Object>>caseError (in category 'error handling') -----
caseError
"Report an error from an in-line or explicit case statement."
+ self error: ('Case not found ({1}), and no otherwise clause' translated format: {self printString})!
- self error: ('Case not found ({1}), and no otherwise clause' format: {self printString})!
Item was changed:
----- Method: Object>>doesNotUnderstand: (in category 'error handling') -----
doesNotUnderstand: aMessage
"Handle the fact that there was an attempt to send the given
message to the receiver but the receiver does not understand
this message (typically sent from the machine when a message
is sent to the receiver and no method is defined for that selector).
Raise the MessageNotUnderstood signal. If it is caught, answer
the result supplied by the exception handler. If it is not caught,
answer the result of resending the message within a guard for
infinite recursion. This allows, for example, the programmer to
implement the method and continue."
"Testing: (3 activeProcess)"
| exception resumeValue |
(exception := MessageNotUnderstood new)
message: aMessage;
receiver: self.
resumeValue := exception signal.
^exception reachedDefaultHandler "i.e. exception was not caught..."
ifTrue:
[[aMessage sentTo: self]
on: MessageNotUnderstood
do: [:ex|
(self == ex receiver
and: [aMessage hasIdenticalContentsAs: ex message]) ifFalse:
[ex pass].
+ self error: 'infinite recursion in doesNotUnderstand:' translated]]
- self error: 'infinite recursion in doesNotUnderstand:']]
ifFalse: [resumeValue]!
Item was changed:
----- Method: Object>>error (in category 'error handling') -----
error
"Throw a generic Error exception."
+ ^self error: 'Error!!' translated.!
- ^self error: 'Error!!'.!
Item was changed:
----- Method: Object>>shouldBeImplemented (in category 'error handling') -----
shouldBeImplemented
"Announce that this message should be implemented"
+ ^ NotImplemented signal: ('{1} or a superclass should implement {2}' translated format: {self className. thisContext sender selector})!
- ^ NotImplemented signal: ('{1} or a superclass should implement {2}' format: {self className. thisContext sender selector})!
Item was changed:
----- Method: Object>>shouldNotImplement (in category 'error handling') -----
shouldNotImplement
"Announce that, although the receiver inherits this message, it should
not implement it."
+ NotImplemented signal: ('{1} is not a message appropriate for a {2}' translated format: {thisContext sender selector. self className}).!
- NotImplemented signal: ('{1} is not a message appropriate for a {2}' format: {thisContext sender selector. self className}).!
Item was changed:
----- Method: Object>>subclassResponsibility (in category 'error handling') -----
subclassResponsibility
"This message sets up a framework for the behavior of the class' subclasses.
Announce that the subclass should have implemented this message."
^ SubclassResponsibility
signal: ('My {1} subclass should have overridden {2}'
+ translated format: {self className. thisContext sender selector}).!
- format: {self className. thisContext sender selector}).!
Item was changed:
----- Method: Object>>traitConflict (in category 'error handling') -----
traitConflict
+ self error: 'A class or trait does not properly resolve a conflict between multiple traits it uses.' translated!
- self error: 'A class or trait does not properly resolve a conflict between multiple traits it uses.'!
Christoph Thiede uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-ct.1557.mcz
==================== Summary ====================
Name: Kernel-ct.1557
Author: ct
Time: 2 March 2024, 6:57:26.957512 pm
UUID: 6f373fc9-2314-3c4b-b252-07eb1d5e1f4b
Ancestors: Kernel-ct.1556, Kernel-ct.1442, Kernel-ct.1410, Kernel-ct.1385
Merge commit.
Kernel-ct.1410:
Makes IllegalResumeAttempt an error.
Revision: Makes IllegalResumeAttempt resumable. See: http://lists.squeakfoundation.org/pipermail/squeak-dev/2021-May/215520.html
Kernel-ct.1385 & Kernel-ct.1442:
Improves multilingual support in common error messages on Object & others.
=============== Diff against Kernel-ct.1556 ===============
Item was changed:
----- Method: AdditionalMethodState>>copyWith: (in category 'copying') -----
copyWith: aPropertyOrPragma "<Association|Pragma>"
"Answer a copy of the receiver which includes aPropertyOrPragma"
| bs copy |
(Association == aPropertyOrPragma class
or: [Pragma == aPropertyOrPragma class]) ifFalse:
+ [self error: ('{1} instances should hold only Associations or Pragmas.' translated format: {self class name})].
- [self error: self class name, ' instances should hold only Associations or Pragmas.'].
"no need to initialize here; we're copying all inst vars"
copy := self class basicNew: (bs := self basicSize) + 1.
1 to: bs do:
[:i|
copy basicAt: i put: (self basicAt: i) shallowCopy].
copy basicAt: bs + 1 put: aPropertyOrPragma.
1 to: self class instSize do:
[:i| copy instVarAt: i put: (self instVarAt: i)].
^copy!
Item was changed:
+ Error subclass: #IllegalResumeAttempt
- Exception subclass: #IllegalResumeAttempt
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Kernel-Exceptions'!
!IllegalResumeAttempt commentStamp: '<historical>' prior: 0!
This class is private to the EHS implementation. An instance of it is signaled whenever an attempt is made to resume from an exception which answers false to #isResumable.!
Item was removed:
- ----- Method: IllegalResumeAttempt>>defaultAction (in category 'handling') -----
- defaultAction
- "No one has handled this error, but now give them a chance to decide how to debug it. If none handle this either then open debugger (see UnhandedError-defaultAction)"
-
- UnhandledError signalForException: self!
Item was changed:
+ ----- Method: IllegalResumeAttempt>>isResumable (in category 'priv handling') -----
- ----- Method: IllegalResumeAttempt>>isResumable (in category 'handling') -----
isResumable
+
+ ^ true!
-
- ^ false!
Item was removed:
- ----- Method: IllegalResumeAttempt>>readMe (in category 'comment') -----
- readMe
-
- "Never handle this exception!!"!
Item was changed:
----- Method: Object>>assert: (in category 'error handling') -----
assert: aBlock
"Throw an assertion error if aBlock does not evaluates to true."
+ aBlock value ifFalse: [AssertionFailure signal: 'Assertion failed' translated]!
- aBlock value ifFalse: [AssertionFailure signal: 'Assertion failed']!
Item was changed:
----- Method: Object>>backwardCompatibilityOnly: (in category 'error handling') -----
backwardCompatibilityOnly: explanationString
"Warn that the sending method has been deprecated. Methods that are tagt with #backwardCompatibility:
are kept for compatibility."
Deprecation
signalForContext: thisContext sender
+ message: ' (but will be kept for compatibility)' translated
- message: ' (but will be kept for compatibility)'
explanation: explanationString!
Item was changed:
----- Method: Object>>caseError (in category 'error handling') -----
caseError
"Report an error from an in-line or explicit case statement."
+ self error: ('Case not found ({1}), and no otherwise clause' translated format: {self printString})!
- self error: ('Case not found ({1}), and no otherwise clause' format: {self printString})!
Item was changed:
----- Method: Object>>doesNotUnderstand: (in category 'error handling') -----
doesNotUnderstand: aMessage
"Handle the fact that there was an attempt to send the given
message to the receiver but the receiver does not understand
this message (typically sent from the machine when a message
is sent to the receiver and no method is defined for that selector).
Raise the MessageNotUnderstood signal. If it is caught, answer
the result supplied by the exception handler. If it is not caught,
answer the result of resending the message within a guard for
infinite recursion. This allows, for example, the programmer to
implement the method and continue."
"Testing: (3 activeProcess)"
| exception resumeValue |
(exception := MessageNotUnderstood new)
message: aMessage;
receiver: self.
resumeValue := exception signal.
^exception reachedDefaultHandler "i.e. exception was not caught..."
ifTrue:
[[aMessage sentTo: self]
on: MessageNotUnderstood
do: [:ex|
(self == ex receiver
and: [aMessage hasIdenticalContentsAs: ex message]) ifFalse:
[ex pass].
+ self error: 'infinite recursion in doesNotUnderstand:' translated]]
- self error: 'infinite recursion in doesNotUnderstand:']]
ifFalse: [resumeValue]!
Item was changed:
----- Method: Object>>error (in category 'error handling') -----
error
"Throw a generic Error exception."
+ ^self error: 'Error!!' translated.!
- ^self error: 'Error!!'.!
Item was changed:
----- Method: Object>>errorImproperStore (in category 'private') -----
errorImproperStore
"Create an error notification that an improper store was attempted."
+ ^ self error: 'Improper store into indexable object' translated!
- self error: 'Improper store into indexable object'!
Item was changed:
----- Method: Object>>errorNonIntegerIndex (in category 'private') -----
errorNonIntegerIndex
"Create an error notification that an improper object was used as an index."
+ ^ self error: 'Only integers should be used as indices' translated!
- self error: 'only integers should be used as indices'!
Item was changed:
----- Method: Object>>errorSubscriptBounds: (in category 'private') -----
errorSubscriptBounds: index
"Create an error notification that an improper integer was used as an index."
+ ^ self error: ('Subscript is out of bounds: {1}' translated format: {index})!
- self error: 'subscript is out of bounds: ' , index printString!
Item was changed:
----- Method: Object>>instVarNamed: (in category 'system primitives') -----
instVarNamed: aString
"Return the value of the instance variable in me with that name. Slow and unclean, but very useful. "
^ self instVarAt: (self class
instVarIndexFor: aString asString
+ ifAbsent: [self error: 'no such inst var' translated])
- ifAbsent: [self error: 'no such inst var'])
!
Item was changed:
----- Method: Object>>instVarNamed:put: (in category 'system primitives') -----
instVarNamed: aString put: aValue
"Store into the value of the instance variable in me of that name. Slow and unclean, but very useful. "
^self
instVarAt: (self class
instVarIndexFor: aString asString
+ ifAbsent: [self error: 'no such inst var' translated])
- ifAbsent: [self error: 'no such inst var'])
put: aValue
!
Item was changed:
----- Method: Object>>shouldBeImplemented (in category 'error handling') -----
shouldBeImplemented
"Announce that this message should be implemented"
+ ^ NotImplemented signal: ('{1} or a superclass should implement {2}' translated format: {self className. thisContext sender selector})!
- ^ NotImplemented signal: ('{1} or a superclass should implement {2}' format: {self className. thisContext sender selector})!
Item was changed:
----- Method: Object>>shouldNotImplement (in category 'error handling') -----
shouldNotImplement
"Announce that, although the receiver inherits this message, it should
not implement it."
+ NotImplemented signal: ('{1} is not a message appropriate for a {2}' translated format: {thisContext sender selector. self className}).!
- NotImplemented signal: ('{1} is not a message appropriate for a {2}' format: {thisContext sender selector. self className}).!
Item was changed:
----- Method: Object>>subclassResponsibility (in category 'error handling') -----
subclassResponsibility
"This message sets up a framework for the behavior of the class' subclasses.
Announce that the subclass should have implemented this message."
^ SubclassResponsibility
signal: ('My {1} subclass should have overridden {2}'
+ translated format: {self className. thisContext sender selector}).!
- format: {self className. thisContext sender selector}).!
Item was changed:
----- Method: Object>>traitConflict (in category 'error handling') -----
traitConflict
+ self error: 'A class or trait does not properly resolve a conflict between multiple traits it uses.' translated!
- self error: 'A class or trait does not properly resolve a conflict between multiple traits it uses.'!
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-ct.1405.mcz
==================== Summary ====================
Name: Kernel-ct.1405
Author: ct
Time: 15 May 2021, 3:56:24.713389 pm
UUID: 9a92be9b-d778-b54f-b659-713451a2ddb2
Ancestors: Kernel-nice.1402
Counterproposal to Kernel-jar.1404 for fixing VM crashes when resuming from a BlockCannotReturn. Instead of enforcing retrial, repair the context stack if the receiver has ended. There are two reasons for that:
1. Not in all situations, the receiver of #cannotReturn: is actually unable to resume. Consider this example for a disproof:
a := [true ifTrue: [^ 1]. 2].
"Both statements need to be executed separately in a Workspace so that [a outerContext sender] becomes nil!"
a value.
In this situation, it is valid to resume from BlockCannotReturn and currently also possible in the Trunk. Note that BlockCannotReturn even overrides #isResumable to answer true, though the class comment discrecommends resuming it.
2. The pattern proposed by Jaromir reminds me of the current implementation of Object >> #doesNotUnderstand: or Object >> #at:, that is, when the error was resumed, just try it again in the manner of a (potentially) infinite recursion. While the issue with infinite debuggers (which was eventually tripped by exactly this pattern) has been solved some time ago [1], I do not really agree with the pattern in general - it makes it unnecessarily hard for ToolSet implementors to consciously resume from an error instead of retrying it (which we have an extra selector on Exception for).
[1] http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-c…
=============== Diff against Kernel-nice.1402 ===============
Item was added:
+ ----- Method: BlockCannotReturn>>defaultResumeValue (in category 'defaults') -----
+ defaultResumeValue
+
+ ^ self result!
Item was changed:
----- Method: Context>>cannotReturn: (in category 'private-exceptions') -----
cannotReturn: result
+ closureOrNil ifNotNil: [
+ | resumptionValue |
+ resumptionValue := self cannotReturn: result to: self home sender.
+ self pc > self endPC ifTrue: [
+ "This block has ended, continue with sender"
+ thisContext privSender: self sender].
+ ^ resumptionValue].
- closureOrNil ifNotNil: [^ self cannotReturn: result to: self home sender].
Processor debugWithTitle: 'Computation has been terminated!!' translated full: false.!
Christoph Thiede uploaded a new version of Collections to project The Inbox:
http://source.squeak.org/inbox/Collections-ct.1062.mcz
==================== Summary ====================
Name: Collections-ct.1062
Author: ct
Time: 2 March 2024, 6:04:18.090276 pm
UUID: 748d7c5e-d166-e44f-b72e-d444b71a1adc
Ancestors: Collections-mt.1058
Proposal: Adds Collection>>orderedGroupBy:[having:] that maintains the order of the first occurence of each key.
Examples - to compare:
((1 to: 20) collect: #asWords) groupBy: #first.
((1 to: 20) collect: #asWords) orderedGroupBy: #first.
Also fixes typos in the comments of groupBy:[having:].
=============== Diff against Collections-mt.1058 ===============
Item was changed:
----- Method: Collection>>groupBy: (in category 'enumerating') -----
groupBy: keyBlock
+ "Like in SQL operation - Split the receivers contents into collections of elements for which keyBlock returns the same results, and return them."
- "Like in SQL operation - Split the recievers contents into collections of elements for which keyBlock returns the same results, and return them."
| result |
result := Dictionary new.
self do: [ :each |
| key |
key := keyBlock value: each.
(result at: key ifAbsentPut: [ OrderedCollection new ])
add: each ].
^result!
Item was changed:
----- Method: Collection>>groupBy:having: (in category 'enumerating') -----
groupBy: keyBlock having: selectBlock
+ "Like in SQL operation - Split the receivers contents into collections of elements for which keyBlock returns the same results, and return those collections allowed by selectBlock."
- "Like in SQL operation - Split the recievers contents into collections of elements for which keyBlock returns the same results, and return those collections allowed by selectBlock."
^(self groupBy: keyBlock) select: selectBlock!
Item was added:
+ ----- Method: Collection>>orderedGroupBy: (in category 'enumerating') -----
+ orderedGroupBy: keyBlock
+ "Like in SQL operation - Split the receivers contents into collections of elements for which keyBlock returns the same results, and return them, maintaining the order of the first occurence of each key."
+
+ | result |
+ result := OrderedDictionary new.
+ self do: [ :each |
+ | key |
+ key := keyBlock value: each.
+ (result at: key ifAbsentPut: [ OrderedCollection new ])
+ add: each ].
+ ^result!
Item was added:
+ ----- Method: Collection>>orderedGroupBy:having: (in category 'enumerating') -----
+ orderedGroupBy: keyBlock having: selectBlock
+ "Like in SQL operation - Split the receivers contents into collections of elements for which keyBlock returns the same results, and return those collections allowed by selectBlock, maintaining the order of the first occurence of each key.."
+
+ ^(self orderedGroupBy: keyBlock) select: selectBlock!
Christoph Thiede uploaded a new version of Regex-Core to project The Inbox:
http://source.squeak.org/inbox/Regex-Core-ct.88.mcz
==================== Summary ====================
Name: Regex-Core-ct.88
Author: ct
Time: 2 March 2024, 5:54:50.709512 pm
UUID: 9dc8a041-9d03-994f-8c9b-4cdb24b5a303
Ancestors: Regex-Core-ct.87
Proposal: Optionally pass matcher to matchBlock in match enumerators.
E.g., this allows:
'Squeak! Is! Great!' copyWithRegex: '(\w+)\p{P}' matchesTranslatedUsing: [:match :matcher | matcher subexpression: 2]
Instead of:
| matcher |
matcher := '(\w+)\p{P}' asRegex.
'Squeak! Is! Great!' copyWithRegex: matcher matchesTranslatedUsing: [:match | matcher subexpression: 2]
=============== Diff against Regex-Core-ct.87 ===============
Item was changed:
----- Method: RxMatcher>>copyStream:to:translatingMatchesUsing: (in category 'match enumeration') -----
copyStream: aStream to: writeStream translatingMatchesUsing: aBlock
"Copy the contents of <aStream> on the <writeStream>, except for the matches. For each match, evaluate <aBlock> passing the matched substring as the argument. Expect the block to answer a String, and write the answer to <writeStream> in place of the match."
| searchStart matchStart matchEnd match |
stream := aStream.
firstTryMatch := true.
[searchStart := aStream position.
self proceedSearchingStream: aStream] whileTrue:
[matchStart := (self subBeginning: 1) first.
matchEnd := (self subEnd: 1) first.
aStream position: searchStart.
searchStart to: matchStart - 1 do:
[:ignoredPos | writeStream nextPut: aStream next].
match := (String new: matchEnd - matchStart + 1) writeStream.
matchStart to: matchEnd - 1 do:
[:ignoredPos | match nextPut: aStream next].
+ writeStream nextPutAll: (aBlock cull: match contents cull: self).
- writeStream nextPutAll: (aBlock value: match contents).
"Be extra careful about successful matches which consume no input.
After those, make sure to advance or finish if already at end."
matchEnd = searchStart ifTrue:
[aStream atEnd
ifTrue: [^self "rest after end of whileTrue: block is a no-op if atEnd"]
ifFalse: [writeStream nextPut: aStream next]]].
aStream position: searchStart.
[aStream atEnd] whileFalse: [writeStream nextPut: aStream next]!
Item was changed:
----- Method: RxMatcher>>matchesIn:collect: (in category 'match enumeration') -----
matchesIn: aString collect: aBlock
"Search aString repeatedly for the matches of the receiver. Evaluate aBlock for each match passing the matched substring as the argument, collect evaluation results in an OrderedCollection, and return in. The following example shows how to use this message to split a string into words."
"'\w+' asRegex matchesIn: 'Now is the Time' collect: [:each | each asLowercase]"
| result |
result := OrderedCollection new.
self
matchesOnStream: aString readStream
+ do: [:match | result add: (aBlock cull: match cull: self)].
- do: [:match | result add: (aBlock value: match)].
^result!
Item was changed:
----- Method: RxMatcher>>matchesOnStream:collect: (in category 'match enumeration') -----
matchesOnStream: aStream collect: aBlock
| result |
result := OrderedCollection new.
self
matchesOnStream: aStream
+ do: [:match | result add: (aBlock cull: match cull: self)].
- do: [:match | result add: (aBlock value: match)].
^result!
Item was changed:
----- Method: RxMatcher>>matchesOnStream:do: (in category 'match enumeration') -----
matchesOnStream: aStream do: aBlock
"Be extra careful about successful matches which consume no input.
After those, make sure to advance or finish if already at end."
| position subexpression |
[
position := aStream position.
self searchStream: aStream
] whileTrue: [
subexpression := self subexpression: 1.
+ aBlock cull: subexpression cull: self.
- aBlock value: subexpression.
subexpression size = 0 ifTrue: [
aStream atEnd
ifTrue: [^self]
ifFalse: [aStream next]]]!