exceptions

David Farber dfarber at numenor.com
Mon Mar 9 22:12:14 UTC 1998


i've coded up an exception mechanism for squeak. it is a port of Bob Hinkle
and Ralph Johnson's exception mechanism for V286. one of the big points of
this setup is that it is supposed to mimic the ParcPlace (and even Tek)
exceptions.

is this useful to anyone from the compatibility standpoint? i don't have
access to a PP environment, so i can't tell for certain that i haven't
introduced some incompatibilty in the translation.

it all *seems* to work, but i haven't hammered on it too hard. i am going to
wait a bit before i throw it up on UIUC; give it a week or two to let the
(inevitable) bugs crawl out.

if you are not already familiar with PP's exception mechanism, i don't know
how useful this will be to you. 'print' the one-liner examples in the
ExceptionCollection class comments to to get a basic idea of what is going
on. i'll put together some better documentation before i put it onto UIUC.

dave

Exceptions.cs
----

Object classPool
    at: 'ErrorSignal'
    ifAbsent: [
        Object classPool at: 'ErrorSignal' put: nil]!

'From Squeak 1.31 of Feb 4, 1998 on 9 March 1998 at 5:21:33 pm'!
Object subclass: #Exception
	instanceVariableNames: 'signal parameter extraString proceedBlock
handlerContext signalContext process '
	classVariableNames: 'EmergencyHandler '
	poolDictionaries: ''
	category: 'Exceptions'!
OrderedCollection variableSubclass: #ExceptionCollection
	instanceVariableNames: ''
	classVariableNames: 'OutOfBoundsError '
	poolDictionaries: ''
	category: 'Exceptions'!
Object subclass: #Signal
	instanceVariableNames: 'parent mayProceed notifierString nameClass
nameMessage '
	classVariableNames: 'GenericSignal NoHandlerSignal ProceedErrorSignal
TimeoutSignal WrongProceedabilitySignal '
	poolDictionaries: ''
	category: 'Exceptions'!

!Object methodsFor: 'as yet unclassified'!
errorSignal
    ^self class errorSignal! !


!Exception methodsFor: 'handling' stamp: 'df 3/7/98 16:04'!
proceed
        "Return nil as the value of the raised signal.  Unwind the stack
        up to that point and resume execution in the context that raised
        the signal."

        ^self proceedWith: nil! !

!Exception methodsFor: 'handling' stamp: 'df 3/9/98 16:34'!
proceedDoing: aBlock
        | answer |
        "Return the value of aBlock as the value of the raised signal.
Unwind the stack
        up to that point and resume execution in the context that raised
        the signal.

        The comment for the PP version says that 'the block is executed in
the handler
        context of the signaller, so (for example) it can raise a different
signal in place
        of the original one.'  I'm not sure exactly what that means, but I
think the code
        below has the effect they're (trying to) describe."

        proceedBlock isNil
                ifTrue: [
                        "If proceedBlock is nil, we're not supposed to
proceed on this
                        Signal, so raise a new error."

                        Signal proceedErrorSignal raiseWith: self]
                ifFalse: [
                        answer := aBlock value.
                        self unwindLaterContextsFrom: handlerContext.
                        proceedBlock value: answer

                        "The next line is how this branch was implemented
originally, but
                        with my implementation it would return *out* of the
signalling context (rather
                        than in to it).  I don't think I've done anything
that would affect this
                        behavior--maybe it was a bug in the original version?"

                        "signalContext returnDoing: aBlock"]! !

!Exception methodsFor: 'handling' stamp: 'df 3/5/98 17:46'!
proceedWith: aValue
        "Return aValue as the value of the raised signal.  Unwind the stack
        up to that point and resume execution in the context that raised
        the signal."

        self proceedDoing: [aValue]! !

!Exception methodsFor: 'handling' stamp: 'df 3/4/98 22:59'!
reject
	"Pass the exception on to the next handler."

	|  |
	self propagatePrivateFrom: handlerContext.! !

