;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: The si:defstruct-description Structure =Text: 3THE SI:DEFSTRUCT-DESCRIPTION STRUCTURE* This section discusses the internal structures used by 2defstruct* that might be useful to programs that want to interface to 2defstruct* nicely. For example, if you want to write a program that examines structures and displays them the way 2describe* (see 4(MISCELL-1)Poking Around in the Lisp World*) and the Inspector do, your program should work by examining these structures. The information in this section is also necessary for anyone who is thinking of defining his own structure types. Whenever the user defines a new structure using 2defstruct*, 2defstruct* creates an instance of the 2si:defstruct-description* structure. This can be found as the 2si:defstruct-description* property of the name of the structure; it contains such useful information as the number of slots in the structure, the 2defstruct* options specified, and so on. This is a simplified version of the way the 2si:defstruct-description* structure is defined. It omits some slots whose meaning is not worth documenting here. (The actual definition is in the 2system-internals* package.) 3(defstruct (defstruct-description* 3 (:default-pointer description)* 3 (:conc-name defstruct-description-))* 3 name* 3 size* 3 property-alist* 3 slot-alist* 3 documentation)* The 2name* slot contains the symbol supplied by the user to be the name of his structure, such as 2spaceship* or 2phone-book-entry*. The 2size* slot contains the total number of slots in an instance of this kind of structure. This is 1not* the same number as that obtained from the 2:size-symbol* or 2:size-macro* options to 2defstruct*. A named structure, for example, usually uses up an extra location to store the name of the structure, so the 2:size-macro* option will get a number one larger than that stored in the 2defstruct* description. The 2property-alist* slot contains an alist with pairs of the form 2(1property-name* . 1property*)* containing properties placed there by the 2:property* option to 2defstruct* or by property names used as options to 2defstruct* (see the 2:property* option, 4(DEFSTRUCT-1)Options to Defstruct*). The 2slot-alist* slot contains an alist of pairs of the form 2(1slot-name* . 1slot-description*)*. A 1slot-description* is an instance of the 2defstruct-slot-description* structure. The 2defstruct-slot-description* structure is defined something like this (with other slots that are omitted here), also in the 2si* package: 3(defstruct (defstruct-slot-description* 3 (:default-pointer slot-description)* 3 * 3:conc-name)* 3 number* 3 ppss* 3 init-code* 3 type* 3 property-alist* 3 ref-macro-name* 3 documentation)* The 2number* slot contains the number of the location of this slot in an instance of the structure. Locations are numbered, starting with 0, and continuing up to a number one less than the size of the structure. The actual location of the slot is determined by the reference-consing function associated with the type of the structure; see 4(DEFSTRUCT-3)Options to si:defstruct-define-type*. The 2ppss* slot contains the byte specifier code for this slot if this slot is a byte field of its location. If this slot is the entire location, then the 2ppss* slot contains 2nil*. The 2init-code* slot contains the initialization code supplied for this slot by the user in his 2defstruct* form. If there is no initialization code for this slot then the init-code slot contains a canonical object which can be obtained (for comparison using 2eq*) as the result of 2(si:defstruct-empty)*. The 2ref-macro-name* slot contains the symbol that is defined as a macro or a subst that expands into a reference to this slot (that is, the name of the accessor function). =Node: Extensions to Defstruct =Text: 3EXTENSIONS TO DEFSTRUCT* The macro 2si:defstruct-define-type* can be used to teach 2defstruct* about new types that it can use to implement structures. 3si:defstruct-define-type* 1Macro* Is used for teaching 2defstruct* about new types. The syntax of 2si:defstruct-define-type* is: 3(si:defstruct-define-type 1type** 3 1option-1* 1option-2* 2...*)* where each 1option* is either the symbolic name of an option or a list of the form 2(1option-name** 2. 1rest*)*. Different options interpret 1rest* in different ways. The symbol 1type* is given an 2si:defstruct-type-description* property of a structure that describes the type completely. The semantics of 2si:defstruct-define-type* is the subject of the rest of this section. =Node: Example =Text: 3EXAMPLE* Let us start by examining a sample call to 2defstruct-define-type*. This is how the 2:list* type of structure might have been defined: 3(si:defstruct-define-type :list* 3 (:cons (initialization-list description* 3 keyword-options) * 3 :list* 3 `(list . ,initialization-list))* 3 (:ref (slot-number description argument)* 3 `(nth ,slot-number ,argument)))* This is the simplest possible form of 2defstruct-define-type*. It provides 2defstruct* with two Lisp forms: one for creating forms to construct instances of the structure, and one for creating forms to become the bodies of accessors for slots of the structure. The keyword 2:cons* is followed by a list of three variables that will be bound while the constructor-creating form is evaluated. The first, 2initialization-list*, will be bound to a list of the initialization forms for the slots of the structure. The second, 2description*, will be bound to the 2defstruct-description* structure for the structure (see 4(DEFSTRUCT-3)The si:defstruct-description Structure*). The third variable and the 2:list* keyword will be explained later. The keyword 2:ref* is followed by a list of three variables that will be bound while the accessor-creating form is evaluated. The first, 2slot-number*, will bound to the number of the slot that the new accessor should reference. The second, 2description*, will be bound to the 2defstruct-description* structure for the structure. The third, 2argument*, will be bound to the form that was provided as the argument to the accessor. =Node: Options to si:defstruct-define-type =Text: 3OPTIONS TO SI:DEFSTRUCT-DEFINE-TYPE* This section is a catalog of all the options currently known about by 2si:defstruct-define-type*. 2:cons* Specifies the code to cons up a form that will construct an instance of a structure of this type. The 2:cons* option has the syntax: 3(:cons (1inits* 1description* 1keywords*) 1kind** 3 1body*)* 1body* is some code that should construct and return a piece of code that will construct, initialize, and return an instance of a structure of this type. The symbol 1inits* will be bound to the information that the constructor conser should use to initialize the slots of the structure. The exact form of this argument is determined by the symbol 1kind*. There are currently two kinds of initialization. There is the 2:list* kind, where 1inits* is bound to a list of initializations, in the correct order, with 2nil*s in uninitialized slots. And there is the 2:alist* kind, where 1inits* is bound to an alist with pairs of the form 2(1slot-number* . 1init-code*)*. Additional kinds may be provided in the future. The symbol 1description* will be bound to the instance of the 2defstruct-description* structure (see 4(DEFSTRUCT-3)The si:defstruct-description Structure*) that 2defstruct* maintains for this particular structure. This is so that the constructor conser can find out such things as the total size of the structure it is supposed to create. The symbol 1keywords* will be bound to an alist with pairs of the form 2(1keyword* .* 1value2)**, where each 1keyword* was a keyword supplied to the constructor that wasn't the name of a slot, and 1value* was the Lisp object that followed the keyword. This is how you can make your own special keywords, like the existing 2:make-array* and 2:times* keywords. See the section on using the constructor, 4(DEFSTRUCT-2)Constructors*. You specify the list of acceptable keywords with the 2:cons-keywords* option (see 4(DEFSTRUCT-3)Options to si:defstruct-define-type*). It is an error not to supply the 2:cons* option to 2si:defstruct-define-type*. 2:ref* Specifies the code to cons up a form that will reference an instance of a structure of this type. The 2:ref* option has the syntax: 3(:ref (1number* 1description* 1arg-1* 2...* 1arg-n*)* 3 1body*)* 1body* is some code that should construct and return a piece of code that will reference an instance of a structure of this type. The symbol 1number* will be bound to the location of the slot that is to be referenced. This is the same number that is found in the number slot of the 2defstruct-slot-description* structure (see 4(DEFSTRUCT-3)The si:defstruct-description Structure*). The symbol 1description* will be bound to the instance of the 2si:defstruct-description* structure that 2defstruct* maintains for this particular structure. The symbols 1arg-i* are bound to the forms supplied to the accessor as arguments. Normally there should be only one of these. The 1last* argument is the one that will be defaulted by the 2:default-pointer* option (see 4(DEFSTRUCT-1)Options to Defstruct*). 2defstruct* will check that the user has supplied exactly 1n* arguments to the accessor function before calling the reference consing code. It is an error not to supply the 2:ref* option to 2si:defstruct-define-type*. 2:overhead* Declares to 2defstruct* that the implementation of this particular type of structure ``uses up'' some number of locations in the object actually constructed. This option is used by various ``named'' types of structures that store the name of the structure in one location. For example, named arrays have an overhead of one, and named array leaders an overhead of two, but named typed arrays have no overhead since the structure type symbol is stored in the array leader whilst the actual data specifying the values of the slots is stored in the array proper. The syntax of 2:overhead* is 2(:overhead 1n*)*, where 1n* is a fixnum that says how many locations of overhead this type needs. This number is used only by the 2:size-macro* and 2:size-symbol* options to 2defstruct* (see 4(DEFSTRUCT-1)Options to Defstruct*). 2:named* Controls the use of the 2:named* option to 2defstruct*. With no argument, the 2:named* option means that this type is one which records the structure type name somehow (not necessarily by using an actual named structure). With an argument, as in 2(:named* 1type-name2)**, the symbol 1type-name* should be the name of some other structure type that 2defstruct* should use if the user specifies this type and 2:named* as well. For example, the definition of the 2:list* type contains 2(:named :named-list)*, saying that a 2defstruct* that specifies 2(:list :named)* really uses type 2:named-list*. 2:cons-keywords* Defines additional constructor keywords for this type of structure. Using these keywords, one may specify additional information about a structure at the time it is created (``consed'') using one of its constructor functions or macros. (The 2:times* constructor keyword for structures of type 2:grouped-array* is an example.) The syntax is: 2(:cons-keywords 1keyword-1* ... 1keyword-n*)* where each 1keyword* is a symbol that the constructor conser expects to find in the 1keywords* alist (explained above). 2:keywords* 2:keywords* is an old name for the 2:cons-keywords* option. 2:defstruct-keywords* Defines additional 2defstruct* options allowed for this type of structure. (The 2:subtype* option for structures of type 2:array* is an example.) These options take effect at the time the structure is defined using 2defstruct*, and thus affect all structures of a particular type (unless overridden in some way.) In contrast, the 2:cons-keywords* options affect the creation of individual structures of a particular type. The syntax is: 2(:defstruct-keywords 1keyword-1* ... 1keyword-n*)* where each 1keyword* is a keyword that 2defstruct* will recognize as an option. 2defstruct* puts such options, with their values, in the 2property-alist* slot of the 2defstuct-description* structure (defined above) 2:predicate* Tells 2defstruct* how to produce predicates for a particular type (for the 2:predicate* option to 2defstruct*). Its syntax is: 3(:predicate (1description* 1name*)* 3 1body2...**)* The variable 1description* is bound to the 2defstruct-description* structure maintained for the structure for which a predicate is being generated. The variable 1name* is bound to the symbol that is to be defined as a predicate. 1body* is a piece of code to compute the defining form for the predicate. A typical use of this option might look like: 3(:predicate (description name)* 3 `(defun ,name (x)* 3 (and (frobbozp x)* 3 (eq (frobbozref x 0)* 3 ',(si:defstruct-description-name* 3 description))))) 2:copier** 2defstruct* knows how to generate a copier function using the constructor and reference code that must be provided with any new defstruct type. Nevertheless it is sometimes desirable to specify a specific method of copying a particular defstruct type. The 2:copier* option to 2si:defstruct-define-type* allow this to be done: 3(:copier (1description* 1name*)* 3 1body*)* As with the 2:predicate* option, 1description* is bound to an instance of the 2defstruct-description* structure, 1name* is bound to the symbol to be defined, and 1body* is some code to evaluate to get the defining form. For example: 3(:copier (description name)* 3 `(fdefine ',name 'copy-frobboz)) 2:defstruct** The 2:defstruct* option to 2si:defstruct-define-type* allows the user to run some code and return some forms as part of the expansion of the 2defstruct* macro. The 2:defstruct* option has the syntax: 3(:defstruct (1description*)* 3 1body*)* 1body* is a piece of code that will be run whenever 2defstruct* is expanding a 2defstruct* form that defines a structure of this type. The symbol 1description* will be bound to the instance of the 2defstruct-description* structure that 2defstruct* maintains for this particular structure. The value returned by the 1body* should be a 1list* of forms to be included with those that the 2defstruct* expands into. Thus, if you only want to run some code at 2defstruct*-expand time, and you don't want to actually output any additional code, then you should be careful to return 2nil* from the code in this option. 2defstruct* will cause the 1body* forms to be evaluated as early as possible in the parsing of a structure definition, and cause the returned forms to be evalutated as late as possible in the macro-expansion of the 2defstuct* forms. This is so that 1body* can rehack arguments, signal errors, and the like before many of 2defstruct*'s internal forms are executed, while enabling it to return code which will modify or extend the default forms produced by a vanilla 2defstruct*.