;;; cc-engine.el --- core syntax guessing engine for CC mode -*- coding: utf-8 -*-
-;; Copyright (C) 1985, 1987, 1992-2015 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1987, 1992-2016 Free Software Foundation, Inc.
;; Authors: 2001- Alan Mackenzie
;; 1998- Martin Stjernholm
(defmacro c-bos-report-error ()
'(unless noerror
(setq c-parsing-error
- (format "No matching `%s' found for `%s' on line %d"
- (elt saved-pos 1)
- (elt saved-pos 2)
- (1+ (count-lines (point-min)
- (c-point 'bol (elt saved-pos 0))))))))
+ (format-message
+ "No matching `%s' found for `%s' on line %d"
+ (elt saved-pos 1)
+ (elt saved-pos 2)
+ (1+ (count-lines (point-min)
+ (c-point 'bol (elt saved-pos 0))))))))
(defun c-beginning-of-statement-1 (&optional lim ignore-labels
noerror comma-delim)
If point is already at the earliest statement within braces or parens,
this function doesn't move back into any whitespace preceding it; it
-returns 'same in this case.
+returns `same' in this case.
Stop at statement continuation tokens like \"else\", \"catch\",
\"finally\" and the \"while\" in \"do ... while\" if the start point
macros before leaving them.
Return:
-'label if stopped at a label or \"case...:\" or \"default:\";
-'same if stopped at the beginning of the current statement;
-'up if stepped to a containing statement;
-'previous if stepped to a preceding statement;
-'beginning if stepped from a statement continuation clause to
+`label' if stopped at a label or \"case...:\" or \"default:\";
+`same' if stopped at the beginning of the current statement;
+`up' if stepped to a containing statement;
+`previous' if stepped to a preceding statement;
+`beginning' if stepped from a statement continuation clause to
its start clause; or
-'macro if stepped to a macro start.
-Note that 'same and not 'label is returned if stopped at the same
+`macro' if stepped to a macro start.
+Note that `same' and not `label' is returned if stopped at the same
label without crossing the colon character.
LIM may be given to limit the search. If the search hits the limit,
point will be left at the closest following token, or at the start
-position if that is less ('same is returned in this case).
+position if that is less (`same' is returned in this case).
NOERROR turns off error logging to `c-parsing-error'.
(save-excursion
(c-forward-sexp) (point)))
;; Just gone back over some paren block?
- ((looking-at "\\s\(")
+ ((looking-at "\\s(")
(save-excursion
(goto-char (1+ (c-down-list-backward
before-sws-pos)))
might start a label (i.e. not part of `::' and not preceded by `?'). If a
single `?' is found, then `c-maybe-labelp' is cleared.
-For AWK, a statement which is terminated by an EOL (not a \; or a }) is
+For AWK, a statement which is terminated by an EOL (not a ; or a }) is
regarded as having a \"virtual semicolon\" immediately after the last token on
the line. If this virtual semicolon is _at_ from, the function recognizes it.
;; same line.
(re-search-forward "\\=\\s *[\n\r]" start t)
- (if (if (let (open-paren-in-column-0-is-defun-start) (forward-comment -1))
+ (if (if (forward-comment -1)
(if (eolp)
;; If forward-comment above succeeded and we're at eol
;; then the newline we moved over above didn't end a
;; line comment, so we give it another go.
- (let (open-paren-in-column-0-is-defun-start)
- (forward-comment -1))
+ (forward-comment -1)
t))
;; Emacs <= 20 and XEmacs move back over the closer of a
;; return t when moving backwards at bob.
(not (bobp))
- (if (let (open-paren-in-column-0-is-defun-start moved-comment)
+ (if (let (moved-comment)
(while
(and (not (setq moved-comment (forward-comment -1)))
;; Cope specifically with ^M^J here -
;; two newlines with horizontal whitespace between them.
;;
;; The reason to include the first following char is to cope with
-;; "rung positions" that doesn't have any ordinary whitespace. If
+;; "rung positions" that don't have any ordinary whitespace. If
;; `c-is-sws' is put on a token character it does not have
;; `c-in-sws' set simultaneously. That's the only case when that
;; can occur, and the reason for not extending the `c-in-sws'
;; if it's anything that can't start syntactic ws, so we can bail out
;; early in the majority of cases when there just are a few ws chars.
(skip-chars-forward " \t\n\r\f\v")
- (when (looking-at c-syntactic-ws-start)
+ (when (or (looking-at c-syntactic-ws-start)
+ (and c-opt-cpp-prefix
+ (looking-at c-noise-macro-name-re)))
(setq rung-end-pos (min (1+ (point)) (point-max)))
(if (setq rung-is-marked (text-property-any rung-pos rung-end-pos
(with-silent-modifications
(while
(progn
+ ;; In the following while form, we move over a "ladder" and
+ ;; following simple WS each time round the loop, appending the WS
+ ;; onto the ladder, joining adjacent ladders, and terminating when
+ ;; there is no more WS or we reach EOB.
(while
(when (and rung-is-marked
(get-text-property (point) 'c-in-sws))
(setq rung-pos (point)
last-put-in-sws-pos rung-pos)))
+ ;; Now move over any comments (x)or a CPP construct.
(setq simple-ws-end (point))
(c-forward-comments)
(forward-line 1)
(setq safe-start t)
;; Don't cache at eob in case the buffer is narrowed.
+ (not (eobp)))
+
+ ((and c-opt-cpp-prefix
+ (looking-at c-noise-macro-name-re))
+ ;; Skip over a noise macro.
+ (goto-char (match-end 1))
+ (setq safe-start t)
(not (eobp)))))
;; We've searched over a piece of non-white syntactic ws. See if this
(when (and (not (bobp))
(save-excursion
(backward-char)
- (looking-at c-syntactic-ws-end)))
-
+ (or (looking-at c-syntactic-ws-end)
+ (and c-opt-cpp-prefix
+ (looking-at c-symbol-char-key)
+ (progn (c-beginning-of-current-token)
+ (looking-at c-noise-macro-name-re))))))
;; Try to find a rung position in the simple ws preceding point, so that
;; we can get a cache hit even if the last bit of the simple ws has
;; changed recently.
(with-silent-modifications
(while
(progn
+ ;; Each time round the next while form, we move back over a ladder
+ ;; and append any simple WS preceding it, if possible joining with
+ ;; the previous ladder.
(while
(when (and rung-is-marked
(not (bobp))
;; narrowed out, and we can't risk marking the simple ws
;; at the end of it.
(goto-char next-rung-pos)
+ t)
+
+ ((and c-opt-cpp-prefix
+ (save-excursion
+ (and (< (skip-syntax-backward "w_") 0)
+ (progn (setq next-rung-pos (point))
+ (looking-at c-noise-macro-name-re)))))
+ ;; Skipped over a noise macro
+ (goto-char next-rung-pos)
t)))
;; We've searched over a piece of non-white syntactic ws. See if this
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Defuns which analyze the buffer, yet don't change `c-state-cache'.
+(defun c-get-fallback-scan-pos (here)
+ ;; Return a start position for building `c-state-cache' from
+ ;; scratch. This will be at the top level, 2 defuns back.
+ (save-excursion
+ ;; Go back 2 bods, but ignore any bogus positions returned by
+ ;; beginning-of-defun (i.e. open paren in column zero).
+ (goto-char here)
+ (let ((cnt 2))
+ (while (not (or (bobp) (zerop cnt)))
+ (c-beginning-of-defun-1) ; Pure elisp BOD.
+ (if (eq (char-after) ?\{)
+ (setq cnt (1- cnt)))))
+ (point)))
+
(defun c-state-balance-parens-backwards (here- here+ top)
;; Return the position of the opening paren/brace/bracket before HERE- which
;; matches the outermost close p/b/b between HERE+ and TOP. Except when
;; o - ('backward nil) - scan backwards (from HERE).
;; o - ('back-and-forward START-POINT) - like 'forward, but when HERE is earlier
;; than GOOD-POS.
+ ;; o - ('BOD START-POINT) - scan forwards from START-POINT, which is at the
+ ;; top level.
;; o - ('IN-LIT nil) - point is inside the literal containing point-min.
(let ((cache-pos (c-get-cache-scan-pos here)) ; highest position below HERE in cache (or 1)
- strategy ; 'forward, 'backward, or 'IN-LIT.
- start-point)
+ BOD-pos ; position of 2nd BOD before HERE.
+ strategy ; 'forward, 'backward, 'BOD, or 'IN-LIT.
+ start-point
+ how-far) ; putative scanning distance.
(setq good-pos (or good-pos (c-state-get-min-scan-pos)))
(cond
((< here (c-state-get-min-scan-pos))
- (setq strategy 'IN-LIT))
+ (setq strategy 'IN-LIT
+ start-point nil
+ cache-pos nil
+ how-far 0))
((<= good-pos here)
(setq strategy 'forward
- start-point (max good-pos cache-pos)))
+ start-point (max good-pos cache-pos)
+ how-far (- here start-point)))
((< (- good-pos here) (- here cache-pos)) ; FIXME!!! ; apply some sort of weighting.
- (setq strategy 'backward))
+ (setq strategy 'backward
+ how-far (- good-pos here)))
(t
(setq strategy 'back-and-forward
- start-point cache-pos)))
+ start-point cache-pos
+ how-far (- here start-point))))
+
+ ;; Might we be better off starting from the top level, two defuns back,
+ ;; instead? This heuristic no longer works well in C++, where
+ ;; declarations inside namespace brace blocks are frequently placed at
+ ;; column zero. (2015-11-10): Remove the condition on C++ Mode.
+ (when (and (or (not (memq 'col-0-paren c-emacs-features))
+ open-paren-in-column-0-is-defun-start)
+ ;; (not (c-major-mode-is 'c++-mode))
+ (> how-far c-state-cache-too-far))
+ (setq BOD-pos (c-get-fallback-scan-pos here)) ; somewhat EXPENSIVE!!!
+ (if (< (- here BOD-pos) how-far)
+ (setq strategy 'BOD
+ start-point BOD-pos)))
+
(list strategy start-point)))
;; pair element into an open paren element. Doing that would mean that the
;; new open paren wouldn't have the required preceding paren pair element.
;;
- ;; This function is called from c-after-change.
+ ;; This function is called from c-before-change.
;; The caches of non-literals:
;; Note that we use "<=" for the possibility of the second char of a two-char
;; Truncate `c-state-cache' and set `c-state-cache-good-pos' to a value
;; below `here'. To maintain its consistency, we may need to insert a new
;; brace pair.
- (let (open-paren-in-column-0-is-defun-start
- (here-bol (c-point 'bol here))
- too-high-pa ; recorded {/(/[ next above here, or nil.
+ (let ((here-bol (c-point 'bol here))
+ too-high-pa ; recorded {/(/[ next above or just below here, or nil.
dropped-cons ; was the last removed element a brace pair?
pa)
;; The easy bit - knock over-the-top bits off `c-state-cache'.
;; Do we need to add in an earlier brace pair, having lopped one off?
(if (and dropped-cons
- (< too-high-pa (+ here c-state-cache-too-far)))
+ (<= too-high-pa here))
(c-append-lower-brace-pair-to-state-cache too-high-pa here here-bol))
(setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
(c-state-get-min-scan-pos)))))
;; This function might do hidden buffer changes.
(let* ((here (point))
(here-bopl (c-point 'bopl))
- open-paren-in-column-0-is-defun-start
strategy ; 'forward, 'backward etc..
;; Candidate positions to start scanning from:
cache-pos ; highest position below HERE already existing in
strategy (car res)
start-point (cadr res))
+ (when (eq strategy 'BOD)
+ (setq c-state-cache nil
+ c-state-cache-good-pos start-point))
+
;; SCAN!
(cond
- ((memq strategy '(forward back-and-forward))
+ ((memq strategy '(forward back-and-forward BOD))
(setq res (c-remove-stale-state-cache start-point here here-bopl))
(setq cache-pos (car res)
scan-backward-pos (cadr res)
(defconst c-jump-syntax-balanced
(if (memq 'gen-string-delim c-emacs-features)
- "\\w\\|\\s_\\|\\s\(\\|\\s\)\\|\\s\"\\|\\s|"
- "\\w\\|\\s_\\|\\s\(\\|\\s\)\\|\\s\""))
+ "\\w\\|\\s_\\|\\s(\\|\\s)\\|\\s\"\\|\\s|"
+ "\\w\\|\\s_\\|\\s(\\|\\s)\\|\\s\""))
(defconst c-jump-syntax-unbalanced
(if (memq 'gen-string-delim c-emacs-features)
tokens like \"==\" as single tokens, i.e. all sequences of symbol
characters are jumped over character by character. This function is
for compatibility only; it's only a wrapper over `c-forward-token-2'."
- (let ((c-nonsymbol-token-regexp "\\s.\\|\\s\(\\|\\s\)"))
+ (let ((c-nonsymbol-token-regexp "\\s."))
(c-forward-token-2 count balanced limit)))
(defun c-backward-token-1 (&optional count balanced limit)
tokens like \"==\" as single tokens, i.e. all sequences of symbol
characters are jumped over character by character. This function is
for compatibility only; it's only a wrapper over `c-backward-token-2'."
- (let ((c-nonsymbol-token-regexp "\\s.\\|\\s\(\\|\\s\)"))
+ (let ((c-nonsymbol-token-regexp "\\s."))
(c-backward-token-2 count balanced limit)))
\f
(defun c-before-change-check-<>-operators (beg end)
;; Unmark certain pairs of "< .... >" which are currently marked as
- ;; template/generic delimiters. (This marking is via syntax-table
- ;; text properties).
+ ;; template/generic delimiters. (This marking is via syntax-table text
+ ;; properties), and expand the (c-new-BEG c-new-END) region to include all
+ ;; unmarked < and > operators within the certain bounds (see below).
;;
;; These pairs are those which are in the current "statement" (i.e.,
;; the region between the {, }, or ; before BEG and the one after
;; FIXME!!! This routine ignores the possibility of macros entirely.
;; 2010-01-29.
(save-excursion
- (let ((beg-lit-limits (progn (goto-char beg) (c-literal-limits)))
- (end-lit-limits (progn (goto-char end) (c-literal-limits)))
- new-beg new-end need-new-beg need-new-end)
- ;; Locate the barrier before the changed region
+ (c-save-buffer-state
+ ((beg-lit-limits (progn (goto-char beg) (c-literal-limits)))
+ (end-lit-limits (progn (goto-char end) (c-literal-limits)))
+ new-beg new-end beg-limit end-limit)
+ ;; Locate the earliest < after the barrier before the changed region,
+ ;; which isn't already marked as a paren.
(goto-char (if beg-lit-limits (car beg-lit-limits) beg))
- (c-syntactic-skip-backward "^;{}" (c-determine-limit 512))
- (setq new-beg (point))
+ (setq beg-limit (c-determine-limit 512))
;; Remove the syntax-table/category properties from each pertinent <...>
- ;; pair. Firsly, the ones with the < before beg and > after beg.
- (while
- (c-search-forward-char-property 'syntax-table c-<-as-paren-syntax beg)
- (if (c-clear-<-pair-props-if-match-after beg (1- (point)))
- (setq need-new-beg t)))
+ ;; pair. Firstly, the ones with the < before beg and > after beg....
+ (while (progn (c-syntactic-skip-backward "^;{}<" beg-limit)
+ (eq (char-before) ?<))
+ (c-backward-token-2)
+ (when (eq (char-after) ?<)
+ (c-clear-<-pair-props-if-match-after beg)))
+ (c-forward-syntactic-ws)
+ (setq new-beg (point))
- ;; Locate the barrier after END.
+ ;; ...Then the ones with < before end and > after end.
(goto-char (if end-lit-limits (cdr end-lit-limits) end))
- (c-syntactic-re-search-forward "[;{}]" (c-determine-+ve-limit 512) 'end)
+ (setq end-limit (c-determine-+ve-limit 512))
+ (while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end)
+ (eq (char-before) ?>))
+ (c-end-of-current-token)
+ (when (eq (char-before) ?>)
+ (c-clear->-pair-props-if-match-before end (1- (point)))))
+ (c-backward-syntactic-ws)
(setq new-end (point))
- ;; Remove syntax-table properties from the remaining pertinent <...>
- ;; pairs, those with a > after end and < before end.
- (while (c-search-backward-char-property 'syntax-table c->-as-paren-syntax end)
- (if (c-clear->-pair-props-if-match-before end)
- (setq need-new-end t)))
-
;; Extend the fontification region, if needed.
- (when need-new-beg
- (goto-char new-beg)
- (c-forward-syntactic-ws)
- (and (< (point) c-new-BEG) (setq c-new-BEG (point))))
-
- (when need-new-end
- (and (> new-end c-new-END) (setq c-new-END new-end))))))
+ (and new-beg
+ (< new-beg c-new-BEG)
+ (setq c-new-BEG new-beg))
+ (and new-end
+ (> new-end c-new-END)
+ (setq c-new-END new-end)))))
(defun c-after-change-check-<>-operators (beg end)
;; This is called from `after-change-functions' when
(c-clear-<>-pair-props)
(forward-char)))))))
-
+(defun c-restore-<>-properties (_beg _end _old-len)
+ ;; This function is called as an after-change function. It restores the
+ ;; category/syntax-table properties on template/generic <..> pairs between
+ ;; c-new-BEG and c-new-END. It may do hidden buffer changes.
+ (c-save-buffer-state ((c-parse-and-markup-<>-arglists t)
+ c-restricted-<>-arglists lit-limits)
+ (goto-char c-new-BEG)
+ (if (setq lit-limits (c-literal-limits))
+ (goto-char (cdr lit-limits)))
+ (while (and (< (point) c-new-END)
+ (c-syntactic-re-search-forward "<" c-new-END 'bound))
+ (backward-char)
+ (save-excursion
+ (c-backward-token-2)
+ (setq c-restricted-<>-arglists
+ (and (not (looking-at c-opt-<>-sexp-key))
+ (progn (c-backward-syntactic-ws) ; to ( or ,
+ (and (memq (char-before) '(?\( ?,)) ; what about <?
+ (not (eq (c-get-char-property (point) 'c-type)
+ 'c-decl-arg-start)))))))
+ (or (c-forward-<>-arglist nil)
+ (forward-char)))))
\f
;; Handling of small scale constructs like types and names.
`(c-forward-type)
`(c-forward-name)))
nil
- (and (looking-at c-keywords-regexp)
- (c-forward-keyword-clause 1))))
+ (cond ((looking-at c-keywords-regexp)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause)))))
(when (memq res '(t known found prefix))
,(when (eq type 'ref)
`(when c-record-type-identifiers
(c-forward-syntactic-ws)
(c-forward-keyword-prefixed-id ,type)))))
+(defun c-forward-noise-clause ()
+ ;; Point is at a c-noise-macro-with-parens-names macro identifier. Go
+ ;; forward over this name, any parenthesis expression which follows it, and
+ ;; any syntactic WS, ending up at the next token. If there is an unbalanced
+ ;; paren expression, leave point at it. Always Return t.
+ (c-forward-token-2)
+ (if (and (eq (char-after) ?\()
+ (c-go-list-forward))
+ (c-forward-syntactic-ws))
+ t)
+
(defun c-forward-keyword-clause (match)
;; Submatch MATCH in the current match data is assumed to surround a
;; token. If it's a keyword, move over it and any immediately
;; Recursive part of `c-forward-<>-arglist'.
;;
;; This function might do hidden buffer changes.
- (let ((start (point)) res pos tmp
+ (let ((start (point)) res pos
;; Cover this so that any recorded found type ranges are
;; automatically lost if it turns out to not be an angle
;; bracket arglist. It's propagated through the return value
;; Stop on ',', '|', '&', '+' and '-' to catch
;; common binary operators that could be between
;; two comparison expressions "a<b" and "c>d".
- "[<;{},|+&-]\\|[>)]"
+ ;; 2016-02-11: C++11 templates can now contain arithmetic
+ ;; expressions, so template detection in C++ is now less
+ ;; robust than it was.
+ c-<>-notable-chars-re
nil t t))
(cond
;; Either an operator starting with '>' or the end of
;; the angle bracket arglist.
- (if (looking-at c->-op-without->-cont-regexp)
+ (if (save-excursion
+ (c-backward-token-2)
+ (looking-at c-multichar->-op-not->>-regexp))
(progn
(goto-char (match-end 0))
t) ; Continue the loop.
;; Either an operator starting with '<' or a nested arglist.
(setq pos (point))
(let (id-start id-end subres keyword-match)
- (cond
+ (cond
;; The '<' begins a multi-char operator.
((looking-at c-<-op-cont-regexp)
- (setq tmp (match-end 0))
(goto-char (match-end 0)))
;; We're at a nested <.....>
((progn
- (setq tmp pos)
- (backward-char) ; to the '<'
+ (backward-char) ; to the '<'
(and
(save-excursion
;; There's always an identifier before an angle
(and keyword-match
(c-keyword-member
(c-keyword-sym (match-string 1))
- 'c-<>-type-kwds)))))))
+ 'c-<>-type-kwds))))))
+ (or subres (goto-char pos))
+ subres)
;; It was an angle bracket arglist.
(setq c-record-found-types subres)
(c-record-ref-id (cons id-start id-end))
(c-record-type-id (cons id-start id-end)))))
- ;; At a "less than" operator.
- (t
- (forward-char)
- )))
- t) ; carry on looping.
+ ;; At a "less than" operator.
+ (t
+ ;; (forward-char) ; NO! We've already gone over the <.
+ )))
+ t) ; carry on looping.
+
+ ((and
+ (eq (char-before) ?\()
+ (c-go-up-list-forward)
+ (eq (char-before) ?\))))
((and (not c-restricted-<>-arglists)
(or (and (eq (char-before) ?&)
; "typedef".
(goto-char (match-end 1))
(c-forward-syntactic-ws)
+
+ (while (cond
+ ((looking-at c-decl-hangon-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
+
(setq pos (point))
(setq name-res (c-forward-name))
res))
(defun c-forward-annotation ()
- ;; Used for Java code only at the moment. Assumes point is on the
- ;; @, moves forward an annotation. returns nil if there is no
- ;; annotation at point.
- (and (looking-at "@")
- (progn (forward-char) t)
- (c-forward-type)
- (progn (c-forward-syntactic-ws) t)
- (if (looking-at "(")
- (c-go-list-forward)
- t)))
+ ;; Used for Java code only at the moment. Assumes point is on the @, moves
+ ;; forward an annotation and returns t. Leaves point unmoved and returns
+ ;; nil if there is no annotation at point.
+ (let ((pos (point)))
+ (or
+ (and (looking-at "@")
+ (not (looking-at c-keywords-regexp))
+ (progn (forward-char) t)
+ (looking-at c-symbol-key)
+ (progn (goto-char (match-end 0))
+ (c-forward-syntactic-ws)
+ t)
+ (if (looking-at "(")
+ (c-go-list-forward)
+ t))
+ (progn (goto-char pos) nil))))
(defmacro c-pull-open-brace (ps)
;; Pull the next open brace from PS (which has the form of paren-state),
(or res (goto-char here))
res))
+(defmacro c-back-over-list-of-member-inits ()
+ ;; Go back over a list of elements, each looking like:
+ ;; <symbol> (<expression>) ,
+ ;; or <symbol> {<expression>} ,
+ ;; when we are putatively immediately after a comma. Stop when we don't see
+ ;; a comma. If either of <symbol> or bracketed <expression> is missing,
+ ;; throw nil to 'level. If the terminating } or ) is unmatched, throw nil
+ ;; to 'done. This is not a general purpose macro!
+ `(while (eq (char-before) ?,)
+ (backward-char)
+ (c-backward-syntactic-ws)
+ (when (not (memq (char-before) '(?\) ?})))
+ (throw 'level nil))
+ (when (not (c-go-list-backward))
+ (throw 'done nil))
+ (c-backward-syntactic-ws)
+ (when (not (c-simple-skip-symbol-backward))
+ (throw 'level nil))
+ (c-backward-syntactic-ws)))
+
(defun c-back-over-member-initializers ()
;; Test whether we are in a C++ member initializer list, and if so, go back
;; to the introducing ":", returning the position of the opening paren of
;; the function's arglist. Otherwise return nil, leaving point unchanged.
(let ((here (point))
(paren-state (c-parse-state))
- res)
-
+ pos level-plausible at-top-level res)
+ ;; Assume tentatively that we're at the top level. Try to go back to the
+ ;; colon we seek.
(setq res
(catch 'done
- (if (not (c-at-toplevel-p))
- (progn
- (while (not (c-at-toplevel-p))
- (goto-char (c-pull-open-brace paren-state)))
- (c-backward-syntactic-ws)
- (when (not (c-simple-skip-symbol-backward))
- (throw 'done nil))
- (c-backward-syntactic-ws))
- (c-backward-syntactic-ws)
- (when (memq (char-before) '(?\) ?}))
- (when (not (c-go-list-backward))
- (throw 'done nil))
- (c-backward-syntactic-ws))
- (when (c-simple-skip-symbol-backward)
- (c-backward-syntactic-ws)))
-
- (while (eq (char-before) ?,)
- (backward-char)
- (c-backward-syntactic-ws)
-
- (when (not (memq (char-before) '(?\) ?})))
- (throw 'done nil))
- (when (not (c-go-list-backward))
- (throw 'done nil))
- (c-backward-syntactic-ws)
- (when (not (c-simple-skip-symbol-backward))
- (throw 'done nil))
- (c-backward-syntactic-ws))
-
- (and
- (eq (char-before) ?:)
- (c-just-after-func-arglist-p))))
+ (setq level-plausible
+ (catch 'level
+ (c-backward-syntactic-ws)
+ (when (memq (char-before) '(?\) ?}))
+ (when (not (c-go-list-backward))
+ (throw 'done nil))
+ (c-backward-syntactic-ws))
+ (when (c-simple-skip-symbol-backward)
+ (c-backward-syntactic-ws))
+ (c-back-over-list-of-member-inits)
+ (and (eq (char-before) ?:)
+ (c-just-after-func-arglist-p))))
+
+ (while (and (not (and level-plausible
+ (setq at-top-level (c-at-toplevel-p))))
+ (setq pos (c-pull-open-brace paren-state))) ; might be a paren.
+ (setq level-plausible
+ (catch 'level
+ (goto-char pos)
+ (c-backward-syntactic-ws)
+ (when (not (c-simple-skip-symbol-backward))
+ (throw 'level nil))
+ (c-backward-syntactic-ws)
+ (c-back-over-list-of-member-inits)
+ (and (eq (char-before) ?:)
+ (c-just-after-func-arglist-p)))))
+ (and at-top-level level-plausible)))
(or res (goto-char here))
res))
;; This identifier is bound only in the inner let.
'(setq start id-start))))
+(defun c-forward-declarator (&optional limit accept-anon)
+ ;; Assuming point is at the start of a declarator, move forward over it,
+ ;; leaving point at the next token after it (e.g. a ) or a ; or a ,).
+ ;;
+ ;; Return a list (ID-START ID-END BRACKETS-AFTER-ID GOT-INIT), where ID-START and
+ ;; ID-END are the bounds of the declarator's identifier, and
+ ;; BRACKETS-AFTER-ID is non-nil if a [...] pair is present after the id.
+ ;; GOT-INIT is non-nil when the declarator is followed by "=" or "(".
+ ;;
+ ;; If ACCEPT-ANON is non-nil, move forward over any "anonymous declarator",
+ ;; i.e. something like the (*) in int (*), such as might be found in a
+ ;; declaration. In such a case ID-START and ID-END in the return value are
+ ;; both set to nil. A "null" "anonymous declarator" gives a non-nil result.
+ ;;
+ ;; If no declarator is found, leave point unmoved and return nil. LIMIT is
+ ;; an optional limit for forward searching.
+ ;;
+ ;; Note that the global variable `c-last-identifier-range' is written to, so
+ ;; the caller should bind it if necessary.
+
+ ;; Inside the following "condition form", we move forward over the
+ ;; declarator's identifier up as far as any opening bracket (for array
+ ;; size) or paren (for parameters of function-type) or brace (for
+ ;; array/struct initialization) or "=" or terminating delimiter
+ ;; (e.g. "," or ";" or "}").
+ (let ((here (point))
+ id-start id-end brackets-after-id paren-depth)
+ (or limit (setq limit (point-max)))
+ (if (and
+ (< (point) limit)
+
+ ;; The following form moves forward over the declarator's
+ ;; identifier (and what precedes it), returning t. If there
+ ;; wasn't one, it returns nil.
+ (let (got-identifier)
+ (setq paren-depth 0)
+ ;; Skip over type decl prefix operators, one for each iteration
+ ;; of the while. These are, e.g. "*" in "int *foo" or "(" and
+ ;; "*" in "int (*foo) (void)" (Note similar code in
+ ;; `c-forward-decl-or-cast-1'.)
+ (while
+ (cond
+ ((looking-at c-decl-hangon-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))
+ ((and (looking-at c-type-decl-prefix-key)
+ (if (and (c-major-mode-is 'c++-mode)
+ (match-beginning 3))
+ ;; If the third submatch matches in C++ then
+ ;; we're looking at an identifier that's a
+ ;; prefix only if it specifies a member pointer.
+ (progn
+ (setq id-start (point))
+ (c-forward-name)
+ (if (looking-at "\\(::\\)")
+ ;; We only check for a trailing "::" and
+ ;; let the "*" that should follow be
+ ;; matched in the next round.
+ t
+ ;; It turned out to be the real identifier,
+ ;; so flag that and stop.
+ (setq got-identifier t)
+ nil))
+ t))
+ (if (eq (char-after) ?\()
+ (progn
+ (setq paren-depth (1+ paren-depth))
+ (forward-char))
+ (goto-char (match-end 1)))
+ (c-forward-syntactic-ws)
+ t)))
+
+ ;; If we haven't passed the identifier already, do it now.
+ (unless got-identifier
+ (setq id-start (point)))
+ (cond
+ ((or got-identifier
+ (c-forward-name))
+ (save-excursion
+ (c-backward-syntactic-ws)
+ (setq id-end (point))))
+ (accept-anon
+ (setq id-start nil id-end nil)
+ t)
+ (t (/= (point) here))))
+
+ ;; Skip out of the parens surrounding the identifier. If closing
+ ;; parens are missing, this form returns nil.
+ (or (= paren-depth 0)
+ (c-safe (goto-char (scan-lists (point) 1 paren-depth))))
+
+ (<= (point) limit)
+
+ ;; Skip over any trailing bit, such as "__attribute__".
+ (progn
+ (while (cond
+ ((looking-at c-decl-hangon-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
+ (<= (point) limit))
+
+ ;; Search syntactically to the end of the declarator (";",
+ ;; ",", a closing paren, eob etc) or to the beginning of an
+ ;; initializer or function prototype ("=" or "\\s\(").
+ ;; Note that square brackets are now not also treated as
+ ;; initializers, since this broke when there were also
+ ;; initializing brace lists.
+ (let (found)
+ (while
+ (and (setq found (c-syntactic-re-search-forward
+ "[;,]\\|\\s)\\|\\'\\|\\(=\\|\\s(\\)" limit t t))
+ (eq (char-before) ?\[)
+ (c-go-up-list-forward))
+ (setq brackets-after-id t))
+ (backward-char)
+ found))
+ (list id-start id-end brackets-after-id (match-beginning 1))
+
+ (goto-char here)
+ nil)))
+
(defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end)
;; Move forward over a declaration or a cast if at the start of one.
;; The point is assumed to be at the start of some token. Nil is
;; macros like __INLINE__, so we recognize both types and known
;; specifiers after them too.
(while
- (let* ((start (point)) kwd-sym kwd-clause-end found-type)
+ (let* ((start (point)) kwd-sym kwd-clause-end found-type noise-start)
+ (cond
;; Look for a specifier keyword clause.
- (when (or (looking-at c-prefix-spec-kwds-re) ;FIXME!!! includes auto
- (and (c-major-mode-is 'java-mode)
- (looking-at "@[A-Za-z0-9]+")))
+ ((or (looking-at c-prefix-spec-kwds-re)
+ (and (c-major-mode-is 'java-mode)
+ (looking-at "@[A-Za-z0-9]+")))
(save-match-data
(if (looking-at c-typedef-key)
- (setq at-typedef t)))
+ (setq at-typedef t)))
(setq kwd-sym (c-keyword-sym (match-string 1)))
(save-excursion
(c-forward-keyword-clause 1)
(setq kwd-clause-end (point))))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (setq noise-start (point))
+ (c-forward-noise-clause)
+ (setq kwd-clause-end (point))))
(when (setq found-type (c-forward-type t)) ; brace-block-too
;; Found a known or possible type or a prefix of a known type.
backup-at-type-decl nil
backup-maybe-typeless nil))
- (if kwd-sym
+ (if (or kwd-sym noise-start)
(progn
;; Handle known specifier keywords and
;; `c-decl-hangon-kwds' which can occur after known
;; types.
- (if (c-keyword-member kwd-sym 'c-decl-hangon-kwds)
- ;; It's a hang-on keyword that can occur anywhere.
+ (if (or (c-keyword-member kwd-sym 'c-decl-hangon-kwds)
+ noise-start)
+ ;; It's a hang-on keyword or noise clause that can occur
+ ;; anywhere.
(progn
- (setq at-decl-or-cast t)
(if at-type
;; Move the identifier start position if
;; we've passed a type.
;; If a known type was found, we still need to skip over any
;; hangon keyword clauses after it. Otherwise it has already
;; been done in the loop above.
- (while (looking-at c-decl-hangon-key)
- (c-forward-keyword-clause 1))
+ (while
+ (cond ((looking-at c-decl-hangon-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
(setq id-start (point)))
((eq at-type 'prefix)
(goto-char id-start)
;; Skip over type decl prefix operators. (Note similar code in
- ;; `c-font-lock-declarators'.)
+ ;; `c-forward-declarator'.)
(if (and c-recognize-typeless-decls
(equal c-type-decl-prefix-key "\\<\\>"))
(when (eq (char-after) ?\()
(setq paren-depth (1- paren-depth))
(forward-char)
t)
- (when (if (save-match-data (looking-at "\\s\("))
+ (when (if (save-match-data (looking-at "\\s("))
(c-safe (c-forward-sexp 1) t)
(goto-char (match-end 1))
t)
(setq at-decl-end
(looking-at (cond ((eq context '<>) "[,>]")
- (context "[,\)]")
+ (context "[,)]")
(t "[,;]"))))
;; Now we've collected info about various characteristics of
;; The closing paren should follow.
(progn
(c-forward-syntactic-ws)
- (looking-at "\\s\)"))
+ (looking-at "\\s)"))
;; There should be a primary expression after it.
(let (pos)
(catch 'break
;; Look for ": superclass-name" or "( category-name )".
- (when (looking-at "[:\(]")
+ (when (looking-at "[:(]")
(setq start-char (char-after))
(forward-char)
(c-forward-syntactic-ws)
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
+ ;; Note to maintainers: this function consumes a great mass of CPU cycles.
+ ;; Its use should thus be minimized as far as possible.
(let ((paren-state (c-parse-state)))
(or (not (c-most-enclosing-brace paren-state))
(c-search-uplist-for-classkey paren-state))))
;; Return the position of the first argument declaration if point is
;; inside a K&R style argument declaration list, nil otherwise.
;; `c-recognize-knr-p' is not checked. If LIM is non-nil, it's a
- ;; position that bounds the backward search for the argument list.
+ ;; position that bounds the backward search for the argument list. This
+ ;; function doesn't move point.
;;
;; Point must be within a possible K&R region, e.g. just before a top-level
;; "{". It must be outside of parens and brackets. The test can return
;; false positives otherwise.
;;
;; This function might do hidden buffer changes.
-
(save-excursion
(save-restriction
;; If we're in a macro, our search range is restricted to it. Narrow to
(macro-end (save-excursion (and macro-start (c-end-of-macro) (point))))
(low-lim (max (or lim (point-min)) (or macro-start (point-min))))
before-lparen after-rparen
- (pp-count-out 20)) ; Max number of paren/brace constructs before
- ; we give up
+ (here (point))
+ (pp-count-out 20) ; Max number of paren/brace constructs before
+ ; we give up.
+ ids ; List of identifiers in the parenthesized list.
+ id-start after-prec-token decl-or-cast decl-res
+ c-last-identifier-range identifier-ok)
(narrow-to-region low-lim (or macro-end (point-max)))
;; Search backwards for the defun's argument list. We give up if we
;; int foo (bar, baz, yuk)
;; int bar [] ;
;; int (*baz) (my_type) ;
- ;; int (*) (void) (*yuk) (void) ;
+ ;; int (*(* yuk) (void)) (void) ;
;; {
+ ;;
+ ;; Additionally, for a knr list to be recognized:
+ ;; o - The identifier of each declarator up to and including the
+ ;; one "near" point must be contained in the arg list.
(catch 'knr
(while (> pp-count-out 0) ; go back one paren/bracket pair each time.
(goto-char before-lparen)
(c-forward-token-2) ; to first token inside parens
(and
- (c-on-identifier)
- (c-forward-token-2)
+ (setq id-start (c-on-identifier)) ; Must be at least one.
(catch 'id-list
- (while (eq (char-after) ?\,)
+ (while
+ (progn
+ (forward-char)
+ (c-end-of-current-token)
+ (push (buffer-substring-no-properties id-start
+ (point))
+ ids)
+ (c-forward-syntactic-ws)
+ (eq (char-after) ?\,))
(c-forward-token-2)
- (unless (c-on-identifier) (throw 'id-list nil))
- (c-forward-token-2))
- (eq (char-after) ?\))))))
+ (unless (setq id-start (c-on-identifier))
+ (throw 'id-list nil)))
+ (eq (char-after) ?\)))))
+ ;; Are all the identifiers in the k&r list up to the
+ ;; current one also in the argument list?
+ (progn
+ (forward-char) ; over the )
+ (setq after-prec-token after-rparen)
+ (c-forward-syntactic-ws)
+ (while (and
+ (or (consp (setq decl-or-cast
+ (c-forward-decl-or-cast-1
+ after-prec-token
+ nil ; Or 'arglist ???
+ nil)))
+ (progn
+ (goto-char after-prec-token)
+ (c-forward-syntactic-ws)
+ (setq identifier-ok (eq (char-after) ?{))
+ nil))
+ (eq (char-after) ?\;)
+ (setq after-prec-token (1+ (point)))
+ (goto-char (car decl-or-cast))
+ (setq decl-res (c-forward-declarator))
+ (setq identifier-ok
+ (member (buffer-substring-no-properties
+ (car decl-res) (cadr decl-res))
+ ids))
+ (progn
+ (goto-char after-prec-token)
+ (prog1 (< (point) here)
+ (c-forward-syntactic-ws))))
+ (setq identifier-ok nil))
+ identifier-ok))
;; ...Yes. We've identified the function's argument list.
(throw 'knr
(progn (goto-char after-rparen)
(c-forward-syntactic-ws)
(point)))
-
;; ...No. The current parens aren't the function's arg list.
(goto-char before-lparen))
;; Check for `c-opt-block-decls-with-vars-key'
;; before the first paren.
(c-syntactic-re-search-forward
- (concat "[;=\(\[{]\\|\\("
+ (concat "[;=([{]\\|\\("
c-opt-block-decls-with-vars-key
"\\)")
lim t t t)
(not (eq (char-before) ?_))
;; Check that the first following paren is
;; the block.
- (c-syntactic-re-search-forward "[;=\(\[{]"
+ (c-syntactic-re-search-forward "[;=([{]"
lim t t t)
(eq (char-before) ?{)))))))
;; The declaration doesn't have any of the
t)
((looking-at c-after-brace-list-key) t)
((looking-at c-brace-list-key) nil)
+ ((eq (char-after) ?\()
+ (and (eq (c-backward-token-2) 0)
+ (or (looking-at c-decl-hangon-key)
+ (looking-at c-noise-macro-with-parens-name-re))))
+
((and c-recognize-<>-arglists
(eq (char-after) ?<)
(looking-at "\\s("))
(> (point) closest-lim))
(not (bobp))
(progn (backward-char)
- (looking-at "[\]\).]\\|\\w\\|\\s_"))
+ (looking-at "[]).]\\|\\w\\|\\s_"))
(c-safe (forward-char)
(goto-char (scan-sexps (point) -1))))
(goto-char containing-sexp)
(if (or (save-excursion
(c-backward-syntactic-ws lim)
+ (while (and (eq (char-before) ?>)
+ (c-get-char-property (1- (point))
+ 'syntax-table)
+ (c-go-list-backward nil lim))
+ (c-backward-syntactic-ws lim))
(and (> (point) (or lim (point-min)))
(c-on-identifier)))
(and c-special-brace-lists
(c-save-buffer-state
((indent-point (point))
(case-fold-search nil)
- open-paren-in-column-0-is-defun-start
;; A whole ugly bunch of various temporary variables. Have
;; to declare them here since it's not possible to declare
;; a variable with only the scope of a cond test and the
paren-state)))
;; CASE 14: A case or default label
- ((looking-at c-label-kwds-regexp)
+ ((save-excursion
+ (and (looking-at c-label-kwds-regexp)
+ (or (c-major-mode-is 'idl-mode)
+ (and
+ containing-sexp
+ (goto-char containing-sexp)
+ (eq (char-after) ?{)
+ (progn (c-backward-syntactic-ws) t)
+ (eq (char-before) ?\))
+ (c-go-list-backward)
+ (progn (c-backward-syntactic-ws) t)
+ (c-simple-skip-symbol-backward)
+ (looking-at c-block-stmt-2-key)))))
(if containing-sexp
(progn
(goto-char containing-sexp)
((save-excursion
(back-to-indentation)
(and (not (looking-at c-syntactic-ws-start))
+ (not (looking-at c-label-kwds-regexp))
(c-forward-label)))
(cond (containing-decl-open
(setq placeholder (c-add-class-syntax 'inclass
;; CASE 5A.3: brace list open
((save-excursion
(c-beginning-of-decl-1 lim)
- (while (looking-at c-specifier-key)
- (goto-char (match-end 1))
- (c-forward-syntactic-ws indent-point))
+ (while (cond
+ ((looking-at c-specifier-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
(setq placeholder (c-point 'boi))
(or (consp special-brace-list)
(and (or (save-excursion
(t
(save-excursion
(c-beginning-of-decl-1 lim)
- (while (looking-at c-specifier-key)
- (goto-char (match-end 1))
- (c-forward-syntactic-ws indent-point))
+ (while (cond
+ ((looking-at c-specifier-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
(c-add-syntax 'defun-open (c-point 'boi))
;; Bogus to use bol here, but it's the legacy. (Resolved,
;; 2007-11-09)
;; Note there is no limit on the backward search here, since member
;; init lists can, in practice, be very large.
((save-excursion
- (when (setq placeholder (c-back-over-member-initializers))
+ (when (and (c-major-mode-is 'c++-mode)
+ (setq placeholder (c-back-over-member-initializers)))
(setq tmp-pos (point))))
(if (= (c-point 'bosws) (1+ tmp-pos))
(progn
(c-beginning-of-statement-1
(c-safe-position (1- containing-sexp) paren-state))
(c-forward-token-2 0)
- (while (looking-at c-specifier-key)
- (goto-char (match-end 1))
- (c-forward-syntactic-ws))
+ (while (cond
+ ((looking-at c-specifier-key)
+ (c-forward-keyword-clause 1))
+ ((looking-at c-noise-macro-with-parens-name-re)
+ (c-forward-noise-clause))))
(c-add-syntax 'brace-list-open (c-point 'boi))))
;; CASE 9B: brace-list-close brace