;;; cc-engine.el --- core syntax guessing engine for CC mode
-;; Copyright (C) 1985, 1987, 1992-2011 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1987, 1992-2013 Free Software Foundation, Inc.
;; Authors: 2001- Alan Mackenzie
;; 1998- Martin Stjernholm
(not prevstate)
(> arg 0)))
-;; Dynamically bound cache for `c-in-literal'.
-(defvar c-in-literal-cache t)
-
\f
;; Basic handling of preprocessor directives.
(point))))
c-macro-start))
+;; One element macro cache to cope with continual movement within very large
+;; CPP macros.
+(defvar c-macro-cache nil)
+(make-variable-buffer-local 'c-macro-cache)
+;; Nil or cons of the bounds of the most recent CPP form probed by
+;; `c-beginning-of-macro', `c-end-of-macro' or `c-syntactic-end-of-macro'.
+;; The cdr will be nil if we know only the start of the CPP form.
+(defvar c-macro-cache-start-pos nil)
+(make-variable-buffer-local 'c-macro-cache-start-pos)
+;; The starting position from where we determined `c-macro-cache'.
+(defvar c-macro-cache-syntactic nil)
+(make-variable-buffer-local 'c-macro-cache-syntactic)
+;; non-nil iff `c-macro-cache' has both elements set AND the cdr is at a
+;; syntactic end of macro, not merely an apparent one.
+
+(defun c-invalidate-macro-cache (beg end)
+ ;; Called from a before-change function. If the change region is before or
+ ;; in the macro characterized by `c-macro-cache' etc., nullify it
+ ;; appropriately. BEG and END are the standard before-change-functions
+ ;; parameters. END isn't used.
+ (cond
+ ((null c-macro-cache))
+ ((< beg (car c-macro-cache))
+ (setq c-macro-cache nil
+ c-macro-cache-start-pos nil
+ c-macro-cache-syntactic nil))
+ ((and (cdr c-macro-cache)
+ (< beg (cdr c-macro-cache)))
+ (setcdr c-macro-cache nil)
+ (setq c-macro-cache-start-pos beg
+ c-macro-cache-syntactic nil))))
+
(defun c-beginning-of-macro (&optional lim)
"Go to the beginning of a preprocessor directive.
Leave point at the beginning of the directive and return t if in one,
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
- (when c-opt-cpp-prefix
- (let ((here (point)))
- (save-restriction
- (if lim (narrow-to-region lim (point-max)))
- (beginning-of-line)
- (while (eq (char-before (1- (point))) ?\\)
- (forward-line -1))
- (back-to-indentation)
- (if (and (<= (point) here)
- (looking-at c-opt-cpp-start))
- t
- (goto-char here)
- nil)))))
+ (let ((here (point)))
+ (when c-opt-cpp-prefix
+ (if (and (car c-macro-cache)
+ (>= (point) (car c-macro-cache))
+ (or (and (cdr c-macro-cache)
+ (<= (point) (cdr c-macro-cache)))
+ (<= (point) c-macro-cache-start-pos)))
+ (unless (< (car c-macro-cache) (or lim (point-min)))
+ (progn (goto-char (max (or lim (point-min)) (car c-macro-cache)))
+ (setq c-macro-cache-start-pos
+ (max c-macro-cache-start-pos here))
+ t))
+ (setq c-macro-cache nil
+ c-macro-cache-start-pos nil
+ c-macro-cache-syntactic nil)
+
+ (save-restriction
+ (if lim (narrow-to-region lim (point-max)))
+ (beginning-of-line)
+ (while (eq (char-before (1- (point))) ?\\)
+ (forward-line -1))
+ (back-to-indentation)
+ (if (and (<= (point) here)
+ (looking-at c-opt-cpp-start))
+ (progn
+ (setq c-macro-cache (cons (point) nil)
+ c-macro-cache-start-pos here)
+ t)
+ (goto-char here)
+ nil))))))
(defun c-end-of-macro ()
"Go to the end of a preprocessor directive.
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
- (while (progn
- (end-of-line)
- (when (and (eq (char-before) ?\\)
- (not (eobp)))
- (forward-char)
- t))))
+ (if (and (cdr c-macro-cache)
+ (<= (point) (cdr c-macro-cache))
+ (>= (point) (car c-macro-cache)))
+ (goto-char (cdr c-macro-cache))
+ (unless (and (car c-macro-cache)
+ (<= (point) c-macro-cache-start-pos)
+ (>= (point) (car c-macro-cache)))
+ (setq c-macro-cache nil
+ c-macro-cache-start-pos nil
+ c-macro-cache-syntactic nil))
+ (while (progn
+ (end-of-line)
+ (when (and (eq (char-before) ?\\)
+ (not (eobp)))
+ (forward-char)
+ t)))
+ (when (car c-macro-cache)
+ (setcdr c-macro-cache (point)))))
(defun c-syntactic-end-of-macro ()
;; Go to the end of a CPP directive, or a "safe" pos just before.
;; at the start of cc-engine.el for more info.
(let* ((here (point))
(there (progn (c-end-of-macro) (point)))
- (s (parse-partial-sexp here there)))
- (while (and (or (nth 3 s) ; in a string
- (nth 4 s)) ; in a comment (maybe at end of line comment)
- (> there here)) ; No infinite loops, please.
- (setq there (1- (nth 8 s)))
- (setq s (parse-partial-sexp here there)))
+ s)
+ (unless c-macro-cache-syntactic
+ (setq s (parse-partial-sexp here there))
+ (while (and (or (nth 3 s) ; in a string
+ (nth 4 s)) ; in a comment (maybe at end of line comment)
+ (> there here)) ; No infinite loops, please.
+ (setq there (1- (nth 8 s)))
+ (setq s (parse-partial-sexp here there)))
+ (setq c-macro-cache-syntactic (car c-macro-cache)))
(point)))
(defun c-forward-over-cpp-define-id ()
((eq sym 'while)
;; Is this a real while, or a do-while?
;; The next `when' triggers unless we are SURE that
- ;; the `while' is not the tailend of a `do-while'.
+ ;; the `while' is not the tail end of a `do-while'.
(when (or (not pptok)
(memq (char-after pptok) delims)
;; The following kludge is to prevent
(c-at-vsemi-p))))
(throw 'done vsemi-pos))
;; In a string/comment?
- ((setq lit-range (c-literal-limits))
+ ((setq lit-range (c-literal-limits from))
(goto-char (cdr lit-range)))
((eq (char-after) ?:)
(forward-char)
;; return t when moving backwards at bob.
(not (bobp))
- (if (let (open-paren-in-column-0-is-defun-start)
- (forward-comment -1))
+ (if (let (open-paren-in-column-0-is-defun-start moved-comment)
+ (while
+ (and (not (setq moved-comment (forward-comment -1)))
+ ;; Cope specifically with ^M^J here -
+ ;; forward-comment sometimes gets stuck after ^Ms,
+ ;; sometimes after ^M^J.
+ (or
+ (when (eq (char-before) ?\r)
+ (backward-char)
+ t)
+ (when (and (eq (char-before) ?\n)
+ (eq (char-before (1- (point))) ?\r))
+ (backward-char 2)
+ t))))
+ moved-comment)
(if (looking-at "\\*/")
;; Emacs <= 20 and XEmacs move back over the
;; closer of a block comment that lacks an opener.
;; high as possible.
(setq rung-pos (point)))
+ (with-silent-modifications
(while
(progn
(while
(1- last-put-in-sws-pos))
(c-remove-is-and-in-sws (1- last-put-in-sws-pos)
last-put-in-sws-pos))))
- )))
+ ))))
(defun c-backward-sws ()
;; Used by `c-backward-syntactic-ws' to implement the unbounded search.
(goto-char (setq rung-pos rung-is-marked))
(goto-char simple-ws-beg))
+ (with-silent-modifications
(while
(progn
(while
last-put-in-sws-pos)
(c-remove-is-and-in-sws last-put-in-sws-pos
(1+ last-put-in-sws-pos)))))
- )))
+ ))))
\f
;; Other whitespace tools
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; We maintain a simple cache of positions which aren't in a literal, so as to
;; speed up testing for non-literality.
-(defconst c-state-nonlit-pos-interval 10000)
+(defconst c-state-nonlit-pos-interval 3000)
;; The approximate interval between entries in `c-state-nonlit-pos-cache'.
(defvar c-state-nonlit-pos-cache nil)
;; reduced by buffer changes, and increased by invocations of
;; `c-state-literal-at'.
+(defvar c-state-semi-nonlit-pos-cache nil)
+(make-variable-buffer-local 'c-state-semi-nonlit-pos-cache)
+;; A list of buffer positions which are known not to be in a literal. This is
+;; ordered with higher positions at the front of the list. Only those which
+;; are less than `c-state-semi-nonlit-pos-cache-limit' are valid.
+
+(defvar c-state-semi-nonlit-pos-cache-limit 1)
+(make-variable-buffer-local 'c-state-semi-nonlit-pos-cache-limit)
+;; An upper limit on valid entries in `c-state-semi-nonlit-pos-cache'. This is
+;; reduced by buffer changes, and increased by invocations of
+;; `c-state-literal-at'. FIXME!!!
+
(defsubst c-state-pp-to-literal (from to)
- ;; Do a parse-partial-sexp from FROM to TO, returning the bounds of any
- ;; literal at TO as a cons, otherwise NIL.
- ;; FROM must not be in a literal, and the buffer should already be wide
- ;; enough.
+ ;; Do a parse-partial-sexp from FROM to TO, returning either
+ ;; (STATE TYPE (BEG . END)) if TO is in a literal; or
+ ;; (STATE) otherwise,
+ ;; where STATE is the parsing state at TO, TYPE is the type of the literal
+ ;; (one of 'c, 'c++, 'string) and (BEG . END) is the boundaries of the literal.
+ ;;
+ ;; Only elements 3 (in a string), 4 (in a comment), 5 (following a quote),
+ ;; 7 (comment type) and 8 (start of comment/string) (and possibly 9) of
+ ;; STATE are valid.
(save-excursion
- (let ((s (parse-partial-sexp from to)))
+ (let ((s (parse-partial-sexp from to))
+ ty)
(when (or (nth 3 s) (nth 4 s)) ; in a string or comment
+ (setq ty (cond
+ ((nth 3 s) 'string)
+ ((eq (nth 7 s) t) 'c++)
+ (t 'c)))
(parse-partial-sexp (point) (point-max)
nil ; TARGETDEPTH
nil ; STOPBEFORE
s ; OLDSTATE
- 'syntax-table) ; stop at end of literal
- (cons (nth 8 s) (point))))))
+ 'syntax-table)) ; stop at end of literal
+ (if ty
+ `(,s ,ty (,(nth 8 s) . ,(point)))
+ `(,s)))))
-(defun c-state-literal-at (here)
- ;; If position HERE is inside a literal, return (START . END), the
- ;; boundaries of the literal (which may be outside the accessible bit of the
- ;; buffer). Otherwise, return nil.
- ;;
- ;; This function is almost the same as `c-literal-limits'. It differs in
- ;; that it is a lower level function, and that it rigourously follows the
- ;; syntax from BOB, whereas `c-literal-limits' uses a "local" safe position.
+(defun c-state-safe-place (here)
+ ;; Return a buffer position before HERE which is "safe", i.e. outside any
+ ;; string, comment, or macro.
;;
;; NOTE: This function manipulates `c-state-nonlit-pos-cache'. This cache
;; MAY NOT contain any positions within macros, since macros are frequently
(widen)
(save-excursion
(let ((c c-state-nonlit-pos-cache)
- pos npos lit)
+ pos npos high-pos lit macro-beg macro-end)
;; Trim the cache to take account of buffer changes.
(while (and c (> (car c) c-state-nonlit-pos-cache-limit))
(setq c (cdr c)))
(setq c-state-nonlit-pos-cache c)
(while (and c (> (car c) here))
+ (setq high-pos (car c))
(setq c (cdr c)))
(setq pos (or (car c) (point-min)))
- (while (<= (setq npos (+ pos c-state-nonlit-pos-interval))
- here)
- (setq lit (c-state-pp-to-literal pos npos))
- (setq pos (or (cdr lit) npos)) ; end of literal containing npos.
- (goto-char pos)
- (when (and (c-beginning-of-macro) (/= (point) pos))
- (c-syntactic-end-of-macro)
- (or (eobp) (forward-char))
- (setq pos (point)))
- (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache)))
+ (unless high-pos
+ (while
+ ;; Add an element to `c-state-nonlit-pos-cache' each iteration.
+ (and
+ (<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
+
+ ;; Test for being in a literal. If so, go to after it.
+ (progn
+ (setq lit (car (cddr (c-state-pp-to-literal pos npos))))
+ (or (null lit)
+ (prog1 (<= (cdr lit) here)
+ (setq npos (cdr lit)))))
+
+ ;; Test for being in a macro. If so, go to after it.
+ (progn
+ (goto-char npos)
+ (setq macro-beg
+ (and (c-beginning-of-macro) (/= (point) npos) (point)))
+ (when macro-beg
+ (c-syntactic-end-of-macro)
+ (or (eobp) (forward-char))
+ (setq macro-end (point)))
+ (or (null macro-beg)
+ (prog1 (<= macro-end here)
+ (setq npos macro-end)))))
+
+ (setq pos npos)
+ (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache)))
+ ;; Add one extra element above HERE so as to to avoid the previous
+ ;; expensive calculation when the next call is close to the current
+ ;; one. This is especially useful when inside a large macro.
+ (setq c-state-nonlit-pos-cache (cons npos c-state-nonlit-pos-cache)))
(if (> pos c-state-nonlit-pos-cache-limit)
(setq c-state-nonlit-pos-cache-limit pos))
- (if (< pos here)
- (setq lit (c-state-pp-to-literal pos here)))
- lit))))
+ pos))))
+
+(defun c-state-semi-safe-place (here)
+ ;; Return a buffer position before HERE which is "safe", i.e. outside any
+ ;; string or comment. It may be in a macro.
+ (save-restriction
+ (widen)
+ (save-excursion
+ (let ((c c-state-semi-nonlit-pos-cache)
+ pos npos high-pos lit macro-beg macro-end)
+ ;; Trim the cache to take account of buffer changes.
+ (while (and c (> (car c) c-state-semi-nonlit-pos-cache-limit))
+ (setq c (cdr c)))
+ (setq c-state-semi-nonlit-pos-cache c)
+
+ (while (and c (> (car c) here))
+ (setq high-pos (car c))
+ (setq c (cdr c)))
+ (setq pos (or (car c) (point-min)))
+
+ (unless high-pos
+ (while
+ ;; Add an element to `c-state-semi-nonlit-pos-cache' each iteration.
+ (and
+ (<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
+
+ ;; Test for being in a literal. If so, go to after it.
+ (progn
+ (setq lit (car (cddr (c-state-pp-to-literal pos npos))))
+ (or (null lit)
+ (prog1 (<= (cdr lit) here)
+ (setq npos (cdr lit))))))
+
+ (setq pos npos)
+ (setq c-state-semi-nonlit-pos-cache
+ (cons pos c-state-semi-nonlit-pos-cache))))
+
+ (if (> pos c-state-semi-nonlit-pos-cache-limit)
+ (setq c-state-semi-nonlit-pos-cache-limit pos))
+ pos))))
+
+(defun c-state-literal-at (here)
+ ;; If position HERE is inside a literal, return (START . END), the
+ ;; boundaries of the literal (which may be outside the accessible bit of the
+ ;; buffer). Otherwise, return nil.
+ ;;
+ ;; This function is almost the same as `c-literal-limits'. Previously, it
+ ;; differed in that it was a lower level function, and that it rigorously
+ ;; followed the syntax from BOB. `c-literal-limits' is now (2011-12)
+ ;; virtually identical to this function.
+ (save-restriction
+ (widen)
+ (save-excursion
+ (let ((pos (c-state-safe-place here)))
+ (car (cddr (c-state-pp-to-literal pos here)))))))
(defsubst c-state-lit-beg (pos)
;; Return the start of the literal containing POS, or POS itself.
start-point cache-pos)))
;; Might we be better off starting from the top level, two defuns back,
- ;; instead?
- (when (> how-far c-state-cache-too-far)
+ ;; instead? This heuristic no longer works well in C++, where
+ ;; declarations inside namespace brace blocks are frequently placed at
+ ;; column zero.
+ (when (and (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
(setq c-state-point-min (point-min)))
(defun c-append-lower-brace-pair-to-state-cache (from &optional upper-lim)
- ;; If there is a brace pair preceding FROM in the buffer (not necessarily
- ;; immediately preceding), push a cons onto `c-state-cache' to represent it.
- ;; FROM must not be inside a literal. If UPPER-LIM is non-nil, we append
- ;; the highest brace pair whose "}" is below UPPER-LIM.
+ ;; If there is a brace pair preceding FROM in the buffer, at the same level
+ ;; of nesting (not necessarily immediately preceding), push a cons onto
+ ;; `c-state-cache' to represent it. FROM must not be inside a literal. If
+ ;; UPPER-LIM is non-nil, we append the highest brace pair whose "}" is below
+ ;; UPPER-LIM.
;;
;; Return non-nil when this has been done.
;;
+ ;; The situation it copes with is this transformation:
+ ;;
+ ;; OLD: { (.) {...........}
+ ;; ^ ^
+ ;; FROM HERE
+ ;;
+ ;; NEW: { {....} (.) {.........
+ ;; ^ ^ ^
+ ;; LOWER BRACE PAIR HERE or HERE
+ ;;
;; This routine should be fast. Since it can get called a LOT, we maintain
;; `c-state-brace-pair-desert', a small cache of "failures", such that we
;; reduce the time wasted in repeated fruitless searches in brace deserts.
;; If we're essentially repeating a fruitless search, just give up.
(unless (and c-state-brace-pair-desert
(eq cache-pos (car c-state-brace-pair-desert))
+ (or (null (car c-state-brace-pair-desert))
+ (> from (car c-state-brace-pair-desert)))
(<= from (cdr c-state-brace-pair-desert)))
- ;; Only search what we absolutely need to:
- (if (and 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)))
+ ;; DESERT-LIM. Avoid repeated searching through the cached desert.
+ (let ((desert-lim
+ (and c-state-brace-pair-desert
+ (eq cache-pos (car c-state-brace-pair-desert))
+ (>= from (cdr c-state-brace-pair-desert))
+ (cdr c-state-brace-pair-desert)))
+ ;; CACHE-LIM. This limit will be necessary when an opening
+ ;; paren at `cache-pos' has just had its matching close paren
+ ;; inserted into the buffer. `cache-pos' continues to be a
+ ;; search bound, even though the algorithm below would skip
+ ;; over the new paren pair.
+ (cache-lim (and cache-pos (< cache-pos from) cache-pos)))
+ (narrow-to-region
+ (cond
+ ((and desert-lim cache-lim)
+ (max desert-lim cache-lim))
+ (desert-lim)
+ (cache-lim)
+ ((point-min)))
+ (point-max)))
;; In the next pair of nested loops, the inner one moves back past a
;; pair of (mis-)matching parens or brackets; the outer one moves
(cons new-cons (cdr c-state-cache))))
(t (setq c-state-cache (cons new-cons c-state-cache)))))
- ;; We haven't found a brace pair. Record this.
+ ;; We haven't found a brace pair. Record this in the cache.
(setq c-state-brace-pair-desert (cons cache-pos from))))))))
(defsubst c-state-push-any-brace-pair (bra+1 macro-start-or-here)
mstart) ; start of a macro.
(save-excursion
- ;; Each time round the following loop, we enter a succesively deeper
+ ;; Each time round the following loop, we enter a successively deeper
;; level of brace/paren nesting. (Except sometimes we "continue at
;; the existing level".) `pa+1' is a pos inside an opening
;; brace/paren/bracket, usually just after it.
c-state-cache-good-pos 1
c-state-nonlit-pos-cache nil
c-state-nonlit-pos-cache-limit 1
+ c-state-semi-nonlit-pos-cache nil
+ c-state-semi-nonlit-pos-cache-limit 1
c-state-brace-pair-desert nil
c-state-point-min 1
c-state-point-min-lit-type nil
;;
;; This function is called from c-after-change.
- ;; The cache of non-literals:
+ ;; The caches of non-literals:
(if (< here c-state-nonlit-pos-cache-limit)
(setq c-state-nonlit-pos-cache-limit here))
+ (if (< here c-state-semi-nonlit-pos-cache-limit)
+ (setq c-state-semi-nonlit-pos-cache-limit here))
;; `c-state-cache':
;; Case 1: if `here' is in a literal containing point-min, everything
(if scan-forward-p
(progn (narrow-to-region (point-min) here)
(c-append-to-state-cache good-pos))
-
- (c-get-cache-scan-pos good-pos))))
+ good-pos)))
(t ; (eq strategy 'IN-LIT)
(setq c-state-cache nil
(fset 'c-real-parse-state (symbol-function 'c-parse-state)))
(cc-bytecomp-defun c-real-parse-state)
+(defvar c-parse-state-point nil)
(defvar c-parse-state-state nil)
(defun c-record-parse-state-state ()
+ (setq c-parse-state-point (point))
(setq c-parse-state-state
(mapcar
(lambda (arg)
- (cons arg (symbol-value arg)))
+ (let ((val (symbol-value arg)))
+ (cons arg
+ (if (consp val)
+ (copy-tree val)
+ val))))
'(c-state-cache
c-state-cache-good-pos
c-state-nonlit-pos-cache
c-state-nonlit-pos-cache-limit
+ c-state-semi-nonlit-pos-cache
+ c-state-semi-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))))
+ c-state-old-cpp-end
+ c-parse-state-point))))
(defun c-replay-parse-state-state ()
(message
(concat "(setq "
c-parse-state-state " ")
")")))
+(defun c-debug-parse-state-double-cons (state)
+ (let (state-car conses-not-ok)
+ (while state
+ (setq state-car (car state)
+ state (cdr state))
+ (if (and (consp state-car)
+ (consp (car state)))
+ (setq conses-not-ok t)))
+ conses-not-ok))
+
(defun c-debug-parse-state ()
(let ((here (point)) (res1 (c-real-parse-state)) res2)
(let ((c-state-cache nil)
here res1 res2)
(message "Old state:")
(c-replay-parse-state-state))
+
+ (when (c-debug-parse-state-double-cons res1)
+ (message "c-parse-state INVALIDITY at %s: %s"
+ here res1)
+ (message "Old state:")
+ (c-replay-parse-state-state))
+
(c-record-parse-state-state)
- res1))
+ res2 ; res1 correct a cascading series of errors ASAP
+ ))
(defun c-toggle-parse-state-debug (&optional arg)
(interactive "P")
(fset 'c-parse-state (symbol-function (if c-debug-parse-state
'c-debug-parse-state
'c-real-parse-state)))
- (c-keep-region-active))
+ (c-keep-region-active)
+ (message "c-debug-parse-state %sabled"
+ (if c-debug-parse-state "en" "dis")))
(when c-debug-parse-state
(c-toggle-parse-state-debug 1))
\f
;; Tools for handling comments and string literals.
-(defun c-slow-in-literal (&optional lim detect-cpp)
+(defun c-in-literal (&optional lim detect-cpp)
"Return the type of literal point is in, if any.
The return value is `c' if in a C-style comment, `c++' if in a C++
style comment, `string' if in a string literal, `pound' if DETECT-CPP
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
-
- (if (and (vectorp c-in-literal-cache)
- (= (point) (aref c-in-literal-cache 0)))
- (aref c-in-literal-cache 1)
- (let ((rtn (save-excursion
- (let* ((pos (point))
- (lim (or lim (progn
- (c-beginning-of-syntax)
- (point))))
- (state (parse-partial-sexp lim pos)))
- (cond
- ((elt state 3) 'string)
- ((elt state 4) (if (elt state 7) 'c++ 'c))
- ((and detect-cpp (c-beginning-of-macro lim)) 'pound)
- (t nil))))))
- ;; cache this result if the cache is enabled
- (if (not c-in-literal-cache)
- (setq c-in-literal-cache (vector (point) rtn)))
- rtn)))
-
-;; XEmacs has a built-in function that should make this much quicker.
-;; I don't think we even need the cache, which makes our lives more
-;; complicated anyway. In this case, lim is only used to detect
-;; cpp directives.
-;;
-;; Note that there is a bug in XEmacs's buffer-syntactic-context when used in
-;; conjunction with syntax-table-properties. The bug is present in, e.g.,
-;; XEmacs 21.4.4. It manifested itself thus:
-;;
-;; Starting with an empty AWK Mode buffer, type
-;; /regexp/ {<C-j>
-;; Point gets wrongly left at column 0, rather than being indented to tab-width.
-;;
-;; AWK Mode is designed such that when the first / is typed, it gets the
-;; syntax-table property "string fence". When the second / is typed, BOTH /s
-;; are given the s-t property "string". However, buffer-syntactic-context
-;; fails to take account of the change of the s-t property on the opening / to
-;; "string", and reports that the { is within a string started by the second /.
-;;
-;; The workaround for this is for the AWK Mode initialization to switch the
-;; defalias for c-in-literal to c-slow-in-literal. This will slow down other
-;; cc-modes in XEmacs whenever an awk-buffer has been initialized.
-;;
-;; (Alan Mackenzie, 2003/4/30).
-
-(defun c-fast-in-literal (&optional lim detect-cpp)
- ;; This function might do hidden buffer changes.
- (let ((context (buffer-syntactic-context)))
- (cond
- ((eq context 'string) 'string)
- ((eq context 'comment) 'c++)
- ((eq context 'block-comment) 'c)
- ((and detect-cpp (save-excursion (c-beginning-of-macro lim))) 'pound))))
-
-(defalias 'c-in-literal
- (if (fboundp 'buffer-syntactic-context)
- 'c-fast-in-literal ; XEmacs
- 'c-slow-in-literal)) ; GNU Emacs
-
-;; The defalias above isn't enough to shut up the byte compiler.
-(cc-bytecomp-defun c-in-literal)
+ (save-restriction
+ (widen)
+ (let* ((safe-place (c-state-semi-safe-place (point)))
+ (lit (c-state-pp-to-literal safe-place (point))))
+ (or (cadr lit)
+ (and detect-cpp
+ (save-excursion (c-beginning-of-macro))
+ 'pound)))))
(defun c-literal-limits (&optional lim near not-in-delimiter)
"Return a cons of the beginning and end positions of the comment or
(save-excursion
(let* ((pos (point))
- (lim (or lim (progn
- (c-beginning-of-syntax)
- (point))))
- (state (parse-partial-sexp lim pos)))
-
- (cond ((elt state 3) ; String.
- (goto-char (elt state 8))
- (cons (point) (or (c-safe (c-forward-sexp 1) (point))
- (point-max))))
-
- ((elt state 4) ; Comment.
- (goto-char (elt state 8))
- (cons (point) (progn (c-forward-single-comment) (point))))
-
- ((and (not not-in-delimiter)
- (not (elt state 5))
- (eq (char-before) ?/)
- (looking-at "[/*]"))
- ;; We're standing in a comment starter.
- (backward-char 1)
- (cons (point) (progn (c-forward-single-comment) (point))))
-
- (near
- (goto-char pos)
-
- ;; Search forward for a literal.
- (skip-chars-forward " \t")
+ (lim (or lim (c-state-semi-safe-place pos)))
+ (pp-to-lit (save-restriction
+ (widen)
+ (c-state-pp-to-literal lim pos)))
+ (state (car pp-to-lit))
+ (lit-limits (car (cddr pp-to-lit))))
- (cond
- ((looking-at c-string-limit-regexp) ; String.
- (cons (point) (or (c-safe (c-forward-sexp 1) (point))
- (point-max))))
+ (cond
+ (lit-limits)
+ ((and (not not-in-delimiter)
+ (not (elt state 5))
+ (eq (char-before) ?/)
+ (looking-at "[/*]")) ; FIXME!!! use c-line/block-comment-starter. 2008-09-28.
+ ;; We're standing in a comment starter.
+ (backward-char 1)
+ (cons (point) (progn (c-forward-single-comment) (point))))
+
+ (near
+ (goto-char pos)
+ ;; Search forward for a literal.
+ (skip-chars-forward " \t")
+ (cond
+ ((looking-at c-string-limit-regexp) ; String.
+ (cons (point) (or (c-safe (c-forward-sexp 1) (point))
+ (point-max))))
- ((looking-at c-comment-start-regexp) ; Line or block comment.
- (cons (point) (progn (c-forward-single-comment) (point))))
+ ((looking-at c-comment-start-regexp) ; Line or block comment.
+ (cons (point) (progn (c-forward-single-comment) (point))))
- (t
- ;; Search backward.
- (skip-chars-backward " \t")
+ (t
+ ;; Search backward.
+ (skip-chars-backward " \t")
- (let ((end (point)) beg)
- (cond
- ((save-excursion
- (< (skip-syntax-backward c-string-syntax) 0)) ; String.
- (setq beg (c-safe (c-backward-sexp 1) (point))))
-
- ((and (c-safe (forward-char -2) t)
- (looking-at "*/"))
- ;; Block comment. Due to the nature of line
- ;; comments, they will always be covered by the
- ;; normal case above.
- (goto-char end)
- (c-backward-single-comment)
- ;; If LIM is bogus, beg will be bogus.
- (setq beg (point))))
-
- (if beg (cons beg end))))))
- ))))
+ (let ((end (point)) beg)
+ (cond
+ ((save-excursion
+ (< (skip-syntax-backward c-string-syntax) 0)) ; String.
+ (setq beg (c-safe (c-backward-sexp 1) (point))))
+
+ ((and (c-safe (forward-char -2) t)
+ (looking-at "*/"))
+ ;; Block comment. Due to the nature of line
+ ;; comments, they will always be covered by the
+ ;; normal case above.
+ (goto-char end)
+ (c-backward-single-comment)
+ ;; If LIM is bogus, beg will be bogus.
+ (setq beg (point))))
+
+ (if beg (cons beg end))))))
+ ))))
;; In case external callers use this; it did have a docstring.
(defalias 'c-literal-limits-fast 'c-literal-limits)
(t 'c))) ; Assuming the range is valid.
range))
+(defsubst c-determine-limit-get-base (start try-size)
+ ;; Get a "safe place" approximately TRY-SIZE characters before START.
+ ;; This doesn't preserve point.
+ (let* ((pos (max (- start try-size) (point-min)))
+ (base (c-state-semi-safe-place pos))
+ (s (parse-partial-sexp base pos)))
+ (if (or (nth 4 s) (nth 3 s)) ; comment or string
+ (nth 8 s)
+ (point))))
+
+(defun c-determine-limit (how-far-back &optional start try-size)
+ ;; Return a buffer position HOW-FAR-BACK non-literal characters from START
+ ;; (default point). This is done by going back further in the buffer then
+ ;; searching forward for literals. The position found won't be in a
+ ;; literal. We start searching for the sought position TRY-SIZE (default
+ ;; twice HOW-FAR-BACK) bytes back from START. This function must be fast.
+ ;; :-)
+ (save-excursion
+ (let* ((start (or start (point)))
+ (try-size (or try-size (* 2 how-far-back)))
+ (base (c-determine-limit-get-base start try-size))
+ (pos base)
+
+ (s (parse-partial-sexp pos pos)) ; null state.
+ stack elt size
+ (count 0))
+ (while (< pos start)
+ ;; Move forward one literal each time round this loop.
+ ;; Move forward to the start of a comment or string.
+ (setq s (parse-partial-sexp
+ pos
+ start
+ nil ; target-depth
+ nil ; stop-before
+ s ; state
+ 'syntax-table)) ; stop-comment
+
+ ;; Gather details of the non-literal-bit - starting pos and size.
+ (setq size (- (if (or (nth 4 s) (nth 3 s))
+ (nth 8 s)
+ (point))
+ pos))
+ (if (> size 0)
+ (setq stack (cons (cons pos size) stack)))
+
+ ;; Move forward to the end of the comment/string.
+ (if (or (nth 4 s) (nth 3 s))
+ (setq s (parse-partial-sexp
+ (point)
+ start
+ nil ; target-depth
+ nil ; stop-before
+ s ; state
+ 'syntax-table))) ; stop-comment
+ (setq pos (point)))
+
+ ;; Now try and find enough non-literal characters recorded on the stack.
+ ;; Go back one recorded literal each time round this loop.
+ (while (and (< count how-far-back)
+ stack)
+ (setq elt (car stack)
+ stack (cdr stack))
+ (setq count (+ count (cdr elt))))
+
+ ;; Have we found enough yet?
+ (cond
+ ((>= count how-far-back)
+ (+ (car elt) (- count how-far-back)))
+ ((eq base (point-min))
+ (point-min))
+ (t
+ (c-determine-limit (- how-far-back count) base try-size))))))
+
+(defun c-determine-+ve-limit (how-far &optional start-pos)
+ ;; Return a buffer position about HOW-FAR non-literal characters forward
+ ;; from START-POS (default point), which must not be inside a literal.
+ (save-excursion
+ (let ((pos (or start-pos (point)))
+ (count how-far)
+ (s (parse-partial-sexp (point) (point)))) ; null state
+ (while (and (not (eobp))
+ (> count 0))
+ ;; Scan over counted characters.
+ (setq s (parse-partial-sexp
+ pos
+ (min (+ pos count) (point-max))
+ nil ; target-depth
+ nil ; stop-before
+ s ; state
+ 'syntax-table)) ; stop-comment
+ (setq count (- count (- (point) pos) 1)
+ pos (point))
+ ;; Scan over literal characters.
+ (if (nth 8 s)
+ (setq s (parse-partial-sexp
+ pos
+ (point-max)
+ nil ; target-depth
+ nil ; stop-before
+ s ; state
+ 'syntax-table) ; stop-comment
+ pos (point))))
+ (point))))
+
\f
;; `c-find-decl-spots' and accompanying stuff.
;; Call CFD-FUN for each possible spot for a declaration, cast or
;; label from the point to CFD-LIMIT.
;;
- ;; CFD-FUN is called with point at the start of the spot. It's
- ;; passed two arguments: The first is the end position of the token
- ;; preceding the spot, or 0 for the implicit match at bob. The
- ;; second is a flag that is t when the match is inside a macro. If
- ;; CFD-FUN adds `c-decl-end' properties somewhere below the current
- ;; spot, it should return non-nil to ensure that the next search
- ;; will find them.
+ ;; CFD-FUN is called with point at the start of the spot. It's passed two
+ ;; arguments: The first is the end position of the token preceding the spot,
+ ;; or 0 for the implicit match at bob. The second is a flag that is t when
+ ;; the match is inside a macro. Point should be moved forward by at least
+ ;; one token.
+ ;;
+ ;; If CFD-FUN adds `c-decl-end' properties somewhere below the current spot,
+ ;; it should return non-nil to ensure that the next search will find them.
;;
;; Such a spot is:
;; o The first token after bob.
(goto-char cfd-continue-pos)
(if (= cfd-continue-pos cfd-limit)
(setq cfd-match-pos cfd-limit)
- (c-find-decl-prefix-search)))))
+ (c-find-decl-prefix-search))))) ; Moves point, sets cfd-continue-pos,
+ ; cfd-match-pos, etc.
\f
;; A cache for found types.
new-beg new-end need-new-beg need-new-end)
;; Locate the barrier before the changed region
(goto-char (if beg-lit-limits (car beg-lit-limits) beg))
- (c-syntactic-skip-backward "^;{}" (max (- beg 2048) (point-min)))
+ (c-syntactic-skip-backward "^;{}" (c-determine-limit 512))
(setq new-beg (point))
;; Remove the syntax-table properties from each pertinent <...> pair.
;; Locate the barrier after END.
(goto-char (if end-lit-limits (cdr end-lit-limits) end))
- (c-syntactic-re-search-forward "[;{}]"
- (min (+ end 2048) (point-max)) 'end)
+ (c-syntactic-re-search-forward "[;{}]" (c-determine-+ve-limit 512) 'end)
(setq new-end (point))
;; Remove syntax-table properties from the remaining pertinent <...>
(when (c-keyword-member kwd-sym 'c-typeless-decl-kwds)
(setq maybe-typeless t))
- ;; Haven't matched a type so it's an umambiguous
+ ;; Haven't matched a type so it's an unambiguous
;; specifier keyword and we know we're in a
;; declaration.
(setq at-decl-or-cast t)
got-suffix-after-parens
(eq (char-after got-suffix-after-parens) ?\())
;; Got a type, no declarator but a paren suffix. I.e. it's a
- ;; normal function call afterall (or perhaps a C++ style object
+ ;; normal function call after all (or perhaps a C++ style object
;; instantiation expression).
(throw 'at-decl-or-cast nil))))
(let ((start (point))
start-char
(c-promote-possible-types t)
+ lim
;; Turn off recognition of angle bracket arglists while parsing
;; types here since the protocol reference list might then be
;; considered part of the preceding name or superclass-name.
; (c-forward-token-2) ; 2006/1/13 This doesn't move if the token's
; at EOB.
(goto-char (match-end 0))
+ (setq lim (point))
(c-skip-ws-forward)
(c-forward-type))
t))))
(progn
- (c-backward-syntactic-ws)
+ (c-backward-syntactic-ws lim)
(c-clear-c-type-property start (1- (point)) 'c-decl-end)
(c-put-c-type-property (1- (point)) 'c-decl-end)
t)
(and
(eq (c-beginning-of-statement-1 lim) 'same)
- (not (or (c-major-mode-is 'objc-mode)
- (c-forward-objc-directive)))
+ (not (and (c-major-mode-is 'objc-mode)
+ (c-forward-objc-directive)))
(setq id-start
(car-safe (c-forward-decl-or-cast-1 (c-point 'bosws) nil nil)))
(save-restriction
;; If we're in a macro, our search range is restricted to it. Narrow to
;; the searchable range.
- (let* ((macro-start (c-query-macro-start))
- (lim (max (or lim (point-min)) (or macro-start (point-min))))
+ (let* ((macro-start (save-excursion (and (c-beginning-of-macro) (point))))
+ (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
- (narrow-to-region lim (c-point 'eol))
+ (pp-count-out 20)) ; Max number of paren/brace constructs before
+ ; we give up
+ (narrow-to-region low-lim (or macro-end (point-max)))
;; Search backwards for the defun's argument list. We give up if we
- ;; encounter a "}" (end of a previous defun) or BOB.
+ ;; encounter a "}" (end of a previous defun) an "=" (which can't be in
+ ;; a knr region) or BOB.
;;
;; The criterion for a paren structure being the arg list is:
;; o - there is non-WS stuff after it but before any "{"; AND
(catch 'knr
(while (> pp-count-out 0) ; go back one paren/bracket pair each time.
(setq pp-count-out (1- pp-count-out))
- (c-syntactic-skip-backward "^)]}")
+ (c-syntactic-skip-backward "^)]}=")
(cond ((eq (char-before) ?\))
(setq after-rparen (point)))
((eq (char-before) ?\])
(setq after-rparen nil))
- (t ; either } (hit previous defun) or no more parens/brackets
+ (t ; either } (hit previous defun) or = or no more
+ ; parens/brackets.
(throw 'knr nil)))
(if after-rparen
;; It can't be the arg list if next token is ; or {
(progn (goto-char after-rparen)
(c-forward-syntactic-ws)
- (not (memq (char-after) '(?\; ?\{))))
+ (not (memq (char-after) '(?\; ?\{ ?\=))))
;; Is the thing preceding the list an identifier (the
;; function name), or a macro expansion?
(progn
(goto-char before-lparen)
(eq (c-backward-token-2) 0)
- (or (c-on-identifier)
+ (or (eq (c-on-identifier) (point))
(and (eq (char-after) ?\))
(c-go-up-list-backward)
(eq (c-backward-token-2) 0)
- (c-on-identifier))))
+ (eq (c-on-identifier) (point)))))
;; Have we got a non-empty list of comma-separated
;; identifiers?
next-open-brace (c-pull-open-brace paren-state)))
open-brace))
+(defun c-cheap-inside-bracelist-p (paren-state)
+ ;; Return the position of the L-brace if point is inside a brace list
+ ;; initialization of an array, etc. This is an approximate function,
+ ;; designed for speed over accuracy. It will not find every bracelist, but
+ ;; a non-nil result is reliable. We simply search for "= {" (naturally with
+ ;; syntactic whitespace allowed). PAREN-STATE is the normal thing that it
+ ;; is everywhere else.
+ (let (b-pos)
+ (save-excursion
+ (while
+ (and (setq b-pos (c-pull-open-brace paren-state))
+ (progn (goto-char b-pos)
+ (c-backward-sws)
+ (c-backward-token-2)
+ (not (looking-at "=")))))
+ b-pos)))
+
(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.
(setq pos (point)))
(and
c-macro-with-semi-re
- (not (c-in-literal))
(eq (skip-chars-backward " \t") 0)
;; Check we've got nothing after this except comments and empty lines
(c-backward-syntactic-ws)
t))
(c-simple-skip-symbol-backward)
- (looking-at c-macro-with-semi-re)))))
+ (looking-at c-macro-with-semi-re)
+ (goto-char pos)
+ (not (c-in-literal)))))) ; The most expensive check last.
(defun c-macro-vsemi-status-unknown-p () t) ; See cc-defs.el.
containing-sexp nil)))
(setq lim (1+ containing-sexp))))
(setq lim (point-min)))
+ (when (c-beginning-of-macro)
+ (goto-char indent-point)
+ (let ((lim1 (c-determine-limit 2000)))
+ (setq lim (max lim lim1))))
;; If we're in a parenthesis list then ',' delimits the
;; "statements" rather than being an operator (with the
'label))
(if (eq step 'up)
(setq placeholder (point))
- ;; There was no containing statement afterall.
+ ;; There was no containing statement after all.
(goto-char placeholder)))))
placeholder))
(if (looking-at c-block-stmt-2-key)
(setq tmpsymbol nil)
(while (and (> (point) placeholder)
(zerop (c-backward-token-2 1 t))
- (/= (char-after) ?=))
+ (not (looking-at "=\\([^=]\\|$\\)")))
(and c-opt-inexpr-brace-list-key
(not tmpsymbol)
(looking-at c-opt-inexpr-brace-list-key)
(setq tmpsymbol 'topmost-intro-cont)))
- (eq (char-after) ?=))
+ (looking-at "=\\([^=]\\|$\\)"))
(looking-at c-brace-list-key))
(save-excursion
(while (and (< (point) indent-point)
;; CASE 5B: After a function header but before the body (or
;; the ending semicolon if there's no body).
((save-excursion
- (when (setq placeholder (c-just-after-func-arglist-p lim))
+ (when (setq placeholder (c-just-after-func-arglist-p
+ (max lim (c-determine-limit 500))))
(setq tmp-pos (point))))
(cond
;; CASE 5B.1: Member init list.
((eq (char-after tmp-pos) ?:)
- (if (or (> tmp-pos indent-point)
+ (if (or (>= tmp-pos indent-point)
(= (c-point 'bosws) (1+ tmp-pos)))
(progn
;; There is no preceding member init clause.
;; top level construct. Or, perhaps, an unrecognized construct.
(t
(while (and (setq placeholder (point))
- (eq (car (c-beginning-of-decl-1 containing-sexp))
+ (eq (car (c-beginning-of-decl-1 containing-sexp)) ; Can't use `lim' here.
'same)
(save-excursion
(c-backward-syntactic-ws)
(eq (cdar c-state-cache) (point)))
;; Speed up the backward search a bit.
(goto-char (caar c-state-cache)))
- (c-beginning-of-decl-1 containing-sexp)
+ (c-beginning-of-decl-1 containing-sexp) ; Can't use `lim' here.
(setq placeholder (point))
(if (= start (point))
;; The '}' is unbalanced.
(c-beginning-of-statement-1 containing-sexp)
(c-add-stmt-syntax 'statement nil t containing-sexp paren-state))
- ;;CASE 5N: We are at a tompmost continuation line and the only
+ ;;CASE 5N: We are at a topmost continuation line and the only
;;preceding items are annotations.
((and (c-major-mode-is 'java-mode)
(setq placeholder (point))