Merge pull request #147 from Ferada/defpackage
authorDavid Vázquez <davazp@gmail.com>
Thu, 17 Oct 2013 20:13:01 +0000 (13:13 -0700)
committerDavid Vázquez <davazp@gmail.com>
Thu, 17 Oct 2013 20:13:01 +0000 (13:13 -0700)
DEFPACKAGE including USE and some more functions.

src/list.lisp
src/package.lisp
tests/list.lisp

index b974cd0..9cb8e45 100644 (file)
 
 (defun cdr (x) (cdr x))
 
+(defun rplaca (cons x)
+  (rplaca cons x))
+
+(defun rplacd (cons x)
+  (rplacd cons x))
+
 (defun first   (x) (car    x))
 (defun second  (x) (cadr   x))
 (defun third   (x) (caddr  x))
       (when (member (funcall key x) list2 :test test :key key)
         (push x new-list)))
     new-list))
+
+(defun get-properties (plist indicator-list)
+  (do* ((plist plist (cddr plist))
+        (cdr (cdr plist) (cdr plist))
+        (car (car plist) (car plist)))
+      ((null plist) (values nil nil nil))
+    (when (null cdr)
+      (error "malformed property list ~S" plist))
+    (let ((found (member car indicator-list :test #'eq)))
+      (when found
+        (return (values car (cadr plist) plist))))))
+
+(defun getf (plist indicator &optional default)
+  (do* ((plist plist (cddr plist))
+        (cdr (cdr plist) (cdr plist))
+        (car (car plist) (car plist)))
+      ((null plist) default)
+    (when (null cdr)
+      (error "malformed property list ~S" plist))
+    (when (eq indicator car)
+      (return (cadr plist)))))
+
+(defun %putf (plist indicator new-value)
+  (do* ((tail plist (cddr tail))
+        (cdr (cdr tail) (cdr tail))
+        (car (car tail) (car tail)))
+      ((null tail) (list* indicator new-value plist))
+    (when (null cdr)
+      (error "malformed property list ~S" tail))
+    (when (eq indicator car)
+      ;; TODO: should be cadr, needs a defsetf for that
+      (setf (car (cdr tail)) new-value)
+      (return tail))))
+
+(define-setf-expander getf (plist indicator &optional default)
+  (multiple-value-bind (dummies vals newval setter getter)
+      (get-setf-expansion plist)
+    (let ((store (gensym))
+          (indicator-sym (gensym))
+          (default-sym (and default (gensym))))
+      (values `(,indicator-sym ,@(and default `(,default-sym)) ,@dummies)
+              `(,indicator ,@(and default `(,default)) ,@vals)
+              `(,store)
+              `(let ((,(car newval) (%putf ,getter ,indicator-sym ,store))
+                     ,@(cdr newval))
+                 ,setter
+                 ,store)
+              `(getf ,getter ,indicator-sym ,@(and default `(,default-sym)))))))
index 3ee5105..7449f84 100644 (file)
@@ -20,9 +20,8 @@
 (defun list-all-packages ()
   (copy-list *package-list*))
 
-(defun make-package (name &key use)
-  (let ((package (new))
-        (use (mapcar #'find-package-or-fail use)))
+(defun %make-package (name use)
+  (let ((package (new)))
     (setf (oget package "packageName") name)
     (setf (oget package "symbols") (new))
     (setf (oget package "exports") (new))
     (push package *package-list*)
     package))
 
+(defun resolve-package-list (packages)
+  (let (result)
+    (dolist (package (mapcar #'find-package-or-fail packages))
+      (pushnew package result :test #'eq))
+    (reverse result)))
+
+(defun make-package (name &key use)
+  (%make-package
+   (string name)
+   (resolve-package-list use)))
+
 (defun packagep (x)
   (and (objectp x) (in "symbols" x)))
 
   `(eval-when (:compile-toplevel :load-toplevel :execute)
      (setq *package* (find-package-or-fail ',string-designator))))
 
+(defmacro defpackage (package &rest options)
+  (let (use)
+    (dolist (option options)
+      (ecase (car option)
+       (:use
+        (setf use (append use (cdr option))))))
+    `(eval-when (:compile-toplevel :load-toplevel :execute)
+       (%defpackage ',(string package) ',use))))
+
+(defun redefine-package (package use)
+  (setf (oget package "use") use)
+  package)
+
+(defun %defpackage (name use)
+  (let ((package (find-package name))
+        (use (resolve-package-list use)))
+    (if package
+        (redefine-package package use)
+        (%make-package name use))))
+
 ;; This function is used internally to initialize the CL package
 ;; with the symbols built during bootstrap.
 (defun %intern-symbol (symbol)
index ffc672d..b59f662 100644 (file)
 (test (let (foo)
         (mapc (lambda (x y z) (push (+ x y z) foo)) '(1 2) '(3) '(4 5 6))
         (equal foo '(8))))
+
+;; GETF
+(test (eq (getf '(a b c d) 'a) 'b))
+(test (null (getf '(a b c d) 'e)))
+(test (equal (let ((x (list 'a 1))) (setf (getf x 'a) 3) x) '(a 3)))
+(test (equal (let ((x (list 'a 1))) (incf (getf x 'a)) x) '(a 2)))
+
+;; GET-PROPERTIES
+(test (equal (multiple-value-list (get-properties '(a b c d) '(b d e))) '(NIL NIL NIL)))
+(test (equal (multiple-value-list (get-properties '(a b c d) '(b a c))) '(a b (a b c d))))
+(test (equal (multiple-value-list (get-properties '(a b c d) '(b c a))) '(a b (a b c d))))