     ;; Objects
     (pairs     pair [("," pairs) ""])
     (pair      id ":" expr)
-    (object    "{" ["" pairs] "}")))
+    (object    "{" ["" pairs] "}"))
+  "The ParselTongue grammar.")
 
 (defvar psl-token-funcs
-  `((number . ,(lambda (expr) (string-to-number (nth 1 expr))))))
+  `((number . ,(lambda (token num) (string-to-number (car num)))))
+  "Syntax tree manipulation functions.")
+
+;;; Parser functions
+
+(defun mpd-get-token-func (token funcs)
+  "Get the manipulation function for the given token."
+  (or (cdr (assoc token funcs)) #'cons))
 
 (defun mpd-parse (tokens &optional funcs)
   "Return the next item in the current buffer."

            (cons result rest)))))))

(defun mpd-match-regex (regex tokens funcs)
  (when (looking-at regex)
    (prog1 (buffer-substring-no-properties (point) (match-end 0))
      (goto-char (match-end 0)))))

(defun mpd-match-token (token tokens funcs)
  (let* ((pattern (cdr (assoc token tokens)))
         (match (mpd-match pattern tokens funcs)))
    (when match (cons token match))))

(defun mpd-match-or (vec tokens funcs)
  (dolist (option (coerce vec 'list))
    (let ((match (mpd-match option tokens funcs)))
      (when match (return match)))))

(defun mpd-match (pattern tokens &optional funcs)
  (search-forward-regexp "[[:space:]]*")
  (let ((start (point))
        (result (etypecase pattern

    (let ((result (mpd-match (car token) tokens funcs)))
      (if result (return result)))))

(defun mpd-match-list (list tokens funcs)
  "Match all patterns in a list."
  (let ((result (mpd-match (car list) tokens funcs)))
    (when result
      (if (null (cdr list))
