aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Mackenzie2018-04-02 11:33:24 +0000
committerAlan Mackenzie2018-04-02 11:33:24 +0000
commitb393ecf8e288f1e1b6a8ac55006715fa1046a5d4 (patch)
tree759f1fa46dae0b8e05feca838dad739a6559a778
parent956c39d11d871d1b6cdf4bc13217e9678d12fd76 (diff)
downloademacs-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.el265
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,
4791i.e. don't stop at positions inside syntactic whitespace or string 4741i.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
4803Note that this function might do hidden buffer changes. See the 4753Note that this function might do hidden buffer changes. See the
4804comment at the start of cc-engine.el for more info." 4754comment 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