cowan@marob.masa.com (John Cowan) (07/27/90)
"
Purpose of GENERATR.ST:
Icon-style generators. A Generator is essentially a
resumable subroutine. The implementation here uses a
Process to support the generator and a pair of Semaphores
to enforce synchronous call and return.
"
Object subclass: #Generator
instanceVariableNames:
'value process callSemaphore returnSemaphore safe failed '
classVariableNames: ''
poolDictionaries: '' !
!Generator class methods !
from: aTwoArgumentBlock
"Answer a new instance of Generator which runs the
code in aTwoArgumentBlock. The first argument
will be the Generator, and the second argument will
be the object passed by the value: method."
^super new initialize: aTwoArgumentBlock! !
!Generator methods !
all
"Answer an OrderedCollection containing all of the
results returned by the receiver."
| answer |
answer := OrderedCollection new.
self do: [:object | answer add: object].
^answer!
do: aBlock
"Invoke the receiver repeatedly, and evaluate aBlock
for each result returned, passing the result to aBlock."
| result |
[result := self value.
self hasReturned] whileFalse:
[aBlock value: result].!
fail
"Terminate the receiver, returning nil to the caller
and setting the failure flag."
failed := true.
self return.!
hasFailed
"Answer true if receiver has failed."
^failed!
hasReturned
"Answer true if receiver has returned."
^process isNil!
initialize: aTwoArgumentBlock
"Private - Initialize instance variables."
callSemaphore := Semaphore new.
failed := false.
returnSemaphore := Semaphore new.
value := nil.
Processor fork:
[process := CurrentProcess.
self wait.
aTwoArgumentBlock value: self value: value.
self fail.]!
mustBeSafe
"Private - Signal an error if receiver is not safe."
safe ifFalse:
[^self error: 'Cannot call a running or failed generator']!
mustBeSelfProcess
"Private - Signal an error if current process is not the
generator process."
CurrentProcess == process ifFalse:
[^self error: 'Cannot invoke generator from outside generator process']!
passBack: anObject
"Private - Pass back anObject to caller and signal him."
self mustBeSelfProcess.
value := anObject.
callSemaphore signal.!
printOn: aStream
"Display the receiver's name to aStream."
aStream nextPutAll: 'Generator:'.
self hash printOn: aStream.!
return
"Terminate the receiver and return nil to the caller."
self return: nil!
return: anObject
"Terminate the receiver and return anObject to the caller."
self passBack: anObject.
self shutdown.!
shutdown
"Private - Terminate receiver's process."
self mustBeSelfProcess.
process := nil.
returnSemaphore := nil.
callSemaphore signal.
Processor schedule.!
suspend
"Suspend the receiver, returning nil to the caller."
^self suspend: nil.!
suspend: anObject
"Suspend the receiver, returning anObject to the caller."
self passBack: anObject.
self wait.
^value!
value
"Invoke or resume the receiver, passing nil."
^self value: nil!
value: anObject
"Invoke or resume the receiver, passing anObject."
self mustBeSafe.
value := anObject.
returnSemaphore signal.
callSemaphore wait.
^value!
wait
"Private - Wait for caller to resume receiver."
self mustBeSelfProcess.
safe := true.
returnSemaphore wait.
safe := false.! !
--
cowan@marob.masa.com (aka ...!hombre!marob!cowan)
e'osai ko sarji la lojban