* lisp/progmodes/cc-engine.el: Permute certain literal cacheing functions

This commit is contained in:
Alan Mackenzie 2019-06-01 20:08:27 +00:00
parent 9dee49ed64
commit 99bc4af9c8

View file

@ -2470,88 +2470,40 @@ comment at the start of cc-engine.el for more info."
(c-skip-ws-forward end+1)
(eq (point) end+1))))))
;; A system for finding noteworthy parens before the point.
(defconst c-state-cache-too-far 5000)
;; A maximum comfortable scanning distance, e.g. between
;; `c-state-cache-good-pos' and "HERE" (where we call c-parse-state). When
;; this distance is exceeded, we take "emergency measures", e.g. by clearing
;; the cache and starting again from point-min or a beginning of defun. This
;; value can be tuned for efficiency or set to a lower value for testing.
(defvar c-state-cache nil)
(make-variable-buffer-local 'c-state-cache)
;; The state cache used by `c-parse-state' to cut down the amount of
;; searching. It's the result from some earlier `c-parse-state' call. See
;; `c-parse-state''s doc string for details of its structure.
;;
;; The use of the cached info is more effective if the next
;; `c-parse-state' call is on a line close by the one the cached state
;; was made at; the cache can actually slow down a little if the
;; cached state was made very far back in the buffer. The cache is
;; most effective if `c-parse-state' is used on each line while moving
;; forward.
(defvar c-state-cache-good-pos 1)
(make-variable-buffer-local 'c-state-cache-good-pos)
;; This is a position where `c-state-cache' is known to be correct, or
;; nil (see below). It's a position inside one of the recorded unclosed
;; parens or the top level, but not further nested inside any literal or
;; subparen that is closed before the last recorded position.
;;
;; The exact position is chosen to try to be close to yet earlier than
;; the position where `c-state-cache' will be called next. Right now
;; the heuristic is to set it to the position after the last found
;; closing paren (of any type) before the line on which
;; `c-parse-state' was called. That is chosen primarily to work well
;; with refontification of the current line.
;;
;; 2009-07-28: When `c-state-point-min' and the last position where
;; `c-parse-state' or for which `c-invalidate-state-cache' was called, are
;; both in the same literal, there is no such "good position", and
;; c-state-cache-good-pos is then nil. This is the ONLY circumstance in which
;; it can be nil. In this case, `c-state-point-min-literal' will be non-nil.
;;
;; 2009-06-12: In a brace desert, c-state-cache-good-pos may also be in
;; the middle of the desert, as long as it is not within a brace pair
;; recorded in `c-state-cache' or a paren/bracket pair.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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 3000)
;; The approximate interval between entries in `c-state-nonlit-pos-cache'.
;; We maintain a sopisticated cache of positions which are in a literal,
;; disregarding macros (i.e. we don't distinguish between "in a macro" and
;; not).
;;
;; This cache is in three parts: two "near" caches, which are association
;; lists of a small number (currently six) of positions and the parser states
;; there; the "far" cache (also known as "the cache"), a list of compressed
;; parser states going back to the beginning of the buffer, one entry every
;; 3000 characters.
;;
;; The two main callable functions embodying this cache are
;; `c-semi-pp-to-literal', which returns a `parse-partial-sexp' state at a
;; given position, together with the start of any literal enclosing it, and
;; `c-full-pp-to-literal', which additionally returns the end of such literal.
;; One of the above "near" caches is associated with each of these functions.
;;
;; When searching this cache, these functions first seek an exact match, then
;; a "close" match from the assiciated near cache. If neither of these
;; succeed, the nearest preceding entry in the far cache is used.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar c-state-nonlit-pos-cache nil)
(make-variable-buffer-local 'c-state-nonlit-pos-cache)
;; A list of buffer positions which are known not to be in a literal or a cpp
;; construct. This is ordered with higher positions at the front of the list.
;; Only those which are less than `c-state-nonlit-pos-cache-limit' are valid.
(defvar c-semi-lit-near-cache nil)
(make-variable-buffer-local 'c-semi-lit-near-cache)
;; A list of up to six recent results from `c-semi-pp-to-literal'. Each
;; element is a cons of the buffer position and the `parse-partial-sexp' state
;; at that position.
(defvar c-state-nonlit-pos-cache-limit 1)
(make-variable-buffer-local 'c-state-nonlit-pos-cache-limit)
;; An upper limit on valid entries in `c-state-nonlit-pos-cache'. This is
(defvar c-semi-near-cache-limit 1)
(make-variable-buffer-local 'c-semi-near-cache-limit)
;; An upper limit on valid entries in `c-semi-lit-near-cache'. This is
;; reduced by buffer changes, and increased by invocations of
;; `c-state-literal-at'.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; We also maintain a less simple cache of positions which aren't in a
;; literal, disregarding macros.
;;
;; This cache is in two parts: the "near" cache, which is an association list
;; of a small number (currently six) of positions and the parser states there;
;; the "far" cache (also known as "the cache"), a list of compressed parser
;; states going back to the beginning of the buffer, one entry every 3000
;; characters.
;;
;; When searching this cache, `c-semi-pp-to-literal' first seeks an
;; exact match, then a "close" match from the near cache. If neither of these
;; succeed, the nearest entry in the far cache is used.
;;
;; Because either sub-cache can raise `c-lit-pos-cache-limit',
;; both of them are "trimmed" together after a buffer change to ensure
;; consistency.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; `c-semi-pp-to-literal'.
(defvar c-lit-pos-cache nil)
(make-variable-buffer-local 'c-lit-pos-cache)
@ -2575,27 +2527,186 @@ comment at the start of cc-engine.el for more info."
;; is reduced by buffer changes, and increased by invocations of
;; `c-parse-ps-state-below'.
(defvar c-semi-lit-near-cache nil)
(make-variable-buffer-local 'c-semi-lit-near-cache)
;; A list of up to six recent results from `c-semi-pp-to-literal'. Each
;; element is a cons of the buffer position and the `parse-partial-sexp' state
;; at that position.
;; Note that as of 2019-05-27, the forms involving CHAR-1 are no longer used.
(defun c-cache-to-parse-ps-state (elt)
;; Create a list suitable to use as the old-state parameter to
;; `parse-partial-sexp', out of ELT, a member of
;; `c-lit-pos-cache'. ELT is either just a number, or a list
;; with 2, 3, or 4 members (See `c-parse-ps-state-to-cache'). That number
;; or the car of the list is the "position element" of ELT, the position
;; where ELT is valid.
;;
;; POINT is left at the postition for which the returned state is valid. It
;; will be either the position element of ELT, or one character before
;; that. (The latter happens in Emacs <= 25 and XEmacs, when ELT indicates
;; its position element directly follows a potential first character of a
;; two char construct (such as a comment opener or an escaped character).)
(if (and (consp elt) (>= (length elt) 3))
;; Inside a string or comment
(let ((depth 0) (containing nil) (last nil)
in-string in-comment (after-quote nil)
(min-depth 0) com-style com-str-start (intermediate nil)
(char-1 (nth 3 elt)) ; first char of poss. 2-char construct
(pos (car elt))
(type (cadr elt)))
(setq com-str-start (car (cddr elt)))
(cond
((or (numberp type) (eq type t)) ; A string
(setq in-string type))
((memq type '(c c++)) ; A comment
(setq in-comment t
com-style (if (eq type 'c++) 1 nil)))
(t (c-benign-error "Invalid type %s in c-cache-to-parse-ps-state"
elt)))
(goto-char (if char-1
(1- pos)
pos))
(if (memq 'pps-extended-state c-emacs-features)
(list depth containing last
in-string in-comment nil
min-depth com-style com-str-start
intermediate nil)
(list depth containing last
in-string in-comment nil
min-depth com-style com-str-start
intermediate)))
(defvar c-semi-near-cache-limit 1)
(make-variable-buffer-local 'c-semi-near-cache-limit)
;; An upper limit on valid entries in `c-semi-lit-near-cache'. This is
;; reduced by buffer changes, and increased by invocations of
;; `c-semi-pp-to-literal'.
;; Not in a string or comment.
(if (memq 'pps-extended-state c-emacs-features)
(progn
(goto-char (if (consp elt) (car elt) elt))
(list 0 nil nil nil nil
(and (consp elt) (eq (nth 1 elt) 9)) ; 9 is syntax code for "escape".
0 nil nil nil
(and (consp elt) (nth 1 elt))))
(goto-char (if (consp elt) (car elt) elt))
(if (and (consp elt) (cdr elt)) (backward-char))
(copy-tree '(0 nil nil nil nil
nil
0 nil nil nil)))))
(defsubst c-truncate-lit-pos-cache (pos)
;; Truncate the upper bound of each of the three caches to POS, if it is
;; higher than that position.
(setq c-lit-pos-cache-limit
(min c-lit-pos-cache-limit pos)
c-semi-near-cache-limit
(min c-semi-near-cache-limit pos)
c-full-near-cache-limit
(min c-full-near-cache-limit pos)))
;; Note that as of 2019-05-27, the forms involving CHAR-1 are no longer used.
(defun c-parse-ps-state-to-cache (state)
;; Convert STATE, a `parse-partial-sexp' state valid at POINT, to an element
;; for the `c-lit-pos-cache' cache. This is one of
;; o - POINT (when point is not in a literal);
;; o - (POINT CHAR-1) (when the last character before point is potentially
;; the first of a two-character construct
;; o - (POINT TYPE STARTING-POS) (when in a literal);
;; o - (POINT TYPE STARTING-POS CHAR-1) (Combination of the previous two),
;; where TYPE is the type of the literal (either 'c, or 'c++, or the
;; character which closes the string), STARTING-POS is the starting
;; position of the comment or string. CHAR-1 is either the character
;; potentially forming the first half of a two-char construct (in Emacs <=
;; 25 and XEmacs) or the syntax of the character (in Emacs >= 26).
(if (memq 'pps-extended-state c-emacs-features)
;; Emacs >= 26.
(let ((basic
(cond
((nth 3 state) ; A string
(list (point) (nth 3 state) (nth 8 state)))
((and (nth 4 state) ; A comment
(not (eq (nth 7 state) 'syntax-table))) ; but not a psuedo comment.
(list (point)
(if (eq (nth 7 state) 1) 'c++ 'c)
(nth 8 state)))
(t ; Neither string nor comment.
(point)))))
(if (nth 10 state)
(append (if (consp basic)
basic
(list basic))
(list (nth 10 state)))
basic))
;; Emacs <= 25, XEmacs.
(cond
((nth 3 state) ; A string
(if (eq (char-before) ?\\)
(list (point) (nth 3 state) (nth 8 state) ?\\)
(list (point) (nth 3 state) (nth 8 state))))
((and (nth 4 state) ; comment
(not (eq (nth 7 state) 'syntax-table)))
(if (and (eq (char-before) ?*)
(> (- (point) (nth 8 state)) 2)) ; not "/*/".
(list (point)
(if (eq (nth 7 state) 1) 'c++ 'c)
(nth 8 state)
?*)
(list (point)
(if (eq (nth 7 state) 1) 'c++ 'c)
(nth 8 state))))
(t (if (memq (char-before) '(?/ ?\\))
(list (point) (char-before))
(point))))))
(defsubst c-ps-state-cache-pos (elt)
;; Get the buffer position from ELT, an element from the cache
;; `c-lit-pos-cache'.
(if (atom elt)
elt
(car elt)))
(defun c-trim-lit-pos-cache ()
;; Trim the `c-lit-pos-cache' to take account of buffer
;; changes, indicated by `c-lit-pos-cache-limit'.
(while (and c-lit-pos-cache
(> (c-ps-state-cache-pos (car c-lit-pos-cache))
c-lit-pos-cache-limit))
(setq c-lit-pos-cache (cdr c-lit-pos-cache))))
(defconst c-state-nonlit-pos-interval 3000)
;; The approximate interval between entries in `c-state-nonlit-pos-cache'.
(defun c-parse-ps-state-below (here)
;; Given a buffer position HERE, Return a cons (CACHE-POS . STATE), where
;; CACHE-POS is a position not very far before HERE for which the
;; parse-partial-sexp STATE is valid. Note that the only valid elements of
;; STATE are those concerning comments and strings; STATE is the state of a
;; null `parse-partial-sexp' scan when CACHE-POS is not in a comment or
;; string.
(save-excursion
(save-restriction
(widen)
(c-trim-lit-pos-cache)
(let ((c c-lit-pos-cache)
elt state npos high-elt)
(while (and c (> (c-ps-state-cache-pos (car c)) here))
(setq high-elt (car c))
(setq c (cdr c)))
(goto-char (or (and c (c-ps-state-cache-pos (car c)))
(point-min)))
(setq state
(if c
(c-cache-to-parse-ps-state (car c))
(copy-tree '(0 nil nil nil nil nil 0 nil nil nil nil))))
(when (not high-elt)
;; We need to extend the cache. Add an element to
;; `c-lit-pos-cache' each iteration of the following.
(while
(<= (setq npos (+ (point) c-state-nonlit-pos-interval)) here)
(setq state (parse-partial-sexp (point) npos nil nil state))
;; If we're after a \ or a / or * which might be a comment
;; delimiter half, move back a character.
(when (or (nth 5 state) ; After a quote character
(and (memq 'pps-extended-state c-emacs-features)
(nth 10 state))) ; in the middle of a 2-char seq.
(setq npos (1- npos))
(backward-char)
(when (nth 10 state)
(setcar (nthcdr 10 state) nil))
(when (nth 5 state)
(setcar (nthcdr 5 state) nil)))
(setq elt (c-parse-ps-state-to-cache state))
(setq c-lit-pos-cache
(cons elt c-lit-pos-cache))))
(if (> (point) c-lit-pos-cache-limit)
(setq c-lit-pos-cache-limit (point)))
(cons (point) state)))))
(defun c-semi-trim-near-cache ()
;; Remove stale entries in `c-semi-lit-near-cache', i.e. those
@ -2891,6 +3002,78 @@ comment at the start of cc-engine.el for more info."
(c-full-put-near-cache-entry here s nil)
(list s))))))))
(defsubst c-truncate-lit-pos-cache (pos)
;; Truncate the upper bound of each of the three caches to POS, if it is
;; higher than that position.
(setq c-lit-pos-cache-limit
(min c-lit-pos-cache-limit pos)
c-semi-near-cache-limit
(min c-semi-near-cache-limit pos)
c-full-near-cache-limit
(min c-full-near-cache-limit pos)))
;; A system for finding noteworthy parens before the point.
(defconst c-state-cache-too-far 5000)
;; A maximum comfortable scanning distance, e.g. between
;; `c-state-cache-good-pos' and "HERE" (where we call c-parse-state). When
;; this distance is exceeded, we take "emergency measures", e.g. by clearing
;; the cache and starting again from point-min or a beginning of defun. This
;; value can be tuned for efficiency or set to a lower value for testing.
(defvar c-state-cache nil)
(make-variable-buffer-local 'c-state-cache)
;; The state cache used by `c-parse-state' to cut down the amount of
;; searching. It's the result from some earlier `c-parse-state' call. See
;; `c-parse-state''s doc string for details of its structure.
;;
;; The use of the cached info is more effective if the next
;; `c-parse-state' call is on a line close by the one the cached state
;; was made at; the cache can actually slow down a little if the
;; cached state was made very far back in the buffer. The cache is
;; most effective if `c-parse-state' is used on each line while moving
;; forward.
(defvar c-state-cache-good-pos 1)
(make-variable-buffer-local 'c-state-cache-good-pos)
;; This is a position where `c-state-cache' is known to be correct, or
;; nil (see below). It's a position inside one of the recorded unclosed
;; parens or the top level, but not further nested inside any literal or
;; subparen that is closed before the last recorded position.
;;
;; The exact position is chosen to try to be close to yet earlier than
;; the position where `c-state-cache' will be called next. Right now
;; the heuristic is to set it to the position after the last found
;; closing paren (of any type) before the line on which
;; `c-parse-state' was called. That is chosen primarily to work well
;; with refontification of the current line.
;;
;; 2009-07-28: When `c-state-point-min' and the last position where
;; `c-parse-state' or for which `c-invalidate-state-cache' was called, are
;; both in the same literal, there is no such "good position", and
;; c-state-cache-good-pos is then nil. This is the ONLY circumstance in which
;; it can be nil. In this case, `c-state-point-min-literal' will be non-nil.
;;
;; 2009-06-12: In a brace desert, c-state-cache-good-pos may also be in
;; the middle of the desert, as long as it is not within a brace pair
;; recorded in `c-state-cache' or a paren/bracket pair.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; We maintain a simple cache of positions which aren't in a literal, so as to
;; speed up testing for non-literality.
(defvar c-state-nonlit-pos-cache nil)
(make-variable-buffer-local 'c-state-nonlit-pos-cache)
;; A list of buffer positions which are known not to be in a literal or a cpp
;; construct. This is ordered with higher positions at the front of the list.
;; Only those which are less than `c-state-nonlit-pos-cache-limit' are valid.
(defvar c-state-nonlit-pos-cache-limit 1)
(make-variable-buffer-local 'c-state-nonlit-pos-cache-limit)
;; An upper limit on valid entries in `c-state-nonlit-pos-cache'. This is
;; reduced by buffer changes, and increased by invocations of
;; `c-state-literal-at'.
(defun c-state-pp-to-literal (from to &optional not-in-delimiter)
;; Do a parse-partial-sexp from FROM to TO, returning either
;; (STATE TYPE (BEG . END)) if TO is in a literal; or
@ -2936,184 +3119,6 @@ comment at the start of cc-engine.el for more info."
(t `(,s)))))))
;; Note that as of 2019-05-27, the forms involving CHAR-1 are no longer used.
(defun c-cache-to-parse-ps-state (elt)
;; Create a list suitable to use as the old-state parameter to
;; `parse-partial-sexp', out of ELT, a member of
;; `c-lit-pos-cache'. ELT is either just a number, or a list
;; with 2, 3, or 4 members (See `c-parse-ps-state-to-cache'). That number
;; or the car of the list is the "position element" of ELT, the position
;; where ELT is valid.
;;
;; POINT is left at the position for which the returned state is valid. It
;; will be either the position element of ELT, or one character before
;; that. (The latter happens in Emacs <= 25 and XEmacs, when ELT indicates
;; its position element directly follows a potential first character of a
;; two char construct (such as a comment opener or an escaped character).)
(if (and (consp elt) (>= (length elt) 3))
;; Inside a string or comment
(let ((depth 0) (containing nil) (last nil)
in-string in-comment (after-quote nil)
(min-depth 0) com-style com-str-start (intermediate nil)
(char-1 (nth 3 elt)) ; first char of poss. 2-char construct
(pos (car elt))
(type (cadr elt)))
(setq com-str-start (car (cddr elt)))
(cond
((or (numberp type) (eq type t)) ; A string
(setq in-string type))
((memq type '(c c++)) ; A comment
(setq in-comment t
com-style (if (eq type 'c++) 1 nil)))
(t (c-benign-error "Invalid type %s in c-cache-to-parse-ps-state"
elt)))
(goto-char (if char-1
(1- pos)
pos))
(if (memq 'pps-extended-state c-emacs-features)
(list depth containing last
in-string in-comment nil
min-depth com-style com-str-start
intermediate nil)
(list depth containing last
in-string in-comment nil
min-depth com-style com-str-start
intermediate)))
;; Not in a string or comment.
(if (memq 'pps-extended-state c-emacs-features)
(progn
(goto-char (if (consp elt) (car elt) elt))
(list 0 nil nil nil nil
(and (consp elt) (eq (nth 1 elt) 9)) ; 9 is syntax code for "escape".
0 nil nil nil
(and (consp elt) (nth 1 elt))))
(goto-char (if (consp elt) (car elt) elt))
(if (and (consp elt) (cdr elt)) (backward-char))
(copy-tree '(0 nil nil nil nil
nil
0 nil nil nil)))))
;; Note that as of 2019-05-27, the forms involving CHAR-1 are no longer used.
(defun c-parse-ps-state-to-cache (state)
;; Convert STATE, a `parse-partial-sexp' state valid at POINT, to an element
;; for the `c-lit-pos-cache' cache. This is one of
;; o - POINT (when point is not in a literal);
;; o - (POINT CHAR-1) (when the last character before point is potentially
;; the first of a two-character construct
;; o - (POINT TYPE STARTING-POS) (when in a literal);
;; o - (POINT TYPE STARTING-POS CHAR-1) (Combination of the previous two),
;; where TYPE is the type of the literal (either 'c, or 'c++, or the
;; character which closes the string), STARTING-POS is the starting
;; position of the comment or string. CHAR-1 is either the character
;; potentially forming the first half of a two-char construct (in Emacs <=
;; 25 and XEmacs) or the syntax of the character (in Emacs >= 26).
(if (memq 'pps-extended-state c-emacs-features)
;; Emacs >= 26.
(let ((basic
(cond
((nth 3 state) ; A string
(list (point) (nth 3 state) (nth 8 state)))
((and (nth 4 state) ; A comment
(not (eq (nth 7 state) 'syntax-table))) ; but not a pseudo comment.
(list (point)
(if (eq (nth 7 state) 1) 'c++ 'c)
(nth 8 state)))
(t ; Neither string nor comment.
(point)))))
(if (nth 10 state)
(append (if (consp basic)
basic
(list basic))
(list (nth 10 state)))
basic))
;; Emacs <= 25, XEmacs.
(cond
((nth 3 state) ; A string
(if (eq (char-before) ?\\)
(list (point) (nth 3 state) (nth 8 state) ?\\)
(list (point) (nth 3 state) (nth 8 state))))
((and (nth 4 state) ; comment
(not (eq (nth 7 state) 'syntax-table)))
(if (and (eq (char-before) ?*)
(> (- (point) (nth 8 state)) 2)) ; not "/*/".
(list (point)
(if (eq (nth 7 state) 1) 'c++ 'c)
(nth 8 state)
?*)
(list (point)
(if (eq (nth 7 state) 1) 'c++ 'c)
(nth 8 state))))
(t (if (memq (char-before) '(?/ ?\\))
(list (point) (char-before))
(point))))))
(defsubst c-ps-state-cache-pos (elt)
;; Get the buffer position from ELT, an element from the cache
;; `c-lit-pos-cache'.
(if (atom elt)
elt
(car elt)))
(defun c-trim-lit-pos-cache ()
;; Trim the `c-lit-pos-cache' to take account of buffer
;; changes, indicated by `c-lit-pos-cache-limit'.
(while (and c-lit-pos-cache
(> (c-ps-state-cache-pos (car c-lit-pos-cache))
c-lit-pos-cache-limit))
(setq c-lit-pos-cache (cdr c-lit-pos-cache))))
(defun c-parse-ps-state-below (here)
;; Given a buffer position HERE, Return a cons (CACHE-POS . STATE), where
;; CACHE-POS is a position not very far before HERE for which the
;; parse-partial-sexp STATE is valid. Note that the only valid elements of
;; STATE are those concerning comments and strings; STATE is the state of a
;; null `parse-partial-sexp' scan when CACHE-POS is not in a comment or
;; string.
(save-excursion
(save-restriction
(widen)
(c-trim-lit-pos-cache)
(let ((c c-lit-pos-cache)
elt state npos high-elt)
(while (and c (> (c-ps-state-cache-pos (car c)) here))
(setq high-elt (car c))
(setq c (cdr c)))
(goto-char (or (and c (c-ps-state-cache-pos (car c)))
(point-min)))
(setq state
(if c
(c-cache-to-parse-ps-state (car c))
(copy-tree '(0 nil nil nil nil nil 0 nil nil nil nil))))
(when (not high-elt)
;; We need to extend the cache. Add an element to
;; `c-lit-pos-cache' each iteration of the following.
(while
(<= (setq npos (+ (point) c-state-nonlit-pos-interval)) here)
(setq state (parse-partial-sexp (point) npos nil nil state))
;; If we're after a \ or a / or * which might be a comment
;; delimiter half, move back a character.
(when (or (nth 5 state) ; After a quote character
(and (memq 'pps-extended-state c-emacs-features)
(nth 10 state))) ; in the middle of a 2-char seq.
(setq npos (1- npos))
(backward-char)
(when (nth 10 state)
(setcar (nthcdr 10 state) nil))
(when (nth 5 state)
(setcar (nthcdr 5 state) nil)))
(setq elt (c-parse-ps-state-to-cache state))
(setq c-lit-pos-cache
(cons elt c-lit-pos-cache))))
(if (> (point) c-lit-pos-cache-limit)
(setq c-lit-pos-cache-limit (point)))
(cons (point) state)))))
(defun c-state-safe-place (here)
;; Return a buffer position before HERE which is "safe", i.e. outside any
;; string, comment, or macro.