 	(insert ?\")
 	(goto-char (match-beginning 0))
 	(insert "\"" )))
-       (ledger-auto-traverse-descriptor-tree 
-	(read (buffer-substring (point-min) (point-max))) 0)))
-
-(defun ledger-auto-traverse-descriptor-tree (tree depth)
-  (dolist (node tree)
-	  (cond ((eq (type-of node) 'string)
-		 (ledger-auto-parse-date-descriptor node))
-		((eq (type-of node) 'cons)
-		 (ledger-auto-traverse-descriptor-tree node (1+ depth))))))
-  
+    
+    ;; read the descriptor string into a lisp object the transform the
+    ;; string descriptor into useable things
+    (ledger-transform-auto-tree 
+     (read (buffer-substring (point-min) (point-max))))))
+
+(defun ledger-transform-auto-tree (tree)
+  (if (consp tree)
+      (let (result)
+	(while (consp tree)
+	  (let ((newcar (car tree)))
+	    (if (consp (car tree))
+		(setq newcar (ledger-transform-auto-tree (car tree))))
+	    (if (consp newcar) 
+		(push newcar result)
+		(push (ledger-auto-parse-date-descriptor newcar) result)) )
+	  (setq tree (cdr tree)))
+	(nconc (nreverse result) tree))))
+
+(defun ledger-auto-split-constraints (descriptor-string)
+  "Return a list with the year, month and day fields split"
+  (let ((fields (split-string descriptor-string "[/\\-]" t))
+	constrain-year constrain-month constrain-day)
+    (if (string= (car fields) "*")
+	(setq constrain-year nil)
+	(setq constrain-year (car fields)))
+    (if (string= (cadr fields) "*")
+	(setq constrain-month nil)
+	(setq constrain-month (cadr fields)))
+    (if (string= (nth 2 fields) "*")
+	(setq constrain-day nil)
+	(setq constrain-day (nth 2 fields)))
+    (list constrain-year constrain-month constrain-day)))
+
+(defun ledger-string-to-number-or-nil (str)
+  (if str
+      (string-to-number str)
+      nil))
+
+(defun ledger-auto-compile-constraints (constraint-list)
+  (let ((year-constraint (ledger-string-to-number-or-nil (nth 0 constraint-list)))
+	(month-constraint (ledger-string-to-number-or-nil (nth 1 constraint-list)))
+	(day-constraint (ledger-string-to-number-or-nil (nth 2 constraint-list))))
+    (ledger-auto-constrain-numerical-date-macro 
+     year-constraint
+     month-constraint
+     day-constraint)))
 
 (defun ledger-auto-parse-date-descriptor (descriptor)
   "Parse the date descriptor, return the evaluator"
-  descriptor)
+  (ledger-auto-compile-constraints 
+   (ledger-auto-split-constraints descriptor)))
 
 (provide 'ldg-auto)
 

  "Take a date descriptor string and return a function that
returns true if the date meets the requirements"
  (with-temp-buffer
    (let (pos)
      (insert descriptor-string)
      (goto-char (point-min))
      (replace-string "[" "(")
      (goto-char (point-min))
      (replace-string "]" ")")
      (goto-char (point-max))
      (while (re-search-backward 
	      (concat "\\([0-9]+\\|[\*]\\)/"  ;; Year slot
		      "\\([\*EO]\\|[0-9]+\\)/" ;; Month slot
		      "\\([\*]\\|\\([0-9][0-9]\\)\\|"
		      "\\([0-5]"
		      "\\(\\(Su\\)\\|"

      (error "Invalid argument to ledger-auto-day-in-month-macro %S %S" 
	     count 
	     day-of-week)))

(defmacro ledger-auto-constrain-numerical-date-macro (year month day)
  "Return a function of date that is only true if all constraints are met.
A nil constraint matches any input, a numerical entry must match that field 
of date."
  ;; Do bounds checking to make sure the incoming date constraint is sane
  (if 
   (if (eval month) ;; if we have a month
       (and (between (eval month) 1 12) ;; make sure it is between 1
					;; and twelve and the number
					;; of days are ok
	    (between (eval day) 1 (ledger-auto-days-in-month (eval month) (eval year))))
       (between (eval day) 1 31))  ;; no month specified, assume 31 days.
   `#'(lambda (date)
	(and ,(if (eval year)  
		  `(if (eq (nth 5 (decode-time date)) ,(eval year)) t)
		  `t)
	     ,(if (eval month)
		  `(if (eq (nth 4 (decode-time date)) ,(eval month)) t)
		  `t)
	     ,(if (eval day)
		  `(if (eq (nth 3 (decode-time date)) ,(eval day)) t))))
   (error "ledger-auto-constraint-numerical-date-macro: date out of range %S %S %S" (eval year) (eval month) (eval day))))



(defmacro ledger-auto-constrain-every-count-day-macro (day-of-week skip start-date)
  "Return a form that is true for every DAY skipping SKIP, starting on START.
For example every second Friday, regardless of month."
  (let ((start-day (nth 6 (decode-time (eval start-date)))))
