emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/sql-smie 5d7ab51: * sql-smie.el: New package


From: Stefan Monnier
Subject: [elpa] externals/sql-smie 5d7ab51: * sql-smie.el: New package
Date: Tue, 10 Mar 2020 08:34:14 -0400 (EDT)

branch: externals/sql-smie
commit 5d7ab517270234e1209fb5165955007ed27ccf5c
Author: Stefan Monnier <address@hidden>
Commit: Stefan Monnier <address@hidden>

    * sql-smie.el: New package
---
 .gitignore  |   3 ++
 sql-smie.el | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8add928
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.elc
+sql-smie-autoloads.el
+sql-smie-pkg.el
diff --git a/sql-smie.el b/sql-smie.el
new file mode 100644
index 0000000..6fb1ff6
--- /dev/null
+++ b/sql-smie.el
@@ -0,0 +1,172 @@
+;;; sql-smie.el --- SMIE support for SQL-mode        -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2020  Free Software Foundation, Inc.
+
+;; Author: Stefan Monnier <address@hidden>
+;; Keywords:
+;; Version: 0
+
+;; 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 <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides SMIE support for SQL-mode.
+;;
+;; It is currently quite inferior to `sql-indent' at indenting SQL code because
+;; it only handles a tiny subset of the SQL language, so don't bother trying it
+;; out for that purpose unless you're interested in improving it.
+;;
+;; To make use of it, you can do something like:
+;;
+;;     (add-hook 'sql-mode-hook #'sql-smie-enable)
+;;
+;; It can be used together with `sql-indent', where `sql-indent' takes care
+;; of indenting and `sql-smie' is used for navigation, auto-fill, blink-paren,
+;; etc...
+
+;;; Code:
+
+(require 'smie)
+
+(defconst sql-smie-grammar
+  ;; FIXME:
+  ;; - Terribly incomplete.
+  (smie-prec2->grammar
+   (smie-bnf->prec2
+    ;; Note: To improve this, http://www.h2database.com/html/grammar.html
+    ;; could be useful.
+    '((id)
+      (insts ("BEGIN" insts "END")
+             (cmd)
+             (foo)
+             (insts ";" insts)
+             ("FOR" range "LOOP" insts "END")
+             ("IF" cond-then-insts "END")
+             ("IF" cond-then-insts "ELSE" insts "END")
+             ("IF" cond-then-insts "ELSIF" cond-then-insts "ELSE" insts "END"))
+      (cond-then-insts (cond "THEN" insts))
+      (cond (exp))
+      (range (id "IN" cmd))
+      (cmd ("SELECT" after-select )
+           ("INSERT INTO" cmd)
+           )
+      (after-select (exp "FROM" arg-of-from)
+                    (after-select "WHERE" arg-of-where)
+                    (after-select "foo BY" after-select))
+      (arg-of-where (arg-of-where "AND" arg-of-where)
+                    (arg-of-where "OR" arg-of-where)(exp))
+      (arg-of-from  (arg-of-from "foo JOIN" arg-of-from)
+                    (arg-of-from "ON" arg-of-from))
+      ;; (select-exp ("*") (exp) (exp "AS" column-alias))
+      ;; (table-exp (id) (table-exp "foo JOIN" table-exp)
+      ;;            (table-exp "ON" exp))
+      (exp (id "IN" exp) (exp "=" exp)
+           ;; FIXME: The "CASE" rules look plain wrong!
+           ("CASE" exp "WHEN" cond-then-insts "ELSE" exp "END")
+           ("CASE" exp "WHEN" cond-then-insts "END")
+           (exp "," exp) (exp "||" exp))
+      )
+    '((assoc ";"))
+    '((assoc "ELSE"))
+    '((assoc "IN") (assoc ",") (assoc "||") (assoc "="))
+    '((assoc "FROM" "WHERE" "foo BY") (assoc "OR") (assoc "AND"))
+    '((assoc "foo JOIN") (assoc "ON")))))
+
+(defconst sql-smie--token-pairs
+  '(("END" ("IF" "LOOP"))
+    ;; FIXME: Reality is more complex than that:
+    ;;     [ { { LEFT | RIGHT } [ OUTER ] | [ INNER ] | CROSS | NATURAL }
+    ;;     JOIN tableExpression [ joinSpecification ] ]
+    (("NATURAL" "INNER" "OUTER" "LEFT" "RIGHT") "JOIN" "foo JOIN")
+    (("GROUP" "ORDER" "PARTITION") "BY" "foo BY")
+    ("INSERT" "INTO" "INSERT INTO")))
+
+(defconst sql-smie--tokens-pairs-by-heads
+  (let ((res (make-hash-table :test #'equal)))
+    (pcase-dolist (`(,head ,tail ,tok) sql-smie--token-pairs)
+      (let ((tok (or tok (if (listp head) tail head))))
+        (dolist (head (if (listp head) head (list head)))
+          (dolist (tail (if (listp tail) tail (list tail)))
+            (push (cons tail tok) (gethash head res))))))
+    res))
+
+(defconst sql-smie--tokens-pairs-by-tails
+  (let ((res (make-hash-table :test #'equal)))
+    (pcase-dolist (`(,head ,tail ,tok) sql-smie--token-pairs)
+      (let ((tok (or tok (if (listp head) tail head))))
+        (dolist (head (if (listp head) head (list head)))
+          (dolist (tail (if (listp tail) tail (list tail)))
+            (push (cons head tok) (gethash tail res))))))
+    res))
+
+(defun sql-smie-forward-token ()
+  (let* ((tok (upcase (smie-default-forward-token)))
+         (paired (gethash tok sql-smie--tokens-pairs-by-heads)))
+    (cond
+     (paired
+      (let* ((pos (point))
+             (next (upcase (smie-default-forward-token)))
+             (tail (assoc next paired)))
+        (if tail
+            (cdr tail)
+          (goto-char pos)
+          tok)))
+     (t tok))))
+
+(defun sql-smie-backward-token ()
+  (let* ((tok (upcase (smie-default-backward-token)))
+         (paired (gethash tok sql-smie--tokens-pairs-by-tails)))
+    (cond
+     (paired
+      (let* ((pos (point))
+             (next (upcase (smie-default-backward-token)))
+             (head (assoc next paired)))
+        (if head
+            (cdr head)
+          (goto-char pos)
+          tok)))
+     (t tok))))
+
+(defun sql-smie-rules (kind token)
+  (pcase (cons kind token)
+    ;; (`(:list-intro . ,_) t) ;;FIXME!
+    (`(:after . ";")
+     ;; Don't align with semi-colon!
+     (smie-backward-sexp token) `(column . ,(smie-indent-virtual)))
+    (`(:before . "(") (smie-rule-parent))
+    (`(:after . "THEN") (smie-rule-parent smie-indent-basic))
+    (`(:before . "IN")
+     (if (smie-rule-parent-p "FOR")
+         (smie-rule-parent smie-indent-basic)))
+    (`(:before . "SELECT")
+     (when (smie-rule-parent-p "INSERT INTO")
+       (goto-char (cadr smie--parent))
+       (sql-smie-backward-token)
+       `(column . ,(+ 0 (smie-indent-virtual)))))
+    (`(:before . "AND")
+     (if (smie-rule-parent-p "WHERE")
+         (smie-rule-parent (max 0 (- (length "WHERE") (length token))))))
+    (`(:before . ,(or "FROM" "WHERE" "foo BY"))
+     (if (smie-rule-parent-p "SELECT")
+         (smie-rule-parent (max 1 (- (length "SELECT") (length token))))))))
+
+
+;;;###autoload
+(defun sql-smie-enable ()
+  (smie-setup sql-smie-grammar #'sql-smie-rules
+              :forward-token #'sql-smie-forward-token
+              :backward-token #'sql-smie-backward-token))
+
+(provide 'sql-smie)
+;;; sql-smie.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]