SPLIT-VALUES-TYPE and VALUES-TYPE-PRIMARY-TYPE redesigned to work with &allow-other...
authorJuanjo Garcia-Ripoll <jjgarcia@users.sf.net>
Thu, 10 Oct 2013 20:47:56 +0000 (22:47 +0200)
committerJuanjo Garcia-Ripoll <jjgarcia@users.sf.net>
Thu, 10 Oct 2013 20:47:56 +0000 (22:47 +0200)
src/cmp/cmptype-arith.lsp

index ae1adfb..e72d370 100644 (file)
   type)
 
 (defun-equal-cached values-type-to-n-types (type length)
-  (if (or (atom type) (not (eql (first type) 'values)))
-      (and (plusp length)
-           (list* type (make-list (1- length) :initial-element 'NULL)))
-      (do* ((l (rest type))
-            (output '())
-            (n length (1- n)))
-           ((or (null l) (zerop n)) (nreverse output))
-        (let ((type (pop l)))
-          (case type
-            (&optional
-             (when (null l)
-               (cmperr "Syntax error in type expression ~S" type))
-             (setf type (pop l)))
-            (&rest
-             (when (null l)
-               (cmperr "Syntax error in type expression ~S" type))
-             (return-from values-type-to-n-types
-               (nreconc output (make-list n :initial-element (first l))))))
-          (push type output)))))
+  (when (plusp length)
+    (do-values-type-to-n-types type length)))
+
+(defun do-values-type-to-n-types (type length)
+  (declare (si::c-local))
+  (multiple-value-bind (required optional rest)
+      (split-values-type type)
+    (let* ((output (nconc required optional))
+          (l (length output)))
+      (if (< l length)
+         (nconc output (make-list (- length l) :initial-element rest))
+       (subseq output 0 (1- length))))))
 
 (defun split-values-type (type)
   (if (or (atom type) (not (eq (first type) 'VALUES)))
-      (values (list type) nil nil)
-      (let ((rest (member '&rest type))
-            (opt (member '&optional type)))
-        (values (ldiff (rest type) (or rest opt))
-                (ldiff (rest (member '&optional type)) rest)
-                (rest (member '&rest type))))))
+      (values (list type) nil nil nil)
+    (loop with required = '()
+         with optional-flag = nil
+         with optional = '()
+         with rest = nil
+         with a-o-k = nil
+         with l = (rest type)
+         while l
+         do (let ((typespec (pop l)))
+              (case typespec
+                (&allow-other-keys
+                 (setf a-o-k t)
+                 (when l
+                   (cmperr "Syntax error in type expression ~S" type)))
+                (&optional
+                 (when optional-flag
+                   (cmperr "Syntax error in type expression ~S" type))
+                 (setf optional-flag t))
+                (&rest
+                 (when (or (null l)
+                           (not (member (rest l) '(() (&allow-other-keys))
+                                        :test #'equal)))
+                   (cmperr "Syntax error in type expression ~S" type))
+                 (setf rest (car l)))
+                (otherwise
+                 (if optional-flag
+                     (push typespec optional)
+                   (push typespec required)))))
+         finally
+         (return (values required (nreverse optional) rest a-o-k)))))
 
 (defun-equal-cached values-type-or (t1 t2)
   (when (or (eq t2 'T) (equalp t2 '(VALUES &REST T)))