parseclj.el (3508B)
1 ;;; parseclj.el --- Clojure/EDN parser -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2017-2021 Arne Brasseur 4 5 ;; Author: Arne Brasseur <arne@arnebrasseur.net> 6 ;; Keywords: lisp clojure edn parser 7 ;; Package-Requires: ((emacs "25")) 8 ;; Version: 1.1.0 9 10 ;; This file is not part of GNU Emacs. 11 12 ;; This file is free software; you can redistribute it and/or modify 13 ;; it under the terms of the GNU General Public License as published by 14 ;; the Free Software Foundation; either version 3, or (at your option) 15 ;; any later version. 16 17 ;; This file is distributed in the hope that it will be useful, 18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 ;; GNU General Public License for more details. 21 22 ;; You should have received a copy of the GNU General Public License 23 ;; along with GNU Emacs; see the file COPYING. If not, write to 24 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 25 ;; Boston, MA 02110-1301, USA. 26 27 ;;; Commentary: 28 29 ;; Top level API for the Clojure parser. 30 31 ;;; Code: 32 33 (require 'map) 34 (require 'seq) 35 36 (require 'parseclj-parser) 37 (require 'parseclj-ast) 38 (require 'parseclj-alist) 39 40 (defun parseclj-parse-clojure (&rest string-and-options) 41 "Parse Clojure source to AST. 42 43 Reads either from the current buffer, starting from point, until 44 `point-max', or reads from the optional string argument. 45 46 STRING-AND-OPTIONS can be an optional string, followed by 47 key-value pairs to specify parsing options. 48 49 - `:lexical-preservation' Retain whitespace, comments, and 50 discards. Defaults to nil. 51 - `:fail-fast' Raise an error when encountering invalid syntax. 52 Defaults to t. 53 - `:read-one' 54 Read a single form. Defaults to false: parse the complete input." 55 (if (stringp (car string-and-options)) 56 (with-temp-buffer 57 (insert (car string-and-options)) 58 (goto-char 1) 59 (apply 'parseclj-parse-clojure (cdr string-and-options))) 60 (let* ((value-p (lambda (e) 61 (and (parseclj-ast-node-p e) 62 (not (member (parseclj-ast-node-type e) '(:whitespace :comment :discard)))))) 63 (options (apply 'parseclj-alist :value-p value-p string-and-options)) 64 (lexical? (map-elt options :lexical-preservation))) 65 (parseclj-parser (if lexical? 66 #'parseclj-ast--reduce-leaf-with-lexical-preservation 67 #'parseclj-ast--reduce-leaf) 68 (if lexical? 69 #'parseclj-ast--reduce-branch-with-lexical-preservation 70 #'parseclj-ast--reduce-branch) 71 options)))) 72 73 (defun parseclj-unparse-clojure (ast) 74 "Parse Clojure AST to source code. 75 76 Given an abstract syntax tree AST (as returned by 77 `parseclj-parse-clojure'), turn it back into source code, and 78 insert it into the current buffer." 79 (if (parseclj-ast-leaf-node-p ast) 80 (insert (map-elt ast :form)) 81 (if (eql (parseclj-ast-node-type ast) :tag) 82 (parseclj-ast--unparse-tag ast) 83 (parseclj-ast--unparse-collection ast)))) 84 85 (defun parseclj-unparse-clojure-to-string (ast) 86 "Parse Clojure AST to a source code string. 87 88 Given an abstract syntax tree AST (as returned by 89 `parseclj-parse-clojure'), turn it back into source code, and 90 return it as a string" 91 (with-temp-buffer 92 (parseclj-unparse-clojure ast) 93 (buffer-substring-no-properties (point-min) (point-max)))) 94 95 (provide 'parseclj) 96 97 ;;; parseclj.el ends here