"======================================================================
|
|   Namespace Method Definitions
|
|   $Revision: 1.7.5$
|   $Date: 2000/05/28 16:56:52$
|   $Author: pb$
|
 ======================================================================"


"======================================================================
|
| Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.
| Written by Paolo Bonzini.
|
| This file is part of the GNU Smalltalk class library.
|
| The GNU Smalltalk class library is free software; you can redistribute it
| and/or modify it under the terms of the GNU Lesser General Public License
| as published by the Free Software Foundation; either version 2.1, or (at
| your option) any later version.
| 
| The GNU Smalltalk class library is distributed in the hope that it will be
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
| General Public License for more details.
| 
| You should have received a copy of the GNU Lesser General Public License
| along with the GNU Smalltalk class library; see the file COPYING.LESSER.
| If not, write to the Free Software Foundation, 59 Temple Place - Suite
| 330, Boston, MA 02111-1307, USA.  
|
 ======================================================================"


RootNamespace variableSubclass: #Namespace
	   instanceVariableNames: ''
	   classVariableNames: 'Current'
	   poolDictionaries: ''
	   category: 'Language-Implementation'
!

Namespace comment: 
'I am a special form of dictionary.  I provide special ways to access my
keys, which typically begin with an uppercase letter.  Classes hold on
an instance of me; it is called their `environment'').

My keys are (expected to be) symbols, so I use == to match searched keys
to those in the dictionary -- this is done expecting it brings a bit more
speed.' !


!Namespace class methodsFor: 'disabling instance creation'!

new
    "Disabled - use #addSubspace: to create instances"
    ^self error: 'use #addSubspace: to create instances'
!

new: size
    "Disabled - use #addSubspace: to create instances"
    ^self error: 'use #addSubspace: to create instances'
! !


!Namespace methodsFor: 'accessing'!

inheritedKeys
    "Answer a Set of all the keys in the receiver and its superspaces"
    ^self keys
	removeAll: self definedKeys
	ifAbsent: [ :each | self error: 'huh?!? synchronization problem?!?' ];

	yourself
! !


!Namespace methodsFor: 'overrides for superspaces'!

associationsDo: aBlock
    "Pass each association in the namespace to aBlock"
    self allAssociations associationsDo: aBlock
!

at: key ifPresent: aBlock
    "If aKey is absent from the receiver and all its superspaces,
     answer nil. Else, evaluate aBlock passing the associated value
     and answer the result of the invocation"

    | index space |
    space := self.
    [
	index := space findIndexOrAnswerNil: key.
	index isNil
    ]   whileTrue: [
	space := space superspace.
	space isNil ifTrue: [ ^nil ].
    ].
    ^aBlock value: (space primAt: index) value
!

associationAt: key ifAbsent: aBlock
    "Return the key/value pair associated to the variable named as
    specified by `key'. If the key is not found search will be
    brought on in superspaces, finally evaluating aBlock if the
    variable cannot be found in any of the superspaces."
    | index space |
    space := self.
    [
	index := space findIndexOrAnswerNil: key.
	index isNil
    ]   whileTrue: [
	space := space superspace.
	space isNil ifTrue: [ ^aBlock value ].
    ].
    ^(space primAt: index) value
!

at: key ifAbsent: aBlock
    "Return the value associated to the variable named as specified
    by `key'. If the key is not found search will be brought on in
    superspaces, finally evaluating aBlock if the variable cannot be
    found in any of the superspaces."
    | index space |
    space := self.
    [
	index := space findIndexOrAnswerNil: key.
	index isNil
    ]   whileTrue: [
	space := space superspace.
	space isNil ifTrue: [ ^aBlock value ].
    ].
    ^(space primAt: index) value
!

do: aBlock
    "Pass each value in the namespace to aBlock"
    self allAssociations do: aBlock
!

includesKey: key
    "Answer whether the receiver or any of its superspaces contain
     the given key"
    | index space |
    space := self.
    [
	index := space findIndexOrAnswerNil: key.
	index isNil
    ]   whileTrue: [
	space := space superspace.
	space isNil ifTrue: [ ^false ].
    ].
    ^true
!

keysAndValuesDo: aBlock
    "Pass to aBlock each of the receiver's keys and values, in two
     separate parameters"
    self allAssociations keysAndValuesDo: aBlock
!

keysDo: aBlock
    "Pass to aBlock each of the receiver's keys"
    self keys do: aBlock
!

set: key to: newValue ifAbsent: aBlock
    "Assign newValue to the variable named as specified by `key'.
    This method won't define a new variable; instead if the key
    is not found it will search in superspaces and evaluate
    aBlock if it is not found. Answer newValue."
    | index space |
    space := self.
    [
	index := space findIndexOrAnswerNil: key.
	index isNil
    ]   whileTrue: [
	space := space superspace.
	space isNil ifTrue: [ ^aBlock value ].
    ].
    (space primAt: index) value: newValue.
    ^newValue
!

size
    "Answer the number of keys in the receiver and each of its superspaces"
    ^super size + self superspace size
! !



!Namespace methodsFor: 'namespace hierarchy'!

siblings
    "Answer all the other namespaces that inherit from the receiver's
    superspace."
    ^self superspace subspaces copy
	remove: self;
	yourself
!

siblingsDo: aBlock
    "Evaluate aBlock once for each of the other namespaces that inherit
    from the receiver's superspace, passing the namespace as a parameter."
    self superspace subspaces do: [ :space |
	space == self ifFalse: [ aBlock value: space ]
    ]
! !


!Namespace methodsFor: 'printing'!

name
    "Answer the receiver's name"
    ^(self superspace keyAtValue: self ifAbsent: [ ^self defaultName ]) asString
!

storeOn: aStream
    "Store Smalltalk code compiling to the receiver"
    | result name |
    name := self name.
    name = '<no name>'
	ifTrue: [ self error: 'cannot print unnamed namespace' ].
    
    self superspace storeOn: aStream.
    aStream space; nextPutAll: name
! !
