[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 3827d26 36/60: Add docs for user-interface functions & com
From: |
Junpeng Qiu |
Subject: |
[elpa] master 3827d26 36/60: Add docs for user-interface functions & combinators |
Date: |
Tue, 25 Oct 2016 17:45:15 +0000 (UTC) |
branch: master
commit 3827d263fec87080fdacea6fa937a2dbb7598335
Author: Junpeng Qiu <address@hidden>
Commit: Junpeng Qiu <address@hidden>
Add docs for user-interface functions & combinators
---
parsec.el | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 132 insertions(+), 13 deletions(-)
diff --git a/parsec.el b/parsec.el
index 4911142..00073f6 100644
--- a/parsec.el
+++ b/parsec.el
@@ -68,6 +68,7 @@
(parsec-error-new-2 expected found)))))))
(defun parsec-ch (ch)
+ "Parse a character CH."
(let ((next-char (char-after)))
(if (and (not (eobp))
(char-equal next-char ch))
@@ -77,6 +78,7 @@
:found (parsec-eof-or-char-as-string)))))
(defun parsec-any-ch ()
+ "Parse any character."
(if (not (eobp))
(prog1 (char-to-string (char-after))
(forward-char))
@@ -84,6 +86,7 @@
:found (parsec-eof-or-char-as-string))))
(defun parsec-satisfy (pred)
+ "Parse any character that satisfies the predicate PRED."
(let ((next-char (char-after)))
(if (and (not (eobp))
(funcall pred next-char))
@@ -93,15 +96,19 @@
:found (parsec-eof-or-char-as-string)))))
(defun parsec-newline ()
+ "Parse a newline character \"\\n\"."
(parsec-ch ?\n))
(defun parsec-crlf ()
+ "Parse a carriage return (\'\\r\') followed by a newline \"\\n\"."
(parsec-and (parsec-ch ?\r) (parsec-ch ?\n)))
(defun parsec-eol ()
+ "Parse a newline or a CRLF and return \"\\n\"."
(parsec-or (parsec-newline) (parsec-crlf)))
(defun parsec-eob ()
+ "Indicate the end of file (buffer)."
(unless (eobp)
(parsec-stop :expected "`EOF'"
:found (parsec-eof-or-char-as-string))))
@@ -109,9 +116,11 @@
(defalias 'parsec-eof 'parsec-eob)
(defun parsec-eol-or-eof ()
+ "Indicate either eol or eof."
(parsec-or (parsec-eol) (parsec-eof)))
(defun parsec-re (regexp)
+ "Parse the input matching the regular expression REGEXP."
(if (looking-at regexp)
(progn (goto-char (match-end 0))
(match-string 0))
@@ -139,27 +148,62 @@
(concat regex-head regex-str regex-end)))
(defun parsec-one-of (&rest chars)
+ "Succeed if the current character is in the supplied list of CHARS.
+Return the parsed character.
+
+> (parsec-one-of ?a ?e ?i ?o ?u)
+
+Note this function is just a wrapper of `parsec-re'. For complicated use
cases,
+consider using `parsec-re' instead."
(parsec-re (format "[%s]" (parsec-make-alternatives chars))))
(defun parsec-none-of (&rest chars)
+ "Succeed if the current character not in the supplied list of CHARS.
+Return the parsed character.
+
+> (parsec-none-of ?a ?e ?i ?o ?u)
+
+Note this function is just a wrapper of `parsec-re'. For complicated use
cases,
+consider using `parsec-re' instead."
(parsec-re (format "[^%s]" (parsec-make-alternatives chars))))
(defsubst parsec-str (str)
+ "Parse STR and only consume the input for an exact match.
+Return the parsed string.
+
+Note this function's behavior is different from the `string'
+function of Haskll's Parsec. Use `parsec-string' if you want the
+same behavior as in Haskell."
(parsec-re (regexp-quote str)))
(defsubst parsec-string (str)
+ "Parse STR and consume the input even for a partial match.
+Return the parsed string.
+
+It is equivalent to calling `parsec-ch' multiples times so the
+input will be consumed if the parser fails in the middle of the
+STR. This function has the same behavior as the `string' function
+of Haskell's Parsec. See also `parsec-str'."
(mapc (lambda (c) (parsec-ch c)) str))
-(defsubst parsec-num (num &rest args)
+(defsubst parsec-num (num)
+ "Parse the number NUM and return the parsed number as a string."
(parsec-re (regexp-quote (number-to-string num))))
(defsubst parsec-letter ()
+ "Parse any English letter."
(parsec-re "[a-zA-Z]"))
(defsubst parsec-digit ()
+ "Parse any digit."
(parsec-re "[0-9]"))
(defmacro parsec-or (&rest parsers)
+ "Try the PARSERS one by one.
+If the current parser succeeds, return its results. If the
+current parser fails without consuming any input, try the next
+parser if available. This combinator fails if the current parser
+fails after consuming some input or there is no more parsers."
(let ((outer-sym (make-symbol "outer"))
(parser-sym (make-symbol "parser"))
(error-sym (make-symbol "err"))
@@ -182,29 +226,40 @@
(concat "None of the parsers succeeds:\n"
(mapconcat #'identity ,error-str-list-sym "\n"))))))))
-(defalias 'parsec-and 'progn)
+(defalias 'parsec-and 'progn
+ "Eval BODY sequentially and return the result of the last parser.
+This combinator fails if one of the parsers fails.")
-(defalias 'parsec-return 'prog1)
+(defalias 'parsec-return 'prog1
+ "Eval FIRST and BODY sequentially and return the results of the first parser.
+This combinator fails if one of the parsers fails.")
-(defalias 'parsec-collect 'list)
+(defalias 'parsec-collect 'list
+ "Collect the results of all the parsers OBJECTS into a list.")
(defun parsec-collect* (&rest args)
+ "Collect the non-nil results of all the parsers ARGS into a list."
(delq nil (apply #'parsec-collect args)))
(defmacro parsec-collect-as-string (&rest forms)
+ "Collect the results of all the parsers FORMS as a string."
`(parsec-list-to-string (parsec-collect ,@forms)))
(defmacro parsec-start (&rest forms)
+ "Eval the parsers FORMS and return the results or a `parsec-error'.
+This combinator should be used at the top level as the entry
+point of your parsing program."
`(catch 'parsec-failed ,@forms))
(defalias 'parsec-parse 'parsec-start)
-(defmacro parsec-try (&rest forms)
+(defmacro parsec-try (parser)
+ "Try PARSER, and pretend that no input is consumed when an error occurs."
(let ((orig-pt-sym (make-symbol "orig-pt"))
(error-sym (make-symbol "err")))
`(let ((,orig-pt-sym (point)))
(parsec-eavesdrop-error ,error-sym
- (parsec-and ,@forms)
+ (parsec-and ,parser)
(goto-char ,orig-pt-sym)))))
(defsubst parsec--atom-tag (name)
@@ -237,24 +292,28 @@
(parsec-throw ,error-sym))))
(defmacro parsec-with-error-message (msg &rest forms)
+ "Use MSG as the error message if an error occurs when Evaling the FORMS."
(declare (indent 1))
`(parsec-eavesdrop-error _
(parsec-and ,@forms)
(parsec-throw (parsec-error-new ,msg))))
(defmacro parsec-ensure (&rest forms)
+ "Exit the program immediately if FORMS fail."
(let ((error-sym (make-symbol "err")))
`(parsec-eavesdrop-error ,error-sym
(parsec-and ,@forms)
(error "%s" (parsec-error-str ,error-sym)))))
(defmacro parsec-ensure-with-error-message (msg &rest forms)
+ "Exit the program immediately with MSG if FORMS fail."
(declare (indent 1))
`(parsec-ensure
(parsec-with-error-message ,msg
(parsec-and ,@forms))))
(defmacro parsec-many (parser)
+ "Apply the PARSER zero or more times and return a list of the results."
(let ((res-sym (make-symbol "results"))
(error-sym (make-symbol "err")))
`(let (,res-sym)
@@ -265,6 +324,7 @@
(nreverse ,res-sym))))
(defmacro parsec-many1 (parser)
+ "Apply the PARSER one or more times and return a list of the results."
`(cons ,parser (parsec-many ,parser)))
(defsubst parsec-list-to-string (l)
@@ -273,12 +333,25 @@
(mapconcat #'identity l "")))
(defmacro parsec-many-as-string (parser)
+ "Apply the PARSER zero or more times and return the results as a string."
`(mapconcat #'identity (parsec-many ,parser) ""))
(defmacro parsec-many1-as-string (parser)
+ "Apply the PARSER one or more times and return the results as a string."
`(mapconcat #'identity (parsec-many1 ,parser) ""))
(defmacro parsec-many-till (parser end &optional type)
+ "Apply PARSER zero or more times until END succeeds.
+The return value is determined by TYPE. If TYPE is `:both', return
+the cons `(many . end)'. If TYPE is `:end', return the result of END.
+In other cases, return the result of PARSER.
+
+Used to scan comments:
+
+> (parsec-and
+> (parsec-str \"<--\")
+> (parsec-many-till (parsec-any-ch) (parsec-str \"-->\")))"
+
(let ((res-sym (make-symbol "results"))
(end-res-sym (make-symbol "end-result")))
`(let ((,res-sym nil) ,end-res-sym)
@@ -294,21 +367,31 @@
(t res-sym)))))
(defmacro parsec-many-till-as-string (parser end &optional type)
+ "Apply PARSER zero or more times until END succeeds.
+Return the result of PARSER or END as a string. TYPE has the same
+meaning as `parsec-many-till'."
(let ((res-sym (make-symbol "results")))
(cond
((eq type :both)
`(let ((,res-sym (parsec-many-till ,parser ,end ,type)))
- (cons (parsec-list-to-string (car ,res-sym)) (cdr ,res-sym))))
+ (cons (parsec-list-to-string (car ,res-sym))
+ (parsec-list-to-string (cdr ,res-sym)))))
(t
`(parsec-list-to-string (parsec-many-till ,parser ,end ,type))))))
(defmacro parsec-until (parser &optional type)
+ "Parse any characters until PARSER succeeds.
+TYPE has the same meaning as `parsec-many-till'."
`(parsec-many-till (parsec-any-ch) ,parser ,type))
(defmacro parsec-until-as-string (parser &optional type)
+ "Parse any characters until PARSER succeeds.
+Return the result of either part as a string. TYPE has the same
+meaning as `parsec-many-till'."
`(parsec-many-till-as-string (parsec-any-ch) ,parser ,type))
(defmacro parsec-not-followed-by (parser)
+ "Succeed only when PARSER fails. Consume no input."
(let ((res-sym (make-symbol "results")))
`(catch 'parsec-not-followed-by
(let ((,res-sym
@@ -319,39 +402,69 @@
(parsec-stop :message (format "Unexpected followed by: %s"
,res-sym))))))
(defmacro parsec-endby (parser end)
+ "Parse zero or more occurrences of PARSER, separated and ended by END.
+Return a list of values returned by PARSER."
`(parsec-many (parsec-return ,parser
,end)))
(defmacro parsec-sepby (parser separator)
+ "Parse zero or more occurrences of PARSER, separated by SEPARATOR.
+Return a list of values returned by PARSER."
`(parsec-or
(cons ,parser (parsec-many (parsec-and ,separator ,parser)))
nil))
(defmacro parsec-between (open close parser)
+ "Parse OPEN, followed by PARSER and CLOSE.
+Return the value returned by PARSER."
`(parsec-and
,open
(parsec-return ,parser
,close)))
(defmacro parsec-count (n parser)
+ "Parse N occurrences of PARSER.
+Return a list of N values returned by PARSER."
(let ((res-sym (make-symbol "results")))
`(let (,res-sym)
(dotimes (_ ,n ,res-sym)
(push ,parser ,res-sym)))))
(defmacro parsec-count-as-string (n parser)
+ "Parse N occurrences of PARSER.
+Return the N values returned by PARSER as a string."
`(parsec-list-to-string (parsec-count ,n ,parser)))
(defmacro parsec-option (opt parser)
+ "Try to apply PARSER and return OPT if PARSER fails without comsuming input."
`(parsec-or ,parser ,opt))
-(defmacro parsec-optional (&rest forms)
- `(parsec-or (parsec-and ,@forms) nil))
+(defmacro parsec-optional (parser)
+ "Apply PARSER zero or one time. Fail if PARSER fails after consuming input.
+Return the result of PARSER or nil.
+
+Note this combinator doesn't discard the result of PARSER so it is
+different from the `optional' function of Haskell's Parsec. If
+you want the Haskell's behavior, use `parsec-optional*'."
+ `(parsec-or ,parser nil))
-(defmacro parsec-optional* (&rest forms)
- `(parsec-and (parsec-optional ,@forms) nil))
+(defmacro parsec-optional* (parser)
+ "Apply PARSER zero or one time and discard the result.
+Fail if PARSER fails after consuming input.
+
+This combinator has the same behavior as the `optional' function of
+Haskell's Parsec."
+ `(parsec-and ,parser nil))
(defmacro parsec-query (parser &rest args)
+ "Get an alternative return value of the PARSER specified by the ARGS.
+
+The args can be in the following forms:
+
+ :beg --> return the point before applying the PARSER
+ :end --> return the point after applying the PARSER
+ :nil --> return nil
+ :groups N --> return Nth group for `parsec-re'."
(let ((orig-pt-sym (make-symbol "orig-pt"))
(res-sym (make-symbol "results")))
`(let ((,orig-pt-sym (point))
@@ -383,18 +496,24 @@
(eq (car x) 'Just))))
(defun parsec-from-just (x)
+ "Retrieve the value from Maybe monad X.
+If X is `(Just . p)', return p. Otherwise return nil."
(and (consp x)
(eq (car x) 'Just)
(cdr x)))
-(defmacro parsec-optional-maybe (&rest forms)
+(defmacro parsec-optional-maybe (parser)
+ "Apply PARSER zero or one time and return the value in a Maybe monad.
+If PARSER fails without consuming any input, return `parsec-nothing'.
+Otherwise, return `(Just . p)' where p is the result of PARSER."
(let ((res-sym (make-symbol "result")))
- `(let ((,res-sym (parsec-optional ,@forms)))
+ `(let ((,res-sym (parsec-optional ,parser)))
(if ,res-sym
(parsec-just ,res-sym)
parsec-nothing))))
(defmacro parsec-with-input (input &rest parsers)
+ "With INPUT, start parsing by applying PARSERS sequentially."
(declare (indent 1))
`(with-temp-buffer
(insert ,input)
- [elpa] master 3503e4a 13/60: Rename for easier understanding, (continued)
- [elpa] master 3503e4a 13/60: Rename for easier understanding, Junpeng Qiu, 2016/10/25
- [elpa] master 4fb2abe 29/60: Update simple-csv-parser, Junpeng Qiu, 2016/10/25
- [elpa] master fa2e6f1 27/60: Add gitignore, Junpeng Qiu, 2016/10/25
- [elpa] master a06220c 42/60: Update README, Junpeng Qiu, 2016/10/25
- [elpa] master f7e8629 26/60: Add tests, Junpeng Qiu, 2016/10/25
- [elpa] master bc11325 50/60: Add file examples/.nosearch, Junpeng Qiu, 2016/10/25
- [elpa] master 1da4344 32/60: Update url-str-parser, Junpeng Qiu, 2016/10/25
- [elpa] master 89dd2ac 54/60: Fix some wording in README, Junpeng Qiu, 2016/10/25
- [elpa] master 55515ca 48/60: Add missing dependencies, Junpeng Qiu, 2016/10/25
- [elpa] master 2e9f962 59/60: Add new package parsec to externals-list, Junpeng Qiu, 2016/10/25
- [elpa] master 3827d26 36/60: Add docs for user-interface functions & combinators,
Junpeng Qiu <=
- [elpa] master 8c108be 56/60: Add parsec-peek and parsec-peek-p, Junpeng Qiu, 2016/10/25
- [elpa] master 6001a70 12/60: Refine and add more parsec API, Junpeng Qiu, 2016/10/25
- [elpa] master da878fa 18/60: Use parsec-query for other return values, Junpeng Qiu, 2016/10/25
- [elpa] master 054a753 06/60: Rename to parsec, Junpeng Qiu, 2016/10/25
- [elpa] master 2cce1e3 37/60: Rename parsec-from-just to parsec-from-maybe, Junpeng Qiu, 2016/10/25
- [elpa] master cdb8c0d 47/60: Remove unused symbols, Junpeng Qiu, 2016/10/25
- [elpa] master fdb3d99 44/60: Fix some code in simple-csv-parser.el, Junpeng Qiu, 2016/10/25
- [elpa] master 701964f 57/60: Prepare headers for GNU ELPA, Junpeng Qiu, 2016/10/25
- [elpa] master cbd3352 55/60: Add parsec-lookahead, Junpeng Qiu, 2016/10/25
- [elpa] master a951fbe 41/60: Unify tag names, Junpeng Qiu, 2016/10/25