Function: sqlind-refine-syntax

sqlind-refine-syntax is a natively compiled function defined in sql-indent.el.

Signature

(sqlind-refine-syntax CONTEXT POS HAVE-BLOCK-CONTEXT)

Documentation

Refine a basic syntax CONTEXT at POS.

CONTEXT is a syntactic context obtained by looking at the statement start and block start, see sqlind-syntax-of-line. We refine it by looking at the contents of the current line and the contents of the anchor.

HAVE-BLOCK-CONTEXT indicates that we are indenting a statement, not a statement-continuation POS is the same as the sqlind-beginning-of-statement.

Source Code

;; Defined in /nix/store/jxjf2h9nnkdqnn1w1mr0ag8bqng2rlrs-emacs-packages-deps/share/emacs/site-lisp/elpa/sql-indent-1.7/sql-indent.el
;;;;; sqlind-syntax-of-line

(defun sqlind-refine-syntax (context pos have-block-context)
  "Refine a basic syntax CONTEXT at POS.
CONTEXT is a syntactic context obtained by looking at the
statement start and block start, see `sqlind-syntax-of-line'.  We
refine it by looking at the contents of the current line and the
contents of the anchor.

HAVE-BLOCK-CONTEXT indicates that we are indenting a statement,
not a statement-continuation POS is the same as the
`sqlind-beginning-of-statement'."
  (let ((syntax (sqlind-syntax context))
        (anchor (sqlind-anchor-point context))
        (syntax-symbol (sqlind-syntax-symbol context)))

    (goto-char pos)

    (cond
      ;; do we start a comment?
      ((and (not (eq syntax-symbol 'comment-continuation))
            (looking-at sqlind-comment-start-skip))
       (push (cons 'comment-start anchor) context))

      ;; Refine a statement continuation
      ((memq syntax-symbol '(statement-continuation nested-statement-continuation))

       ;; a (nested) statement continuation which starts with loop
       ;; or then is a block start
       (if (and have-block-context (looking-at "\\(loop\\|then\\|when\\)\\_>"))
           (push (cons (list 'block-start (intern (sqlind-match-string 0))) anchor)
                 context)
         ;; else
         (goto-char anchor)
         (when (eq syntax 'nested-statement-continuation)
           (forward-char 1)
           (sqlind-forward-syntactic-ws)
           (setq anchor (point)))

         ;; when all we have before `pos' is a label, we have a
         ;; labeled-statement-start
         (when (looking-at "<<\\([a-z0-9_]+\\)>>")
           (goto-char (match-end 0))
           (forward-char 1)
           (sqlind-forward-syntactic-ws)
           (when (eq (point) pos)
             (push (cons 'labeled-statement-start anchor) context)))

         (when (looking-at "when\\_>")
           (let* ((acontext (sqlind-syntax-of-line))
                  (asyntax (sqlind-syntax acontext)))
             (cond ((equal asyntax '(in-block exception ""))
                    (push (cons '(in-block exception-handler "") (point)) context))
                   ((equal asyntax '(block-start when))
                    ;; Refine again in the context of the when line
                    (setq context (sqlind-refine-syntax (cdr acontext) pos have-block-context))))))

         ;; maybe we have a DML statement (select, insert, update and
         ;; delete)

         ;; skip a cursor definition if it is before our point, in the
         ;; following format:
         ;;
         ;; CURSOR name IS
         ;; CURSOR name type IS
         (when (looking-at "cursor\\b")
           (let ((origin (point)))
             (forward-sexp 1)           ; skip "cursor"
             (sqlind-forward-syntactic-ws)
             (forward-sexp 1)
             (sqlind-forward-syntactic-ws)
             (if (looking-at "is\\b")
                 (progn
                   (goto-char (match-end 0))
                   (sqlind-forward-syntactic-ws))
               (forward-sexp 1)
               (sqlind-forward-syntactic-ws)
               (when (looking-at "is\\b")
                 (goto-char (match-end 0))
                 (sqlind-forward-syntactic-ws)))
             (unless (<= (point) pos)
               (goto-char origin))))

         ;; Skip a PostgreSQL cursor declaration
         (when (and (eq sql-product 'postgres)
                    (looking-at "\\(\\(declare\\)\\|\\(cursor\\)\\|\\(for\\)\\)\\b"))
           (when (re-search-forward "\\b\\(select\\|update\\|delete\\|insert\\)\\b" pos 'noerror)
             (goto-char (match-beginning 0))))

         ;; skip a forall statement if it is before our point
         (when (looking-at "forall\\b")
           (when (re-search-forward "\\b\\(select\\|update\\|delete\\|insert\\)\\b" pos 'noerror)
             (goto-char (match-beginning 0))))

         ;; only check for syntax inside DML clauses if we are not
         ;; at the start of one.
         (when (< (point) pos)
           (cond
             ;; NOTE: We only catch here "CASE" expressions, not CASE
             ;; statements.  We also catch assignments with case (var
             ;; := CASE ...)
             ((looking-at "\\(\\w+[ \t\r\n\f]+:=[ \t\r\n\f]+\\)?\\(case\\)")
              (when (< (match-beginning 2) pos)
                (push (sqlind-syntax-in-case pos (match-beginning 2)) context)))
             ((looking-at "with")
              (push (sqlind-syntax-in-with pos (point)) context))
             ((looking-at "select")
              (push (sqlind-syntax-in-select pos (point)) context))
             ((and (eq sql-product 'postgres)
                   (looking-at "perform"))
              (push (sqlind-syntax-in-select pos (point)) context))
             ((looking-at "insert")
              (push (sqlind-syntax-in-insert pos (point)) context))
             ((looking-at "delete")
              (push (sqlind-syntax-in-delete pos (point)) context))
             ((looking-at "update")
              (push (sqlind-syntax-in-update pos (point)) context))))

         (when (eq (sqlind-syntax-symbol context) 'select-column-continuation)
           (let ((cdef (sqlind-column-definition-start pos (sqlind-anchor-point context))))
             (when cdef
               (save-excursion
                 (goto-char cdef)
                 (when (looking-at "case")
                   (push (sqlind-syntax-in-case pos (point)) context))))))

         (when (eq (sqlind-syntax-symbol context) 'nested-statement-continuation)
           (save-excursion
             ;; Look for a join expression inside a nested statement, see #70
	     (goto-char pos)
	     (when (or (looking-at sqlind-join-condition-regexp)
		       (progn (forward-word -1) (looking-at sqlind-join-condition-regexp)))
	       ;; look for the join start, that will be the anchor
               (let ((jstart (sqlind-find-join-start (point) anchor)))
                 (when jstart
                   (push (cons 'select-join-condition jstart) context))))))

         ))

    ;; create block start syntax if needed

    ((and (eq syntax-symbol 'in-block)
          (memq (nth 1 syntax) '(if elsif elseif then case))
          (looking-at "\\(then\\|\\(els\\(e\\|e?if\\)\\)\\)\\_>"))
     (let ((what (intern (sqlind-match-string 0))))
       ;; the only invalid combination is a then statement in
       ;; an (in-block "then") context
       (unless (and (eq what 'then) (equal (nth 1 syntax) 'then))
         (push (cons (list 'block-start what) anchor) context))))

    ((and (eq syntax-symbol 'in-block)
          (eq (nth 1 syntax) 'exception)
          (not (looking-at "\\(when\\|end\\)\\_>")))
     (save-excursion
       (when (sqlind-search-backward pos "when\\_>" anchor)
         (push (cons (list 'in-block 'exception-handler) (point)) context))))

    ;; note that begin is not a block-start in a 'in-begin-block
    ;; context
    ((and (memq syntax-symbol '(defun-start declare-statement toplevel
                                package package-body))
          (or (looking-at "begin\\_>")
              (and (eq sql-product 'postgres) (looking-at "\\$\\$"))))
     (push (cons (list 'block-start 'begin) anchor) context))

    ((and (memq syntax-symbol '(defun-start package package-body))
          (looking-at "\\(is\\|as\\)\\_>"))
     (push (cons (list 'block-start 'is-or-as) anchor) context))

    ((and (memq syntax-symbol '(in-begin-block in-block))
          (looking-at "exception\\_>"))
     (push (cons (list 'block-start 'exception) anchor) context))

    ((and (eq syntax-symbol 'in-block)
          (memq (nth 1 syntax) '(then case))
          (not (looking-at "end\\s-*\\_<\\(if\\|case\\)\\_>")))
     (if (looking-at "when\\_>")
         (push (cons (list 'block-start 'when) anchor) context)
       ;; NOTE: the "when" case is handed above
       (when (sqlind-search-backward pos "when\\_>" anchor)
         (push (cons '(in-block when) (point)) context))))

    ;; indenting the select clause inside a view or a "create table as"
    ;; statement.
    ((and (eq syntax-symbol 'create-statement)
          (memq (nth 1 syntax) '(view table)))
     (goto-char anchor)
     (catch 'done
       (while (re-search-forward "\\bselect\\b" pos 'noerror)
         (goto-char (match-beginning 0))
         (when (sqlind-same-level-statement (point) anchor)
           (push (sqlind-syntax-in-select pos (point)) context)
           (throw 'done nil))
         (goto-char (match-end 0)))))

    ;; create a block-end syntax if needed

    ((and (not (eq syntax-symbol 'comment-continuation))
          (looking-at "end[ \t\r\n\f]*\\(\\_<\\(?:if\\|loop\\|case\\)\\_>\\)?[ \t\r\n\f]*\\(\\_<\\(?:[a-z0-9_]+\\)\\_>\\)?"))
     ;; so we see the syntax which closes the current block.  We still
     ;; need to check if the current end is a valid closing block
     (let ((kind (or (sqlind-match-string 1) ""))
           (label (or (sqlind-match-string 2) "")))
       (push (sqlind-refine-end-syntax
              (if (equal kind "") nil (intern kind))
              label (point) context)
             context)))

    ((and (eq sql-product 'postgres)
          (not (eq syntax-symbol 'comment-continuation))
          (looking-at "\\$\\$"))
     (push (sqlind-refine-end-syntax
            nil "" (point) context)
           context))

    ;; See #92 and pr92b.sql, no such thing as a nested declare statement, use
    ;; the context of the previous declare-statement!
    ((and (eq sql-product 'postgres)
          (eq syntax-symbol 'declare-statement)
          (looking-at "declare\\_>"))
     (goto-char anchor)
     (setq context (sqlind-syntax-of-line)))

    )
  context))