AtomImpl.Mesa. Note that BasicAtomImpl also exports values to Atom.mesa
Last Modified On January 17, 1983 1:37 pm by Warren Teitelman
DIRECTORY
AMBridge USING [TVForReferent],
AMTypes USING [Class, Range, UnderType, TVType, TypeClass],
Atom USING [emptyAtom, PropList, GetPName, GetPropFromList, PutPropOnList],
AtomsPrivate USING [AtomRec, UnsafeMakeAtom],
Convert USING [MapValue],
List USING [IsAList],
Rope USING [Length],
RTTypesBasic USING [EquivalentTypes, GetCanonicalType, GetTypeAttachment, PutTypeAttachment],
RTBasic USING [nullType, Type],
SafeStorage USING [NewZone]
;
AtomImpl: CEDAR PROGRAM
IMPORTS AMBridge, AMTypes, Atom, List, AtomsPrivate, Rope, Convert, RTTypesBasic, SafeStorage
EXPORTS Atom
SHARES AtomsPrivate
= BEGIN OPEN Atom;
PropZone: ZONE ← SafeStorage.NewZone[]; -- This should be moved into Atom interface so can be shared.
Creating Atoms
MakeAtomFromString: PROCEDURE [ref: REF READONLY TEXT] RETURNS[ATOM] = TRUSTED {
IF ref = NIL THEN RETURN[Atom.emptyAtom]
ELSE RETURN[AtomsPrivate.UnsafeMakeAtom[LOOPHOLE[ref, LONG POINTER TO READONLY TEXT]]];
}; -- of MakeAtomFromString
gennum: LONG CARDINAL ← 10000;
genstr: REF TEXTNEW[TEXT[5]];
Gensym: PUBLIC PROC [c: CHARACTER ← 'A] RETURNS[ATOM] = {
GenSym1: PROC [c: CHARACTER] = CHECKED {genstr[i] ← c; i ← i+1};
i: NAT ← 0;
gennum ← gennum + 1;
Convert.MapValue[put: GenSym1, value: [unsigned[gennum]]];
genstr[0] ← c;
genstr.length ← i;
RETURN[MakeAtomFromString[genstr]];
}; -- of Gensym
property list operations types
the following provide property list operations on types. They are included here because this interface is really a combination of atoms and property list operations. and they are used in both streams as well as by the userexec. Note that using them will invoke the runtime type package.
TypeRecord: TYPE = RECORD[forThis: PropList ← NIL, forRefThis: PropList ← NIL]; -- describes type attachment. .
TypePutProp: PUBLIC PROC [type: RTBasic.Type ← RTBasic.nullType, prop: REF ANY, val: REF ANY] = {
OPEN AMTypes;
underType: RTBasic.Type = UnderType[type];
class: Class = TypeClass[underType];
typeInfo: REF TypeRecord;
IF class = ref OR class = list OR List.IsAList[underType: underType] THEN {
-- if type is a ref type, attach to referent as well, so that if you start with the ref, and therefore can only obtain type for its referent, will still be able to find the type attachment.. IF there were a way of getting to type REF FOO from type FOO, then this would be unnecessary because if you wanted to know whether REF FOO had a type attachment and you had a FOO in hand, you would simply construct that type.
referentType: RTBasic.Type ← RTTypesBasic.GetCanonicalType[Range[type]];
typeInfo ← NARROW[RTTypesBasic.GetTypeAttachment[referentType]];
IF typeInfo = NIL THEN
{typeInfo ← PropZone.NEW[TypeRecord ← []];
RTTypesBasic.PutTypeAttachment[referentType, typeInfo]
}; 
typeInfo.forRefThis ← Atom.PutPropOnList[typeInfo.forRefThis, prop, val];
};
type ← RTTypesBasic.GetCanonicalType[type];
typeInfo ← NARROW[RTTypesBasic.GetTypeAttachment[type]];
IF typeInfo = NIL THEN
{typeInfo ← PropZone.NEW[TypeRecord ← []];
RTTypesBasic.PutTypeAttachment[type, typeInfo]
}; 
typeInfo.forThis ← Atom.PutPropOnList[typeInfo.forThis, prop, val];
}; -- of TypePutProp
TypeGetProp: PUBLIC PROC [type: RTBasic.Type ← RTBasic.nullType, prop: REF ANY, dereferenced: BOOLEANFALSE, ref: REF ANYNIL] RETURNS[REF ANY] = {
OPEN RTTypesBasic;
typeInfo: REF TypeRecord;
IF type = RTBasic.nullType THEN TRUSTED {
IF ref # NIL THEN {
type ← AMTypes.TVType[AMBridge.TVForReferent[ref]];
dereferenced ← TRUE;
}
ELSE RETURN[NIL];
};
type ← RTTypesBasic.GetCanonicalType[type];
typeInfo ← NARROW[RTTypesBasic.GetTypeAttachment[type]];
IF typeInfo = NIL THEN RETURN[NIL];
RETURN[Atom.GetPropFromList[IF dereferenced THEN typeInfo.forRefThis ELSE typeInfo.forThis, prop]];
}; -- of TypeGetProp
miscellaneous
IsAnAtom: PUBLIC PROC [type: RTBasic.Type, dereferenced: BOOLEANFALSE] RETURNS[BOOLEAN] = {
-- e.g. if x: TYPE = LIST OF REF ANY, and you obtain a tv for the first element of x, its type is of REF ANY. The only way to find out if this is an atom is to ask whether the type of its referent is the same as that of the type of the range of ATOM. This procedure does that for you. If dereferenced = TRUE, then x is a tv for the referent, and in this case the test is whether the type of x is the type of the range of ATOM.
RETURN[RTTypesBasic.EquivalentTypes[IF dereferenced THEN type ELSE AMTypes.Range[type], CODE[AtomsPrivate.AtomRec]]];
};
Length: PUBLIC PROC [self: ATOM] RETURNS[LONG INTEGER] = {
-- number of characters in pname
RETURN[Rope.Length[Atom.GetPName[self]]];
};
END.