Commit | Line | Data |
---|---|---|
785eecbb RS |
1 | ;;; cc-engine.el --- core syntax guessing engine for CC mode |
2 | ||
034babe1 | 3 | ;; Copyright (C) 1985,1987,1992-2003, 2004, 2005 Free Software Foundation, Inc. |
785eecbb | 4 | |
d9e94c22 MS |
5 | ;; Authors: 1998- Martin Stjernholm |
6 | ;; 1992-1999 Barry A. Warsaw | |
785eecbb RS |
7 | ;; 1987 Dave Detlefs and Stewart Clamen |
8 | ;; 1985 Richard M. Stallman | |
0ec8351b | 9 | ;; Maintainer: bug-cc-mode@gnu.org |
785eecbb | 10 | ;; Created: 22-Apr-1997 (split from cc-mode.el) |
6430c434 | 11 | ;; Version: See cc-mode.el |
785eecbb RS |
12 | ;; Keywords: c languages oop |
13 | ||
14 | ;; This file is part of GNU Emacs. | |
15 | ||
16 | ;; GNU Emacs is free software; you can redistribute it and/or modify | |
17 | ;; it under the terms of the GNU General Public License as published by | |
18 | ;; the Free Software Foundation; either version 2, or (at your option) | |
19 | ;; any later version. | |
20 | ||
21 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
22 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | ;; GNU General Public License for more details. | |
25 | ||
26 | ;; You should have received a copy of the GNU General Public License | |
3efc2cd7 MS |
27 | ;; along with this program; see the file COPYING. If not, write to |
28 | ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
29 | ;; Boston, MA 02110-1301, USA. | |
785eecbb | 30 | |
3afbc435 PJ |
31 | ;;; Commentary: |
32 | ||
a66cd3ee MS |
33 | ;; The functions which have docstring documentation can be considered |
34 | ;; part of an API which other packages can use in CC Mode buffers. | |
35 | ;; Otoh, undocumented functions and functions with the documentation | |
36 | ;; in comments are considered purely internal and can change semantics | |
37 | ;; or even disappear in the future. | |
38 | ;; | |
39 | ;; (This policy applies to CC Mode as a whole, not just this file. It | |
40 | ;; probably also applies to many other Emacs packages, but here it's | |
41 | ;; clearly spelled out.) | |
42 | ||
d9e94c22 MS |
43 | ;; Hidden buffer changes |
44 | ;; | |
45 | ;; Various functions in CC Mode use text properties for caching and | |
46 | ;; syntactic markup purposes, and those of them that might modify such | |
47 | ;; properties are said to do "hidden buffer changes". They should be | |
48 | ;; used within `c-save-buffer-state' or a similar function that saves | |
49 | ;; and restores buffer modifiedness etc. | |
50 | ;; | |
51 | ;; Interactive functions are assumed to not do hidden buffer changes | |
52 | ;; (this isn't applicable in the specific parts of them that do real | |
53 | ;; changes, though). | |
54 | ;; | |
55 | ;; All other functions are assumed to do hidden buffer changes and | |
56 | ;; must thus be wrapped inside `c-save-buffer-state' if they're used | |
57 | ;; from any function that does not do hidden buffer changes. | |
58 | ;; | |
59 | ;; Every function, except the interactive ones, that doesn't do hidden | |
60 | ;; buffer changes have that explicitly stated in their docstring or | |
61 | ;; comment. | |
62 | ||
63 | ;; Use of text properties | |
64 | ;; | |
65 | ;; CC Mode uses several text properties internally to mark up various | |
66 | ;; positions, e.g. to improve speed and to eliminate glitches in | |
67 | ;; interactive refontification. | |
68 | ;; | |
7bfc3fdb MS |
69 | ;; Note: This doc is for internal use only. Other packages should not |
70 | ;; assume that these text properties are used as described here. | |
71 | ;; | |
d9e94c22 MS |
72 | ;; 'syntax-table |
73 | ;; Used to modify the syntax of some characters. Currently used to | |
74 | ;; mark the "<" and ">" of angle bracket parens with paren syntax. | |
75 | ;; | |
76 | ;; This property is used on single characters and is therefore | |
77 | ;; always treated as front and rear nonsticky (or start and end open | |
78 | ;; in XEmacs vocabulary). It's therefore installed on | |
79 | ;; `text-property-default-nonsticky' if that variable exists (Emacs | |
80 | ;; >= 21). | |
81 | ;; | |
82 | ;; 'c-is-sws and 'c-in-sws | |
83 | ;; Used by `c-forward-syntactic-ws' and `c-backward-syntactic-ws' to | |
84 | ;; speed them up. See the comment blurb before `c-put-is-sws' | |
85 | ;; below for further details. | |
86 | ;; | |
87 | ;; 'c-type | |
88 | ;; This property is used on single characters to mark positions with | |
89 | ;; special syntactic relevance of various sorts. It's primary use | |
90 | ;; is to avoid glitches when multiline constructs are refontified | |
91 | ;; interactively (on font lock decoration level 3). It's cleared in | |
92 | ;; a region before it's fontified and is then put on relevant chars | |
93 | ;; in that region as they are encountered during the fontification. | |
94 | ;; The value specifies the kind of position: | |
95 | ;; | |
96 | ;; 'c-decl-arg-start | |
97 | ;; Put on the last char of the token preceding each declaration | |
98 | ;; inside a declaration style arglist (typically in a function | |
99 | ;; prototype). | |
100 | ;; | |
101 | ;; 'c-decl-end | |
102 | ;; Put on the last char of the token preceding a declaration. | |
103 | ;; This is used in cases where declaration boundaries can't be | |
104 | ;; recognized simply by looking for a token like ";" or "}". | |
105 | ;; `c-type-decl-end-used' must be set if this is used (see also | |
106 | ;; `c-find-decl-spots'). | |
107 | ;; | |
108 | ;; 'c-<>-arg-sep | |
109 | ;; Put on the commas that separate arguments in angle bracket | |
110 | ;; arglists like C++ template arglists. | |
111 | ;; | |
112 | ;; 'c-decl-id-start and 'c-decl-type-start | |
113 | ;; Put on the last char of the token preceding each declarator | |
114 | ;; in the declarator list of a declaration. They are also used | |
115 | ;; between the identifiers cases like enum declarations. | |
116 | ;; 'c-decl-type-start is used when the declarators are types, | |
117 | ;; 'c-decl-id-start otherwise. | |
118 | ;; | |
119 | ;; 'c-awk-NL-prop | |
120 | ;; Used in AWK mode to mark the various kinds of newlines. See | |
121 | ;; cc-awk.el. | |
122 | ||
3afbc435 PJ |
123 | ;;; Code: |
124 | ||
0ec8351b | 125 | (eval-when-compile |
51f606de | 126 | (let ((load-path |
130c507e GM |
127 | (if (and (boundp 'byte-compile-dest-file) |
128 | (stringp byte-compile-dest-file)) | |
129 | (cons (file-name-directory byte-compile-dest-file) load-path) | |
51f606de | 130 | load-path))) |
d9e94c22 | 131 | (load "cc-bytecomp" nil t))) |
130c507e GM |
132 | |
133 | (cc-require 'cc-defs) | |
d9e94c22 | 134 | (cc-require-when-compile 'cc-langs) |
130c507e | 135 | (cc-require 'cc-vars) |
d9e94c22 MS |
136 | |
137 | ;; Some functions/constants in cc-awk.el that are called/referenced here. | |
138 | ;; (Can't use cc-require due to cyclicity.) | |
139 | (cc-bytecomp-defun c-awk-unstick-NL-prop) | |
140 | (cc-bytecomp-defun c-awk-clear-NL-props) | |
141 | (cc-bytecomp-defvar awk-mode-syntax-table) | |
142 | (cc-bytecomp-defun c-awk-backward-syntactic-ws) | |
143 | (cc-bytecomp-defun c-awk-after-logical-semicolon) | |
144 | (cc-bytecomp-defun c-awk-NL-prop-not-set) | |
145 | (cc-bytecomp-defun c-awk-completed-stmt-ws-ends-line-p) | |
146 | (cc-bytecomp-defun c-awk-completed-stmt-ws-ends-prev-line-p) | |
147 | (cc-bytecomp-defun c-awk-prev-line-incomplete-p) | |
148 | (cc-bytecomp-defun c-awk-after-change) | |
130c507e GM |
149 | |
150 | ;; Silence the compiler. | |
151 | (cc-bytecomp-defun buffer-syntactic-context) ; XEmacs | |
0ec8351b | 152 | |
51f606de | 153 | \f |
d9e94c22 MS |
154 | ;; Make declarations for all the `c-lang-defvar' variables in cc-langs. |
155 | ||
156 | (defmacro c-declare-lang-variables () | |
157 | `(progn | |
485fe977 RS |
158 | ,@(apply 'nconc |
159 | (mapcar (lambda (init) | |
160 | `(,(if (elt init 2) | |
161 | `(defvar ,(car init) nil ,(elt init 2)) | |
162 | `(defvar ,(car init) nil)) | |
163 | (make-variable-buffer-local ',(car init)))) | |
164 | (cdr c-lang-variable-inits))))) | |
d9e94c22 MS |
165 | (c-declare-lang-variables) |
166 | ||
167 | \f | |
168 | ;;; Internal state variables. | |
169 | ||
170 | ;; Internal state of hungry delete key feature | |
171 | (defvar c-hungry-delete-key nil) | |
172 | (make-variable-buffer-local 'c-hungry-delete-key) | |
173 | ||
174 | ;; Internal state of auto newline feature. | |
175 | (defvar c-auto-newline nil) | |
176 | (make-variable-buffer-local 'c-auto-newline) | |
177 | ||
178 | ;; Internal auto-newline/hungry-delete designation string for mode line. | |
179 | (defvar c-auto-hungry-string nil) | |
180 | (make-variable-buffer-local 'c-auto-hungry-string) | |
181 | ||
a66cd3ee MS |
182 | (defun c-calculate-state (arg prevstate) |
183 | ;; Calculate the new state of PREVSTATE, t or nil, based on arg. If | |
184 | ;; arg is nil or zero, toggle the state. If arg is negative, turn | |
185 | ;; the state off, and if arg is positive, turn the state on | |
186 | (if (or (not arg) | |
187 | (zerop (setq arg (prefix-numeric-value arg)))) | |
188 | (not prevstate) | |
189 | (> arg 0))) | |
190 | ||
d9e94c22 | 191 | ;; Dynamically bound cache for `c-in-literal'. |
130c507e | 192 | (defvar c-in-literal-cache t) |
d9e94c22 MS |
193 | |
194 | ;; Must be set in buffers where the `c-type' text property might be used | |
195 | ;; with the value `c-decl-end'. | |
196 | (defvar c-type-decl-end-used nil) | |
197 | (make-variable-buffer-local 'c-type-decl-end-used) | |
198 | ||
199 | \f | |
037558bf MS |
200 | ;; Basic handling of preprocessor directives. |
201 | ||
202 | ;; This is a dynamically bound cache used together with | |
203 | ;; `c-query-macro-start' and `c-query-and-set-macro-start'. It only | |
204 | ;; works as long as point doesn't cross a macro boundary. | |
205 | (defvar c-macro-start 'unknown) | |
206 | ||
207 | (defsubst c-query-and-set-macro-start () | |
208 | ;; This function does not do any hidden buffer changes. | |
209 | (if (symbolp c-macro-start) | |
210 | (setq c-macro-start (save-excursion | |
211 | (and (c-beginning-of-macro) | |
212 | (point)))) | |
213 | c-macro-start)) | |
214 | ||
215 | (defsubst c-query-macro-start () | |
216 | ;; This function does not do any hidden buffer changes. | |
217 | (if (symbolp c-macro-start) | |
218 | (save-excursion | |
219 | (and (c-beginning-of-macro) | |
220 | (point))) | |
221 | c-macro-start)) | |
222 | ||
223 | (defun c-beginning-of-macro (&optional lim) | |
224 | "Go to the beginning of a preprocessor directive. | |
225 | Leave point at the beginning of the directive and return t if in one, | |
226 | otherwise return nil and leave point unchanged. | |
227 | ||
228 | This function does not do any hidden buffer changes." | |
229 | (when c-opt-cpp-prefix | |
230 | (let ((here (point))) | |
231 | (save-restriction | |
232 | (if lim (narrow-to-region lim (point-max))) | |
233 | (beginning-of-line) | |
234 | (while (eq (char-before (1- (point))) ?\\) | |
235 | (forward-line -1)) | |
236 | (back-to-indentation) | |
237 | (if (and (<= (point) here) | |
238 | (looking-at c-opt-cpp-start)) | |
239 | t | |
240 | (goto-char here) | |
241 | nil))))) | |
242 | ||
243 | (defun c-end-of-macro () | |
244 | "Go to the end of a preprocessor directive. | |
245 | More accurately, move point to the end of the closest following line | |
246 | that doesn't end with a line continuation backslash. | |
247 | ||
248 | This function does not do any hidden buffer changes." | |
249 | (while (progn | |
250 | (end-of-line) | |
251 | (when (and (eq (char-before) ?\\) | |
252 | (not (eobp))) | |
253 | (forward-char) | |
254 | t)))) | |
255 | ||
256 | (defun c-forward-to-cpp-define-body () | |
257 | ;; Assuming point is at the "#" that introduces a preprocessor | |
258 | ;; directive, it's moved forward to the start of the definition body | |
259 | ;; if it's a "#define". Non-nil is returned in this case, in all | |
260 | ;; other cases nil is returned and point isn't moved. | |
261 | (when (and (looking-at | |
262 | (concat "#[ \t]*" | |
263 | "define[ \t]+\\(\\sw\\|_\\)+\\(\([^\)]*\)\\)?" | |
264 | "\\([ \t]\\|\\\\\n\\)*")) | |
265 | (not (= (match-end 0) (c-point 'eol)))) | |
266 | (goto-char (match-end 0)))) | |
267 | ||
268 | \f | |
d9e94c22 MS |
269 | ;;; Basic utility functions. |
270 | ||
271 | (defun c-syntactic-content (from to) | |
272 | ;; Return the given region as a string where all syntactic | |
273 | ;; whitespace is removed or, where necessary, replaced with a single | |
274 | ;; space. | |
275 | (save-excursion | |
276 | (goto-char from) | |
277 | (let* ((parts (list nil)) (tail parts) pos) | |
278 | (while (re-search-forward c-syntactic-ws-start to t) | |
279 | (goto-char (setq pos (match-beginning 0))) | |
280 | (c-forward-syntactic-ws to) | |
281 | (if (= (point) pos) | |
282 | (forward-char) | |
283 | (if (and (> pos from) | |
284 | (< (point) to) | |
285 | (looking-at "\\w\\|\\s_") | |
286 | (save-excursion | |
287 | (goto-char (1- pos)) | |
288 | (looking-at "\\w\\|\\s_"))) | |
289 | (progn | |
290 | (setcdr tail (list (buffer-substring-no-properties from pos) | |
291 | " ")) | |
292 | (setq tail (cddr tail))) | |
293 | (setcdr tail (list (buffer-substring-no-properties from pos))) | |
294 | (setq tail (cdr tail))) | |
295 | (setq from (point)))) | |
296 | (setcdr tail (list (buffer-substring-no-properties from to))) | |
297 | (apply 'concat (cdr parts))))) | |
298 | ||
299 | (defsubst c-keyword-sym (keyword) | |
300 | ;; Return non-nil if the string KEYWORD is a known keyword. More | |
301 | ;; precisely, the value is the symbol for the keyword in | |
302 | ;; `c-keywords-obarray'. | |
303 | (intern-soft keyword c-keywords-obarray)) | |
304 | ||
305 | (defsubst c-keyword-member (keyword-sym lang-constant) | |
306 | ;; Return non-nil if the symbol KEYWORD-SYM, as returned by | |
307 | ;; `c-keyword-sym', is a member of LANG-CONSTANT, which is the name | |
308 | ;; of a language constant that ends with "-kwds". If KEYWORD-SYM is | |
309 | ;; nil then the result is nil. | |
310 | (get keyword-sym lang-constant)) | |
311 | ||
312 | ;; String syntax chars, suitable for skip-syntax-(forward|backward). | |
313 | (defconst c-string-syntax (if (memq 'gen-string-delim c-emacs-features) | |
314 | "\"|" | |
315 | "\"")) | |
316 | ||
317 | ;; Regexp matching string start syntax. | |
318 | (defconst c-string-limit-regexp (if (memq 'gen-string-delim c-emacs-features) | |
319 | "\\s\"\\|\\s|" | |
320 | "\\s\"")) | |
321 | ||
322 | ;; Holds formatted error strings for the few cases where parse errors | |
323 | ;; are reported. | |
a66cd3ee | 324 | (defvar c-parsing-error nil) |
d9e94c22 MS |
325 | (make-variable-buffer-local 'c-parsing-error) |
326 | ||
327 | (defun c-echo-parsing-error (&optional quiet) | |
328 | ;; This function does not do any hidden buffer changes. | |
329 | (when (and c-report-syntactic-errors c-parsing-error (not quiet)) | |
330 | (c-benign-error "%s" c-parsing-error)) | |
331 | c-parsing-error) | |
332 | ||
333 | ;; Faces given to comments and string literals. This is used in some | |
334 | ;; situations to speed up recognition; it isn't mandatory that font | |
335 | ;; locking is in use. This variable is extended with the face in | |
336 | ;; `c-doc-face-name' when fontification is activated in cc-fonts.el. | |
1e330469 | 337 | (defvar c-literal-faces |
bbf87c29 RS |
338 | '(font-lock-comment-face font-lock-string-face |
339 | font-lock-comment-delimiter-face)) | |
d9e94c22 | 340 | |
037558bf MS |
341 | (defun c-shift-line-indentation (shift-amt) |
342 | ;; This function does not do any hidden buffer changes. | |
343 | (let ((pos (- (point-max) (point))) | |
344 | (c-macro-start c-macro-start) | |
345 | tmp-char-inserted) | |
346 | (if (zerop shift-amt) | |
347 | nil | |
348 | (when (and (c-query-and-set-macro-start) | |
349 | (looking-at "[ \t]*\\\\$") | |
350 | (save-excursion | |
351 | (skip-chars-backward " \t") | |
352 | (bolp))) | |
353 | (insert ?x) | |
354 | (backward-char) | |
355 | (setq tmp-char-inserted t)) | |
356 | (unwind-protect | |
357 | (let ((col (current-indentation))) | |
358 | (delete-region (c-point 'bol) (c-point 'boi)) | |
359 | (beginning-of-line) | |
360 | (indent-to (+ col shift-amt))) | |
361 | (when tmp-char-inserted | |
362 | (delete-char 1)))) | |
363 | ;; If initial point was within line's indentation and we're not on | |
364 | ;; a line with a line continuation in a macro, position after the | |
365 | ;; indentation. Else stay at same point in text. | |
366 | (if (and (< (point) (c-point 'boi)) | |
367 | (not tmp-char-inserted)) | |
368 | (back-to-indentation) | |
369 | (if (> (- (point-max) pos) (point)) | |
370 | (goto-char (- (point-max) pos)))))) | |
371 | ||
d9e94c22 MS |
372 | \f |
373 | ;; Some debug tools to visualize various special positions. This | |
374 | ;; debug code isn't as portable as the rest of CC Mode. | |
375 | ||
376 | (cc-bytecomp-defun overlays-in) | |
377 | (cc-bytecomp-defun overlay-get) | |
378 | (cc-bytecomp-defun overlay-start) | |
379 | (cc-bytecomp-defun overlay-end) | |
380 | (cc-bytecomp-defun delete-overlay) | |
381 | (cc-bytecomp-defun overlay-put) | |
382 | (cc-bytecomp-defun make-overlay) | |
383 | ||
384 | (defun c-debug-add-face (beg end face) | |
385 | (c-save-buffer-state ((overlays (overlays-in beg end)) overlay) | |
386 | (while overlays | |
387 | (setq overlay (car overlays) | |
388 | overlays (cdr overlays)) | |
389 | (when (eq (overlay-get overlay 'face) face) | |
390 | (setq beg (min beg (overlay-start overlay)) | |
391 | end (max end (overlay-end overlay))) | |
392 | (delete-overlay overlay))) | |
393 | (overlay-put (make-overlay beg end) 'face face))) | |
394 | ||
395 | (defun c-debug-remove-face (beg end face) | |
396 | (c-save-buffer-state ((overlays (overlays-in beg end)) overlay | |
397 | (ol-beg beg) (ol-end end)) | |
398 | (while overlays | |
399 | (setq overlay (car overlays) | |
400 | overlays (cdr overlays)) | |
401 | (when (eq (overlay-get overlay 'face) face) | |
402 | (setq ol-beg (min ol-beg (overlay-start overlay)) | |
403 | ol-end (max ol-end (overlay-end overlay))) | |
404 | (delete-overlay overlay))) | |
405 | (when (< ol-beg beg) | |
406 | (overlay-put (make-overlay ol-beg beg) 'face face)) | |
407 | (when (> ol-end end) | |
408 | (overlay-put (make-overlay end ol-end) 'face face)))) | |
409 | ||
410 | \f | |
411 | ;; `c-beginning-of-statement-1' and accompanying stuff. | |
130c507e | 412 | |
64001211 RS |
413 | ;; KLUDGE ALERT: c-maybe-labelp is used to pass information between |
414 | ;; c-crosses-statement-barrier-p and c-beginning-of-statement-1. A | |
415 | ;; better way should be implemented, but this will at least shut up | |
416 | ;; the byte compiler. | |
417 | (defvar c-maybe-labelp nil) | |
418 | ||
d9e94c22 MS |
419 | ;; New awk-compatible version of c-beginning-of-statement-1, ACM 2002/6/22 |
420 | ||
a66cd3ee MS |
421 | ;; Macros used internally in c-beginning-of-statement-1 for the |
422 | ;; automaton actions. | |
423 | (defmacro c-bos-push-state () | |
424 | '(setq stack (cons (cons state saved-pos) | |
425 | stack))) | |
426 | (defmacro c-bos-pop-state (&optional do-if-done) | |
427 | `(if (setq state (car (car stack)) | |
428 | saved-pos (cdr (car stack)) | |
429 | stack (cdr stack)) | |
430 | t | |
431 | ,do-if-done | |
432 | (throw 'loop nil))) | |
433 | (defmacro c-bos-pop-state-and-retry () | |
434 | '(throw 'loop (setq state (car (car stack)) | |
435 | saved-pos (cdr (car stack)) | |
436 | ;; Throw nil if stack is empty, else throw non-nil. | |
437 | stack (cdr stack)))) | |
438 | (defmacro c-bos-save-pos () | |
439 | '(setq saved-pos (vector pos tok ptok pptok))) | |
440 | (defmacro c-bos-restore-pos () | |
441 | '(unless (eq (elt saved-pos 0) start) | |
442 | (setq pos (elt saved-pos 0) | |
443 | tok (elt saved-pos 1) | |
444 | ptok (elt saved-pos 2) | |
445 | pptok (elt saved-pos 3)) | |
446 | (goto-char pos) | |
447 | (setq sym nil))) | |
448 | (defmacro c-bos-save-error-info (missing got) | |
449 | `(setq saved-pos (vector pos ,missing ,got))) | |
450 | (defmacro c-bos-report-error () | |
451 | '(unless noerror | |
452 | (setq c-parsing-error | |
453 | (format "No matching `%s' found for `%s' on line %d" | |
454 | (elt saved-pos 1) | |
455 | (elt saved-pos 2) | |
456 | (1+ (count-lines (point-min) | |
457 | (c-point 'bol (elt saved-pos 0)))))))) | |
458 | ||
459 | (defun c-beginning-of-statement-1 (&optional lim ignore-labels | |
460 | noerror comma-delim) | |
461 | "Move to the start of the current statement or declaration, or to | |
462 | the previous one if already at the beginning of one. Only | |
463 | statements/declarations on the same level are considered, i.e. don't | |
464 | move into or out of sexps (not even normal expression parentheses). | |
465 | ||
d9e94c22 MS |
466 | Stop at statement continuation tokens like \"else\", \"catch\", |
467 | \"finally\" and the \"while\" in \"do ... while\" if the start point | |
468 | is within the continuation. If starting at such a token, move to the | |
469 | corresponding statement start. If at the beginning of a statement, | |
470 | move to the closest containing statement if there is any. This might | |
471 | also stop at a continuation clause. | |
a66cd3ee MS |
472 | |
473 | Labels are treated as separate statements if IGNORE-LABELS is non-nil. | |
474 | The function is not overly intelligent in telling labels from other | |
475 | uses of colons; if used outside a statement context it might trip up | |
476 | on e.g. inherit colons, so IGNORE-LABELS should be used then. There | |
477 | should be no such mistakes in a statement context, however. | |
478 | ||
479 | Macros are ignored unless point is within one, in which case the | |
480 | content of the macro is treated as normal code. Aside from any normal | |
481 | statement starts found in it, stop at the first token of the content | |
482 | in the macro, i.e. the expression of an \"#if\" or the start of the | |
483 | definition in a \"#define\". Also stop at start of macros before | |
484 | leaving them. | |
485 | ||
486 | Return 'label if stopped at a label, 'same if stopped at the beginning | |
487 | of the current statement, 'up if stepped to a containing statement, | |
488 | 'previous if stepped to a preceding statement, 'beginning if stepped | |
489 | from a statement continuation clause to its start clause, or 'macro if | |
490 | stepped to a macro start. Note that 'same and not 'label is returned | |
491 | if stopped at the same label without crossing the colon character. | |
492 | ||
493 | LIM may be given to limit the search. If the search hits the limit, | |
494 | point will be left at the closest following token, or at the start | |
495 | position if that is less ('same is returned in this case). | |
496 | ||
497 | NOERROR turns off error logging to `c-parsing-error'. | |
498 | ||
499 | Normally only ';' is considered to delimit statements, but if | |
500 | COMMA-DELIM is non-nil then ',' is treated likewise." | |
501 | ||
d9e94c22 MS |
502 | ;; The bulk of this function is a pushdown automaton that looks at statement |
503 | ;; boundaries and the tokens (such as "while") in c-opt-block-stmt-key. Its | |
504 | ;; purpose is to keep track of nested statements, ensuring that such | |
505 | ;; statments are skipped over in their entirety (somewhat akin to what C-M-p | |
506 | ;; does with nested braces/brackets/parentheses). | |
a66cd3ee MS |
507 | ;; |
508 | ;; Note: The position of a boundary is the following token. | |
509 | ;; | |
d9e94c22 MS |
510 | ;; Beginning with the current token (the one following point), move back one |
511 | ;; sexp at a time (where a sexp is, more or less, either a token or the | |
512 | ;; entire contents of a brace/bracket/paren pair). Each time a statement | |
513 | ;; boundary is crossed or a "while"-like token is found, update the state of | |
514 | ;; the PDA. Stop at the beginning of a statement when the stack (holding | |
515 | ;; nested statement info) is empty and the position has been moved. | |
516 | ;; | |
517 | ;; The following variables constitute the PDA: | |
518 | ;; | |
519 | ;; sym: This is either the "while"-like token (e.g. 'for) we've just | |
520 | ;; scanned back over, 'boundary if we've just gone back over a | |
521 | ;; statement boundary, or nil otherwise. | |
522 | ;; state: takes one of the values (nil else else-boundary while | |
523 | ;; while-boundary catch catch-boundary). | |
524 | ;; nil means "no "while"-like token yet scanned". | |
525 | ;; 'else, for example, means "just gone back over an else". | |
526 | ;; 'else-boundary means "just gone back over a statement boundary | |
527 | ;; immediately after having gone back over an else". | |
528 | ;; saved-pos: A vector of either saved positions (tok ptok pptok, etc.) or | |
529 | ;; of error reporting information. | |
530 | ;; stack: The stack onto which the PDA pushes its state. Each entry | |
531 | ;; consists of a saved value of state and saved-pos. An entry is | |
532 | ;; pushed when we move back over a "continuation" token (e.g. else) | |
533 | ;; and popped when we encounter the corresponding opening token | |
534 | ;; (e.g. if). | |
535 | ;; | |
536 | ;; | |
537 | ;; The following diagram briefly outlines the PDA. | |
a66cd3ee MS |
538 | ;; |
539 | ;; Common state: | |
d9e94c22 MS |
540 | ;; "else": Push state, goto state `else'. |
541 | ;; "while": Push state, goto state `while'. | |
542 | ;; "catch" or "finally": Push state, goto state `catch'. | |
543 | ;; boundary: Pop state. | |
a66cd3ee MS |
544 | ;; other: Do nothing special. |
545 | ;; | |
d9e94c22 MS |
546 | ;; State `else': |
547 | ;; boundary: Goto state `else-boundary'. | |
548 | ;; other: Error, pop state, retry token. | |
549 | ;; | |
550 | ;; State `else-boundary': | |
551 | ;; "if": Pop state. | |
552 | ;; boundary: Error, pop state. | |
553 | ;; other: See common state. | |
554 | ;; | |
555 | ;; State `while': | |
556 | ;; boundary: Save position, goto state `while-boundary'. | |
557 | ;; other: Pop state, retry token. | |
558 | ;; | |
559 | ;; State `while-boundary': | |
560 | ;; "do": Pop state. | |
561 | ;; boundary: Restore position if it's not at start, pop state. [*see below] | |
562 | ;; other: See common state. | |
563 | ;; | |
564 | ;; State `catch': | |
565 | ;; boundary: Goto state `catch-boundary'. | |
566 | ;; other: Error, pop state, retry token. | |
567 | ;; | |
568 | ;; State `catch-boundary': | |
569 | ;; "try": Pop state. | |
570 | ;; "catch": Goto state `catch'. | |
571 | ;; boundary: Error, pop state. | |
572 | ;; other: See common state. | |
573 | ;; | |
574 | ;; [*] In the `while-boundary' state, we had pushed a 'while state, and were | |
575 | ;; searching for a "do" which would have opened a do-while. If we didn't | |
576 | ;; find it, we discard the analysis done since the "while", go back to this | |
577 | ;; token in the buffer and restart the scanning there, this time WITHOUT | |
578 | ;; pushing the 'while state onto the stack. | |
579 | ;; | |
a66cd3ee MS |
580 | ;; In addition to the above there is some special handling of labels |
581 | ;; and macros. | |
582 | ||
583 | (let ((case-fold-search nil) | |
584 | (start (point)) | |
585 | macro-start | |
586 | (delims (if comma-delim '(?\; ?,) '(?\;))) | |
587 | (c-stmt-delim-chars (if comma-delim | |
588 | c-stmt-delim-chars-with-comma | |
589 | c-stmt-delim-chars)) | |
590 | pos ; Current position. | |
d9e94c22 | 591 | boundary-pos ; Position of last stmt boundary character (e.g. ;). |
a66cd3ee MS |
592 | after-labels-pos ; Value of tok after first found colon. |
593 | last-label-pos ; Value of tok after last found colon. | |
d9e94c22 MS |
594 | sym ; Symbol just scanned back over (e.g. 'while or |
595 | ; 'boundary). See above | |
596 | state ; Current state in the automaton. See above. | |
597 | saved-pos ; Current saved positions. See above | |
a66cd3ee | 598 | stack ; Stack of conses (state . saved-pos). |
d9e94c22 | 599 | (cond-key (or c-opt-block-stmt-key ; regexp which matches "for", "if", etc. |
a66cd3ee | 600 | "\\<\\>")) ; Matches nothing. |
d9e94c22 | 601 | (ret 'same) ; Return value. |
a66cd3ee MS |
602 | tok ptok pptok ; Pos of last three sexps or bounds. |
603 | c-in-literal-cache c-maybe-labelp saved) | |
604 | ||
605 | (save-restriction | |
606 | (if lim (narrow-to-region lim (point-max))) | |
607 | ||
608 | (if (save-excursion | |
609 | (and (c-beginning-of-macro) | |
610 | (/= (point) start))) | |
611 | (setq macro-start (point))) | |
612 | ||
d9e94c22 | 613 | ;; Try to skip back over unary operator characters, to register |
a66cd3ee MS |
614 | ;; that we've moved. |
615 | (while (progn | |
616 | (setq pos (point)) | |
7bfc3fdb MS |
617 | (if (c-mode-is-new-awk-p) |
618 | (c-awk-backward-syntactic-ws) | |
619 | (c-backward-syntactic-ws)) | |
d9e94c22 MS |
620 | (/= (skip-chars-backward "-+!*&~@`#") 0))) ; ACM, 2002/5/31; |
621 | ; Make a variable in | |
622 | ; cc-langs.el, maybe | |
623 | ||
624 | ;; Skip back over any semicolon here. If it was a bare semicolon, we're | |
625 | ;; done. Later on we ignore the boundaries for statements that doesn't | |
626 | ;; contain any sexp. The only thing that is affected is that the error | |
627 | ;; checking is a little less strict, and we really don't bother. | |
a66cd3ee MS |
628 | (if (and (memq (char-before) delims) |
629 | (progn (forward-char -1) | |
630 | (setq saved (point)) | |
d9e94c22 MS |
631 | (if (c-mode-is-new-awk-p) |
632 | (c-awk-backward-syntactic-ws) | |
633 | (c-backward-syntactic-ws)) | |
a66cd3ee MS |
634 | (or (memq (char-before) delims) |
635 | (memq (char-before) '(?: nil)) | |
d9e94c22 MS |
636 | (eq (char-syntax (char-before)) ?\() |
637 | (and (c-mode-is-new-awk-p) | |
638 | (c-awk-after-logical-semicolon))))) ; ACM 2002/6/22 | |
639 | ;; ACM, 2002/7/20: What about giving a limit to the above function? | |
640 | ;; ACM, 2003/6/16: The above two lines (checking for | |
641 | ;; awk-logical-semicolon) are probably redundant after rewriting | |
642 | ;; c-awk-backward-syntactic-ws. | |
a66cd3ee MS |
643 | (setq ret 'previous |
644 | pos saved) | |
645 | ||
646 | ;; Begin at start and not pos to detect macros if we stand | |
647 | ;; directly after the #. | |
648 | (goto-char start) | |
649 | (if (looking-at "\\<\\|\\W") | |
650 | ;; Record this as the first token if not starting inside it. | |
651 | (setq tok start)) | |
652 | ||
d9e94c22 MS |
653 | ;; The following while loop goes back one sexp (balanced parens, |
654 | ;; etc. with contents, or symbol or suchlike) each iteration. This | |
655 | ;; movement is accomplished with a call to scan-sexps approx 130 lines | |
656 | ;; below. | |
a66cd3ee MS |
657 | (while |
658 | (catch 'loop ;; Throw nil to break, non-nil to continue. | |
659 | (cond | |
d9e94c22 MS |
660 | ;; Check for macro start. Take this out for AWK Mode (ACM, 2002/5/31) |
661 | ;; NO!! just make sure macro-start is nil in AWK Mode (ACM, 2002/6/22) | |
662 | ;; It always is (ACM, 2002/6/23) | |
a66cd3ee MS |
663 | ((save-excursion |
664 | (and macro-start | |
a66cd3ee MS |
665 | (progn (skip-chars-backward " \t") |
666 | (eq (char-before) ?#)) | |
667 | (progn (setq saved (1- (point))) | |
668 | (beginning-of-line) | |
669 | (not (eq (char-before (1- (point))) ?\\))) | |
d9e94c22 | 670 | (looking-at c-opt-cpp-start) |
a66cd3ee MS |
671 | (progn (skip-chars-forward " \t") |
672 | (eq (point) saved)))) | |
673 | (goto-char saved) | |
674 | (if (and (c-forward-to-cpp-define-body) | |
675 | (progn (c-forward-syntactic-ws start) | |
676 | (< (point) start))) | |
677 | ;; Stop at the first token in the content of the macro. | |
678 | (setq pos (point) | |
679 | ignore-labels t) ; Avoid the label check on exit. | |
680 | (setq pos saved | |
681 | ret 'macro | |
682 | ignore-labels t)) | |
683 | (throw 'loop nil)) | |
684 | ||
d9e94c22 MS |
685 | ;; Do a round through the automaton if we've just passed a |
686 | ;; statement boundary or passed a "while"-like token. | |
a66cd3ee MS |
687 | ((or sym |
688 | (and (looking-at cond-key) | |
689 | (setq sym (intern (match-string 1))))) | |
690 | ||
691 | (when (and (< pos start) (null stack)) | |
692 | (throw 'loop nil)) | |
693 | ||
d9e94c22 MS |
694 | ;; The PDA state handling. |
695 | ;; | |
037558bf | 696 | ;; Refer to the description of the PDA in the opening |
d9e94c22 MS |
697 | ;; comments. In the following OR form, the first leaf |
698 | ;; attempts to handles one of the specific actions detailed | |
699 | ;; (e.g., finding token "if" whilst in state `else-boundary'). | |
700 | ;; We drop through to the second leaf (which handles common | |
701 | ;; state) if no specific handler is found in the first cond. | |
702 | ;; If a parsing error is detected (e.g. an "else" with no | |
703 | ;; preceding "if"), we throw to the enclosing catch. | |
704 | ;; | |
705 | ;; Note that the (eq state 'else) means | |
706 | ;; "we've just passed an else", NOT "we're looking for an | |
707 | ;; else". | |
a66cd3ee MS |
708 | (or (cond |
709 | ((eq state 'else) | |
710 | (if (eq sym 'boundary) | |
711 | (setq state 'else-boundary) | |
712 | (c-bos-report-error) | |
713 | (c-bos-pop-state-and-retry))) | |
714 | ||
715 | ((eq state 'else-boundary) | |
716 | (cond ((eq sym 'if) | |
717 | (c-bos-pop-state (setq ret 'beginning))) | |
718 | ((eq sym 'boundary) | |
719 | (c-bos-report-error) | |
720 | (c-bos-pop-state)))) | |
721 | ||
722 | ((eq state 'while) | |
723 | (if (and (eq sym 'boundary) | |
724 | ;; Since this can cause backtracking we do a | |
725 | ;; little more careful analysis to avoid it: | |
726 | ;; If there's a label in front of the while | |
727 | ;; it can't be part of a do-while. | |
728 | (not after-labels-pos)) | |
729 | (progn (c-bos-save-pos) | |
730 | (setq state 'while-boundary)) | |
d9e94c22 | 731 | (c-bos-pop-state-and-retry))) ; Can't be a do-while |
a66cd3ee MS |
732 | |
733 | ((eq state 'while-boundary) | |
734 | (cond ((eq sym 'do) | |
735 | (c-bos-pop-state (setq ret 'beginning))) | |
d9e94c22 MS |
736 | ((eq sym 'boundary) ; isn't a do-while |
737 | (c-bos-restore-pos) ; the position of the while | |
738 | (c-bos-pop-state)))) ; no longer searching for do. | |
a66cd3ee MS |
739 | |
740 | ((eq state 'catch) | |
741 | (if (eq sym 'boundary) | |
742 | (setq state 'catch-boundary) | |
743 | (c-bos-report-error) | |
744 | (c-bos-pop-state-and-retry))) | |
745 | ||
746 | ((eq state 'catch-boundary) | |
747 | (cond | |
748 | ((eq sym 'try) | |
749 | (c-bos-pop-state (setq ret 'beginning))) | |
750 | ((eq sym 'catch) | |
751 | (setq state 'catch)) | |
752 | ((eq sym 'boundary) | |
753 | (c-bos-report-error) | |
754 | (c-bos-pop-state))))) | |
755 | ||
d9e94c22 MS |
756 | ;; This is state common. We get here when the previous |
757 | ;; cond statement found no particular state handler. | |
a66cd3ee | 758 | (cond ((eq sym 'boundary) |
d9e94c22 MS |
759 | ;; If we have a boundary at the start |
760 | ;; position we push a frame to go to the | |
761 | ;; previous statement. | |
762 | (if (>= pos start) | |
763 | (c-bos-push-state) | |
764 | (c-bos-pop-state))) | |
a66cd3ee MS |
765 | ((eq sym 'else) |
766 | (c-bos-push-state) | |
767 | (c-bos-save-error-info 'if 'else) | |
768 | (setq state 'else)) | |
769 | ((eq sym 'while) | |
770 | (when (or (not pptok) | |
d9e94c22 MS |
771 | (memq (char-after pptok) delims) |
772 | (and (c-mode-is-new-awk-p) | |
773 | (or | |
774 | ;; might we be calling this from | |
775 | ;; c-awk-after-if-do-for-while-condition-p? | |
776 | ;; If so, avoid infinite recursion. | |
777 | (and (eq (point) start) | |
778 | (c-awk-NL-prop-not-set)) | |
779 | ;; The following may recursively | |
780 | ;; call this function. | |
781 | (c-awk-completed-stmt-ws-ends-line-p pptok)))) | |
a66cd3ee MS |
782 | ;; Since this can cause backtracking we do a |
783 | ;; little more careful analysis to avoid it: If | |
784 | ;; the while isn't followed by a semicolon it | |
785 | ;; can't be a do-while. | |
d9e94c22 | 786 | ;; ACM, 2002/5/31; IT CAN IN AWK Mode. ;-( |
a66cd3ee MS |
787 | (c-bos-push-state) |
788 | (setq state 'while))) | |
789 | ((memq sym '(catch finally)) | |
790 | (c-bos-push-state) | |
791 | (c-bos-save-error-info 'try sym) | |
792 | (setq state 'catch)))) | |
793 | ||
794 | (when c-maybe-labelp | |
795 | ;; We're either past a statement boundary or at the | |
796 | ;; start of a statement, so throw away any label data | |
797 | ;; for the previous one. | |
798 | (setq after-labels-pos nil | |
799 | last-label-pos nil | |
800 | c-maybe-labelp nil)))) | |
801 | ||
d9e94c22 MS |
802 | ;; Step to the previous sexp, but not if we crossed a |
803 | ;; boundary, since that doesn't consume an sexp. | |
a66cd3ee MS |
804 | (if (eq sym 'boundary) |
805 | (setq ret 'previous) | |
d9e94c22 MS |
806 | |
807 | ;; HERE IS THE SINGLE PLACE INSIDE THE PDA LOOP WHERE WE MOVE | |
808 | ;; BACKWARDS THROUGH THE SOURCE. The following loop goes back | |
809 | ;; one sexp and then only loops in special circumstances (line | |
810 | ;; continuations and skipping past entire macros). | |
a66cd3ee | 811 | (while |
041ec7f6 | 812 | (progn |
a66cd3ee | 813 | (or (c-safe (goto-char (scan-sexps (point) -1)) t) |
d9e94c22 MS |
814 | ;; Give up if we hit an unbalanced block. |
815 | ;; Since the stack won't be empty the code | |
816 | ;; below will report a suitable error. | |
a66cd3ee MS |
817 | (throw 'loop nil)) |
818 | (cond ((looking-at "\\\\$") | |
819 | ;; Step again if we hit a line continuation. | |
820 | t) | |
821 | (macro-start | |
822 | ;; If we started inside a macro then this | |
823 | ;; sexp is always interesting. | |
824 | nil) | |
d9e94c22 | 825 | ((not (c-mode-is-new-awk-p)) ; Changed from t, ACM 2002/6/25 |
a66cd3ee MS |
826 | ;; Otherwise check that we didn't step |
827 | ;; into a macro from the end. | |
828 | (let ((macro-start | |
829 | (save-excursion | |
830 | (and (c-beginning-of-macro) | |
831 | (point))))) | |
832 | (when macro-start | |
833 | (goto-char macro-start) | |
834 | t)))))) | |
835 | ||
d9e94c22 | 836 | ;; Did the last movement by a sexp cross a statement boundary? |
a66cd3ee MS |
837 | (when (save-excursion |
838 | (if (if (eq (char-after) ?{) | |
839 | (c-looking-at-inexpr-block lim nil) | |
d9e94c22 MS |
840 | (looking-at "\\s\(")) |
841 | ||
842 | ;; Should not include the paren sexp we've | |
843 | ;; passed over in the boundary check. | |
844 | (if (> (point) (- pos 100)) | |
845 | (c-forward-sexp 1) | |
846 | ||
847 | ;; Find its end position this way instead of | |
848 | ;; moving forward if the sexp is large. | |
849 | (goto-char pos) | |
850 | (while | |
851 | (progn | |
852 | (goto-char (1+ (c-down-list-backward))) | |
853 | (unless macro-start | |
854 | ;; Check that we didn't step into | |
855 | ;; a macro from the end. | |
856 | (let ((macro-start | |
857 | (save-excursion | |
858 | (and (c-beginning-of-macro) | |
859 | (point))))) | |
860 | (when macro-start | |
861 | (goto-char macro-start) | |
862 | t))))))) | |
863 | ||
a66cd3ee MS |
864 | (setq boundary-pos (c-crosses-statement-barrier-p |
865 | (point) pos))) | |
d9e94c22 | 866 | |
a66cd3ee MS |
867 | (setq pptok ptok |
868 | ptok tok | |
869 | tok boundary-pos | |
870 | sym 'boundary) | |
d9e94c22 | 871 | (throw 'loop t))) ; like a C "continue". Analyze the next sexp. |
a66cd3ee | 872 | |
037558bf MS |
873 | (when (and (numberp c-maybe-labelp) |
874 | (not ignore-labels) | |
875 | (not (looking-at "\\s\("))) | |
a66cd3ee MS |
876 | ;; c-crosses-statement-barrier-p has found a colon, so |
877 | ;; we might be in a label now. | |
878 | (if (not after-labels-pos) | |
879 | (setq after-labels-pos tok)) | |
880 | (setq last-label-pos tok | |
881 | c-maybe-labelp t)) | |
882 | ||
883 | ;; ObjC method def? | |
884 | (when (and c-opt-method-key | |
885 | (setq saved (c-in-method-def-p))) | |
886 | (setq pos saved | |
887 | ignore-labels t) ; Avoid the label check on exit. | |
888 | (throw 'loop nil)) | |
889 | ||
d9e94c22 | 890 | ;; We've moved back by a sexp, so update the token positions. |
a66cd3ee MS |
891 | (setq sym nil |
892 | pptok ptok | |
893 | ptok tok | |
894 | tok (point) | |
d9e94c22 | 895 | pos tok))) ; Not nil (for the while loop). |
a66cd3ee MS |
896 | |
897 | ;; If the stack isn't empty there might be errors to report. | |
898 | (while stack | |
899 | (if (and (vectorp saved-pos) (eq (length saved-pos) 3)) | |
900 | (c-bos-report-error)) | |
901 | (setq saved-pos (cdr (car stack)) | |
902 | stack (cdr stack))) | |
903 | ||
904 | (when (and (eq ret 'same) | |
905 | (not (memq sym '(boundary ignore nil)))) | |
906 | ;; Need to investigate closer whether we've crossed | |
907 | ;; between a substatement and its containing statement. | |
908 | (if (setq saved (if (looking-at c-block-stmt-1-key) | |
909 | ptok | |
910 | pptok)) | |
911 | (cond ((> start saved) (setq pos saved)) | |
912 | ((= start saved) (setq ret 'up))))) | |
913 | ||
d9e94c22 MS |
914 | (when (and c-maybe-labelp |
915 | (not ignore-labels) | |
916 | (not (eq ret 'beginning)) | |
917 | after-labels-pos) | |
a66cd3ee MS |
918 | ;; We're in a label. Maybe we should step to the statement |
919 | ;; after it. | |
920 | (if (< after-labels-pos start) | |
921 | (setq pos after-labels-pos) | |
922 | (setq ret 'label) | |
923 | (if (< last-label-pos start) | |
924 | (setq pos last-label-pos))))) | |
925 | ||
926 | ;; Skip over the unary operators that can start the statement. | |
927 | (goto-char pos) | |
928 | (while (progn | |
7bfc3fdb MS |
929 | (if (c-mode-is-new-awk-p) |
930 | (c-awk-backward-syntactic-ws) | |
931 | (c-backward-syntactic-ws)) | |
d9e94c22 | 932 | (/= (skip-chars-backward "-+!*&~@`#") 0)) ; Hopefully the # won't hurt awk. |
a66cd3ee MS |
933 | (setq pos (point))) |
934 | (goto-char pos) | |
935 | ret))) | |
785eecbb | 936 | |
785eecbb | 937 | (defun c-crosses-statement-barrier-p (from to) |
a66cd3ee MS |
938 | "Return non-nil if buffer positions FROM to TO cross one or more |
939 | statement or declaration boundaries. The returned value is actually | |
d9e94c22 MS |
940 | the position of the earliest boundary char. FROM must not be within |
941 | a string or comment. | |
a66cd3ee MS |
942 | |
943 | The variable `c-maybe-labelp' is set to the position of the first `:' that | |
944 | might start a label (i.e. not part of `::' and not preceded by `?'). If a | |
945 | single `?' is found, then `c-maybe-labelp' is cleared." | |
946 | (let ((skip-chars c-stmt-delim-chars) | |
947 | lit-range) | |
948 | (save-excursion | |
949 | (catch 'done | |
950 | (goto-char from) | |
951 | (while (progn (skip-chars-forward skip-chars to) | |
785eecbb | 952 | (< (point) to)) |
d9e94c22 MS |
953 | (if (setq lit-range (c-literal-limits from)) ; Have we landed in a string/comment? |
954 | (progn (goto-char (setq from (cdr lit-range))) | |
955 | (if (and (c-mode-is-new-awk-p) (bolp)) ; ACM 2002/7/17. Make sure we | |
956 | (backward-char))) ; don't skip over a virtual semi-colon after an awk comment. :-( | |
a66cd3ee MS |
957 | (cond ((eq (char-after) ?:) |
958 | (forward-char) | |
959 | (if (and (eq (char-after) ?:) | |
960 | (< (point) to)) | |
961 | ;; Ignore scope operators. | |
962 | (forward-char) | |
963 | (setq c-maybe-labelp (1- (point))))) | |
964 | ((eq (char-after) ??) | |
965 | ;; A question mark. Can't be a label, so stop | |
966 | ;; looking for more : and ?. | |
967 | (setq c-maybe-labelp nil | |
968 | skip-chars (substring c-stmt-delim-chars 0 -2))) | |
d9e94c22 MS |
969 | ((and (eolp) ; Can only happen in AWK Mode |
970 | (not (c-awk-completed-stmt-ws-ends-line-p))) | |
971 | (forward-char)) | |
972 | ((and (c-mode-is-new-awk-p) | |
973 | (bolp) lit-range ; awk: comment/string ended prev line. | |
974 | (not (c-awk-completed-stmt-ws-ends-prev-line-p)))) | |
a66cd3ee MS |
975 | (t (throw 'done (point)))))) |
976 | nil)))) | |
785eecbb RS |
977 | |
978 | \f | |
d9e94c22 MS |
979 | ;; A set of functions that covers various idiosyncrasies in |
980 | ;; implementations of `forward-comment'. | |
981 | ||
982 | ;; Note: Some emacsen considers incorrectly that any line comment | |
983 | ;; ending with a backslash continues to the next line. I can't think | |
984 | ;; of any way to work around that in a reliable way without changing | |
985 | ;; the buffer, though. Suggestions welcome. ;) (No, temporarily | |
986 | ;; changing the syntax for backslash doesn't work since we must treat | |
987 | ;; escapes in string literals correctly.) | |
988 | ||
989 | (defun c-forward-single-comment () | |
990 | "Move forward past whitespace and the closest following comment, if any. | |
991 | Return t if a comment was found, nil otherwise. In either case, the | |
992 | point is moved past the following whitespace. Line continuations, | |
993 | i.e. a backslashes followed by line breaks, are treated as whitespace. | |
994 | The line breaks that end line comments are considered to be the | |
995 | comment enders, so the point will be put on the beginning of the next | |
996 | line if it moved past a line comment. | |
997 | ||
998 | This function does not do any hidden buffer changes." | |
999 | ||
1000 | (let ((start (point))) | |
1001 | (when (looking-at "\\([ \t\n\r\f\v]\\|\\\\[\n\r]\\)+") | |
1002 | (goto-char (match-end 0))) | |
1003 | ||
1004 | (when (forward-comment 1) | |
1005 | (if (eobp) | |
1006 | ;; Some emacsen (e.g. XEmacs 21) return t when moving | |
1007 | ;; forwards at eob. | |
1008 | nil | |
1009 | ||
1010 | ;; Emacs includes the ending newline in a b-style (c++) | |
1011 | ;; comment, but XEmacs doesn't. We depend on the Emacs | |
1012 | ;; behavior (which also is symmetric). | |
1013 | (if (and (eolp) (elt (parse-partial-sexp start (point)) 7)) | |
1014 | (condition-case nil (forward-char 1))) | |
1015 | ||
1016 | t)))) | |
1017 | ||
1018 | (defsubst c-forward-comments () | |
1019 | "Move forward past all following whitespace and comments. | |
1020 | Line continuations, i.e. a backslashes followed by line breaks, are | |
1021 | treated as whitespace. | |
1022 | ||
1023 | This function does not do any hidden buffer changes." | |
1024 | ||
1025 | (while (or | |
1026 | ;; If forward-comment in at least XEmacs 21 is given a large | |
1027 | ;; positive value, it'll loop all the way through if it hits | |
1028 | ;; eob. | |
1029 | (and (forward-comment 5) | |
1030 | ;; Some emacsen (e.g. XEmacs 21) return t when moving | |
1031 | ;; forwards at eob. | |
1032 | (not (eobp))) | |
1033 | ||
1034 | (when (looking-at "\\\\[\n\r]") | |
1035 | (forward-char 2) | |
1036 | t)))) | |
1037 | ||
1038 | (defun c-backward-single-comment () | |
1039 | "Move backward past whitespace and the closest preceding comment, if any. | |
1040 | Return t if a comment was found, nil otherwise. In either case, the | |
1041 | point is moved past the preceding whitespace. Line continuations, | |
1042 | i.e. a backslashes followed by line breaks, are treated as whitespace. | |
1043 | The line breaks that end line comments are considered to be the | |
1044 | comment enders, so the point cannot be at the end of the same line to | |
1045 | move over a line comment. | |
1046 | ||
1047 | This function does not do any hidden buffer changes." | |
1048 | ||
1049 | (let ((start (point))) | |
1050 | ;; When we got newline terminated comments, forward-comment in all | |
1051 | ;; supported emacsen so far will stop at eol of each line not | |
1052 | ;; ending with a comment when moving backwards. This corrects for | |
1053 | ;; that, and at the same time handles line continuations. | |
1054 | (while (progn | |
1055 | (skip-chars-backward " \t\n\r\f\v") | |
1056 | (and (looking-at "[\n\r]") | |
1057 | (eq (char-before) ?\\) | |
1058 | (< (point) start))) | |
1059 | (backward-char)) | |
1060 | ||
1061 | (if (bobp) | |
1062 | ;; Some emacsen (e.g. Emacs 19.34) return t when moving | |
1063 | ;; backwards at bob. | |
1064 | nil | |
1065 | ||
1066 | ;; Leave point after the closest following newline if we've | |
1067 | ;; backed up over any above, since forward-comment won't move | |
1068 | ;; backward over a line comment if point is at the end of the | |
1069 | ;; same line. | |
1070 | (re-search-forward "\\=\\s *[\n\r]" start t) | |
1071 | ||
1072 | (if (if (forward-comment -1) | |
1073 | (if (eolp) | |
1074 | ;; If forward-comment above succeeded and we're at eol | |
1075 | ;; then the newline we moved over above didn't end a | |
1076 | ;; line comment, so we give it another go. | |
1077 | (forward-comment -1) | |
1078 | t)) | |
1079 | ||
1080 | ;; Emacs <= 20 and XEmacs move back over the closer of a | |
1081 | ;; block comment that lacks an opener. | |
1082 | (if (looking-at "\\*/") | |
1083 | (progn (forward-char 2) nil) | |
1084 | t))))) | |
1085 | ||
1086 | (defsubst c-backward-comments () | |
1087 | "Move backward past all preceding whitespace and comments. | |
1088 | Line continuations, i.e. a backslashes followed by line breaks, are | |
1089 | treated as whitespace. The line breaks that end line comments are | |
1090 | considered to be the comment enders, so the point cannot be at the end | |
1091 | of the same line to move over a line comment. | |
1092 | ||
1093 | This function does not do any hidden buffer changes." | |
1094 | ||
1095 | (let ((start (point))) | |
1096 | (while (and | |
1097 | ;; `forward-comment' in some emacsen (e.g. Emacs 19.34) | |
1098 | ;; return t when moving backwards at bob. | |
1099 | (not (bobp)) | |
1100 | ||
1101 | (if (forward-comment -1) | |
1102 | (if (looking-at "\\*/") | |
1103 | ;; Emacs <= 20 and XEmacs move back over the | |
1104 | ;; closer of a block comment that lacks an opener. | |
1105 | (progn (forward-char 2) nil) | |
1106 | t) | |
1107 | ||
1108 | ;; XEmacs treats line continuations as whitespace but | |
1109 | ;; only in the backward direction, which seems a bit | |
1110 | ;; odd. Anyway, this is necessary for Emacs. | |
1111 | (when (and (looking-at "[\n\r]") | |
1112 | (eq (char-before) ?\\) | |
1113 | (< (point) start)) | |
1114 | (backward-char) | |
1115 | t)))))) | |
1116 | ||
1117 | \f | |
d9e94c22 | 1118 | ;; Tools for skipping over syntactic whitespace. |
a66cd3ee | 1119 | |
d9e94c22 MS |
1120 | ;; The following functions use text properties to cache searches over |
1121 | ;; large regions of syntactic whitespace. It works as follows: | |
1122 | ;; | |
1123 | ;; o If a syntactic whitespace region contains anything but simple | |
1124 | ;; whitespace (i.e. space, tab and line breaks), the text property | |
1125 | ;; `c-in-sws' is put over it. At places where we have stopped | |
1126 | ;; within that region there's also a `c-is-sws' text property. | |
1127 | ;; That since there typically are nested whitespace inside that | |
1128 | ;; must be handled separately, e.g. whitespace inside a comment or | |
1129 | ;; cpp directive. Thus, from one point with `c-is-sws' it's safe | |
1130 | ;; to jump to another point with that property within the same | |
1131 | ;; `c-in-sws' region. It can be likened to a ladder where | |
1132 | ;; `c-in-sws' marks the bars and `c-is-sws' the rungs. | |
1133 | ;; | |
1134 | ;; o The `c-is-sws' property is put on the simple whitespace chars at | |
1135 | ;; a "rung position" and also maybe on the first following char. | |
1136 | ;; As many characters as can be conveniently found in this range | |
1137 | ;; are marked, but no assumption can be made that the whole range | |
1138 | ;; is marked (it could be clobbered by later changes, for | |
1139 | ;; instance). | |
1140 | ;; | |
1141 | ;; Note that some part of the beginning of a sequence of simple | |
1142 | ;; whitespace might be part of the end of a preceding line comment | |
1143 | ;; or cpp directive and must not be considered part of the "rung". | |
1144 | ;; Such whitespace is some amount of horizontal whitespace followed | |
1145 | ;; by a newline. In the case of cpp directives it could also be | |
1146 | ;; two newlines with horizontal whitespace between them. | |
1147 | ;; | |
1148 | ;; The reason to include the first following char is to cope with | |
1149 | ;; "rung positions" that doesn't have any ordinary whitespace. If | |
1150 | ;; `c-is-sws' is put on a token character it does not have | |
1151 | ;; `c-in-sws' set simultaneously. That's the only case when that | |
1152 | ;; can occur, and the reason for not extending the `c-in-sws' | |
1153 | ;; region to cover it is that the `c-in-sws' region could then be | |
1154 | ;; accidentally merged with a following one if the token is only | |
1155 | ;; one character long. | |
1156 | ;; | |
1157 | ;; o On buffer changes the `c-in-sws' and `c-is-sws' properties are | |
1158 | ;; removed in the changed region. If the change was inside | |
1159 | ;; syntactic whitespace that means that the "ladder" is broken, but | |
1160 | ;; a later call to `c-forward-sws' or `c-backward-sws' will use the | |
1161 | ;; parts on either side and use an ordinary search only to "repair" | |
1162 | ;; the gap. | |
1163 | ;; | |
1164 | ;; Special care needs to be taken if a region is removed: If there | |
1165 | ;; are `c-in-sws' on both sides of it which do not connect inside | |
1166 | ;; the region then they can't be joined. If e.g. a marked macro is | |
1167 | ;; broken, syntactic whitespace inside the new text might be | |
1168 | ;; marked. If those marks would become connected with the old | |
1169 | ;; `c-in-sws' range around the macro then we could get a ladder | |
1170 | ;; with one end outside the macro and the other at some whitespace | |
1171 | ;; within it. | |
1172 | ;; | |
1173 | ;; The main motivation for this system is to increase the speed in | |
1174 | ;; skipping over the large whitespace regions that can occur at the | |
1175 | ;; top level in e.g. header files that contain a lot of comments and | |
1176 | ;; cpp directives. For small comments inside code it's probably | |
1177 | ;; slower than using `forward-comment' straightforwardly, but speed is | |
1178 | ;; not a significant factor there anyway. | |
1179 | ||
1180 | ; (defface c-debug-is-sws-face | |
1181 | ; '((t (:background "GreenYellow"))) | |
1182 | ; "Debug face to mark the `c-is-sws' property.") | |
1183 | ; (defface c-debug-in-sws-face | |
1184 | ; '((t (:underline t))) | |
1185 | ; "Debug face to mark the `c-in-sws' property.") | |
1186 | ||
1187 | ; (defun c-debug-put-sws-faces () | |
1188 | ; ;; Put the sws debug faces on all the `c-is-sws' and `c-in-sws' | |
1189 | ; ;; properties in the buffer. | |
1190 | ; (interactive) | |
1191 | ; (save-excursion | |
1192 | ; (let (in-face) | |
1193 | ; (goto-char (point-min)) | |
1194 | ; (setq in-face (if (get-text-property (point) 'c-is-sws) | |
1195 | ; (point))) | |
1196 | ; (while (progn | |
1197 | ; (goto-char (next-single-property-change | |
1198 | ; (point) 'c-is-sws nil (point-max))) | |
1199 | ; (if in-face | |
1200 | ; (progn | |
1201 | ; (c-debug-add-face in-face (point) 'c-debug-is-sws-face) | |
1202 | ; (setq in-face nil)) | |
1203 | ; (setq in-face (point))) | |
1204 | ; (not (eobp)))) | |
1205 | ; (goto-char (point-min)) | |
1206 | ; (setq in-face (if (get-text-property (point) 'c-in-sws) | |
1207 | ; (point))) | |
1208 | ; (while (progn | |
1209 | ; (goto-char (next-single-property-change | |
1210 | ; (point) 'c-in-sws nil (point-max))) | |
1211 | ; (if in-face | |
1212 | ; (progn | |
1213 | ; (c-debug-add-face in-face (point) 'c-debug-in-sws-face) | |
1214 | ; (setq in-face nil)) | |
1215 | ; (setq in-face (point))) | |
1216 | ; (not (eobp))))))) | |
1217 | ||
1218 | (defmacro c-debug-sws-msg (&rest args) | |
1219 | ;;`(message ,@args) | |
1220 | ) | |
1221 | ||
1222 | (defmacro c-put-is-sws (beg end) | |
1223 | `(let ((beg ,beg) (end ,end)) | |
1224 | (put-text-property beg end 'c-is-sws t) | |
1225 | ,@(when (facep 'c-debug-is-sws-face) | |
1226 | `((c-debug-add-face beg end 'c-debug-is-sws-face))))) | |
1227 | ||
1228 | (defmacro c-put-in-sws (beg end) | |
1229 | `(let ((beg ,beg) (end ,end)) | |
1230 | (put-text-property beg end 'c-in-sws t) | |
1231 | ,@(when (facep 'c-debug-is-sws-face) | |
1232 | `((c-debug-add-face beg end 'c-debug-in-sws-face))))) | |
1233 | ||
1234 | (defmacro c-remove-is-sws (beg end) | |
1235 | `(let ((beg ,beg) (end ,end)) | |
1236 | (remove-text-properties beg end '(c-is-sws nil)) | |
1237 | ,@(when (facep 'c-debug-is-sws-face) | |
1238 | `((c-debug-remove-face beg end 'c-debug-is-sws-face))))) | |
1239 | ||
1240 | (defmacro c-remove-in-sws (beg end) | |
1241 | `(let ((beg ,beg) (end ,end)) | |
1242 | (remove-text-properties beg end '(c-in-sws nil)) | |
1243 | ,@(when (facep 'c-debug-is-sws-face) | |
1244 | `((c-debug-remove-face beg end 'c-debug-in-sws-face))))) | |
1245 | ||
1246 | (defmacro c-remove-is-and-in-sws (beg end) | |
1247 | `(let ((beg ,beg) (end ,end)) | |
1248 | (remove-text-properties beg end '(c-is-sws nil c-in-sws nil)) | |
1249 | ,@(when (facep 'c-debug-is-sws-face) | |
1250 | `((c-debug-remove-face beg end 'c-debug-is-sws-face) | |
1251 | (c-debug-remove-face beg end 'c-debug-in-sws-face))))) | |
1252 | ||
1253 | (defsubst c-invalidate-sws-region-after (beg end) | |
1254 | ;; Called from `after-change-functions'. Note that if | |
1255 | ;; `c-forward-sws' or `c-backward-sws' are used outside | |
1256 | ;; `c-save-buffer-state' or similar then this will remove the cache | |
1257 | ;; properties right after they're added. | |
1258 | ||
1259 | (save-excursion | |
1260 | ;; Adjust the end to remove the properties in any following simple | |
1261 | ;; ws up to and including the next line break, if there is any | |
1262 | ;; after the changed region. This is necessary e.g. when a rung | |
1263 | ;; marked empty line is converted to a line comment by inserting | |
1264 | ;; "//" before the line break. In that case the line break would | |
1265 | ;; keep the rung mark which could make a later `c-backward-sws' | |
1266 | ;; move into the line comment instead of over it. | |
1267 | (goto-char end) | |
1268 | (skip-chars-forward " \t\f\v") | |
1269 | (when (and (eolp) (not (eobp))) | |
1270 | (setq end (1+ (point))))) | |
1271 | ||
1272 | (when (and (= beg end) | |
1273 | (get-text-property beg 'c-in-sws) | |
2a15eb73 | 1274 | (> beg (point-min)) |
d9e94c22 MS |
1275 | (get-text-property (1- beg) 'c-in-sws)) |
1276 | ;; Ensure that an `c-in-sws' range gets broken. Note that it isn't | |
1277 | ;; safe to keep a range that was continuous before the change. E.g: | |
1278 | ;; | |
1279 | ;; #define foo | |
1280 | ;; \ | |
1281 | ;; bar | |
1282 | ;; | |
1283 | ;; There can be a "ladder" between "#" and "b". Now, if the newline | |
1284 | ;; after "foo" is removed then "bar" will become part of the cpp | |
1285 | ;; directive instead of a syntactically relevant token. In that | |
1286 | ;; case there's no longer syntactic ws from "#" to "b". | |
1287 | (setq beg (1- beg))) | |
1288 | ||
1289 | (c-debug-sws-msg "c-invalidate-sws-region-after [%s..%s]" beg end) | |
1290 | (c-remove-is-and-in-sws beg end)) | |
1291 | ||
1292 | (defun c-forward-sws () | |
1293 | ;; Used by `c-forward-syntactic-ws' to implement the unbounded search. | |
1294 | ||
1295 | (let (;; `rung-pos' is set to a position as early as possible in the | |
1296 | ;; unmarked part of the simple ws region. | |
1297 | (rung-pos (point)) next-rung-pos rung-end-pos last-put-in-sws-pos | |
1298 | rung-is-marked next-rung-is-marked simple-ws-end | |
1299 | ;; `safe-start' is set when it's safe to cache the start position. | |
1300 | ;; It's not set if we've initially skipped over comments and line | |
1301 | ;; continuations since we might have gone out through the end of a | |
1302 | ;; macro then. This provision makes `c-forward-sws' not populate the | |
1303 | ;; cache in the majority of cases, but otoh is `c-backward-sws' by far | |
1304 | ;; more common. | |
1305 | safe-start) | |
1306 | ||
1307 | ;; Skip simple ws and do a quick check on the following character to see | |
1308 | ;; if it's anything that can't start syntactic ws, so we can bail out | |
1309 | ;; early in the majority of cases when there just are a few ws chars. | |
1310 | (skip-chars-forward " \t\n\r\f\v") | |
1311 | (when (looking-at c-syntactic-ws-start) | |
1312 | ||
1313 | (setq rung-end-pos (min (1+ (point)) (point-max))) | |
1314 | (if (setq rung-is-marked (text-property-any rung-pos rung-end-pos | |
1315 | 'c-is-sws t)) | |
1316 | ;; Find the last rung position to avoid setting properties in all | |
1317 | ;; the cases when the marked rung is complete. | |
1318 | ;; (`next-single-property-change' is certain to move at least one | |
1319 | ;; step forward.) | |
1320 | (setq rung-pos (1- (next-single-property-change | |
1321 | rung-is-marked 'c-is-sws nil rung-end-pos))) | |
1322 | ;; Got no marked rung here. Since the simple ws might have started | |
1323 | ;; inside a line comment or cpp directive we must set `rung-pos' as | |
1324 | ;; high as possible. | |
1325 | (setq rung-pos (point))) | |
1326 | ||
1327 | (while | |
1328 | (progn | |
1329 | (while | |
1330 | (when (and rung-is-marked | |
1331 | (get-text-property (point) 'c-in-sws)) | |
1332 | ||
1333 | ;; The following search is the main reason that `c-in-sws' | |
1334 | ;; and `c-is-sws' aren't combined to one property. | |
1335 | (goto-char (next-single-property-change | |
1336 | (point) 'c-in-sws nil (point-max))) | |
1337 | (unless (get-text-property (point) 'c-is-sws) | |
1338 | ;; If the `c-in-sws' region extended past the last | |
1339 | ;; `c-is-sws' char we have to go back a bit. | |
1340 | (or (get-text-property (1- (point)) 'c-is-sws) | |
1341 | (goto-char (previous-single-property-change | |
1342 | (point) 'c-is-sws))) | |
1343 | (backward-char)) | |
1344 | ||
1345 | (c-debug-sws-msg | |
1346 | "c-forward-sws cached move %s -> %s (max %s)" | |
1347 | rung-pos (point) (point-max)) | |
1348 | ||
1349 | (setq rung-pos (point)) | |
1350 | (and (> (skip-chars-forward " \t\n\r\f\v") 0) | |
1351 | (not (eobp)))) | |
1352 | ||
1353 | ;; We'll loop here if there is simple ws after the last rung. | |
1354 | ;; That means that there's been some change in it and it's | |
1355 | ;; possible that we've stepped into another ladder, so extend | |
1356 | ;; the previous one to join with it if there is one, and try to | |
1357 | ;; use the cache again. | |
1358 | (c-debug-sws-msg | |
1359 | "c-forward-sws extending rung with [%s..%s] (max %s)" | |
1360 | (1+ rung-pos) (1+ (point)) (point-max)) | |
1361 | (unless (get-text-property (point) 'c-is-sws) | |
1362 | ;; Remove any `c-in-sws' property from the last char of | |
1363 | ;; the rung before we mark it with `c-is-sws', so that we | |
1364 | ;; won't connect with the remains of a broken "ladder". | |
1365 | (c-remove-in-sws (point) (1+ (point)))) | |
1366 | (c-put-is-sws (1+ rung-pos) | |
1367 | (1+ (point))) | |
1368 | (c-put-in-sws rung-pos | |
1369 | (setq rung-pos (point) | |
1370 | last-put-in-sws-pos rung-pos))) | |
1371 | ||
1372 | (setq simple-ws-end (point)) | |
1373 | (c-forward-comments) | |
1374 | ||
1375 | (cond | |
1376 | ((/= (point) simple-ws-end) | |
1377 | ;; Skipped over comments. Don't cache at eob in case the buffer | |
1378 | ;; is narrowed. | |
1379 | (not (eobp))) | |
1380 | ||
1381 | ((save-excursion | |
1382 | (and c-opt-cpp-prefix | |
1383 | (looking-at c-opt-cpp-start) | |
1384 | (progn (skip-chars-backward " \t") | |
1385 | (bolp)) | |
1386 | (or (bobp) | |
1387 | (progn (backward-char) | |
1388 | (not (eq (char-before) ?\\)))))) | |
1389 | ;; Skip a preprocessor directive. | |
1390 | (end-of-line) | |
1391 | (while (and (eq (char-before) ?\\) | |
1392 | (= (forward-line 1) 0)) | |
1393 | (end-of-line)) | |
1394 | (forward-line 1) | |
1395 | (setq safe-start t) | |
1396 | ;; Don't cache at eob in case the buffer is narrowed. | |
1397 | (not (eobp))))) | |
1398 | ||
1399 | ;; We've searched over a piece of non-white syntactic ws. See if this | |
1400 | ;; can be cached. | |
1401 | (setq next-rung-pos (point)) | |
1402 | (skip-chars-forward " \t\n\r\f\v") | |
1403 | (setq rung-end-pos (min (1+ (point)) (point-max))) | |
1404 | ||
1405 | (if (or | |
1406 | ;; Cache if we haven't skipped comments only, and if we started | |
1407 | ;; either from a marked rung or from a completely uncached | |
1408 | ;; position. | |
1409 | (and safe-start | |
1410 | (or rung-is-marked | |
1411 | (not (get-text-property simple-ws-end 'c-in-sws)))) | |
1412 | ||
1413 | ;; See if there's a marked rung in the encountered simple ws. If | |
1414 | ;; so then we can cache, unless `safe-start' is nil. Even then | |
1415 | ;; we need to do this to check if the cache can be used for the | |
1416 | ;; next step. | |
1417 | (and (setq next-rung-is-marked | |
1418 | (text-property-any next-rung-pos rung-end-pos | |
1419 | 'c-is-sws t)) | |
1420 | safe-start)) | |
b2acd789 | 1421 | |
0ec8351b | 1422 | (progn |
d9e94c22 MS |
1423 | (c-debug-sws-msg |
1424 | "c-forward-sws caching [%s..%s] - [%s..%s] (max %s)" | |
1425 | rung-pos (1+ simple-ws-end) next-rung-pos rung-end-pos | |
1426 | (point-max)) | |
1427 | ||
1428 | ;; Remove the properties for any nested ws that might be cached. | |
1429 | ;; Only necessary for `c-is-sws' since `c-in-sws' will be set | |
1430 | ;; anyway. | |
1431 | (c-remove-is-sws (1+ simple-ws-end) next-rung-pos) | |
1432 | (unless (and rung-is-marked (= rung-pos simple-ws-end)) | |
1433 | (c-put-is-sws rung-pos | |
1434 | (1+ simple-ws-end)) | |
1435 | (setq rung-is-marked t)) | |
1436 | (c-put-in-sws rung-pos | |
1437 | (setq rung-pos (point) | |
1438 | last-put-in-sws-pos rung-pos)) | |
1439 | (unless (get-text-property (1- rung-end-pos) 'c-is-sws) | |
1440 | ;; Remove any `c-in-sws' property from the last char of | |
1441 | ;; the rung before we mark it with `c-is-sws', so that we | |
1442 | ;; won't connect with the remains of a broken "ladder". | |
1443 | (c-remove-in-sws (1- rung-end-pos) rung-end-pos)) | |
1444 | (c-put-is-sws next-rung-pos | |
1445 | rung-end-pos)) | |
1446 | ||
1447 | (c-debug-sws-msg | |
1448 | "c-forward-sws not caching [%s..%s] - [%s..%s] (max %s)" | |
1449 | rung-pos (1+ simple-ws-end) next-rung-pos rung-end-pos | |
1450 | (point-max)) | |
1451 | ||
1452 | ;; Set `rung-pos' for the next rung. It's the same thing here as | |
1453 | ;; initially, except that the rung position is set as early as | |
1454 | ;; possible since we can't be in the ending ws of a line comment or | |
1455 | ;; cpp directive now. | |
1456 | (if (setq rung-is-marked next-rung-is-marked) | |
1457 | (setq rung-pos (1- (next-single-property-change | |
1458 | rung-is-marked 'c-is-sws nil rung-end-pos))) | |
1459 | (setq rung-pos next-rung-pos)) | |
1460 | (setq safe-start t))) | |
1461 | ||
1462 | ;; Make sure that the newly marked `c-in-sws' region doesn't connect to | |
1463 | ;; another one after the point (which might occur when editing inside a | |
1464 | ;; comment or macro). | |
1465 | (when (eq last-put-in-sws-pos (point)) | |
1466 | (cond ((< last-put-in-sws-pos (point-max)) | |
1467 | (c-debug-sws-msg | |
1468 | "c-forward-sws clearing at %s for cache separation" | |
1469 | last-put-in-sws-pos) | |
1470 | (c-remove-in-sws last-put-in-sws-pos | |
1471 | (1+ last-put-in-sws-pos))) | |
1472 | (t | |
1473 | ;; If at eob we have to clear the last character before the end | |
1474 | ;; instead since the buffer might be narrowed and there might | |
1475 | ;; be a `c-in-sws' after (point-max). In this case it's | |
1476 | ;; necessary to clear both properties. | |
1477 | (c-debug-sws-msg | |
1478 | "c-forward-sws clearing thoroughly at %s for cache separation" | |
1479 | (1- last-put-in-sws-pos)) | |
1480 | (c-remove-is-and-in-sws (1- last-put-in-sws-pos) | |
1481 | last-put-in-sws-pos)))) | |
1482 | ))) | |
b2acd789 | 1483 | |
d9e94c22 MS |
1484 | (defun c-backward-sws () |
1485 | ;; Used by `c-backward-syntactic-ws' to implement the unbounded search. | |
1486 | ||
1487 | (let (;; `rung-pos' is set to a position as late as possible in the unmarked | |
1488 | ;; part of the simple ws region. | |
1489 | (rung-pos (point)) next-rung-pos last-put-in-sws-pos | |
1490 | rung-is-marked simple-ws-beg cmt-skip-pos) | |
1491 | ||
1492 | ;; Skip simple horizontal ws and do a quick check on the preceding | |
1493 | ;; character to see if it's anying that can't end syntactic ws, so we can | |
1494 | ;; bail out early in the majority of cases when there just are a few ws | |
1495 | ;; chars. Newlines are complicated in the backward direction, so we can't | |
1496 | ;; skip over them. | |
1497 | (skip-chars-backward " \t\f") | |
1498 | (when (and (not (bobp)) | |
1499 | (save-excursion | |
1500 | (backward-char) | |
1501 | (looking-at c-syntactic-ws-end))) | |
1502 | ||
1503 | ;; Try to find a rung position in the simple ws preceding point, so that | |
1504 | ;; we can get a cache hit even if the last bit of the simple ws has | |
1505 | ;; changed recently. | |
1506 | (setq simple-ws-beg (point)) | |
1507 | (skip-chars-backward " \t\n\r\f\v") | |
1508 | (if (setq rung-is-marked (text-property-any | |
1509 | (point) (min (1+ rung-pos) (point-max)) | |
1510 | 'c-is-sws t)) | |
1511 | ;; `rung-pos' will be the earliest marked position, which means that | |
1512 | ;; there might be later unmarked parts in the simple ws region. | |
1513 | ;; It's not worth the effort to fix that; the last part of the | |
1514 | ;; simple ws is also typically edited often, so it could be wasted. | |
1515 | (goto-char (setq rung-pos rung-is-marked)) | |
1516 | (goto-char simple-ws-beg)) | |
1517 | ||
1518 | (while | |
1519 | (progn | |
1520 | (while | |
1521 | (when (and rung-is-marked | |
1522 | (not (bobp)) | |
1523 | (get-text-property (1- (point)) 'c-in-sws)) | |
1524 | ||
1525 | ;; The following search is the main reason that `c-in-sws' | |
1526 | ;; and `c-is-sws' aren't combined to one property. | |
1527 | (goto-char (previous-single-property-change | |
1528 | (point) 'c-in-sws nil (point-min))) | |
1529 | (unless (get-text-property (point) 'c-is-sws) | |
1530 | ;; If the `c-in-sws' region extended past the first | |
1531 | ;; `c-is-sws' char we have to go forward a bit. | |
1532 | (goto-char (next-single-property-change | |
1533 | (point) 'c-is-sws))) | |
1534 | ||
1535 | (c-debug-sws-msg | |
1536 | "c-backward-sws cached move %s <- %s (min %s)" | |
1537 | (point) rung-pos (point-min)) | |
1538 | ||
1539 | (setq rung-pos (point)) | |
1540 | (if (and (< (min (skip-chars-backward " \t\f\v") | |
1541 | (progn | |
1542 | (setq simple-ws-beg (point)) | |
1543 | (skip-chars-backward " \t\n\r\f\v"))) | |
1544 | 0) | |
1545 | (setq rung-is-marked | |
1546 | (text-property-any (point) rung-pos | |
1547 | 'c-is-sws t))) | |
1548 | t | |
1549 | (goto-char simple-ws-beg) | |
1550 | nil)) | |
1551 | ||
1552 | ;; We'll loop here if there is simple ws before the first rung. | |
1553 | ;; That means that there's been some change in it and it's | |
1554 | ;; possible that we've stepped into another ladder, so extend | |
1555 | ;; the previous one to join with it if there is one, and try to | |
1556 | ;; use the cache again. | |
1557 | (c-debug-sws-msg | |
1558 | "c-backward-sws extending rung with [%s..%s] (min %s)" | |
1559 | rung-is-marked rung-pos (point-min)) | |
1560 | (unless (get-text-property (1- rung-pos) 'c-is-sws) | |
1561 | ;; Remove any `c-in-sws' property from the last char of | |
1562 | ;; the rung before we mark it with `c-is-sws', so that we | |
1563 | ;; won't connect with the remains of a broken "ladder". | |
1564 | (c-remove-in-sws (1- rung-pos) rung-pos)) | |
1565 | (c-put-is-sws rung-is-marked | |
1566 | rung-pos) | |
1567 | (c-put-in-sws rung-is-marked | |
1568 | (1- rung-pos)) | |
1569 | (setq rung-pos rung-is-marked | |
1570 | last-put-in-sws-pos rung-pos)) | |
1571 | ||
1572 | (c-backward-comments) | |
1573 | (setq cmt-skip-pos (point)) | |
a66cd3ee | 1574 | |
d9e94c22 MS |
1575 | (cond |
1576 | ((and c-opt-cpp-prefix | |
1577 | (/= cmt-skip-pos simple-ws-beg) | |
1578 | (c-beginning-of-macro)) | |
1579 | ;; Inside a cpp directive. See if it should be skipped over. | |
1580 | (let ((cpp-beg (point))) | |
1581 | ||
1582 | ;; Move back over all line continuations in the region skipped | |
1583 | ;; over by `c-backward-comments'. If we go past it then we | |
1584 | ;; started inside the cpp directive. | |
1585 | (goto-char simple-ws-beg) | |
1586 | (beginning-of-line) | |
1587 | (while (and (> (point) cmt-skip-pos) | |
1588 | (progn (backward-char) | |
1589 | (eq (char-before) ?\\))) | |
1590 | (beginning-of-line)) | |
1591 | ||
1592 | (if (< (point) cmt-skip-pos) | |
1593 | ;; Don't move past the cpp directive if we began inside | |
1594 | ;; it. Note that the position at the end of the last line | |
1595 | ;; of the macro is also considered to be within it. | |
1596 | (progn (goto-char cmt-skip-pos) | |
1597 | nil) | |
1598 | ||
1599 | ;; It's worthwhile to spend a little bit of effort on finding | |
1600 | ;; the end of the macro, to get a good `simple-ws-beg' | |
1601 | ;; position for the cache. Note that `c-backward-comments' | |
1602 | ;; could have stepped over some comments before going into | |
1603 | ;; the macro, and then `simple-ws-beg' must be kept on the | |
1604 | ;; same side of those comments. | |
1605 | (goto-char simple-ws-beg) | |
1606 | (skip-chars-backward " \t\n\r\f\v") | |
1607 | (if (eq (char-before) ?\\) | |
1608 | (forward-char)) | |
1609 | (forward-line 1) | |
1610 | (if (< (point) simple-ws-beg) | |
1611 | ;; Might happen if comments after the macro were skipped | |
1612 | ;; over. | |
1613 | (setq simple-ws-beg (point))) | |
1614 | ||
1615 | (goto-char cpp-beg) | |
1616 | t))) | |
1617 | ||
1618 | ((/= (save-excursion | |
1619 | (skip-chars-forward " \t\n\r\f\v" simple-ws-beg) | |
1620 | (setq next-rung-pos (point))) | |
1621 | simple-ws-beg) | |
1622 | ;; Skipped over comments. Must put point at the end of | |
1623 | ;; the simple ws at point since we might be after a line | |
1624 | ;; comment or cpp directive that's been partially | |
1625 | ;; narrowed out, and we can't risk marking the simple ws | |
1626 | ;; at the end of it. | |
1627 | (goto-char next-rung-pos) | |
1628 | t))) | |
1629 | ||
1630 | ;; We've searched over a piece of non-white syntactic ws. See if this | |
1631 | ;; can be cached. | |
1632 | (setq next-rung-pos (point)) | |
1633 | (skip-chars-backward " \t\f\v") | |
1634 | ||
1635 | (if (or | |
1636 | ;; Cache if we started either from a marked rung or from a | |
1637 | ;; completely uncached position. | |
1638 | rung-is-marked | |
1639 | (not (get-text-property (1- simple-ws-beg) 'c-in-sws)) | |
1640 | ||
1641 | ;; Cache if there's a marked rung in the encountered simple ws. | |
1642 | (save-excursion | |
1643 | (skip-chars-backward " \t\n\r\f\v") | |
1644 | (text-property-any (point) (min (1+ next-rung-pos) (point-max)) | |
1645 | 'c-is-sws t))) | |
a66cd3ee | 1646 | |
d9e94c22 MS |
1647 | (progn |
1648 | (c-debug-sws-msg | |
1649 | "c-backward-sws caching [%s..%s] - [%s..%s] (min %s)" | |
1650 | (point) (1+ next-rung-pos) | |
1651 | simple-ws-beg (min (1+ rung-pos) (point-max)) | |
1652 | (point-min)) | |
1653 | ||
1654 | ;; Remove the properties for any nested ws that might be cached. | |
1655 | ;; Only necessary for `c-is-sws' since `c-in-sws' will be set | |
1656 | ;; anyway. | |
1657 | (c-remove-is-sws (1+ next-rung-pos) simple-ws-beg) | |
1658 | (unless (and rung-is-marked (= simple-ws-beg rung-pos)) | |
1659 | (let ((rung-end-pos (min (1+ rung-pos) (point-max)))) | |
1660 | (unless (get-text-property (1- rung-end-pos) 'c-is-sws) | |
1661 | ;; Remove any `c-in-sws' property from the last char of | |
1662 | ;; the rung before we mark it with `c-is-sws', so that we | |
1663 | ;; won't connect with the remains of a broken "ladder". | |
1664 | (c-remove-in-sws (1- rung-end-pos) rung-end-pos)) | |
1665 | (c-put-is-sws simple-ws-beg | |
1666 | rung-end-pos) | |
1667 | (setq rung-is-marked t))) | |
1668 | (c-put-in-sws (setq simple-ws-beg (point) | |
1669 | last-put-in-sws-pos simple-ws-beg) | |
1670 | rung-pos) | |
1671 | (c-put-is-sws (setq rung-pos simple-ws-beg) | |
1672 | (1+ next-rung-pos))) | |
1673 | ||
1674 | (c-debug-sws-msg | |
1675 | "c-backward-sws not caching [%s..%s] - [%s..%s] (min %s)" | |
1676 | (point) (1+ next-rung-pos) | |
1677 | simple-ws-beg (min (1+ rung-pos) (point-max)) | |
1678 | (point-min)) | |
1679 | (setq rung-pos next-rung-pos | |
1680 | simple-ws-beg (point)) | |
1681 | )) | |
1682 | ||
1683 | ;; Make sure that the newly marked `c-in-sws' region doesn't connect to | |
1684 | ;; another one before the point (which might occur when editing inside a | |
1685 | ;; comment or macro). | |
1686 | (when (eq last-put-in-sws-pos (point)) | |
1687 | (cond ((< (point-min) last-put-in-sws-pos) | |
1688 | (c-debug-sws-msg | |
1689 | "c-backward-sws clearing at %s for cache separation" | |
1690 | (1- last-put-in-sws-pos)) | |
1691 | (c-remove-in-sws (1- last-put-in-sws-pos) | |
1692 | last-put-in-sws-pos)) | |
1693 | ((> (point-min) 1) | |
1694 | ;; If at bob and the buffer is narrowed, we have to clear the | |
1695 | ;; character we're standing on instead since there might be a | |
1696 | ;; `c-in-sws' before (point-min). In this case it's necessary | |
1697 | ;; to clear both properties. | |
1698 | (c-debug-sws-msg | |
1699 | "c-backward-sws clearing thoroughly at %s for cache separation" | |
1700 | last-put-in-sws-pos) | |
1701 | (c-remove-is-and-in-sws last-put-in-sws-pos | |
1702 | (1+ last-put-in-sws-pos))))) | |
1703 | ))) | |
785eecbb | 1704 | |
d9e94c22 MS |
1705 | \f |
1706 | ;; A system for handling noteworthy parens before the point. | |
e1c458ae | 1707 | |
d9e94c22 MS |
1708 | (defvar c-state-cache nil) |
1709 | (make-variable-buffer-local 'c-state-cache) | |
1710 | ;; The state cache used by `c-parse-state' to cut down the amount of | |
1711 | ;; searching. It's the result from some earlier `c-parse-state' call. | |
1712 | ;; The use of the cached info is more effective if the next | |
1713 | ;; `c-parse-state' call is on a line close by the one the cached state | |
1714 | ;; was made at; the cache can actually slow down a little if the | |
1715 | ;; cached state was made very far back in the buffer. The cache is | |
1716 | ;; most effective if `c-parse-state' is used on each line while moving | |
1717 | ;; forward. | |
e1c458ae | 1718 | |
d9e94c22 MS |
1719 | (defvar c-state-cache-start 1) |
1720 | (make-variable-buffer-local 'c-state-cache-start) | |
1721 | ;; This is (point-min) when `c-state-cache' was calculated, since a | |
1722 | ;; change of narrowing is likely to affect the parens that are visible | |
1723 | ;; before the point. | |
1724 | ||
1725 | (defsubst c-invalidate-state-cache (pos) | |
1726 | ;; Invalidate all info on `c-state-cache' that applies to the buffer | |
1727 | ;; at POS or higher. This is much like `c-whack-state-after', but | |
1728 | ;; it never changes a paren pair element into an open paren element. | |
1729 | ;; Doing that would mean that the new open paren wouldn't have the | |
1730 | ;; required preceding paren pair element. | |
1731 | ;; | |
1732 | ;; This function does not do any hidden buffer changes. | |
1733 | (while (and c-state-cache | |
1734 | (let ((elem (car c-state-cache))) | |
1735 | (if (consp elem) | |
1736 | (or (<= pos (car elem)) | |
1737 | (< pos (cdr elem))) | |
1738 | (<= pos elem)))) | |
1739 | (setq c-state-cache (cdr c-state-cache)))) | |
785eecbb RS |
1740 | |
1741 | (defun c-parse-state () | |
a66cd3ee MS |
1742 | ;; Finds and records all noteworthy parens between some good point |
1743 | ;; earlier in the file and point. That good point is at least the | |
1744 | ;; beginning of the top-level construct we are in, or the beginning | |
1745 | ;; of the preceding top-level construct if we aren't in one. | |
785eecbb | 1746 | ;; |
a66cd3ee MS |
1747 | ;; The returned value is a list of the noteworthy parens with the |
1748 | ;; last one first. If an element in the list is an integer, it's | |
1749 | ;; the position of an open paren which has not been closed before | |
d9e94c22 | 1750 | ;; the point. If an element is a cons, it gives the position of a |
a66cd3ee MS |
1751 | ;; closed brace paren pair; the car is the start paren position and |
1752 | ;; the cdr is the position following the closing paren. Only the | |
1753 | ;; last closed brace paren pair before each open paren is recorded, | |
1754 | ;; and thus the state never contains two cons elements in | |
1755 | ;; succession. | |
d9e94c22 MS |
1756 | ;; |
1757 | ;; Currently no characters which are given paren syntax with the | |
1758 | ;; syntax-table property are recorded, i.e. angle bracket arglist | |
1759 | ;; parens are never present here. Note that this might change. | |
1760 | ;; | |
1761 | ;; This function does not do any hidden buffer changes. | |
1762 | ||
a66cd3ee MS |
1763 | (save-restriction |
1764 | (let* ((here (point)) | |
1765 | (c-macro-start (c-query-macro-start)) | |
1766 | (in-macro-start (or c-macro-start (point))) | |
e33c01bb | 1767 | old-state last-pos pairs pos save-pos) |
d9e94c22 MS |
1768 | (c-invalidate-state-cache (point)) |
1769 | ||
1770 | ;; If the minimum position has changed due to narrowing then we | |
1771 | ;; have to fix the tail of `c-state-cache' accordingly. | |
1772 | (unless (= c-state-cache-start (point-min)) | |
1773 | (if (> (point-min) c-state-cache-start) | |
1774 | ;; If point-min has moved forward then we just need to cut | |
1775 | ;; off a bit of the tail. | |
1776 | (let ((ptr (cons nil c-state-cache)) elem) | |
449a2b0d | 1777 | (while (and (setq elem (car-safe (cdr ptr))) |
d9e94c22 MS |
1778 | (>= (if (consp elem) (car elem) elem) |
1779 | (point-min))) | |
449a2b0d | 1780 | (setq ptr (cdr ptr))) |
d9e94c22 MS |
1781 | (when (consp ptr) |
1782 | (if (eq (cdr ptr) c-state-cache) | |
1783 | (setq c-state-cache nil) | |
1784 | (setcdr ptr nil)))) | |
1785 | ;; If point-min has moved backward then we drop the state | |
1786 | ;; completely. It's possible to do a better job here and | |
1787 | ;; recalculate the top only. | |
1788 | (setq c-state-cache nil)) | |
1789 | (setq c-state-cache-start (point-min))) | |
1790 | ||
a66cd3ee MS |
1791 | ;; Get the latest position we know are directly inside the |
1792 | ;; closest containing paren of the cached state. | |
1793 | (setq last-pos (and c-state-cache | |
1794 | (if (consp (car c-state-cache)) | |
1795 | (cdr (car c-state-cache)) | |
1796 | (1+ (car c-state-cache))))) | |
d9e94c22 | 1797 | |
a66cd3ee MS |
1798 | ;; Check if the found last-pos is in a macro. If it is, and |
1799 | ;; we're not in the same macro, we must discard everything on | |
1800 | ;; c-state-cache that is inside the macro before using it. | |
1801 | (when last-pos | |
1802 | (save-excursion | |
1803 | (goto-char last-pos) | |
1804 | (when (and (c-beginning-of-macro) | |
1805 | (/= (point) in-macro-start)) | |
d9e94c22 | 1806 | (c-invalidate-state-cache (point)) |
a66cd3ee MS |
1807 | ;; Set last-pos again, just like above. |
1808 | (setq last-pos (and c-state-cache | |
1809 | (if (consp (car c-state-cache)) | |
1810 | (cdr (car c-state-cache)) | |
1811 | (1+ (car c-state-cache)))))))) | |
d9e94c22 | 1812 | |
a66cd3ee MS |
1813 | (setq pos |
1814 | ;; Find the start position for the forward search. (Can't | |
1815 | ;; search in the backward direction since point might be | |
1816 | ;; in some kind of literal.) | |
1817 | (or (when last-pos | |
d9e94c22 | 1818 | |
a66cd3ee MS |
1819 | ;; There's a cached state with a containing paren. Pop |
1820 | ;; off the stale containing sexps from it by going | |
1821 | ;; forward out of parens as far as possible. | |
1822 | (narrow-to-region (point-min) here) | |
1823 | (let (placeholder pair-beg) | |
1824 | (while (and c-state-cache | |
1825 | (setq placeholder | |
1826 | (c-up-list-forward last-pos))) | |
1827 | (setq last-pos placeholder) | |
1828 | (if (consp (car c-state-cache)) | |
1829 | (setq pair-beg (car-safe (cdr c-state-cache)) | |
1830 | c-state-cache (cdr-safe (cdr c-state-cache))) | |
1831 | (setq pair-beg (car c-state-cache) | |
1832 | c-state-cache (cdr c-state-cache)))) | |
d9e94c22 | 1833 | |
a66cd3ee MS |
1834 | (when (and pair-beg (eq (char-after pair-beg) ?{)) |
1835 | ;; The last paren pair we moved out from was a brace | |
1836 | ;; pair. Modify the state to record this as a closed | |
1837 | ;; pair now. | |
1838 | (if (consp (car-safe c-state-cache)) | |
1839 | (setq c-state-cache (cdr c-state-cache))) | |
1840 | (setq c-state-cache (cons (cons pair-beg last-pos) | |
1841 | c-state-cache)))) | |
d9e94c22 | 1842 | |
a66cd3ee MS |
1843 | ;; Check if the preceding balanced paren is within a |
1844 | ;; macro; it should be ignored if we're outside the | |
1845 | ;; macro. There's no need to check any further upwards; | |
1846 | ;; if the macro contains an unbalanced opening paren then | |
1847 | ;; we're smoked anyway. | |
1848 | (when (and (<= (point) in-macro-start) | |
1849 | (consp (car c-state-cache))) | |
1850 | (save-excursion | |
1851 | (goto-char (car (car c-state-cache))) | |
1852 | (when (c-beginning-of-macro) | |
1853 | (setq here (point) | |
1854 | c-state-cache (cdr c-state-cache))))) | |
d9e94c22 | 1855 | |
a66cd3ee MS |
1856 | (when c-state-cache |
1857 | (setq old-state c-state-cache) | |
1858 | last-pos)) | |
d9e94c22 | 1859 | |
a66cd3ee | 1860 | (save-excursion |
785eecbb | 1861 | ;; go back 2 bods, but ignore any bogus positions |
a66cd3ee MS |
1862 | ;; returned by beginning-of-defun (i.e. open paren in |
1863 | ;; column zero) | |
1864 | (goto-char here) | |
785eecbb | 1865 | (let ((cnt 2)) |
a66cd3ee MS |
1866 | (while (not (or (bobp) (zerop cnt))) |
1867 | (c-beginning-of-defun-1) | |
1868 | (if (eq (char-after) ?\{) | |
1869 | (setq cnt (1- cnt))))) | |
1870 | (point)))) | |
d9e94c22 | 1871 | |
a66cd3ee | 1872 | (narrow-to-region (point-min) here) |
d9e94c22 | 1873 | |
a66cd3ee MS |
1874 | (while pos |
1875 | ;; Find the balanced brace pairs. | |
e33c01bb MS |
1876 | (setq save-pos pos |
1877 | pairs nil) | |
a66cd3ee MS |
1878 | (while (and (setq last-pos (c-down-list-forward pos)) |
1879 | (setq pos (c-up-list-forward last-pos))) | |
1880 | (if (eq (char-before last-pos) ?{) | |
1881 | (setq pairs (cons (cons last-pos pos) pairs)))) | |
d9e94c22 | 1882 | |
a66cd3ee MS |
1883 | ;; Should ignore any pairs that are in a macro, providing |
1884 | ;; we're not in the same one. | |
1885 | (when (and pairs (< (car (car pairs)) in-macro-start)) | |
1886 | (while (and (save-excursion | |
1887 | (goto-char (car (car pairs))) | |
1888 | (c-beginning-of-macro)) | |
1889 | (setq pairs (cdr pairs))))) | |
d9e94c22 | 1890 | |
a66cd3ee MS |
1891 | ;; Record the last brace pair. |
1892 | (when pairs | |
1893 | (if (and (eq c-state-cache old-state) | |
1894 | (consp (car-safe c-state-cache))) | |
1895 | ;; There's a closed pair on the cached state but we've | |
1896 | ;; found a later one, so remove it. | |
1897 | (setq c-state-cache (cdr c-state-cache))) | |
1898 | (setq pairs (car pairs)) | |
1899 | (setcar pairs (1- (car pairs))) | |
0e35704f MS |
1900 | (when (consp (car-safe c-state-cache)) |
1901 | ;; There could already be a cons first in `c-state-cache' | |
d9e94c22 | 1902 | ;; if we've e.g. jumped over an unbalanced open paren in a |
0e35704f MS |
1903 | ;; macro below. |
1904 | (setq c-state-cache (cdr c-state-cache))) | |
a66cd3ee | 1905 | (setq c-state-cache (cons pairs c-state-cache))) |
d9e94c22 | 1906 | |
a66cd3ee MS |
1907 | (if last-pos |
1908 | ;; Prepare to loop, but record the open paren only if it's | |
d9e94c22 | 1909 | ;; outside a macro or within the same macro as point, and |
2a15eb73 | 1910 | ;; if it is a legitimate open paren and not some character |
d9e94c22 | 1911 | ;; that got an open paren syntax-table property. |
a66cd3ee MS |
1912 | (progn |
1913 | (setq pos last-pos) | |
d9e94c22 MS |
1914 | (if (and (or (>= last-pos in-macro-start) |
1915 | (save-excursion | |
1916 | (goto-char last-pos) | |
1917 | (not (c-beginning-of-macro)))) | |
2a15eb73 MS |
1918 | ;; Check for known types of parens that we want |
1919 | ;; to record. The syntax table is not to be | |
1920 | ;; trusted here since the caller might be using | |
1921 | ;; e.g. `c++-template-syntax-table'. | |
1922 | (memq (char-before last-pos) '(?{ ?\( ?\[))) | |
d9e94c22 MS |
1923 | (setq c-state-cache (cons (1- last-pos) c-state-cache)))) |
1924 | ||
a66cd3ee MS |
1925 | (if (setq last-pos (c-up-list-forward pos)) |
1926 | ;; Found a close paren without a corresponding opening | |
1927 | ;; one. Maybe we didn't go back far enough, so try to | |
1928 | ;; scan backward for the start paren and then start over. | |
1929 | (progn | |
1930 | (setq pos (c-up-list-backward pos) | |
1931 | c-state-cache nil) | |
e33c01bb MS |
1932 | (when (or (not pos) |
1933 | ;; Emacs (up to at least 21.2) can get confused by | |
1934 | ;; open parens in column zero inside comments: The | |
1935 | ;; sexp functions can then misbehave and bring us | |
1936 | ;; back to the same point again. Check this so that | |
1937 | ;; we don't get an infinite loop. | |
1938 | (>= pos save-pos)) | |
a66cd3ee MS |
1939 | (setq pos last-pos |
1940 | c-parsing-error | |
1941 | (format "Unbalanced close paren at line %d" | |
1942 | (1+ (count-lines (point-min) | |
1943 | (c-point 'bol last-pos))))))) | |
1944 | (setq pos nil)))) | |
d9e94c22 | 1945 | |
a66cd3ee MS |
1946 | c-state-cache))) |
1947 | ||
1948 | ;; Debug tool to catch cache inconsistencies. | |
1949 | (defvar c-debug-parse-state nil) | |
1950 | (unless (fboundp 'c-real-parse-state) | |
1951 | (fset 'c-real-parse-state (symbol-function 'c-parse-state))) | |
1952 | (cc-bytecomp-defun c-real-parse-state) | |
1953 | (defun c-debug-parse-state () | |
1954 | (let ((res1 (c-real-parse-state)) res2) | |
1955 | (let ((c-state-cache nil)) | |
1956 | (setq res2 (c-real-parse-state))) | |
1957 | (unless (equal res1 res2) | |
1958 | (error "c-parse-state inconsistency: using cache: %s, from scratch: %s" | |
1959 | res1 res2)) | |
1960 | res1)) | |
1961 | (defun c-toggle-parse-state-debug (&optional arg) | |
1962 | (interactive "P") | |
1963 | (setq c-debug-parse-state (c-calculate-state arg c-debug-parse-state)) | |
1964 | (fset 'c-parse-state (symbol-function (if c-debug-parse-state | |
1965 | 'c-debug-parse-state | |
1966 | 'c-real-parse-state))) | |
1967 | (c-keep-region-active)) | |
1968 | ||
d9e94c22 MS |
1969 | (defun c-whack-state-before (bufpos paren-state) |
1970 | ;; Whack off any state information from PAREN-STATE which lies | |
1971 | ;; before BUFPOS. Not destructive on PAREN-STATE. | |
1972 | ;; | |
1973 | ;; This function does not do any hidden buffer changes. | |
1974 | (let* ((newstate (list nil)) | |
1975 | (ptr newstate) | |
1976 | car) | |
1977 | (while paren-state | |
1978 | (setq car (car paren-state) | |
1979 | paren-state (cdr paren-state)) | |
1980 | (if (< (if (consp car) (car car) car) bufpos) | |
1981 | (setq paren-state nil) | |
1982 | (setcdr ptr (list car)) | |
1983 | (setq ptr (cdr ptr)))) | |
1984 | (cdr newstate))) | |
1985 | ||
1986 | (defun c-whack-state-after (bufpos paren-state) | |
1987 | ;; Whack off any state information from PAREN-STATE which lies at or | |
1988 | ;; after BUFPOS. Not destructive on PAREN-STATE. | |
1989 | ;; | |
1990 | ;; This function does not do any hidden buffer changes. | |
1991 | (catch 'done | |
1992 | (while paren-state | |
1993 | (let ((car (car paren-state))) | |
1994 | (if (consp car) | |
1995 | ;; just check the car, because in a balanced brace | |
1996 | ;; expression, it must be impossible for the corresponding | |
1997 | ;; close brace to be before point, but the open brace to | |
1998 | ;; be after. | |
1999 | (if (<= bufpos (car car)) | |
2000 | nil ; whack it off | |
2001 | (if (< bufpos (cdr car)) | |
2002 | ;; its possible that the open brace is before | |
2003 | ;; bufpos, but the close brace is after. In that | |
2004 | ;; case, convert this to a non-cons element. The | |
2005 | ;; rest of the state is before bufpos, so we're | |
2006 | ;; done. | |
2007 | (throw 'done (cons (car car) (cdr paren-state))) | |
2008 | ;; we know that both the open and close braces are | |
2009 | ;; before bufpos, so we also know that everything else | |
2010 | ;; on state is before bufpos. | |
2011 | (throw 'done paren-state))) | |
2012 | (if (<= bufpos car) | |
2013 | nil ; whack it off | |
2014 | ;; it's before bufpos, so everything else should too. | |
2015 | (throw 'done paren-state))) | |
2016 | (setq paren-state (cdr paren-state))) | |
2017 | nil))) | |
2018 | ||
2019 | (defun c-most-enclosing-brace (paren-state &optional bufpos) | |
2020 | ;; Return the bufpos of the innermost enclosing open paren before | |
2021 | ;; bufpos that hasn't been narrowed out, or nil if none was found. | |
2022 | ;; | |
2023 | ;; This function does not do any hidden buffer changes. | |
2024 | (let (enclosingp) | |
2025 | (or bufpos (setq bufpos 134217727)) | |
2026 | (while paren-state | |
2027 | (setq enclosingp (car paren-state) | |
2028 | paren-state (cdr paren-state)) | |
2029 | (if (or (consp enclosingp) | |
2030 | (>= enclosingp bufpos)) | |
2031 | (setq enclosingp nil) | |
2032 | (if (< enclosingp (point-min)) | |
2033 | (setq enclosingp nil)) | |
2034 | (setq paren-state nil))) | |
2035 | enclosingp)) | |
2036 | ||
2037 | (defun c-least-enclosing-brace (paren-state &optional bufpos) | |
2038 | ;; Return the bufpos of the outermost enclosing open paren before | |
2039 | ;; bufpos that hasn't been narrowed out, or nil if none was found. | |
2040 | ;; | |
2041 | ;; This function does not do any hidden buffer changes. | |
2042 | (let (pos elem) | |
2043 | (or bufpos (setq bufpos 134217727)) | |
2044 | (while paren-state | |
2045 | (setq elem (car paren-state) | |
2046 | paren-state (cdr paren-state)) | |
2047 | (unless (or (consp elem) | |
2048 | (>= elem bufpos)) | |
2049 | (if (>= elem (point-min)) | |
2050 | (setq pos elem)))) | |
2051 | pos)) | |
2052 | ||
2053 | (defun c-safe-position (bufpos paren-state) | |
2054 | ;; Return the closest known safe position higher up than BUFPOS, or | |
2055 | ;; nil if PAREN-STATE doesn't contain one. Return nil if BUFPOS is | |
2056 | ;; nil, which is useful to find the closest limit before a given | |
2057 | ;; limit that might be nil. | |
2058 | ;; | |
2059 | ;; This function does not do any hidden buffer changes. | |
2060 | (when bufpos | |
2061 | (let (elem) | |
2062 | (catch 'done | |
2063 | (while paren-state | |
2064 | (setq elem (car paren-state)) | |
2065 | (if (consp elem) | |
2066 | (cond ((< (cdr elem) bufpos) | |
2067 | (throw 'done (cdr elem))) | |
2068 | ((< (car elem) bufpos) | |
2069 | ;; See below. | |
2070 | (throw 'done (min (1+ (car elem)) bufpos)))) | |
2071 | (if (< elem bufpos) | |
2072 | ;; elem is the position at and not after the opening paren, so | |
2073 | ;; we can go forward one more step unless it's equal to | |
2074 | ;; bufpos. This is useful in some cases avoid an extra paren | |
2075 | ;; level between the safe position and bufpos. | |
2076 | (throw 'done (min (1+ elem) bufpos)))) | |
2077 | (setq paren-state (cdr paren-state))))))) | |
2078 | ||
2079 | (defun c-beginning-of-syntax () | |
2080 | ;; This is used for `font-lock-beginning-of-syntax-function'. It | |
2081 | ;; goes to the closest previous point that is known to be outside | |
2082 | ;; any string literal or comment. `c-state-cache' is used if it has | |
2083 | ;; a position in the vicinity. | |
2084 | (let* ((paren-state c-state-cache) | |
2085 | elem | |
2086 | ||
2087 | (pos (catch 'done | |
2088 | ;; Note: Similar code in `c-safe-position'. The | |
2089 | ;; difference is that we accept a safe position at | |
2090 | ;; the point and don't bother to go forward past open | |
2091 | ;; parens. | |
2092 | (while paren-state | |
2093 | (setq elem (car paren-state)) | |
2094 | (if (consp elem) | |
2095 | (cond ((<= (cdr elem) (point)) | |
2096 | (throw 'done (cdr elem))) | |
2097 | ((<= (car elem) (point)) | |
2098 | (throw 'done (car elem)))) | |
2099 | (if (<= elem (point)) | |
2100 | (throw 'done elem))) | |
2101 | (setq paren-state (cdr paren-state))) | |
2102 | (point-min)))) | |
2103 | ||
2104 | (if (> pos (- (point) 4000)) | |
2105 | (goto-char pos) | |
2106 | ;; The position is far back. Try `c-beginning-of-defun-1' | |
2107 | ;; (although we can't be entirely sure it will go to a position | |
2108 | ;; outside a comment or string in current emacsen). FIXME: | |
2109 | ;; Consult `syntax-ppss' here. | |
2110 | (c-beginning-of-defun-1) | |
2111 | (if (< (point) pos) | |
2112 | (goto-char pos))))) | |
2113 | ||
2114 | \f | |
2115 | ;; Tools for scanning identifiers and other tokens. | |
2116 | ||
2117 | (defun c-on-identifier () | |
2118 | "Return non-nil if the point is on or directly after an identifier. | |
2119 | Keywords are recognized and not considered identifiers. If an | |
2120 | identifier is detected, the returned value is its starting position. | |
2121 | If an identifier both starts and stops at the point \(can only happen | |
2122 | in Pike) then the point for the preceding one is returned. | |
2123 | ||
2124 | This function does not do any hidden buffer changes." | |
2125 | ||
2126 | (save-excursion | |
2127 | (if (zerop (skip-syntax-backward "w_")) | |
2128 | ||
2129 | (when (c-major-mode-is 'pike-mode) | |
2130 | ;; Handle the `<operator> syntax in Pike. | |
2131 | (let ((pos (point))) | |
2a15eb73 | 2132 | (skip-chars-backward "-!%&*+/<=>^|~[]()") |
d9e94c22 MS |
2133 | (and (if (< (skip-chars-backward "`") 0) |
2134 | t | |
2135 | (goto-char pos) | |
2136 | (eq (char-after) ?\`)) | |
2137 | (looking-at c-symbol-key) | |
2138 | (>= (match-end 0) pos) | |
2139 | (point)))) | |
2140 | ||
2141 | (and (not (looking-at c-keywords-regexp)) | |
2142 | (point))))) | |
2143 | ||
2144 | (defsubst c-simple-skip-symbol-backward () | |
2145 | ;; If the point is at the end of a symbol then skip backward to the | |
2146 | ;; beginning of it. Don't move otherwise. Return non-nil if point | |
2147 | ;; moved. | |
2148 | (or (< (skip-syntax-backward "w_") 0) | |
2149 | (and (c-major-mode-is 'pike-mode) | |
2150 | ;; Handle the `<operator> syntax in Pike. | |
2151 | (let ((pos (point))) | |
2a15eb73 | 2152 | (if (and (< (skip-chars-backward "-!%&*+/<=>^|~[]()") 0) |
d9e94c22 MS |
2153 | (< (skip-chars-backward "`") 0) |
2154 | (looking-at c-symbol-key) | |
2155 | (>= (match-end 0) pos)) | |
2156 | t | |
2157 | (goto-char pos) | |
2158 | nil))))) | |
2159 | ||
2160 | (defsubst c-beginning-of-current-token (&optional back-limit) | |
2161 | ;; Move to the beginning of the current token. Do not move if not | |
2162 | ;; in the middle of one. BACK-LIMIT may be used to bound the | |
2163 | ;; backward search; if given it's assumed to be at the boundary | |
2164 | ;; between two tokens. | |
2165 | (if (looking-at "\\w\\|\\s_") | |
2166 | (skip-syntax-backward "w_" back-limit) | |
2167 | (let ((start (point))) | |
2168 | (when (< (skip-syntax-backward ".()" back-limit) 0) | |
2169 | (while (let ((pos (or (and (looking-at c-nonsymbol-token-regexp) | |
2170 | (match-end 0)) | |
2171 | ;; `c-nonsymbol-token-regexp' should always match | |
2172 | ;; since we've skipped backward over punctuator | |
2173 | ;; or paren syntax, but consume one char in case | |
2174 | ;; it doesn't so that we don't leave point before | |
2175 | ;; some earlier incorrect token. | |
2176 | (1+ (point))))) | |
2177 | (if (<= pos start) | |
2178 | (goto-char pos)) | |
2179 | (< pos start))))))) | |
2180 | ||
ff959bab | 2181 | (defun c-end-of-current-token (&optional back-limit) |
d9e94c22 MS |
2182 | ;; Move to the end of the current token. Do not move if not in the |
2183 | ;; middle of one. BACK-LIMIT may be used to bound the backward | |
2184 | ;; search; if given it's assumed to be at the boundary between two | |
ff959bab | 2185 | ;; tokens. Return non-nil if the point is moved, nil otherwise. |
d9e94c22 MS |
2186 | (let ((start (point))) |
2187 | (cond ((< (skip-syntax-backward "w_" (1- start)) 0) | |
2188 | (skip-syntax-forward "w_")) | |
2189 | ((< (skip-syntax-backward ".()" back-limit) 0) | |
2190 | (while (progn | |
2191 | (if (looking-at c-nonsymbol-token-regexp) | |
2192 | (goto-char (match-end 0)) | |
2193 | ;; `c-nonsymbol-token-regexp' should always match since | |
2194 | ;; we've skipped backward over punctuator or paren | |
2195 | ;; syntax, but move forward in case it doesn't so that | |
2196 | ;; we don't leave point earlier than we started with. | |
2197 | (forward-char)) | |
ff959bab MS |
2198 | (< (point) start))))) |
2199 | (> (point) start))) | |
d9e94c22 MS |
2200 | |
2201 | (defconst c-jump-syntax-balanced | |
2202 | (if (memq 'gen-string-delim c-emacs-features) | |
2203 | "\\w\\|\\s_\\|\\s\(\\|\\s\)\\|\\s\"\\|\\s|" | |
2204 | "\\w\\|\\s_\\|\\s\(\\|\\s\)\\|\\s\"")) | |
2205 | ||
2206 | (defconst c-jump-syntax-unbalanced | |
2207 | (if (memq 'gen-string-delim c-emacs-features) | |
2208 | "\\w\\|\\s_\\|\\s\"\\|\\s|" | |
2209 | "\\w\\|\\s_\\|\\s\"")) | |
2210 | ||
2211 | (defun c-forward-token-2 (&optional count balanced limit) | |
2212 | "Move forward by tokens. | |
2213 | A token is defined as all symbols and identifiers which aren't | |
2214 | syntactic whitespace \(note that multicharacter tokens like \"==\" are | |
2215 | treated properly). Point is always either left at the beginning of a | |
2216 | token or not moved at all. COUNT specifies the number of tokens to | |
2217 | move; a negative COUNT moves in the opposite direction. A COUNT of 0 | |
2218 | moves to the next token beginning only if not already at one. If | |
2219 | BALANCED is true, move over balanced parens, otherwise move into them. | |
2220 | Also, if BALANCED is true, never move out of an enclosing paren. | |
2221 | ||
2222 | LIMIT sets the limit for the movement and defaults to the point limit. | |
2223 | The case when LIMIT is set in the middle of a token, comment or macro | |
2224 | is handled correctly, i.e. the point won't be left there. | |
2225 | ||
2226 | Return the number of tokens left to move \(positive or negative). If | |
2227 | BALANCED is true, a move over a balanced paren counts as one. Note | |
2228 | that if COUNT is 0 and no appropriate token beginning is found, 1 will | |
2229 | be returned. Thus, a return value of 0 guarantees that point is at | |
2230 | the requested position and a return value less \(without signs) than | |
2231 | COUNT guarantees that point is at the beginning of some token." | |
2232 | ||
2233 | (or count (setq count 1)) | |
2234 | (if (< count 0) | |
2235 | (- (c-backward-token-2 (- count) balanced limit)) | |
2236 | ||
2237 | (let ((jump-syntax (if balanced | |
2238 | c-jump-syntax-balanced | |
2239 | c-jump-syntax-unbalanced)) | |
2240 | (last (point)) | |
2241 | (prev (point))) | |
2242 | ||
2243 | (if (zerop count) | |
2244 | ;; If count is zero we should jump if in the middle of a token. | |
2245 | (c-end-of-current-token)) | |
2246 | ||
2247 | (save-restriction | |
2248 | (if limit (narrow-to-region (point-min) limit)) | |
2249 | (if (/= (point) | |
2250 | (progn (c-forward-syntactic-ws) (point))) | |
2251 | ;; Skip whitespace. Count this as a move if we did in | |
2252 | ;; fact move. | |
2253 | (setq count (max (1- count) 0))) | |
2254 | ||
2255 | (if (eobp) | |
2256 | ;; Moved out of bounds. Make sure the returned count isn't zero. | |
2257 | (progn | |
2258 | (if (zerop count) (setq count 1)) | |
2259 | (goto-char last)) | |
2260 | ||
2261 | ;; Use `condition-case' to avoid having the limit tests | |
2262 | ;; inside the loop. | |
2263 | (condition-case nil | |
2264 | (while (and | |
2265 | (> count 0) | |
2266 | (progn | |
2267 | (setq last (point)) | |
2268 | (cond ((looking-at jump-syntax) | |
2269 | (goto-char (scan-sexps (point) 1)) | |
2270 | t) | |
2271 | ((looking-at c-nonsymbol-token-regexp) | |
2272 | (goto-char (match-end 0)) | |
2273 | t) | |
2274 | ;; `c-nonsymbol-token-regexp' above should always | |
2275 | ;; match if there are correct tokens. Try to | |
2276 | ;; widen to see if the limit was set in the | |
2277 | ;; middle of one, else fall back to treating | |
2278 | ;; the offending thing as a one character token. | |
2279 | ((and limit | |
2280 | (save-restriction | |
2281 | (widen) | |
2282 | (looking-at c-nonsymbol-token-regexp))) | |
2283 | nil) | |
2284 | (t | |
2285 | (forward-char) | |
2286 | t)))) | |
2287 | (c-forward-syntactic-ws) | |
2288 | (setq prev last | |
2289 | count (1- count))) | |
2290 | (error (goto-char last))) | |
2291 | ||
2292 | (when (eobp) | |
2293 | (goto-char prev) | |
2294 | (setq count (1+ count))))) | |
2295 | ||
2296 | count))) | |
2297 | ||
2298 | (defun c-backward-token-2 (&optional count balanced limit) | |
2299 | "Move backward by tokens. | |
2300 | See `c-forward-token-2' for details." | |
2301 | ||
2302 | (or count (setq count 1)) | |
2303 | (if (< count 0) | |
2304 | (- (c-forward-token-2 (- count) balanced limit)) | |
2305 | ||
2306 | (or limit (setq limit (point-min))) | |
2307 | (let ((jump-syntax (if balanced | |
2308 | c-jump-syntax-balanced | |
2309 | c-jump-syntax-unbalanced)) | |
2310 | (last (point))) | |
2311 | ||
2312 | (if (zerop count) | |
2313 | ;; The count is zero so try to skip to the beginning of the | |
2314 | ;; current token. | |
2315 | (if (> (point) | |
2316 | (progn (c-beginning-of-current-token) (point))) | |
2317 | (if (< (point) limit) | |
2318 | ;; The limit is inside the same token, so return 1. | |
2319 | (setq count 1)) | |
2320 | ||
2321 | ;; We're not in the middle of a token. If there's | |
2322 | ;; whitespace after the point then we must move backward, | |
2323 | ;; so set count to 1 in that case. | |
2324 | (and (looking-at c-syntactic-ws-start) | |
2325 | ;; If we're looking at a '#' that might start a cpp | |
2326 | ;; directive then we have to do a more elaborate check. | |
2327 | (or (/= (char-after) ?#) | |
2328 | (not c-opt-cpp-prefix) | |
2329 | (save-excursion | |
2330 | (and (= (point) | |
2331 | (progn (beginning-of-line) | |
2332 | (looking-at "[ \t]*") | |
2333 | (match-end 0))) | |
2334 | (or (bobp) | |
2335 | (progn (backward-char) | |
2336 | (not (eq (char-before) ?\\))))))) | |
2337 | (setq count 1)))) | |
2338 | ||
2339 | ;; Use `condition-case' to avoid having to check for buffer | |
2340 | ;; limits in `backward-char', `scan-sexps' and `goto-char' below. | |
2341 | (condition-case nil | |
2342 | (while (and | |
2343 | (> count 0) | |
2344 | (progn | |
2345 | (c-backward-syntactic-ws) | |
2346 | (backward-char) | |
2347 | (if (looking-at jump-syntax) | |
2348 | (goto-char (scan-sexps (1+ (point)) -1)) | |
2349 | ;; This can be very inefficient if there's a long | |
2350 | ;; sequence of operator tokens without any separation. | |
2351 | ;; That doesn't happen in practice, anyway. | |
2352 | (c-beginning-of-current-token)) | |
2353 | (>= (point) limit))) | |
2354 | (setq last (point) | |
2355 | count (1- count))) | |
2356 | (error (goto-char last))) | |
2357 | ||
2358 | (if (< (point) limit) | |
2359 | (goto-char last)) | |
2360 | ||
2361 | count))) | |
2362 | ||
2363 | (defun c-forward-token-1 (&optional count balanced limit) | |
2364 | "Like `c-forward-token-2' but doesn't treat multicharacter operator | |
2365 | tokens like \"==\" as single tokens, i.e. all sequences of symbol | |
2366 | characters are jumped over character by character. This function is | |
2367 | for compatibility only; it's only a wrapper over `c-forward-token-2'." | |
2368 | (let ((c-nonsymbol-token-regexp "\\s.\\|\\s\(\\|\\s\)")) | |
2369 | (c-forward-token-2 count balanced limit))) | |
2370 | ||
2371 | (defun c-backward-token-1 (&optional count balanced limit) | |
2372 | "Like `c-backward-token-2' but doesn't treat multicharacter operator | |
2373 | tokens like \"==\" as single tokens, i.e. all sequences of symbol | |
2374 | characters are jumped over character by character. This function is | |
2375 | for compatibility only; it's only a wrapper over `c-backward-token-2'." | |
2376 | (let ((c-nonsymbol-token-regexp "\\s.\\|\\s\(\\|\\s\)")) | |
2377 | (c-backward-token-2 count balanced limit))) | |
2378 | ||
2379 | \f | |
2380 | ;; Tools for doing searches restricted to syntactically relevant text. | |
2381 | ||
2382 | (defun c-syntactic-re-search-forward (regexp &optional bound noerror | |
2383 | paren-level not-inside-token | |
2384 | lookbehind-submatch) | |
2385 | "Like `re-search-forward', but only report matches that are found | |
2386 | in syntactically significant text. I.e. matches in comments, macros | |
2387 | or string literals are ignored. The start point is assumed to be | |
2388 | outside any comment, macro or string literal, or else the content of | |
2389 | that region is taken as syntactically significant text. | |
2390 | ||
2391 | If PAREN-LEVEL is non-nil, an additional restriction is added to | |
2a15eb73 MS |
2392 | ignore matches in nested paren sexps. The search will also not go |
2393 | outside the current list sexp, which has the effect that if the point | |
2394 | should be moved to BOUND when no match is found \(i.e. NOERROR is | |
2395 | neither nil nor t), then it will be at the closing paren if the end of | |
2396 | the current list sexp is encountered first. | |
d9e94c22 MS |
2397 | |
2398 | If NOT-INSIDE-TOKEN is non-nil, matches in the middle of tokens are | |
2399 | ignored. Things like multicharacter operators and special symbols | |
2400 | \(e.g. \"`()\" in Pike) are handled but currently not floating point | |
2401 | constants. | |
2402 | ||
2403 | If LOOKBEHIND-SUBMATCH is non-nil, it's taken as a number of a | |
2404 | subexpression in REGEXP. The end of that submatch is used as the | |
2405 | position to check for syntactic significance. If LOOKBEHIND-SUBMATCH | |
2406 | isn't used or if that subexpression didn't match then the start | |
2407 | position of the whole match is used instead. The \"look behind\" | |
2408 | subexpression is never tested before the starting position, so it | |
2409 | might be a good idea to include \\=\\= as a match alternative in it. | |
2410 | ||
2411 | Optimization note: Matches might be missed if the \"look behind\" | |
2a15eb73 | 2412 | subexpression can match the end of nonwhite syntactic whitespace, |
d9e94c22 | 2413 | i.e. the end of comments or cpp directives. This since the function |
2a15eb73 MS |
2414 | skips over such things before resuming the search. It's on the other |
2415 | hand not safe to assume that the \"look behind\" subexpression never | |
2416 | matches syntactic whitespace. | |
2417 | ||
2418 | Bug: Unbalanced parens inside cpp directives are currently not handled | |
2419 | correctly \(i.e. they don't get ignored as they should) when | |
2420 | PAREN-LEVEL is set." | |
d9e94c22 MS |
2421 | |
2422 | (or bound (setq bound (point-max))) | |
2423 | (if paren-level (setq paren-level -1)) | |
2424 | ||
2425 | ;;(message "c-syntactic-re-search-forward %s %s %S" (point) bound regexp) | |
2426 | ||
2427 | (let ((start (point)) | |
2a15eb73 MS |
2428 | tmp |
2429 | ;; Start position for the last search. | |
2430 | search-pos | |
2431 | ;; The `parse-partial-sexp' state between the start position | |
2432 | ;; and the point. | |
2433 | state | |
2434 | ;; The current position after the last state update. The next | |
2435 | ;; `parse-partial-sexp' continues from here. | |
2436 | (state-pos (point)) | |
2437 | ;; The position at which to check the state and the state | |
2438 | ;; there. This is separate from `state-pos' since we might | |
2439 | ;; need to back up before doing the next search round. | |
2440 | check-pos check-state | |
2441 | ;; Last position known to end a token. | |
d9e94c22 | 2442 | (last-token-end-pos (point-min)) |
2a15eb73 MS |
2443 | ;; Set when a valid match is found. |
2444 | found) | |
d9e94c22 MS |
2445 | |
2446 | (condition-case err | |
2447 | (while | |
2448 | (and | |
2a15eb73 MS |
2449 | (progn |
2450 | (setq search-pos (point)) | |
2451 | (re-search-forward regexp bound noerror)) | |
d9e94c22 MS |
2452 | |
2453 | (progn | |
2a15eb73 MS |
2454 | (setq state (parse-partial-sexp |
2455 | state-pos (match-beginning 0) paren-level nil state) | |
2456 | state-pos (point)) | |
d9e94c22 | 2457 | (if (setq check-pos (and lookbehind-submatch |
2a15eb73 MS |
2458 | (or (not paren-level) |
2459 | (>= (car state) 0)) | |
d9e94c22 MS |
2460 | (match-end lookbehind-submatch))) |
2461 | (setq check-state (parse-partial-sexp | |
2a15eb73 MS |
2462 | state-pos check-pos paren-level nil state)) |
2463 | (setq check-pos state-pos | |
d9e94c22 MS |
2464 | check-state state)) |
2465 | ||
2a15eb73 MS |
2466 | ;; NOTE: If we got a look behind subexpression and get |
2467 | ;; an insignificant match in something that isn't | |
d9e94c22 MS |
2468 | ;; syntactic whitespace (i.e. strings or in nested |
2469 | ;; parentheses), then we can never skip more than a | |
2a15eb73 MS |
2470 | ;; single character from the match start position |
2471 | ;; (i.e. `state-pos' here) before continuing the | |
2472 | ;; search. That since the look behind subexpression | |
2473 | ;; might match the end of the insignificant region in | |
2474 | ;; the next search. | |
d9e94c22 MS |
2475 | |
2476 | (cond | |
d9e94c22 MS |
2477 | ((elt check-state 7) |
2478 | ;; Match inside a line comment. Skip to eol. Use | |
2479 | ;; `re-search-forward' instead of `skip-chars-forward' to get | |
2480 | ;; the right bound behavior. | |
2481 | (re-search-forward "[\n\r]" bound noerror)) | |
2482 | ||
2483 | ((elt check-state 4) | |
2484 | ;; Match inside a block comment. Skip to the '*/'. | |
2485 | (search-forward "*/" bound noerror)) | |
2486 | ||
2487 | ((and (not (elt check-state 5)) | |
2488 | (eq (char-before check-pos) ?/) | |
2a15eb73 | 2489 | (not (c-get-char-property (1- check-pos) 'syntax-table)) |
d9e94c22 MS |
2490 | (memq (char-after check-pos) '(?/ ?*))) |
2491 | ;; Match in the middle of the opener of a block or line | |
2492 | ;; comment. | |
2493 | (if (= (char-after check-pos) ?/) | |
2494 | (re-search-forward "[\n\r]" bound noerror) | |
2495 | (search-forward "*/" bound noerror))) | |
2496 | ||
2a15eb73 MS |
2497 | ;; The last `parse-partial-sexp' above might have |
2498 | ;; stopped short of the real check position if the end | |
2499 | ;; of the current sexp was encountered in paren-level | |
2500 | ;; mode. The checks above are always false in that | |
2501 | ;; case, and since they can do better skipping in | |
2502 | ;; lookbehind-submatch mode, we do them before | |
2503 | ;; checking the paren level. | |
2504 | ||
2505 | ((and paren-level | |
2506 | (/= (setq tmp (car check-state)) 0)) | |
2507 | ;; Check the paren level first since we're short of the | |
2508 | ;; syntactic checking position if the end of the | |
2509 | ;; current sexp was encountered by `parse-partial-sexp'. | |
2510 | (if (> tmp 0) | |
2511 | ||
2512 | ;; Inside a nested paren sexp. | |
2513 | (if lookbehind-submatch | |
2514 | ;; See the NOTE above. | |
2515 | (progn (goto-char state-pos) t) | |
2516 | ;; Skip out of the paren quickly. | |
2517 | (setq state (parse-partial-sexp state-pos bound 0 nil state) | |
2518 | state-pos (point))) | |
2519 | ||
2520 | ;; Have exited the current paren sexp. | |
2521 | (if noerror | |
2522 | (progn | |
2523 | ;; The last `parse-partial-sexp' call above | |
2524 | ;; has left us just after the closing paren | |
2525 | ;; in this case, so we can modify the bound | |
2526 | ;; to leave the point at the right position | |
2527 | ;; upon return. | |
2528 | (setq bound (1- (point))) | |
2529 | nil) | |
2530 | (signal 'search-failed (list regexp))))) | |
2531 | ||
2532 | ((setq tmp (elt check-state 3)) | |
2533 | ;; Match inside a string. | |
2534 | (if (or lookbehind-submatch | |
2535 | (not (integerp tmp))) | |
2536 | ;; See the NOTE above. | |
2537 | (progn (goto-char state-pos) t) | |
2538 | ;; Skip to the end of the string before continuing. | |
2539 | (let ((ender (make-string 1 tmp)) (continue t)) | |
2540 | (while (if (search-forward ender bound noerror) | |
2541 | (progn | |
2542 | (setq state (parse-partial-sexp | |
2543 | state-pos (point) nil nil state) | |
2544 | state-pos (point)) | |
2545 | (elt state 3)) | |
2546 | (setq continue nil))) | |
2547 | continue))) | |
d9e94c22 MS |
2548 | |
2549 | ((save-excursion | |
2550 | (save-match-data | |
2551 | (c-beginning-of-macro start))) | |
2552 | ;; Match inside a macro. Skip to the end of it. | |
2553 | (c-end-of-macro) | |
2554 | (cond ((<= (point) bound) t) | |
2555 | (noerror nil) | |
2a15eb73 | 2556 | (t (signal 'search-failed (list regexp))))) |
d9e94c22 | 2557 | |
2a15eb73 MS |
2558 | ((and not-inside-token |
2559 | (or (< check-pos last-token-end-pos) | |
2560 | (< check-pos | |
2561 | (save-excursion | |
2562 | (goto-char check-pos) | |
2563 | (save-match-data | |
2564 | (c-end-of-current-token last-token-end-pos)) | |
2565 | (setq last-token-end-pos (point)))))) | |
2566 | ;; Inside a token. | |
2567 | (if lookbehind-submatch | |
2568 | ;; See the NOTE above. | |
2569 | (goto-char state-pos) | |
2570 | (goto-char (min last-token-end-pos bound)))) | |
d9e94c22 MS |
2571 | |
2572 | (t | |
2573 | ;; A real match. | |
2574 | (setq found t) | |
2a15eb73 MS |
2575 | nil))) |
2576 | ||
2577 | ;; Should loop to search again, but take care to avoid | |
2578 | ;; looping on the same spot. | |
2579 | (or (/= search-pos (point)) | |
2580 | (if (= (point) bound) | |
2581 | (if noerror | |
2582 | nil | |
2583 | (signal 'search-failed (list regexp))) | |
2584 | (forward-char) | |
2585 | t)))) | |
d9e94c22 MS |
2586 | |
2587 | (error | |
2588 | (goto-char start) | |
2589 | (signal (car err) (cdr err)))) | |
2590 | ||
2a15eb73 | 2591 | ;;(message "c-syntactic-re-search-forward done %s" (or (match-end 0) (point))) |
d9e94c22 MS |
2592 | |
2593 | (if found | |
2594 | (progn | |
2a15eb73 MS |
2595 | (goto-char (match-end 0)) |
2596 | (match-end 0)) | |
d9e94c22 MS |
2597 | |
2598 | ;; Search failed. Set point as appropriate. | |
2a15eb73 MS |
2599 | (if (eq noerror t) |
2600 | (goto-char start) | |
2601 | (goto-char bound)) | |
d9e94c22 MS |
2602 | nil))) |
2603 | ||
2604 | (defun c-syntactic-skip-backward (skip-chars &optional limit) | |
2605 | "Like `skip-chars-backward' but only look at syntactically relevant chars, | |
2606 | i.e. don't stop at positions inside syntactic whitespace or string | |
2607 | literals. Preprocessor directives are also ignored, with the exception | |
2608 | of the one that the point starts within, if any. If LIMIT is given, | |
037558bf | 2609 | it's assumed to be at a syntactically relevant position." |
d9e94c22 MS |
2610 | |
2611 | (let ((start (point)) | |
2612 | ;; A list of syntactically relevant positions in descending | |
2613 | ;; order. It's used to avoid scanning repeatedly over | |
2614 | ;; potentially large regions with `parse-partial-sexp' to verify | |
2615 | ;; each position. | |
2616 | safe-pos-list | |
2617 | ;; The result from `c-beginning-of-macro' at the start position or the | |
2618 | ;; start position itself if it isn't within a macro. Evaluated on | |
2619 | ;; demand. | |
2620 | start-macro-beg) | |
2621 | ||
2622 | (while (progn | |
2623 | (while (and | |
2624 | (< (skip-chars-backward skip-chars limit) 0) | |
2625 | ||
2626 | ;; Use `parse-partial-sexp' from a safe position down to | |
2627 | ;; the point to check if it's outside comments and | |
2628 | ;; strings. | |
2629 | (let ((pos (point)) safe-pos state) | |
2630 | ;; Pick a safe position as close to the point as | |
2631 | ;; possible. | |
2632 | ;; | |
2633 | ;; FIXME: Consult `syntax-ppss' here if our | |
2634 | ;; cache doesn't give a good position. | |
2635 | (while (and safe-pos-list | |
2636 | (> (car safe-pos-list) (point))) | |
2637 | (setq safe-pos-list (cdr safe-pos-list))) | |
2638 | (unless (setq safe-pos (car-safe safe-pos-list)) | |
2639 | (setq safe-pos (max (or (c-safe-position | |
2640 | (point) (or c-state-cache | |
2641 | (c-parse-state))) | |
2642 | 0) | |
2643 | (point-min)) | |
2644 | safe-pos-list (list safe-pos))) | |
2645 | ||
2646 | (while (progn | |
2647 | (setq state (parse-partial-sexp | |
2648 | safe-pos pos 0)) | |
2649 | (< (point) pos)) | |
2650 | ;; Cache positions along the way to use if we have to | |
2651 | ;; back up more. Every closing paren on the same | |
2652 | ;; level seems like fairly well spaced positions. | |
2653 | (setq safe-pos (point) | |
2654 | safe-pos-list (cons safe-pos safe-pos-list))) | |
2655 | ||
2656 | (cond | |
2657 | ((or (elt state 3) (elt state 4)) | |
2658 | ;; Inside string or comment. Continue search at the | |
2659 | ;; beginning of it. | |
2660 | (if (setq pos (nth 8 state)) | |
2661 | ;; It's an emacs where `parse-partial-sexp' | |
2662 | ;; supplies the starting position. | |
2663 | (goto-char pos) | |
2664 | (goto-char (car (c-literal-limits safe-pos)))) | |
2665 | t) | |
2666 | ||
2667 | ((c-beginning-of-macro limit) | |
2668 | ;; Inside a macro. | |
2669 | (if (< (point) | |
2670 | (or start-macro-beg | |
2671 | (setq start-macro-beg | |
2672 | (save-excursion | |
2673 | (goto-char start) | |
2674 | (c-beginning-of-macro limit) | |
2675 | (point))))) | |
2676 | t | |
2677 | ;; It's inside the same macro we started in so it's | |
2678 | ;; a relevant match. | |
2679 | (goto-char pos) | |
2680 | nil)))))) | |
2681 | ||
2682 | (> (point) | |
2683 | (progn | |
2684 | ;; Skip syntactic ws afterwards so that we don't stop at the | |
2685 | ;; end of a comment if `skip-chars' is something like "^/". | |
2686 | (c-backward-syntactic-ws) | |
2687 | (point))))) | |
2688 | ||
2689 | (- (point) start))) | |
2690 | ||
2691 | \f | |
2692 | ;; Tools for handling comments and string literals. | |
2693 | ||
2694 | (defun c-slow-in-literal (&optional lim detect-cpp) | |
2695 | "Return the type of literal point is in, if any. | |
2696 | The return value is `c' if in a C-style comment, `c++' if in a C++ | |
2697 | style comment, `string' if in a string literal, `pound' if DETECT-CPP | |
2698 | is non-nil and in a preprocessor line, or nil if somewhere else. | |
2699 | Optional LIM is used as the backward limit of the search. If omitted, | |
2700 | or nil, `c-beginning-of-defun' is used. | |
2701 | ||
2702 | The last point calculated is cached if the cache is enabled, i.e. if | |
2703 | `c-in-literal-cache' is bound to a two element vector. | |
2704 | ||
2705 | This function does not do any hidden buffer changes." | |
2706 | (if (and (vectorp c-in-literal-cache) | |
2707 | (= (point) (aref c-in-literal-cache 0))) | |
2708 | (aref c-in-literal-cache 1) | |
2709 | (let ((rtn (save-excursion | |
2710 | (let* ((pos (point)) | |
2711 | (lim (or lim (progn | |
2712 | (c-beginning-of-syntax) | |
2713 | (point)))) | |
2714 | (state (parse-partial-sexp lim pos))) | |
2715 | (cond | |
2716 | ((elt state 3) 'string) | |
2717 | ((elt state 4) (if (elt state 7) 'c++ 'c)) | |
2718 | ((and detect-cpp (c-beginning-of-macro lim)) 'pound) | |
2719 | (t nil)))))) | |
2720 | ;; cache this result if the cache is enabled | |
2721 | (if (not c-in-literal-cache) | |
2722 | (setq c-in-literal-cache (vector (point) rtn))) | |
2723 | rtn))) | |
2724 | ||
2725 | ;; XEmacs has a built-in function that should make this much quicker. | |
2726 | ;; I don't think we even need the cache, which makes our lives more | |
2727 | ;; complicated anyway. In this case, lim is only used to detect | |
2728 | ;; cpp directives. | |
2729 | ;; | |
2730 | ;; Note that there is a bug in Xemacs's buffer-syntactic-context when used in | |
2731 | ;; conjunction with syntax-table-properties. The bug is present in, e.g., | |
2732 | ;; Xemacs 21.4.4. It manifested itself thus: | |
2733 | ;; | |
2734 | ;; Starting with an empty AWK Mode buffer, type | |
2735 | ;; /regexp/ {<C-j> | |
2736 | ;; Point gets wrongly left at column 0, rather than being indented to tab-width. | |
2737 | ;; | |
2738 | ;; AWK Mode is designed such that when the first / is typed, it gets the | |
2739 | ;; syntax-table property "string fence". When the second / is typed, BOTH /s | |
2740 | ;; are given the s-t property "string". However, buffer-syntactic-context | |
2741 | ;; fails to take account of the change of the s-t property on the opening / to | |
2742 | ;; "string", and reports that the { is within a string started by the second /. | |
2743 | ;; | |
2744 | ;; The workaround for this is for the AWK Mode initialisation to switch the | |
2745 | ;; defalias for c-in-literal to c-slow-in-literal. This will slow down other | |
2746 | ;; cc-modes in Xemacs whenever an awk-buffer has been initialised. | |
2747 | ;; | |
2748 | ;; (Alan Mackenzie, 2003/4/30). | |
2749 | ||
2750 | (defun c-fast-in-literal (&optional lim detect-cpp) | |
2751 | (let ((context (buffer-syntactic-context))) | |
2752 | (cond | |
2753 | ((eq context 'string) 'string) | |
2754 | ((eq context 'comment) 'c++) | |
2755 | ((eq context 'block-comment) 'c) | |
2756 | ((and detect-cpp (save-excursion (c-beginning-of-macro lim))) 'pound)))) | |
2757 | ||
2758 | (defalias 'c-in-literal | |
2759 | (if (fboundp 'buffer-syntactic-context) | |
7bfc3fdb | 2760 | 'c-fast-in-literal ; XEmacs |
d9e94c22 MS |
2761 | 'c-slow-in-literal)) ; GNU Emacs |
2762 | ||
2763 | ;; The defalias above isn't enough to shut up the byte compiler. | |
2764 | (cc-bytecomp-defun c-in-literal) | |
2765 | ||
2766 | (defun c-literal-limits (&optional lim near not-in-delimiter) | |
2767 | "Return a cons of the beginning and end positions of the comment or | |
2768 | string surrounding point (including both delimiters), or nil if point | |
2769 | isn't in one. If LIM is non-nil, it's used as the \"safe\" position | |
2770 | to start parsing from. If NEAR is non-nil, then the limits of any | |
2771 | literal next to point is returned. \"Next to\" means there's only | |
2772 | spaces and tabs between point and the literal. The search for such a | |
2773 | literal is done first in forward direction. If NOT-IN-DELIMITER is | |
2774 | non-nil, the case when point is inside a starting delimiter won't be | |
2775 | recognized. This only has effect for comments, which have starting | |
2776 | delimiters with more than one character. | |
2777 | ||
2778 | This function does not do any hidden buffer changes." | |
2779 | ||
2780 | (save-excursion | |
2781 | (let* ((pos (point)) | |
2782 | (lim (or lim (progn | |
2783 | (c-beginning-of-syntax) | |
2784 | (point)))) | |
2785 | (state (parse-partial-sexp lim pos))) | |
2786 | ||
2787 | (cond ((elt state 3) | |
2788 | ;; String. Search backward for the start. | |
2789 | (while (elt state 3) | |
2790 | (search-backward (make-string 1 (elt state 3))) | |
2791 | (setq state (parse-partial-sexp lim (point)))) | |
2792 | (cons (point) (or (c-safe (c-forward-sexp 1) (point)) | |
2793 | (point-max)))) | |
2794 | ||
2795 | ((elt state 7) | |
2796 | ;; Line comment. Search from bol for the comment starter. | |
2797 | (beginning-of-line) | |
2798 | (setq state (parse-partial-sexp lim (point)) | |
2799 | lim (point)) | |
2800 | (while (not (elt state 7)) | |
2801 | (search-forward "//") ; Should never fail. | |
2802 | (setq state (parse-partial-sexp | |
2803 | lim (point) nil nil state) | |
2804 | lim (point))) | |
2805 | (backward-char 2) | |
2806 | (cons (point) (progn (c-forward-single-comment) (point)))) | |
2807 | ||
2808 | ((elt state 4) | |
2809 | ;; Block comment. Search backward for the comment starter. | |
2810 | (while (elt state 4) | |
2811 | (search-backward "/*") ; Should never fail. | |
2812 | (setq state (parse-partial-sexp lim (point)))) | |
2813 | (cons (point) (progn (c-forward-single-comment) (point)))) | |
2814 | ||
2815 | ((and (not not-in-delimiter) | |
2816 | (not (elt state 5)) | |
2817 | (eq (char-before) ?/) | |
2818 | (looking-at "[/*]")) | |
2819 | ;; We're standing in a comment starter. | |
2820 | (backward-char 1) | |
2821 | (cons (point) (progn (c-forward-single-comment) (point)))) | |
2822 | ||
2823 | (near | |
2824 | (goto-char pos) | |
2825 | ||
2826 | ;; Search forward for a literal. | |
2827 | (skip-chars-forward " \t") | |
2828 | ||
2829 | (cond | |
2830 | ((looking-at c-string-limit-regexp) ; String. | |
2831 | (cons (point) (or (c-safe (c-forward-sexp 1) (point)) | |
2832 | (point-max)))) | |
2833 | ||
2834 | ((looking-at c-comment-start-regexp) ; Line or block comment. | |
2835 | (cons (point) (progn (c-forward-single-comment) (point)))) | |
2836 | ||
2837 | (t | |
2838 | ;; Search backward. | |
2839 | (skip-chars-backward " \t") | |
2840 | ||
2841 | (let ((end (point)) beg) | |
2842 | (cond | |
2843 | ((save-excursion | |
2844 | (< (skip-syntax-backward c-string-syntax) 0)) ; String. | |
2845 | (setq beg (c-safe (c-backward-sexp 1) (point)))) | |
2846 | ||
2847 | ((and (c-safe (forward-char -2) t) | |
2848 | (looking-at "*/")) | |
2849 | ;; Block comment. Due to the nature of line | |
2850 | ;; comments, they will always be covered by the | |
2851 | ;; normal case above. | |
2852 | (goto-char end) | |
2853 | (c-backward-single-comment) | |
2854 | ;; If LIM is bogus, beg will be bogus. | |
2855 | (setq beg (point)))) | |
2856 | ||
2857 | (if beg (cons beg end)))))) | |
2858 | )))) | |
2859 | ||
2860 | (defun c-literal-limits-fast (&optional lim near not-in-delimiter) | |
2861 | ;; Like c-literal-limits, but for emacsen whose `parse-partial-sexp' | |
2862 | ;; returns the pos of the comment start. | |
2863 | ||
2864 | "Return a cons of the beginning and end positions of the comment or | |
2865 | string surrounding point (including both delimiters), or nil if point | |
2866 | isn't in one. If LIM is non-nil, it's used as the \"safe\" position | |
2867 | to start parsing from. If NEAR is non-nil, then the limits of any | |
2868 | literal next to point is returned. \"Next to\" means there's only | |
2869 | spaces and tabs between point and the literal. The search for such a | |
2870 | literal is done first in forward direction. If NOT-IN-DELIMITER is | |
2871 | non-nil, the case when point is inside a starting delimiter won't be | |
2872 | recognized. This only has effect for comments, which have starting | |
2873 | delimiters with more than one character. | |
2874 | ||
2875 | This function does not do any hidden buffer changes." | |
2876 | ||
2877 | (save-excursion | |
2878 | (let* ((pos (point)) | |
2879 | (lim (or lim (progn | |
2880 | (c-beginning-of-syntax) | |
2881 | (point)))) | |
2882 | (state (parse-partial-sexp lim pos))) | |
2883 | ||
2884 | (cond ((elt state 3) ; String. | |
2885 | (goto-char (elt state 8)) | |
2886 | (cons (point) (or (c-safe (c-forward-sexp 1) (point)) | |
2887 | (point-max)))) | |
2888 | ||
2889 | ((elt state 4) ; Comment. | |
2890 | (goto-char (elt state 8)) | |
2891 | (cons (point) (progn (c-forward-single-comment) (point)))) | |
2892 | ||
2893 | ((and (not not-in-delimiter) | |
2894 | (not (elt state 5)) | |
2895 | (eq (char-before) ?/) | |
2896 | (looking-at "[/*]")) | |
2897 | ;; We're standing in a comment starter. | |
2898 | (backward-char 1) | |
2899 | (cons (point) (progn (c-forward-single-comment) (point)))) | |
2900 | ||
2901 | (near | |
2902 | (goto-char pos) | |
2903 | ||
2904 | ;; Search forward for a literal. | |
2905 | (skip-chars-forward " \t") | |
2906 | ||
2907 | (cond | |
2908 | ((looking-at c-string-limit-regexp) ; String. | |
2909 | (cons (point) (or (c-safe (c-forward-sexp 1) (point)) | |
2910 | (point-max)))) | |
2911 | ||
2912 | ((looking-at c-comment-start-regexp) ; Line or block comment. | |
2913 | (cons (point) (progn (c-forward-single-comment) (point)))) | |
2914 | ||
2915 | (t | |
2916 | ;; Search backward. | |
2917 | (skip-chars-backward " \t") | |
2918 | ||
2919 | (let ((end (point)) beg) | |
2920 | (cond | |
2921 | ((save-excursion | |
2922 | (< (skip-syntax-backward c-string-syntax) 0)) ; String. | |
2923 | (setq beg (c-safe (c-backward-sexp 1) (point)))) | |
2924 | ||
2925 | ((and (c-safe (forward-char -2) t) | |
2926 | (looking-at "*/")) | |
2927 | ;; Block comment. Due to the nature of line | |
2928 | ;; comments, they will always be covered by the | |
2929 | ;; normal case above. | |
2930 | (goto-char end) | |
2931 | (c-backward-single-comment) | |
2932 | ;; If LIM is bogus, beg will be bogus. | |
2933 | (setq beg (point)))) | |
2934 | ||
2935 | (if beg (cons beg end)))))) | |
2936 | )))) | |
2937 | ||
2938 | (if (memq 'pps-extended-state c-emacs-features) | |
2939 | (defalias 'c-literal-limits 'c-literal-limits-fast)) | |
2940 | ||
2941 | (defun c-collect-line-comments (range) | |
2942 | "If the argument is a cons of two buffer positions (such as returned by | |
2943 | `c-literal-limits'), and that range contains a C++ style line comment, | |
2944 | then an extended range is returned that contains all adjacent line | |
2945 | comments (i.e. all comments that starts in the same column with no | |
2946 | empty lines or non-whitespace characters between them). Otherwise the | |
2947 | argument is returned. | |
2948 | ||
2949 | This function does not do any hidden buffer changes." | |
2950 | (save-excursion | |
2951 | (condition-case nil | |
2952 | (if (and (consp range) (progn | |
2953 | (goto-char (car range)) | |
2954 | (looking-at "//"))) | |
2955 | (let ((col (current-column)) | |
2956 | (beg (point)) | |
2957 | (bopl (c-point 'bopl)) | |
2958 | (end (cdr range))) | |
2959 | ;; Got to take care in the backward direction to handle | |
2960 | ;; comments which are preceded by code. | |
2961 | (while (and (c-backward-single-comment) | |
2962 | (>= (point) bopl) | |
2963 | (looking-at "//") | |
2964 | (= col (current-column))) | |
2965 | (setq beg (point) | |
2966 | bopl (c-point 'bopl))) | |
2967 | (goto-char end) | |
2968 | (while (and (progn (skip-chars-forward " \t") | |
2969 | (looking-at "//")) | |
2970 | (= col (current-column)) | |
2971 | (prog1 (zerop (forward-line 1)) | |
2972 | (setq end (point))))) | |
2973 | (cons beg end)) | |
2974 | range) | |
2975 | (error range)))) | |
2976 | ||
2977 | (defun c-literal-type (range) | |
2978 | "Convenience function that given the result of `c-literal-limits', | |
2979 | returns nil or the type of literal that the range surrounds. It's | |
2980 | much faster than using `c-in-literal' and is intended to be used when | |
2981 | you need both the type of a literal and its limits. | |
2982 | ||
2983 | This function does not do any hidden buffer changes." | |
2984 | (if (consp range) | |
2985 | (save-excursion | |
2986 | (goto-char (car range)) | |
2987 | (cond ((looking-at c-string-limit-regexp) 'string) | |
2988 | ((or (looking-at "//") ; c++ line comment | |
2989 | (and (looking-at "\\s<") ; comment starter | |
2990 | (looking-at "#"))) ; awk comment. | |
2991 | 'c++) | |
2992 | (t 'c))) ; Assuming the range is valid. | |
2993 | range)) | |
2994 | ||
2995 | \f | |
2996 | ;; `c-find-decl-spots' and accompanying stuff. | |
2997 | ||
2998 | ;; Variables used in `c-find-decl-spots' to cache the search done for | |
2999 | ;; the first declaration in the last call. When that function starts, | |
3000 | ;; it needs to back up over syntactic whitespace to look at the last | |
3001 | ;; token before the region being searched. That can sometimes cause | |
3002 | ;; moves back and forth over a quite large region of comments and | |
3003 | ;; macros, which would be repeated for each changed character when | |
3004 | ;; we're called during fontification, since font-lock refontifies the | |
3005 | ;; current line for each change. Thus it's worthwhile to cache the | |
3006 | ;; first match. | |
3007 | ;; | |
3008 | ;; `c-find-decl-syntactic-pos' is a syntactically relevant position in | |
3009 | ;; the syntactic whitespace less or equal to some start position. | |
3010 | ;; There's no cached value if it's nil. | |
3011 | ;; | |
3012 | ;; `c-find-decl-match-pos' is the match position if | |
3013 | ;; `c-find-decl-prefix-search' matched before the syntactic whitespace | |
3014 | ;; at `c-find-decl-syntactic-pos', or nil if there's no such match. | |
3015 | (defvar c-find-decl-syntactic-pos nil) | |
3016 | (make-variable-buffer-local 'c-find-decl-syntactic-pos) | |
3017 | (defvar c-find-decl-match-pos nil) | |
3018 | (make-variable-buffer-local 'c-find-decl-match-pos) | |
3019 | ||
3020 | (defsubst c-invalidate-find-decl-cache (change-min-pos) | |
3021 | (and c-find-decl-syntactic-pos | |
3022 | (< change-min-pos c-find-decl-syntactic-pos) | |
3023 | (setq c-find-decl-syntactic-pos nil))) | |
3024 | ||
3025 | ; (defface c-debug-decl-spot-face | |
3026 | ; '((t (:background "Turquoise"))) | |
3027 | ; "Debug face to mark the spots where `c-find-decl-spots' stopped.") | |
3028 | ; (defface c-debug-decl-sws-face | |
3029 | ; '((t (:background "Khaki"))) | |
3030 | ; "Debug face to mark the syntactic whitespace between the declaration | |
3031 | ; spots and the preceding token end.") | |
3032 | ||
3033 | (defmacro c-debug-put-decl-spot-faces (match-pos decl-pos) | |
3034 | (when (facep 'c-debug-decl-spot-face) | |
3035 | `(let ((match-pos ,match-pos) (decl-pos ,decl-pos)) | |
3036 | (c-debug-add-face (max match-pos (point-min)) decl-pos | |
3037 | 'c-debug-decl-sws-face) | |
3038 | (c-debug-add-face decl-pos (min (1+ decl-pos) (point-max)) | |
3039 | 'c-debug-decl-spot-face)))) | |
3040 | (defmacro c-debug-remove-decl-spot-faces (beg end) | |
3041 | (when (facep 'c-debug-decl-spot-face) | |
3042 | `(progn | |
3043 | (c-debug-remove-face ,beg ,end 'c-debug-decl-spot-face) | |
3044 | (c-debug-remove-face ,beg ,end 'c-debug-decl-sws-face)))) | |
3045 | ||
3046 | (defmacro c-find-decl-prefix-search () | |
3047 | ;; Macro used inside `c-find-decl-spots'. It ought to be a defun, | |
3048 | ;; but it contains lots of free variables that refer to things | |
3049 | ;; inside `c-find-decl-spots'. The point is left at `cfd-match-pos' | |
3050 | ;; if there is a match, otherwise at `cfd-limit'. | |
3051 | ||
3052 | '(progn | |
3053 | ;; Find the next property match position if we haven't got one already. | |
3054 | (unless cfd-prop-match | |
3055 | (save-excursion | |
3056 | (while (progn | |
3057 | (goto-char (next-single-property-change | |
3058 | (point) 'c-type nil cfd-limit)) | |
3059 | (and (< (point) cfd-limit) | |
3060 | (not (eq (c-get-char-property (1- (point)) 'c-type) | |
3061 | 'c-decl-end))))) | |
3062 | (setq cfd-prop-match (point)))) | |
3063 | ||
3064 | ;; Find the next `c-decl-prefix-re' match if we haven't got one already. | |
3065 | (unless cfd-re-match | |
3066 | (while (and (setq cfd-re-match | |
3067 | (re-search-forward c-decl-prefix-re cfd-limit 'move)) | |
3068 | (c-got-face-at (1- (setq cfd-re-match (match-end 1))) | |
3069 | c-literal-faces)) | |
3070 | ;; Search again if the match is within a comment or a string literal. | |
3071 | (while (progn | |
3072 | (goto-char (next-single-property-change | |
3073 | cfd-re-match 'face nil cfd-limit)) | |
3074 | (and (< (point) cfd-limit) | |
3075 | (c-got-face-at (point) c-literal-faces))) | |
3076 | (setq cfd-re-match (point)))) | |
3077 | (unless cfd-re-match | |
3078 | (setq cfd-re-match cfd-limit))) | |
3079 | ||
3080 | ;; Choose whichever match is closer to the start. | |
3081 | (if (< cfd-re-match cfd-prop-match) | |
3082 | (setq cfd-match-pos cfd-re-match | |
3083 | cfd-re-match nil) | |
3084 | (setq cfd-match-pos cfd-prop-match | |
3085 | cfd-prop-match nil)) | |
3086 | ||
3087 | (goto-char cfd-match-pos) | |
3088 | ||
3089 | (when (< cfd-match-pos cfd-limit) | |
3090 | ;; Skip forward past comments only so we don't skip macros. | |
3091 | (c-forward-comments) | |
3092 | ;; Set the position to continue at. We can avoid going over | |
3093 | ;; the comments skipped above a second time, but it's possible | |
3094 | ;; that the comment skipping has taken us past `cfd-prop-match' | |
3095 | ;; since the property might be used inside comments. | |
3096 | (setq cfd-continue-pos (if cfd-prop-match | |
3097 | (min cfd-prop-match (point)) | |
3098 | (point)))))) | |
3099 | ||
3100 | (defun c-find-decl-spots (cfd-limit cfd-decl-re cfd-face-checklist cfd-fun) | |
3101 | ;; Call CFD-FUN for each possible spot for a declaration from the | |
3102 | ;; point to CFD-LIMIT. A spot for a declaration is the first token | |
3103 | ;; in the buffer and each token after the ones matched by | |
3104 | ;; `c-decl-prefix-re' and after the occurrences of the `c-type' | |
3105 | ;; property with the value `c-decl-end' (if `c-type-decl-end-used' | |
3106 | ;; is set). Only a spot that match CFD-DECL-RE and whose face is in | |
3107 | ;; the CFD-FACE-CHECKLIST list causes CFD-FUN to be called. The | |
3108 | ;; face check is disabled if CFD-FACE-CHECKLIST is nil. | |
3109 | ;; | |
3110 | ;; If the match is inside a macro then the buffer is narrowed to the | |
3111 | ;; end of it, so that CFD-FUN can investigate the following tokens | |
3112 | ;; without matching something that begins inside a macro and ends | |
3113 | ;; outside it. It's to avoid this work that the CFD-DECL-RE and | |
3114 | ;; CFD-FACE-CHECKLIST checks exist. | |
3115 | ;; | |
3116 | ;; CFD-FUN is called with point at the start of the spot. It's | |
3117 | ;; passed two arguments: The first is the end position of the token | |
3118 | ;; that `c-decl-prefix-re' matched, or 0 for the implicit match at | |
3119 | ;; bob. The second is a flag that is t when the match is inside a | |
3120 | ;; macro. | |
3121 | ;; | |
3122 | ;; It's assumed that comment and strings are fontified in the | |
3123 | ;; searched range. | |
3124 | ;; | |
3125 | ;; This is mainly used in fontification, and so has an elaborate | |
3126 | ;; cache to handle repeated calls from the same start position; see | |
3127 | ;; the variables above. | |
3128 | ;; | |
3129 | ;; All variables in this function begin with `cfd-' to avoid name | |
3130 | ;; collision with the (dynamically bound) variables used in CFD-FUN. | |
3131 | ||
3132 | (let ((cfd-buffer-end (point-max)) | |
3133 | ;; The last regexp match found by `c-find-decl-prefix-search'. | |
3134 | cfd-re-match | |
3135 | ;; The last `c-decl-end' found by `c-find-decl-prefix-search'. | |
3136 | ;; If searching for the property isn't needed then we disable | |
3137 | ;; it by faking a first match at the limit. | |
3138 | (cfd-prop-match (unless c-type-decl-end-used cfd-limit)) | |
3139 | ;; The position of the last match found by | |
3140 | ;; `c-find-decl-prefix-search'. For regexp matches it's the | |
3141 | ;; end of the matched token, for property matches it's the end | |
3142 | ;; of the property. 0 for the implicit match at bob. | |
3143 | ;; `cfd-limit' if there's no match. | |
3144 | (cfd-match-pos cfd-limit) | |
3145 | ;; The position to continue searching at. | |
3146 | cfd-continue-pos | |
3147 | ;; The position of the last "real" token we've stopped at. | |
3148 | ;; This can be greater than `cfd-continue-pos' when we get | |
3149 | ;; hits inside macros or at `c-decl-end' positions inside | |
3150 | ;; comments. | |
3151 | (cfd-token-pos 0) | |
3152 | ;; The end position of the last entered macro. | |
3153 | (cfd-macro-end 0)) | |
3154 | ||
3155 | ;; Initialize by finding a syntactically relevant start position | |
3156 | ;; before the point, and do the first `c-decl-prefix-re' search | |
3157 | ;; unless we're at bob. | |
3158 | ||
3159 | (let ((start-pos (point)) syntactic-pos) | |
3160 | ;; Must back up a bit since we look for the end of the previous | |
3161 | ;; statement or declaration, which is earlier than the first | |
3162 | ;; returned match. | |
3163 | ||
3164 | (when (c-got-face-at (point) c-literal-faces) | |
3165 | ;; But first we need to move to a syntactically relevant | |
3166 | ;; position. Use the faces to back up to the start of the | |
3167 | ;; comment or string literal. | |
3168 | (when (and (not (bobp)) | |
3169 | (c-got-face-at (1- (point)) c-literal-faces)) | |
3170 | (while (progn | |
3171 | (goto-char (previous-single-property-change | |
3172 | (point) 'face nil (point-min))) | |
3173 | (and (> (point) (point-min)) | |
3174 | (c-got-face-at (point) c-literal-faces))))) | |
3175 | ||
3176 | ;; XEmacs doesn't fontify the quotes surrounding string | |
3177 | ;; literals. | |
3178 | (and (featurep 'xemacs) | |
3179 | (eq (get-text-property (point) 'face) | |
3180 | 'font-lock-string-face) | |
3181 | (not (bobp)) | |
3182 | (progn (backward-char) | |
3183 | (not (looking-at c-string-limit-regexp))) | |
3184 | (forward-char)) | |
3185 | ||
3186 | ;; The font lock package might not have fontified the start of | |
3187 | ;; the literal at all so check that we have arrived at | |
3188 | ;; something that looks like a start or else resort to | |
3189 | ;; `c-literal-limits'. | |
3190 | (unless (looking-at c-literal-start-regexp) | |
3191 | (let ((range (c-literal-limits))) | |
3192 | (if range (goto-char (car range)))))) | |
3193 | ||
3194 | ;; Must back out of any macro so that we don't miss any | |
3195 | ;; declaration that could follow after it, unless the limit is | |
3196 | ;; inside the macro. We only check that for the current line to | |
3197 | ;; save some time; it's enough for the by far most common case | |
3198 | ;; when font-lock refontifies the current line only. | |
3199 | (when (save-excursion | |
3200 | (and (= (forward-line 1) 0) | |
3efc2cd7 | 3201 | (bolp) ; forward-line has funny behavior at eob. |
d9e94c22 MS |
3202 | (or (< (c-point 'eol) cfd-limit) |
3203 | (progn (backward-char) | |
3204 | (not (eq (char-before) ?\\)))))) | |
3205 | (c-beginning-of-macro)) | |
3206 | ||
3207 | ;; Clear the cache if it applied further down. | |
3208 | (c-invalidate-find-decl-cache start-pos) | |
3209 | ||
3210 | (setq syntactic-pos (point)) | |
3211 | (c-backward-syntactic-ws c-find-decl-syntactic-pos) | |
3212 | ||
3213 | ;; If we hit `c-find-decl-syntactic-pos' and | |
3214 | ;; `c-find-decl-match-pos' is set then we install the cached | |
3215 | ;; values. If we hit `c-find-decl-syntactic-pos' and | |
3216 | ;; `c-find-decl-match-pos' is nil then we know there's no decl | |
3217 | ;; prefix in the whitespace before `c-find-decl-syntactic-pos' | |
3218 | ;; and so we can continue the search from this point. If we | |
3219 | ;; didn't hit `c-find-decl-syntactic-pos' then we're now in the | |
3220 | ;; right spot to begin searching anyway. | |
3221 | (if (and (eq (point) c-find-decl-syntactic-pos) | |
3222 | c-find-decl-match-pos) | |
3223 | ||
3224 | (progn | |
3225 | ;; The match is always outside macros and comments so we | |
3226 | ;; start at the next token. The loop below will later go | |
3227 | ;; back using `cfd-continue-pos' to fix declarations inside | |
3228 | ;; the syntactic ws. | |
3229 | (goto-char syntactic-pos) | |
3230 | (c-forward-syntactic-ws) | |
3231 | (setq cfd-match-pos c-find-decl-match-pos | |
3232 | cfd-continue-pos syntactic-pos) | |
3233 | (if (< cfd-continue-pos (point)) | |
3234 | (setq cfd-token-pos (point)))) | |
3235 | ||
3236 | (setq c-find-decl-syntactic-pos syntactic-pos) | |
3237 | ||
3238 | (when (if (bobp) | |
3239 | ;; Always consider bob a match to get the first declaration | |
3240 | ;; in the file. Do this separately instead of letting | |
3241 | ;; `c-decl-prefix-re' match bob, so that it always can | |
3242 | ;; consume at least one character to ensure that we won't | |
3243 | ;; get stuck in an infinite loop. | |
3244 | (setq cfd-re-match 0) | |
3245 | (backward-char) | |
3246 | (c-beginning-of-current-token) | |
3247 | (< (point) cfd-limit)) | |
3248 | ;; Do an initial search now. In the bob case above it's only done | |
3249 | ;; to search for the `c-type' property. | |
3250 | (c-find-decl-prefix-search)) | |
3251 | ||
3252 | ;; Advance `cfd-continue-pos' if we got a hit before the start | |
3253 | ;; position. The earliest position that could affect after | |
3254 | ;; the start position is the char before the preceding | |
3255 | ;; comments. | |
3256 | (when (and cfd-continue-pos (< cfd-continue-pos start-pos)) | |
3257 | (goto-char syntactic-pos) | |
3258 | (c-backward-comments) | |
3259 | (unless (bobp) | |
3260 | (backward-char) | |
3261 | (c-beginning-of-current-token)) | |
3262 | (setq cfd-continue-pos (max cfd-continue-pos (point)))) | |
3263 | ||
3264 | ;; If we got a match it's always outside macros and comments so | |
3265 | ;; advance to the next token and set `cfd-token-pos'. The loop | |
3266 | ;; below will later go back using `cfd-continue-pos' to fix | |
3267 | ;; declarations inside the syntactic ws. | |
3268 | (when (and (< cfd-match-pos cfd-limit) (< (point) syntactic-pos)) | |
3269 | (goto-char syntactic-pos) | |
3270 | (c-forward-syntactic-ws) | |
3271 | (and cfd-continue-pos | |
3272 | (< cfd-continue-pos (point)) | |
3273 | (setq cfd-token-pos (point)))) | |
3274 | ||
3275 | (setq c-find-decl-match-pos (and (< cfd-match-pos start-pos) | |
3276 | cfd-match-pos)))) | |
3277 | ||
3278 | ;; Now loop. We already got the first match. | |
3279 | ||
3280 | (while (progn | |
3281 | (while (and | |
3282 | (< cfd-match-pos cfd-limit) | |
3283 | ||
3284 | (or | |
3285 | ;; Kludge to filter out matches on the "<" that | |
3286 | ;; aren't open parens, for the sake of languages | |
3287 | ;; that got `c-recognize-<>-arglists' set. | |
3288 | (and (eq (char-before cfd-match-pos) ?<) | |
3289 | (not (c-get-char-property (1- cfd-match-pos) | |
3290 | 'syntax-table))) | |
3291 | ||
3292 | ;; If `cfd-continue-pos' is less or equal to | |
3293 | ;; `cfd-token-pos', we've got a hit inside a macro | |
3294 | ;; that's in the syntactic whitespace before the last | |
3295 | ;; "real" declaration we've checked. If they're equal | |
3296 | ;; we've arrived at the declaration a second time, so | |
3297 | ;; there's nothing to do. | |
3298 | (= cfd-continue-pos cfd-token-pos) | |
3299 | ||
3300 | (progn | |
3301 | ;; If `cfd-continue-pos' is less than `cfd-token-pos' | |
3302 | ;; we're still searching for declarations embedded in | |
3303 | ;; the syntactic whitespace. In that case we need | |
3304 | ;; only to skip comments and not macros, since they | |
3305 | ;; can't be nested, and that's already been done in | |
3306 | ;; `c-find-decl-prefix-search'. | |
3307 | (when (> cfd-continue-pos cfd-token-pos) | |
3308 | (c-forward-syntactic-ws) | |
3309 | (setq cfd-token-pos (point))) | |
3310 | ||
3311 | ;; Continue if the following token fails the | |
3312 | ;; CFD-DECL-RE and CFD-FACE-CHECKLIST checks. | |
3313 | (when (or (>= (point) cfd-limit) | |
3314 | (not (looking-at cfd-decl-re)) | |
3315 | (and cfd-face-checklist | |
3316 | (not (c-got-face-at | |
3317 | (point) cfd-face-checklist)))) | |
3318 | (goto-char cfd-continue-pos) | |
3319 | t))) | |
3320 | ||
3321 | (< (point) cfd-limit)) | |
3322 | (c-find-decl-prefix-search)) | |
3323 | ||
3324 | (< (point) cfd-limit)) | |
3325 | ||
3326 | (when (progn | |
3327 | ;; Narrow to the end of the macro if we got a hit inside | |
3328 | ;; one, to avoid recognizing things that start inside | |
3329 | ;; the macro and end outside it. | |
3330 | (when (> cfd-match-pos cfd-macro-end) | |
3331 | ;; Not in the same macro as in the previous round. | |
3332 | (save-excursion | |
3333 | (goto-char cfd-match-pos) | |
3334 | (setq cfd-macro-end | |
3335 | (if (save-excursion (and (c-beginning-of-macro) | |
3336 | (< (point) cfd-match-pos))) | |
3337 | (progn (c-end-of-macro) | |
3338 | (point)) | |
3339 | 0)))) | |
3340 | ||
3341 | (if (zerop cfd-macro-end) | |
3342 | t | |
3343 | (if (> cfd-macro-end (point)) | |
3344 | (progn (narrow-to-region (point-min) cfd-macro-end) | |
3345 | t) | |
3346 | ;; The matched token was the last thing in the | |
3347 | ;; macro, so the whole match is bogus. | |
3348 | (setq cfd-macro-end 0) | |
3349 | nil))) | |
3350 | ||
3351 | (c-debug-put-decl-spot-faces cfd-match-pos (point)) | |
3352 | (funcall cfd-fun cfd-match-pos (/= cfd-macro-end 0)) | |
3353 | ||
3354 | (when (/= cfd-macro-end 0) | |
3355 | ;; Restore limits if we did macro narrowment above. | |
3356 | (narrow-to-region (point-min) cfd-buffer-end))) | |
3357 | ||
3358 | (goto-char cfd-continue-pos) | |
3359 | (if (= cfd-continue-pos cfd-limit) | |
3360 | (setq cfd-match-pos cfd-limit) | |
3361 | (c-find-decl-prefix-search))))) | |
3362 | ||
3363 | \f | |
3364 | ;; A cache for found types. | |
3365 | ||
3366 | ;; Buffer local variable that contains an obarray with the types we've | |
3367 | ;; found. If a declaration is recognized somewhere we record the | |
3368 | ;; fully qualified identifier in it to recognize it as a type | |
3369 | ;; elsewhere in the file too. This is not accurate since we do not | |
3370 | ;; bother with the scoping rules of the languages, but in practice the | |
3371 | ;; same name is seldom used as both a type and something else in a | |
3372 | ;; file, and we only use this as a last resort in ambiguous cases (see | |
3373 | ;; `c-font-lock-declarations'). | |
3374 | (defvar c-found-types nil) | |
3375 | (make-variable-buffer-local 'c-found-types) | |
3376 | ||
3377 | (defsubst c-clear-found-types () | |
3378 | ;; Clears `c-found-types'. | |
a66cd3ee | 3379 | ;; |
d9e94c22 MS |
3380 | ;; This function does not do any hidden buffer changes. |
3381 | (setq c-found-types (make-vector 53 0))) | |
3382 | ||
3383 | (defun c-add-type (from to) | |
3384 | ;; Add the given region as a type in `c-found-types'. If the region | |
3385 | ;; doesn't match an existing type but there is a type which is equal | |
3386 | ;; to the given one except that the last character is missing, then | |
3387 | ;; the shorter type is removed. That's done to avoid adding all | |
3388 | ;; prefixes of a type as it's being entered and font locked. This | |
3389 | ;; doesn't cover cases like when characters are removed from a type | |
3390 | ;; or added in the middle. We'd need the position of point when the | |
3391 | ;; font locking is invoked to solve this well. | |
3392 | (unless (and c-recognize-<>-arglists | |
3393 | (save-excursion | |
3394 | (goto-char from) | |
3395 | (c-syntactic-re-search-forward "<" to t))) | |
3396 | ;; To avoid storing very long strings, do not add a type that | |
3397 | ;; contains '<' in languages with angle bracket arglists, since | |
3398 | ;; the type then probably contains a C++ template spec and those | |
3399 | ;; can be fairly sized programs in themselves. | |
3400 | (let ((type (c-syntactic-content from to))) | |
3401 | (unless (intern-soft type c-found-types) | |
3402 | (unintern (substring type 0 -1) c-found-types) | |
3403 | (intern type c-found-types))))) | |
3404 | ||
3405 | (defsubst c-check-type (from to) | |
3406 | ;; Return non-nil if the given region contains a type in | |
3407 | ;; `c-found-types'. | |
3408 | (intern-soft (c-syntactic-content from to) c-found-types)) | |
3409 | ||
3410 | (defun c-list-found-types () | |
3411 | ;; Return all the types in `c-found-types' as a sorted list of | |
3412 | ;; strings. | |
3413 | (let (type-list) | |
3414 | (mapatoms (lambda (type) | |
3415 | (setq type-list (cons (symbol-name type) | |
3416 | type-list))) | |
3417 | c-found-types) | |
3418 | (sort type-list 'string-lessp))) | |
a66cd3ee | 3419 | |
d9e94c22 MS |
3420 | \f |
3421 | ;; Handling of small scale constructs like types and names. | |
3422 | ||
3423 | (defun c-remove-<>-arglist-properties (from to) | |
3424 | ;; Remove all the properties put by `c-forward-<>-arglist' in the | |
3425 | ;; specified region. Point is clobbered. | |
3426 | (goto-char from) | |
3427 | (while (progn (skip-chars-forward "^<>," to) | |
3428 | (< (point) to)) | |
3429 | (if (eq (char-after) ?,) | |
3430 | (when (eq (c-get-char-property (point) 'c-type) 'c-<>-arg-sep) | |
3431 | (c-clear-char-property (point) 'c-type)) | |
3432 | (c-clear-char-property (point) 'syntax-table)) | |
3433 | (forward-char))) | |
3434 | ||
3435 | ;; Dynamically bound variable that instructs `c-forward-type' to also | |
3436 | ;; treat possible types (i.e. those that it normally returns 'maybe or | |
3437 | ;; 'found for) as actual types (and always return 'found for them). | |
3438 | ;; This means that it records them in `c-record-type-identifiers' if | |
3439 | ;; that is set, and that it adds them to `c-found-types'. | |
3440 | (defvar c-promote-possible-types nil) | |
3441 | ||
3442 | ;; Dynamically bound variable that instructs `c-forward-<>-arglist' to | |
037558bf MS |
3443 | ;; not accept arglists that contain binary operators. |
3444 | ;; | |
3445 | ;; This is primarily used to handle C++ template arglists. C++ | |
3446 | ;; disambiguates them by checking whether the preceding name is a | |
3447 | ;; template or not. We can't do that, so we assume it is a template | |
3448 | ;; if it can be parsed as one. That usually works well since | |
3449 | ;; comparison expressions on the forms "a < b > c" or "a < b, c > d" | |
3450 | ;; in almost all cases would be pointless. | |
3451 | ;; | |
3452 | ;; However, in function arglists, e.g. in "foo (a < b, c > d)", we | |
3453 | ;; should let the comma separate the function arguments instead. And | |
3454 | ;; in a context where the value of the expression is taken, e.g. in | |
3455 | ;; "if (a < b || c > d)", it's probably not a template. | |
3456 | (defvar c-restricted-<>-arglists nil) | |
d9e94c22 MS |
3457 | |
3458 | ;; Dynamically bound variables that instructs `c-forward-name', | |
3459 | ;; `c-forward-type' and `c-forward-<>-arglist' to record the ranges of | |
3460 | ;; all the type and reference identifiers they encounter. They will | |
3461 | ;; build lists on these variables where each element is a cons of the | |
3462 | ;; buffer positions surrounding each identifier. This recording is | |
3463 | ;; only activated when `c-record-type-identifiers' is non-nil. | |
3464 | ;; | |
3465 | ;; All known types that can't be identifiers are recorded, and also | |
3466 | ;; other possible types if `c-promote-possible-types' is set. | |
3467 | ;; Recording is however disabled inside angle bracket arglists that | |
3468 | ;; are encountered inside names and other angle bracket arglists. | |
3469 | ;; Such occurences are taken care of by `c-font-lock-<>-arglists' | |
3470 | ;; instead. | |
3471 | ;; | |
3472 | ;; Only the names in C++ template style references (e.g. "tmpl" in | |
3473 | ;; "tmpl<a,b>::foo") are recorded as references, other references | |
3474 | ;; aren't handled here. | |
3475 | (defvar c-record-type-identifiers nil) | |
3476 | (defvar c-record-ref-identifiers nil) | |
3477 | ||
3478 | ;; If `c-record-type-identifiers' is set, this will receive a cons | |
3479 | ;; cell of the range of the last single identifier symbol stepped over | |
3480 | ;; by `c-forward-name' if it's successful. This is the range that | |
3481 | ;; should be put on one of the record lists by the caller. It's | |
3482 | ;; assigned nil if there's no such symbol in the name. | |
3483 | (defvar c-last-identifier-range nil) | |
3484 | ||
3485 | (defmacro c-record-type-id (range) | |
3486 | (if (eq (car-safe range) 'cons) | |
3487 | ;; Always true. | |
3488 | `(setq c-record-type-identifiers | |
3489 | (cons ,range c-record-type-identifiers)) | |
3490 | `(let ((range ,range)) | |
3491 | (if range | |
3492 | (setq c-record-type-identifiers | |
3493 | (cons range c-record-type-identifiers)))))) | |
3494 | ||
3495 | (defmacro c-record-ref-id (range) | |
3496 | (if (eq (car-safe range) 'cons) | |
3497 | ;; Always true. | |
3498 | `(setq c-record-ref-identifiers | |
3499 | (cons ,range c-record-ref-identifiers)) | |
3500 | `(let ((range ,range)) | |
3501 | (if range | |
3502 | (setq c-record-ref-identifiers | |
3503 | (cons range c-record-ref-identifiers)))))) | |
3504 | ||
3505 | ;; Dynamically bound variable that instructs `c-forward-type' to | |
3506 | ;; record the ranges of types that only are found. Behaves otherwise | |
3507 | ;; like `c-record-type-identifiers'. | |
3508 | (defvar c-record-found-types nil) | |
3509 | ||
3510 | (defmacro c-forward-keyword-prefixed-id (type) | |
3511 | ;; Used internally in `c-forward-keyword-clause' to move forward | |
3512 | ;; over a type (if TYPE is 'type) or a name (otherwise) which | |
3513 | ;; possibly is prefixed by keywords and their associated clauses. | |
3514 | ;; Try with a type/name first to not trip up on those that begin | |
3515 | ;; with a keyword. Return t if a known or found type is moved | |
3516 | ;; over. The point is clobbered if nil is returned. If range | |
3517 | ;; recording is enabled, the identifier is recorded on as a type | |
3518 | ;; if TYPE is 'type or as a reference if TYPE is 'ref. | |
3519 | `(let (res) | |
3520 | (while (if (setq res ,(if (eq type 'type) | |
3521 | `(c-forward-type) | |
3522 | `(c-forward-name))) | |
3523 | nil | |
3524 | (and (looking-at c-keywords-regexp) | |
3525 | (c-forward-keyword-clause)))) | |
3526 | (when (memq res '(t known found prefix)) | |
3527 | ,(when (eq type 'ref) | |
3528 | `(when c-record-type-identifiers | |
3529 | (c-record-ref-id c-last-identifier-range))) | |
3530 | t))) | |
3531 | ||
3532 | (defmacro c-forward-id-comma-list (type) | |
3533 | ;; Used internally in `c-forward-keyword-clause' to move forward | |
3534 | ;; over a comma separated list of types or names using | |
3535 | ;; `c-forward-keyword-prefixed-id'. | |
3536 | `(while (and (progn | |
3537 | (setq safe-pos (point)) | |
3538 | (eq (char-after) ?,)) | |
3539 | (progn | |
3540 | (forward-char) | |
3541 | (c-forward-syntactic-ws) | |
3542 | (c-forward-keyword-prefixed-id ,type))))) | |
3543 | ||
3544 | (defun c-forward-keyword-clause () | |
3545 | ;; The first submatch in the current match data is assumed to | |
3546 | ;; surround a token. If it's a keyword, move over it and any | |
3547 | ;; following clauses associated with it, stopping at the next | |
3548 | ;; following token. t is returned in that case, otherwise the point | |
3549 | ;; stays and nil is returned. The kind of clauses that are | |
3550 | ;; recognized are those specified by `c-type-list-kwds', | |
3551 | ;; `c-ref-list-kwds', `c-colon-type-list-kwds', | |
3552 | ;; `c-paren-nontype-kwds', `c-paren-type-kwds', `c-<>-type-kwds', | |
3553 | ;; and `c-<>-arglist-kwds'. | |
3554 | ||
3555 | (let ((kwd-sym (c-keyword-sym (match-string 1))) safe-pos pos) | |
3556 | (when kwd-sym | |
3557 | (goto-char (match-end 1)) | |
3558 | (c-forward-syntactic-ws) | |
3559 | (setq safe-pos (point)) | |
a66cd3ee | 3560 | |
d9e94c22 MS |
3561 | (cond |
3562 | ((and (c-keyword-member kwd-sym 'c-type-list-kwds) | |
3563 | (c-forward-keyword-prefixed-id type)) | |
3564 | ;; There's a type directly after a keyword in `c-type-list-kwds'. | |
3565 | (c-forward-id-comma-list type)) | |
3566 | ||
3567 | ((and (c-keyword-member kwd-sym 'c-ref-list-kwds) | |
3568 | (c-forward-keyword-prefixed-id ref)) | |
3569 | ;; There's a name directly after a keyword in `c-ref-list-kwds'. | |
3570 | (c-forward-id-comma-list ref)) | |
3571 | ||
3572 | ((and (c-keyword-member kwd-sym 'c-paren-any-kwds) | |
3573 | (eq (char-after) ?\()) | |
3574 | ;; There's an open paren after a keyword in `c-paren-any-kwds'. | |
3575 | ||
3576 | (forward-char) | |
3577 | (when (and (setq pos (c-up-list-forward)) | |
3578 | (eq (char-before pos) ?\))) | |
3579 | (when (and c-record-type-identifiers | |
3580 | (c-keyword-member kwd-sym 'c-paren-type-kwds)) | |
3581 | ;; Use `c-forward-type' on every identifier we can find | |
3582 | ;; inside the paren, to record the types. | |
3583 | (while (c-syntactic-re-search-forward c-symbol-start pos t) | |
3584 | (goto-char (match-beginning 0)) | |
3585 | (unless (c-forward-type) | |
3586 | (looking-at c-symbol-key) ; Always matches. | |
3587 | (goto-char (match-end 0))))) | |
3588 | ||
3589 | (goto-char pos) | |
3590 | (c-forward-syntactic-ws) | |
3591 | (setq safe-pos (point)))) | |
3592 | ||
3593 | ((and (c-keyword-member kwd-sym 'c-<>-sexp-kwds) | |
3594 | (eq (char-after) ?<) | |
3595 | (c-forward-<>-arglist (c-keyword-member kwd-sym 'c-<>-type-kwds) | |
3596 | (or c-record-type-identifiers | |
037558bf | 3597 | c-restricted-<>-arglists))) |
d9e94c22 MS |
3598 | (c-forward-syntactic-ws) |
3599 | (setq safe-pos (point))) | |
3600 | ||
3601 | ((and (c-keyword-member kwd-sym 'c-nonsymbol-sexp-kwds) | |
449a2b0d MS |
3602 | (not (looking-at c-symbol-start)) |
3603 | (c-safe (c-forward-sexp) t)) | |
d9e94c22 MS |
3604 | (c-forward-syntactic-ws) |
3605 | (setq safe-pos (point)))) | |
3606 | ||
3607 | (when (and (c-keyword-member kwd-sym 'c-colon-type-list-kwds) | |
3608 | (progn | |
3609 | ;; If a keyword matched both one of the types above and | |
3610 | ;; this one, we match `c-colon-type-list-re' after the | |
3611 | ;; clause matched above. | |
3612 | (goto-char safe-pos) | |
3613 | (looking-at c-colon-type-list-re)) | |
3614 | (progn | |
3615 | (goto-char (match-end 0)) | |
3616 | (c-forward-syntactic-ws) | |
3617 | (c-forward-keyword-prefixed-id type))) | |
3618 | ;; There's a type after the `c-colon-type-list-re' | |
3619 | ;; match after a keyword in `c-colon-type-list-kwds'. | |
3620 | (c-forward-id-comma-list type)) | |
3621 | ||
3622 | (goto-char safe-pos) | |
3623 | t))) | |
3624 | ||
3625 | (defun c-forward-<>-arglist (all-types reparse) | |
3626 | ;; The point is assumed to be at a '<'. Try to treat it as the open | |
3627 | ;; paren of an angle bracket arglist and move forward to the the | |
3628 | ;; corresponding '>'. If successful, the point is left after the | |
3629 | ;; '>' and t is returned, otherwise the point isn't moved and nil is | |
3630 | ;; returned. If ALL-TYPES is t then all encountered arguments in | |
3631 | ;; the arglist that might be types are treated as found types. | |
3632 | ;; | |
3633 | ;; The surrounding '<' and '>' are given syntax-table properties to | |
3634 | ;; make them behave like parentheses. Each argument separating ',' | |
3635 | ;; is also set to `c-<>-arg-sep' in the `c-type' property. These | |
3636 | ;; properties are also cleared in a relevant region forward from the | |
3637 | ;; point if they seems to be set and it turns out to not be an | |
3638 | ;; arglist. | |
3639 | ;; | |
3640 | ;; If the arglist has been successfully parsed before then paren | |
3641 | ;; syntax properties will be exploited to quickly jump to the end, | |
3642 | ;; but that can be disabled by setting REPARSE to t. That is | |
3643 | ;; necessary if the various side effects, e.g. recording of type | |
3644 | ;; ranges, are important. Setting REPARSE to t only applies | |
3645 | ;; recursively to nested angle bracket arglists if | |
037558bf | 3646 | ;; `c-restricted-<>-arglists' is set. |
d9e94c22 MS |
3647 | |
3648 | (let ((start (point)) | |
3649 | ;; If `c-record-type-identifiers' is set then activate | |
3650 | ;; recording of any found types that constitute an argument in | |
3651 | ;; the arglist. | |
3652 | (c-record-found-types (if c-record-type-identifiers t))) | |
3653 | (if (catch 'angle-bracket-arglist-escape | |
3654 | (setq c-record-found-types | |
3655 | (c-forward-<>-arglist-recur all-types reparse))) | |
3656 | (progn | |
3657 | (when (consp c-record-found-types) | |
3658 | (setq c-record-type-identifiers | |
3659 | ;; `nconc' doesn't mind that the tail of | |
3660 | ;; `c-record-found-types' is t. | |
3661 | (nconc c-record-found-types c-record-type-identifiers))) | |
3662 | t) | |
3663 | ||
3664 | (goto-char start) | |
a66cd3ee | 3665 | nil))) |
785eecbb | 3666 | |
d9e94c22 MS |
3667 | (defun c-forward-<>-arglist-recur (all-types reparse) |
3668 | ;; Recursive part of `c-forward-<>-arglist'. | |
3669 | ||
3670 | (let ((start (point)) res pos tmp | |
3671 | ;; Cover this so that any recorded found type ranges are | |
3672 | ;; automatically lost if it turns out to not be an angle | |
3673 | ;; bracket arglist. It's propagated through the return value | |
3674 | ;; on successful completion. | |
3675 | (c-record-found-types c-record-found-types) | |
3676 | ;; List that collects the positions after the argument | |
3677 | ;; separating ',' in the arglist. | |
3678 | arg-start-pos) | |
3679 | ||
3680 | ;; If the '<' has paren open syntax then we've marked it as an | |
3681 | ;; angle bracket arglist before, so try to skip to the end and see | |
3682 | ;; that the close paren matches. | |
3683 | (if (and (c-get-char-property (point) 'syntax-table) | |
3684 | (progn | |
3685 | (forward-char) | |
3686 | (if (and (not (looking-at c-<-op-cont-regexp)) | |
3687 | (if (c-parse-sexp-lookup-properties) | |
3688 | (c-go-up-list-forward) | |
3689 | (catch 'at-end | |
3690 | (let ((depth 1)) | |
3691 | (while (c-syntactic-re-search-forward | |
3692 | "[<>]" nil t t) | |
3693 | (when (c-get-char-property (1- (point)) | |
3694 | 'syntax-table) | |
3695 | (if (eq (char-before) ?<) | |
3696 | (setq depth (1+ depth)) | |
3697 | (setq depth (1- depth)) | |
3698 | (when (= depth 0) (throw 'at-end t))))) | |
3699 | nil))) | |
3700 | (not (looking-at c->-op-cont-regexp)) | |
3701 | (save-excursion | |
3702 | (backward-char) | |
3703 | (= (point) | |
3704 | (progn (c-beginning-of-current-token) | |
3705 | (point))))) | |
3706 | ||
3707 | ;; Got an arglist that appears to be valid. | |
3708 | (if reparse | |
3709 | ;; Reparsing is requested, so zap the properties in the | |
3710 | ;; region and go on to redo it. It's done here to | |
3711 | ;; avoid leaving it behind if we exit through | |
3712 | ;; `angle-bracket-arglist-escape' below. | |
3713 | (progn | |
3714 | (c-remove-<>-arglist-properties start (point)) | |
3715 | (goto-char start) | |
3716 | nil) | |
3717 | t) | |
3718 | ||
3719 | ;; Got unmatched paren brackets or either paren was | |
3720 | ;; actually some other token. Recover by clearing the | |
3721 | ;; syntax properties on all the '<' and '>' in the | |
3722 | ;; range where we'll search for the arglist below. | |
3723 | (goto-char start) | |
3724 | (while (progn (skip-chars-forward "^<>,;{}") | |
3725 | (looking-at "[<>,]")) | |
3726 | (if (eq (char-after) ?,) | |
3727 | (when (eq (c-get-char-property (point) 'c-type) | |
3728 | 'c-<>-arg-sep) | |
3729 | (c-clear-char-property (point) 'c-type)) | |
3730 | (c-clear-char-property (point) 'syntax-table)) | |
3731 | (forward-char)) | |
3732 | (goto-char start) | |
3733 | nil))) | |
3734 | t | |
3735 | ||
3736 | (forward-char) | |
3737 | (unless (looking-at c-<-op-cont-regexp) | |
3738 | (while (and | |
3739 | (progn | |
3740 | ||
3741 | (when c-record-type-identifiers | |
3742 | (if all-types | |
3743 | ||
3744 | ;; All encountered identifiers are types, so set the | |
3745 | ;; promote flag and parse the type. | |
3746 | (progn | |
3747 | (c-forward-syntactic-ws) | |
3748 | (when (looking-at c-identifier-start) | |
3749 | (let ((c-promote-possible-types t)) | |
3750 | (c-forward-type)))) | |
3751 | ||
3752 | ;; Check if this arglist argument is a sole type. If | |
3753 | ;; it's known then it's recorded in | |
3754 | ;; `c-record-type-identifiers'. If it only is found | |
3755 | ;; then it's recorded in `c-record-found-types' which we | |
3756 | ;; might roll back if it turns out that this isn't an | |
3757 | ;; angle bracket arglist afterall. | |
3758 | (when (memq (char-before) '(?, ?<)) | |
3759 | (let ((orig-record-found-types c-record-found-types)) | |
3760 | (c-forward-syntactic-ws) | |
3761 | (and (memq (c-forward-type) '(known found)) | |
3762 | (not (looking-at "[,>]")) | |
3763 | ;; A found type was recorded but it's not the | |
3764 | ;; only thing in the arglist argument, so reset | |
3765 | ;; `c-record-found-types'. | |
3766 | (setq c-record-found-types | |
3767 | orig-record-found-types)))))) | |
3768 | ||
3769 | (setq pos (point)) | |
3770 | (or (when (eq (char-after) ?>) | |
3771 | ;; Must check for '>' at the very start separately, | |
3772 | ;; since the regexp below has to avoid ">>" without | |
3773 | ;; using \\=. | |
3774 | (forward-char) | |
3775 | t) | |
3776 | ||
037558bf MS |
3777 | ;; Note: These regexps exploit the match order in \| so |
3778 | ;; that "<>" is matched by "<" rather than "[^>:-]>". | |
d9e94c22 | 3779 | (c-syntactic-re-search-forward |
037558bf MS |
3780 | (if c-restricted-<>-arglists |
3781 | ;; Stop on ',', '|', '&', '+' and '-' to catch | |
3782 | ;; common binary operators that could be between | |
3783 | ;; two comparison expressions "a<b" and "c>d". | |
3784 | "[<;{},|&+-]\\|\\([^>:-]>\\)" | |
3785 | ;; Otherwise we still stop on ',' to find the | |
3786 | ;; argument start positions. | |
3787 | "[<;{},]\\|\\([^>:-]>\\)") | |
3788 | nil 'move t t 1) | |
d9e94c22 MS |
3789 | |
3790 | ;; If the arglist starter has lost its open paren | |
3791 | ;; syntax but not the closer, we won't find the | |
3792 | ;; closer above since we only search in the | |
3793 | ;; balanced sexp. In that case we stop just short | |
3794 | ;; of it so check if the following char is the closer. | |
3795 | (when (eq (char-after) ?>) | |
3796 | ;; Remove its syntax so that we don't enter the | |
3797 | ;; recovery code below. That's not necessary | |
3798 | ;; since there's no real reason to suspect that | |
3799 | ;; things inside the arglist are unbalanced. | |
3800 | (c-clear-char-property (point) 'syntax-table) | |
3801 | (forward-char) | |
3802 | t))) | |
3803 | ||
3804 | (cond | |
3805 | ((eq (char-before) ?>) | |
3806 | ;; Either an operator starting with '>' or the end of | |
3807 | ;; the angle bracket arglist. | |
3808 | ||
3809 | (if (and (/= (1- (point)) pos) | |
3810 | (c-get-char-property (1- (point)) 'syntax-table) | |
3811 | (progn | |
3812 | (c-clear-char-property (1- (point)) 'syntax-table) | |
3813 | (c-parse-sexp-lookup-properties))) | |
3814 | ||
3815 | ;; We've skipped past a list that ended with '>'. It | |
3816 | ;; must be unbalanced since nested arglists are handled | |
3817 | ;; in the case below. Recover by removing all paren | |
3818 | ;; properties on '<' and '>' in the searched region and | |
3819 | ;; redo the search. | |
3820 | (progn | |
3821 | (c-remove-<>-arglist-properties pos (point)) | |
3822 | (goto-char pos) | |
3823 | t) | |
3824 | ||
3825 | (if (looking-at c->-op-cont-regexp) | |
3826 | (progn | |
3827 | (when (text-property-not-all | |
3828 | (1- (point)) (match-end 0) 'syntax-table nil) | |
3829 | (c-remove-<>-arglist-properties (1- (point)) | |
3830 | (match-end 0))) | |
3831 | (goto-char (match-end 0)) | |
3832 | t) | |
3833 | ||
3834 | ;; The angle bracket arglist is finished. | |
3835 | (while arg-start-pos | |
3836 | (c-put-char-property (1- (car arg-start-pos)) | |
3837 | 'c-type 'c-<>-arg-sep) | |
3838 | (setq arg-start-pos (cdr arg-start-pos))) | |
3839 | (c-mark-<-as-paren start) | |
3840 | (c-mark->-as-paren (1- (point))) | |
3841 | (setq res t) | |
3842 | nil))) | |
3843 | ||
3844 | ((eq (char-before) ?<) | |
3845 | ;; Either an operator starting with '<' or a nested arglist. | |
3846 | ||
3847 | (setq pos (point)) | |
3848 | (let (id-start id-end subres keyword-match) | |
3849 | (if (if (looking-at c-<-op-cont-regexp) | |
3850 | (setq tmp (match-end 0)) | |
3851 | (setq tmp pos) | |
3852 | (backward-char) | |
3853 | (not | |
3854 | (and | |
3855 | ||
3856 | (save-excursion | |
3857 | ;; There's always an identifier before a angle | |
3858 | ;; bracket arglist, or a keyword in | |
3859 | ;; `c-<>-type-kwds' or `c-<>-arglist-kwds'. | |
3860 | (c-backward-syntactic-ws) | |
3861 | (setq id-end (point)) | |
3862 | (c-simple-skip-symbol-backward) | |
3863 | (when (or (setq keyword-match | |
3864 | (looking-at c-opt-<>-sexp-key)) | |
3865 | (not (looking-at c-keywords-regexp))) | |
3866 | (setq id-start (point)))) | |
3867 | ||
3868 | (setq subres | |
3869 | (let ((c-record-type-identifiers nil) | |
3870 | (c-record-found-types nil)) | |
3871 | (c-forward-<>-arglist-recur | |
3872 | (and keyword-match | |
3873 | (c-keyword-member | |
3874 | (c-keyword-sym (match-string 1)) | |
3875 | 'c-<>-type-kwds)) | |
3876 | (and reparse | |
037558bf | 3877 | c-restricted-<>-arglists)))) |
d9e94c22 MS |
3878 | ))) |
3879 | ||
3880 | ;; It was not an angle bracket arglist. | |
3881 | (progn | |
3882 | (when (text-property-not-all | |
3883 | (1- pos) tmp 'syntax-table nil) | |
3884 | (if (c-parse-sexp-lookup-properties) | |
3885 | ;; Got an invalid open paren syntax on this | |
3886 | ;; '<'. We'll probably get an unbalanced '>' | |
3887 | ;; further ahead if we just remove the syntax | |
3888 | ;; here, so recover by removing all paren | |
3889 | ;; properties up to and including the | |
3890 | ;; balancing close paren. | |
3891 | (parse-partial-sexp pos (point-max) -1) | |
3892 | (goto-char tmp)) | |
3893 | (c-remove-<>-arglist-properties pos (point))) | |
3894 | (goto-char tmp)) | |
3895 | ||
3896 | ;; It was an angle bracket arglist. | |
3897 | (setq c-record-found-types subres) | |
3898 | ||
3899 | ;; Record the identifier before the template as a type | |
3900 | ;; or reference depending on whether the arglist is last | |
3901 | ;; in a qualified identifier. | |
3902 | (when (and c-record-type-identifiers | |
3903 | (not keyword-match)) | |
3904 | (if (and c-opt-identifier-concat-key | |
3905 | (progn | |
3906 | (c-forward-syntactic-ws) | |
3907 | (looking-at c-opt-identifier-concat-key))) | |
3908 | (c-record-ref-id (cons id-start id-end)) | |
3909 | (c-record-type-id (cons id-start id-end)))))) | |
3910 | t) | |
3911 | ||
3912 | ((and (eq (char-before) ?,) | |
037558bf | 3913 | (not c-restricted-<>-arglists)) |
d9e94c22 MS |
3914 | ;; Just another argument. Record the position. The |
3915 | ;; type check stuff that made us stop at it is at | |
3916 | ;; the top of the loop. | |
3917 | (setq arg-start-pos (cons (point) arg-start-pos))) | |
3918 | ||
3919 | (t | |
3920 | ;; Got a character that can't be in an angle bracket | |
3921 | ;; arglist argument. Abort using `throw', since | |
3922 | ;; it's useless to try to find a surrounding arglist | |
3923 | ;; if we're nested. | |
3924 | (throw 'angle-bracket-arglist-escape nil)))))) | |
3925 | ||
3926 | (if res | |
3927 | (or c-record-found-types t))))) | |
3928 | ||
3929 | (defun c-forward-name () | |
3930 | ;; Move forward over a complete name if at the beginning of one, | |
3931 | ;; stopping at the next following token. If the point is not at | |
3932 | ;; something that are recognized as name then it stays put. A name | |
3933 | ;; could be something as simple as "foo" in C or something as | |
3934 | ;; complex as "X<Y<class A<int>::B, BIT_MAX >> b>, ::operator<> :: | |
3935 | ;; Z<(a>b)> :: operator const X<&foo>::T Q::G<unsigned short | |
3936 | ;; int>::*volatile const" in C++ (this function is actually little | |
3937 | ;; more than a `looking-at' call in all modes except those that, | |
3938 | ;; like C++, have `c-recognize-<>-arglists' set). Return nil if no | |
3939 | ;; name is found, 'template if it's an identifier ending with an | |
3940 | ;; angle bracket arglist, 'operator of it's an operator identifier, | |
3941 | ;; or t if it's some other kind of name. | |
3942 | ||
3943 | (let ((pos (point)) res id-start id-end | |
3944 | ;; Turn off `c-promote-possible-types' here since we might | |
3945 | ;; call `c-forward-<>-arglist' and we don't want it to promote | |
3946 | ;; every suspect thing in the arglist to a type. We're | |
3947 | ;; typically called from `c-forward-type' in this case, and | |
3948 | ;; the caller only wants the top level type that it finds to | |
3949 | ;; be promoted. | |
3950 | c-promote-possible-types) | |
3951 | (while | |
3952 | (and | |
3953 | (looking-at c-identifier-key) | |
3954 | ||
3955 | (progn | |
3956 | ;; Check for keyword. We go to the last symbol in | |
3957 | ;; `c-identifier-key' first. | |
3958 | (if (eq c-identifier-key c-symbol-key) | |
3959 | (setq id-start (point) | |
3960 | id-end (match-end 0)) | |
3961 | (goto-char (setq id-end (match-end 0))) | |
3962 | (c-simple-skip-symbol-backward) | |
3963 | (setq id-start (point))) | |
3964 | ||
3965 | (if (looking-at c-keywords-regexp) | |
3966 | (when (and (c-major-mode-is 'c++-mode) | |
3967 | (looking-at | |
3968 | (cc-eval-when-compile | |
3969 | (concat "\\(operator\\|\\(template\\)\\)" | |
3970 | "\\(" (c-lang-const c-nonsymbol-key c++) | |
3971 | "\\|$\\)"))) | |
3972 | (if (match-beginning 2) | |
3973 | ;; "template" is only valid inside an | |
3974 | ;; identifier if preceded by "::". | |
3975 | (save-excursion | |
3976 | (c-backward-syntactic-ws) | |
3977 | (and (c-safe (backward-char 2) t) | |
3978 | (looking-at "::"))) | |
3979 | t)) | |
3980 | ||
3981 | ;; Handle a C++ operator or template identifier. | |
3982 | (goto-char id-end) | |
3983 | (c-forward-syntactic-ws) | |
3984 | (cond ((eq (char-before id-end) ?e) | |
3985 | ;; Got "... ::template". | |
3986 | (let ((subres (c-forward-name))) | |
3987 | (when subres | |
3988 | (setq pos (point) | |
3989 | res subres)))) | |
3990 | ||
3991 | ((looking-at c-identifier-start) | |
3992 | ;; Got a cast operator. | |
3993 | (when (c-forward-type) | |
3994 | (setq pos (point) | |
3995 | res 'operator) | |
3996 | ;; Now we should match a sequence of either | |
3997 | ;; '*', '&' or a name followed by ":: *", | |
3998 | ;; where each can be followed by a sequence | |
3999 | ;; of `c-opt-type-modifier-key'. | |
4000 | (while (cond ((looking-at "[*&]") | |
4001 | (goto-char (match-end 0)) | |
4002 | t) | |
4003 | ((looking-at c-identifier-start) | |
4004 | (and (c-forward-name) | |
4005 | (looking-at "::") | |
4006 | (progn | |
4007 | (goto-char (match-end 0)) | |
4008 | (c-forward-syntactic-ws) | |
4009 | (eq (char-after) ?*)) | |
4010 | (progn | |
4011 | (forward-char) | |
4012 | t)))) | |
4013 | (while (progn | |
4014 | (c-forward-syntactic-ws) | |
4015 | (setq pos (point)) | |
4016 | (looking-at c-opt-type-modifier-key)) | |
4017 | (goto-char (match-end 1)))))) | |
4018 | ||
4019 | ((looking-at c-overloadable-operators-regexp) | |
4020 | ;; Got some other operator. | |
4021 | (when c-record-type-identifiers | |
4022 | (setq c-last-identifier-range | |
4023 | (cons (point) (match-end 0)))) | |
4024 | (goto-char (match-end 0)) | |
4025 | (c-forward-syntactic-ws) | |
4026 | (setq pos (point) | |
4027 | res 'operator))) | |
4028 | ||
4029 | nil) | |
4030 | ||
4031 | (when c-record-type-identifiers | |
4032 | (setq c-last-identifier-range | |
4033 | (cons id-start id-end))) | |
4034 | (goto-char id-end) | |
4035 | (c-forward-syntactic-ws) | |
4036 | (setq pos (point) | |
4037 | res t))) | |
4038 | ||
4039 | (progn | |
4040 | (goto-char pos) | |
4041 | (when (or c-opt-identifier-concat-key | |
4042 | c-recognize-<>-arglists) | |
4043 | ||
4044 | (cond | |
4045 | ((and c-opt-identifier-concat-key | |
4046 | (looking-at c-opt-identifier-concat-key)) | |
4047 | ;; Got a concatenated identifier. This handles the | |
4048 | ;; cases with tricky syntactic whitespace that aren't | |
4049 | ;; covered in `c-identifier-key'. | |
4050 | (goto-char (match-end 0)) | |
4051 | (c-forward-syntactic-ws) | |
4052 | t) | |
4053 | ||
4054 | ((and c-recognize-<>-arglists | |
4055 | (eq (char-after) ?<)) | |
4056 | ;; Maybe an angle bracket arglist. | |
4057 | (when (let ((c-record-type-identifiers nil) | |
4058 | (c-record-found-types nil)) | |
4059 | (c-forward-<>-arglist | |
037558bf | 4060 | nil c-restricted-<>-arglists)) |
d9e94c22 MS |
4061 | (c-forward-syntactic-ws) |
4062 | (setq pos (point)) | |
4063 | (if (and c-opt-identifier-concat-key | |
4064 | (looking-at c-opt-identifier-concat-key)) | |
4065 | ;; Continue if there's an identifier concatenation | |
4066 | ;; operator after the template argument. | |
4067 | (progn | |
4068 | (when c-record-type-identifiers | |
4069 | (c-record-ref-id (cons id-start id-end)) | |
4070 | (setq c-last-identifier-range nil)) | |
4071 | (forward-char 2) | |
4072 | (c-forward-syntactic-ws) | |
4073 | t) | |
4074 | ;; `c-add-type' isn't called here since we don't | |
4075 | ;; want to add types containing angle bracket | |
4076 | ;; arglists. | |
4077 | (when c-record-type-identifiers | |
4078 | (c-record-type-id (cons id-start id-end)) | |
4079 | (setq c-last-identifier-range nil)) | |
4080 | (setq res 'template) | |
4081 | nil))) | |
4082 | ))))) | |
4083 | ||
4084 | (goto-char pos) | |
4085 | res)) | |
4086 | ||
4087 | (defun c-forward-type () | |
4088 | ;; Move forward over a type spec if at the beginning of one, | |
4089 | ;; stopping at the next following token. Return t if it's a known | |
2a15eb73 MS |
4090 | ;; type that can't be a name or other expression, 'known if it's an |
4091 | ;; otherwise known type (according to `*-font-lock-extra-types'), | |
4092 | ;; 'prefix if it's a known prefix of a type, 'found if it's a type | |
4093 | ;; that matches one in `c-found-types', 'maybe if it's an identfier | |
4094 | ;; that might be a type, or nil if it can't be a type (the point | |
4095 | ;; isn't moved then). The point is assumed to be at the beginning | |
4096 | ;; of a token. | |
d9e94c22 MS |
4097 | ;; |
4098 | ;; Note that this function doesn't skip past the brace definition | |
4099 | ;; that might be considered part of the type, e.g. | |
4100 | ;; "enum {a, b, c} foo". | |
4101 | (let ((start (point)) pos res res2 id-start id-end id-range) | |
4102 | ||
4103 | ;; Skip leading type modifiers. If any are found we know it's a | |
4104 | ;; prefix of a type. | |
4105 | (when c-opt-type-modifier-key | |
4106 | (while (looking-at c-opt-type-modifier-key) | |
4107 | (goto-char (match-end 1)) | |
4108 | (c-forward-syntactic-ws) | |
4109 | (setq res 'prefix))) | |
4110 | ||
4111 | (cond | |
4112 | ((looking-at c-type-prefix-key) | |
4113 | ;; Looking at a keyword that prefixes a type identifier, | |
4114 | ;; e.g. "class". | |
4115 | (goto-char (match-end 1)) | |
4116 | (c-forward-syntactic-ws) | |
4117 | (setq pos (point)) | |
4118 | (if (memq (setq res2 (c-forward-name)) '(t template)) | |
4119 | (progn | |
4120 | (when (eq res2 t) | |
4121 | ;; In many languages the name can be used without the | |
4122 | ;; prefix, so we add it to `c-found-types'. | |
4123 | (c-add-type pos (point)) | |
4124 | (when c-record-type-identifiers | |
4125 | (c-record-type-id c-last-identifier-range))) | |
4126 | (setq res t)) | |
4127 | ;; Invalid syntax. | |
4128 | (goto-char start) | |
4129 | (setq res nil))) | |
4130 | ||
4131 | ((progn | |
4132 | (setq pos nil) | |
4133 | (if (looking-at c-identifier-start) | |
4134 | (save-excursion | |
4135 | (setq id-start (point) | |
4136 | res2 (c-forward-name)) | |
4137 | (when res2 | |
4138 | (setq id-end (point) | |
4139 | id-range c-last-identifier-range)))) | |
4140 | (and (cond ((looking-at c-primitive-type-key) | |
4141 | (setq res t)) | |
4142 | ((c-with-syntax-table c-identifier-syntax-table | |
4143 | (looking-at c-known-type-key)) | |
4144 | (setq res 'known))) | |
4145 | (or (not id-end) | |
4146 | (>= (save-excursion | |
4147 | (save-match-data | |
4148 | (goto-char (match-end 1)) | |
4149 | (c-forward-syntactic-ws) | |
4150 | (setq pos (point)))) | |
4151 | id-end) | |
4152 | (setq res nil)))) | |
4153 | ;; Looking at a primitive or known type identifier. We've | |
4154 | ;; checked for a name first so that we don't go here if the | |
4155 | ;; known type match only is a prefix of another name. | |
4156 | ||
4157 | (setq id-end (match-end 1)) | |
4158 | ||
4159 | (when (and c-record-type-identifiers | |
4160 | (or c-promote-possible-types (eq res t))) | |
4161 | (c-record-type-id (cons (match-beginning 1) (match-end 1)))) | |
4162 | ||
4163 | (if (and c-opt-type-component-key | |
4164 | (save-match-data | |
4165 | (looking-at c-opt-type-component-key))) | |
4166 | ;; There might be more keywords for the type. | |
4167 | (let (safe-pos) | |
4168 | (c-forward-keyword-clause) | |
4169 | (while (progn | |
4170 | (setq safe-pos (point)) | |
4171 | (looking-at c-opt-type-component-key)) | |
4172 | (when (and c-record-type-identifiers | |
4173 | (looking-at c-primitive-type-key)) | |
4174 | (c-record-type-id (cons (match-beginning 1) | |
4175 | (match-end 1)))) | |
4176 | (c-forward-keyword-clause)) | |
4177 | (if (looking-at c-primitive-type-key) | |
4178 | (progn | |
4179 | (when c-record-type-identifiers | |
4180 | (c-record-type-id (cons (match-beginning 1) | |
4181 | (match-end 1)))) | |
4182 | (c-forward-keyword-clause) | |
4183 | (setq res t)) | |
4184 | (goto-char safe-pos) | |
4185 | (setq res 'prefix))) | |
4186 | (unless (save-match-data (c-forward-keyword-clause)) | |
4187 | (if pos | |
4188 | (goto-char pos) | |
4189 | (goto-char (match-end 1)) | |
4190 | (c-forward-syntactic-ws))))) | |
4191 | ||
4192 | (res2 | |
4193 | (cond ((eq res2 t) | |
4194 | ;; A normal identifier. | |
4195 | (goto-char id-end) | |
4196 | (if (or res c-promote-possible-types) | |
4197 | (progn | |
4198 | (c-add-type id-start id-end) | |
4199 | (when c-record-type-identifiers | |
4200 | (c-record-type-id id-range)) | |
4201 | (unless res | |
4202 | (setq res 'found))) | |
4203 | (setq res (if (c-check-type id-start id-end) | |
4204 | ;; It's an identifier that has been used as | |
4205 | ;; a type somewhere else. | |
4206 | 'found | |
4207 | ;; It's an identifier that might be a type. | |
4208 | 'maybe)))) | |
4209 | ((eq res2 'template) | |
4210 | ;; A template is a type. | |
4211 | (goto-char id-end) | |
4212 | (setq res t)) | |
4213 | (t | |
4214 | ;; Otherwise it's an operator identifier, which is not a type. | |
4215 | (goto-char start) | |
4216 | (setq res nil))))) | |
4217 | ||
4218 | (when res | |
4219 | ;; Skip trailing type modifiers. If any are found we know it's | |
4220 | ;; a type. | |
4221 | (when c-opt-type-modifier-key | |
4222 | (while (looking-at c-opt-type-modifier-key) | |
4223 | (goto-char (match-end 1)) | |
4224 | (c-forward-syntactic-ws) | |
4225 | (setq res t))) | |
4226 | ||
4227 | ;; Step over any type suffix operator. Do not let the existence | |
4228 | ;; of these alter the classification of the found type, since | |
4229 | ;; these operators typically are allowed in normal expressions | |
4230 | ;; too. | |
4231 | (when c-opt-type-suffix-key | |
4232 | (while (looking-at c-opt-type-suffix-key) | |
4233 | (goto-char (match-end 1)) | |
4234 | (c-forward-syntactic-ws))) | |
4235 | ||
4236 | (when c-opt-type-concat-key | |
4237 | ;; Look for a trailing operator that concatenate the type with | |
4238 | ;; a following one, and if so step past that one through a | |
4239 | ;; recursive call. | |
4240 | (setq pos (point)) | |
4241 | (let* ((c-promote-possible-types (or (memq res '(t known)) | |
4242 | c-promote-possible-types)) | |
4243 | ;; If we can't promote then set `c-record-found-types' so that | |
4244 | ;; we can merge in the types from the second part afterwards if | |
4245 | ;; it turns out to be a known type there. | |
4246 | (c-record-found-types (and c-record-type-identifiers | |
4247 | (not c-promote-possible-types)))) | |
4248 | (if (and (looking-at c-opt-type-concat-key) | |
4249 | ||
4250 | (progn | |
4251 | (goto-char (match-end 1)) | |
4252 | (c-forward-syntactic-ws) | |
4253 | (setq res2 (c-forward-type)))) | |
4254 | ||
4255 | (progn | |
4256 | ;; If either operand certainly is a type then both are, but we | |
4257 | ;; don't let the existence of the operator itself promote two | |
4258 | ;; uncertain types to a certain one. | |
4259 | (cond ((eq res t)) | |
2a15eb73 | 4260 | ((eq res2 t) |
d9e94c22 MS |
4261 | (c-add-type id-start id-end) |
4262 | (when c-record-type-identifiers | |
4263 | (c-record-type-id id-range)) | |
4264 | (setq res t)) | |
2a15eb73 MS |
4265 | ((eq res 'known)) |
4266 | ((eq res2 'known) | |
4267 | (setq res 'known)) | |
d9e94c22 MS |
4268 | ((eq res 'found)) |
4269 | ((eq res2 'found) | |
4270 | (setq res 'found)) | |
4271 | (t | |
4272 | (setq res 'maybe))) | |
4273 | ||
4274 | (when (and (eq res t) | |
4275 | (consp c-record-found-types)) | |
4276 | ;; Merge in the ranges of any types found by the second | |
4277 | ;; `c-forward-type'. | |
4278 | (setq c-record-type-identifiers | |
4279 | ;; `nconc' doesn't mind that the tail of | |
4280 | ;; `c-record-found-types' is t. | |
4281 | (nconc c-record-found-types | |
4282 | c-record-type-identifiers)))) | |
4283 | ||
4284 | (goto-char pos)))) | |
4285 | ||
4286 | (when (and c-record-found-types (memq res '(known found)) id-range) | |
4287 | (setq c-record-found-types | |
4288 | (cons id-range c-record-found-types)))) | |
4289 | ||
4290 | ;;(message "c-forward-type %s -> %s: %s" start (point) res) | |
4291 | ||
4292 | res)) | |
4293 | ||
785eecbb | 4294 | \f |
d9e94c22 MS |
4295 | ;; Handling of large scale constructs like statements and declarations. |
4296 | ||
785eecbb RS |
4297 | (defun c-beginning-of-inheritance-list (&optional lim) |
4298 | ;; Go to the first non-whitespace after the colon that starts a | |
4299 | ;; multiple inheritance introduction. Optional LIM is the farthest | |
4300 | ;; back we should search. | |
d9e94c22 MS |
4301 | (let* ((lim (or lim (save-excursion |
4302 | (c-beginning-of-syntax) | |
4303 | (point))))) | |
a66cd3ee | 4304 | (c-with-syntax-table c++-template-syntax-table |
d9e94c22 MS |
4305 | (c-backward-token-2 0 t lim) |
4306 | (while (and (or (looking-at c-symbol-start) | |
037558bf | 4307 | (looking-at "[<,]\\|::")) |
d9e94c22 | 4308 | (zerop (c-backward-token-2 1 t lim)))) |
a66cd3ee | 4309 | (skip-chars-forward "^:")))) |
785eecbb | 4310 | |
785eecbb RS |
4311 | (defun c-in-method-def-p () |
4312 | ;; Return nil if we aren't in a method definition, otherwise the | |
4313 | ;; position of the initial [+-]. | |
4314 | (save-excursion | |
4315 | (beginning-of-line) | |
a66cd3ee MS |
4316 | (and c-opt-method-key |
4317 | (looking-at c-opt-method-key) | |
785eecbb RS |
4318 | (point)) |
4319 | )) | |
4320 | ||
a66cd3ee MS |
4321 | ;; Contributed by Kevin Ryde <user42@zip.com.au>. |
4322 | (defun c-in-gcc-asm-p () | |
4323 | ;; Return non-nil if point is within a gcc \"asm\" block. | |
4324 | ;; | |
4325 | ;; This should be called with point inside an argument list. | |
4326 | ;; | |
4327 | ;; Only one level of enclosing parentheses is considered, so for | |
4328 | ;; instance `nil' is returned when in a function call within an asm | |
4329 | ;; operand. | |
4330 | ||
4331 | (and c-opt-asm-stmt-key | |
4332 | (save-excursion | |
4333 | (beginning-of-line) | |
4334 | (backward-up-list 1) | |
4335 | (c-beginning-of-statement-1 (point-min) nil t) | |
4336 | (looking-at c-opt-asm-stmt-key)))) | |
4337 | ||
abb7e5cf SM |
4338 | (defun c-at-toplevel-p () |
4339 | "Return a determination as to whether point is at the `top-level'. | |
4340 | Being at the top-level means that point is either outside any | |
d9e94c22 MS |
4341 | enclosing block (such function definition), or only inside a class, |
4342 | namespace or other block that contains another declaration level. | |
abb7e5cf SM |
4343 | |
4344 | If point is not at the top-level (e.g. it is inside a method | |
4345 | definition), then nil is returned. Otherwise, if point is at a | |
4346 | top-level not enclosed within a class definition, t is returned. | |
4347 | Otherwise, a 2-vector is returned where the zeroth element is the | |
4348 | buffer position of the start of the class declaration, and the first | |
4349 | element is the buffer position of the enclosing class's opening | |
4350 | brace." | |
a66cd3ee MS |
4351 | (let ((paren-state (c-parse-state))) |
4352 | (or (not (c-most-enclosing-brace paren-state)) | |
4353 | (c-search-uplist-for-classkey paren-state)))) | |
4354 | ||
d9e94c22 | 4355 | (defun c-just-after-func-arglist-p (&optional lim) |
449a2b0d | 4356 | ;; Return non-nil if we are between a function's argument list closing |
785eecbb RS |
4357 | ;; paren and its opening brace. Note that the list close brace |
4358 | ;; could be followed by a "const" specifier or a member init hanging | |
d9e94c22 MS |
4359 | ;; colon. LIM is used as bound for some backward buffer searches; |
4360 | ;; the search might continue past it. | |
a66cd3ee MS |
4361 | ;; |
4362 | ;; Note: This test is easily fooled. It only works reasonably well | |
4363 | ;; in the situations where `c-guess-basic-syntax' uses it. | |
785eecbb | 4364 | (save-excursion |
d9e94c22 MS |
4365 | (if (c-mode-is-new-awk-p) |
4366 | (c-awk-backward-syntactic-ws lim) | |
4367 | (c-backward-syntactic-ws lim)) | |
4368 | (let ((checkpoint (point))) | |
785eecbb RS |
4369 | ;; could be looking at const specifier |
4370 | (if (and (eq (char-before) ?t) | |
4371 | (forward-word -1) | |
a66cd3ee MS |
4372 | (looking-at "\\<const\\>[^_]")) |
4373 | (c-backward-syntactic-ws lim) | |
785eecbb RS |
4374 | ;; otherwise, we could be looking at a hanging member init |
4375 | ;; colon | |
4376 | (goto-char checkpoint) | |
2c9c1954 MS |
4377 | (while (and |
4378 | (eq (char-before) ?,) | |
4379 | ;; this will catch member inits with multiple | |
4380 | ;; line arglists | |
4381 | (progn | |
4382 | (forward-char -1) | |
4383 | (c-backward-syntactic-ws (c-point 'bol)) | |
4384 | (c-safe (c-backward-sexp 1) t)) | |
4385 | (or (not (looking-at "\\s\(")) | |
4386 | (c-safe (c-backward-sexp 1) t))) | |
a66cd3ee | 4387 | (c-backward-syntactic-ws lim)) |
785eecbb RS |
4388 | (if (and (eq (char-before) ?:) |
4389 | (progn | |
4390 | (forward-char -1) | |
a66cd3ee MS |
4391 | (c-backward-syntactic-ws lim) |
4392 | (looking-at "\\([ \t\n]\\|\\\\\n\\)*:\\([^:]+\\|$\\)"))) | |
785eecbb RS |
4393 | nil |
4394 | (goto-char checkpoint)) | |
4395 | ) | |
a66cd3ee | 4396 | (setq checkpoint (point)) |
785eecbb | 4397 | (and (eq (char-before) ?\)) |
a66cd3ee MS |
4398 | ;; Check that it isn't a cpp expression, e.g. the |
4399 | ;; expression of an #if directive or the "function header" | |
4400 | ;; of a #define. | |
4401 | (or (not (c-beginning-of-macro)) | |
4402 | (and (c-forward-to-cpp-define-body) | |
4403 | (< (point) checkpoint))) | |
449a2b0d MS |
4404 | ;; Check if we are looking at an ObjC method def or a class |
4405 | ;; category. | |
4406 | (not (and c-opt-method-key | |
4407 | (progn | |
4408 | (goto-char checkpoint) | |
4409 | (c-safe (c-backward-sexp) t)) | |
4410 | (progn | |
4411 | (c-backward-syntactic-ws lim) | |
4412 | (or (memq (char-before) '(?- ?+)) | |
4413 | (and (c-safe (c-forward-sexp -2) t) | |
4414 | (looking-at c-class-key)))))) | |
4415 | ;; Pike has compound types that include parens, | |
4416 | ;; e.g. "array(string)". Check that we aren't after one. | |
4417 | (not (and (c-major-mode-is 'pike-mode) | |
4418 | (progn | |
4419 | (goto-char checkpoint) | |
4420 | (c-safe (c-backward-sexp 2) t)) | |
4421 | (looking-at c-primitive-type-key))) | |
4422 | )))) | |
785eecbb | 4423 | |
a66cd3ee MS |
4424 | (defun c-in-knr-argdecl (&optional lim) |
4425 | ;; Return the position of the first argument declaration if point is | |
4426 | ;; inside a K&R style argument declaration list, nil otherwise. | |
4427 | ;; `c-recognize-knr-p' is not checked. If LIM is non-nil, it's a | |
4428 | ;; position that bounds the backward search for the argument list. | |
4429 | ;; | |
4430 | ;; Note: A declaration level context is assumed; the test can return | |
037558bf | 4431 | ;; false positives for statements. |
d9e94c22 | 4432 | |
a66cd3ee MS |
4433 | (save-excursion |
4434 | (save-restriction | |
d9e94c22 | 4435 | |
a66cd3ee MS |
4436 | ;; Go back to the closest preceding normal parenthesis sexp. We |
4437 | ;; take that as the argument list in the function header. Then | |
4438 | ;; check that it's followed by some symbol before the next ';' | |
4439 | ;; or '{'. If it does, it's the header of the K&R argdecl we're | |
4440 | ;; in. | |
037558bf | 4441 | (if lim (narrow-to-region lim (c-point 'eol))) |
d9e94c22 MS |
4442 | (let ((outside-macro (not (c-query-macro-start))) |
4443 | paren-end) | |
4444 | ||
4445 | (catch 'done | |
037558bf | 4446 | (while (if (and (setq paren-end (c-down-list-backward (point))) |
d9e94c22 MS |
4447 | (eq (char-after paren-end) ?\))) |
4448 | (progn | |
4449 | (goto-char (1+ paren-end)) | |
4450 | (if outside-macro | |
4451 | (c-beginning-of-macro))) | |
4452 | (throw 'done nil)))) | |
4453 | ||
4454 | (and (progn | |
a66cd3ee MS |
4455 | (c-forward-syntactic-ws) |
4456 | (looking-at "\\w\\|\\s_")) | |
037558bf MS |
4457 | |
4458 | (save-excursion | |
4459 | ;; The function header in a K&R declaration should only | |
4460 | ;; contain identifiers separated by comma. It should | |
4461 | ;; also contain at least one identifier since there | |
4462 | ;; wouldn't be anything to declare in the K&R region | |
4463 | ;; otherwise. | |
4464 | (when (c-go-up-list-backward paren-end) | |
4465 | (forward-char) | |
4466 | (catch 'knr-ok | |
4467 | (while t | |
4468 | (c-forward-syntactic-ws) | |
4469 | (if (or (looking-at c-known-type-key) | |
4470 | (looking-at c-keywords-regexp)) | |
4471 | (throw 'knr-ok nil)) | |
4472 | (c-forward-token-2) | |
4473 | (if (eq (char-after) ?,) | |
4474 | (forward-char) | |
4475 | (throw 'knr-ok (and (eq (char-after) ?\)) | |
4476 | (= (point) paren-end)))))))) | |
d9e94c22 MS |
4477 | |
4478 | (save-excursion | |
4479 | ;; If it's a K&R declaration then we're now at the | |
4480 | ;; beginning of the function arglist. Check that there | |
4481 | ;; isn't a '=' before it in this statement since that | |
4482 | ;; means it some kind of initialization instead. | |
4483 | (c-syntactic-skip-backward "^;=}{") | |
4484 | (not (eq (char-before) ?=))) | |
4485 | ||
a66cd3ee | 4486 | (point)))))) |
785eecbb RS |
4487 | |
4488 | (defun c-skip-conditional () | |
4489 | ;; skip forward over conditional at point, including any predicate | |
4490 | ;; statements in parentheses. No error checking is performed. | |
0ec8351b BW |
4491 | (c-forward-sexp (cond |
4492 | ;; else if() | |
a66cd3ee MS |
4493 | ((looking-at (concat "\\<else" |
4494 | "\\([ \t\n]\\|\\\\\n\\)+" | |
4495 | "if\\>\\([^_]\\|$\\)")) | |
4496 | 3) | |
0ec8351b | 4497 | ;; do, else, try, finally |
a66cd3ee MS |
4498 | ((looking-at (concat "\\<\\(" |
4499 | "do\\|else\\|try\\|finally" | |
4500 | "\\)\\>\\([^_]\\|$\\)")) | |
130c507e | 4501 | 1) |
ce8c7486 | 4502 | ;; for, if, while, switch, catch, synchronized, foreach |
0ec8351b | 4503 | (t 2)))) |
785eecbb | 4504 | |
a66cd3ee MS |
4505 | (defun c-after-conditional (&optional lim) |
4506 | ;; If looking at the token after a conditional then return the | |
4507 | ;; position of its start, otherwise return nil. | |
4508 | (save-excursion | |
d9e94c22 | 4509 | (and (zerop (c-backward-token-2 1 t lim)) |
a66cd3ee MS |
4510 | (or (looking-at c-block-stmt-1-key) |
4511 | (and (eq (char-after) ?\() | |
d9e94c22 | 4512 | (zerop (c-backward-token-2 1 t lim)) |
a66cd3ee MS |
4513 | (looking-at c-block-stmt-2-key))) |
4514 | (point)))) | |
4515 | ||
4516 | (defsubst c-backward-to-block-anchor (&optional lim) | |
4517 | ;; Assuming point is at a brace that opens a statement block of some | |
4518 | ;; kind, move to the proper anchor point for that block. It might | |
4519 | ;; need to be adjusted further by c-add-stmt-syntax, but the | |
4520 | ;; position at return is suitable as start position for that | |
4521 | ;; function. | |
4522 | (unless (= (point) (c-point 'boi)) | |
4523 | (let ((start (c-after-conditional lim))) | |
4524 | (if start | |
4525 | (goto-char start))))) | |
4526 | ||
037558bf | 4527 | (defsubst c-backward-to-decl-anchor (&optional lim) |
a66cd3ee MS |
4528 | ;; Assuming point is at a brace that opens the block of a top level |
4529 | ;; declaration of some kind, move to the proper anchor point for | |
4530 | ;; that block. | |
4531 | (unless (= (point) (c-point 'boi)) | |
037558bf | 4532 | (c-beginning-of-statement-1 lim))) |
a66cd3ee | 4533 | |
ff959bab | 4534 | (defun c-search-decl-header-end () |
a66cd3ee MS |
4535 | ;; Search forward for the end of the "header" of the current |
4536 | ;; declaration. That's the position where the definition body | |
4537 | ;; starts, or the first variable initializer, or the ending | |
4538 | ;; semicolon. I.e. search forward for the closest following | |
4539 | ;; (syntactically relevant) '{', '=' or ';' token. Point is left | |
4540 | ;; _after_ the first found token, or at point-max if none is found. | |
ff959bab MS |
4541 | |
4542 | (let ((base (point))) | |
4543 | (if (c-major-mode-is 'c++-mode) | |
4544 | ||
4545 | ;; In C++ we need to take special care to handle operator | |
4546 | ;; tokens and those pesky template brackets. | |
4547 | (while (and | |
4548 | (c-syntactic-re-search-forward "[;{<=]" nil 'move t t) | |
4549 | (or | |
4550 | (c-end-of-current-token base) | |
4551 | ;; Handle operator identifiers, i.e. ignore any | |
4552 | ;; operator token preceded by "operator". | |
4553 | (save-excursion | |
4554 | (and (c-safe (c-backward-sexp) t) | |
3efc2cd7 | 4555 | (looking-at "operator\\>\\([^_]\\|$\\)"))) |
ff959bab MS |
4556 | (and (eq (char-before) ?<) |
4557 | (c-with-syntax-table c++-template-syntax-table | |
4558 | (if (c-safe (goto-char (c-up-list-forward (point)))) | |
4559 | t | |
4560 | (goto-char (point-max)) | |
4561 | nil))))) | |
4562 | (setq base (point))) | |
4563 | ||
4564 | (while (and | |
4565 | (c-syntactic-re-search-forward "[;{=]" nil 'move t t) | |
4566 | (c-end-of-current-token base)) | |
4567 | (setq base (point)))))) | |
a66cd3ee MS |
4568 | |
4569 | (defun c-beginning-of-decl-1 (&optional lim) | |
4570 | ;; Go to the beginning of the current declaration, or the beginning | |
4571 | ;; of the previous one if already at the start of it. Point won't | |
4572 | ;; be moved out of any surrounding paren. Return a cons cell on the | |
4573 | ;; form (MOVE . KNR-POS). MOVE is like the return value from | |
4574 | ;; `c-beginning-of-statement-1'. If point skipped over some K&R | |
4575 | ;; style argument declarations (and they are to be recognized) then | |
4576 | ;; KNR-POS is set to the start of the first such argument | |
4577 | ;; declaration, otherwise KNR-POS is nil. If LIM is non-nil, it's a | |
4578 | ;; position that bounds the backward search. | |
4579 | ;; | |
4580 | ;; NB: Cases where the declaration continues after the block, as in | |
4581 | ;; "struct foo { ... } bar;", are currently recognized as two | |
4582 | ;; declarations, e.g. "struct foo { ... }" and "bar;" in this case. | |
4583 | (catch 'return | |
4584 | (let* ((start (point)) | |
d9e94c22 MS |
4585 | (last-stmt-start (point)) |
4586 | (move (c-beginning-of-statement-1 lim t t))) | |
a66cd3ee | 4587 | |
a66cd3ee MS |
4588 | ;; `c-beginning-of-statement-1' stops at a block start, but we |
4589 | ;; want to continue if the block doesn't begin a top level | |
2a15eb73 MS |
4590 | ;; construct, i.e. if it isn't preceded by ';', '}', ':', bob, |
4591 | ;; or an open paren. | |
d9e94c22 MS |
4592 | (let ((beg (point)) tentative-move) |
4593 | (while (and | |
4594 | ;; Must check with c-opt-method-key in ObjC mode. | |
4595 | (not (and c-opt-method-key | |
4596 | (looking-at c-opt-method-key))) | |
4597 | (/= last-stmt-start (point)) | |
4598 | (progn | |
4599 | (c-backward-syntactic-ws lim) | |
4600 | (not (memq (char-before) '(?\; ?} ?: nil)))) | |
2a15eb73 MS |
4601 | (save-excursion |
4602 | (backward-char) | |
4603 | (not (looking-at "\\s("))) | |
d9e94c22 MS |
4604 | ;; Check that we don't move from the first thing in a |
4605 | ;; macro to its header. | |
4606 | (not (eq (setq tentative-move | |
4607 | (c-beginning-of-statement-1 lim t t)) | |
4608 | 'macro))) | |
4609 | (setq last-stmt-start beg | |
4610 | beg (point) | |
4611 | move tentative-move)) | |
4612 | (goto-char beg)) | |
4613 | ||
4614 | (when c-recognize-knr-p | |
4615 | (let ((fallback-pos (point)) knr-argdecl-start) | |
4616 | ;; Handle K&R argdecls. Back up after the "statement" jumped | |
4617 | ;; over by `c-beginning-of-statement-1', unless it was the | |
4618 | ;; function body, in which case we're sitting on the opening | |
4619 | ;; brace now. Then test if we're in a K&R argdecl region and | |
4620 | ;; that we started at the other side of the first argdecl in | |
4621 | ;; it. | |
4622 | (unless (eq (char-after) ?{) | |
4623 | (goto-char last-stmt-start)) | |
4624 | (if (and (setq knr-argdecl-start (c-in-knr-argdecl lim)) | |
4625 | (< knr-argdecl-start start) | |
4626 | (progn | |
4627 | (goto-char knr-argdecl-start) | |
4628 | (not (eq (c-beginning-of-statement-1 lim t t) 'macro)))) | |
4629 | (throw 'return | |
4630 | (cons (if (eq (char-after fallback-pos) ?{) | |
4631 | 'previous | |
4632 | 'same) | |
4633 | knr-argdecl-start)) | |
4634 | (goto-char fallback-pos)))) | |
4635 | ||
4636 | (when c-opt-access-key | |
4637 | ;; Might have ended up before a protection label. This should | |
4638 | ;; perhaps be checked before `c-recognize-knr-p' to be really | |
4639 | ;; accurate, but we know that no language has both. | |
4640 | (while (looking-at c-opt-access-key) | |
4641 | (goto-char (match-end 0)) | |
4642 | (c-forward-syntactic-ws) | |
4643 | (when (>= (point) start) | |
4644 | (goto-char start) | |
4645 | (throw 'return (cons 'same nil))))) | |
4646 | ||
4647 | ;; `c-beginning-of-statement-1' counts each brace block as a | |
4648 | ;; separate statement, so the result will be 'previous if we've | |
4649 | ;; moved over any. If they were brace list initializers we might | |
4650 | ;; not have moved over a declaration boundary though, so change it | |
4651 | ;; to 'same if we've moved past a '=' before '{', but not ';'. | |
4652 | ;; (This ought to be integrated into `c-beginning-of-statement-1', | |
4653 | ;; so we avoid this extra pass which potentially can search over a | |
4654 | ;; large amount of text.) | |
4655 | (if (and (eq move 'previous) | |
4656 | (c-with-syntax-table (if (c-major-mode-is 'c++-mode) | |
4657 | c++-template-syntax-table | |
4658 | (syntax-table)) | |
4659 | (save-excursion | |
4660 | (and (c-syntactic-re-search-forward "[;={]" start t t t) | |
4661 | (eq (char-before) ?=) | |
4662 | (c-syntactic-re-search-forward "[;{]" start t t) | |
4663 | (eq (char-before) ?{) | |
4664 | (c-safe (goto-char (c-up-list-forward (point))) t) | |
4665 | (not (c-syntactic-re-search-forward ";" start t t)))))) | |
4666 | (cons 'same nil) | |
4667 | (cons move nil))))) | |
a66cd3ee MS |
4668 | |
4669 | (defun c-end-of-decl-1 () | |
4670 | ;; Assuming point is at the start of a declaration (as detected by | |
4671 | ;; e.g. `c-beginning-of-decl-1'), go to the end of it. Unlike | |
4672 | ;; `c-beginning-of-decl-1', this function handles the case when a | |
4673 | ;; block is followed by identifiers in e.g. struct declarations in C | |
4674 | ;; or C++. If a proper end was found then t is returned, otherwise | |
4675 | ;; point is moved as far as possible within the current sexp and nil | |
4676 | ;; is returned. This function doesn't handle macros; use | |
4677 | ;; `c-end-of-macro' instead in those cases. | |
ce8c7486 | 4678 | (let ((start (point)) |
a66cd3ee MS |
4679 | (decl-syntax-table (if (c-major-mode-is 'c++-mode) |
4680 | c++-template-syntax-table | |
4681 | (syntax-table)))) | |
4682 | (catch 'return | |
4683 | (c-search-decl-header-end) | |
4684 | ||
4685 | (when (and c-recognize-knr-p | |
4686 | (eq (char-before) ?\;) | |
4687 | (c-in-knr-argdecl start)) | |
4688 | ;; Stopped at the ';' in a K&R argdecl section which is | |
4689 | ;; detected using the same criteria as in | |
4690 | ;; `c-beginning-of-decl-1'. Move to the following block | |
4691 | ;; start. | |
d9e94c22 | 4692 | (c-syntactic-re-search-forward "{" nil 'move t)) |
a66cd3ee MS |
4693 | |
4694 | (when (eq (char-before) ?{) | |
4695 | ;; Encountered a block in the declaration. Jump over it. | |
4696 | (condition-case nil | |
4697 | (goto-char (c-up-list-forward (point))) | |
d9e94c22 MS |
4698 | (error (goto-char (point-max)) |
4699 | (throw 'return nil))) | |
a66cd3ee MS |
4700 | (if (or (not c-opt-block-decls-with-vars-key) |
4701 | (save-excursion | |
4702 | (c-with-syntax-table decl-syntax-table | |
4703 | (let ((lim (point))) | |
4704 | (goto-char start) | |
b3cf7e18 MS |
4705 | (not (and |
4706 | ;; Check for `c-opt-block-decls-with-vars-key' | |
4707 | ;; before the first paren. | |
4708 | (c-syntactic-re-search-forward | |
d9e94c22 | 4709 | (concat "[;=\(\[{]\\|\\(" |
b3cf7e18 MS |
4710 | c-opt-block-decls-with-vars-key |
4711 | "\\)") | |
d9e94c22 | 4712 | lim t t t) |
b3cf7e18 MS |
4713 | (match-beginning 1) |
4714 | (not (eq (char-before) ?_)) | |
d9e94c22 MS |
4715 | ;; Check that the first following paren is |
4716 | ;; the block. | |
4717 | (c-syntactic-re-search-forward "[;=\(\[{]" | |
4718 | lim t t t) | |
b3cf7e18 | 4719 | (eq (char-before) ?{))))))) |
a66cd3ee MS |
4720 | ;; The declaration doesn't have any of the |
4721 | ;; `c-opt-block-decls-with-vars' keywords in the | |
4722 | ;; beginning, so it ends here at the end of the block. | |
4723 | (throw 'return t))) | |
4724 | ||
4725 | (c-with-syntax-table decl-syntax-table | |
4726 | (while (progn | |
4727 | (if (eq (char-before) ?\;) | |
4728 | (throw 'return t)) | |
d9e94c22 | 4729 | (c-syntactic-re-search-forward ";" nil 'move t)))) |
a66cd3ee | 4730 | nil))) |
ce8c7486 GM |
4731 | |
4732 | (defun c-beginning-of-member-init-list (&optional limit) | |
037558bf | 4733 | ;; Go to the beginning of a member init list (i.e. just after the |
d9e94c22 | 4734 | ;; ':') if inside one. Returns t in that case, nil otherwise. |
ce8c7486 GM |
4735 | (or limit |
4736 | (setq limit (point-min))) | |
4737 | (skip-chars-forward " \t") | |
d9e94c22 | 4738 | |
ce8c7486 GM |
4739 | (if (eq (char-after) ?,) |
4740 | (forward-char 1) | |
4741 | (c-backward-syntactic-ws limit)) | |
d9e94c22 MS |
4742 | |
4743 | (catch 'exit | |
4744 | (while (and (< limit (point)) | |
4745 | (eq (char-before) ?,)) | |
4746 | ||
4747 | ;; this will catch member inits with multiple | |
4748 | ;; line arglists | |
4749 | (forward-char -1) | |
4750 | (c-backward-syntactic-ws limit) | |
4751 | (if (eq (char-before) ?\)) | |
4752 | (unless (c-safe (c-backward-sexp 1)) | |
4753 | (throw 'exit nil))) | |
4754 | (c-backward-syntactic-ws limit) | |
4755 | ||
4756 | ;; Skip over any template arg to the class. This way with a | |
4757 | ;; syntax table is bogus but it'll have to do for now. | |
4758 | (if (and (eq (char-before) ?>) | |
4759 | (c-major-mode-is 'c++-mode)) | |
4760 | (c-with-syntax-table c++-template-syntax-table | |
4761 | (unless (c-safe (c-backward-sexp 1)) | |
4762 | (throw 'exit nil)))) | |
4763 | (c-safe (c-backward-sexp 1)) | |
4764 | (c-backward-syntactic-ws limit) | |
4765 | ||
4766 | ;; Skip backwards over a fully::qualified::name. | |
4767 | (while (and (eq (char-before) ?:) | |
4768 | (save-excursion | |
4769 | (forward-char -1) | |
4770 | (eq (char-before) ?:))) | |
4771 | (backward-char 2) | |
4772 | (c-safe (c-backward-sexp 1))) | |
4773 | ||
4774 | ;; If we've stepped over a number then this is a bitfield. | |
4775 | (when (and c-opt-bitfield-key | |
4776 | (looking-at "[0-9]")) | |
4777 | (throw 'exit nil)) | |
4778 | ||
4779 | ;; now continue checking | |
4780 | (c-backward-syntactic-ws limit)) | |
4781 | ||
4782 | (and (< limit (point)) | |
4783 | (eq (char-before) ?:)))) | |
ce8c7486 | 4784 | |
a66cd3ee | 4785 | (defun c-search-uplist-for-classkey (paren-state) |
785eecbb | 4786 | ;; search for the containing class, returning a 2 element vector if |
0ec8351b BW |
4787 | ;; found. aref 0 contains the bufpos of the boi of the class key |
4788 | ;; line, and aref 1 contains the bufpos of the open brace. | |
a66cd3ee MS |
4789 | (if (null paren-state) |
4790 | ;; no paren-state means we cannot be inside a class | |
785eecbb | 4791 | nil |
a66cd3ee | 4792 | (let ((carcache (car paren-state)) |
785eecbb RS |
4793 | search-start search-end) |
4794 | (if (consp carcache) | |
4795 | ;; a cons cell in the first element means that there is some | |
4796 | ;; balanced sexp before the current bufpos. this we can | |
4797 | ;; ignore. the nth 1 and nth 2 elements define for us the | |
4798 | ;; search boundaries | |
a66cd3ee MS |
4799 | (setq search-start (nth 2 paren-state) |
4800 | search-end (nth 1 paren-state)) | |
785eecbb RS |
4801 | ;; if the car was not a cons cell then nth 0 and nth 1 define |
4802 | ;; for us the search boundaries | |
a66cd3ee MS |
4803 | (setq search-start (nth 1 paren-state) |
4804 | search-end (nth 0 paren-state))) | |
785eecbb RS |
4805 | ;; if search-end is nil, or if the search-end character isn't an |
4806 | ;; open brace, we are definitely not in a class | |
d9e94c22 MS |
4807 | (if (or (not search-end) |
4808 | (< search-end (point-min)) | |
4809 | (not (eq (char-after search-end) ?{))) | |
4810 | nil | |
785eecbb RS |
4811 | ;; now, we need to look more closely at search-start. if |
4812 | ;; search-start is nil, then our start boundary is really | |
4813 | ;; point-min. | |
4814 | (if (not search-start) | |
4815 | (setq search-start (point-min)) | |
4816 | ;; if search-start is a cons cell, then we can start | |
4817 | ;; searching from the end of the balanced sexp just ahead of | |
4818 | ;; us | |
4819 | (if (consp search-start) | |
d9e94c22 MS |
4820 | (setq search-start (cdr search-start)) |
4821 | ;; Otherwise we start searching within the surrounding paren sexp. | |
4822 | (setq search-start (1+ search-start)))) | |
785eecbb RS |
4823 | ;; now we can do a quick regexp search from search-start to |
4824 | ;; search-end and see if we can find a class key. watch for | |
4825 | ;; class like strings in literals | |
4826 | (save-excursion | |
4827 | (save-restriction | |
4828 | (goto-char search-start) | |
a66cd3ee | 4829 | (let (foundp class match-end) |
785eecbb RS |
4830 | (while (and (not foundp) |
4831 | (progn | |
a66cd3ee | 4832 | (c-forward-syntactic-ws search-end) |
785eecbb | 4833 | (> search-end (point))) |
d9e94c22 MS |
4834 | ;; Add one to the search limit, to allow |
4835 | ;; matching of the "{" in the regexp. | |
4836 | (re-search-forward c-decl-block-key | |
4837 | (1+ search-end) | |
4838 | t)) | |
785eecbb RS |
4839 | (setq class (match-beginning 0) |
4840 | match-end (match-end 0)) | |
a66cd3ee | 4841 | (goto-char class) |
785eecbb | 4842 | (if (c-in-literal search-start) |
a66cd3ee MS |
4843 | (goto-char match-end) ; its in a comment or string, ignore |
4844 | (c-skip-ws-forward) | |
785eecbb RS |
4845 | (setq foundp (vector (c-point 'boi) search-end)) |
4846 | (cond | |
4847 | ;; check for embedded keywords | |
4848 | ((let ((char (char-after (1- class)))) | |
4849 | (and char | |
4850 | (memq (char-syntax char) '(?w ?_)))) | |
4851 | (goto-char match-end) | |
4852 | (setq foundp nil)) | |
4853 | ;; make sure we're really looking at the start of a | |
a66cd3ee MS |
4854 | ;; class definition, and not an ObjC method. |
4855 | ((and c-opt-method-key | |
4856 | (re-search-forward c-opt-method-key search-end t) | |
0ec8351b | 4857 | (not (c-in-literal class))) |
785eecbb | 4858 | (setq foundp nil)) |
0ec8351b | 4859 | ;; Check if this is an anonymous inner class. |
a66cd3ee MS |
4860 | ((and c-opt-inexpr-class-key |
4861 | (looking-at c-opt-inexpr-class-key)) | |
d9e94c22 | 4862 | (while (and (zerop (c-forward-token-2 1 t)) |
0ec8351b BW |
4863 | (looking-at "(\\|\\w\\|\\s_\\|\\."))) |
4864 | (if (eq (point) search-end) | |
4865 | ;; We're done. Just trap this case in the cond. | |
4866 | nil | |
4867 | ;; False alarm; all conditions aren't satisfied. | |
4868 | (setq foundp nil))) | |
785eecbb RS |
4869 | ;; Its impossible to define a regexp for this, and |
4870 | ;; nearly so to do it programmatically. | |
4871 | ;; | |
4872 | ;; ; picks up forward decls | |
4873 | ;; = picks up init lists | |
4874 | ;; ) picks up return types | |
4875 | ;; > picks up templates, but remember that we can | |
4876 | ;; inherit from templates! | |
4877 | ((let ((skipchars "^;=)")) | |
4878 | ;; try to see if we found the `class' keyword | |
4879 | ;; inside a template arg list | |
4880 | (save-excursion | |
4881 | (skip-chars-backward "^<>" search-start) | |
4882 | (if (eq (char-before) ?<) | |
4883 | (setq skipchars (concat skipchars ">")))) | |
0ec8351b BW |
4884 | (while (progn |
4885 | (skip-chars-forward skipchars search-end) | |
4886 | (c-in-literal class)) | |
4887 | (forward-char)) | |
785eecbb RS |
4888 | (/= (point) search-end)) |
4889 | (setq foundp nil)) | |
4890 | ))) | |
4891 | foundp)) | |
4892 | ))))) | |
4893 | ||
a66cd3ee | 4894 | (defun c-inside-bracelist-p (containing-sexp paren-state) |
785eecbb RS |
4895 | ;; return the buffer position of the beginning of the brace list |
4896 | ;; statement if we're inside a brace list, otherwise return nil. | |
4897 | ;; CONTAINING-SEXP is the buffer pos of the innermost containing | |
130c507e GM |
4898 | ;; paren. BRACE-STATE is the remainder of the state of enclosing |
4899 | ;; braces | |
785eecbb RS |
4900 | ;; |
4901 | ;; N.B.: This algorithm can potentially get confused by cpp macros | |
4902 | ;; places in inconvenient locations. Its a trade-off we make for | |
4903 | ;; speed. | |
4904 | (or | |
d9e94c22 | 4905 | ;; This will pick up brace list declarations. |
b2acd789 RS |
4906 | (c-safe |
4907 | (save-excursion | |
4908 | (goto-char containing-sexp) | |
0ec8351b | 4909 | (c-forward-sexp -1) |
b2acd789 | 4910 | (let (bracepos) |
d9e94c22 | 4911 | (if (and (or (looking-at c-brace-list-key) |
0ec8351b | 4912 | (progn (c-forward-sexp -1) |
d9e94c22 | 4913 | (looking-at c-brace-list-key))) |
a66cd3ee | 4914 | (setq bracepos (c-down-list-forward (point))) |
b2acd789 RS |
4915 | (not (c-crosses-statement-barrier-p (point) |
4916 | (- bracepos 2)))) | |
4917 | (point))))) | |
785eecbb RS |
4918 | ;; this will pick up array/aggregate init lists, even if they are nested. |
4919 | (save-excursion | |
0ec8351b BW |
4920 | (let ((class-key |
4921 | ;; Pike can have class definitions anywhere, so we must | |
4922 | ;; check for the class key here. | |
4923 | (and (c-major-mode-is 'pike-mode) | |
a66cd3ee MS |
4924 | c-decl-block-key)) |
4925 | bufpos braceassignp lim next-containing) | |
785eecbb RS |
4926 | (while (and (not bufpos) |
4927 | containing-sexp) | |
a66cd3ee MS |
4928 | (when paren-state |
4929 | (if (consp (car paren-state)) | |
4930 | (setq lim (cdr (car paren-state)) | |
4931 | paren-state (cdr paren-state)) | |
4932 | (setq lim (car paren-state))) | |
4933 | (when paren-state | |
4934 | (setq next-containing (car paren-state) | |
4935 | paren-state (cdr paren-state)))) | |
785eecbb | 4936 | (goto-char containing-sexp) |
a66cd3ee MS |
4937 | (if (c-looking-at-inexpr-block next-containing next-containing) |
4938 | ;; We're in an in-expression block of some kind. Do not | |
4939 | ;; check nesting. We deliberately set the limit to the | |
4940 | ;; containing sexp, so that c-looking-at-inexpr-block | |
4941 | ;; doesn't check for an identifier before it. | |
0ec8351b BW |
4942 | (setq containing-sexp nil) |
4943 | ;; see if the open brace is preceded by = or [...] in | |
4944 | ;; this statement, but watch out for operator= | |
a66cd3ee | 4945 | (setq braceassignp 'dontknow) |
d9e94c22 | 4946 | (c-backward-token-2 1 t lim) |
6393fef2 | 4947 | ;; Checks to do only on the first sexp before the brace. |
d9e94c22 | 4948 | (when (and c-opt-inexpr-brace-list-key |
6393fef2 RS |
4949 | (eq (char-after) ?\[)) |
4950 | ;; In Java, an initialization brace list may follow | |
4951 | ;; directly after "new Foo[]", so check for a "new" | |
4952 | ;; earlier. | |
4953 | (while (eq braceassignp 'dontknow) | |
4954 | (setq braceassignp | |
d9e94c22 MS |
4955 | (cond ((/= (c-backward-token-2 1 t lim) 0) nil) |
4956 | ((looking-at c-opt-inexpr-brace-list-key) t) | |
6393fef2 RS |
4957 | ((looking-at "\\sw\\|\\s_\\|[.[]") |
4958 | ;; Carry on looking if this is an | |
4959 | ;; identifier (may contain "." in Java) | |
4960 | ;; or another "[]" sexp. | |
4961 | 'dontknow) | |
4962 | (t nil))))) | |
4963 | ;; Checks to do on all sexps before the brace, up to the | |
4964 | ;; beginning of the statement. | |
4965 | (while (eq braceassignp 'dontknow) | |
0ec8351b BW |
4966 | (cond ((eq (char-after) ?\;) |
4967 | (setq braceassignp nil)) | |
4968 | ((and class-key | |
4969 | (looking-at class-key)) | |
4970 | (setq braceassignp nil)) | |
4971 | ((eq (char-after) ?=) | |
4972 | ;; We've seen a =, but must check earlier tokens so | |
4973 | ;; that it isn't something that should be ignored. | |
4974 | (setq braceassignp 'maybe) | |
4975 | (while (and (eq braceassignp 'maybe) | |
d9e94c22 | 4976 | (zerop (c-backward-token-2 1 t lim))) |
0ec8351b BW |
4977 | (setq braceassignp |
4978 | (cond | |
4979 | ;; Check for operator = | |
a66cd3ee | 4980 | ((looking-at "operator\\>[^_]") nil) |
130c507e GM |
4981 | ;; Check for `<opchar>= in Pike. |
4982 | ((and (c-major-mode-is 'pike-mode) | |
4983 | (or (eq (char-after) ?`) | |
4984 | ;; Special case for Pikes | |
4985 | ;; `[]=, since '[' is not in | |
4986 | ;; the punctuation class. | |
4987 | (and (eq (char-after) ?\[) | |
4988 | (eq (char-before) ?`)))) | |
4989 | nil) | |
0ec8351b BW |
4990 | ((looking-at "\\s.") 'maybe) |
4991 | ;; make sure we're not in a C++ template | |
4992 | ;; argument assignment | |
a66cd3ee MS |
4993 | ((and |
4994 | (c-major-mode-is 'c++-mode) | |
4995 | (save-excursion | |
4996 | (let ((here (point)) | |
4997 | (pos< (progn | |
4998 | (skip-chars-backward "^<>") | |
4999 | (point)))) | |
5000 | (and (eq (char-before) ?<) | |
5001 | (not (c-crosses-statement-barrier-p | |
5002 | pos< here)) | |
5003 | (not (c-in-literal)) | |
5004 | )))) | |
0ec8351b | 5005 | nil) |
6393fef2 RS |
5006 | (t t)))))) |
5007 | (if (and (eq braceassignp 'dontknow) | |
d9e94c22 | 5008 | (/= (c-backward-token-2 1 t lim) 0)) |
6393fef2 RS |
5009 | (setq braceassignp nil))) |
5010 | (if (not braceassignp) | |
0ec8351b BW |
5011 | (if (eq (char-after) ?\;) |
5012 | ;; Brace lists can't contain a semicolon, so we're done. | |
5013 | (setq containing-sexp nil) | |
a66cd3ee MS |
5014 | ;; Go up one level. |
5015 | (setq containing-sexp next-containing | |
5016 | lim nil | |
5017 | next-containing nil)) | |
0ec8351b BW |
5018 | ;; we've hit the beginning of the aggregate list |
5019 | (c-beginning-of-statement-1 | |
a66cd3ee | 5020 | (c-most-enclosing-brace paren-state)) |
0ec8351b | 5021 | (setq bufpos (point)))) |
a66cd3ee | 5022 | ) |
785eecbb RS |
5023 | bufpos)) |
5024 | )) | |
5025 | ||
0ec8351b BW |
5026 | (defun c-looking-at-special-brace-list (&optional lim) |
5027 | Content-type: text/html