-
Notifications
You must be signed in to change notification settings - Fork 0
/
cc-engine.el
11114 lines (10118 loc) · 402 KB
/
cc-engine.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;; cc-engine.el --- core syntax guessing engine for CC mode
;; Copyright (C) 1985, 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
;; 2010, 2011 Free Software Foundation, Inc.
;; Authors: 2001- Alan Mackenzie
;; 1998- Martin Stjernholm
;; 1992-1999 Barry A. Warsaw
;; 1987 Dave Detlefs and Stewart Clamen
;; 1985 Richard M. Stallman
;; Maintainer: [email protected]
;; Created: 22-Apr-1997 (split from cc-mode.el)
;; Version: See cc-mode.el
;; Keywords: c languages oop
;; This file is part of GNU Emacs.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING. If not, see
;; <http://www.gnu.org/licenses/>.
;;; Commentary:
;; The functions which have docstring documentation can be considered
;; part of an API which other packages can use in CC Mode buffers.
;; Otoh, undocumented functions and functions with the documentation
;; in comments are considered purely internal and can change semantics
;; or even disappear in the future.
;;
;; (This policy applies to CC Mode as a whole, not just this file. It
;; probably also applies to many other Emacs packages, but here it's
;; clearly spelled out.)
;; Hidden buffer changes
;;
;; Various functions in CC Mode use text properties for caching and
;; syntactic markup purposes, and those of them that might modify such
;; properties but still don't modify the buffer in a visible way are
;; said to do "hidden buffer changes". They should be used within
;; `c-save-buffer-state' or a similar function that saves and restores
;; buffer modifiedness, disables buffer change hooks, etc.
;;
;; Interactive functions are assumed to not do hidden buffer changes,
;; except in the specific parts of them that do real changes.
;;
;; Lineup functions are assumed to do hidden buffer changes. They
;; must not do real changes, though.
;;
;; All other functions that do hidden buffer changes have that noted
;; in their doc string or comment.
;;
;; The intention with this system is to avoid wrapping every leaf
;; function that do hidden buffer changes inside
;; `c-save-buffer-state'. It should be used as near the top of the
;; interactive functions as possible.
;;
;; Functions called during font locking are allowed to do hidden
;; buffer changes since the font-lock package run them in a context
;; similar to `c-save-buffer-state' (in fact, that function is heavily
;; inspired by `save-buffer-state' in the font-lock package).
;; Use of text properties
;;
;; CC Mode uses several text properties internally to mark up various
;; positions, e.g. to improve speed and to eliminate glitches in
;; interactive refontification.
;;
;; Note: This doc is for internal use only. Other packages should not
;; assume that these text properties are used as described here.
;;
;; 'category
;; Used for "indirection". With its help, some other property can
;; be cheaply and easily switched on or off everywhere it occurs.
;;
;; 'syntax-table
;; Used to modify the syntax of some characters. It is used to
;; mark the "<" and ">" of angle bracket parens with paren syntax, and
;; to "hide" obtrusive characters in preprocessor lines.
;;
;; This property is used on single characters and is therefore
;; always treated as front and rear nonsticky (or start and end open
;; in XEmacs vocabulary). It's therefore installed on
;; `text-property-default-nonsticky' if that variable exists (Emacs
;; >= 21).
;;
;; 'c-is-sws and 'c-in-sws
;; Used by `c-forward-syntactic-ws' and `c-backward-syntactic-ws' to
;; speed them up. See the comment blurb before `c-put-is-sws'
;; below for further details.
;;
;; 'c-type
;; This property is used on single characters to mark positions with
;; special syntactic relevance of various sorts. Its primary use is
;; to avoid glitches when multiline constructs are refontified
;; interactively (on font lock decoration level 3). It's cleared in
;; a region before it's fontified and is then put on relevant chars
;; in that region as they are encountered during the fontification.
;; The value specifies the kind of position:
;;
;; 'c-decl-arg-start
;; Put on the last char of the token preceding each declaration
;; inside a declaration style arglist (typically in a function
;; prototype).
;;
;; 'c-decl-end
;; Put on the last char of the token preceding a declaration.
;; This is used in cases where declaration boundaries can't be
;; recognized simply by looking for a token like ";" or "}".
;; `c-type-decl-end-used' must be set if this is used (see also
;; `c-find-decl-spots').
;;
;; 'c-<>-arg-sep
;; Put on the commas that separate arguments in angle bracket
;; arglists like C++ template arglists.
;;
;; 'c-decl-id-start and 'c-decl-type-start
;; Put on the last char of the token preceding each declarator
;; in the declarator list of a declaration. They are also used
;; between the identifiers cases like enum declarations.
;; 'c-decl-type-start is used when the declarators are types,
;; 'c-decl-id-start otherwise.
;;
;; 'c-awk-NL-prop
;; Used in AWK mode to mark the various kinds of newlines. See
;; cc-awk.el.
;;; Code:
(eval-when-compile
(let ((load-path
(if (and (boundp 'byte-compile-dest-file)
(stringp byte-compile-dest-file))
(cons (file-name-directory byte-compile-dest-file) load-path)
load-path)))
(load "cc-bytecomp" nil t)))
(cc-require 'cc-defs)
(cc-require-when-compile 'cc-langs)
(cc-require 'cc-vars)
;; Silence the compiler.
(cc-bytecomp-defun buffer-syntactic-context) ; XEmacs
(cc-bytecomp-defun c-fontify-recorded-types-and-refs)
(cc-bytecomp-defvar c-maybe-stale-found-type)
;; Make declarations for all the `c-lang-defvar' variables in cc-langs.
(defmacro c-declare-lang-variables ()
`(progn
,@(mapcan (lambda (init)
`(,(if (elt init 2)
`(defvar ,(car init) nil ,(elt init 2))
`(defvar ,(car init) nil))
(make-variable-buffer-local ',(car init))))
(cdr c-lang-variable-inits))))
(c-declare-lang-variables)
;;; Internal state variables.
;; Internal state of hungry delete key feature
(defvar c-hungry-delete-key nil)
(make-variable-buffer-local 'c-hungry-delete-key)
;; The electric flag (toggled by `c-toggle-electric-state').
;; If t, electric actions (like automatic reindentation, and (if
;; c-auto-newline is also set) auto newlining) will happen when an electric
;; key like `{' is pressed (or an electric keyword like `else').
(defvar c-electric-flag t)
(make-variable-buffer-local 'c-electric-flag)
;; Internal state of auto newline feature.
(defvar c-auto-newline nil)
(make-variable-buffer-local 'c-auto-newline)
;; Included in the mode line to indicate the active submodes.
;; (defvar c-submode-indicators nil)
;; (make-variable-buffer-local 'c-submode-indicators)
(defun c-calculate-state (arg prevstate)
;; Calculate the new state of PREVSTATE, t or nil, based on arg. If
;; arg is nil or zero, toggle the state. If arg is negative, turn
;; the state off, and if arg is positive, turn the state on
(if (or (not arg)
(zerop (setq arg (prefix-numeric-value arg))))
(not prevstate)
(> arg 0)))
;; Basic handling of preprocessor directives.
;; This is a dynamically bound cache used together with
;; `c-query-macro-start' and `c-query-and-set-macro-start'. It only
;; works as long as point doesn't cross a macro boundary.
(defvar c-macro-start 'unknown)
(defsubst c-query-and-set-macro-start ()
(if (symbolp c-macro-start)
(setq c-macro-start (save-excursion
(c-save-buffer-state ()
(and (c-beginning-of-macro)
(point)))))
c-macro-start))
(defsubst c-query-macro-start ()
(if (symbolp c-macro-start)
(save-excursion
(c-save-buffer-state ()
(and (c-beginning-of-macro)
(point))))
c-macro-start))
;; One element macro cache to cope with continual movement within very large
;; CPP macros.
(defvar c-macro-cache nil)
(make-variable-buffer-local 'c-macro-cache)
;; Nil or cons of the bounds of the most recent CPP form probed by
;; `c-beginning-of-macro', `c-end-of-macro' or `c-syntactic-end-of-macro'.
;; The cdr will be nil if we know only the start of the CPP form.
(defvar c-macro-cache-start-pos nil)
(make-variable-buffer-local 'c-macro-cache-start-pos)
;; The starting position from where we determined `c-macro-cache'.
(defvar c-macro-cache-syntactic nil)
(make-variable-buffer-local 'c-macro-cache-syntactic)
;; non-nil iff `c-macro-cache' has both elements set AND the cdr is at a
;; syntactic end of macro, not merely an apparent one.
(defun c-invalidate-macro-cache (beg end)
;; Called from a before-change function. If the change region is before or
;; in the macro characterized by `c-macro-cache' etc., nullify it
;; appropriately. BEG and END are the standard before-change-functions
;; parameters. END isn't used.
(cond
((null c-macro-cache))
((< beg (car c-macro-cache))
(setq c-macro-cache nil
c-macro-cache-start-pos nil
c-macro-cache-syntactic nil))
((and (cdr c-macro-cache)
(< beg (cdr c-macro-cache)))
(setcdr c-macro-cache nil)
(setq c-macro-cache-start-pos beg
c-macro-cache-syntactic nil))))
(defun c-macro-is-genuine-p ()
;; Check that the ostensible CPP construct at point is a real one. In
;; particular, if point is on the first line of a narrowed buffer, make sure
;; that the "#" isn't, say, the second character of a "##" operator. Return
;; t when the macro is real, nil otherwise.
(let ((here (point)))
(beginning-of-line)
(prog1
(if (and (eq (point) (point-min))
(/= (point) 1))
(save-restriction
(widen)
(beginning-of-line)
(and (looking-at c-anchored-cpp-prefix)
(eq (match-beginning 1) here)))
t)
(goto-char here))))
(defun c-beginning-of-macro (&optional lim)
"Go to the beginning of a preprocessor directive.
Leave point at the beginning of the directive and return t if in one,
otherwise return nil and leave point unchanged.
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
(let ((here (point)))
(when c-opt-cpp-prefix
(if (and (car c-macro-cache)
(>= (point) (car c-macro-cache))
(or (and (cdr c-macro-cache)
(<= (point) (cdr c-macro-cache)))
(<= (point) c-macro-cache-start-pos)))
(unless (< (car c-macro-cache) (or lim (point-min)))
(progn (goto-char (max (or lim (point-min)) (car c-macro-cache)))
(setq c-macro-cache-start-pos
(max c-macro-cache-start-pos here))
t))
(setq c-macro-cache nil
c-macro-cache-start-pos nil
c-macro-cache-syntactic nil)
(save-restriction
(if lim (narrow-to-region lim (point-max)))
(beginning-of-line)
(while (eq (char-before (1- (point))) ?\\)
(forward-line -1))
(back-to-indentation)
(if (and (<= (point) here)
(looking-at c-opt-cpp-start)
(c-macro-is-genuine-p))
(progn
(setq c-macro-cache (cons (point) nil)
c-macro-cache-start-pos here)
t)
(goto-char here)
nil))))))
(defun c-end-of-macro ()
"Go to the end of a preprocessor directive.
More accurately, move the point to the end of the closest following
line that doesn't end with a line continuation backslash - no check is
done that the point is inside a cpp directive to begin with.
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
(if (and (cdr c-macro-cache)
(<= (point) (cdr c-macro-cache))
(>= (point) (car c-macro-cache)))
(goto-char (cdr c-macro-cache))
(unless (and (car c-macro-cache)
(<= (point) c-macro-cache-start-pos)
(>= (point) (car c-macro-cache)))
(setq c-macro-cache nil
c-macro-cache-start-pos nil
c-macro-cache-syntactic nil))
(while (progn
(end-of-line)
(when (and (eq (char-before) ?\\)
(not (eobp)))
(forward-char)
t)))
(when (car c-macro-cache)
(setcdr c-macro-cache (point)))))
(defun c-syntactic-end-of-macro ()
;; Go to the end of a CPP directive, or a "safe" pos just before.
;;
;; This is normally the end of the next non-escaped line. A "safe"
;; position is one not within a string or comment. (The EOL on a line
;; comment is NOT "safe").
;;
;; This function must only be called from the beginning of a CPP construct.
;;
;; Note that this function might do hidden buffer changes. See the comment
;; at the start of cc-engine.el for more info.
(let* ((here (point))
(there (progn (c-end-of-macro) (point)))
s)
(unless c-macro-cache-syntactic
(setq s (parse-partial-sexp here there))
(while (and (or (nth 3 s) ; in a string
(nth 4 s)) ; in a comment (maybe at end of line comment)
(> there here)) ; No infinite loops, please.
(setq there (1- (nth 8 s)))
(setq s (parse-partial-sexp here there)))
(setq c-macro-cache-syntactic (car c-macro-cache)))
(point)))
(defun c-forward-over-cpp-define-id ()
;; Assuming point is at the "#" that introduces a preprocessor
;; directive, it's moved forward to the end of the identifier which is
;; "#define"d (or whatever c-opt-cpp-macro-define specifies). Non-nil
;; is returned in this case, in all other cases nil is returned and
;; point isn't moved.
;;
;; This function might do hidden buffer changes.
(when (and c-opt-cpp-macro-define-id
(looking-at c-opt-cpp-macro-define-id))
(goto-char (match-end 0))))
(defun c-forward-to-cpp-define-body ()
;; Assuming point is at the "#" that introduces a preprocessor
;; directive, it's moved forward to the start of the definition body
;; if it's a "#define" (or whatever c-opt-cpp-macro-define
;; specifies). Non-nil is returned in this case, in all other cases
;; nil is returned and point isn't moved.
;;
;; This function might do hidden buffer changes.
(when (and c-opt-cpp-macro-define-start
(looking-at c-opt-cpp-macro-define-start)
(not (= (match-end 0) (c-point 'eol))))
(goto-char (match-end 0))))
;;; Basic utility functions.
(defun c-syntactic-content (from to paren-level)
;; Return the given region as a string where all syntactic
;; whitespace is removed or, where necessary, replaced with a single
;; space. If PAREN-LEVEL is given then all parens in the region are
;; collapsed to "()", "[]" etc.
;;
;; This function might do hidden buffer changes.
(save-excursion
(save-restriction
(narrow-to-region from to)
(goto-char from)
(let* ((parts (list nil)) (tail parts) pos in-paren)
(while (re-search-forward c-syntactic-ws-start to t)
(goto-char (setq pos (match-beginning 0)))
(c-forward-syntactic-ws)
(if (= (point) pos)
(forward-char)
(when paren-level
(save-excursion
(setq in-paren (= (car (parse-partial-sexp from pos 1)) 1)
pos (point))))
(if (and (> pos from)
(< (point) to)
(looking-at "\\w\\|\\s_")
(save-excursion
(goto-char (1- pos))
(looking-at "\\w\\|\\s_")))
(progn
(setcdr tail (list (buffer-substring-no-properties from pos)
" "))
(setq tail (cddr tail)))
(setcdr tail (list (buffer-substring-no-properties from pos)))
(setq tail (cdr tail)))
(when in-paren
(when (= (car (parse-partial-sexp pos to -1)) -1)
(setcdr tail (list (buffer-substring-no-properties
(1- (point)) (point))))
(setq tail (cdr tail))))
(setq from (point))))
(setcdr tail (list (buffer-substring-no-properties from to)))
(apply 'concat (cdr parts))))))
(defun c-shift-line-indentation (shift-amt)
;; Shift the indentation of the current line with the specified
;; amount (positive inwards). The buffer is modified only if
;; SHIFT-AMT isn't equal to zero.
(let ((pos (- (point-max) (point)))
(c-macro-start c-macro-start)
tmp-char-inserted)
(if (zerop shift-amt)
nil
;; If we're on an empty line inside a macro, we take the point
;; to be at the current indentation and shift it to the
;; appropriate column. This way we don't treat the extra
;; whitespace out to the line continuation as indentation.
(when (and (c-query-and-set-macro-start)
(looking-at "[ \t]*\\\\$")
(save-excursion
(skip-chars-backward " \t")
(bolp)))
(insert ?x)
(backward-char)
(setq tmp-char-inserted t))
(unwind-protect
(let ((col (current-indentation)))
(delete-region (c-point 'bol) (c-point 'boi))
(beginning-of-line)
(indent-to (+ col shift-amt)))
(when tmp-char-inserted
(delete-char 1))))
;; If initial point was within line's indentation and we're not on
;; a line with a line continuation in a macro, position after the
;; indentation. Else stay at same point in text.
(if (and (< (point) (c-point 'boi))
(not tmp-char-inserted))
(back-to-indentation)
(if (> (- (point-max) pos) (point))
(goto-char (- (point-max) pos))))))
(defsubst c-keyword-sym (keyword)
;; Return non-nil if the string KEYWORD is a known keyword. More
;; precisely, the value is the symbol for the keyword in
;; `c-keywords-obarray'.
(intern-soft keyword c-keywords-obarray))
(defsubst c-keyword-member (keyword-sym lang-constant)
;; Return non-nil if the symbol KEYWORD-SYM, as returned by
;; `c-keyword-sym', is a member of LANG-CONSTANT, which is the name
;; of a language constant that ends with "-kwds". If KEYWORD-SYM is
;; nil then the result is nil.
(get keyword-sym lang-constant))
;; String syntax chars, suitable for skip-syntax-(forward|backward).
(defconst c-string-syntax (if (memq 'gen-string-delim c-emacs-features)
"\"|"
"\""))
;; Regexp matching string limit syntax.
(defconst c-string-limit-regexp (if (memq 'gen-string-delim c-emacs-features)
"\\s\"\\|\\s|"
"\\s\""))
;; Regexp matching WS followed by string limit syntax.
(defconst c-ws*-string-limit-regexp
(concat "[ \t]*\\(" c-string-limit-regexp "\\)"))
;; Holds formatted error strings for the few cases where parse errors
;; are reported.
(defvar c-parsing-error nil)
(make-variable-buffer-local 'c-parsing-error)
(defun c-echo-parsing-error (&optional quiet)
(when (and c-report-syntactic-errors c-parsing-error (not quiet))
(c-benign-error "%s" c-parsing-error))
c-parsing-error)
;; Faces given to comments and string literals. This is used in some
;; situations to speed up recognition; it isn't mandatory that font
;; locking is in use. This variable is extended with the face in
;; `c-doc-face-name' when fontification is activated in cc-fonts.el.
(defvar c-literal-faces
(append '(font-lock-comment-face font-lock-string-face)
(when (facep 'font-lock-comment-delimiter-face)
;; New in Emacs 22.
'(font-lock-comment-delimiter-face))))
(defsubst c-put-c-type-property (pos value)
;; Put a c-type property with the given value at POS.
(c-put-char-property pos 'c-type value))
(defun c-clear-c-type-property (from to value)
;; Remove all occurrences of the c-type property that has the given
;; value in the region between FROM and TO. VALUE is assumed to not
;; be nil.
;;
;; Note: This assumes that c-type is put on single chars only; it's
;; very inefficient if matching properties cover large regions.
(save-excursion
(goto-char from)
(while (progn
(when (eq (get-text-property (point) 'c-type) value)
(c-clear-char-property (point) 'c-type))
(goto-char (c-next-single-property-change (point) 'c-type nil to))
(< (point) to)))))
;; Some debug tools to visualize various special positions. This
;; debug code isn't as portable as the rest of CC Mode.
(cc-bytecomp-defun overlays-in)
(cc-bytecomp-defun overlay-get)
(cc-bytecomp-defun overlay-start)
(cc-bytecomp-defun overlay-end)
(cc-bytecomp-defun delete-overlay)
(cc-bytecomp-defun overlay-put)
(cc-bytecomp-defun make-overlay)
(defun c-debug-add-face (beg end face)
(c-save-buffer-state ((overlays (overlays-in beg end)) overlay)
(while overlays
(setq overlay (car overlays)
overlays (cdr overlays))
(when (eq (overlay-get overlay 'face) face)
(setq beg (min beg (overlay-start overlay))
end (max end (overlay-end overlay)))
(delete-overlay overlay)))
(overlay-put (make-overlay beg end) 'face face)))
(defun c-debug-remove-face (beg end face)
(c-save-buffer-state ((overlays (overlays-in beg end)) overlay
(ol-beg beg) (ol-end end))
(while overlays
(setq overlay (car overlays)
overlays (cdr overlays))
(when (eq (overlay-get overlay 'face) face)
(setq ol-beg (min ol-beg (overlay-start overlay))
ol-end (max ol-end (overlay-end overlay)))
(delete-overlay overlay)))
(when (< ol-beg beg)
(overlay-put (make-overlay ol-beg beg) 'face face))
(when (> ol-end end)
(overlay-put (make-overlay end ol-end) 'face face))))
;; `c-beginning-of-statement-1' and accompanying stuff.
;; KLUDGE ALERT: c-maybe-labelp is used to pass information between
;; c-crosses-statement-barrier-p and c-beginning-of-statement-1. A
;; better way should be implemented, but this will at least shut up
;; the byte compiler.
(defvar c-maybe-labelp)
;; New awk-compatible version of c-beginning-of-statement-1, ACM 2002/6/22
;; Macros used internally in c-beginning-of-statement-1 for the
;; automaton actions.
(defmacro c-bos-push-state ()
'(setq stack (cons (cons state saved-pos)
stack)))
(defmacro c-bos-pop-state (&optional do-if-done)
`(if (setq state (car (car stack))
saved-pos (cdr (car stack))
stack (cdr stack))
t
,do-if-done
(throw 'loop nil)))
(defmacro c-bos-pop-state-and-retry ()
'(throw 'loop (setq state (car (car stack))
saved-pos (cdr (car stack))
;; Throw nil if stack is empty, else throw non-nil.
stack (cdr stack))))
(defmacro c-bos-save-pos ()
'(setq saved-pos (vector pos tok ptok pptok)))
(defmacro c-bos-restore-pos ()
'(unless (eq (elt saved-pos 0) start)
(setq pos (elt saved-pos 0)
tok (elt saved-pos 1)
ptok (elt saved-pos 2)
pptok (elt saved-pos 3))
(goto-char pos)
(setq sym nil)))
(defmacro c-bos-save-error-info (missing got)
`(setq saved-pos (vector pos ,missing ,got)))
(defmacro c-bos-report-error ()
'(unless noerror
(setq c-parsing-error
(format "No matching `%s' found for `%s' on line %d"
(elt saved-pos 1)
(elt saved-pos 2)
(1+ (count-lines (point-min)
(c-point 'bol (elt saved-pos 0))))))))
(defun c-beginning-of-statement-1 (&optional lim ignore-labels
noerror comma-delim)
"Move to the start of the current statement or declaration, or to
the previous one if already at the beginning of one. Only
statements/declarations on the same level are considered, i.e. don't
move into or out of sexps (not even normal expression parentheses).
If point is already at the earliest statement within braces or parens,
this function doesn't move back into any whitespace preceding it; it
returns 'same in this case.
Stop at statement continuation tokens like \"else\", \"catch\",
\"finally\" and the \"while\" in \"do ... while\" if the start point
is within the continuation. If starting at such a token, move to the
corresponding statement start. If at the beginning of a statement,
move to the closest containing statement if there is any. This might
also stop at a continuation clause.
Labels are treated as part of the following statements if
IGNORE-LABELS is non-nil. (FIXME: Doesn't work if we stop at a known
statement start keyword.) Otherwise, each label is treated as a
separate statement.
Macros are ignored \(i.e. skipped over) unless point is within one, in
which case the content of the macro is treated as normal code. Aside
from any normal statement starts found in it, stop at the first token
of the content in the macro, i.e. the expression of an \"#if\" or the
start of the definition in a \"#define\". Also stop at start of
macros before leaving them.
Return:
'label if stopped at a label or \"case...:\" or \"default:\";
'same if stopped at the beginning of the current statement;
'up if stepped to a containing statement;
'previous if stepped to a preceding statement;
'beginning if stepped from a statement continuation clause to
its start clause; or
'macro if stepped to a macro start.
Note that 'same and not 'label is returned if stopped at the same
label without crossing the colon character.
LIM may be given to limit the search. If the search hits the limit,
point will be left at the closest following token, or at the start
position if that is less ('same is returned in this case).
NOERROR turns off error logging to `c-parsing-error'.
Normally only ';' and virtual semicolons are considered to delimit
statements, but if COMMA-DELIM is non-nil then ',' is treated
as a delimiter too.
Note that this function might do hidden buffer changes. See the
comment at the start of cc-engine.el for more info."
;; The bulk of this function is a pushdown automaton that looks at statement
;; boundaries and the tokens (such as "while") in c-opt-block-stmt-key. Its
;; purpose is to keep track of nested statements, ensuring that such
;; statements are skipped over in their entirety (somewhat akin to what C-M-p
;; does with nested braces/brackets/parentheses).
;;
;; Note: The position of a boundary is the following token.
;;
;; Beginning with the current token (the one following point), move back one
;; sexp at a time (where a sexp is, more or less, either a token or the
;; entire contents of a brace/bracket/paren pair). Each time a statement
;; boundary is crossed or a "while"-like token is found, update the state of
;; the PDA. Stop at the beginning of a statement when the stack (holding
;; nested statement info) is empty and the position has been moved.
;;
;; The following variables constitute the PDA:
;;
;; sym: This is either the "while"-like token (e.g. 'for) we've just
;; scanned back over, 'boundary if we've just gone back over a
;; statement boundary, or nil otherwise.
;; state: takes one of the values (nil else else-boundary while
;; while-boundary catch catch-boundary).
;; nil means "no "while"-like token yet scanned".
;; 'else, for example, means "just gone back over an else".
;; 'else-boundary means "just gone back over a statement boundary
;; immediately after having gone back over an else".
;; saved-pos: A vector of either saved positions (tok ptok pptok, etc.) or
;; of error reporting information.
;; stack: The stack onto which the PDA pushes its state. Each entry
;; consists of a saved value of state and saved-pos. An entry is
;; pushed when we move back over a "continuation" token (e.g. else)
;; and popped when we encounter the corresponding opening token
;; (e.g. if).
;;
;;
;; The following diagram briefly outlines the PDA.
;;
;; Common state:
;; "else": Push state, goto state `else'.
;; "while": Push state, goto state `while'.
;; "catch" or "finally": Push state, goto state `catch'.
;; boundary: Pop state.
;; other: Do nothing special.
;;
;; State `else':
;; boundary: Goto state `else-boundary'.
;; other: Error, pop state, retry token.
;;
;; State `else-boundary':
;; "if": Pop state.
;; boundary: Error, pop state.
;; other: See common state.
;;
;; State `while':
;; boundary: Save position, goto state `while-boundary'.
;; other: Pop state, retry token.
;;
;; State `while-boundary':
;; "do": Pop state.
;; boundary: Restore position if it's not at start, pop state. [*see below]
;; other: See common state.
;;
;; State `catch':
;; boundary: Goto state `catch-boundary'.
;; other: Error, pop state, retry token.
;;
;; State `catch-boundary':
;; "try": Pop state.
;; "catch": Goto state `catch'.
;; boundary: Error, pop state.
;; other: See common state.
;;
;; [*] In the `while-boundary' state, we had pushed a 'while state, and were
;; searching for a "do" which would have opened a do-while. If we didn't
;; find it, we discard the analysis done since the "while", go back to this
;; token in the buffer and restart the scanning there, this time WITHOUT
;; pushing the 'while state onto the stack.
;;
;; In addition to the above there is some special handling of labels
;; and macros.
(let ((case-fold-search nil)
(start (point))
macro-start
(delims (if comma-delim '(?\; ?,) '(?\;)))
(c-stmt-delim-chars (if comma-delim
c-stmt-delim-chars-with-comma
c-stmt-delim-chars))
c-in-literal-cache c-maybe-labelp after-case:-pos saved
;; Current position.
pos
;; Position of last stmt boundary character (e.g. ;).
boundary-pos
;; The position of the last sexp or bound that follows the
;; first found colon, i.e. the start of the nonlabel part of
;; the statement. It's `start' if a colon is found just after
;; the start.
after-labels-pos
;; Like `after-labels-pos', but the first such position inside
;; a label, i.e. the start of the last label before the start
;; of the nonlabel part of the statement.
last-label-pos
;; The last position where a label is possible provided the
;; statement started there. It's nil as long as no invalid
;; label content has been found (according to
;; `c-nonlabel-token-key'). It's `start' if no valid label
;; content was found in the label. Note that we might still
;; regard it a label if it starts with `c-label-kwds'.
label-good-pos
;; Putative positions of the components of a bitfield declaration,
;; e.g. "int foo : NUM_FOO_BITS ;"
bitfield-type-pos bitfield-id-pos bitfield-size-pos
;; Symbol just scanned back over (e.g. 'while or 'boundary).
;; See above.
sym
;; Current state in the automaton. See above.
state
;; Current saved positions. See above.
saved-pos
;; Stack of conses (state . saved-pos).
stack
;; Regexp which matches "for", "if", etc.
(cond-key (or c-opt-block-stmt-key
"\\<\\>")) ; Matches nothing.
;; Return value.
(ret 'same)
;; Positions of the last three sexps or bounds we've stopped at.
tok ptok pptok)
(save-restriction
(if lim (narrow-to-region lim (point-max)))
(if (save-excursion
(and (c-beginning-of-macro)
(/= (point) start)))
(setq macro-start (point)))
;; Try to skip back over unary operator characters, to register
;; that we've moved.
(while (progn
(setq pos (point))
(c-backward-syntactic-ws)
;; Protect post-++/-- operators just before a virtual semicolon.
(and (not (c-at-vsemi-p))
(/= (skip-chars-backward "-+!*&~@`#") 0))))
;; Skip back over any semicolon here. If it was a bare semicolon, we're
;; done. Later on we ignore the boundaries for statements that don't
;; contain any sexp. The only thing that is affected is that the error
;; checking is a little less strict, and we really don't bother.
(if (and (memq (char-before) delims)
(progn (forward-char -1)
(setq saved (point))
(c-backward-syntactic-ws)
(or (memq (char-before) delims)
(memq (char-before) '(?: nil))
(eq (char-syntax (char-before)) ?\()
(c-at-vsemi-p))))
(setq ret 'previous
pos saved)
;; Begin at start and not pos to detect macros if we stand
;; directly after the #.
(goto-char start)
(if (looking-at "\\<\\|\\W")
;; Record this as the first token if not starting inside it.
(setq tok start))
;; The following while loop goes back one sexp (balanced parens,
;; etc. with contents, or symbol or suchlike) each iteration. This
;; movement is accomplished with a call to c-backward-sexp approx 170
;; lines below.
;;
;; The loop is exited only by throwing nil to the (catch 'loop ...):
;; 1. On reaching the start of a macro;
;; 2. On having passed a stmt boundary with the PDA stack empty;
;; 3. On reaching the start of an Objective C method def;
;; 4. From macro `c-bos-pop-state'; when the stack is empty;
;; 5. From macro `c-bos-pop-state-and-retry' when the stack is empty.
(while
(catch 'loop ;; Throw nil to break, non-nil to continue.
(cond
;; Are we in a macro, just after the opening #?
((save-excursion
(and macro-start ; Always NIL for AWK.
(progn (skip-chars-backward " \t")
(eq (char-before) ?#))
(progn (setq saved (1- (point)))
(beginning-of-line)
(not (eq (char-before (1- (point))) ?\\)))
(looking-at c-opt-cpp-start)
(progn (skip-chars-forward " \t")
(eq (point) saved))))
(goto-char saved)
(if (and (c-forward-to-cpp-define-body)
(progn (c-forward-syntactic-ws start)
(< (point) start)))
;; Stop at the first token in the content of the macro.
(setq pos (point)
ignore-labels t) ; Avoid the label check on exit.
(setq pos saved
ret 'macro
ignore-labels t))
(throw 'loop nil)) ; 1. Start of macro.
;; Do a round through the automaton if we've just passed a
;; statement boundary or passed a "while"-like token.
((or sym
(and (looking-at cond-key)
(setq sym (intern (match-string 1)))))
(when (and (< pos start) (null stack))
(throw 'loop nil)) ; 2. Statement boundary.
;; The PDA state handling.
;;
;; Refer to the description of the PDA in the opening
;; comments. In the following OR form, the first leaf
;; attempts to handles one of the specific actions detailed
;; (e.g., finding token "if" whilst in state `else-boundary').
;; We drop through to the second leaf (which handles common
;; state) if no specific handler is found in the first cond.
;; If a parsing error is detected (e.g. an "else" with no
;; preceding "if"), we throw to the enclosing catch.
;;
;; Note that the (eq state 'else) means
;; "we've just passed an else", NOT "we're looking for an
;; else".
(or (cond
((eq state 'else)
(if (eq sym 'boundary)
(setq state 'else-boundary)
(c-bos-report-error)
(c-bos-pop-state-and-retry)))
((eq state 'else-boundary)
(cond ((eq sym 'if)
(c-bos-pop-state (setq ret 'beginning)))
((eq sym 'boundary)
(c-bos-report-error)
(c-bos-pop-state))))
((eq state 'while)
(if (and (eq sym 'boundary)
;; Since this can cause backtracking we do a
;; little more careful analysis to avoid it:
;; If there's a label in front of the while
;; it can't be part of a do-while.
(not after-labels-pos))
(progn (c-bos-save-pos)
(setq state 'while-boundary))
(c-bos-pop-state-and-retry))) ; Can't be a do-while
((eq state 'while-boundary)
(cond ((eq sym 'do)
(c-bos-pop-state (setq ret 'beginning)))
((eq sym 'boundary) ; isn't a do-while
(c-bos-restore-pos) ; the position of the while
(c-bos-pop-state)))) ; no longer searching for do.
((eq state 'catch)
(if (eq sym 'boundary)
(setq state 'catch-boundary)
(c-bos-report-error)
(c-bos-pop-state-and-retry)))
((eq state 'catch-boundary)
(cond
((eq sym 'try)
(c-bos-pop-state (setq ret 'beginning)))
((eq sym 'catch)
(setq state 'catch))
((eq sym 'boundary)
(c-bos-report-error)
(c-bos-pop-state)))))
;; This is state common. We get here when the previous
;; cond statement found no particular state handler.
(cond ((eq sym 'boundary)
;; If we have a boundary at the start
;; position we push a frame to go to the
;; previous statement.
(if (>= pos start)
(c-bos-push-state)
(c-bos-pop-state)))
((eq sym 'else)
(c-bos-push-state)
(c-bos-save-error-info 'if 'else)
(setq state 'else))
((eq sym 'while)
;; Is this a real while, or a do-while?
;; The next `when' triggers unless we are SURE that
;; the `while' is not the tail end of a `do-while'.
(when (or (not pptok)
(memq (char-after pptok) delims)
;; The following kludge is to prevent
;; infinite recursion when called from
;; c-awk-after-if-for-while-condition-p,
;; or the like.
(and (eq (point) start)
(c-vsemi-status-unknown-p))
(c-at-vsemi-p pptok))
;; Since this can cause backtracking we do a
;; little more careful analysis to avoid it: If
;; the while isn't followed by a (possibly
;; virtual) semicolon it can't be a do-while.
(c-bos-push-state)
(setq state 'while)))
((memq sym '(catch finally))
(c-bos-push-state)
(c-bos-save-error-info 'try sym)
(setq state 'catch))))
(when c-maybe-labelp
;; We're either past a statement boundary or at the