Index: trunk/csv.lisp
===================================================================
--- trunk/csv.lisp	(revision trunk,11)
+++ trunk/csv.lisp	(revision trunk,12)
@@ -2,4 +2,5 @@
 (require '#:parse)
 (require '#:cl-ppcre)
+(require '#:local-time)
 (use-package '#:dso-lex)
 (import 'parse::substring)
@@ -35,5 +36,5 @@
 	(destructuring-bind (class image) (first token-list)
 	  (when (eq class ',class)
-	    (values t (rest token-list) (list class image))))))))
+	    (values t (rest token-list) (list image))))))))
 
 (defmatcher comma)
@@ -57,6 +58,5 @@
   (row (t-value (* row-rest) (= t-newline))
        (lambda (row)
-	 (princ row)
-	 (mapcar #'second (cons (first row) (mapcar #'second (second row))))))
+	 (mapcar #'car (cons (first row) (mapcar #'second (second row))))))
   (row-rest ((= t-comma) t-value) cdr))
 
Index: trunk/parse3.lisp
===================================================================
--- trunk/parse3.lisp	(revision trunk,11)
+++ trunk/parse3.lisp	(revision trunk,12)
@@ -1,2 +1,6 @@
+(in-package #:dso-parse)
+
+
+
 (defmacro while (cond &body body)
   `(do ()
@@ -6,4 +10,11 @@
 (defmacro if-matches-parser (input parser (next match)
 			     &body (&optional (then t) else))
+  "Matches if the function named by PARSER accepts the input.  Such a
+parser must return T, the remaining unmatched input, and the accepted
+input as values (in that order), or NIL if matching fails.
+
+NOTE: A parser that accepts a portion of input but does not wish to
+emit it may do so.  For example, a parser may return the values T,
+\"blah....\", NIL."
   (declare (symbol parser next match))
   (with-gensyms (ok)
@@ -13,4 +24,5 @@
 (defmacro if-matches-char (input char (next match)
 			   &body (&optional (then t) else))
+  "Matches if the first character of INPUT is CHAR."
   (declare (symbol next match)
 	   (character char))
@@ -23,4 +35,5 @@
 (defmacro if-matches-string (input string (next match)
 			     &body (&optional (then t) else))
+  "Matches if INPUT is prefixed by STRING."
   (declare (symbol next match)
 	   (string string))
@@ -35,4 +48,6 @@
 (defmacro if-matches-regex (input regex (next match)
 			    &body (&optional (then t) else))
+  "Matches if REGEX matches the beginning of INPUT (REGEX is modified
+to anchor to the beginning automatically)."
   (declare (string regex)
 	   (symbol next match))
@@ -51,4 +66,6 @@
   (declare (symbol next match)
 	   (list alts))
+  "Matches if any of ALTS match INPUT.  The first rule in ALTS that
+matches is used to consume input and build the parse tree."
   (if alts
       `(if-matches ,input ,(first alts) (,next ,match)
@@ -61,4 +78,7 @@
 (defmacro if-matches-sequence (input seq (next match)
 			       &body (&optional (then t) else))
+  "Matches if all of the rules in SEQ match INPUT in sequence (ie, the
+second rule matches what is left of the input after the first rule has
+matched, and so on)."
   (destructuring-bind (head . tail) seq
     (if tail
@@ -78,5 +98,7 @@
 (defmacro if-matches-eqcount (input count rule (next match)
 			      &body (&optional (then t) else))
-  "WARNING: ELSE code executes in an anonymous block!"
+  "Matches if RULE matches INPUT exactly COUNT times in sequence.
+
+WARNING: ELSE code executes in an anonymous block!"
   (declare ((or null (integer 0)) count)
 	   (symbol next match))
@@ -95,4 +117,7 @@
 (defmacro if-matches-maxcount (input count rule (next match)
 			       &body (&optional (then t) else))
+  "Always matches INPUT, but attempts to match RULE up to COUNT times
+in sequence (ie, RULE is matched against INPUT from 0 to COUNT times).
+If COUNT is NIL, RULE is matched as often as it will."
   (declare ((or null (integer 0)) count)
 	   (symbol next match)
@@ -114,4 +139,8 @@
 (defmacro if-matches-count (input mincount maxcount rule (next match)
 			    &body (&optional (then t) else))
+  "Matches RULE against INPUT from MINCOUNT to MAXCOUNT times
+sequentially.  If MINCOUNT is NIL, it is treated as 0.  If MAXCOUNT is
+NIL, RULE is matched as often as it will (after the MINCOUNT is
+satisfied)."
   (when (and maxcount mincount) (setf maxcount (- maxcount mincount)))
   (with-gensyms (next2 match2)
