Pipal.mesa 
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Created at the beginning of 1988 by Bertrand, Louis & Rick
Louis Monier January 14, 1988 12:54:29 pm PST
Bertrand Serlet May 18, 1988 11:57:35 am PDT
Barth, January 28, 1988 4:20:58 pm PST
DIRECTORY Basics, IO, RefTab, Rope, SafeStorage;
Pipal: CEDAR DEFINITIONS = BEGIN
Theory
Pipal is a sacred fig-tree for the Buddhists. The rest is self-explanatory.
Basic Type Aliases
ROPE: TYPE = Rope.ROPE;
Errors
Error: SIGNAL [reason: ATOM ← $Client, message: ROPENIL, data: REF ANYNIL];
Every procedure which raises this error must document in the interface the reason atoms which it might use.
Classes and Methods
Class: TYPE = SafeStorage.Type;
For efficiency reasons, the class of an object is its Cedar type.
Method: TYPE = NAT;
For efficiency reasons, the implementation deals with a method as an index, not as a pointer to a data structure. Clients should not assume any property of the representation of methods, except that in a single VM two methods are the same if and only if their method index's are equal.
RegisterClass: PROC [name: ROPE, type: SafeStorage.Type] RETURNS [class: Class];
Low level definition of a new class.
Type is the Cedar type of objects af class name. This restricts objects of different classes to be of different types.
Double registration:
- same name, same type or not: legal, but any data attached to old registration is lost; a message is issued in the terminal
- different name, same type: crash
RegisterMethod: PROC [name: ROPE] RETURNS [method: Method];
Low level definition of a new method.
Double registration under the same name: returns a new method index, and any data attached to old method is lost; a message is issued in the terminal
ClassName: PROC [class: Class] RETURNS [name: ROPENIL];
Returns registration name, NIL if class has not been registered.
MethodName: PROC [method: Method] RETURNS [name: ROPENIL];
Returns registration name, NIL if method has not been registered.
PutClassMethod: PROC [class: Class, method: Method, data: REF];
Usually data is a REF PROC.
GetClassMethod: PROC [class: Class, method: Method] RETURNS [data: REFNIL];
Usually data is a REF PROC.
Objects
Object: TYPE = REF;
Objects: TYPE = LIST OF Object;
ObjectClass: PROC [object: Object] RETURNS [class: Class];
Uses the Cedar type of the object and the class registration table to extract the object class.
ObjectMethod: PROC [object: Object, method: Method] RETURNS [data: REFNIL];
Short cut for GetClassMethod[ObjectClass[object], method].
Universal Composition Classes
Overlay
overlayClass: Class;
OverlayIndex: TYPE = NAT;
Overlay: TYPE = REF OverlayRec;
OverlayRec: TYPE = RECORD [children: SEQUENCE size: OverlayIndex OF Object];
void: READONLY Overlay;
Overlay with no element. Neutral element for various operations!
CreateOverlay: PROC [children: Objects] RETURNS [overlay: Overlay];
It is legal for an overlay to have no child, but then it must be void.
Children of an overlay are not ordered.
CreateOv: PROC [children: Objects] RETURNS [Object];
Optimizes the creation of an overlay for the case when there is only one child.
ExpandOverlay: PROC [object: Pipal.Object] RETURNS [children: Objects ← NIL];
Crash and burn if the object is not an overlay.
Icon
iconClass: Class;
Icon: TYPE = REF IconRec;
IconRec: TYPE = RECORD [
reference: Object, -- the appearance (painted)
referent: Object]; -- the guts
CreateIcon: PROC [reference: Object, referent: Object] RETURNS [icon: Icon];
Annotation
The annotation class can be used for any immutable annotation (i.e. a property whose key and value will never change during a VM).
annotationClass: Class;
Annotation: TYPE = REF AnnotationRec;
AnnotationRec: TYPE = RECORD [
child: Object,
key: ATOM,
value: REF
];
CreateAnnotation: PROC [child: Object, key: ATOM, value: REF] RETURNS [annotation: Annotation];
It is convenient when objects are created by code, to name them without using visible properties.
nameProp: ATOM;
The annotation value must the name ROPE.
Universal Methods
Hash
High quality hashing.
hashMethod: Method;
HashProc: TYPE = PROC [object: Object] RETURNS [hash: CARD];
Hash: HashProc;
No describeMethod method => HashObjectClass[object>]".
HashObjectClass: HashProc;
Hashes the class of the object.
Equal
Since high quality hashing exists, efficient conservative equality is possible.
Having an equality implies:
- maximum sharing by avoiding creation of duplicate objects;
- successive unpickling produce identical objects ...
- therefore allowing for a simple saving of caches;
- possibility to implement utilities such as diff.
equalMethod: Method;
EqualProc: TYPE = PROC [object1, object2: Object] RETURNS [equal: BOOLFALSE];
Invariant: Equal[object1, object2] => Class[object1]=Class[object2] and Hash[object1]=Hash[object2].
EqualProcs can assume that object1 and object2 are of the same class.
Equal: EqualProc;
If objects are REF-equal it is easy.
If classes are different or if hashes are different, objects must be different.
Then, if there is an EqualProc, it is applied; otherwise FALSE is returned.
Describe
The describe method is useful for debugging and (poor) user-interface.
describeMethod: Method;
DescribeProc: TYPE = PROC [out: IO.STREAM, object: Object, indent: NAT ← 0, level: NAT ← 2, cr: BOOLTRUE];
Describe: DescribeProc;
No describeMethod method => "<ClassName> object".
Debugging feature: also knows how to describe object RefTabs, object SymTabs, and list of objects.
DescribeToRope: PROC [object: Object, indent: NAT ← 0, level: NAT ← 1, cr: BOOLFALSE] RETURNS [ROPE];
Same as previous but returns a ROPE.
PutIndent: PROC [out: IO.STREAM, indent: NAT, cr: BOOLTRUE];
Utility that puts on out a CR (iff cr) followed by indent spaces.
Utilities
This section regroups various utilities always useful.
Object Caches
ObjectCache: TYPE = RefTab.Ref;
CreateObjectCache: PROC RETURNS [ObjectCache];
Creates a new RefTab, and keeps a pointer on it in order to be able to do flushes.
FlushObjectCaches: PROC [object: Object];
Flushes all object caches for object.
Operations on objects
Reverse: PROC [objects: Objects] RETURNS [Objects];
Reverses!
Add: PROC [objects: Objects, candidate: Object] RETURNS [Objects];
Same list is returned if candidate is already a member.
Delete: PROC [objects: Objects, candidate: Object] RETURNS [Objects];
Same list is returned if candidate is not a member.
Member: PROC [objects: Objects, candidate: Object] RETURNS [BOOL];
Searches for candidate in objects.
Length: PROC [objects: Objects] RETURNS [INT];
Returns the # of elements in the list.
CompareProc: TYPE = PROC [object1, object2: Object] RETURNS [Basics.Comparison];
Sort: PROC [objects: Objects, compare: CompareProc] RETURNS [Objects];
Attention: modifies in place objects!
Objects Predicates
AlwaysTrue: PROC [Object] RETURNS [BOOL];
AlwaysFalse: PROC [Object] RETURNS [BOOL];
Class Tables
It is often convenient to have tables keyed by Class. The implementation of Pipal itself uses such convenience.
ClassTable: TYPE = REF ClassTableRec;
ClassTableRec: PRIVATE TYPE = ARRAY SafeStorage.TypeIndex OF REF;
Clients should not depend on this type, as representation might change.
CreateClassTable: PROC RETURNS [table: ClassTable];
StoreInClassTable: PROC [table: ClassTable, class: Class, value: REF];
FetchFromClassTable: PROC [table: ClassTable, class: Class] RETURNS [value: REFNIL];
END.