!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: symboll.gs,v 1.16 2008-01-09 22:50:19 stever Exp $
!
! Superclass Hierarchy:
!   SymbolList, Array, SequenceableCollection, Collection, Object.
!
!=========================================================================

removeallmethods SymbolList
removeallclassmethods SymbolList

! SymbolList disallows gci store, part of fix 31942 .
! This  class modification is done in  bomlastconv.gs , because we
! don't have methods filed in for UserProfile yet at this point of filein.
! run
! SymbolList _disallowGciCreateStore .   
! ^ SymbolList _structuralUpdatesDisallowed
! %

category: 'For Documentation Installation only'
classmethod: SymbolList
installDocumentation

| doc txt |
doc := GsClassDocumentation newForClass: self.

txt := (GsDocText new) details:
'A SymbolList is an Array whose elements are instances of SymbolDictionary.

 It is used in compilation of GemStone Smalltalk code, in order to resolve
 references to objects by name.  Given a Symbol as a name, the SymbolList
 searches its dictionary elements in order, and the first key that matches the
 given Symbol then resolves to the object that is the value at that key in that
 dictionary.

 Constraints on indexable fields are enforced by behavior in this class.' .
doc documentClassWith: txt.

self description: doc.
%

category: 'Accessing'
method: SymbolList
names

"Returns an Array of Strings containing the names of the receiver's
 SymbolDictionaries.

 This method assumes that each SymbolDictionary in the receiver contains a
 SymbolAssociation whose value is that SymbolDictionary.  If any
 SymbolDictionary does not contain such a SymbolAssociation, it is
 represented in the result Array as '(unnamed Dictionary)'."

| result aDict aSymAssoc|
result:= Array new .
1 to: self size do:[:j|
  aDict := self at: j .
  aDict == nil
    ifTrue:[ result add: '(nil)' ]
    ifFalse:[
      aSymAssoc:= aDict associationsDetect:[:anAssoc | anAssoc value == aDict] 
			ifNone:[ nil ].
      aSymAssoc == nil
        ifTrue:[ result add: '(unnamed Dictionary)' ]
        ifFalse:[ result add: (aSymAssoc key)]
      ].
  ].
^ result
%
category: 'Formatting'
method: SymbolList
namesReport

"Returns a formatted String describing the position and name of each Dictionary
 in the receiver's symbol list.

 This method assumes that each Dictionary in the symbol list contains an
 Association whose value is that Dictionary.  If any Dictionary does not
 contain such an Association, it is represented in the result String as
 '(unnamed Dictionary)'."

"used by the topaz list dictionaries command"

| arrayOfNames result lf |

arrayOfNames := self names .
result := String new .
lf := Character lf .
1 to: arrayOfNames size do:[:j|
  result add: (j asString).
  result addAll: '  '.
  result addAll: (arrayOfNames at: j) .
  result add: lf.
  ].
^result
%

category: 'Searching'
method: SymbolList
resolveSymbol: aString

"Searches the receiver for an Association whose key is equal to aString, and
 returns that Association.  If no such Association is found, returns nil."

<primitive: 49>

(aString isKindOf: Symbol) ifFalse:[
  ^ self resolveSymbol: aString asSymbol
  ].
aString _validateClasses: #[String, DoubleByteString].
self _primitiveFailed: #resolveSymbol: .
self _uncontinuableError
%

category: 'Searching'
method: SymbolList
objectNamed: aSymbol

"Returns the first object in the receiver that has the given name.  If no object
 is found with the given name, returns nil."

| assn |

assn := self resolveSymbol: aSymbol.
assn == nil ifTrue: [ ^nil ].
^assn value
%

category: 'Updating'
method: SymbolList
createDictionaryNamed: dictName at: anIndex 

"Creates a new SymbolDictionary in the Segment of the receiver.  Adds to the
 dictionary an Association whose key is dictName and whose value is the
 dictionary.  Inserts the dictionary in the receiver at anIndex.

 If anIndex is less than 1, the dictionary is inserted at the front of the list.
 If anIndex is greater than the size of the list, it is inserted at the end of
 the list.  If the receiver already contains a dictionary named dictName, raises
 an error."

