[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master a5ca813 04/60: Full & simple parser
From: |
Junpeng Qiu |
Subject: |
[elpa] master a5ca813 04/60: Full & simple parser |
Date: |
Tue, 25 Oct 2016 17:45:12 +0000 (UTC) |
branch: master
commit a5ca813b59aa66f26c416004d2cf410f4e6048ba
Author: Junpeng Qiu <address@hidden>
Commit: Junpeng Qiu <address@hidden>
Full & simple parser
---
csv-parser.el => full-csv-parser.el | 74 ++++++--------------
parsec.el | 131 +++++++++++++++++++++++------------
simple-csv-parser.el | 56 +++++++++++++++
3 files changed, 166 insertions(+), 95 deletions(-)
diff --git a/csv-parser.el b/full-csv-parser.el
similarity index 53%
rename from csv-parser.el
rename to full-csv-parser.el
index 5ead855..75225a4 100644
--- a/csv-parser.el
+++ b/full-csv-parser.el
@@ -1,4 +1,4 @@
-;;; csv-parser.el --- Sample csv parser using parsec.el -*- lexical-binding:
t; -*-
+;;; full-csv-parser.el --- Sample csv parser using parsec.el -*-
lexical-binding: t; -*-
;; Copyright (C) 2016 Junpeng Qiu
@@ -20,64 +20,37 @@
;;; Commentary:
-;;
+;; Ref: http://book.realworldhaskell.org/read/using-parsec.html
;;; Code:
-
(defun csv-file ()
- (pl-many (csv-line)))
+ (pl-ensure
+ (pl-return (pl-endby (csv-line) (csv-eol))
+ (pl-eob))))
(defun csv-line ()
- (prog1 (csv-cells)
- (csv-eol)))
-
-(defun csv-eol ()
- (pl-or (pl-str "\n\r")
- (pl-str "\r\n")
- (pl-str "\n")
- (pl-str "\r")
- (pl-eob)))
-
-(defun csv-cells ()
- (cons (csv-cell-content) (csv-remaining-cells)))
-
-(defun csv-cell-content ()
- (pl-many-as-string (pl-re "[^,\n]")))
-
-(defun csv-remaining-cells ()
- (pl-or (pl-and (pl-ch ?,) (csv-cells))
- nil))
-
+ (pl-sepby (csv-cell) (pl-ch ?,)))
-(defun csv-file1 ()
- (pl-endby (csv-line1) (csv-eol)))
-
-(defun csv-line1 ()
- (pl-sepby (csv-cell2) (pl-ch ?,)))
-
-(defun csv-cell1 ()
- (pl-many-as-string (pl-re "[^,\r\n]")))
-
-(defun csv-cell2 ()
- (pl-or (csv-quoted-cell) (pl-many (pl-re "[^,\n\r]"))))
+(defun csv-cell ()
+ (pl-or (csv-quoted-cell) (pl-many-as-string (pl-re "[^,\n\r]"))))
(defun csv-quoted-cell ()
- (pl-ch ?\")
- (prog1 (pl-many (csv-quoted-char))
- (pl-failed (pl-ch ?\") "quote at end of cell")))
+ (pl-and (pl-ch ?\")
+ (pl-return (pl-many-as-string (csv-quoted-char))
+ (pl-ensure (pl-ch ?\")))))
(defun csv-quoted-char ()
(pl-or (pl-re "[^\"]")
(pl-and (pl-str "\"\"")
"\"")))
-(defun parse-csv1 (input)
- (with-temp-buffer
- (insert input)
- (goto-char (point-min))
- (csv-file1)))
-(parse-csv1 "\"a,1,s,b,\r\nd,e,f")
+(defun csv-eol ()
+ (pl-or (pl-str "\n\r")
+ (pl-str "\r\n")
+ (pl-str "\n")
+ (pl-str "\r")
+ (pl-eob)))
(defun parse-csv (input)
(with-temp-buffer
@@ -85,11 +58,10 @@
(goto-char (point-min))
(csv-file)))
-(parse-csv "a1s,b,\n\nd,e,f")
-(with-temp-buffer
- (insert "a,b,")
- (goto-char (point-min))
- (csv-line))
+(parse-csv "\"a,1,s\"s,b,\r\nd,e,f")
+(parse-csv "\"e\"\",f")
+(parse-csv "\"a,1,\r\n")
+(parse-csv "\"a,1,\"\",b,\r\nd,,f")
-(provide 'csv-parser)
-;;; csv-parser.el ends here
+(provide 'full-csv-parser)
+;;; full-csv-parser.el ends here
diff --git a/parsec.el b/parsec.el
index 1b52e22..7bca129 100644
--- a/parsec.el
+++ b/parsec.el
@@ -30,24 +30,55 @@
"Combinator parsing library for Emacs, similar to Haskell's Parsec"
:group 'development)
+(defun pl-eob-or-char-as-string ()
+ (let ((c (char-after)))
+ (if c
+ (char-to-string c)
+ "`eob'")))
+
+(defun pl-msg (msg)
+ (cons 'pl-msg msg))
+
+(defun pl-msg-p (msg)
+ (and (consp msg)
+ (eq (car msg) 'pl-msg)))
+
+(defalias 'pl-msg-get 'cdr)
+
+(defun pl-stop (&rest args)
+ (throw 'failed
+ (let ((msg (plist-get args :message))
+ (expected (plist-get args :expected))
+ (found (plist-get args :found)))
+ (when (or (stringp msg)
+ (and (stringp expected)
+ (stringp found)))
+ (pl-msg (if (stringp msg)
+ msg
+ (format "Found \"%s\" -> Expected \"%s\""
+ found expected)))))))
+
(defun pl-ch (ch &rest args)
- (if (and (not (eobp))
- (char-equal (char-after) ch))
- (prog1
- (cond
- ((memq :nil args) nil)
- ((memq :beg args)
- (point))
- ((memq :end args)
- (1+ (point)))
- (t
- (char-to-string ch)))
- (forward-char 1))
- (throw 'failed nil)))
+ (let ((next-char (char-after)))
+ (if (and (not (eobp))
+ (char-equal next-char ch))
+ (prog1
+ (cond
+ ((memq :nil args) nil)
+ ((memq :beg args)
+ (point))
+ ((memq :end args)
+ (1+ (point)))
+ (t
+ (char-to-string ch)))
+ (forward-char 1))
+ (pl-stop :expected (char-to-string ch)
+ :found (pl-eob-or-char-as-string)))))
(defun pl-eob ()
(unless (eobp)
- (throw 'failed nil)))
+ (pl-stop :expected "`eob'"
+ :found (pl-eob-or-char-as-string))))
(defun pl-re (regexp &rest args)
(if (looking-at regexp)
@@ -69,7 +100,8 @@
(t
(match-string 0)))
(goto-char (match-end 0)))
- (throw 'failed nil)))
+ (pl-stop :expected regexp
+ :found (pl-eob-or-char-as-string))))
(defsubst pl-str (str &rest args)
(pl-re (regexp-quote str)))
@@ -79,47 +111,58 @@
(defmacro pl-or (&rest parsers)
(let ((outer-sym (make-symbol "outer"))
- (parser-sym (make-symbol "parser"))
- (error-sym (make-symbol "error-message")))
+ (parser-sym (make-symbol "parser")))
`(loop named ,outer-sym for ,parser-sym in ',parsers
- finally (throw 'failed nil) do
- (when (setq ,error-sym
- (catch 'failed
- (return-from ,outer-sym (eval ,parser-sym))))
- (error ,error-sym)))))
+ finally (pl-stop :message "None of the parsers succeeds") do
+ (pl-try
+ (return-from ,outer-sym (eval ,parser-sym))))))
(defalias 'pl-and 'progn)
-(defmacro pl-failed (parser msg)
- `(pl-or ,parser
- (throw 'failed ,msg)))
+(defalias 'pl-return 'prog1)
(defmacro pl-try (&rest forms)
`(catch 'failed ,@forms))
+(defmacro pl-try-with-message (msg &rest forms)
+ (declare (indent 1))
+ (let ((res-sym (make-symbol "result")))
+ `(let ((,res-sym (pl-try ,@forms)))
+ ,(if msg
+ `(if (pl-msg-p ,res-sym)
+ (pl-msg ,msg)
+ ,res-sym)
+ `,res-sym))))
+
+(defmacro pl-ensure-with-message (msg &rest forms)
+ (declare (indent 1))
+ (let* ((error-sym (make-symbol "err")))
+ `(let (,error-sym)
+ (if (pl-msg-p (setq ,error-sym
+ (pl-try-with-message ,msg ,@forms)))
+ (error (pl-msg-get ,error-sym))
+ ,error-sym))))
+
+(defmacro pl-ensure (&rest forms)
+ `(pl-ensure-with-message nil ,@forms))
+
(defalias 'pl-parse 'pl-try)
(defmacro pl-until (parser &optional &key skip)
- (let ((error-sym (make-symbol "error-message")))
- `(let (,error-sym)
- (catch 'done
- (while (not (eobp))
- (when (setq ,error-sym
- (catch 'failed
- (throw 'done ,parser)))
- (error ,error-sym))
- ,(if skip
- `(,skip 1)
- `(forward-char 1)))))))
+ `(catch 'done
+ (while (not (eobp))
+ (pl-try
+ (throw 'done ,parser))
+ ,(if skip
+ `(,skip 1)
+ `(forward-char 1)))))
(defmacro pl-many (parser)
- (let ((res (make-symbol "results"))
- (msg (make-symbol "error-message")))
- `(let (,res ,msg)
- (when (setq ,msg (pl-try
- (while (not (eobp))
- (push ,parser ,res))))
- (error ,msg))
+ (let ((res (make-symbol "results")))
+ `(let (,res)
+ (pl-try
+ (while (not (eobp))
+ (push ,parser ,res)))
(nreverse ,res))))
(defun pl-list-to-string (l)
@@ -129,7 +172,7 @@
`(mapconcat #'identity (pl-many ,parser) ""))
(defmacro pl-endby (parser end)
- `(pl-many (prog1 ,parser
+ `(pl-many (pl-return ,parser
,end)))
(defmacro pl-sepby (parser separator)
diff --git a/simple-csv-parser.el b/simple-csv-parser.el
new file mode 100644
index 0000000..7bff683
--- /dev/null
+++ b/simple-csv-parser.el
@@ -0,0 +1,56 @@
+;;; simple-csv-parser.el --- Simple CSV parser using parsec.el -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2016 Junpeng Qiu
+
+;; Author: Junpeng Qiu <address@hidden>
+;; Keywords: extensions
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Ref: http://book.realworldhaskell.org/read/using-parsec.html
+
+;;; Code:
+
+(defun s-csv-file ()
+ (pl-many (s-csv-line)))
+
+(defun s-csv-line ()
+ (prog1 (s-csv-cells)
+ (s-csv-eol)))
+
+(defun s-csv-eol ()
+ (pl-or (pl-str "\n")
+ (pl-eob)))
+
+(defun s-csv-cells ()
+ (cons (s-csv-cell-content) (s-csv-remaining-cells)))
+
+(defun s-csv-cell-content ()
+ (pl-many-as-string (pl-re "[^,\n]")))
+
+(defun s-csv-remaining-cells ()
+ (pl-or (pl-and (pl-ch ?,) (s-csv-cells)) nil))
+
+(defun s-parse-csv (input)
+ (with-temp-buffer
+ (insert input)
+ (goto-char (point-min))
+ (s-csv-file)))
+
+(s-parse-csv "a1s,b,d,e,f")
+
+(provide 'simple-csv-parser)
+;;; simple-csv-parser.el ends here
- [elpa] master updated (e479a3e -> dfb3af0), Junpeng Qiu, 2016/10/25
- [elpa] master d21bf7d 14/60: Remove unused code, Junpeng Qiu, 2016/10/25
- [elpa] master 108879f 11/60: Better propagate naming and implementation, Junpeng Qiu, 2016/10/25
- [elpa] master 5810eef 21/60: Remove parsec-continue, Junpeng Qiu, 2016/10/25
- [elpa] master 452ec1e 35/60: Update scheme parser, Junpeng Qiu, 2016/10/25
- [elpa] master 14b28a1 16/60: Add basic README, Junpeng Qiu, 2016/10/25
- [elpa] master 606fed1 10/60: Add simple JSON parser, Junpeng Qiu, 2016/10/25
- [elpa] master d8cd9d6 17/60: Better naming, Junpeng Qiu, 2016/10/25
- [elpa] master a5ca813 04/60: Full & simple parser,
Junpeng Qiu <=
- [elpa] master 9996b5b 31/60: Update full-csv-parser, Junpeng Qiu, 2016/10/25
- [elpa] master bdfcbde 23/60: Update library description, Junpeng Qiu, 2016/10/25
- [elpa] master 2e8c52b 40/60: Make sure parsec-not-followed-by consumes no input, Junpeng Qiu, 2016/10/25
- [elpa] master fb26929 34/60: Fix parsec-make-alternatives, Junpeng Qiu, 2016/10/25
- [elpa] master 31388e6 52/60: Add -s aliases, Junpeng Qiu, 2016/10/25
- [elpa] master 34521c6 53/60: Update README about *-s functions, Junpeng Qiu, 2016/10/25
- [elpa] master 8f0c266 58/60: Add doc for parsec-peek(-p), Junpeng Qiu, 2016/10/25
- [elpa] master ffd42de 45/60: Use simple-csv-parser.el as a demo, Junpeng Qiu, 2016/10/25
- [elpa] master bf49fb6 38/60: Upate README, Junpeng Qiu, 2016/10/25
- [elpa] master 966ca9e 43/60: Add comments to parsec.el, Junpeng Qiu, 2016/10/25