Model subclass: #Building
	instanceVariableNames: ''
	classVariableNames: 'MooseAttributeTypeErrorSignal MooseConnectionError MooseConnectionTypeErrorSignal MooseErrorSignal MooseTypeErrorSignal '
	poolDictionaries: ''
	category: 'BuildingADT'
	keys: ''
	attributes: ''
	relations: ''!



!Building methodsFor: 'slang-io'!

writeSlangAttributesOn: aSlangHandler 
	"Writes slang-representations off all defined non-key-attributes of the 
	receiver 
	on aSlangHandler, e.g. 
	'(attr1 value1) 
	(attr2 value2) 
	... 
	(attrN valueN)'"

	self class allAttributes
		do: 
			[:eachAttribute | 
			| eachValue |
			eachValue := self perform: (eachAttribute asString, 'Local') asSymbol.
			eachValue notNil
				ifTrue: 
					[aSlangHandler openList.
					aSlangHandler writeString: '_' , eachAttribute asString.
					eachValue class knowsAboutSlang
						ifTrue: [eachValue writeSlangOn: aSlangHandler]
						ifFalse: [aSlangHandler writeString: eachValue printString].
					aSlangHandler closeList.
					aSlangHandler newLine]].
	^aSlangHandler!

writeSlangDataOn: aSlangHandler 
	"Writes the slang-representation of the receiver's data on aSlangHandler"

	aSlangHandler openRecord.
	aSlangHandler tabsIncrease; newLine.
	self writeSlangKeysOn: aSlangHandler.
	self writeSlangAttributesOn: aSlangHandler.
	self writeSlangRelationsOn: aSlangHandler.
	aSlangHandler tabsDecrease; newLine.
	aSlangHandler closeRecord.
	aSlangHandler newLine.
	^aSlangHandler!

writeSlangDRefOn: aSlangHandler 
	"Writes a slang-reference of the receiver, wich is marked deleted"

	aSlangHandler openList.
	aSlangHandler writeString: 'KEY'.
	aSlangHandler writeString: _key negated printString.
	aSlangHandler writeString: self class name,'Class'.
	aSlangHandler closeList.
	^self!

writeSlangKeysOn: aSlangHandler 
	"Writes slang-representations off all defined key-attributes of the receiver 
	on aSlangHandler. This will include the unique key of the receiver, e.g. 
	'(KEY <_key>) 
	(key1 value1) 
	(key2 value2) 
	... 
	(keyN valueN)'"

	aSlangHandler openList.
	aSlangHandler writeString: 'KEY'.
	aSlangHandler writeString: _key printString.
	aSlangHandler closeList.
	aSlangHandler newLine.
	self class allKeys
		do: 
			[:eachKey | 
			| eachValue |
			eachValue := self perform: eachKey.
			eachValue isNil
				ifFalse: 
					[aSlangHandler openList.
					aSlangHandler writeString: '_' , eachKey asString.
					eachValue class knowsAboutSlang
						ifTrue: [eachValue writeSlangOn: aSlangHandler]
						ifFalse: [aSlangHandler writeString: eachValue printString].
					aSlangHandler closeList.
					aSlangHandler newLine]].
	^aSlangHandler!

writeSlangRefOn: aSlangHandler 
	"Writes a slang-reference of the receiver"

	aSlangHandler openList.
	aSlangHandler writeString: 'KEY'.
	aSlangHandler writeString: _key printString.
	aSlangHandler writeString: self class name,'Class'.
	aSlangHandler closeList.
	^self!