| newDict nameSym offset |

self _validatePrivilege.
nameSym := dictName asSymbol .
self do:[ :aDict | 
  (aDict names includesIdentical: nameSym) ifTrue:[ 
    aDict _error: #rtErrDuplicateKey args: #[ nameSym ].
    ].
  ].
newDict := SymbolDictionary new name: nameSym; yourself .
newDict assignToSegment: self segment .
(newDict associationAt: nameSym) assignToSegment: self segment .
offset := anIndex .
offset < 1 ifTrue:[ offset := 1 ].
offset > self size 
  ifTrue:[ self addLast: newDict ]
  ifFalse:[ self insertObject: newDict at: offset ].
%

category: 'Updating'
method: SymbolList
removeDictionaryNamed: aSymbol 

"Removes the first dictionary found in the receiver that contains an Association
 whose key is aSymbol and whose value is the dictionary.  Returns the removed
 dictionary.

 If no such dictionary is found, raises a KeyNotFound error."

self _validatePrivilege.
^ self removeDictionaryNamed: aSymbol ifAbsent:[ 
    self _error: #rtErrKeyNotFound args: #[ aSymbol ].  
    nil 
    ] 
%

category: 'Updating'
method: SymbolList
replaceElementsFrom: aSymbolList

"Removes all elements in the receiver and inserts all elements of aSymbolList in
 it, in the same order as in aSymbolList.
 
 If the argument is not a SymbolList, raises an error."

| newSize |
self _validatePrivilege: aSymbolList.
aSymbolList == self ifTrue:[ ^ self ].
(aSymbolList isKindOf: SymbolList) ifFalse:[ 
  aSymbolList _validateClass: SymbolList .
  ^ self
  ].
newSize := aSymbolList size.
self size: aSymbolList size .
aSymbolList copyFrom: 1 to: newSize into: self startingAt: 1 .
%

category: 'Updating'
method: SymbolList
removeDictionaryNamed: aSymbol ifAbsent: aBlock 

"Removes the first dictionary found in the receiver that contains an Association
 whose key is aSymbol and whose value is the dictionary.  Returns the removed
 dictionary.

 If no such dictionary is found, returns the result of evaluating the
 zero-argument Block aBlock." 

| nameSym |

self _validatePrivilege.
nameSym := aSymbol asSymbol .
1 to: self size do:[ :j | | aDict |
  aDict := self at: j .
  (aDict names includesIdentical: nameSym) ifTrue:[ 
    self deleteObjectAt: j .
    ^ aDict .
    ].
  ].
^ aBlock value
%

category: 'Searching'
method: SymbolList
symbolResolutionOf: aString

"Searches the receiver for aString.  If aString is found, returns a formatted
 String that describes the position in the receiver of the Dictionary defining
 aString, the name of that Dictionary, and aString.

 Generates an error if aString is not defined in the receiver."

"Example: GsSession currentSession symbolList symbolResolutionOf: #Integer"

| lf result theAssoc aDict aSymbol |

