Function: vhdl-get-syntactic-context

vhdl-get-syntactic-context is a byte-compiled function defined in vhdl-mode.el.gz.

Signature

(vhdl-get-syntactic-context)

Documentation

Guess the syntactic description of the current line of VHDL code.

Source Code

;; Defined in /usr/src/emacs/lisp/progmodes/vhdl-mode.el.gz
(defun vhdl-get-syntactic-context ()
  "Guess the syntactic description of the current line of VHDL code."
  (save-excursion
    (save-restriction
      (beginning-of-line)
      (let* ((indent-point (point))
	     (case-fold-search t)
	     vec literal containing-sexp preceding-sexp
	     containing-begin containing-mid containing-leader
	     char-before-ip char-after-ip begin-after-ip end-after-ip
	     placeholder lim library-unit
	    )

	;; Reset the syntactic context
	(setq vhdl-syntactic-context nil)

	(save-excursion
	  ;; Move to the start of the previous library unit, and
	  ;; record the position of the "begin" keyword.
	  (setq placeholder (vhdl-beginning-of-libunit))
	  ;; The position of the "libunit" keyword gives us a gross
	  ;; limit point.
	  (setq lim (point))
	  )

	;; If there is a previous library unit, and we are enclosed by
	;; it, then set the syntax accordingly.
	(and placeholder
	     (setq library-unit (vhdl-get-library-unit lim placeholder))
	     (vhdl-add-syntax library-unit lim))

	;; Find the surrounding state.
	(if (setq vec (vhdl-get-block-state lim))
	    (progn
	      (setq containing-sexp (aref vec 0))
	      (setq preceding-sexp (aref vec 1))
	      (setq containing-begin (aref vec 2))
	      (setq containing-mid (aref vec 3))
	      ))

	;; set the limit on the farthest back we need to search
	(setq lim (if containing-sexp
		      (save-excursion
			(goto-char containing-sexp)
			;; set containing-leader if required
			(if (looking-at vhdl-leader-re)
			    (setq containing-leader (vhdl-end-of-leader)))
			(vhdl-point 'bol))
		    (point-min)))

	;; cache char before and after indent point, and move point to
	;; the most likely position to perform the majority of tests
	(goto-char indent-point)
	(skip-chars-forward " \t")
	(setq literal (vhdl-in-literal))
	(setq char-after-ip (following-char))
	(setq begin-after-ip (and
			      (not literal)
			      (looking-at vhdl-begin-fwd-re)
			      (or (not (looking-at "\\<use\\>"))
				  (save-excursion
				    (back-to-indentation)
				    (looking-at "\\(\\w+\\s-*:\\s-*\\)?\\<\\(case\\|elsif\\|if\\)\\>")))
			      (vhdl-begin-p)))
	(setq end-after-ip (and
			    (not literal)
			    (looking-at vhdl-end-fwd-re)
			    (vhdl-end-p)))
	(vhdl-backward-syntactic-ws lim)
	(setq char-before-ip (preceding-char))
	(goto-char indent-point)
	(skip-chars-forward " \t")

	;; now figure out syntactic qualities of the current line
	(cond
	 ;; CASE 1: in a string or comment.
	 ((memq literal '(string comment))
	  (vhdl-add-syntax literal (vhdl-point 'bopl)))
	 ;; CASE 2: Line is at top level.
	 ((null containing-sexp)
	  ;; Find the point to which indentation will be relative
	  (save-excursion
	    (if (null preceding-sexp)
		;; CASE 2X.1
		;; no preceding-sexp -> use the preceding statement
		(vhdl-beginning-of-statement-1 lim)
	      ;; CASE 2X.2
	      ;; if there is a preceding-sexp then indent relative to it
	      (goto-char preceding-sexp)
	      ;; if not at boi, then the block-opening keyword is
	      ;; probably following a label, so we need a different
	      ;; relpos
	      (if (/= (point) (vhdl-point 'boi))
		  ;; CASE 2X.3
		  (vhdl-beginning-of-statement-1 lim)))
	    ;; v-b-o-s could have left us at point-min
	    (and (bobp)
		 ;; CASE 2X.4
		 (vhdl-forward-syntactic-ws indent-point))
	    (setq placeholder (point)))
	  (cond
	   ;; CASE 2A : we are looking at a block-open
	   (begin-after-ip
	    (vhdl-add-syntax 'block-open placeholder))
	   ;; CASE 2B: we are looking at a block-close
	   (end-after-ip
	    (vhdl-add-syntax 'block-close placeholder))
	   ;; CASE 2C: we are looking at a top-level statement
	   ((progn
	      (vhdl-backward-syntactic-ws lim)
	      (or (bobp)
		  (and (= (preceding-char) ?\;)
		       (not (vhdl-in-quote-p)))))
	    (vhdl-add-syntax 'statement placeholder))
	   ;; CASE 2D: we are looking at a top-level statement-cont
	   (t
	    (vhdl-beginning-of-statement-1 lim)
	    ;; v-b-o-s could have left us at point-min
	    (and (bobp)
		 ;; CASE 2D.1
		 (vhdl-forward-syntactic-ws indent-point))
	    (vhdl-add-syntax 'statement-cont (point)))
	   )) ; end CASE 2
	 ;; CASE 3: line is inside parentheses.  Most likely we are
	 ;; either in a subprogram argument (interface) list, or a
	 ;; continued expression containing parentheses.
	 ((null containing-begin)
	  (vhdl-backward-syntactic-ws containing-sexp)
	  (cond
	   ;; CASE 3A: we are looking at the arglist closing paren
	   ((eq char-after-ip ?\))
	    (goto-char containing-sexp)
	    (vhdl-add-syntax 'arglist-close (vhdl-point 'boi)))
	   ;; CASE 3B: we are looking at the first argument in an empty
	   ;; argument list.
	   ((eq char-before-ip ?\()
	    (goto-char containing-sexp)
	    (vhdl-add-syntax 'arglist-intro (vhdl-point 'boi)))
	   ;; CASE 3C: we are looking at an arglist continuation line,
	   ;; but the preceding argument is on the same line as the
	   ;; opening paren.  This case includes multi-line
	   ;; expression paren groupings.
	   ((and (save-excursion
		   (goto-char (1+ containing-sexp))
		   (skip-chars-forward " \t")
		   (not (eolp))
		   (not (looking-at "--\\|`")))
		 (save-excursion
		   (vhdl-beginning-of-statement-1 containing-sexp)
		   (skip-chars-backward " \t(")
		   (while (and (= (preceding-char) ?\;)
			       (not (vhdl-in-quote-p)))
		     (vhdl-beginning-of-statement-1 containing-sexp)
		     (skip-chars-backward " \t("))
		   (<= (point) containing-sexp)))
	    (goto-char containing-sexp)
	    (vhdl-add-syntax 'arglist-cont-nonempty (vhdl-point 'boi)))
	   ;; CASE 3D: we are looking at just a normal arglist
	   ;; continuation line
	   (t (vhdl-beginning-of-statement-1 containing-sexp)
	      (vhdl-forward-syntactic-ws indent-point)
	      (vhdl-add-syntax 'arglist-cont (vhdl-point 'boi)))
	   ))
	 ;; CASE 4: A block mid open
	 ((and begin-after-ip
	       (looking-at containing-mid))
	  (goto-char containing-sexp)
	  ;; If the \"begin\" keyword is a trailer, then find v-b-o-s
	  (if (looking-at vhdl-trailer-re)
	      ;; CASE 4.1
	      (progn (forward-sexp) (vhdl-beginning-of-statement-1 nil)))
	  (vhdl-backward-skip-label (vhdl-point 'boi))
	  (vhdl-add-syntax 'block-open (point)))
	 ;; CASE 5: block close brace
	 (end-after-ip
	  (goto-char containing-sexp)
	  ;; If the \"begin\" keyword is a trailer, then find v-b-o-s
	  (if (looking-at vhdl-trailer-re)
	      ;; CASE 5.1
	      (progn (forward-sexp) (vhdl-beginning-of-statement-1 nil)))
	  (vhdl-backward-skip-label (vhdl-point 'boi))
	  (vhdl-add-syntax 'block-close (point)))
	 ;; CASE 6: A continued statement
	 ((and (/= char-before-ip ?\;)
	       ;; check it's not a trailer begin keyword, or a begin
	       ;; keyword immediately following a label.
	       (not (and begin-after-ip
			 (or (looking-at vhdl-trailer-re)
			     (save-excursion
			       (vhdl-backward-skip-label containing-sexp)))))
	       ;; check it's not a statement keyword
	       (not (and (looking-at vhdl-statement-fwd-re)
			 (vhdl-statement-p)))
	       ;; see if the b-o-s is before the indent point
	       (> indent-point
		  (save-excursion
		    (vhdl-beginning-of-statement-1 containing-sexp)
		    ;; If we ended up after a leader, then this will
		    ;; move us forward to the start of the first
		    ;; statement.  Note that a containing sexp here is
		    ;; always a keyword, not a paren, so this will
		    ;; have no effect if we hit the containing-sexp.
		    (vhdl-forward-syntactic-ws indent-point)
		    (setq placeholder (point))))
	       ;; check it's not a block-intro
	       (/= placeholder containing-sexp)
	       ;; check it's not a case block-intro
	       (save-excursion
		 (goto-char placeholder)
		 (or (not (looking-at vhdl-case-alternative-re))
		     (> (match-end 0) indent-point))))
	  ;; Make placeholder skip a label, but only if it puts us
	  ;; before the indent point at the start of a line.
	  (let ((new placeholder))
	    (if (and (> indent-point
			(save-excursion
			  (goto-char placeholder)
			  (vhdl-forward-skip-label indent-point)
			  (setq new (point))))
		     (save-excursion
		       (goto-char new)
		       (eq new (progn (back-to-indentation) (point)))))
		(setq placeholder new)))
	  (vhdl-add-syntax 'statement-cont placeholder)
	  (if begin-after-ip
	      (vhdl-add-syntax 'block-open)))
	 ;; Statement. But what kind?
	 ;; CASE 7: A case alternative key
	 ((and (looking-at vhdl-case-alternative-re)
	       (vhdl-case-alternative-p containing-sexp))
	  ;; for a case alternative key, we set relpos to the first
	  ;; non-whitespace char on the line containing the "case"
	  ;; keyword.
	  (goto-char containing-sexp)
	  ;; If the \"begin\" keyword is a trailer, then find v-b-o-s
	  (if (looking-at vhdl-trailer-re)
	      (progn (forward-sexp) (vhdl-beginning-of-statement-1 nil)))
	  (vhdl-add-syntax 'case-alternative (vhdl-point 'boi)))
	 ;; CASE 8: statement catchall
	 (t
	  ;; we know its a statement, but we need to find out if it is
	  ;; the first statement in a block
	  (if containing-leader
	      (goto-char containing-leader)
	    (goto-char containing-sexp)
	    ;; Note that a containing sexp here is always a keyword,
	    ;; not a paren, so skip over the keyword.
	    (forward-sexp))
	  ;; move to the start of the first statement
	  (vhdl-forward-syntactic-ws indent-point)
	  (setq placeholder (point))
	  ;; we want to ignore case alternatives keys when skipping forward
	  (let (incase-p)
	    (while (looking-at vhdl-case-alternative-re)
	      (setq incase-p (point))
	      ;; we also want to skip over the body of the
	      ;; case/when statement if that doesn't put us at
	      ;; after the indent-point
	      (while (vhdl-skip-case-alternative indent-point))
	      ;; set up the match end
	      (looking-at vhdl-case-alternative-re)
	      (goto-char (match-end 0))
	      ;; move to the start of the first case alternative statement
	      (vhdl-forward-syntactic-ws indent-point)
	      (setq placeholder (point)))
	    (cond
	     ;; CASE 8A: we saw a case/when statement so we must be
	     ;; in a switch statement.  find out if we are at the
	     ;; statement just after a case alternative key
	     ((and incase-p
		   (= (point) indent-point))
	      ;; relpos is the "when" keyword
	      (vhdl-add-syntax 'statement-case-intro incase-p))
	     ;; CASE 8B: any old statement
	     ((< (point) indent-point)
	      ;; relpos is the first statement of the block
	      (vhdl-add-syntax 'statement placeholder)
	      (if begin-after-ip
		  (vhdl-add-syntax 'block-open)))
	     ;; CASE 8C: first statement in a block
	     (t
	      (goto-char containing-sexp)
	      ;; If the \"begin\" keyword is a trailer, then find v-b-o-s
	      (if (looking-at vhdl-trailer-re)
		  (progn (forward-sexp) (vhdl-beginning-of-statement-1 nil)))
	      (vhdl-backward-skip-label (vhdl-point 'boi))
	      (vhdl-add-syntax 'statement-block-intro (point))
	      (if begin-after-ip
		  (vhdl-add-syntax 'block-open)))
	     )))
	 )

	;; now we need to look at any modifiers
	(goto-char indent-point)
	(skip-chars-forward " \t")
	(if (or (looking-at "--") (looking-at "/\\*"))
	    (vhdl-add-syntax 'comment))
	(if (looking-at "`")
	    (vhdl-add-syntax 'directive))
	(if (eq literal 'pound)
	    (vhdl-add-syntax 'cpp-macro))
	;; return the syntax
	vhdl-syntactic-context))))