!Exception methodsFor: 'handling' stamp: 'df 3/9/98 16:39'!
restart
	"Restart the #handle:do: context."

	self unwindLaterContextsFrom: handlerContext.
	handlerContext restart.
	process := Processor activeProcess.
	[
		"Transcript show: process printString; cr.
		Transcript show: process suspendedContext printString; cr.
		Transcript show: handlerContext printString; cr.
		Transcript show: handlerContext sender printString; cr."

		process popTo: handlerContext.

		"Transcript show: process printString; cr.
		Transcript show: process suspendedContext printString; cr.
		Transcript show: handlerContext sender printString; cr; cr."

		process resume.] fork.

	process suspend.
! !

!Exception methodsFor: 'handling' stamp: 'df 3/9/98 16:07'!
restartDo: aBlock
	"Restart the #handle:do: context, but replace the value of the doBlock
	(ie, second parameter) with aBlock."

	handlerContext tempAt: 2 put: aBlock.
	self restart.
! !

!Exception methodsFor: 'handling' stamp: 'df 3/7/98 16:09'!
return
        "Return nil as the value of the handle:do: message that
        caught this Exception."

        self returnWith: nil! !

!Exception methodsFor: 'handling' stamp: 'df 3/9/98 16:40'!
returnDoing: aBlock
	"The stack is unwound to he context of the handle:do
	message that caught this Exception, at which point
	aBlock is evaluated and its value returned as the
	value of the handle:do: message."

	| answer |

	answer := aBlock value.
	self unwindLaterContextsFrom: handlerContext.
	(handlerContext at: 3) value: answer.! !

!Exception methodsFor: 'handling' stamp: 'df 3/5/98 17:10'!
returnWith: aValue
        "Return aValue as the value of the handle:do: message that
        caught this Exception."

        self returnDoing: [aValue].
! !

!Exception methodsFor: 'public' stamp: 'df 3/7/98 16:02'!
defaultHandlerAction: parm
        "Choose the default handler response."

        ^self returnWith: parm! !

!Exception methodsFor: 'public' stamp: 'df 3/7/98 16:03'!
errorString
        "Return the error string for this Exception, which is generated
        by its Signal."

        ^signal errorStringExtra: extraString with: parameter! !

