Function: sqlind-refine-end-syntax

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

Signature

(sqlind-refine-end-syntax END-KIND END-LABEL END-POS CONTEXT)

Documentation

Return a 'block-end syntax when line contains an "end" keyword.

END-KIND contains the symbol after the end statement ('if if the statement is an "end if", 'loop if the statement is an
"end loop", etc). This can be nil if there is a plain "end"
keyword.

END-LABEL contains the label of the end statement, when there is one.

END-POS is the position where the "end" keyword is.

CONTEXT represents the syntactic context up to the current line.

The function will perform some validations, for example, an "end if" must close an if statement, an "end loop" must close a loop, etc. It will return a 'syntax-error syntax if the validation fails.

If all checks pass, it will return a (block-end KIND LABEL) where KIND is the symbol determining the type of the block ('if,
'loop, 'procedure, etc) and LABEL is the block label, if
there is any.

Source Code

;; Defined in /nix/store/jxjf2h9nnkdqnn1w1mr0ag8bqng2rlrs-emacs-packages-deps/share/emacs/site-lisp/elpa/sql-indent-1.7/sql-indent.el
;;;;; Refine the syntax of an end statement.

(defun sqlind-refine-end-syntax (end-kind end-label end-pos context)
  "Return a \\='block-end syntax when line contains an \"end\" keyword.

END-KIND contains the symbol after the end statement (\\='if if
the statement is an \"end if\", \\='loop if the statement is an
\"end loop\", etc).  This can be nil if there is a plain \"end\"
keyword.

END-LABEL contains the label of the end statement, when there is
one.

END-POS is the position where the \"end\" keyword is.

CONTEXT represents the syntactic context up to the current line.

The function will perform some validations, for example, an \"end
if\" must close an if statement, an \"end loop\" must close a
loop, etc.  It will return a \\='syntax-error syntax if the
validation fails.

If all checks pass, it will return a (block-end KIND LABEL) where
KIND is the symbol determining the type of the block (\\='if,
\\='loop, \\='procedure, etc) and LABEL is the block label, if
there is any."
  (catch 'done

    (when (null context)                ; can happen
      (throw 'done
        (cons (list 'syntax-error "end statement closes nothing"
                    end-pos end-pos)
              end-pos)))

    (let ((syntax (sqlind-syntax context))
          (anchor (sqlind-anchor-point context))
          (syntax-symbol (sqlind-syntax-symbol context)))
      (cond
	((memq syntax-symbol '(package package-body))
	 ;; we are closing a package declaration or body, `end-kind' must be
	 ;; empty, `end-label' can be empty or it must match the package name
	 (throw 'done
	   (cons
	    (cond (end-kind   ; no end-kind is allowed for a package
		   (list 'syntax-error
			 "bad closing for package" anchor end-pos))
		  ((sqlind-labels-match end-label (nth 1 syntax))
		   (list 'block-end syntax-symbol (nth 1 syntax)))
		  (t
		   (list 'syntax-error "mismatched end label for package"
			 anchor end-pos)))
	    anchor)))

	((eq syntax-symbol 'in-begin-block)
	 ;; we are closing a begin block (either toplevel, procedure/function
	 ;; or a simple begin block.  `end-kind' must be empty, `end-label'
	 ;; can be empty or it must match the pakage-name
	 (let ((block-label (nth 2 syntax)))
	   (throw 'done
	     (cons
	      (cond (end-kind ; no end-kind is allowed for a begin block
		     (list 'syntax-error
			   "bad closing for begin block" anchor end-pos))
		    ((sqlind-labels-match end-label block-label)
		     (list 'block-end (nth 1 syntax) block-label))
		    (t
		     (list 'syntax-error "mismatched end label for block"
			   anchor end-pos)))
	      anchor))))

	((eq syntax-symbol 'in-block)
	 (let ((block-kind (nth 1 syntax))
	       (block-label (nth 2 syntax)))
	   (cond
	     ((eq block-kind 'exception)
	      (goto-char anchor)
	      (throw 'done
		(sqlind-refine-end-syntax
		 end-kind end-label end-pos (sqlind-syntax-of-line))))

	     ((eq block-kind 'loop)
	      (throw 'done
		(cons
		 (cond ((not (eq end-kind 'loop))
			(list 'syntax-error "bad closing for loop block"
			      anchor end-pos))
		       ((not (sqlind-labels-match end-label block-label))
			(list 'syntax-error "mismatched end label for loop"
			      anchor end-pos))
		       (t
			(list 'block-end block-kind block-label)))
		 anchor)))

	     ((eq block-kind 'then)
	      (goto-char anchor)

	      (catch 'found
		(while t
		  (let ((then-context (sqlind-syntax-of-line)))
		    (goto-char (cdar then-context))
		    (cond
		      ((looking-at "when\\_>\\|then\\_>") t)
		      ((looking-at "\\(?:<<\\([a-z0-9_]+\\)>>[ \t\r\n\f]*\\)?\\_<\\(if\\|case\\)\\_>")
		       (throw 'found t))
		      (t
		       (throw 'done
			 (cons
			  (list 'syntax-error "bad syntax start for then keyword"
				(point) (point))
			  anchor)))))))

	      (let ((start-label (or (sqlind-match-string 1) ""))
		    (start-kind (intern (sqlind-match-string 2))))
		(throw 'done
		  (cons
		   (cond ((not (or (null end-kind) (eq end-kind start-kind)))
			  (list 'syntax-error "bad closing for if/case block"
				(point) end-pos))
			 ((not (sqlind-labels-match end-label start-label))
			  (list 'syntax-error "mismatched labels for if/case block"
				(point) end-pos))
			 (t
			  (list 'block-end start-kind start-label)))
		   anchor))))

	     ((memq block-kind '(else elsif elseif))
	      ;; search the enclosing then context and refine form there.  The
	      ;; `cdr' in sqlind-syntax-of-line is used to remove the
	      ;; block-start context for the else clause
	      (goto-char anchor)
	      (throw 'done
		(sqlind-refine-end-syntax
		 end-kind end-label end-pos (cdr (sqlind-syntax-of-line)))))

	     ((memq block-kind '(if case))
	      (throw 'done
		(cons
		 (cond ((not (eq end-kind block-kind))
			(list 'syntax-error "bad closing for if/case block"
			      anchor end-pos))
		       ((not (sqlind-labels-match end-label block-label))
			(list 'syntax-error
			      "bad closing for if/case block (label mismatch)"
			      anchor end-pos))
		       (t (list 'block-end block-kind block-label)))
		 anchor)))
	     )))

	((memq syntax-symbol '(block-start comment-start))
	 ;; there is a more generic context following one of these
	 (throw 'done
	   (sqlind-refine-end-syntax
	    end-kind end-label end-pos (cdr context))))

	((eq syntax-symbol 'defun-start)
	 (throw 'done
	   (cons
	    (if (and (null end-kind)
		     (sqlind-labels-match end-label (nth 1 syntax)))
		(list 'block-end 'defun end-label)
		(list 'syntax-error "mismatched end label for defun"
		      anchor end-pos))
	    anchor)))

	((eq syntax-symbol 'block-end)
	 (goto-char anchor)
	 (forward-line -1)
	 (throw 'done
	   (sqlind-refine-end-syntax
	    end-kind end-label end-pos (sqlind-syntax-of-line)))))

      ;; if the above cond fell through, we have a syntax error
      (cons (list 'syntax-error "end statement closes nothing"
		  end-pos end-pos)
	    anchor))))