KipperDoc.tioga
Sturgis, May 21, 1986 11:21:11 am PDT
Kipper
CEDAR 6.1 — FOR INTERNAL XEROX USE ONLY
Kipper
Howard Sturgis
© Copyright 1986 Xerox Corporation. All rights reserved.
Abstract:
Kipper vt : to cure (split dressed fish) by salting and smoking
Kipper is a general purpose marshalling package, providing an external representation for complex Cedar data structures. It can handle structures containing multiple allocated records, linked together by REFs. Cyclic data structures are permitted. Kipper accepts a description of a Cedar Type Structure, and generates a set of Cedar stub procedures. These stub procedures convert data objects of the given type into a sequence of 16 bit words sent to an IO.STREAM, and convert from a sequence of 16 bit words obtained from an IO.STREAM into a copy of the original data structure.
Created by: Howard Sturgis
Maintained by: Howard Sturgis <Sturgis.pa>
Keywords: Pickle, Marshall
XEROX  Xerox Corporation
   Palo Alto Research Center
   3333 Coyote Hill Road
   Palo Alto, California 94304

For Internal Xerox Use Only
1. Introduction
Kipper vt : to cure (split dressed fish) by salting and smoking
Kipper is a general purpose marshalling package, providing an external representation for complex Cedar data structures. It can handle structures containing multiple allocated records, linked together by REFs. Cyclic data structures are permitted. Kipper accepts a source file describing a Cedar Type Structure, and generates a set of Cedar stub procedures. These stub procedures convert data objects of the given type into a sequence of 16 bit words sent to an IO.STREAM, and convert from a sequence of 16 bit words obtained from an IO.STREAM into a copy of the original data structure.
Each kippering stub procedure takes a Cedar REF as an argument. The stub procedure marshalls all allocated records that are reachable from the given REF by following successive imbedded REFs. Cyclic data structures are handled by recognizing repeated occurrences of the same REF. This same mechanism guarantees that two REFs are equal in the reconstructed data structure if and only if the corresponding REFs were equal in the original data structure. Each unkippering stub procedure returns a Cedar REF as a result.
Kipper treats a compound data structure as a multiply rooted directed graph, where the nodes are allocated records, and the arcs are Cedar REFs. One such graph is kippered (or unkippered) in a single Kipper session. An exception to this model is that the internal structure of a ROPE is not duplicated; Kipper treats a ROPE as a REF to a sequence of characters, and the result of kippering and unkippering a ROPE is a REF to an identical sequence of characters. Of course, if two ROPEs that are identical REFs occur in the kippered data structure, the resulting two REFs will also be identical.
A single kippering session is started by creating a Kipperer from an existing IO.STREAM. This Kipperer contains, among other things, a Hash table for recording REFs. A compound data strucuture is kippered by successively calling appropriate stub procedures for each root record in the directed graph. The created Kipperer is an argument to each call on a stub procedure. The session is closed by calling IO.Close on the stream from which the Kipperer was created.
A single unkippering session is started by creating an UnKipperer from an existing IO.STREAM. This UnKipperer is supplied as an argument to successive calls of unkippering stub procedures. This sequence of calls must match the original sequence of kippering calls, Kipper makes no attempt to check. The session is closed by calling IO.Close on the stream from which the UnKipperer was created.
The following section describes how to use Kipper.
2. Using Kipper
General
There are several steps in using Kipper:
1) Write a Kipper source file describing the Cedar type structure to be Kippered.
2) Translate the Kipper source file into a Cedar definitions file and a Cedar implementation file.
3) Write Cedar client code that controls the Kippering and UnKippering.
4) Include both the generated stub implementation code and KipperSupportImpl when running the client code.
A complete working example may by found in Kipper.df, composed from the files:
DemoTestSubject.cm
TestSubject.kipper
TestTestSubject.mesa
TestSubjectPackage.config
TestSubject.load.
Kipper Source File
In order to allow for future flexibility, Kipper uses a special source file to described the type structure, rather than reading Cedar source files, or Cedar BCDs. As an example of this flexibility it will eventually be possible to specify that certain REF types are to be handled by user supplied procedures, rather than by Kipper generated stubs. (This feature is not yet available.) As a convenience, Kipper constructs actual Cedar Type declarations for the described types, and places these declarations in a generated Cedar definitions file.
A Kipper source file closely resembles a Cedar DEFINITIONS file, with a syntax that is close to the Cedar Type syntax. Kipper generates a set of stub procedures for Kippering certain of the types described in this source file. In addition, Kipper will place Cedar type definitions for the described types in the generated DEFINITIONS file.
Here is a simple example of a source file. For other examples, look for files with a ".Kipper" extension in Kipper.df.
Foo: MODULE =
BEGIN
Item: TYPE = REF ItemBody;
ItemBody: TYPE = RECORD[z, b: INT];
Set: CEDAR TYPE FROM FooOther = {a, b, c};
END.
Kipper source files have the following structure:
1) The source file has the extension ".Kipper".
2) It has the following global structure:
Foo: MODULE =
BEGIN
declaration;
...
declaration;
END.
3) Each declaration has one of the two forms:
"name1, ..., nameN: TYPE = typeexp", or
"name1, ..., nameN: CEDAR TYPE FROM FileName = typeexp"
where the names are Cedar Identifier tokens.
4) typeexp is a Cedar Type Constructor, limited to:
Identifier
either a locally declared Identifier, or one of the following pre-declared Cedar types
BOOL
BOOLEAN
CARD ( = Basics.CARD)
CARDINAL
CHAR
CHARACTER
INT
INTEGER
NAT
REAL
ROPE ( = Rope.ROPE)
WORD
REF ANY
REF typeexp
RECORD[ pairlist ]
{ elementlist }
LIST OF typeexp
5) pairlist is a sequence of pairitems separated by commas, where a pairitem has the form
name1, ..., nameN: typeexp
6) an elementlist is a sequence of Cedar Identifiers separated by commas.
7) comments are permitted, using the same syntax as in Cedar source files.
Sometimes one does not want Kipper to generate Cedar type declarations, for example when Kippering types declared in existing system modules. In this case, Kipper permits a reference to an existing type declaration using the CEDAR TYPE FROM construction. When such a reference is made, the Kipper source file must also contain a description of the referenced type structure. It is up to the user to assure that this description is consistent with the existing type declaration, Kipper does not check for consistency. In the simple example given above, it is assumed that there is a Type declaration for Set in FooOther.mesa, and that it has the form "Set: TYPE = {a, b, c}".
Generated Files
Kipper generates two Cedar source files: a definitions file and an implementation file. For a module named Foo, the definitions file is named "Foo.mesa", and the implementation file is named "FooImpl.mesa". The definitions file contains Cedar type declarations for the types described in the Kipper source file, and Kipper and UnKipper procedure declarations for certain REF types. The implementation file contains the bodies of the Kipper and UnKipper procedures.
Stub procedures are generated for each REF type explicitly mentioned in the source file, and if there happen to be record types without an explicitly mentioned REF type, stub procedures are generated for REFs to those record Types.
Stub Procedures
Stub procedures are generated for each REF type mentioned in the Kipper source file. A LIST type is treated as a REF type for this purpose. If a REF ANY is mentioned, REF ANY stub procedures are also generated, which understand the named REF and RECORD types occurring in the source file. In addition, stub procedures are generated for named record types for which no explicit REF type is mentioned. The names of the generated stub procedures are constructed from the type names.
If T is the name of a REF type, then the following two stub procedures are generated:
KipperT: PROC[kipperer: Kipperer, TVal: T];
UnKipperT: PROC[unKipperer: UnKipperer] RETURNS[TVal: T];
If R is the name of a RECORD type for which no no explicite REF type is mentioned, then the following two stub procedures are generated:
KipperRRef: PROC[kipperer: Kipperer, RRef: REF R];
UnKipperRRef: PROC[unKipperer: UnKipperer] RETURNS[RRef: REF R];
Finally, if a REF ANY is mentioned, the following two stub procedures are generated:
KipperANYRef: PROC[kipperer: Kipperer, ANYRef: REF ANY];
UnKipperANYRef: PROC[unKipperer: UnKipperer] RETURNS[ANYRef: REF ANY];
Run time support
Run time support is contained in KipperSupport and KipperSupportImpl. Kipper support contains the following:
1) Type declarations for Kipperer and UnKipperer
2) CreateKipper and CreateUnKipper procedures.
3) Client callable procedures for kippering and unkippering certain simple types, e.g. ROPEs, INTEGERs, etc., within a single session.
4) Procedures that are called by the generated stub procedures.
Client Code
A client program may contain both Kippering and UnKippering code. It has the following general form:
BEGIN
refX: REF X ← ... ;
sOut: IO.STREAM ← ... ;
k:KipperSupport.Kipperer ← KipperSupport.CreateKipperer[sOut];
KipperXRef[k, refX];
sOut.Close[];
END;
BEGIN
sIn: IO.STREAM ← ... ;
uk:KipperSupport.UnKipperer ← KipperSupport.CreateUnKipperer[sIn];
newRefX: REF X;
newRefX ← UnKipperXRef[uk];
sIn.Close[];
END;
If sOut is written to a file, and sIn is later opened on the same file, then newRefX will contain a pointer to a collection of linked allocated objects that is a copy of that to which refX pointed.