rs@uunet.UU.NET (Rich Salz) (08/04/87)
Submitted-by: Roy D'Souza <dsouza%hplabsc@hplabs.HP.COM> Posting-number: Volume 10, Issue 87 Archive-name: comobj.lisp/Part13 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 13 (of 13)." # Contents: co-parse.l PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'co-parse.l' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'co-parse.l'\" else echo shar: Extracting \"'co-parse.l'\" \(56836 characters\) sed "s/^X//" >'co-parse.l' <<'END_OF_FILE' X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; X; File: co-parse.l X; RCS: $Revision: 1.1 $ X; SCCS: %A% %G% %U% X; Description: Commonobjects parser for the Commonobjects-Commonloops X; interface. X; Author: Roy D'Souza, HPL/DCC X; Created: 20-Nov-86 X; Modified: 4-Mar-87 11:22:29 (James Kempf) X; Mode: Lisp X; Package: COMMON-OBJECTS-PARSER X; Status: Distribution X; X; (c) Copyright 1987, HP Labs, all rights reserved. X; X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; X; Copyright (c) 1987 Hewlett-Packard Corporation. All rights reserved. X; X; Use and copying of this software and preparation of derivative works based X; upon this software are permitted. Any distribution of this software or X; derivative works must comply with all applicable United States export X; control laws. X; X; This software is made available AS IS, and Hewlett-Packard Corporation makes X; no warranty about the software, its performance or its conformity to any X; specification. X; X; Suggestions, comments and requests for improvement may be mailed to X; aiws@hplabs.HP.COM X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Preliminaries X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X(provide "co-parse") X X;;;Package COMMON-OBJECTS-PARSER contains the parser. For ease of X;;; typing, CO-PARSER can be used. X X;;;These symbols from the COMMON-OBJECTS package are needed at compile X;;; time. Create the package if not there. Note that I don't want X;;; to export them, because a user of the COMMON-OBJECTS package X;;; shouldn't know about them. I therefore use fully qualified X;;; symbols in the code. X X(in-package :common-objects :nicknames '(co) :use '(lisp pcl)) X(intern "ASSIGNEDP") X(intern "METHOD-ALIST") X(intern "SELF") X(intern "INIT-KEYWORDS") X(intern "LEGAL-PARENT-P") X(in-package 'common-objects-parser :nicknames '(co-parser) :use '(lisp pcl)) X X;;Export functions needed for parsing X X(export X '( X co-parse-define-type-call X co-parse-method-macro-call X co-parse-call-to-method X co-process-var-options X co-parse-options X co-deftype-error X co-legal-type-or-method-name X $UNDEFINED-TYPE-NAME X $TYPE-INFO-SLOT X $TYPE-NAME-SLOT X $VARIABLE-NAMES-SLOT X $INITABLE-VARIABLES-SLOT X $SETTABLE-VARIABLES-SLOT X $GETTABLE-VARIABLES-SLOT X $PARENT-TYPES-SLOT X $PARENTS-INFO-SLOT X $A-LIST-METHOD-TABLE-SLOT X $TREAT-AS-VARIABLES-SLOT X $INIT-KEYWORDS-SLOT X $NO-INIT-KEYWORD-CHECK-SLOT X $METHODS-TO-NOT-DEFINE-SLOT X $METHODS-TO-INHERIT-SLOT X $LET-PSEUDO-INFO-SLOT X $INFO-NUMBER-OF-SLOTS X X ) X) X X;;Need the PCL and pcl-patches module X(require "pcl") X(require "pcl-patches") X X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Constant Definition X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X;;Type names are set to this when types are undefined. X X(defconstant $UNDEFINED-TYPE-NAME '*now-an-undefined-type*) X X;;Offsets into the vector used to parse type definitions. X X(defconstant $TYPE-INFO-SLOT 0) X X(defconstant $TYPE-NAME-SLOT 1) X X(defconstant $VARIABLE-NAMES-SLOT 2) X X(defconstant $INITABLE-VARIABLES-SLOT 3) X X(defconstant $SETTABLE-VARIABLES-SLOT 4) X X(defconstant $GETTABLE-VARIABLES-SLOT 5) X X(defconstant $PARENT-TYPES-SLOT 6) X X(defconstant $PARENTS-INFO-SLOT 7) X X(defconstant $A-LIST-METHOD-TABLE-SLOT 8) X X(defconstant $TREAT-AS-VARIABLES-SLOT 9) X X(defconstant $INIT-KEYWORDS-SLOT 10) X X(defconstant $NO-INIT-KEYWORD-CHECK-SLOT 11) X X(defconstant $METHODS-TO-NOT-DEFINE-SLOT 12) X X(defconstant $METHODS-TO-INHERIT-SLOT 13) X X(defconstant $LET-PSEUDO-INFO-SLOT 14) X X(defconstant $EXPLICITLY-LISTED-METHODS-SLOT 15) X X;;List of all universal method names X X(defconstant X $DEFINE-TYPE-UNIVERSAL-METHODS X '(:describe X :print X :initialize X :initialize-variables X :init X :eql X :equal X :equalp X :typep X :copy X :copy-state X :copy-instance) X) X X;;Size of the vector used in type definition parsing. X X(defconstant $INFO-NUMBER-OF-SLOTS 16) X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; General Macro Definitions X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X(defmacro get-parents-info (type-info) X X; Allow for more convenient access of parent information. X X `(aref ,type-info $parents-info-slot)) X X(defmacro set-parents-info (type-info new-value) X `(setf (aref ,type-info $parents-info-slot) ,new-value)) X X(defmacro co-deftype-error (format &rest arguments) X X `(error (concatenate 'simple-string X "DEFINE-TYPE: In type '~s', " X ,format) X ,@arguments)) X X X(defmacro define-method-error (format &rest arguments) X X `(error X (format nil X (concatenate 'simple-string "DEFINE-METHOD: " ,format) X ,@arguments))) X X(defmacro return-keyword-from-variable (var) X `(intern ,var (find-package "KEYWORD")) X) X X;;type-partially-defined?-Find out if a CommonLoops class is X;; defined and return the class object if so. X X(defmacro type-partially-defined? (name) X X `(class-named ,name T)) X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; General Function and Method Definitions X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X;;type-name-Return the name of the type X X(defun type-name (tinfo) X X (if (%instancep tinfo) X (class-name tinfo) X (svref tinfo $TYPE-NAME-SLOT) X ) X X) ;type-name X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Top Level Type Definition X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X X(defun co-parse-define-type-call X (define-type-call type-name doc-string options-list) X X; Parse the various pieces of the call to DEFINE-TYPE. Return multiple values X; of the form: (TYPE-NAME DOC-STRING OPTIONS-LIST) OPTIONS-LIST doesn't have to X; exist. If it doesn't, NIL is returned for it value (assuming NIL is X; given as their initial value passed into the routine). In either X; case it is disreguarded. Example call, DEFINE-TYPE-CALL = X; (DEFINE-TYPE NOSE (:INHERIT-FROM PARENT)). X X (setf define-type-call (cdr define-type-call)) X X; This should now be the list of arguments to the DEFINE-TYPE. X; Example define-type-call = (NOSE (:INHERIT-FROM PARENT)). X X (unless (proper-list define-type-call) X X ; THEN The call to DEFINE-TYPE is not a proper list. X X (error X (format nil X "DEFINE-TYPE: The call,~% (DEFINE-TYPE '~S'),~% is missing arguments or is not a proper list." X define-type-call))) X X; Get the name of the type X X (setf type-name (first define-type-call)) X (setf define-type-call (cdr define-type-call)) X X; see if there is a documentation string X X (when X (setq doc-string X (and (consp define-type-call) X (stringp (car (the cons define-type-call))) X (list (car (the cons define-type-call))) X ; list form for ,@ substitution X )) X (setf define-type-call (cdr define-type-call))) X X; Example, define-type-call = ((:INHERIT-FROM PARENT)). X; Now look for options. X X (when (consp define-type-call) X X ; THEN We have options. X X (setf options-list define-type-call)) X X; Return the parsed fields as a list for MULTIPLE-VALUE-SETQ X X (values type-name doc-string options-list) X X) ;co-parse-define-type-call X X;;proper-list-Return T if X is a proper list, i.e., no dotted tail X X(defun proper-list (x) X X; Return T on if x is a proper list (i.e., not (a b c . d)). NIL is X; not considered a proper list. X X (and (consp x) (not (cdr (last x))))) X X(defun co-process-var-options X (type-info options-list var-names var-assignments) X X; Returns multiple values. These values are: X; (VAR-NAMES VAR-ASSIGNMENTS OPTIONS-LIST) X; Go through OPTIONS-LIST and find all the :VAR options. Take X; these and process them producing the list of variable names, the X; variable assignment code and the list of options without the :VAR X; options. X X (let X ( X (variable nil) X (var-assignment nil) X (new-options-list nil) X (option-name nil) X (option-info nil) X ) X;;;; (Declare (ignore option-name)) X X (dolist (option options-list X (values var-names var-assignments new-options-list) X ) X X (multiple-value-setq (option-name option-info) X (option-ok? option type-info 'regular-option) X ) X X ; Will only return to here if we didn't get an error. X X ; Check if spec is an instance variable spec X X (if (not (member 'variable-option (cdr option-info) :test #'eq)) X X ;;THEN Add this non-:VAR option to the options list X X (setf new-options-list (nconc new-options-list (list option))) X X X X ; ELSE We have a instance variable specification. X ; Now return the name of the variable and initialization X ; code. X X X (progn X (multiple-value-setq (variable var-assignment) X (parse-option X type-info X var-names X option X option-info X ) X ) X X X (setf var-names (nconc var-names (list variable))) X X (when var-assignment X X ; THEN Add the assignment to the list of assignments. X X (setf var-assignments X (nconc var-assignments (list var-assignment)) X ) X ) ;when X X ) ;progn X X ) ;if X ); dolist X X ) ;let X X); end co-process-var-options X X(defun co-parse-options (type-info var-names options) X X; It is legal for OPTIONS to be NIL. X; Example: OPTIONS = ((:REDEFINED-METHODS m1 m2 m3) X; :ALL-INITABLE) X X (let ((options-so-far nil) X (option-name nil) X (option-info nil)) X X (dolist (option options) X X ; OPTION-INFO will be NIL if OPTION-NAME is not a legal X ; option, or a list of information that tells what X ; characteristics this option has. Note that currently, if an X ; error occurs in OPTION-OK? we will NOT return to this X ; function. The check for '(WHEN OPTION-INFO...' is for future X ; continuable errors. If 'ONCE' is on this list, it means the X ; option can only occur once. X X (multiple-value-setq (option-name option-info) X (option-ok? option type-info 'regular-option)) X (when option-info X X ; THEN The OPTION is a real one. X ; Now make sure it doesn't occur more then once. X X (if X (and (member option-name options-so-far :test #'eq) X X (member 'once (cdr option-info) :test #'eq)) X X ; THEN We have duplicate options. Give an error. X X (co-deftype-error X "duplicate option,~% '~s',~% specified." X (type-name type-info) X option) X X ; ELSE Everything is ok. X X (progn X (setf options-so-far (cons option-name options-so-far)) X (parse-option type-info var-names option option-info))))) X )) X X(defun parse-option (type-info var-names option option-info) X X; This routine calls the right function to parse OPTION. This X; function is the first element of OPTION-INFO. Example: OPTION = X; (:REDEFINED-METHODS M1 M2 M3) The option given is either a symbol X; or a list. When a list, the rest of the arguments will be passed to X; the function (may be NIL). If a symbol, NIL is passed as arguments. X; NOTE: Should make sure that the value returned by the option is X; the value of this routine, since some code may want to use X; the value returned (like the caller of the :VAR option). X X (apply (car option-info) X (list var-names (if (consp option) (cdr option) nil) type-info))) X X(defun option-ok? (option type-info type-of-option) X X; Return the information about this option or NIL. Return the name of X; the option followed by the information for the option as a pair. If X; the option is not of the correct form give an error message. Check X; to make sure the option exists. Also check that the form of option X; is legal according to the information returned. This includes X; whether the option is allowed as a symbol or in list form. And X; whether it is allowed to not have any arguments when in the list X; form. Also if a list, check if each element is a symbol, and not NIL. X; This is done if CHECK-ARGUMENTS was included in the option X; information. If the KEYWORDS option is also included with X; CHECK-ARGUMENTS, each of the symbols given must also be in the X; keyword package. If VARIABLES is included in the option information, X; SELF is also checked for each option element. The X; option CAN-HAVE-LIST-ELEMENTS causes list element arguments to be X; ignored. If this option is not there and a list element is X; found, an error message is issued. Type-info is used strictly for X; error messages. Will return NIL for the error conditions. Sample, X; X; OPTION = '(:REDEFINED-METHODS A B C)' or ':ALL-SETTABLE' X; X; TYPE-OF-OPTION is used to decide wheter we are dealing with an X; option or a suboption of :INHERIT-FROM. NOTE: Currently, this X; function will never return if an error occurs but we prepare for X; future continuable errors. X X (let* X ((option-info X (if (consp option) X X ; THEN Use the first element of the option as the option name. X X (return-option-info (car option) type-of-option) X X ; ELSE Use the option itself as the option name. X X (return-option-info option type-of-option))) X X (type-name (type-name type-info)) X (check-as-variables (member 'variable option-info :test #'eq)) X (can-have-list-elements X (member 'can-have-list-elements option-info :test #'eq)) X (keyword-arguments (member 'keywords option-info :test #'eq))) X X X (unless option-info X X ; THEN We have an illegal option. X X (co-deftype-error X "no such option (or suboption) as:~% '~s'." X type-name X option)) X X ; We have a real option. Make sure it is of the right form. X X (if (consp option) X X ; THEN Check to make sure it can be a pair. X X (if X (not (member 'list (cdr option-info) :test #'eq)) X X ; THEN Wrong form for option. X X (co-deftype-error X "option,~% '~S',~% must occur as a symbol." X type-name X option) X X ; ELSE Ok so far. Make sure the list form is a proper list. X ; Now check if the option has no arguments and if X ; if does make sure it can. X X (progn X (unless (proper-list option) X ; THEN Not a proper list. X (co-deftype-error X "the option,~% '~S',~% must be a proper list." X type-name X option)) X (if X (and (not (cdr option)) X (not (member 'no-arguments (cdr option-info) :test #'eq))) X X ; THEN Arguments must be specified to option. X X (co-deftype-error X "option,~% '~S',~% requires arguments." X type-name X option) X X ; ELSE Check each element of the list, if necessary, to X ; make sure it is a symbol, not NIL. Also check for X ; SELF if VARIABES is in the X ; option info. X ; Return the information. X X (progn X (when (member 'check-arguments (cdr option-info) :test #'eq) X X ; THEN Check the arguments. X X (dolist (option-arg (cdr option)) X (if (consp option-arg) X (unless can-have-list-elements X X ; THEN List arguments are not allowed. X X (co-deftype-error X "illegal argument '~S' found in option,~% '~S'." X type-name X option-arg X option)) X X ; ELSE Check if a correct symbol. X X (if X (or X (not (co-legal-type-or-method-name option-arg)) X (and check-as-variables X (not X (legal-instance-variable)))) X X ; THEN Illegal argument in option. X X (co-deftype-error X "illegal argument '~S' found in option,~% '~S'." X type-name X option-arg X option) X X ; ELSE Check if the option-arg must be a keyword. X X (when X (and keyword-arguments X (not (keywordp option-arg))) X X ; THEN We have a DEFINE-TYPE in which the X ; arguments must all be symbols in the X ; keyword package. X (co-deftype-error X "'~S' of the option,~%'~S'~%is illegal. Must be a symbol from the keyword package." X type-name X option-arg X option)))))) X (values (car option) option-info))))) X X ; ELSE We have the symbol form of the option. X X (if (member 'symbol (cdr option-info) :test #'eq) X X ; THEN Return the information. X X (values option option-info) X X ; ELSE Wrong form for option. X X (co-deftype-error X "option,~% '~S',~% must occur in list form." X type-name X option))))) X X X(defun co-legal-type-or-method-name (type-or-method-name) X X; Return T only if the name given is a non-nil symbol. X X (and (symbolp type-or-method-name) type-or-method-name)) X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Detailed Option Parsing X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X(defun return-option-info (option-name option-type) X X; Whenever a new option is added, this function must be updated. X; Should return NIL, if garbage option-names are given. The option X; information returned has the form: X; (FUNCTION-NAME . INFORMATION). X; FUNCTION-NAME is the name of the function to call that parses the X; given option. INFORMATION is a list of information to use in X; syntaxing the option. This list includes: X; SYMBOL - option can occur in symbol form. X; LIST - option can occur in list form. X; CHECK-ARGUMENTS - When an option is in list form, this specifies that X; each element of the option list is to be checked to X; be a symbol which is not NIL. X; KEYWORDS - An addition to the CHECK-ARGUMENTS option, this says X; that each element must be a symbol from the keyword X; package. Must occur with the CHECK-ARGUMENTS option. X; NO-ARGUMENTS - This specifies that a list form of the option can X; occur without any arguments (i.e., X; (:METHODS). X; VARIABLE - The items in this options list are instance variables. X; Check that they are not SELF or MYSELF.Make sure X; they are not symbols from the X; keyword package. X; CAN-HAVE-LIST-ELEMENTS - This option says that having list elements is X; legal. These elements are simply ignored. X; ONCE - This option can only occur once. X; VARIABLE-OPTION - Currently used in the :VAR option. Tells whether X; an option is a variable option (:VAR) without X; using the name of the option. This allows easy X; renaming of the :VAR option. X; VALUE-RETURNED-SUBOPTION - States that this suboption returns a X; value that is needed. A test is made X; to save the return value when a suboption X; has this characteristic. X; X; Note that this list is used for parsing suboptions as well as X; options. The handling of suboptions and options in the same way is X; done for flexibility and understandability even though some of the X; options may not currently apply to both options and suboptions. X; X X (case option-type X X (var-suboption (return-var-suboption-info option-name)) X X (inherit-from-suboption X (return-inherit-from-suboption-info option-name)) X X (regular-option (return-regular-option-info option-name)))) X X(defun return-var-suboption-info (option-name) X X; Return information as stated in comments of RETURN-OPTION-INFO X; about the suboptions of the :VAR option. X X (case option-name X X (:init '(parse-var-init-suboption list once value-returned-suboption)) X X (:type '(parse-var-type-suboption list once)) X X (:initable '(parse-var-initable-suboption symbol once)) X X (:settable '(parse-var-settable-suboption symbol once)) X X (:gettable '(parse-var-gettable-suboption symbol once)) X X (otherwise nil) X )) X X(defun parse-var-initable-suboption (args initable-variable type-info) X (declare (ignore args)) X X; ARGS will always be NIL. X X (setf (svref type-info $initable-variables-slot) X (add-to-set X (svref type-info $initable-variables-slot) X initable-variable))) X X(defun parse-var-gettable-suboption (args gettable-variable type-info) X (declare (ignore args)) X X; ARGS will always be NIL. X X (setf (svref type-info $gettable-variables-slot) X (add-to-set X (svref type-info $gettable-variables-slot) X gettable-variable))) X X(defun parse-var-settable-suboption (args settable-variable type-info) X (declare (ignore args)) X X; ARGS will always be NIL. X X (setf (svref type-info $initable-variables-slot) X (add-to-set X (svref type-info $initable-variables-slot) X settable-variable)) X X (setf (svref type-info $gettable-variables-slot) X (add-to-set X (svref type-info $gettable-variables-slot) X settable-variable)) X X (setf (svref type-info $settable-variables-slot) X (add-to-set X (svref type-info $settable-variables-slot) X settable-variable))) X X(defun add-to-set (set new-elements) X X; Add the elements in NEW-ELEMENTS to SET if they are not already X; there. NEW-ELEMENTS can be a list of id's or an id. It is assumed X; that the order of the elements within the set is NOT important. If X; NEW-ELEMENTS is NIL, simply return set. X X (cond ((null new-elements) set) X ((symbolp new-elements) X X ; THEN Add the element to the set, if necessary. X X (adjoin new-elements set :test #'eq)) X X (t X X ; ELSE Add each element of the list of elements. X X (let ((new-set set)) X (dolist (element new-elements) X (setf new-set (adjoin element new-set :test #'eq))) X new-set)))) X X X(defun parse-var-type-suboption (args variable type-info) X X; Example, ARGS = (FIXNUM). A declaration like (:TYPE FIXNUM) => X; (DECLARE (TYPE FIXNUM A)). X X (unless (and (consp args) (= (length args) 1)) ;rds 3/8 eq->= X X ; THEN We have something like (:TYPE . 2). X X (co-deftype-error X "'~S'~% is an illegal form of :TYPE suboption." X (type-name type-info) X (cons :type args))) X X; Add this declaration to the list of declarations. X; Note that more will be added to this slot when :VARIABLES suboptions are X; parsed, and at the end parsing the type. :VARIABLES is, however, X; currently unsupported. X X (setf (svref type-info $let-pseudo-info-slot) X (nconc (svref type-info $let-pseudo-info-slot) X (list `(declare (type ,(car args) ,variable)))))) X X X(defun parse-var-init-suboption (args variable type-info) X X; Return the variable initialization form. For example, if VARIABLE = X; REAL-PART and ARGS = (0.0), would return: X; (unless X; (assignedp real-part) X; (setf real-part 0.0)) X X (unless (and (consp args) (= (length args) 1)) ;rds 3/8 eq->= X X ; THEN We have something like (:INIT 1 2). X X (co-deftype-error X "illegal initialization form,~%'~S',~%given for instance variable '~S'." X (type-name type-info) X (cons :init args) X variable)) X X (let ((default-value (first args))) X `(unless X (co::assignedp ,variable) X X ; THEN X X (setf ,variable ,default-value)))) X X(defun return-inherit-from-suboption-info (option-name) X X; Return information as stated in comments of RETURN-OPTION-INFO X; about the suboptions of the :INHERIT-FROM option. X X (case option-name X X (:init-keywords X '(parse-init-keywords-suboption X symbol X list X once X check-arguments X keywords)) X X ;;:VARIABLES suboption not allowed in COOL. This is due to X ;; lack of code walker hooks. X X#| X (:variables X '(parse-variables-suboption X list X once X no-arguments X check-arguments X variable X can-have-list-elements)) X|# X X (:methods X '(parse-methods-suboption list once check-arguments no-arguments)) X X (otherwise nil))) X X(defun return-regular-option-info (option-name) X X; Return information as stated in comments of RETURN-OPTION-INFO X; about the options of DEFINE-TYPE. X X (case option-name X X X ;;:FAST-METHODS not supported in COOL. Implementation dependent. X X#| X (:fast-methods X '(parse-fast-methods-option list once check-arguments no-arguments)) X|# X X ;;In line methods are not supported in COOL. Implementation dependent. X X#| X (:inline-methods X '(parse-inline-methods-option list once check-arguments no-arguments)) X X (:notinline-methods X '(parse-notinline-methods-option X list X once X check-arguments X no-arguments)) X X|# X X (:init-keywords X '(parse-init-keywords-option X list X once X check-arguments X no-arguments X keywords)) X X (:no-init-keyword-check X '(parse-no-init-keyword-check-option symbol once)) X X (:inherit-from '(parse-inherit-from-option list)) X X (:var '(parse-var-option list variable-option)) X X (:redefined-methods X '(parse-redefined-methods-option X list X once X check-arguments X no-arguments)) X X (:all-settable '(parse-all-settable-option symbol once)) X X (:all-gettable '(parse-all-gettable-option symbol once)) X X (:all-initable '(parse-all-initable-option symbol once)) X X (otherwise nil))) X X(defun parse-init-keywords-suboption (type-info parent-type-info args) X X; If ARGS is NIL, we have the symbol form. If ARGS is a list, we have X; the list form. Examples: ARGS = NIL X; ARGS = (:EXCEPT j k l), (:EXCEPT) X; (:INIT-KEYWORDS :EXCEPT) is treated as all keywords. If this X; function returns, then everything went ok as far as errors. If ARGS X; is a list, we know it is proper, and each init keyword is a symbol and X; not NIL. This function may change the $INIT-KEYWORDS-SLOT of X; type-info. X X (let* X ((parent-init-keywords X (co::init-keywords parent-type-info)) X (keywords-to-add parent-init-keywords)) X X (when args X X ; THEN We have the except form. X ; Check and make sure the :EXCEPT is found. X X (if X (not (eq (car args) ':except)) X X ; THEN We have an error. X X (co-deftype-error X "~%'~S'~% was found following the :INIT-KEYWORDS suboption, expected to see 'EXCEPT'." X (type-name type-info) X (car args)) X X ; ELSE ok so far. X X (progn (setq args (cdr args)) X (when (consp args) X X ; THEN There is something following the :EXCEPT. X X (dolist (keyword args) X X ; See if the keyword is in the list of REAL X ; keywords for the parent. X X (if X (not X (member keyword X parent-init-keywords X :test X #'eq)) X X ; THEN Print a warning message is ignore. X X (warn X (format X NIL X "DEFINE-TYPE: Init keyword, '~A', is not a keyword of '~A' in :INIT-KEYWORDS suboption." X keyword X (type-name parent-type-info))) X X ; ELSE The keyword is legit. X X (setf keywords-to-add X (remove keyword X keywords-to-add X :test X #'eq X :count X 1)))))))) X X ; keywords-to-add should be correctly setup now. X ; Add the elements of this list that are not already there, to the X ; existing list of keywords for this type. X X (setf (svref type-info $INIT-KEYWORDS-SLOT) X (add-to-set X (svref type-info $INIT-KEYWORDS-SLOT) X keywords-to-add)))) X X(defun parse-methods-suboption (type-info parent-type-info args) X X; At this point, we know that ARGS is a proper list where each element X; is a symbol that is not NIL. Sample, args = (:EXCEPT M1 M2 M3), X; (:EXCEPT), (). If method names are duplicated, the duplicates are X; ignored. This function should change the $METHODS-TO-INHERIT-SLOT as X; in the following example: X; PARENT-TYPE-INFO for PARENT2 and the total methods for PARENT2 X; are M1, M2,...,M6 and if ARGS = (:EXCEPT M1 M2 M3), and if X; $METHODS-TO-INHERIT-SLOT looked like: X; ((<parent1 type info object> .(M1 M2 M3))), then X; $METHODS-TO-INHERIT-SLOT would look like: X; ((<parent1 type info object> . (M1 M2 M3)) X; (<parent2 type info object> . (M4 M5 M6))) X; after this routine completes. When this routine finishes, we are X; guaranteed that each method added to the $METHODS-TO-INHERIT-SLOT is an X; existing methods of the parent. X X (let X ((parent-methods X (co::method-alist parent-type-info)) X (methods-to-inherit nil) X (except-form? X (when (and args (eq (car args) ':except)) X X ; THEN Skip over the :EXCEPT argument. X X (setf args (cdr args)) X t))) X X ; ARGS will be NIL or a list at this point. If NIL, we have (:METHODS) X ; or (:METHODS :EXCEPT). X X (dolist (method args) X (unless (assoc method parent-methods :test #'eq) X X ; THEN The method doesn't exits, give a warning. X X (warn X (format nil X "DEFINE-TYPE: Method '~S' of the :METHODS suboption doesn't~% exist in parent '~S'." X method X (type-name parent-type-info))))) X X (if except-form? X X ; THEN We have the :EXCEPT form. List all methods that are not X ; specified and are not universal methods. If X ; (:METHODS :EXCEPT), all methods not universal methods are X ; added. X X (dolist (method-function-pair parent-methods) X X ; As long as the method is not an exception (:EXCEPT) X ; and not a universal method of the parent, inherit it. X X (unless X (or (member (car method-function-pair) args :test #'eq) X (member (car method-function-pair) X $DEFINE-TYPE-UNIVERSAL-METHODS X :test X #'eq)) X X ; THEN The method we are looking at is desired X ; for inheritance. X X (setf methods-to-inherit X (add-to-set X methods-to-inherit X (car method-function-pair))))) X X ; ELSE We have the normal form. If some of the args were not real X ; methods. If (:METHODS), nothing is done. X X (dolist (method args) X (when (assoc method parent-methods :test #'eq) X X ; THEN The method really exists. X X (setf methods-to-inherit X (add-to-set methods-to-inherit method)) X X ; Add to the list of explicitly stated methods to inherit. X ; This is used for error checking with methods to not X ; redefine later. X X (setf X (svref type-info $EXPLICITLY-LISTED-METHODS-SLOT) X (add-to-set X (svref type-info X $EXPLICITLY-LISTED-METHODS-SLOT) X method))))) X X ; Now add this list of methods to the type-info vector. X ; 'methods-to-inherit' may be NIL. X X (setf (svref type-info $METHODS-TO-INHERIT-SLOT) X (append (svref type-info $METHODS-TO-INHERIT-SLOT) X (list (cons parent-type-info methods-to-inherit)))))) X X X(defun parse-var-option (var-names args type-info) X X; ARGS = (IV1 (:TYPE INTEGER) (:INIT 0.0) :SETTABLE) Return something X; of the form: X; (VARIABLE-NAME . VAR-ASSIGNMENT) X; VARIABLE-NAME is the name of the instance variable. VAR-ASSIGNMENT X; is the code needed to initialize this instance variable. X X (unless (and (consp args) (symbolp (car args))) X X ; THEN We have an error. X X (co-deftype-error X "a symbol must follow a :VAR option." X (type-name type-info))) X X (let ((variable (car args)) X (var-assignment nil)) X X ; Make sure the instance variable name is legal. X X (instance-variable-ok? variable var-names (type-name type-info)) X X ; Now parse all the suboptions of the :VAR option. X ; VAR-ASSIGNMENT will be NIL if there is no :INIT suboption. X X (setf var-assignment X (parse-var-suboptions type-info (cdr args) variable)) X (values variable var-assignment))) X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Detailed :VAR Suboption Parsing X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X(defun parse-var-suboptions (type-info suboptions variable) X X; This routine returns the code for initialization of the instance X; variable VARIABLE. It is legal for suboptions to be NIL. For X; understandibility, expandability, and consistancy the parsing of X; suboptions uses the same techniques with the same keywords that option X; option parsing does. This is true even though some of the option X; information may not be shared between options and suboptions. See X; CO-PARSE-OPTIONS and its constituent routines. X; X; Example: SUBOPTIONS = ((:INIT 0.0) X; (:TYPE INTEGER) X; :SETTABLE) X X (let ((suboptions-so-far nil) X (suboption-name nil) X (suboption-info nil) X (init-info nil) X ) X X (dolist (suboption suboptions) X X ; SUBOPTION-INFO will be NIL if SUBOPTION-NAME is not a X ; legal suboption, or a list of information that tells what X ; characteristics this suboption has. Note that currently, X ; if an error occurs in SUBOPTION-OK? we will NOT return X ; to this function. The check for '(WHEN SUBOPTION-INFO...)' X ; is for future continuable errors. If 'ONCE' is on this X ; list, it means the suboption can only occur once. X X (multiple-value-setq (suboption-name suboption-info) X (option-ok? X suboption X type-info X 'var-suboption)) X (when suboption-info X X ; THEN The suboption is a real one. X ; Now make sure it doesn't occur more then once. X X (if X (and X (member suboption-name suboptions-so-far :test #'eq) X (member 'once (cdr suboption-info) :test #'eq)) X X ; THEN We have duplicate suboptions. Give an error. X X (co-deftype-error X "duplicate suboption,~% '~S',~% specified to :VAR option." X (type-name type-info) X suboption) X X ; ELSE Everything is ok. X X (progn X (setf suboptions-so-far X (cons suboption-name suboptions-so-far)) X (if X (member 'value-returned-suboption X (cdr suboption-info) X :test X #'eq) X X ; THEN We must save the return value. X X (setf init-info X (parse-var-suboption X type-info X variable X suboption X suboption-info)) X X ; ELSE We don't care about the return value. X X (parse-var-suboption X type-info X variable X suboption X suboption-info))))) X X ) ;dolist X X ;;Return the init-info X X init-info X X ) ;let X X) ;end parse-var-suboptions X X(defun parse-var-suboption (type-info variable suboption suboption-info) X X; This routine calls the right function to parse SUBOPTION. This X; function is the first element of SUBOPTION-INFO. Example: X; SUBOPTION = (:INIT 0.0) The SUBOPTION given is either a symbol or a X; list. When a list, the rest of the arguments will be passed to the X; function (may be NIL). If a symbol, NIL is passed as arguments. X; NOTE: Should make sure that the value returned by the suboption is X; the value of this routine, since some code may want to use X; the value returned (like the value of the :INIT suboption). X X (apply (car suboption-info) X (list (if (consp suboption) (cdr suboption) nil) X variable X type-info))) X X X(defun instance-variable-ok? (variable list-of-variables type-name) X X; Signal a standard error if the variable is SELF, X; one of the variables that are already in the list X; of variables, or a keyword. X; TYPE-NAME is used for error messages by CO-DEFTYPE-ERROR. X X (unless (legal-instance-variable variable) X X ; THEN error. X X (co-deftype-error X "'SELF' NIL, or symbol from the keyword package~%was found as an instance variable." X type-name)) X X (when (member variable list-of-variables :test #'eq) X X ; THEN We have a duplicate variable. X X (co-deftype-error X "instance variable '~S' occurs more~%than once." X type-name X variable))) X X(defun legal-instance-variable (variable) X X; Return T if VARIABLE satisfies restrictions on instance variables. X; Return NIL otherwise. Currently, the variable must be a non-NIL symbol X; that is not SELF. X; Must also be a symbol that is NOT in the X; keyword package. X X (and (symbolp variable) X variable X (not (eq variable 'co::self)) X (not (keywordp variable)))) X X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Parsing of :ALL-xxx X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X(defun parse-all-initable-option (var-names args type-info) X X; Parses: :ALL-INITABLE. ARGS will be NIL. X X (parse-initable-option var-names args type-info)) X X(defun parse-all-gettable-option (var-names args type-info) X X; Parses: :ALL-GETTABLE. ARGS will be NIL. X X (parse-gettable-option var-names args type-info)) X X(defun parse-all-settable-option (var-names args type-info) X X; Parses: :ALL-SETTABLE. ARGS will be NIL. X X (parse-settable-option var-names args type-info)) X X(defun parse-gettable-option (var-names args type-info) X X; Example ARGS = (A B C D), NIL. X; Duplicate variables specified are ignored. X X (dolist (gettable-variable (or args var-names)) X X (if (member gettable-variable var-names :test #'eq) X X ; THEN This variable is a real instance variable. X X (setf (svref type-info $gettable-variables-slot) X (add-to-set X (svref type-info $GETTABLE-VARIABLES-SLOT) X gettable-variable)) X ; ELSE We have an illegal variable name. X X (co-deftype-error X "variable '~S' in the settable~% options list is not an instance variable.~%" X (type-name type-info) X gettable-variable)))) X X(defun parse-settable-option (var-names args type-info) X X; Example ARGS = (A B C D), NIL. Duplicate variables specified are X; ignored. Each settable instance variable X; is added to the list of gettable and initable instance variables as X; well. X X (dolist (settable-variable (or args var-names)) X X (if (not (member settable-variable var-names :test #'eq)) X X ; THEN We have an illegal variable name. X X (co-deftype-error X "variable '~S' in the settable~% options list is not an instance variable~%." X (type-name type-info) X settable-variable) X X ; ELSE This variable is a real instance variable. X X (progn X (setf (svref type-info $initable-variables-slot) X (add-to-set X (svref type-info $initable-variables-slot) X settable-variable)) X (setf (svref type-info $gettable-variables-slot) X (add-to-set X (svref type-info $gettable-variables-slot) X settable-variable)) X (setf (svref type-info $settable-variables-slot) X (add-to-set X (svref type-info $settable-variables-slot) X settable-variable)))))) X X(defun parse-initable-option (var-names args type-info) X X; Example ARGS = (A B C D), NIL. Duplicate X; variables specified are ignored. X X (dolist (initable-variable (or args var-names)) X X (if (member initable-variable var-names :test #'eq) X X ; THEN This variable is a real instance variable. X X (setf (svref type-info $initable-variables-slot) X (add-to-set X (svref type-info $initable-variables-slot) X X initable-variable)) X ; ELSE We have an (svref type-info $initable-variables-serror X "variable '~S' in the initable~% options list is not an instance variable.~%" X (type-name type-info) X initable-variable)))) X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Parsing of :INIT-KEYWORDS Option and Suboption and :REDEFINED-METHODS X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X(defun parse-init-keywords-option (var-names args type-info) X (declare (ignore var-names)) X X; Parses: (:INIT-KEYWORDS <symbol>). Doesn't use VAR-NAMES. By the X; time this routine is called, each element of args has been checked to X; be a symbol not equal to NIL. ARGS is also a proper list. For X; (:INIT-KEYWORDS), ARGS will be NIL. We add the existing X; init-keywords because we may have hit :INIT-KEYWORDS suboptions from X; :INHERIT-FROM options. X X (setf (svref type-info $INIT-KEYWORDS-SLOT) X (add-to-set (svref type-info $INIT-KEYWORDS-SLOT) args))) X X(defun parse-no-init-keyword-check-option (var-names args type-info) X (declare (ignore args var-names)) X X; Parses: :NO-INIT-KEYWORD-CHECK. VAR-NAMES is not used. X X (setf (svref type-info $NO-INIT-KEYWORD-CHECK-SLOT) t)) X X(defun parse-redefined-methods-option (var-names args type-info) X X (declare (ignore var-names)) X X; Parses: (:REDEFINED-METHODS M1 M2 M3), or (:REDEFINED-METHODS). ARGS X; = (M1 M2 M3). At this point, ARGS is guaranteed to be a proper list X; where each element is a symbol that is non-NIL. For X; (:REDEFINED-METHODS), args is NIL. NOTE: The order of arguments are X; stored away doesn't matter. X X (setf (svref type-info $methods-to-not-define-slot) X (remove-duplicates args :test #'eq))) X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Parsing of :INHERIT-FROM Option and Suboption X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X(defun parse-inherit-from-option (var-names args type-info) X (declare (ignore var-names)) X X; ARGS is the list of remaining stuff inside the :INHERIT-FROM option. X; We know that ARGS is a proper list and that it has at least one element. X; Sample: ARGS = (PARENT1 (:METHODS M1 M2 M3) X; (:VARIABLES X Y Z) X; (:INIT-KEYWORDS :EXCEPT Q)) X; VAR-NAMES is not used. Note that for error handling to be changed to X; continuable errors, these options will have to be changed, since side X; effects to type info can occur before a syntax error occurs. When X; finished, the $PARENT-TYPES-SLOT and the $PARENTS-INFO-SLOT may be X; changed. X X (if (and (consp args) (symbolp (car args))) X X ; THEN The form of the parent is ok. X ; Now check if it is partially defined. X X (let ((parent-type-info (type-partially-defined? (car args))) X (parents (svref type-info $PARENT-TYPES-SLOT)) X (new-parent (car args))) X X (if (not parent-type-info) X X ; THEN The parent isn't defined. Give an error. X X (co-deftype-error X "~%the parent '~s',~s of the :INHERIT-FROM option, is not defined." X (type-name type-info) X new-parent) X X ; ELSE The parent is partially defined. X ; First check that options specified are ok. X ; Add the parent to the type-info slot. We must append X ; since the order is important -- the first :INHERIT-FROM option X ; must be the first parent. X ; Check that we don't have something like: X ; (INHERIT-FROM B...) X ; (INHERIT-FROM B...) within the type definition. X (if X (member new-parent parents :test #'eq) X X ; THEN Two or more parents that are the same parent. X X (co-deftype-error X "~~Sarent '~s' of type '~s'~s can only be a parent once." X (type-name type-info) X new-parent X (type-name type-info)) X X ; ELSE Everything is ok. X ; Add the parents type-info to be used later. X ; This is stored in the same order as the parents in the X ; $PARENT-TYPES-SLOT for consistency. X X (progn X (set-parents-info X type-info X (append (get-parents-info type-info) X (list X (list new-parent parent-type-info '*place-holder*)))) X (setf (svref type-info $PARENT-TYPES-SLOT) X (append parents (list new-parent))) X (parse-inherit-from-suboptions X type-info X parent-type-info X (cdr args)))))) X X ; ELSE The parent form is illegal. X X (co-deftype-error X "~%a symbol must follow an :INHERIT-FROM~% option." X (type-name type-info)))) X X(defun parse-inherit-from-suboptions X (type-info parent-type-info suboptions) X X; It is legal for SUBOPTIONS to be NIL. For understandibility, X; expandability, and consistancy the parsing of subptions uses the same X; techniques with the same keywords for option information. This is X; true even though some of the option information may not be shared X; between options and suboptions. See CO-PARSE-OPTIONS and its X; constituent routines. NOTE: If the name of :METHODS option is ever X; changed (in RETURN-OPTION-INFO) the references to :METHODS must be X; changed here as well. X; X; Example: SUBOPTIONS = ((:VARIABLES A B) X; (:METHODS C D) X; (:INIT-KEYWORDS EXCEPT J)) X X (let ((suboptions-so-far nil) X (suboption-name nil) X (suboption-info nil)) X X (dolist (suboption suboptions) X X ; SUBOPTION-INFO will be NIL if SUBOPTION-NAME is not a X ; legal suboption, or a list of information that tells what X ; characteristics this suboption has. Note that currently, X ; if an error occurs in SUBOPTON-OK? we will NOT return X ; to this function. The check for (WHEN SUBOPTION-INFO...) X ; is for future continuable errors. If 'ONCE' is on this X ; list, it means the suboption can only occur once. X X (multiple-value-setq (suboption-name suboption-info) X (option-ok? X suboption X type-info X 'inherit-from-suboption)) X (when suboption-info X X ; THEN The suboption is a real one. X ; Now make sure it doesn't occur more then once. X X (if X (and (member suboption-name suboptions-so-far :test #'eq) X (member 'once (cdr suboption-info) :test #'eq)) X X ; THEN We have duplicate suboptions. Give an error. X X (co-deftype-error X "duplicate suboption,~s '~s',~s specified to :INHERIT-FROM option." X (type-name type-info) X suboption) X X ; ELSE Everything is ok. X X (progn X (setf suboptions-so-far X (cons suboption-name suboptions-so-far)) X (parse-inherit-from-suboption X type-info X parent-type-info X suboption X suboption-info))))) X X ; Now check the one funny case: If the :METHODS option was NOT present. X X (unless (member ':methods suboptions-so-far :test #'eq) X X ; THEN We had no :METHODS suboption, so inherit all methods X ; (but not universal methods). Do this by making X ; a suboption (:METHODS :EXCEPT), and having it parsed. X X (multiple-value-setq (suboption-name suboption-info) X (option-ok? X '(:methods :except) X type-info X 'inherit-from-suboption)) X X (parse-inherit-from-suboption X type-info X parent-type-info X '(:methods :except) X suboption-info)))) X X(defun parse-inherit-from-suboption X (type-info parent-type-info suboption suboption-info) X X; Example: SUBOPTION = (:INIT-KEYWORDS :EXCEPT J K L) The suboption X; given is either a symbol or a list. When a list, the rest of the X; arguments will be passed to the function (may be NIL). If a symbol, X; NIL is passed as arguments. X X (apply (car suboption-info) X (list type-info X parent-type-info X (if (consp suboption) (cdr suboption) nil)))) X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Method Definition X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X(defun co-parse-method-macro-call X (spec argument-list body) X X; Make sure that the type-name and method-name are ok. Also, that the X; call is a proper list. X; Note that use of instance variable names as formal X; parameter names to the method and use of SELF as a formal parameter X; name are not checked. X X (let X ( X (type-name NIL) X (method-name NIL) X ) X X ; Check to be sure the body is a proper list or NIL X X (unless (or (null body) (proper-list body)) X X ; THEN the method definition is not a proper list X X (define-method-error X "The call,~% '(DEFINE-METHOD ~S ~S ~S)',~% is missing arguments or is an improper list." X spec argument-list body)) X X ; Check the spec X X (unless (and (proper-list spec) (= (length spec) 2)) ;rds 3/8 eq->= X X ; THEN The form of the (type-name method-name) is incorrect. X X (define-method-error X "The type-name and method-name in the call,~% '(DEFINE-METHOD ~S ~S ~S)',~% must be a two element proper list." X spec argument-list body)) X X (setf method-name (second spec)) X (setf type-name (first spec)) X X (unless (co-legal-type-or-method-name type-name) X X ; THEN Invalid type. X X (define-method-error X "Type name '~S' in the call,~% '(DEFINE-METHOD ~S ~S ~S)',~% must be a non-NIL symbol." X type-name X spec X argument-list X body)) X X (unless (co-legal-type-or-method-name method-name) X X ; THEN Invalid method. X X (define-method-error X "Method name '~S' in the call,~% '(DEFINE-METHOD ~S ~S ~S)',~% must be a non-NIL symbol." X method-name X spec X argument-list X body)) X X ; Check that the argument-list is indeed a list. X X (unless (or (null argument-list) (proper-list argument-list)) X (define-method-error X "The argument list in the call,~% '(DEFINE-METHOD ~S ~S ~S)',~% is missing or must be a proper list." X spec X argument-list X body)) X X ) ;let X) ;co-parse-method-macro-call X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X; Call-Method Support X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X(defun co-parse-call-to-method (call-method-call which-func class-name) X X; Parse a call to a CALL-METHOD or APPLY-METHOD. Signal any X; errors in syntax. X; 'which-func' is either "CALL-METHOD" or "APPLY-METHOD". X X (let ((method-name nil) X (rest-of-call call-method-call)) X X (setf rest-of-call (cdr rest-of-call)) X X ; This should now be the list of arguments X X (unless (proper-list rest-of-call) X X ; THEN The call to CALL-METHOD is not a proper list. X X (error X (format nil X "~A: The call,~% '~S',~% is missing arguments or is an improper list." X which-func X call-method-call))) X X ; If the form is APPLY-METHOD, check to be sure the argument list is X ; not NIl X X (when (equalp which-func "APPLY-METHOD") X (unless (cadr rest-of-call) X X (error X (format nil X "APPLY-METHOD: The call,~% '~S',~% has no argument list." X call-method-call X ) X ) X ) X ) X X (setf method-name (first rest-of-call)) X X (cond X ((co-legal-type-or-method-name method-name) X X ; THEN We have the local form of call-method (i.e., X ; (CALL-METHOD MOOSE 3) ) so just return. X X NIL X ) X X ; ELSE Check if a two element list, each element a symbol. X X ((consp method-name) X (unless X (and (= (length method-name) 2) X (proper-list method-name) X (co-legal-type-or-method-name (first method-name)) X (co-legal-type-or-method-name (second method-name)) X (co::legal-parent-p class-name (first method-name))) X X ; Incorrect parent form of call-method. X X (error X (format nil X "~A: Illegal parent reference '~S' in~% '~S'.~% Must have the form: '(type-symbol operation-symbol)'." X which-func X method-name X call-method-call) X )) X ) X X ; Anything else is an error. X X (t X (error X (format nil X "~A: Incorrect form '~S' in~% '~S'.~% Expecting non-NIL symbol or list or two non-NIL symbols." X which-func X method-name X call-method-call)))) X X ) ;let X X) ;co-parse-call-to-method X X(defun check-that-method-to-call-exists X (possible-method-name child-name parent-name parent-methods) X X; Return the name of the method we will be calling. X; The method name to use is determined as follows: First, always use the ':' X; version of the name. If the method with this name is not defined, X; check if the name without the ':' is defined. If it is, issue a X; warning message that we are calling this method. If it isn't X; defined, issue a warning message that the method is not defined and X; that we will call the ':' version when it is defined. For example, X; if we had the POSSIBLE-METHOD-NAME of A we would first check if a X; method named :A existed in the PARENT-METHODS. If it does, we X; return :A. If it doesn't, we see if a method with the name A X; exists. If it does, we return this name and give a warning. If it X; doesn't, we return :A and give a warning. X X (let* X ((method-to-call X (return-keyword-from-variable possible-method-name)) X (saved-method-to-call method-to-call)) X X (unless (assoc method-to-call parent-methods :test #'eq) X X ; THEN The ':' version of the method doesn't exist. X ; Now check if the non-colon version exists. X X (setf method-to-call possible-method-name) X X (if X (assoc method-to-call parent-methods :test #'eq) X X ; THEN We are calling the non-colon version of the method. X ; Give a warning message. X X (warn X (format nil X "DEFINE-TYPE: In type, '~A', '~A' of :VARIABLES suboption, will reference the parent method '~A'." X child-name X possible-method-name X possible-method-name)) X X ; ELSE Give a warning that we will assume calling the ':' version. X X (progn (setf method-to-call saved-method-to-call) X (warn X (format nil X "DEFINE-TYPE: In type, '~A', '~A' of :VARIABLES suboption, has no corresponding method defined in parent '~A'. Will assume you want to call method '~A'." X child-name X possible-method-name X parent-name X method-to-call))))) X method-to-call)) X X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X END_OF_FILE if test 56836 -ne `wc -c <'co-parse.l'`; then echo shar: \"'co-parse.l'\" unpacked with wrong size! fi # end of 'co-parse.l' fi echo shar: End of archive 13 \(of 13\). cp /dev/null ark13isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 13 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Rich $alz "Anger is an energy" Cronus Project, BBN Labs rsalz@bbn.com Moderator, comp.sources.unix sources@uunet.uat c