;; The last position where a label is possible provided the
;; statement started there. It's nil as long as no invalid
;; label content has been found (according to
- ;; `c-nonlabel-token-key'. It's `start' if no valid label
+ ;; `c-nonlabel-token-key'). It's `start' if no valid label
;; content was found in the label. Note that we might still
;; regard it a label if it starts with `c-label-kwds'.
label-good-pos
+ ;; Putative positions of the components of a bitfield declaration,
+ ;; e.g. "int foo : NUM_FOO_BITS ;"
+ bitfield-type-pos bitfield-id-pos bitfield-size-pos
;; Symbol just scanned back over (e.g. 'while or 'boundary).
;; See above.
sym
;; Record this as the first token if not starting inside it.
(setq tok start))
- ;; The following while loop goes back one sexp (balanced parens,
- ;; etc. with contents, or symbol or suchlike) each iteration. This
- ;; movement is accomplished with a call to scan-sexps approx 130 lines
- ;; below.
+
+ ;; The following while loop goes back one sexp (balanced parens,
+ ;; etc. with contents, or symbol or suchlike) each iteration. This
+ ;; movement is accomplished with a call to c-backward-sexp approx 170
+ ;; lines below.
+ ;;
+ ;; The loop is exited only by throwing nil to the (catch 'loop ...):
+ ;; 1. On reaching the start of a macro;
+ ;; 2. On having passed a stmt boundary with the PDA stack empty;
+ ;; 3. On reaching the start of an Objective C method def;
+ ;; 4. From macro `c-bos-pop-state'; when the stack is empty;
+ ;; 5. From macro `c-bos-pop-state-and-retry' when the stack is empty.
(while
(catch 'loop ;; Throw nil to break, non-nil to continue.
(cond
+ ;; Are we in a macro, just after the opening #?
((save-excursion
(and macro-start ; Always NIL for AWK.
(progn (skip-chars-backward " \t")
(setq pos saved
ret 'macro
ignore-labels t))
- (throw 'loop nil))
+ (throw 'loop nil)) ; 1. Start of macro.
;; Do a round through the automaton if we've just passed a
;; statement boundary or passed a "while"-like token.
(setq sym (intern (match-string 1)))))
(when (and (< pos start) (null stack))
- (throw 'loop nil))
+ (throw 'loop nil)) ; 2. Statement boundary.
;; The PDA state handling.
;;
;; HERE IS THE SINGLE PLACE INSIDE THE PDA LOOP WHERE WE MOVE
;; BACKWARDS THROUGH THE SOURCE.
- ;; This is typically fast with the caching done by
- ;; c-(backward|forward)-sws.
(c-backward-syntactic-ws)
-
(let ((before-sws-pos (point))
- ;; Set as long as we have to continue jumping by sexps.
- ;; It's the position to use as end in the next round.
- sexp-loop-continue-pos
;; The end position of the area to search for statement
;; barriers in this round.
- (sexp-loop-end-pos pos))
+ (maybe-after-boundary-pos pos))
- ;; The following while goes back one sexp per iteration.
+ ;; Go back over exactly one logical sexp, taking proper
+ ;; account of macros and escaped EOLs.
(while
(progn
(unless (c-safe (c-backward-sexp) t)
;; stack won't be empty the code below will report a
;; suitable error.
(throw 'loop nil))
-
- ;; Check if the sexp movement crossed a statement or
- ;; declaration boundary. But first modify the point
- ;; so that `c-crosses-statement-barrier-p' only looks
- ;; at the non-sexp chars following the sexp.
- (save-excursion
- (when (setq
- boundary-pos
- (cond
- ((if macro-start
- nil
- (save-excursion
- (when (c-beginning-of-macro)
- ;; Set continuation position in case
- ;; `c-crosses-statement-barrier-p'
- ;; doesn't detect anything below.
- (setq sexp-loop-continue-pos (point)))))
- ;; If the sexp movement took us into a
- ;; macro then there were only some non-sexp
- ;; chars after it. Skip out of the macro
- ;; to analyze them but not the non-sexp
- ;; chars that might be inside the macro.
- (c-end-of-macro)
- (c-crosses-statement-barrier-p
- (point) sexp-loop-end-pos))
-
- ((and
- (eq (char-after) ?{)
- (not (c-looking-at-inexpr-block lim nil t)))
- ;; Passed a block sexp. That's a boundary
- ;; alright.
- (point))
-
- ((looking-at "\\s\(")
- ;; Passed some other paren. Only analyze
- ;; the non-sexp chars after it.
- (goto-char (1+ (c-down-list-backward
- before-sws-pos)))
- ;; We're at a valid token start position
- ;; (outside the `save-excursion') if
- ;; `c-crosses-statement-barrier-p' failed.
- (c-crosses-statement-barrier-p
- (point) sexp-loop-end-pos))
-
- (t
- ;; Passed a symbol sexp or line
- ;; continuation. It doesn't matter that
- ;; it's included in the analyzed region.
- (if (c-crosses-statement-barrier-p
- (point) sexp-loop-end-pos)
- t
- ;; If it was a line continuation then we
- ;; have to continue looping.
- (if (looking-at "\\\\$")
- (setq sexp-loop-continue-pos (point)))
- nil))))
-
- (setq pptok ptok
- ptok tok
- tok boundary-pos
- sym 'boundary)
- ;; Like a C "continue". Analyze the next sexp.
- (throw 'loop t)))
-
- sexp-loop-continue-pos) ; End of "go back a sexp" loop condition.
- (goto-char sexp-loop-continue-pos)
- (setq sexp-loop-end-pos sexp-loop-continue-pos
- sexp-loop-continue-pos nil))))
+ (cond
+ ;; Have we moved into a macro?
+ ((and (not macro-start)
+ (c-beginning-of-macro))
+ ;; Have we crossed a statement boundary? If not,
+ ;; keep going back until we find one or a "real" sexp.
+ (and
+ (save-excursion
+ (c-end-of-macro)
+ (not (c-crosses-statement-barrier-p
+ (point) maybe-after-boundary-pos)))
+ (setq maybe-after-boundary-pos (point))))
+ ;; Have we just gone back over an escaped NL? This
+ ;; doesn't count as a sexp.
+ ((looking-at "\\\\$")))))
+
+ ;; Have we crossed a statement boundary?
+ (setq boundary-pos
+ (cond
+ ;; Are we at a macro beginning?
+ ((and (not macro-start)
+ c-opt-cpp-prefix
+ (looking-at c-opt-cpp-prefix))
+ (save-excursion
+ (c-end-of-macro)
+ (c-crosses-statement-barrier-p
+ (point) maybe-after-boundary-pos)))
+ ;; Just gone back over a brace block?
+ ((and
+ (eq (char-after) ?{)
+ (not (c-looking-at-inexpr-block lim nil t)))
+ (save-excursion
+ (c-forward-sexp) (point)))
+ ;; Just gone back over some paren block?
+ ((looking-at "\\s\(")
+ (save-excursion
+ (goto-char (1+ (c-down-list-backward
+ before-sws-pos)))
+ (c-crosses-statement-barrier-p
+ (point) maybe-after-boundary-pos)))
+ ;; Just gone back over an ordinary symbol of some sort?
+ (t (c-crosses-statement-barrier-p
+ (point) maybe-after-boundary-pos))))
+
+ (when boundary-pos
+ (setq pptok ptok
+ ptok tok
+ tok boundary-pos
+ sym 'boundary)
+ ;; Like a C "continue". Analyze the next sexp.
+ (throw 'loop t))))
;; ObjC method def?
(when (and c-opt-method-key
(setq saved (c-in-method-def-p)))
(setq pos saved
ignore-labels t) ; Avoid the label check on exit.
- (throw 'loop nil))
+ (throw 'loop nil)) ; 3. ObjC method def.
+
+ ;; Might we have a bitfield declaration, "<type> <id> : <size>"?
+ (if c-has-bitfields
+ (cond
+ ;; The : <size> and <id> fields?
+ ((and (numberp c-maybe-labelp)
+ (not bitfield-size-pos)
+ (save-excursion
+ (goto-char (or tok start))
+ (not (looking-at c-keywords-regexp)))
+ (not (looking-at c-keywords-regexp))
+ (not (c-punctuation-in (point) c-maybe-labelp)))
+ (setq bitfield-size-pos (or tok start)
+ bitfield-id-pos (point)))
+ ;; The <type> field?
+ ((and bitfield-id-pos
+ (not bitfield-type-pos))
+ (if (and (looking-at c-symbol-key) ; Can only be an integer type. :-)
+ (not (looking-at c-not-primitive-type-keywords-regexp))
+ (not (c-punctuation-in (point) tok)))
+ (setq bitfield-type-pos (point))
+ (setq bitfield-size-pos nil
+ bitfield-id-pos nil)))))
;; Handle labels.
(unless (eq ignore-labels t)
;; (including a case label) or something like C++'s "public:"?
;; A case label might use an expression rather than a token.
(setq after-case:-pos (or tok start))
- (if (looking-at c-nonlabel-token-key) ; e.g. "while" or "'a'"
+ (if (or (looking-at c-nonlabel-token-key) ; e.g. "while" or "'a'"
+ ;; Catch C++'s inheritance construct "class foo : bar".
+ (save-excursion
+ (and
+ (c-safe (c-backward-sexp) t)
+ (looking-at c-nonlabel-token-2-key))))
(setq c-maybe-labelp nil)
(if after-labels-pos ; Have we already encountered a label?
(if (not last-label-pos)
pptok ptok
ptok tok
tok (point)
- pos tok))) ; Not nil (for the while loop).
-
+ pos tok) ; always non-nil
+ ) ; end of (catch loop ....)
+ ) ; end of sexp-at-a-time (while ....)
+
;; If the stack isn't empty there might be errors to report.
(while stack
(if (and (vectorp saved-pos) (eq (length saved-pos) 3))
(eq c-maybe-labelp t)
(not (eq ret 'beginning))
after-labels-pos
+ (not bitfield-type-pos) ; Bitfields take precedence over labels.
(or (not label-good-pos)
(<= label-good-pos pos)
(progn
(goto-char pos)
ret)))
+(defun c-punctuation-in (from to)
+ "Return non-nil if there is a non-comment non-macro punctuation character
+between FROM and TO. FROM must not be in a string or comment. The returned
+value is the position of the first such character."
+ (save-excursion
+ (goto-char from)
+ (let ((pos (point)))
+ (while (progn (skip-chars-forward c-symbol-chars to)
+ (c-forward-syntactic-ws to)
+ (> (point) pos))
+ (setq pos (point))))
+ (and (< (point) to) (point))))
+
(defun c-crosses-statement-barrier-p (from to)
"Return non-nil if buffer positions FROM to TO cross one or more
statement or declaration boundaries. The returned value is actually
;; same line.
(re-search-forward "\\=\\s *[\n\r]" start t)
- (if (if (forward-comment -1)
+ (if (if (let (open-paren-in-column-0-is-defun-start) (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.
- (forward-comment -1)
+ (let (open-paren-in-column-0-is-defun-start)
+ (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 (forward-comment -1)
+ (if (let (open-paren-in-column-0-is-defun-start)
+ (forward-comment -1))
(if (looking-at "\\*/")
;; Emacs <= 20 and XEmacs move back over the
;; closer of a block comment that lacks an opener.
pos))
(defsubst c-state-cache-non-literal-place (pos state)
- ;; Return a position outside of a string/comment at or before POS.
+ ;; Return a position outside of a string/comment/macro at or before POS.
;; STATE is the parse-partial-sexp state at POS.
- (if (or (nth 3 state) ; in a string?
- (nth 4 state)) ; in a comment?
- (nth 8 state)
- pos))
-
+ (let ((res (if (or (nth 3 state) ; in a string?
+ (nth 4 state)) ; in a comment?
+ (nth 8 state)
+ pos)))
+ (save-excursion
+ (goto-char res)
+ (if (c-beginning-of-macro)
+ (point)
+ res))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Stuff to do with point-min, and coping with any literal there.
(<= from (cdr c-state-brace-pair-desert)))
;; Only search what we absolutely need to:
(if (and c-state-brace-pair-desert
- (> from (cdr c-state-brace-pair-desert)))
+ (eq cache-pos (car c-state-brace-pair-desert)))
(narrow-to-region (cdr c-state-brace-pair-desert) (point-max)))
;; In the next pair of nested loops, the inner one moves back past a
(unless (fboundp 'c-real-parse-state)
(fset 'c-real-parse-state (symbol-function 'c-parse-state)))
(cc-bytecomp-defun c-real-parse-state)
+
+(defvar c-parse-state-state nil)
+(defun c-record-parse-state-state ()
+ (setq c-parse-state-state
+ (mapcar
+ (lambda (arg)
+ (cons arg (symbol-value arg)))
+ '(c-state-cache
+ c-state-cache-good-pos
+ c-state-nonlit-pos-cache
+ c-state-nonlit-pos-cache-limit
+ c-state-brace-pair-desert
+ c-state-point-min
+ c-state-point-min-lit-type
+ c-state-point-min-lit-start
+ c-state-min-scan-pos
+ c-state-old-cpp-beg
+ c-state-old-cpp-end))))
+(defun c-replay-parse-state-state ()
+ (message
+ (concat "(setq "
+ (mapconcat
+ (lambda (arg)
+ (format "%s %s%s" (car arg) (if (atom (cdr arg)) "" "'") (cdr arg)))
+ c-parse-state-state " ")
+ ")")))
+
(defun c-debug-parse-state ()
(let ((here (point)) (res1 (c-real-parse-state)) res2)
(let ((c-state-cache nil)
;; The cache can actually go further back due to the ad-hoc way
;; the first paren is found, so try to whack off a bit of its
;; start before complaining.
- (save-excursion
- (goto-char (or (c-least-enclosing-brace res2) (point)))
- (c-beginning-of-defun-1)
- (while (not (or (bobp) (eq (char-after) ?{)))
- (c-beginning-of-defun-1))
- (unless (equal (c-whack-state-before (point) res1) res2)
- (message (concat "c-parse-state inconsistency at %s: "
- "using cache: %s, from scratch: %s")
- here res1 res2))))
+ ;; (save-excursion
+ ;; (goto-char (or (c-least-enclosing-brace res2) (point)))
+ ;; (c-beginning-of-defun-1)
+ ;; (while (not (or (bobp) (eq (char-after) ?{)))
+ ;; (c-beginning-of-defun-1))
+ ;; (unless (equal (c-whack-state-before (point) res1) res2)
+ ;; (message (concat "c-parse-state inconsistency at %s: "
+ ;; "using cache: %s, from scratch: %s")
+ ;; here res1 res2)))
+ (message (concat "c-parse-state inconsistency at %s: "
+ "using cache: %s, from scratch: %s")
+ here res1 res2)
+ (message "Old state:")
+ (c-replay-parse-state-state))
+ (c-record-parse-state-state)
res1))
(defun c-toggle-parse-state-debug (&optional arg)
(let* ((start (point)) kwd-sym kwd-clause-end found-type)
;; Look for a specifier keyword clause.
- (when (looking-at c-prefix-spec-kwds-re)
+ (when (or (looking-at c-prefix-spec-kwds-re)
+ (and (c-major-mode-is 'java-mode)
+ (looking-at "@[A-Za-z0-9]+")))
(if (looking-at c-typedef-key)
(setq at-typedef t))
(setq kwd-sym (c-keyword-sym (match-string 1)))
;; `c-font-lock-declarators'.)
(while (and (looking-at c-type-decl-prefix-key)
(if (and (c-major-mode-is 'c++-mode)
- (match-beginning 2))
+ (match-beginning 3))
;; If the second submatch matches in C++ then
;; we're looking at an identifier that's a
;; prefix only if it specifies a member pointer.
(if backup-at-type
(progn
- ;; CASE 3
- (when (= (point) start)
- ;; Got a plain list of identifiers. If a colon follows it's
- ;; a valid label. Otherwise the last one probably is the
- ;; declared identifier and we should back up to the previous
- ;; type, providing it isn't a cast.
+
+ ;; CASE 3
+ (when (= (point) start)
+ ;; Got a plain list of identifiers. If a colon follows it's
+ ;; a valid label, or maybe a bitfield. Otherwise the last
+ ;; one probably is the declared identifier and we should
+ ;; back up to the previous type, providing it isn't a cast.
(if (and (eq (char-after) ?:)
(not (c-major-mode-is 'java-mode)))
- ;; If we've found a specifier keyword then it's a
- ;; declaration regardless.
- (throw 'at-decl-or-cast (eq at-decl-or-cast t))
- (setq backup-if-not-cast t)
- (throw 'at-decl-or-cast t)))
+ (cond
+ ;; If we've found a specifier keyword then it's a
+ ;; declaration regardless.
+ ((eq at-decl-or-cast t)
+ (throw 'at-decl-or-cast t))
+ ((and c-has-bitfields
+ (eq at-decl-or-cast 'ids)) ; bitfield.
+ (setq backup-if-not-cast t)
+ (throw 'at-decl-or-cast t)))
+
+ (setq backup-if-not-cast t)
+ (throw 'at-decl-or-cast t)))
;; CASE 4
(when (and got-suffix
(back-to-indentation)
(vector (point) open-paren-pos))))))
+(defmacro c-pull-open-brace (ps)
+ ;; Pull the next open brace from PS (which has the form of paren-state),
+ ;; skipping over any brace pairs. Returns NIL when PS is exhausted.
+ `(progn
+ (while (consp (car ,ps))
+ (setq ,ps (cdr ,ps)))
+ (prog1 (car ,ps)
+ (setq ,ps (cdr ,ps)))))
+
+(defun c-most-enclosing-decl-block (paren-state)
+ ;; Return the buffer position of the most enclosing decl-block brace (in the
+ ;; sense of c-looking-at-decl-block) in the PAREN-STATE structure, or nil if
+ ;; none was found.
+ (let* ((open-brace (c-pull-open-brace paren-state))
+ (next-open-brace (c-pull-open-brace paren-state)))
+ (while (and open-brace
+ (save-excursion
+ (goto-char open-brace)
+ (not (c-looking-at-decl-block next-open-brace nil))))
+ (setq open-brace next-open-brace
+ next-open-brace (c-pull-open-brace paren-state)))
+ open-brace))
+
(defun c-inside-bracelist-p (containing-sexp paren-state)
;; return the buffer position of the beginning of the brace list
;; statement if we're inside a brace list, otherwise return nil.
(c-beginning-of-statement-1 containing-sexp)
(c-add-syntax 'annotation-var-cont (point)))
+ ;; CASE G: a template list continuation?
+ ;; Mostly a duplication of case 5D.3 to fix templates-19:
+ ((and (c-major-mode-is 'c++-mode)
+ (save-excursion
+ (goto-char indent-point)
+ (c-with-syntax-table c++-template-syntax-table
+ (setq placeholder (c-up-list-backward)))
+ (and placeholder
+ (eq (char-after placeholder) ?<)
+ (/= (char-before placeholder) ?<)
+ (progn
+ (goto-char (1+ placeholder))
+ (not (looking-at c-<-op-cont-regexp))))))
+ (c-with-syntax-table c++-template-syntax-table
+ (goto-char placeholder)
+ (c-beginning-of-statement-1 containing-sexp t)
+ (if (save-excursion
+ (c-backward-syntactic-ws containing-sexp)
+ (eq (char-before) ?<))
+ ;; In a nested template arglist.
+ (progn
+ (goto-char placeholder)
+ (c-syntactic-skip-backward "^,;" containing-sexp t)
+ (c-forward-syntactic-ws))
+ (back-to-indentation)))
+ ;; FIXME: Should use c-add-stmt-syntax, but it's not yet
+ ;; template aware.
+ (c-add-syntax 'template-args-cont (point) placeholder))
+
;; CASE D: continued statement.
(t
(c-beginning-of-statement-1 containing-sexp)
(c-most-enclosing-brace paren-state (point))
paren-state))
- ;; CASE 19: line is an expression, not a statement, and is directly
- ;; contained by a template delimiter. Most likely, we are in a
- ;; template arglist within a statement. This case is based on CASE
- ;; 7. At some point in the future, we may wish to create more
- ;; syntactic symbols such as `template-intro',
- ;; `template-cont-nonempty', etc., and distinguish between them as we
- ;; do for `arglist-intro' etc. (2009-12-07).
- ((and c-recognize-<>-arglists
- (setq containing-< (c-up-list-backward indent-point containing-sexp))
- (eq (char-after containing-<) ?\<))
- (setq placeholder (c-point 'boi containing-<))
- (goto-char containing-sexp) ; Most nested Lbrace/Lparen (but not
- ; '<') before indent-point.
- (if (>= (point) placeholder)
- (progn
- (forward-char)
- (skip-chars-forward " \t"))
- (goto-char placeholder))
- (c-add-stmt-syntax 'template-args-cont (list containing-<) t
- (c-most-enclosing-brace c-state-cache (point))
- paren-state))
-
;; CASE 7B: Looking at the opening brace of an
;; in-expression block or brace list. C.f. cases 4, 16A
;; and 17E.
paren-state))
))
+ ;; CASE 19: line is an expression, not a statement, and is directly
+ ;; contained by a template delimiter. Most likely, we are in a
+ ;; template arglist within a statement. This case is based on CASE
+ ;; 7. At some point in the future, we may wish to create more
+ ;; syntactic symbols such as `template-intro',
+ ;; `template-cont-nonempty', etc., and distinguish between them as we
+ ;; do for `arglist-intro' etc. (2009-12-07).
+ ((and c-recognize-<>-arglists
+ (setq containing-< (c-up-list-backward indent-point containing-sexp))
+ (eq (char-after containing-<) ?\<))
+ (setq placeholder (c-point 'boi containing-<))
+ (goto-char containing-sexp) ; Most nested Lbrace/Lparen (but not
+ ; '<') before indent-point.
+ (if (>= (point) placeholder)
+ (progn
+ (forward-char)
+ (skip-chars-forward " \t"))
+ (goto-char placeholder))
+ (c-add-stmt-syntax 'template-args-cont (list containing-<) t
+ (c-most-enclosing-brace c-state-cache (point))
+ paren-state))
+
;; CASE 17: Statement or defun catchall.
(t
(goto-char indent-point)