+(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
+ ;; there's a macro, HERE- and HERE+ are the same. Like this:
+ ;;
+ ;; ............................................
+ ;; | |
+ ;; ( [ ( .........#macro.. ) ( ) ] )
+ ;; ^ ^ ^ ^
+ ;; | | | |
+ ;; return HERE- HERE+ TOP
+ ;;
+ ;; If there aren't enough opening paren/brace/brackets, return the position
+ ;; of the outermost one found, or HERE- if there are none. If there are no
+ ;; closeing p/b/bs between HERE+ and TOP, return HERE-. HERE-/+ and TOP
+ ;; must not be inside literals. Only the accessible portion of the buffer
+ ;; will be scanned.
+
+ ;; PART 1: scan from `here+' up to `top', accumulating ")"s which enclose
+ ;; `here'. Go round the next loop each time we pass over such a ")". These
+ ;; probably match "("s before `here-'.
+ (let (pos pa ren+1 lonely-rens)
+ (save-excursion
+ (save-restriction
+ (narrow-to-region (point-min) top) ; This can move point, sometimes.
+ (setq pos here+)
+ (c-safe
+ (while
+ (setq ren+1 (scan-lists pos 1 1)) ; might signal
+ (setq lonely-rens (cons ren+1 lonely-rens)
+ pos ren+1)))))
+
+ ;; PART 2: Scan back before `here-' searching for the "("s
+ ;; matching/mismatching the ")"s found above. We only need to direct the
+ ;; caller to scan when we've encountered unmatched right parens.
+ (setq pos here-)
+ (when lonely-rens
+ (c-safe
+ (while
+ (and lonely-rens ; actual values aren't used.
+ (setq pa (scan-lists pos -1 1)))
+ (setq pos pa)
+ (setq lonely-rens (cdr lonely-rens)))))
+ pos))
+
+(defun c-parse-state-get-strategy (here good-pos)
+ ;; Determine the scanning strategy for adjusting `c-parse-state', attempting
+ ;; to minimise the amount of scanning. HERE is the pertinent position in
+ ;; the buffer, GOOD-POS is a position where `c-state-cache' (possibly with
+ ;; its head trimmed) is known to be good, or nil if there is no such
+ ;; position.
+ ;;
+ ;; The return value is a list, one of the following:
+ ;;
+ ;; o - ('forward CACHE-POS START-POINT) - scan forward from START-POINT,
+ ;; which is not less than CACHE-POS.
+ ;; o - ('backward CACHE-POS nil) - scan backwards (from HERE).
+ ;; o - ('BOD nil START-POINT) - scan forwards from START-POINT, which is at the
+ ;; top level.
+ ;; o - ('IN-LIT nil nil) - point is inside the literal containing point-min.
+ ;; , where CACHE-POS is the highest position recorded in `c-state-cache' at
+ ;; or below HERE.
+ (let ((cache-pos (c-get-cache-scan-pos here)) ; highest position below HERE in cache (or 1)
+ 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
+ start-point nil
+ cache-pos nil
+ how-far 0))
+ ((<= good-pos here)
+ (setq strategy 'forward
+ 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
+ how-far (- good-pos here)))
+ (t
+ (setq strategy 'forward
+ how-far (- here cache-pos)
+ 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)
+ (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
+ (and (memq strategy '(forward backward)) cache-pos)
+ (and (memq strategy '(forward BOD)) start-point))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Routines which change `c-state-cache' and associated values.
+(defun c-renarrow-state-cache ()
+ ;; The region (more precisely, point-min) has changed since we
+ ;; calculated `c-state-cache'. Amend `c-state-cache' accordingly.
+ (if (< (point-min) c-state-point-min)
+ ;; If point-min has MOVED BACKWARDS then we drop the state completely.
+ ;; It would be possible to do a better job here and recalculate the top
+ ;; only.
+ (progn
+ (c-state-mark-point-min-literal)
+ (setq c-state-cache nil
+ c-state-cache-good-pos c-state-min-scan-pos
+ c-state-brace-pair-desert nil))
+
+ ;; point-min has MOVED FORWARD.
+
+ ;; Is the new point-min inside a (different) literal?
+ (unless (and c-state-point-min-lit-start ; at prev. point-min
+ (< (point-min) (c-state-get-min-scan-pos)))
+ (c-state-mark-point-min-literal))
+
+ ;; Cut off a bit of the tail from `c-state-cache'.
+ (let ((ptr (cons nil c-state-cache))
+ pa)
+ (while (and (setq pa (c-state-cache-top-lparen (cdr ptr)))
+ (>= pa (point-min)))
+ (setq ptr (cdr ptr)))
+
+ (when (consp ptr)
+ (if (eq (cdr ptr) c-state-cache)
+ (setq c-state-cache nil
+ c-state-cache-good-pos c-state-min-scan-pos)
+ (setcdr ptr nil)
+ (setq c-state-cache-good-pos (1+ (c-state-cache-top-lparen))))
+ )))
+
+ (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.
+ ;;
+ ;; Return non-nil when this has been done.
+ ;;
+ ;; 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.
+ (save-excursion
+ (save-restriction
+ (let ((bra from) ce ; Positions of "{" and "}".
+ new-cons
+ (cache-pos (c-state-cache-top-lparen)) ; might be nil.
+ (macro-start-or-from
+ (progn (goto-char from)
+ (c-beginning-of-macro)
+ (point))))
+ (or upper-lim (setq upper-lim from))
+
+ ;; 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))
+ (<= 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)))
+ (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
+ ;; pair of (mis-)matching parens or brackets; the outer one moves
+ ;; back over a sequence of unmatched close brace/paren/bracket each
+ ;; time round.
+ (while
+ (progn
+ (c-safe
+ (while
+ (and (setq ce (scan-lists bra -1 -1)) ; back past )/]/}; might signal
+ (setq bra (scan-lists ce -1 1)) ; back past (/[/{; might signal
+ (or (> ce upper-lim)
+ (not (eq (char-after bra) ?\{))
+ (and (goto-char bra)
+ (c-beginning-of-macro)
+ (< (point) macro-start-or-from))))))
+ (and ce (< ce bra)))
+ (setq bra ce)) ; If we just backed over an unbalanced closing
+ ; brace, ignore it.
+
+ (if (and ce (< bra ce) (eq (char-after bra) ?\{))
+ ;; We've found the desired brace-pair.
+ (progn
+ (setq new-cons (cons bra (1+ ce)))
+ (cond
+ ((consp (car c-state-cache))
+ (setcar c-state-cache new-cons))
+ ((and (numberp (car c-state-cache)) ; probably never happens
+ (< ce (car c-state-cache)))
+ (setcdr c-state-cache
+ (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.
+ (setq c-state-brace-pair-desert (cons cache-pos from))))))))
+
+(defsubst c-state-push-any-brace-pair (bra+1 macro-start-or-here)
+ ;; If BRA+1 is nil, do nothing. Otherwise, BRA+1 is the buffer position
+ ;; following a {, and that brace has a (mis-)matching } (or ]), and we
+ ;; "push" "a" brace pair onto `c-state-cache'.
+ ;;
+ ;; Here "push" means overwrite the top element if it's itself a brace-pair,
+ ;; otherwise push it normally.
+ ;;
+ ;; The brace pair we push is normally the one surrounding BRA+1, but if the
+ ;; latter is inside a macro, not being a macro containing
+ ;; MACRO-START-OR-HERE, we scan backwards through the buffer for a non-macro
+ ;; base pair. This latter case is assumed to be rare.
+ ;;
+ ;; Note: POINT is not preserved in this routine.
+ (if bra+1
+ (if (or (> bra+1 macro-start-or-here)
+ (progn (goto-char bra+1)
+ (not (c-beginning-of-macro))))
+ (setq c-state-cache
+ (cons (cons (1- bra+1)
+ (scan-lists bra+1 1 1))
+ (if (consp (car c-state-cache))
+ (cdr c-state-cache)
+ c-state-cache)))
+ ;; N.B. This defsubst codes one method for the simple, normal case,
+ ;; and a more sophisticated, slower way for the general case. Don't
+ ;; eliminate this defsubst - it's a speed optimisation.
+ (c-append-lower-brace-pair-to-state-cache (1- bra+1)))))
+
+(defun c-append-to-state-cache (from)
+ ;; Scan the buffer from FROM to (point-max), adding elements into
+ ;; `c-state-cache' for braces etc. Return a candidate for
+ ;; `c-state-cache-good-pos'.
+ ;;
+ ;; FROM must be after the latest brace/paren/bracket in `c-state-cache', if
+ ;; any. Typically, it is immediately after it. It must not be inside a
+ ;; literal.
+ (let ((here-bol (c-point 'bol (point-max)))
+ (macro-start-or-here
+ (save-excursion (goto-char (point-max))
+ (if (c-beginning-of-macro)
+ (point)
+ (point-max))))
+ pa+1 ; pos just after an opening PAren (or brace).
+ (ren+1 from) ; usually a pos just after an closing paREN etc.
+ ; Is actually the pos. to scan for a (/{/[ from,
+ ; which sometimes is after a silly )/}/].
+ paren+1 ; Pos after some opening or closing paren.
+ paren+1s ; A list of `paren+1's; used to determine a
+ ; good-pos.
+ bra+1 ce+1 ; just after L/R bra-ces.
+ bra+1s ; list of OLD values of bra+1.
+ mstart) ; start of a macro.
+
+ (save-excursion
+ ;; Each time round the following loop, we enter a succesively 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.
+ (while
+ (progn
+ ;; Each time round the next loop moves forward over an opening then
+ ;; a closing brace/bracket/paren. This loop is white hot, so it
+ ;; plays ugly tricks to go fast. DON'T PUT ANYTHING INTO THIS
+ ;; LOOP WHICH ISN'T ABSOLUTELY NECESSARY!!! It terminates when a
+ ;; call of `scan-lists' signals an error, which happens when there
+ ;; are no more b/b/p's to scan.
+ (c-safe
+ (while t
+ (setq pa+1 (scan-lists ren+1 1 -1) ; Into (/{/[; might signal
+ paren+1s (cons pa+1 paren+1s))
+ (setq ren+1 (scan-lists pa+1 1 1)) ; Out of )/}/]; might signal
+ (if (and (eq (char-before pa+1) ?{)) ; Check for a macro later.
+ (setq bra+1 pa+1))
+ (setcar paren+1s ren+1)))
+
+ (if (and pa+1 (> pa+1 ren+1))
+ ;; We've just entered a deeper nesting level.
+ (progn
+ ;; Insert the brace pair (if present) and the single open
+ ;; paren/brace/bracket into `c-state-cache' It cannot be
+ ;; inside a macro, except one around point, because of what
+ ;; `c-neutralize-syntax-in-CPP' has done.
+ (c-state-push-any-brace-pair bra+1 macro-start-or-here)
+ ;; Insert the opening brace/bracket/paren position.
+ (setq c-state-cache (cons (1- pa+1) c-state-cache))
+ ;; Clear admin stuff for the next more nested part of the scan.
+ (setq ren+1 pa+1 pa+1 nil bra+1 nil bra+1s nil)
+ t) ; Carry on the loop
+
+ ;; All open p/b/b's at this nesting level, if any, have probably
+ ;; been closed by matching/mismatching ones. We're probably
+ ;; finished - we just need to check for having found an
+ ;; unmatched )/}/], which we ignore. Such a )/}/] can't be in a
+ ;; macro, due the action of `c-neutralize-syntax-in-CPP'.
+ (c-safe (setq ren+1 (scan-lists ren+1 1 1)))))) ; acts as loop control.
+
+ ;; Record the final, innermost, brace-pair if there is one.
+ (c-state-push-any-brace-pair bra+1 macro-start-or-here)
+
+ ;; Determine a good pos
+ (while (and (setq paren+1 (car paren+1s))
+ (> (if (> paren+1 macro-start-or-here)
+ paren+1
+ (goto-char paren+1)
+ (setq mstart (and (c-beginning-of-macro)
+ (point)))
+ (or mstart paren+1))
+ here-bol))
+ (setq paren+1s (cdr paren+1s)))
+ (cond
+ ((and paren+1 mstart)
+ (min paren+1 mstart))
+ (paren+1)
+ (t from)))))
+
+(defun c-remove-stale-state-cache (good-pos pps-point)
+ ;; Remove stale entries from the `c-cache-state', i.e. those which will
+ ;; not be in it when it is amended for position (point-max).
+ ;; Additionally, the "outermost" open-brace entry before (point-max)
+ ;; will be converted to a cons if the matching close-brace is scanned.
+ ;;
+ ;; GOOD-POS is a "maximal" "safe position" - there must be no open
+ ;; parens/braces/brackets between GOOD-POS and (point-max).
+ ;;
+ ;; As a second thing, calculate the result of parse-partial-sexp at
+ ;; PPS-POINT, w.r.t. GOOD-POS. The motivation here is that
+ ;; `c-state-cache-good-pos' may become PPS-POINT, but the caller may need to
+ ;; adjust it to get outside a string/comment. (Sorry about this! The code
+ ;; needs to be FAST).
+ ;;
+ ;; Return a list (GOOD-POS SCAN-BACK-POS PPS-STATE), where
+ ;; o - GOOD-POS is a position where the new value `c-state-cache' is known
+ ;; to be good (we aim for this to be as high as possible);
+ ;; o - SCAN-BACK-POS, if not nil, indicates there may be a brace pair
+ ;; preceding POS which needs to be recorded in `c-state-cache'. It is a
+ ;; position to scan backwards from.
+ ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
+ (save-restriction
+ (narrow-to-region 1 (point-max))
+ (save-excursion
+ (let* ((in-macro-start ; start of macro containing (point-max) or nil.
+ (save-excursion
+ (goto-char (point-max))
+ (and (c-beginning-of-macro)
+ (point))))
+ (good-pos-actual-macro-start ; Start of macro containing good-pos
+ ; or nil
+ (and (< good-pos (point-max))
+ (save-excursion
+ (goto-char good-pos)
+ (and (c-beginning-of-macro)
+ (point)))))
+ (good-pos-actual-macro-end ; End of this macro, (maybe
+ ; (point-max)), or nil.
+ (and good-pos-actual-macro-start
+ (save-excursion
+ (goto-char good-pos-actual-macro-start)
+ (c-end-of-macro)
+ (point))))
+ pps-state ; Will be 9 or 10 elements long.
+ pos
+ upper-lim ; ,beyond which `c-state-cache' entries are removed
+ scan-back-pos
+ pair-beg pps-point-state target-depth)
+
+ ;; Remove entries beyond (point-max). Also remove any entries inside
+ ;; a macro, unless (point-max) is in the same macro.
+ (setq upper-lim
+ (if (or (null c-state-old-cpp-beg)
+ (and (> (point-max) c-state-old-cpp-beg)
+ (< (point-max) c-state-old-cpp-end)))
+ (point-max)
+ (min (point-max) c-state-old-cpp-beg)))
+ (while (and c-state-cache (>= (c-state-cache-top-lparen) upper-lim))
+ (setq c-state-cache (cdr c-state-cache)))
+ ;; If `upper-lim' is inside the last recorded brace pair, remove its
+ ;; RBrace and indicate we'll need to search backwards for a previous
+ ;; brace pair.
+ (when (and c-state-cache
+ (consp (car c-state-cache))
+ (> (cdar c-state-cache) upper-lim))
+ (setcar c-state-cache (caar c-state-cache))
+ (setq scan-back-pos (car c-state-cache)))
+
+ ;; The next loop jumps forward out of a nested level of parens each
+ ;; time round; the corresponding elements in `c-state-cache' are
+ ;; removed. `pos' is just after the brace-pair or the open paren at
+ ;; (car c-state-cache). There can be no open parens/braces/brackets
+ ;; between `good-pos'/`good-pos-actual-macro-start' and (point-max),
+ ;; due to the interface spec to this function.
+ (setq pos (if (and good-pos-actual-macro-end
+ (not (eq good-pos-actual-macro-start
+ in-macro-start)))
+ (1+ good-pos-actual-macro-end) ; get outside the macro as
+ ; marked by a `category' text property.
+ good-pos))
+ (goto-char pos)
+ (while (and c-state-cache
+ (< (point) (point-max)))
+ (cond
+ ((null pps-state) ; first time through
+ (setq target-depth -1))
+ ((eq (car pps-state) target-depth) ; found closing ),},]
+ (setq target-depth (1- (car pps-state))))
+ ;; Do nothing when we've merely reached pps-point.
+ )
+
+ ;; Scan!
+ (setq pps-state
+ (parse-partial-sexp
+ (point) (if (< (point) pps-point) pps-point (point-max))
+ target-depth
+ nil pps-state))
+
+ (if (= (point) pps-point)
+ (setq pps-point-state pps-state))
+
+ (when (eq (car pps-state) target-depth)
+ (setq pos (point)) ; POS is now just after an R-paren/brace.
+ (cond
+ ((and (consp (car c-state-cache))
+ (eq (point) (cdar c-state-cache)))
+ ;; We've just moved out of the paren pair containing the brace-pair
+ ;; at (car c-state-cache). `pair-beg' is where the open paren is,
+ ;; and is potentially where the open brace of a cons in
+ ;; c-state-cache will be.
+ (setq pair-beg (car-safe (cdr c-state-cache))
+ c-state-cache (cdr-safe (cdr c-state-cache)))) ; remove {}pair + containing Lparen.
+ ((numberp (car c-state-cache))
+ (setq pair-beg (car c-state-cache)
+ c-state-cache (cdr c-state-cache))) ; remove this
+ ; containing Lparen
+ ((numberp (cadr c-state-cache))
+ (setq pair-beg (cadr c-state-cache)
+ c-state-cache (cddr c-state-cache))) ; Remove a paren pair
+ ; together with enclosed brace pair.
+ ;; (t nil) ; Ignore an unmated Rparen.
+ )))
+
+ (if (< (point) pps-point)
+ (setq pps-state (parse-partial-sexp (point) pps-point
+ nil nil ; TARGETDEPTH, STOPBEFORE
+ pps-state)))
+
+ ;; If the last paren pair we moved out of was actually a brace pair,
+ ;; insert it into `c-state-cache'.
+ (when (and pair-beg (eq (char-after pair-beg) ?{))
+ (if (consp (car-safe c-state-cache))
+ (setq c-state-cache (cdr c-state-cache)))
+ (setq c-state-cache (cons (cons pair-beg pos)
+ c-state-cache)))
+
+ (list pos scan-back-pos pps-state)))))
+
+(defun c-remove-stale-state-cache-backwards (here cache-pos)
+ ;; Strip stale elements of `c-state-cache' by moving backwards through the
+ ;; buffer, and inform the caller of the scenario detected.
+ ;;
+ ;; HERE is the position we're setting `c-state-cache' for.
+ ;; CACHE-POS is just after the latest recorded position in `c-state-cache'
+ ;; before HERE, or a position at or near point-min which isn't in a
+ ;; literal.
+ ;;
+ ;; This function must only be called only when (> `c-state-cache-good-pos'
+ ;; HERE). Usually the gap between CACHE-POS and HERE is large. It is thus
+ ;; optimised to eliminate (or minimise) scanning between these two
+ ;; positions.
+ ;;
+ ;; Return a three element list (GOOD-POS SCAN-BACK-POS FWD-FLAG), where:
+ ;; o - GOOD-POS is a "good position", where `c-state-cache' is valid, or
+ ;; could become so after missing elements are inserted into
+ ;; `c-state-cache'. This is JUST AFTER an opening or closing
+ ;; brace/paren/bracket which is already in `c-state-cache' or just before
+ ;; one otherwise. exceptionally (when there's no such b/p/b handy) the BOL
+ ;; before `here''s line, or the start of the literal containing it.
+ ;; o - SCAN-BACK-POS, if non-nil, indicates there may be a brace pair
+ ;; preceding POS which isn't recorded in `c-state-cache'. It is a position
+ ;; to scan backwards from.
+ ;; o - FWD-FLAG, if non-nil, indicates there may be parens/braces between
+ ;; POS and HERE which aren't recorded in `c-state-cache'.
+ ;;
+ ;; The comments in this defun use "paren" to mean parenthesis or square
+ ;; bracket (as contrasted with a brace), and "(" and ")" likewise.
+ ;;
+ ;; . {..} (..) (..) ( .. { } ) (...) ( .... . ..)
+ ;; | | | | | |
+ ;; CP E here D C good
+ (let ((pos c-state-cache-good-pos)
+ pa ren ; positions of "(" and ")"
+ dropped-cons ; whether the last element dropped from `c-state-cache'
+ ; was a cons (representing a brace-pair)
+ good-pos ; see above.
+ lit ; (START . END) of a literal containing some point.
+ here-lit-start here-lit-end ; bounds of literal containing `here'
+ ; or `here' itself.
+ here- here+ ; start/end of macro around HERE, or HERE
+ (here-bol (c-point 'bol here))
+ (too-far-back (max (- here c-state-cache-too-far) 1)))
+
+ ;; Remove completely irrelevant entries from `c-state-cache'.
+ (while (and c-state-cache
+ (>= (setq pa (c-state-cache-top-lparen)) here))
+ (setq dropped-cons (consp (car c-state-cache)))
+ (setq c-state-cache (cdr c-state-cache))
+ (setq pos pa))
+ ;; At this stage, (> pos here);
+ ;; (< (c-state-cache-top-lparen) here) (or is nil).
+
+ (cond
+ ((and (consp (car c-state-cache))
+ (> (cdar c-state-cache) here))
+ ;; CASE 1: The top of the cache is a brace pair which now encloses
+ ;; `here'. As good-pos, return the address. of the "{". Since we've no
+ ;; knowledge of what's inside these braces, we have no alternative but
+ ;; to direct the caller to scan the buffer from the opening brace.
+ (setq pos (caar c-state-cache))
+ (setcar c-state-cache pos)
+ (list (1+ pos) pos t)) ; return value. We've just converted a brace pair
+ ; entry into a { entry, so the caller needs to
+ ; search for a brace pair before the {.
+
+ ;; `here' might be inside a literal. Check for this.
+ ((progn
+ (setq lit (c-state-literal-at here)
+ here-lit-start (or (car lit) here)
+ here-lit-end (or (cdr lit) here))
+ ;; Has `here' just "newly entered" a macro?
+ (save-excursion
+ (goto-char here-lit-start)
+ (if (and (c-beginning-of-macro)
+ (or (null c-state-old-cpp-beg)
+ (not (= (point) c-state-old-cpp-beg))))
+ (progn
+ (setq here- (point))
+ (c-end-of-macro)
+ (setq here+ (point)))
+ (setq here- here-lit-start
+ here+ here-lit-end)))
+
+ ;; `here' might be nested inside any depth of parens (or brackets but
+ ;; not braces). Scan backwards to find the outermost such opening
+ ;; paren, if there is one. This will be the scan position to return.
+ (save-restriction
+ (narrow-to-region cache-pos (point-max))
+ (setq pos (c-state-balance-parens-backwards here- here+ pos)))
+ nil)) ; for the cond
+
+ ((< pos here-lit-start)
+ ;; CASE 2: Address of outermost ( or [ which now encloses `here', but
+ ;; didn't enclose the (previous) `c-state-cache-good-pos'. If there is
+ ;; a brace pair preceding this, it will already be in `c-state-cache',
+ ;; unless there was a brace pair after it, i.e. there'll only be one to
+ ;; scan for if we've just deleted one.
+ (list pos (and dropped-cons pos) t)) ; Return value.
+
+ ;; `here' isn't enclosed in a (previously unrecorded) bracket/paren.
+ ;; Further forward scanning isn't needed, but we still need to find a
+ ;; GOOD-POS. Step out of all enclosing "("s on HERE's line.
+ ((progn
+ (save-restriction
+ (narrow-to-region here-bol (point-max))
+ (setq pos here-lit-start)
+ (c-safe (while (setq pa (scan-lists pos -1 1))
+ (setq pos pa)))) ; might signal
+ nil)) ; for the cond
+
+ ((setq ren (c-safe-scan-lists pos -1 -1 too-far-back))
+ ;; CASE 3: After a }/)/] before `here''s BOL.
+ (list (1+ ren) (and dropped-cons pos) nil)) ; Return value
+
+ (t
+ ;; CASE 4; Best of a bad job: BOL before `here-bol', or beginning of
+ ;; literal containing it.
+ (setq good-pos (c-state-lit-beg (c-point 'bopl here-bol)))
+ (list good-pos (and dropped-cons good-pos) nil)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Externally visible routines.
+
+(defun c-state-cache-init ()
+ (setq c-state-cache nil
+ c-state-cache-good-pos 1
+ c-state-nonlit-pos-cache nil
+ c-state-nonlit-pos-cache-limit 1
+ c-state-brace-pair-desert nil
+ c-state-point-min 1
+ c-state-point-min-lit-type nil
+ c-state-point-min-lit-start nil
+ c-state-min-scan-pos 1
+ c-state-old-cpp-beg nil
+ c-state-old-cpp-end nil)
+ (c-state-mark-point-min-literal))
+
+(defun c-invalidate-state-cache-1 (here)
+ ;; Invalidate all info on `c-state-cache' that applies to the buffer at HERE
+ ;; or higher and set `c-state-cache-good-pos' accordingly. The cache is
+ ;; left in a consistent state.
+ ;;
+ ;; This is much like `c-whack-state-after', but it never changes a paren
+ ;; 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.
+
+ ;; The cache of non-literals:
+ (if (< here c-state-nonlit-pos-cache-limit)
+ (setq c-state-nonlit-pos-cache-limit here))
+
+ ;; `c-state-cache':
+ ;; Case 1: if `here' is in a literal containing point-min, everything
+ ;; becomes (or is already) nil.
+ (if (or (null c-state-cache-good-pos)
+ (< here (c-state-get-min-scan-pos)))
+ (setq c-state-cache nil
+ c-state-cache-good-pos nil
+ c-state-min-scan-pos nil)
+
+;;; 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 ((here-bol (c-point 'bol here))
+ too-high-pa ; recorded {/(/[ next above 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'.
+ (while (and c-state-cache
+ (>= (setq pa (c-state-cache-top-paren)) here))
+ (setq dropped-cons (consp (car c-state-cache))
+ too-high-pa (c-state-cache-top-lparen)
+ c-state-cache (cdr 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)))
+ (c-append-lower-brace-pair-to-state-cache too-high-pa here-bol))
+ (setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
+ (c-state-get-min-scan-pos)))))
+
+ ;; The brace-pair desert marker:
+ (when (car c-state-brace-pair-desert)
+ (if (< here (car c-state-brace-pair-desert))
+ (setq c-state-brace-pair-desert nil)
+ (if (< here (cdr c-state-brace-pair-desert))
+ (setcdr c-state-brace-pair-desert here)))))
+
+(defun c-parse-state-1 ()
+ ;; Find and record all noteworthy parens between some good point earlier in
+ ;; the file and point. That good point is at least the beginning of the
+ ;; top-level construct we are in, or the beginning of the preceding
+ ;; top-level construct if we aren't in one.
+ ;;
+ ;; The returned value is a list of the noteworthy parens with the last one
+ ;; first. If an element in the list is an integer, it's the position of an
+ ;; open paren (of any type) which has not been closed before the point. If
+ ;; an element is a cons, it gives the position of a closed BRACE paren
+ ;; pair[*]; the car is the start brace position and the cdr is the position
+ ;; following the closing brace. Only the last closed brace paren pair
+ ;; before each open paren and before the point is recorded, and thus the
+ ;; state never contains two cons elements in succession. When a close brace
+ ;; has no matching open brace (e.g., the matching brace is outside the
+ ;; visible region), it is not represented in the returned value.
+ ;;
+ ;; [*] N.B. The close "brace" might be a mismatching close bracket or paren.
+ ;; This defun explicitly treats mismatching parens/braces/brackets as
+ ;; matching. It is the open brace which makes it a "brace" pair.
+ ;;
+ ;; If POINT is within a macro, open parens and brace pairs within
+ ;; THIS macro MIGHT be recorded. This depends on whether their
+ ;; syntactic properties have been suppressed by
+ ;; `c-neutralize-syntax-in-CPP'. This might need fixing (2008-12-11).