writeSlangRelationsOn: aSlangHandler 
	"Writes references to all connected objects on aSlangHandler. If the 
	connected object is an instance of a subclass of the expected class, then 
	the name of the class is also noticed. The instance of the relation-object 
	has to write the slang-representation of its connections."

	| relAnz names |
	names := self class allRelations.
	relAnz := names size.
	names 
		do: 
			[:eachRel | 
			| eachRelVal |
			eachRelVal := self perform: (eachRel asString, 'Local') asSymbol.
			eachRelVal isEmpty
				ifFalse: 
					[aSlangHandler openList.
					aSlangHandler writeString: '_' , eachRel asString.
					eachRelVal writeSlangOn: aSlangHandler.
					aSlangHandler closeList.
					relAnz := relAnz - 1.
					relAnz isZero ifFalse: [aSlangHandler newLine]]].
	^aSlangHandler! !


!Building methodsFor: 'printing'!

printOn: aStream 
	"Print the classname and the keyattribute/value-pairs on aStream. e.g. 'an 
	Instance( key1: value1 key2: value2 ... keyN: valueN )'. This replaces the 
	printOn-method of the ST-Library"

	| title keys |
	title := self class name.
	keys := self class allKeys.
	aStream nextPutAll: ((title at: 1) isVowel
			ifTrue: ['an ']
			ifFalse: ['a ']).
	aStream nextPutAll: self class name.
	keys size isZero
		ifTrue: [aStream nextPutAll: '<' , _key printString , '>'; cr]
		ifFalse: 
			[aStream nextPut: $(.
			keys do: [:each | aStream nextPutAll: ' ' , each asString , ': ' , (self perform: each) printString].
			aStream nextPutAll: ' )'; cr].
	^self! !


!Building methodsFor: 'error handling'!

mooseAttributeTypeError: aString 
	"Raise a non-proceedable signal that indicates an error with the argument as the message.
	This additional message is the one a subclass should override in order to
	change the handling of errors.
	Remove any trailing spaces from aString, since we know we don't
	want other strings appended to this one."

	| lastNonSpace |
	lastNonSpace := aString findLast: [:ch | ch ~= Character space].
	^self mooseAttributeTypeErrorSignal raiseErrorString: (aString copyFrom: 1 to: lastNonSpace)!

mooseAttributeTypeErrorSignal
	"Answer the Signal used for type-checking -errors, which occur with 
	attributes. 
	(self attributeTypeError:)."

	^self class mooseAttributeTypeErrorSignal!

mooseConnectionError: aString 
	"Raise a non-proceedable signal that indicates an error with the argument as the message.
	This additional message is the one a subclass should override in order to
	change the handling of errors.
	Remove any trailing spaces from aString, since we know we don't
	want other strings appended to this one."

	| lastNonSpace |
	lastNonSpace := aString findLast: [:ch | ch ~= Character space].
	^self mooseConnectionErrorSignal raiseErrorString: (aString copyFrom: 1 to: lastNonSpace)!

mooseConnectionErrorSignal
	"Answer the Signal used for connection-errors 
	(self mooseConnectionError:)."

	^self class mooseConnectionErrorSignal!

mooseConnectionTypeError: aString 
	"Raise a non-proceedable signal that indicates an error with the argument as the message.
	This additional message is the one a subclass should override in order to
	change the handling of errors.
	Remove any trailing spaces from aString, since we know we don't
	want other strings appended to this one."

	| lastNonSpace |
	lastNonSpace := aString findLast: [:ch | ch ~= Character space].
	^self mooseConnectionTypeErrorSignal raiseErrorString: (aString copyFrom: 1 to: lastNonSpace)!

mooseConnectionTypeErrorSignal
	"Answer the Signal used for connection-type errors 
	(self mooseConnectionTypeError:)."

	^self class mooseConnectionTypeErrorSignal!

mooseError: aString 
	"Raise a non-proceedable signal that indicates an error with the argument as the message.
	This additional message is the one a subclass should override in order to
	change the handling of errors.
	Remove any trailing spaces from aString, since we know we don't
	want other strings appended to this one."

	| lastNonSpace |
	lastNonSpace := aString findLast: [:ch | ch ~= Character space].
	^self mooseErrorSignal raiseErrorString: (aString copyFrom: 1 to: lastNonSpace)!

mooseErrorSignal
	"Answer the Signal used for miscellaneous errors 
	(self mooseError:)."

	^self class mooseErrorSignal!

mooseTypeError: aString 
	"Raise a non-proceedable signal that indicates an error with the argument as the message.
	This additional message is the one a subclass should override in order to
	change the handling of errors.
	Remove any trailing spaces from aString, since we know we don't
	want other strings appended to this one."

	| lastNonSpace |
	lastNonSpace := aString findLast: [:ch | ch ~= Character space].
	^self mooseTypeErrorSignal raiseErrorString: (aString copyFrom: 1 to: lastNonSpace)!

mooseTypeErrorSignal
	"Answer the Signal used for type-checking -errors 
	(self typeError:)."

	^self class mooseTypeErrorSignal! !


!Building methodsFor: 'initialize-release'!

initialize
	"Generated by MPOK 2.8."

	"Do initialization for the receiver, e.g. get a unique key."

	super initialize.
	_key isNil ifTrue:[_key := self class nextKey].
	^self! !

"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

Building class
	instanceVariableNames: ''!



!Building class methodsFor: 'accessing'!

allAttributes
	"Answers an array of all attributes-names for 
	the receiver."

	^self allAttributeVarNames!

allKeys
	"Answers an array of all key-names for 
	the receiver."

	^self allKeyVarNames!

allRelations
	"Answers an array of all relation-names for 
	the receiver."

	^self allRelationVarNames!

myAttributes
	"Answers an array of attributes-names for 
	the receiver."

	^self attributePool keys!

myKeys
	"Answers an array of key-names for 
	the receiver."

	^self keyPool keys!

myRelations
	"Answers an array of relation-names for 
	the receiver."

	^self relationPool keys!

specificationsForRelation: aSymbol
	"Look-up the specifications for the specified relation."

	^self relationPool at: aSymbol ifAbsent:[superclass specificationsForRelation: aSymbol]!

typeForAttribute: aSymbol 
	"Look-up the type for the specified attribute."

	^self attributePool at: aSymbol ifAbsent: [superclass typeForAttribute: aSymbol]!

typeForKey: aSymbol 
	"Look-up the type for the specified key."

	^self keyPool at: aSymbol ifAbsent: [superclass typeForKey: aSymbol]! !


!Building class methodsFor: 'slang-io'!

adtName
	"Answer the name of the adt (used for slang)"

	^'Building'!

calculateAllReferencedObjectsOf: aCollection for: aSet 
	"Ths methods calculates the transitive closure of the elements in 
	aCollections and adds it to aSet."

	aCollection
		do: 
			[:each | 
			| relations |
			aSet add: each.
			relations := each class allRelations.
			relations
				do: 
					[:rel | 
					| connections |
					connections := (each perform: rel).
					connections do: [:object | (aSet includes: object)
							ifFalse: [self calculateAllReferencedObjectsOf: (OrderedCollection with: object)
									for: aSet]]]].
	^aSet!

readSlangFile: aString 
	"This method reads a Slangfile named by aString and answers 
	aDictionary, 
	indexed by th classnames of the read objects, containing all objects 
	of the 
	file. Because the Slangparser is stream-based, this method provides 
	a 
	template"

	| aSet aDictionary aSlangHandler aFile aStream adtName aClass aClassName |
	aDictionary := Dictionary new.
	aFile := UnixFilename named: aString.
	aStream := aFile readStream.
	aSlangHandler := SlangHandler newOn: aStream.
	aSlangHandler open: #read.
	aSlangHandler skipBracket.
	adtName := aSlangHandler readString.
	Transcript cr; show: Date today printString , ' at: ' , Time now printString , ' reading Slangfile ' , aString , ' for ' , adtName; cr.
	aSlangHandler skipBracket.
	[aSlangHandler skipBracket = $(]
		whileTrue: 
			[aClassName := aSlangHandler readClassName.
			aClass := Smalltalk at: aClassName ifAbsent: [nil].
			aClass notNil
				ifTrue: 
					[aSet := aDictionary at: aClass name ifAbsent: [aDictionary at: aClass name put: Set new].
					[aSlangHandler skipBracket = $<]
						whileTrue: [aSet add: (aClass readSlangFrom: aSlangHandler)]]
				ifFalse: [aSlangHandler skipList]].
	aSlangHandler skipBracket.
	aSlangHandler close.
	Transcript cr; show: 'Parser finished. '.
	aSlangHandler makeConnections.
	aSlangHandler printStatistics.
	aStream close.
	^aDictionary!

readSlangFrom: aSlangHandler 
	"Answers an instance of the receiver read from aSlangHandler"

	| keys attributes relations selector key aClass anInstance attrDictionary relDictionary |
	attrDictionary := Dictionary new.
	relDictionary := Dictionary new.
	keys := self allKeys asArray.
	attributes := self allAttributes asArray.
	relations := self allRelations.
	aSlangHandler skipBracket.
	aSlangHandler readString.
	key := SmallInteger readFromString: aSlangHandler readString.
	aSlangHandler skipBracket.
	[aSlangHandler skipBracket = $(]
		whileTrue: 
			[| classDesc ref |
			selector := aSlangHandler readSelector.
			(relations includes: selector)
				ifTrue: 
					[classDesc := self specificationsForRelation: selector.
					ref := true]
				ifFalse: 
					[classDesc := (keys includes: selector)
								ifTrue: [self typeForKey: selector]
								ifFalse: [self typeForAttribute: selector].
					ref := false].
			classDesc isNil
				ifTrue: 
					[aSlangHandler skipList.
					Transcript cr; show: self name asString , ': Skipping list labeled: ' , selector asString]
				ifFalse: 
					[ref
						ifTrue: 
							[aClass := Smalltalk at: (classDesc at: #type).
							relDictionary at: selector put: (aClass readSlangFrom: aSlangHandler)]
						ifFalse: 
							[aClass := Smalltalk at: classDesc.
							attrDictionary at: selector put: (aClass knowsAboutSlang
									ifTrue: [aClass readSlangFrom: aSlangHandler]
									ifFalse: [aClass readFromString: aSlangHandler readString])].
					aSlangHandler skipBracket]].
	anInstance := self new.
	keys , attributes
		do: 
			[:each | 
			| aValue |
			aValue := attrDictionary at: each ifAbsent: [nil].
			aValue isNil ifFalse: [anInstance perform: (each asString , ':') asSymbol with: aValue]].
	aSlangHandler requestConnections: relDictionary for: anInstance.
	aSlangHandler register: anInstance for: key.
	^anInstance!

sortClasses: aSet 
	"This method answers a Dictionary, indexed by the classNames of the sets 
	Elements."

	| aDictionary |
	aDictionary := Dictionary new.
	aSet
		do: 
			[:each | 
			| aCollection className |
			className := each class name.
			aCollection := aDictionary at: className ifAbsent: [aDictionary at: className put: OrderedCollection new].
			aCollection add: each].
	^aDictionary!

writeSlangFile: aString on: aCollection 
	"This methods writes all elements of aCollection an their transitive closure 
	into a file named by aString. Because the slang-output is stream-based, 
	this method provides a template."

	| aSlangHandler aFile aStream classes aSet total |
	Transcript cr; cr; show: Date today printString , ' ' , Time now printString , ' writing Slangfile ' , aString , ' for ' , self adtName.
	aFile := UnixFilename named: aString.
	aStream := aFile writeStream.
	aSlangHandler := SlangHandler newOn: aStream.
	aSlangHandler open: #write.
	aSlangHandler openList.
	aSlangHandler writeString: self adtName.
	aSlangHandler tabsIncrease; newLine.
	aSlangHandler openRecord.
	aSet := self calculateAllReferencedObjectsOf: aCollection for: Set new.
	classes := self sortClasses: aSet.
	total := 0.
	classes keys
		do: 
			[:eachClass | 
			| num |
			num := (classes at: eachClass) size.
			Transcript cr; show: num printString , ' instances of ' , eachClass asString.
			total := total + num.
			aSlangHandler tabsIncrease; newLine.
			aSlangHandler openList.
			aSlangHandler writeString: eachClass asString,'Class'.
			aSlangHandler tabsIncrease; newLine.
			(classes at: eachClass)
				do: [:eachInst | eachInst writeSlangDataOn: aSlangHandler].
			aSlangHandler tabsDecrease.
			aSlangHandler closeList.
			aSlangHandler tabsDecrease].
	aSlangHandler newLine.
	aSlangHandler closeRecord.
	aSlangHandler tabsDecrease; newLine.
	aSlangHandler close.
	aStream close.
	Transcript cr; show: '-----'; cr; show: total printString , ' total'; cr.
	^self! !


!Building class methodsFor: 'Signal constants'!

connectionErrorSignal
	"The parameter for an exception raised by this signal or its children 
	is a MessageSend describing the operation that failed."

	^ConnectionErrorSignal!

mooseAttributeTypeErrorSignal
	"The parameter for an exception raised by this signal or its children 
	is a MessageSend describing the operation that failed."

	^MooseAttributeTypeErrorSignal!

mooseConnectionTypeErrorSignal
	"The parameter for an exception raised by this signal or its children 
	is a MessageSend describing the operation that failed."

	^MooseConnectionTypeErrorSignal!

mooseErrorSignal
	"The parameter for an exception raised by this signal or its children 
	is a MessageSend describing the operation that failed."

	^MooseErrorSignal!

typeErrorSignal
	"The parameter for an exception raised by this signal or its children 
	is a MessageSend describing the operation that failed."

	^TypeErrorSignal! !


!Building class methodsFor: 'class initialization'!

initialize
	"Generated by MPOK 2.8."

	"Do the initialization for the receiver, e.g. initialize the
	error-handling-stuff."
	self name == #Building
		ifTrue: [ self initSignals ].
	^self!

initSignals
	"Do the signal initialization for the receiver."

	| es mes |
	es := Object errorSignal.
	MooseErrorSignal :=  (es := (es newSignalMayProceed: true)
	notifierString: 'Moose error';
		nameClass: self message: #mooseErrorSignal).
	mes := es.
	MooseTypeErrorSignal := (es := (mes newSignal)
		notifierString: 'Type-check failed';
		nameClass: self message: #mooseTypeErrorSignal).
	MooseAttributeTypeErrorSignal := ((es newSignal)
		notifierString: 'Attribute-Type-check failed';
		nameClass: self message: #mooseAttributeTypeErrorSignal).
	MooseConnectionTypeErrorSignal := ((es newSignal)
		notifierString: 'ConnectionType-check failed';
		nameClass: self message: #mooseConnectionTypeErrorSignal).
	MooseConnectionErrorSignal := ((mes newSignal)
		notifierString: '(Dis-) Connection failed';
		nameClass: self message: #mooseConnectionErrorSignal).
	^self! !


!Building class methodsFor: 'instance creation'!

new
	"Generated by MPOK 2.8."

	"Create a new instance of the Receiver. This method implements the
	standard-constructor for Moose-Classes"

	^super new initialize.!

newOn: anInstance
	"Generated by MPOK 2.8."

	"Create a new instance of the Receiver. This method implements the
	copy-constructor for Moose-Classes"

	| newInstance |
	newInstance := super newOn: anInstance.
	newInstance initialize.
	newInstance resetAllConnections.
	^newInstance! !

Building initialize!


To increase readability of this file, some HTML tags have been included

(click here for the original file)