Commit | Line | Data |
---|---|---|
785eecbb RS |
1 | ;;; cc-engine.el --- core syntax guessing engine for CC mode |
2 | ||
130c507e | 3 | ;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. |
785eecbb | 4 | |
ce8c7486 GM |
5 | ;; Authors: 2000- Martin Stjernholm |
6 | ;; 1998-1999 Barry A. Warsaw and Martin Stjernholm | |
0ec8351b | 7 | ;; 1992-1997 Barry A. Warsaw |
785eecbb RS |
8 | ;; 1987 Dave Detlefs and Stewart Clamen |
9 | ;; 1985 Richard M. Stallman | |
0ec8351b | 10 | ;; Maintainer: bug-cc-mode@gnu.org |
785eecbb | 11 | ;; Created: 22-Apr-1997 (split from cc-mode.el) |
6430c434 | 12 | ;; Version: See cc-mode.el |
785eecbb RS |
13 | ;; Keywords: c languages oop |
14 | ||
15 | ;; This file is part of GNU Emacs. | |
16 | ||
17 | ;; GNU Emacs is free software; you can redistribute it and/or modify | |
18 | ;; it under the terms of the GNU General Public License as published by | |
19 | ;; the Free Software Foundation; either version 2, or (at your option) | |
20 | ;; any later version. | |
21 | ||
22 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | ;; GNU General Public License for more details. | |
26 | ||
27 | ;; You should have received a copy of the GNU General Public License | |
a66cd3ee | 28 | ;; along with GNU Emacs; see the file COPYING. If not, write to |
130c507e | 29 | ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
785eecbb RS |
30 | ;; Boston, MA 02111-1307, USA. |
31 | ||
3afbc435 PJ |
32 | ;;; Commentary: |
33 | ||
a66cd3ee MS |
34 | ;; The functions which have docstring documentation can be considered |
35 | ;; part of an API which other packages can use in CC Mode buffers. | |
36 | ;; Otoh, undocumented functions and functions with the documentation | |
37 | ;; in comments are considered purely internal and can change semantics | |
38 | ;; or even disappear in the future. | |
39 | ;; | |
40 | ;; (This policy applies to CC Mode as a whole, not just this file. It | |
41 | ;; probably also applies to many other Emacs packages, but here it's | |
42 | ;; clearly spelled out.) | |
43 | ||
3afbc435 PJ |
44 | ;;; Code: |
45 | ||
0ec8351b | 46 | (eval-when-compile |
51f606de | 47 | (let ((load-path |
130c507e GM |
48 | (if (and (boundp 'byte-compile-dest-file) |
49 | (stringp byte-compile-dest-file)) | |
50 | (cons (file-name-directory byte-compile-dest-file) load-path) | |
51f606de | 51 | load-path))) |
130c507e GM |
52 | (require 'cc-bytecomp))) |
53 | ||
54 | (cc-require 'cc-defs) | |
55 | (cc-require 'cc-vars) | |
56 | (cc-require 'cc-langs) | |
57 | ||
58 | ;; Silence the compiler. | |
59 | (cc-bytecomp-defun buffer-syntactic-context) ; XEmacs | |
0ec8351b | 60 | |
51f606de | 61 | \f |
a66cd3ee MS |
62 | (defun c-calculate-state (arg prevstate) |
63 | ;; Calculate the new state of PREVSTATE, t or nil, based on arg. If | |
64 | ;; arg is nil or zero, toggle the state. If arg is negative, turn | |
65 | ;; the state off, and if arg is positive, turn the state on | |
66 | (if (or (not arg) | |
67 | (zerop (setq arg (prefix-numeric-value arg)))) | |
68 | (not prevstate) | |
69 | (> arg 0))) | |
70 | ||
71 | \f | |
130c507e | 72 | (defvar c-in-literal-cache t) |
a66cd3ee | 73 | (defvar c-parsing-error nil) |
130c507e | 74 | |
64001211 RS |
75 | ;; KLUDGE ALERT: c-maybe-labelp is used to pass information between |
76 | ;; c-crosses-statement-barrier-p and c-beginning-of-statement-1. A | |
77 | ;; better way should be implemented, but this will at least shut up | |
78 | ;; the byte compiler. | |
79 | (defvar c-maybe-labelp nil) | |
80 | ||
a66cd3ee MS |
81 | ;; Macros used internally in c-beginning-of-statement-1 for the |
82 | ;; automaton actions. | |
83 | (defmacro c-bos-push-state () | |
84 | '(setq stack (cons (cons state saved-pos) | |
85 | stack))) | |
86 | (defmacro c-bos-pop-state (&optional do-if-done) | |
87 | `(if (setq state (car (car stack)) | |
88 | saved-pos (cdr (car stack)) | |
89 | stack (cdr stack)) | |
90 | t | |
91 | ,do-if-done | |
92 | (throw 'loop nil))) | |
93 | (defmacro c-bos-pop-state-and-retry () | |
94 | '(throw 'loop (setq state (car (car stack)) | |
95 | saved-pos (cdr (car stack)) | |
96 | ;; Throw nil if stack is empty, else throw non-nil. | |
97 | stack (cdr stack)))) | |
98 | (defmacro c-bos-save-pos () | |
99 | '(setq saved-pos (vector pos tok ptok pptok))) | |
100 | (defmacro c-bos-restore-pos () | |
101 | '(unless (eq (elt saved-pos 0) start) | |
102 | (setq pos (elt saved-pos 0) | |
103 | tok (elt saved-pos 1) | |
104 | ptok (elt saved-pos 2) | |
105 | pptok (elt saved-pos 3)) | |
106 | (goto-char pos) | |
107 | (setq sym nil))) | |
108 | (defmacro c-bos-save-error-info (missing got) | |
109 | `(setq saved-pos (vector pos ,missing ,got))) | |
110 | (defmacro c-bos-report-error () | |
111 | '(unless noerror | |
112 | (setq c-parsing-error | |
113 | (format "No matching `%s' found for `%s' on line %d" | |
114 | (elt saved-pos 1) | |
115 | (elt saved-pos 2) | |
116 | (1+ (count-lines (point-min) | |
117 | (c-point 'bol (elt saved-pos 0)))))))) | |
118 | ||
119 | (defun c-beginning-of-statement-1 (&optional lim ignore-labels | |
120 | noerror comma-delim) | |
121 | "Move to the start of the current statement or declaration, or to | |
122 | the previous one if already at the beginning of one. Only | |
123 | statements/declarations on the same level are considered, i.e. don't | |
124 | move into or out of sexps (not even normal expression parentheses). | |
125 | ||
126 | Stop at statement continuations like \"else\", \"catch\", \"finally\" | |
127 | and the \"while\" in \"do ... while\" if the start point is within | |
128 | them. If starting at such a continuation, move to the corresponding | |
129 | statement start. If at the beginning of a statement, move to the | |
130 | closest containing statement if there is any. This might also stop at | |
131 | a continuation clause. | |
132 | ||
133 | Labels are treated as separate statements if IGNORE-LABELS is non-nil. | |
134 | The function is not overly intelligent in telling labels from other | |
135 | uses of colons; if used outside a statement context it might trip up | |
136 | on e.g. inherit colons, so IGNORE-LABELS should be used then. There | |
137 | should be no such mistakes in a statement context, however. | |
138 | ||
139 | Macros are ignored unless point is within one, in which case the | |
140 | content of the macro is treated as normal code. Aside from any normal | |
141 | statement starts found in it, stop at the first token of the content | |
142 | in the macro, i.e. the expression of an \"#if\" or the start of the | |
143 | definition in a \"#define\". Also stop at start of macros before | |
144 | leaving them. | |
145 | ||
146 | Return 'label if stopped at a label, 'same if stopped at the beginning | |
147 | of the current statement, 'up if stepped to a containing statement, | |
148 | 'previous if stepped to a preceding statement, 'beginning if stepped | |
149 | from a statement continuation clause to its start clause, or 'macro if | |
150 | stepped to a macro start. Note that 'same and not 'label is returned | |
151 | if stopped at the same label without crossing the colon character. | |
152 | ||
153 | LIM may be given to limit the search. If the search hits the limit, | |
154 | point will be left at the closest following token, or at the start | |
155 | position if that is less ('same is returned in this case). | |
156 | ||
157 | NOERROR turns off error logging to `c-parsing-error'. | |
158 | ||
159 | Normally only ';' is considered to delimit statements, but if | |
160 | COMMA-DELIM is non-nil then ',' is treated likewise." | |
161 | ||
162 | ;; The bulk of this function is a pushdown automaton that looks at | |
163 | ;; statement boundaries and the tokens in c-opt-block-stmt-key. | |
164 | ;; | |
165 | ;; Note: The position of a boundary is the following token. | |
166 | ;; | |
167 | ;; Begin with current token, stop when stack is empty and the | |
168 | ;; position has been moved. | |
169 | ;; | |
170 | ;; Common state: | |
171 | ;; "else": Push state, goto state `else': | |
172 | ;; boundary: Goto state `else-boundary': | |
173 | ;; "if": Pop state. | |
174 | ;; boundary: Error, pop state. | |
175 | ;; other: See common state. | |
176 | ;; other: Error, pop state, retry token. | |
177 | ;; "while": Push state, goto state `while': | |
178 | ;; boundary: Save position, goto state `while-boundary': | |
179 | ;; "do": Pop state. | |
180 | ;; boundary: Restore position if it's not at start, pop state. | |
181 | ;; other: See common state. | |
182 | ;; other: Pop state, retry token. | |
183 | ;; "catch" or "finally": Push state, goto state `catch': | |
184 | ;; boundary: Goto state `catch-boundary': | |
185 | ;; "try": Pop state. | |
186 | ;; "catch": Goto state `catch'. | |
187 | ;; boundary: Error, pop state. | |
188 | ;; other: See common state. | |
189 | ;; other: Error, pop state, retry token. | |
190 | ;; other: Do nothing special. | |
191 | ;; | |
192 | ;; In addition to the above there is some special handling of labels | |
193 | ;; and macros. | |
194 | ||
195 | (let ((case-fold-search nil) | |
196 | (start (point)) | |
197 | macro-start | |
198 | (delims (if comma-delim '(?\; ?,) '(?\;))) | |
199 | (c-stmt-delim-chars (if comma-delim | |
200 | c-stmt-delim-chars-with-comma | |
201 | c-stmt-delim-chars)) | |
202 | pos ; Current position. | |
203 | boundary-pos ; Position of last boundary. | |
204 | after-labels-pos ; Value of tok after first found colon. | |
205 | last-label-pos ; Value of tok after last found colon. | |
206 | sym ; Current symbol in the alphabet. | |
207 | state ; Current state in the automaton. | |
208 | saved-pos ; Current saved positions. | |
209 | stack ; Stack of conses (state . saved-pos). | |
210 | (cond-key (or c-opt-block-stmt-key | |
211 | "\\<\\>")) ; Matches nothing. | |
212 | (ret 'same) | |
213 | tok ptok pptok ; Pos of last three sexps or bounds. | |
214 | c-in-literal-cache c-maybe-labelp saved) | |
215 | ||
216 | (save-restriction | |
217 | (if lim (narrow-to-region lim (point-max))) | |
218 | ||
219 | (if (save-excursion | |
220 | (and (c-beginning-of-macro) | |
221 | (/= (point) start))) | |
222 | (setq macro-start (point))) | |
223 | ||
224 | ;; Try to skip over unary operator characters, to register | |
225 | ;; that we've moved. | |
226 | (while (progn | |
227 | (setq pos (point)) | |
228 | (c-backward-syntactic-ws) | |
229 | (/= (skip-chars-backward "-+!*&~@`#") 0))) | |
230 | ||
231 | ;; First check for bare semicolon. Later on we ignore the | |
232 | ;; boundaries for statements that doesn't contain any sexp. | |
233 | ;; The only thing that is affected is that the error checking | |
234 | ;; is a little less strict, and we really don't bother. | |
235 | (if (and (memq (char-before) delims) | |
236 | (progn (forward-char -1) | |
237 | (setq saved (point)) | |
238 | (c-backward-syntactic-ws) | |
239 | (or (memq (char-before) delims) | |
240 | (memq (char-before) '(?: nil)) | |
241 | (eq (char-syntax (char-before)) ?\()))) | |
242 | (setq ret 'previous | |
243 | pos saved) | |
244 | ||
245 | ;; Begin at start and not pos to detect macros if we stand | |
246 | ;; directly after the #. | |
247 | (goto-char start) | |
248 | (if (looking-at "\\<\\|\\W") | |
249 | ;; Record this as the first token if not starting inside it. | |
250 | (setq tok start)) | |
251 | ||
252 | (while | |
253 | (catch 'loop ;; Throw nil to break, non-nil to continue. | |
254 | (cond | |
255 | ;; Check for macro start. | |
256 | ((save-excursion | |
257 | (and macro-start | |
258 | (looking-at "[ \t]*[a-zA-Z0-9!]") | |
259 | (progn (skip-chars-backward " \t") | |
260 | (eq (char-before) ?#)) | |
261 | (progn (setq saved (1- (point))) | |
262 | (beginning-of-line) | |
263 | (not (eq (char-before (1- (point))) ?\\))) | |
264 | (progn (skip-chars-forward " \t") | |
265 | (eq (point) saved)))) | |
266 | (goto-char saved) | |
267 | (if (and (c-forward-to-cpp-define-body) | |
268 | (progn (c-forward-syntactic-ws start) | |
269 | (< (point) start))) | |
270 | ;; Stop at the first token in the content of the macro. | |
271 | (setq pos (point) | |
272 | ignore-labels t) ; Avoid the label check on exit. | |
273 | (setq pos saved | |
274 | ret 'macro | |
275 | ignore-labels t)) | |
276 | (throw 'loop nil)) | |
277 | ||
278 | ;; Do a round through the automaton if we found a | |
279 | ;; boundary or if looking at a statement keyword. | |
280 | ((or sym | |
281 | (and (looking-at cond-key) | |
282 | (setq sym (intern (match-string 1))))) | |
283 | ||
284 | (when (and (< pos start) (null stack)) | |
285 | (throw 'loop nil)) | |
286 | ||
287 | ;; The state handling. Continue in the common state for | |
288 | ;; unhandled cases. | |
289 | (or (cond | |
290 | ((eq state 'else) | |
291 | (if (eq sym 'boundary) | |
292 | (setq state 'else-boundary) | |
293 | (c-bos-report-error) | |
294 | (c-bos-pop-state-and-retry))) | |
295 | ||
296 | ((eq state 'else-boundary) | |
297 | (cond ((eq sym 'if) | |
298 | (c-bos-pop-state (setq ret 'beginning))) | |
299 | ((eq sym 'boundary) | |
300 | (c-bos-report-error) | |
301 | (c-bos-pop-state)))) | |
302 | ||
303 | ((eq state 'while) | |
304 | (if (and (eq sym 'boundary) | |
305 | ;; Since this can cause backtracking we do a | |
306 | ;; little more careful analysis to avoid it: | |
307 | ;; If there's a label in front of the while | |
308 | ;; it can't be part of a do-while. | |
309 | (not after-labels-pos)) | |
310 | (progn (c-bos-save-pos) | |
311 | (setq state 'while-boundary)) | |
312 | (c-bos-pop-state-and-retry))) | |
313 | ||
314 | ((eq state 'while-boundary) | |
315 | (cond ((eq sym 'do) | |
316 | (c-bos-pop-state (setq ret 'beginning))) | |
317 | ((eq sym 'boundary) | |
318 | (c-bos-restore-pos) | |
319 | (c-bos-pop-state)))) | |
320 | ||
321 | ((eq state 'catch) | |
322 | (if (eq sym 'boundary) | |
323 | (setq state 'catch-boundary) | |
324 | (c-bos-report-error) | |
325 | (c-bos-pop-state-and-retry))) | |
326 | ||
327 | ((eq state 'catch-boundary) | |
328 | (cond | |
329 | ((eq sym 'try) | |
330 | (c-bos-pop-state (setq ret 'beginning))) | |
331 | ((eq sym 'catch) | |
332 | (setq state 'catch)) | |
333 | ((eq sym 'boundary) | |
334 | (c-bos-report-error) | |
335 | (c-bos-pop-state))))) | |
336 | ||
337 | ;; This is state common. | |
338 | (cond ((eq sym 'boundary) | |
339 | (if (< pos start) | |
340 | (c-bos-pop-state) | |
341 | (c-bos-push-state))) | |
342 | ((eq sym 'else) | |
343 | (c-bos-push-state) | |
344 | (c-bos-save-error-info 'if 'else) | |
345 | (setq state 'else)) | |
346 | ((eq sym 'while) | |
347 | (when (or (not pptok) | |
348 | (memq (char-after pptok) delims)) | |
349 | ;; Since this can cause backtracking we do a | |
350 | ;; little more careful analysis to avoid it: If | |
351 | ;; the while isn't followed by a semicolon it | |
352 | ;; can't be a do-while. | |
353 | (c-bos-push-state) | |
354 | (setq state 'while))) | |
355 | ((memq sym '(catch finally)) | |
356 | (c-bos-push-state) | |
357 | (c-bos-save-error-info 'try sym) | |
358 | (setq state 'catch)))) | |
359 | ||
360 | (when c-maybe-labelp | |
361 | ;; We're either past a statement boundary or at the | |
362 | ;; start of a statement, so throw away any label data | |
363 | ;; for the previous one. | |
364 | (setq after-labels-pos nil | |
365 | last-label-pos nil | |
366 | c-maybe-labelp nil)))) | |
367 | ||
368 | ;; Step to next sexp, but not if we crossed a boundary, since | |
369 | ;; that doesn't consume an sexp. | |
370 | (if (eq sym 'boundary) | |
371 | (setq ret 'previous) | |
372 | (while | |
041ec7f6 | 373 | (progn |
a66cd3ee MS |
374 | (or (c-safe (goto-char (scan-sexps (point) -1)) t) |
375 | (throw 'loop nil)) | |
376 | (cond ((looking-at "\\\\$") | |
377 | ;; Step again if we hit a line continuation. | |
378 | t) | |
379 | (macro-start | |
380 | ;; If we started inside a macro then this | |
381 | ;; sexp is always interesting. | |
382 | nil) | |
383 | (t | |
384 | ;; Otherwise check that we didn't step | |
385 | ;; into a macro from the end. | |
386 | (let ((macro-start | |
387 | (save-excursion | |
388 | (and (c-beginning-of-macro) | |
389 | (point))))) | |
390 | (when macro-start | |
391 | (goto-char macro-start) | |
392 | t)))))) | |
393 | ||
394 | ;; Check for statement boundary. | |
395 | (when (save-excursion | |
396 | (if (if (eq (char-after) ?{) | |
397 | (c-looking-at-inexpr-block lim nil) | |
398 | (eq (char-syntax (char-after)) ?\()) | |
399 | ;; Need to move over parens and | |
400 | ;; in-expression blocks to get a good start | |
401 | ;; position for the boundary check. | |
402 | (c-forward-sexp 1)) | |
403 | (setq boundary-pos (c-crosses-statement-barrier-p | |
404 | (point) pos))) | |
405 | (setq pptok ptok | |
406 | ptok tok | |
407 | tok boundary-pos | |
408 | sym 'boundary) | |
409 | (throw 'loop t))) | |
410 | ||
411 | (when (and (numberp c-maybe-labelp) (not ignore-labels)) | |
412 | ;; c-crosses-statement-barrier-p has found a colon, so | |
413 | ;; we might be in a label now. | |
414 | (if (not after-labels-pos) | |
415 | (setq after-labels-pos tok)) | |
416 | (setq last-label-pos tok | |
417 | c-maybe-labelp t)) | |
418 | ||
419 | ;; ObjC method def? | |
420 | (when (and c-opt-method-key | |
421 | (setq saved (c-in-method-def-p))) | |
422 | (setq pos saved | |
423 | ignore-labels t) ; Avoid the label check on exit. | |
424 | (throw 'loop nil)) | |
425 | ||
426 | (setq sym nil | |
427 | pptok ptok | |
428 | ptok tok | |
429 | tok (point) | |
430 | pos tok))) ; Not nil. | |
431 | ||
432 | ;; If the stack isn't empty there might be errors to report. | |
433 | (while stack | |
434 | (if (and (vectorp saved-pos) (eq (length saved-pos) 3)) | |
435 | (c-bos-report-error)) | |
436 | (setq saved-pos (cdr (car stack)) | |
437 | stack (cdr stack))) | |
438 | ||
439 | (when (and (eq ret 'same) | |
440 | (not (memq sym '(boundary ignore nil)))) | |
441 | ;; Need to investigate closer whether we've crossed | |
442 | ;; between a substatement and its containing statement. | |
443 | (if (setq saved (if (looking-at c-block-stmt-1-key) | |
444 | ptok | |
445 | pptok)) | |
446 | (cond ((> start saved) (setq pos saved)) | |
447 | ((= start saved) (setq ret 'up))))) | |
448 | ||
449 | (when (and c-maybe-labelp (not ignore-labels) after-labels-pos) | |
450 | ;; We're in a label. Maybe we should step to the statement | |
451 | ;; after it. | |
452 | (if (< after-labels-pos start) | |
453 | (setq pos after-labels-pos) | |
454 | (setq ret 'label) | |
455 | (if (< last-label-pos start) | |
456 | (setq pos last-label-pos))))) | |
457 | ||
458 | ;; Skip over the unary operators that can start the statement. | |
459 | (goto-char pos) | |
460 | (while (progn | |
461 | (c-backward-syntactic-ws) | |
462 | (/= (skip-chars-backward "-+!*&~@`#") 0)) | |
463 | (setq pos (point))) | |
464 | (goto-char pos) | |
465 | ret))) | |
785eecbb | 466 | |
785eecbb | 467 | (defun c-crosses-statement-barrier-p (from to) |
a66cd3ee MS |
468 | "Return non-nil if buffer positions FROM to TO cross one or more |
469 | statement or declaration boundaries. The returned value is actually | |
470 | the position of the earliest boundary char. | |
471 | ||
472 | The variable `c-maybe-labelp' is set to the position of the first `:' that | |
473 | might start a label (i.e. not part of `::' and not preceded by `?'). If a | |
474 | single `?' is found, then `c-maybe-labelp' is cleared." | |
475 | (let ((skip-chars c-stmt-delim-chars) | |
476 | lit-range) | |
477 | (save-excursion | |
478 | (catch 'done | |
479 | (goto-char from) | |
480 | (while (progn (skip-chars-forward skip-chars to) | |
785eecbb | 481 | (< (point) to)) |
a66cd3ee MS |
482 | (if (setq lit-range (c-literal-limits from)) |
483 | (goto-char (setq from (cdr lit-range))) | |
484 | (cond ((eq (char-after) ?:) | |
485 | (forward-char) | |
486 | (if (and (eq (char-after) ?:) | |
487 | (< (point) to)) | |
488 | ;; Ignore scope operators. | |
489 | (forward-char) | |
490 | (setq c-maybe-labelp (1- (point))))) | |
491 | ((eq (char-after) ??) | |
492 | ;; A question mark. Can't be a label, so stop | |
493 | ;; looking for more : and ?. | |
494 | (setq c-maybe-labelp nil | |
495 | skip-chars (substring c-stmt-delim-chars 0 -2))) | |
496 | (t (throw 'done (point)))))) | |
497 | nil)))) | |
785eecbb RS |
498 | |
499 | \f | |
a66cd3ee MS |
500 | ;; This is a dynamically bound cache used together with |
501 | ;; c-query-macro-start and c-query-and-set-macro-start. It only works | |
502 | ;; as long as point doesn't cross a macro boundary. | |
503 | (defvar c-macro-start 'unknown) | |
504 | ||
505 | (defsubst c-query-and-set-macro-start () | |
506 | (if (symbolp c-macro-start) | |
507 | (setq c-macro-start (save-excursion | |
508 | (and (c-beginning-of-macro) | |
509 | (point)))) | |
510 | c-macro-start)) | |
511 | ||
512 | (defsubst c-query-macro-start () | |
513 | (if (symbolp c-macro-start) | |
514 | (save-excursion | |
515 | (and (c-beginning-of-macro) | |
516 | (point))) | |
517 | c-macro-start)) | |
518 | ||
130c507e | 519 | (defun c-beginning-of-macro (&optional lim) |
a66cd3ee MS |
520 | "Go to the beginning of a cpp macro definition. |
521 | Leave point at the beginning of the macro and return t if in a cpp | |
522 | macro definition, otherwise return nil and leave point unchanged." | |
130c507e | 523 | (let ((here (point))) |
a66cd3ee MS |
524 | (save-restriction |
525 | (if lim (narrow-to-region lim (point-max))) | |
526 | (beginning-of-line) | |
527 | (while (eq (char-before (1- (point))) ?\\) | |
528 | (forward-line -1)) | |
529 | (back-to-indentation) | |
530 | (if (and (<= (point) here) | |
531 | (looking-at "#[ \t]*[a-zA-Z0-9!]")) | |
532 | t | |
533 | (goto-char here) | |
534 | nil)))) | |
535 | ||
536 | (defun c-end-of-macro () | |
537 | "Go to the end of a cpp macro definition. | |
538 | More accurately, move point to the end of the closest following line | |
539 | that doesn't end with a line continuation backslash." | |
540 | (while (progn | |
541 | (end-of-line) | |
542 | (when (and (eq (char-before) ?\\) | |
543 | (not (eobp))) | |
544 | (forward-char) | |
545 | t)))) | |
546 | ||
547 | (defun c-forward-comment (count) | |
548 | ;; Insulation from various idiosyncrasies in implementations of | |
549 | ;; `forward-comment'. | |
550 | ;; | |
551 | ;; Note: Some emacsen considers incorrectly that any line comment | |
552 | ;; ending with a backslash continues to the next line. I can't | |
553 | ;; think of any way to work around that in a reliable way without | |
554 | ;; changing the buffer, though. Suggestions welcome. ;) (No, | |
555 | ;; temporarily changing the syntax for backslash doesn't work since | |
556 | ;; we must treat escapes in string literals correctly.) | |
557 | ;; | |
558 | ;; Another note: When moving backwards over a block comment, there's | |
559 | ;; a bug in forward-comment that can make it stop at "/*" inside a | |
560 | ;; line comment. Haven't yet found a reasonably cheap way to kludge | |
561 | ;; around that one either. :\ | |
562 | (let ((here (point))) | |
563 | (if (>= count 0) | |
564 | (when (forward-comment count) | |
565 | (if (eobp) | |
566 | ;; Some emacsen (e.g. XEmacs 21) return t when moving | |
567 | ;; forwards at eob. | |
568 | nil | |
569 | ;; Emacs includes the ending newline in a b-style (c++) | |
570 | ;; comment, but XEmacs doesn't. We depend on the Emacs | |
571 | ;; behavior (which also is symmetric). | |
572 | (if (and (eolp) (nth 7 (parse-partial-sexp here (point)))) | |
573 | (condition-case nil (forward-char 1))) | |
574 | t)) | |
575 | ;; When we got newline terminated comments, | |
576 | ;; forward-comment in all supported emacsen so far will | |
577 | ;; stop at eol of each line not ending with a comment when | |
578 | ;; moving backwards. The following corrects for it when | |
579 | ;; count is -1. The other common case, when count is | |
580 | ;; large and negative, works regardless. It's too much | |
581 | ;; work to correct for the rest of the cases. | |
582 | (skip-chars-backward " \t\n\r\f") | |
583 | (if (bobp) | |
584 | ;; Some emacsen return t when moving backwards at bob. | |
585 | nil | |
586 | (re-search-forward "[\n\r]" here t) | |
587 | (let* ((res (if (forward-comment count) | |
588 | (if (eolp) (forward-comment -1) t))) | |
589 | (savepos (point))) | |
590 | ;; XEmacs treats line continuations as whitespace (but only | |
591 | ;; in the backward direction). | |
592 | (while (and (progn (end-of-line) (< (point) here)) | |
593 | (eq (char-before) ?\\)) | |
594 | (setq res nil | |
595 | savepos (point)) | |
596 | (forward-line)) | |
597 | (goto-char savepos) | |
598 | res))))) | |
130c507e | 599 | |
a66cd3ee MS |
600 | (defun c-forward-comment-lc (count) |
601 | ;; Like `c-forward-comment', but treat line continuations as | |
602 | ;; whitespace. | |
603 | (catch 'done | |
604 | (if (> count 0) | |
605 | (while (if (c-forward-comment 1) | |
606 | (progn | |
607 | (setq count (1- count)) | |
608 | (> count 0)) | |
609 | (if (looking-at "\\\\$") | |
610 | (progn | |
611 | (forward-char) | |
612 | t) | |
613 | (throw 'done nil)))) | |
614 | (while (if (c-forward-comment -1) | |
615 | (progn | |
616 | (setq count (1+ count)) | |
617 | (< count 0)) | |
618 | (if (and (eolp) (eq (char-before) ?\\)) | |
619 | (progn | |
620 | (backward-char) | |
621 | t) | |
622 | (throw 'done nil))))) | |
623 | t)) | |
785eecbb RS |
624 | |
625 | (defun c-forward-syntactic-ws (&optional lim) | |
a66cd3ee MS |
626 | "Forward skip of syntactic whitespace. |
627 | Syntactic whitespace is defined as whitespace characters, comments, | |
628 | and preprocessor directives. However if point starts inside a comment | |
629 | or preprocessor directive, the content of it is not treated as | |
630 | whitespace. LIM sets an upper limit of the forward movement, if | |
631 | specified." | |
632 | (let ((here (point-max))) | |
633 | (or lim (setq lim here)) | |
e1c458ae | 634 | (while (/= here (point)) |
a66cd3ee MS |
635 | ;; If forward-comment in at least XEmacs 21 is given a large |
636 | ;; positive value, it'll loop all the way through if it hits eob. | |
637 | (while (c-forward-comment 5)) | |
e1c458ae | 638 | (setq here (point)) |
a66cd3ee MS |
639 | (cond |
640 | ;; Skip line continuations. | |
641 | ((looking-at "\\\\$") | |
642 | (forward-char)) | |
643 | ;; Skip preprocessor directives. | |
644 | ((and (looking-at "#[ \t]*[a-zA-Z0-9!]") | |
645 | (progn (skip-chars-backward " \t") | |
646 | (bolp))) | |
647 | (end-of-line) | |
648 | (while (and (<= (point) lim) | |
649 | (eq (char-before) ?\\) | |
650 | (= (forward-line 1) 0)) | |
651 | (end-of-line)) | |
652 | (when (> (point) lim) | |
653 | ;; Don't move past the macro if that'd take us past the limit. | |
654 | (goto-char here))) | |
655 | ;; Skip in-comment line continuations (used for Pike refdoc). | |
656 | ((and c-opt-in-comment-lc (looking-at c-opt-in-comment-lc)) | |
657 | (goto-char (match-end 0))))) | |
658 | (goto-char (min (point) lim)))) | |
e1c458ae | 659 | |
785eecbb | 660 | (defun c-backward-syntactic-ws (&optional lim) |
a66cd3ee MS |
661 | "Backward skip of syntactic whitespace. |
662 | Syntactic whitespace is defined as whitespace characters, comments, | |
663 | and preprocessor directives. However if point starts inside a comment | |
664 | or preprocessor directive, the content of it is not treated as | |
665 | whitespace. LIM sets a lower limit of the backward movement, if | |
666 | specified." | |
667 | (let ((start-line (c-point 'bol)) | |
668 | (here (point-min)) | |
669 | (line-cont 'maybe) | |
670 | prev-pos) | |
671 | (or lim (setq lim here)) | |
e1c458ae | 672 | (while (/= here (point)) |
a66cd3ee MS |
673 | (setq prev-pos (point)) |
674 | ;; If forward-comment in Emacs 19.34 is given a large negative | |
675 | ;; value, it'll loop all the way through if it hits bob. | |
676 | (while (c-forward-comment -5)) | |
e1c458ae | 677 | (setq here (point)) |
a66cd3ee MS |
678 | (cond |
679 | ((and (eolp) | |
680 | (eq (char-before) ?\\) | |
681 | (if (<= prev-pos (c-point 'eonl)) | |
682 | t | |
683 | ;; Passed a line continuation, but not from the line we | |
684 | ;; started on. | |
685 | (forward-char) | |
686 | (setq line-cont nil))) | |
687 | (backward-char) | |
688 | (setq line-cont t)) | |
689 | ((progn | |
690 | (when (eq line-cont 'maybe) | |
691 | (save-excursion | |
692 | (end-of-line) | |
693 | (setq line-cont (eq (char-before) ?\\)))) | |
694 | (or line-cont | |
695 | (and (< (point) start-line) | |
696 | (c-beginning-of-macro)))) | |
697 | (if (< (point) lim) | |
698 | ;; Don't move past the macro if we began inside it or at | |
699 | ;; the end of the same line, or if the move would take us | |
700 | ;; past the limit. | |
701 | (goto-char here)) | |
702 | (setq line-cont nil)) | |
703 | ;; Skip in-comment line continuations (used for Pike refdoc). | |
704 | ((and c-opt-in-comment-lc | |
705 | (save-excursion | |
706 | (and (c-safe (beginning-of-line) | |
707 | (backward-char 2) | |
708 | t) | |
709 | (looking-at c-opt-in-comment-lc) | |
710 | (eq (match-end 0) here)))) | |
711 | (goto-char (match-beginning 0))))) | |
712 | (goto-char (max (point) lim)))) | |
b2acd789 RS |
713 | |
714 | (defun c-forward-token-1 (&optional count balanced lim) | |
a66cd3ee MS |
715 | "Move forward by tokens. |
716 | A token is defined as all symbols and identifiers which aren't | |
717 | syntactic whitespace \(note that e.g. \"->\" is considered to be two | |
718 | tokens). Point is always either left at the beginning of a token or | |
719 | not moved at all. COUNT specifies the number of tokens to move; a | |
720 | negative COUNT moves in the opposite direction. A COUNT of 0 moves to | |
721 | the next token beginning only if not already at one. If BALANCED is | |
722 | true, move over balanced parens, otherwise move into them. Also, if | |
723 | BALANCED is true, never move out of an enclosing paren. LIM sets the | |
724 | limit for the movement and defaults to the point limit. | |
725 | ||
726 | Return the number of tokens left to move \(positive or negative). If | |
727 | BALANCED is true, a move over a balanced paren counts as one. Note | |
728 | that if COUNT is 0 and no appropriate token beginning is found, 1 will | |
729 | be returned. Thus, a return value of 0 guarantees that point is at | |
730 | the requested position and a return value less \(without signs) than | |
731 | COUNT guarantees that point is at the beginning of some token." | |
0ec8351b BW |
732 | (or count (setq count 1)) |
733 | (if (< count 0) | |
734 | (- (c-backward-token-1 (- count) balanced lim)) | |
735 | (let ((jump-syntax (if balanced | |
736 | '(?w ?_ ?\( ?\) ?\" ?\\ ?/ ?$ ?') | |
737 | '(?w ?_ ?\" ?\\ ?/ ?'))) | |
738 | (last (point)) | |
739 | (prev (point))) | |
0ec8351b BW |
740 | (save-restriction |
741 | (if lim (narrow-to-region (point-min) lim)) | |
130c507e GM |
742 | (if (/= (point) |
743 | (progn (c-forward-syntactic-ws) (point))) | |
744 | ;; Skip whitespace. Count this as a move if we did in fact | |
745 | ;; move and aren't out of bounds. | |
746 | (or (eobp) | |
747 | (setq count (max (1- count) 0)))) | |
748 | (if (and (= count 0) | |
749 | (or (and (memq (char-syntax (or (char-after) ? )) '(?w ?_)) | |
750 | (memq (char-syntax (or (char-before) ? )) '(?w ?_))) | |
751 | (eobp))) | |
752 | ;; If count is zero we should jump if in the middle of a | |
753 | ;; token or if there is whitespace between point and the | |
754 | ;; following token beginning. | |
755 | (setq count 1)) | |
0ec8351b BW |
756 | (if (eobp) |
757 | (goto-char last) | |
130c507e | 758 | ;; Avoid having the limit tests inside the loop. |
0ec8351b BW |
759 | (condition-case nil |
760 | (while (> count 0) | |
761 | (setq prev last | |
762 | last (point)) | |
763 | (if (memq (char-syntax (char-after)) jump-syntax) | |
764 | (goto-char (scan-sexps (point) 1)) | |
765 | (forward-char)) | |
a66cd3ee | 766 | (c-forward-syntactic-ws) |
0ec8351b BW |
767 | (setq count (1- count))) |
768 | (error (goto-char last))) | |
769 | (when (eobp) | |
770 | (goto-char prev) | |
771 | (setq count (1+ count))))) | |
772 | count))) | |
b2acd789 RS |
773 | |
774 | (defun c-backward-token-1 (&optional count balanced lim) | |
a66cd3ee MS |
775 | "Move backward by tokens. |
776 | See `c-forward-token-1' for details." | |
0ec8351b BW |
777 | (or count (setq count 1)) |
778 | (if (< count 0) | |
779 | (- (c-forward-token-1 (- count) balanced lim)) | |
780 | (let ((jump-syntax (if balanced | |
781 | '(?w ?_ ?\( ?\) ?\" ?\\ ?/ ?$ ?') | |
782 | '(?w ?_ ?\" ?\\ ?/ ?'))) | |
783 | last) | |
784 | (if (and (= count 0) | |
785 | (or (and (memq (char-syntax (or (char-after) ? )) '(?w ?_)) | |
786 | (memq (char-syntax (or (char-before) ? )) '(?w ?_))) | |
787 | (/= (point) | |
a66cd3ee MS |
788 | (save-excursion |
789 | (c-forward-syntactic-ws (1+ lim)) | |
790 | (point))) | |
0ec8351b BW |
791 | (eobp))) |
792 | ;; If count is zero we should jump if in the middle of a | |
793 | ;; token or if there is whitespace between point and the | |
794 | ;; following token beginning. | |
795 | (setq count 1)) | |
0ec8351b BW |
796 | (save-restriction |
797 | (if lim (narrow-to-region lim (point-max))) | |
798 | (or (bobp) | |
799 | (progn | |
130c507e | 800 | ;; Avoid having the limit tests inside the loop. |
0ec8351b BW |
801 | (condition-case nil |
802 | (while (progn | |
803 | (setq last (point)) | |
804 | (> count 0)) | |
a66cd3ee | 805 | (c-backward-syntactic-ws) |
0ec8351b BW |
806 | (if (memq (char-syntax (char-before)) jump-syntax) |
807 | (goto-char (scan-sexps (point) -1)) | |
808 | (backward-char)) | |
809 | (setq count (1- count))) | |
810 | (error (goto-char last))) | |
811 | (if (bobp) (goto-char last))))) | |
812 | count))) | |
b2acd789 | 813 | |
a66cd3ee MS |
814 | (defun c-syntactic-re-search-forward (regexp &optional bound noerror count |
815 | paren-level) | |
816 | ;; Like `re-search-forward', but only report matches that are found | |
817 | ;; in syntactically significant text. I.e. matches that begins in | |
818 | ;; comments, macros or string literals are ignored. The start point | |
819 | ;; is assumed to be outside any comment, macro or string literal, or | |
820 | ;; else the content of that region is taken as syntactically | |
821 | ;; significant text. If PAREN-LEVEL is non-nil, an additional | |
822 | ;; restriction is added to ignore matches in nested paren sexps, and | |
823 | ;; the search will also not go outside the current paren sexp. | |
824 | (or bound (setq bound (point-max))) | |
825 | (or count (setq count 1)) | |
826 | (if paren-level (setq paren-level -1)) | |
827 | (let ((start (point)) | |
828 | (pos (point)) | |
829 | match-pos state) | |
830 | (condition-case err | |
831 | (while (and (> count 0) | |
832 | (re-search-forward regexp bound noerror)) | |
833 | (setq match-pos (point) | |
834 | state (parse-partial-sexp pos (match-beginning 0) | |
835 | paren-level nil state) | |
836 | pos (point)) | |
837 | (cond ((nth 3 state) | |
838 | ;; Match inside a string. Skip to the end of it | |
839 | ;; before continuing. | |
840 | (let ((ender (make-string 1 (nth 3 state)))) | |
841 | (while (progn | |
842 | (search-forward ender bound noerror) | |
843 | (setq state (parse-partial-sexp pos (point) | |
844 | nil nil state) | |
845 | pos (point)) | |
846 | (nth 3 state))))) | |
847 | ((nth 7 state) | |
848 | ;; Match inside a line comment. Skip to eol. Use | |
849 | ;; re-search-forward for it to get the right bound | |
850 | ;; behavior. | |
851 | (re-search-forward "[\n\r]" bound noerror)) | |
852 | ((nth 4 state) | |
853 | ;; Match inside a block comment. Skip to the '*/'. | |
854 | (re-search-forward "\\*/" bound noerror)) | |
855 | ((save-excursion (c-beginning-of-macro start)) | |
856 | ;; Match inside a macro. Skip to the end of it. | |
857 | (c-end-of-macro)) | |
858 | ((and paren-level (/= (car state) 0)) | |
859 | (if (> (car state) 0) | |
860 | ;; Match inside a nested paren sexp. Skip out of it. | |
861 | (setq state (parse-partial-sexp pos bound 0 nil state) | |
862 | pos (point)) | |
863 | ;; Have exited the current paren sexp. The | |
864 | ;; parse-partial-sexp above has left us just after | |
865 | ;; the closing paren in this case. Just make | |
866 | ;; re-search-forward above fail in the appropriate | |
867 | ;; way; we'll adjust the leave off point below if | |
868 | ;; necessary. | |
869 | (setq bound (point)))) | |
870 | (t | |
871 | ;; A real match. | |
872 | (setq count (1- count))))) | |
873 | (error | |
874 | (goto-char start) | |
875 | (signal (car err) (cdr err)))) | |
876 | (if (= count 0) | |
877 | (progn | |
878 | (goto-char match-pos) | |
879 | match-pos) | |
880 | ;; Search failed. Set point as appropriate. | |
881 | (cond ((eq noerror t) | |
882 | (goto-char start)) | |
883 | (paren-level | |
884 | (if (eq (car (parse-partial-sexp pos bound -1 nil state)) -1) | |
885 | (backward-char))) | |
886 | (t | |
887 | (goto-char bound))) | |
888 | nil))) | |
889 | ||
b2acd789 | 890 | \f |
a66cd3ee MS |
891 | (defun c-in-literal (&optional lim detect-cpp) |
892 | "Return the type of literal point is in, if any. | |
893 | The return value is `c' if in a C-style comment, `c++' if in a C++ | |
894 | style comment, `string' if in a string literal, `pound' if DETECT-CPP | |
895 | is non-nil and on a preprocessor line, or nil if somewhere else. | |
896 | Optional LIM is used as the backward limit of the search. If omitted, | |
897 | or nil, `c-beginning-of-defun' is used. | |
898 | ||
899 | The last point calculated is cached if the cache is enabled, i.e. if | |
900 | `c-in-literal-cache' is bound to a two element vector." | |
130c507e | 901 | (if (and (vectorp c-in-literal-cache) |
785eecbb RS |
902 | (= (point) (aref c-in-literal-cache 0))) |
903 | (aref c-in-literal-cache 1) | |
904 | (let ((rtn (save-excursion | |
905 | (let* ((lim (or lim (c-point 'bod))) | |
785eecbb RS |
906 | (state (parse-partial-sexp lim (point)))) |
907 | (cond | |
908 | ((nth 3 state) 'string) | |
909 | ((nth 4 state) (if (nth 7 state) 'c++ 'c)) | |
a66cd3ee | 910 | ((and detect-cpp (c-beginning-of-macro lim)) 'pound) |
785eecbb RS |
911 | (t nil)))))) |
912 | ;; cache this result if the cache is enabled | |
130c507e GM |
913 | (if (not c-in-literal-cache) |
914 | (setq c-in-literal-cache (vector (point) rtn))) | |
785eecbb RS |
915 | rtn))) |
916 | ||
e1c458ae RS |
917 | ;; XEmacs has a built-in function that should make this much quicker. |
918 | ;; I don't think we even need the cache, which makes our lives more | |
a66cd3ee MS |
919 | ;; complicated anyway. In this case, lim is only used to detect |
920 | ;; cpp directives. | |
921 | (defun c-fast-in-literal (&optional lim detect-cpp) | |
e1c458ae RS |
922 | (let ((context (buffer-syntactic-context))) |
923 | (cond | |
924 | ((eq context 'string) 'string) | |
925 | ((eq context 'comment) 'c++) | |
926 | ((eq context 'block-comment) 'c) | |
a66cd3ee | 927 | ((and detect-cpp (save-excursion (c-beginning-of-macro lim))) 'pound)))) |
e1c458ae RS |
928 | |
929 | (if (fboundp 'buffer-syntactic-context) | |
930 | (defalias 'c-in-literal 'c-fast-in-literal)) | |
931 | ||
51f606de | 932 | (defun c-literal-limits (&optional lim near not-in-delimiter) |
a66cd3ee MS |
933 | "Return a cons of the beginning and end positions of the comment or |
934 | string surrounding point (including both delimiters), or nil if point | |
935 | isn't in one. If LIM is non-nil, it's used as the \"safe\" position | |
936 | to start parsing from. If NEAR is non-nil, then the limits of any | |
937 | literal next to point is returned. \"Next to\" means there's only [ | |
938 | \t] between point and the literal. The search for such a literal is | |
939 | done first in forward direction. If NOT-IN-DELIMITER is non-nil, the | |
940 | case when point is inside a starting delimiter won't be recognized. | |
941 | This only has effect for comments, which have starting delimiters with | |
942 | more than one character." | |
e1c458ae | 943 | (save-excursion |
0ec8351b BW |
944 | (let* ((pos (point)) |
945 | (lim (or lim (c-point 'bod))) | |
e1c458ae RS |
946 | (state (parse-partial-sexp lim (point)))) |
947 | (cond ((nth 3 state) | |
948 | ;; String. Search backward for the start. | |
949 | (while (nth 3 state) | |
950 | (search-backward (make-string 1 (nth 3 state))) | |
951 | (setq state (parse-partial-sexp lim (point)))) | |
0ec8351b | 952 | (cons (point) (or (c-safe (c-forward-sexp 1) (point)) |
e1c458ae RS |
953 | (point-max)))) |
954 | ((nth 7 state) | |
0ec8351b | 955 | ;; Line comment. Search from bol for the comment starter. |
e1c458ae RS |
956 | (beginning-of-line) |
957 | (setq state (parse-partial-sexp lim (point)) | |
958 | lim (point)) | |
959 | (while (not (nth 7 state)) | |
960 | (search-forward "//") ; Should never fail. | |
961 | (setq state (parse-partial-sexp | |
962 | lim (point) nil nil state) | |
963 | lim (point))) | |
964 | (backward-char 2) | |
51f606de | 965 | (cons (point) (progn (c-forward-comment 1) (point)))) |
e1c458ae | 966 | ((nth 4 state) |
0ec8351b | 967 | ;; Block comment. Search backward for the comment starter. |
e1c458ae RS |
968 | (while (nth 4 state) |
969 | (search-backward "/*") ; Should never fail. | |
970 | (setq state (parse-partial-sexp lim (point)))) | |
51f606de GM |
971 | (cons (point) (progn (c-forward-comment 1) (point)))) |
972 | ((and (not not-in-delimiter) | |
973 | (not (nth 5 state)) | |
974 | (eq (char-before) ?/) | |
975 | (looking-at "[/*]")) | |
e1c458ae | 976 | ;; We're standing in a comment starter. |
51f606de GM |
977 | (backward-char 1) |
978 | (cons (point) (progn (c-forward-comment 1) (point)))) | |
0ec8351b BW |
979 | (near |
980 | (goto-char pos) | |
981 | ;; Search forward for a literal. | |
982 | (skip-chars-forward " \t") | |
983 | (cond | |
984 | ((eq (char-syntax (or (char-after) ?\ )) ?\") ; String. | |
985 | (cons (point) (or (c-safe (c-forward-sexp 1) (point)) | |
986 | (point-max)))) | |
987 | ((looking-at "/[/*]") ; Line or block comment. | |
51f606de | 988 | (cons (point) (progn (c-forward-comment 1) (point)))) |
0ec8351b BW |
989 | (t |
990 | ;; Search backward. | |
991 | (skip-chars-backward " \t") | |
992 | (let ((end (point)) beg) | |
993 | (cond | |
994 | ((eq (char-syntax (or (char-before) ?\ )) ?\") ; String. | |
995 | (setq beg (c-safe (c-backward-sexp 1) (point)))) | |
996 | ((and (c-safe (forward-char -2) t) | |
997 | (looking-at "*/")) | |
998 | ;; Block comment. Due to the nature of line | |
999 | ;; comments, they will always be covered by the | |
1000 | ;; normal case above. | |
1001 | (goto-char end) | |
51f606de | 1002 | (c-forward-comment -1) |
0ec8351b BW |
1003 | ;; If LIM is bogus, beg will be bogus. |
1004 | (setq beg (point)))) | |
1005 | (if beg (cons beg end)))))) | |
e1c458ae RS |
1006 | )))) |
1007 | ||
51f606de | 1008 | (defun c-literal-limits-fast (&optional lim near not-in-delimiter) |
0ec8351b | 1009 | ;; Like c-literal-limits, but for emacsen whose `parse-partial-sexp' |
51f606de | 1010 | ;; returns the pos of the comment start. |
e1c458ae | 1011 | (save-excursion |
51f606de GM |
1012 | (let* ((pos (point)) |
1013 | (lim (or lim (c-point 'bod))) | |
1014 | (state (parse-partial-sexp lim (point)))) | |
e1c458ae RS |
1015 | (cond ((nth 3 state) ; String. |
1016 | (goto-char (nth 8 state)) | |
0ec8351b | 1017 | (cons (point) (or (c-safe (c-forward-sexp 1) (point)) |
e1c458ae RS |
1018 | (point-max)))) |
1019 | ((nth 4 state) ; Comment. | |
1020 | (goto-char (nth 8 state)) | |
51f606de GM |
1021 | (cons (point) (progn (c-forward-comment 1) (point)))) |
1022 | ((and (not not-in-delimiter) | |
1023 | (not (nth 5 state)) | |
1024 | (eq (char-before) ?/) | |
1025 | (looking-at "[/*]")) | |
1026 | ;; We're standing in a comment starter. | |
1027 | (backward-char 1) | |
1028 | (cons (point) (progn (c-forward-comment 1) (point)))) | |
1029 | (near | |
1030 | (goto-char pos) | |
1031 | ;; Search forward for a literal. | |
1032 | (skip-chars-forward " \t") | |
1033 | (cond | |
1034 | ((eq (char-syntax (or (char-after) ?\ )) ?\") ; String. | |
1035 | (cons (point) (or (c-safe (c-forward-sexp 1) (point)) | |
1036 | (point-max)))) | |
1037 | ((looking-at "/[/*]") ; Line or block comment. | |
1038 | (cons (point) (progn (c-forward-comment 1) (point)))) | |
1039 | (t | |
1040 | ;; Search backward. | |
1041 | (skip-chars-backward " \t") | |
1042 | (let ((end (point)) beg) | |
1043 | (cond | |
1044 | ((eq (char-syntax (or (char-before) ?\ )) ?\") ; String. | |
1045 | (setq beg (c-safe (c-backward-sexp 1) (point)))) | |
1046 | ((and (c-safe (forward-char -2) t) | |
1047 | (looking-at "*/")) | |
1048 | ;; Block comment. Due to the nature of line | |
1049 | ;; comments, they will always be covered by the | |
1050 | ;; normal case above. | |
1051 | (goto-char end) | |
1052 | (c-forward-comment -1) | |
1053 | ;; If LIM is bogus, beg will be bogus. | |
1054 | (setq beg (point)))) | |
1055 | (if beg (cons beg end)))))) | |
e1c458ae RS |
1056 | )))) |
1057 | ||
51f606de GM |
1058 | (if (c-safe (> (length (save-excursion (parse-partial-sexp 1 1))) 8)) |
1059 | (defalias 'c-literal-limits 'c-literal-limits-fast)) | |
1060 | ||
e1c458ae | 1061 | (defun c-collect-line-comments (range) |
a66cd3ee MS |
1062 | "If the argument is a cons of two buffer positions (such as returned by |
1063 | `c-literal-limits'), and that range contains a C++ style line comment, | |
1064 | then an extended range is returned that contains all adjacent line | |
1065 | comments (i.e. all comments that starts in the same column with no | |
1066 | empty lines or non-whitespace characters between them). Otherwise the | |
1067 | argument is returned." | |
e1c458ae RS |
1068 | (save-excursion |
1069 | (condition-case nil | |
1070 | (if (and (consp range) (progn | |
1071 | (goto-char (car range)) | |
1072 | (looking-at "//"))) | |
b2acd789 RS |
1073 | (let ((col (current-column)) |
1074 | (beg (point)) | |
130c507e | 1075 | (bopl (c-point 'bopl)) |
b2acd789 | 1076 | (end (cdr range))) |
130c507e GM |
1077 | ;; Got to take care in the backward direction to handle |
1078 | ;; comments which are preceded by code. | |
51f606de | 1079 | (while (and (c-forward-comment -1) |
130c507e | 1080 | (>= (point) bopl) |
b2acd789 RS |
1081 | (looking-at "//") |
1082 | (= col (current-column))) | |
130c507e GM |
1083 | (setq beg (point) |
1084 | bopl (c-point 'bopl))) | |
b2acd789 | 1085 | (goto-char end) |
51f606de GM |
1086 | (while (and (progn (skip-chars-forward " \t") |
1087 | (looking-at "//")) | |
1088 | (= col (current-column)) | |
1089 | (prog1 (zerop (forward-line 1)) | |
1090 | (setq end (point))))) | |
b2acd789 | 1091 | (cons beg end)) |
e1c458ae RS |
1092 | range) |
1093 | (error range)))) | |
1094 | ||
0ec8351b | 1095 | (defun c-literal-type (range) |
a66cd3ee MS |
1096 | "Convenience function that given the result of `c-literal-limits', |
1097 | returns nil or the type of literal that the range surrounds. It's | |
1098 | much faster than using `c-in-literal' and is intended to be used when | |
1099 | you need both the type of a literal and its limits." | |
0ec8351b | 1100 | (if (consp range) |
51f606de GM |
1101 | (save-excursion |
1102 | (goto-char (car range)) | |
1103 | (cond ((eq (char-syntax (or (char-after) ?\ )) ?\") 'string) | |
1104 | ((looking-at "//") 'c++) | |
1105 | (t 'c))) ; Assuming the range is valid. | |
0ec8351b BW |
1106 | range)) |
1107 | ||
e1c458ae | 1108 | |
785eecbb RS |
1109 | \f |
1110 | ;; utilities for moving and querying around syntactic elements | |
a66cd3ee MS |
1111 | |
1112 | (defvar c-state-cache nil) | |
1113 | (make-variable-buffer-local 'c-state-cache) | |
1114 | ;; The state cache used by `c-parse-state' to cut down the amount of | |
1115 | ;; searching. It's the result from some earlier `c-parse-state' call. | |
1116 | ;; The use of the cached info is more effective if the next | |
1117 | ;; `c-parse-state' call is on a line close by the one the cached state | |
1118 | ;; was made at; the cache can actually slow down a little if the | |
1119 | ;; cached state was made very far back in the buffer. The cache is | |
1120 | ;; most effective if `c-parse-state' is used on each line while moving | |
1121 | ;; forward. | |
1122 | ||
1123 | (defvar c-state-cache-start nil) | |
1124 | ;; This (point-min) when `c-state-cache' was calculated, to detect | |
1125 | ;; that the start point hasn't changed due to narrowing. | |
785eecbb RS |
1126 | |
1127 | (defun c-parse-state () | |
a66cd3ee MS |
1128 | ;; Finds and records all noteworthy parens between some good point |
1129 | ;; earlier in the file and point. That good point is at least the | |
1130 | ;; beginning of the top-level construct we are in, or the beginning | |
1131 | ;; of the preceding top-level construct if we aren't in one. | |
785eecbb | 1132 | ;; |
a66cd3ee MS |
1133 | ;; The returned value is a list of the noteworthy parens with the |
1134 | ;; last one first. If an element in the list is an integer, it's | |
1135 | ;; the position of an open paren which has not been closed before | |
1136 | ;; point. If an element is a cons, it gives the position of a | |
1137 | ;; closed brace paren pair; the car is the start paren position and | |
1138 | ;; the cdr is the position following the closing paren. Only the | |
1139 | ;; last closed brace paren pair before each open paren is recorded, | |
1140 | ;; and thus the state never contains two cons elements in | |
1141 | ;; succession. | |
1142 | (save-restriction | |
1143 | (let* ((here (point)) | |
1144 | (c-macro-start (c-query-macro-start)) | |
1145 | (in-macro-start (or c-macro-start (point))) | |
1146 | old-state last-pos pairs pos) | |
1147 | ;; Somewhat ugly use of c-check-state-cache to get rid of the | |
1148 | ;; part of the state cache that is after point. Can't use | |
1149 | ;; c-whack-state-after for the same reasons as in that function. | |
1150 | (c-check-state-cache (point) nil nil) | |
1151 | ;; Get the latest position we know are directly inside the | |
1152 | ;; closest containing paren of the cached state. | |
1153 | (setq last-pos (and c-state-cache | |
1154 | (if (consp (car c-state-cache)) | |
1155 | (cdr (car c-state-cache)) | |
1156 | (1+ (car c-state-cache))))) | |
1157 | ;; Check if the found last-pos is in a macro. If it is, and | |
1158 | ;; we're not in the same macro, we must discard everything on | |
1159 | ;; c-state-cache that is inside the macro before using it. | |
1160 | (when last-pos | |
1161 | (save-excursion | |
1162 | (goto-char last-pos) | |
1163 | (when (and (c-beginning-of-macro) | |
1164 | (/= (point) in-macro-start)) | |
1165 | (c-check-state-cache (point) nil nil) | |
1166 | ;; Set last-pos again, just like above. | |
1167 | (setq last-pos (and c-state-cache | |
1168 | (if (consp (car c-state-cache)) | |
1169 | (cdr (car c-state-cache)) | |
1170 | (1+ (car c-state-cache)))))))) | |
1171 | (setq pos | |
1172 | ;; Find the start position for the forward search. (Can't | |
1173 | ;; search in the backward direction since point might be | |
1174 | ;; in some kind of literal.) | |
1175 | (or (when last-pos | |
1176 | ;; There's a cached state with a containing paren. Pop | |
1177 | ;; off the stale containing sexps from it by going | |
1178 | ;; forward out of parens as far as possible. | |
1179 | (narrow-to-region (point-min) here) | |
1180 | (let (placeholder pair-beg) | |
1181 | (while (and c-state-cache | |
1182 | (setq placeholder | |
1183 | (c-up-list-forward last-pos))) | |
1184 | (setq last-pos placeholder) | |
1185 | (if (consp (car c-state-cache)) | |
1186 | (setq pair-beg (car-safe (cdr c-state-cache)) | |
1187 | c-state-cache (cdr-safe (cdr c-state-cache))) | |
1188 | (setq pair-beg (car c-state-cache) | |
1189 | c-state-cache (cdr c-state-cache)))) | |
1190 | (when (and pair-beg (eq (char-after pair-beg) ?{)) | |
1191 | ;; The last paren pair we moved out from was a brace | |
1192 | ;; pair. Modify the state to record this as a closed | |
1193 | ;; pair now. | |
1194 | (if (consp (car-safe c-state-cache)) | |
1195 | (setq c-state-cache (cdr c-state-cache))) | |
1196 | (setq c-state-cache (cons (cons pair-beg last-pos) | |
1197 | c-state-cache)))) | |
1198 | ;; Check if the preceding balanced paren is within a | |
1199 | ;; macro; it should be ignored if we're outside the | |
1200 | ;; macro. There's no need to check any further upwards; | |
1201 | ;; if the macro contains an unbalanced opening paren then | |
1202 | ;; we're smoked anyway. | |
1203 | (when (and (<= (point) in-macro-start) | |
1204 | (consp (car c-state-cache))) | |
1205 | (save-excursion | |
1206 | (goto-char (car (car c-state-cache))) | |
1207 | (when (c-beginning-of-macro) | |
1208 | (setq here (point) | |
1209 | c-state-cache (cdr c-state-cache))))) | |
1210 | (when c-state-cache | |
1211 | (setq old-state c-state-cache) | |
1212 | last-pos)) | |
1213 | (save-excursion | |
785eecbb | 1214 | ;; go back 2 bods, but ignore any bogus positions |
a66cd3ee MS |
1215 | ;; returned by beginning-of-defun (i.e. open paren in |
1216 | ;; column zero) | |
1217 | (goto-char here) | |
785eecbb | 1218 | (let ((cnt 2)) |
a66cd3ee MS |
1219 | (while (not (or (bobp) (zerop cnt))) |
1220 | (c-beginning-of-defun-1) | |
1221 | (if (eq (char-after) ?\{) | |
1222 | (setq cnt (1- cnt))))) | |
1223 | (point)))) | |
1224 | (narrow-to-region (point-min) here) | |
1225 | (while pos | |
1226 | ;; Find the balanced brace pairs. | |
1227 | (setq pairs nil) | |
1228 | (while (and (setq last-pos (c-down-list-forward pos)) | |
1229 | (setq pos (c-up-list-forward last-pos))) | |
1230 | (if (eq (char-before last-pos) ?{) | |
1231 | (setq pairs (cons (cons last-pos pos) pairs)))) | |
1232 | ;; Should ignore any pairs that are in a macro, providing | |
1233 | ;; we're not in the same one. | |
1234 | (when (and pairs (< (car (car pairs)) in-macro-start)) | |
1235 | (while (and (save-excursion | |
1236 | (goto-char (car (car pairs))) | |
1237 | (c-beginning-of-macro)) | |
1238 | (setq pairs (cdr pairs))))) | |
1239 | ;; Record the last brace pair. | |
1240 | (when pairs | |
1241 | (if (and (eq c-state-cache old-state) | |
1242 | (consp (car-safe c-state-cache))) | |
1243 | ;; There's a closed pair on the cached state but we've | |
1244 | ;; found a later one, so remove it. | |
1245 | (setq c-state-cache (cdr c-state-cache))) | |
1246 | (setq pairs (car pairs)) | |
1247 | (setcar pairs (1- (car pairs))) | |
1248 | (setq c-state-cache (cons pairs c-state-cache))) | |
1249 | (if last-pos | |
1250 | ;; Prepare to loop, but record the open paren only if it's | |
1251 | ;; outside a macro or within the same macro as point. | |
1252 | (progn | |
1253 | (setq pos last-pos) | |
1254 | (if (or (>= last-pos in-macro-start) | |
1255 | (save-excursion | |
1256 | (goto-char last-pos) | |
1257 | (not (c-beginning-of-macro)))) | |
1258 | (setq c-state-cache (cons (1- pos) c-state-cache)))) | |
1259 | (if (setq last-pos (c-up-list-forward pos)) | |
1260 | ;; Found a close paren without a corresponding opening | |
1261 | ;; one. Maybe we didn't go back far enough, so try to | |
1262 | ;; scan backward for the start paren and then start over. | |
1263 | (progn | |
1264 | (setq pos (c-up-list-backward pos) | |
1265 | c-state-cache nil) | |
1266 | (unless pos | |
1267 | (setq pos last-pos | |
1268 | c-parsing-error | |
1269 | (format "Unbalanced close paren at line %d" | |
1270 | (1+ (count-lines (point-min) | |
1271 | (c-point 'bol last-pos))))))) | |
1272 | (setq pos nil)))) | |
1273 | c-state-cache))) | |
1274 | ||
1275 | ;; Debug tool to catch cache inconsistencies. | |
1276 | (defvar c-debug-parse-state nil) | |
1277 | (unless (fboundp 'c-real-parse-state) | |
1278 | (fset 'c-real-parse-state (symbol-function 'c-parse-state))) | |
1279 | (cc-bytecomp-defun c-real-parse-state) | |
1280 | (defun c-debug-parse-state () | |
1281 | (let ((res1 (c-real-parse-state)) res2) | |
1282 | (let ((c-state-cache nil)) | |
1283 | (setq res2 (c-real-parse-state))) | |
1284 | (unless (equal res1 res2) | |
1285 | (error "c-parse-state inconsistency: using cache: %s, from scratch: %s" | |
1286 | res1 res2)) | |
1287 | res1)) | |
1288 | (defun c-toggle-parse-state-debug (&optional arg) | |
1289 | (interactive "P") | |
1290 | (setq c-debug-parse-state (c-calculate-state arg c-debug-parse-state)) | |
1291 | (fset 'c-parse-state (symbol-function (if c-debug-parse-state | |
1292 | 'c-debug-parse-state | |
1293 | 'c-real-parse-state))) | |
1294 | (c-keep-region-active)) | |
1295 | ||
1296 | (defun c-check-state-cache (beg end old-length) | |
1297 | ;; Used on `after-change-functions' to adjust `c-state-cache'. | |
1298 | ;; Prefer speed to finesse here, since there will be many more calls | |
1299 | ;; to this function than times `c-state-cache' is used. | |
1300 | ;; | |
1301 | ;; This is much like `c-whack-state-after', but it never changes a | |
1302 | ;; paren pair element into an open paren element. Doing that would | |
1303 | ;; mean that the new open paren wouldn't have the required preceding | |
1304 | ;; paren pair element. | |
1305 | (if (not (eq c-state-cache-start (point-min))) | |
1306 | (setq c-state-cache-start (point-min) | |
1307 | c-state-cache nil) | |
1308 | (while (and c-state-cache | |
1309 | (let ((elem (car c-state-cache))) | |
1310 | (if (consp elem) | |
1311 | (or (<= beg (car elem)) | |
1312 | (< beg (cdr elem))) | |
1313 | (<= beg elem)))) | |
1314 | (setq c-state-cache (cdr c-state-cache))))) | |
1315 | ||
1316 | (defun c-whack-state-before (bufpos paren-state) | |
1317 | ;; Whack off any state information from PAREN-STATE which lies | |
1318 | ;; before BUFPOS. Not destructive on PAREN-STATE. | |
1319 | (let* ((newstate (list nil)) | |
1320 | (ptr newstate) | |
1321 | car) | |
1322 | (while paren-state | |
1323 | (setq car (car paren-state) | |
1324 | paren-state (cdr paren-state)) | |
1325 | (if (< (if (consp car) (car car) car) bufpos) | |
1326 | (setq paren-state nil) | |
1327 | (setcdr ptr (list car)) | |
1328 | (setq ptr (cdr ptr)))) | |
1329 | (cdr newstate))) | |
1330 | ||
1331 | (defun c-whack-state-after (bufpos paren-state) | |
1332 | ;; Whack off any state information from PAREN-STATE which lies at or | |
1333 | ;; after BUFPOS. Not destructive on PAREN-STATE. | |
1334 | (catch 'done | |
1335 | (while paren-state | |
1336 | (let ((car (car paren-state))) | |
1337 | (if (consp car) | |
1338 | ;; just check the car, because in a balanced brace | |
1339 | ;; expression, it must be impossible for the corresponding | |
1340 | ;; close brace to be before point, but the open brace to | |
1341 | ;; be after. | |
1342 | (if (<= bufpos (car car)) | |
1343 | nil ; whack it off | |
1344 | (if (< bufpos (cdr car)) | |
1345 | ;; its possible that the open brace is before | |
1346 | ;; bufpos, but the close brace is after. In that | |
1347 | ;; case, convert this to a non-cons element. The | |
1348 | ;; rest of the state is before bufpos, so we're | |
1349 | ;; done. | |
1350 | (throw 'done (cons (car car) (cdr paren-state))) | |
1351 | ;; we know that both the open and close braces are | |
1352 | ;; before bufpos, so we also know that everything else | |
1353 | ;; on state is before bufpos. | |
1354 | (throw 'done paren-state))) | |
1355 | (if (<= bufpos car) | |
785eecbb | 1356 | nil ; whack it off |
a66cd3ee MS |
1357 | ;; it's before bufpos, so everything else should too. |
1358 | (throw 'done paren-state))) | |
1359 | (setq paren-state (cdr paren-state))) | |
1360 | nil))) | |
785eecbb RS |
1361 | |
1362 | \f | |
1363 | (defun c-beginning-of-inheritance-list (&optional lim) | |
1364 | ;; Go to the first non-whitespace after the colon that starts a | |
1365 | ;; multiple inheritance introduction. Optional LIM is the farthest | |
1366 | ;; back we should search. | |
a66cd3ee MS |
1367 | (let* ((lim (or lim (c-point 'bod)))) |
1368 | (c-with-syntax-table c++-template-syntax-table | |
1369 | (c-backward-token-1 0 t lim) | |
1370 | (while (and (looking-at "[_a-zA-Z<,]") | |
1371 | (= (c-backward-token-1 1 t lim) 0))) | |
1372 | (skip-chars-forward "^:")))) | |
785eecbb | 1373 | |
785eecbb RS |
1374 | (defun c-in-method-def-p () |
1375 | ;; Return nil if we aren't in a method definition, otherwise the | |
1376 | ;; position of the initial [+-]. | |
1377 | (save-excursion | |
1378 | (beginning-of-line) | |
a66cd3ee MS |
1379 | (and c-opt-method-key |
1380 | (looking-at c-opt-method-key) | |
785eecbb RS |
1381 | (point)) |
1382 | )) | |
1383 | ||
a66cd3ee MS |
1384 | ;; Contributed by Kevin Ryde <user42@zip.com.au>. |
1385 | (defun c-in-gcc-asm-p () | |
1386 | ;; Return non-nil if point is within a gcc \"asm\" block. | |
1387 | ;; | |
1388 | ;; This should be called with point inside an argument list. | |
1389 | ;; | |
1390 | ;; Only one level of enclosing parentheses is considered, so for | |
1391 | ;; instance `nil' is returned when in a function call within an asm | |
1392 | ;; operand. | |
1393 | ||
1394 | (and c-opt-asm-stmt-key | |
1395 | (save-excursion | |
1396 | (beginning-of-line) | |
1397 | (backward-up-list 1) | |
1398 | (c-beginning-of-statement-1 (point-min) nil t) | |
1399 | (looking-at c-opt-asm-stmt-key)))) | |
1400 | ||
abb7e5cf SM |
1401 | (defun c-at-toplevel-p () |
1402 | "Return a determination as to whether point is at the `top-level'. | |
1403 | Being at the top-level means that point is either outside any | |
a66cd3ee MS |
1404 | enclosing block (such function definition), or inside a class, |
1405 | namespace or extern definition, but outside any method blocks. | |
abb7e5cf SM |
1406 | |
1407 | If point is not at the top-level (e.g. it is inside a method | |
1408 | definition), then nil is returned. Otherwise, if point is at a | |
1409 | top-level not enclosed within a class definition, t is returned. | |
1410 | Otherwise, a 2-vector is returned where the zeroth element is the | |
1411 | buffer position of the start of the class declaration, and the first | |
1412 | element is the buffer position of the enclosing class's opening | |
1413 | brace." | |
a66cd3ee MS |
1414 | (let ((paren-state (c-parse-state))) |
1415 | (or (not (c-most-enclosing-brace paren-state)) | |
1416 | (c-search-uplist-for-classkey paren-state)))) | |
1417 | ||
1418 | (defun c-forward-to-cpp-define-body () | |
1419 | ;; Assuming point is at the "#" that introduces a preprocessor | |
1420 | ;; directive, it's moved forward to the start of the definition body | |
1421 | ;; if it's a "#define". Non-nil is returned in this case, in all | |
1422 | ;; other cases nil is returned and point isn't moved. | |
1423 | (when (and (looking-at | |
1424 | (concat "#[ \t]*" | |
1425 | "define[ \t]+\\(\\sw\\|_\\)+\\(\([^\)]*\)\\)?" | |
1426 | "\\([ \t]\\|\\\\\n\\)*")) | |
1427 | (not (= (match-end 0) (c-point 'eol)))) | |
1428 | (goto-char (match-end 0)))) | |
1429 | ||
1430 | (defun c-just-after-func-arglist-p (&optional containing lim) | |
785eecbb RS |
1431 | ;; Return t if we are between a function's argument list closing |
1432 | ;; paren and its opening brace. Note that the list close brace | |
1433 | ;; could be followed by a "const" specifier or a member init hanging | |
1434 | ;; colon. Optional CONTAINING is position of containing s-exp open | |
a66cd3ee MS |
1435 | ;; brace. If not supplied, point is used as search start. LIM is |
1436 | ;; used as bound for some backward buffer searches; the search might | |
1437 | ;; continue past it. | |
1438 | ;; | |
1439 | ;; Note: This test is easily fooled. It only works reasonably well | |
1440 | ;; in the situations where `c-guess-basic-syntax' uses it. | |
785eecbb | 1441 | (save-excursion |
a66cd3ee | 1442 | (c-backward-syntactic-ws lim) |
785eecbb RS |
1443 | (let ((checkpoint (or containing (point)))) |
1444 | (goto-char checkpoint) | |
1445 | ;; could be looking at const specifier | |
1446 | (if (and (eq (char-before) ?t) | |
1447 | (forward-word -1) | |
a66cd3ee MS |
1448 | (looking-at "\\<const\\>[^_]")) |
1449 | (c-backward-syntactic-ws lim) | |
785eecbb RS |
1450 | ;; otherwise, we could be looking at a hanging member init |
1451 | ;; colon | |
1452 | (goto-char checkpoint) | |
ce8c7486 GM |
1453 | (while (eq (char-before) ?,) |
1454 | ;; this will catch member inits with multiple | |
1455 | ;; line arglists | |
1456 | (forward-char -1) | |
1457 | (c-backward-syntactic-ws (c-point 'bol)) | |
1458 | (if (eq (char-before) ?\)) | |
1459 | (c-backward-sexp 2) | |
1460 | (c-backward-sexp 1)) | |
a66cd3ee | 1461 | (c-backward-syntactic-ws lim)) |
785eecbb RS |
1462 | (if (and (eq (char-before) ?:) |
1463 | (progn | |
1464 | (forward-char -1) | |
a66cd3ee MS |
1465 | (c-backward-syntactic-ws lim) |
1466 | (looking-at "\\([ \t\n]\\|\\\\\n\\)*:\\([^:]+\\|$\\)"))) | |
785eecbb RS |
1467 | nil |
1468 | (goto-char checkpoint)) | |
1469 | ) | |
a66cd3ee | 1470 | (setq checkpoint (point)) |
785eecbb | 1471 | (and (eq (char-before) ?\)) |
a66cd3ee MS |
1472 | ;; Check that it isn't a cpp expression, e.g. the |
1473 | ;; expression of an #if directive or the "function header" | |
1474 | ;; of a #define. | |
1475 | (or (not (c-beginning-of-macro)) | |
1476 | (and (c-forward-to-cpp-define-body) | |
1477 | (< (point) checkpoint))) | |
1478 | ;; check if we are looking at an ObjC method def | |
1479 | (or (not c-opt-method-key) | |
785eecbb | 1480 | (progn |
a66cd3ee | 1481 | (goto-char checkpoint) |
0ec8351b | 1482 | (c-forward-sexp -1) |
785eecbb | 1483 | (forward-char -1) |
a66cd3ee | 1484 | (c-backward-syntactic-ws lim) |
785eecbb RS |
1485 | (not (or (memq (char-before) '(?- ?+)) |
1486 | ;; or a class category | |
1487 | (progn | |
0ec8351b | 1488 | (c-forward-sexp -2) |
785eecbb RS |
1489 | (looking-at c-class-key)) |
1490 | ))))) | |
1491 | ))) | |
1492 | ||
a66cd3ee MS |
1493 | (defun c-in-knr-argdecl (&optional lim) |
1494 | ;; Return the position of the first argument declaration if point is | |
1495 | ;; inside a K&R style argument declaration list, nil otherwise. | |
1496 | ;; `c-recognize-knr-p' is not checked. If LIM is non-nil, it's a | |
1497 | ;; position that bounds the backward search for the argument list. | |
1498 | ;; | |
1499 | ;; Note: A declaration level context is assumed; the test can return | |
1500 | ;; false positives for statements and #define headers. This test is | |
1501 | ;; even more easily fooled than `c-just-after-func-arglist-p'. | |
1502 | (save-excursion | |
1503 | (save-restriction | |
1504 | ;; Go back to the closest preceding normal parenthesis sexp. We | |
1505 | ;; take that as the argument list in the function header. Then | |
1506 | ;; check that it's followed by some symbol before the next ';' | |
1507 | ;; or '{'. If it does, it's the header of the K&R argdecl we're | |
1508 | ;; in. | |
1509 | (if lim (narrow-to-region lim (point))) | |
1510 | (let (paren-end) | |
1511 | (and (c-safe (setq paren-end (c-down-list-backward (point)))) | |
1512 | (eq (char-after paren-end) ?\)) | |
1513 | (progn | |
1514 | (goto-char (1+ paren-end)) | |
1515 | (c-forward-syntactic-ws) | |
1516 | (looking-at "\\w\\|\\s_")) | |
1517 | (c-safe (c-up-list-backward paren-end)) | |
1518 | (point)))))) | |
785eecbb RS |
1519 | |
1520 | (defun c-skip-conditional () | |
1521 | ;; skip forward over conditional at point, including any predicate | |
1522 | ;; statements in parentheses. No error checking is performed. | |
0ec8351b BW |
1523 | (c-forward-sexp (cond |
1524 | ;; else if() | |
a66cd3ee MS |
1525 | ((looking-at (concat "\\<else" |
1526 | "\\([ \t\n]\\|\\\\\n\\)+" | |
1527 | "if\\>\\([^_]\\|$\\)")) | |
1528 | 3) | |
0ec8351b | 1529 | ;; do, else, try, finally |
a66cd3ee MS |
1530 | ((looking-at (concat "\\<\\(" |
1531 | "do\\|else\\|try\\|finally" | |
1532 | "\\)\\>\\([^_]\\|$\\)")) | |
130c507e | 1533 | 1) |
ce8c7486 | 1534 | ;; for, if, while, switch, catch, synchronized, foreach |
0ec8351b | 1535 | (t 2)))) |
785eecbb | 1536 | |
a66cd3ee MS |
1537 | (defun c-after-conditional (&optional lim) |
1538 | ;; If looking at the token after a conditional then return the | |
1539 | ;; position of its start, otherwise return nil. | |
1540 | (save-excursion | |
1541 | (and (= (c-backward-token-1 1 t lim) 0) | |
1542 | (or (looking-at c-block-stmt-1-key) | |
1543 | (and (eq (char-after) ?\() | |
1544 | (= (c-backward-token-1 1 t lim) 0) | |
1545 | (looking-at c-block-stmt-2-key))) | |
1546 | (point)))) | |
1547 | ||
1548 | (defsubst c-backward-to-block-anchor (&optional lim) | |
1549 | ;; Assuming point is at a brace that opens a statement block of some | |
1550 | ;; kind, move to the proper anchor point for that block. It might | |
1551 | ;; need to be adjusted further by c-add-stmt-syntax, but the | |
1552 | ;; position at return is suitable as start position for that | |
1553 | ;; function. | |
1554 | (unless (= (point) (c-point 'boi)) | |
1555 | (let ((start (c-after-conditional lim))) | |
1556 | (if start | |
1557 | (goto-char start))))) | |
1558 | ||
1559 | (defun c-backward-to-decl-anchor (&optional lim) | |
1560 | ;; Assuming point is at a brace that opens the block of a top level | |
1561 | ;; declaration of some kind, move to the proper anchor point for | |
1562 | ;; that block. | |
1563 | (unless (= (point) (c-point 'boi)) | |
1564 | ;; What we have below is actually an extremely stripped variant of | |
1565 | ;; c-beginning-of-statement-1. | |
1566 | (let ((pos (point))) | |
1567 | ;; Switch syntax table to avoid stopping at line continuations. | |
1568 | (save-restriction | |
1569 | (if lim (narrow-to-region lim (point-max))) | |
1570 | (while (and (progn | |
1571 | (c-backward-syntactic-ws) | |
1572 | (c-safe (goto-char (scan-sexps (point) -1)) t)) | |
1573 | (not (c-crosses-statement-barrier-p (point) pos))) | |
1574 | (setq pos (point))) | |
1575 | (goto-char pos))))) | |
1576 | ||
1577 | (defsubst c-search-decl-header-end () | |
1578 | ;; Search forward for the end of the "header" of the current | |
1579 | ;; declaration. That's the position where the definition body | |
1580 | ;; starts, or the first variable initializer, or the ending | |
1581 | ;; semicolon. I.e. search forward for the closest following | |
1582 | ;; (syntactically relevant) '{', '=' or ';' token. Point is left | |
1583 | ;; _after_ the first found token, or at point-max if none is found. | |
1584 | (c-with-syntax-table (if (c-major-mode-is 'c++-mode) | |
1585 | c++-template-syntax-table | |
1586 | (syntax-table)) | |
1587 | (while (and (c-syntactic-re-search-forward "[;{=]" nil 'move 1 t) | |
1588 | ;; In Pike it can be an operator identifier containing | |
1589 | ;; '='. | |
1590 | (c-major-mode-is 'pike-mode) | |
1591 | (eq (char-before) ?=) | |
1592 | (c-on-identifier))))) | |
1593 | ||
1594 | (defun c-beginning-of-decl-1 (&optional lim) | |
1595 | ;; Go to the beginning of the current declaration, or the beginning | |
1596 | ;; of the previous one if already at the start of it. Point won't | |
1597 | ;; be moved out of any surrounding paren. Return a cons cell on the | |
1598 | ;; form (MOVE . KNR-POS). MOVE is like the return value from | |
1599 | ;; `c-beginning-of-statement-1'. If point skipped over some K&R | |
1600 | ;; style argument declarations (and they are to be recognized) then | |
1601 | ;; KNR-POS is set to the start of the first such argument | |
1602 | ;; declaration, otherwise KNR-POS is nil. If LIM is non-nil, it's a | |
1603 | ;; position that bounds the backward search. | |
1604 | ;; | |
1605 | ;; NB: Cases where the declaration continues after the block, as in | |
1606 | ;; "struct foo { ... } bar;", are currently recognized as two | |
1607 | ;; declarations, e.g. "struct foo { ... }" and "bar;" in this case. | |
1608 | (catch 'return | |
1609 | (let* ((start (point)) | |
1610 | (last-stmt-start (point)) | |
b3cf7e18 | 1611 | (move (c-beginning-of-statement-1 lim t t))) |
a66cd3ee MS |
1612 | |
1613 | (while (and (/= last-stmt-start (point)) | |
1614 | (save-excursion | |
1615 | (c-backward-syntactic-ws lim) | |
1616 | (not (memq (char-before) '(?\; ?} ?: nil))))) | |
1617 | ;; `c-beginning-of-statement-1' stops at a block start, but we | |
1618 | ;; want to continue if the block doesn't begin a top level | |
1619 | ;; construct, i.e. if it isn't preceded by ';', '}', ':', or bob. | |
1620 | (setq last-stmt-start (point) | |
b3cf7e18 | 1621 | move (c-beginning-of-statement-1 lim t t))) |
a66cd3ee MS |
1622 | |
1623 | (when c-recognize-knr-p | |
1624 | (let ((fallback-pos (point)) knr-argdecl-start) | |
1625 | ;; Handle K&R argdecls. Back up after the "statement" jumped | |
1626 | ;; over by `c-beginning-of-statement-1', unless it was the | |
1627 | ;; function body, in which case we're sitting on the opening | |
1628 | ;; brace now. Then test if we're in a K&R argdecl region and | |
1629 | ;; that we started at the other side of the first argdecl in | |
1630 | ;; it. | |
1631 | (unless (eq (char-after) ?{) | |
1632 | (goto-char last-stmt-start)) | |
1633 | (if (and (setq knr-argdecl-start (c-in-knr-argdecl lim)) | |
1634 | (< knr-argdecl-start start) | |
1635 | (progn | |
1636 | (goto-char knr-argdecl-start) | |
b3cf7e18 | 1637 | (not (eq (c-beginning-of-statement-1 lim t t) 'macro)))) |
a66cd3ee MS |
1638 | (throw 'return |
1639 | (cons (if (eq (char-after fallback-pos) ?{) | |
1640 | 'previous | |
1641 | 'same) | |
1642 | knr-argdecl-start)) | |
1643 | (goto-char fallback-pos)))) | |
1644 | ||
b3cf7e18 MS |
1645 | (when c-opt-access-key |
1646 | ;; Might have ended up before a protection label. This should | |
1647 | ;; perhaps be checked before `c-recognize-knr-p' to be really | |
1648 | ;; accurate, but we know that no language has both. | |
1649 | (while (looking-at c-opt-access-key) | |
1650 | (goto-char (match-end 0)) | |
1651 | (c-forward-syntactic-ws) | |
1652 | (when (>= (point) start) | |
1653 | (goto-char start) | |
1654 | (throw 'return (cons 'same nil))))) | |
1655 | ||
a66cd3ee MS |
1656 | ;; `c-beginning-of-statement-1' counts each brace block as a |
1657 | ;; separate statement, so the result will be 'previous if we've | |
1658 | ;; moved over any. If they were brace list initializers we might | |
1659 | ;; not have moved over a declaration boundary though, so change it | |
1660 | ;; to 'same if we've moved past a '=' before '{', but not ';'. | |
1661 | ;; (This ought to be integrated into `c-beginning-of-statement-1', | |
1662 | ;; so we avoid this extra pass which potentially can search over a | |
1663 | ;; large amount of text.) | |
1664 | (if (and (eq move 'previous) | |
1665 | (c-with-syntax-table (if (c-major-mode-is 'c++-mode) | |
1666 | c++-template-syntax-table | |
1667 | (syntax-table)) | |
1668 | (save-excursion | |
1669 | (and (c-syntactic-re-search-forward "[;={]" start t 1 t) | |
1670 | (eq (char-before) ?=) | |
1671 | (c-syntactic-re-search-forward "[;{]" start t 1 t) | |
1672 | (eq (char-before) ?{) | |
1673 | (c-safe (goto-char (c-up-list-forward (point))) t) | |
1674 | (not (c-syntactic-re-search-forward ";" start t 1 t)))))) | |
1675 | (cons 'same nil) | |
1676 | (cons move nil))))) | |
1677 | ||
1678 | (defun c-end-of-decl-1 () | |
1679 | ;; Assuming point is at the start of a declaration (as detected by | |
1680 | ;; e.g. `c-beginning-of-decl-1'), go to the end of it. Unlike | |
1681 | ;; `c-beginning-of-decl-1', this function handles the case when a | |
1682 | ;; block is followed by identifiers in e.g. struct declarations in C | |
1683 | ;; or C++. If a proper end was found then t is returned, otherwise | |
1684 | ;; point is moved as far as possible within the current sexp and nil | |
1685 | ;; is returned. This function doesn't handle macros; use | |
1686 | ;; `c-end-of-macro' instead in those cases. | |
ce8c7486 | 1687 | (let ((start (point)) |
a66cd3ee MS |
1688 | (decl-syntax-table (if (c-major-mode-is 'c++-mode) |
1689 | c++-template-syntax-table | |
1690 | (syntax-table)))) | |
1691 | (catch 'return | |
1692 | (c-search-decl-header-end) | |
1693 | ||
1694 | (when (and c-recognize-knr-p | |
1695 | (eq (char-before) ?\;) | |
1696 | (c-in-knr-argdecl start)) | |
1697 | ;; Stopped at the ';' in a K&R argdecl section which is | |
1698 | ;; detected using the same criteria as in | |
1699 | ;; `c-beginning-of-decl-1'. Move to the following block | |
1700 | ;; start. | |
1701 | (c-syntactic-re-search-forward "{" nil 'move 1 t)) | |
1702 | ||
1703 | (when (eq (char-before) ?{) | |
1704 | ;; Encountered a block in the declaration. Jump over it. | |
1705 | (condition-case nil | |
1706 | (goto-char (c-up-list-forward (point))) | |
1707 | (goto-char (point-max)) | |
1708 | (throw 'return nil)) | |
1709 | (if (or (not c-opt-block-decls-with-vars-key) | |
1710 | (save-excursion | |
1711 | (c-with-syntax-table decl-syntax-table | |
1712 | (let ((lim (point))) | |
1713 | (goto-char start) | |
b3cf7e18 MS |
1714 | (not (and |
1715 | ;; Check for `c-opt-block-decls-with-vars-key' | |
1716 | ;; before the first paren. | |
1717 | (c-syntactic-re-search-forward | |
1718 | (concat "[;=\(\[{]\\|\\<\\(" | |
1719 | c-opt-block-decls-with-vars-key | |
1720 | "\\)") | |
1721 | lim t 1 t) | |
1722 | (match-beginning 1) | |
1723 | (not (eq (char-before) ?_)) | |
1724 | ;; Check that the first following paren is the block. | |
1725 | (c-syntactic-re-search-forward "[;=\(\[{]" lim t 1 t) | |
1726 | (eq (char-before) ?{))))))) | |
a66cd3ee MS |
1727 | ;; The declaration doesn't have any of the |
1728 | ;; `c-opt-block-decls-with-vars' keywords in the | |
1729 | ;; beginning, so it ends here at the end of the block. | |
1730 | (throw 'return t))) | |
1731 | ||
1732 | (c-with-syntax-table decl-syntax-table | |
1733 | (while (progn | |
1734 | (if (eq (char-before) ?\;) | |
1735 | (throw 'return t)) | |
1736 | (c-syntactic-re-search-forward ";" nil 'move 1 t)))) | |
1737 | nil))) | |
ce8c7486 GM |
1738 | |
1739 | (defun c-beginning-of-member-init-list (&optional limit) | |
1740 | ;; Goes to the beginning of a member init list (i.e. just after the | |
1741 | ;; ':') if inside one. Returns t in that case, nil otherwise. | |
1742 | (or limit | |
1743 | (setq limit (point-min))) | |
1744 | (skip-chars-forward " \t") | |
1745 | (if (eq (char-after) ?,) | |
1746 | (forward-char 1) | |
1747 | (c-backward-syntactic-ws limit)) | |
174acba3 SM |
1748 | (while (and (< limit (point)) |
1749 | (eq (char-before) ?,)) | |
1750 | ;; this will catch member inits with multiple | |
1751 | ;; line arglists | |
1752 | (forward-char -1) | |
1753 | (c-backward-syntactic-ws limit) | |
1754 | (if (eq (char-before) ?\)) | |
130c507e | 1755 | (c-backward-sexp 1)) |
174acba3 SM |
1756 | (c-backward-syntactic-ws limit) |
1757 | ;; Skip over any template arg to the class. | |
1758 | (if (eq (char-before) ?>) | |
1759 | (c-with-syntax-table c++-template-syntax-table | |
1760 | (c-backward-sexp 1))) | |
1761 | (c-backward-sexp 1) | |
1762 | (c-backward-syntactic-ws limit) | |
1763 | ;; Skip backwards over a fully::qualified::name. | |
1764 | (while (and (eq (char-before) ?:) | |
1765 | (save-excursion | |
1766 | (forward-char -1) | |
1767 | (eq (char-before) ?:))) | |
1768 | (backward-char 2) | |
1769 | (c-backward-sexp 1)) | |
1770 | ;; now continue checking | |
1771 | (c-backward-syntactic-ws limit)) | |
ce8c7486 GM |
1772 | (and (< limit (point)) |
1773 | (eq (char-before) ?:))) | |
1774 | ||
a66cd3ee | 1775 | (defun c-search-uplist-for-classkey (paren-state) |
785eecbb | 1776 | ;; search for the containing class, returning a 2 element vector if |
0ec8351b BW |
1777 | ;; found. aref 0 contains the bufpos of the boi of the class key |
1778 | ;; line, and aref 1 contains the bufpos of the open brace. | |
a66cd3ee MS |
1779 | (if (null paren-state) |
1780 | ;; no paren-state means we cannot be inside a class | |
785eecbb | 1781 | nil |
a66cd3ee | 1782 | (let ((carcache (car paren-state)) |
785eecbb RS |
1783 | search-start search-end) |
1784 | (if (consp carcache) | |
1785 | ;; a cons cell in the first element means that there is some | |
1786 | ;; balanced sexp before the current bufpos. this we can | |
1787 | ;; ignore. the nth 1 and nth 2 elements define for us the | |
1788 | ;; search boundaries | |
a66cd3ee MS |
1789 | (setq search-start (nth 2 paren-state) |
1790 | search-end (nth 1 paren-state)) | |
785eecbb RS |
1791 | ;; if the car was not a cons cell then nth 0 and nth 1 define |
1792 | ;; for us the search boundaries | |
a66cd3ee MS |
1793 | (setq search-start (nth 1 paren-state) |
1794 | search-end (nth 0 paren-state))) | |
785eecbb RS |
1795 | ;; if search-end is nil, or if the search-end character isn't an |
1796 | ;; open brace, we are definitely not in a class | |
1797 | (if (or (not search-end) | |
1798 | (< search-end (point-min)) | |
1799 | (not (eq (char-after search-end) ?{))) | |
1800 | nil | |
1801 | ;; now, we need to look more closely at search-start. if | |
1802 | ;; search-start is nil, then our start boundary is really | |
1803 | ;; point-min. | |
1804 | (if (not search-start) | |
1805 | (setq search-start (point-min)) | |
1806 | ;; if search-start is a cons cell, then we can start | |
1807 | ;; searching from the end of the balanced sexp just ahead of | |
1808 | ;; us | |
1809 | (if (consp search-start) | |
1810 | (setq search-start (cdr search-start)))) | |
1811 | ;; now we can do a quick regexp search from search-start to | |
1812 | ;; search-end and see if we can find a class key. watch for | |
1813 | ;; class like strings in literals | |
1814 | (save-excursion | |
1815 | (save-restriction | |
1816 | (goto-char search-start) | |
a66cd3ee | 1817 | (let (foundp class match-end) |
785eecbb RS |
1818 | (while (and (not foundp) |
1819 | (progn | |
a66cd3ee | 1820 | (c-forward-syntactic-ws search-end) |
785eecbb | 1821 | (> search-end (point))) |
a66cd3ee | 1822 | (re-search-forward c-decl-block-key search-end t)) |
785eecbb RS |
1823 | (setq class (match-beginning 0) |
1824 | match-end (match-end 0)) | |
a66cd3ee | 1825 | (goto-char class) |
785eecbb | 1826 | (if (c-in-literal search-start) |
a66cd3ee MS |
1827 | (goto-char match-end) ; its in a comment or string, ignore |
1828 | (c-skip-ws-forward) | |
785eecbb RS |
1829 | (setq foundp (vector (c-point 'boi) search-end)) |
1830 | (cond | |
1831 | ;; check for embedded keywords | |
1832 | ((let ((char (char-after (1- class)))) | |
1833 | (and char | |
1834 | (memq (char-syntax char) '(?w ?_)))) | |
1835 | (goto-char match-end) | |
1836 | (setq foundp nil)) | |
1837 | ;; make sure we're really looking at the start of a | |
a66cd3ee MS |
1838 | ;; class definition, and not an ObjC method. |
1839 | ((and c-opt-method-key | |
1840 | (re-search-forward c-opt-method-key search-end t) | |
0ec8351b | 1841 | (not (c-in-literal class))) |
785eecbb | 1842 | (setq foundp nil)) |
0ec8351b | 1843 | ;; Check if this is an anonymous inner class. |
a66cd3ee MS |
1844 | ((and c-opt-inexpr-class-key |
1845 | (looking-at c-opt-inexpr-class-key)) | |
0ec8351b BW |
1846 | (while (and (= (c-forward-token-1 1 t) 0) |
1847 | (looking-at "(\\|\\w\\|\\s_\\|\\."))) | |
1848 | (if (eq (point) search-end) | |
1849 | ;; We're done. Just trap this case in the cond. | |
1850 | nil | |
1851 | ;; False alarm; all conditions aren't satisfied. | |
1852 | (setq foundp nil))) | |
785eecbb RS |
1853 | ;; Its impossible to define a regexp for this, and |
1854 | ;; nearly so to do it programmatically. | |
1855 | ;; | |
1856 | ;; ; picks up forward decls | |
1857 | ;; = picks up init lists | |
1858 | ;; ) picks up return types | |
1859 | ;; > picks up templates, but remember that we can | |
1860 | ;; inherit from templates! | |
1861 | ((let ((skipchars "^;=)")) | |
1862 | ;; try to see if we found the `class' keyword | |
1863 | ;; inside a template arg list | |
1864 | (save-excursion | |
1865 | (skip-chars-backward "^<>" search-start) | |
1866 | (if (eq (char-before) ?<) | |
1867 | (setq skipchars (concat skipchars ">")))) | |
0ec8351b BW |
1868 | (while (progn |
1869 | (skip-chars-forward skipchars search-end) | |
1870 | (c-in-literal class)) | |
1871 | (forward-char)) | |
785eecbb RS |
1872 | (/= (point) search-end)) |
1873 | (setq foundp nil)) | |
1874 | ))) | |
1875 | foundp)) | |
1876 | ))))) | |
1877 | ||
a66cd3ee | 1878 | (defun c-inside-bracelist-p (containing-sexp paren-state) |
785eecbb RS |
1879 | ;; return the buffer position of the beginning of the brace list |
1880 | ;; statement if we're inside a brace list, otherwise return nil. | |
1881 | ;; CONTAINING-SEXP is the buffer pos of the innermost containing | |
130c507e GM |
1882 | ;; paren. BRACE-STATE is the remainder of the state of enclosing |
1883 | ;; braces | |
785eecbb RS |
1884 | ;; |
1885 | ;; N.B.: This algorithm can potentially get confused by cpp macros | |
1886 | ;; places in inconvenient locations. Its a trade-off we make for | |
1887 | ;; speed. | |
1888 | (or | |
1889 | ;; this will pick up enum lists | |
b2acd789 RS |
1890 | (c-safe |
1891 | (save-excursion | |
1892 | (goto-char containing-sexp) | |
0ec8351b | 1893 | (c-forward-sexp -1) |
b2acd789 | 1894 | (let (bracepos) |
a66cd3ee | 1895 | (if (and (or (looking-at "enum\\>[^_]") |
0ec8351b | 1896 | (progn (c-forward-sexp -1) |
a66cd3ee MS |
1897 | (looking-at "enum\\>[^_]"))) |
1898 | (setq bracepos (c-down-list-forward (point))) | |
b2acd789 RS |
1899 | (not (c-crosses-statement-barrier-p (point) |
1900 | (- bracepos 2)))) | |
1901 | (point))))) | |
785eecbb RS |
1902 | ;; this will pick up array/aggregate init lists, even if they are nested. |
1903 | (save-excursion | |
0ec8351b BW |
1904 | (let ((class-key |
1905 | ;; Pike can have class definitions anywhere, so we must | |
1906 | ;; check for the class key here. | |
1907 | (and (c-major-mode-is 'pike-mode) | |
a66cd3ee MS |
1908 | c-decl-block-key)) |
1909 | bufpos braceassignp lim next-containing) | |
785eecbb RS |
1910 | (while (and (not bufpos) |
1911 | containing-sexp) | |
a66cd3ee MS |
1912 | (when paren-state |
1913 | (if (consp (car paren-state)) | |
1914 | (setq lim (cdr (car paren-state)) | |
1915 | paren-state (cdr paren-state)) | |
1916 | (setq lim (car paren-state))) | |
1917 | (when paren-state | |
1918 | (setq next-containing (car paren-state) | |
1919 | paren-state (cdr paren-state)))) | |
785eecbb | 1920 | (goto-char containing-sexp) |
a66cd3ee MS |
1921 | (if (c-looking-at-inexpr-block next-containing next-containing) |
1922 | ;; We're in an in-expression block of some kind. Do not | |
1923 | ;; check nesting. We deliberately set the limit to the | |
1924 | ;; containing sexp, so that c-looking-at-inexpr-block | |
1925 | ;; doesn't check for an identifier before it. | |
0ec8351b BW |
1926 | (setq containing-sexp nil) |
1927 | ;; see if the open brace is preceded by = or [...] in | |
1928 | ;; this statement, but watch out for operator= | |
a66cd3ee | 1929 | (setq braceassignp 'dontknow) |
6393fef2 RS |
1930 | (c-backward-token-1 1 t lim) |
1931 | ;; Checks to do only on the first sexp before the brace. | |
1932 | (when (and (c-major-mode-is 'java-mode) | |
1933 | (eq (char-after) ?\[)) | |
1934 | ;; In Java, an initialization brace list may follow | |
1935 | ;; directly after "new Foo[]", so check for a "new" | |
1936 | ;; earlier. | |
1937 | (while (eq braceassignp 'dontknow) | |
1938 | (setq braceassignp | |
1939 | (cond ((/= (c-backward-token-1 1 t lim) 0) nil) | |
130c507e | 1940 | ((looking-at "new\\>[^_]") t) |
6393fef2 RS |
1941 | ((looking-at "\\sw\\|\\s_\\|[.[]") |
1942 | ;; Carry on looking if this is an | |
1943 | ;; identifier (may contain "." in Java) | |
1944 | ;; or another "[]" sexp. | |
1945 | 'dontknow) | |
1946 | (t nil))))) | |
1947 | ;; Checks to do on all sexps before the brace, up to the | |
1948 | ;; beginning of the statement. | |
1949 | (while (eq braceassignp 'dontknow) | |
0ec8351b BW |
1950 | (cond ((eq (char-after) ?\;) |
1951 | (setq braceassignp nil)) | |
1952 | ((and class-key | |
1953 | (looking-at class-key)) | |
1954 | (setq braceassignp nil)) | |
1955 | ((eq (char-after) ?=) | |
1956 | ;; We've seen a =, but must check earlier tokens so | |
1957 | ;; that it isn't something that should be ignored. | |
1958 | (setq braceassignp 'maybe) | |
1959 | (while (and (eq braceassignp 'maybe) | |
1960 | (zerop (c-backward-token-1 1 t lim))) | |
1961 | (setq braceassignp | |
1962 | (cond | |
1963 | ;; Check for operator = | |
a66cd3ee | 1964 | ((looking-at "operator\\>[^_]") nil) |
130c507e GM |
1965 | ;; Check for `<opchar>= in Pike. |
1966 | ((and (c-major-mode-is 'pike-mode) | |
1967 | (or (eq (char-after) ?`) | |
1968 | ;; Special case for Pikes | |
1969 | ;; `[]=, since '[' is not in | |
1970 | ;; the punctuation class. | |
1971 | (and (eq (char-after) ?\[) | |
1972 | (eq (char-before) ?`)))) | |
1973 | nil) | |
0ec8351b BW |
1974 | ((looking-at "\\s.") 'maybe) |
1975 | ;; make sure we're not in a C++ template | |
1976 | ;; argument assignment | |
a66cd3ee MS |
1977 | ((and |
1978 | (c-major-mode-is 'c++-mode) | |
1979 | (save-excursion | |
1980 | (let ((here (point)) | |
1981 | (pos< (progn | |
1982 | (skip-chars-backward "^<>") | |
1983 | (point)))) | |
1984 | (and (eq (char-before) ?<) | |
1985 | (not (c-crosses-statement-barrier-p | |
1986 | pos< here)) | |
1987 | (not (c-in-literal)) | |
1988 | )))) | |
0ec8351b | 1989 | nil) |
6393fef2 RS |
1990 | (t t)))))) |
1991 | (if (and (eq braceassignp 'dontknow) | |
1992 | (/= (c-backward-token-1 1 t lim) 0)) | |
1993 | (setq braceassignp nil))) | |
1994 | (if (not braceassignp) | |
0ec8351b BW |
1995 | (if (eq (char-after) ?\;) |
1996 | ;; Brace lists can't contain a semicolon, so we're done. | |
1997 | (setq containing-sexp nil) | |
a66cd3ee MS |
1998 | ;; Go up one level. |
1999 | (setq containing-sexp next-containing | |
2000 | lim nil | |
2001 | next-containing nil)) | |
0ec8351b BW |
2002 | ;; we've hit the beginning of the aggregate list |
2003 | (c-beginning-of-statement-1 | |
a66cd3ee | 2004 | (c-most-enclosing-brace paren-state)) |
0ec8351b | 2005 | (setq bufpos (point)))) |
a66cd3ee | 2006 | ) |
785eecbb RS |
2007 | bufpos)) |
2008 | )) | |
2009 | ||
0ec8351b BW |
2010 | (defun c-looking-at-special-brace-list (&optional lim) |
2011 | Content-type: text/html