diff options
| author | Alan Mackenzie | 2018-04-02 11:33:24 +0000 |
|---|---|---|
| committer | Alan Mackenzie | 2018-04-02 11:33:24 +0000 |
| commit | b393ecf8e288f1e1b6a8ac55006715fa1046a5d4 (patch) | |
| tree | 759f1fa46dae0b8e05feca838dad739a6559a778 | |
| parent | 956c39d11d871d1b6cdf4bc13217e9678d12fd76 (diff) | |
| download | emacs-b393ecf8e288f1e1b6a8ac55006715fa1046a5d4.tar.gz emacs-b393ecf8e288f1e1b6a8ac55006715fa1046a5d4.zip | |
Optimize c-syntactic-skip-backward, c-determine-limit for large comment blocks
* lisp/progmodes/cc-engine.el (c-ssb-lit-begin): Remove.
(c-syntactic-skip-backward): Remove the surrounding c-self-bind-state-cache.
Use the standard function c-literal-start in place of the special purpose
c-ssb-lit-begin. With a suitable skip-chars argument (the usual case),
optimize by invoking c-backward-syntactic-ws to move back over comment blocks.
(c-determine-limit-get-base): Inovke an early c-backward-syntactic-ws.
(c-determine-limit): Use c-forward-comment whilst moving forward. Cope with
an empty position stack whilst looking for non-literals (bug fix). In the
recursive call, double try-size to prevent Lisp stack overflow.
| -rw-r--r-- | lisp/progmodes/cc-engine.el | 265 |
1 files changed, 115 insertions, 150 deletions
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 26ce2c919e8..ac1b462ee27 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el | |||
| @@ -4736,56 +4736,6 @@ comment at the start of cc-engine.el for more info." | |||
| 4736 | 4736 | ||
| 4737 | (defvar safe-pos-list) ; bound in c-syntactic-skip-backward | 4737 | (defvar safe-pos-list) ; bound in c-syntactic-skip-backward |
| 4738 | 4738 | ||
| 4739 | (defsubst c-ssb-lit-begin () | ||
| 4740 | ;; Return the start of the literal point is in, or nil. | ||
| 4741 | ;; We read and write the variables `safe-pos', `safe-pos-list', `state' | ||
| 4742 | ;; bound in the caller. | ||
| 4743 | |||
| 4744 | ;; Use `parse-partial-sexp' from a safe position down to the point to check | ||
| 4745 | ;; if it's outside comments and strings. | ||
| 4746 | (save-excursion | ||
| 4747 | (let ((pos (point)) safe-pos state) | ||
| 4748 | ;; Pick a safe position as close to the point as possible. | ||
| 4749 | ;; | ||
| 4750 | ;; FIXME: Consult `syntax-ppss' here if our cache doesn't give a good | ||
| 4751 | ;; position. | ||
| 4752 | |||
| 4753 | (while (and safe-pos-list | ||
| 4754 | (> (car safe-pos-list) (point))) | ||
| 4755 | (setq safe-pos-list (cdr safe-pos-list))) | ||
| 4756 | (unless (setq safe-pos (car-safe safe-pos-list)) | ||
| 4757 | (setq safe-pos (max (or (c-safe-position | ||
| 4758 | (point) (c-parse-state)) | ||
| 4759 | 0) | ||
| 4760 | (point-min)) | ||
| 4761 | safe-pos-list (list safe-pos))) | ||
| 4762 | |||
| 4763 | ;; Cache positions along the way to use if we have to back up more. We | ||
| 4764 | ;; cache every closing paren on the same level. If the paren cache is | ||
| 4765 | ;; relevant in this region then we're typically already on the same | ||
| 4766 | ;; level as the target position. Note that we might cache positions | ||
| 4767 | ;; after opening parens in case safe-pos is in a nested list. That's | ||
| 4768 | ;; both uncommon and harmless. | ||
| 4769 | (while (progn | ||
| 4770 | (setq state (parse-partial-sexp | ||
| 4771 | safe-pos pos 0)) | ||
| 4772 | (< (point) pos)) | ||
| 4773 | (setq safe-pos (point) | ||
| 4774 | safe-pos-list (cons safe-pos safe-pos-list))) | ||
| 4775 | |||
| 4776 | ;; If the state contains the start of the containing sexp we cache that | ||
| 4777 | ;; position too, so that parse-partial-sexp in the next run has a bigger | ||
| 4778 | ;; chance of starting at the same level as the target position and thus | ||
| 4779 | ;; will get more good safe positions into the list. | ||
| 4780 | (if (elt state 1) | ||
| 4781 | (setq safe-pos (1+ (elt state 1)) | ||
| 4782 | safe-pos-list (cons safe-pos safe-pos-list))) | ||
| 4783 | |||
| 4784 | (if (or (elt state 3) (elt state 4)) | ||
| 4785 | ;; Inside string or comment. Continue search at the | ||
| 4786 | ;; beginning of it. | ||
| 4787 | (elt state 8))))) | ||
| 4788 | |||
| 4789 | (defun c-syntactic-skip-backward (skip-chars &optional limit paren-level) | 4739 | (defun c-syntactic-skip-backward (skip-chars &optional limit paren-level) |
| 4790 | "Like `skip-chars-backward' but only look at syntactically relevant chars, | 4740 | "Like `skip-chars-backward' but only look at syntactically relevant chars, |
| 4791 | i.e. don't stop at positions inside syntactic whitespace or string | 4741 | i.e. don't stop at positions inside syntactic whitespace or string |
| @@ -4802,108 +4752,110 @@ Non-nil is returned if the point moved, nil otherwise. | |||
| 4802 | 4752 | ||
| 4803 | Note that this function might do hidden buffer changes. See the | 4753 | Note that this function might do hidden buffer changes. See the |
| 4804 | comment at the start of cc-engine.el for more info." | 4754 | comment at the start of cc-engine.el for more info." |
| 4805 | 4755 | (let* ((start (point)) | |
| 4806 | (c-self-bind-state-cache | ||
| 4807 | (let ((start (point)) | ||
| 4808 | ;; A list of syntactically relevant positions in descending | ||
| 4809 | ;; order. It's used to avoid scanning repeatedly over | ||
| 4810 | ;; potentially large regions with `parse-partial-sexp' to verify | ||
| 4811 | ;; each position. Used in `c-ssb-lit-begin' | ||
| 4812 | safe-pos-list | ||
| 4813 | ;; The result from `c-beginning-of-macro' at the start position or the | 4756 | ;; The result from `c-beginning-of-macro' at the start position or the |
| 4814 | ;; start position itself if it isn't within a macro. Evaluated on | 4757 | ;; start position itself if it isn't within a macro. |
| 4815 | ;; demand. | 4758 | (start-macro-beg |
| 4816 | start-macro-beg | 4759 | (save-excursion |
| 4760 | (goto-char start) | ||
| 4761 | (c-beginning-of-macro limit) | ||
| 4762 | (point))) | ||
| 4763 | lit-beg | ||
| 4817 | ;; The earliest position after the current one with the same paren | 4764 | ;; The earliest position after the current one with the same paren |
| 4818 | ;; level. Used only when `paren-level' is set. | 4765 | ;; level. Used only when `paren-level' is set. |
| 4819 | lit-beg | 4766 | (paren-level-pos (point)) |
| 4820 | (paren-level-pos (point))) | 4767 | ;; Whether we can optimize with an early `c-backward-syntactic-ws'. |
| 4768 | (opt-ws (string-match "^\\^[^ \t\n\r]+$" skip-chars))) | ||
| 4821 | 4769 | ||
| 4822 | (while | 4770 | ;; In the next while form, we only loop when `skip-chars' is something |
| 4823 | (progn | 4771 | ;; like "^/" and we've stopped at the end of a block comment. |
| 4824 | ;; The next loop "tries" to find the end point each time round, | 4772 | (while |
| 4825 | ;; loops when it hasn't succeeded. | 4773 | (progn |
| 4826 | (while | 4774 | ;; The next loop "tries" to find the end point each time round, |
| 4827 | (and | 4775 | ;; loops when it's ended up at the wrong level of nesting. |
| 4828 | (let ((pos (point))) | 4776 | (while |
| 4829 | (while (and | 4777 | (and |
| 4830 | (< (skip-chars-backward skip-chars limit) 0) | 4778 | ;; Optimize for, in particular, large blocks of comments from |
| 4831 | ;; Don't stop inside a literal. | 4779 | ;; `comment-region'. |
| 4832 | (when (setq lit-beg (c-ssb-lit-begin)) | 4780 | (progn (when opt-ws |
| 4781 | (c-backward-syntactic-ws) | ||
| 4782 | (setq paren-level-pos (point))) | ||
| 4783 | t) | ||
| 4784 | ;; Move back to a candidate end point which isn't in a literal | ||
| 4785 | ;; or in a macro we didn't start in. | ||
| 4786 | (let ((pos (point)) | ||
| 4787 | macro-start) | ||
| 4788 | (while (and | ||
| 4789 | (< (skip-chars-backward skip-chars limit) 0) | ||
| 4790 | (or | ||
| 4791 | (when (setq lit-beg (c-literal-start)) | ||
| 4833 | (goto-char lit-beg) | 4792 | (goto-char lit-beg) |
| 4834 | t))) | 4793 | t) |
| 4835 | (< (point) pos)) | 4794 | ;; Don't stop inside a macro we didn't start in. |
| 4836 | 4795 | (when | |
| 4837 | (let ((pos (point)) state-2 pps-end-pos) | 4796 | (save-excursion |
| 4838 | 4797 | (and (c-beginning-of-macro limit) | |
| 4839 | (cond | 4798 | (< (point) start-macro-beg) |
| 4840 | ((and paren-level | 4799 | (setq macro-start (point)))) |
| 4841 | (save-excursion | 4800 | (goto-char macro-start)))) |
| 4842 | (setq state-2 (parse-partial-sexp | 4801 | (when opt-ws |
| 4843 | pos paren-level-pos -1) | 4802 | (c-backward-syntactic-ws))) |
| 4844 | pps-end-pos (point)) | 4803 | (< (point) pos)) |
| 4845 | (/= (car state-2) 0))) | 4804 | |
| 4846 | ;; Not at the right level. | 4805 | ;; Check whether we're at the wrong level of nesting (when |
| 4847 | 4806 | ;; `paren-level' is non-nil). | |
| 4848 | (if (and (< (car state-2) 0) | 4807 | (let ((pos (point)) state-2 pps-end-pos) |
| 4849 | ;; We stop above if we go out of a paren. | 4808 | (when |
| 4850 | ;; Now check whether it precedes or is | 4809 | (and paren-level |
| 4851 | ;; nested in the starting sexp. | 4810 | (save-excursion |
| 4852 | (save-excursion | 4811 | (setq state-2 (parse-partial-sexp |
| 4853 | (setq state-2 | 4812 | pos paren-level-pos -1) |
| 4854 | (parse-partial-sexp | 4813 | pps-end-pos (point)) |
| 4855 | pps-end-pos paren-level-pos | 4814 | (/= (car state-2) 0))) |
| 4856 | nil nil state-2)) | 4815 | ;; Not at the right level. |
| 4857 | (< (car state-2) 0))) | 4816 | (if (and (< (car state-2) 0) |
| 4858 | 4817 | ;; We stop above if we go out of a paren. | |
| 4859 | ;; We've stopped short of the starting position | 4818 | ;; Now check whether it precedes or is |
| 4860 | ;; so the hit was inside a nested list. Go up | 4819 | ;; nested in the starting sexp. |
| 4861 | ;; until we are at the right level. | 4820 | (save-excursion |
| 4862 | (condition-case nil | 4821 | (setq state-2 |
| 4863 | (progn | 4822 | (parse-partial-sexp |
| 4864 | (goto-char (scan-lists pos -1 | 4823 | pps-end-pos paren-level-pos |
| 4865 | (- (car state-2)))) | 4824 | nil nil state-2)) |
| 4866 | (setq paren-level-pos (point)) | 4825 | (< (car state-2) 0))) |
| 4867 | (if (and limit (>= limit paren-level-pos)) | 4826 | |
| 4868 | (progn | 4827 | ;; We've stopped short of the starting position |
| 4869 | (goto-char limit) | 4828 | ;; so the hit was inside a nested list. Go up |
| 4870 | nil) | 4829 | ;; until we are at the right level. |
| 4871 | t)) | 4830 | (condition-case nil |
| 4872 | (error | 4831 | (progn |
| 4873 | (goto-char (or limit (point-min))) | 4832 | (goto-char (scan-lists pos -1 |
| 4874 | nil)) | 4833 | (- (car state-2)))) |
| 4875 | 4834 | (setq paren-level-pos (point)) | |
| 4876 | ;; The hit was outside the list at the start | 4835 | (if (and limit (>= limit paren-level-pos)) |
| 4877 | ;; position. Go to the start of the list and exit. | 4836 | (progn |
| 4878 | (goto-char (1+ (elt state-2 1))) | 4837 | (goto-char limit) |
| 4879 | nil)) | 4838 | nil) |
| 4880 | 4839 | t)) | |
| 4881 | ((c-beginning-of-macro limit) | 4840 | (error |
| 4882 | ;; Inside a macro. | 4841 | (goto-char (or limit (point-min))) |
| 4883 | (if (< (point) | 4842 | nil)) |
| 4884 | (or start-macro-beg | 4843 | |
| 4885 | (setq start-macro-beg | 4844 | ;; The hit was outside the list at the start |
| 4886 | (save-excursion | 4845 | ;; position. Go to the start of the list and exit. |
| 4887 | (goto-char start) | 4846 | (goto-char (1+ (elt state-2 1))) |
| 4888 | (c-beginning-of-macro limit) | 4847 | nil))))) |
| 4889 | (point))))) | 4848 | |
| 4890 | t | 4849 | (> (point) |
| 4891 | 4850 | (progn | |
| 4892 | ;; It's inside the same macro we started in so it's | 4851 | ;; Skip syntactic ws afterwards so that we don't stop at the |
| 4893 | ;; a relevant match. | 4852 | ;; end of a comment if `skip-chars' is something like "^/". |
| 4894 | (goto-char pos) | 4853 | (c-backward-syntactic-ws) |
| 4895 | nil)))))) | 4854 | (point))))) |
| 4896 | |||
| 4897 | (> (point) | ||
| 4898 | (progn | ||
| 4899 | ;; Skip syntactic ws afterwards so that we don't stop at the | ||
| 4900 | ;; end of a comment if `skip-chars' is something like "^/". | ||
| 4901 | (c-backward-syntactic-ws) | ||
| 4902 | (point))))) | ||
| 4903 | 4855 | ||
| 4904 | ;; We might want to extend this with more useful return values in | 4856 | ;; We might want to extend this with more useful return values in |
| 4905 | ;; the future. | 4857 | ;; the future. |
| 4906 | (/= (point) start)))) | 4858 | (/= (point) start))) |
| 4907 | 4859 | ||
| 4908 | ;; The following is an alternative implementation of | 4860 | ;; The following is an alternative implementation of |
| 4909 | ;; `c-syntactic-skip-backward' that uses backward movement to keep | 4861 | ;; `c-syntactic-skip-backward' that uses backward movement to keep |
| @@ -5186,6 +5138,9 @@ comment at the start of cc-engine.el for more info." | |||
| 5186 | (defsubst c-determine-limit-get-base (start try-size) | 5138 | (defsubst c-determine-limit-get-base (start try-size) |
| 5187 | ;; Get a "safe place" approximately TRY-SIZE characters before START. | 5139 | ;; Get a "safe place" approximately TRY-SIZE characters before START. |
| 5188 | ;; This defsubst doesn't preserve point. | 5140 | ;; This defsubst doesn't preserve point. |
| 5141 | (goto-char start) | ||
| 5142 | (c-backward-syntactic-ws) | ||
| 5143 | (setq start (point)) | ||
| 5189 | (let* ((pos (max (- start try-size) (point-min))) | 5144 | (let* ((pos (max (- start try-size) (point-min))) |
| 5190 | (s (c-state-semi-pp-to-literal pos)) | 5145 | (s (c-state-semi-pp-to-literal pos)) |
| 5191 | (cand (or (car (cddr s)) pos))) | 5146 | (cand (or (car (cddr s)) pos))) |
| @@ -5195,9 +5150,9 @@ comment at the start of cc-engine.el for more info." | |||
| 5195 | (point)))) | 5150 | (point)))) |
| 5196 | 5151 | ||
| 5197 | (defun c-determine-limit (how-far-back &optional start try-size) | 5152 | (defun c-determine-limit (how-far-back &optional start try-size) |
| 5198 | ;; Return a buffer position HOW-FAR-BACK non-literal characters from | 5153 | ;; Return a buffer position approximately HOW-FAR-BACK non-literal |
| 5199 | ;; START (default point). The starting position, either point or | 5154 | ;; characters from START (default point). The starting position, either |
| 5200 | ;; START may not be in a comment or string. | 5155 | ;; point or START may not be in a comment or string. |
| 5201 | ;; | 5156 | ;; |
| 5202 | ;; The position found will not be before POINT-MIN and won't be in a | 5157 | ;; The position found will not be before POINT-MIN and won't be in a |
| 5203 | ;; literal. | 5158 | ;; literal. |
| @@ -5215,6 +5170,12 @@ comment at the start of cc-engine.el for more info." | |||
| 5215 | (s (parse-partial-sexp pos pos)) ; null state. | 5170 | (s (parse-partial-sexp pos pos)) ; null state. |
| 5216 | stack elt size | 5171 | stack elt size |
| 5217 | (count 0)) | 5172 | (count 0)) |
| 5173 | ;; Optimization for large blocks of comments, particularly those being | ||
| 5174 | ;; created by `comment-region'. | ||
| 5175 | (goto-char pos) | ||
| 5176 | (forward-comment try-size) | ||
| 5177 | (setq pos (point)) | ||
| 5178 | |||
| 5218 | (while (< pos start) | 5179 | (while (< pos start) |
| 5219 | ;; Move forward one literal each time round this loop. | 5180 | ;; Move forward one literal each time round this loop. |
| 5220 | ;; Move forward to the start of a comment or string. | 5181 | ;; Move forward to the start of a comment or string. |
| @@ -5257,6 +5218,10 @@ comment at the start of cc-engine.el for more info." | |||
| 5257 | 5218 | ||
| 5258 | ;; Have we found enough yet? | 5219 | ;; Have we found enough yet? |
| 5259 | (cond | 5220 | (cond |
| 5221 | ((null elt) ; No non-literal characters found. | ||
| 5222 | (if (> base (point-min)) | ||
| 5223 | (c-determine-limit how-far-back base (* 2 try-size)) | ||
| 5224 | (point-min))) | ||
| 5260 | ((>= count how-far-back) | 5225 | ((>= count how-far-back) |
| 5261 | (+ (car elt) (- count how-far-back))) | 5226 | (+ (car elt) (- count how-far-back))) |
| 5262 | ((eq base (point-min)) | 5227 | ((eq base (point-min)) |
| @@ -5264,7 +5229,7 @@ comment at the start of cc-engine.el for more info." | |||
| 5264 | ((> base (- start try-size)) ; Can only happen if we hit point-min. | 5229 | ((> base (- start try-size)) ; Can only happen if we hit point-min. |
| 5265 | (car elt)) | 5230 | (car elt)) |
| 5266 | (t | 5231 | (t |
| 5267 | (c-determine-limit (- how-far-back count) base try-size)))))) | 5232 | (c-determine-limit (- how-far-back count) base (* 2 try-size))))))) |
| 5268 | 5233 | ||
| 5269 | (defun c-determine-+ve-limit (how-far &optional start-pos) | 5234 | (defun c-determine-+ve-limit (how-far &optional start-pos) |
| 5270 | ;; Return a buffer position about HOW-FAR non-literal characters forward | 5235 | ;; Return a buffer position about HOW-FAR non-literal characters forward |