[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/parseclj 7beff77b15 083/185: Introduce parseclj-parse-cloj
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/parseclj 7beff77b15 083/185: Introduce parseclj-parse-clojure |
Date: |
Tue, 28 Dec 2021 14:05:20 -0500 (EST) |
branch: elpa/parseclj
commit 7beff77b154b4d39672f66632c92d071fe7d6842
Author: Arne Brasseur <arne@arnebrasseur.net>
Commit: Arne Brasseur <arne@arnebrasseur.net>
Introduce parseclj-parse-clojure
---
parseclj-ast.el | 16 +--------
parseclj.el | 86 ++++++++++++++++++++++++++++++++++++-----------
test/parseclj-ast-test.el | 10 +++---
3 files changed, 72 insertions(+), 40 deletions(-)
diff --git a/parseclj-ast.el b/parseclj-ast.el
index c4b52e1bd9..0632fa35e8 100644
--- a/parseclj-ast.el
+++ b/parseclj-ast.el
@@ -61,20 +61,6 @@
(parseclj--make-node type pos :children children)
stack)))))
-(defun parseclj-ast-parse ()
- "Parse Clojure code in buffer to AST.
-
-Parses code in the current buffer, starting from the current
-position of (point)."
- (parseclj-parse #'parseclj-ast--reduce-leaf #'parseclj-ast--reduce-branch))
-
-(defun parseclj-ast-parse-str (s)
- "Parse Clojure code in string S to AST."
- (with-temp-buffer
- (insert s)
- (goto-char 1)
- (parseclj-ast-parse)))
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Unparser
@@ -95,7 +81,7 @@ position of (point)."
(parseclj-ast-unparse (car (a-get node :children)))))
(defun parseclj-ast-unparse (node)
- (if (parseclj--is-leaf? node)
+ (if (parseclj--leaf? node)
(insert (alist-get ':form node))
(let ((subnodes (alist-get ':children node)))
(cl-case (a-get node ':node-type)
diff --git a/parseclj.el b/parseclj.el
index 9b8617c3c5..d4cf1fefa0 100644
--- a/parseclj.el
+++ b/parseclj.el
@@ -38,29 +38,26 @@
(require 'parseclj-ast)
(defvar parseclj--leaf-tokens '(:whitespace
- :comment
- :number
- :nil
- :true
- :false
- :symbol
- :keyword
- :string
- :character)
+ :comment
+ :number
+ :nil
+ :true
+ :false
+ :symbol
+ :keyword
+ :string
+ :character)
"Tokens that represent leaf nodes in the AST.")
(defvar parseclj--closer-tokens '(:rparen
- :rbracket
- :rbrace)
+ :rbracket
+ :rbrace)
"Tokens that represent closing of an AST branch.")
-(defun parseclj--is-leaf? (node)
+(defun parseclj--leaf? (node)
+ "Return `t' if the given ast NODE is a leaf node."
(member (a-get node ':node-type) parseclj--leaf-tokens))
-(defun parseclj--is-open-prefix? (el)
- (and (member (parseclj-lex-token-type el) '(:discard :tag))
- (parseclj-lex-token? el)))
-
;; The EDN spec is not clear about wether \u0123 and \o012 are supported in
;; strings. They are described as character literals, but not as string escape
;; codes. In practice all implementations support them (mostly with broken
@@ -137,7 +134,30 @@
(message "STACK: %S , CLOSER: %S" stack closer-token)
(error "Syntax Error")))))
-(defun parseclj-parse (reduce-leaf reduce-branch)
+(defun parseclj-parse (reduce-leaf reduce-branch &optional options)
+ "Clojure/EDN stack-based shift-reduce parser.
+
+REDUCE-LEAF does reductions for leaf nodes. It is a function that
+takes the current value of the stack and a token, and either
+returns an updated stack, with a new leaf node at the
+top (front), or returns the stack unmodified.
+
+REDUCE-BRANCH does reductions for branch nodes. It is a function
+that takes the current value of the stack, the type of branch
+node to create, and a list of child nodes, and returns an updated
+stack, with the new node at the top (front).
+
+What \"node\" means in this case is up to the reducing functions,
+it could be AST nodes (as in the case of
+`parseclj-parse-clojure'), or plain values/sexps (as in the case
+of `parseedn-read'), or something else. The only requirement is
+that they should not put raw tokens back on the stack, as the
+parser relies on the presence or absence of these to detect parse
+errors.
+
+OPTIONS is an association list which is passed on to the reducing
+functions.
+"
(let ((stack nil))
(while (not (eq (parseclj-lex-token-type (setq token (parseclj-lex-next)))
:eof))
@@ -153,15 +173,41 @@
;; Reduce based on top two items on the stack (special prefixed elements)
(seq-let [top lookup] stack
- (when (and (parseclj--is-open-prefix? lookup)
- (not (parseclj-lex-token? top))) ;; top is fully reduced
- (setf stack (funcall reduce-branch (cddr stack) lookup (list
top))))))
+ (when (and (parseclj-lex-token? lookup)
+ (not (parseclj-lex-token? top)) ;; top is fully reduced
+ (member (parseclj-lex-token-type lookup) '(:discard :tag)))
+ (setf stack (funcall reduce-branch (cddr stack) lookup (list
top))))))
;; reduce root
(setf stack (funcall reduce-branch stack '((type . :root) (pos . 1))
stack))
;; (message "RESULT: %S" stack)
stack))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Top level API
+
+(defun parseclj-parse-clojure (&rest string-and-options)
+ "Parse Clojure source to AST.
+
+Reads either from the current buffer, starting from point, until
+point-max, or reads from the optional string argument.
+
+STRING-AND-OPTIONS can be an optional string, followed by
+key-value pairs to specify parsing options.
+
+- `:lexical-preservation' Retain whitespace, comments, and
+ discards. Defaults to false (`nil').
+- `:fail-fast' Raise an error
+ when encountering invalid syntax. Defaults to true (`t'). "
+ (if (stringp (car string-and-options))
+ (with-temp-buffer
+ (insert (car string-and-options))
+ (goto-char 1)
+ (apply 'parseclj-parse-clojure (cdr string-and-options)))
+ (parseclj-parse #'parseclj-ast--reduce-leaf
+ #'parseclj-ast--reduce-branch
+ (apply 'a-list string-and-options))))
+
(provide 'parseclj)
diff --git a/test/parseclj-ast-test.el b/test/parseclj-ast-test.el
index 59ec572e86..7283b8de68 100644
--- a/test/parseclj-ast-test.el
+++ b/test/parseclj-ast-test.el
@@ -32,20 +32,20 @@
(load "test/parseclj-test-data.el")
-(defmacro define-parseclj-ast-parse-tests ()
+(defmacro define-parseclj-parse-clojure-tests ()
`(progn
,@(mapcar
(lambda (pair)
(let ((name (car pair))
(data (cdr pair)))
(if (and (a-get data :source) (a-get data :ast))
- (let ((test-name (intern (concat "parseclj-ast-parse:" name))))
+ (let ((test-name (intern (concat "parseclj-parse-clojure:"
name))))
`(ert-deftest ,test-name ()
:tags '(parseclj-ast)
(with-temp-buffer
(insert ,(a-get data :source))
(goto-char 1)
- (should (a-equal (parseclj-ast-parse) ',(a-get data
:ast)))))))))
+ (should (a-equal (parseclj-parse-clojure) ',(a-get data
:ast)))))))))
parseclj-test-data)))
(defmacro define-parseclj-ast-roundtrip-tests ()
@@ -58,11 +58,11 @@
(let ((test-name (intern (concat "parseclj-ast-rountrip:"
name))))
`(ert-deftest ,test-name ()
:tags '(parseclj-ast-rountrip)
- (should (a-equal (parseclj-ast-parse-str
(parseclj-ast-unparse-str ',(a-get data :ast))) ',(a-get data :ast))))))))
+ (should (a-equal (parseclj-parse-clojure
(parseclj-ast-unparse-str ',(a-get data :ast))) ',(a-get data :ast))))))))
parseclj-test-data)))
(define-parseclj-ast-roundtrip-tests)
-(define-parseclj-ast-parse-tests)
+(define-parseclj-parse-clojure-tests)
;;; parseclj-ast-test.el ends here
- [nongnu] elpa/parseclj f8822bb43c 040/185: Add support for tags in lexer, (continued)
- [nongnu] elpa/parseclj f8822bb43c 040/185: Add support for tags in lexer, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 43f59dcb91 043/185: Avoid dropping whitespaces, handling them while reducing, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 7733985037 047/185: DESIGN.md-related adjustments, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj c906de33a1 048/185: Rewrite all tests, and add new tests for the AST "printer", ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 697618dbb1 049/185: Merge pull request #1 from volrath/master, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj e7686c49ed 052/185: Greater parity with edn.el, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 2da47798d9 057/185: Enable more edn.el tests, document how time/uuid are stored, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj f6de87fbe6 067/185: Split EDN and AST handling in separate files, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj d410a1530e 096/185: Add code-checking defaults to `dir-locals.el`, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 3a92eafce9 079/185: Rename reduce-node to reduce-branch, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 7beff77b15 083/185: Introduce parseclj-parse-clojure,
ELPA Syncer <=
- [nongnu] elpa/parseclj 3d261f5d3c 072/185: Bump version of a, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 47cf208a91 091/185: Fix parsing of tags/discard with :lexical-preservation, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj da4bacb5f5 078/185: Rename parseclj-reduce to parseclj-parse, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 2a42dcb6fa 066/185: Update License info in README, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj ba9f4d723f 076/185: Document proposal for alternative package organization, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj a8e1de0d62 075/185: Merge pull request #4 from lambdaisland/edn-ast-split, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 6fdf22a553 062/185: Update license, fix dependencies, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 5fbe901cba 071/185: Parse/unparse :tag, rountrip AST, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj 6e0dc9516c 093/185: Add missing require, ELPA Syncer, 2021/12/28
- [nongnu] elpa/parseclj b79b3a5438 098/185: Add documentation to `parseclj-ast.el`, ELPA Syncer, 2021/12/28