(require 'stdlib) ;; TODO ;; - fast implementations using hashtable, symbol-table (struc.) ;; - implementation as a facade to the standard symbol-plist stuff ;; - make `plist' a proper type with make-datum, see rep.data.* impl. (define-structure plist (export make-plist plist-p plist-get plist-put plist-remprop plist-member plist->list plist->alist alist->plist) (open rep rep.data.datums stdlib) ;; (define type-id 'plist) ;; (define-datum-printer type-id ;; (lambda (plist stream) ;; (declare (unused plist)) ;; (write stream "#"))) (define (find plist property) (cond ((null plist) nil) ((eq (first plist) property) (list (first plist) (second plist))) (t (find (cddr plist) property)))) ;; public interface (define (make-plist) "Create new propery list" ;;(make-datum (cons 'plist '()) type-id)) (cons 'plist '())) (define (plist-p plist) "Returns `t' when PLIST is a proper property list." (eq (first plist) 'plist)) (define (plist-get plist property #!optional default) "This function extracts a value from a property list. The function returns the value corresponding to the given PROPERTY, or DEFAULT if PROPERTY is not one of the properties on the list." (let ((cell (find (rest plist) property))) (if cell (second cell) default))) (define (plist-put plist property value) "This function changes the value in PLIST of PROPERTY to VALUE. If PROPERTY is already a property on the list, its value is set to VALUE, otherwise the new PROPERTY VALUE pair is added. The new plist is returned; use `(setq x (plist-put x property value))' to be sure to use the new value. The PLIST is modified by side effects." (rplacd plist (nconc (rest plist) (list property value)))) (define (plist-remprop plist property) "This function removes from PLIST the property PROPERTY and its value. The new plist is returned; use `(setq x (plist-remprop x property))' to be sure to use the new value. The PLIST is modified by side effects." 'todo) (define (plist-member plist property) "This function returns `t' if PROPERTY has a value specified in PLIST." (not (null (find (rest plist) property)))) (define (plist->list plist) (rest plist)) (define (plist->alist plist) 'todo) (define (alist->plist alist) 'todo)) (require 'plist) ;;(define pl (cons 'plist (list 'aap 1 'noot 2))) ;;(puts pl) ;;(puts (plist-get pl 'aap)) ;;(puts (plist-get pl 'noot)) ;;(puts (plist-get pl 'mies)) ;;(puts (plist-get pl 'mies 42)) (setq pl (make-plist)) (plist-put pl 'aap "aap") ;;(plist-put pl 'aap 42) ; FIXME should replace (plist-put pl 'noot (lambda (x) (* x x))) (puts (plist->list pl)) (puts pl) (puts (plist-get pl 'aap)) (puts (plist-get pl 'mies)) (puts (plist-get pl 'mies 42)) (puts (mapcar (lambda (pr) (plist-member pl pr)) '(aap noot mies))) (puts (funcall (plist-get pl 'noot) 16)) ;; from xemacs info: ;; Property Lists ;; ============== ;; ;; A "property list" (or "plist") is another way of representing a ;; mapping from keys to values. Instead of the list consisting of conses ;; of a key and a value, the keys and values alternate as successive ;; entries in the list. Thus, the association list ;; ;; ((a . 1) (b . 2) (c . 3)) ;; ;; has the equivalent property list form ;; ;; (a 1 b 2 c 3) ;; ;; Property lists are used to represent the properties associated with ;; various sorts of objects, such as symbols, strings, frames, etc. The ;; convention is that property lists can be modified in-place, while ;; association lists generally are not. ;; ;; Plists come in two varieties: "normal" plists, whose keys are ;; compared with `eq', and "lax" plists, whose keys are compared with ;; `equal', ;; ;; - Function: valid-plist-p plist ;; Given a plist, this function returns non-`nil' if its format is ;; correct. If it returns `nil', `check-valid-plist' will signal an ;; error when given the plist; that means it's a malformed or circular ;; plist or has non-symbols as keywords. ;; ;; - Function: check-valid-plist plist ;; Given a plist, this function signals an error if there is anything ;; wrong with it. This means that it's a malformed or circular plist. ;; ;; Working With Normal Plists ;; -------------------------- ;; ;; - Function: plist-get plist property &optional default ;; This function extracts a value from a property list. The function ;; returns the value corresponding to the given PROPERTY, or DEFAULT ;; if PROPERTY is not one of the properties on the list. ;; ;; - Function: plist-put plist property value ;; This function changes the value in PLIST of PROPERTY to VALUE. If ;; PROPERTY is already a property on the list, its value is set to ;; VALUE, otherwise the new PROPERTY VALUE pair is added. The new ;; plist is returned; use `(setq x (plist-put x property value))' to ;; be sure to use the new value. The PLIST is modified by side ;; effects. ;; ;; - Function: plist-remprop plist property ;; This function removes from PLIST the property PROPERTY and its ;; value. The new plist is returned; use `(setq x (plist-remprop x ;; property))' to be sure to use the new value. The PLIST is ;; modified by side effects. ;; ;; - Function: plist-member plist property ;; This function returns `t' if PROPERTY has a value specified in ;; PLIST. ;; ;; In the following functions, if optional arg NIL-MEANS-NOT-PRESENT is ;; non-`nil', then a property with a `nil' value is ignored or removed. ;; This feature is a virus that has infected old Lisp implementations (and ;; thus E-Lisp, due to RMS's enamorment with old Lisps), but should not be ;; used except for backward compatibility. ;; ;; - Function: plists-eq a b &optional nil-means-not-present ;; This function returns non-`nil' if property lists A and B are `eq' ;; (i.e. their values are `eq'). ;; ;; - Function: plists-equal a b &optional nil-means-not-present ;; This function returns non-`nil' if property lists A and B are ;; `equal' (i.e. their values are `equal'; their keys are still ;; compared using `eq'). ;; ;; - Function: canonicalize-plist plist &optional nil-means-not-present ;; This function destructively removes any duplicate entries from a ;; plist. In such cases, the first entry applies. ;; ;; The new plist is returned. If NIL-MEANS-NOT-PRESENT is given, the ;; return value may not be `eq' to the passed-in value, so make sure ;; to `setq' the value back into where it came from. ;; ;; Working With Lax Plists ;; ----------------------- ;; ;; Recall that a "lax plist" is a property list whose keys are compared ;; using `equal' instead of `eq'. ;; ;; - Function: lax-plist-get lax-plist property &optional default ;; This function extracts a value from a lax property list. The ;; function returns the value corresponding to the given PROPERTY, or ;; DEFAULT if PROPERTY is not one of the properties on the list. ;; ;; - Function: lax-plist-put lax-plist property value ;; This function changes the value in LAX-PLIST of PROPERTY to VALUE. ;; ;; - Function: lax-plist-remprop lax-plist property ;; This function removes from LAX-PLIST the property PROPERTY and its ;; value. The new plist is returned; use `(setq x (lax-plist-remprop ;; x property))' to be sure to use the new value. The LAX-PLIST is ;; modified by side effects. ;; ;; - Function: lax-plist-member lax-plist property ;; This function returns `t' if PROPERTY has a value specified in ;; LAX-PLIST. ;; ;; In the following functions, if optional arg NIL-MEANS-NOT-PRESENT is ;; non-`nil', then a property with a `nil' value is ignored or removed. ;; This feature is a virus that has infected old Lisp implementations (and ;; thus E-Lisp, due to RMS's enamorment with old Lisps), but should not be ;; used except for backward compatibility. ;; ;; - Function: lax-plists-eq a b &optional nil-means-not-present ;; This function returns non-`nil' if lax property lists A and B are ;; `eq' (i.e. their values are `eq'; their keys are still compared ;; using `equal'). ;; ;; - Function: lax-plists-equal a b &optional nil-means-not-present ;; This function returns non-`nil' if lax property lists A and B are ;; `equal' (i.e. their values are `equal'). ;; ;; - Function: canonicalize-lax-plist lax-plist &optional ;; nil-means-not-present ;; This function destructively removes any duplicate entries from a ;; lax plist. In such cases, the first entry applies. ;; ;; The new plist is returned. If NIL-MEANS-NOT-PRESENT is given, the ;; return value may not be `eq' to the passed-in value, so make sure ;; to `setq' the value back into where it came from. ;; ;; Converting Plists To/From Alists ;; -------------------------------- ;; ;; - Function: alist-to-plist alist ;; This function converts association list ALIST into the equivalent ;; property-list form. The plist is returned. This converts from ;; ;; ((a . 1) (b . 2) (c . 3)) ;; ;; into ;; ;; (a 1 b 2 c 3) ;; ;; The original alist is not modified. ;; ;; - Function: plist-to-alist plist ;; This function converts property list PLIST into the equivalent ;; association-list form. The alist is returned. This converts from ;; ;; (a 1 b 2 c 3) ;; ;; into ;; ;; ((a . 1) (b . 2) (c . 3)) ;; ;; The original plist is not modified. ;; ;; The following two functions are equivalent to the preceding two ;; except that they destructively modify their arguments, using cons cells ;; from the original list to form the new list rather than allocating new ;; cons cells. ;; ;; - Function: destructive-alist-to-plist alist ;; This function destructively converts association list ALIST into ;; the equivalent property-list form. The plist is returned. ;; ;; - Function: destructive-plist-to-alist plist ;; This function destructively converts property list PLIST into the ;; equivalent association-list form. The alist is returned.