aSymbol := Symbol _existingWithAll: aString.
aSymbol == nil ifTrue:[ self _error: #rtErrSymNotFound args: #[aString] ].

result := String new.
lf := Character lf.
1 to: self size do:[ :j|
  aDict := self at: j .
  aDict == nil ifFalse:[
    (aDict at: aSymbol ifAbsent: [ nil ]) ~~ nil ifTrue:[
      " found aSymbol in this dict "
      result add: lf; add: (j asString); addAll: '  '.
      theAssoc:= aDict associationsDetect: [:anAssoc | anAssoc value == aDict]
                               ifNone: [ nil ] .
      theAssoc == nil
        ifTrue:[ result add: '(Unnamed Dictionary)']
        ifFalse: [ result add: theAssoc key ].
      result add: lf; addAll: '      '; addAll: aSymbol;
                 addAll: '  '; add: ((aDict at: aSymbol) asString).
      ^ result 
      ].
    ].
  ].
^ self _error: #rtErrSymNotFound args: #[ aString ]
%

category: 'Repository Conversion'
method: SymbolList
convertContentsTo5

"Private."

1 to: self size do: [ :i |
  self at: i put: ((self at: i) convertTo5)
  ] .
self convertNativeLanguage
%

category: 'Repository Conversion'
method: SymbolList
convertNativeLanguage

""

| ugAssoc ug langSym |
ugAssoc := self resolveSymbol: #UserGlobals .
ugAssoc ~~ nil ifTrue:[ 
  ug := ugAssoc value .
  langSym := ug at: #NativeLanguage otherwise: nil .
  langSym ~~ nil ifTrue:[
    ug at: #NativeLanguage put: langSym asSymbol
    ].
  ].
%

category: 'Repository Conversion'
method: SymbolList
convRecompileAllClasses

"Recompiles methods in all classes in the receiver, using the receiver
 as the symbol list for recompilation."

1 to: self size do:[:j |
  (self at: j) convRecompileAllClassesWith: self
  ].
%

category: 'Searching'
method: SymbolList
dictionaryAndSymbolOf: anObject

"Returns the Dictionary that names anObject, and also returns the
 name which that Dictionary associates with anObject.  More precisely, this
 returns an Array containing two elements:

 * The Dictionary in the receiver that contains an Association whose
   value is anObject.
 * The Symbol which is that Association's key.

 The receiver is searched in the same order that the compiler searches it.
 (For more information about symbol resolution, see the GemStone Programming
 Guide.)  If anObject is not found in the receiver, returns nil."


1 to: self size do:[ :j | | aDict |
  aDict := self at: j .
  aDict ~~ nil ifTrue:[
    aDict associationsDo:[ :assoc |    
      assoc value == anObject ifTrue:[ ^ #[ aDict, assoc key ] ].
      ].
    ].
  ].
^ nil
%

category: 'CodeModification Override'
method: SymbolList
, aSequenceableCollection

self _validatePrivilegeAdd: aSequenceableCollection.
^ super , aSequenceableCollection
%

!  _validateElement: added with fix 31942
category: 'Private'
method: SymbolList
_validateElement: anObj

"if anObj is a kind of SymbolDictionary, return anObj,
 otherwise generate a constraint error "
(anObj isKindOf: SymbolDictionary) ifFalse:[ 
  System signal: 2107
    args: #[ self , anObj, SymbolDictionary, anObj class]
    signalDictionary: (Globals at: #GemStoneError) .
  self _uncontinuableError .
].
^ anObj 
%

category: 'CodeModification Override'
method: SymbolList
add: newObject

self _validatePrivilegeAdd: newObject.
^ super add: (self _validateElement: newObject)
%

category: 'CodeModification Override'
method: SymbolList
add: newObject after: target

self _validatePrivilegeAdd: newObject.
^ super add: (self _validateElement: newObject) after: target
%

category: 'CodeModification Override'
method: SymbolList
add: newObject before: target

self _validatePrivilegeAdd: newObject.
^ super add: (self _validateElement: newObject)  before: target
%

category: 'CodeModification Override'
method: SymbolList
addAll: aCollection

self _validatePrivilegeAdd: aCollection.
aCollection do:[:anObj | self _validateElement: anObj ].
^ super addAll: aCollection
%

category: 'CodeModification Override'
method: SymbolList
addAll: aCollection afterIndex: index

self _validatePrivilegeAdd: aCollection.
aCollection do:[:anObj | self _validateElement: anObj ].
^ super addAll: aCollection afterIndex: index
%

category: 'CodeModification Override'
method: SymbolList
addAll: aCollection before: target

self _validatePrivilegeAdd: aCollection.
aCollection do:[:anObj | self _validateElement: anObj ].
^ super addAll: aCollection before: target

%
category: 'CodeModification Override'
method: SymbolList
addAll: aCollection beforeIndex: index

self _validatePrivilegeAdd: aCollection.
aCollection do:[:anObj | self _validateElement: anObj ].
^ super addAll: aCollection beforeIndex: index
%

category: 'CodeModification Override'
method: SymbolList
addLast: newObject

self _validatePrivilegeAdd: newObject.
^ super addLast: (self _validateElement: newObject)
%

category: 'CodeModification Override'
method: SymbolList
atAllPut: anObject

self _validatePrivilegeAdd: anObject.
^ super atAllPut: (self _validateElement: anObject)
%

category: 'CodeModification Override'
method: SymbolList
first: anObject

self _validatePrivilegeAdd: anObject.
^ super first: (self _validateElement: anObject)
%

category: 'CodeModification Override'
method: SymbolList
insertAll: aCollection at: anIndex

self _validatePrivilegeAdd: aCollection.
aCollection do:[:anObj | self _validateElement: anObj ].
^ super insertAll: aCollection at: anIndex
%

category: 'CodeModification Override'
method: SymbolList
insertObject: anObject at: anIndex

self _validatePrivilegeAdd: anObject.
^ super insertObject: (self _validateElement: anObject)  at: anIndex
%

category: 'CodeModification Override'
method: SymbolList
last: anObject

self _validatePrivilegeAdd: anObject.
^ super last: (self _validateElement: anObject)
%

category: 'CodeModification Override'
method: SymbolList
remove: oldObject

self _validatePrivilege: oldObject.
^ super remove: oldObject
%

category: 'CodeModification Override'
method: SymbolList
remove: oldObject ifAbsent: anExceptionBlock

self _validatePrivilege: oldObject.
^ super remove: oldObject ifAbsent: anExceptionBlock
%

category: 'CodeModification Override'
method: SymbolList
removeAll: aCollection

self _validatePrivilege: aCollection.
^ super removeAll: aCollection
%

category: 'CodeModification Override'
method: SymbolList
removeAllIdentical: aCollection

self _validatePrivilege: aCollection.
^ super removeAllIdentical: aCollection
%

category: 'CodeModification Override'
method: SymbolList
removeAllSuchThat: aBlock

self _validatePrivilege: self.
^ super removeAllSuchThat: aBlock
%

category: 'CodeModification Override'
method: SymbolList
removeAtIndex: anIndex

self _validatePrivilege: self.
^ super removeAtIndex: anIndex
%

category: 'CodeModification Override'
method: SymbolList
removeFirst

self _validatePrivilege: self.
^ super removeFirst
%

category: 'CodeModification Override'
method: SymbolList
removeFrom: startIndex to: stopIndex

self _validatePrivilege: self.
^ super removeFrom: startIndex to: stopIndex
%

! size: added with fix 31942
category: 'CodeModification Override'
method: SymbolList
size: anInteger

self _validatePrivilege: self.
^ super size: anInteger 
%

category: 'CodeModification Override'
method: SymbolList
protectedRemoveFrom: startIndex to: stopIndex

<protected>
^ super removeFrom: startIndex to: stopIndex
%


category: 'CodeModification Override'
method: SymbolList
removeIdentical: oldObject

self _validatePrivilege: oldObject.
^ super removeIdentical: oldObject
%

category: 'CodeModification Override'
method: SymbolList
removeIdentical: oldObject ifAbsent: anExceptionBlock

self _validatePrivilege: oldObject.
^ super removeIdentical: oldObject ifAbsent: anExceptionBlock
%

category: 'CodeModification Override'
method: SymbolList
removeLast

self _validatePrivilege: self.
^ super removeLast
%

category: 'CodeModification Override'
method: SymbolList
replaceFrom: startIndex to: stopIndex with: aCollection

self _validatePrivilege: self.
self _validatePrivilegeAdd: aCollection.
aCollection do:[:anObj | self _validateElement: anObj ].
^ super replaceFrom: startIndex to: stopIndex with: aCollection
%

category: 'CodeModification Override'
method: SymbolList
replaceFrom: startIndex to: stopIndex with: aSeqCollection startingAt: repIndex

| count |
self _validatePrivilege: self.
self _validatePrivilegeAdd: aSeqCollection.
count := stopIndex - startIndex + 1 .
0 to: count -1 do:[:j |
  self _validateElement:( aSeqCollection at: repIndex + j) 
  ]. 
^ super replaceFrom: startIndex to: stopIndex with: aSeqCollection startingAt: repIndex
%

category: 'CodeModification Override'
method: SymbolList
replaceFrom: startIndex to: stopIndex withObject: anObject

self _validatePrivilege: self.
self _validatePrivilegeAdd: anObject.
self _validateElement: anObject .
^ super replaceFrom: startIndex to: stopIndex withObject: anObject
%

category: 'CodeModification Override'
method: SymbolList
_addAllFromNsc: aBag

self _validatePrivilegeAdd: aBag.
aBag do:[:anObj | self _validateElement: anObj ].
^ super addAllFromNsc: aBag
%

category: 'CodeModification Override'
method: SymbolList
at: anIndex put: aValue

self _validatePrivilegeAdd: aValue.
self _validateElement: aValue .
^ super at: anIndex put: aValue
%

category: 'CodeModification Override'
method: SymbolList
_at: anIndex put: aValue

self _validatePrivilegeAdd: aValue.
self _validateElement: aValue .
^ super _at: anIndex put: aValue
%

category: 'CodeModification Override'
method: SymbolList
_basicAt: anIndex put: aValue

self _validatePrivilegeAdd: aValue.
self _validateElement: aValue .
^ super _basicAt: anIndex put: aValue
%

category: 'CodeModification Override'
method: SymbolList
_deleteNoShrinkFrom: startIndex to: stopIndex

self _validatePrivilege: self.
^ super _deleteNoShrinkFrom: startIndex to: stopIndex
%

category: 'CodeModification Override'
method: SymbolList
_insertAt: destOffset 
from: anArray 
fromStart: startOffset
fromEnd: endOffset 
numToMoveDown: numToMove 

self _validatePrivilegeAdd: anArray.
startOffset to: endOffset do:[ :j | self _validateElement:(anArray at: j) ].
^ super 
    _insertAt: destOffset 
    from: anArray 
    fromStart: startOffset
    fromEnd: endOffset 
    numToMoveDown: numToMove 
%

category: 'CodeModification Override'
method: SymbolList
_primitiveAt: anIndex put: aValue

self _validatePrivilegeAdd: aValue.
self _validateElement: aValue .
^ super _primitiveAt: anIndex put: aValue
%

category: 'CodeModification Override'
method: SymbolList
_unsafeAt: anIndex put: aValue

self _validatePrivilegeAdd: aValue.
self _validateElement: aValue .
^ super _unsafeAt: anIndex put: aValue
%

category: 'Updating'
method: SymbolList
_validatePrivilege

" To fix 36822, the final version of this method is compiled 
  by file gssession.gs " 

| upro |
upro := System myUserProfile .
self == upro symbolList ifTrue:[
  upro _validateCodeModificationPrivilege
] ifFalse:[
  upro _validatePrivilegeName: #OtherPassword 
]
%

! added _validatePrivilegeAdd: for bug 31284
category: 'Updating'
method: SymbolList
_validatePrivilegeAdd: item

"Check that item satisfies constraints and then check privilege."

(item isKindOf: SymbolDictionary) ifTrue: [ 
  ^ self _validatePrivilege: item
].
(item isKindOf: Collection) 
  ifTrue: [ item do: [:x | x _validateClass: SymbolDictionary ]. ]
  ifFalse:[ item _validateClass: SymbolDictionary ].

^ self _validatePrivilege: item 
%

category: 'Updating'
method: SymbolList
_validatePrivilege: item

"Only need to #_validatePrivilege if adding/removing a SymbolDictionary"

(item isKindOf: SymbolDictionary) ifTrue: [ 
   ^ self _validatePrivilege 
  ].
(item isKindOf: Collection) ifTrue: [
  item do: [:x | 
    (x isKindOf: SymbolDictionary) ifTrue: [ 
      self _validatePrivilege.
      ^ self
      ]
    ]
  ].
%

! _gciInitialize added with fix 31942
category: 'Instance Initialization'
method: SymbolList
_gciInitialize

self size: 0
%

! _deferredGciUpdateWith: added with fix 31942
category: 'Private'
method: SymbolList
_deferredGciUpdateWith: valueArray

self size == 0 ifTrue:[
  self addAll: valueArray .    
] ifFalse: [
  " semantics of the deferred update not defined"
  self _error: #errNoStructuralUpdate 
]
%


