1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-26 15:10:50 -08:00

CC Mode internal cache: Handle a cache pos being inside a two-char construct.

Cache c-state-semi-nonlit-pos-cache was failing when a cache position was,
e.g., between the two characters of an opening comment "/*", and additionally
there were an odd number of quote marks (apostrophes) in the comment.  This
happened in .../src/xdisp.c in the Emacs master branch around 2017-05-02 at
buffer position 615001.

* lisp/progmodes/cc-defs.el (c-emacs-features): Repurpose symbol
pps-extended-state to mean that there are at least 11 elements in the parser
state.

* lisp/progmodes/cc-engine.el (c-cache-to-parse-ps-state)
(c-parse-ps-state-to-cache): Rewrite these to use enhanced cache element list
types which indicate potentially being inside two-char constructs.
(c-parse-ps-state-below): Rewrite to use the new versions of the above two
functions.
This commit is contained in:
Alan Mackenzie 2017-05-07 09:27:00 +00:00
parent 55b07d3379
commit bcbd8f7e4e
2 changed files with 125 additions and 57 deletions

View file

@ -1914,14 +1914,18 @@ non-nil, a caret is prepended to invert the set."
(set-buffer-modified-p nil))
(kill-buffer buf))
;; See if `parse-partial-sexp' returns the eighth element.
(if (c-safe (>= (length (save-excursion
(parse-partial-sexp (point) (point))))
10))
(setq list (cons 'pps-extended-state list))
(error (concat
"CC Mode is incompatible with this version of Emacs - "
"`parse-partial-sexp' has to return at least 10 elements.")))
;; Check how many elements `parse-partial-sexp' returns.
(let ((ppss-size (or (c-safe (length
(save-excursion
(parse-partial-sexp (point) (point)))))
0)))
(cond
((>= ppss-size 11) (setq list (cons 'pps-extended-state list)))
((>= ppss-size 10))
(t (error
(concat
"CC Mode is incompatible with this version of Emacs - "
"`parse-partial-sexp' has to return at least 10 elements.")))))
;;(message "c-emacs-features: %S" list)
list)
@ -1944,10 +1948,9 @@ might be present:
(i.e. the syntax class `!').
`gen-string-delim' Generic string delimiters work
(i.e. the syntax class `|').
`pps-extended-state' `parse-partial-sexp' returns a list with at least 10
elements, i.e. it contains the position of the start of
the last comment or string. It's always set - CC Mode
no longer works in emacsen without this feature.
`pps-extended-state' `parse-partial-sexp' returns a list with at least 11
elements, i.e. it indicates having stopped after the
first character of a potential two-char construct.
`posix-char-classes' The regexp engine understands POSIX character classes.
`col-0-paren' It's possible to turn off the ad-hoc rule that a paren
in column zero is the start of a defun.

View file

@ -2575,17 +2575,24 @@ comment at the start of cc-engine.el for more info."
(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. ELT is either just a number, a buffer
;; position, or it is a list (POS TYPE STARTING-POS). Here POS is the
;; buffer position the other elements are pertinent for, TYPE is either 'c
;; or 'c++ (for a comment) or a character (for a string delimiter) or t
;; (meaning a string fence opened the string), STARTING-POS is the starting
;; position of the comment or string.
(if (consp elt)
;; `parse-partial-sexp', out of ELT, a member of
;; `c-state-semi-nonlit-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)
(between-syntax 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
@ -2596,28 +2603,88 @@ comment at the start of cc-engine.el for more info."
com-style (if (eq type 'c++) 1 nil)))
(t (c-benign-error "Invalid type %s in c-cache-to-parse-ps-state"
elt)))
(list depth containing last
in-string in-comment after-quote
min-depth com-style com-str-start
intermediate nil))
(copy-tree '(0 nil nil nil nil nil 0 nil nil nil nil))))
(if (memq 'pps-extended-state c-emacs-features)
(progn
(goto-char pos)
(list depth containing last
in-string in-comment after-quote
min-depth com-style com-str-start
intermediate char-1))
(goto-char (if char-1
(1- pos)
pos))
(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)))))
(defun c-parse-ps-state-to-cache (state)
;; Convert STATE, a `parse-partial-sexp' state valid at POINT, to an element
;; for the `c-state-semi-nonlit-pos-cache' cache. This is either POINT
;; (when point is not in a literal) or a list (POINT TYPE STARTING-POS),
;; where TYPE is the type of the literal, either 'string, 'c, or 'c++, and
;; STARTING-POS is the starting position of the comment or string.
(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))))
;; for the `c-state-semi-nonlit-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
@ -2637,7 +2704,7 @@ comment at the start of cc-engine.el for more info."
(save-restriction
(widen)
(let ((c c-state-semi-nonlit-pos-cache)
elt state pos npos high-elt)
elt state npos high-elt)
;; Trim the cache to take account of buffer changes.
(while (and c (> (c-ps-state-cache-pos (car c))
c-state-semi-nonlit-pos-cache-limit))
@ -2647,29 +2714,27 @@ comment at the start of cc-engine.el for more info."
(while (and c (> (c-ps-state-cache-pos (car c)) here))
(setq high-elt (car c))
(setq c (cdr c)))
(setq pos (or (and c (c-ps-state-cache-pos (car c)))
(point-min)))
(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))))
(if high-elt
(setq state (c-cache-to-parse-ps-state (car c)))
(setq elt (if c (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-state-semi-nonlit-pos-cache' each iteration of the following.
(while
;; Add an element to `c-state-semi-nonlit-pos-cache' each iteration.
(<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
(setq state (parse-partial-sexp pos npos nil nil state))
(<= (setq npos (+ (point) c-state-nonlit-pos-interval)) here)
(setq state (parse-partial-sexp (point) npos nil nil state))
(setq elt (c-parse-ps-state-to-cache state))
(setq c-state-semi-nonlit-pos-cache
(cons elt c-state-semi-nonlit-pos-cache))
(setq pos npos)))
(cons elt c-state-semi-nonlit-pos-cache))))
(if (> pos c-state-semi-nonlit-pos-cache-limit)
(setq c-state-semi-nonlit-pos-cache-limit pos))
(if (> (point) c-state-semi-nonlit-pos-cache-limit)
(setq c-state-semi-nonlit-pos-cache-limit (point)))
(cons pos state)))))
(cons (point) state)))))
(defun c-state-safe-place (here)
;; Return a buffer position before HERE which is "safe", i.e. outside any