diff options
author | Alan Mackenzie <acm@muc.de> | 2016-06-27 11:34:02 +0000 |
---|---|---|
committer | Alan Mackenzie <acm@muc.de> | 2016-06-27 11:34:02 +0000 |
commit | 8040d99b6294ad798d4ab677ba20082b45fd2e7d (patch) | |
tree | 9c53c471d718eb1a2028168705324ffa9501cac4 /lisp/progmodes/cc-engine.el | |
parent | 15c307417f7bc13b27f06994dd931cb04873a26f (diff) | |
download | emacs-8040d99b6294ad798d4ab677ba20082b45fd2e7d.tar.gz emacs-8040d99b6294ad798d4ab677ba20082b45fd2e7d.tar.bz2 emacs-8040d99b6294ad798d4ab677ba20082b45fd2e7d.zip |
Amend a cache so that typing into C++ raw strings has no undue delay.
Also amend the code so that low-level searches to the end of literals are done
only when these positions get used.
* lisp/progmodes/cc-engine.el (c-crosses-statement-barrier-p): Use the new
c-literal-start instead of c-literal-limit.
(c-state-semi-nonlit-pos-cache): Change the structure of this cache, such that
it stores details of the literal at a point, rather than merely points outside
of literals.
(c-state-semi-pp-to-literal, c-state-full-pp-to-literal)
(c-cache-to-parse-ps-state, c-parse-ps-state-to-cache, c-ps-state-cache-pos)
(c-parse-ps-state-below, c-literal-start): New functions.
(c-state-semi-safe-place): Removed.
(c-in-literal): Use c-state-semi-pp-to-literal, so as not to scan to its end.
(c-literal-limits, c-determine-limit-get-base): consequential amendments.
(c-find-decl-spots, c-before-change-check-<>-operators, c-raw-string-pos)
(c-guess-basic-syntax (CASE 2)): Avoid needless scans to end of literals.
* lisp/progmodes/cc-fonts.el (c-font-lock-doc-comments): Avoid needless scans
to end of literals.
* lisp/progmodes/cc-mode.el (c-fl-decl-start): Avoid needless scans to end of
literals.
* lisp/progmodes/cc-cmds.el (c-beginning-of-defun, c-end-of-defun)
(c-defun-name, c-declaration-limits): Avoid needless scans to end of literals.
Diffstat (limited to 'lisp/progmodes/cc-engine.el')
-rw-r--r-- | lisp/progmodes/cc-engine.el | 312 |
1 files changed, 238 insertions, 74 deletions
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 17415a259b6..4bc4056081b 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -1300,7 +1300,7 @@ comment at the start of cc-engine.el for more info." c-stmt-delim-chars)) (non-skip-list (append (substring skip-chars 1) nil)) ; e.g. (?# ?\; ?{ ?} ?? ?:) - lit-range vsemi-pos) + lit-range lit-start vsemi-pos) (save-restriction (widen) (save-excursion @@ -1315,8 +1315,8 @@ comment at the start of cc-engine.el for more info." ((and (bolp) (save-excursion (progn - (if (setq lit-range (c-literal-limits from)) ; Have we landed in a string/comment? - (goto-char (car lit-range))) + (if (setq lit-start (c-literal-start from)) ; Have we landed in a string/comment? + (goto-char lit-start)) (c-backward-syntactic-ws) ; ? put a limit here, maybe? (setq vsemi-pos (point)) (c-at-vsemi-p)))) @@ -2279,15 +2279,110 @@ comment at the start of cc-engine.el for more info." (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. +;; A list of elements which are either buffer positions (when such positions +;; are not in literals) or lists of the form (POS TYPE START), where POS is +;; a buffer position inside a literal, TYPE is the type of the literal +;; ('string, 'c, or 'c++) and START is the start of the literal. (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!!! +;; 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-parse-ps-state-below'. + +(defun c-state-semi-pp-to-literal (here &optional not-in-delimiter) + ;; Do a parse-partial-sexp from a position in the buffer before HERE which + ;; isn't in a literal, and return information about HERE, either: + ;; (STATE TYPE BEG) if HERE is in a literal; or + ;; (STATE) otherwise, + ;; where STATE is the parsing state at HERE, TYPE is the type of the literal + ;; enclosing HERE, (one of 'string, 'c, 'c++) and BEG is the starting + ;; position of that literal (including the delimiter). + ;; + ;; Unless NOT-IN-DELIMITER is non-nil, when TO is inside a two-character + ;; comment opener, this is recognized as being in a comment literal. + ;; + ;; Only elements 3 (in a string), 4 (in a comment), 5 (following a quote), 7 + ;; (comment type), and 8 (start of comment/string), and possibly 10 (in + ;; newer Emacsen only, the syntax of a position after a potential first char + ;; of a two char construct) of STATE are valid. + (save-excursion + (save-match-data + (let* ((base-and-state (c-parse-ps-state-below here)) + (base (car base-and-state)) + (s (cdr base-and-state)) + (s (parse-partial-sexp base here nil nil s)) + ty) + (cond + ((or (nth 3 s) (nth 4 s)) ; in a string or comment + (setq ty (cond + ((nth 3 s) 'string) + ((nth 7 s) 'c++) + (t 'c))) + (list s ty (nth 8 s))) + + ((and (not not-in-delimiter) ; inside a comment starter + (not (bobp)) + (progn (backward-char) + (and (not (and (memq 'category-properties c-emacs-features) + (looking-at "\\s!"))) + (looking-at c-comment-start-regexp)))) + (setq ty (if (looking-at c-block-comment-start-regexp) 'c 'c++)) + (list s ty (point))) + + (t (list s))))))) + +(defun c-state-full-pp-to-literal (here &optional not-in-delimiter) + ;; This function will supersede c-state-pp-to-literal. + ;; + ;; Do a parse-partial-sexp from a position in the buffer before HERE which + ;; isn't in a literal, and return information about HERE, either: + ;; (STATE TYPE (BEG . END)) if HERE is in a literal; or + ;; (STATE) otherwise, + ;; where STATE is the parsing state at HERE, TYPE is the type of the literal + ;; enclosing HERE, (one of 'string, 'c, 'c++) and (BEG . END) is the + ;; boundaries of that literal (including the delimiters). + ;; + ;; Unless NOT-IN-DELIMITER is non-nil, when TO is inside a two-character + ;; comment opener, this is recognized as being in a comment literal. + ;; + ;; Only elements 3 (in a string), 4 (in a comment), 5 (following a quote), 7 + ;; (comment type), and 8 (start of comment/string), and possibly 10 (in + ;; newer Emacsen only, the syntax of a position after a potential first char + ;; of a two char construct) of STATE are valid. + (save-excursion + (save-match-data + (let* ((base-and-state (c-parse-ps-state-below here)) + (base (car base-and-state)) + (s (cdr base-and-state)) + (s (parse-partial-sexp base here nil nil s)) + ty start) + (cond + ((or (nth 3 s) (nth 4 s)) ; in a string or comment + (setq ty (cond + ((nth 3 s) 'string) + ((nth 7 s) 'c++) + (t 'c))) + (setq start (nth 8 s)) + (parse-partial-sexp here (point-max) + nil ; TARGETDEPTH + nil ; STOPBEFORE + s ; OLDSTATE + 'syntax-table) ; stop at end of literal + (list s ty (cons start (point)))) + + ((and (not not-in-delimiter) ; inside a comment starter + (not (bobp)) + (progn (backward-char) + (and (not (and (memq 'category-properties c-emacs-features) + (looking-at "\\s!"))) + (looking-at c-comment-start-regexp)))) + (setq ty (if (looking-at c-block-comment-start-regexp) 'c 'c++) + start (point)) + (forward-comment 1) + (list s ty (cons start (point)))) + + (t (list s))))))) (defsubst c-state-pp-to-literal (from to &optional not-in-delimiter) ;; Do a parse-partial-sexp from FROM to TO, returning either @@ -2332,6 +2427,103 @@ comment at the start of cc-engine.el for more info." (t `(,s))))))) +(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) + (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) + (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))) + (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)))) + +(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))) + ((nth 4 state) ; A comment + (list (point) + (if (eq (nth 7 state) 1) 'c++ 'c) + (nth 8 state))) + (t ; Neither string nor comment. + (point)))) + +(defsubst c-ps-state-cache-pos (elt) + ;; Get the buffer position from ELT, an element from the cache + ;; `c-state-semi-nonlit-pos-cache'. + (if (atom elt) + elt + (car elt))) + +(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-restriction + (widen) + (save-excursion + (let ((c c-state-semi-nonlit-pos-cache) + elt state pos npos high-elt) + ;; Trim the cache to take account of buffer changes. + (while (and c (> (c-ps-state-cache-pos (c-ps-state-cache-pos (car c))) + c-state-semi-nonlit-pos-cache-limit)) + (setq c (cdr c))) + (setq c-state-semi-nonlit-pos-cache c) + + (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))) + + (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)))) + (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 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))) + + (if (> pos c-state-semi-nonlit-pos-cache-limit) + (setq c-state-semi-nonlit-pos-cache-limit pos)) + + (cons pos state))))) + (defun c-state-safe-place (here) ;; Return a buffer position before HERE which is "safe", i.e. outside any ;; string, comment, or macro. @@ -2397,45 +2589,6 @@ comment at the start of cc-engine.el for more info." (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 @@ -4633,8 +4786,7 @@ Note that this function might do hidden buffer changes. See the comment at the start of cc-engine.el for more info." (save-restriction (widen) - (let* ((safe-place (c-state-semi-safe-place (point))) - (lit (c-state-pp-to-literal safe-place (point)))) + (let ((lit (c-state-semi-pp-to-literal (point)))) (or (cadr lit) (and detect-cpp (save-excursion (c-beginning-of-macro)) @@ -4656,14 +4808,19 @@ Note that this function might do hidden buffer changes. See the comment at the start of cc-engine.el for more info." (save-excursion - (let* ((pos (point)) - (lim (or lim (c-state-semi-safe-place pos))) - (pp-to-lit (save-restriction - (widen) - (c-state-pp-to-literal lim pos not-in-delimiter))) - (state (car pp-to-lit)) - (lit-limits (car (cddr pp-to-lit)))) - + (let* + ((pos (point)) + (lit-limits + (if lim + (let ((s (parse-partial-sexp lim (point)))) + (when (or (nth 3 s) (nth 4 s)) + (cons (nth 8 s) + (progn (parse-partial-sexp (point) (point-max) + nil 'syntax-table + s) + (point))))) + (let ((pp-to-lit (c-state-full-pp-to-literal pos not-in-delimiter))) + (car (cddr pp-to-lit)))))) (cond (lit-limits) @@ -4702,6 +4859,16 @@ comment at the start of cc-engine.el for more info." (if beg (cons beg end)))))) )))) +(defun c-literal-start (&optional safe-pos) + "Return the start of the string or comment surrounding point, or nil if +point isn't in one. SAFE-POS, if non-nil, is a position before point which is +a known \"safe position\", i.e. outside of any string or comment." + (if safe-pos + (let ((s (parse-partial-sexp safe-pos (point)))) + (and (or (nth 3 s) (nth 4 s)) + (nth 8 s))) + (car (cddr (c-state-semi-pp-to-literal (point)))))) + ;; In case external callers use this; it did have a docstring. (defalias 'c-literal-limits-fast 'c-literal-limits) @@ -4766,13 +4933,10 @@ comment at the start of cc-engine.el for more info." (defsubst c-determine-limit-get-base (start try-size) ;; Get a "safe place" approximately TRY-SIZE characters before START. - ;; This doesn't preserve point. + ;; This defsubst 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)))) + (s (c-state-semi-pp-to-literal pos))) + (or (car (cddr s)) pos))) (defun c-determine-limit (how-far-back &optional start try-size) ;; Return a buffer position HOW-FAR-BACK non-literal characters from START @@ -5152,8 +5316,9 @@ comment at the start of cc-engine.el for more info." ;; arrived at something that looks like a start or else ;; resort to `c-literal-limits'. (unless (looking-at c-literal-start-regexp) - (let ((range (c-literal-limits))) - (if range (goto-char (car range))))) + (let ((lit-start (c-literal-start))) + (if lit-start (goto-char lit-start))) + ) (setq start-in-literal (point))) ; end of `and' arm. @@ -5690,12 +5855,12 @@ comment at the start of cc-engine.el for more info." ;; 2010-01-29. (save-excursion (c-save-buffer-state - ((beg-lit-limits (progn (goto-char beg) (c-literal-limits))) + ((beg-lit-start (progn (goto-char beg) (c-literal-start))) (end-lit-limits (progn (goto-char end) (c-literal-limits))) new-beg new-end beg-limit end-limit) ;; Locate the earliest < after the barrier before the changed region, ;; which isn't already marked as a paren. - (goto-char (if beg-lit-limits (car beg-lit-limits) beg)) + (goto-char (or beg-lit-start beg)) (setq beg-limit (c-determine-limit 512)) ;; Remove the syntax-table/category properties from each pertinent <...> @@ -5854,9 +6019,8 @@ comment at the start of cc-engine.el for more info." ;; ;; Note: this routine is dependant upon the correct syntax-table text ;; properties being set. - (let* ((safe (c-state-semi-safe-place (point))) - (state (c-state-pp-to-literal safe (point))) - open-quote-pos open-paren-pos close-paren-pos close-quote-pos id) + (let ((state (c-state-semi-pp-to-literal (point))) + open-quote-pos open-paren-pos close-paren-pos close-quote-pos id) (save-excursion (when (and @@ -5865,7 +6029,7 @@ comment at the start of cc-engine.el for more info." (or (eq (char-after) ?\") (search-backward "\"" (max (- (point) 17) (point-min)) t))) ((and (eq (cadr state) 'string) - (goto-char (car (nth 2 state))) + (goto-char (nth 2 state)) (or (eq (char-after) ?\") (search-backward "\"" (max (- (point) 17) (point-min)) t)) (not (bobp))))) @@ -10551,8 +10715,8 @@ comment at the start of cc-engine.el for more info." ;; versions, which results in that we get nil from ;; `c-literal-limits' even when `c-in-literal' claims ;; we're inside a comment. - (setq placeholder (c-literal-limits lim))) - (c-add-syntax literal (car placeholder))) + (setq placeholder (c-literal-start lim))) + (c-add-syntax literal placeholder)) ;; CASE 3: in a cpp preprocessor macro continuation. ((and (save-excursion |