123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- DEFSTRUCT - "Structure" definition facility.
- --------------------------------------------
- Defstruct is similar to the Spice (Common) Lisp/Lisp machine/Maclisp flavor
- of struct definitions, and is expected to be subsumed by the Mode package.
- It is implemented in PSL as a function which builds access macros and fns
- for "typed" vectors, including constructor and alterant macros, a type
- predicate for the structure type, and individual selector/assignment fns
- for the elements. Defstruct understands a keyword-option oriented
- structure specification.
- First a few miscellaneous functions on types, before we get into the depths
- of defining Defstructs:
- DefstructP( NAME:id ): extra-boolean expr
- ---- -- ------------- ----
- is a predicate that returns non-NIL (the Defstruct definition) if NAME
- is a structured type which has been defined using Defstruct, or NIL if
- it is not.
- DefstructType( S:struct ): id expr
- - ------ -- ----
- returns the type name field of an instance of a structured type, or
- NIL if S cannot be a defstruct type.
- SubTypeP( NAME1:id, NAME2:id ): boolean expr
- ----- -- ----- -- ------- ----
- returns true if NAME1 is a structured type which has been !:Include'd in
- the definition of structured type NAME2, possibly through intermediate
- structure definitions. (In other words, the selectors of NAME1 can be
- applied to NAME2.)
- Now the function which defines the beasties, in all its gory glory:
- Defstruct( name-and-options:{id,list}, [slot-descs:{id,list}] ): id fexpr
- ---------------- -- ---- ---------- -- ---- -- -----
- Defines a record-structure data type. A general call to defstruct
- looks like this: (in Rlisp syntax)
- defstruct( struct-name( option-1, option-2, ... ),
- slot-description-1,
- slot-description-2,
- ...
- ); % (The name of the defined structure is returned.)
- where slot-descriptions are:
- slot-name( default-init, slot-option-1, slot-option-2, ... )
- Struct-name and slot-name are id's. If there are no options following
- a name in a spec, it can be a bare id with no option argument list.
- The default-init form is optional and may be omitted. The default-init
- form is evaluated EACH TIME a structure is to be constructed and the
- value is used as the initial value of the slot. Options are either a
- keyword id, or the keyword followed by its argument list. Options are
- described below.
- A call to a Constructor macro has the form:
- MakeThing( slot-name-1( value-expr-1 ),
- slot-name-2( value-expr-2 ),
- ... );
- where the slot-name:value lists override the default-init values
- which were part of the structure definition. Note that the
- slot-names look like unary functions of the value, so the parens can
- be left off. A call to MakeThing with no arguments of course takes
- all of the default values. The order of evaluation of the
- default-init forms and the list of assigned values is undefined, so
- code should not depend upon the ordering.
- Implementors Note: Common/LispMachine Lisps define it this
- way, but Is this necessary? It wouldn't be too tough to
- make the order be the same as the struct defn, or the
- argument order in the constructor call. Maybe they think
- such things should not be advertized and thus constrained
- in the future. Or perhaps the theory is that constucts
- such as this can be compiled more efficiently if the
- ordering is flexible?? Also, should the overridden
- default-init forms be evaluated or not? I think not.
- The Alterant macro calls have a similar form:
- AlterThing( thing,
- slot-name-1 value-expr-1,
- slot-name-2 value-expr-2,
- ... );
- where the first argument evaluates to the struct to be altered. (The
- optional parens were left off here.) This is just a
- multiple-assignment form, which eventually goes through the slot
- depositors. Remember that the slot-names are used, not the depositor
- names. (See !:Prefix, below.) The altered structure instance
- is returned as the value of an Alterant macro.
- Implementators note: Common/LispMachine Lisp defines this
- such that all of the slots are altered in parallel AFTER
- the new value forms are evaluated, but still with the order
- of evaluation of the forms undefined. This seemed to lose
- more than it gained, but arguments for its worth will be
- entertained.
- Options:
- Structure options appear as an argument list to the struct-name. Many
- of the options themselves take argument lists, which are sometimes
- optional. Option id's all start with a colon (!:), on the theory that
- this distinguishes them from other things.
- By default, the names of the constructor, alterant and predicate
- macros are MakeName, AlterName and NameP, where "Name" is the
- struct-name. The !:Constructor, !:Alterant, and !:Predicate options
- can be used to override the default names. Their argument is the
- name to use, and a name of NIL causes the respective macro not to be
- defined at all.
- The !:Creator option causes a different form of constructor to be
- defined, in addition to the regular "Make" constructor (which can be
- suppressed.) As in the !:Constructor option above, an argument
- supplies the name fo the macro, but the default name in this case is
- CreateName. A call to a Creator macro has the form:
- CreateThing( slot-value-1, slot-value-2, ... );
- where ALL of the slot-values of the structure MUST BE PRESENT, in the
- order they appear in the structure definition. No checking is done,
- other than assuring that the number of values is the same as the
- number of slots. For obvous reasons, constructors of this form ARE
- NOT RECOMMENDED for structures with many fields, or which may be
- expanded or modified.
- Slot selector macros may appear on either the LHS or the RHS of an
- assignment. They are by default named the same as the slot-names,
- but can be given a common prefix by the !:Prefix option. If
- !:Prefix does not have an argument, the structure name is the
- prefix. If there is an argument, it should be a string or an id
- whose printname is the prefix.
- The !:Include option allows building a new structure definition as an
- extension of an old one. The required argument is the name of a
- previously defined structure type. The access functions for the
- slots of the source type will also work on instances of the new type.
- This can be used to build hierarchies of types, where the source
- types contain generic information in common to the more specific
- subtypes which !:Include them.
- The !:IncludeInit option takes an argument list of
- "slot-name(default-init)" pairs, like slot-descriptors without
- slot-options, and files them away to modify the default-init values for
- fields inherited as part of the !:Include'd structure type.
- Slot Options:
- Slot-options include the !:Type option, which has an argument
- declaring the type of the slot as a type id or list of permissible
- type id's. This is not enforced now, but anticipates the Mode system
- structures.
- The !:UserGet and !:UserPut slot-options allow overriding the simple
- vector reference and assignment semantics of the generated selector
- macros with user-defined functions. The !:UserGet fn name is a
- combination of the slot-name and a !:Prefix if applicable. The
- !:UserPut fn name is the same, with "Put" prefixed. One application
- of this capability is building depositors which handle the
- incremental maintenance of parallel datastructures as a side effect,
- such as automatically maintaining display file representations of
- objects which are resident in a remote display processor in parallel
- with modifications to the Lisp structures which describe the objects.
- The Make and Create macros bypass the depositors, while Alter uses them.
- A simple example: (Input lines have a "> " prompt at the beginning.)
- > % (Do definitions twice to see what functions were defined.)
- > macro procedure TWICE u; list( 'PROGN, second u, second u );
- TWICE
- > % A definition of Complex, structure with Real and Imaginary parts.
- > % Redefine to see what functions were defined. Give 0 Init values.
- > TWICE
- > Defstruct( Complex( !:Creator(Complex) ), R(0), I(0) );
- *** Function `MAKECOMPLEX' has been redefined
- *** Function `ALTERCOMPLEX' has been redefined
- *** Function `COMPLEXP' has been redefined
- *** Function `COMPLEX' has been redefined
- *** Function `R' has been redefined
- *** Function `PUTR' has been redefined
- *** Function `I' has been redefined
- *** Function `PUTI' has been redefined
- *** Defstruct `COMPLEX' has been redefined
- COMPLEX
- > C0 := MakeComplex(); % Constructor with default inits.
- [COMPLEX 0 0]
- > ComplexP C0; % Predicate.
- T
- > C1:=MakeComplex( R 1, I 2 ); % Constructor with named values.
- [COMPLEX 1 2]
- > R(C1); I(C1); % Named selectors.
- 1
- 2
- > C2:=Complex(3,4) % Creator with positional values.
- [COMPLEX 3 4]
- > AlterComplex( C1, R(2), I(3) ); % Alterant with named values.
- [COMPLEX 2 3]
- > C1;
- [COMPLEX 2 3]
- > R(C1):=5; I(C1):=6; % Named depositors.
- 5
- 6
- > C1;
- [COMPLEX 5 6]
- > % Show use of Include Option. (Again, redef to show fns defined.)
- > TWICE
- > Defstruct( MoreComplex( !:Include(Complex) ), Z(99) );
- *** Function `MAKEMORECOMPLEX' has been redefined
- *** Function `ALTERMORECOMPLEX' has been redefined
- *** Function `MORECOMPLEXP' has been redefined
- *** Function `Z' has been redefined
- *** Function `PUTZ' has been redefined
- *** Defstruct `MORECOMPLEX' has been redefined
- MORECOMPLEX
- > M0 := MakeMoreComplex();
- [MORECOMPLEX 0 0 99]
- > M1 := MakeMoreComplex( R 1, I 2, Z 3 );
- [MORECOMPLEX 1 2 3]
- > R C1;
- 5
- > R M1;
- 1
- > % A more complicated example: The structures which are used in the
- > % Defstruct facility to represent defstructs. (The EX prefix has
- > % been added to the names to protect the innocent...)
- > TWICE % Redef to show fns generated.
- > Defstruct(
- > EXDefstructDescriptor( !:Prefix(EXDsDesc), !:Creator ),
- > DsSize( !:Type int ), % (Upper Bound of vector.)
- > Prefix( !:Type string ),
- > SlotAlist( !:Type alist ), % (Cdrs are SlotDescriptors.)
- > ConsName( !:Type fnId ),
- > AltrName( !:Type fnId ),
- > PredName( !:Type fnId ),
- > CreateName( !:Type fnId ),
- > Include( !:Type typeid ),
- > InclInit( !:Type alist )
- > );
- *** Function `MAKEEXDEFSTRUCTDESCRIPTOR' has been redefined
- *** Function `ALTEREXDEFSTRUCTDESCRIPTOR' has been redefined
- *** Function `EXDEFSTRUCTDESCRIPTORP' has been redefined
- *** Function `CREATEEXDEFSTRUCTDESCRIPTOR' has been redefined
- *** Function `EXDSDESCDSSIZE' has been redefined
- *** Function `PUTEXDSDESCDSSIZE' has been redefined
- *** Function `EXDSDESCPREFIX' has been redefined
- *** Function `PUTEXDSDESCPREFIX' has been redefined
- *** Function `EXDSDESCSLOTALIST' has been redefined
- *** Function `PUTEXDSDESCSLOTALIST' has been redefined
- *** Function `EXDSDESCCONSNAME' has been redefined
- *** Function `PUTEXDSDESCCONSNAME' has been redefined
- *** Function `EXDSDESCALTRNAME' has been redefined
- *** Function `PUTEXDSDESCALTRNAME' has been redefined
- *** Function `EXDSDESCPREDNAME' has been redefined
- *** Function `PUTEXDSDESCPREDNAME' has been redefined
- *** Function `EXDSDESCCREATENAME' has been redefined
- *** Function `PUTEXDSDESCCREATENAME' has been redefined
- *** Function `EXDSDESCINCLUDE' has been redefined
- *** Function `PUTEXDSDESCINCLUDE' has been redefined
- *** Function `EXDSDESCINCLINIT' has been redefined
- *** Function `PUTEXDSDESCINCLINIT' has been redefined
- *** Defstruct `EXDEFSTRUCTDESCRIPTOR' has been redefined
- EXDEFSTRUCTDESCRIPTOR
- > TWICE % Redef to show fns generated.
- > Defstruct(
- > EXSlotDescriptor( !:Prefix(EXSlotDesc), !:Creator ),
- > SlotNum( !:Type int ),
- > InitForm( !:Type form ),
- > SlotFn( !:Type fnId ), % Selector/Depositor id.
- > SlotType( !:Type type ), % Hm...
- > UserGet( !:Type boolean ),
- > UserPut( !:Type boolean )
- > );
- *** Function `MAKEEXSLOTDESCRIPTOR' has been redefined
- *** Function `ALTEREXSLOTDESCRIPTOR' has been redefined
- *** Function `EXSLOTDESCRIPTORP' has been redefined
- *** Function `CREATEEXSLOTDESCRIPTOR' has been redefined
- *** Function `EXSLOTDESCSLOTNUM' has been redefined
- *** Function `PUTEXSLOTDESCSLOTNUM' has been redefined
- *** Function `EXSLOTDESCINITFORM' has been redefined
- *** Function `PUTEXSLOTDESCINITFORM' has been redefined
- *** Function `EXSLOTDESCSLOTFN' has been redefined
- *** Function `PUTEXSLOTDESCSLOTFN' has been redefined
- *** Function `EXSLOTDESCSLOTTYPE' has been redefined
- *** Function `PUTEXSLOTDESCSLOTTYPE' has been redefined
- *** Function `EXSLOTDESCUSERGET' has been redefined
- *** Function `PUTEXSLOTDESCUSERGET' has been redefined
- *** Function `EXSLOTDESCUSERPUT' has been redefined
- *** Function `PUTEXSLOTDESCUSERPUT' has been redefined
- *** Defstruct `EXSLOTDESCRIPTOR' has been redefined
- EXSLOTDESCRIPTOR
- > END;
- NIL
|