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