Page Numbers: Yes First Page: 1
Heading:
UNPUBLISHED WORKING DRAFT - DO NOT COPY OR DISTRIBUTE
September 21, 1978 6:26 PM 3: Datatypes [IVY]<KRL>document>str-lev-mem
3. Specification of the memory level data structures in KRL-1
A number of the other specifications depend on an understanding of the basic data objects which can be manipulated by KRL-1 programs. This document describes the memory level objects in the system from an interface point of view -- talking about how they are used and what they mean without going into details of their actual implementation in LISP data structures and on secondary storage. It includes a functional specification of the data types (i.e. the functions for accessing and manipulating them). The document Conversion contains some information on the intermediate level structures, but a complete specification has yet to be written.
To find out where the structures described herein come from, see the documents Syntax and Conversion. To find out how the user can manipulate them at the highest level, see the document Levels.
The basic data types
There are two basic kinds of objects manipulated by KRL-1 code -- LISP pointers and KRL handles. When we want to refer to the union of these, we will use the term pointer, using handle and LISP pointer when more specificity is needed. LISP pointers are the standard objects manipulated by INTERLISP, including list cells, atoms, strings, arrays, user defined datatypes, and numbers (as in LISP, smallnums are thought of as pointers, even though in the specific implementation they are actually stored locally). KRL handles come in many types, but there are three of primary importance -- those which point to units, those which point to anchors, and those which point to descriptors. In fact, in the current design, KRL handles will be pointers to LISP datatypes, but conceptually they are a separate kind of thing -- indicated in a type test as handle rather than datatype. There are many issues involved in actually implementing handles in a layered storage environment, but these are all made invisible by the primitives which do operations on handles, so the user (including system builders outside of the memory subsystem) need not be concerned with them.
Anchors
Anchors are the fundamental semantic element in the system. Each anchor consists of a description, in terms of one or more descriptors, of some object, which is called the referent of the anchor or description. Memory structure is built up out of anchors which contain handles for descriptors, which in turn have fields whose contents are handles for other anchors, or pointers to LISP objects. A subset of the anchors in memory are labelled anchors (which correspond to the slots of units). The label of a labelled anchor has two parts, the unit name and the slot name, each of which is a LISP atom (literal atom). Labelled anchors are usually considered Primary, that is, they are the principle characterization of their referent, although other, nonprimary, anchors may also describe it.
Descriptors
Descriptors are drawn from a limited set of forms which make possible a variety of assertions about the referent of the description they are a part of. Each different type of descriptor has a different set of fields which specify the asserted relation of the referent to other memory level objects. All descriptors contain a back pointer to the anchor which contains them.
Units
Conceptually the unit is a collection of labelled anchors which describe a structured decomposition of a prototype. It serves as the template for describing other objects in terms of that prototype. The actual memory level structure called a unit simply contains a directory of its slots and a pointer to its texual origin, if any.
MetaAnchors
Anchors, descriptors and units, in addition to their other fields, all have a distinguished field which contains a handle for an anchor called the metaAnchor. This anchor can contain descriptors which describe the object for which they are the meta description. They describe the object itself, not its referent. They can be thought of as information about the object for use in the operation of the system.
Layer-crossing descriptors
In writing KRL descriptions which serve as meta-descriptions of things within the KRL system, there will often be cases when the referent of a description (the thing in the world corresponding to the anchor containing the description) is a LISP or KRL object. There are two descriptors (represented as distinct descriptor types in memory) which permit this kind of layer-crossing. The LispPointer descriptor (indicated in the syntax with a single quote) has a single field which contains a LISP pointer, and is interpreted as meaning that the description in which it appears is a description of the thing to which it points (any LISP object). The KrlPointer descriptor (see discussion of the syntax below) is similar, except that it contains a handle. It is critical to realize the difference between a KrlPointer descriptor and a Coreference descriptor. Each contains a single field, which is filled by a handle (although the KrlPointer descriptor allows that handle to be to an anchor or descriptor, while in a coreference it must be to an anchor). But the interpretations are quite different. A KrlPointer descriptor means that the object being described is the KRL object being pointed to, while a coreference descriptor means that the object being described is the same one as the one described in the anchor being pointed to.
In memory, all KrlPointer descriptors are the same -- containing a single field which contains a handle. However, the representation in the syntax (at the message and intermediate levels) depends on just what that handle points to. There are five distinct cases:
Labelled anchors: A KrlPointer which points to a labelled anchor is represented in the syntax by a form whose key word is Structure and which contains the slot name and, if the reference is to a slot in a unit other than the lexically enclosing one, the unit name of the labelled anchor, separated by the key word inUnit. Thus, the descriptor Structure self inUnit Sam could be part of a description of the self-slot anchor in the unit named Sam. To repeat the previous warning, this is different from The self inUnit Sam (or simply Sam) which is part of a description of the thing described by the self slot of Sam.
Structures with local names: To effect sharing of structure, that is to get a KrlPointer to a specific structure, whether descriptor, or labelled or unlabelled anchor, it can be given a local name and then referred to using that name. Details of how to set up local names are given below.
There is a new descriptor* for referencing structures with local names. The syntax is as follows:
"StructureNamed" literalAtom [("inUnit" | "fromUnit") unitName]
This descriptor is converted to an indirect KrlPointer for the designated structure. Just as for slot pointers or KrlPointer descriptors, the unit defaults to the lexically enclosing one. A runtime signal will be generated in case undefined names are actively referenced. Attempting to give two structures within the same unit the same name will cause a syntax error at readin time or an error signal at runtime.
*This replaces the old NoteRef descriptor.
Unlabelled anchors: A KrlPointer which points to an unlabelled anchor is represented in the syntax by printing the character \ followed by the syntactic forms for the descriptors appearing in that anchor. Note that this is the form we have previously referred to as "KRL quote". In fact when the parser hits a KRL quote (in the surface syntax), what is actually stored in memory structures is a KrlPointer descriptor with its pointer pointing to an unlabelled anchor containing the memory structures corresponding to the quoted description. There is an important caveat about this descriptor, which corresponds closely to the situation in LISP. If two KrlPointer descriptors point to the same unlabelled anchor, and the structures containing them are printed out, the contents of the anchor will be printed out for each. On reading back in, they will point to separate unlabelled anchors with identical contents -- i.e. EQUAL but not EQ. As in LISP using simple print and read, shared pointers are not preserved under a memory -> syntax -> memory conversion. The system is designed so that sharing goes through labelled anchors or local names (just as sharing through atoms in LISP is preserved through syntax).
Descriptors: A KrlPointer which points to a descriptor is represented in the syntax as the character sequence \~ followed by the syntactic form for the descriptor. We had not previously distinguished descriptors from anchors in quotation, and this convention is needed to distinguish a descriptor from an unlabelled anchor containing only that descriptor. As with unlabelled anchors, no sharing of structure can be indicated in the syntax.
Units: A KrlPointer which points to a unit is represented in the syntax as the character sequence \# followed by the syntactic form for the unit.
Details on local names
To name a structure declaratively footnote it with the pseudo-functional CallMe(name), e.g.:
# PaloAlto
self: The↑1 hometown from1: CallMe(’FirstSpec)
a Person with name = "Danny"
@CallMe(’FirstCitizensName)
FirstSpec names a descriptor, FirstCitizensName names an anchor.
To name a structure dynamically, that is from LISP at runtime, one needs a handle for the object and either a handle for the unit which contains it, the name of that unit, or a handle for the slot which contains it. Then one calls the function CallStructure(structure context name) where structure is a handle to the structure to be named, context is one of the three things just mentioned which serve to determine the unit which contains the structure, and name is an atom to be given as name to the structure.
CallStructure doesn’t exist. It will be written if anybody wants it. ht.
In either case, an object will be created in memory, called a Local Name Pair, which is named by the given local name and contains a handle to the structure named.
Because of the level of indirection provided by the local name pair, it does not matter at conversion time whether references are encountered before names or vice versa. Use of GetNamePair (see below in the implementation section) with structureFlg = T at runtime will generate a signal if the linkage is still unresolved.
# # # # # # # # # # # # # # # # #
Record Declarations and Access Functions
The field structure of the basic system objects at the memory level follow hereafter. For each type of object its name followed by a list of fields is given, for each indicating whether it is an ordinary field containing a single handle, a variable length field containing multiple handles or a flag field. Then follow the type of handle each field contains and comments on the contents expected. If objects of this type can be named, a note describing the form of the name is given immediately after the type name. Access functions particular to a given object follow thereafter: The access functions common to all objects are deferred to the end, as are comments about the overall naming structure of the system.
The information which follows is presented independently of the actual implementation of memory level objects, but some intrusion by reality is unavoidable.
The frequent appearance of arguments to access functions with names like oldHandle are an artifact of the need to conserve storage in LISP by reusing old handes to return values or hold temporary intermediate results during some access.
Variable length fields are implemented by allocating fixed length fields which, when filled, are extended by pointing to an extra block of storage, also fixed length, and so on. Handles are actually removed from such fields not by compaction, but by overwriting with a special skip handle.
The field for the descriptors of an anchor is of this type, for instance.
Flag fields are implemented via a bit, not in the object itself, but in the handle for that object.
Unit Units are named by atoms
metaAnchorordinaryAnchor
contains the memory level versions of any footnotes on the unit which were of lasting significance: so far only Comment: All the other system pseudofunctionals so far conceived of take effect and disappear at cataloging or conversion time: user functionals will not disappear
memFileordinaryCharacterString
an atom giving the file name for the file origin of the unit
memBPtrordinary*Integer
the character position of the first character of the unit definition
memEPtrordinary*Integer
the character position of the last plus one character of the unit definition
*These fields do not contain handles, but rather the integer in question itself.
slotAnchorsvariableAnchor
the slot anchors of the unit, in no particular order, probably typein for text based units and eldest first for created ones
Namedflag
no longer used
GetUnit(atom oldHandle)
Returns a handle to a unit with name atom or else NIL. If atom is NIL, uses value of LASTUNIT, the name of the last unit used at the top level. If atom is already a unit, returns it, but as side effect looks up name and puts it in LASTUNIT. Does spelling correction if necessary. Reuses oldHandle if present.
Anchor Anchors are either unnamed or named by pairs of atoms: unit name and slot name
metaAnchorordinaryAnchor
contains traps, CallMe functionals, Comments, and anything else the user explicitly puts there which is not removed by the cataloger (see the partialMeta field below)
descrsvariableDescriptor
the descriptors, if any, contained in this anchor
Namedflag
true for labelled anchors, otherwise false
Primaryflag
true if this is the primary anchor for the thing it describes. Normally true if Named is true
PartialMetaflag
if true of an anchor which is meta to some structure, then there were pseudo-functionals footnoted on that structure which were cataloged and removed. That is, simply printing the contents of this anchor will not dump all the original footnotes
BackPtrflag
if true then this is not the expected meta anchor for the descriptor to which it is attached, but rather a back pointer.
WrongUflag
if true then mappings with this slot as focus are atypical with respect to uniqueness. For a self slot this means no folding, for others, folding. See the Conversion document under UniqueMap.
SlotFor(unitName slotName oldHandle failFlg)
Returns a handle to the indicated slot anchor of the indicated unit or else NIL. Reuses oldHandle if present. Assumes unitName is a dotted pair of unitName and slotName if slotName is NIL. If the indicated anchor is not there, will build one with the correct name (but will not insert it in the slot directory of the appropriate unit), provided failFlg is NIL. If failFlg is T and the anchor is not there, will return NIL.
Set
metaAnchorordinaryAnchor
as for Anchor above
elementsvariableAnchor
the anchors, if any, which describe the elements of the set
Sequence
metaAnchorordinaryAnchor
as for Anchor above
elementsvariableAnchor
the anchors, if any, which describe the elements of the sequence
Coreference
metaAnchorordinaryAnchor
as for Anchor above
corefordinaryAnchor
the labelled anchor asserted to also describe the referent of the coreference
LispPointer
metaAnchorordinaryAnchor
as for Anchor above
lispPointerordinaryCharacters or pseudohandle or number
the LISP object refered to. type is determined by the flags described below
FixPflag*
the lispPointer field is not a handle, but rather a 36 bit integer which is the referent
FloatPflag*
the lispPointer field is not a handle, but rather a 36 bit floating point number which is the referent
AtomPflag*
the lispPointer field is a handle to a CharacterString, whose contents as a LISP atom is the referent
StringPflag*
the lispPointer field is a handle to a CharacterString, whose contents as a LISP string is the referent
*At most one of these flags can be set. If none are set, then the lispPointer field contains a pseudohandle (see below under the Cross Linking array), which can be converted (via LispFor, see below) to an arbitrary S expression.
LispContentsOf(handle)
Returns the LISP referent of handle, which must be to a LispPointer. Successive calls with the same argument will produce EQ results only for LispPointers with AtomP set, with no flags set, or with FixP set when the integer in question is ’small’.
LispPointerTo(ptr oldHandle indirectFlg)
Creates a LispPointer which refers to the LISP object ptr and returns a handle to it. Reuses oldHandle if present. Unless indirectFlg is set, will move strings, atoms and numbers to memory space. If indirectFlg is set, will always use a pseudohandle (see below). Normal system operation does not set indirectFlg when building LispPointers.
LispFor(pseudohandle)
Returns the true LISP object pointed to from pseudohandle, which must be a pseudohandle. See the discussion of the Cross Linking array in the implementation section. Unless you have evilly constructed a bogus pseudohandle, this cannot cause an error.
HandleFor(ptr oldHandle)
Returns a pseudohandle to the LISP object ptr. Reuses oldHandle if present. If it is a pseudohandle, reuses its slot in the array, thus freeing the old contents. Note that this means any extant copies of oldHandle will no longer point to the old contents, and they may be garbage collected.
ReleaseHandle(pseudohandle)
Does (HandleFor NIL pseudohandle), that is frees the old contents of pseudohandle by pointing it at NIL. Note that this means any extant copies of pseudohandle will no longer point to its old contents, and they may be garbage collected.
CharacterString
charactersfunny
this is the only truly variable length field/object in the system. It contains the characters for a string or atom, and can only be accessed via the following two functions:
PutStringOnFile(ptr oldHandle)
Creates a new CharacterString and returns a handle to it. Reuses oldHandle if present. The character string contains the characters of the LISP pname of ptr.
GetStringFromFile(handle)
Returns a LISP string containing the characters in the character string pointed to by handle. Uses a temporary string, so a copy should be made immediately if the results are to be kept around.
KrlPointer
metaAnchorordinaryAnchor
as for Anchor above
referentordinaryAnchor or Descriptor or LocalNamePair
the referent of the containing description
Indirectflag
if true then handle does not point directly to the referent, but rather to a local name pair which points to it. The StructureNamed form builds an indirect KrlPointer; the Structure, \, and \~ forms build a direct KrlPointer
LocalNamePair Local Name Pairs are named by pairs of atoms: unit name and local name
namedStructureordinaryAnchor or Descriptor
the handle for the thing named
GetNamePair(unitName localName oldHandle structureFlg)
Returns a handle to the local name pair for the structure in the indicated unit with the indicated local name, provided structureFlg is NIL, otherwise a handle to the structure itself. In the first case, if there is no such local name pair, it creates it. In the second case, that is with structureFlg non-NIL, signals NoLocalName if either there is no such local name pair, or if there is but its namedStructure field is empty. Reuses oldHandle if present.
MapDescriptor
metaAnchorordinaryAnchor
as for Anchor above
focusSlotordinaryAnchor
the slot anchor which is the focus of the mapping. self for perspectives and the thing after the the for specifications
prototypeordinaryAnchor
the self anchor of the template for the mapping
templateAnchorsvariableAnchor
the slot anchors in the template, one for each map pair. Matches up one for one with the elements in the next field. may include the self anchor
instanceAnchorsvariableAnchor
the anchors at the instance end of the mapping. Matches up one for one with the elements in the previous field
InterpretedMapD this is a flavor of MapDescriptor for use when one or more of the fillers is really meta information. The system functionals Or, Not, During, Always, Currently, and Default and the Case and LISP statements translate this way, as do any user functionals specified as interpreted and any perspectives or specifications with prototype @... See the Conversion document for a discussion of the detailed representation of the various system functionals. Some of them use the fields in non-canonical fashion.
metaAnchorordinaryAnchor
as for Anchor above
focusSlotordinaryAnchor
the slot anchor which is the focus of the mapping. self for perspectives and e.g.s and the thing after the the for specifications
prototypeordinaryAnchor
the self anchor of the template for the mapping
templateAnchorsvariableAnchor
the slot anchors in the template, one for each map pair. Matches up one for one with the elements in the next field. may include the self anchor
instanceAnchorsvariableAnchor
the anchors at the instance end of the mapping. Matches up one for one with the elements in the previous field
Reflexive
metaAnchorordinaryAnchor
as for Anchor above
templateordinaryAnchor
the labelled anchor in a template which corresponds to the one in the instance which is asserted to describe the referent
# # # ## # ## # ## # ## # ## # ## # # #
A Few Words About the Memory System
All KRL memory structures are resident in a memory file, not in LISP’s address space. Handles are lisp datatypes which include a pointer to this file. The file is divided into named allocation spaces. Using an allocation space for a particular class of objects should improve the paging behaviour of the system. Objects on the file are accessible by handles or, in some cases, by name. The file includes a hash table which associates strings with handles. Units have simple names. Slots (that is, labelled anchors) have compound names, composed of the unit name and slot name concatenated with a null character in between. Local names also have compound names, composed of the unit name and local name concatenated with the sequence null l null in between. Allocation space names also have compound names, as if they were slots of a unit called KrlSysMemSpace.
Naming Functions
FileObjectName(handle noErrFlg)
Returns the name of a named object pointed to by handle, either as an atom, if simple, or a CONS of 2 atoms, if compound. If nothing found under that name, returns NIL if noErrFlg else causes an error.
GetFileObject(name oldHandle type)
Looks up name on file. Reuses oldHandle if present. type is optional, giving the type of object expected, which will otherwise be assumed to be unit if name is an atom, slot if it’s a CONS. Use is not encouraged: use GetUnit, SlotFor, or GetNamePair.
SpaceName(handle oldHandle)
Returns the name of the allocation space handle points into as an atom. Reuses oldHandle as a temporary if present.
General Access Functions
FetchMem(handle field oldHandle)
Returns the handle in field of the object pointed to by handle. Smashes this into oldHandle if "present". As this is a computed macro, "present" means in the calling form. Thus (FetchMem Foo metaAnchor BAR) will cause an error if BAR is not bound to a handle at runtime. Fetch accesses to variable length fields should not be done directly, as they smash the handle to point to the first word of the field, e.g., (FetchMem Foo descrs), where Foo originally pointed to the front of an anchor, would increment it by 2 to point directly to the first word of the descrs field, as well as fetching its contents. Use the functions provided for variable length fields (see below).
StoreMem(handle field valueHandle)
Puts valueHandle into field of object pointed to by handle. Value is not interesting.
KrlCreate(objectType objectName spaceName oldHandle . flgs)
Allocates an object of type objectType in space
(OR spaceName CURRENTMEMORYSPACE ’NeutralSpace).
Gives it objectName if present. Smashes into oldHandle if present. Turns on flgs, which must be names of flag fields in the object, if any. objectName, spaceName and oldHandle can be NIL at runtime (not like FetchMem). Turns on lastEntry bit in appropriate places in the variable length fields of the object.
EQH(h1 h2)
EQUAL for handles, returns T if h1 and h2 are handles for the same object. Error if both args not handles.
CopyHandle(oldHandle copyHandle)
Returns a copy of oldHandle itself, reuses copyHandle if present (in the form). Moves all 36 bits.
NullHandle(handle)
Returns T if handle is file NIL, that is points nowhere (0), NIL otherwise.
Access to Variable Length Fields
AppendHandle(newHandle pointerHandle oldHandle noSmashFlg)
InsertHandle(newHandle pointerHandle oldHandle noSmashFlg)
Put newHandle into a variable length field just ahead of (Insert) or just after (Append) where pointerHandle points. Uses oldHandle as a temporary if present (in form, see above under FetchMem). Unless noSmashFlg is non-NIL, smashes pointerHandle as it ripples down the sequence, and returns it as value, though probably it’s not of any use.
FindHandle(datum handle field oldHandle) ~ FMEMB
Constructs code which returns either NIL or a pointer to the first non-degenerate (NULL, SKIP, or EXTEND) entry which is EQH to datum in the variable length field field of the object pointed to by handle, if field is given, else in the variable length field into which handle points directly. Revises oldHandle if given, but even so builds one more handle.
NthHandle (handle field n oldHandle pointerFlg) ~ NTH
Like FindHandle but gets nth real handle or NIL. If pointerFlg, it returns a handle which points to the nth handle (i.e., a tail like FindHandle), otherwise the nth handle itself.
NullifyHandle(handle)
Smashes the handle pointed to by handle to be of type skip, thus eliminating it.
DeleteHandle(datum handle field oldHandle) ~ DREMOVE
= (NullifyHandle (FindHandle datum handle field oldHandle))
Return T if done, else NIL
DeleteNthHandle(handle field n oldHandle)
= (NullifyHandle (NthHandle handle field n oldHandle T))
Returns T if done, else NIL
IncludeHandle(newHandle pointerHandle field oldHandle noFillSkipFlg smashFlg)
Adds newHandle to the variable length field field of pointerHandle (if field is there) or else to the variable length field pointed into by pointerHandle. Puts it in first available spot unless noFillSkipFlg, in which case puts it at the end. If smashFlg, then smashes pointerHandle as it goes, returning with it pointing to new entry.
CLISP Iterative Operators
(1a)(for X fromField field ofHandle {smashIt} handle...
(1b)(for X fromHandle {smashIt} handle...
Braces ({}) indicate optional CLISP words.
The body of the statement will be done with X bound to a handle which successively will be each real handle in the variable length field field of the object pointed to by handle (case 1a) or of the variable length field pointed into directly by handle (case 1b). In either case smashIt indicates handle is to be smashed as we go along. A new handle for X is not built each time, so to save it use CopyHandle, e.g., ...collect (CopyHandle X)).
...as i from 1 as y in Y... does the right thing.
(2a) (...addHandle {dontFillSkips} h toField field ofHandle {smashIt} handle)
(2b) (...addHandle {dontFillSkips} h toHandle {smashIt} handle)
These are for use as the body of an iterative statement. They efficiently call
(IncludeHandle h handle (field) dontFillSkips smashIt)
for each iteration on h. That is they add all the h’s to the variable length field field of handle (case 2a) or to the variable length field pointed into directly by handle (case 2b), filling skips unless dontFillSkips is there, otherwise adding only at end, smashing handle if smashIt is there, otherwise not.
...useHandle oldHandle
If this occurs in any of the above they will reuse oldHandle as a temporary. If both smashIt and useHandle are there, these forms build no new handles.
# # # ## # ## # ## # ## # ## # ## # # #
Miscellaneous useful functions
PPU(unitnames file pcols)
Prints the unit or units specified by unitnames (list or atom is ok) on file controled for spacing by pcols. If the unit has a file origin, simply does a COPYBYTES. Otherwise prints from the memory level structures. pcols is interpreted as follows:
((descrRightMargin descrOverflowStart)
(footnoteRightMargin footnoteOverflowStart footnoteLeftMargin)).
See the global variables FILEPRINTCOLS and TTYPRINTCOLS for the defaults.
PPMU(unitnames file pcols)
Like PPU, but always prints from the memory level structure.
PPINT, PPNEXUS, PPK
These are the prettyprinting functions for intermediate level structures, nexi, and (memory file) handles respectively. That is, (PPV x) will invoke one of them if x is of the associated type.
EDITKRL(k)
For getting into the editor with a nexus, because e.g. EDITV won’t let you in with a no LISTP argument.
IntLevelP(x)
Returns x if it is an intermediate level structure, otherwise NIL.
KrlType(x)
Returns the atomic name of the type of x: its descriptor name if it is an intermediate structure, its file object type if it is a handle, and otherwise its LISP type name.
UnitP(x)
Returns x if it is the handle to a unit, otherwise NIL.
CHECKPOINT(fname)
Copies the current memory file to fname.KRL (or MEMSTATE.KRL) if fname is NIL) and saves the internal state there as well.
KLOGOUT(fname)
Quits KRL, first saving the internal state on the current memory file, if fname is NIL, otherwise copies the memory file to fname.KRL and saves state there.
GetHandle()
Gets a (possibly dirty) handle from a free pool, ot else builds a new one.
FreeHandle(h)
Returns a handle to the pool for reuse
CreateSpace(name)
Declares name to be an allocation space name and enables subsequent location of memory file objects in that space. Must be called before creating any objects destined for a particular space.
ReenterKrl(sFlg)
Closes the current memory file and puts you thru the initialization dialog again. If sFlg is non-NIL, saves state first.
SpaceName(handle oldHandle)
Returns the name of the space that the object pointed to by handle is allocated in. Will either use oldHandle for scratch or build one.
ConstantHandle()
A macro which will allocate a constant handle for e.g. use as a scratch handle. Should be used only very carefully in recursive contexts.
HandleValue(h)
Returns the 36 bit actual contents of h, a handle, as a large integer.
PrintVarField(h)
Dumps a portion of the memory file beginning where h points to the teletype in a concievably enlightening form. For debugging only.
KrlCopy(x oldHandle level)
Copies x, reuses oldHandle if given, down to depth level (0 = no copy at all), or all the way if level is NIL, the usual case.
KrlEqual(k1 k2)
T if k1 is equal to k2 on a field by field basis, all the way down. Map descriptors must have the same filler pairs with the same contents, but not necessarily in the same order. Sets must have the same members, but not necessarily in the same order.
AddToMetaAnchor(handle descriptor)
Adds descriptor to the meta anchor of the object pointed to by handle, creating one if necessary.
DirtyUnit(name)
Marks the unit named name as no longer corresponding to it file based message level definition.
EQHL(l1 l2)
T if l1 and l2 are lists containing pairwise EQH handles.
NewUnit(unitName spaceName oldHandle)
Creates a new unit with the given name in the given space. Returns a handle to its self slot, which it builds if necessary and includes in the unit’s slot directory. Reuses oldHandle if present.
GenUnit(seed spaceName oldHandle)
Calls NewUnit with a new name based on seed if present, else ’GU.
PutBackPtr(backPtr handle)
Makes handle, which should be for a descriptor, have backPtr (which should be for the anchor wherein handle is) as its back pointer.
GetBackPtr(handle oldHandle)
Returns the back pointer of the descriptor handle.
PutMetaAnchor(handle anchor)
Makes anchor the meta anchor for handle. The only safe way to do this. The metaAnchor field should never be accessed via FetchMem or StoreMem.
GetMetaAnchor(handle oldHandle)
Returns the meta anchor for handle, or NIL if not there.
GetPairName(lnp)
Returns the name of lnp, a local name pair, as a dotted pair of the unit name and local name.
MemDescriptorP(x)
T if x is a handle to a for real descriptor, NIL otherwise (not a handle, or not a handle to a slot or a unit or an anchor or some system internal object).
TypeD(handle)
The descriptor name of something which MemDescriptorP is true of, e.g. MapDescriptor.
TypeI(handle)
The name of the prototype of the InterpretedMapD handle.
TypeK(x)
For any x, returns one of Unit, Anchor, Descriptor, Lisp, MemSys.
Lisp is for non-handles, MemSys for system internal handles.
GetUnitName(handle)
The unit name of the slot anchor handle.
GetSlotName(handle)
The slot name of the slot anchor handle.
Miscellaneous implementation notes
KRLBASERECORDS has the declarations for the memory structures which live off the file. The form is
(KRLMEMSTRUC name field1 field2 ...) {Named} {(Flags flg 1 flg2...flg5)} . Tail)
Field = atom (for 1 word fields) | (atom number) (for n word fields)
Every descriptor should have the field metaAnchor as second field, that is, second in the list if unnamed, first if named.
Message level surrogates build intermediate records of type surrogate for ! !! or !!! except for !Name e, which produces (LIST e), so ConvFns should, when seeking an atom, do
(if (LISTP a) then (EVAL (CAR a)) else a)