summaryrefslogtreecommitdiff
path: root/lisp/progmodes/cc-engine.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/cc-engine.el')
-rw-r--r--lisp/progmodes/cc-engine.el545
1 files changed, 443 insertions, 102 deletions
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 0865ddfed69..10355451480 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -1,6 +1,6 @@
;;; 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-2012 Free Software Foundation, Inc.
;; Authors: 2001- Alan Mackenzie
;; 1998- Martin Stjernholm
@@ -219,6 +219,38 @@
(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,
@@ -226,19 +258,36 @@ otherwise return nil and leave point unchanged.
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.
@@ -248,12 +297,24 @@ done that the point is inside a cpp directive to begin with.
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.
@@ -268,12 +329,15 @@ comment at the start of cc-engine.el for more info."
;; 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 ()
@@ -1182,7 +1246,7 @@ comment at the start of cc-engine.el for more info."
(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)
@@ -1624,6 +1688,7 @@ comment at the start of cc-engine.el for more info."
;; high as possible.
(setq rung-pos (point)))
+ (with-silent-modifications
(while
(progn
(while
@@ -1779,7 +1844,7 @@ comment at the start of cc-engine.el for more info."
(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.
@@ -1817,6 +1882,7 @@ comment at the start of cc-engine.el for more info."
(goto-char (setq rung-pos rung-is-marked))
(goto-char simple-ws-beg))
+ (with-silent-modifications
(while
(progn
(while
@@ -2002,7 +2068,7 @@ comment at the start of cc-engine.el for more info."
last-put-in-sws-pos)
(c-remove-is-and-in-sws last-put-in-sws-pos
(1+ last-put-in-sws-pos)))))
- )))
+ ))))
;; Other whitespace tools
@@ -2074,7 +2140,7 @@ comment at the start of cc-engine.el for more info."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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)
@@ -2089,6 +2155,18 @@ comment at the start of cc-engine.el for more info."
;; 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 either
;; (STATE TYPE (BEG . END)) if TO is in a literal; or
@@ -2129,38 +2207,100 @@ comment at the start of cc-engine.el for more info."
(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 (car (cddr (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))
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 rigourously
+ ;; 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
@@ -2421,8 +2561,11 @@ comment at the start of cc-engine.el for more info."
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
@@ -2474,13 +2617,24 @@ comment at the start of cc-engine.el for more info."
(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.
@@ -2498,11 +2652,29 @@ comment at the start of cc-engine.el for more info."
;; 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
@@ -2536,7 +2708,7 @@ comment at the start of cc-engine.el for more info."
(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)
@@ -2594,7 +2766,7 @@ comment at the start of cc-engine.el for more info."
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.
@@ -2925,6 +3097,8 @@ comment at the start of cc-engine.el for more info."
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
@@ -2968,9 +3142,11 @@ comment at the start of cc-engine.el for more info."
;;
;; 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
@@ -3110,8 +3286,7 @@ comment at the start of cc-engine.el for more info."
(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
@@ -3173,23 +3348,32 @@ comment at the start of cc-engine.el for more info."
(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 "
@@ -3199,6 +3383,16 @@ comment at the start of cc-engine.el for more info."
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)
@@ -3231,8 +3425,16 @@ comment at the start of cc-engine.el for more info."
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")
@@ -3240,7 +3442,9 @@ comment at the start of cc-engine.el for more info."
(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))
@@ -4211,12 +4415,14 @@ The last point calculated is cached if the cache is enabled, i.e. if
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
- (let* ((safe-place (c-state-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))))
+ (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
@@ -4235,10 +4441,11 @@ comment at the start of cc-engine.el for more info."
(save-excursion
(let* ((pos (point))
- (lim (or lim (c-state-safe-place pos)))
- (pp-to-lit (c-state-pp-to-literal lim pos))
+ (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-type (cadr pp-to-lit))
(lit-limits (car (cddr pp-to-lit))))
(cond
@@ -4348,6 +4555,110 @@ comment at the start of cc-engine.el for more info."
(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))))
+
;; `c-find-decl-spots' and accompanying stuff.
@@ -4484,13 +4795,14 @@ comment at the start of cc-engine.el for more info."
;; 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.
@@ -4864,7 +5176,8 @@ comment at the start of cc-engine.el for more info."
(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.
;; A cache for found types.
@@ -5134,7 +5447,7 @@ comment at the start of cc-engine.el for more info."
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.
@@ -5145,8 +5458,7 @@ comment at the start of cc-engine.el for more info."
;; 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 <...>
@@ -7303,6 +7615,7 @@ comment at the start of cc-engine.el for more info."
(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.
@@ -7330,6 +7643,7 @@ comment at the start of cc-engine.el for more info."
; (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))
@@ -7354,7 +7668,7 @@ comment at the start of cc-engine.el for more info."
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)
@@ -7451,8 +7765,8 @@ comment at the start of cc-engine.el for more info."
(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)))
@@ -7497,14 +7811,17 @@ comment at the start of cc-engine.el for more info."
(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
@@ -7524,12 +7841,13 @@ comment at the start of cc-engine.el for more info."
(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
@@ -7545,18 +7863,18 @@ comment at the start of cc-engine.el for more info."
;; 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?
@@ -8044,6 +8362,23 @@ comment at the start of cc-engine.el for more info."
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.
@@ -8395,7 +8730,6 @@ comment at the start of cc-engine.el for more info."
(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
@@ -8426,7 +8760,9 @@ comment at the start of cc-engine.el for more info."
(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.
@@ -8967,6 +9303,10 @@ comment at the start of cc-engine.el for more info."
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
@@ -9276,12 +9616,12 @@ comment at the start of cc-engine.el for more info."
(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)
@@ -9331,13 +9671,14 @@ comment at the start of cc-engine.el for more info."
;; 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.
@@ -9539,7 +9880,7 @@ comment at the start of cc-engine.el for more info."
;; 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)
@@ -9642,7 +9983,7 @@ comment at the start of cc-engine.el for more info."
(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.