!Exception methodsFor: 'public' stamp: 'df 3/5/98 16:24'!
fetchHandlerBlock: startContext
	"Find the context of the exception handler block"

	| aContext |
	aContext := startContext.
	
	[aContext notNil]
		whileTrue:
			[(aContext selector == #handle:do:)
				ifTrue:
					[handlerContext := aContext.
					^aContext tempAt: 1].
			aContext := aContext sender].
	^nil! !

!Exception methodsFor: 'public' stamp: 'df 3/7/98 16:04'!
parameter
        ^parameter! !

!Exception methodsFor: 'public' stamp: 'df 3/5/98 17:03'!
propagateFrom: startContext
        "Starting below startContext, look down the call stack to find a
handler for this
        Exception, and execute the handler once you've found it.

        In the original Tek version this would have been an infinite loop,
allowing handlers
        to pass on control to others without explicitly doing a reject.  In
PP, though, any
        handler that doesn't take a positive action is assumed to take a
default action,
        which at this point is a #returnWith:."

        signalContext := startContext.

        ^self propagatePrivateFrom: startContext! !

!Exception methodsFor: 'public' stamp: 'df 3/7/98 16:10'!
signal
        "This is the signal whose raising created this exception."

        ^signal! !

!Exception methodsFor: 'public' stamp: 'df 3/5/98 17:48'!
signal: sig parameter: par extraString: str proceedBlock: pb
        "Initialize the Exception's instance variables.
        sig is the Signal whose raising created this Exception.
        par and str are used to generate this Exception's error string.
        pb is either a block used to proceed or nil, indicating that
        proceeding isn't allowed."

        signal := sig.
        parameter := par.
        extraString := str.
        proceedBlock := pb! !

!Exception methodsFor: 'public' stamp: 'df 3/9/98 16:43'!
unwindLaterContextsFrom: exContext
	""

	| aContext | 
	aContext := signalContext.
	
	[aContext == exContext]
		whileFalse:
			[(aContext selector == #valueOnUnwindDo:)
				ifTrue:
					[(aContext tempAt:1 ) value]
				ifFalse:
					[(aContext selector == #valueNowOrOnUnwindDo:)
						ifTrue: [(aContext tempAt:1 ) value]].
			aContext := aContext sender].
	^nil! !

!Exception methodsFor: 'private' stamp: 'df 3/7/98 16:03'!
handlerContext
        "Return the context of the #handle:do: message that will
        handle this Exception."

        ^handlerContext! !

!Exception methodsFor: 'private' stamp: 'df 3/7/98 16:04'!
initialContext
        "Return the context passed into this Exception via the #propagateFrom:
        message.  This is the context where signal was first raised."

        ^signalContext! !

!Exception methodsFor: 'private' stamp: 'df 3/5/98 17:09'!
propagatePrivateFrom: startContext
        "Starting below startContext, look down the call stack to find a
handler for this
        Exception, and execute the handler once you've found it.  This is
called from
        #propagateFrom: and also after a #reject."

        | result handlerBlock unhandledExc |

        handlerBlock := self fetchHandlerBlock: startContext.

        handlerBlock isNil
                ifFalse: [result := handlerBlock value: self]
                ifTrue: [(Signal noHandlerSignal accepts: signal)
                        ifTrue: [
                                "This exception represents an unhandled
exception already.  It must
                                have been rejected to get down the call
stack below Signal>>noHandlerSignal,
                                so just use the EmergencyHandler--that's
what it's there for.  For an
                                unhandled exception, parameter should be the
exception that couldn't be
                                handled originally."

                                ^EmergencyHandler value: parameter value:
parameter initialContext]
                        ifFalse: [
                                "There's no handler for this exception, so
raise an unhandled-exception exception.
                                Note that we pass self as the parameter to
the new exception, which is why we
                                knew what the value of parameter would be in
the comment above."

                                unhandledExc := self class new
                                        signal: Signal noHandlerSignal
                                        parameter: self
                                        extraString: nil
                                        proceedBlock: nil.
                                (handlerBlock := unhandledExc
fetchHandlerBlock: signalContext) isNil
                                        ifTrue: [
                                                "We got trouble!!!!  Use the
EmergencyHandler again, and tell someone
                                                to get an
unhandled-exception handler together."

                                                ^EmergencyHandler value:
self value: signalContext]
                                        ifFalse: [result := handlerBlock
value: unhandledExc]]].

        "If we get here, the selected handler didn't choose a specific
        option between proceeding, returning, and rejecting, so choose
        the default response."

        ^self defaultHandlerAction: result! !

!Exception methodsFor: 'private' stamp: 'df 3/7/98 16:10'!
willProceed
        "This exception can proceed if proceedBlock isn't nil; otherwise
        proceeding isn't allowed."

        ^proceedBlock notNil! !


!ExceptionCollection commentStamp: 'df 3/9/98 17:21' prior: 0!
Examples:

({1. 2. 3. 4. 5} as: ExceptionCollection) getFifthElement
({1. 2. 3. 4} as: ExceptionCollection) getFifthElement
({1. 2. 3. 4} as: ExceptionCollection) getDoubledFifthElement
({1. 2. 3. 4} as: ExceptionCollection) getForcedFifthElement
!

!ExceptionCollection methodsFor: 'as yet unclassified' stamp: 'df 3/5/98 17:41'!
at: anIndex
	""

	(self size < anIndex)
		ifTrue: [^OutOfBoundsError raise]
		ifFalse: [^super at: anIndex].! !

!ExceptionCollection methodsFor: 'as yet unclassified' stamp: 'df 3/7/98 17:35'!
doubledAt: anIndex
	""

	| value |

	value := (self size < anIndex)
		ifTrue: [OutOfBoundsError raiseRequest]
		ifFalse: [super at: anIndex].
	^value * 2
! !

!ExceptionCollection methodsFor: 'as yet unclassified' stamp: 'df 3/7/98 17:36'!
getDoubledFifthElement

	^OutOfBoundsError
		handle: [:exception | exception proceedWith: 5]
		do: [self doubledAt: 5]
! !

!ExceptionCollection methodsFor: 'as yet unclassified' stamp: 'df 3/7/98 15:45'!
getFifthElement

	^OutOfBoundsError
		handle: [:exception | exception returnWith: 'Bob']
		do: [self at: 5]
! !

!ExceptionCollection methodsFor: 'as yet unclassified' stamp: 'df 3/9/98 09:41'!
getForcedFifthElement

	^OutOfBoundsError
		handle:
			[:exception |
			self add: 'Bob'.
			exception restart]
		do: [self at: 5]
! !


!Object class methodsFor: 'as yet unclassified'!
errorSignal
    ^ErrorSignal! !


!Exception class methodsFor: 'as yet unclassified' stamp: 'df 3/7/98 16:01'!
emergency: exception from: context
        "Define a default emergency handler.
        This one is appropriate for development
        environments, but not for runtime."

        self halt! !

!Exception class methodsFor: 'as yet unclassified' stamp: 'df 3/7/98 16:01'!
emergencyHandler: aBlock
        "Define an emergency handler
        for unhandled exceptions."
        EmergencyHandler := aBlock! !

!Exception class methodsFor: 'as yet unclassified' stamp: 'df 3/7/98 16:02'!
initialize
        "Install the emergency handler"
        "Exception initialize"

        self emergencyHandler: [:exception :context | self emergency:
exception from: context]! !


!ExceptionCollection class methodsFor: 'as yet unclassified' stamp: 'df
3/5/98 17:37'!
initialize
	"comment stating purpose of message"

	|  |
	OutOfBoundsError := Signal genericSignal newSignal.! !


!Signal methodsFor: 'public-creation' stamp: 'df 3/5/98 17:35'!
newSignal
        "Create a new signal, whose parent is self and whose proceedability
        is false.

        Note that basicNew has to be used below, since Signal>>new
        creates a signal whose parent is Object>>errorSignal."

        ^self class basicNew parent: self! !

!Signal methodsFor: 'public-creation' stamp: 'df 3/5/98 17:22'!
newSignalMayProceed: proceedBoolean
        "Create a new signal, whose parent is self and whose proceedability
        is equal to proceedBoolean.

        Note that basicNew has to be used below, since Signal>>new
        creates a signal whose parent is Object>>errorSignal."

        ^self class basicNew parent: self mayProceed: proceedBoolean! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 19:39'!
accepts: aSignal
        "Answer true if a handler for this Signal should be run
        to handle aSignal.   A Signal will handle any exception
        raised on itself *or* on one of its children, so accept
        if self == aSignal, or if aSignal equals one of this Signal's
        children."

        | p |
        ^aSignal == self or:
                [(p := aSignal parent) notNil and: [self accepts: p]]! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 19:39'!
deepCopy
        "According to the PP implementation, deepCopying a Signal
        'doesn't make any sense.'  I'm not sure why, so I'll allow
        deepCopying for now."

        "^super deepCopyError"

        ^super deepCopy! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 19:40'!
errorString
        "Build the error string from notifierString.  Prepend my parent's
        errorString if notifierString starts with a blank."

        ^notifierString isNil
                ifTrue: [parent errorString]
                ifFalse: [(notifierString isEmpty not and: [
                                notifierString first = Character space])
                        ifTrue: [parent errorString, notifierString]
                        ifFalse: [notifierString]]! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 19:40'!
errorStringExtra: aString
        "Build the error string from aString.  Prepend my
        errorString if aString starts with a blank."

        ^aString isNil
                ifTrue: [self errorString]
                ifFalse: [(aString isEmpty not and:
                                [aString first = Character space])
                        ifTrue: [self errorString, aString]
                        ifFalse: [aString]]! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 19:42'!
errorStringExtra: aString with: parameter
        "Build the error string from aString.  Append parameter's
        printString if my error string ends with a blank.

        They didn't have the check for isEmpty not in the PP version,
        but it seems necessary to me."

        | errorString |
        errorString := self errorStringExtra: aString.
        ^(errorString isEmpty not and:
                        [errorString last = Character space])
                ifTrue: [errorString, parameter printString]
                ifFalse: [errorString]! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/8/98 21:46'!
handle: handlerBlock do: doBlock
	"Evaluate doBlock. If all goes well, return its value.
	If an exception occurs than the returned value could
	be generated by evaluating returnBlock."

	| returnBlock |
	thisContext push: nil.
	thisContext pop.
	returnBlock := [:value | ^value].

	^doBlock value! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 19:42'!
isClassSignal
        "Return true if this Signal belongs to a class, which means
        that it's stored in one of nameClass' class variables and
        returned (statically) via the method nameMessage.

        In the PP version they test whether this method returnsStaticVariable;
        for Tek the closest equivalent seems to be isReturnField.  For
        Digitalk, I just check that nameClass supports nameMessage and
        that the return from sending nameMessage is this signal."

        | assoc |
        ^nameClass notNil and:
                [(nameClass class includesSelector: nameMessage) and:
                        [(nameClass perform: nameMessage) == self]]! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 17:39'!
mayProceed
        "Answer true if execution can proceed from this signal's context."

        ^mayProceed! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 17:22'!
nameClass: aClass message: aSymbol
        "nameClass and nameMessage are used in printOn:."

        nameClass := aClass.
        nameMessage := aSymbol! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 17:33'!
newException
        "Create a new Exception object.
        Provided as a method for over-riding."

        ^Exception new! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 17:23'!
notifierString: aString
        "notifierString is used to generate this Signal's error string, and
        for printOn:.

        If aString starts with a blank, this Signal will build its error
        string by appending aString to this Signal's parent's error string."

        notifierString := aString! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 19:43'!
parent
        ^parent! !

!Signal methodsFor: 'public-misc' stamp: 'df 3/5/98 19:44'!
printOn: aStream
        self isClassSignal
                ifTrue: [aStream nextPutAll: nameClass printString, ' ',
                        nameMessage]
                ifFalse: [super printOn: aStream.
                        notifierString isNil
                                ifTrue: [aStream nextPutAll: ' with parent: '.
                                        parent printOn: aStream]
                                ifFalse: [aStream nextPutAll: ' with
notifierString: '.
                                        notifierString printOn: aStream]]! !

!Signal methodsFor: 'public-raises' stamp: 'df 3/5/98 19:41'!
raise
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender.
        The Exception may not proceed back into this signaller."

        ^self
                raiseWith: nil
                startAbove: thisContext
                extraString: nil
                proceed: false! !

!Signal methodsFor: 'public-raises' stamp: 'df 3/5/98 19:46'!
raiseErrorString: aString
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender.
        Pass aString to the Exception for its error message.
        The Exception may not proceed back into this signaller."

        ^self
                raiseWith: nil
                startAbove: thisContext
                extraString: aString
                proceed: false! !

!Signal methodsFor: 'public-raises' stamp: 'df 3/7/98 17:09'!
raiseReturn
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender's home's
sender.
        The Exception may not proceed back into this signaller."

        ^self
                raiseReturnWith: nil
                startAbove: thisContext
                extraString: nil
                proceed: false! !

!Signal methodsFor: 'public-raises' stamp: 'df 3/7/98 17:09'!
raiseReturnErrorString: aString
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender's home's
sender.
        Pass aString to the Exception for its error message.
        The Exception may not proceed back into this signaller."

        ^self
                raiseReturnWith: nil
                startAbove: thisContext
                extraString: aString
                proceed: false! !

!Signal methodsFor: 'public-raises' stamp: 'df 3/7/98 17:09'!
raiseReturnWith: parameter
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender's home's
sender.
        Pass parameter to the Exception to use as its parameter.
        The Exception may not proceed back into this signaller."

        ^self
                raiseReturnWith: parameter
                startAbove: thisContext
                extraString: nil
                proceed: false! !

!Signal methodsFor: 'public-raises' stamp: 'df 3/7/98 17:09'!
raiseReturnWith: parameter errorString: aString
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender's home's
sender.
        Pass parameter to the Exception to use as its parameter.
        Pass aString to the Exception for its error message.
        The Exception may not proceed back into this signaller."

        ^self
                raiseReturnWith: parameter
                startAbove: thisContext
                extraString: aString
                proceed: false! !

!Signal methodsFor: 'public-raises' stamp: 'df 3/7/98 17:09'!
raiseWith: parameter
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender.
        Pass parameter to the Exception to use as its parameter.
        The Exception may not proceed back into this signaller."

        ^self
                raiseWith: parameter
                startAbove: thisContext
                extraString: nil
                proceed: false! !

!Signal methodsFor: 'public-raises' stamp: 'df 3/7/98 17:09'!
raiseWith: parameter errorString: aString
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender.
        Pass parameter to the Exception to use as its parameter.
        Pass aString to the Exception for its error message.
        The Exception may not proceed back into this signaller."

        ^self
                raiseWith: parameter
                startAbove: thisContext
                extraString: aString
                proceed: false! !

!Signal methodsFor: 'public-raise requests' stamp: 'df 3/5/98 19:46'!
raiseRequest
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender.
        The Exception may proceed back into this signaller."

        ^self
                raiseWith: nil
                startAbove: thisContext
                extraString: nil
                proceed: true! !

!Signal methodsFor: 'public-raise requests' stamp: 'df 3/5/98 19:46'!
raiseRequestErrorString: aString
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender.
        Pass aString to the Exception for its error message.
        The Exception may proceed back into this signaller."

        ^self
                raiseWith: nil
                startAbove: thisContext
                extraString: aString
                proceed: true! !

!Signal methodsFor: 'public-raise requests' stamp: 'df 3/5/98 19:45'!
raiseRequestReturn
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender's home's
sender.
        The Exception may proceed back into this signaller."

        ^self
                raiseReturnWith: nil
                startAbove: self thisContext
                extraString: nil
                proceed: true! !

!Signal methodsFor: 'public-raise requests' stamp: 'df 3/5/98 19:47'!
raiseRequestReturnErrorString: aString
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender's home's
sender.
        Pass aString to the Exception for its error message.
        The Exception may proceed back into this signaller."

        ^self
                raiseReturnWith: nil
                startAbove: self thisContext
                extraString: aString
                proceed: true! !

!Signal methodsFor: 'public-raise requests' stamp: 'df 3/5/98 19:47'!
raiseRequestReturnWith: parameter
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender's home's
sender.
        Pass parameter to the Exception to use as its parameter.
        The Exception may proceed back into this signaller."

        ^self
                raiseReturnWith: parameter
                startAbove: self thisContext
                extraString: nil
                proceed: true! !

!Signal methodsFor: 'public-raise requests' stamp: 'df 3/5/98 19:48'!
raiseRequestReturnWith: parameter errorString: aString
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender's home's
sender.
        Pass parameter to the Exception to use as its parameter.
        Pass aString to the Exception for its error message.
        The Exception may proceed back into this signaller."

        ^self
                raiseReturnWith: parameter
                startAbove: self thisContext
                extraString: aString
                proceed: true! !

!Signal methodsFor: 'public-raise requests' stamp: 'df 3/5/98 19:48'!
raiseRequestWith: parameter
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender.
        Pass parameter to the Exception to use as its parameter.
        The Exception may proceed back into this signaller."

        ^self
                raiseWith: parameter
                startAbove: self thisContext
                extraString: nil
                proceed: true! !

!Signal methodsFor: 'public-raise requests' stamp: 'df 3/7/98 17:08'!
raiseRequestWith: parameter errorString: string
        "Create an Exception on the receiver and search for a handler.
        Search for a handler starting at self thisContext's sender.
        Pass parameter to the Exception to use as its parameter.
        The Exception may proceed back into this signaller."

        ^self
                raiseWith: parameter
                startAbove: self thisContext
                extraString: string
                proceed: true! !

!Signal methodsFor: 'private' stamp: 'df 3/5/98 17:39'!
parent: aSignal
        "Set this Signal's parent to aSignal.  This may only be done once.
        If this Signal is raised, it can be handled by any handler for it *or*
        one of its ancestors."

        self parent: aSignal mayProceed: aSignal mayProceed! !

!Signal methodsFor: 'private' stamp: 'df 3/5/98 17:23'!
parent: aSignal mayProceed: aBoolean
        "Set this Signal's parent to aSignal.  This may only be done once.
        If this Signal is raised, it can be handled by any handler for it
*or*          one of its ancestors."

        parent notNil
                ifTrue: [self error: 'Tried to reset a Signal''s parent.'.
                        ^self].
        parent := aSignal.
        mayProceed := aBoolean! !

!Signal methodsFor: 'private' stamp: 'df 3/5/98 19:50'!
raiseReturnWith: parameter startAbove: context extraString: str proceed:
aBoolean
        "Create an exception on the receiver.   Start looking for a
        handler in the sender of context's sender's home.  Ie, if context
        is a BlockContext, start looking for a handler in the sender of
        the method that defines the block executing in context."

        "In the PP version, they checked to see whether
                context sender home == nil.
        This could happen if the block was optimized.  Check whether
        this is possible in Tektronix-land."

        ^self
                raiseWith: parameter
                startingAt:  context sender home sender
                extraString: str
                proceed: aBoolean! !

!Signal methodsFor: 'private' stamp: 'df 3/4/98 23:27'!
raiseWith: parameter startAbove: context extraString: str proceed: aBoolean
        "Create an exception on the receiver.   Start looking for a
        handler in the sender of context."

        ^self
                raiseWith: parameter
                startingAt: context sender
                extraString: str
                proceed: aBoolean! !

!Signal methodsFor: 'private' stamp: 'df 3/4/98 22:15'!
raiseWith: parameter startingAt: context extraString: str proceed: aBoolean
	"Create a new exception and have it look for handlers starting at <context>"

	| exception |
	exception := self newException
					signal: self
					parameter: parameter
					extraString: str
					proceedBlock:
						(aBoolean
							ifTrue: [[:value | ^value]]
							ifFalse: [nil]).
	^exception propagateFrom: context! !


!Signal class methodsFor: 'as yet unclassified' stamp: 'df 3/5/98 17:19'!
genericSignal
        ^GenericSignal! !

!Signal class methodsFor: 'as yet unclassified' stamp: 'df 3/5/98 19:36'!
initialize
        "Initialize the Signals provided through this class' instance
        variables.

        Signal initialize"

        | signal |

        "Create the generic Signal."
        signal := self basicNew
                notifierString: 'An unknown Signal with: ';
                nameClass: self message: #genericSignal.
        signal parent: nil mayProceed: true.
        GenericSignal isNil
                ifTrue: [GenericSignal := signal]
                ifFalse: [GenericSignal become: signal].

        "Create the Signal to handle unhandled exceptions."
        NoHandlerSignal := GenericSignal newSignal
                notifierString: 'No handler was found for an Exception: ';
                nameClass: self message: #noHandlerSignal.

        "The next Signals will inherit from Object>>errorSignal."
        signal := Object errorSignal.

        "The PP version doesn't have this, but it's not clear to me where
        Object>>errorSignal ever gets initialized!!!!"
        signal isNil ifTrue: [
                ErrorSignal := GenericSignal newSignal
                        notifierString: 'Error - ';
                        nameClass: Object message: #errorSignal.
                        signal := ErrorSignal].

        "Create the Signal to handle a proceed in an Exception that can't
proceed."
        ProceedErrorSignal := signal newSignal
                notifierString: 'A handler tried to proceed from a
non-proceedable Exception: ';
                nameClass: self message: #proceedErrorSignal.

        "Create the Signal to handle mismatched proceedability."
        WrongProceedabilitySignal := signal newSignal
                notifierString: 'The raiser and the Signal do not agree
about proceedability: ';
                nameClass: self message: #wrongProceedabilitySignal.

        "Create the Signal to handle time-out errors."
        TimeoutSignal := signal newSignal
                notifierString: 'Timeout: ';
                nameClass: self message: #timeoutSignal.! !

!Signal class methodsFor: 'as yet unclassified' stamp: 'df 3/5/98 19:36'!
new
        "Return a new signal whose parent is Object>>errorSignal.

        If you want a signal with some other parent, use
        Signal class>>basicNew and Signal>>parent:."

        ^Object errorSignal newSignal! !

!Signal class methodsFor: 'as yet unclassified' stamp: 'df 3/5/98 19:37'!
noHandlerSignal
        "This Signal catches unhandled exceptions."

        ^NoHandlerSignal! !

!Signal class methodsFor: 'as yet unclassified' stamp: 'df 3/5/98 19:37'!
proceedErrorSignal
        "This signal catches the event that a handler tries to
        proceed through a non-proceedable exception."

        ^ProceedErrorSignal! !

!Signal class methodsFor: 'as yet unclassified' stamp: 'df 3/5/98 19:37'!
timeoutSignal
        "This Signal catches timeouts."

        ^TimeoutSignal! !

!Signal class methodsFor: 'as yet unclassified' stamp: 'df 3/5/98 19:38'!
wrongProceedabilitySignal
        "This signal catches the event when a non-proceedable signal
        is raised via one of the Signal>>raiseRequest* messages."

        ^WrongProceedabilitySignal! !


Exception initialize!
Signal initialize!
ExceptionCollection initialize!

--



--
        j. david farber
    oo architect+mentor
numenor labs incorporated
in sunny boulder colorado
    dfarber at numenor.com
        www.numenor.com





More information about the Squeak-dev mailing list