Mercurial > emacs
changeset 51714:bc91cbf50c24
Updated CC Mode to version 5.30.
author | Martin Stjernholm <mast@lysator.liu.se> |
---|---|
date | Thu, 03 Jul 2003 12:30:59 +0000 |
parents | 205602055b5f |
children | 6e2487a7e9ff |
files | lisp/ChangeLog lisp/progmodes/cc-align.el lisp/progmodes/cc-awk.el lisp/progmodes/cc-bytecomp.el lisp/progmodes/cc-cmds.el lisp/progmodes/cc-compat.el lisp/progmodes/cc-defs.el lisp/progmodes/cc-engine.el lisp/progmodes/cc-fonts.el lisp/progmodes/cc-langs.el lisp/progmodes/cc-menus.el lisp/progmodes/cc-mode.el lisp/progmodes/cc-styles.el lisp/progmodes/cc-vars.el |
diffstat | 14 files changed, 14936 insertions(+), 3001 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ChangeLog Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/ChangeLog Thu Jul 03 12:30:59 2003 +0000 @@ -1,3 +1,1279 @@ +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-menus.el (cc-imenu-init): Do not set + `imenu-create-index-function' if the second argument is left + out. This bug broke the imenu support in C, C++ and Java + modes. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el, progmodes/cc-align.el + (c-add-stmt-syntax, c-lineup-arglist, + c-lineup-arglist-close-under-paren): Fixes to cope with + special brace lists in Pike. + +2003-07-03 Alan Mackenzie <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el: awk-mode: Call c-awk-after-change to + ensure syntax-table props at loading. + + * progmodes/cc-fonts.el: Put (cc-require-when-compile 'cc-awk) + to eliminate compile-time errors. + +2003-07-03 Alan Mackenzie <bug-cc-mode@gnu.org> + + * progmodes/cc-awk.el, progmodes/cc-engine.el: Added code to + analyze AWK top-level forms properly (c-guess-basic-syntax + CASE 5P), c-awk-backward-syntactic-ws. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-fix.el: cc-mode-19.el has been renamed to + progmodes/cc-fix.el since it now contains compatibility stuff + for later versions than (X)Emacs 19. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (c-paren-nontype-kwds): New language + constant. + + (c-other-decl-kwds, c-postfix-decl-spec-kwds): Added compiler + specific declspec keywords: __attribute__ for gcc and + __declspec for msvc. + + * progmodes/cc-fonts.el (c-font-lock-declarations, + c-complex-decl-matchers): Support specifiers in a couple more + contexts to cope with msvc '__declspec'. + + * progmodes/cc-engine.el (c-forward-keyword-clause): Support + `c-paren-nontype-kwds'. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (c-primary-expr-regexp): Don't match a + bare period as a float. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-bytecomp.el (cc-bytecomp-setup-environment): Do + not cover functions that have been bound. + + (cc-external-require): New macro to use for requiring external + packages, to handle the environment correctly. + + * progmodes/cc-defs.el, progmodes/cc-fix.el, + progmodes/cc-fonts.el, progmodes/cc-mode.el: Replaced external + require's with `cc-external-require'. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-member-init-list, + c-guess-basic-syntax): Fixes in handling of bitfields. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (comment-end): Put a space in front of + the comment ender in C, as it was before the move from + progmodes/cc-mode.el. + +2003-07-03 Alan Mackenzie <bug-cc-mode@gnu.org> + + * progmodes/cc-fonts.el: Do not load progmodes/cc-awk.elc or + awk-font-lock-keywords unless there is an AWK Mode buffer. + +2003-07-03 Alan Mackenzie <bug-cc-mode@gnu.org> + + * progmodes/cc-awk.el: New file that implements AWK support, + superseding the old separate derived mode in awk-mode.el. + + * progmodes/cc-vars.el, cc-mode-19.el, progmodes/cc-langs.el, + progmodes/cc-mode.el, progmodes/cc-defs.el, + progmodes/cc-engine.el, progmodes/cc-fonts.el: Changes for the + new AWK support. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el, progmodes/cc-langs.el + (c-decl-block-key, c-search-uplist-for-classkey): Check that + the modifier is followed by "{" in Pike before considering it + to start a class-like block. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el (c-initialize-cc-mode): Added some + compatibility to make this function behave somewhat more as + documented for derived modes. It's still not enough to make + the old AWK mode behave reasonably, but it's been like this a + long time now so fixing it more might cause trouble + elsewhere. :P + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-fonts.el (c-remove-font-lock-face): New macro + to remove a font lock face properly (especially in XEmacs). + + * progmodes/cc-bytecomp.el (cc-bytecomp-obsolete-fun): Added + the same kludge as in `cc-bytecomp-obsolete-var' to avoid a + confused compiler warning. + + * progmodes/cc-engine.el (c-forward-type): Fixed a bug in the + handling of concatenated types when the component types are + known. + + * progmodes/cc-fonts.el (c-constant-face-name): Added face name variable to + avoid the use of `font-lock-constant-face' for constants in + emacsen that doesn't have it. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-styles.el, progmodes/cc-vars.el, + progmodes/cc-cmds.el: Fixes for the syntactic symbols for + module and composition blocks. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el (c-basic-common-init): Use + `open-paren-in-column-0-is-defun-start' if it exists and + works. + + * progmodes/cc-vars.el (c-emacs-features): Added `col-0-paren' + to detect when `open-paren-in-column-0-is-defun-start' exists + and actually works. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-argcont, + c-lineup-gcc-asm-reg): Don't quote nil in docstrings. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-vars.el, progmodes/cc-langs.el + (c-primitive-type-kwds, c-font-lock-extra-types): "complex" + and "imaginary" aren't keywords in C99, only macros that + expand to the keywords "_Complex" and "_Imaginary", so make + the former a bit less hardcoded by putting it on + `c-font-lock-extra-types' instead. There are also "bool" and + "_Bool" that work the same way. + + (c-constant-kwds): "false" and "true" are standard constant + macros in C99. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-menus.el, progmodes/cc-langs.el, + progmodes/cc-engine.el, progmodes/cc-fonts.el, + progmodes/cc-cmds.el: Fixed various regexps to use POSIX char + classes when that is supported. + + * progmodes/cc-defs.el (c-alpha, c-alnum, c-digit, c-upper, + c-lower): New constants to make it easier to create regexps + that use POSIX char classes in emacsen that support them. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-vars.el (c-emacs-features): Detect in the + regexp engine understands POSIX char classes. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el (c-after-change): Added kludge for bug + where this function sometimes gets positions outside the + buffer range. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-member-init-list): + Better handling of paretheses in unexpected places. + + * progmodes/cc-engine.el (c-forward-<>-arglist-recur): Fixed a + regexp match order problem that could cause empty template + args on the form "<>" to be missed. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-parse-state): Added kludge to + avoid an infinite loop when Emacs' open-paren-in-column-zero + rule kicks in and causes the sexp functions to misbehave. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-member-init-list): + Fixed bug when C++-like code is encountered in non-C++ mode. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el (c-make-keywords-re): Added option to + specify the language to look up `c-nonsymbol-key' in. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el, progmodes/cc-engine.el + (c-auto-newline-analysis): New dynamically bound variable to + turn off the topmost-intro-cont/statement-cont kludge for + brace lists during the analysis for the auto newline feature. + This fixes some cases where the setting for `brace-list-open' + on `c-hanging-braces-alist' didn't have any effect. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (c-literal-start-regexp): Yet another + language variable. + + * progmodes/cc-fonts.el (c-font-lock-doc-comments, + c-find-invalid-doc-markup, javadoc-font-lock-keywords): Fixed + fontification of the markup in Javadoc comments. + + * progmodes/cc-engine.el: Fixes in face handling to cope with + doc comments. + + (c-find-decl-spots): More failsafe skipping of comments and + strings that only have been partially fontified. + + * progmodes/cc-defs.el (c-got-face-at): New subst to test + faces at positions easier. + + * progmodes/cc-defs.el (c-safe-scan-lists): New wrapper macro + to avoid the warnings with too many args to `scan-lists' in + Emacs. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-syntactic-skip-backward): New + function to make syntactic searches in the backward direction + easier. + + (c-beginning-of-statement-1): Optimized skipping over large paren + sexps somewhat. + + (c-safe-position): Removed the odd macro handling which was + centered around the point instead of the passed position. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-in-knr-argdecl): Do not trip up on + initialization expressions. + + * progmodes/cc-align.el (c-lineup-arglist, + c-lineup-close-paren, c-lineup-arglist-close-under-paren): + Tuned the "macro block" heuristics to work better in nested + arglist situations. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-styles.el (c-set-offset): Don't find a default + syntactic element through syntactic analysis if called outside + a CC Mode buffer. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el (c-basic-common-init): Install + `c-fill-paragraph' on `fill-paragraph-function'. Although + it's not the normal way to call it in a CC Mode buffer it + makes a direct call to `fill-paragraph' work better. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-vars.el, progmodes/cc-mode.el + (c-require-final-newline): Made this variable an alist to + specify a value for each language. The default value causes + `require-final-newline' to be set to t only in languages where + the standard requires a final newline. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el, progmodes/cc-vars.el + (c-require-final-newline): Added a variable to make the + initialization of `require-final-newline' more configurable. + + * progmodes/cc-vars.el (c-mode-common-hook): Do not change the + format string to "CC Mode Common Hook" since that causes + confusion (although it is a more accurate name). + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-fonts.el (javadoc-font-lock-keywords, + autodoc-font-lock-keywords): Support for Javadoc and Pike + Autodoc doc comments. + + * progmodes/cc-vars.el (c-doc-comment-style): New variable to + control the fontification of documentation comments on top of + the normal mode font lock. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el, progmodes/cc-fonts.el + (c-primary-expr-regexp, c-font-lock-declarations): Avoid false + recognition of parens as casts when they are followed by an + operator that is both prefix and infix. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-guess-fill-prefix): Tuned the + heuristics of when to use `c-block-comment-prefix' for an + unclosed block comment. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el, progmodes/cc-langs.el + (c-nonsymbol-sexp-kwds, c-forward-keyword-clause): Handle + keywords like "extern" that can be followed by e.g. a string + literal. + + * progmodes/cc-defs.el (c-make-keywords-re): Make a regexp + correctly with one submatch when adorn is set and the list is + empty. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-fonts.el (c-font-lock-declarations): Fixed a + search that could go far past the relevant region and cause + slowness. Do not limit the declaration detection to the + fontified region since that can cause misfontification in + multiline declarations. + + * progmodes/cc-engine.el (c-find-decl-spots): Added limit + argument to handle declarations spanning the fontification + limit better. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-in-literal, c-literal-limits, + c-literal-limits-fast, c-beginning-of-inheritance-list): Use + the paren cache instead of the impaired ad hoc in + `beginning-of-defun', so that these functions doesn't trip up + on "{" in the first column inside strings or comments. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-vars.el (c-hanging-braces-alist): Added + `statement-cont' and made it auto newline free by default. + + * progmodes/cc-cmds.el (c-electric-brace): Added + `statement-cont' to the list of syntactic symbols to consider + for auto newlines since it can be used for in-statement brace + lists. + + * progmodes/cc-vars.el (c-emacs-features): There's no need to + have this constant autoloaded. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-fonts.el (c-font-lock-declarations): Use + `c-recognize-typeless-decls' to avoid fontifying some macro + constructs as declarations in languages where a preceding type + is mandatory. + + * progmodes/cc-langs.el (c-recognize-typeless-decls): New + language variable. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-close-paren): Use + `c-syntactic-eol' when checking if the open paren ends its + line. + + * progmodes/cc-langs.el (c-syntactic-eol): Handle a line + continuation backslash. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-snug-do-while): Compatibility fix + for changed structure in `c-syntactic-context'. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-parse-state): Filter angle bracket + arglist parens in a better way than disabling the syntax table + properties completely. + + * progmodes/cc-fonts.el (c-cpp-matchers): Handle line + continuations in cpp expressions. Do not fontify symbols after + #ifdef etc as variables since that isn't consistent with how + the face is used elsewhere (i.e. only for the definition of + the symbol). + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el: Added autoload directives for the + interface functions in cc-langs. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-fonts.el (c-font-lock-declarations): Added a + property to handle refontication in multiline declaration + arglists better. + + (c-font-lock-<>-arglists): Fix to handle recursive template + arglists better. (As a side effect this will make + fontification work better in older emacsen too.) + + * progmodes/cc-engine.el (c-forward-<>-arglist, + c-remove-<>-arglist-properties): Use a common text property + `c-type' for all sorts of CC Mode char classification, to + avoid cases when then same char is given conflicting types. + + (c-forward-<>-arglist): New reparse argument to control that + aspect explicitly. + + (c-forward-name, c-forward-type): Changes in the handling of + recursive template arglists. Fixes to cope with the new 'known + type classification. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el (c-basic-common-init): Added the new + char property `c-type' to `text-property-default-nonsticky'. + + * progmodes/cc-defs.el (c-put-char-property, + c-get-char-property, c-clear-char-property, + c-clear-char-properties): Generalized `c-put-char-syntax' and + `c-get-char-syntax' to handle any property. + + * progmodes/cc-bytecomp.el (cc-bytecomp-defun): Fixed bug that + caused existing function definitions to be overridden by + phonies when the bytecomp environment is restored. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-mask-paragraph): Masking is + necessary in normal code too to avoid getting a fill prefix + from a nearby comment. Changed the name from `c-mask-comment' + to a more accurate one. + + * progmodes/cc-defs.el, progmodes/cc-mode.el: Changed the + auto-load-alist strategy to not add entries on package load, + to be defensive in the case that autoloads are updated in + older emacsen. The bug that would occur in that case would + probably be rather nasty for the average user. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-fonts.el (c-font-lock-declarations): Fine + tuning of the decision tree that tells declarations from + expressions to produce better results in some ambiguous cases. + + * progmodes/cc-fonts.el (c-font-lock-syntactic-face-function): + Removed since it doesn't give the control we want. + + (c-font-lock-invalid-string): Replacement for + `c-font-lock-syntactic-face-function' that puts the error face + on the string opener only, to avoid the annoying excessive use + of the error face while a string literal is being written. + + (c-basic-matchers-before): Use `c-font-lock-invalid-string'. + + * progmodes/cc-engine.el (c-string-syntax, + c-string-limit-regexp): Added constants to use when handling + string limits, since not all old emacsen react well to the "|" + syntax class. + + (c-literal-limits, c-literal-limits-fast, c-literal-type): Use + `c-string-syntax' and `c-string-limit-regexp'. Replaced some + hardcoded comment start regexps with `c-comment-start-regexp'. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el: Added an association for pike-mode on + `intepreter-mode-alist'. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el: Add the `auto-mode-alist' entries to + the end instead of the start of the list, to avoid overriding + user additions that are made before this file is loaded when + the entries don't correspond to any already on + `auto-mode-alist'. + + This is done through the third append argument to + `auto-mode-alist'. That doesn't exist in older (X)Emacsen, so + the function is adviced in cc-defs. However, that advice + doesn't help if the autoloads are updated in an old (X)Emacs + with this version of CC Mode, but I believe it's unlikely that + anyone does that when CC Mode isn't distributed with with it. + + * progmodes/cc-defs.el (add-to-list): Added advice to get the + optional third append argument in older (X)Emacsen. + + * progmodes/cc-langs.el (c-keywords-obarray): Kludge for + strange bug in Emacs that gives so odd errors that I frankly + don't even muster to begin trying to narrow it down. If + someone is so inclined, restore the commented code, byte + compile, and try to open a C++ file or something in font lock + mode. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el: Updated the IDL support from the + specs. This also adds the keywords for the variants PSDL and + CIDL. (This is mostly done from reading the grammars only; + very lightly tested.) + + * progmodes/cc-langs.el (c-type-list-kwds): Added "new" in + Java. + + * progmodes/cc-fonts.el: Made sure that + `parse-sexp-lookup-properties' is properly insulated from + clobbering by the font-lock package at all relevant entry + points. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (c-opt-after-id-concat-key): New + language constant to make the recognition of identifier + qualifiers more flexible. Recognize the identifier before + ".*" as a qualifier in Java. + + (c-identifier-key): Recognize "::*" inside identifiers in C++. + Recognize identifiers ending with ".*" in Java for the sake of + import directives. + + (c-type-list-kwds, c-ref-list-kwds): Recognize "import" and + "package" declarations in Java. + + * progmodes/cc-vars.el (c-doc-face, c-doc-marker-face, + c-doc-markup-face): Removed since they aren't used (and + probably won't be). + + * progmodes/cc-langs.el (c-ref-list-kwds): New language + constant to specify keywords followed by references. + + (c-last-identifier-range): New variable to avoid going back to + search for the identifier to font lock after a call to + `c-forward-name'. + + (c-type-prefix-kwds, c-type-list-kwds): Fixed classification of + "@interface" etc in Objective-C. + + * progmodes/cc-engine.el (c-forward-keyword-clause): Fixed + handling of keyword prefixes in `c-type-list-kwds' and + `c-colon-type-list-kwds' clauses. + + (c-keyword-sym, c-keyword-member): New functions to lookup and + categorize keywords. + + (c-forward-keyword-clause): New function to move over a keyword + and its associated clause according to `c-<>-arglist-kwds' etc. + + * progmodes/cc-langs.el (c-typeless-decl-kwds, + c-type-list-kwds, c-colon-type-list-kwds, + c-colon-type-list-re, c-paren-type-kwds): New language + constants and variables to generalize the recognition of + various language constructs. + + (c-keywords): Did away with the list of `*-kwds' constants. It's + now built through macro expansion. + + (c-keywords-obarray): New language variable which contains each + keyword as a symbol, to make fast reverse lookup of keywords to + the `*-kwds' lists they come from. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el (c-lang-defconst-eval-immediately): + Added macro to be able to do direct evaluation in + `c-lang-defconst' forms. + + * progmodes/cc-engine.el (c-syntactic-re-search-forward): + Fixed a bug which could cause the point to end up outside the + containing sexp if PAREN-LEVEL was used. + + * progmodes/cc-engine.el, progmodes/cc-fonts.el, + progmodes/cc-langs.el: Generalized the C++ template arglist + support to handle angle bracket arglists in any language. + + (c-recognize-<>-arglists, c-<>-arglist-kwds, + c-opt-<>-arglist-start): New language variables to control + angle bracket arglists. + + (c-opt-type-suffix-key): Use `c-recognize-<>-arglists' in + Objective-C instead of matching a protocol reference list as a + type suffix. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-gnu-impose-minimum): Fixed a missing + `save-excursion' that caused the point to jump around. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el, progmodes/cc-menus.el (objc-mode, + cc-imenu-init): Fixed initialization bug that has made the + Objective-C support inoperational since 5.26. + + (cc-imenu-objc-generic-expression): Updated submatch indices + due to changes in `cc-imenu-c++-generic-expression'. + + (cc-imenu-objc-function): Don't add an empty "C" menu since + imenu doesn't like that. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-arglist, + c-lineup-arglist-close-under-paren, c-lineup-close-paren): + Added DWIM to the functions that line up at or after the + arglist open paren to avoid that if there are brace blocks + inside, e.g. when a macro contains a code block. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-vars.el (objc-font-lock-extra-types): Changed + default to treat identifiers starting with capital letters as + types, according to Objective-C naming conventions. The types + previously on the list is part of the language and therefore + on `c-primitive-type-kwds' instead. + + * progmodes/cc-fonts.el: Fixed font locking in Objective-C. + Be more careful about returning nil from functions used + directly as font-lock matchers. + + * progmodes/cc-mode.el (c-font-lock-init): Made the syntax + table modification element of `font-lock-defaults' + parameterized over the languages. + + * progmodes/cc-langs.el: Updated the Objective-C constants + according to the language spec. The "@" chars that start + directives are now considered part of the keywords to make + things easier. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el: (c-(up|down)-list-(forward|backward)): + Made the position optional and added docstrings. + + (c-go-(up|down)-list-(forward|backward)): Added variants of the + above that move point and return successfulness instead. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-fonts.el (c-font-lock-<>-arglists): New + function to fontify all occurrences of template arglists in + C++. + + * progmodes/cc-engine.el (c-disallow-comma-in-<>-arglists): + New variable to be able to avoid false recognition of template + arglists in some cases. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-fonts.el, progmodes/cc-langs.el + (c-decl-prefix-re, c-font-lock-declarations): Match template + open brackets to get a declaration in the first template + argument. + + (c-complex-decl-matchers): Fontify the second type in a "class + X = Y" expression in C++. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-forward-<>-arglist): Broke out the + recursive part to a new function to improve efficiency when a + nested template arglist search turns out to be futile. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-menus.el (cc-imenu-java-generic-expression): + Improved to avoid false matches on e.g. "else if (foo)". + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-forward-token-2, + c-backward-token-2): New functions that work like the -1 + variants but that handles multicharacter operator tokens. + + * progmodes/cc-engine.el (c-inside-bracelist-p, + c-guess-basic-syntax): Did away with the hardcoded regexps to + recognize "typedef" declaration prefixes, "extern" and + "namespace" blocks, "enum"-style brace list declarations and + Java-style array initializers with "new". + + * progmodes/cc-langs.el (c-brace-list-decl-kwds, + c-brace-list-key, c-inexpr-brace-list-kwds, + c-opt-inexpr-brace-list-key): New language constants and + variables to parameterize some more of the hardcoded regexps + in cc-engine. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-cascaded-calls): Do not + allow cascaded call lists containing both "->" and ".". + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el, progmodes/cc-cmds.el, + progmodes/cc-defs.el, progmodes/cc-engine.el, + progmodes/cc-fonts.el, progmodes/cc-langs.el, + progmodes/cc-mode.el, progmodes/cc-styles.el: New language + variable system to make it easier to set up optimized language + variables and to extend them in third party derived modes. + cc-langs is no longer required at runtime. + + * progmodes/cc-mode.el (c-basic-common-init): No longer + initializes the language variables. It's necessary that the + caller does that directly since the evaluated values for them + now get compiled in directly. + + (c-font-lock-init, c-common-init): Separated the font-lock + initialization from `c-common-init'. + + * progmodes/cc-mode.el (c-define-abbrev-table): Do not + override an existing abbrev table. + + (c-Java-defun-prompt-regexp): Moved here from cc-langs since + cc-langs isn't always loaded at runtime. + + * progmodes/cc-langs.el (c-make-init-lang-vars-fun, + c-init-language-vars): Changed to allow language variable + initialization from derived modes. + + (c-mode-menu): New language variable for the mode menu. + + (c-make-mode-syntax-table, c-mode-syntax-table, + make-c++-template-syntax-table): New language variables for syntax + tables. The code that initializes them has been moved to cc-mode + to make it possible to avoid loading cc-langs at runtime. + + * progmodes/cc-engine.el, progmodes/cc-langs.el + (c-hungry-delete-key, c-auto-newline, c-auto-hungry-string): + Moved these state variables from cc-langs to cc-engine to make + it possible to avoid loading cc-langs at runtime. + + * progmodes/cc-defs.el (c-lang-defconst, c-lang-const): Moved + from cc-langs and rewritten to make the language constant + system usable from derived modes. + + (c-add-language): New function intended for use from derived modes + that add new C-like languages. + + * progmodes/cc-defs.el, progmodes/cc-vars.el + (c-buffer-is-cc-mode): Moved from cc-vars to cc-defs to define + it during compilation. + + * progmodes/cc-bytecomp.el (cc-require-when-compile): New + support macro for compile time `require's. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el, progmodes/cc-mode.el (c-version): + Moved from cc-mode to cc-defs to make it accessible to the + other components. + + * progmodes/cc-engine.el (c-forward-token-1, + c-backward-token-1): Compatibility fix for emacsen that + doesn't understand generic string delimiters. + + * progmodes/cc-vars.el (c-emacs-features): Added detection of + generic string and comment delimiters. + + * progmodes/cc-defs.el, progmodes/cc-langs.el + (c-make-keywords-re): Changed interface to make it more + extensible. + + * progmodes/cc-langs.el, progmodes/cc-defs.el (c-regexp-opt, + c-regexp-opt-depth, c-make-keywords-re): Moved from cc-langs + to cc-defs since they are generally useful. + + * progmodes/cc-bytecomp.el, progmodes/cc-defs.el + (cc-eval-when-compile): Moved from cc-bytecomp to cc-defs to + allow use at runtime. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-bytecomp.el (cc-eval-when-compile): Workaround + for a bug with nested `eval-when-compile' in XEmacs 21. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el: Added autoloaded forms to install the + appropriate file suffixes on `auto-mode-alist'. Necessary in + XEmacs 21.5, and it can be useful elsewhere too. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-cascaded-calls): Handle "." + too, for use in Java. + + * progmodes/cc-engine.el (c-forward-sws, c-backward-sws): Do + not handle cpp directives in languages that doesn't have any. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (c-operators): Added a high level + description of all operators, along with their precedence and + associativity. + + * progmodes/cc-align.el (c-lineup-multi-inher): Fixed bug + where the position of the point and not the beginning of the + line was used to calculate the indentation. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el, progmodes/cc-engine.el + (c-backward-single-comment, c-backward-comments): Added kludge + for the bug in `forward-comment' in most (X)Emacs versions + where it moves back over the "*/" of a block comment if + there's no matching "/*". This has become more important now + since it can cause incorrect caching by `c-backward-sws'. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-hungry-backspace, + c-hungry-delete-forward): New functions to do hungry deletion + regardless of hungry-delete mode. Contributed by Kevin Ryde. + + * progmodes/cc-engine.el (c-forward-sws, c-backward-sws, + c-invalidate-sws-region): Use text properties to cache regions + with complex syntactic whitespace. This helps a lot in + improving responsiveness when there are lots of comments and + cpp directives before point. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-guess.el, progmodes/cc-langs.el, + progmodes/cc-menus.el, progmodes/cc-mode.el, + progmodes/cc-styles.el, progmodes/cc-vars.el, + progmodes/cc-engine.el, progmodes/cc-fonts.el, + progmodes/cc-cmds.el, progmodes/cc-defs.el: Introduced a + classification of functions into those that make "hidden + buffer changes" and those who don't. This is prompted by the + increasing use of text properties for various things, to + correctly cover the silly buffer modifications that is caused + by text property changes. + + (c-save-buffer-state): New macro that's put around any code that + can manipulate text properties. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el (c-basic-common-init): Setup + `text-property-default-nonsticky' to avoid messing with the + rear-nonsticky property on each character in Emacs 21. + + * progmodes/cc-defs.el (c-clear-char-syntax, + c-put-char-syntax): Macros that sets and removes the + syntax-table property on a single character and makes the + property nonsticky in both directions in a suitable way for + each (X)Emacs flavor. + + * progmodes/cc-vars.el, progmodes/cc-defs.el, + progmodes/cc-engine.el, progmodes/cc-mode.el: Use + `lookup-syntax-properties' in XEmacs to control whether the + syntax-table property has any effect or not. + + (c-parse-sexp-lookup-properties): New macro that expands to either + `parse-sexp-lookup-properties' or `lookup-syntax-properties'. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el, progmodes/cc-engine.el, + progmodes/cc-fonts.el: Put the faces into the buffer in the + same way as the font-lock package does. This fixes a + compatibility problem with XEmacs which sets an extra + font-lock property. + + * progmodes/cc-fonts.el (c-put-font-lock-face): A macro that + finds out the right way to put font lock faces at compile + time. We're definitely not byte code portable between Emacs + and XEmacs now. + + * progmodes/cc-engine.el (c-forward-sws, c-backward-sws): + Implemented a cache for the last large skipped over syntactic + whitespace. This also has most effect after many macros. + + * progmodes/cc-engine.el, progmodes/cc-defs.el + (c-forward-syntactic-ws, c-backward-syntactic-ws): Utilize the + limit better when one is passed. These are now macros to + avoid a little overhead when no limit is given. + + (c-forward-sws, c-backward-sws): New functions called by the + macros above to do the unbounded search. + + * progmodes/cc-fonts.el (c-font-lock-declarations): + Implemented a cache for the first backward search for a + preceding `c-decl-prefix-re' match. This typically speeds up + interactive refontification a lot on the top level of macro + heavy header files. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-vars.el (c-emacs-features): Added check for + syntax text properties. + + * progmodes/cc-mode.el (c-basic-common-init): Turn on + `parse-sexp-lookup-properties' if it's supported. Define the + variable in any case since it's used at runtime to check on + this. + + * progmodes/cc-langs.el (c-identifier-key): Support C++ + destructor names. + + (c-identifier-start, c-op-token-regexp, c-type-modifier-kwds, + c-opt-type-modifier-key, c-opt-type-component-key, + c-typedef-specifier-kwds, c-typedef-specifier-key, + c-paren-stmt-kwds, c-paren-stmt-key, c-syntactic-ws-start): A + bunch of new language constants and variables to support the + improved handling of names and types. + + * progmodes/cc-fonts.el (c-font-lock-declarators, + c-font-lock-declarations): Handle C++ template declarations + and template references. Fontify complex types and names more + accurately by delegating it to `c-forward-type' and + `c-forward-name'. Fontify the identifiers in typedef + declarations as types. + + * progmodes/cc-engine.el (c-forward-<>-arglist): New function + to move forward over a C++ template arglist. It also marks + the '<' and '>' chars with paren syntax using the syntax-table + property, to speed up later calls in emacsen that support + syntax text properties (Emacs >= 20 and (undocumented) XEmacs + 21). + + This also has the very interesting effect that if font locking + is used with decoration level 3 or higher in these emacsen + then template arglists will behave just like paren sexps with + the various sexp movement commands. + + (c-forward-name): New function to move over a name. Simple in + most languages except C++ where a name can contain template + arglists and therefore almost arbitrary expressions. + + (c-on-identifier): Fix for Pike operator identifiers. + + (c-simple-skip-symbol-backward, c-syntactic-content, + c-remove-<>-paren-properties): New helper functions. + + * progmodes/cc-defs.el: (c-clear-char-syntax, + c-mark-paren-open, c-mark-paren-close): New support functions + to handle syntactic properties on C++ template arglist + brackets. + + (c-put-type-face, c-put-reference-face): Helpers to put faces on + regions, since there are a bit of that inside `c-forward-name' etc + in progmodes/cc-engine.el. + + * progmodes/cc-engine.el, progmodes/cc-fonts.el, + progmodes/cc-langs.el: Fixed the names on a number of regexp + language variables to conform to the nomenclature and + shortened some names. + + * progmodes/cc-align.el, progmodes/cc-cmds.el, + progmodes/cc-fonts.el, progmodes/cc-engine.el + (c-syntactic-re-search-forward): Removed the COUNT argument + since it's never used. Added an argument to tell which + subexpression whose end should be tested for syntactic + relevance. Using this also removes some optimizations, so + that it's possible to use a look behind subexpression that + matches the end of a literal or a close paren when PAREN-LEVEL + is used. + + (c-guess-continued-construct): Don't match <<= or >>= for the + stream-op syntactic element. + + * progmodes/cc-defs.el (c-paren-re, c-identifier-re): Removed + these helper macros since better and more correct tools are + now available in progmodes/cc-langs.el. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-string-cont): New lineup + function to line up string literals that will be concatenated. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (c-populate-syntax-table): XEmacs + classifies the hard space character as a symbol character but + it's better to let it be in the punctuation class so that it's + always highlighted with the inverted invalid face. It can + perhaps be argued that that character is allowed in + identifiers in some languages (haven't checked), but using it + would still be extremely confusing. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-statement-1): Fixed a + case when a labeled substatement caused incorrect association + of the following continuation clause. + + * progmodes/cc-engine.el (c-syntactic-re-search-forward): + Handle the case when the syntactic match position is in the + middle of a comment starter. + + (c-guess-continued-construct): Analyze the "K&R region" of a + function nested inside a function as func-decl-cont and not + statement-cont. New case E. Also cleaned up case C (stream-op + recognition) a bit. + + * progmodes/cc-engine.el (c-parse-state, c-check-state-cache): + Moved the check on `c-state-cache-start' from + `c-check-state-cache' to `c-parse-state' so that the state + cache isn't zapped if `c-check-state-cache' but not + `c-parse-state' is called during a temporary narrowing. This + fixes a performance problem that could occur when + `fill-paragraph' is used in font lock mode on a comment at the + end of a large class or function. + + (c-state-cache-start): Fixed buffer localness. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el: Updates from the C99 standard (or + actually from the latest web accessible draft of it). + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el: Updated the keywords and operator + tokens from the latest C++ and Java standards. Some other + multichar token corrections. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el, progmodes/cc-engine.el, + progmodes/cc-vars.el (c-syntactic-context, + c-syntactic-element): Do not bind any values to these + variables globally since they should always be dynamically + bound. This makes it much easier to debug cases when they've + gotten global values somehow. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (c-regexp-opt): Fix to work around the + non-greedy behavior that the regexp engine sometimes exposes. + This bug only shows in (X)Emacs 19 where there's no regexp-opt + package. + + * progmodes/cc-engine.el (c-syntactic-re-search-forward): + Added a feature to filter out matches in the middle of tokens. + Changed the comment to a docstring since I consider this + function generally useful. + + * progmodes/cc-defs.el (c-mode-symbol): Broke out a part of + `c-mode-var'. + + * progmodes/cc-align.el (c-lineup-cascaded-calls, + c-lineup-gcc-asm-reg): Cope with that `c-most-enclosing-brace' + might return nil. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-found-types, c-clear-found-types, + c-add-type, c-check-type, c-add-complex-type, + c-list-found-types, c-forward-type): Added a sort of symbol + table for types: If a name is recognized as a type in a + declaration it's added in an obarray to be able to recognize + it in other ambiguous declarations. + + (c-remove-ws): New helper function to canonicalize fully + qualified identifiers for `c-found-types'. + + * progmodes/cc-defs.el (c-mode-var): New defsubst to access + mode prefixed variables uniformly. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-arglist-close-under-paren): + Work correctly with nested arglist-cont-nonempty symbols. + + (c-lineup-arglist-operators): New lineup function to line up infix + operators under the open paren of the surrounding sexp. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-forward-syntactic-ws): Fixed a bug + that could cause an infinite loop if something that looks like + a macro begins in the middle of a line. + + (c-parse-state): Fixed a bug that could cause `c-state-cache' + to contain two conses in sequence when there's an unbalanced + open paren in a macro. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el (c-face-name-p): A defsubst to + recognize the name of a face in a way that works also in + XEmacs. + + * progmodes/cc-engine.el (c-forward-type): New function to + move past a type spec. + + * progmodes/cc-engine.el (c-syntactic-re-search-forward): + Fixed behavior when the limit is reached inside a comment, + string, or a macro. + + * progmodes/cc-align.el, progmodes/cc-cmds.el, + progmodes/cc-engine.el (c-forward-single-comment, + c-forward-comments, c-backward-single-comment, + c-backward-comments): New replacements for `c-forward-comment' + that wraps `forward-comment' more efficiently in each of the + four different cases it's actually used. These replacements + also treats line continuations as whitespace. + + (c-forward-comment): Removed. The four different cases above + are basically different, so it's better to make them into + separate functions than choose between them at runtime using + the argument. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-gnu-impose-minimum): Fixed bug due + to the new placement of cpp-macro and comment-intro in the + syntactic context, as pointed out by Kevin Ryde. Changed the + method that decides whether point is inside a top-level + construct to one that doesn't depend on the set of syntactic + elements so much. + + * progmodes/cc-defs.el (c-point): Use the functions + `line-beginning-position' and `line-end-position' in emacsen + that have them (currently Emacs 20 and later). + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-mask-comment): Fixed a bug that + sometimes caused code after a closed block comment to be taken + into account when the fill prefix is calculated. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-arglist, c-lineup-argcont, + c-lineup-math, c-lineup-cascaded-calls, c-lineup-gcc-asm-reg): + Fixes to cope correctly with nested arglists for the lineups + that can be used with arglist-cont-nonempty. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-add-stmt-syntax, + c-guess-basic-syntax): Changed the anchor position of + arglist-cont-nonempty and arglist-close so that a relative + indentation like + can be used with consistent results. Prior + to this, the indentation engine more or less assumed that + arglist-cont-nonempty always used `c-lineup-arglist'. Those + two syntax symbols also get the opening paren as an extra + position, to make it possible for `c-lineup-arglist' to + continue to do a proper job. + + * progmodes/cc-engine.el (c-get-syntactic-indentation): A + vector with an absolute indentation column now only overrides + the indentation for surrounding structures, i.e. those whose + syntactic elements are earlier in the `c-syntactic-context' + list, but not nested ones. This so that + e.g. `c-lineup-arglist' can reliably line up with the first + argument but still allow relative indentation changes for + nested things, e.g. the arglist-close of a nested argument + list. This change means that the order in + `c-syntactic-context' has become more essential. + + (c-guess-basic-syntax): Changes to make the nesting order of the + returned syntax list correct. + + Compatibility note: This change means that `c-lineup-dont-change' + now (again) isn't absolutely sure to keep the current indentation. + However, I believe that most people use it for comments, macros + and string literals, and since those are nested innermost it won't + matter. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el, progmodes/cc-defs.el, + progmodes/cc-engine.el, progmodes/cc-vars.el + (c-guess-basic-syntax, c-calc-offset, + c-get-syntactic-indentation, c-syntactic-context): Extended + the representation of the syntactic context: Previously it was + a list containing cons cells of the found syntactic symbols + and their relpos values. Now each element is instead a list + containing the syntactic symbol in the first element and the + relpos (if any) in the second. After that there might be more + elements, depending on the syntactic symbol. The line-up + functions get these additional elements as extra arguments. + + This change is slightly incompatible. Although the calling + convention for line-up functions is strictly extended, the format + of the `c-syntactic-context' variable has changed slightly. It's + believed that this incompatibility is minor, though; not a single + line-up function distributed with CC Mode needed to be changed, + for instance. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-styles.el (c-set-style, c-set-style-1): Added + another state for the `dont-override' flag where it only keeps + globally set variables. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el (c-postprocess-file-styles): Do nothing + except in CC Mode modes. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-vars.el, progmodes/cc-fonts.el, + progmodes/cc-langs.el, progmodes/cc-mode.el: Added font lock + support. + + * progmodes/cc-engine.el (c-beginning-of-syntax): New function + to be used for font-lock-beginning-of-syntax-function. It + uses the state cache to quickly find a good position. + + * progmodes/cc-defs.el (c-major-mode-is): Allow a list of + modes. Made it a macro ensure that it's optimized to either + eq or memq for constant arguments. + + * progmodes/cc-mode.el (c-common-init): Did away with the + hardcoded setting of `comment-column'; it's a user variable + that we have no business meddling with. Since the default + value for it is 32 in all supported (X)Emacs versions, it's + also safe from a compatibility perspective. + + * progmodes/cc-mode.el (c-basic-common-init): New function + that contains only the syntax and line breaking/filling + initialization. It's intended for use by other modes that + embed CC Mode. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-add-stmt-syntax): Fixed some cases + of wrong anchoring, e.g. for else-if compounds. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-guess-basic-syntax): Fixed anchor + position for defun-open in K&R style functions. + + * progmodes/cc-engine.el (c-in-knr-argdecl): Don't trip up on + macros. + + (c-search-decl-header-end): Handle C++ template arguments more + correctly. + + (c-beginning-of-decl-1): Fix when the declaration is first in a + macro. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-decl-1): Better way + to handle protection labels, one which doesn't get confused by + inherit colons. + + (c-end-of-decl-1): Don't treat functions that have "class" or + "struct" in the return type as classes or structs. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (c-make-keywords-re): Fixed the + keyword adornment so that it works when a keyword ends with + "_". + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-mask-comment): More fixes when used + from `c-do-auto-fill' and point is at or near the limit of the + comment. Fixed bug when the prefix from `c-guess-fill-prefix' + is longer than the text on the first line of the comment when + it's masked. + +2003-07-03 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-mask-comment): Fixed bug where point + was moved to the following line when it was at the first line + of a block comment where comment-start-skip matched to eol. + 2003-07-01 Luc Teirlinck <teirllm@mail.auburn.edu> * info.el (Info-fontify-menu-headers): Only fontify `* Menu:' at
--- a/lisp/progmodes/cc-align.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-align.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,9 @@ ;;; cc-align.el --- custom indentation functions for CC Mode -;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1992-1997 Barry A. Warsaw +;; Authors: 1998- Martin Stjernholm +;; 1992-1999 Barry A. Warsaw ;; 1987 Dave Detlefs and Stewart Clamen ;; 1985 Richard M. Stallman ;; Maintainer: bug-cc-mode@gnu.org @@ -39,16 +38,27 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) (cc-require 'cc-defs) (cc-require 'cc-vars) -(cc-require 'cc-langs) (cc-require 'cc-engine) ;; Standard indentation line-ups +;; Calling convention: +;; +;; The single argument is a cons cell containing the syntactic symbol +;; in the car, and the relpos (a.k.a. anchor position) in the cdr. +;; The cdr may be nil for syntactic symbols which doesn't have an +;; associated relpos. +;; +;; Some syntactic symbols provide more information, usually more +;; interesting positions. The complete list for the syntactic element +;; (beginning with the symbol itself) is available in +;; `c-syntactic-element'. + (defun c-lineup-topmost-intro-cont (langelem) "Line up declaration continuation lines zero or one indentation step. For lines in the \"header\" of a definition, zero is used. For other @@ -88,17 +98,55 @@ (defun c-lineup-arglist (langelem) "Line up the current argument line under the first argument. +As a special case, if an argument on the same line as the open +parenthesis starts with a brace block opener, the indentation is +`c-basic-offset' only. This is intended as a \"DWIM\" measure in +cases like macros that contains statement blocks, e.g: + +A_VERY_LONG_MACRO_NAME ({ + some (code, with + long, lines * in[it]); + }); +<--> c-basic-offset + +This is motivated partly because it's more in line with how code +blocks are handled, and partly since it approximates the behavior of +earlier CC Mode versions, which due to inaccurate analysis tended to +indent such cases this way. + Works with: arglist-cont-nonempty, arglist-close." (save-excursion - (beginning-of-line) - (let ((containing-sexp (c-most-enclosing-brace (c-parse-state)))) - (goto-char (1+ containing-sexp)) - (let ((eol (c-point 'eol))) + (goto-char (1+ (elt c-syntactic-element 2))) + + ;; Don't stop in the middle of a special brace list opener + ;; like "({". + (when c-special-brace-lists + (let ((special-list (c-looking-at-special-brace-list))) + (when special-list + (goto-char (+ (car (car special-list)) 2))))) + + (let ((savepos (point)) + (eol (c-point 'eol))) + + ;; Find out if an argument on the same line starts with an + ;; unclosed open brace paren. Note similar code in + ;; `c-lineup-close-paren' and + ;; `c-lineup-arglist-close-under-paren'. + (if (and (c-syntactic-re-search-forward "{" eol t t) + (looking-at c-syntactic-eol) + (progn (backward-char) + (not (c-looking-at-special-brace-list))) + (progn (c-backward-syntactic-ws) + (or (= (point) savepos) + (eq (char-before) ?,)))) + c-basic-offset + + ;; Normal case. Indent to the token after the arglist open paren. + (goto-char savepos) (c-forward-syntactic-ws) (when (< (point) eol) - (goto-char (1+ containing-sexp)) - (skip-chars-forward " \t"))) - (vector (current-column))))) + (goto-char savepos) + (skip-chars-forward " \t")) + (vector (current-column)))))) ;; Contributed by Kevin Ryde <user42@zip.com.au>. (defun c-lineup-argcont (elem) @@ -118,32 +166,46 @@ (save-excursion (beginning-of-line) - (let ((bol (point))) - ;; Previous line ending in a comma means we're the start of an - ;; argument. This should quickly catch most cases not for us. - (c-backward-syntactic-ws) - (let ((c (char-before))) - (unless (eq c ?,) + (when (eq (car elem) 'arglist-cont-nonempty) + ;; Our argument list might not be the innermost one. If it + ;; isn't, go back to the last position in it. We do this by + ;; stepping back over open parens until we get to the open paren + ;; of our argument list. + (let ((open-paren (elt c-syntactic-element 2)) + (paren-state (c-parse-state))) + (while (not (eq (car paren-state) open-paren)) + (goto-char (car paren-state)) + (setq paren-state (cdr paren-state))))) + + (let ((start (point)) c) - ;; In a gcc asm, ":" on the previous line means the start of an - ;; argument. And lines starting with ":" are not for us, don't - ;; want them to indent to the preceding operand. - (let ((gcc-asm (save-excursion - (goto-char bol) - (c-in-gcc-asm-p)))) - (unless (and gcc-asm - (or (eq c ?:) - (save-excursion - (goto-char bol) - (looking-at "[ \t]*:")))) + (when (bolp) + ;; Previous line ending in a comma means we're the start of an + ;; argument. This should quickly catch most cases not for us. + ;; This case is only applicable if we're the innermost arglist. + (c-backward-syntactic-ws) + (setq c (char-before))) - (c-lineup-argcont-scan (if gcc-asm ?:)) - (vector (current-column))))))))) + (unless (eq c ?,) + ;; In a gcc asm, ":" on the previous line means the start of an + ;; argument. And lines starting with ":" are not for us, don't + ;; want them to indent to the preceding operand. + (let ((gcc-asm (save-excursion + (goto-char start) + (c-in-gcc-asm-p)))) + (unless (and gcc-asm + (or (eq c ?:) + (save-excursion + (goto-char start) + (looking-at "[ \t]*:")))) + + (c-lineup-argcont-scan (if gcc-asm ?:)) + (vector (current-column)))))))) (defun c-lineup-argcont-scan (&optional other-match) ;; Find the start of an argument, for `c-lineup-argcont'. - (when (eq 0 (c-backward-token-1 1 t)) + (when (zerop (c-backward-token-2 1 t)) (let ((c (char-after))) (if (or (eq c ?,) (eq c other-match)) (progn @@ -152,8 +214,8 @@ (c-lineup-argcont-scan other-match))))) (defun c-lineup-arglist-intro-after-paren (langelem) - "Line up a line just after the open paren of the surrounding paren or -brace block. + "Line up a line to just after the open paren of the surrounding paren +or brace block. Works with: defun-block-intro, brace-list-intro, statement-block-intro, statement-case-intro, arglist-intro." @@ -164,16 +226,79 @@ (vector (1+ (current-column))))) (defun c-lineup-arglist-close-under-paren (langelem) - "Line up a closing paren line under the corresponding open paren. + "Line up a line under the enclosing open paren. +Normally used to line up a closing paren in the same column as its +corresponding open paren, but can also be used with arglist-cont and +arglist-cont-nonempty to line up all lines inside a parenthesis under +the open paren. + +As a special case, if a brace block is opened at the same line as the +open parenthesis of the argument list, the indentation is +`c-basic-offset' only. See `c-lineup-arglist' for further discussion +of this \"DWIM\" measure. + +Works with: Almost all symbols, but are typically most useful on +arglist-close, brace-list-close, arglist-cont and arglist-cont-nonempty." + (save-excursion + (let (special-list paren-start savepos) + (if (memq (car langelem) '(arglist-cont-nonempty arglist-close)) + (goto-char (elt c-syntactic-element 2)) + (beginning-of-line) + (c-go-up-list-backward)) + + (if (and c-special-brace-lists + (setq special-list (c-looking-at-special-brace-list))) + ;; Don't stop in the middle of a special brace list opener + ;; like "({". + (progn + (setq paren-start (car (car special-list))) + (goto-char (+ paren-start 2))) + (setq paren-start (point)) + (forward-char 1)) -Works with: defun-close, class-close, inline-close, block-close, -brace-list-close, arglist-close, extern-lang-close, namespace-close -\(for most of these, a zero offset will normally produce the same -result, though)." + (setq savepos (point)) + ;; Find out if an argument on the same line starts with an + ;; unclosed open brace paren. Note similar code in + ;; `c-lineup-arglist' and `c-lineup-close-paren'. + (if (and (c-syntactic-re-search-forward "{" (c-point 'eol) t t) + (looking-at c-syntactic-eol) + (progn (backward-char) + (not (c-looking-at-special-brace-list))) + (progn (c-backward-syntactic-ws) + (or (= (point) savepos) + (eq (char-before) ?,)))) + c-basic-offset + + ;; Normal case. Indent to the arglist open paren. + (goto-char paren-start) + (vector (current-column)))))) + +(defun c-lineup-arglist-operators (langelem) + "Line up lines starting with an infix operator under the open paren. +Return nil on lines that don't start with an operator, to leave those +cases to other lineup functions. Example: + +if ( x < 10 + || at_limit (x, <- c-lineup-arglist-operators + list) <- c-lineup-arglist-operators returns nil + ) + +Since this function doesn't do anything for lines without an infix +operator you typically want to use it together with some other lineup +settings, e.g. as follows \(the arglist-close setting is just a +suggestion to get a consistent style): + +\(c-set-offset 'arglist-cont '(c-lineup-arglist-operators 0)) +\(c-set-offset 'arglist-cont-nonempty '(c-lineup-arglist-operators + c-lineup-arglist)) +\(c-set-offset 'arglist-close '(c-lineup-arglist-close-under-paren)) + +Works with: arglist-cont, arglist-cont-nonempty." (save-excursion - (beginning-of-line) - (backward-up-list 1) - (vector (current-column)))) + (back-to-indentation) + (when (looking-at "[-+|&*%<>=]\\|\\(/[^/*]\\)") + ;; '-' can be both an infix and a prefix operator, but I'm lazy now.. + (c-lineup-arglist-close-under-paren langelem)))) (defun c-lineup-close-paren (langelem) "Line up the closing paren under its corresponding open paren if the @@ -184,25 +309,45 @@ char ** int, char ** ) <-> ) <- c-lineup-close-paren -Works with: defun-close, class-close, inline-close, block-close, -brace-list-close, arglist-close, extern-lang-close, namespace-close." +As a special case, if a brace block is opened at the same line as the +open parenthesis of the argument list, the indentation is +`c-basic-offset' instead of the open paren column. See +`c-lineup-arglist' for further discussion of this \"DWIM\" measure. + +Works with: All *-close symbols." (save-excursion - (condition-case nil - (let (opencol spec) - (beginning-of-line) - (backward-up-list 1) - (setq spec (c-looking-at-special-brace-list)) - (if spec (goto-char (car (car spec)))) - (setq opencol (current-column)) - (forward-char 1) - (if spec (progn - (c-forward-syntactic-ws) - (forward-char 1))) - (c-forward-syntactic-ws (c-point 'eol)) - (if (eolp) - 0 - (vector opencol))) - (error nil)))) + (beginning-of-line) + (c-go-up-list-backward) + + (let ((spec (c-looking-at-special-brace-list)) savepos argstart) + (if spec (goto-char (car (car spec)))) + (setq savepos (point)) + (forward-char 1) + (when spec + (c-forward-syntactic-ws) + (forward-char 1)) + + (if (looking-at c-syntactic-eol) + ;; The arglist is "empty". + 0 + + ;; Find out if an argument on the same line starts with an + ;; unclosed open brace paren. Note similar code in + ;; `c-lineup-arglist' and + ;; `c-lineup-arglist-close-under-paren'. + (setq argstart (point)) + (if (and (c-syntactic-re-search-forward "{" (c-point 'eol) t t) + (looking-at c-syntactic-eol) + (progn (backward-char) + (not (c-looking-at-special-brace-list))) + (progn (c-backward-syntactic-ws) + (or (= (point) argstart) + (eq (char-before) ?,)))) + c-basic-offset + + ;; Normal case. Indent to the arglist open paren. + (goto-char savepos) + (vector (current-column))))))) (defun c-lineup-streamop (langelem) "Line up C++ stream operators under each other. @@ -232,6 +377,7 @@ Works with: inher-cont, member-init-cont." (save-excursion + (back-to-indentation) (let* ((eol (c-point 'eol)) (here (point)) (char-after-ip (progn @@ -253,12 +399,13 @@ (if (or (eolp) (looking-at c-comment-start-regexp)) (c-forward-syntactic-ws here)) - (vector (current-column)) + (if (< (point) here) + (vector (current-column))) ))) (defun c-lineup-java-inher (langelem) "Line up Java implements and extends declarations. -If class names follows on the same line as the implements/extends +If class names follow on the same line as the implements/extends keyword, they are lined up under each other. Otherwise, they are indented by adding `c-basic-offset' to the column of the keyword. E.g: @@ -279,7 +426,7 @@ (defun c-lineup-java-throws (langelem) "Line up Java throws declarations. -If exception names follows on the same line as the throws keyword, +If exception names follow on the same line as the throws keyword, they are lined up under each other. Otherwise, they are indented by adding `c-basic-offset' to the column of the throws keyword. The throws keyword itself is also indented by `c-basic-offset' from the @@ -295,11 +442,11 @@ (let* ((lim (1- (c-point 'bol))) (throws (catch 'done (goto-char (cdr langelem)) - (while (zerop (c-forward-token-1 1 t lim)) + (while (zerop (c-forward-token-2 1 t lim)) (if (looking-at "throws\\>[^_]") (throw 'done t)))))) (if throws - (if (zerop (c-forward-token-1 1 nil (c-point 'eol))) + (if (zerop (c-forward-token-2 1 nil (c-point 'eol))) (vector (current-column)) (back-to-indentation) (vector (+ (current-column) c-basic-offset))) @@ -470,7 +617,7 @@ (cond ;; CASE 1: preserve aligned comments ((save-excursion - (and (c-forward-comment -1) + (and (c-backward-single-comment) (= col (current-column)))) (vector col)) ; Return an absolute column. ;; indent as specified by c-comment-only-line-offset @@ -534,46 +681,69 @@ the current line contains an equal sign too, try to align it with the first one. -Works with: statement-cont, arglist-cont, arglist-cont-nonempty." - (save-excursion - (let ((equalp (save-excursion - (goto-char (c-point 'boi)) - (let ((eol (c-point 'eol))) - (c-forward-token-1 0 t eol) - (while (and (not (eq (char-after) ?=)) - (= (c-forward-token-1 1 t eol) 0)))) - (and (eq (char-after) ?=) - (- (point) (c-point 'boi))))) - donep) - (if (cdr langelem) (goto-char (cdr langelem))) - (while (and (not donep) - (< (point) (c-point 'eol))) - (skip-chars-forward "^=" (c-point 'eol)) - (if (c-in-literal (cdr langelem)) - (forward-char 1) - (setq donep t))) - (if (or (not (eq (char-after) ?=)) +Works with: topmost-intro-cont, statement-cont, arglist-cont, +arglist-cont-nonempty." + (let (startpos endpos equalp) + + (if (eq (car langelem) 'arglist-cont-nonempty) + ;; If it's an arglist-cont-nonempty then we're only interested + ;; in equal signs outside it. We don't search for a "=" on + ;; the current line since that'd have a different nesting + ;; compared to the one we should align with. + (save-excursion + (save-restriction + (setq endpos (nth 2 c-syntactic-element)) + (narrow-to-region (cdr langelem) endpos) + (if (setq startpos (c-up-list-backward endpos)) + (setq startpos (1+ startpos)) + (setq startpos (cdr langelem))))) + + (setq startpos (cdr langelem) + endpos (point)) + + ;; Find a syntactically relevant and unnested "=" token on the + ;; current line. equalp is in that case set to the number of + ;; columns to left shift the current line to align it with the + ;; goal column. + (save-excursion + (beginning-of-line) + (when (c-syntactic-re-search-forward + ;; This regexp avoids matches on ==. + "\\(\\=\\|[^=]\\)=\\([^=]\\|$\\)" + (c-point 'eol) t t) + (setq equalp (- (match-beginning 2) (c-point 'boi)))))) + + (save-excursion + (goto-char startpos) + (if (or (if (c-syntactic-re-search-forward + "\\(\\=\\|[^=]\\)=\\([^=]\\|$\\)" + (min endpos (c-point 'eol)) t t) + (progn + (goto-char (match-beginning 2)) + nil) + t) (save-excursion - (forward-char 1) (c-forward-syntactic-ws (c-point 'eol)) (eolp))) - ;; there's no equal sign on the line + ;; There's no equal sign on the line, or there is one but + ;; nothing follows it. c-basic-offset + ;; calculate indentation column after equals and ws, unless ;; our line contains an equals sign (if (not equalp) (progn - (forward-char 1) (skip-chars-forward " \t") (setq equalp 0))) + (vector (- (current-column) equalp))) ))) (defun c-lineup-cascaded-calls (langelem) "Line up \"cascaded calls\" under each other. -If the line begins with \"->\" and the preceding line ends with one or -more function calls preceded by \"->\", then the arrow is lined up with -the first of those \"->\". E.g: +If the line begins with \"->\" or \".\" and the preceding line ends +with one or more function calls preceded by the same token, then the +arrow is lined up with the first of those tokens. E.g: result = proc->add(17)->add(18) ->add(19) + <- c-lineup-cascaded-calls @@ -582,22 +752,63 @@ In any other situation nil is returned to allow use in list expressions. -Works with: statement-cont, arglist-cont, arglist-cont-nonempty." - (save-excursion - (let ((bopl (c-point 'bopl)) col) +Works with: topmost-intro-cont, statement-cont, arglist-cont, +arglist-cont-nonempty." + + (if (and (eq (car langelem) 'arglist-cont-nonempty) + (not (eq (nth 2 c-syntactic-element) + (c-most-enclosing-brace (c-parse-state))))) + ;; The innermost open paren is not our one, so don't do + ;; anything. This can occur for arglist-cont-nonempty with + ;; nested arglist starts on the same line. + nil + + (save-excursion (back-to-indentation) - (when (and (looking-at "->") - (= (c-backward-token-1 1 t bopl) 0) - (eq (char-after) ?\() - (= (c-backward-token-1 3 t bopl) 0) - (looking-at "->")) - (setq col (current-column)) - (while (and (= (c-backward-token-1 1 t bopl) 0) - (eq (char-after) ?\() - (= (c-backward-token-1 3 t bopl) 0) - (looking-at "->")) - (setq col (current-column))) - (vector col))))) + (let ((operator (and (looking-at "->\\|\\.") + (regexp-quote (match-string 0)))) + (stmt-start (cdr langelem)) col) + + (when (and operator + (looking-at operator) + (zerop (c-backward-token-2 1 t stmt-start)) + (eq (char-after) ?\() + (zerop (c-backward-token-2 2 t stmt-start)) + (looking-at operator)) + (setq col (current-column)) + + (while (and (zerop (c-backward-token-2 1 t stmt-start)) + (eq (char-after) ?\() + (zerop (c-backward-token-2 2 t stmt-start)) + (looking-at operator)) + (setq col (current-column))) + + (vector col)))))) + +(defun c-lineup-string-cont (langelem) + "Line up a continued string under the one it continues. +A continued string in this sense is where a string literal follows +directly after another one. E.g: + +result = prefix + \"A message \" + \"string.\"; <- c-lineup-string-cont + +Nil is returned in other situations, to allow stacking with other +lineup functions. + +Works with: topmost-intro-cont, statement-cont, arglist-cont, +arglist-cont-nonempty." + (save-excursion + (back-to-indentation) + (and (looking-at "\\s\"") + (let ((quote (char-after)) pos) + (while (and (progn (c-backward-syntactic-ws) + (eq (char-before) quote)) + (c-safe (c-backward-sexp) t) + (/= (setq pos (point)) (c-point 'boi)))) + (when pos + (goto-char pos) + (vector (current-column))))))) (defun c-lineup-template-args (langelem) "Line up template argument lines under the first argument. @@ -610,11 +821,11 @@ (beginning-of-line) (backward-up-list 1) (if (and (eq (char-after) ?<) - (zerop (c-forward-token-1 1 nil (c-point 'eol)))) + (zerop (c-forward-token-2 1 nil (c-point 'eol)))) (vector (current-column)))))) (defun c-lineup-ObjC-method-call (langelem) - "Line up selector args as elisp-mode does with function args: + "Line up selector args as Emacs Lisp mode does with function args: Go to the position right after the message receiver, and if you are at the end of the line, indent the current line c-basic-offset columns from the opening bracket; otherwise you are looking at the first @@ -736,8 +947,8 @@ second `c-basic-offset' is added. Works with: defun-close, defun-block-intro, block-close, -brace-list-close, brace-list-intro, statement-block-intro, inclass, -inextern-lang, innamespace." +brace-list-close, brace-list-intro, statement-block-intro and all in* +symbols, e.g. inclass and inextern-lang." (save-excursion (goto-char (cdr langelem)) (back-to-indentation) @@ -775,13 +986,13 @@ } while (0) <-> } while (0) <- c-lineup-cpp-define The relative indentation returned by `c-lineup-cpp-define' is zero and -two, respectively, in these two examples. They are then added to the +two, respectively, in these two examples. They are then added to the two column indentation that statement-block-intro gives in both cases here. If the relative indentation is zero, then nil is returned instead. -This useful in a list expression to specify the default indentation on -the top level. +That is useful in a list expression to specify the default indentation +on the top level. If `c-syntactic-indentation-in-macros' is nil then this function keeps the current indentation, except for empty lines \(ignoring the ending @@ -855,6 +1066,13 @@ (and c-opt-asm-stmt-key + ;; Don't do anything if the innermost open paren isn't our one. + ;; This can occur for arglist-cont-nonempty with nested arglist + ;; starts on the same line. + (or (not (eq (car elem) 'arglist-cont-nonempty)) + (eq (elt c-syntactic-element 2) + (c-most-enclosing-brace (c-parse-state)))) + ;; Find the ":" to align to. Look for this first so as to quickly ;; eliminate pretty much all cases which are not for us. (re-search-backward "^[ \t]*:[ \t]*\\(.\\)?" (cdr elem) t) @@ -893,7 +1111,7 @@ (let (langelem) (if (and (eq syntax 'block-close) (setq langelem (assq 'block-close c-syntactic-context)) - (progn (goto-char (cdr langelem)) + (progn (goto-char (elt langelem 1)) (if (eq (char-after) ?{) (c-safe (c-forward-sexp -1))) (looking-at "\\<do\\>[^_]"))) @@ -904,27 +1122,32 @@ "Imposes a minimum indentation for lines inside a top-level construct. The variable `c-label-minimum-indentation' specifies the minimum indentation amount." - (let ((non-top-levels '(defun-block-intro statement statement-cont - statement-block-intro statement-case-intro - statement-case-open substatement substatement-open - case-label label do-while-closure else-clause - )) - (syntax c-syntactic-context) - langelem) - (while syntax - (setq langelem (car (car syntax)) - syntax (cdr syntax)) - ;; don't adjust macro or comment-only lines - (cond ((memq langelem '(cpp-macro comment-intro)) - (setq syntax nil)) - ((memq langelem non-top-levels) - (save-excursion - (setq syntax nil) - (back-to-indentation) - (if (zerop (current-column)) - (insert-char ?\ c-label-minimum-indentation t)) - )) - )))) + + ;; Don't adjust macro or comment-only lines. + (unless (or (assq 'cpp-macro c-syntactic-context) + (assq 'comment-intro c-syntactic-context)) + + (let ((paren-state (save-excursion + ;; Get the parenthesis state, but skip past + ;; an initial closing paren on the line since + ;; the close brace of a block shouldn't be + ;; considered to be inside the block. + (back-to-indentation) + (when (looking-at "\\s\)") + (forward-char)) + (c-parse-state)))) + + ;; Search for an enclosing brace on paren-state. + (while (and paren-state + (not (and (integer-or-marker-p (car paren-state)) + (eq (char-after (car paren-state)) ?{)))) + (setq paren-state (cdr paren-state))) + + (when paren-state + (save-excursion + (back-to-indentation) + (if (zerop (current-column)) + (insert-char ?\ c-label-minimum-indentation t))))))) ;; Useful for c-hanging-semi&comma-criteria
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/progmodes/cc-awk.el Thu Jul 03 12:30:59 2003 +0000 @@ -0,0 +1,905 @@ +;;; cc-awk.el --- AWK specific code within cc-mode. + +;; Copyright (C) 1988,94,96,2000,01,02,03 Free Software Foundation, Inc. + +;; Author: Alan Mackenzie (originally based on awk-mode.el) +;; Maintainer: FSF +;; Keywords: AWK, cc-mode, unix, languages + +;; 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 2, 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 GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file contains (most of) the adaptations to cc-mode required for the +;; integration of AWK Mode. +;; It is organised thusly: +;; 1. The AWK Mode syntax table. +;; 2. Indentation calculation stuff ("c-awk-NL-prop text-property"). +;; 3. Syntax-table property/font-locking stuff, but not including the +;; font-lock-keywords setting. +;; 4. The AWK Mode before/after-change-functions. +;; 5. AWK Mode specific versions of commands like beginning-of-defun. +;; The AWK Mode keymap, abbreviation table, and the mode function itself are +;; in cc-mode.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) + +;; Silence the byte compiler. +(cc-bytecomp-defvar font-lock-mode) ; Checked with boundp before use. + +;; Some functions in cc-engine that are used below. There's a cyclic +;; dependency so it can't be required here. (Perhaps some functions +;; could be moved to cc-engine to avoid it.) +(cc-bytecomp-defun c-backward-token-1) +(cc-bytecomp-defun c-beginning-of-statement-1) +(cc-bytecomp-defun c-backward-sws) + +(defvar awk-mode-syntax-table + (let ((st (make-syntax-table))) + (modify-syntax-entry ?\\ "\\" st) + (modify-syntax-entry ?\n "> " st) + (modify-syntax-entry ?\r "> " st) + (modify-syntax-entry ?\f "> " st) + (modify-syntax-entry ?\# "< " st) + ;; / can delimit regexes or be a division operator. By default we assume + ;; that it is a division sign, and fix the regexp operator cases with + ;; `font-lock-syntactic-keywords'. + (modify-syntax-entry ?/ "." st) ; ACM 2002/4/27. + (modify-syntax-entry ?* "." st) + (modify-syntax-entry ?+ "." st) + (modify-syntax-entry ?- "." st) + (modify-syntax-entry ?= "." st) + (modify-syntax-entry ?% "." st) + (modify-syntax-entry ?< "." st) + (modify-syntax-entry ?> "." st) + (modify-syntax-entry ?& "." st) + (modify-syntax-entry ?| "." st) + (modify-syntax-entry ?_ "_" st) + (modify-syntax-entry ?\' "." st) + st) + "Syntax table in use in AWK Mode buffers.") + +;; ACM, 2002/5/29: +;; +;; The next section of code is about determining whether or not an AWK +;; statement is complete or not. We use this to indent the following line. +;; The determination is pretty straightforward in C, where a statement ends +;; with either a ; or a }. Only "while" really gives any trouble there, since +;; it might be the end of a do-while. In AWK, on the other hand, semicolons +;; are rarely used, and EOLs _usually_ act as "virtual semicolons". In +;; addition, we have the complexity of escaped EOLs. The core of this +;; analysis is in the middle of the function +;; c-awk-calculate-NL-prop-prev-line, about 130 lines lower down. +;; +;; To avoid continually repeating this expensive analysis, we "cache" its +;; result in a text-property, c-awk-NL-prop, whose value for a line is set on +;; the EOL (if any) which terminates that line. Should the property be +;; required for the very last line (which has no EOL), it is calculated as +;; required but not cached. The c-awk-NL-prop property should be thought of +;; as only really valid immediately after a buffer change, not a permanently +;; set property. (By contrast, the syntax-table text properties (set by an +;; after-change function) must be constantly updated for the mode to work +;; properly). +;; +;; The valid values for c-awk-NL-prop are: +;; +;; nil The property is not currently set for this line. +;; '#' There is NO statement on this line (at most a comment), and no open +;; statement from a previous line which could have been completed on this +;; line. +;; '{' There is an unfinished statement on this (or a previous) line which +;; doesn't require \s to continue onto another line, e.g. the line ends +;; with {, or the && operator, or "if (condition)". Note that even if the +;; newline is redundantly escaped, it remains a '{' line. +;; '\' There is an escaped newline at the end of this line and this '\' is +;; essential to the syntax of the program. (i.e. if it had been a +;; frivolous \, it would have been ignored and the line been given one of +;; the other property values.) +;; ';' A statement is completed as the last thing (aside from ws) on the line - +;; i.e. there is (at least part of) a statement on this line, and the last +;; statement on the line is complete, OR (2002/10/25) the line is +;; content-free but terminates a statement from the preceding (continued) +;; line (which has property \). +;; +;; This set of values has been chosen so that the property's value on a line +;; is completely determined by the contents of the line and the property on +;; the previous line, EXCEPT for where a "while" might be the closing +;; statement of a do-while. + +(defun c-awk-after-if-for-while-condition-p (&optional do-lim) + ;; Are we just after the ) in "if/for/while (<condition>)"? + ;; + ;; Note that the end of the ) in a do .... while (<condition>) doesn't + ;; count, since the purpose of this routine is essentially to decide + ;; whether to indent the next line. + ;; + ;; DO-LIM sets a limit on how far back we search for the "do" of a possible + ;; do-while. + (and + (eq (char-before) ?\)) + (save-excursion + (let ((par-pos (c-safe (scan-lists (point) -1 0)))) + (when par-pos + (goto-char par-pos) ; back over "(...)" + (c-backward-token-1) ; BOB isn't a problem. + (or (looking-at "\\(if\\|for\\)\\>\\([^_]\\|$\\)") + (and (looking-at "while\\>\\([^_]\\|$\\)") ; Ensure this isn't a do-while. + (not (eq (c-beginning-of-statement-1 do-lim) + 'beginning))))))))) + +(defun c-awk-after-function-decl-param-list () + ;; Are we just after the ) in "function foo (bar)" ? + (and (eq (char-before) ?\)) + (save-excursion + (let ((par-pos (c-safe (scan-lists (point) -1 0)))) + (when par-pos + (goto-char par-pos) ; back over "(...)" + (c-backward-token-1) ; BOB isn't a problem + (and (looking-at "[_a-zA-Z][_a-zA-Z0-9]*\\>") + (progn (c-backward-token-1) + (looking-at "func\\(tion\\)?\\>")))))))) + +;; 2002/11/8: FIXME! Check c-backward-token-1/2 for success (0 return code). +(defun c-awk-after-continue-token () +;; Are we just after a token which can be continued onto the next line without +;; a backslash? + (save-excursion + (c-backward-token-1) ; FIXME 2002/10/27. What if this fails? + (if (and (looking-at "[&|]") (not (bobp))) + (backward-char)) ; c-backward-token-1 doesn't do this :-( + (looking-at "[,{?:]\\|&&\\|||\\|do\\>\\|else\\>"))) + +(defun c-awk-after-rbrace-or-statement-semicolon () + ;; Are we just after a } or a ; which closes a statement? + ;; Be careful about ;s in for loop control bits. They don't count! + (or (eq (char-before) ?\}) + (and + (eq (char-before) ?\;) + (save-excursion + (let ((par-pos (c-safe (scan-lists (point) -1 1)))) + (when par-pos + (goto-char par-pos) ; go back to containing ( + (not (and (looking-at "(") + (c-backward-token-1) ; BOB isn't a problem + (looking-at "for\\>"))))))))) + +(defun c-awk-back-to-contentful-text-or-NL-prop () + ;; Move back to just after the first found of either (i) an EOL which has + ;; the c-awk-NL-prop text-property set; or (ii) non-ws text; or (iii) BOB. + ;; We return either the value of c-awk-NL-prop (in case (i)) or nil. + ;; Calling function can best distinguish cases (ii) and (iii) with (bolp). + ;; + ;; Note that an escaped eol counts as whitespace here. + ;; + ;; Kludge: If c-backward-syntactic-ws gets stuck at a BOL, it is likely + ;; that the previous line contains an unterminated string (without \). In + ;; this case, assume that the previous line's c-awk-NL-prop is a ;. + ;; + ;; POINT MUST BE AT THE START OF A LINE when calling this function. This + ;; is to ensure that the various backward-comment functions will work + ;; properly. + (let ((nl-prop nil) + bol-pos bsws-pos) ; starting pos for a backward-syntactic-ws call. + (while ;; We are at a BOL here. Go back one line each iteration. + (and + (not (bobp)) + (not (setq nl-prop (c-get-char-property (1- (point)) 'c-awk-NL-prop))) + (progn (setq bol-pos (c-point 'bopl)) + (setq bsws-pos (point)) + ;; N.B. the following function will not go back past an EOL if + ;; there is an open string (without \) on the previous line. + (c-backward-syntactic-ws bol-pos) + (or (/= (point) bsws-pos) + (progn (setq nl-prop ?\;) + nil))) + ;; If we had a backslash at EOL, c-backward-syntactic-ws will + ;; have gone backwards over it. Check the backslash was "real". + (progn + (if (looking-at "[ \t]*\\\\+$") + (if (progn + (end-of-line) + (search-backward-regexp + "\\(^\\|[^\\]\\)\\(\\\\\\\\\\)*\\\\$" ; ODD number of \s at EOL :-) + bol-pos t)) + (progn (end-of-line) ; escaped EOL. + (backward-char) + (c-backward-syntactic-ws bol-pos)) + (end-of-line))) ; The \ at eol is a fake. + (bolp)))) + nl-prop)) + +(defun c-awk-calculate-NL-prop-prev-line (&optional do-lim) + ;; Calculate and set the value of the c-awk-NL-prop on the immediately + ;; preceding EOL. This may also involve doing the same for several + ;; preceding EOLs. + ;; + ;; NOTE that if the property was already set, we return it without + ;; recalculation. (This is by accident rather than design.) + ;; + ;; Return the property which got set (or was already set) on the previous + ;; line. Return nil if we hit BOB. + ;; + ;; See c-awk-after-if-for-while-condition-p for a description of DO-LIM. + (save-excursion + (save-match-data + (beginning-of-line) + (let* ((pos (point)) + (nl-prop (c-awk-back-to-contentful-text-or-NL-prop))) + ;; We are either (1) at a BOL (with nl-prop containing the previous + ;; line's c-awk-NL-prop) or (2) after contentful text on a line. At + ;; the BOB counts as case (1), so we test next for bolp rather than + ;; non-nil nl-prop. + (when (not (bolp)) + (setq nl-prop + (cond + ;; Incomplete statement which doesn't require escaped EOL? + ((or (c-awk-after-if-for-while-condition-p do-lim) + (c-awk-after-function-decl-param-list) + (c-awk-after-continue-token)) + ?\{) + ;; Escaped EOL (where there's also something to continue)? + ((and (looking-at "[ \t]*\\\\$") + (not (c-awk-after-rbrace-or-statement-semicolon))) + ?\\) + (t ?\;))) ; A statement was completed on this line + (end-of-line) + (c-put-char-property (point) 'c-awk-NL-prop nl-prop) + (forward-line)) + + ;; We are now at a (possibly empty) sequence of content-free lines. + ;; Set c-awk-NL-prop on each of these lines's EOL. + (while (< (point) pos) ; one content-free line each iteration. + (cond ; recalculate nl-prop from previous line's value. + ((memq nl-prop '(?\; nil)) (setq nl-prop ?\#)) + ((eq nl-prop ?\\) + (if (not (looking-at "[ \t]*\\\\$")) (setq nl-prop ?\;))) ; was ?\# 2002/10/25 + ;; ?\# (empty line) and ?\{ (open stmt) don't change. + ) + (forward-line) + (c-put-char-property (1- (point)) 'c-awk-NL-prop nl-prop)) + nl-prop)))) + +(defun c-awk-get-NL-prop-prev-line (&optional do-lim) + ;; Get the c-awk-NL-prop text-property from the previous line, calculating + ;; it if necessary. Return nil iff we're already at BOB. + ;; See c-awk-after-if-for-while-condition-p for a description of DO-LIM. + (if (bobp) + nil + (or (c-get-char-property (c-point 'eopl) 'c-awk-NL-prop) + (c-awk-calculate-NL-prop-prev-line do-lim)))) + +(defun c-awk-get-NL-prop-cur-line (&optional do-lim) + ;; Get the c-awk-NL-prop text-property from the current line, calculating it + ;; if necessary. (As a special case, the property doesn't get set on an + ;; empty line at EOB (there's no position to set the property on), but the + ;; function returns the property value an EOL would have got.) + ;; + ;; See c-awk-after-if-for-while-condition-p for a description of DO-LIM. + (save-excursion + (let ((extra-nl nil)) + (end-of-line) ; Necessary for the following test to work. + (when (= (forward-line) 1) ; if we were on the last line.... + (insert-char ?\n 1) ; ...artificial eol is needed for comment detection. + (setq extra-nl t)) + (prog1 (c-awk-get-NL-prop-prev-line do-lim) + (if extra-nl (delete-backward-char 1)))))) + +(defun c-awk-prev-line-incomplete-p (&optional do-lim) + ;; Is there an incomplete statement at the end of the previous line? + ;; See c-awk-after-if-for-while-condition-p for a description of DO-LIM. + (memq (c-awk-get-NL-prop-prev-line do-lim) '(?\\ ?\{))) + +(defun c-awk-cur-line-incomplete-p (&optional do-lim) + ;; Is there an incomplete statement at the end of the current line? + ;; See c-awk-after-if-for-while-condition-p for a description of DO-LIM. + (memq (c-awk-get-NL-prop-cur-line do-lim) '(?\\ ?\{))) + +(defun c-awk-completed-stmt-ws-ends-prev-line-p (&optional do-lim) + ;; Is there a termination of a statement as the last thing (apart from an + ;; optional comment) on the previous line? + ;; See c-awk-after-if-for-while-condition-p for a description of DO-LIM. + (eq (c-awk-get-NL-prop-prev-line do-lim) ?\;)) + +(defun c-awk-completed-stmt-ws-ends-line-p (&optional pos do-lim) + ;; Same as previous function, but for the line containing position POS (or + ;; the current line if POS is omitted). + ;; See c-awk-after-if-for-while-condition-p for a description of DO-LIM. + (save-excursion + (if pos (goto-char pos)) + (eq (c-awk-get-NL-prop-cur-line do-lim) ?\;))) + +(defun c-awk-after-logical-semicolon (&optional do-lim) +;; Are we at BOL, the preceding EOL being a "logical semicolon"? +;; See c-awk-after-if-for-while-condition-p for a description of DO-LIM. + (and (bolp) + (eq (c-awk-get-NL-prop-prev-line do-lim) ?\;))) + +(defun c-awk-backward-syntactic-ws (&optional lim) +;; Skip backwards over awk-syntactic whitespace. This is whitespace +;; characters, comments, and NEWLINES WHICH AREN'T "VIRTUAL SEMICOLONS". For +;; this function, a newline isn't a "virtual semicolon" if that line ends with +;; a real semicolon (or closing brace). +;; However if point starts inside a comment or preprocessor directive, the +;; content of it is not treated as whitespace. LIM (optional) sets a limit on +;; the backward movement. + (let ((lim (or lim (point-min))) + after-real-br) + (c-backward-syntactic-ws (max lim (c-point 'bol))) + (while ; go back one WS line each time round this loop. + (and (bolp) + (> (point) lim) + (/= (c-awk-get-NL-prop-prev-line) ?\;) + (/= (point) + ;; The following function requires point at BONL [not EOL] to + ;; recognise a preceding comment,. + (progn (c-backward-syntactic-ws (max lim (c-point 'bopl))) + (point))))) + ;; Does the previous line end with a real ; or }? If so, go back to it. + (if (and (bolp) + (eq (c-awk-get-NL-prop-prev-line) ?\;) + (save-excursion + (c-backward-syntactic-ws (max lim (c-point 'bopl))) + (setq after-real-br (point)) + (c-awk-after-rbrace-or-statement-semicolon))) + (goto-char after-real-br)))) + +(defun c-awk-NL-prop-not-set () + ;; Is the NL-prop on the current line either nil or unset? + (not (c-get-char-property (c-point 'eol) 'c-awk-NL-prop))) + +(defun c-awk-clear-NL-props (beg end) + ;; This function is run from before-change-hooks. It clears the + ;; c-awk-NL-prop text property from beg to the end of the buffer (The END + ;; parameter is ignored). This ensures that the indentation engine will + ;; never use stale values for this property. + (save-restriction + (widen) + (c-clear-char-properties beg (point-max) 'c-awk-NL-prop))) + +(defun c-awk-unstick-NL-prop () + ;; Ensure that the text property c-awk-NL-prop is "non-sticky". Without + ;; this, a new newline inserted after an old newline (e.g. by C-j) would + ;; inherit any c-awk-NL-prop from the old newline. This would be a Bad + ;; Thing. This function's action is required by c-put-char-property. + (if (and (boundp 'text-property-default-nonsticky) ; doesn't exist in Xemacs + (not (assoc 'c-awk-NL-prop text-property-default-nonsticky))) + (setq text-property-default-nonsticky + (cons '(c-awk-NL-prop . t) text-property-default-nonsticky)))) + +;; The following is purely a diagnostic command, to be commented out of the +;; final release. ACM, 2002/6/1 +;; (defun NL-props () +;; (interactive) +;; (let (pl-prop cl-prop) +;; (message "Prev-line: %s Cur-line: %s" +;; (if (setq pl-prop (c-get-char-property (c-point 'eopl) 'c-awk-NL-prop)) +;; (char-to-string pl-prop) +;; "nil") +;; (if (setq cl-prop (c-get-char-property (c-point 'eol) 'c-awk-NL-prop)) +;; (char-to-string cl-prop) +;; "nil")))) +;(define-key awk-mode-map [?\C-c ?\r] 'NL-props) ; commented out, 2002/8/31 +;for now. In the byte compiled version, this causes things to crash because +;awk-mode-map isn't yet defined. :-( + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; The following section of the code is to do with font-locking. The biggest +;; problem for font-locking is deciding whether a / is a regular expression +;; delimiter or a division sign - determining precisely where strings and +;; regular expressions start and stop is also troublesome. This is the +;; purpose of the function c-awk-set-syntax-table-properties and the myriad +;; elisp regular expressions it uses. +;; +;; Because AWK is a line oriented language, I felt the normal cc-mode strategy +;; for font-locking unterminated strings (i.e. font-locking the buffer up to +;; the next string delimiter as a string) was inappropriate. Instead, +;; unbalanced string/regexp delimiters are given the warning font, being +;; refonted with the string font as soon as the matching delimiter is entered. +;; +;; This requires the region processed by the current font-lock after-change +;; function to have access to the start of the string/regexp, which may be +;; several lines back. The elisp "advice" feature is used on these functions +;; to allow this. + +(defun c-awk-beginning-of-logical-line (&optional pos) +;; Go back to the start of the (apparent) current line (or the start of the +;; line containing POS), returning the buffer position of that point. I.e., +;; go back to the last line which doesn't have an escaped EOL before it. +;; +;; This is guaranteed to be "safe" for syntactic analysis, i.e. outwith any +;; comment, string or regexp. IT MAY WELL BE that this function should not be +;; executed on a narrowed buffer. + (if pos (goto-char pos)) + (forward-line 0) + (while (and (> (point) (point-min)) + (eq (char-before (1- (point))) ?\\)) + (forward-line -1)) + (point)) + +(defun c-awk-end-of-logical-line (&optional pos) +;; Go forward to the end of the (apparent) current logical line (or the end of +;; the line containing POS), returning the buffer position of that point. I.e., +;; go to the end of the next line which doesn't have an escaped EOL. +;; +;; This is guaranteed to be "safe" for syntactic analysis, i.e. outwith any +;; comment, string or regexp. IT MAY WELL BE that this function should not be +;; executed on a narrowed buffer. + (if pos (goto-char pos)) + (end-of-line) + (while (and (< (point) (point-max)) + (eq (char-before) ?\\)) + (end-of-line 2)) + (point)) + +;; N.B. In the following regexps, an EOL is either \n OR \r. This is because +;; Emacs has in the past used \r to mark hidden lines in some fashion (and +;; maybe still does). + +(defconst c-awk-esc-pair-re "\\\\\\(.\\|\n\\|\r\\|\\'\\)") +;; Matches any escaped (with \) character-pair, including an escaped newline. +(defconst c-awk-comment-without-nl "#.*") +;; Matches an AWK comment, not including the terminating NL (if any). Note +;; that the "enclosing" (elisp) regexp must ensure the # is real. +(defconst c-awk-nl-or-eob "\\(\n\\|\r\\|\\'\\)") +;; Matches a newline, or the end of buffer. + +;; "Space" regular expressions. +(defconst c-awk-escaped-nl "\\\\[\n\r]") +;; Matches an escaped newline. +(defconst c-awk-escaped-nls* (concat "\\(" c-awk-escaped-nl "\\)*")) +;; Matches a possibly empty sequence of escaped newlines. Used in +;; awk-font-lock-keywords. +;; (defconst c-awk-escaped-nls*-with-space* +;; (concat "\\(" c-awk-escaped-nls* "\\|" "[ \t]+" "\\)*")) +;; The above RE was very slow. It's runtime was doubling with each additional +;; space :-( Reformulate it as below: +(defconst c-awk-escaped-nls*-with-space* + (concat "\\(" c-awk-escaped-nl "\\|" "[ \t]" "\\)*")) +;; Matches a possibly empty sequence of escaped newlines with optional +;; interspersed spaces and tabs. Used in awk-font-lock-keywords. + +;; REGEXPS FOR "HARMLESS" STRINGS/LINES. +(defconst c-awk-harmless-char-re "[^_#/\"\\\\\n\r]") +;; Matches any character but a _, #, /, ", \, or newline. N.B. _" starts a +;; localisation string in gawk 3.1 +(defconst c-awk-harmless-_ "_\\([^\"]\\|\\'\\)") +;; Matches an underline NOT followed by ". +(defconst c-awk-harmless-string*-re + (concat "\\(" c-awk-harmless-char-re "\\|" c-awk-esc-pair-re "\\|" c-awk-harmless-_ "\\)*")) +;; Matches a (possibly empty) sequence of chars without unescaped /, ", \, +;; #, or newlines. +(defconst c-awk-harmless-string*-here-re + (concat "\\=" c-awk-harmless-string*-re)) +;; Matches the (possibly empty) sequence of chars without unescaped /, ", \, +;; at point. +(defconst c-awk-harmless-line-re + (concat c-awk-harmless-string*-re + "\\(" c-awk-comment-without-nl "\\)?" c-awk-nl-or-eob)) +;; Matches (the tail of) an AWK \"logical\" line not containing an unescaped +;; " or /. "logical" means "possibly containing escaped newlines". A comment +;; is matched as part of the line even if it contains a " or a /. The End of +;; buffer is also an end of line. +(defconst c-awk-harmless-lines+-here-re + (concat "\\=\\(" c-awk-harmless-line-re "\\)+")) +;; Matches a sequence of (at least one) \"harmless-line\" at point. + + +;; REGEXPS FOR AWK STRINGS. +(defconst c-awk-string-ch-re "[^\"\\\n\r]") +;; Matches any character which can appear unescaped in a string. +(defconst c-awk-string-innards-re + (concat "\\(" c-awk-string-ch-re "\\|" c-awk-esc-pair-re "\\)*")) +;; Matches the inside of an AWK string (i.e. without the enclosing quotes). +(defconst c-awk-string-without-end-here-re + (concat "\\=_?\"" c-awk-string-innards-re)) +;; Matches an AWK string at point up to, but not including, any terminator. +;; A gawk 3.1+ string may look like _"localisable string". + +;; REGEXPS FOR AWK REGEXPS. +(defconst c-awk-regexp-normal-re "[^[/\\\n\r]") +;; Matches any AWK regexp character which doesn't require special analysis. +(defconst c-awk-escaped-newlines*-re "\\(\\\\[\n\r]\\)*") +;; Matches a (possibly empty) sequence of escaped newlines. +(defconst c-awk-regexp-char-class-re + (concat "\\[" c-awk-escaped-newlines*-re "^?" c-awk-escaped-newlines*-re "]?" + "\\(" c-awk-esc-pair-re "\\|" "[^]\n\r]" "\\)*" "\\(]\\|$\\)")) +;; Matches a regexp char class, up to (but not including) EOL if the ] is +;; missing. +(defconst c-awk-regexp-innards-re + (concat "\\(" c-awk-esc-pair-re "\\|" c-awk-regexp-char-class-re + "\\|" c-awk-regexp-normal-re "\\)*")) +;; Matches the inside of an AWK regexp (i.e. without the enclosing /s) +(defconst c-awk-regexp-without-end-re + (concat "/" c-awk-regexp-innards-re)) +;; Matches an AWK regexp up to, but not including, any terminating /. + +;; REGEXPS used for scanning an AWK buffer in order to decide IF A '/' IS A +;; REGEXP OPENER OR A DIVISION SIGN. By "state" in the following is meant +;; whether a '/' at the current position would by a regexp opener or a +;; division sign. +(defconst c-awk-neutral-re +; "\\([{}@` \t]\\|\\+\\+\\|--\\|\\\\.\\)+") ; changed, 2003/6/7 + "\\([{}@` \t]\\|\\+\\+\\|--\\|\\\\.\\)") +;; A "neutral" char(pair). Doesn't change the "state" of a subsequent /. +;; This is space/tab, braces, an auto-increment/decrement operator or an +;; escaped character. Or one of the (illegal) characters @ or `. But NOT an +;; end of line (even if escpaed). +(defconst c-awk-neutrals*-re + (concat "\\(" c-awk-neutral-re "\\)*")) +;; A (possibly empty) string of neutral characters (or character pairs). +(defconst c-awk-var-num-ket-re "[]\)0-9a-zA-Z_$.\x80-\xff]+") +;; Matches a char which is a constituent of a variable or number, or a ket +;; (i.e. closing bracKET), round or square. Assume that all characters \x80 to +;; \xff are "letters". +(defconst c-awk-div-sign-re + (concat c-awk-var-num-ket-re c-awk-neutrals*-re "/")) +;; Will match a piece of AWK buffer ending in / which is a division sign, in +;; a context where an immediate / would be a regexp bracket. It follows a +;; variable or number (with optional intervening "neutral" characters). This +;; will only work when there won't be a preceding " or / before the sought / +;; to foul things up. +(defconst c-awk-non-arith-op-bra-re + "[[\(&=:!><,?;'~|]") +;; Matches an openeing BRAcket ,round or square, or any operator character +;; apart from +,-,/,*,%. For the purpose at hand (detecting a / which is a +;; regexp bracket) these arith ops are unnecessary and a pain, because of "++" +;; and "--". +(defconst c-awk-regexp-sign-re + (concat c-awk-non-arith-op-bra-re c-awk-neutrals*-re "/")) +;; Will match a piece of AWK buffer ending in / which is an opening regexp +;; bracket, in a context where an immediate / would be a division sign. This +;; will only work when there won't be a preceding " or / before the sought / +;; to foul things up. + +;; ACM, 2002/02/15: The idea of the next function is to put the "Error font" +;; on strings/regexps which are missing their closing delimiter. +;; 2002/4/28. The default syntax for / has been changed from "string" to +;; "punctuation", to reduce hassle when this character appears within a string +;; or comment. + +(defun c-awk-set-string-regexp-syntax-table-properties (beg end) +;; BEG and END bracket a (possibly unterminated) string or regexp. The +;; opening delimiter is after BEG, and the closing delimiter, IF ANY, is AFTER +;; END. Set the appropriate syntax-table properties on the delimiters and +;; contents of this string/regex. +;; +;; "String" here can also mean a gawk 3.1 "localizable" string which starts +;; with _". In this case, we step over the _ and ignore it; It will get it's +;; font from an entry in awk-font-lock-keywords. +;; +;; If the closing delimiter is missing (i.e., there is an EOL there) set the +;; STRING-FENCE property on the opening " or / and closing EOL. + (if (eq (char-after beg) ?_) (setq beg (1+ beg))) + + ;; First put the properties on the delimiters. + (cond ((eq end (point-max)) ; string/regexp terminated by EOB + (put-text-property beg (1+ beg) 'syntax-table '(15))) ; (15) = "string fence" + ((/= (char-after beg) (char-after end)) ; missing end delimiter + (put-text-property beg (1+ beg) 'syntax-table '(15)) + (put-text-property end (1+ end) 'syntax-table '(15))) + ((eq (char-after beg) ?/) ; Properly bracketed regexp + (put-text-property beg (1+ beg) 'syntax-table '(7)) ; (7) = "string" + (put-text-property end (1+ end) 'syntax-table '(7))) + (t)) ; Properly bracketed string: Nothing to do. + ;; Now change the properties of any escaped "s in the string to punctuation. + (save-excursion + (goto-char (1+ beg)) + (or (eobp) + (while (search-forward "\"" end t) + (put-text-property (1- (point)) (point) 'syntax-table '(1)))))) + +(defun c-awk-syntax-tablify-string () + ;; Point is at the opening " or _" of a string. Set the syntax-table + ;; properties on this string, leaving point just after the string. + ;; + ;; The result is nil if a / immediately after the string would be a regexp + ;; opener, t if it would be a division sign. + (search-forward-regexp c-awk-string-without-end-here-re nil t) ; a (possibly unterminated) string + (c-awk-set-string-regexp-syntax-table-properties + (match-beginning 0) (match-end 0)) + (cond ((looking-at "\"") + (forward-char) + t) ; In AWK, ("15" / 5) gives 3 ;-) + ((looking-at "[\n\r]") ; Unterminated string with EOL. + (forward-char) + nil) ; / on next line would start a regexp + (t nil))) ; Unterminated string at EOB + +(defun c-awk-syntax-tablify-/ (anchor anchor-state-/div) + ;; Point is at a /. Determine whether this is a division sign or a regexp + ;; opener, and if the latter, apply syntax-table properties to the entire + ;; regexp. Point is left immediately after the division sign or regexp, as + ;; the case may be. + ;; + ;; ANCHOR-STATE-/DIV identifies whether a / at ANCHOR would have been a + ;; division sign (value t) or a regexp opener (value nil). The idea is that + ;; we analyse the line from ANCHOR up till point to determine what the / at + ;; point is. + ;; + ;; The result is what ANCHOR-STATE-/DIV (see above) is where point is left. + (let ((/point (point))) + (goto-char anchor) + ;; Analyse the line to find out what the / is. + (if (if anchor-state-/div + (not (search-forward-regexp c-awk-regexp-sign-re (1+ /point) t)) + (search-forward-regexp c-awk-div-sign-re (1+ /point) t)) + ;; A division sign. + (progn (goto-char (1+ /point)) nil) + ;; A regexp opener + ;; Jump over the regexp innards, setting the match data. + (goto-char /point) + (search-forward-regexp c-awk-regexp-without-end-re) + (c-awk-set-string-regexp-syntax-table-properties + (match-beginning 0) (match-end 0)) + (cond ((looking-at "/") ; Terminating / + (forward-char) + t) + ((looking-at "[\n\r]") ; Incomplete regexp terminated by EOL + (forward-char) + nil) ; / on next line would start another regexp + (t nil))))) ; Unterminated regexp at EOB + +(defun c-awk-set-syntax-table-properties (lim) +;; Scan the buffer text between point and LIM, setting (and clearing) the +;; syntax-table property where necessary. +;; +;; This function is designed to be called as the FUNCTION in a MATCHER in +;; font-lock-syntactic-keywords, and it always returns NIL (to inhibit +;; repeated calls from font-lock: See elisp info page "Search-based +;; Fontification"). It also gets called, with a bit of glue, from +;; after-change-functions when font-lock isn't active. Point is left +;; "undefined" after this function exits. THE BUFFER SHOULD HAVE BEEN +;; WIDENED, AND ANY PRECIOUS MATCH-DATA SAVED BEFORE CALLING THIS ROUTINE. +;; +;; We need to set/clear the syntax-table property on: +;; (i) / - It is set to "string" on a / which is the opening or closing +;; delimiter of the properly terminated regexp (and left unset on a +;; division sign). +;; (ii) the opener of an unterminated string/regexp, we set the property +;; "generic string delimiter" on both the opening " or / and the end of the +;; line where the closing delimiter is missing. +;; (iii) "s inside strings/regexps (these will all be escaped "s). They are +;; given the property "punctuation". This will later allow other routines +;; to use the regexp "\\S\"*" to skip over the string innards. +;; (iv) Inside a comment, all syntax-table properties are cleared. + (let (anchor + (anchor-state-/div nil)) ; t means a following / would be a div sign. + (c-awk-beginning-of-logical-line) ; ACM 2002/7/21. This is probably redundant. + (put-text-property (point) lim 'syntax-table nil) + (search-forward-regexp c-awk-harmless-lines+-here-re nil t) ; skip harmless lines. + + ;; Once round the next loop for each string, regexp, or div sign + (while (< (point) lim) + (setq anchor (point)) + (search-forward-regexp c-awk-harmless-string*-here-re nil t) + ;; We are now looking at either a " or a /. + ;; Do our thing on the string, regexp or divsion sign. + (setq anchor-state-/div + (if (looking-at "_?\"") + (c-awk-syntax-tablify-string) + (c-awk-syntax-tablify-/ anchor anchor-state-/div))) + + ;; Skip any further "harmless" lines before the next tricky one. + (if (search-forward-regexp c-awk-harmless-lines+-here-re nil t) + (setq anchor-state-/div nil))) + nil)) + + +;; ACM, 2002/07/21: Thoughts: We need an AWK Mode after-change function to set +;; the syntax-table properties even when font-lock isn't enabled, for the +;; subsequent use of movement functions, etc. However, it seems that if font +;; lock _is_ enabled, we can always leave it to do the job. +(defvar c-awk-old-EOLL 0) +(make-variable-buffer-local 'c-awk-old-EOLL) +;; End of logical line following the region which is about to be changed. Set +;; in c-awk-before-change and used in c-awk-after-change. + +(defun c-awk-before-change (beg end) +;; This function is called exclusively from the before-change-functions hook. +;; It does two things: Finds the end of the (logical) line on which END lies, +;; and clears c-awk-NL-prop text properties from this point onwards. + (save-restriction + (save-excursion + (setq c-awk-old-EOLL (c-awk-end-of-logical-line end)) + (c-save-buffer-state nil + (c-awk-clear-NL-props end (point-max)))))) + +(defun c-awk-end-of-change-region (beg end old-len) + ;; Find the end of the region which needs to be font-locked after a change. + ;; This is the end of the logical line on which the change happened, either + ;; as it was before the change, or as it is now, which ever is later. + ;; N.B. point is left undefined. + (max (+ (- c-awk-old-EOLL old-len) (- end beg)) + (c-awk-end-of-logical-line end))) + +(defun c-awk-after-change (beg end old-len) +;; This function is called exclusively as an after-change function in +;; AWK Mode. It ensures that the syntax-table properties get set in the +;; changed region. However, if font-lock is enabled, this function does +;; nothing, since an enabled font-lock after-change function will always do +;; this. + (unless (and (boundp 'font-lock-mode) font-lock-mode) + (save-restriction + (save-excursion + (setq end (c-awk-end-of-change-region beg end old-len)) + (c-awk-beginning-of-logical-line beg) + (c-save-buffer-state nil ; So that read-only status isn't affected. + ; (e.g. when first loading the buffer) + (c-awk-set-syntax-table-properties end)))))) + +;; ACM 2002/5/25. When font-locking is invoked by a buffer change, the region +;; specified by the font-lock after-change function must be expanded to +;; include ALL of any string or regexp within the region. The simplest way to +;; do this in practice is to use the beginning/end-of-logical-line functions. +;; Don't overlook the possibility of the buffer change being the "recapturing" +;; of a previously escaped newline. +(defmacro c-awk-advise-fl-for-awk-region (function) + `(defadvice ,function (before get-awk-region activate) +;; When font-locking an AWK Mode buffer, make sure that any string/regexp is +;; completely font-locked. + (when (eq major-mode 'awk-mode) + (save-excursion + (ad-set-arg 1 (c-awk-end-of-change-region + (ad-get-arg 0) ; beg + (ad-get-arg 1) ; end + (ad-get-arg 2))) ; old-len + (ad-set-arg 0 (c-awk-beginning-of-logical-line (ad-get-arg 0))))))) + +(c-awk-advise-fl-for-awk-region font-lock-after-change-function) +(c-awk-advise-fl-for-awk-region jit-lock-after-change) +(c-awk-advise-fl-for-awk-region lazy-lock-defer-rest-after-change) +(c-awk-advise-fl-for-awk-region lazy-lock-defer-line-after-change) + +;; ACM 2002/9/29. Functions for C-M-a and C-M-e + +(defconst c-awk-terminated-regexp-or-string-here-re "\\=\\s\"\\S\"*\\s\"") +;; Matches a terminated string/regexp (utilising syntax-table properties). + +(defconst c-awk-unterminated-regexp-or-string-here-re "\\=\\s|\\S|*$") +;; Matches an unterminated string/regexp, NOT including the eol at the end. + +(defconst c-awk-harmless-pattern-characters* + (concat "\\([^{;#/\"\\\\\n\r]\\|" c-awk-esc-pair-re "\\)*")) +;; Matches any "harmless" character in a pattern or an escaped character pair. + +(defun c-awk-beginning-of-defun (&optional arg) + "Move backward to the beginning of an AWK \"defun\". With ARG, do it that +many times. Negative arg -N means move forward to Nth following beginning of +defun. Returns t unless search stops due to beginning or end of buffer. + +By a \"defun\" is meant either a pattern-action pair or a function. The start +of a defun is recognised as code starting at column zero which is neither a +closing brace nor a comment nor a continuation of the previous line. Unlike +in some other modes, having an opening brace at column 0 is neither necessary +nor helpful." + (interactive "p") + (save-match-data + (c-save-buffer-state ; ensures the buffer is writable. + nil + (let ((found t)) ; Has the most recent regexp search found b-of-defun? + (if (>= arg 0) + ;; Go back one defun each time round the following loop. (For +ve arg) + (while (and found (> arg 0) (not (eq (point) (point-min)))) + ;; Go back one "candidate" each time round the next loop until one + ;; is genuinely a beginning-of-defun. + (while (and (setq found (search-backward-regexp + "^[^#} \t\n\r]" (point-min) 'stop-at-limit)) + (not (memq (c-awk-get-NL-prop-prev-line) '(?\; ?\#))))) + (setq arg (1- arg))) + ;; The same for a -ve arg. + (if (not (eq (point) (point-max))) (forward-char 1)) + (while (and found (< arg 0) (not (eq (point) (point-max)))) ; The same for -ve arg. + (while (and (setq found (search-forward-regexp + "^[^#} \t\n\r]" (point-max) 'stop-at-limit)) + (not (memq (c-awk-get-NL-prop-prev-line) '(?\; ?\#))))) + (setq arg (1+ arg))) + (if found (goto-char (match-beginning 0)))) + (eq arg 0))))) + +(defun c-awk-forward-awk-pattern () + ;; Point is at the start of an AWK pattern (which may be null) or function + ;; declaration. Move to the pattern's end, and past any trailing space or + ;; comment. Typically, we stop at the { which denotes the corresponding AWK + ;; action/function body. Otherwise we stop at the EOL (or ;) marking the + ;; absence of an explicit action. + (while + (progn + (search-forward-regexp c-awk-harmless-pattern-characters*) + (if (looking-at "#") (end-of-line)) + (cond + ((eobp) nil) + ((looking-at "[{;]") nil) ; We've finished! + ((eolp) + (if (c-awk-cur-line-incomplete-p) + (forward-line) ; returns non-nil + nil)) + ((search-forward-regexp c-awk-terminated-regexp-or-string-here-re nil t)) + ((search-forward-regexp c-awk-unterminated-regexp-or-string-here-re nil t)) + ((looking-at "/") (forward-char) t))))) ; division sign. + +(defun c-awk-end-of-defun1 () + ;; point is at the start of a "defun". Move to its end. Return end position. + (c-awk-forward-awk-pattern) + (cond + ((looking-at "{") (goto-char (scan-sexps (point) 1))) + ((looking-at ";") (forward-char)) + ((eolp)) + (t (error "c-awk-end-of-defun1: Failure of c-awk-forward-awk-pattern"))) + (point)) + +(defun c-awk-beginning-of-defun-p () + ;; Are we already at the beginning of a defun? (i.e. at code in column 0 + ;; which isn't a }, and isn't a continuation line of any sort. + (and (looking-at "^[^#} \t\n\r]") + (not (c-awk-prev-line-incomplete-p)))) + +(defun c-awk-end-of-defun (&optional arg) + "Move forward to next end of defun. With argument, do it that many times. +Negative argument -N means move back to Nth preceding end of defun. + +An end of a defun occurs right after the closing brace that matches the +opening brace at its start, or immediately after the AWK pattern when there is +no explicit action; see function `c-awk-beginning-of-defun'." + (interactive "p") + (or arg (setq arg 1)) + (save-match-data + (c-save-buffer-state + nil + (let ((start-point (point)) end-point) + ;; Strategy: (For +ve ARG): If we're not already at a beginning-of-defun, + ;; move backwards to one. + ;; Repeat [(i) move forward to end-of-current-defun (see below); + ;; (ii) If this isn't it, move forward to beginning-of-defun]. + ;; We start counting ARG only when step (i) has passed the original point. + (when (> arg 0) + ;; Try to move back to a beginning-of-defun, if not already at one. + (if (not (c-awk-beginning-of-defun-p)) + (when (not (c-awk-beginning-of-defun 1)) ; No bo-defun before point. + (goto-char start-point) + (c-awk-beginning-of-defun -1))) ; if this fails, we're at EOB, tough! + ;; Now count forward, one defun at a time + (while (and (not (eobp)) + (c-awk-end-of-defun1) + (if (> (point) start-point) (setq arg (1- arg)) t) + (> arg 0) + (c-awk-beginning-of-defun -1)))) + + (when (< arg 0) + (setq end-point start-point) + (while (and (not (bobp)) + (c-awk-beginning-of-defun 1) + (if (< (setq end-point (if (bobp) (point) + (save-excursion (c-awk-end-of-defun1)))) + start-point) + (setq arg (1+ arg)) t) + (< arg 0))) + (goto-char (min start-point end-point))))))) + +(cc-provide 'cc-awk) ; Changed from 'awk-mode, ACM 2002/5/21 +;;; awk-mode.el ends here
--- a/lisp/progmodes/cc-bytecomp.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-bytecomp.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,6 +1,6 @@ ;;; cc-bytecomp.el --- compile time setup for proper compilation -;; Copyright (C) 2000, 01 Free Software Foundation, Inc. +;; Copyright (C) 2000, 01, 02, 03 Free Software Foundation, Inc. ;; Author: Martin Stjernholm ;; Maintainer: bug-cc-mode@gnu.org @@ -34,7 +34,44 @@ ;; ;; There's really nothing CC Mode specific here; this functionality ;; ought to be provided by the byte compilers or some accompanying -;; library. +;; library. To use it from some package "foo.el", begin by putting +;; the following blurb at the top of the file: +;; +;; (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)) +;; +;; This (unfortunately rather clumsy) form will ensure that the +;; cc-bytecomp.el in the same directory as foo.el is loaded during +;; byte compilation of the latter. +;; +;; At the end of foo.el there should normally be a "(provide 'foo)". +;; Replace it with "(cc-provide 'foo)"; that is necessary to restore +;; the environment after the byte compilation. If you don't have a +;; `provide' at the end, you have to add the following as the very +;; last form in the file: +;; +;; (eval-when-compile (cc-bytecomp-restore-environment)) +;; +;; Now everything is set to use the various functions and macros in +;; this package. +;; +;; If your package is split into several files, you should use +;; `cc-require', `cc-require-when-compile' or `cc-load' to load them. +;; That ensures that the files in the same directory always are +;; loaded, to avoid mixup with other versions of them that might exist +;; elsewhere in the load path. +;; +;; To suppress byte compiler warnings, use the macros +;; `cc-bytecomp-defun', `cc-bytecomp-defvar', +;; `cc-bytecomp-obsolete-fun', and `cc-bytecomp-obsolete-var'. +;; +;; This file is not used at all after the package has been byte +;; compiled. It is however necessary when running uncompiled. ;;; Code: @@ -42,53 +79,20 @@ (defvar cc-bytecomp-unbound-variables nil) (defvar cc-bytecomp-original-functions nil) (defvar cc-bytecomp-original-properties nil) -(defvar cc-bytecomp-load-depth 0) (defvar cc-bytecomp-loaded-files nil) (defvar cc-bytecomp-environment-set nil) -(put 'cc-eval-when-compile 'lisp-indent-hook 0) -(defmacro cc-eval-when-compile (&rest body) - "Like `progn', but evaluates the body at compile time. -The result of the body appears to the compiler as a quoted constant. - -This variant works around what looks like a bug in -`eval-when-compile': During byte compilation it byte compiles its -contents before evaluating it. That can cause forms to be compiled in -situations they aren't intended to be compiled. See cc-bytecomp.el -for further discussion." - ;; - ;; Example: It's not possible to defsubst a primitive, e.g. the - ;; following will produce an error (in any emacs flavor), since - ;; `nthcdr' is a primitive function that's handled specially by the - ;; byte compiler and thus can't be redefined: - ;; - ;; (defsubst nthcdr (val) val) - ;; - ;; `defsubst', like `defmacro', needs to be evaluated at compile - ;; time, so this will produce an error during byte compilation. - ;; - ;; CC Mode occasionally needs to do things like this for cross-emacs - ;; compatibility (although we try to avoid it since it results in - ;; byte code that isn't compatible between emacsen). It therefore - ;; uses the following to conditionally do a `defsubst': - ;; - ;; (eval-when-compile - ;; (if (not (fboundp 'foo)) - ;; (defsubst foo ...))) - ;; - ;; But `eval-when-compile' byte compiles its contents and _then_ - ;; evaluates it (in all current emacs versions, up to and including - ;; Emacs 20.6 and XEmacs 21.1 as of this writing). So this will - ;; still produce an error, since the byte compiler will get to the - ;; defsubst anyway. That's arguably a bug because the point with - ;; `eval-when-compile' is that it should evaluate rather than - ;; compile its contents. - `(eval-when-compile (eval '(progn ,@body)))) +(defmacro cc-bytecomp-debug-msg (&rest args) + ;;`(message ,@args) + ) (defun cc-bytecomp-setup-environment () ;; Eval'ed during compilation to setup variables, functions etc ;; declared with `cc-bytecomp-defvar' et al. - (if (= cc-bytecomp-load-depth 0) + (if (not load-in-progress) + ;; Look at `load-in-progress' to tell whether we're called + ;; directly in the file being compiled or just from some file + ;; being loaded during compilation. (let (p) (if cc-bytecomp-environment-set (error "Byte compilation environment already set - \ @@ -98,46 +102,85 @@ (if (not (boundp (car p))) (progn (eval `(defvar ,(car p))) - (set (car p) 'cc-bytecomp-ignore))) + (set (car p) (intern (concat "cc-bytecomp-ignore-var:" + (symbol-name (car p))))) + (cc-bytecomp-debug-msg + "cc-bytecomp-setup-environment: Covered variable %s" + (car p)))) (setq p (cdr p))) (setq p cc-bytecomp-original-functions) (while p (let ((fun (car (car p))) (temp-macro (car (cdr (car p))))) - (if temp-macro - (eval `(defmacro ,fun ,@temp-macro)) - (fset fun 'cc-bytecomp-ignore))) + (if (not (fboundp fun)) + (if temp-macro + (progn + (eval `(defmacro ,fun ,@temp-macro)) + (cc-bytecomp-debug-msg + "cc-bytecomp-setup-environment: Bound macro %s" fun)) + (fset fun (intern (concat "cc-bytecomp-ignore-fun:" + (symbol-name fun)))) + (cc-bytecomp-debug-msg + "cc-bytecomp-setup-environment: Covered function %s" fun)))) (setq p (cdr p))) (setq p cc-bytecomp-original-properties) (while p (let ((sym (car (car (car p)))) (prop (cdr (car (car p)))) (tempdef (car (cdr (car p))))) - (put sym prop tempdef)) + (put sym prop tempdef) + (cc-bytecomp-debug-msg + "cc-bytecomp-setup-environment: Bound property %s for %s to %s" + prop sym tempdef)) (setq p (cdr p))) - (setq cc-bytecomp-environment-set t)))) + (setq cc-bytecomp-environment-set t) + (cc-bytecomp-debug-msg + "cc-bytecomp-setup-environment: Done")))) (defun cc-bytecomp-restore-environment () ;; Eval'ed during compilation to restore variables, functions etc ;; declared with `cc-bytecomp-defvar' et al. - (if (= cc-bytecomp-load-depth 0) + (if (not load-in-progress) (let (p) (setq p cc-bytecomp-unbound-variables) (while p (let ((var (car p))) - (if (and (boundp var) - (eq var 'cc-bytecomp-ignore)) - (makunbound var))) + (if (boundp var) + (if (eq (intern (concat "cc-bytecomp-ignore-var:" + (symbol-name var))) + (symbol-value var)) + (progn + (makunbound var) + (cc-bytecomp-debug-msg + "cc-bytecomp-restore-environment: Unbound variable %s" + var)) + (cc-bytecomp-debug-msg + "cc-bytecomp-restore-environment: Not restoring variable %s" + var)))) (setq p (cdr p))) (setq p cc-bytecomp-original-functions) (while p (let ((fun (car (car p))) + (temp-macro (car (cdr (car p)))) (def (car (cdr (cdr (car p)))))) - (if (and (fboundp fun) - (eq (symbol-function fun) 'cc-bytecomp-ignore)) - (if (eq def 'unbound) - (fmakunbound fun) - (fset fun def)))) + (if (fboundp fun) + (if (eq (or temp-macro + (intern (concat "cc-bytecomp-ignore-fun:" + (symbol-name fun)))) + (symbol-function fun)) + (if (eq def 'unbound) + (progn + (fmakunbound fun) + (cc-bytecomp-debug-msg + "cc-bytecomp-restore-environment: Unbound function %s" + fun)) + (fset fun def) + (cc-bytecomp-debug-msg + "cc-bytecomp-restore-environment: Restored function %s" + fun)) + (cc-bytecomp-debug-msg + "cc-bytecomp-restore-environment: Not restoring function %s" + fun)))) (setq p (cdr p))) (setq p cc-bytecomp-original-properties) (while p @@ -146,40 +189,60 @@ (tempdef (car (cdr (car p)))) (origdef (cdr (cdr (car p))))) (if (eq (get sym prop) tempdef) - (put sym prop origdef))) + (progn + (put sym prop origdef) + (cc-bytecomp-debug-msg + "cc-bytecomp-restore-environment: Restored property %s for %s to %s" + prop sym origdef)) + (cc-bytecomp-debug-msg + "cc-bytecomp-restore-environment: Not restoring property %s for %s" + prop sym))) (setq p (cdr p))) - (setq cc-bytecomp-environment-set nil)))) + (setq cc-bytecomp-environment-set nil) + (cc-bytecomp-debug-msg + "cc-bytecomp-restore-environment: Done")))) + +(eval + ;; This eval is to avoid byte compilation of the function below. + ;; There's some bug in XEmacs 21.4.6 that can cause it to dump core + ;; here otherwise. My theory is that `cc-bytecomp-load' might be + ;; redefined recursively during the `load' inside it, and if it in + ;; that case is byte compiled then the byte interpreter gets + ;; confused. I haven't succeeded in isolating the bug, though. /mast -(defun cc-bytecomp-load (cc-part) - ;; Eval'ed during compilation to load a CC Mode file from the source - ;; directory (assuming it's the same as the compiled file - ;; destination dir). - (if (and (boundp 'byte-compile-dest-file) - (stringp byte-compile-dest-file)) - (progn - (cc-bytecomp-restore-environment) - (let ((cc-bytecomp-load-depth (1+ cc-bytecomp-load-depth)) - (load-path - (cons (file-name-directory byte-compile-dest-file) - load-path)) - (cc-file (concat cc-part ".el"))) - (if (member cc-file cc-bytecomp-loaded-files) - () - (setq cc-bytecomp-loaded-files - (cons cc-file cc-bytecomp-loaded-files)) - (load cc-file nil t t))) - (cc-bytecomp-setup-environment) - t))) + '(defun cc-bytecomp-load (cc-part) + ;; Eval'ed during compilation to load a CC Mode file from the source + ;; directory (assuming it's the same as the compiled file + ;; destination dir). + (if (and (boundp 'byte-compile-dest-file) + (stringp byte-compile-dest-file)) + (progn + (cc-bytecomp-restore-environment) + (let ((load-path + (cons (file-name-directory byte-compile-dest-file) + load-path)) + (cc-file (concat cc-part ".el"))) + (if (member cc-file cc-bytecomp-loaded-files) + () + (setq cc-bytecomp-loaded-files + (cons cc-file cc-bytecomp-loaded-files)) + (cc-bytecomp-debug-msg + "cc-bytecomp-load: Loading %S" cc-file) + (load cc-file nil t t) + (cc-bytecomp-debug-msg + "cc-bytecomp-load: Loaded %S" cc-file))) + (cc-bytecomp-setup-environment) + t)))) (defmacro cc-require (cc-part) - "Force loading of the corresponding .el file in the current -directory during compilation, but compile in a `require'. Don't use -within `eval-when-compile'. + "Force loading of the corresponding .el file in the current directory +during compilation, but compile in a `require'. Don't use within +`eval-when-compile'. Having cyclic cc-require's will result in infinite recursion. That's somewhat intentional." `(progn - (cc-eval-when-compile (cc-bytecomp-load (symbol-name ,cc-part))) + (eval-when-compile (cc-bytecomp-load (symbol-name ,cc-part))) (require ,cc-part))) (defmacro cc-provide (feature) @@ -190,9 +253,9 @@ (provide ,feature))) (defmacro cc-load (cc-part) - "Force loading of the corresponding .el file in the current -directory during compilation. Don't use outside `eval-when-compile' -or `eval-and-compile'. + "Force loading of the corresponding .el file in the current directory +during compilation. Don't use outside `eval-when-compile' or +`eval-and-compile'. Having cyclic cc-load's will result in infinite recursion. That's somewhat intentional." @@ -200,6 +263,27 @@ (cc-bytecomp-load ,cc-part)) (load ,cc-part nil t nil))) +(defmacro cc-require-when-compile (cc-part) + "Force loading of the corresponding .el file in the current directory +during compilation, but do a compile time `require' otherwise. Don't +use within `eval-when-compile'." + `(eval-when-compile + (if (and (featurep 'cc-bytecomp) + (cc-bytecomp-is-compiling)) + (if (or (not load-in-progress) + (not (featurep ,cc-part))) + (cc-bytecomp-load (symbol-name ,cc-part))) + (require ,cc-part)))) + +(defmacro cc-external-require (feature) + "Do a `require' of an external package. +This restores and sets up the compilation environment before and +afterwards. Don't use within `eval-when-compile'." + `(progn + (eval-when-compile (cc-bytecomp-restore-environment)) + (require ,feature) + (eval-when-compile (cc-bytecomp-setup-environment)))) + (defun cc-bytecomp-is-compiling () "Return non-nil if eval'ed during compilation. Don't use outside `eval-when-compile'." @@ -211,58 +295,95 @@ to silence the byte compiler. Don't use within `eval-when-compile'." `(eval-when-compile (if (boundp ',var) - nil + (cc-bytecomp-debug-msg + "cc-bytecomp-defvar: %s bound already as variable" ',var) (if (not (memq ',var cc-bytecomp-unbound-variables)) - (setq cc-bytecomp-unbound-variables - (cons ',var cc-bytecomp-unbound-variables))) + (progn + (cc-bytecomp-debug-msg + "cc-bytecomp-defvar: Saving %s (as unbound)" ',var) + (setq cc-bytecomp-unbound-variables + (cons ',var cc-bytecomp-unbound-variables)))) (if (and (cc-bytecomp-is-compiling) - (= cc-bytecomp-load-depth 0)) + (not load-in-progress)) (progn (defvar ,var) - (set ',var 'cc-bytecomp-ignore)))))) + (set ',var (intern (concat "cc-bytecomp-ignore-var:" + (symbol-name ',var)))) + (cc-bytecomp-debug-msg + "cc-bytecomp-defvar: Covered variable %s" ',var)))))) (defmacro cc-bytecomp-defun (fun) "Bind the symbol as a function during compilation of the file, -to silence the byte compiler. Don't use within `eval-when-compile'." +to silence the byte compiler. Don't use within `eval-when-compile'. + +If the symbol already is bound as a function, it will keep that +definition. That means that this macro will not shut up warnings +about incorrect number of arguments. It's dangerous to try to replace +existing functions since the byte compiler might need the definition +at compile time, e.g. for macros and inline functions." `(eval-when-compile (if (fboundp ',fun) - nil + (cc-bytecomp-debug-msg + "cc-bytecomp-defun: %s bound already as function" ',fun) (if (not (assq ',fun cc-bytecomp-original-functions)) - (setq cc-bytecomp-original-functions - (cons (list ',fun nil 'unbound) - cc-bytecomp-original-functions))) + (progn + (cc-bytecomp-debug-msg + "cc-bytecomp-defun: Saving %s (as unbound)" ',fun) + (setq cc-bytecomp-original-functions + (cons (list ',fun nil 'unbound) + cc-bytecomp-original-functions)))) (if (and (cc-bytecomp-is-compiling) - (= cc-bytecomp-load-depth 0)) - (fset ',fun 'cc-bytecomp-ignore))))) + (not load-in-progress)) + (progn + (fset ',fun (intern (concat "cc-bytecomp-ignore-fun:" + (symbol-name ',fun)))) + (cc-bytecomp-debug-msg + "cc-bytecomp-defun: Covered function %s" ',fun)))))) (put 'cc-bytecomp-defmacro 'lisp-indent-function 'defun) (defmacro cc-bytecomp-defmacro (fun &rest temp-macro) "Bind the symbol as a macro during compilation (and evaluation) of the file. Don't use outside `eval-when-compile'." - `(progn - (if (not (assq ',fun cc-bytecomp-original-functions)) - (setq cc-bytecomp-original-functions - (cons (list ',fun - ',temp-macro - (if (fboundp ',fun) - (symbol-function ',fun) - 'unbound)) - cc-bytecomp-original-functions))) - (defmacro ,fun ,@temp-macro))) + `(let ((orig-fun (assq ',fun cc-bytecomp-original-functions))) + (if (not orig-fun) + (setq orig-fun + (list ',fun + nil + (if (fboundp ',fun) + (progn + (cc-bytecomp-debug-msg + "cc-bytecomp-defmacro: Saving %s" ',fun) + (symbol-function ',fun)) + (cc-bytecomp-debug-msg + "cc-bytecomp-defmacro: Saving %s as unbound" ',fun) + 'unbound)) + cc-bytecomp-original-functions + (cons orig-fun cc-bytecomp-original-functions))) + (defmacro ,fun ,@temp-macro) + (cc-bytecomp-debug-msg + "cc-bytecomp-defmacro: Bound macro %s" ',fun) + (setcar (cdr orig-fun) (symbol-function ',fun)))) (defmacro cc-bytecomp-put (symbol propname value) "Set a property on a symbol during compilation (and evaluation) of the file. Don't use outside `eval-when-compile'." - `(cc-eval-when-compile + `(eval-when-compile (if (not (assoc (cons ,symbol ,propname) cc-bytecomp-original-properties)) - (setq cc-bytecomp-original-properties - (cons (cons (cons ,symbol ,propname) - (cons ,value (get ,symbol ,propname))) - cc-bytecomp-original-properties))) - (put ,symbol ,propname ,value))) + (progn + (cc-bytecomp-debug-msg + "cc-bytecomp-put: Saving property %s for %s with value %s" + ,propname ,symbol (get ,symbol ,propname)) + (setq cc-bytecomp-original-properties + (cons (cons (cons ,symbol ,propname) + (cons ,value (get ,symbol ,propname))) + cc-bytecomp-original-properties)))) + (put ,symbol ,propname ,value) + (cc-bytecomp-debug-msg + "cc-bytecomp-put: Bound property %s for %s to %s" + ,propname ,symbol ,value))) (defmacro cc-bytecomp-obsolete-var (symbol) - "Suppress warnings about that the given symbol is an obsolete variable. + "Suppress warnings that the given symbol is an obsolete variable. Don't use within `eval-when-compile'." `(eval-when-compile (if (get ',symbol 'byte-obsolete-variable) @@ -278,21 +399,38 @@ (byte-compile-obsolete form))) (defmacro cc-bytecomp-obsolete-fun (symbol) - "Suppress warnings about that the given symbol is an obsolete function. + "Suppress warnings that the given symbol is an obsolete function. Don't use within `eval-when-compile'." `(eval-when-compile (if (eq (get ',symbol 'byte-compile) 'byte-compile-obsolete) (cc-bytecomp-put ',symbol 'byte-compile - 'cc-bytecomp-ignore-obsolete)))) + 'cc-bytecomp-ignore-obsolete) + ;; This avoids a superfluous compiler warning + ;; about calling `get' for effect. + t))) -;; Override ourselves with a version loaded from source if we're -;; compiling, like cc-require does for all the other files. -(if (and (cc-bytecomp-is-compiling) - (= cc-bytecomp-load-depth 0)) - (let ((load-path - (cons (file-name-directory byte-compile-dest-file) load-path)) - (cc-bytecomp-load-depth 1)) - (load "cc-bytecomp.el" nil t t))) +(defmacro cc-bytecomp-boundp (symbol) + "Return non-nil if the given symbol is bound as a variable outside +the compilation. This is the same as using `boundp' but additionally +exclude any variables that have been bound during compilation with +`cc-bytecomp-defvar'." + (if (and (cc-bytecomp-is-compiling) + (memq (car (cdr symbol)) cc-bytecomp-unbound-variables)) + nil + `(boundp ,symbol))) + +(defmacro cc-bytecomp-fboundp (symbol) + "Return non-nil if the given symbol is bound as a function outside +the compilation. This is the same as using `fboundp' but additionally +exclude any functions that have been bound during compilation with +`cc-bytecomp-defun'." + (let (fun-elem) + (if (and (cc-bytecomp-is-compiling) + (setq fun-elem (assq (car (cdr symbol)) + cc-bytecomp-original-functions)) + (eq (elt fun-elem 2) 'unbound)) + nil + `(fboundp ,symbol)))) (provide 'cc-bytecomp)
--- a/lisp/progmodes/cc-cmds.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-cmds.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,9 @@ ;;; cc-cmds.el --- user level commands for CC Mode -;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1992-1997 Barry A. Warsaw +;; Authors: 1998- Martin Stjernholm +;; 1992-1999 Barry A. Warsaw ;; 1987 Dave Detlefs and Stewart Clamen ;; 1985 Richard M. Stallman ;; Maintainer: bug-cc-mode@gnu.org @@ -39,11 +38,10 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) (cc-require 'cc-defs) (cc-require 'cc-vars) -(cc-require 'cc-langs) (cc-require 'cc-engine) ;; Silence the compiler. @@ -57,6 +55,7 @@ (defvar c-fix-backslashes t) (defun c-shift-line-indentation (shift-amt) + ;; This function does not do any hidden buffer changes. (let ((pos (- (point-max) (point))) (c-macro-start c-macro-start) tmp-char-inserted) @@ -96,6 +95,9 @@ is otherwise empty \(ignoring any line continuation backslash), but that's not done if IGNORE-POINT-POS is non-nil. Returns the amount of indentation change \(in columns)." + ;; + ;; This function does not do any hidden buffer changes. + (let ((line-cont-backslash (save-excursion (end-of-line) (eq (char-before) ?\\))) @@ -124,18 +126,21 @@ (setq c-fix-backslashes t)) (if c-syntactic-indentation (setq c-parsing-error - (or (let* ((c-parsing-error nil) - (c-syntactic-context (or syntax - c-syntactic-context - (c-guess-basic-syntax))) - indent) - (setq indent (c-get-syntactic-indentation - c-syntactic-context)) - (and (not (c-echo-parsing-error quiet)) - c-echo-syntactic-information-p - (message "syntax: %s, indent: %d" - c-syntactic-context indent)) - (setq shift-amt (- indent (current-indentation))) + (or (let ((c-parsing-error nil) + (c-syntactic-context + (or syntax + (and (boundp 'c-syntactic-context) + c-syntactic-context)))) + (c-save-buffer-state (indent) + (unless c-syntactic-context + (setq c-syntactic-context (c-guess-basic-syntax))) + (setq indent (c-get-syntactic-indentation + c-syntactic-context)) + (and (not (c-echo-parsing-error quiet)) + c-echo-syntactic-information-p + (message "syntax: %s, indent: %d" + c-syntactic-context indent)) + (setq shift-amt (- indent (current-indentation)))) (c-shift-line-indentation shift-amt) (run-hooks 'c-special-indent-hook) c-parsing-error) @@ -165,7 +170,10 @@ and takes care to set the indentation before calling `indent-according-to-mode', so that lineup functions like `c-lineup-dont-change' works better." - ;; FIXME: Backslashes before eol in comments and literals aren't + ;; + ;; This function does not do any hidden buffer changes. + + ;; TODO: Backslashes before eol in comments and literals aren't ;; kept intact. (let ((c-macro-start (c-query-macro-start)) ;; Avoid calling c-backslash-region from c-indent-line if it's @@ -210,7 +218,8 @@ ;; Reindent syntactically. The indentation done above is not ;; wasted, since c-indent-line might look at the current ;; indentation. - (let ((c-syntactic-context (c-guess-basic-syntax))) + (let ((c-syntactic-context (c-save-buffer-state nil + (c-guess-basic-syntax)))) ;; We temporarily insert another line break, so that the ;; lineup functions will see the line as empty. That makes ;; e.g. c-lineup-cpp-define more intuitive since it then @@ -236,7 +245,12 @@ With universal argument, inserts the analysis as a comment on that line." (interactive "P") (let* ((c-parsing-error nil) - (syntax (c-guess-basic-syntax))) + (syntax (if (boundp 'c-syntactic-context) + ;; Use `c-syntactic-context' in the same way as + ;; `c-indent-line', to be consistent. + c-syntactic-context + (c-save-buffer-state nil + (c-guess-basic-syntax))))) (if (not (consp arg)) (message "syntactic analysis: %s" syntax) (indent-for-comment) @@ -325,28 +339,32 @@ ;; Electric keys (defun c-electric-backspace (arg) - "Deletes preceding character or whitespace. + "Delete the preceding character or whitespace. If `c-hungry-delete-key' is non-nil, as evidenced by the \"/h\" or \"/ah\" string on the mode line, then all preceding whitespace is consumed. If however a prefix argument is supplied, or `c-hungry-delete-key' is nil, or point is inside a literal then the -function in the variable `c-backspace-function' is called. - -See also \\[c-electric-delete]." +function in the variable `c-backspace-function' is called." (interactive "*P") (if (or (not c-hungry-delete-key) arg (c-in-literal)) (funcall c-backspace-function (prefix-numeric-value arg)) - (let ((here (point))) - (c-skip-ws-backward) - (if (/= (point) here) - (delete-region (point) here) - (funcall c-backspace-function 1) - )))) + (c-hungry-backspace))) + +(defun c-hungry-backspace () + "Delete the preceding character or all preceding whitespace +back to the previous non-whitespace character. +See also \\[c-hungry-delete-forward]." + (interactive) + (let ((here (point))) + (c-skip-ws-backward) + (if (/= (point) here) + (delete-region (point) here) + (funcall c-backspace-function 1)))) (defun c-electric-delete-forward (arg) - "Deletes following character or whitespace. + "Delete the following character or whitespace. If `c-hungry-delete-key' is non-nil, as evidenced by the \"/h\" or \"/ah\" string on the mode line, then all following whitespace is consumed. If however a prefix argument is supplied, or @@ -357,12 +375,20 @@ arg (c-in-literal)) (funcall c-delete-function (prefix-numeric-value arg)) - (let ((here (point))) - (c-skip-ws-forward) - (if (/= (point) here) - (delete-region (point) here) - (funcall c-delete-function 1))))) + (c-hungry-delete-forward))) +(defun c-hungry-delete-forward () + "Delete the following character or all following whitespace +up to the next non-whitespace character. +See also \\[c-hungry-backspace]." + (interactive) + (let ((here (point))) + (c-skip-ws-forward) + (if (/= (point) here) + (delete-region (point) here) + (funcall c-delete-function 1)))) + +;; This function is only used in XEmacs. (defun c-electric-delete (arg) "Deletes preceding or following character or whitespace. This function either deletes forward as `c-electric-delete-forward' or @@ -455,8 +481,13 @@ substatement-open statement-case-open extern-lang-open extern-lang-close namespace-open namespace-close + module-open module-close + composition-open composition-close inexpr-class-open inexpr-class-close - )) + ;; `statement-cont' is here for the case with a brace + ;; list opener inside a statement. C.f. CASE B.2 in + ;; `c-guess-continued-construct'. + statement-cont)) (insertion-point (point)) (preserve-p (and (not (bobp)) (eq ?\ (char-syntax (char-before))))) @@ -476,7 +507,8 @@ (if (eq last-command-char ?{) (setq c-state-cache (cons (point) c-state-cache))) (self-insert-command (prefix-numeric-value arg)) - (let ((c-syntactic-indentation-in-macros t)) + (c-save-buffer-state ((c-syntactic-indentation-in-macros t) + (c-auto-newline-analysis t)) ;; Turn on syntactic macro analysis to help with auto ;; newlines only. (setq syntax (c-guess-basic-syntax))) @@ -501,10 +533,11 @@ ;; (Pike-style) brace list. (if (and c-special-brace-lists (save-excursion - (c-safe (if (= (char-before) ?{) - (forward-char -1) - (c-forward-sexp -1)) - (c-looking-at-special-brace-list)))) + (c-save-buffer-state nil + (c-safe (if (= (char-before) ?{) + (forward-char -1) + (c-forward-sexp -1)) + (c-looking-at-special-brace-list))))) (setq newlines nil)) ;; If syntax is a function symbol, then call it using the ;; defined semantics. @@ -533,7 +566,9 @@ ;; indentation, we need to recalculate syntax for ;; the current line. (if (/= (point) here) - (let ((c-syntactic-indentation-in-macros t)) + (c-save-buffer-state + ((c-syntactic-indentation-in-macros t) + (c-auto-newline-analysis t)) ;; Turn on syntactic macro analysis to help ;; with auto newlines only. (setq syntax (c-guess-basic-syntax)))))))) @@ -553,7 +588,8 @@ (if (not (memq 'before newlines)) ;; since we're hanging the brace, we need to recalculate ;; syntax. - (let ((c-syntactic-indentation-in-macros t)) + (c-save-buffer-state ((c-syntactic-indentation-in-macros t) + (c-auto-newline-analysis t)) ;; Turn on syntactic macro analysis to help with auto ;; newlines only. (setq syntax (c-guess-basic-syntax)))) @@ -605,7 +641,7 @@ (c-skip-ws-backward) (setq mbeg (point)) (eq (char-before) ?\))) - (= (c-backward-token-1 1 t) 0) + (zerop (c-save-buffer-state nil (c-backward-token-2 1 t))) (eq (char-after) ?\() (progn (setq tmp (point)) @@ -632,7 +668,8 @@ (not executing-kbd-macro) old-blink-paren (save-excursion - (c-backward-syntactic-ws safepos) + (c-save-buffer-state nil + (c-backward-syntactic-ws safepos)) (funcall old-blink-paren))))) (defun c-electric-slash (arg) @@ -804,7 +841,9 @@ ;; since that's made with c-syntactic-indentation-in-macros ;; always set to t. (indent-according-to-mode)) - (let* ((c-syntactic-indentation-in-macros t) + (c-save-buffer-state + ((c-syntactic-indentation-in-macros t) + (c-auto-newline-analysis t) ;; Turn on syntactic macro analysis to help with auto newlines ;; only. (syntax (c-guess-basic-syntax)) @@ -822,7 +861,7 @@ (or (c-lookup-lists '(case-label label access-label) syntax c-hanging-colons-alist) (c-lookup-lists '(member-init-intro inher-intro) - (let ((buffer-undo-list t)) + (progn (insert ?\n) (unwind-protect (c-guess-basic-syntax) @@ -995,14 +1034,20 @@ ;; originally contributed by Terry_Glanfield.Southern@rxuk.xerox.com (defun c-forward-into-nomenclature (&optional arg) "Move forward to end of a nomenclature section or word. -With arg, to it arg times." +With arg, do it arg times." (interactive "p") (let ((case-fold-search nil)) (if (> arg 0) - (re-search-forward "\\W*\\([A-Z]*[a-z0-9]*\\)" (point-max) t arg) + (re-search-forward + (cc-eval-when-compile + (concat "\\W*\\([" c-upper "]*[" c-lower c-digit "]*\\)")) + (point-max) t arg) (while (and (< arg 0) (re-search-backward - "\\(\\(\\W\\|[a-z0-9]\\)[A-Z]+\\|\\W\\w+\\)" + (cc-eval-when-compile + (concat + "\\(\\(\\W\\|[" c-lower c-digit "]\\)[" c-upper "]+" + "\\|\\W\\w+\\)")) (point-min) 0)) (forward-char 1) (setq arg (1+ arg))))) @@ -1040,15 +1085,16 @@ (if (< arg 0) (when (c-end-of-defun (- arg)) - (c-forward-syntactic-ws) + (c-save-buffer-state nil (c-forward-syntactic-ws)) t) - (catch 'exit - (while (> arg 0) - ;; Note: Partial code duplication in `c-end-of-defun' and - ;; `c-declaration-limits'. + (c-save-buffer-state (paren-state lim pos) + (catch 'exit + (while (> arg 0) + ;; Note: Partial code duplication in `c-end-of-defun' and + ;; `c-declaration-limits'. - (let ((paren-state (c-parse-state)) lim pos) + (setq paren-state (c-parse-state)) (unless (c-safe (goto-char (c-least-enclosing-brace paren-state)) ;; If we moved to the outermost enclosing paren @@ -1079,8 +1125,7 @@ ;; Check if the declaration contains a brace ;; block. If not, we try another one. (setq pos (point)) - (not (and (c-syntactic-re-search-forward - "[;{]" nil t 1 t) + (not (and (c-syntactic-re-search-forward "[;{]" nil t t) (or (eq (char-before) ?{) (and c-recognize-knr-p ;; Might have stopped on the @@ -1113,7 +1158,7 @@ ;; the previous declaration then we use the current point ;; instead. (while (and (/= (point) (c-point 'boi)) - (c-forward-comment -1))) + (c-backward-single-comment))) (if (/= (point) (c-point 'boi)) (goto-char pos)) @@ -1135,15 +1180,16 @@ (if (< arg 0) (when (c-beginning-of-defun (- arg)) - (c-backward-syntactic-ws) + (c-save-buffer-state nil (c-backward-syntactic-ws)) t) - (catch 'exit - (while (> arg 0) - ;; Note: Partial code duplication in `c-beginning-of-defun' - ;; and `c-declaration-limits'. + (c-save-buffer-state (paren-state lim pos) + (catch 'exit + (while (> arg 0) + ;; Note: Partial code duplication in `c-beginning-of-defun' + ;; and `c-declaration-limits'. - (let ((paren-state (c-parse-state)) lim pos) + (setq paren-state (c-parse-state)) (unless (c-safe (goto-char (c-least-enclosing-brace paren-state)) ;; If we moved to the outermost enclosing paren @@ -1170,7 +1216,7 @@ ;; in a `c-opt-block-decls-with-vars-key' declaration, but ;; then we won't move significantly far here. (goto-char pos) - (c-forward-token-1 0)) + (c-forward-token-2 0)) (while (let ((start (point))) (c-end-of-decl-1) @@ -1188,7 +1234,7 @@ ;; block. If not, we try another one. (setq pos (point)) (goto-char start) - (not (c-syntactic-re-search-forward "{" pos t 1 t)))))) + (not (c-syntactic-re-search-forward "{" pos t t)))))) (setq pos (point)) ;; Try to be line oriented; position point after the next @@ -1196,7 +1242,7 @@ ;; next declaration then we use the current point instead. (while (and (not (bolp)) (not (looking-at "\\s *$")) - (c-forward-comment 1))) + (c-forward-single-comment))) (cond ((bolp)) ((looking-at "\\s *$") (forward-line 1)) @@ -1254,7 +1300,7 @@ ;; declaration, but then we won't move significantly far ;; here. (goto-char pos) - (while (c-forward-comment 10)) + (c-forward-comments) (when (and near (c-beginning-of-macro)) (throw 'exit @@ -1294,7 +1340,7 @@ (cons (progn (setq pos (point)) (while (and (/= (point) (c-point 'boi)) - (c-forward-comment -1))) + (c-backward-single-comment))) (if (/= (point) (c-point 'boi)) pos (point))) @@ -1305,7 +1351,7 @@ (setq pos (point)) (while (and (not (bolp)) (not (looking-at "\\s *$")) - (c-forward-comment 1))) + (c-forward-single-comment))) (cond ((bolp) (point)) ((looking-at "\\s *$") @@ -1323,12 +1369,14 @@ function does not require the declaration to contain a brace block." (interactive) - ;; We try to be line oriented, unless there are several - ;; declarations on the same line. - (if (looking-at c-syntactic-eol) - (c-backward-token-1 1 nil (c-point 'bol))) + (let (decl-limits) + (c-save-buffer-state nil + ;; We try to be line oriented, unless there are several + ;; declarations on the same line. + (if (looking-at c-syntactic-eol) + (c-backward-token-2 1 nil (c-point 'bol))) + (setq decl-limits (c-declaration-limits t))) - (let ((decl-limits (c-declaration-limits t))) (if (not decl-limits) (error "Cannot find any declaration") (goto-char (car decl-limits)) @@ -1354,9 +1402,10 @@ more \"DWIM:ey\"." (interactive (list (prefix-numeric-value current-prefix-arg) nil t)) - (let* ((count (or count 1)) - here - (range (c-collect-line-comments (c-literal-limits lim)))) + (c-save-buffer-state + ((count (or count 1)) + here + (range (c-collect-line-comments (c-literal-limits lim)))) (while (and (/= count 0) (or (not lim) (> (point) lim))) (setq here (point)) @@ -1364,9 +1413,9 @@ (save-excursion ;; Find the comment next to point if we're not in one. (if (> count 0) - (if (c-forward-comment-lc -1) + (if (c-backward-single-comment) (setq range (cons (point) - (progn (c-forward-comment-lc 1) + (progn (c-forward-single-comment) (point)))) (c-skip-ws-backward) (setq range (point)) @@ -1381,7 +1430,7 @@ (c-forward-sexp 1) (point)))) (setq range (point)) - (setq range (if (c-forward-comment-lc 1) + (setq range (if (c-forward-single-comment) (cons range (point)) nil)))) (setq range (c-collect-line-comments range)))) @@ -1509,7 +1558,6 @@ ;; into parens. Also stop before `#' when it's at boi ;; on a line. (let ((literal-pos (not sentence-flag)) - (large-enough (- (point-max))) last last-below-line) (catch 'done (while t @@ -1532,13 +1580,13 @@ ;; style comment. /mast ;;(c-skip-ws-backward) (if literal-pos - (c-forward-comment-lc large-enough) - (when (c-forward-comment-lc -1) + (c-backward-comments) + (when (c-backward-single-comment) ;; Record position of first comment. (save-excursion - (c-forward-comment-lc 1) + (c-forward-single-comment) (setq literal-pos (point))) - (c-forward-comment-lc large-enough))) + (c-backward-comments))) (unless last-below-line (if (save-excursion (re-search-forward "\\(^\\|[^\\]\\)$" last t)) @@ -1590,19 +1638,18 @@ ;; and move into parens. Also stop at eol of lines ;; with `#' at the boi. (let ((literal-pos (not sentence-flag)) - (large-enough (point-max)) last) (catch 'done (while t (setq last (point)) (if literal-pos - (c-forward-comment-lc large-enough) + (c-forward-comments) (if (progn (c-skip-ws-forward) ;; Record position of first comment. (setq literal-pos (point)) - (c-forward-comment-lc 1)) - (c-forward-comment-lc large-enough) + (c-forward-single-comment)) + (c-forward-comments) (setq literal-pos nil))) (cond ((and (eq (char-after) ?{) (not (and c-special-brace-lists @@ -1736,16 +1783,13 @@ ;; Recurse to handle value as a new spec. (c-calc-comment-indent (cdr entry))))))) -;; To avoid warning about assignment without reference wrt -;; c-add-syntax below. -(cc-bytecomp-defvar syntactic-relpos) - (defun c-comment-indent () "Used by `indent-for-comment' to create and indent comments. See `c-indent-comment-alist' for a description." (save-excursion (end-of-line) - (let* ((eot (let ((lim (c-literal-limits (c-point 'bol) t))) + (c-save-buffer-state + ((eot (let ((lim (c-literal-limits (c-point 'bol) t))) (or (when (consp lim) (goto-char (car lim)) (when (looking-at "/[/*]") @@ -1771,8 +1815,7 @@ 'other)))) (if (and (memq line-type '(anchored-comment empty-line)) c-indent-comments-syntactically-p) - (let ((syntax (c-guess-basic-syntax)) - syntactic-relpos) + (let ((c-syntactic-context (c-guess-basic-syntax))) ;; BOGOSITY ALERT: if we're looking at the eol, its ;; because indent-for-comment hasn't put the comment-start ;; in the buffer yet. this will screw up the syntactic @@ -1787,7 +1830,7 @@ c-comment-only-line-offset (cons c-comment-only-line-offset c-comment-only-line-offset)))) - (c-get-syntactic-indentation syntax))) + (c-get-syntactic-indentation c-syntactic-context))) (goto-char eot) (c-calc-comment-indent line-type))))) @@ -1811,7 +1854,7 @@ (interactive "p") (c-forward-conditional (- count) -1) (c-keep-region-active)) - + (defun c-up-conditional-with-else (count) "Move back to the containing preprocessor conditional, including `#else'. Just like `c-up-conditional', except it also stops at `#else' @@ -2071,15 +2114,18 @@ continuation backslashes, unless `c-auto-align-backslashes' is nil." (interactive "*") (let ((here (point-marker)) decl-limits) - ;; We try to be line oriented, unless there are several - ;; declarations on the same line. - (if (looking-at c-syntactic-eol) - (c-backward-token-1 1 nil (c-point 'bol)) - (c-forward-token-1 0 nil (c-point 'eol))) (unwind-protect - (if (setq decl-limits (c-declaration-limits nil)) - (c-indent-region (car decl-limits) - (cdr decl-limits))) + (progn + (c-save-buffer-state nil + ;; We try to be line oriented, unless there are several + ;; declarations on the same line. + (if (looking-at c-syntactic-eol) + (c-backward-token-2 1 nil (c-point 'bol)) + (c-forward-token-2 0 nil (c-point 'eol))) + (setq decl-limits (c-declaration-limits nil))) + (if decl-limits + (c-indent-region (car decl-limits) + (cdr decl-limits)))) (goto-char here) (set-marker here nil)))) @@ -2090,12 +2136,12 @@ non-nil." (save-excursion (goto-char end) - (skip-chars-backward " \t\n\r") + (skip-chars-backward " \t\n\r\f\v") (setq end (point)) (goto-char start) ;; Advance to first nonblank line. (beginning-of-line) - (skip-chars-forward " \t\n\r") + (skip-chars-forward " \t\n\r\f\v") (setq start (point)) (beginning-of-line) (setq c-parsing-error @@ -2120,7 +2166,8 @@ (skip-chars-forward " \t\n") (beginning-of-line) ;; Get syntax and indent. - (setq syntax (c-guess-basic-syntax)) + (c-save-buffer-state nil + (setq syntax (c-guess-basic-syntax))) (if (and c-auto-align-backslashes (assq 'cpp-macro syntax)) ;; Record macro start. @@ -2149,6 +2196,8 @@ (defun c-fn-region-is-active-p () ;; Function version of the macro for use in places that aren't ;; compiled, e.g. in the menus. + ;; + ;; This function does not do any hidden buffer changes. (c-region-is-active-p)) (defun c-indent-line-or-region () @@ -2165,6 +2214,7 @@ (defvar c-progress-info nil) (defun c-progress-init (start end context) + ;; This function does not do any hidden buffer changes. (cond ;; Be silent ((not c-progress-interval)) @@ -2186,7 +2236,7 @@ )) (defun c-progress-update () - ;; update progress + ;; This function does not do any hidden buffer changes. (if (not (and c-progress-info c-progress-interval)) nil (let ((now (nth 1 (current-time))) @@ -2203,7 +2253,7 @@ ))) (defun c-progress-fini (context) - ;; finished + ;; This function does not do any hidden buffer changes. (if (not c-progress-interval) nil (if (or (eq context (aref c-progress-info 3)) @@ -2364,6 +2414,7 @@ (set-marker point-pos nil)))) (defun c-append-backslashes-forward (to-mark column point-pos) + ;; This function does not do any hidden buffer changes. (let ((state (parse-partial-sexp (c-point 'bol) (point)))) (if column (while @@ -2435,6 +2486,7 @@ (= (forward-line 1) 0))))))) (defun c-delete-backslashes-forward (to-mark point-pos) + ;; This function does not do any hidden buffer changes. (while (and (<= (point) to-mark) (progn @@ -2478,6 +2530,7 @@ ;; comment. Return a cons of the prefix string and the column where ;; it ends. If fill-prefix is set, it'll override. Note that this ;; function also uses the value of point in some heuristics. + (let* ((here (point)) (prefix-regexp (concat "[ \t]*\\(" c-current-comment-prefix @@ -2486,38 +2539,40 @@ prefix-regexp comment-start-skip)) prefix-line comment-prefix res comment-text-end) + (cond (fill-prefix (setq res (cons fill-prefix ;; Ugly way of getting the column after the fill ;; prefix; it'd be nice with a current-column ;; that works on strings.. - (let ((buffer-modified (buffer-modified-p)) - (buffer-undo-list t) - (start (point))) + (let ((start (point))) (unwind-protect (progn (insert-and-inherit "\n" fill-prefix) (current-column)) - (delete-region start (point)) - (set-buffer-modified-p buffer-modified)))))) + (delete-region start (point))))))) + ((eq lit-type 'c++) (save-excursion ;; Set fallback for comment-prefix if none is found. (setq comment-prefix "// " comment-text-end (cdr lit-limits)) + (beginning-of-line) (if (> (point) (car lit-limits)) ;; The current line is not the comment starter, so the ;; comment has more than one line, and it can therefore be ;; used to find the comment fill prefix. (setq prefix-line (point)) + (goto-char (car lit-limits)) (if (and (= (forward-line 1) 0) (< (point) (cdr lit-limits))) ;; The line after the comment starter is inside the ;; comment, so we can use it. (setq prefix-line (point)) + ;; The comment is only one line. Take the comment prefix ;; from it and keep the indentation. (goto-char (car lit-limits)) @@ -2525,6 +2580,7 @@ (goto-char (match-end 0)) (forward-char 2) (skip-chars-forward " \t")) + (let (str col) (if (eq (c-point 'boi) (car lit-limits)) ;; There is only whitespace before the comment @@ -2532,12 +2588,11 @@ (setq str (buffer-substring-no-properties (c-point 'bol) (point)) col (current-column)) + ;; There is code before the comment starter, so we ;; have to temporarily insert and indent a new line to ;; get the right space/tab mix in the indentation. - (let ((buffer-modified (buffer-modified-p)) - (buffer-undo-list t) - (prefix-len (- (point) (car lit-limits))) + (let ((prefix-len (- (point) (car lit-limits))) tmp) (unwind-protect (progn @@ -2549,8 +2604,8 @@ (setq str (buffer-substring-no-properties (c-point 'bol) (point)) col (current-column))) - (delete-region (car lit-limits) tmp) - (set-buffer-modified-p buffer-modified)))) + (delete-region (car lit-limits) tmp)))) + (setq res (if (or (string-match "\\s \\'" str) (not (eolp))) (cons str col) @@ -2558,11 +2613,13 @@ ;; after it. Default to a single space. (cons (concat str " ") (1+ col)))) ))))) + (t (setq comment-text-end (save-excursion (goto-char (- (cdr lit-limits) 2)) (if (looking-at "\\*/") (point) (cdr lit-limits)))) + (save-excursion (beginning-of-line) (if (and (> (point) (car lit-limits)) @@ -2573,75 +2630,124 @@ ;; to be used for the comment fill prefix. (setq prefix-line (point)) (goto-char (car lit-limits)) - (if (or (/= (forward-line 1) 0) - (>= (point) (cdr lit-limits)) - (and (looking-at "[ \t]*\\*/") - (eq (cdr lit-limits) (match-end 0))) - (and (looking-at prefix-regexp) - (<= (1- (cdr lit-limits)) (match-end 0))) - (and (< here (point)) - (or (not (match-beginning 0)) - (looking-at "[ \t]*\\\\?$")))) - ;; The comment is either one line or the next line - ;; contains just the comment ender. Also, if point is - ;; on the comment opener line and the following line is - ;; empty or doesn't match c-current-comment-prefix we - ;; assume that this is in fact a not yet closed one line - ;; comment, so we shouldn't look for the comment prefix - ;; on the next line. In these cases we have no - ;; information about a suitable comment prefix, so we - ;; resort to c-block-comment-prefix. - (setq comment-prefix (or c-block-comment-prefix "") - res (let ((buffer-modified (buffer-modified-p)) - (buffer-undo-list t) - tmp-pre tmp-post) - ;; The comment doesn't give any information - ;; about the indentation column. We'll have to - ;; temporarily insert a new comment line and - ;; indent it to find the correct column. - (unwind-protect - (progn - (goto-char (car lit-limits)) - (if (looking-at comment-start-regexp) - (goto-char (min (match-end 0) - comment-text-end)) - (forward-char 2) - (skip-chars-forward " \t")) - (when (eq (char-syntax (char-before)) ?\ ) - ;; If there's ws on the current - ;; line, we'll use it instead of - ;; what's ending comment-prefix. - (setq comment-prefix - (concat (substring comment-prefix - 0 (string-match - "\\s *\\'" - comment-prefix)) - (buffer-substring-no-properties - (save-excursion - (skip-chars-backward " \t") - (point)) - (point))))) - (setq tmp-pre (point-marker)) - ;; We insert an extra non-whitespace - ;; character before the line break and - ;; after comment-prefix in case it's - ;; "" or ends with whitespace. - (insert-and-inherit "x\n" comment-prefix "x") - (setq tmp-post (point-marker)) - (indent-according-to-mode) - (goto-char (1- tmp-post)) - (cons (buffer-substring-no-properties - (c-point 'bol) (point)) - (current-column))) - (when tmp-post - (delete-region tmp-pre tmp-post) - (set-marker tmp-pre nil) - (set-marker tmp-post nil)) - (set-buffer-modified-p buffer-modified)))) - ;; Otherwise the line after the comment starter is good - ;; enough to find the prefix in. - (setq prefix-line (point))))))) - (or res + + (cond ((or (/= (forward-line 1) 0) + (>= (point) (cdr lit-limits)) + (and (looking-at "[ \t]*\\*/") + (eq (cdr lit-limits) (match-end 0))) + (and (looking-at prefix-regexp) + (<= (1- (cdr lit-limits)) (match-end 0)))) + ;; The comment is either one line or the next line contains + ;; just the comment ender. In this case we have no + ;; information about a suitable comment prefix, so we resort + ;; to c-block-comment-prefix. + (setq comment-prefix (or c-block-comment-prefix ""))) + + ((< here (point)) + ;; The point was on the comment opener line, so we might want + ;; to treat this as a not yet closed comment. + + (if (and (match-beginning 1) + (/= (match-beginning 1) (match-end 1))) + ;; Above `prefix-regexp' matched a nonempty prefix on the + ;; second line, so let's use it. Normally it should do + ;; to set `prefix-line' and let the code below pick up + ;; the whole prefix, but if there's no text after the + ;; match then it will probably fall back to no prefix at + ;; all if the comment isn't closed yet, so in that case + ;; it's better to force use of the prefix matched now. + (if (= (match-end 0) (c-point 'eol)) + (setq comment-prefix (match-string 1)) + (setq prefix-line (point))) + + ;; There's no nonempty prefix on the line after the + ;; comment opener. If the line is empty, or if the + ;; text on has less or equal indentation than the + ;; comment starter we assume it's an unclosed + ;; comment starter, i.e. that + ;; `c-block-comment-prefix' should be used. + ;; Otherwise we assume it's a closed comment where + ;; the prefix really is the empty string. + ;; E.g. this is an unclosed comment: + ;; + ;; /* + ;; foo + ;; + ;; But this is not: + ;; + ;; /* + ;; foo + ;; */ + ;; + ;; (Looking for the presence of the comment closer + ;; rarely works since it's probably the closer of + ;; some comment further down when the comment + ;; really is unclosed.) + (if (<= (save-excursion (back-to-indentation) + (current-column)) + (save-excursion (goto-char (car lit-limits)) + (current-column))) + (setq comment-prefix (or c-block-comment-prefix "")) + (setq prefix-line (point))))) + + (t + ;; Otherwise the line after the comment starter is good + ;; enough to find the prefix in. + (setq prefix-line (point)))) + + (when comment-prefix + ;; Haven't got the comment prefix on any real line that we + ;; can take it from, so we have to temporarily insert + ;; `comment-prefix' on a line and indent it to find the + ;; correct column and the correct mix of tabs and spaces. + (setq res + (let (tmp-pre tmp-post) + (unwind-protect + (progn + + (goto-char (car lit-limits)) + (if (looking-at comment-start-regexp) + (goto-char (min (match-end 0) + comment-text-end)) + (forward-char 2) + (skip-chars-forward " \t")) + + (when (eq (char-syntax (char-before)) ?\ ) + ;; If there's ws on the current line, we'll use it + ;; instead of what's ending comment-prefix. + (setq comment-prefix + (concat (substring comment-prefix + 0 (string-match + "\\s *\\'" + comment-prefix)) + (buffer-substring-no-properties + (save-excursion + (skip-chars-backward " \t") + (point)) + (point))))) + + (setq tmp-pre (point-marker)) + + ;; We insert an extra non-whitespace character + ;; before the line break and after comment-prefix in + ;; case it's "" or ends with whitespace. + (insert-and-inherit "x\n" comment-prefix "x") + (setq tmp-post (point-marker)) + + (indent-according-to-mode) + + (goto-char (1- tmp-post)) + (cons (buffer-substring-no-properties + (c-point 'bol) (point)) + (current-column))) + + (when tmp-post + (delete-region tmp-pre tmp-post) + (set-marker tmp-pre nil) + (set-marker tmp-post nil)))))))))) + + (or res ; Found a good prefix above. + (save-excursion ;; prefix-line is the bol of a line on which we should try ;; to find the prefix. @@ -2664,11 +2770,13 @@ (match-beginning 0) (match-end 0)) fb-endpos (match-end 0))) t)))) + (or (catch 'found ;; Search for a line which has text after the prefix ;; so that we get the proper amount of whitespace ;; after it. We start with the current line, then ;; search backwards, then forwards. + (goto-char prefix-line) (when (and (funcall test-line) (or (/= (match-end 1) (match-end 0)) @@ -2681,6 +2789,7 @@ (throw 'found (cons fb-string (progn (goto-char fb-endpos) (current-column))))) + (if (eq lit-type 'c++) ;; For line comments we can search up to and ;; including the first line. @@ -2692,12 +2801,15 @@ (while (and (zerop (forward-line -1)) (> (point) (car lit-limits))) (funcall test-line))) + (goto-char prefix-line) (while (and (zerop (forward-line 1)) (< (point) (cdr lit-limits))) (funcall test-line)) + (goto-char prefix-line) nil) + (when fb-string ;; A good line wasn't found, but at least we have a ;; fallback that matches the comment prefix regexp. @@ -2708,6 +2820,7 @@ ;; There are ws or text after the prefix, so ;; let's use it. (cons fb-string (current-column))) + ((progn ;; Check if there's any whitespace padding ;; on the comment start line that we can @@ -2719,6 +2832,7 @@ (skip-chars-forward " \t")) (or (not (eolp)) (eq (char-syntax (char-before)) ?\ ))) + (setq fb-string (buffer-substring-no-properties (save-excursion (skip-chars-backward " \t") @@ -2726,9 +2840,8 @@ (point))) (goto-char fb-endpos) (skip-chars-backward " \t") - (let ((buffer-modified (buffer-modified-p)) - (buffer-undo-list t) - (tmp (point))) + + (let ((tmp (point))) ;; Got to mess in the buffer once again to ;; ensure the column gets correct. :P (unwind-protect @@ -2738,14 +2851,15 @@ (c-point 'bol) (point)) (current-column))) - (delete-region tmp (point)) - (set-buffer-modified-p buffer-modified)))) + (delete-region tmp (point))))) + (t ;; Last resort: Just add a single space after ;; the prefix. (cons (concat fb-string " ") (progn (goto-char fb-endpos) (1+ (current-column))))))) + ;; The line doesn't match the comment prefix regexp. (if comment-prefix ;; We have a fallback for line comments that we must use. @@ -2754,6 +2868,7 @@ comment-prefix) (progn (back-to-indentation) (+ (current-column) (length comment-prefix)))) + ;; Assume we are dealing with a "free text" block ;; comment where the lines doesn't have any comment ;; prefix at all and we should just fill it as @@ -2761,14 +2876,21 @@ '("" . 0)))))) )) -(defun c-mask-comment (fill-paragraph apply-outside-literal fun &rest args) - ;; Calls FUN with ARGS ar arguments. If point is inside a comment, - ;; the comment starter and ender are masked and the buffer is - ;; narrowed to make it look like a normal paragraph during the call. +(defun c-mask-paragraph (fill-paragraph apply-outside-literal fun &rest args) + ;; Calls FUN with ARGS ar arguments while the current paragraph is + ;; masked to allow adaptive filling to work correctly. That + ;; includes narrowing the buffer and, if point is inside a comment, + ;; masking the comment starter and ender appropriately. ;; - ;; FILL-PARAGRAPH is non-nil if called for paragraph filling. The - ;; position of point is then less significant when doing masking and - ;; narrowing. + ;; FILL-PARAGRAPH is non-nil if called for whole paragraph filling. + ;; The position of point is then less significant when doing masking + ;; and narrowing. + ;; + ;; If APPLY-OUTSIDE-LITERAL is nil then the function will be called + ;; only if the point turns out to be inside a comment or a string. + ;; + ;; This function does not do any hidden buffer changes. + (let (fill ;; beg and end limits the region to narrow. end is a marker. beg end @@ -2785,11 +2907,13 @@ (here (point)) (c-lit-limits c-lit-limits) (c-lit-type c-lit-type)) + ;; Restore point on undo. It's necessary since we do a lot of ;; hidden inserts and deletes below that should be as transparent ;; as possible. (if (and buffer-undo-list (not (eq buffer-undo-list t))) (setq buffer-undo-list (cons (point) buffer-undo-list))) + (save-restriction ;; Widen to catch comment limits correctly. (widen) @@ -2798,6 +2922,7 @@ (setq c-lit-limits (c-collect-line-comments c-lit-limits)) (unless c-lit-type (setq c-lit-type (c-literal-type c-lit-limits)))) + (save-excursion (unless (c-safe (backward-char) (forward-paragraph) @@ -2812,14 +2937,17 @@ (goto-char here) (backward-paragraph)) (setq beg (point))) + (unwind-protect (progn (cond + ((eq c-lit-type 'c++) ; Line comment. (save-excursion ;; Limit to the comment or paragraph end, whichever ;; comes first. (set-marker end (min end (cdr c-lit-limits))) + (when (<= beg (car c-lit-limits)) ;; The region includes the comment starter, so we must ;; check it. @@ -2830,8 +2958,10 @@ (setq beg (c-point 'bol)) ;; The first line contains code before the ;; comment. We must fake a line that doesn't. - (setq tmp-pre t))) - )) + (setq tmp-pre t)))) + + (setq apply-outside-literal t)) + ((eq c-lit-type 'c) ; Block comment. (when (>= end (cdr c-lit-limits)) ;; The region includes the comment ender which we might @@ -2843,63 +2973,78 @@ c-current-comment-prefix "\\)\\*/")) (eq (cdr c-lit-limits) (match-end 0)) - ;; Leave the comment ender on its own line. + ;; The comment ender is on a line of its + ;; own. Keep it that way. (set-marker end (point)))) - (when fill-paragraph - ;; The comment ender should hang. Replace all cruft - ;; between it and the last word with one or two 'x' - ;; and include it in the region. We'll change them - ;; back to spaces afterwards. - (let* ((ender-start (save-excursion - (goto-char (cdr c-lit-limits)) - (skip-syntax-backward "^w ") - (point))) - (point-rel (- ender-start here)) - spaces) - (save-excursion - (goto-char (cdr c-lit-limits)) - (setq tmp-post (point-marker)) - (insert ?\n) - (set-marker end (point)) - (forward-line -1) - (if (and (looking-at (concat "[ \t]*\\(\\(" - c-current-comment-prefix - "\\)[ \t]*\\)")) - (eq ender-start (match-end 0))) - ;; The comment ender is prefixed by nothing - ;; but a comment line prefix. Remove it - ;; along with surrounding ws. - (setq spaces (- (match-end 1) (match-end 2))) - (goto-char ender-start)) - (skip-chars-backward " \t\r\n") - (if (/= (point) ender-start) - (progn - (if (<= here (point)) - ;; Don't adjust point below if it's - ;; before the string we replace. - (setq point-rel -1)) - ;; Keep one or two spaces between the text and - ;; the ender, depending on how many there are now. - (unless spaces - (setq spaces (- ender-start (point)))) - (setq spaces - (max (min spaces - (if sentence-end-double-space 2 1)) - 1)) - ;; Insert the filler first to keep marks right. - (insert-char ?x spaces t) - (delete-region (point) (+ ender-start spaces)) - (setq hang-ender-stuck spaces) - (setq point-rel - (and (>= point-rel 0) - (- (point) (min point-rel spaces))))) - (setq point-rel nil))) - (if point-rel - ;; Point was in the middle of the string we - ;; replaced above, so put it back in the same - ;; relative position, counting from the end. - (goto-char point-rel)) - )))) + + (if fill-paragraph + ;; The comment ender should hang. Replace all + ;; cruft between it and the last word with one or + ;; two 'x' and include it in the region. We'll + ;; change them back to spaces afterwards. This + ;; isn't done when auto filling, since that'd + ;; effectively make it impossible to insert extra + ;; spaces before the comment ender. + (let* ((ender-start (save-excursion + (goto-char (cdr c-lit-limits)) + (skip-syntax-backward "^w ") + (point))) + (point-rel (- ender-start here)) + spaces) + + (save-excursion + (goto-char (cdr c-lit-limits)) + (setq tmp-post (point-marker)) + (insert ?\n) + (set-marker end (point)) + (forward-line -1) + (if (and (looking-at (concat "[ \t]*\\(\\(" + c-current-comment-prefix + "\\)[ \t]*\\)")) + (eq ender-start (match-end 0))) + ;; The comment ender is prefixed by nothing + ;; but a comment line prefix. Remove it + ;; along with surrounding ws. + (setq spaces (- (match-end 1) (match-end 2))) + (goto-char ender-start)) + (skip-chars-backward " \t\r\n") + + (if (/= (point) ender-start) + (progn + (if (<= here (point)) + ;; Don't adjust point below if it's + ;; before the string we replace. + (setq point-rel -1)) + ;; Keep one or two spaces between the + ;; text and the ender, depending on how + ;; many there are now. + (unless spaces + (setq spaces (- ender-start (point)))) + (setq spaces + (max + (min spaces + (if sentence-end-double-space 2 1)) + 1)) + ;; Insert the filler first to keep marks right. + (insert-char ?x spaces t) + (delete-region (point) (+ ender-start spaces)) + (setq hang-ender-stuck spaces) + (setq point-rel + (and (>= point-rel 0) + (- (point) (min point-rel spaces))))) + (setq point-rel nil))) + + (if point-rel + ;; Point was in the middle of the string we + ;; replaced above, so put it back in the same + ;; relative position, counting from the end. + (goto-char point-rel))) + + ;; We're doing auto filling. Just move the marker + ;; to the comment end to ignore any code after the + ;; comment. + (move-marker end (cdr c-lit-limits))))) + (when (<= beg (car c-lit-limits)) ;; The region includes the comment starter. (save-excursion @@ -2908,7 +3053,10 @@ ;; Begin with the next line. (setq beg (c-point 'bonl)) ;; Fake the fill prefix in the first line. - (setq tmp-pre t))))) + (setq tmp-pre t)))) + + (setq apply-outside-literal t)) + ((eq c-lit-type 'string) ; String. (save-excursion (when (>= end (cdr c-lit-limits)) @@ -2922,13 +3070,46 @@ ;; Leave the start line if it's ;; nothing but an escaped newline. (1+ (match-end 0)) - (point)))))) - (t (setq beg nil))) + (point))))) + (setq apply-outside-literal t)) + + ((eq c-lit-type 'pound) ; Macro + ;; Narrow to the macro limits if they are nearer than the + ;; paragraph limits. Don't know if this is necessary but + ;; do it for completeness sake (doing auto filling at all + ;; inside macros is bogus to begin with since the line + ;; continuation backslashes aren't handled). + (save-excursion + (c-beginning-of-macro) + (beginning-of-line) + (if (> (point) beg) + (setq beg (point))) + (c-end-of-macro) + (forward-line) + (if (< (point) end) + (set-marker end (point))))) + + (t ; Other code. + ;; Try to avoid comments and macros in the paragraph to + ;; avoid that the adaptive fill mode gets the prefix from + ;; them. + (c-save-buffer-state nil + (save-excursion + (goto-char beg) + (c-forward-syntactic-ws end) + (beginning-of-line) + (setq beg (point)) + (goto-char end) + (c-backward-syntactic-ws beg) + (forward-line) + (set-marker end (point)))))) + (when tmp-pre ;; Temporarily insert the fill prefix after the comment ;; starter so that the first line looks like any other ;; comment line in the narrowed region. - (setq fill (c-guess-fill-prefix c-lit-limits c-lit-type)) + (setq fill (c-save-buffer-state nil + (c-guess-fill-prefix c-lit-limits c-lit-type))) (unless (string-match (concat "\\`[ \t]*\\(" c-current-comment-prefix "\\)[ \t]*\\'") @@ -2965,49 +3146,53 @@ (insert-and-inherit "\n" (car fill)) (insert-char ?x (- col (current-column)) t)) (setcdr tmp-pre (point)))))) - (if beg - (let ((fill-prefix - (or fill-prefix - ;; Kludge: If the function that adapts the - ;; fill prefix doesn't produce the required - ;; comment starter for line comments, then - ;; force it by setting fill-prefix. - (when (and (eq c-lit-type 'c++) - ;; Kludge the kludge: - ;; filladapt-mode doesn't have - ;; this problem, but it doesn't - ;; override fill-context-prefix - ;; currently (version 2.12). - (not (and (boundp 'filladapt-mode) - filladapt-mode)) - (not (string-match - "\\`[ \t]*//" - (or (fill-context-prefix beg end) - "")))) + + (when apply-outside-literal + ;; `apply-outside-literal' is always set to t here if + ;; we're inside a literal. + + (let ((fill-prefix + (or fill-prefix + ;; Kludge: If the function that adapts the fill prefix + ;; doesn't produce the required comment starter for + ;; line comments, then force it by setting fill-prefix. + (when (and (eq c-lit-type 'c++) + ;; Kludge the kludge: filladapt-mode doesn't + ;; have this problem, but it currently + ;; doesn't override fill-context-prefix + ;; (version 2.12). + (not (and (boundp 'filladapt-mode) + filladapt-mode)) + (not (string-match + "\\`[ \t]*//" + (or (fill-context-prefix beg end) + "")))) + (c-save-buffer-state nil (car (or fill (c-guess-fill-prefix - c-lit-limits c-lit-type)))))) - ;; Save the relative position of point if it's - ;; outside the region we're going to narrow. Want - ;; to restore it in that case, but otherwise it - ;; should be moved according to the called - ;; function. - (point-rel (cond ((< (point) beg) (- (point) beg)) - ((> (point) end) (- (point) end))))) - ;; Preparations finally done! Now we can call the - ;; actual function. - (prog1 - (save-restriction - (narrow-to-region beg end) - (apply fun args)) - (if point-rel - ;; Restore point if it was outside the region. - (if (< point-rel 0) - (goto-char (+ beg point-rel)) - (goto-char (+ end point-rel)))))) - (when apply-outside-literal - (apply fun args)))) + c-lit-limits c-lit-type))))))) + + ;; Save the relative position of point if it's outside the + ;; region we're going to narrow. Want to restore it in that + ;; case, but otherwise it should be moved according to the + ;; called function. + (point-rel (cond ((< (point) beg) (- (point) beg)) + ((> (point) end) (- (point) end))))) + + ;; Preparations finally done! Now we can call the + ;; actual function. + (prog1 + (save-restriction + (narrow-to-region beg end) + (apply fun args)) + (if point-rel + ;; Restore point if it was outside the region. + (if (< point-rel 0) + (goto-char (+ beg point-rel)) + (goto-char (+ end point-rel)))))))) + (when (consp tmp-pre) (delete-region (car tmp-pre) (cdr tmp-pre))) + (when tmp-post (save-excursion (goto-char tmp-post) @@ -3023,6 +3208,7 @@ (delete-char hang-ender-stuck) (goto-char here)) (set-marker tmp-post nil)) + (set-marker end nil)))) (defun c-fill-paragraph (&optional arg) @@ -3050,7 +3236,7 @@ ;; Avoid infinite recursion. (if (not (eq fill-paragraph-function 'c-fill-paragraph)) fill-paragraph-function))) - (c-mask-comment t nil 'fill-paragraph arg)) + (c-mask-paragraph t nil 'fill-paragraph arg)) ;; Always return t. This has the effect that if filling isn't done ;; above, it isn't done at all, and it's therefore effectively ;; disabled in normal code. @@ -3059,6 +3245,8 @@ (defun c-do-auto-fill () ;; Do automatic filling if not inside a context where it should be ;; ignored. + ;; + ;; This function does not do any hidden buffer changes. (let ((c-auto-fill-prefix ;; The decision whether the line should be broken is actually ;; done in c-indent-new-comment-line, which do-auto-fill @@ -3067,7 +3255,7 @@ ;; also used to detect whether fill-prefix is user set or ;; generated automatically by do-auto-fill. fill-prefix)) - (c-mask-comment nil t 'do-auto-fill))) + (c-mask-paragraph nil t 'do-auto-fill))) (defun c-indent-new-comment-line (&optional soft allow-auto-fill) "Break line at point and indent, continuing comment or macro if within one. @@ -3143,10 +3331,11 @@ (end-of-line) (< (point) (cdr c-lit-limits)))) ;; Inside a comment that should be continued. - (let ((fill (c-guess-fill-prefix - (setq c-lit-limits - (c-collect-line-comments c-lit-limits)) - c-lit-type)) + (let ((fill (c-save-buffer-state nil + (c-guess-fill-prefix + (setq c-lit-limits + (c-collect-line-comments c-lit-limits)) + c-lit-type))) (pos (point)) (comment-text-end (or (and (eq c-lit-type 'c) @@ -3279,7 +3468,7 @@ (c-query-and-set-macro-start) (<= (save-excursion (goto-char c-macro-start) - (if (looking-at "#[ \t]*[a-zA-Z0-9!]+") + (if (looking-at c-opt-cpp-start) (goto-char (match-end 0))) (point)) (point))))
--- a/lisp/progmodes/cc-compat.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-compat.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,9 @@ ;;; cc-compat.el --- cc-mode compatibility with c-mode.el confusion -;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1994-1997 Barry A. Warsaw +;; Authors: 1998- Martin Stjernholm +;; 1994-1999 Barry A. Warsaw ;; Maintainer: bug-cc-mode@gnu.org ;; Created: August 1994, split from cc-mode.el ;; Version: See cc-mode.el @@ -51,7 +50,7 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) (cc-require 'cc-defs) (cc-require 'cc-vars) @@ -106,7 +105,7 @@ (if (eq (char-before) ?{) (forward-char -1) (goto-char (cdr langelem))) - (let* ((curcol (save-excursion + (let* ((curcol (save-excursion (goto-char (cdr langelem)) (current-column))) (bocm-lossage @@ -138,7 +137,7 @@ (defun cc-block-close-offset (langelem) (save-excursion (let* ((here (point)) - bracep + bracep (curcol (progn (goto-char (cdr langelem)) (current-column))) @@ -154,7 +153,7 @@ (current-column)))) (- bocm-lossage curcol (if bracep 0 c-indent-level))))) - + (defun cc-substatement-open-offset (langelem) (+ c-continued-statement-offset c-continued-brace-offset))
--- a/lisp/progmodes/cc-defs.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-defs.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,9 @@ ;;; cc-defs.el --- compile time definitions for CC Mode -;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1992-1997 Barry A. Warsaw +;; Authors: 1998- Martin Stjernholm +;; 1992-1999 Barry A. Warsaw ;; 1987 Dave Detlefs and Stewart Clamen ;; 1985 Richard M. Stallman ;; Maintainer: bug-cc-mode@gnu.org @@ -31,6 +30,9 @@ ;;; Commentary: +;; This file contains macros, defsubsts, and various other things that +;; must be loaded early both during compilation and at runtime. + ;;; Code: (eval-when-compile @@ -39,9 +41,29 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) + +;; `require' in XEmacs doesn't have the third NOERROR argument. +(condition-case nil (require 'regexp-opt) (file-error nil)) -;; cc-mode-19.el contains compatibility macros that should be used if +;; Silence the compiler. +(cc-bytecomp-defvar c-enable-xemacs-performance-kludge-p) ; In cc-vars.el +(cc-bytecomp-defvar c-emacs-features) ; In cc-vars.el +(cc-bytecomp-defun buffer-syntactic-context-depth) ; XEmacs +(cc-bytecomp-defun region-active-p) ; XEmacs +(cc-bytecomp-defvar zmacs-region-stays) ; XEmacs +(cc-bytecomp-defvar zmacs-regions) ; XEmacs +(cc-bytecomp-defvar mark-active) ; Emacs +(cc-bytecomp-defvar deactivate-mark) ; Emacs +(cc-bytecomp-defvar inhibit-point-motion-hooks) ; Emacs +(cc-bytecomp-defvar parse-sexp-lookup-properties) ; Emacs 20+ +(cc-bytecomp-defvar text-property-default-nonsticky) ; Emacs 21 +(cc-bytecomp-defvar lookup-syntax-properties) ; XEmacs 21 +(cc-bytecomp-defun string-to-syntax) ; Emacs 21 +(cc-bytecomp-defun regexp-opt-depth) ; (X)Emacs 20+ + + +;; cc-fix.el contains compatibility macros that should be used if ;; needed. (eval-and-compile (if (or (not (fboundp 'functionp)) @@ -52,152 +74,488 @@ (progn (eval '(char-after)) t) (error nil))) (not (fboundp 'when)) - (not (fboundp 'unless))) - (cc-load "cc-mode-19"))) + (not (fboundp 'unless)) + (not (fboundp 'regexp-opt)) + (not (cc-bytecomp-fboundp 'regexp-opt-depth)) + (/= (regexp-opt-depth "\\(\\(\\)\\)") 2)) + (cc-load "cc-fix") + (defalias 'c-regexp-opt 'regexp-opt) + (defalias 'c-regexp-opt-depth 'regexp-opt-depth))) + +(eval-after-load "font-lock" + '(if (and (not (featurep 'cc-fix)) ; only load the file once. + (let (font-lock-keywords) + (font-lock-compile-keywords '("\\<\\>")) + font-lock-keywords)) ; did the previous call foul this up? + (load "cc-fix"))) + +;; The above takes care of the delayed loading, but this is necessary +;; to ensure correct byte compilation. +(eval-when-compile + (if (and (not (featurep 'cc-fix)) + (progn + (require 'font-lock) + (let (font-lock-keywords) + (font-lock-compile-keywords '("\\<\\>")) + font-lock-keywords))) + (cc-load "cc-fix"))) + +(cc-external-require 'cl) + + +;;; Variables also used at compile time. + +(defconst c-version "5.30.1" + "CC Mode version number.") + +(defconst c-version-sym (intern c-version)) +;; A little more compact and faster in comparisons. + +(defvar c-buffer-is-cc-mode nil + "Non-nil for all buffers with a major mode derived from CC Mode. +Otherwise, this variable is nil. I.e. this variable is non-nil for +`c-mode', `c++-mode', `objc-mode', `java-mode', `idl-mode', +`pike-mode', and any other non-CC Mode mode that calls +`c-initialize-cc-mode' (e.g. `awk-mode'). The value is the mode +symbol itself (i.e. `c-mode' etc) of the original CC Mode mode, or +just t if it's not known.") +(make-variable-buffer-local 'c-buffer-is-cc-mode) + +;; Have to make `c-buffer-is-cc-mode' permanently local so that it +;; survives the initialization of the derived mode. +(put 'c-buffer-is-cc-mode 'permanent-local t) -;; Silence the compiler. -(cc-bytecomp-defvar c-enable-xemacs-performance-kludge-p) ; In cc-vars.el -(cc-bytecomp-defvar c-buffer-is-cc-mode) ; In cc-vars.el -(cc-bytecomp-defun buffer-syntactic-context-depth) ; XEmacs -(cc-bytecomp-defun region-active-p) ; XEmacs -(cc-bytecomp-defvar zmacs-region-stays) ; XEmacs -(cc-bytecomp-defvar zmacs-regions) ; XEmacs -(cc-bytecomp-defvar mark-active) ; Emacs -(cc-bytecomp-defun scan-lists) ; 5 args in XEmacs, 3 in Emacs -(require 'derived) ; Only necessary in Emacs + +;; The following is used below during compilation. +(eval-and-compile + (defvar c-inside-eval-when-compile nil) + + (defmacro cc-eval-when-compile (&rest body) + "Like `progn', but evaluates the body at compile time. +The result of the body appears to the compiler as a quoted constant. + +This variant works around bugs in `eval-when-compile' in various +\(X)Emacs versions. See cc-defs.el for details." + + (if c-inside-eval-when-compile + ;; XEmacs 21.4.6 has a bug in `eval-when-compile' in that it + ;; evaluates its body at macro expansion time if it's nested + ;; inside another `eval-when-compile'. So we use a dynamically + ;; bound variable to avoid nesting them. + `(progn ,@body) + + `(eval-when-compile + ;; In all (X)Emacsen so far, `eval-when-compile' byte compiles + ;; its contents before evaluating it. That can cause forms to + ;; be compiled in situations they aren't intended to be + ;; compiled. + ;; + ;; Example: It's not possible to defsubst a primitive, e.g. the + ;; following will produce an error (in any emacs flavor), since + ;; `nthcdr' is a primitive function that's handled specially by + ;; the byte compiler and thus can't be redefined: + ;; + ;; (defsubst nthcdr (val) val) + ;; + ;; `defsubst', like `defmacro', needs to be evaluated at + ;; compile time, so this will produce an error during byte + ;; compilation. + ;; + ;; CC Mode occasionally needs to do things like this for + ;; cross-emacs compatibility. It therefore uses the following + ;; to conditionally do a `defsubst': + ;; + ;; (eval-when-compile + ;; (if (not (fboundp 'foo)) + ;; (defsubst foo ...))) + ;; + ;; But `eval-when-compile' byte compiles its contents and + ;; _then_ evaluates it (in all current emacs versions, up to + ;; and including Emacs 20.6 and XEmacs 21.1 as of this + ;; writing). So this will still produce an error, since the + ;; byte compiler will get to the defsubst anyway. That's + ;; arguably a bug because the point with `eval-when-compile' is + ;; that it should evaluate rather than compile its contents. + ;; + ;; We get around it by expanding the body to a quoted + ;; constant that we eval. That otoh introduce a problem in + ;; that a returned lambda expression doesn't get byte + ;; compiled (even if `function' is used). + (eval '(let ((c-inside-eval-when-compile t)) ,@body))))) + + (put 'cc-eval-when-compile 'lisp-indent-hook 0)) ;;; Macros. -;;; Helpers for building regexps. -(defmacro c-paren-re (re) - `(concat "\\(" ,re "\\)")) -(defmacro c-identifier-re (re) - `(concat "\\<\\(" ,re "\\)\\>[^_]")) +(defmacro c-point (position &optional point) + "Return the value of certain commonly referenced POSITIONs relative to POINT. +The current point is used if POINT isn't specified. POSITION can be +one of the following symbols: + +`bol' -- beginning of line +`eol' -- end of line +`bod' -- beginning of defun +`eod' -- end of defun +`boi' -- beginning of indentation +`ionl' -- indentation of next line +`iopl' -- indentation of previous line +`bonl' -- beginning of next line +`eonl' -- end of next line +`bopl' -- beginning of previous line +`eopl' -- end of previous line + +If the referenced position doesn't exist, the closest accessible point +to it is returned. This function does not modify point or mark. + +This function does not do any hidden buffer changes." + + (if (eq (car-safe position) 'quote) + (let ((position (eval position))) + (cond + + ((eq position 'bol) + (if (and (fboundp 'line-beginning-position) (not point)) + `(line-beginning-position) + `(save-excursion + ,@(if point `((goto-char ,point))) + (beginning-of-line) + (point)))) + + ((eq position 'eol) + (if (and (fboundp 'line-end-position) (not point)) + `(line-end-position) + `(save-excursion + ,@(if point `((goto-char ,point))) + (end-of-line) + (point)))) + + ((eq position 'boi) + `(save-excursion + ,@(if point `((goto-char ,point))) + (back-to-indentation) + (point))) + + ((eq position 'bod) + `(save-excursion + ,@(if point `((goto-char ,point))) + (c-beginning-of-defun-1) + (point))) + + ((eq position 'eod) + `(save-excursion + ,@(if point `((goto-char ,point))) + (c-end-of-defun-1) + (point))) + + ((eq position 'bopl) + (if (and (fboundp 'line-beginning-position) (not point)) + `(line-beginning-position 0) + `(save-excursion + ,@(if point `((goto-char ,point))) + (forward-line -1) + (point)))) -(defmacro c-point (position &optional point) - ;; Returns the value of certain commonly referenced POSITIONs - ;; relative to POINT. The current point is used if POINT isn't - ;; specified. POSITION can be one of the following symbols: - ;; - ;; bol -- beginning of line - ;; eol -- end of line - ;; bod -- beginning of defun - ;; eod -- end of defun - ;; boi -- beginning of indentation - ;; ionl -- indentation of next line - ;; iopl -- indentation of previous line - ;; bonl -- beginning of next line - ;; eonl -- end of next line - ;; bopl -- beginning of previous line - ;; eopl -- end of previous line - ;; - ;; If the referenced position doesn't exist, the closest accessible - ;; point to it is returned. This function does not modify point or - ;; mark. - `(save-excursion - ,(if point `(goto-char ,point)) - ,(if (and (eq (car-safe position) 'quote) - (symbolp (eval position))) - (let ((position (eval position))) - (cond - ((eq position 'bol) `(beginning-of-line)) - ((eq position 'eol) `(end-of-line)) - ((eq position 'boi) `(back-to-indentation)) - ((eq position 'bod) `(c-beginning-of-defun-1)) - ((eq position 'bonl) `(forward-line 1)) - ((eq position 'bopl) `(forward-line -1)) - ((eq position 'eod) `(c-end-of-defun-1)) - ((eq position 'eopl) `(progn - (beginning-of-line) - (or (bobp) (backward-char)))) - ((eq position 'eonl) `(progn - (forward-line 1) - (end-of-line))) - ((eq position 'iopl) `(progn - (forward-line -1) - (back-to-indentation))) - ((eq position 'ionl) `(progn - (forward-line 1) - (back-to-indentation))) - (t (error "unknown buffer position requested: %s" position)))) - ;;(message "c-point long expansion") - `(let ((position ,position)) - (cond - ((eq position 'bol) (beginning-of-line)) - ((eq position 'eol) (end-of-line)) - ((eq position 'boi) (back-to-indentation)) - ((eq position 'bod) (c-beginning-of-defun-1)) - ((eq position 'bonl) (forward-line 1)) - ((eq position 'bopl) (forward-line -1)) - ((eq position 'eod) (c-end-of-defun-1)) - ((eq position 'eopl) (progn - (beginning-of-line) - (or (bobp) (backward-char)))) - ((eq position 'eonl) (progn - (forward-line 1) - (end-of-line))) - ((eq position 'iopl) (progn - (forward-line -1) - (back-to-indentation))) - ((eq position 'ionl) (progn - (forward-line 1) - (back-to-indentation))) - (t (error "unknown buffer position requested: %s" position))))) - (point))) + ((eq position 'bonl) + (if (and (fboundp 'line-beginning-position) (not point)) + `(line-beginning-position 2) + `(save-excursion + ,@(if point `((goto-char ,point))) + (forward-line 1) + (point)))) + + ((eq position 'eopl) + (if (and (fboundp 'line-end-position) (not point)) + `(line-end-position 0) + `(save-excursion + ,@(if point `((goto-char ,point))) + (beginning-of-line) + (or (bobp) (backward-char)) + (point)))) + + ((eq position 'eonl) + (if (and (fboundp 'line-end-position) (not point)) + `(line-end-position 2) + `(save-excursion + ,@(if point `((goto-char ,point))) + (forward-line 1) + (end-of-line) + (point)))) + + ((eq position 'iopl) + `(save-excursion + ,@(if point `((goto-char ,point))) + (forward-line -1) + (back-to-indentation) + (point))) + + ((eq position 'ionl) + `(save-excursion + ,@(if point `((goto-char ,point))) + (forward-line 1) + (back-to-indentation) + (point))) + + (t (error "Unknown buffer position requested: %s" position)))) + + ;;(message "c-point long expansion") + `(save-excursion + ,@(if point `((goto-char ,point))) + (let ((position ,position)) + (cond + ((eq position 'bol) (beginning-of-line)) + ((eq position 'eol) (end-of-line)) + ((eq position 'boi) (back-to-indentation)) + ((eq position 'bod) (c-beginning-of-defun-1)) + ((eq position 'eod) (c-end-of-defun-1)) + ((eq position 'bopl) (forward-line -1)) + ((eq position 'bonl) (forward-line 1)) + ((eq position 'eopl) (progn + (beginning-of-line) + (or (bobp) (backward-char)))) + ((eq position 'eonl) (progn + (forward-line 1) + (end-of-line))) + ((eq position 'iopl) (progn + (forward-line -1) + (back-to-indentation))) + ((eq position 'ionl) (progn + (forward-line 1) + (back-to-indentation))) + (t (error "Unknown buffer position requested: %s" position)))) + (point)))) (defmacro c-safe (&rest body) ;; safely execute BODY, return nil if an error occurred + ;; + ;; This function does not do any hidden buffer changes. `(condition-case nil (progn ,@body) (error nil))) (put 'c-safe 'lisp-indent-function 0) -(defmacro c-forward-sexp (&optional arg) - ;; like forward-sexp except - ;; 1. this is much stripped down from the XEmacs version - ;; 2. this cannot be used as a command, so we're insulated from - ;; XEmacs' losing efforts to make forward-sexp more user - ;; friendly - ;; 3. Preserves the semantics most of CC Mode is based on - (or arg (setq arg 1)) - `(goto-char (or (scan-sexps (point) ,arg) - ,(if (numberp arg) - (if (> arg 0) `(point-max) `(point-min)) - `(if (> ,arg 0) (point-max) (point-min)))))) +;; The following is essentially `save-buffer-state' from lazy-lock.el. +;; It ought to be a standard macro. +(defmacro c-save-buffer-state (varlist &rest body) + "Bind variables according to VARLIST (in `let*' style) and eval BODY, +then restore the buffer state under the assumption that no significant +modification has been made. A change is considered significant if it +affects the buffer text in any way that isn't completely restored +again. Changes in text properties like `face' or `syntax-table' are +considered insignificant. This macro allows text properties to be +changed, even in a read-only buffer. + +The return value is the value of the last form in BODY." + `(let* ((modified (buffer-modified-p)) (buffer-undo-list t) + (inhibit-read-only t) (inhibit-point-motion-hooks t) + before-change-functions after-change-functions + deactivate-mark + ,@varlist) + (prog1 (progn ,@body) + (and (not modified) + (buffer-modified-p) + (set-buffer-modified-p nil))))) +(put 'c-save-buffer-state 'lisp-indent-function 1) + +(defmacro c-forward-syntactic-ws (&optional limit) + "Forward skip over syntactic whitespace. +Syntactic whitespace is defined as whitespace characters, comments, +and preprocessor directives. However if point starts inside a comment +or preprocessor directive, the content of it is not treated as +whitespace. + +LIMIT sets an upper limit of the forward movement, if specified. If +LIMIT or the end of the buffer is reached inside a comment or +preprocessor directive, the point will be left there. + +Note that this function might do hidden buffer changes. See the +comment at the start of cc-engine.el for more info." + (if limit + `(save-restriction + (narrow-to-region (point-min) (or ,limit (point-max))) + (c-forward-sws)) + '(c-forward-sws))) -(defmacro c-backward-sexp (&optional arg) - ;; See c-forward-sexp and reverse directions - (or arg (setq arg 1)) - `(c-forward-sexp ,(if (numberp arg) (- arg) `(- ,arg)))) +(defmacro c-backward-syntactic-ws (&optional limit) + "Backward skip over syntactic whitespace. +Syntactic whitespace is defined as whitespace characters, comments, +and preprocessor directives. However if point starts inside a comment +or preprocessor directive, the content of it is not treated as +whitespace. + +LIMIT sets a lower limit of the backward movement, if specified. If +LIMIT is reached inside a line comment or preprocessor directive then +the point is moved into it past the whitespace at the end. + +Note that this function might do hidden buffer changes. See the +comment at the start of cc-engine.el for more info." + (if limit + `(save-restriction + (narrow-to-region (or ,limit (point-min)) (point-max)) + (c-backward-sws)) + '(c-backward-sws))) + +(defmacro c-forward-sexp (&optional count) + "Move forward across COUNT balanced expressions. +A negative COUNT means move backward. Signal an error if the move +fails for any reason. +This is like `forward-sexp' except that it isn't interactive and does +not do any user friendly adjustments of the point and that it isn't +susceptible to user configurations such as disabling of signals in +certain situations. + +This function does not do any hidden buffer changes." + (or count (setq count 1)) + `(goto-char (or (scan-sexps (point) ,count) + ,(if (numberp count) + (if (> count 0) `(point-max) `(point-min)) + `(if (> ,count 0) (point-max) (point-min)))))) + +(defmacro c-backward-sexp (&optional count) + "See `c-forward-sexp' and reverse directions." + (or count (setq count 1)) + `(c-forward-sexp ,(if (numberp count) (- count) `(- ,count)))) + +(defmacro c-safe-scan-lists (from count depth) + "Like `scan-lists' but returns nil instead of signalling errors. + +This function does not do any hidden buffer changes." + (if (featurep 'xemacs) + `(scan-lists ,from ,count ,depth nil t) + `(c-safe (scan-lists ,from ,count ,depth)))) + + ;; Wrappers for common scan-lists cases, mainly because it's almost ;; impossible to get a feel for how that function works. -(defmacro c-up-list-forward (pos) - `(c-safe (scan-lists ,pos 1 1))) -(defmacro c-up-list-backward (pos) - `(c-safe (scan-lists ,pos -1 1))) -(defmacro c-down-list-forward (pos) - `(c-safe (scan-lists ,pos 1 -1))) -(defmacro c-down-list-backward (pos) - `(c-safe (scan-lists ,pos -1 -1))) + +(defmacro c-up-list-forward (&optional pos) + "Return the first position after the list sexp containing POS, +or nil if no such position exists. The point is used if POS is left out. + +This function does not do any hidden buffer changes." + `(c-safe-scan-lists ,(or pos `(point)) 1 1)) + +(defmacro c-up-list-backward (&optional pos) + "Return the position of the start of the list sexp containing POS, +or nil if no such position exists. The point is used if POS is left out. + +This function does not do any hidden buffer changes." + `(c-safe-scan-lists ,(or pos `(point)) -1 1)) + +(defmacro c-down-list-forward (&optional pos) + "Return the first position inside the first list sexp after POS, +or nil if no such position exists. The point is used if POS is left out. + +This function does not do any hidden buffer changes." + `(c-safe-scan-lists ,(or pos `(point)) 1 -1)) + +(defmacro c-down-list-backward (&optional pos) + "Return the last position inside the last list sexp before POS, +or nil if no such position exists. The point is used if POS is left out. + +This function does not do any hidden buffer changes." + `(c-safe-scan-lists ,(or pos `(point)) -1 -1)) + +(defmacro c-go-up-list-forward (&optional pos) + "Move the point to the first position after the list sexp containing POS, +or the point if POS is left out. Return t if such a position exists, +otherwise nil is returned and the point isn't moved. + +This function does not do any hidden buffer changes." + `(c-safe (goto-char (scan-lists ,(or pos `(point)) 1 1)) t)) + +(defmacro c-go-up-list-backward (&optional pos) + "Move the point to the position of the start of the list sexp containing POS, +or the point if POS is left out. Return t if such a position exists, +otherwise nil is returned and the point isn't moved. + +This function does not do any hidden buffer changes." + `(c-safe (goto-char (scan-lists ,(or pos `(point)) -1 1)) t)) + +(defmacro c-go-down-list-forward (&optional pos) + "Move the point to the first position inside the first list sexp after POS, +or the point if POS is left out. Return t if such a position exists, +otherwise nil is returned and the point isn't moved. + +This function does not do any hidden buffer changes." + `(c-safe (goto-char (scan-lists ,(or pos `(point)) 1 -1)) t)) -(defmacro c-add-syntax (symbol &optional relpos) - ;; a simple macro to append the syntax in symbol to the syntax list. - ;; try to increase performance by using this macro - `(let ((relpos-tmp ,relpos)) - (if relpos-tmp (setq syntactic-relpos relpos-tmp)) - (setq syntax (cons (cons ,symbol relpos-tmp) syntax)))) +(defmacro c-go-down-list-backward (&optional pos) + "Move the point to the last position inside the last list sexp before POS, +or the point if POS is left out. Return t if such a position exists, +otherwise nil is returned and the point isn't moved. + +This function does not do any hidden buffer changes." + `(c-safe (goto-char (scan-lists ,(or pos `(point)) -1 -1)) t)) + + +(defmacro c-beginning-of-defun-1 () + ;; Wrapper around beginning-of-defun. + ;; + ;; NOTE: This function should contain the only explicit use of + ;; beginning-of-defun in CC Mode. Eventually something better than + ;; b-o-d will be available and this should be the only place the + ;; code needs to change. Everything else should use + ;; (c-beginning-of-defun-1) + ;; + ;; This is really a bit too large to be a macro but that isn't a + ;; problem as long as it only is used in one place in + ;; `c-parse-state'. + ;; + ;; This function does not do any hidden buffer changes. + + `(progn + (if (and ,(cc-bytecomp-fboundp 'buffer-syntactic-context-depth) + c-enable-xemacs-performance-kludge-p) + ,(when (cc-bytecomp-fboundp 'buffer-syntactic-context-depth) + ;; XEmacs only. This can improve the performance of + ;; c-parse-state to between 3 and 60 times faster when + ;; braces are hung. It can also degrade performance by + ;; about as much when braces are not hung. + '(let (pos) + (while (not pos) + (save-restriction + (widen) + (setq pos (c-safe-scan-lists + (point) -1 (buffer-syntactic-context-depth)))) + (cond + ((bobp) (setq pos (point-min))) + ((not pos) + (let ((distance (skip-chars-backward "^{"))) + ;; unbalanced parenthesis, while illegal C code, + ;; shouldn't cause an infloop! See unbal.c + (when (zerop distance) + ;; Punt! + (beginning-of-defun) + (setq pos (point))))) + ((= pos 0)) + ((not (eq (char-after pos) ?{)) + (goto-char pos) + (setq pos nil)) + )) + (goto-char pos))) + ;; Emacs, which doesn't have buffer-syntactic-context-depth + (beginning-of-defun)) + ;; if defun-prompt-regexp is non-nil, b-o-d won't leave us at the + ;; open brace. + (and defun-prompt-regexp + (looking-at defun-prompt-regexp) + (goto-char (match-end 0))))) (defmacro c-benign-error (format &rest args) ;; Formats an error message for the echo area and dings, i.e. like ;; `error' but doesn't abort. + ;; + ;; This function does not do any hidden buffer changes. `(progn (message ,format ,@args) (ding))) (defmacro c-update-modeline () ;; set the c-auto-hungry-string for the correct designation on the modeline + ;; + ;; This function does not do any hidden buffer changes. `(progn (setq c-auto-hungry-string (if c-auto-newline @@ -208,6 +566,8 @@ (defmacro c-with-syntax-table (table &rest code) ;; Temporarily switches to the specified syntax table in a failsafe ;; way to execute code. + ;; + ;; This function does not do any hidden buffer changes. `(let ((c-with-syntax-table-orig-table (syntax-table))) (unwind-protect (progn @@ -219,19 +579,21 @@ (defmacro c-skip-ws-forward (&optional limit) "Skip over any whitespace following point. This function skips over horizontal and vertical whitespace and line -continuations." +continuations. + +This function does not do any hidden buffer changes." (if limit - `(let ((-limit- (or ,limit (point-max)))) + `(let ((limit (or ,limit (point-max)))) (while (progn ;; skip-syntax-* doesn't count \n as whitespace.. - (skip-chars-forward " \t\n\r\f" -limit-) + (skip-chars-forward " \t\n\r\f\v" limit) (when (and (eq (char-after) ?\\) - (< (point) -limit-)) + (< (point) limit)) (forward-char) (or (eolp) (progn (backward-char) nil)))))) '(while (progn - (skip-chars-forward " \t\n\r\f") + (skip-chars-forward " \t\n\r\f\v") (when (eq (char-after) ?\\) (forward-char) (or (eolp) @@ -240,31 +602,194 @@ (defmacro c-skip-ws-backward (&optional limit) "Skip over any whitespace preceding point. This function skips over horizontal and vertical whitespace and line -continuations." +continuations. + +This function does not do any hidden buffer changes." (if limit - `(let ((-limit- (or ,limit (point-min)))) + `(let ((limit (or ,limit (point-min)))) (while (progn ;; skip-syntax-* doesn't count \n as whitespace.. - (skip-chars-backward " \t\n\r\f" -limit-) + (skip-chars-backward " \t\n\r\f\v" limit) (and (eolp) (eq (char-before) ?\\) - (> (point) -limit-))) + (> (point) limit))) (backward-char))) '(while (progn - (skip-chars-backward " \t\n\r\f") + (skip-chars-backward " \t\n\r\f\v") (and (eolp) (eq (char-before) ?\\))) (backward-char)))) +(defmacro c-major-mode-is (mode) + "Return non-nil if the current CC Mode major mode is MODE. +MODE is either a mode symbol or a list of mode symbols. + +This function does not do any hidden buffer changes." + (if (eq (car-safe mode) 'quote) + (let ((mode (eval mode))) + (if (listp mode) + `(memq c-buffer-is-cc-mode ',mode) + `(eq c-buffer-is-cc-mode ',mode))) + `(let ((mode ,mode)) + (if (listp mode) + (memq c-buffer-is-cc-mode mode) + (eq c-buffer-is-cc-mode mode))))) + +(defmacro c-parse-sexp-lookup-properties () + ;; Return the value of the variable that says whether the + ;; syntax-table property affects the sexp routines. Always return + ;; nil in (X)Emacsen without support for that. + ;; + ;; This function does not do any hidden buffer changes. + (cond ((cc-bytecomp-boundp 'parse-sexp-lookup-properties) + `parse-sexp-lookup-properties) + ((cc-bytecomp-boundp 'lookup-syntax-properties) + `lookup-syntax-properties) + (t nil))) + + +;; Macros/functions to handle so-called "char properties", which are +;; properties set on a single character and that never spreads to any +;; other characters. + +(eval-and-compile + ;; Constant used at compile time to decide whether or not to use + ;; XEmacs extents. Check all the extent functions we'll use since + ;; some packages might add compatibility aliases for some of them in + ;; Emacs. + (defconst c-use-extents (and (cc-bytecomp-fboundp 'extent-at) + (cc-bytecomp-fboundp 'set-extent-property) + (cc-bytecomp-fboundp 'set-extent-properties) + (cc-bytecomp-fboundp 'make-extent) + (cc-bytecomp-fboundp 'extent-property) + (cc-bytecomp-fboundp 'delete-extent) + (cc-bytecomp-fboundp 'map-extents)))) + +;; `c-put-char-property' is complex enough in XEmacs and Emacs < 21 to +;; make it a function. +(defalias 'c-put-char-property-fun + (cc-eval-when-compile + (cond (c-use-extents + ;; XEmacs. + (byte-compile + (lambda (pos property value) + (let ((ext (extent-at pos nil property))) + (if ext + (set-extent-property ext property value) + (set-extent-properties (make-extent pos (1+ pos)) + (cons property + (cons value + '(start-open t + end-open t))))))))) + + ((not (cc-bytecomp-boundp 'text-property-default-nonsticky)) + ;; In Emacs < 21 we have to mess with the `rear-nonsticky' property. + (byte-compile + (lambda (pos property value) + (put-text-property pos (1+ pos) property value) + (let ((prop (get-text-property pos 'rear-nonsticky))) + (or (memq property prop) + (put-text-property pos (1+ pos) + 'rear-nonsticky + (cons property prop)))))))))) +(cc-bytecomp-defun c-put-char-property-fun) ; Make it known below. + +(defmacro c-put-char-property (pos property value) + ;; Put the given property with the given value on the character at + ;; POS and make it front and rear nonsticky, or start and end open + ;; in XEmacs vocabulary. If the character already has the given + ;; property then the value is replaced, and the behavior is + ;; undefined if that property has been put by some other function. + ;; PROPERTY is assumed to be constant. + ;; + ;; If there's a `text-property-default-nonsticky' variable (Emacs + ;; 21) then it's assumed that the property is present on it. + (setq property (eval property)) + (if (or c-use-extents + (not (cc-bytecomp-boundp 'text-property-default-nonsticky))) + ;; XEmacs and Emacs < 21. + `(c-put-char-property-fun ,pos ',property ,value) + ;; In Emacs 21 we got the `rear-nonsticky' property covered + ;; by `text-property-default-nonsticky'. + `(let ((-pos- ,pos)) + (put-text-property -pos- (1+ -pos-) ',property ,value)))) + +(defmacro c-get-char-property (pos property) + ;; Get the value of the given property on the character at POS if + ;; it's been put there by `c-put-char-property'. PROPERTY is + ;; assumed to be constant. + (setq property (eval property)) + (if c-use-extents + ;; XEmacs. + `(let ((ext (extent-at ,pos nil ',property))) + (if ext (extent-property ext ',property))) + ;; Emacs. + `(get-text-property ,pos ',property))) + +;; `c-clear-char-property' is complex enough in Emacs < 21 to make it +;; a function, since we have to mess with the `rear-nonsticky' property. +(defalias 'c-clear-char-property-fun + (cc-eval-when-compile + (unless (or c-use-extents + (cc-bytecomp-boundp 'text-property-default-nonsticky)) + (byte-compile + (lambda (pos property) + (when (get-text-property pos property) + (remove-text-properties pos (1+ pos) (list property nil)) + (put-text-property pos (1+ pos) + 'rear-nonsticky + (delq property (get-text-property + pos 'rear-nonsticky))))))))) +(cc-bytecomp-defun c-clear-char-property-fun) ; Make it known below. + +(defmacro c-clear-char-property (pos property) + ;; Remove the given property on the character at POS if it's been put + ;; there by `c-put-char-property'. PROPERTY is assumed to be + ;; constant. + (setq property (eval property)) + (cond (c-use-extents + ;; XEmacs. + `(let ((ext (extent-at ,pos nil ',property))) + (if ext (delete-extent ext)))) + ((cc-bytecomp-boundp 'text-property-default-nonsticky) + ;; In Emacs 21 we got the `rear-nonsticky' property covered + ;; by `text-property-default-nonsticky'. + `(let ((pos ,pos)) + (remove-text-properties pos (1+ pos) + '(,property nil)))) + (t + ;; Emacs < 21. + `(c-clear-char-property-fun ,pos ',property)))) + +(defmacro c-clear-char-properties (from to property) + ;; Remove all the occurences of the given property in the given + ;; region that has been put with `c-put-char-property'. PROPERTY is + ;; assumed to be constant. + ;; + ;; Note that this function does not clean up the property from the + ;; lists of the `rear-nonsticky' properties in the region, if such + ;; are used. Thus it should not be used for common properties like + ;; `syntax-table'. + (setq property (eval property)) + (if c-use-extents + ;; XEmacs. + `(map-extents (lambda (ext ignored) + (delete-extent ext)) + nil ,from ,to nil nil ',property) + ;; Emacs. + `(remove-text-properties ,from ,to '(,property nil)))) + + ;; Make edebug understand the macros. (eval-after-load "edebug" '(progn - (def-edebug-spec c-paren-re t) - (def-edebug-spec c-identifier-re t) - (def-edebug-spec c-point ([&or symbolp form] &optional form)) + (def-edebug-spec c-point t) (def-edebug-spec c-safe t) - (def-edebug-spec c-forward-sexp (&optional [&or numberp form])) - (def-edebug-spec c-backward-sexp (&optional [&or numberp form])) + (def-edebug-spec c-save-buffer-state let*) + (def-edebug-spec c-forward-syntactic-ws t) + (def-edebug-spec c-backward-syntactic-ws t) + (def-edebug-spec c-forward-sexp t) + (def-edebug-spec c-backward-sexp t) (def-edebug-spec c-up-list-forward t) (def-edebug-spec c-up-list-backward t) (def-edebug-spec c-down-list-forward t) @@ -274,60 +799,22 @@ (def-edebug-spec c-benign-error t) (def-edebug-spec c-with-syntax-table t) (def-edebug-spec c-skip-ws-forward t) - (def-edebug-spec c-skip-ws-backward t))) + (def-edebug-spec c-skip-ws-backward t) + (def-edebug-spec c-major-mode-is t) + (def-edebug-spec c-put-char-property t) + (def-edebug-spec c-get-char-property t) + (def-edebug-spec c-clear-char-property t) + (def-edebug-spec c-clear-char-properties t) + (def-edebug-spec cc-eval-when-compile t))) -;;; Inline functions. + +;;; Functions. ;; Note: All these after the macros, to be on safe side in avoiding ;; bugs where macros are defined too late. These bugs often only show ;; when the files are compiled in a certain order within the same ;; session. -(defsubst c-beginning-of-defun-1 () - ;; Wrapper around beginning-of-defun. - ;; - ;; NOTE: This function should contain the only explicit use of - ;; beginning-of-defun in CC Mode. Eventually something better than - ;; b-o-d will be available and this should be the only place the - ;; code needs to change. Everything else should use - ;; (c-beginning-of-defun-1) - (if (and (fboundp 'buffer-syntactic-context-depth) - c-enable-xemacs-performance-kludge-p) - ;; XEmacs only. This can improve the performance of - ;; c-parse-state to between 3 and 60 times faster when - ;; braces are hung. It can also degrade performance by - ;; about as much when braces are not hung. - (let (pos) - (while (not pos) - (save-restriction - (widen) - (setq pos (scan-lists (point) -1 - (buffer-syntactic-context-depth) - nil t))) - (cond - ((bobp) (setq pos (point-min))) - ((not pos) - (let ((distance (skip-chars-backward "^{"))) - ;; unbalanced parenthesis, while illegal C code, - ;; shouldn't cause an infloop! See unbal.c - (when (zerop distance) - ;; Punt! - (beginning-of-defun) - (setq pos (point))))) - ((= pos 0)) - ((not (eq (char-after pos) ?{)) - (goto-char pos) - (setq pos nil)) - )) - (goto-char pos)) - ;; Emacs, which doesn't have buffer-syntactic-context-depth - (beginning-of-defun)) - ;; if defun-prompt-regexp is non-nil, b-o-d won't leave us at the - ;; open brace. - (and defun-prompt-regexp - (looking-at defun-prompt-regexp) - (goto-char (match-end 0)))) - (defsubst c-end-of-defun-1 () ;; Replacement for end-of-defun that use c-beginning-of-defun-1. (let ((start (point))) @@ -341,9 +828,29 @@ (if (< (point) start) (goto-char (point-max))))) +(defconst c-<-as-paren-syntax '(4 . ?>)) + +(defsubst c-mark-<-as-paren (pos) + ;; Mark the "<" character at POS as an sexp list opener using the + ;; syntax-table property. Note that Emacs 19 and XEmacs <= 20 + ;; doesn't support syntax properties, so this function might not + ;; have any effect. + (c-put-char-property pos 'syntax-table c-<-as-paren-syntax)) + +(defconst c->-as-paren-syntax '(5 . ?<)) + +(defsubst c-mark->-as-paren (pos) + ;; Mark the ">" character at POS as an sexp list closer using the + ;; syntax-table property. Note that Emacs 19 and XEmacs <= 20 + ;; doesn't support syntax properties, so this function might not + ;; have any effect. + (c-put-char-property pos 'syntax-table c->-as-paren-syntax)) + (defsubst c-intersect-lists (list alist) ;; return the element of ALIST that matches the first element found ;; in LIST. Uses assq. + ;; + ;; This function does not do any hidden buffer changes. (let (match) (while (and list (not (setq match (assq (car list) alist)))) @@ -353,11 +860,15 @@ (defsubst c-lookup-lists (list alist1 alist2) ;; first, find the first entry from LIST that is present in ALIST1, ;; then find the entry in ALIST2 for that entry. + ;; + ;; This function does not do any hidden buffer changes. (assq (car (c-intersect-lists list alist1)) alist2)) (defsubst c-langelem-col (langelem &optional preserve-point) - ;; convenience routine to return the column of langelem's relpos. - ;; Leaves point at the relpos unless preserve-point is non-nil. + "Convenience routine to return the column of LANGELEM's relpos. +Leaves point at the relpos unless PRESERVE-POINT is non-nil. + +This function does not do any hidden buffer changes." (if (cdr langelem) (let ((here (point))) (goto-char (cdr langelem)) @@ -370,12 +881,16 @@ (defsubst c-keep-region-active () ;; Do whatever is necessary to keep the region active in XEmacs. ;; This is not needed for Emacs. + ;; + ;; This function does not do any hidden buffer changes. (and (boundp 'zmacs-region-stays) (setq zmacs-region-stays t))) (defsubst c-region-is-active-p () ;; Return t when the region is active. The determination of region ;; activeness is different in both Emacs and XEmacs. + ;; + ;; This function does not do any hidden buffer changes. (cond ;; XEmacs ((and (fboundp 'region-active-p) @@ -387,8 +902,621 @@ ;; fallback; shouldn't get here (t (mark t)))) -(defsubst c-major-mode-is (mode) - (eq c-buffer-is-cc-mode mode)) +(put 'c-mode 'c-mode-prefix "c-") +(put 'c++-mode 'c-mode-prefix "c++-") +(put 'objc-mode 'c-mode-prefix "objc-") +(put 'java-mode 'c-mode-prefix "java-") +(put 'idl-mode 'c-mode-prefix "idl-") +(put 'pike-mode 'c-mode-prefix "pike-") +(put 'awk-mode 'c-mode-prefix "awk-") + +(defsubst c-mode-symbol (suffix) + "Prefix the current mode prefix (e.g. \"c-\") to SUFFIX and return +the corresponding symbol. + +This function does not do any hidden buffer changes." + (or c-buffer-is-cc-mode + (error "Not inside a CC Mode based mode")) + (let ((mode-prefix (get c-buffer-is-cc-mode 'c-mode-prefix))) + (or mode-prefix + (error "%S has no mode prefix known to `c-mode-symbol'" + c-buffer-is-cc-mode)) + (intern (concat mode-prefix suffix)))) + +(defsubst c-mode-var (suffix) + "Prefix the current mode prefix (e.g. \"c-\") to SUFFIX and return +the value of the variable with that name. + +This function does not do any hidden buffer changes." + (symbol-value (c-mode-symbol suffix))) + +(defsubst c-mode-is-new-awk-p () + ;; Is the current mode the "new" awk mode? It is important for + ;; (e.g.) the cc-engine functions do distinguish between the old and + ;; new awk-modes. + (and (c-major-mode-is 'awk-mode) + (memq 'syntax-properties c-emacs-features))) + +(defsubst c-got-face-at (pos faces) + "Return non-nil if position POS in the current buffer has any of the +faces in the list FACES. + +This function does not do any hidden buffer changes." + (let ((pos-faces (get-text-property pos 'face))) + (if (consp pos-faces) + (progn + (while (and pos-faces + (not (memq (car pos-faces) faces))) + (setq pos-faces (cdr pos-faces))) + pos-faces) + (memq pos-faces faces)))) + +(defsubst c-face-name-p (facename) + ;; Return t if FACENAME is the name of a face. This method is + ;; necessary since facep in XEmacs only returns t for the actual + ;; face objects (while it's only their names that are used just + ;; about anywhere else) without providing a predicate that tests + ;; face names. + ;; + ;; This function does not do any hidden buffer changes. + (memq facename (face-list))) + +(defun c-make-keywords-re (adorn list &optional mode) + "Make a regexp that matches all the strings the list. +Duplicates in the list are removed. The regexp may contain zero or +more submatch expressions. + +If ADORN is non-nil there will be at least one submatch and the first +matches the whole keyword, and the regexp will also not match a prefix +of any identifier. Adorned regexps cannot be appended. The language +variable `c-nonsymbol-key' is used to make the adornment. The +optional MODE specifies the language to get it in. The default is the +current language (taken from `c-buffer-is-cc-mode')." + (setq list (delete-duplicates list :test 'string-equal)) + (if list + (let ((re (c-regexp-opt list))) + ;; Add our own grouping parenthesis around re instead of + ;; passing adorn to `regexp-opt', since in XEmacs it makes the + ;; top level grouping "shy". + (if adorn + (concat "\\(" re "\\)" + "\\(" + (c-get-lang-constant 'c-nonsymbol-key nil mode) + "\\|$\\)") + re)) + ;; Produce a regexp that matches nothing. + (if adorn + "\\(\\<\\>\\)" + "\\<\\>"))) +(put 'c-make-keywords-re 'lisp-indent-function 1) + + +;;; Some helper constants. + +;; If the regexp engine supports POSIX char classes (e.g. Emacs 21) +;; then we can use them to handle extended charsets correctly. +(if (string-match "[[:alpha:]]" "a") ; Can't use c-emacs-features here. + (progn + (defconst c-alpha "[:alpha:]") + (defconst c-alnum "[:alnum:]") + (defconst c-digit "[:digit:]") + (defconst c-upper "[:upper:]") + (defconst c-lower "[:lower:]")) + (defconst c-alpha "a-zA-Z") + (defconst c-alnum "a-zA-Z0-9") + (defconst c-digit "0-9") + (defconst c-upper "A-Z") + (defconst c-lower "a-z")) + + +;;; System for handling language dependent constants. + +;; This is used to set various language dependent data in a flexible +;; way: Language constants can be built from the values of other +;; language constants, also those for other languages. They can also +;; process the values of other language constants uniformly across all +;; the languages. E.g. one language constant can list all the type +;; keywords in each language, and another can build a regexp for each +;; language from those lists without code duplication. +;; +;; Language constants are defined with `c-lang-defconst', and their +;; value forms (referred to as source definitions) are evaluated only +;; on demand when requested for a particular language with +;; `c-lang-const'. It's therefore possible to refer to the values of +;; constants defined later in the file, or in another file, just as +;; long as all the relevant `c-lang-defconst' have been loaded when +;; `c-lang-const' is actually evaluated from somewhere else. +;; +;; `c-lang-const' forms are also evaluated at compile time and +;; replaced with the values they produce. Thus there's no overhead +;; for this system when compiled code is used - only the values +;; actually used in the code are present, and the file(s) containing +;; the `c-lang-defconst' forms don't need to be loaded at all then. +;; There are however safeguards to make sure that they can be loaded +;; to get the source definitions for the values if there's a mismatch +;; in compiled versions, or if `c-lang-const' is used uncompiled. +;; +;; Note that the source definitions in a `c-lang-defconst' form are +;; compiled into the .elc file where it stands; there's no need to +;; load the source file to get it. +;; +;; See cc-langs.el for more details about how this system is deployed +;; in CC Mode, and how the associated language variable system +;; (`c-lang-defvar') works. That file also contains a lot of +;; examples. + +(defun c-add-language (mode base-mode) + "Declare a new language in the language dependent variable system. +This is intended to be used by modes that inherit CC Mode to add new +languages. It should be used at the top level before any calls to +`c-lang-defconst'. MODE is the mode name symbol for the new language, +and BASE-MODE is the mode name symbol for the language in CC Mode that +is to be the template for the new mode. + +The exact effect of BASE-MODE is to make all language constants that +haven't got a setting in the new language fall back to their values in +BASE-MODE. It does not have any effect outside the language constant +system." + (unless (string-match "\\`\\(.*-\\)mode\\'" (symbol-name mode)) + (error "The mode name symbol `%s' must end with \"-mode\"" mode)) + (put mode 'c-mode-prefix (match-string 1 (symbol-name mode))) + (unless (get base-mode 'c-mode-prefix) + (error "Unknown base mode `%s'" base-mode) + (put mode 'c-fallback-mode base-mode))) + +(defvar c-lang-constants (make-vector 151 0)) +;; This obarray is a cache to keep track of the language constants +;; defined by `c-lang-defconst' and the evaluated values returned by +;; `c-lang-const'. It's mostly used at compile time but it's not +;; stored in compiled files. +;; +;; The obarray contains all the language constants as symbols. The +;; value cells hold the evaluated values as alists where each car is +;; the mode name symbol and the corresponding cdr is the evaluated +;; value in that mode. The property lists hold the source definitions +;; and other miscellaneous data. The obarray might also contain +;; various other symbols, but those don't have any variable bindings. + +(defvar c-lang-const-expansion nil) +(defvar c-langs-are-parametric nil) + +(defsubst c-get-current-file () + ;; Return the base name of the current file. + (let ((file (cond + (load-in-progress + ;; Being loaded. + load-file-name) + ((and (boundp 'byte-compile-dest-file) + (stringp byte-compile-dest-file)) + ;; Being compiled. + byte-compile-dest-file) + (t + ;; Being evaluated interactively. + (buffer-file-name))))) + (and file + (file-name-sans-extension + (file-name-nondirectory file))))) + +(defmacro c-lang-defconst-eval-immediately (form) + "Can be used inside a VAL in `c-lang-defconst' to evaluate FORM +immediately, i.e. at the same time as the `c-lang-defconst' form +itself is evaluated." + ;; Evaluate at macro expansion time, i.e. in the + ;; `cl-macroexpand-all' inside `c-lang-defconst'. + (eval form)) + +(defmacro c-lang-defconst (name &rest args) + "Set the language specific values of the language constant NAME. +The second argument can be an optional docstring. The rest of the +arguments are one or more repetitions of LANG VAL where LANG specifies +the language(s) that VAL applies to. LANG is the name of the +language, i.e. the mode name without the \"-mode\" suffix, or a list +of such language names, or `t' for all languages. VAL is a form to +evaluate to get the value. + +If LANG isn't `t' or one of the core languages in CC Mode, it must +have been declared with `c-add-language'. + +Neither NAME, LANG nor VAL are evaluated directly - they should not be +quoted. `c-lang-defconst-eval-immediately' can however be used inside +VAL to evaluate parts of it directly. + +When VAL is evaluated for some language, that language is temporarily +made current so that `c-lang-const' without an explicit language can +be used inside VAL to refer to the value of a language constant in the +same language. That is particularly useful if LANG is `t'. + +VAL is not evaluated right away but rather when the value is requested +with `c-lang-const'. Thus it's possible to use `c-lang-const' inside +VAL to refer to language constants that haven't been defined yet. +However, if the definition of a language constant is in another file +then that file must be loaded \(at compile time) before it's safe to +reference the constant. + +The assignments in ARGS are processed in sequence like `setq', so +\(c-lang-const NAME) may be used inside a VAL to refer to the last +assigned value to this language constant, or a value that it has +gotten in another earlier loaded file. + +To work well with repeated loads and interactive reevaluation, only +one `c-lang-defconst' for each NAME is permitted per file. If there +already is one it will be completely replaced; the value in the +earlier definition will not affect `c-lang-const' on the same +constant. A file is identified by its base name. + +This macro does not do any hidden buffer changes." + + (let* ((sym (intern (symbol-name name) c-lang-constants)) + ;; Make `c-lang-const' expand to a straightforward call to + ;; `c-get-lang-constant' in `cl-macroexpand-all' below. + ;; + ;; (The default behavior, i.e. to expand to a call inside + ;; `eval-when-compile' should be equivalent, since that macro + ;; should only expand to its content if it's used inside a + ;; form that's already evaluated at compile time. It's + ;; however necessary to use our cover macro + ;; `cc-eval-when-compile' due to bugs in `eval-when-compile', + ;; and it expands to a bulkier form that in this case only is + ;; unnecessary garbage that we don't want to store in the + ;; language constant source definitions.) + (c-lang-const-expansion 'call) + (c-langs-are-parametric t) + bindings + pre-files) + + (or (symbolp name) + (error "Not a symbol: %s" name)) + + (when (stringp (car-safe args)) + ;; The docstring is hardly used anywhere since there's no normal + ;; symbol to attach it to. It's primarily for getting the right + ;; format in the source. + (put sym 'variable-documentation (car args)) + (setq args (cdr args))) + + (or args + (error "No assignments in `c-lang-defconst' for %s" name)) + + ;; Rework ARGS to an association list to make it easier to handle. + ;; It's reversed at the same time to make it easier to implement + ;; the demand-driven (i.e. reversed) evaluation in `c-lang-const'. + (while args + (let ((assigned-mode + (cond ((eq (car args) t) t) + ((symbolp (car args)) + (list (intern (concat (symbol-name (car args)) + "-mode")))) + ((listp (car args)) + (mapcar (lambda (lang) + (or (symbolp lang) + (error "Not a list of symbols: %s" + (car args))) + (intern (concat (symbol-name lang) + "-mode"))) + (car args))) + (t (error "Not a symbol or a list of symbols: %s" + (car args))))) + val) + + (or (cdr args) + (error "No value for %s" (car args))) + (setq args (cdr args) + val (car args)) + + ;; Emacs has a weird bug where it seems to fail to read + ;; backquote lists from byte compiled files correctly (,@ + ;; forms, to be specific), so make sure the bindings in the + ;; expansion below doesn't contain any backquote stuff. + ;; (XEmacs handles it correctly and doesn't need this for that + ;; reason, but we also use this expansion handle + ;; `c-lang-defconst-eval-immediately' and to register + ;; dependencies on the `c-lang-const's in VAL.) + (setq val (cl-macroexpand-all val)) + + (setq bindings (cons (cons assigned-mode val) bindings) + args (cdr args)))) + + ;; Compile in the other files that have provided source + ;; definitions for this symbol, to make sure the order in the + ;; `source' property is correct even when files are loaded out of + ;; order. + (setq pre-files (nreverse + ;; Reverse to get the right load order. + (mapcar 'car (get sym 'source)))) + + `(eval-and-compile + (c-define-lang-constant ',name ',bindings + ,@(and pre-files `(',pre-files)))))) + +(put 'c-lang-defconst 'lisp-indent-function 1) +(eval-after-load "edebug" + '(def-edebug-spec c-lang-defconst + (&define name [&optional stringp] [&rest sexp def-form]))) + +(defun c-define-lang-constant (name bindings &optional pre-files) + ;; Used by `c-lang-defconst'. This function does not do any hidden + ;; buffer changes. + + (let* ((sym (intern (symbol-name name) c-lang-constants)) + (source (get sym 'source)) + (file (intern + (or (c-get-current-file) + (error "`c-lang-defconst' must be used in a file")))) + (elem (assq file source))) + + ;;(when (cdr-safe elem) + ;; (message "Language constant %s redefined in %S" name file)) + + ;; Note that the order in the source alist is relevant. Like how + ;; `c-lang-defconst' reverses the bindings, this reverses the + ;; order between files so that the last to evaluate comes first. + (unless elem + (while pre-files + (unless (assq (car pre-files) source) + (setq source (cons (list (car pre-files)) source))) + (setq pre-files (cdr pre-files))) + (put sym 'source (cons (setq elem (list file)) source))) + + (setcdr elem bindings) + + ;; Bind the symbol as a variable, or clear any earlier evaluated + ;; value it has. + (set sym nil) + + ;; Clear the evaluated values that depend on this source. + (let ((agenda (get sym 'dependents)) + (visited (make-vector 101 0)) + ptr) + (while agenda + (setq sym (car agenda) + agenda (cdr agenda)) + (intern (symbol-name sym) visited) + (set sym nil) + (setq ptr (get sym 'dependents)) + (while ptr + (setq sym (car ptr) + ptr (cdr ptr)) + (unless (intern-soft (symbol-name sym) visited) + (setq agenda (cons sym agenda)))))) + + name)) + +(defmacro c-lang-const (name &optional lang) + "Get the mode specific value of the language constant NAME in language LANG. +LANG is the name of the language, i.e. the mode name without the +\"-mode\" suffix. If used inside `c-lang-defconst' or +`c-lang-defvar', LANG may be left out to refer to the current +language. NAME and LANG are not evaluated so they should not be +quoted. + +This macro does not do any hidden buffer changes." + + (or (symbolp name) + (error "Not a symbol: %s" name)) + (or (symbolp lang) + (error "Not a symbol: %s" lang)) + + (let ((sym (intern (symbol-name name) c-lang-constants)) + mode source-files args) + + (if lang + (progn + (setq mode (intern (concat (symbol-name lang) "-mode"))) + (unless (get mode 'c-mode-prefix) + (error + "Unknown language %S since it got no `c-mode-prefix' property" + (symbol-name lang)))) + (if c-buffer-is-cc-mode + (setq lang c-buffer-is-cc-mode) + (or c-langs-are-parametric + (error + "`c-lang-const' requires a literal language in this context")))) + + (if (eq c-lang-const-expansion 'immediate) + ;; No need to find out the source file(s) when we evaluate + ;; immediately since all the info is already there in the + ;; `source' property. + `',(c-get-lang-constant name nil mode) + + (let ((file (c-get-current-file))) + (if file (setq file (intern file))) + ;; Get the source file(s) that must be loaded to get the value + ;; of the constant. If the symbol isn't defined yet we assume + ;; that its definition will come later in this file, and thus + ;; are no file dependencies needed. + (setq source-files (nreverse + ;; Reverse to get the right load order. + (mapcan (lambda (elem) + (if (eq file (car elem)) + nil ; Exclude our own file. + (list (car elem)))) + (get sym 'source))))) + + ;; Spend some effort to make a compact call to + ;; `c-get-lang-constant' since it will be compiled in. + (setq args (and mode `(',mode))) + (if (or source-files args) + (setq args (cons (and source-files `',source-files) + args))) + + (if (or (eq c-lang-const-expansion 'call) + load-in-progress + (not (boundp 'byte-compile-dest-file)) + (not (stringp byte-compile-dest-file))) + ;; Either a straight call is requested in the context, or + ;; we're not being byte compiled so the compile time stuff + ;; below is unnecessary. + `(c-get-lang-constant ',name ,@args) + + ;; Being compiled. If the loading and compiling version is + ;; the same we use a value that is evaluated at compile time, + ;; otherwise it's evaluated at runtime. + `(if (eq c-version-sym ',c-version-sym) + (cc-eval-when-compile + (c-get-lang-constant ',name ,@args)) + (c-get-lang-constant ',name ,@args)))))) + +(defvar c-lang-constants-under-evaluation nil) + +(defun c-get-lang-constant (name &optional source-files mode) + ;; Used by `c-lang-const'. This function does not do any hidden + ;; buffer changes. + + (or mode + (setq mode c-buffer-is-cc-mode) + (error "No current language")) + + (let* ((sym (intern (symbol-name name) c-lang-constants)) + (source (get sym 'source)) + elem + (eval-in-sym (and c-lang-constants-under-evaluation + (caar c-lang-constants-under-evaluation)))) + + ;; Record the dependencies between this symbol and the one we're + ;; being evaluated in. + (when eval-in-sym + (or (memq eval-in-sym (get sym 'dependents)) + (put sym 'dependents (cons eval-in-sym (get sym 'dependents))))) + + ;; Make sure the source files have entries on the `source' + ;; property so that loading will take place when necessary. + (while source-files + (unless (assq (car source-files) source) + (put sym 'source + (setq source (cons (list (car source-files)) source))) + ;; Might pull in more definitions which affect the value. The + ;; clearing of dependent values etc is done when the + ;; definition is encountered during the load; this is just to + ;; jump past the check for a cached value below. + (set sym nil)) + (setq source-files (cdr source-files))) + + (if (and (boundp sym) + (setq elem (assq mode (symbol-value sym)))) + (cdr elem) + + ;; Check if an evaluation of this symbol is already underway. + ;; In that case we just continue with the "assignment" before + ;; the one currently being evaluated, thereby creating the + ;; illusion if a `setq'-like sequence of assignments. + (let* ((c-buffer-is-cc-mode mode) + (source-pos + (or (assq sym c-lang-constants-under-evaluation) + (cons sym (vector source nil)))) + ;; Append `c-lang-constants-under-evaluation' even if an + ;; earlier entry is found. It's only necessary to get + ;; the recording of dependencies above correct. + (c-lang-constants-under-evaluation + (cons source-pos c-lang-constants-under-evaluation)) + (fallback (get mode 'c-fallback-mode)) + value + ;; Make sure the recursion limits aren't very low + ;; since the `c-lang-const' dependencies can go deep. + (max-specpdl-size (max max-specpdl-size 3000)) + (max-lisp-eval-depth (max max-lisp-eval-depth 1000))) + + (if (if fallback + (let ((backup-source-pos (copy-sequence (cdr source-pos)))) + (and + ;; First try the original mode but don't accept an + ;; entry matching all languages since the fallback + ;; mode might have an explicit entry before that. + (eq (setq value (c-find-assignment-for-mode + (cdr source-pos) mode nil name)) + c-lang-constants) + ;; Try again with the fallback mode from the + ;; original position. Note that + ;; `c-buffer-is-cc-mode' still is the real mode if + ;; language parameterization takes place. + (eq (setq value (c-find-assignment-for-mode + (setcdr source-pos backup-source-pos) + fallback t name)) + c-lang-constants))) + ;; A simple lookup with no fallback mode. + (eq (setq value (c-find-assignment-for-mode + (cdr source-pos) mode t name)) + c-lang-constants)) + (error + "`%s' got no (prior) value in %s (might be a cyclic reference)" + name mode)) + + (condition-case err + (setq value (eval value)) + (error + ;; Print a message to aid in locating the error. We don't + ;; print the error itself since that will be done later by + ;; some caller higher up. + (message "Eval error in the `c-lang-defconst' for `%s' in %s:" + sym mode) + (makunbound sym) + (signal (car err) (cdr err)))) + + (set sym (cons (cons mode value) (symbol-value sym))) + value)))) + +(defun c-find-assignment-for-mode (source-pos mode match-any-lang name) + ;; Find the first assignment entry that applies to MODE at or after + ;; SOURCE-POS. If MATCH-ANY-LANG is non-nil, entries with `t' as + ;; the language list are considered to match, otherwise they don't. + ;; On return SOURCE-POS is updated to point to the next assignment + ;; after the returned one. If no assignment is found, + ;; `c-lang-constants' is returned as a magic value. + ;; + ;; SOURCE-POS is a vector that points out a specific assignment in + ;; the double alist that's used in the `source' property. The first + ;; element is the position in the top alist which is indexed with + ;; the source files, and the second element is the position in the + ;; nested bindings alist. + ;; + ;; NAME is only used for error messages. + + (catch 'found + (let ((file-entry (elt source-pos 0)) + (assignment-entry (elt source-pos 1)) + assignment) + + (while (if assignment-entry + t + ;; Handled the last assignment from one file, begin on the + ;; next. Due to the check in `c-lang-defconst', we know + ;; there's at least one. + (when file-entry + + (unless (aset source-pos 1 + (setq assignment-entry (cdar file-entry))) + ;; The file containing the source definitions has not + ;; been loaded. + (let ((file (symbol-name (caar file-entry))) + (c-lang-constants-under-evaluation nil)) + ;;(message (concat "Loading %s to get the source " + ;; "value for language constant %s") + ;; file name) + (load file)) + + (unless (setq assignment-entry (cdar file-entry)) + ;; The load didn't fill in the source for the + ;; constant as expected. The situation is + ;; probably that a derived mode was written for + ;; and compiled with another version of CC Mode, + ;; and the requested constant isn't in the + ;; currently loaded one. Put in a dummy + ;; assignment that matches no language. + (setcdr (car file-entry) + (setq assignment-entry (list (list nil)))))) + + (aset source-pos 0 (setq file-entry (cdr file-entry))) + t)) + + (setq assignment (car assignment-entry)) + (aset source-pos 1 + (setq assignment-entry (cdr assignment-entry))) + + (when (if (listp (car assignment)) + (memq mode (car assignment)) + match-any-lang) + (throw 'found (cdr assignment)))) + + c-lang-constants))) (cc-provide 'cc-defs)
--- a/lisp/progmodes/cc-engine.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-engine.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,9 @@ ;;; cc-engine.el --- core syntax guessing engine for CC mode -;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. - -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1992-1997 Barry A. Warsaw +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. + +;; Authors: 1998- Martin Stjernholm +;; 1992-1999 Barry A. Warsaw ;; 1987 Dave Detlefs and Stewart Clamen ;; 1985 Richard M. Stallman ;; Maintainer: bug-cc-mode@gnu.org @@ -41,6 +40,83 @@ ;; 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 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 etc. +;; +;; Interactive functions are assumed to not do hidden buffer changes +;; (this isn't applicable in the specific parts of them that do real +;; changes, though). +;; +;; All other functions are assumed to do hidden buffer changes and +;; must thus be wrapped inside `c-save-buffer-state' if they're used +;; from any function that does not do hidden buffer changes. +;; +;; Every function, except the interactive ones, that doesn't do hidden +;; buffer changes have that explicitly stated in their docstring or +;; comment. + +;; 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. +;; +;; 'syntax-table +;; Used to modify the syntax of some characters. Currently used to +;; mark the "<" and ">" of angle bracket parens with paren syntax. +;; +;; 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. It's 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 @@ -49,16 +125,56 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) (cc-require 'cc-defs) +(cc-require-when-compile 'cc-langs) (cc-require 'cc-vars) -(cc-require 'cc-langs) + +;; Some functions/constants in cc-awk.el that are called/referenced here. +;; (Can't use cc-require due to cyclicity.) +(cc-bytecomp-defun c-awk-unstick-NL-prop) +(cc-bytecomp-defun c-awk-clear-NL-props) +(cc-bytecomp-defvar awk-mode-syntax-table) +(cc-bytecomp-defun c-awk-backward-syntactic-ws) +(cc-bytecomp-defun c-awk-after-logical-semicolon) +(cc-bytecomp-defun c-awk-NL-prop-not-set) +(cc-bytecomp-defun c-awk-completed-stmt-ws-ends-line-p) +(cc-bytecomp-defun c-awk-completed-stmt-ws-ends-prev-line-p) +(cc-bytecomp-defun c-awk-prev-line-incomplete-p) +(cc-bytecomp-defun c-awk-after-change) ;; Silence the compiler. (cc-bytecomp-defun buffer-syntactic-context) ; XEmacs +;; 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) + +;; Internal state of auto newline feature. +(defvar c-auto-newline nil) +(make-variable-buffer-local 'c-auto-newline) + +;; Internal auto-newline/hungry-delete designation string for mode line. +(defvar c-auto-hungry-string nil) +(make-variable-buffer-local 'c-auto-hungry-string) + (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 @@ -68,9 +184,126 @@ (not prevstate) (> arg 0))) - +;; Dynamically bound cache for `c-in-literal'. (defvar c-in-literal-cache t) + +;; Must be set in buffers where the `c-type' text property might be used +;; with the value `c-decl-end'. +(defvar c-type-decl-end-used nil) +(make-variable-buffer-local 'c-type-decl-end-used) + + +;;; Basic utility functions. + +(defun c-syntactic-content (from to) + ;; Return the given region as a string where all syntactic + ;; whitespace is removed or, where necessary, replaced with a single + ;; space. + (save-excursion + (goto-char from) + (let* ((parts (list nil)) (tail parts) pos) + (while (re-search-forward c-syntactic-ws-start to t) + (goto-char (setq pos (match-beginning 0))) + (c-forward-syntactic-ws to) + (if (= (point) pos) + (forward-char) + (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))) + (setq from (point)))) + (setcdr tail (list (buffer-substring-no-properties from to))) + (apply 'concat (cdr parts))))) + +(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 start syntax. +(defconst c-string-limit-regexp (if (memq 'gen-string-delim c-emacs-features) + "\\s\"\\|\\s|" + "\\s\"")) + +;; 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) + ;; This function does not do any hidden buffer changes. + (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. +(defconst c-literal-faces + '(font-lock-comment-face font-lock-string-face)) + + +;; 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 @@ -78,6 +311,8 @@ ;; the byte compiler. (defvar c-maybe-labelp nil) +;; 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 () @@ -123,12 +358,12 @@ statements/declarations on the same level are considered, i.e. don't move into or out of sexps (not even normal expression parentheses). -Stop at statement continuations like \"else\", \"catch\", \"finally\" -and the \"while\" in \"do ... while\" if the start point is within -them. If starting at such a continuation, 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. +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 separate statements if IGNORE-LABELS is non-nil. The function is not overly intelligent in telling labels from other @@ -159,36 +394,84 @@ Normally only ';' is considered to delimit statements, but if COMMA-DELIM is non-nil then ',' is treated likewise." - ;; The bulk of this function is a pushdown automaton that looks at - ;; statement boundaries and the tokens in c-opt-block-stmt-key. + ;; 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 + ;; statments 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. ;; - ;; Begin with current token, stop when stack is empty and the - ;; position has been moved. + ;; 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': - ;; boundary: Goto state `else-boundary': - ;; "if": Pop state. - ;; boundary: Error, pop state. - ;; other: See common state. - ;; other: Error, pop state, retry token. - ;; "while": Push state, goto state `while': - ;; boundary: Save position, goto state `while-boundary': - ;; "do": Pop state. - ;; boundary: Restore position if it's not at start, pop state. - ;; other: See common state. - ;; other: Pop state, retry token. - ;; "catch" or "finally": Push state, goto state `catch': - ;; boundary: Goto state `catch-boundary': - ;; "try": Pop state. - ;; "catch": Goto state `catch'. - ;; boundary: Error, pop state. - ;; other: See common state. - ;; other: Error, pop state, retry token. + ;; "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. @@ -200,16 +483,17 @@ c-stmt-delim-chars-with-comma c-stmt-delim-chars)) pos ; Current position. - boundary-pos ; Position of last boundary. + boundary-pos ; Position of last stmt boundary character (e.g. ;). after-labels-pos ; Value of tok after first found colon. last-label-pos ; Value of tok after last found colon. - sym ; Current symbol in the alphabet. - state ; Current state in the automaton. - saved-pos ; Current saved positions. + sym ; Symbol just scanned back over (e.g. 'while or + ; 'boundary). See above + state ; Current state in the automaton. See above. + saved-pos ; Current saved positions. See above stack ; Stack of conses (state . saved-pos). - (cond-key (or c-opt-block-stmt-key + (cond-key (or c-opt-block-stmt-key ; regexp which matches "for", "if", etc. "\\<\\>")) ; Matches nothing. - (ret 'same) + (ret 'same) ; Return value. tok ptok pptok ; Pos of last three sexps or bounds. c-in-literal-cache c-maybe-labelp saved) @@ -221,24 +505,37 @@ (/= (point) start))) (setq macro-start (point))) - ;; Try to skip over unary operator characters, to register + ;; Try to skip back over unary operator characters, to register ;; that we've moved. (while (progn (setq pos (point)) - (c-backward-syntactic-ws) - (/= (skip-chars-backward "-+!*&~@`#") 0))) - - ;; First check for bare semicolon. Later on we ignore the - ;; boundaries for statements that doesn'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. + (c-backward-syntactic-ws) ; might go back an awk-mode virtual semicolon, here. + ; How about using c-awk-NL-prop for AWK Mode, here. + ; Something like c-awk-backward-syntactic-ws. + ; 2002/6/22. Doesn't matter! Leave it as it is. + (/= (skip-chars-backward "-+!*&~@`#") 0))) ; ACM, 2002/5/31; + ; Make a variable in + ; cc-langs.el, maybe + + ;; Skip back over any semicolon here. If it was a bare semicolon, we're + ;; done. Later on we ignore the boundaries for statements that doesn'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) + (if (c-mode-is-new-awk-p) + (c-awk-backward-syntactic-ws) + (c-backward-syntactic-ws)) (or (memq (char-before) delims) (memq (char-before) '(?: nil)) - (eq (char-syntax (char-before)) ?\()))) + (eq (char-syntax (char-before)) ?\() + (and (c-mode-is-new-awk-p) + (c-awk-after-logical-semicolon))))) ; ACM 2002/6/22 + ;; ACM, 2002/7/20: What about giving a limit to the above function? + ;; ACM, 2003/6/16: The above two lines (checking for + ;; awk-logical-semicolon) are probably redundant after rewriting + ;; c-awk-backward-syntactic-ws. (setq ret 'previous pos saved) @@ -249,18 +546,24 @@ ;; 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 scan-sexps approx 130 lines + ;; below. (while (catch 'loop ;; Throw nil to break, non-nil to continue. (cond - ;; Check for macro start. + ;; Check for macro start. Take this out for AWK Mode (ACM, 2002/5/31) + ;; NO!! just make sure macro-start is nil in AWK Mode (ACM, 2002/6/22) + ;; It always is (ACM, 2002/6/23) ((save-excursion (and macro-start - (looking-at "[ \t]*[a-zA-Z0-9!]") (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) @@ -275,8 +578,8 @@ ignore-labels t)) (throw 'loop nil)) - ;; Do a round through the automaton if we found a - ;; boundary or if looking at a statement keyword. + ;; 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))))) @@ -284,8 +587,20 @@ (when (and (< pos start) (null stack)) (throw 'loop nil)) - ;; The state handling. Continue in the common state for - ;; unhandled cases. + ;; The PDA state handling. + ;; + ;; Refer to the description of the PDA in the openining + ;; 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) @@ -309,14 +624,14 @@ (not after-labels-pos)) (progn (c-bos-save-pos) (setq state 'while-boundary)) - (c-bos-pop-state-and-retry))) + (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) - (c-bos-restore-pos) - (c-bos-pop-state)))) + ((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) @@ -334,22 +649,37 @@ (c-bos-report-error) (c-bos-pop-state))))) - ;; This is state common. + ;; This is state common. We get here when the previous + ;; cond statement found no particular state handler. (cond ((eq sym 'boundary) - (if (< pos start) - (c-bos-pop-state) - (c-bos-push-state))) + ;; 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) (when (or (not pptok) - (memq (char-after pptok) delims)) + (memq (char-after pptok) delims) + (and (c-mode-is-new-awk-p) + (or + ;; might we be calling this from + ;; c-awk-after-if-do-for-while-condition-p? + ;; If so, avoid infinite recursion. + (and (eq (point) start) + (c-awk-NL-prop-not-set)) + ;; The following may recursively + ;; call this function. + (c-awk-completed-stmt-ws-ends-line-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 semicolon it ;; can't be a do-while. + ;; ACM, 2002/5/31; IT CAN IN AWK Mode. ;-( (c-bos-push-state) (setq state 'while))) ((memq sym '(catch finally)) @@ -365,13 +695,21 @@ last-label-pos nil c-maybe-labelp nil)))) - ;; Step to next sexp, but not if we crossed a boundary, since - ;; that doesn't consume a sexp. + ;; Step to the previous sexp, but not if we crossed a + ;; boundary, since that doesn't consume an sexp. (if (eq sym 'boundary) (setq ret 'previous) + + ;; HERE IS THE SINGLE PLACE INSIDE THE PDA LOOP WHERE WE MOVE + ;; BACKWARDS THROUGH THE SOURCE. The following loop goes back + ;; one sexp and then only loops in special circumstances (line + ;; continuations and skipping past entire macros). (while (progn (or (c-safe (goto-char (scan-sexps (point) -1)) t) + ;; Give up if we hit an unbalanced block. + ;; Since the stack won't be empty the code + ;; below will report a suitable error. (throw 'loop nil)) (cond ((looking-at "\\\\$") ;; Step again if we hit a line continuation. @@ -380,7 +718,7 @@ ;; If we started inside a macro then this ;; sexp is always interesting. nil) - (t + ((not (c-mode-is-new-awk-p)) ; Changed from t, ACM 2002/6/25 ;; Otherwise check that we didn't step ;; into a macro from the end. (let ((macro-start @@ -391,22 +729,42 @@ (goto-char macro-start) t)))))) - ;; Check for statement boundary. + ;; Did the last movement by a sexp cross a statement boundary? (when (save-excursion (if (if (eq (char-after) ?{) (c-looking-at-inexpr-block lim nil) - (eq (char-syntax (char-after)) ?\()) - ;; Need to move over parens and - ;; in-expression blocks to get a good start - ;; position for the boundary check. - (c-forward-sexp 1)) + (looking-at "\\s\(")) + + ;; Should not include the paren sexp we've + ;; passed over in the boundary check. + (if (> (point) (- pos 100)) + (c-forward-sexp 1) + + ;; Find its end position this way instead of + ;; moving forward if the sexp is large. + (goto-char pos) + (while + (progn + (goto-char (1+ (c-down-list-backward))) + (unless macro-start + ;; Check that we didn't step into + ;; a macro from the end. + (let ((macro-start + (save-excursion + (and (c-beginning-of-macro) + (point))))) + (when macro-start + (goto-char macro-start) + t))))))) + (setq boundary-pos (c-crosses-statement-barrier-p (point) pos))) + (setq pptok ptok ptok tok tok boundary-pos sym 'boundary) - (throw 'loop t))) + (throw 'loop t))) ; like a C "continue". Analyze the next sexp. (when (and (numberp c-maybe-labelp) (not ignore-labels)) ;; c-crosses-statement-barrier-p has found a colon, so @@ -423,11 +781,12 @@ ignore-labels t) ; Avoid the label check on exit. (throw 'loop nil)) + ;; We've moved back by a sexp, so update the token positions. (setq sym nil pptok ptok ptok tok tok (point) - pos tok))) ; Not nil. + pos tok))) ; Not nil (for the while loop). ;; If the stack isn't empty there might be errors to report. (while stack @@ -446,7 +805,10 @@ (cond ((> start saved) (setq pos saved)) ((= start saved) (setq ret 'up))))) - (when (and c-maybe-labelp (not ignore-labels) after-labels-pos) + (when (and c-maybe-labelp + (not ignore-labels) + (not (eq ret 'beginning)) + after-labels-pos) ;; We're in a label. Maybe we should step to the statement ;; after it. (if (< after-labels-pos start) @@ -459,7 +821,7 @@ (goto-char pos) (while (progn (c-backward-syntactic-ws) - (/= (skip-chars-backward "-+!*&~@`#") 0)) + (/= (skip-chars-backward "-+!*&~@`#") 0)) ; Hopefully the # won't hurt awk. (setq pos (point))) (goto-char pos) ret))) @@ -467,7 +829,8 @@ (defun c-crosses-statement-barrier-p (from to) "Return non-nil if buffer positions FROM to TO cross one or more statement or declaration boundaries. The returned value is actually -the position of the earliest boundary char. +the position of the earliest boundary char. FROM must not be within +a string or comment. The variable `c-maybe-labelp' is set to the position of the first `:' that might start a label (i.e. not part of `::' and not preceded by `?'). If a @@ -479,8 +842,10 @@ (goto-char from) (while (progn (skip-chars-forward skip-chars to) (< (point) to)) - (if (setq lit-range (c-literal-limits from)) - (goto-char (setq from (cdr lit-range))) + (if (setq lit-range (c-literal-limits from)) ; Have we landed in a string/comment? + (progn (goto-char (setq from (cdr lit-range))) + (if (and (c-mode-is-new-awk-p) (bolp)) ; ACM 2002/7/17. Make sure we + (backward-char))) ; don't skip over a virtual semi-colon after an awk comment. :-( (cond ((eq (char-after) ?:) (forward-char) (if (and (eq (char-after) ?:) @@ -493,16 +858,164 @@ ;; looking for more : and ?. (setq c-maybe-labelp nil skip-chars (substring c-stmt-delim-chars 0 -2))) + ((and (eolp) ; Can only happen in AWK Mode + (not (c-awk-completed-stmt-ws-ends-line-p))) + (forward-char)) + ((and (c-mode-is-new-awk-p) + (bolp) lit-range ; awk: comment/string ended prev line. + (not (c-awk-completed-stmt-ws-ends-prev-line-p)))) (t (throw 'done (point)))))) nil)))) +;; A set of functions that covers various idiosyncrasies in +;; implementations of `forward-comment'. + +;; Note: Some emacsen considers incorrectly that any line comment +;; ending with a backslash continues to the next line. I can't think +;; of any way to work around that in a reliable way without changing +;; the buffer, though. Suggestions welcome. ;) (No, temporarily +;; changing the syntax for backslash doesn't work since we must treat +;; escapes in string literals correctly.) + +(defun c-forward-single-comment () + "Move forward past whitespace and the closest following comment, if any. +Return t if a comment was found, nil otherwise. In either case, the +point is moved past the following whitespace. Line continuations, +i.e. a backslashes followed by line breaks, are treated as whitespace. +The line breaks that end line comments are considered to be the +comment enders, so the point will be put on the beginning of the next +line if it moved past a line comment. + +This function does not do any hidden buffer changes." + + (let ((start (point))) + (when (looking-at "\\([ \t\n\r\f\v]\\|\\\\[\n\r]\\)+") + (goto-char (match-end 0))) + + (when (forward-comment 1) + (if (eobp) + ;; Some emacsen (e.g. XEmacs 21) return t when moving + ;; forwards at eob. + nil + + ;; Emacs includes the ending newline in a b-style (c++) + ;; comment, but XEmacs doesn't. We depend on the Emacs + ;; behavior (which also is symmetric). + (if (and (eolp) (elt (parse-partial-sexp start (point)) 7)) + (condition-case nil (forward-char 1))) + + t)))) + +(defsubst c-forward-comments () + "Move forward past all following whitespace and comments. +Line continuations, i.e. a backslashes followed by line breaks, are +treated as whitespace. + +This function does not do any hidden buffer changes." + + (while (or + ;; If forward-comment in at least XEmacs 21 is given a large + ;; positive value, it'll loop all the way through if it hits + ;; eob. + (and (forward-comment 5) + ;; Some emacsen (e.g. XEmacs 21) return t when moving + ;; forwards at eob. + (not (eobp))) + + (when (looking-at "\\\\[\n\r]") + (forward-char 2) + t)))) + +(defun c-backward-single-comment () + "Move backward past whitespace and the closest preceding comment, if any. +Return t if a comment was found, nil otherwise. In either case, the +point is moved past the preceding whitespace. Line continuations, +i.e. a backslashes followed by line breaks, are treated as whitespace. +The line breaks that end line comments are considered to be the +comment enders, so the point cannot be at the end of the same line to +move over a line comment. + +This function does not do any hidden buffer changes." + + (let ((start (point))) + ;; When we got newline terminated comments, forward-comment in all + ;; supported emacsen so far will stop at eol of each line not + ;; ending with a comment when moving backwards. This corrects for + ;; that, and at the same time handles line continuations. + (while (progn + (skip-chars-backward " \t\n\r\f\v") + (and (looking-at "[\n\r]") + (eq (char-before) ?\\) + (< (point) start))) + (backward-char)) + + (if (bobp) + ;; Some emacsen (e.g. Emacs 19.34) return t when moving + ;; backwards at bob. + nil + + ;; Leave point after the closest following newline if we've + ;; backed up over any above, since forward-comment won't move + ;; backward over a line comment if point is at the end of the + ;; same line. + (re-search-forward "\\=\\s *[\n\r]" start t) + + (if (if (forward-comment -1) + (if (eolp) + ;; If forward-comment above succeeded and we're at eol + ;; then the newline we moved over above didn't end a + ;; line comment, so we give it another go. + (forward-comment -1) + t)) + + ;; Emacs <= 20 and XEmacs move back over the closer of a + ;; block comment that lacks an opener. + (if (looking-at "\\*/") + (progn (forward-char 2) nil) + t))))) + +(defsubst c-backward-comments () + "Move backward past all preceding whitespace and comments. +Line continuations, i.e. a backslashes followed by line breaks, are +treated as whitespace. The line breaks that end line comments are +considered to be the comment enders, so the point cannot be at the end +of the same line to move over a line comment. + +This function does not do any hidden buffer changes." + + (let ((start (point))) + (while (and + ;; `forward-comment' in some emacsen (e.g. Emacs 19.34) + ;; return t when moving backwards at bob. + (not (bobp)) + + (if (forward-comment -1) + (if (looking-at "\\*/") + ;; Emacs <= 20 and XEmacs move back over the + ;; closer of a block comment that lacks an opener. + (progn (forward-char 2) nil) + t) + + ;; XEmacs treats line continuations as whitespace but + ;; only in the backward direction, which seems a bit + ;; odd. Anyway, this is necessary for Emacs. + (when (and (looking-at "[\n\r]") + (eq (char-before) ?\\) + (< (point) start)) + (backward-char) + t)))))) + + +;; 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. +;; `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 () + ;; This function does not do any hidden buffer changes. (if (symbolp c-macro-start) (setq c-macro-start (save-excursion (and (c-beginning-of-macro) @@ -510,6 +1023,7 @@ c-macro-start)) (defsubst c-query-macro-start () + ;; This function does not do any hidden buffer changes. (if (symbolp c-macro-start) (save-excursion (and (c-beginning-of-macro) @@ -517,26 +1031,31 @@ c-macro-start)) (defun c-beginning-of-macro (&optional lim) - "Go to the beginning of a cpp macro definition. -Leave point at the beginning of the macro and return t if in a cpp -macro definition, otherwise return nil and leave point unchanged." - (let ((here (point))) - (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 "#[ \t]*[a-zA-Z0-9!]")) - t - (goto-char here) - nil)))) + "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. + +This function does not do any hidden buffer changes." + (when c-opt-cpp-prefix + (let ((here (point))) + (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)) + t + (goto-char here) + nil))))) (defun c-end-of-macro () - "Go to the end of a cpp macro definition. + "Go to the end of a preprocessor directive. More accurately, move point to the end of the closest following line -that doesn't end with a line continuation backslash." +that doesn't end with a line continuation backslash. + +This function does not do any hidden buffer changes." (while (progn (end-of-line) (when (and (eq (char-before) ?\\) @@ -544,571 +1063,608 @@ (forward-char) t)))) -(defun c-forward-comment (count) - ;; Insulation from various idiosyncrasies in implementations of - ;; `forward-comment'. - ;; - ;; Note: Some emacsen considers incorrectly that any line comment - ;; ending with a backslash continues to the next line. I can't - ;; think of any way to work around that in a reliable way without - ;; changing the buffer, though. Suggestions welcome. ;) (No, - ;; temporarily changing the syntax for backslash doesn't work since - ;; we must treat escapes in string literals correctly.) - ;; - ;; Another note: When moving backwards over a block comment, there's - ;; a bug in forward-comment that can make it stop at "/*" inside a - ;; line comment. Haven't yet found a reasonably cheap way to kludge - ;; around that one either. :\ - (let ((here (point))) - (if (>= count 0) - (when (forward-comment count) - (if (eobp) - ;; Some emacsen (e.g. XEmacs 21) return t when moving - ;; forwards at eob. - nil - ;; Emacs includes the ending newline in a b-style (c++) - ;; comment, but XEmacs doesn't. We depend on the Emacs - ;; behavior (which also is symmetric). - (if (and (eolp) (nth 7 (parse-partial-sexp here (point)))) - (condition-case nil (forward-char 1))) - t)) - ;; When we got newline terminated comments, - ;; forward-comment in all supported emacsen so far will - ;; stop at eol of each line not ending with a comment when - ;; moving backwards. The following corrects for it when - ;; count is -1. The other common case, when count is - ;; large and negative, works regardless. It's too much - ;; work to correct for the rest of the cases. - (skip-chars-backward " \t\n\r\f") - (if (bobp) - ;; Some emacsen return t when moving backwards at bob. - nil - (re-search-forward "[\n\r]" here t) - (let* ((res (if (forward-comment count) - (if (eolp) (forward-comment -1) t))) - (savepos (point))) - ;; XEmacs treats line continuations as whitespace (but only - ;; in the backward direction). - (while (and (progn (end-of-line) (< (point) here)) - (eq (char-before) ?\\)) - (setq res nil - savepos (point)) - (forward-line)) - (goto-char savepos) - res))))) - -(defun c-forward-comment-lc (count) - ;; Like `c-forward-comment', but treat line continuations as - ;; whitespace. - (catch 'done - (if (> count 0) - (while (if (c-forward-comment 1) - (progn - (setq count (1- count)) - (> count 0)) - (if (looking-at "\\\\$") - (progn - (forward-char) - t) - (throw 'done nil)))) - (while (if (c-forward-comment -1) - (progn - (setq count (1+ count)) - (< count 0)) - (if (and (eolp) (eq (char-before) ?\\)) - (progn - (backward-char) - t) - (throw 'done nil))))) - t)) - -(defun c-forward-syntactic-ws (&optional lim) - "Forward skip of syntactic whitespace. -Syntactic whitespace is defined as whitespace characters, comments, -and preprocessor directives. However if point starts inside a comment -or preprocessor directive, the content of it is not treated as -whitespace. LIM sets an upper limit of the forward movement, if -specified." - (let ((here (point-max))) - (or lim (setq lim here)) - (while (/= here (point)) - ;; If forward-comment in at least XEmacs 21 is given a large - ;; positive value, it'll loop all the way through if it hits eob. - (while (c-forward-comment 5)) - (setq here (point)) - (cond - ;; Skip line continuations. - ((looking-at "\\\\$") - (forward-char)) - ;; Skip preprocessor directives. - ((and (looking-at "#[ \t]*[a-zA-Z0-9!]") - (save-excursion - (skip-chars-backward " \t") - (bolp))) - (end-of-line) - (while (and (<= (point) lim) - (eq (char-before) ?\\) - (= (forward-line 1) 0)) - (end-of-line)) - (when (> (point) lim) - ;; Don't move past the macro if that'd take us past the limit. - (goto-char here))) - ;; Skip in-comment line continuations (used for Pike refdoc). - ((and c-opt-in-comment-lc (looking-at c-opt-in-comment-lc)) - (goto-char (match-end 0))))) - (goto-char (min (point) lim)))) - -(defun c-backward-syntactic-ws (&optional lim) - "Backward skip of syntactic whitespace. -Syntactic whitespace is defined as whitespace characters, comments, -and preprocessor directives. However if point starts inside a comment -or preprocessor directive, the content of it is not treated as -whitespace. LIM sets a lower limit of the backward movement, if -specified." - (let ((start-line (c-point 'bol)) - (here (point-min)) - (line-cont 'maybe) - prev-pos) - (or lim (setq lim here)) - (while (/= here (point)) - (setq prev-pos (point)) - ;; If forward-comment in Emacs 19.34 is given a large negative - ;; value, it'll loop all the way through if it hits bob. - (while (c-forward-comment -5)) - (setq here (point)) - (cond - ((and (eolp) - (eq (char-before) ?\\) - (if (<= prev-pos (c-point 'eonl)) - t - ;; Passed a line continuation, but not from the line we - ;; started on. - (forward-char) - (setq line-cont nil))) - (backward-char) - (setq line-cont t)) - ((progn - (when (eq line-cont 'maybe) - (save-excursion - (end-of-line) - (setq line-cont (eq (char-before) ?\\)))) - (or line-cont - (and (< (point) start-line) - (c-beginning-of-macro)))) - (if (< (point) lim) - ;; Don't move past the macro if we began inside it or at - ;; the end of the same line, or if the move would take us - ;; past the limit. - (goto-char here)) - (setq line-cont nil)) - ;; Skip in-comment line continuations (used for Pike refdoc). - ((and c-opt-in-comment-lc - (save-excursion - (and (c-safe (beginning-of-line) - (backward-char 2) - t) - (looking-at c-opt-in-comment-lc) - (eq (match-end 0) here)))) - (goto-char (match-beginning 0))))) - (goto-char (max (point) lim)))) - -(defun c-forward-token-1 (&optional count balanced lim) - "Move forward by tokens. -A token is defined as all symbols and identifiers which aren't -syntactic whitespace \(note that e.g. \"->\" is considered to be two -tokens). Point is always either left at the beginning of a token or -not moved at all. COUNT specifies the number of tokens to move; a -negative COUNT moves in the opposite direction. A COUNT of 0 moves to -the next token beginning only if not already at one. If BALANCED is -true, move over balanced parens, otherwise move into them. Also, if -BALANCED is true, never move out of an enclosing paren. LIM sets the -limit for the movement and defaults to the point limit. - -Return the number of tokens left to move \(positive or negative). If -BALANCED is true, a move over a balanced paren counts as one. Note -that if COUNT is 0 and no appropriate token beginning is found, 1 will -be returned. Thus, a return value of 0 guarantees that point is at -the requested position and a return value less \(without signs) than -COUNT guarantees that point is at the beginning of some token." - (or count (setq count 1)) - (if (< count 0) - (- (c-backward-token-1 (- count) balanced lim)) - (let ((jump-syntax (if balanced - '(?w ?_ ?\( ?\) ?\" ?\\ ?/ ?$ ?') - '(?w ?_ ?\" ?\\ ?/ ?'))) - (last (point)) - (prev (point))) - (save-restriction - (if lim (narrow-to-region (point-min) lim)) - (if (/= (point) - (progn (c-forward-syntactic-ws) (point))) - ;; Skip whitespace. Count this as a move if we did in fact - ;; move and aren't out of bounds. - (or (eobp) - (setq count (max (1- count) 0)))) - (if (and (= count 0) - (or (and (memq (char-syntax (or (char-after) ? )) '(?w ?_)) - (memq (char-syntax (or (char-before) ? )) '(?w ?_))) - (eobp))) - ;; If count is zero we should jump if in the middle of a - ;; token or if there is whitespace between point and the - ;; following token beginning. - (setq count 1)) - (if (eobp) - (goto-char last) - ;; Avoid having the limit tests inside the loop. - (condition-case nil - (while (> count 0) - (setq prev last - last (point)) - (if (memq (char-syntax (char-after)) jump-syntax) - (goto-char (scan-sexps (point) 1)) - (forward-char)) - (c-forward-syntactic-ws) - (setq count (1- count))) - (error (goto-char last))) - (when (eobp) - (goto-char prev) - (setq count (1+ count))))) - count))) - -(defun c-backward-token-1 (&optional count balanced lim) - "Move backward by tokens. -See `c-forward-token-1' for details." - (or count (setq count 1)) - (if (< count 0) - (- (c-forward-token-1 (- count) balanced lim)) - (let ((jump-syntax (if balanced - '(?w ?_ ?\( ?\) ?\" ?\\ ?/ ?$ ?') - '(?w ?_ ?\" ?\\ ?/ ?'))) - last) - (if (and (= count 0) - (or (and (memq (char-syntax (or (char-after) ? )) '(?w ?_)) - (memq (char-syntax (or (char-before) ? )) '(?w ?_))) - (/= (point) - (save-excursion - (c-forward-syntactic-ws (1+ lim)) - (point))) - (eobp))) - ;; If count is zero we should jump if in the middle of a - ;; token or if there is whitespace between point and the - ;; following token beginning. - (setq count 1)) - (save-restriction - (if lim (narrow-to-region lim (point-max))) - (or (bobp) - (progn - ;; Avoid having the limit tests inside the loop. - (condition-case nil - (while (progn - (setq last (point)) - (> count 0)) - (c-backward-syntactic-ws) - (if (memq (char-syntax (char-before)) jump-syntax) - (goto-char (scan-sexps (point) -1)) - (backward-char)) - (setq count (1- count))) - (error (goto-char last))) - (if (bobp) (goto-char last))))) - count))) - -(defun c-syntactic-re-search-forward (regexp &optional bound noerror count - paren-level) - ;; Like `re-search-forward', but only report matches that are found - ;; in syntactically significant text. I.e. matches that begins in - ;; comments, macros or string literals are ignored. The start point - ;; is assumed to be outside any comment, macro or string literal, or - ;; else the content of that region is taken as syntactically - ;; significant text. If PAREN-LEVEL is non-nil, an additional - ;; restriction is added to ignore matches in nested paren sexps, and - ;; the search will also not go outside the current paren sexp. - (or bound (setq bound (point-max))) - (or count (setq count 1)) - (if paren-level (setq paren-level -1)) - (let ((start (point)) - (pos (point)) - match-pos state) - (condition-case err - (while (and (> count 0) - (re-search-forward regexp bound noerror)) - (setq match-pos (point) - state (parse-partial-sexp pos (match-beginning 0) - paren-level nil state) - pos (point)) - (cond ((nth 3 state) - ;; Match inside a string. Skip to the end of it - ;; before continuing. - (let ((ender (make-string 1 (nth 3 state)))) - (while (progn - (search-forward ender bound noerror) - (setq state (parse-partial-sexp pos (point) - nil nil state) - pos (point)) - (nth 3 state))))) - ((nth 7 state) - ;; Match inside a line comment. Skip to eol. Use - ;; re-search-forward for it to get the right bound - ;; behavior. - (re-search-forward "[\n\r]" bound noerror)) - ((nth 4 state) - ;; Match inside a block comment. Skip to the '*/'. - (re-search-forward "\\*/" bound noerror)) - ((save-excursion (c-beginning-of-macro start)) - ;; Match inside a macro. Skip to the end of it. - (c-end-of-macro)) - ((and paren-level (/= (car state) 0)) - (if (> (car state) 0) - ;; Match inside a nested paren sexp. Skip out of it. - (setq state (parse-partial-sexp pos bound 0 nil state) - pos (point)) - ;; Have exited the current paren sexp. The - ;; parse-partial-sexp above has left us just after - ;; the closing paren in this case. Just make - ;; re-search-forward above fail in the appropriate - ;; way; we'll adjust the leave off point below if - ;; necessary. - (setq bound (point)))) - (t - ;; A real match. - (setq count (1- count))))) - (error - (goto-char start) - (signal (car err) (cdr err)))) - (if (= count 0) - (progn - (goto-char match-pos) - match-pos) - ;; Search failed. Set point as appropriate. - (cond ((eq noerror t) - (goto-char start)) - (paren-level - (if (eq (car (parse-partial-sexp pos bound -1 nil state)) -1) - (backward-char))) - (t - (goto-char bound))) - nil))) +(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". Non-nil is returned in this case, in all + ;; other cases nil is returned and point isn't moved. + (when (and (looking-at + (concat "#[ \t]*" + "define[ \t]+\\(\\sw\\|_\\)+\\(\([^\)]*\)\\)?" + "\\([ \t]\\|\\\\\n\\)*")) + (not (= (match-end 0) (c-point 'eol)))) + (goto-char (match-end 0)))) -(defun c-in-literal (&optional lim detect-cpp) - "Return the type of literal point is in, if any. -The return value is `c' if in a C-style comment, `c++' if in a C++ -style comment, `string' if in a string literal, `pound' if DETECT-CPP -is non-nil and on a preprocessor line, or nil if somewhere else. -Optional LIM is used as the backward limit of the search. If omitted, -or nil, `c-beginning-of-defun' is used. - -The last point calculated is cached if the cache is enabled, i.e. if -`c-in-literal-cache' is bound to a two element vector." - (if (and (vectorp c-in-literal-cache) - (= (point) (aref c-in-literal-cache 0))) - (aref c-in-literal-cache 1) - (let ((rtn (save-excursion - (let* ((lim (or lim (c-point 'bod))) - (state (parse-partial-sexp lim (point)))) - (cond - ((nth 3 state) 'string) - ((nth 4 state) (if (nth 7 state) 'c++ 'c)) - ((and detect-cpp (c-beginning-of-macro lim)) 'pound) - (t nil)))))) - ;; cache this result if the cache is enabled - (if (not c-in-literal-cache) - (setq c-in-literal-cache (vector (point) rtn))) - rtn))) - -;; XEmacs has a built-in function that should make this much quicker. -;; I don't think we even need the cache, which makes our lives more -;; complicated anyway. In this case, lim is only used to detect -;; cpp directives. -(defun c-fast-in-literal (&optional lim detect-cpp) - (let ((context (buffer-syntactic-context))) - (cond - ((eq context 'string) 'string) - ((eq context 'comment) 'c++) - ((eq context 'block-comment) 'c) - ((and detect-cpp (save-excursion (c-beginning-of-macro lim))) 'pound)))) - -(if (fboundp 'buffer-syntactic-context) - (defalias 'c-in-literal 'c-fast-in-literal)) - -(defun c-literal-limits (&optional lim near not-in-delimiter) - "Return a cons of the beginning and end positions of the comment or -string surrounding point (including both delimiters), or nil if point -isn't in one. If LIM is non-nil, it's used as the \"safe\" position -to start parsing from. If NEAR is non-nil, then the limits of any -literal next to point is returned. \"Next to\" means there's only [ -\t] between point and the literal. The search for such a literal is -done first in forward direction. If NOT-IN-DELIMITER is non-nil, the -case when point is inside a starting delimiter won't be recognized. -This only has effect for comments, which have starting delimiters with -more than one character." +;; Tools for skipping over syntactic whitespace. + +;; The following functions use text properties to cache searches over +;; large regions of syntactic whitespace. It works as follows: +;; +;; o If a syntactic whitespace region contains anything but simple +;; whitespace (i.e. space, tab and line breaks), the text property +;; `c-in-sws' is put over it. At places where we have stopped +;; within that region there's also a `c-is-sws' text property. +;; That since there typically are nested whitespace inside that +;; must be handled separately, e.g. whitespace inside a comment or +;; cpp directive. Thus, from one point with `c-is-sws' it's safe +;; to jump to another point with that property within the same +;; `c-in-sws' region. It can be likened to a ladder where +;; `c-in-sws' marks the bars and `c-is-sws' the rungs. +;; +;; o The `c-is-sws' property is put on the simple whitespace chars at +;; a "rung position" and also maybe on the first following char. +;; As many characters as can be conveniently found in this range +;; are marked, but no assumption can be made that the whole range +;; is marked (it could be clobbered by later changes, for +;; instance). +;; +;; Note that some part of the beginning of a sequence of simple +;; whitespace might be part of the end of a preceding line comment +;; or cpp directive and must not be considered part of the "rung". +;; Such whitespace is some amount of horizontal whitespace followed +;; by a newline. In the case of cpp directives it could also be +;; two newlines with horizontal whitespace between them. +;; +;; The reason to include the first following char is to cope with +;; "rung positions" that doesn't have any ordinary whitespace. If +;; `c-is-sws' is put on a token character it does not have +;; `c-in-sws' set simultaneously. That's the only case when that +;; can occur, and the reason for not extending the `c-in-sws' +;; region to cover it is that the `c-in-sws' region could then be +;; accidentally merged with a following one if the token is only +;; one character long. +;; +;; o On buffer changes the `c-in-sws' and `c-is-sws' properties are +;; removed in the changed region. If the change was inside +;; syntactic whitespace that means that the "ladder" is broken, but +;; a later call to `c-forward-sws' or `c-backward-sws' will use the +;; parts on either side and use an ordinary search only to "repair" +;; the gap. +;; +;; Special care needs to be taken if a region is removed: If there +;; are `c-in-sws' on both sides of it which do not connect inside +;; the region then they can't be joined. If e.g. a marked macro is +;; broken, syntactic whitespace inside the new text might be +;; marked. If those marks would become connected with the old +;; `c-in-sws' range around the macro then we could get a ladder +;; with one end outside the macro and the other at some whitespace +;; within it. +;; +;; The main motivation for this system is to increase the speed in +;; skipping over the large whitespace regions that can occur at the +;; top level in e.g. header files that contain a lot of comments and +;; cpp directives. For small comments inside code it's probably +;; slower than using `forward-comment' straightforwardly, but speed is +;; not a significant factor there anyway. + +; (defface c-debug-is-sws-face +; '((t (:background "GreenYellow"))) +; "Debug face to mark the `c-is-sws' property.") +; (defface c-debug-in-sws-face +; '((t (:underline t))) +; "Debug face to mark the `c-in-sws' property.") + +; (defun c-debug-put-sws-faces () +; ;; Put the sws debug faces on all the `c-is-sws' and `c-in-sws' +; ;; properties in the buffer. +; (interactive) +; (save-excursion +; (let (in-face) +; (goto-char (point-min)) +; (setq in-face (if (get-text-property (point) 'c-is-sws) +; (point))) +; (while (progn +; (goto-char (next-single-property-change +; (point) 'c-is-sws nil (point-max))) +; (if in-face +; (progn +; (c-debug-add-face in-face (point) 'c-debug-is-sws-face) +; (setq in-face nil)) +; (setq in-face (point))) +; (not (eobp)))) +; (goto-char (point-min)) +; (setq in-face (if (get-text-property (point) 'c-in-sws) +; (point))) +; (while (progn +; (goto-char (next-single-property-change +; (point) 'c-in-sws nil (point-max))) +; (if in-face +; (progn +; (c-debug-add-face in-face (point) 'c-debug-in-sws-face) +; (setq in-face nil)) +; (setq in-face (point))) +; (not (eobp))))))) + +(defmacro c-debug-sws-msg (&rest args) + ;;`(message ,@args) + ) + +(defmacro c-put-is-sws (beg end) + `(let ((beg ,beg) (end ,end)) + (put-text-property beg end 'c-is-sws t) + ,@(when (facep 'c-debug-is-sws-face) + `((c-debug-add-face beg end 'c-debug-is-sws-face))))) + +(defmacro c-put-in-sws (beg end) + `(let ((beg ,beg) (end ,end)) + (put-text-property beg end 'c-in-sws t) + ,@(when (facep 'c-debug-is-sws-face) + `((c-debug-add-face beg end 'c-debug-in-sws-face))))) + +(defmacro c-remove-is-sws (beg end) + `(let ((beg ,beg) (end ,end)) + (remove-text-properties beg end '(c-is-sws nil)) + ,@(when (facep 'c-debug-is-sws-face) + `((c-debug-remove-face beg end 'c-debug-is-sws-face))))) + +(defmacro c-remove-in-sws (beg end) + `(let ((beg ,beg) (end ,end)) + (remove-text-properties beg end '(c-in-sws nil)) + ,@(when (facep 'c-debug-is-sws-face) + `((c-debug-remove-face beg end 'c-debug-in-sws-face))))) + +(defmacro c-remove-is-and-in-sws (beg end) + `(let ((beg ,beg) (end ,end)) + (remove-text-properties beg end '(c-is-sws nil c-in-sws nil)) + ,@(when (facep 'c-debug-is-sws-face) + `((c-debug-remove-face beg end 'c-debug-is-sws-face) + (c-debug-remove-face beg end 'c-debug-in-sws-face))))) + +(defsubst c-invalidate-sws-region-after (beg end) + ;; Called from `after-change-functions'. Note that if + ;; `c-forward-sws' or `c-backward-sws' are used outside + ;; `c-save-buffer-state' or similar then this will remove the cache + ;; properties right after they're added. + (save-excursion - (let* ((pos (point)) - (lim (or lim (c-point 'bod))) - (state (parse-partial-sexp lim (point)))) - (cond ((nth 3 state) - ;; String. Search backward for the start. - (while (nth 3 state) - (search-backward (make-string 1 (nth 3 state))) - (setq state (parse-partial-sexp lim (point)))) - (cons (point) (or (c-safe (c-forward-sexp 1) (point)) - (point-max)))) - ((nth 7 state) - ;; Line comment. Search from bol for the comment starter. - (beginning-of-line) - (setq state (parse-partial-sexp lim (point)) - lim (point)) - (while (not (nth 7 state)) - (search-forward "//") ; Should never fail. - (setq state (parse-partial-sexp - lim (point) nil nil state) - lim (point))) - (backward-char 2) - (cons (point) (progn (c-forward-comment 1) (point)))) - ((nth 4 state) - ;; Block comment. Search backward for the comment starter. - (while (nth 4 state) - (search-backward "/*") ; Should never fail. - (setq state (parse-partial-sexp lim (point)))) - (cons (point) (progn (c-forward-comment 1) (point)))) - ((and (not not-in-delimiter) - (not (nth 5 state)) - (eq (char-before) ?/) - (looking-at "[/*]")) - ;; We're standing in a comment starter. - (backward-char 1) - (cons (point) (progn (c-forward-comment 1) (point)))) - (near - (goto-char pos) - ;; Search forward for a literal. - (skip-chars-forward " \t") - (cond - ((eq (char-syntax (or (char-after) ?\ )) ?\") ; String. - (cons (point) (or (c-safe (c-forward-sexp 1) (point)) - (point-max)))) - ((looking-at "/[/*]") ; Line or block comment. - (cons (point) (progn (c-forward-comment 1) (point)))) + ;; Adjust the end to remove the properties in any following simple + ;; ws up to and including the next line break, if there is any + ;; after the changed region. This is necessary e.g. when a rung + ;; marked empty line is converted to a line comment by inserting + ;; "//" before the line break. In that case the line break would + ;; keep the rung mark which could make a later `c-backward-sws' + ;; move into the line comment instead of over it. + (goto-char end) + (skip-chars-forward " \t\f\v") + (when (and (eolp) (not (eobp))) + (setq end (1+ (point))))) + + (when (and (= beg end) + (get-text-property beg 'c-in-sws) + (not (bobp)) + (get-text-property (1- beg) 'c-in-sws)) + ;; Ensure that an `c-in-sws' range gets broken. Note that it isn't + ;; safe to keep a range that was continuous before the change. E.g: + ;; + ;; #define foo + ;; \ + ;; bar + ;; + ;; There can be a "ladder" between "#" and "b". Now, if the newline + ;; after "foo" is removed then "bar" will become part of the cpp + ;; directive instead of a syntactically relevant token. In that + ;; case there's no longer syntactic ws from "#" to "b". + (setq beg (1- beg))) + + (c-debug-sws-msg "c-invalidate-sws-region-after [%s..%s]" beg end) + (c-remove-is-and-in-sws beg end)) + +(defun c-forward-sws () + ;; Used by `c-forward-syntactic-ws' to implement the unbounded search. + + (let (;; `rung-pos' is set to a position as early as possible in the + ;; unmarked part of the simple ws region. + (rung-pos (point)) next-rung-pos rung-end-pos last-put-in-sws-pos + rung-is-marked next-rung-is-marked simple-ws-end + ;; `safe-start' is set when it's safe to cache the start position. + ;; It's not set if we've initially skipped over comments and line + ;; continuations since we might have gone out through the end of a + ;; macro then. This provision makes `c-forward-sws' not populate the + ;; cache in the majority of cases, but otoh is `c-backward-sws' by far + ;; more common. + safe-start) + + ;; Skip simple ws and do a quick check on the following character to see + ;; if it's anything that can't start syntactic ws, so we can bail out + ;; early in the majority of cases when there just are a few ws chars. + (skip-chars-forward " \t\n\r\f\v") + (when (looking-at c-syntactic-ws-start) + + (setq rung-end-pos (min (1+ (point)) (point-max))) + (if (setq rung-is-marked (text-property-any rung-pos rung-end-pos + 'c-is-sws t)) + ;; Find the last rung position to avoid setting properties in all + ;; the cases when the marked rung is complete. + ;; (`next-single-property-change' is certain to move at least one + ;; step forward.) + (setq rung-pos (1- (next-single-property-change + rung-is-marked 'c-is-sws nil rung-end-pos))) + ;; Got no marked rung here. Since the simple ws might have started + ;; inside a line comment or cpp directive we must set `rung-pos' as + ;; high as possible. + (setq rung-pos (point))) + + (while + (progn + (while + (when (and rung-is-marked + (get-text-property (point) 'c-in-sws)) + + ;; The following search is the main reason that `c-in-sws' + ;; and `c-is-sws' aren't combined to one property. + (goto-char (next-single-property-change + (point) 'c-in-sws nil (point-max))) + (unless (get-text-property (point) 'c-is-sws) + ;; If the `c-in-sws' region extended past the last + ;; `c-is-sws' char we have to go back a bit. + (or (get-text-property (1- (point)) 'c-is-sws) + (goto-char (previous-single-property-change + (point) 'c-is-sws))) + (backward-char)) + + (c-debug-sws-msg + "c-forward-sws cached move %s -> %s (max %s)" + rung-pos (point) (point-max)) + + (setq rung-pos (point)) + (and (> (skip-chars-forward " \t\n\r\f\v") 0) + (not (eobp)))) + + ;; We'll loop here if there is simple ws after the last rung. + ;; That means that there's been some change in it and it's + ;; possible that we've stepped into another ladder, so extend + ;; the previous one to join with it if there is one, and try to + ;; use the cache again. + (c-debug-sws-msg + "c-forward-sws extending rung with [%s..%s] (max %s)" + (1+ rung-pos) (1+ (point)) (point-max)) + (unless (get-text-property (point) 'c-is-sws) + ;; Remove any `c-in-sws' property from the last char of + ;; the rung before we mark it with `c-is-sws', so that we + ;; won't connect with the remains of a broken "ladder". + (c-remove-in-sws (point) (1+ (point)))) + (c-put-is-sws (1+ rung-pos) + (1+ (point))) + (c-put-in-sws rung-pos + (setq rung-pos (point) + last-put-in-sws-pos rung-pos))) + + (setq simple-ws-end (point)) + (c-forward-comments) + + (cond + ((/= (point) simple-ws-end) + ;; Skipped over comments. Don't cache at eob in case the buffer + ;; is narrowed. + (not (eobp))) + + ((save-excursion + (and c-opt-cpp-prefix + (looking-at c-opt-cpp-start) + (progn (skip-chars-backward " \t") + (bolp)) + (or (bobp) + (progn (backward-char) + (not (eq (char-before) ?\\)))))) + ;; Skip a preprocessor directive. + (end-of-line) + (while (and (eq (char-before) ?\\) + (= (forward-line 1) 0)) + (end-of-line)) + (forward-line 1) + (setq safe-start t) + ;; Don't cache at eob in case the buffer is narrowed. + (not (eobp))))) + + ;; We've searched over a piece of non-white syntactic ws. See if this + ;; can be cached. + (setq next-rung-pos (point)) + (skip-chars-forward " \t\n\r\f\v") + (setq rung-end-pos (min (1+ (point)) (point-max))) + + (if (or + ;; Cache if we haven't skipped comments only, and if we started + ;; either from a marked rung or from a completely uncached + ;; position. + (and safe-start + (or rung-is-marked + (not (get-text-property simple-ws-end 'c-in-sws)))) + + ;; See if there's a marked rung in the encountered simple ws. If + ;; so then we can cache, unless `safe-start' is nil. Even then + ;; we need to do this to check if the cache can be used for the + ;; next step. + (and (setq next-rung-is-marked + (text-property-any next-rung-pos rung-end-pos + 'c-is-sws t)) + safe-start)) + + (progn + (c-debug-sws-msg + "c-forward-sws caching [%s..%s] - [%s..%s] (max %s)" + rung-pos (1+ simple-ws-end) next-rung-pos rung-end-pos + (point-max)) + + ;; Remove the properties for any nested ws that might be cached. + ;; Only necessary for `c-is-sws' since `c-in-sws' will be set + ;; anyway. + (c-remove-is-sws (1+ simple-ws-end) next-rung-pos) + (unless (and rung-is-marked (= rung-pos simple-ws-end)) + (c-put-is-sws rung-pos + (1+ simple-ws-end)) + (setq rung-is-marked t)) + (c-put-in-sws rung-pos + (setq rung-pos (point) + last-put-in-sws-pos rung-pos)) + (unless (get-text-property (1- rung-end-pos) 'c-is-sws) + ;; Remove any `c-in-sws' property from the last char of + ;; the rung before we mark it with `c-is-sws', so that we + ;; won't connect with the remains of a broken "ladder". + (c-remove-in-sws (1- rung-end-pos) rung-end-pos)) + (c-put-is-sws next-rung-pos + rung-end-pos)) + + (c-debug-sws-msg + "c-forward-sws not caching [%s..%s] - [%s..%s] (max %s)" + rung-pos (1+ simple-ws-end) next-rung-pos rung-end-pos + (point-max)) + + ;; Set `rung-pos' for the next rung. It's the same thing here as + ;; initially, except that the rung position is set as early as + ;; possible since we can't be in the ending ws of a line comment or + ;; cpp directive now. + (if (setq rung-is-marked next-rung-is-marked) + (setq rung-pos (1- (next-single-property-change + rung-is-marked 'c-is-sws nil rung-end-pos))) + (setq rung-pos next-rung-pos)) + (setq safe-start t))) + + ;; Make sure that the newly marked `c-in-sws' region doesn't connect to + ;; another one after the point (which might occur when editing inside a + ;; comment or macro). + (when (eq last-put-in-sws-pos (point)) + (cond ((< last-put-in-sws-pos (point-max)) + (c-debug-sws-msg + "c-forward-sws clearing at %s for cache separation" + last-put-in-sws-pos) + (c-remove-in-sws last-put-in-sws-pos + (1+ last-put-in-sws-pos))) (t - ;; Search backward. - (skip-chars-backward " \t") - (let ((end (point)) beg) - (cond - ((eq (char-syntax (or (char-before) ?\ )) ?\") ; String. - (setq beg (c-safe (c-backward-sexp 1) (point)))) - ((and (c-safe (forward-char -2) t) - (looking-at "*/")) - ;; Block comment. Due to the nature of line - ;; comments, they will always be covered by the - ;; normal case above. - (goto-char end) - (c-forward-comment -1) - ;; If LIM is bogus, beg will be bogus. - (setq beg (point)))) - (if beg (cons beg end)))))) - )))) - -(defun c-literal-limits-fast (&optional lim near not-in-delimiter) - ;; Like c-literal-limits, but for emacsen whose `parse-partial-sexp' - ;; returns the pos of the comment start. - (save-excursion - (let* ((pos (point)) - (lim (or lim (c-point 'bod))) - (state (parse-partial-sexp lim (point)))) - (cond ((nth 3 state) ; String. - (goto-char (nth 8 state)) - (cons (point) (or (c-safe (c-forward-sexp 1) (point)) - (point-max)))) - ((nth 4 state) ; Comment. - (goto-char (nth 8 state)) - (cons (point) (progn (c-forward-comment 1) (point)))) - ((and (not not-in-delimiter) - (not (nth 5 state)) - (eq (char-before) ?/) - (looking-at "[/*]")) - ;; We're standing in a comment starter. - (backward-char 1) - (cons (point) (progn (c-forward-comment 1) (point)))) - (near - (goto-char pos) - ;; Search forward for a literal. - (skip-chars-forward " \t") - (cond - ((eq (char-syntax (or (char-after) ?\ )) ?\") ; String. - (cons (point) (or (c-safe (c-forward-sexp 1) (point)) - (point-max)))) - ((looking-at "/[/*]") ; Line or block comment. - (cons (point) (progn (c-forward-comment 1) (point)))) - (t - ;; Search backward. - (skip-chars-backward " \t") - (let ((end (point)) beg) - (cond - ((eq (char-syntax (or (char-before) ?\ )) ?\") ; String. - (setq beg (c-safe (c-backward-sexp 1) (point)))) - ((and (c-safe (forward-char -2) t) - (looking-at "*/")) - ;; Block comment. Due to the nature of line - ;; comments, they will always be covered by the - ;; normal case above. - (goto-char end) - (c-forward-comment -1) - ;; If LIM is bogus, beg will be bogus. - (setq beg (point)))) - (if beg (cons beg end)))))) - )))) - -(if (c-safe (> (length (save-excursion (parse-partial-sexp 1 1))) 8)) - (defalias 'c-literal-limits 'c-literal-limits-fast)) - -(defun c-collect-line-comments (range) - "If the argument is a cons of two buffer positions (such as returned by -`c-literal-limits'), and that range contains a C++ style line comment, -then an extended range is returned that contains all adjacent line -comments (i.e. all comments that starts in the same column with no -empty lines or non-whitespace characters between them). Otherwise the -argument is returned." - (save-excursion - (condition-case nil - (if (and (consp range) (progn - (goto-char (car range)) - (looking-at "//"))) - (let ((col (current-column)) - (beg (point)) - (bopl (c-point 'bopl)) - (end (cdr range))) - ;; Got to take care in the backward direction to handle - ;; comments which are preceded by code. - (while (and (c-forward-comment -1) - (>= (point) bopl) - (looking-at "//") - (= col (current-column))) - (setq beg (point) - bopl (c-point 'bopl))) - (goto-char end) - (while (and (progn (skip-chars-forward " \t") - (looking-at "//")) - (= col (current-column)) - (prog1 (zerop (forward-line 1)) - (setq end (point))))) - (cons beg end)) - range) - (error range)))) - -(defun c-literal-type (range) - "Convenience function that given the result of `c-literal-limits', -returns nil or the type of literal that the range surrounds. It's -much faster than using `c-in-literal' and is intended to be used when -you need both the type of a literal and its limits." - (if (consp range) - (save-excursion - (goto-char (car range)) - (cond ((eq (char-syntax (or (char-after) ?\ )) ?\") 'string) - ((looking-at "//") 'c++) - (t 'c))) ; Assuming the range is valid. - range)) - + ;; If at eob we have to clear the last character before the end + ;; instead since the buffer might be narrowed and there might + ;; be a `c-in-sws' after (point-max). In this case it's + ;; necessary to clear both properties. + (c-debug-sws-msg + "c-forward-sws clearing thoroughly at %s for cache separation" + (1- last-put-in-sws-pos)) + (c-remove-is-and-in-sws (1- last-put-in-sws-pos) + last-put-in-sws-pos)))) + ))) + +(defun c-backward-sws () + ;; Used by `c-backward-syntactic-ws' to implement the unbounded search. + + (let (;; `rung-pos' is set to a position as late as possible in the unmarked + ;; part of the simple ws region. + (rung-pos (point)) next-rung-pos last-put-in-sws-pos + rung-is-marked simple-ws-beg cmt-skip-pos) + + ;; Skip simple horizontal ws and do a quick check on the preceding + ;; character to see if it's anying that can't end syntactic ws, so we can + ;; bail out early in the majority of cases when there just are a few ws + ;; chars. Newlines are complicated in the backward direction, so we can't + ;; skip over them. + (skip-chars-backward " \t\f") + (when (and (not (bobp)) + (save-excursion + (backward-char) + (looking-at c-syntactic-ws-end))) + + ;; Try to find a rung position in the simple ws preceding point, so that + ;; we can get a cache hit even if the last bit of the simple ws has + ;; changed recently. + (setq simple-ws-beg (point)) + (skip-chars-backward " \t\n\r\f\v") + (if (setq rung-is-marked (text-property-any + (point) (min (1+ rung-pos) (point-max)) + 'c-is-sws t)) + ;; `rung-pos' will be the earliest marked position, which means that + ;; there might be later unmarked parts in the simple ws region. + ;; It's not worth the effort to fix that; the last part of the + ;; simple ws is also typically edited often, so it could be wasted. + (goto-char (setq rung-pos rung-is-marked)) + (goto-char simple-ws-beg)) + + (while + (progn + (while + (when (and rung-is-marked + (not (bobp)) + (get-text-property (1- (point)) 'c-in-sws)) + + ;; The following search is the main reason that `c-in-sws' + ;; and `c-is-sws' aren't combined to one property. + (goto-char (previous-single-property-change + (point) 'c-in-sws nil (point-min))) + (unless (get-text-property (point) 'c-is-sws) + ;; If the `c-in-sws' region extended past the first + ;; `c-is-sws' char we have to go forward a bit. + (goto-char (next-single-property-change + (point) 'c-is-sws))) + + (c-debug-sws-msg + "c-backward-sws cached move %s <- %s (min %s)" + (point) rung-pos (point-min)) + + (setq rung-pos (point)) + (if (and (< (min (skip-chars-backward " \t\f\v") + (progn + (setq simple-ws-beg (point)) + (skip-chars-backward " \t\n\r\f\v"))) + 0) + (setq rung-is-marked + (text-property-any (point) rung-pos + 'c-is-sws t))) + t + (goto-char simple-ws-beg) + nil)) + + ;; We'll loop here if there is simple ws before the first rung. + ;; That means that there's been some change in it and it's + ;; possible that we've stepped into another ladder, so extend + ;; the previous one to join with it if there is one, and try to + ;; use the cache again. + (c-debug-sws-msg + "c-backward-sws extending rung with [%s..%s] (min %s)" + rung-is-marked rung-pos (point-min)) + (unless (get-text-property (1- rung-pos) 'c-is-sws) + ;; Remove any `c-in-sws' property from the last char of + ;; the rung before we mark it with `c-is-sws', so that we + ;; won't connect with the remains of a broken "ladder". + (c-remove-in-sws (1- rung-pos) rung-pos)) + (c-put-is-sws rung-is-marked + rung-pos) + (c-put-in-sws rung-is-marked + (1- rung-pos)) + (setq rung-pos rung-is-marked + last-put-in-sws-pos rung-pos)) + + (c-backward-comments) + (setq cmt-skip-pos (point)) + + (cond + ((and c-opt-cpp-prefix + (/= cmt-skip-pos simple-ws-beg) + (c-beginning-of-macro)) + ;; Inside a cpp directive. See if it should be skipped over. + (let ((cpp-beg (point))) + + ;; Move back over all line continuations in the region skipped + ;; over by `c-backward-comments'. If we go past it then we + ;; started inside the cpp directive. + (goto-char simple-ws-beg) + (beginning-of-line) + (while (and (> (point) cmt-skip-pos) + (progn (backward-char) + (eq (char-before) ?\\))) + (beginning-of-line)) + + (if (< (point) cmt-skip-pos) + ;; Don't move past the cpp directive if we began inside + ;; it. Note that the position at the end of the last line + ;; of the macro is also considered to be within it. + (progn (goto-char cmt-skip-pos) + nil) + + ;; It's worthwhile to spend a little bit of effort on finding + ;; the end of the macro, to get a good `simple-ws-beg' + ;; position for the cache. Note that `c-backward-comments' + ;; could have stepped over some comments before going into + ;; the macro, and then `simple-ws-beg' must be kept on the + ;; same side of those comments. + (goto-char simple-ws-beg) + (skip-chars-backward " \t\n\r\f\v") + (if (eq (char-before) ?\\) + (forward-char)) + (forward-line 1) + (if (< (point) simple-ws-beg) + ;; Might happen if comments after the macro were skipped + ;; over. + (setq simple-ws-beg (point))) + + (goto-char cpp-beg) + t))) + + ((/= (save-excursion + (skip-chars-forward " \t\n\r\f\v" simple-ws-beg) + (setq next-rung-pos (point))) + simple-ws-beg) + ;; Skipped over comments. Must put point at the end of + ;; the simple ws at point since we might be after a line + ;; comment or cpp directive that's been partially + ;; narrowed out, and we can't risk marking the simple ws + ;; at the end of it. + (goto-char next-rung-pos) + t))) + + ;; We've searched over a piece of non-white syntactic ws. See if this + ;; can be cached. + (setq next-rung-pos (point)) + (skip-chars-backward " \t\f\v") + + (if (or + ;; Cache if we started either from a marked rung or from a + ;; completely uncached position. + rung-is-marked + (not (get-text-property (1- simple-ws-beg) 'c-in-sws)) + + ;; Cache if there's a marked rung in the encountered simple ws. + (save-excursion + (skip-chars-backward " \t\n\r\f\v") + (text-property-any (point) (min (1+ next-rung-pos) (point-max)) + 'c-is-sws t))) + + (progn + (c-debug-sws-msg + "c-backward-sws caching [%s..%s] - [%s..%s] (min %s)" + (point) (1+ next-rung-pos) + simple-ws-beg (min (1+ rung-pos) (point-max)) + (point-min)) + + ;; Remove the properties for any nested ws that might be cached. + ;; Only necessary for `c-is-sws' since `c-in-sws' will be set + ;; anyway. + (c-remove-is-sws (1+ next-rung-pos) simple-ws-beg) + (unless (and rung-is-marked (= simple-ws-beg rung-pos)) + (let ((rung-end-pos (min (1+ rung-pos) (point-max)))) + (unless (get-text-property (1- rung-end-pos) 'c-is-sws) + ;; Remove any `c-in-sws' property from the last char of + ;; the rung before we mark it with `c-is-sws', so that we + ;; won't connect with the remains of a broken "ladder". + (c-remove-in-sws (1- rung-end-pos) rung-end-pos)) + (c-put-is-sws simple-ws-beg + rung-end-pos) + (setq rung-is-marked t))) + (c-put-in-sws (setq simple-ws-beg (point) + last-put-in-sws-pos simple-ws-beg) + rung-pos) + (c-put-is-sws (setq rung-pos simple-ws-beg) + (1+ next-rung-pos))) + + (c-debug-sws-msg + "c-backward-sws not caching [%s..%s] - [%s..%s] (min %s)" + (point) (1+ next-rung-pos) + simple-ws-beg (min (1+ rung-pos) (point-max)) + (point-min)) + (setq rung-pos next-rung-pos + simple-ws-beg (point)) + )) + + ;; Make sure that the newly marked `c-in-sws' region doesn't connect to + ;; another one before the point (which might occur when editing inside a + ;; comment or macro). + (when (eq last-put-in-sws-pos (point)) + (cond ((< (point-min) last-put-in-sws-pos) + (c-debug-sws-msg + "c-backward-sws clearing at %s for cache separation" + (1- last-put-in-sws-pos)) + (c-remove-in-sws (1- last-put-in-sws-pos) + last-put-in-sws-pos)) + ((> (point-min) 1) + ;; If at bob and the buffer is narrowed, we have to clear the + ;; character we're standing on instead since there might be a + ;; `c-in-sws' before (point-min). In this case it's necessary + ;; to clear both properties. + (c-debug-sws-msg + "c-backward-sws clearing thoroughly at %s for cache separation" + last-put-in-sws-pos) + (c-remove-is-and-in-sws last-put-in-sws-pos + (1+ last-put-in-sws-pos))))) + ))) -;; utilities for moving and querying around syntactic elements +;; A system for handling noteworthy parens before the point. (defvar c-state-cache nil) (make-variable-buffer-local 'c-state-cache) @@ -1121,9 +1677,27 @@ ;; most effective if `c-parse-state' is used on each line while moving ;; forward. -(defvar c-state-cache-start nil) -;; This (point-min) when `c-state-cache' was calculated, to detect -;; that the start point hasn't changed due to narrowing. +(defvar c-state-cache-start 1) +(make-variable-buffer-local 'c-state-cache-start) +;; This is (point-min) when `c-state-cache' was calculated, since a +;; change of narrowing is likely to affect the parens that are visible +;; before the point. + +(defsubst c-invalidate-state-cache (pos) + ;; Invalidate all info on `c-state-cache' that applies to the buffer + ;; at POS or higher. This is much like `c-whack-state-after', but + ;; it never changes a paren pair element into an open paren element. + ;; Doing that would mean that the new open paren wouldn't have the + ;; required preceding paren pair element. + ;; + ;; This function does not do any hidden buffer changes. + (while (and c-state-cache + (let ((elem (car c-state-cache))) + (if (consp elem) + (or (<= pos (car elem)) + (< pos (cdr elem))) + (<= pos elem)))) + (setq c-state-cache (cdr c-state-cache)))) (defun c-parse-state () ;; Finds and records all noteworthy parens between some good point @@ -1134,27 +1708,54 @@ ;; The returned value is a list of the noteworthy parens with the ;; last one first. If an element in the list is an integer, it's ;; the position of an open paren which has not been closed before - ;; point. If an element is a cons, it gives the position of a + ;; the point. If an element is a cons, it gives the position of a ;; closed brace paren pair; the car is the start paren position and ;; the cdr is the position following the closing paren. Only the ;; last closed brace paren pair before each open paren is recorded, ;; and thus the state never contains two cons elements in ;; succession. + ;; + ;; Currently no characters which are given paren syntax with the + ;; syntax-table property are recorded, i.e. angle bracket arglist + ;; parens are never present here. Note that this might change. + ;; + ;; This function does not do any hidden buffer changes. + (save-restriction (let* ((here (point)) (c-macro-start (c-query-macro-start)) (in-macro-start (or c-macro-start (point))) old-state last-pos pairs pos save-pos) - ;; Somewhat ugly use of c-check-state-cache to get rid of the - ;; part of the state cache that is after point. Can't use - ;; c-whack-state-after for the same reasons as in that function. - (c-check-state-cache (point) nil nil) + (c-invalidate-state-cache (point)) + + ;; If the minimum position has changed due to narrowing then we + ;; have to fix the tail of `c-state-cache' accordingly. + (unless (= c-state-cache-start (point-min)) + (if (> (point-min) c-state-cache-start) + ;; If point-min has moved forward then we just need to cut + ;; off a bit of the tail. + (let ((ptr (cons nil c-state-cache)) elem) + (while (and (setq elem (cdr ptr)) + (>= (if (consp elem) (car elem) elem) + (point-min))) + (setq ptr elem)) + (when (consp ptr) + (if (eq (cdr ptr) c-state-cache) + (setq c-state-cache nil) + (setcdr ptr nil)))) + ;; If point-min has moved backward then we drop the state + ;; completely. It's possible to do a better job here and + ;; recalculate the top only. + (setq c-state-cache nil)) + (setq c-state-cache-start (point-min))) + ;; Get the latest position we know are directly inside the ;; closest containing paren of the cached state. (setq last-pos (and c-state-cache (if (consp (car c-state-cache)) (cdr (car c-state-cache)) (1+ (car c-state-cache))))) + ;; Check if the found last-pos is in a macro. If it is, and ;; we're not in the same macro, we must discard everything on ;; c-state-cache that is inside the macro before using it. @@ -1163,17 +1764,19 @@ (goto-char last-pos) (when (and (c-beginning-of-macro) (/= (point) in-macro-start)) - (c-check-state-cache (point) nil nil) + (c-invalidate-state-cache (point)) ;; Set last-pos again, just like above. (setq last-pos (and c-state-cache (if (consp (car c-state-cache)) (cdr (car c-state-cache)) (1+ (car c-state-cache)))))))) + (setq pos ;; Find the start position for the forward search. (Can't ;; search in the backward direction since point might be ;; in some kind of literal.) (or (when last-pos + ;; There's a cached state with a containing paren. Pop ;; off the stale containing sexps from it by going ;; forward out of parens as far as possible. @@ -1188,6 +1791,7 @@ c-state-cache (cdr-safe (cdr c-state-cache))) (setq pair-beg (car c-state-cache) c-state-cache (cdr c-state-cache)))) + (when (and pair-beg (eq (char-after pair-beg) ?{)) ;; The last paren pair we moved out from was a brace ;; pair. Modify the state to record this as a closed @@ -1196,6 +1800,7 @@ (setq c-state-cache (cdr c-state-cache))) (setq c-state-cache (cons (cons pair-beg last-pos) c-state-cache)))) + ;; Check if the preceding balanced paren is within a ;; macro; it should be ignored if we're outside the ;; macro. There's no need to check any further upwards; @@ -1208,9 +1813,11 @@ (when (c-beginning-of-macro) (setq here (point) c-state-cache (cdr c-state-cache))))) + (when c-state-cache (setq old-state c-state-cache) last-pos)) + (save-excursion ;; go back 2 bods, but ignore any bogus positions ;; returned by beginning-of-defun (i.e. open paren in @@ -1222,7 +1829,9 @@ (if (eq (char-after) ?\{) (setq cnt (1- cnt))))) (point)))) + (narrow-to-region (point-min) here) + (while pos ;; Find the balanced brace pairs. (setq save-pos pos @@ -1231,6 +1840,7 @@ (setq pos (c-up-list-forward last-pos))) (if (eq (char-before last-pos) ?{) (setq pairs (cons (cons last-pos pos) pairs)))) + ;; Should ignore any pairs that are in a macro, providing ;; we're not in the same one. (when (and pairs (< (car (car pairs)) in-macro-start)) @@ -1238,6 +1848,7 @@ (goto-char (car (car pairs))) (c-beginning-of-macro)) (setq pairs (cdr pairs))))) + ;; Record the last brace pair. (when pairs (if (and (eq c-state-cache old-state) @@ -1249,20 +1860,25 @@ (setcar pairs (1- (car pairs))) (when (consp (car-safe c-state-cache)) ;; There could already be a cons first in `c-state-cache' - ;; if we've jumped over an unbalanced open paren in a + ;; if we've e.g. jumped over an unbalanced open paren in a ;; macro below. (setq c-state-cache (cdr c-state-cache))) (setq c-state-cache (cons pairs c-state-cache))) + (if last-pos ;; Prepare to loop, but record the open paren only if it's - ;; outside a macro or within the same macro as point. + ;; outside a macro or within the same macro as point, and + ;; if it is a "real" open paren and not some character + ;; that got an open paren syntax-table property. (progn (setq pos last-pos) - (if (or (>= last-pos in-macro-start) - (save-excursion - (goto-char last-pos) - (not (c-beginning-of-macro)))) - (setq c-state-cache (cons (1- pos) c-state-cache)))) + (if (and (or (>= last-pos in-macro-start) + (save-excursion + (goto-char last-pos) + (not (c-beginning-of-macro)))) + (= (char-syntax (char-before last-pos)) ?\()) + (setq c-state-cache (cons (1- last-pos) c-state-cache)))) + (if (setq last-pos (c-up-list-forward pos)) ;; Found a close paren without a corresponding opening ;; one. Maybe we didn't go back far enough, so try to @@ -1283,6 +1899,7 @@ (1+ (count-lines (point-min) (c-point 'bol last-pos))))))) (setq pos nil)))) + c-state-cache))) ;; Debug tool to catch cache inconsistencies. @@ -1306,29 +1923,11 @@ 'c-real-parse-state))) (c-keep-region-active)) -(defun c-check-state-cache (beg end old-length) - ;; Used on `after-change-functions' to adjust `c-state-cache'. - ;; Prefer speed to finesse here, since there will be many more calls - ;; to this function than times `c-state-cache' is used. - ;; - ;; This is much like `c-whack-state-after', but it never changes a - ;; paren pair element into an open paren element. Doing that would - ;; mean that the new open paren wouldn't have the required preceding - ;; paren pair element. - (if (not (eq c-state-cache-start (point-min))) - (setq c-state-cache-start (point-min) - c-state-cache nil) - (while (and c-state-cache - (let ((elem (car c-state-cache))) - (if (consp elem) - (or (<= beg (car elem)) - (< beg (cdr elem))) - (<= beg elem)))) - (setq c-state-cache (cdr c-state-cache))))) - (defun c-whack-state-before (bufpos paren-state) ;; Whack off any state information from PAREN-STATE which lies ;; before BUFPOS. Not destructive on PAREN-STATE. + ;; + ;; This function does not do any hidden buffer changes. (let* ((newstate (list nil)) (ptr newstate) car) @@ -1344,6 +1943,8 @@ (defun c-whack-state-after (bufpos paren-state) ;; Whack off any state information from PAREN-STATE which lies at or ;; after BUFPOS. Not destructive on PAREN-STATE. + ;; + ;; This function does not do any hidden buffer changes. (catch 'done (while paren-state (let ((car (car paren-state))) @@ -1372,16 +1973,2231 @@ (setq paren-state (cdr paren-state))) nil))) +(defun c-most-enclosing-brace (paren-state &optional bufpos) + ;; Return the bufpos of the innermost enclosing open paren before + ;; bufpos that hasn't been narrowed out, or nil if none was found. + ;; + ;; This function does not do any hidden buffer changes. + (let (enclosingp) + (or bufpos (setq bufpos 134217727)) + (while paren-state + (setq enclosingp (car paren-state) + paren-state (cdr paren-state)) + (if (or (consp enclosingp) + (>= enclosingp bufpos)) + (setq enclosingp nil) + (if (< enclosingp (point-min)) + (setq enclosingp nil)) + (setq paren-state nil))) + enclosingp)) + +(defun c-least-enclosing-brace (paren-state &optional bufpos) + ;; Return the bufpos of the outermost enclosing open paren before + ;; bufpos that hasn't been narrowed out, or nil if none was found. + ;; + ;; This function does not do any hidden buffer changes. + (let (pos elem) + (or bufpos (setq bufpos 134217727)) + (while paren-state + (setq elem (car paren-state) + paren-state (cdr paren-state)) + (unless (or (consp elem) + (>= elem bufpos)) + (if (>= elem (point-min)) + (setq pos elem)))) + pos)) + +(defun c-safe-position (bufpos paren-state) + ;; Return the closest known safe position higher up than BUFPOS, or + ;; nil if PAREN-STATE doesn't contain one. Return nil if BUFPOS is + ;; nil, which is useful to find the closest limit before a given + ;; limit that might be nil. + ;; + ;; This function does not do any hidden buffer changes. + (when bufpos + (let (elem) + (catch 'done + (while paren-state + (setq elem (car paren-state)) + (if (consp elem) + (cond ((< (cdr elem) bufpos) + (throw 'done (cdr elem))) + ((< (car elem) bufpos) + ;; See below. + (throw 'done (min (1+ (car elem)) bufpos)))) + (if (< elem bufpos) + ;; elem is the position at and not after the opening paren, so + ;; we can go forward one more step unless it's equal to + ;; bufpos. This is useful in some cases avoid an extra paren + ;; level between the safe position and bufpos. + (throw 'done (min (1+ elem) bufpos)))) + (setq paren-state (cdr paren-state))))))) + +(defun c-beginning-of-syntax () + ;; This is used for `font-lock-beginning-of-syntax-function'. It + ;; goes to the closest previous point that is known to be outside + ;; any string literal or comment. `c-state-cache' is used if it has + ;; a position in the vicinity. + (let* ((paren-state c-state-cache) + elem + + (pos (catch 'done + ;; Note: Similar code in `c-safe-position'. The + ;; difference is that we accept a safe position at + ;; the point and don't bother to go forward past open + ;; parens. + (while paren-state + (setq elem (car paren-state)) + (if (consp elem) + (cond ((<= (cdr elem) (point)) + (throw 'done (cdr elem))) + ((<= (car elem) (point)) + (throw 'done (car elem)))) + (if (<= elem (point)) + (throw 'done elem))) + (setq paren-state (cdr paren-state))) + (point-min)))) + + (if (> pos (- (point) 4000)) + (goto-char pos) + ;; The position is far back. Try `c-beginning-of-defun-1' + ;; (although we can't be entirely sure it will go to a position + ;; outside a comment or string in current emacsen). FIXME: + ;; Consult `syntax-ppss' here. + (c-beginning-of-defun-1) + (if (< (point) pos) + (goto-char pos))))) + +;; Tools for scanning identifiers and other tokens. + +(defun c-on-identifier () + "Return non-nil if the point is on or directly after an identifier. +Keywords are recognized and not considered identifiers. If an +identifier is detected, the returned value is its starting position. +If an identifier both starts and stops at the point \(can only happen +in Pike) then the point for the preceding one is returned. + +This function does not do any hidden buffer changes." + + (save-excursion + (if (zerop (skip-syntax-backward "w_")) + + (when (c-major-mode-is 'pike-mode) + ;; Handle the `<operator> syntax in Pike. + (let ((pos (point))) + (skip-chars-backward "!%&*+\\-/<=>^|~[]()") + (and (if (< (skip-chars-backward "`") 0) + t + (goto-char pos) + (eq (char-after) ?\`)) + (looking-at c-symbol-key) + (>= (match-end 0) pos) + (point)))) + + (and (not (looking-at c-keywords-regexp)) + (point))))) + +(defsubst c-simple-skip-symbol-backward () + ;; If the point is at the end of a symbol then skip backward to the + ;; beginning of it. Don't move otherwise. Return non-nil if point + ;; moved. + (or (< (skip-syntax-backward "w_") 0) + (and (c-major-mode-is 'pike-mode) + ;; Handle the `<operator> syntax in Pike. + (let ((pos (point))) + (if (and (< (skip-chars-backward "!%&*+\\-/<=>^|~[]()") 0) + (< (skip-chars-backward "`") 0) + (looking-at c-symbol-key) + (>= (match-end 0) pos)) + t + (goto-char pos) + nil))))) + +(defsubst c-beginning-of-current-token (&optional back-limit) + ;; Move to the beginning of the current token. Do not move if not + ;; in the middle of one. BACK-LIMIT may be used to bound the + ;; backward search; if given it's assumed to be at the boundary + ;; between two tokens. + (if (looking-at "\\w\\|\\s_") + (skip-syntax-backward "w_" back-limit) + (let ((start (point))) + (when (< (skip-syntax-backward ".()" back-limit) 0) + (while (let ((pos (or (and (looking-at c-nonsymbol-token-regexp) + (match-end 0)) + ;; `c-nonsymbol-token-regexp' should always match + ;; since we've skipped backward over punctuator + ;; or paren syntax, but consume one char in case + ;; it doesn't so that we don't leave point before + ;; some earlier incorrect token. + (1+ (point))))) + (if (<= pos start) + (goto-char pos)) + (< pos start))))))) + +(defsubst c-end-of-current-token (&optional back-limit) + ;; Move to the end of the current token. Do not move if not in the + ;; middle of one. BACK-LIMIT may be used to bound the backward + ;; search; if given it's assumed to be at the boundary between two + ;; tokens. + (let ((start (point))) + (cond ((< (skip-syntax-backward "w_" (1- start)) 0) + (skip-syntax-forward "w_")) + ((< (skip-syntax-backward ".()" back-limit) 0) + (while (progn + (if (looking-at c-nonsymbol-token-regexp) + (goto-char (match-end 0)) + ;; `c-nonsymbol-token-regexp' should always match since + ;; we've skipped backward over punctuator or paren + ;; syntax, but move forward in case it doesn't so that + ;; we don't leave point earlier than we started with. + (forward-char)) + (< (point) start))))))) + +(defconst c-jump-syntax-balanced + (if (memq 'gen-string-delim c-emacs-features) + "\\w\\|\\s_\\|\\s\(\\|\\s\)\\|\\s\"\\|\\s|" + "\\w\\|\\s_\\|\\s\(\\|\\s\)\\|\\s\"")) + +(defconst c-jump-syntax-unbalanced + (if (memq 'gen-string-delim c-emacs-features) + "\\w\\|\\s_\\|\\s\"\\|\\s|" + "\\w\\|\\s_\\|\\s\"")) + +(defun c-forward-token-2 (&optional count balanced limit) + "Move forward by tokens. +A token is defined as all symbols and identifiers which aren't +syntactic whitespace \(note that multicharacter tokens like \"==\" are +treated properly). Point is always either left at the beginning of a +token or not moved at all. COUNT specifies the number of tokens to +move; a negative COUNT moves in the opposite direction. A COUNT of 0 +moves to the next token beginning only if not already at one. If +BALANCED is true, move over balanced parens, otherwise move into them. +Also, if BALANCED is true, never move out of an enclosing paren. + +LIMIT sets the limit for the movement and defaults to the point limit. +The case when LIMIT is set in the middle of a token, comment or macro +is handled correctly, i.e. the point won't be left there. + +Return the number of tokens left to move \(positive or negative). If +BALANCED is true, a move over a balanced paren counts as one. Note +that if COUNT is 0 and no appropriate token beginning is found, 1 will +be returned. Thus, a return value of 0 guarantees that point is at +the requested position and a return value less \(without signs) than +COUNT guarantees that point is at the beginning of some token." + + (or count (setq count 1)) + (if (< count 0) + (- (c-backward-token-2 (- count) balanced limit)) + + (let ((jump-syntax (if balanced + c-jump-syntax-balanced + c-jump-syntax-unbalanced)) + (last (point)) + (prev (point))) + + (if (zerop count) + ;; If count is zero we should jump if in the middle of a token. + (c-end-of-current-token)) + + (save-restriction + (if limit (narrow-to-region (point-min) limit)) + (if (/= (point) + (progn (c-forward-syntactic-ws) (point))) + ;; Skip whitespace. Count this as a move if we did in + ;; fact move. + (setq count (max (1- count) 0))) + + (if (eobp) + ;; Moved out of bounds. Make sure the returned count isn't zero. + (progn + (if (zerop count) (setq count 1)) + (goto-char last)) + + ;; Use `condition-case' to avoid having the limit tests + ;; inside the loop. + (condition-case nil + (while (and + (> count 0) + (progn + (setq last (point)) + (cond ((looking-at jump-syntax) + (goto-char (scan-sexps (point) 1)) + t) + ((looking-at c-nonsymbol-token-regexp) + (goto-char (match-end 0)) + t) + ;; `c-nonsymbol-token-regexp' above should always + ;; match if there are correct tokens. Try to + ;; widen to see if the limit was set in the + ;; middle of one, else fall back to treating + ;; the offending thing as a one character token. + ((and limit + (save-restriction + (widen) + (looking-at c-nonsymbol-token-regexp))) + nil) + (t + (forward-char) + t)))) + (c-forward-syntactic-ws) + (setq prev last + count (1- count))) + (error (goto-char last))) + + (when (eobp) + (goto-char prev) + (setq count (1+ count))))) + + count))) + +(defun c-backward-token-2 (&optional count balanced limit) + "Move backward by tokens. +See `c-forward-token-2' for details." + + (or count (setq count 1)) + (if (< count 0) + (- (c-forward-token-2 (- count) balanced limit)) + + (or limit (setq limit (point-min))) + (let ((jump-syntax (if balanced + c-jump-syntax-balanced + c-jump-syntax-unbalanced)) + (last (point))) + + (if (zerop count) + ;; The count is zero so try to skip to the beginning of the + ;; current token. + (if (> (point) + (progn (c-beginning-of-current-token) (point))) + (if (< (point) limit) + ;; The limit is inside the same token, so return 1. + (setq count 1)) + + ;; We're not in the middle of a token. If there's + ;; whitespace after the point then we must move backward, + ;; so set count to 1 in that case. + (and (looking-at c-syntactic-ws-start) + ;; If we're looking at a '#' that might start a cpp + ;; directive then we have to do a more elaborate check. + (or (/= (char-after) ?#) + (not c-opt-cpp-prefix) + (save-excursion + (and (= (point) + (progn (beginning-of-line) + (looking-at "[ \t]*") + (match-end 0))) + (or (bobp) + (progn (backward-char) + (not (eq (char-before) ?\\))))))) + (setq count 1)))) + + ;; Use `condition-case' to avoid having to check for buffer + ;; limits in `backward-char', `scan-sexps' and `goto-char' below. + (condition-case nil + (while (and + (> count 0) + (progn + (c-backward-syntactic-ws) + (backward-char) + (if (looking-at jump-syntax) + (goto-char (scan-sexps (1+ (point)) -1)) + ;; This can be very inefficient if there's a long + ;; sequence of operator tokens without any separation. + ;; That doesn't happen in practice, anyway. + (c-beginning-of-current-token)) + (>= (point) limit))) + (setq last (point) + count (1- count))) + (error (goto-char last))) + + (if (< (point) limit) + (goto-char last)) + + count))) + +(defun c-forward-token-1 (&optional count balanced limit) + "Like `c-forward-token-2' but doesn't treat multicharacter operator +tokens like \"==\" as single tokens, i.e. all sequences of symbol +characters are jumped over character by character. This function is +for compatibility only; it's only a wrapper over `c-forward-token-2'." + (let ((c-nonsymbol-token-regexp "\\s.\\|\\s\(\\|\\s\)")) + (c-forward-token-2 count balanced limit))) + +(defun c-backward-token-1 (&optional count balanced limit) + "Like `c-backward-token-2' but doesn't treat multicharacter operator +tokens like \"==\" as single tokens, i.e. all sequences of symbol +characters are jumped over character by character. This function is +for compatibility only; it's only a wrapper over `c-backward-token-2'." + (let ((c-nonsymbol-token-regexp "\\s.\\|\\s\(\\|\\s\)")) + (c-backward-token-2 count balanced limit))) + + +;; Tools for doing searches restricted to syntactically relevant text. + +(defun c-syntactic-re-search-forward (regexp &optional bound noerror + paren-level not-inside-token + lookbehind-submatch) + "Like `re-search-forward', but only report matches that are found +in syntactically significant text. I.e. matches in comments, macros +or string literals are ignored. The start point is assumed to be +outside any comment, macro or string literal, or else the content of +that region is taken as syntactically significant text. + +If PAREN-LEVEL is non-nil, an additional restriction is added to +ignore matches in nested paren sexps, and the search will also not go +outside the current paren sexp. + +If NOT-INSIDE-TOKEN is non-nil, matches in the middle of tokens are +ignored. Things like multicharacter operators and special symbols +\(e.g. \"`()\" in Pike) are handled but currently not floating point +constants. + +If LOOKBEHIND-SUBMATCH is non-nil, it's taken as a number of a +subexpression in REGEXP. The end of that submatch is used as the +position to check for syntactic significance. If LOOKBEHIND-SUBMATCH +isn't used or if that subexpression didn't match then the start +position of the whole match is used instead. The \"look behind\" +subexpression is never tested before the starting position, so it +might be a good idea to include \\=\\= as a match alternative in it. + +Optimization note: Matches might be missed if the \"look behind\" +subexpression should match the end of nonwhite syntactic whitespace, +i.e. the end of comments or cpp directives. This since the function +skips over such things before resuming the search. It's also not safe +to assume that the \"look behind\" subexpression never can match +syntactic whitespace." + + (or bound (setq bound (point-max))) + (if paren-level (setq paren-level -1)) + + ;;(message "c-syntactic-re-search-forward %s %s %S" (point) bound regexp) + + (let ((start (point)) + (pos (point)) + (last-token-end-pos (point-min)) + match-pos found state check-pos check-state tmp) + + (condition-case err + (while + (and + (re-search-forward regexp bound noerror) + + (progn + (setq match-pos (point) + state (parse-partial-sexp + pos (match-beginning 0) paren-level nil state) + pos (point)) + (if (setq check-pos (and lookbehind-submatch + (match-end lookbehind-submatch))) + (setq check-state (parse-partial-sexp + pos check-pos paren-level nil state)) + (setq check-pos pos + check-state state)) + + ;; If we got a look behind subexpression and get an + ;; insignificant match in something that isn't + ;; syntactic whitespace (i.e. strings or in nested + ;; parentheses), then we can never skip more than a + ;; single character from the match position before + ;; continuing the search. That since the look behind + ;; subexpression might match the end of the + ;; insignificant region. + + (cond + ((setq tmp (elt check-state 3)) + ;; Match inside a string. + (if (or lookbehind-submatch + (not (integerp tmp))) + (goto-char (min (1+ pos) bound)) + ;; Skip to the end of the string before continuing. + (let ((ender (make-string 1 tmp)) (continue t)) + (while (if (search-forward ender bound noerror) + (progn + (setq state (parse-partial-sexp + pos (point) nil nil state) + pos (point)) + (elt state 3)) + (setq continue nil))) + continue))) + + ((elt check-state 7) + ;; Match inside a line comment. Skip to eol. Use + ;; `re-search-forward' instead of `skip-chars-forward' to get + ;; the right bound behavior. + (re-search-forward "[\n\r]" bound noerror)) + + ((elt check-state 4) + ;; Match inside a block comment. Skip to the '*/'. + (search-forward "*/" bound noerror)) + + ((and (not (elt check-state 5)) + (eq (char-before check-pos) ?/) + (memq (char-after check-pos) '(?/ ?*))) + ;; Match in the middle of the opener of a block or line + ;; comment. + (if (= (char-after check-pos) ?/) + (re-search-forward "[\n\r]" bound noerror) + (search-forward "*/" bound noerror))) + + ((and not-inside-token + (or (< check-pos last-token-end-pos) + (< check-pos + (save-excursion + (goto-char check-pos) + (c-end-of-current-token last-token-end-pos) + (setq last-token-end-pos (point)))))) + ;; Match inside a token. + (cond ((<= (point) bound) + (goto-char (min (1+ pos) bound)) + t) + (noerror nil) + (t (signal 'search-failed "end of token")))) + + ((save-excursion + (save-match-data + (c-beginning-of-macro start))) + ;; Match inside a macro. Skip to the end of it. + (c-end-of-macro) + (cond ((<= (point) bound) t) + (noerror nil) + (t (signal 'search-failed "end of macro")))) + + ((and paren-level + (/= (setq tmp (car check-state)) 0)) + (if (> tmp 0) + ;; Match inside a nested paren sexp. + (if lookbehind-submatch + (goto-char (min (1+ pos) bound)) + ;; Skip out of the paren quickly. + (setq state (parse-partial-sexp pos bound 0 nil state) + pos (point))) + ;; Have exited the current paren sexp. The + ;; `parse-partial-sexp' above has left us just after the + ;; closing paren in this case. Just make + ;; `re-search-forward' above fail in the appropriate way; + ;; we'll adjust the leave off point below if necessary. + (setq bound (point)))) + + (t + ;; A real match. + (setq found t) + nil))))) + + (error + (goto-char start) + (signal (car err) (cdr err)))) + + ;;(message "c-syntactic-re-search-forward done %s" (or match-pos (point))) + + (if found + (progn + (goto-char match-pos) + match-pos) + + ;; Search failed. Set point as appropriate. + (cond ((eq noerror t) + (goto-char start)) + (paren-level + (if (eq (car (parse-partial-sexp pos bound -1 nil state)) -1) + (backward-char))) + (t + (goto-char bound))) + nil))) + +(defun c-syntactic-skip-backward (skip-chars &optional limit) + "Like `skip-chars-backward' but only look at syntactically relevant chars, +i.e. don't stop at positions inside syntactic whitespace or string +literals. Preprocessor directives are also ignored, with the exception +of the one that the point starts within, if any. If LIMIT is given, +it's assumed to be at a syntactically relevant position. + +This function does not do any hidden buffer changes." + + (let ((start (point)) + ;; A list of syntactically relevant positions in descending + ;; order. It's used to avoid scanning repeatedly over + ;; potentially large regions with `parse-partial-sexp' to verify + ;; each position. + safe-pos-list + ;; The result from `c-beginning-of-macro' at the start position or the + ;; start position itself if it isn't within a macro. Evaluated on + ;; demand. + start-macro-beg) + + (while (progn + (while (and + (< (skip-chars-backward skip-chars limit) 0) + + ;; Use `parse-partial-sexp' from a safe position down to + ;; the point to check if it's outside comments and + ;; strings. + (let ((pos (point)) safe-pos state) + ;; Pick a safe position as close to the point as + ;; possible. + ;; + ;; FIXME: Consult `syntax-ppss' here if our + ;; cache doesn't give a good position. + (while (and safe-pos-list + (> (car safe-pos-list) (point))) + (setq safe-pos-list (cdr safe-pos-list))) + (unless (setq safe-pos (car-safe safe-pos-list)) + (setq safe-pos (max (or (c-safe-position + (point) (or c-state-cache + (c-parse-state))) + 0) + (point-min)) + safe-pos-list (list safe-pos))) + + (while (progn + (setq state (parse-partial-sexp + safe-pos pos 0)) + (< (point) pos)) + ;; Cache positions along the way to use if we have to + ;; back up more. Every closing paren on the same + ;; level seems like fairly well spaced positions. + (setq safe-pos (point) + safe-pos-list (cons safe-pos safe-pos-list))) + + (cond + ((or (elt state 3) (elt state 4)) + ;; Inside string or comment. Continue search at the + ;; beginning of it. + (if (setq pos (nth 8 state)) + ;; It's an emacs where `parse-partial-sexp' + ;; supplies the starting position. + (goto-char pos) + (goto-char (car (c-literal-limits safe-pos)))) + t) + + ((c-beginning-of-macro limit) + ;; Inside a macro. + (if (< (point) + (or start-macro-beg + (setq start-macro-beg + (save-excursion + (goto-char start) + (c-beginning-of-macro limit) + (point))))) + t + ;; It's inside the same macro we started in so it's + ;; a relevant match. + (goto-char pos) + nil)))))) + + (> (point) + (progn + ;; Skip syntactic ws afterwards so that we don't stop at the + ;; end of a comment if `skip-chars' is something like "^/". + (c-backward-syntactic-ws) + (point))))) + + (- (point) start))) + + +;; Tools for handling comments and string literals. + +(defun c-slow-in-literal (&optional lim detect-cpp) + "Return the type of literal point is in, if any. +The return value is `c' if in a C-style comment, `c++' if in a C++ +style comment, `string' if in a string literal, `pound' if DETECT-CPP +is non-nil and in a preprocessor line, or nil if somewhere else. +Optional LIM is used as the backward limit of the search. If omitted, +or nil, `c-beginning-of-defun' is used. + +The last point calculated is cached if the cache is enabled, i.e. if +`c-in-literal-cache' is bound to a two element vector. + +This function does not do any hidden buffer changes." + (if (and (vectorp c-in-literal-cache) + (= (point) (aref c-in-literal-cache 0))) + (aref c-in-literal-cache 1) + (let ((rtn (save-excursion + (let* ((pos (point)) + (lim (or lim (progn + (c-beginning-of-syntax) + (point)))) + (state (parse-partial-sexp lim pos))) + (cond + ((elt state 3) 'string) + ((elt state 4) (if (elt state 7) 'c++ 'c)) + ((and detect-cpp (c-beginning-of-macro lim)) 'pound) + (t nil)))))) + ;; cache this result if the cache is enabled + (if (not c-in-literal-cache) + (setq c-in-literal-cache (vector (point) rtn))) + rtn))) + +;; XEmacs has a built-in function that should make this much quicker. +;; I don't think we even need the cache, which makes our lives more +;; complicated anyway. In this case, lim is only used to detect +;; cpp directives. +;; +;; Note that there is a bug in Xemacs's buffer-syntactic-context when used in +;; conjunction with syntax-table-properties. The bug is present in, e.g., +;; Xemacs 21.4.4. It manifested itself thus: +;; +;; Starting with an empty AWK Mode buffer, type +;; /regexp/ {<C-j> +;; Point gets wrongly left at column 0, rather than being indented to tab-width. +;; +;; AWK Mode is designed such that when the first / is typed, it gets the +;; syntax-table property "string fence". When the second / is typed, BOTH /s +;; are given the s-t property "string". However, buffer-syntactic-context +;; fails to take account of the change of the s-t property on the opening / to +;; "string", and reports that the { is within a string started by the second /. +;; +;; The workaround for this is for the AWK Mode initialisation to switch the +;; defalias for c-in-literal to c-slow-in-literal. This will slow down other +;; cc-modes in Xemacs whenever an awk-buffer has been initialised. +;; +;; (Alan Mackenzie, 2003/4/30). + +(defun c-fast-in-literal (&optional lim detect-cpp) + (let ((context (buffer-syntactic-context))) + (cond + ((eq context 'string) 'string) + ((eq context 'comment) 'c++) + ((eq context 'block-comment) 'c) + ((and detect-cpp (save-excursion (c-beginning-of-macro lim))) 'pound)))) + +(defalias 'c-in-literal + (if (fboundp 'buffer-syntactic-context) + 'c-fast-in-literal ; Xemacs + 'c-slow-in-literal)) ; GNU Emacs + +;; The defalias above isn't enough to shut up the byte compiler. +(cc-bytecomp-defun c-in-literal) + +(defun c-literal-limits (&optional lim near not-in-delimiter) + "Return a cons of the beginning and end positions of the comment or +string surrounding point (including both delimiters), or nil if point +isn't in one. If LIM is non-nil, it's used as the \"safe\" position +to start parsing from. If NEAR is non-nil, then the limits of any +literal next to point is returned. \"Next to\" means there's only +spaces and tabs between point and the literal. The search for such a +literal is done first in forward direction. If NOT-IN-DELIMITER is +non-nil, the case when point is inside a starting delimiter won't be +recognized. This only has effect for comments, which have starting +delimiters with more than one character. + +This function does not do any hidden buffer changes." + + (save-excursion + (let* ((pos (point)) + (lim (or lim (progn + (c-beginning-of-syntax) + (point)))) + (state (parse-partial-sexp lim pos))) + + (cond ((elt state 3) + ;; String. Search backward for the start. + (while (elt state 3) + (search-backward (make-string 1 (elt state 3))) + (setq state (parse-partial-sexp lim (point)))) + (cons (point) (or (c-safe (c-forward-sexp 1) (point)) + (point-max)))) + + ((elt state 7) + ;; Line comment. Search from bol for the comment starter. + (beginning-of-line) + (setq state (parse-partial-sexp lim (point)) + lim (point)) + (while (not (elt state 7)) + (search-forward "//") ; Should never fail. + (setq state (parse-partial-sexp + lim (point) nil nil state) + lim (point))) + (backward-char 2) + (cons (point) (progn (c-forward-single-comment) (point)))) + + ((elt state 4) + ;; Block comment. Search backward for the comment starter. + (while (elt state 4) + (search-backward "/*") ; Should never fail. + (setq state (parse-partial-sexp lim (point)))) + (cons (point) (progn (c-forward-single-comment) (point)))) + + ((and (not not-in-delimiter) + (not (elt state 5)) + (eq (char-before) ?/) + (looking-at "[/*]")) + ;; We're standing in a comment starter. + (backward-char 1) + (cons (point) (progn (c-forward-single-comment) (point)))) + + (near + (goto-char pos) + + ;; Search forward for a literal. + (skip-chars-forward " \t") + + (cond + ((looking-at c-string-limit-regexp) ; String. + (cons (point) (or (c-safe (c-forward-sexp 1) (point)) + (point-max)))) + + ((looking-at c-comment-start-regexp) ; Line or block comment. + (cons (point) (progn (c-forward-single-comment) (point)))) + + (t + ;; Search backward. + (skip-chars-backward " \t") + + (let ((end (point)) beg) + (cond + ((save-excursion + (< (skip-syntax-backward c-string-syntax) 0)) ; String. + (setq beg (c-safe (c-backward-sexp 1) (point)))) + + ((and (c-safe (forward-char -2) t) + (looking-at "*/")) + ;; Block comment. Due to the nature of line + ;; comments, they will always be covered by the + ;; normal case above. + (goto-char end) + (c-backward-single-comment) + ;; If LIM is bogus, beg will be bogus. + (setq beg (point)))) + + (if beg (cons beg end)))))) + )))) + +(defun c-literal-limits-fast (&optional lim near not-in-delimiter) + ;; Like c-literal-limits, but for emacsen whose `parse-partial-sexp' + ;; returns the pos of the comment start. + + "Return a cons of the beginning and end positions of the comment or +string surrounding point (including both delimiters), or nil if point +isn't in one. If LIM is non-nil, it's used as the \"safe\" position +to start parsing from. If NEAR is non-nil, then the limits of any +literal next to point is returned. \"Next to\" means there's only +spaces and tabs between point and the literal. The search for such a +literal is done first in forward direction. If NOT-IN-DELIMITER is +non-nil, the case when point is inside a starting delimiter won't be +recognized. This only has effect for comments, which have starting +delimiters with more than one character. + +This function does not do any hidden buffer changes." + + (save-excursion + (let* ((pos (point)) + (lim (or lim (progn + (c-beginning-of-syntax) + (point)))) + (state (parse-partial-sexp lim pos))) + + (cond ((elt state 3) ; String. + (goto-char (elt state 8)) + (cons (point) (or (c-safe (c-forward-sexp 1) (point)) + (point-max)))) + + ((elt state 4) ; Comment. + (goto-char (elt state 8)) + (cons (point) (progn (c-forward-single-comment) (point)))) + + ((and (not not-in-delimiter) + (not (elt state 5)) + (eq (char-before) ?/) + (looking-at "[/*]")) + ;; We're standing in a comment starter. + (backward-char 1) + (cons (point) (progn (c-forward-single-comment) (point)))) + + (near + (goto-char pos) + + ;; Search forward for a literal. + (skip-chars-forward " \t") + + (cond + ((looking-at c-string-limit-regexp) ; String. + (cons (point) (or (c-safe (c-forward-sexp 1) (point)) + (point-max)))) + + ((looking-at c-comment-start-regexp) ; Line or block comment. + (cons (point) (progn (c-forward-single-comment) (point)))) + + (t + ;; Search backward. + (skip-chars-backward " \t") + + (let ((end (point)) beg) + (cond + ((save-excursion + (< (skip-syntax-backward c-string-syntax) 0)) ; String. + (setq beg (c-safe (c-backward-sexp 1) (point)))) + + ((and (c-safe (forward-char -2) t) + (looking-at "*/")) + ;; Block comment. Due to the nature of line + ;; comments, they will always be covered by the + ;; normal case above. + (goto-char end) + (c-backward-single-comment) + ;; If LIM is bogus, beg will be bogus. + (setq beg (point)))) + + (if beg (cons beg end)))))) + )))) + +(if (memq 'pps-extended-state c-emacs-features) + (defalias 'c-literal-limits 'c-literal-limits-fast)) + +(defun c-collect-line-comments (range) + "If the argument is a cons of two buffer positions (such as returned by +`c-literal-limits'), and that range contains a C++ style line comment, +then an extended range is returned that contains all adjacent line +comments (i.e. all comments that starts in the same column with no +empty lines or non-whitespace characters between them). Otherwise the +argument is returned. + +This function does not do any hidden buffer changes." + (save-excursion + (condition-case nil + (if (and (consp range) (progn + (goto-char (car range)) + (looking-at "//"))) + (let ((col (current-column)) + (beg (point)) + (bopl (c-point 'bopl)) + (end (cdr range))) + ;; Got to take care in the backward direction to handle + ;; comments which are preceded by code. + (while (and (c-backward-single-comment) + (>= (point) bopl) + (looking-at "//") + (= col (current-column))) + (setq beg (point) + bopl (c-point 'bopl))) + (goto-char end) + (while (and (progn (skip-chars-forward " \t") + (looking-at "//")) + (= col (current-column)) + (prog1 (zerop (forward-line 1)) + (setq end (point))))) + (cons beg end)) + range) + (error range)))) + +(defun c-literal-type (range) + "Convenience function that given the result of `c-literal-limits', +returns nil or the type of literal that the range surrounds. It's +much faster than using `c-in-literal' and is intended to be used when +you need both the type of a literal and its limits. + +This function does not do any hidden buffer changes." + (if (consp range) + (save-excursion + (goto-char (car range)) + (cond ((looking-at c-string-limit-regexp) 'string) + ((or (looking-at "//") ; c++ line comment + (and (looking-at "\\s<") ; comment starter + (looking-at "#"))) ; awk comment. + 'c++) + (t 'c))) ; Assuming the range is valid. + range)) + + +;; `c-find-decl-spots' and accompanying stuff. + +;; Variables used in `c-find-decl-spots' to cache the search done for +;; the first declaration in the last call. When that function starts, +;; it needs to back up over syntactic whitespace to look at the last +;; token before the region being searched. That can sometimes cause +;; moves back and forth over a quite large region of comments and +;; macros, which would be repeated for each changed character when +;; we're called during fontification, since font-lock refontifies the +;; current line for each change. Thus it's worthwhile to cache the +;; first match. +;; +;; `c-find-decl-syntactic-pos' is a syntactically relevant position in +;; the syntactic whitespace less or equal to some start position. +;; There's no cached value if it's nil. +;; +;; `c-find-decl-match-pos' is the match position if +;; `c-find-decl-prefix-search' matched before the syntactic whitespace +;; at `c-find-decl-syntactic-pos', or nil if there's no such match. +(defvar c-find-decl-syntactic-pos nil) +(make-variable-buffer-local 'c-find-decl-syntactic-pos) +(defvar c-find-decl-match-pos nil) +(make-variable-buffer-local 'c-find-decl-match-pos) + +(defsubst c-invalidate-find-decl-cache (change-min-pos) + (and c-find-decl-syntactic-pos + (< change-min-pos c-find-decl-syntactic-pos) + (setq c-find-decl-syntactic-pos nil))) + +; (defface c-debug-decl-spot-face +; '((t (:background "Turquoise"))) +; "Debug face to mark the spots where `c-find-decl-spots' stopped.") +; (defface c-debug-decl-sws-face +; '((t (:background "Khaki"))) +; "Debug face to mark the syntactic whitespace between the declaration +; spots and the preceding token end.") + +(defmacro c-debug-put-decl-spot-faces (match-pos decl-pos) + (when (facep 'c-debug-decl-spot-face) + `(let ((match-pos ,match-pos) (decl-pos ,decl-pos)) + (c-debug-add-face (max match-pos (point-min)) decl-pos + 'c-debug-decl-sws-face) + (c-debug-add-face decl-pos (min (1+ decl-pos) (point-max)) + 'c-debug-decl-spot-face)))) +(defmacro c-debug-remove-decl-spot-faces (beg end) + (when (facep 'c-debug-decl-spot-face) + `(progn + (c-debug-remove-face ,beg ,end 'c-debug-decl-spot-face) + (c-debug-remove-face ,beg ,end 'c-debug-decl-sws-face)))) + +(defmacro c-find-decl-prefix-search () + ;; Macro used inside `c-find-decl-spots'. It ought to be a defun, + ;; but it contains lots of free variables that refer to things + ;; inside `c-find-decl-spots'. The point is left at `cfd-match-pos' + ;; if there is a match, otherwise at `cfd-limit'. + + '(progn + ;; Find the next property match position if we haven't got one already. + (unless cfd-prop-match + (save-excursion + (while (progn + (goto-char (next-single-property-change + (point) 'c-type nil cfd-limit)) + (and (< (point) cfd-limit) + (not (eq (c-get-char-property (1- (point)) 'c-type) + 'c-decl-end))))) + (setq cfd-prop-match (point)))) + + ;; Find the next `c-decl-prefix-re' match if we haven't got one already. + (unless cfd-re-match + (while (and (setq cfd-re-match + (re-search-forward c-decl-prefix-re cfd-limit 'move)) + (c-got-face-at (1- (setq cfd-re-match (match-end 1))) + c-literal-faces)) + ;; Search again if the match is within a comment or a string literal. + (while (progn + (goto-char (next-single-property-change + cfd-re-match 'face nil cfd-limit)) + (and (< (point) cfd-limit) + (c-got-face-at (point) c-literal-faces))) + (setq cfd-re-match (point)))) + (unless cfd-re-match + (setq cfd-re-match cfd-limit))) + + ;; Choose whichever match is closer to the start. + (if (< cfd-re-match cfd-prop-match) + (setq cfd-match-pos cfd-re-match + cfd-re-match nil) + (setq cfd-match-pos cfd-prop-match + cfd-prop-match nil)) + + (goto-char cfd-match-pos) + + (when (< cfd-match-pos cfd-limit) + ;; Skip forward past comments only so we don't skip macros. + (c-forward-comments) + ;; Set the position to continue at. We can avoid going over + ;; the comments skipped above a second time, but it's possible + ;; that the comment skipping has taken us past `cfd-prop-match' + ;; since the property might be used inside comments. + (setq cfd-continue-pos (if cfd-prop-match + (min cfd-prop-match (point)) + (point)))))) + +(defun c-find-decl-spots (cfd-limit cfd-decl-re cfd-face-checklist cfd-fun) + ;; Call CFD-FUN for each possible spot for a declaration from the + ;; point to CFD-LIMIT. A spot for a declaration is the first token + ;; in the buffer and each token after the ones matched by + ;; `c-decl-prefix-re' and after the occurrences of the `c-type' + ;; property with the value `c-decl-end' (if `c-type-decl-end-used' + ;; is set). Only a spot that match CFD-DECL-RE and whose face is in + ;; the CFD-FACE-CHECKLIST list causes CFD-FUN to be called. The + ;; face check is disabled if CFD-FACE-CHECKLIST is nil. + ;; + ;; If the match is inside a macro then the buffer is narrowed to the + ;; end of it, so that CFD-FUN can investigate the following tokens + ;; without matching something that begins inside a macro and ends + ;; outside it. It's to avoid this work that the CFD-DECL-RE and + ;; CFD-FACE-CHECKLIST checks exist. + ;; + ;; CFD-FUN is called with point at the start of the spot. It's + ;; passed two arguments: The first is the end position of the token + ;; that `c-decl-prefix-re' matched, or 0 for the implicit match at + ;; bob. The second is a flag that is t when the match is inside a + ;; macro. + ;; + ;; It's assumed that comment and strings are fontified in the + ;; searched range. + ;; + ;; This is mainly used in fontification, and so has an elaborate + ;; cache to handle repeated calls from the same start position; see + ;; the variables above. + ;; + ;; All variables in this function begin with `cfd-' to avoid name + ;; collision with the (dynamically bound) variables used in CFD-FUN. + + (let ((cfd-buffer-end (point-max)) + ;; The last regexp match found by `c-find-decl-prefix-search'. + cfd-re-match + ;; The last `c-decl-end' found by `c-find-decl-prefix-search'. + ;; If searching for the property isn't needed then we disable + ;; it by faking a first match at the limit. + (cfd-prop-match (unless c-type-decl-end-used cfd-limit)) + ;; The position of the last match found by + ;; `c-find-decl-prefix-search'. For regexp matches it's the + ;; end of the matched token, for property matches it's the end + ;; of the property. 0 for the implicit match at bob. + ;; `cfd-limit' if there's no match. + (cfd-match-pos cfd-limit) + ;; The position to continue searching at. + cfd-continue-pos + ;; The position of the last "real" token we've stopped at. + ;; This can be greater than `cfd-continue-pos' when we get + ;; hits inside macros or at `c-decl-end' positions inside + ;; comments. + (cfd-token-pos 0) + ;; The end position of the last entered macro. + (cfd-macro-end 0)) + + ;; Initialize by finding a syntactically relevant start position + ;; before the point, and do the first `c-decl-prefix-re' search + ;; unless we're at bob. + + (let ((start-pos (point)) syntactic-pos) + ;; Must back up a bit since we look for the end of the previous + ;; statement or declaration, which is earlier than the first + ;; returned match. + + (when (c-got-face-at (point) c-literal-faces) + ;; But first we need to move to a syntactically relevant + ;; position. Use the faces to back up to the start of the + ;; comment or string literal. + (when (and (not (bobp)) + (c-got-face-at (1- (point)) c-literal-faces)) + (while (progn + (goto-char (previous-single-property-change + (point) 'face nil (point-min))) + (and (> (point) (point-min)) + (c-got-face-at (point) c-literal-faces))))) + + ;; XEmacs doesn't fontify the quotes surrounding string + ;; literals. + (and (featurep 'xemacs) + (eq (get-text-property (point) 'face) + 'font-lock-string-face) + (not (bobp)) + (progn (backward-char) + (not (looking-at c-string-limit-regexp))) + (forward-char)) + + ;; The font lock package might not have fontified the start of + ;; the literal at all so check that we have arrived at + ;; something that looks like a start or else resort to + ;; `c-literal-limits'. + (unless (looking-at c-literal-start-regexp) + (let ((range (c-literal-limits))) + (if range (goto-char (car range)))))) + + ;; Must back out of any macro so that we don't miss any + ;; declaration that could follow after it, unless the limit is + ;; inside the macro. We only check that for the current line to + ;; save some time; it's enough for the by far most common case + ;; when font-lock refontifies the current line only. + (when (save-excursion + (and (= (forward-line 1) 0) + (or (< (c-point 'eol) cfd-limit) + (progn (backward-char) + (not (eq (char-before) ?\\)))))) + (c-beginning-of-macro)) + + ;; Clear the cache if it applied further down. + (c-invalidate-find-decl-cache start-pos) + + (setq syntactic-pos (point)) + (c-backward-syntactic-ws c-find-decl-syntactic-pos) + + ;; If we hit `c-find-decl-syntactic-pos' and + ;; `c-find-decl-match-pos' is set then we install the cached + ;; values. If we hit `c-find-decl-syntactic-pos' and + ;; `c-find-decl-match-pos' is nil then we know there's no decl + ;; prefix in the whitespace before `c-find-decl-syntactic-pos' + ;; and so we can continue the search from this point. If we + ;; didn't hit `c-find-decl-syntactic-pos' then we're now in the + ;; right spot to begin searching anyway. + (if (and (eq (point) c-find-decl-syntactic-pos) + c-find-decl-match-pos) + + (progn + ;; The match is always outside macros and comments so we + ;; start at the next token. The loop below will later go + ;; back using `cfd-continue-pos' to fix declarations inside + ;; the syntactic ws. + (goto-char syntactic-pos) + (c-forward-syntactic-ws) + (setq cfd-match-pos c-find-decl-match-pos + cfd-continue-pos syntactic-pos) + (if (< cfd-continue-pos (point)) + (setq cfd-token-pos (point)))) + + (setq c-find-decl-syntactic-pos syntactic-pos) + + (when (if (bobp) + ;; Always consider bob a match to get the first declaration + ;; in the file. Do this separately instead of letting + ;; `c-decl-prefix-re' match bob, so that it always can + ;; consume at least one character to ensure that we won't + ;; get stuck in an infinite loop. + (setq cfd-re-match 0) + (backward-char) + (c-beginning-of-current-token) + (< (point) cfd-limit)) + ;; Do an initial search now. In the bob case above it's only done + ;; to search for the `c-type' property. + (c-find-decl-prefix-search)) + + ;; Advance `cfd-continue-pos' if we got a hit before the start + ;; position. The earliest position that could affect after + ;; the start position is the char before the preceding + ;; comments. + (when (and cfd-continue-pos (< cfd-continue-pos start-pos)) + (goto-char syntactic-pos) + (c-backward-comments) + (unless (bobp) + (backward-char) + (c-beginning-of-current-token)) + (setq cfd-continue-pos (max cfd-continue-pos (point)))) + + ;; If we got a match it's always outside macros and comments so + ;; advance to the next token and set `cfd-token-pos'. The loop + ;; below will later go back using `cfd-continue-pos' to fix + ;; declarations inside the syntactic ws. + (when (and (< cfd-match-pos cfd-limit) (< (point) syntactic-pos)) + (goto-char syntactic-pos) + (c-forward-syntactic-ws) + (and cfd-continue-pos + (< cfd-continue-pos (point)) + (setq cfd-token-pos (point)))) + + (setq c-find-decl-match-pos (and (< cfd-match-pos start-pos) + cfd-match-pos)))) + + ;; Now loop. We already got the first match. + + (while (progn + (while (and + (< cfd-match-pos cfd-limit) + + (or + ;; Kludge to filter out matches on the "<" that + ;; aren't open parens, for the sake of languages + ;; that got `c-recognize-<>-arglists' set. + (and (eq (char-before cfd-match-pos) ?<) + (not (c-get-char-property (1- cfd-match-pos) + 'syntax-table))) + + ;; If `cfd-continue-pos' is less or equal to + ;; `cfd-token-pos', we've got a hit inside a macro + ;; that's in the syntactic whitespace before the last + ;; "real" declaration we've checked. If they're equal + ;; we've arrived at the declaration a second time, so + ;; there's nothing to do. + (= cfd-continue-pos cfd-token-pos) + + (progn + ;; If `cfd-continue-pos' is less than `cfd-token-pos' + ;; we're still searching for declarations embedded in + ;; the syntactic whitespace. In that case we need + ;; only to skip comments and not macros, since they + ;; can't be nested, and that's already been done in + ;; `c-find-decl-prefix-search'. + (when (> cfd-continue-pos cfd-token-pos) + (c-forward-syntactic-ws) + (setq cfd-token-pos (point))) + + ;; Continue if the following token fails the + ;; CFD-DECL-RE and CFD-FACE-CHECKLIST checks. + (when (or (>= (point) cfd-limit) + (not (looking-at cfd-decl-re)) + (and cfd-face-checklist + (not (c-got-face-at + (point) cfd-face-checklist)))) + (goto-char cfd-continue-pos) + t))) + + (< (point) cfd-limit)) + (c-find-decl-prefix-search)) + + (< (point) cfd-limit)) + + (when (progn + ;; Narrow to the end of the macro if we got a hit inside + ;; one, to avoid recognizing things that start inside + ;; the macro and end outside it. + (when (> cfd-match-pos cfd-macro-end) + ;; Not in the same macro as in the previous round. + (save-excursion + (goto-char cfd-match-pos) + (setq cfd-macro-end + (if (save-excursion (and (c-beginning-of-macro) + (< (point) cfd-match-pos))) + (progn (c-end-of-macro) + (point)) + 0)))) + + (if (zerop cfd-macro-end) + t + (if (> cfd-macro-end (point)) + (progn (narrow-to-region (point-min) cfd-macro-end) + t) + ;; The matched token was the last thing in the + ;; macro, so the whole match is bogus. + (setq cfd-macro-end 0) + nil))) + + (c-debug-put-decl-spot-faces cfd-match-pos (point)) + (funcall cfd-fun cfd-match-pos (/= cfd-macro-end 0)) + + (when (/= cfd-macro-end 0) + ;; Restore limits if we did macro narrowment above. + (narrow-to-region (point-min) cfd-buffer-end))) + + (goto-char cfd-continue-pos) + (if (= cfd-continue-pos cfd-limit) + (setq cfd-match-pos cfd-limit) + (c-find-decl-prefix-search))))) + + +;; A cache for found types. + +;; Buffer local variable that contains an obarray with the types we've +;; found. If a declaration is recognized somewhere we record the +;; fully qualified identifier in it to recognize it as a type +;; elsewhere in the file too. This is not accurate since we do not +;; bother with the scoping rules of the languages, but in practice the +;; same name is seldom used as both a type and something else in a +;; file, and we only use this as a last resort in ambiguous cases (see +;; `c-font-lock-declarations'). +(defvar c-found-types nil) +(make-variable-buffer-local 'c-found-types) + +(defsubst c-clear-found-types () + ;; Clears `c-found-types'. + ;; + ;; This function does not do any hidden buffer changes. + (setq c-found-types (make-vector 53 0))) + +(defun c-add-type (from to) + ;; Add the given region as a type in `c-found-types'. If the region + ;; doesn't match an existing type but there is a type which is equal + ;; to the given one except that the last character is missing, then + ;; the shorter type is removed. That's done to avoid adding all + ;; prefixes of a type as it's being entered and font locked. This + ;; doesn't cover cases like when characters are removed from a type + ;; or added in the middle. We'd need the position of point when the + ;; font locking is invoked to solve this well. + (unless (and c-recognize-<>-arglists + (save-excursion + (goto-char from) + (c-syntactic-re-search-forward "<" to t))) + ;; To avoid storing very long strings, do not add a type that + ;; contains '<' in languages with angle bracket arglists, since + ;; the type then probably contains a C++ template spec and those + ;; can be fairly sized programs in themselves. + (let ((type (c-syntactic-content from to))) + (unless (intern-soft type c-found-types) + (unintern (substring type 0 -1) c-found-types) + (intern type c-found-types))))) + +(defsubst c-check-type (from to) + ;; Return non-nil if the given region contains a type in + ;; `c-found-types'. + (intern-soft (c-syntactic-content from to) c-found-types)) + +(defun c-list-found-types () + ;; Return all the types in `c-found-types' as a sorted list of + ;; strings. + (let (type-list) + (mapatoms (lambda (type) + (setq type-list (cons (symbol-name type) + type-list))) + c-found-types) + (sort type-list 'string-lessp))) + + +;; Handling of small scale constructs like types and names. + +(defun c-remove-<>-arglist-properties (from to) + ;; Remove all the properties put by `c-forward-<>-arglist' in the + ;; specified region. Point is clobbered. + (goto-char from) + (while (progn (skip-chars-forward "^<>," to) + (< (point) to)) + (if (eq (char-after) ?,) + (when (eq (c-get-char-property (point) 'c-type) 'c-<>-arg-sep) + (c-clear-char-property (point) 'c-type)) + (c-clear-char-property (point) 'syntax-table)) + (forward-char))) + +;; Dynamically bound variable that instructs `c-forward-type' to also +;; treat possible types (i.e. those that it normally returns 'maybe or +;; 'found for) as actual types (and always return 'found for them). +;; This means that it records them in `c-record-type-identifiers' if +;; that is set, and that it adds them to `c-found-types'. +(defvar c-promote-possible-types nil) + +;; Dynamically bound variable that instructs `c-forward-<>-arglist' to +;; not accept arglists that contain more than one argument. It's used +;; to handle ambiguous cases like "foo (a < b, c > d)" better. +(defvar c-disallow-comma-in-<>-arglists nil) + +;; Dynamically bound variables that instructs `c-forward-name', +;; `c-forward-type' and `c-forward-<>-arglist' to record the ranges of +;; all the type and reference identifiers they encounter. They will +;; build lists on these variables where each element is a cons of the +;; buffer positions surrounding each identifier. This recording is +;; only activated when `c-record-type-identifiers' is non-nil. +;; +;; All known types that can't be identifiers are recorded, and also +;; other possible types if `c-promote-possible-types' is set. +;; Recording is however disabled inside angle bracket arglists that +;; are encountered inside names and other angle bracket arglists. +;; Such occurences are taken care of by `c-font-lock-<>-arglists' +;; instead. +;; +;; Only the names in C++ template style references (e.g. "tmpl" in +;; "tmpl<a,b>::foo") are recorded as references, other references +;; aren't handled here. +(defvar c-record-type-identifiers nil) +(defvar c-record-ref-identifiers nil) + +;; If `c-record-type-identifiers' is set, this will receive a cons +;; cell of the range of the last single identifier symbol stepped over +;; by `c-forward-name' if it's successful. This is the range that +;; should be put on one of the record lists by the caller. It's +;; assigned nil if there's no such symbol in the name. +(defvar c-last-identifier-range nil) + +(defmacro c-record-type-id (range) + (if (eq (car-safe range) 'cons) + ;; Always true. + `(setq c-record-type-identifiers + (cons ,range c-record-type-identifiers)) + `(let ((range ,range)) + (if range + (setq c-record-type-identifiers + (cons range c-record-type-identifiers)))))) + +(defmacro c-record-ref-id (range) + (if (eq (car-safe range) 'cons) + ;; Always true. + `(setq c-record-ref-identifiers + (cons ,range c-record-ref-identifiers)) + `(let ((range ,range)) + (if range + (setq c-record-ref-identifiers + (cons range c-record-ref-identifiers)))))) + +;; Dynamically bound variable that instructs `c-forward-type' to +;; record the ranges of types that only are found. Behaves otherwise +;; like `c-record-type-identifiers'. +(defvar c-record-found-types nil) + +(defmacro c-forward-keyword-prefixed-id (type) + ;; Used internally in `c-forward-keyword-clause' to move forward + ;; over a type (if TYPE is 'type) or a name (otherwise) which + ;; possibly is prefixed by keywords and their associated clauses. + ;; Try with a type/name first to not trip up on those that begin + ;; with a keyword. Return t if a known or found type is moved + ;; over. The point is clobbered if nil is returned. If range + ;; recording is enabled, the identifier is recorded on as a type + ;; if TYPE is 'type or as a reference if TYPE is 'ref. + `(let (res) + (while (if (setq res ,(if (eq type 'type) + `(c-forward-type) + `(c-forward-name))) + nil + (and (looking-at c-keywords-regexp) + (c-forward-keyword-clause)))) + (when (memq res '(t known found prefix)) + ,(when (eq type 'ref) + `(when c-record-type-identifiers + (c-record-ref-id c-last-identifier-range))) + t))) + +(defmacro c-forward-id-comma-list (type) + ;; Used internally in `c-forward-keyword-clause' to move forward + ;; over a comma separated list of types or names using + ;; `c-forward-keyword-prefixed-id'. + `(while (and (progn + (setq safe-pos (point)) + (eq (char-after) ?,)) + (progn + (forward-char) + (c-forward-syntactic-ws) + (c-forward-keyword-prefixed-id ,type))))) + +(defun c-forward-keyword-clause () + ;; The first submatch in the current match data is assumed to + ;; surround a token. If it's a keyword, move over it and any + ;; following clauses associated with it, stopping at the next + ;; following token. t is returned in that case, otherwise the point + ;; stays and nil is returned. The kind of clauses that are + ;; recognized are those specified by `c-type-list-kwds', + ;; `c-ref-list-kwds', `c-colon-type-list-kwds', + ;; `c-paren-nontype-kwds', `c-paren-type-kwds', `c-<>-type-kwds', + ;; and `c-<>-arglist-kwds'. + + (let ((kwd-sym (c-keyword-sym (match-string 1))) safe-pos pos) + (when kwd-sym + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (setq safe-pos (point)) + + (cond + ((and (c-keyword-member kwd-sym 'c-type-list-kwds) + (c-forward-keyword-prefixed-id type)) + ;; There's a type directly after a keyword in `c-type-list-kwds'. + (c-forward-id-comma-list type)) + + ((and (c-keyword-member kwd-sym 'c-ref-list-kwds) + (c-forward-keyword-prefixed-id ref)) + ;; There's a name directly after a keyword in `c-ref-list-kwds'. + (c-forward-id-comma-list ref)) + + ((and (c-keyword-member kwd-sym 'c-paren-any-kwds) + (eq (char-after) ?\()) + ;; There's an open paren after a keyword in `c-paren-any-kwds'. + + (forward-char) + (when (and (setq pos (c-up-list-forward)) + (eq (char-before pos) ?\))) + (when (and c-record-type-identifiers + (c-keyword-member kwd-sym 'c-paren-type-kwds)) + ;; Use `c-forward-type' on every identifier we can find + ;; inside the paren, to record the types. + (while (c-syntactic-re-search-forward c-symbol-start pos t) + (goto-char (match-beginning 0)) + (unless (c-forward-type) + (looking-at c-symbol-key) ; Always matches. + (goto-char (match-end 0))))) + + (goto-char pos) + (c-forward-syntactic-ws) + (setq safe-pos (point)))) + + ((and (c-keyword-member kwd-sym 'c-<>-sexp-kwds) + (eq (char-after) ?<) + (c-forward-<>-arglist (c-keyword-member kwd-sym 'c-<>-type-kwds) + (or c-record-type-identifiers + c-disallow-comma-in-<>-arglists))) + (c-forward-syntactic-ws) + (setq safe-pos (point))) + + ((and (c-keyword-member kwd-sym 'c-nonsymbol-sexp-kwds) + (not (looking-at c-symbol-start))) + (c-forward-sexp) + (c-forward-syntactic-ws) + (setq safe-pos (point)))) + + (when (and (c-keyword-member kwd-sym 'c-colon-type-list-kwds) + (progn + ;; If a keyword matched both one of the types above and + ;; this one, we match `c-colon-type-list-re' after the + ;; clause matched above. + (goto-char safe-pos) + (looking-at c-colon-type-list-re)) + (progn + (goto-char (match-end 0)) + (c-forward-syntactic-ws) + (c-forward-keyword-prefixed-id type))) + ;; There's a type after the `c-colon-type-list-re' + ;; match after a keyword in `c-colon-type-list-kwds'. + (c-forward-id-comma-list type)) + + (goto-char safe-pos) + t))) + +(defun c-forward-<>-arglist (all-types reparse) + ;; The point is assumed to be at a '<'. Try to treat it as the open + ;; paren of an angle bracket arglist and move forward to the the + ;; corresponding '>'. If successful, the point is left after the + ;; '>' and t is returned, otherwise the point isn't moved and nil is + ;; returned. If ALL-TYPES is t then all encountered arguments in + ;; the arglist that might be types are treated as found types. + ;; + ;; The surrounding '<' and '>' are given syntax-table properties to + ;; make them behave like parentheses. Each argument separating ',' + ;; is also set to `c-<>-arg-sep' in the `c-type' property. These + ;; properties are also cleared in a relevant region forward from the + ;; point if they seems to be set and it turns out to not be an + ;; arglist. + ;; + ;; If the arglist has been successfully parsed before then paren + ;; syntax properties will be exploited to quickly jump to the end, + ;; but that can be disabled by setting REPARSE to t. That is + ;; necessary if the various side effects, e.g. recording of type + ;; ranges, are important. Setting REPARSE to t only applies + ;; recursively to nested angle bracket arglists if + ;; `c-disallow-comma-in-<>-arglists' is set. + ;; + ;; This is primarily used in C++ to mark up template arglists. C++ + ;; disambiguates them by checking whether the preceding name is a + ;; template or not. We can't do that, so we assume it is a template + ;; if it can be parsed as one. This usually works well since + ;; comparison expressions on the forms "a < b > c" or "a < b, c > d" + ;; in almost all cases would be pointless. Cases like function + ;; calls on the form "foo (a < b, c > d)" needs to be handled + ;; specially through the `c-disallow-comma-in-<>-arglists' variable. + + (let ((start (point)) + ;; If `c-record-type-identifiers' is set then activate + ;; recording of any found types that constitute an argument in + ;; the arglist. + (c-record-found-types (if c-record-type-identifiers t))) + (if (catch 'angle-bracket-arglist-escape + (setq c-record-found-types + (c-forward-<>-arglist-recur all-types reparse))) + (progn + (when (consp c-record-found-types) + (setq c-record-type-identifiers + ;; `nconc' doesn't mind that the tail of + ;; `c-record-found-types' is t. + (nconc c-record-found-types c-record-type-identifiers))) + t) + + (goto-char start) + nil))) + +(defun c-forward-<>-arglist-recur (all-types reparse) + ;; Recursive part of `c-forward-<>-arglist'. + + (let ((start (point)) res pos tmp + ;; Cover this so that any recorded found type ranges are + ;; automatically lost if it turns out to not be an angle + ;; bracket arglist. It's propagated through the return value + ;; on successful completion. + (c-record-found-types c-record-found-types) + ;; List that collects the positions after the argument + ;; separating ',' in the arglist. + arg-start-pos) + + ;; If the '<' has paren open syntax then we've marked it as an + ;; angle bracket arglist before, so try to skip to the end and see + ;; that the close paren matches. + (if (and (c-get-char-property (point) 'syntax-table) + (progn + (forward-char) + (if (and (not (looking-at c-<-op-cont-regexp)) + (if (c-parse-sexp-lookup-properties) + (c-go-up-list-forward) + (catch 'at-end + (let ((depth 1)) + (while (c-syntactic-re-search-forward + "[<>]" nil t t) + (when (c-get-char-property (1- (point)) + 'syntax-table) + (if (eq (char-before) ?<) + (setq depth (1+ depth)) + (setq depth (1- depth)) + (when (= depth 0) (throw 'at-end t))))) + nil))) + (not (looking-at c->-op-cont-regexp)) + (save-excursion + (backward-char) + (= (point) + (progn (c-beginning-of-current-token) + (point))))) + + ;; Got an arglist that appears to be valid. + (if reparse + ;; Reparsing is requested, so zap the properties in the + ;; region and go on to redo it. It's done here to + ;; avoid leaving it behind if we exit through + ;; `angle-bracket-arglist-escape' below. + (progn + (c-remove-<>-arglist-properties start (point)) + (goto-char start) + nil) + t) + + ;; Got unmatched paren brackets or either paren was + ;; actually some other token. Recover by clearing the + ;; syntax properties on all the '<' and '>' in the + ;; range where we'll search for the arglist below. + (goto-char start) + (while (progn (skip-chars-forward "^<>,;{}") + (looking-at "[<>,]")) + (if (eq (char-after) ?,) + (when (eq (c-get-char-property (point) 'c-type) + 'c-<>-arg-sep) + (c-clear-char-property (point) 'c-type)) + (c-clear-char-property (point) 'syntax-table)) + (forward-char)) + (goto-char start) + nil))) + t + + (forward-char) + (unless (looking-at c-<-op-cont-regexp) + (while (and + (progn + + (when c-record-type-identifiers + (if all-types + + ;; All encountered identifiers are types, so set the + ;; promote flag and parse the type. + (progn + (c-forward-syntactic-ws) + (when (looking-at c-identifier-start) + (let ((c-promote-possible-types t)) + (c-forward-type)))) + + ;; Check if this arglist argument is a sole type. If + ;; it's known then it's recorded in + ;; `c-record-type-identifiers'. If it only is found + ;; then it's recorded in `c-record-found-types' which we + ;; might roll back if it turns out that this isn't an + ;; angle bracket arglist afterall. + (when (memq (char-before) '(?, ?<)) + (let ((orig-record-found-types c-record-found-types)) + (c-forward-syntactic-ws) + (and (memq (c-forward-type) '(known found)) + (not (looking-at "[,>]")) + ;; A found type was recorded but it's not the + ;; only thing in the arglist argument, so reset + ;; `c-record-found-types'. + (setq c-record-found-types + orig-record-found-types)))))) + + (setq pos (point)) + (or (when (eq (char-after) ?>) + ;; Must check for '>' at the very start separately, + ;; since the regexp below has to avoid ">>" without + ;; using \\=. + (forward-char) + t) + + ;; Note: This regexp exploits the match order in + ;; \| so that "<>" is matched by "<" rather than + ;; "[^>:-]>". + (c-syntactic-re-search-forward + "[<;{},]\\|\\([^>:-]>\\)" nil 'move t t 1) + + ;; If the arglist starter has lost its open paren + ;; syntax but not the closer, we won't find the + ;; closer above since we only search in the + ;; balanced sexp. In that case we stop just short + ;; of it so check if the following char is the closer. + (when (eq (char-after) ?>) + ;; Remove its syntax so that we don't enter the + ;; recovery code below. That's not necessary + ;; since there's no real reason to suspect that + ;; things inside the arglist are unbalanced. + (c-clear-char-property (point) 'syntax-table) + (forward-char) + t))) + + (cond + ((eq (char-before) ?>) + ;; Either an operator starting with '>' or the end of + ;; the angle bracket arglist. + + (if (and (/= (1- (point)) pos) + (c-get-char-property (1- (point)) 'syntax-table) + (progn + (c-clear-char-property (1- (point)) 'syntax-table) + (c-parse-sexp-lookup-properties))) + + ;; We've skipped past a list that ended with '>'. It + ;; must be unbalanced since nested arglists are handled + ;; in the case below. Recover by removing all paren + ;; properties on '<' and '>' in the searched region and + ;; redo the search. + (progn + (c-remove-<>-arglist-properties pos (point)) + (goto-char pos) + t) + + (if (looking-at c->-op-cont-regexp) + (progn + (when (text-property-not-all + (1- (point)) (match-end 0) 'syntax-table nil) + (c-remove-<>-arglist-properties (1- (point)) + (match-end 0))) + (goto-char (match-end 0)) + t) + + ;; The angle bracket arglist is finished. + (while arg-start-pos + (c-put-char-property (1- (car arg-start-pos)) + 'c-type 'c-<>-arg-sep) + (setq arg-start-pos (cdr arg-start-pos))) + (c-mark-<-as-paren start) + (c-mark->-as-paren (1- (point))) + (setq res t) + nil))) + + ((eq (char-before) ?<) + ;; Either an operator starting with '<' or a nested arglist. + + (setq pos (point)) + (let (id-start id-end subres keyword-match) + (if (if (looking-at c-<-op-cont-regexp) + (setq tmp (match-end 0)) + (setq tmp pos) + (backward-char) + (not + (and + + (save-excursion + ;; There's always an identifier before a angle + ;; bracket arglist, or a keyword in + ;; `c-<>-type-kwds' or `c-<>-arglist-kwds'. + (c-backward-syntactic-ws) + (setq id-end (point)) + (c-simple-skip-symbol-backward) + (when (or (setq keyword-match + (looking-at c-opt-<>-sexp-key)) + (not (looking-at c-keywords-regexp))) + (setq id-start (point)))) + + (setq subres + (let ((c-record-type-identifiers nil) + (c-record-found-types nil)) + (c-forward-<>-arglist-recur + (and keyword-match + (c-keyword-member + (c-keyword-sym (match-string 1)) + 'c-<>-type-kwds)) + (and reparse + c-disallow-comma-in-<>-arglists)))) + ))) + + ;; It was not an angle bracket arglist. + (progn + (when (text-property-not-all + (1- pos) tmp 'syntax-table nil) + (if (c-parse-sexp-lookup-properties) + ;; Got an invalid open paren syntax on this + ;; '<'. We'll probably get an unbalanced '>' + ;; further ahead if we just remove the syntax + ;; here, so recover by removing all paren + ;; properties up to and including the + ;; balancing close paren. + (parse-partial-sexp pos (point-max) -1) + (goto-char tmp)) + (c-remove-<>-arglist-properties pos (point))) + (goto-char tmp)) + + ;; It was an angle bracket arglist. + (setq c-record-found-types subres) + + ;; Record the identifier before the template as a type + ;; or reference depending on whether the arglist is last + ;; in a qualified identifier. + (when (and c-record-type-identifiers + (not keyword-match)) + (if (and c-opt-identifier-concat-key + (progn + (c-forward-syntactic-ws) + (looking-at c-opt-identifier-concat-key))) + (c-record-ref-id (cons id-start id-end)) + (c-record-type-id (cons id-start id-end)))))) + t) + + ((and (eq (char-before) ?,) + (not c-disallow-comma-in-<>-arglists)) + ;; Just another argument. Record the position. The + ;; type check stuff that made us stop at it is at + ;; the top of the loop. + (setq arg-start-pos (cons (point) arg-start-pos))) + + (t + ;; Got a character that can't be in an angle bracket + ;; arglist argument. Abort using `throw', since + ;; it's useless to try to find a surrounding arglist + ;; if we're nested. + (throw 'angle-bracket-arglist-escape nil)))))) + + (if res + (or c-record-found-types t))))) + +(defun c-forward-name () + ;; Move forward over a complete name if at the beginning of one, + ;; stopping at the next following token. If the point is not at + ;; something that are recognized as name then it stays put. A name + ;; could be something as simple as "foo" in C or something as + ;; complex as "X<Y<class A<int>::B, BIT_MAX >> b>, ::operator<> :: + ;; Z<(a>b)> :: operator const X<&foo>::T Q::G<unsigned short + ;; int>::*volatile const" in C++ (this function is actually little + ;; more than a `looking-at' call in all modes except those that, + ;; like C++, have `c-recognize-<>-arglists' set). Return nil if no + ;; name is found, 'template if it's an identifier ending with an + ;; angle bracket arglist, 'operator of it's an operator identifier, + ;; or t if it's some other kind of name. + + (let ((pos (point)) res id-start id-end + ;; Turn off `c-promote-possible-types' here since we might + ;; call `c-forward-<>-arglist' and we don't want it to promote + ;; every suspect thing in the arglist to a type. We're + ;; typically called from `c-forward-type' in this case, and + ;; the caller only wants the top level type that it finds to + ;; be promoted. + c-promote-possible-types) + (while + (and + (looking-at c-identifier-key) + + (progn + ;; Check for keyword. We go to the last symbol in + ;; `c-identifier-key' first. + (if (eq c-identifier-key c-symbol-key) + (setq id-start (point) + id-end (match-end 0)) + (goto-char (setq id-end (match-end 0))) + (c-simple-skip-symbol-backward) + (setq id-start (point))) + + (if (looking-at c-keywords-regexp) + (when (and (c-major-mode-is 'c++-mode) + (looking-at + (cc-eval-when-compile + (concat "\\(operator\\|\\(template\\)\\)" + "\\(" (c-lang-const c-nonsymbol-key c++) + "\\|$\\)"))) + (if (match-beginning 2) + ;; "template" is only valid inside an + ;; identifier if preceded by "::". + (save-excursion + (c-backward-syntactic-ws) + (and (c-safe (backward-char 2) t) + (looking-at "::"))) + t)) + + ;; Handle a C++ operator or template identifier. + (goto-char id-end) + (c-forward-syntactic-ws) + (cond ((eq (char-before id-end) ?e) + ;; Got "... ::template". + (let ((subres (c-forward-name))) + (when subres + (setq pos (point) + res subres)))) + + ((looking-at c-identifier-start) + ;; Got a cast operator. + (when (c-forward-type) + (setq pos (point) + res 'operator) + ;; Now we should match a sequence of either + ;; '*', '&' or a name followed by ":: *", + ;; where each can be followed by a sequence + ;; of `c-opt-type-modifier-key'. + (while (cond ((looking-at "[*&]") + (goto-char (match-end 0)) + t) + ((looking-at c-identifier-start) + (and (c-forward-name) + (looking-at "::") + (progn + (goto-char (match-end 0)) + (c-forward-syntactic-ws) + (eq (char-after) ?*)) + (progn + (forward-char) + t)))) + (while (progn + (c-forward-syntactic-ws) + (setq pos (point)) + (looking-at c-opt-type-modifier-key)) + (goto-char (match-end 1)))))) + + ((looking-at c-overloadable-operators-regexp) + ;; Got some other operator. + (when c-record-type-identifiers + (setq c-last-identifier-range + (cons (point) (match-end 0)))) + (goto-char (match-end 0)) + (c-forward-syntactic-ws) + (setq pos (point) + res 'operator))) + + nil) + + (when c-record-type-identifiers + (setq c-last-identifier-range + (cons id-start id-end))) + (goto-char id-end) + (c-forward-syntactic-ws) + (setq pos (point) + res t))) + + (progn + (goto-char pos) + (when (or c-opt-identifier-concat-key + c-recognize-<>-arglists) + + (cond + ((and c-opt-identifier-concat-key + (looking-at c-opt-identifier-concat-key)) + ;; Got a concatenated identifier. This handles the + ;; cases with tricky syntactic whitespace that aren't + ;; covered in `c-identifier-key'. + (goto-char (match-end 0)) + (c-forward-syntactic-ws) + t) + + ((and c-recognize-<>-arglists + (eq (char-after) ?<)) + ;; Maybe an angle bracket arglist. + (when (let ((c-record-type-identifiers nil) + (c-record-found-types nil)) + (c-forward-<>-arglist + nil c-disallow-comma-in-<>-arglists)) + (c-forward-syntactic-ws) + (setq pos (point)) + (if (and c-opt-identifier-concat-key + (looking-at c-opt-identifier-concat-key)) + ;; Continue if there's an identifier concatenation + ;; operator after the template argument. + (progn + (when c-record-type-identifiers + (c-record-ref-id (cons id-start id-end)) + (setq c-last-identifier-range nil)) + (forward-char 2) + (c-forward-syntactic-ws) + t) + ;; `c-add-type' isn't called here since we don't + ;; want to add types containing angle bracket + ;; arglists. + (when c-record-type-identifiers + (c-record-type-id (cons id-start id-end)) + (setq c-last-identifier-range nil)) + (setq res 'template) + nil))) + ))))) + + (goto-char pos) + res)) + +(defun c-forward-type () + ;; Move forward over a type spec if at the beginning of one, + ;; stopping at the next following token. Return t if it's a known + ;; type that can't be a name, 'known if it's an otherwise known type + ;; (according to `*-font-lock-extra-types'), 'prefix if it's a known + ;; prefix of a type, 'found if it's a type that matches one in + ;; `c-found-types', 'maybe if it's an identfier that might be a + ;; type, or nil if it can't be a type (the point isn't moved then). + ;; The point is assumed to be at the beginning of a token. + ;; + ;; Note that this function doesn't skip past the brace definition + ;; that might be considered part of the type, e.g. + ;; "enum {a, b, c} foo". + (let ((start (point)) pos res res2 id-start id-end id-range) + + ;; Skip leading type modifiers. If any are found we know it's a + ;; prefix of a type. + (when c-opt-type-modifier-key + (while (looking-at c-opt-type-modifier-key) + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (setq res 'prefix))) + + (cond + ((looking-at c-type-prefix-key) + ;; Looking at a keyword that prefixes a type identifier, + ;; e.g. "class". + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (setq pos (point)) + (if (memq (setq res2 (c-forward-name)) '(t template)) + (progn + (when (eq res2 t) + ;; In many languages the name can be used without the + ;; prefix, so we add it to `c-found-types'. + (c-add-type pos (point)) + (when c-record-type-identifiers + (c-record-type-id c-last-identifier-range))) + (setq res t)) + ;; Invalid syntax. + (goto-char start) + (setq res nil))) + + ((progn + (setq pos nil) + (if (looking-at c-identifier-start) + (save-excursion + (setq id-start (point) + res2 (c-forward-name)) + (when res2 + (setq id-end (point) + id-range c-last-identifier-range)))) + (and (cond ((looking-at c-primitive-type-key) + (setq res t)) + ((c-with-syntax-table c-identifier-syntax-table + (looking-at c-known-type-key)) + (setq res 'known))) + (or (not id-end) + (>= (save-excursion + (save-match-data + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (setq pos (point)))) + id-end) + (setq res nil)))) + ;; Looking at a primitive or known type identifier. We've + ;; checked for a name first so that we don't go here if the + ;; known type match only is a prefix of another name. + + (setq id-end (match-end 1)) + + (when (and c-record-type-identifiers + (or c-promote-possible-types (eq res t))) + (c-record-type-id (cons (match-beginning 1) (match-end 1)))) + + (if (and c-opt-type-component-key + (save-match-data + (looking-at c-opt-type-component-key))) + ;; There might be more keywords for the type. + (let (safe-pos) + (c-forward-keyword-clause) + (while (progn + (setq safe-pos (point)) + (looking-at c-opt-type-component-key)) + (when (and c-record-type-identifiers + (looking-at c-primitive-type-key)) + (c-record-type-id (cons (match-beginning 1) + (match-end 1)))) + (c-forward-keyword-clause)) + (if (looking-at c-primitive-type-key) + (progn + (when c-record-type-identifiers + (c-record-type-id (cons (match-beginning 1) + (match-end 1)))) + (c-forward-keyword-clause) + (setq res t)) + (goto-char safe-pos) + (setq res 'prefix))) + (unless (save-match-data (c-forward-keyword-clause)) + (if pos + (goto-char pos) + (goto-char (match-end 1)) + (c-forward-syntactic-ws))))) + + (res2 + (cond ((eq res2 t) + ;; A normal identifier. + (goto-char id-end) + (if (or res c-promote-possible-types) + (progn + (c-add-type id-start id-end) + (when c-record-type-identifiers + (c-record-type-id id-range)) + (unless res + (setq res 'found))) + (setq res (if (c-check-type id-start id-end) + ;; It's an identifier that has been used as + ;; a type somewhere else. + 'found + ;; It's an identifier that might be a type. + 'maybe)))) + ((eq res2 'template) + ;; A template is a type. + (goto-char id-end) + (setq res t)) + (t + ;; Otherwise it's an operator identifier, which is not a type. + (goto-char start) + (setq res nil))))) + + (when res + ;; Skip trailing type modifiers. If any are found we know it's + ;; a type. + (when c-opt-type-modifier-key + (while (looking-at c-opt-type-modifier-key) + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (setq res t))) + + ;; Step over any type suffix operator. Do not let the existence + ;; of these alter the classification of the found type, since + ;; these operators typically are allowed in normal expressions + ;; too. + (when c-opt-type-suffix-key + (while (looking-at c-opt-type-suffix-key) + (goto-char (match-end 1)) + (c-forward-syntactic-ws))) + + (when c-opt-type-concat-key + ;; Look for a trailing operator that concatenate the type with + ;; a following one, and if so step past that one through a + ;; recursive call. + (setq pos (point)) + (let* ((c-promote-possible-types (or (memq res '(t known)) + c-promote-possible-types)) + ;; If we can't promote then set `c-record-found-types' so that + ;; we can merge in the types from the second part afterwards if + ;; it turns out to be a known type there. + (c-record-found-types (and c-record-type-identifiers + (not c-promote-possible-types)))) + (if (and (looking-at c-opt-type-concat-key) + + (progn + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (setq res2 (c-forward-type)))) + + (progn + ;; If either operand certainly is a type then both are, but we + ;; don't let the existence of the operator itself promote two + ;; uncertain types to a certain one. + (cond ((eq res t)) + ((or (eq res 'known) (memq res2 '(t known))) + (c-add-type id-start id-end) + (when c-record-type-identifiers + (c-record-type-id id-range)) + (setq res t)) + ((eq res 'found)) + ((eq res2 'found) + (setq res 'found)) + (t + (setq res 'maybe))) + + (when (and (eq res t) + (consp c-record-found-types)) + ;; Merge in the ranges of any types found by the second + ;; `c-forward-type'. + (setq c-record-type-identifiers + ;; `nconc' doesn't mind that the tail of + ;; `c-record-found-types' is t. + (nconc c-record-found-types + c-record-type-identifiers)))) + + (goto-char pos)))) + + (when (and c-record-found-types (memq res '(known found)) id-range) + (setq c-record-found-types + (cons id-range c-record-found-types)))) + + ;;(message "c-forward-type %s -> %s: %s" start (point) res) + + res)) + + +;; Handling of large scale constructs like statements and declarations. + (defun c-beginning-of-inheritance-list (&optional lim) ;; Go to the first non-whitespace after the colon that starts a ;; multiple inheritance introduction. Optional LIM is the farthest ;; back we should search. - (let* ((lim (or lim (c-point 'bod)))) + (let* ((lim (or lim (save-excursion + (c-beginning-of-syntax) + (point))))) (c-with-syntax-table c++-template-syntax-table - (c-backward-token-1 0 t lim) - (while (and (looking-at "[_a-zA-Z<,]") - (= (c-backward-token-1 1 t lim) 0))) + (c-backward-token-2 0 t lim) + (while (and (or (looking-at c-symbol-start) + (looking-at "[<,]")) + (zerop (c-backward-token-2 1 t lim)))) (skip-chars-forward "^:")))) (defun c-in-method-def-p () @@ -1414,8 +4230,8 @@ (defun c-at-toplevel-p () "Return a determination as to whether point is at the `top-level'. Being at the top-level means that point is either outside any -enclosing block (such function definition), or inside a class, -namespace or extern definition, but outside any method blocks. +enclosing block (such function definition), or only inside a class, +namespace or other block that contains another declaration level. If point is not at the top-level (e.g. it is inside a method definition), then nil is returned. Otherwise, if point is at a @@ -1428,33 +4244,20 @@ (or (not (c-most-enclosing-brace paren-state)) (c-search-uplist-for-classkey paren-state)))) -(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". Non-nil is returned in this case, in all - ;; other cases nil is returned and point isn't moved. - (when (and (looking-at - (concat "#[ \t]*" - "define[ \t]+\\(\\sw\\|_\\)+\\(\([^\)]*\)\\)?" - "\\([ \t]\\|\\\\\n\\)*")) - (not (= (match-end 0) (c-point 'eol)))) - (goto-char (match-end 0)))) - -(defun c-just-after-func-arglist-p (&optional containing lim) +(defun c-just-after-func-arglist-p (&optional lim) ;; Return t if we are between a function's argument list closing ;; paren and its opening brace. Note that the list close brace ;; could be followed by a "const" specifier or a member init hanging - ;; colon. Optional CONTAINING is position of containing s-exp open - ;; brace. If not supplied, point is used as search start. LIM is - ;; used as bound for some backward buffer searches; the search might - ;; continue past it. + ;; colon. LIM is used as bound for some backward buffer searches; + ;; the search might continue past it. ;; ;; Note: This test is easily fooled. It only works reasonably well ;; in the situations where `c-guess-basic-syntax' uses it. (save-excursion - (c-backward-syntactic-ws lim) - (let ((checkpoint (or containing (point)))) - (goto-char checkpoint) + (if (c-mode-is-new-awk-p) + (c-awk-backward-syntactic-ws lim) + (c-backward-syntactic-ws lim)) + (let ((checkpoint (point))) ;; could be looking at const specifier (if (and (eq (char-before) ?t) (forward-word -1) @@ -1510,24 +4313,44 @@ ;; position that bounds the backward search for the argument list. ;; ;; Note: A declaration level context is assumed; the test can return - ;; false positives for statements and #define headers. This test is - ;; even more easily fooled than `c-just-after-func-arglist-p'. + ;; false positives for statements. This test is even more easily + ;; fooled than `c-just-after-func-arglist-p'. + (save-excursion (save-restriction + ;; Go back to the closest preceding normal parenthesis sexp. We ;; take that as the argument list in the function header. Then ;; check that it's followed by some symbol before the next ';' ;; or '{'. If it does, it's the header of the K&R argdecl we're ;; in. (if lim (narrow-to-region lim (point))) - (let (paren-end) - (and (c-safe (setq paren-end (c-down-list-backward (point)))) - (eq (char-after paren-end) ?\)) - (progn - (goto-char (1+ paren-end)) + (let ((outside-macro (not (c-query-macro-start))) + paren-end) + + (catch 'done + (while (if (and (c-safe (setq paren-end + (c-down-list-backward (point)))) + (eq (char-after paren-end) ?\))) + (progn + (goto-char (1+ paren-end)) + (if outside-macro + (c-beginning-of-macro))) + (throw 'done nil)))) + + (and (progn (c-forward-syntactic-ws) (looking-at "\\w\\|\\s_")) (c-safe (c-up-list-backward paren-end)) + + (save-excursion + ;; If it's a K&R declaration then we're now at the + ;; beginning of the function arglist. Check that there + ;; isn't a '=' before it in this statement since that + ;; means it some kind of initialization instead. + (c-syntactic-skip-backward "^;=}{") + (not (eq (char-before) ?=))) + (point)))))) (defun c-skip-conditional () @@ -1551,10 +4374,10 @@ ;; If looking at the token after a conditional then return the ;; position of its start, otherwise return nil. (save-excursion - (and (= (c-backward-token-1 1 t lim) 0) + (and (zerop (c-backward-token-2 1 t lim)) (or (looking-at c-block-stmt-1-key) (and (eq (char-after) ?\() - (= (c-backward-token-1 1 t lim) 0) + (zerop (c-backward-token-2 1 t lim)) (looking-at c-block-stmt-2-key))) (point)))) @@ -1594,15 +4417,17 @@ ;; semicolon. I.e. search forward for the closest following ;; (syntactically relevant) '{', '=' or ';' token. Point is left ;; _after_ the first found token, or at point-max if none is found. - (c-with-syntax-table (if (c-major-mode-is 'c++-mode) - c++-template-syntax-table - (syntax-table)) - (while (and (c-syntactic-re-search-forward "[;{=]" nil 'move 1 t) - ;; In Pike it can be an operator identifier containing - ;; '='. - (c-major-mode-is 'pike-mode) - (eq (char-before) ?=) - (c-on-identifier))))) + (if (c-major-mode-is 'c++-mode) + ;; In C++ we need to take special care to handle those pesky + ;; template brackets. + (while (and (c-syntactic-re-search-forward "[;{=<]" nil 'move t) + (when (eq (char-before) ?<) + (c-with-syntax-table c++-template-syntax-table + (if (c-safe (goto-char (c-up-list-forward (point)))) + t + (goto-char (point-max)) + nil))))) + (c-syntactic-re-search-forward "[;{=]" nil 'move t t))) (defun c-beginning-of-decl-1 (&optional lim) ;; Go to the beginning of the current declaration, or the beginning @@ -1620,73 +4445,85 @@ ;; declarations, e.g. "struct foo { ... }" and "bar;" in this case. (catch 'return (let* ((start (point)) - (last-stmt-start (point)) - (move (c-beginning-of-statement-1 lim t t))) - - (while (and (/= last-stmt-start (point)) - (save-excursion - (c-backward-syntactic-ws lim) - (not (memq (char-before) '(?\; ?} ?: nil))))) + (last-stmt-start (point)) + (move (c-beginning-of-statement-1 lim t t))) + ;; `c-beginning-of-statement-1' stops at a block start, but we ;; want to continue if the block doesn't begin a top level ;; construct, i.e. if it isn't preceded by ';', '}', ':', or bob. - (setq last-stmt-start (point) - move (c-beginning-of-statement-1 lim t t))) - - (when c-recognize-knr-p - (let ((fallback-pos (point)) knr-argdecl-start) - ;; Handle K&R argdecls. Back up after the "statement" jumped - ;; over by `c-beginning-of-statement-1', unless it was the - ;; function body, in which case we're sitting on the opening - ;; brace now. Then test if we're in a K&R argdecl region and - ;; that we started at the other side of the first argdecl in - ;; it. - (unless (eq (char-after) ?{) - (goto-char last-stmt-start)) - (if (and (setq knr-argdecl-start (c-in-knr-argdecl lim)) - (< knr-argdecl-start start) - (progn - (goto-char knr-argdecl-start) - (not (eq (c-beginning-of-statement-1 lim t t) 'macro)))) - (throw 'return - (cons (if (eq (char-after fallback-pos) ?{) - 'previous - 'same) - knr-argdecl-start)) - (goto-char fallback-pos)))) - - (when c-opt-access-key - ;; Might have ended up before a protection label. This should - ;; perhaps be checked before `c-recognize-knr-p' to be really - ;; accurate, but we know that no language has both. - (while (looking-at c-opt-access-key) - (goto-char (match-end 0)) - (c-forward-syntactic-ws) - (when (>= (point) start) - (goto-char start) - (throw 'return (cons 'same nil))))) - - ;; `c-beginning-of-statement-1' counts each brace block as a - ;; separate statement, so the result will be 'previous if we've - ;; moved over any. If they were brace list initializers we might - ;; not have moved over a declaration boundary though, so change it - ;; to 'same if we've moved past a '=' before '{', but not ';'. - ;; (This ought to be integrated into `c-beginning-of-statement-1', - ;; so we avoid this extra pass which potentially can search over a - ;; large amount of text.) - (if (and (eq move 'previous) - (c-with-syntax-table (if (c-major-mode-is 'c++-mode) - c++-template-syntax-table - (syntax-table)) - (save-excursion - (and (c-syntactic-re-search-forward "[;={]" start t 1 t) - (eq (char-before) ?=) - (c-syntactic-re-search-forward "[;{]" start t 1 t) - (eq (char-before) ?{) - (c-safe (goto-char (c-up-list-forward (point))) t) - (not (c-syntactic-re-search-forward ";" start t 1 t)))))) - (cons 'same nil) - (cons move nil))))) + (let ((beg (point)) tentative-move) + (while (and + ;; Must check with c-opt-method-key in ObjC mode. + (not (and c-opt-method-key + (looking-at c-opt-method-key))) + (/= last-stmt-start (point)) + (progn + (c-backward-syntactic-ws lim) + (not (memq (char-before) '(?\; ?} ?: nil)))) + ;; Check that we don't move from the first thing in a + ;; macro to its header. + (not (eq (setq tentative-move + (c-beginning-of-statement-1 lim t t)) + 'macro))) + (setq last-stmt-start beg + beg (point) + move tentative-move)) + (goto-char beg)) + + (when c-recognize-knr-p + (let ((fallback-pos (point)) knr-argdecl-start) + ;; Handle K&R argdecls. Back up after the "statement" jumped + ;; over by `c-beginning-of-statement-1', unless it was the + ;; function body, in which case we're sitting on the opening + ;; brace now. Then test if we're in a K&R argdecl region and + ;; that we started at the other side of the first argdecl in + ;; it. + (unless (eq (char-after) ?{) + (goto-char last-stmt-start)) + (if (and (setq knr-argdecl-start (c-in-knr-argdecl lim)) + (< knr-argdecl-start start) + (progn + (goto-char knr-argdecl-start) + (not (eq (c-beginning-of-statement-1 lim t t) 'macro)))) + (throw 'return + (cons (if (eq (char-after fallback-pos) ?{) + 'previous + 'same) + knr-argdecl-start)) + (goto-char fallback-pos)))) + + (when c-opt-access-key + ;; Might have ended up before a protection label. This should + ;; perhaps be checked before `c-recognize-knr-p' to be really + ;; accurate, but we know that no language has both. + (while (looking-at c-opt-access-key) + (goto-char (match-end 0)) + (c-forward-syntactic-ws) + (when (>= (point) start) + (goto-char start) + (throw 'return (cons 'same nil))))) + + ;; `c-beginning-of-statement-1' counts each brace block as a + ;; separate statement, so the result will be 'previous if we've + ;; moved over any. If they were brace list initializers we might + ;; not have moved over a declaration boundary though, so change it + ;; to 'same if we've moved past a '=' before '{', but not ';'. + ;; (This ought to be integrated into `c-beginning-of-statement-1', + ;; so we avoid this extra pass which potentially can search over a + ;; large amount of text.) + (if (and (eq move 'previous) + (c-with-syntax-table (if (c-major-mode-is 'c++-mode) + c++-template-syntax-table + (syntax-table)) + (save-excursion + (and (c-syntactic-re-search-forward "[;={]" start t t t) + (eq (char-before) ?=) + (c-syntactic-re-search-forward "[;{]" start t t) + (eq (char-before) ?{) + (c-safe (goto-char (c-up-list-forward (point))) t) + (not (c-syntactic-re-search-forward ";" start t t)))))) + (cons 'same nil) + (cons move nil))))) (defun c-end-of-decl-1 () ;; Assuming point is at the start of a declaration (as detected by @@ -1711,14 +4548,14 @@ ;; detected using the same criteria as in ;; `c-beginning-of-decl-1'. Move to the following block ;; start. - (c-syntactic-re-search-forward "{" nil 'move 1 t)) + (c-syntactic-re-search-forward "{" nil 'move t)) (when (eq (char-before) ?{) ;; Encountered a block in the declaration. Jump over it. (condition-case nil (goto-char (c-up-list-forward (point))) - (goto-char (point-max)) - (throw 'return nil)) + (error (goto-char (point-max)) + (throw 'return nil))) (if (or (not c-opt-block-decls-with-vars-key) (save-excursion (c-with-syntax-table decl-syntax-table @@ -1728,14 +4565,16 @@ ;; Check for `c-opt-block-decls-with-vars-key' ;; before the first paren. (c-syntactic-re-search-forward - (concat "[;=\(\[{]\\|\\<\\(" + (concat "[;=\(\[{]\\|\\(" c-opt-block-decls-with-vars-key "\\)") - lim t 1 t) + lim t t t) (match-beginning 1) (not (eq (char-before) ?_)) - ;; Check that the first following paren is the block. - (c-syntactic-re-search-forward "[;=\(\[{]" lim t 1 t) + ;; Check that the first following paren is + ;; the block. + (c-syntactic-re-search-forward "[;=\(\[{]" + lim t t t) (eq (char-before) ?{))))))) ;; The declaration doesn't have any of the ;; `c-opt-block-decls-with-vars' keywords in the @@ -1746,44 +4585,61 @@ (while (progn (if (eq (char-before) ?\;) (throw 'return t)) - (c-syntactic-re-search-forward ";" nil 'move 1 t)))) + (c-syntactic-re-search-forward ";" nil 'move t)))) nil))) (defun c-beginning-of-member-init-list (&optional limit) ;; Goes to the beginning of a member init list (i.e. just after the - ;; ':') if inside one. Returns t in that case, nil otherwise. + ;; ':') if inside one. Returns t in that case, nil otherwise. (or limit (setq limit (point-min))) (skip-chars-forward " \t") + (if (eq (char-after) ?,) (forward-char 1) (c-backward-syntactic-ws limit)) - (while (and (< limit (point)) - (eq (char-before) ?,)) - ;; this will catch member inits with multiple - ;; line arglists - (forward-char -1) - (c-backward-syntactic-ws limit) - (if (eq (char-before) ?\)) - (c-backward-sexp 1)) - (c-backward-syntactic-ws limit) - ;; Skip over any template arg to the class. - (if (eq (char-before) ?>) - (c-with-syntax-table c++-template-syntax-table - (c-backward-sexp 1))) - (c-backward-sexp 1) - (c-backward-syntactic-ws limit) - ;; Skip backwards over a fully::qualified::name. - (while (and (eq (char-before) ?:) - (save-excursion - (forward-char -1) - (eq (char-before) ?:))) - (backward-char 2) - (c-backward-sexp 1)) - ;; now continue checking - (c-backward-syntactic-ws limit)) - (and (< limit (point)) - (eq (char-before) ?:))) + + (catch 'exit + (while (and (< limit (point)) + (eq (char-before) ?,)) + + ;; this will catch member inits with multiple + ;; line arglists + (forward-char -1) + (c-backward-syntactic-ws limit) + (if (eq (char-before) ?\)) + (unless (c-safe (c-backward-sexp 1)) + (throw 'exit nil))) + (c-backward-syntactic-ws limit) + + ;; Skip over any template arg to the class. This way with a + ;; syntax table is bogus but it'll have to do for now. + (if (and (eq (char-before) ?>) + (c-major-mode-is 'c++-mode)) + (c-with-syntax-table c++-template-syntax-table + (unless (c-safe (c-backward-sexp 1)) + (throw 'exit nil)))) + (c-safe (c-backward-sexp 1)) + (c-backward-syntactic-ws limit) + + ;; Skip backwards over a fully::qualified::name. + (while (and (eq (char-before) ?:) + (save-excursion + (forward-char -1) + (eq (char-before) ?:))) + (backward-char 2) + (c-safe (c-backward-sexp 1))) + + ;; If we've stepped over a number then this is a bitfield. + (when (and c-opt-bitfield-key + (looking-at "[0-9]")) + (throw 'exit nil)) + + ;; now continue checking + (c-backward-syntactic-ws limit)) + + (and (< limit (point)) + (eq (char-before) ?:)))) (defun c-search-uplist-for-classkey (paren-state) ;; search for the containing class, returning a 2 element vector if @@ -1807,11 +4663,10 @@ search-end (nth 0 paren-state))) ;; if search-end is nil, or if the search-end character isn't an ;; open brace, we are definitely not in a class - (when (consp search-end) - (setq search-end (car search-end))) - (unless (or (not search-end) - (< search-end (point-min)) - (not (eq (char-after search-end) ?{))) + (if (or (not search-end) + (< search-end (point-min)) + (not (eq (char-after search-end) ?{))) + nil ;; now, we need to look more closely at search-start. if ;; search-start is nil, then our start boundary is really ;; point-min. @@ -1821,7 +4676,9 @@ ;; searching from the end of the balanced sexp just ahead of ;; us (if (consp search-start) - (setq search-start (cdr search-start)))) + (setq search-start (cdr search-start)) + ;; Otherwise we start searching within the surrounding paren sexp. + (setq search-start (1+ search-start)))) ;; now we can do a quick regexp search from search-start to ;; search-end and see if we can find a class key. watch for ;; class like strings in literals @@ -1833,7 +4690,11 @@ (progn (c-forward-syntactic-ws search-end) (> search-end (point))) - (re-search-forward c-decl-block-key search-end t)) + ;; Add one to the search limit, to allow + ;; matching of the "{" in the regexp. + (re-search-forward c-decl-block-key + (1+ search-end) + t)) (setq class (match-beginning 0) match-end (match-end 0)) (goto-char class) @@ -1857,7 +4718,7 @@ ;; Check if this is an anonymous inner class. ((and c-opt-inexpr-class-key (looking-at c-opt-inexpr-class-key)) - (while (and (= (c-forward-token-1 1 t) 0) + (while (and (zerop (c-forward-token-2 1 t)) (looking-at "(\\|\\w\\|\\s_\\|\\."))) (if (eq (point) search-end) ;; We're done. Just trap this case in the cond. @@ -1900,15 +4761,15 @@ ;; places in inconvenient locations. Its a trade-off we make for ;; speed. (or - ;; this will pick up enum lists + ;; This will pick up brace list declarations. (c-safe (save-excursion (goto-char containing-sexp) (c-forward-sexp -1) (let (bracepos) - (if (and (or (looking-at "enum\\>[^_]") + (if (and (or (looking-at c-brace-list-key) (progn (c-forward-sexp -1) - (looking-at "enum\\>[^_]"))) + (looking-at c-brace-list-key))) (setq bracepos (c-down-list-forward (point))) (not (c-crosses-statement-barrier-p (point) (- bracepos 2)))) @@ -1941,17 +4802,17 @@ ;; see if the open brace is preceded by = or [...] in ;; this statement, but watch out for operator= (setq braceassignp 'dontknow) - (c-backward-token-1 1 t lim) + (c-backward-token-2 1 t lim) ;; Checks to do only on the first sexp before the brace. - (when (and (c-major-mode-is 'java-mode) + (when (and c-opt-inexpr-brace-list-key (eq (char-after) ?\[)) ;; In Java, an initialization brace list may follow ;; directly after "new Foo[]", so check for a "new" ;; earlier. (while (eq braceassignp 'dontknow) (setq braceassignp - (cond ((/= (c-backward-token-1 1 t lim) 0) nil) - ((looking-at "new\\>[^_]") t) + (cond ((/= (c-backward-token-2 1 t lim) 0) nil) + ((looking-at c-opt-inexpr-brace-list-key) t) ((looking-at "\\sw\\|\\s_\\|[.[]") ;; Carry on looking if this is an ;; identifier (may contain "." in Java) @@ -1971,7 +4832,7 @@ ;; that it isn't something that should be ignored. (setq braceassignp 'maybe) (while (and (eq braceassignp 'maybe) - (zerop (c-backward-token-1 1 t lim))) + (zerop (c-backward-token-2 1 t lim))) (setq braceassignp (cond ;; Check for operator = @@ -2003,7 +4864,7 @@ nil) (t t)))))) (if (and (eq braceassignp 'dontknow) - (/= (c-backward-token-1 1 t lim) 0)) + (/= (c-backward-token-2 1 t lim) 0)) (setq braceassignp nil))) (if (not braceassignp) (if (eq (char-after) ?\;) @@ -2121,7 +4982,7 @@ ;; in-expression class. (let ((prev (point))) (while (and - (= (c-backward-token-1 1 nil closest-lim) 0) + (= (c-backward-token-2 1 nil closest-lim) 0) (eq (char-syntax (char-after)) ?w)) (setq prev (point))) (goto-char prev) @@ -2132,7 +4993,7 @@ (save-excursion (and (c-major-mode-is 'pike-mode) (progn (goto-char block-follows) - (= (c-forward-token-1 1 t) 0)) + (zerop (c-forward-token-2 1 t))) (eq (char-after) ?\()))) (cons 'inexpr-class (point)))) ((and c-opt-inexpr-block-key @@ -2183,86 +5044,6 @@ paren-state) containing-sexp))))) -(defun c-on-identifier () - "Return non-nil if we're on or directly after an identifier. -Keywords are recognized and not considered identifiers." - (if (or (memq (char-syntax (or (char-after) ? )) '(?w ?_)) - (memq (char-syntax (or (char-before) ? )) '(?w ?_))) - (save-excursion - (skip-syntax-backward "w_") - (not (looking-at c-keywords-regexp))) - (if (c-major-mode-is 'pike-mode) - ;; Handle the `<operator> syntax in Pike. - (save-excursion - (if (eq (char-after) ?\`) (forward-char)) - (skip-chars-backward "!%&*+\\-/<=>^|~") - (let ((pos (point))) - (cond ((memq (char-before) '(?\) ?\])) - (c-safe (backward-char 2))) - ((memq (char-before) '(?\( ?\[)) - (c-safe (backward-char 1)))) - (if (not (looking-at "()\\|\\[]")) - (goto-char pos))) - (and (eq (char-before) ?\`) - (looking-at "[-!%&*+/<=>^|~]\\|()\\|\\[]")))))) - - -(defun c-most-enclosing-brace (paren-state &optional bufpos) - ;; Return the bufpos of the innermost enclosing brace before bufpos - ;; that hasn't been narrowed out, or nil if none was found. - (let (enclosingp) - (or bufpos (setq bufpos 134217727)) - (while paren-state - (setq enclosingp (car paren-state) - paren-state (cdr paren-state)) - (if (or (consp enclosingp) - (>= enclosingp bufpos)) - (setq enclosingp nil) - (if (< enclosingp (point-min)) - (setq enclosingp nil)) - (setq paren-state nil))) - enclosingp)) - -(defun c-least-enclosing-brace (paren-state &optional bufpos) - ;; Return the bufpos of the outermost enclosing brace before bufpos - ;; that hasn't been narrowed out, or nil if none was found. - (let (pos elem) - (or bufpos (setq bufpos 134217727)) - (while paren-state - (setq elem (car paren-state) - paren-state (cdr paren-state)) - (unless (or (consp elem) - (>= elem bufpos)) - (if (>= elem (point-min)) - (setq pos elem)))) - pos)) - -(defun c-safe-position (bufpos paren-state) - ;; Return the closest known safe position higher up than BUFPOS, or - ;; nil if PAREN-STATE doesn't contain one. Return nil if BUFPOS is - ;; nil, which is useful to find the closest limit before a given - ;; limit that might be nil. - (when bufpos - (let ((c-macro-start (c-query-macro-start)) safepos) - (if (and c-macro-start - (< c-macro-start bufpos)) - ;; Make sure bufpos is outside the macro we might be in. - (setq bufpos c-macro-start)) - (catch 'done - (while paren-state - (setq safepos - (if (consp (car paren-state)) - (cdr (car paren-state)) - (car paren-state))) - (if (< safepos bufpos) - (throw 'done safepos) - (setq paren-state (cdr paren-state)))) - (if (eq c-macro-start bufpos) - ;; Backed up bufpos to the macro start and got outside the - ;; state. We know the macro is at the top level in this case, - ;; so we can use the macro start as the safe position. - c-macro-start))))) - (defun c-narrow-out-enclosing-class (paren-state lim) ;; Narrow the buffer so that the enclosing class is hidden. Uses ;; and returns the value from c-search-uplist-for-classkey. @@ -2289,21 +5070,34 @@ inclass-p)) -;; c-guess-basic-syntax implements the main decision tree for -;; determining the syntactic analysis of the current line of code. -;; Yes, it's huge and bloated! - -;; It's useful to break out some parts of the decision tree to -;; separate functions, which are all collected below. Use dynamic -;; binding to propagate back the syntax results from them. -(defvar syntax) -(defvar syntactic-relpos) +;; `c-guess-basic-syntax' and the functions that precedes it below +;; implements the main decision tree for determining the syntactic +;; analysis of the current line of code. + +;; Dynamically bound to t when `c-guess-basic-syntax' is called during +;; auto newline analysis. +(defvar c-auto-newline-analysis nil) + +(defsubst c-add-syntax (symbol &rest args) + ;; A simple function to prepend a new syntax element to + ;; `c-syntactic-context'. Using `setq' on it is unsafe since it + ;; should always be dynamically bound but since we read it first + ;; we'll fail properly anyway if this function is misused. + (setq c-syntactic-context (cons (cons symbol args) + c-syntactic-context))) + +(defsubst c-append-syntax (symbol &rest args) + ;; Like `c-add-syntax' but appends to the end of the syntax list. + ;; (Normally not necessary.) + (setq c-syntactic-context (nconc c-syntactic-context + (list (cons symbol args))))) (defun c-add-stmt-syntax (syntax-symbol + syntax-extra-args stop-at-boi-only + at-block-start containing-sexp - paren-state - &optional at-block-start) + paren-state) ;; Do the generic processing to anchor the given syntax symbol on ;; the preceding statement: Skip over any labels and containing ;; statements on the same line, and then search backward until we @@ -2312,9 +5106,12 @@ ;; ;; Point is assumed to be at the prospective anchor point for the ;; given SYNTAX-SYMBOL. More syntax entries are added if we need to - ;; skip past block opens and containing statement. All the added + ;; skip past open parens and containing statements. All the added ;; syntax elements will get the same anchor point. ;; + ;; SYNTAX-EXTRA-ARGS are a list of the extra arguments for the + ;; syntax symbol. They are appended after the anchor point. + ;; ;; If STOP-AT-BOI-ONLY is nil, we might stop in the middle of the ;; line if another statement precedes the current one on this line. ;; @@ -2325,14 +5122,14 @@ (if (= (point) (c-point 'boi)) ;; This is by far the most common case, so let's give it special ;; treatment. - (c-add-syntax syntax-symbol (point)) - - (let* ((savepos (point)) - (syms (list syntax-symbol)) - (syms-tail syms) - (boi (c-point 'boi)) - (prev-paren (if at-block-start ?{ (char-after))) - step-type step-tmp at-comment add-inexpr-stmt) + (apply 'c-add-syntax syntax-symbol (point) syntax-extra-args) + + (let ((savepos (point)) + (syntax-last c-syntactic-context) + (boi (c-point 'boi)) + (prev-paren (if at-block-start ?{ (char-after))) + step-type step-tmp at-comment special-list) + (apply 'c-add-syntax syntax-symbol nil syntax-extra-args) ;; Begin by skipping any labels and containing statements that ;; are on the same line. @@ -2351,6 +5148,7 @@ ;; Loop if we have to back out of the containing block. (while (progn + ;; Loop if we have to back up another statement. (while (progn @@ -2358,7 +5156,7 @@ ;; Always start by skipping over any comments that ;; stands between the statement and boi. (while (and (/= (setq savepos (point)) boi) - (c-forward-comment -1)) + (c-backward-single-comment)) (setq at-comment t boi (c-point 'boi))) (goto-char savepos) @@ -2397,8 +5195,7 @@ ;; if" clauses won't indent deeper and deeper. (when (and (eq step-type 'up) (< (point) boi)) - (setcdr syms-tail (list 'substatement)) - (setq syms-tail (cdr syms-tail))) + (c-add-syntax 'substatement nil)) (setq boi (c-point 'boi)) (/= (point) savepos))))) @@ -2410,30 +5207,49 @@ (when (and (eq step-type 'same) containing-sexp) (goto-char containing-sexp) + + ;; Don't stop in the middle of a special brace list opener + ;; like "({". + (when (and c-special-brace-lists + (setq special-list + (c-looking-at-special-brace-list))) + (setq containing-sexp (car (car special-list))) + (goto-char containing-sexp)) + (setq paren-state (c-whack-state-after containing-sexp paren-state) - containing-sexp (c-most-enclosing-brace paren-state)) - - - (when (eq (setq prev-paren (char-after)) ?\() - (c-backward-syntactic-ws containing-sexp) - (when (c-on-identifier) - ;; Arrived at a function arglist start. Exit with - ;; the position of the first argument inside it. - (goto-char savepos) - (throw 'done t)) - ;; We're in an in-expression statement. Remember - ;; this. We'll iterate below, but won't add any - ;; syntax element. - (setq add-inexpr-stmt t)) - - (setq savepos (point) - boi (c-point 'boi) - step-type (c-beginning-of-statement-1 containing-sexp)) + containing-sexp (c-most-enclosing-brace paren-state) + savepos (point) + boi (c-point 'boi)) + + (if (eq (setq prev-paren (char-after)) ?\() + (progn + (c-backward-syntactic-ws containing-sexp) + (when (/= savepos boi) + (if (and (or (not (looking-at "\\>")) + (not (c-on-identifier))) + (not special-list) + (save-excursion + (c-forward-syntactic-ws) + (forward-char) + (c-forward-syntactic-ws) + (eq (char-after) ?{))) + ;; We're in an in-expression statement. + ;; This syntactic element won't get an anchor pos. + (c-add-syntax 'inexpr-statement) + (c-add-syntax 'arglist-cont-nonempty nil savepos))) + (goto-char (max boi + (if containing-sexp + (1+ containing-sexp) + (point-min)))) + (setq step-type 'same)) + (setq step-type + (c-beginning-of-statement-1 containing-sexp))) (let ((at-bod (and (eq step-type 'same) (/= savepos (point)) (eq prev-paren ?{)))) + (when (= savepos boi) ;; If the open brace was at boi, we're always ;; done. The c-beginning-of-statement-1 call @@ -2443,10 +5259,10 @@ (setq savepos nil)) (when (eq prev-paren ?{) - (setcdr syms-tail (list (if at-bod - 'defun-block-intro - 'statement-block-intro))) - (setq syms-tail (cdr syms-tail))) + (c-add-syntax (if at-bod + 'defun-block-intro + 'statement-block-intro) + nil)) (when (and (not at-bod) savepos) ;; Loop if the brace wasn't at boi, and we didn't @@ -2462,11 +5278,14 @@ (setq boi (c-point 'boi))))) ))) - (while syms - (c-add-syntax (car syms) (point)) - (setq syms (cdr syms))) - (if add-inexpr-stmt - (c-add-syntax 'inexpr-statement)) + ;; Fill in the current point as the anchor for all the symbols + ;; added above. + (let ((p c-syntactic-context)) + (while (not (eq p syntax-last)) + (if (cdr (car p)) + (setcar (cdr (car p)) (point))) + (setq p (cdr p)))) + ))) (defun c-add-class-syntax (symbol classkey paren-state) @@ -2499,9 +5318,11 @@ ;; This function contains the decision tree reached through both ;; cases 18 and 10. It's a continued statement or top level ;; construct of some kind. + (let (special-brace-list) (goto-char indent-point) (skip-chars-forward " \t") + (cond ;; (CASE A removed.) ;; CASE B: open braces for class or brace-lists @@ -2509,66 +5330,95 @@ (or (and c-special-brace-lists (c-looking-at-special-brace-list)) (eq char-after-ip ?{))) + (cond ;; CASE B.1: class-open ((save-excursion - (goto-char indent-point) - (skip-chars-forward " \t{") + (skip-chars-forward "{") (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) (and decl (setq beg-of-same-or-containing-stmt (aref decl 0))) )) (c-add-syntax 'class-open beg-of-same-or-containing-stmt)) + ;; CASE B.2: brace-list-open ((or (consp special-brace-list) (save-excursion (goto-char beg-of-same-or-containing-stmt) - (looking-at "enum\\>[^_]")) - (save-excursion - (goto-char indent-point) - (while (and (> (point) beg-of-same-or-containing-stmt) - (= (c-backward-token-1 1 t) 0) - (/= (char-after) ?=))) - (eq (char-after) ?=))) + (c-syntactic-re-search-forward "=\\([^=]\\|$\\)" + indent-point t t t))) ;; The most semantically accurate symbol here is - ;; brace-list-open, but we report it simply as a statement-cont. - ;; The reason is that one normally adjusts brace-list-open for - ;; brace lists as top-level constructs, and brace lists inside - ;; statements is a completely different context. + ;; brace-list-open, but we normally report it simply as a + ;; statement-cont. The reason is that one normally adjusts + ;; brace-list-open for brace lists as top-level constructs, + ;; and brace lists inside statements is a completely different + ;; context. C.f. case 5A.3. (c-beginning-of-statement-1 containing-sexp) - (c-add-stmt-syntax 'statement-cont nil containing-sexp paren-state)) + (c-add-stmt-syntax (if c-auto-newline-analysis + ;; Turn off the dwim above when we're + ;; analyzing the nature of the brace + ;; for the auto newline feature. + 'brace-list-open + 'statement-cont) + nil nil nil + containing-sexp paren-state)) + ;; CASE B.3: The body of a function declared inside a normal ;; block. Can occur e.g. in Pike and when using gcc ;; extensions. Might also trigger it with some macros followed ;; by blocks, and this gives sane indentation then too. - ;; C.f. cases 16F and 17G. - ((progn - (goto-char indent-point) - (and (not (c-looking-at-bos)) - (eq (c-beginning-of-statement-1 containing-sexp nil nil t) - 'same))) - (c-add-stmt-syntax 'defun-open t containing-sexp paren-state)) + ;; C.f. cases E, 16F and 17G. + ((and (not (c-looking-at-bos)) + (eq (c-beginning-of-statement-1 containing-sexp nil nil t) + 'same)) + (c-add-stmt-syntax 'defun-open nil t nil + containing-sexp paren-state)) + ;; CASE B.4: Continued statement with block open. (t (goto-char beg-of-same-or-containing-stmt) - (c-add-stmt-syntax 'statement-cont nil containing-sexp paren-state) + (c-add-stmt-syntax 'statement-cont nil nil nil + containing-sexp paren-state) (c-add-syntax 'block-open)) )) + ;; CASE C: iostream insertion or extraction operator - ((and (looking-at "<<\\|>>") + ((and (looking-at "\\(<<\\|>>\\)\\([^=]\\|$\\)") (save-excursion (goto-char beg-of-same-or-containing-stmt) - (while (and (re-search-forward "<<\\|>>" indent-point 'move) - (c-in-literal beg-of-same-or-containing-stmt))) - ;; if we ended up at indent-point, then the first streamop is on a - ;; separate line. Indent the line like a statement-cont instead - (when (/= (point) indent-point) + ;; If there is no preceding streamop in the statement + ;; then indent this line as a normal statement-cont. + (when (c-syntactic-re-search-forward + "\\(<<\\|>>\\)\\([^=]\\|$\\)" indent-point 'move t t) (c-add-syntax 'stream-op (c-point 'boi)) t)))) + + ;; CASE E: In the "K&R region" of a function declared inside a + ;; normal block. C.f. case B.3. + ((and (save-excursion + ;; Check that the next token is a '{'. This works as + ;; long as no language that allows nested function + ;; definitions doesn't allow stuff like member init + ;; lists, K&R declarations or throws clauses there. + ;; + ;; Note that we do a forward search for something ahead + ;; of the indentation line here. That's not good since + ;; the user might not have typed it yet. Unfortunately + ;; it's exceedingly tricky to recognize a function + ;; prototype in a code block without resorting to this. + (c-forward-syntactic-ws) + (eq (char-after) ?{)) + (not (c-looking-at-bos)) + (eq (c-beginning-of-statement-1 containing-sexp nil nil t) + 'same)) + (c-add-stmt-syntax 'func-decl-cont nil t nil + containing-sexp paren-state)) + ;; CASE D: continued statement. (t (c-beginning-of-statement-1 containing-sexp) - (c-add-stmt-syntax 'statement-cont nil containing-sexp paren-state)) + (c-add-stmt-syntax 'statement-cont nil nil nil + containing-sexp paren-state)) ))) (defun c-guess-basic-syntax () @@ -2580,16 +5430,17 @@ (case-fold-search nil) (paren-state (c-parse-state)) literal containing-sexp char-before-ip char-after-ip lim - syntax placeholder c-in-literal-cache step-type + c-syntactic-context placeholder c-in-literal-cache step-type tmpsymbol keyword injava-inher special-brace-list ;; narrow out any enclosing class or extern "C" block (inclass-p (c-narrow-out-enclosing-class paren-state indent-point)) - ;; c-state-cache is shadowed here. That means we must - ;; not do any changes during the execution of this - ;; function, since c-check-state-cache then would change - ;; this local variable and leave a bogus value in the - ;; global one. + ;; `c-state-cache' is shadowed here so that we don't + ;; throw it away due to the narrowing that might be done + ;; by the function above. That means we must not do any + ;; changes during the execution of this function, since + ;; `c-invalidate-state-cache' then would change this local + ;; variable and leave a bogus value in the global one. (c-state-cache (if inclass-p (c-whack-state-before (point-min) paren-state) paren-state)) @@ -2599,23 +5450,20 @@ ;; a relpos. It's stored in syntactic-relpos. syntactic-relpos (c-stmt-delim-chars c-stmt-delim-chars)) - ;; check for meta top-level enclosing constructs, possible - ;; extern language definitions, possibly (in C++) namespace - ;; definitions. + ;; Check for meta top-level enclosing constructs such as + ;; extern language definitions. (save-excursion (save-restriction (widen) - (if (and inclass-p - (progn - (goto-char (aref inclass-p 0)) - (looking-at c-other-decl-block-key))) - (let ((enclosing (match-string 1))) - (cond - ((string-equal enclosing "extern") - (setq inenclosing-p 'extern)) - ((string-equal enclosing "namespace") - (setq inenclosing-p 'namespace)) - ))))) + (when (and inclass-p + (progn + (goto-char (aref inclass-p 0)) + (looking-at c-other-decl-block-key))) + (setq inenclosing-p (match-string 1)) + (if (string-equal inenclosing-p "extern") + ;; Compatibility with legacy choice of name for the + ;; extern-lang syntactic symbols. + (setq inenclosing-p "extern-lang"))))) ;; Init some position variables: ;; @@ -2682,8 +5530,17 @@ ((eq literal 'string) (c-add-syntax 'string (c-point 'bopl))) ;; CASE 2: in a C or C++ style comment. - ((memq literal '(c c++)) - (c-add-syntax literal (car (c-literal-limits lim)))) + ((and (memq literal '(c c++)) + ;; This is a kludge for XEmacs where we use + ;; `buffer-syntactic-context', which doesn't correctly + ;; recognize "\*/" to end a block comment. + ;; `parse-partial-sexp' which is used by + ;; `c-literal-limits' will however do that in most + ;; versions, which results in that we get nil from + ;; `c-literal-limits' even when `c-in-literal' claims + ;; we're inside a comment. + (setq placeholder (c-literal-limits lim))) + (c-add-syntax literal (car placeholder))) ;; CASE 3: in a cpp preprocessor macro continuation. ((and (save-excursion (when (c-beginning-of-macro) @@ -2712,7 +5569,8 @@ ;; CASE 11: an else clause? ((looking-at "else\\>[^_]") (c-beginning-of-statement-1 containing-sexp) - (c-add-stmt-syntax 'else-clause t containing-sexp paren-state)) + (c-add-stmt-syntax 'else-clause nil t nil + containing-sexp paren-state)) ;; CASE 12: while closure of a do/while construct? ((and (looking-at "while\\>[^_]") (save-excursion @@ -2720,7 +5578,8 @@ 'beginning) (setq placeholder (point))))) (goto-char placeholder) - (c-add-stmt-syntax 'do-while-closure t containing-sexp paren-state)) + (c-add-stmt-syntax 'do-while-closure nil t nil + containing-sexp paren-state)) ;; CASE 13: A catch or finally clause? This case is simpler ;; than if-else and do-while, because a block is required ;; after every try, catch and finally. @@ -2742,11 +5601,14 @@ (looking-at "\\(try\\|catch\\)\\>[^_]") (setq placeholder (point)))) (goto-char placeholder) - (c-add-stmt-syntax 'catch-clause t containing-sexp paren-state)) + (c-add-stmt-syntax 'catch-clause nil t nil + containing-sexp paren-state)) ;; CASE 18: A substatement we can recognize by keyword. ((save-excursion (and c-opt-block-stmt-key - (not (eq char-before-ip ?\;)) + (if (c-mode-is-new-awk-p) + (c-awk-prev-line-incomplete-p containing-sexp) ; ACM 2002/3/29 + (not (eq char-before-ip ?\;))) (not (memq char-after-ip '(?\) ?\] ?,))) (or (not (eq char-before-ip ?})) (c-looking-at-inexpr-block-backward c-state-cache)) @@ -2780,7 +5642,7 @@ ;; Necessary to catch e.g. synchronized in Java, ;; which can be used both as statement and ;; modifier. - (and (= (c-forward-token-1 1 nil) 0) + (and (zerop (c-forward-token-2 1 nil)) (eq (char-after) ?\()) (looking-at c-opt-block-stmt-key)))) (if (eq step-type 'up) @@ -2789,16 +5651,16 @@ (goto-char placeholder) (cond ((eq char-after-ip ?{) - (c-add-stmt-syntax 'substatement-open nil + (c-add-stmt-syntax 'substatement-open nil nil nil containing-sexp paren-state)) ((save-excursion (goto-char indent-point) (back-to-indentation) (looking-at c-label-key)) - (c-add-stmt-syntax 'substatement-label nil + (c-add-stmt-syntax 'substatement-label nil nil nil containing-sexp paren-state)) (t - (c-add-stmt-syntax 'substatement nil + (c-add-stmt-syntax 'substatement nil nil nil containing-sexp paren-state)))) ;; CASE 18B: Some other substatement. This is shared ;; with case 10. @@ -2829,7 +5691,7 @@ 'lambda-intro-cont))) (goto-char (cdr placeholder)) (back-to-indentation) - (c-add-stmt-syntax tmpsymbol t + (c-add-stmt-syntax tmpsymbol nil t nil (c-most-enclosing-brace c-state-cache (point)) (c-whack-state-after (point) paren-state)) (unless (eq (point) (cdr placeholder)) @@ -2844,22 +5706,24 @@ (c-looking-at-special-brace-list)) (eq char-after-ip ?{))) (cond - ;; CASE 5A.1: extern language or namespace construct + ;; CASE 5A.1: Non-class declaration block open. ((save-excursion (goto-char indent-point) (skip-chars-forward " \t") - (and (c-safe (progn (c-backward-sexp 2) t)) + (and (c-safe (c-backward-sexp 2) t) (looking-at c-other-decl-block-key) (setq keyword (match-string 1) placeholder (point)) - (or (and (string-equal keyword "namespace") - (setq tmpsymbol 'namespace-open)) - (and (string-equal keyword "extern") - (progn - (c-forward-sexp 1) - (c-forward-syntactic-ws) - (eq (char-after) ?\")) - (setq tmpsymbol 'extern-lang-open))) + (if (string-equal keyword "extern") + ;; Special case for extern-lang-open. The + ;; check for a following string is disabled + ;; since it doesn't disambiguate anything. + (and ;;(progn + ;; (c-forward-sexp 1) + ;; (c-forward-syntactic-ws) + ;; (eq (char-after) ?\")) + (setq tmpsymbol 'extern-lang-open)) + (setq tmpsymbol (intern (concat keyword "-open")))) )) (goto-char placeholder) (c-add-syntax tmpsymbol (c-point 'boi))) @@ -2874,30 +5738,32 @@ (c-add-syntax 'class-open placeholder)) ;; CASE 5A.3: brace list open ((save-excursion - (c-beginning-of-statement-1 lim t) - (if (looking-at "typedef\\>[^_]") - (progn (c-forward-sexp 1) - (c-forward-syntactic-ws indent-point))) + (c-beginning-of-decl-1 lim) + (while (looking-at c-specifier-key) + (goto-char (match-end 1)) + (c-forward-syntactic-ws indent-point)) (setq placeholder (c-point 'boi)) (or (consp special-brace-list) (and (or (save-excursion (goto-char indent-point) (setq tmpsymbol nil) (while (and (> (point) placeholder) - (= (c-backward-token-1 1 t) 0) + (zerop (c-backward-token-2 1 t)) (/= (char-after) ?=)) - (if (and (not tmpsymbol) - (looking-at "new\\>[^_]")) - (setq tmpsymbol 'topmost-intro-cont))) + (and c-opt-inexpr-brace-list-key + (not tmpsymbol) + (looking-at c-opt-inexpr-brace-list-key) + (setq tmpsymbol 'topmost-intro-cont))) (eq (char-after) ?=)) - (looking-at "enum\\>[^_]")) + (looking-at c-brace-list-key)) (save-excursion (while (and (< (point) indent-point) - (= (c-forward-token-1 1 t) 0) + (zerop (c-forward-token-2 1 t)) (not (memq (char-after) '(?\; ?\())))) (not (memq (char-after) '(?\; ?\())) )))) - (if (and (c-major-mode-is 'java-mode) + (if (and (not c-auto-newline-analysis) + (c-major-mode-is 'java-mode) (eq tmpsymbol 'topmost-intro-cont)) ;; We're in Java and have found that the open brace ;; belongs to a "new Foo[]" initialization list, @@ -2906,7 +5772,7 @@ ;; therefore treat it as any topmost continuation ;; even though the semantically correct symbol still ;; is brace-list-open, on the same grounds as in - ;; case 10B.2. + ;; case B.2. (progn (c-beginning-of-statement-1 lim) (c-add-syntax 'topmost-intro-cont (c-point 'boi))) @@ -2924,7 +5790,7 @@ (c-add-syntax 'defun-open (c-point 'bol))) ))) ;; CASE 5B: first K&R arg decl or member init - ((c-just-after-func-arglist-p nil lim) + ((c-just-after-func-arglist-p lim) (cond ;; CASE 5B.1: a member init ((or (eq char-before-ip ?:) @@ -2976,12 +5842,12 @@ (when (eq char-after-ip ?,) (skip-chars-forward " \t") (forward-char)) - (looking-at c-opt-decl-spec-key))) + (looking-at c-opt-postfix-decl-spec-key))) (and (or (eq char-before-ip ?:) ;; watch out for scope operator (save-excursion (and (eq char-after-ip ?:) - (c-safe (progn (forward-char 1) t)) + (c-safe (forward-char 1) t) (not (eq (char-after) ?:)) ))) (save-excursion @@ -3000,7 +5866,7 @@ cont done) (save-excursion (while (not done) - (cond ((looking-at c-opt-decl-spec-key) + (cond ((looking-at c-opt-postfix-decl-spec-key) (setq injava-inher (cons cont (point)) done t)) ((or (not (c-safe (c-forward-sexp -1) t)) @@ -3057,20 +5923,22 @@ (save-excursion ;; Note: We use the fact that lim is always after any ;; preceding brace sexp. - (while (and (= (c-backward-token-1 1 t lim) 0) + (while (and (zerop (c-backward-token-2 1 t lim)) (not (looking-at "[;<,=]")))) (or (memq (char-after) '(?, ?=)) (and (c-major-mode-is 'c++-mode) - (= (c-backward-token-1 1 nil lim) 0) + (zerop (c-backward-token-2 1 nil lim)) (eq (char-after) ?<))))) (goto-char indent-point) - (c-beginning-of-member-init-list lim) + (setq placeholder + (c-beginning-of-member-init-list lim)) (cond ;; CASE 5D.1: hanging member init colon, but watch out ;; for bogus matches on access specifiers inside classes. - ((and (save-excursion + ((and placeholder + (save-excursion (setq placeholder (point)) - (c-backward-token-1 1 t lim) + (c-backward-token-2 1 t lim) (and (eq (char-after) ?:) (not (eq (char-before) ?:)))) (save-excursion @@ -3118,12 +5986,12 @@ (c-beginning-of-statement-1 lim) (setq placeholder (point)) (if (looking-at "static\\>[^_]") - (c-forward-token-1 1 nil indent-point)) + (c-forward-token-2 1 nil indent-point)) (and (looking-at c-class-key) - (= (c-forward-token-1 2 nil indent-point) 0) + (zerop (c-forward-token-2 2 nil indent-point)) (if (eq (char-after) ?<) (c-with-syntax-table c++-template-syntax-table - (= (c-forward-token-1 1 t indent-point) 0)) + (zerop (c-forward-token-2 1 t indent-point))) t) (eq (char-after) ?:)))) (goto-char placeholder) @@ -3144,7 +6012,7 @@ ;; the first variable declaration. C.f. case 5N. 'topmost-intro-cont 'statement-cont) - nil containing-sexp paren-state)) + nil nil nil containing-sexp paren-state)) )) ;; CASE 5E: we are looking at a access specifier ((and inclass-p @@ -3153,14 +6021,12 @@ (setq placeholder (c-add-class-syntax 'inclass inclass-p paren-state)) ;; Append access-label with the same anchor point as inclass gets. - (nconc syntax (list (cons 'access-label placeholder)))) - ;; CASE 5F: extern-lang-close or namespace-close? + (c-append-syntax 'access-label placeholder)) + ;; CASE 5F: Close of a non-class declaration level block. ((and inenclosing-p (eq char-after-ip ?})) - (setq tmpsymbol (if (eq inenclosing-p 'extern) - 'extern-lang-close - 'namespace-close)) - (c-add-syntax tmpsymbol (aref inclass-p 0))) + (c-add-syntax (intern (concat inenclosing-p "-close")) + (aref inclass-p 0))) ;; CASE 5G: we are looking at the brace which closes the ;; enclosing nested class decl ((and inclass-p @@ -3169,7 +6035,7 @@ (save-restriction (widen) (forward-char 1) - (and (c-safe (progn (c-backward-sexp 1) t)) + (and (c-safe (c-backward-sexp 1) t) (= (point) (aref inclass-p 1)) )))) (c-add-class-syntax 'class-close inclass-p paren-state)) @@ -3193,6 +6059,17 @@ (looking-at c-opt-method-key)) (c-beginning-of-statement-1 lim) (c-add-syntax 'objc-method-intro (c-point 'boi))) + ;; CASE 5P: AWK pattern or function or continuation + ;; thereof. + ((c-mode-is-new-awk-p) + (setq placeholder (point)) + (c-add-stmt-syntax + (if (and (eq (c-beginning-of-statement-1) 'same) + (/= (point) placeholder)) + 'topmost-intro-cont + 'topmost-intro) + nil nil nil + containing-sexp paren-state)) ;; CASE 5N: At a variable declaration that follows a class ;; definition or some other block declaration that doesn't ;; end at the closing '}'. C.f. case 5D.5. @@ -3212,7 +6089,7 @@ (c-end-of-decl-1) (> (point) indent-point)))))) (goto-char placeholder) - (c-add-stmt-syntax 'topmost-intro-cont nil + (c-add-stmt-syntax 'topmost-intro-cont nil nil nil containing-sexp paren-state)) ;; CASE 5J: we are at the topmost level, make ;; sure we skip back past any access specifiers @@ -3221,12 +6098,14 @@ c-opt-access-key (not (bobp)) (save-excursion - (c-safe (progn (c-backward-sexp 1) t)) + (c-safe (c-backward-sexp 1) t) (looking-at c-opt-access-key))) (c-backward-sexp 1) (c-backward-syntactic-ws lim)) (or (bobp) - (memq (char-before) '(?\; ?})) + (if (c-mode-is-new-awk-p) + (not (c-awk-prev-line-incomplete-p)) + (memq (char-before) '(?\; ?}))) (and (c-major-mode-is 'objc-mode) (progn (c-beginning-of-statement-1 lim) @@ -3243,12 +6122,10 @@ (goto-char (aref inclass-p 1)) (or (= (point) (c-point 'boi)) (goto-char (aref inclass-p 0))) - (cond - ((eq inenclosing-p 'extern) - (c-add-syntax 'inextern-lang (c-point 'boi))) - ((eq inenclosing-p 'namespace) - (c-add-syntax 'innamespace (c-point 'boi))) - (t (c-add-class-syntax 'inclass inclass-p paren-state))) + (if inenclosing-p + (c-add-syntax (intern (concat "in" inenclosing-p)) + (c-point 'boi)) + (c-add-class-syntax 'inclass inclass-p paren-state)) )) (when (and c-syntactic-indentation-in-macros macro-start @@ -3284,16 +6161,20 @@ (c-looking-at-special-brace-list))) (eq (char-after containing-sexp) ?{))) (cond - ;; CASE 7A: we are looking at the arglist closing paren + ;; CASE 7A: we are looking at the arglist closing paren. + ;; C.f. case 7F. ((memq char-after-ip '(?\) ?\])) (goto-char containing-sexp) (setq placeholder (c-point 'boi)) - (when (and (c-safe (backward-up-list 1) t) - (> (point) placeholder)) - (forward-char) - (skip-chars-forward " \t") - (setq placeholder (point))) - (c-add-syntax 'arglist-close placeholder)) + (if (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (progn + (forward-char) + (skip-chars-forward " \t")) + (goto-char placeholder)) + (c-add-stmt-syntax 'arglist-close (list containing-sexp) t nil + (c-most-enclosing-brace paren-state (point)) + (c-whack-state-after (point) paren-state))) ;; CASE 7B: Looking at the opening brace of an ;; in-expression block or brace list. C.f. cases 4, 16A ;; and 17E. @@ -3315,7 +6196,7 @@ ))) (goto-char placeholder) (back-to-indentation) - (c-add-stmt-syntax (car tmpsymbol) t + (c-add-stmt-syntax (car tmpsymbol) nil t nil (c-most-enclosing-brace paren-state (point)) (c-whack-state-after (point) paren-state)) (if (/= (point) placeholder) @@ -3336,7 +6217,7 @@ ;; these things as statements ((progn (goto-char containing-sexp) - (and (c-safe (progn (c-forward-sexp -1) t)) + (and (c-safe (c-forward-sexp -1) t) (looking-at "\\<for\\>[^_]"))) (goto-char (1+ containing-sexp)) (c-forward-syntactic-ws indent-point) @@ -3359,7 +6240,7 @@ ;; but the preceding argument is on the same line as the ;; opening paren. This case includes multi-line ;; mathematical paren groupings, but we could be on a - ;; for-list continuation line + ;; for-list continuation line. C.f. case 7A. ((progn (goto-char (1+ containing-sexp)) (skip-chars-forward " \t") @@ -3367,12 +6248,16 @@ (not (looking-at "\\\\$")))) (goto-char containing-sexp) (setq placeholder (c-point 'boi)) - (when (and (c-safe (backward-up-list 1) t) - (> (point) placeholder)) - (forward-char) - (skip-chars-forward " \t") - (setq placeholder (point))) - (c-add-syntax 'arglist-cont-nonempty placeholder)) + (if (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (progn + (forward-char) + (skip-chars-forward " \t")) + (goto-char placeholder)) + (c-add-stmt-syntax 'arglist-cont-nonempty (list containing-sexp) + t nil + (c-most-enclosing-brace c-state-cache (point)) + (c-whack-state-after (point) paren-state))) ;; CASE 7G: we are looking at just a normal arglist ;; continuation line (t (c-forward-syntactic-ws indent-point) @@ -3383,7 +6268,7 @@ (save-excursion (goto-char indent-point) (skip-chars-forward " \t") - (looking-at c-opt-decl-spec-key))) + (looking-at c-opt-postfix-decl-spec-key))) (goto-char indent-point) (skip-chars-forward " \t") (cond @@ -3400,12 +6285,13 @@ (c-add-syntax 'inher-cont (point)) ))) ;; CASE 9: we are inside a brace-list - ((setq special-brace-list - (or (and c-special-brace-lists - (save-excursion - (goto-char containing-sexp) - (c-looking-at-special-brace-list))) - (c-inside-bracelist-p containing-sexp paren-state))) + ((and (not (c-mode-is-new-awk-p)) ; Maybe this isn't needed (ACM, 2002/3/29) + (setq special-brace-list + (or (and c-special-brace-lists + (save-excursion + (goto-char containing-sexp) + (c-looking-at-special-brace-list))) + (c-inside-bracelist-p containing-sexp paren-state)))) (cond ;; CASE 9A: In the middle of a special brace list opener. ((and (consp special-brace-list) @@ -3418,11 +6304,13 @@ (if (and (bolp) (assoc 'statement-cont (setq placeholder (c-guess-basic-syntax)))) - (setq syntax placeholder) + (setq c-syntactic-context placeholder) (c-beginning-of-statement-1 (c-safe-position (1- containing-sexp) paren-state)) - (c-forward-token-1 0) - (if (looking-at "typedef\\>[^_]") (c-forward-token-1 1)) + (c-forward-token-2 0) + (while (looking-at c-specifier-key) + (goto-char (match-end 1)) + (c-forward-syntactic-ws)) (c-add-syntax 'brace-list-open (c-point 'boi)))) ;; CASE 9B: brace-list-close brace ((if (consp special-brace-list) @@ -3438,27 +6326,25 @@ (eq (1+ (point)) (cdr (car special-brace-list)))) ;; We were before the special close char. (and (eq (char-after) (cdr (cdr special-brace-list))) - (= (c-forward-token-1) 0) + (zerop (c-forward-token-2)) (eq (1+ (point)) (cdr (car special-brace-list))))))) ;; Normal brace list check. (and (eq char-after-ip ?}) - (c-safe (progn (goto-char (c-up-list-backward (point))) - t)) + (c-safe (goto-char (c-up-list-backward (point))) t) (= (point) containing-sexp))) (if (eq (point) (c-point 'boi)) (c-add-syntax 'brace-list-close (point)) (setq lim (c-most-enclosing-brace c-state-cache (point))) (c-beginning-of-statement-1 lim) - (c-add-stmt-syntax 'brace-list-close t lim - (c-whack-state-after (point) paren-state) - t))) + (c-add-stmt-syntax 'brace-list-close nil t t lim + (c-whack-state-after (point) paren-state)))) (t ;; Prepare for the rest of the cases below by going to the ;; token following the opening brace (if (consp special-brace-list) (progn (goto-char (car (car special-brace-list))) - (c-forward-token-1 1 nil indent-point)) + (c-forward-token-2 1 nil indent-point)) (goto-char containing-sexp)) (forward-char) (let ((start (point))) @@ -3475,9 +6361,8 @@ (c-add-syntax 'brace-list-intro (point)) (setq lim (c-most-enclosing-brace c-state-cache (point))) (c-beginning-of-statement-1 lim) - (c-add-stmt-syntax 'brace-list-intro t lim - (c-whack-state-after (point) paren-state) - t))) + (c-add-stmt-syntax 'brace-list-intro nil t t lim + (c-whack-state-after (point) paren-state)))) ;; CASE 9D: this is just a later brace-list-entry or ;; brace-entry-open (t (if (or (eq char-after-ip ?{) @@ -3491,9 +6376,11 @@ )) )))) ;; CASE 10: A continued statement or top level construct. - ((and (not (memq char-before-ip '(?\; ?:))) - (or (not (eq char-before-ip ?})) - (c-looking-at-inexpr-block-backward c-state-cache)) + ((and (if (c-mode-is-new-awk-p) + (c-awk-prev-line-incomplete-p containing-sexp) ; ACM 2002/3/29 + (and (not (memq char-before-ip '(?\; ?:))) + (or (not (eq char-before-ip ?})) + (c-looking-at-inexpr-block-backward c-state-cache)))) (> (point) (save-excursion (c-beginning-of-statement-1 containing-sexp) @@ -3510,7 +6397,8 @@ (goto-char containing-sexp) (setq lim (c-most-enclosing-brace c-state-cache containing-sexp)) (c-backward-to-block-anchor lim) - (c-add-stmt-syntax 'case-label t lim paren-state)) + (c-add-stmt-syntax 'case-label nil t nil + lim paren-state)) ;; CASE 15: any other label ((looking-at c-label-key) (goto-char containing-sexp) @@ -3525,7 +6413,8 @@ 'case-label 'label))) (c-backward-to-block-anchor lim) - (c-add-stmt-syntax tmpsymbol t lim paren-state)) + (c-add-stmt-syntax tmpsymbol nil t nil + lim paren-state)) ;; CASE 16: block close brace, possibly closing the defun or ;; the class ((eq char-after-ip ?}) @@ -3539,7 +6428,8 @@ ;; e.g. a macro argument. ((c-after-conditional) (c-backward-to-block-anchor lim) - (c-add-stmt-syntax 'block-close t lim paren-state)) + (c-add-stmt-syntax 'block-close nil t nil + lim paren-state)) ;; CASE 16A: closing a lambda defun or an in-expression ;; block? C.f. cases 4, 7B and 17E. ((setq placeholder (c-looking-at-inexpr-block @@ -3554,13 +6444,13 @@ (c-add-syntax tmpsymbol (point)) (goto-char (cdr placeholder)) (back-to-indentation) - (c-add-stmt-syntax tmpsymbol t + (c-add-stmt-syntax tmpsymbol nil t nil (c-most-enclosing-brace paren-state (point)) (c-whack-state-after (point) paren-state)) (if (/= (point) (cdr placeholder)) (c-add-syntax (car placeholder))))) ;; CASE 16B: does this close an inline or a function in - ;; an extern block or namespace? + ;; a non-class declaration level block? ((setq placeholder (c-search-uplist-for-classkey paren-state)) (c-backward-to-decl-anchor lim) (back-to-indentation) @@ -3584,7 +6474,8 @@ (back-to-indentation) (if (/= (point) containing-sexp) (goto-char placeholder)) - (c-add-stmt-syntax 'defun-close t lim paren-state)) + (c-add-stmt-syntax 'defun-close nil t nil + lim paren-state)) ;; CASE 16C: if there an enclosing brace that hasn't ;; been narrowed out by a class, then this is a ;; block-close. C.f. case 17H. @@ -3603,7 +6494,8 @@ (goto-char containing-sexp) ;; c-backward-to-block-anchor not necessary here; those ;; situations are handled in case 16E above. - (c-add-stmt-syntax 'block-close t lim paren-state))) + (c-add-stmt-syntax 'block-close nil t nil + lim paren-state))) ;; CASE 16D: find out whether we're closing a top-level ;; class or a defun (t @@ -3634,7 +6526,7 @@ ;; CASE 17B: continued statement ((and (eq step-type 'same) (/= (point) indent-point)) - (c-add-stmt-syntax 'statement-cont nil + (c-add-stmt-syntax 'statement-cont nil nil nil containing-sexp paren-state)) ;; CASE 17A: After a case/default label? ((progn @@ -3646,14 +6538,15 @@ (c-add-stmt-syntax (if (eq char-after-ip ?{) 'statement-case-open 'statement-case-intro) - t containing-sexp paren-state)) + nil t nil containing-sexp paren-state)) ;; CASE 17D: any old statement ((progn (while (eq step-type 'label) (setq step-type (c-beginning-of-statement-1 containing-sexp))) (eq step-type 'previous)) - (c-add-stmt-syntax 'statement t containing-sexp paren-state) + (c-add-stmt-syntax 'statement nil t nil + containing-sexp paren-state) (if (eq char-after-ip ?{) (c-add-syntax 'block-open))) ;; CASE 17I: Inside a substatement block. @@ -3664,7 +6557,8 @@ (setq lim (c-most-enclosing-brace paren-state containing-sexp)) (c-after-conditional)) (c-backward-to-block-anchor lim) - (c-add-stmt-syntax 'statement-block-intro t lim paren-state) + (c-add-stmt-syntax 'statement-block-intro nil t nil + lim paren-state) (if (eq char-after-ip ?{) (c-add-syntax 'block-open))) ;; CASE 17E: first statement in an in-expression block. @@ -3680,7 +6574,7 @@ (c-add-syntax tmpsymbol (point)) (goto-char (cdr placeholder)) (back-to-indentation) - (c-add-stmt-syntax tmpsymbol t + (c-add-stmt-syntax tmpsymbol nil t nil (c-most-enclosing-brace c-state-cache (point)) (c-whack-state-after (point) paren-state)) (if (/= (point) (cdr placeholder)) @@ -3691,10 +6585,6 @@ ;; statement in a top-level defun. we can tell this is it ;; if there are no enclosing braces that haven't been ;; narrowed out by a class (i.e. don't use bod here). - ;; However, we first check for statements that we can - ;; recognize by keywords. That increases the robustness in - ;; cases where statements are used on the top level, - ;; e.g. in macro definitions. ((save-excursion (save-restriction (widen) @@ -3715,7 +6605,8 @@ (back-to-indentation) (if (/= (point) containing-sexp) (goto-char placeholder)) - (c-add-stmt-syntax 'defun-block-intro t lim paren-state)) + (c-add-stmt-syntax 'defun-block-intro nil t nil + lim paren-state)) ;; CASE 17H: First statement in a block. C.f. case 16C. (t ;; If the block is preceded by a case/switch label on the @@ -3731,7 +6622,8 @@ (goto-char containing-sexp) ;; c-backward-to-block-anchor not necessary here; those ;; situations are handled in case 17I above. - (c-add-stmt-syntax 'statement-block-intro t lim paren-state)) + (c-add-stmt-syntax 'statement-block-intro nil t nil + lim paren-state)) (if (eq char-after-ip ?{) (c-add-syntax 'block-open))) )) @@ -3741,34 +6633,48 @@ (skip-chars-forward " \t") ;; are we looking at a comment only line? (when (and (looking-at c-comment-start-regexp) - (/= (c-forward-token-1 0 nil (c-point 'eol)) 0)) - (c-add-syntax 'comment-intro)) + (/= (c-forward-token-2 0 nil (c-point 'eol)) 0)) + (c-append-syntax 'comment-intro)) ;; we might want to give additional offset to friends (in C++). (when (and c-opt-friend-key (looking-at c-opt-friend-key)) - (c-add-syntax 'friend)) + (c-append-syntax 'friend)) + + ;; Set syntactic-relpos. + (let ((p c-syntactic-context)) + (while (and p + (if (integerp (car-safe (cdr-safe (car p)))) + (progn + (setq syntactic-relpos (car (cdr (car p)))) + nil) + t)) + (setq p (cdr p)))) + ;; Start of or a continuation of a preprocessor directive? (if (and macro-start (eq macro-start (c-point 'boi)) (not (and (c-major-mode-is 'pike-mode) (eq (char-after (1+ macro-start)) ?\")))) - (c-add-syntax 'cpp-macro) + (c-append-syntax 'cpp-macro) (when (and c-syntactic-indentation-in-macros macro-start) (if in-macro-expr - (when (or (< syntactic-relpos macro-start) - (not (or (assq 'arglist-intro syntax) - (assq 'arglist-cont syntax) - (assq 'arglist-cont-nonempty syntax) - (assq 'arglist-close syntax)))) + (when (or + (< syntactic-relpos macro-start) + (not (or + (assq 'arglist-intro c-syntactic-context) + (assq 'arglist-cont c-syntactic-context) + (assq 'arglist-cont-nonempty c-syntactic-context) + (assq 'arglist-close c-syntactic-context)))) ;; If inside a cpp expression, i.e. anywhere in a ;; cpp directive except a #define body, we only let ;; through the syntactic analysis that is internal ;; in the expression. That means the arglist ;; elements, if they are anchored inside the cpp ;; expression. - (setq syntax `((cpp-macro-cont . ,macro-start)))) + (setq c-syntactic-context nil) + (c-add-syntax 'cpp-macro-cont macro-start)) (when (and (eq macro-start syntactic-relpos) - (not (assq 'cpp-define-intro syntax)) + (not (assq 'cpp-define-intro c-syntactic-context)) (save-excursion (goto-char macro-start) (or (not (c-forward-to-cpp-define-body)) @@ -3779,13 +6685,10 @@ ;; indentation of the #define body. (c-add-syntax 'cpp-define-intro))))) ;; return the syntax - syntax)))) + c-syntactic-context)))) -(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) +;; Indentation calculation. (defun c-evaluate-offset (offset langelem symbol) ;; offset can be a number, a function, a variable, a list, or one of @@ -3799,7 +6702,10 @@ ((eq offset '/) (/ (- c-basic-offset) 2)) ((numberp offset) offset) ((functionp offset) (c-evaluate-offset - (funcall offset langelem) langelem symbol)) + (funcall offset + (cons (car langelem) + (car-safe (cdr langelem)))) + langelem symbol)) ((vectorp offset) offset) ((null offset) nil) ((listp offset) @@ -3813,10 +6719,13 @@ (t (symbol-value offset)) )) -(defun c-get-offset (langelem) - "Get offset from LANGELEM which is a cons cell of the form: -\(SYMBOL . RELPOS). The symbol is matched against `c-offsets-alist' -and the offset found there is returned." +(defun c-calc-offset (langelem) + ;; Get offset from LANGELEM which is a list beginning with the + ;; syntactic symbol and followed by any analysis data it provides. + ;; That data may be zero or more elements, but if at least one is + ;; given then the first is the relpos (or nil). The symbol is + ;; matched against `c-offsets-alist' and the offset calculated from + ;; that is returned. (let* ((symbol (car langelem)) (match (assq symbol c-offsets-alist)) (offset (cdr-safe match))) @@ -3832,34 +6741,56 @@ 0)) )) +(defun c-get-offset (langelem) + ;; This is a compatibility wrapper for `c-calc-offset' in case + ;; someone is calling it directly. It takes an old style syntactic + ;; element on the form (SYMBOL . RELPOS) and converts it to the new + ;; list form. + (if (cdr langelem) + (c-calc-offset (list (car langelem) (cdr langelem))) + (c-calc-offset langelem))) + (defun c-get-syntactic-indentation (langelems) - "Apply `c-get-offset' to a list of langelem cells to get the total -syntactic indentation. The anchor position, whose column is used as a -base for all the collected offsets, is taken from the first element -with a relpos." + ;; Calculate the syntactic indentation from a syntactic description + ;; as returned by `c-guess-syntax'. + ;; ;; Note that topmost-intro always has a relpos at bol, for ;; historical reasons. It's often used together with other symbols ;; that has more sane positions. Since we always use the first ;; found relpos, we rely on that these other symbols always precede ;; topmost-intro in the LANGELEMS list. (let ((indent 0) anchor) - (catch 'done - (while langelems - (let ((res (c-get-offset (car langelems)))) - (if (vectorp res) - (throw 'done (elt res 0)) - (unless anchor - (let ((relpos (cdr (car langelems)))) - (if relpos - (setq anchor relpos)))) - (setq indent (+ indent res) - langelems (cdr langelems))))) - (+ indent - (if anchor - (save-excursion - (goto-char anchor) - (current-column)) - 0))))) + + (while langelems + (let* ((c-syntactic-element (car langelems)) + (res (c-calc-offset c-syntactic-element))) + + (if (vectorp res) + ;; Got an absolute column that overrides any indentation + ;; we've collected so far, but not the relative + ;; indentation we might get for the nested structures + ;; further down the langelems list. + (setq indent (elt res 0) + anchor (point-min)) ; A position at column 0. + + ;; Got a relative change of the current calculated + ;; indentation. + (setq indent (+ indent res)) + + ;; Use the anchor position from the first syntactic + ;; element with one. + (unless anchor + (let ((relpos (car-safe (cdr (car langelems))))) + (if relpos + (setq anchor relpos))))) + + (setq langelems (cdr langelems)))) + + (if anchor + (+ indent (save-excursion + (goto-char anchor) + (current-column))) + indent))) (cc-provide 'cc-engine)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/progmodes/cc-fonts.el Thu Jul 03 12:30:59 2003 +0000 @@ -0,0 +1,2879 @@ +;;; cc-fonts.el --- font lock support for CC Mode + +;; Copyright (C) 2002, 03 Free Software Foundation, Inc. + +;; Authors: 2003- Alan Mackenzie +;; 2002- Martin Stjernholm +;; Maintainer: bug-cc-mode@gnu.org +;; Created: 07-Jan-2002 +;; 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 2, 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, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; Some comments on the use of faces: +;; +;; o `c-label-face-name' is either `font-lock-constant-face' (in Emacs +;; 20 and later), or `font-lock-reference-face'. +;; +;; o `c-constant-face-name', `c-reference-face-name' and +;; `c-doc-markup-face-name' are essentially set up like +;; `c-label-face-name'. +;; +;; o `c-preprocessor-face-name' is `font-lock-preprocessor-face' in +;; XEmacs and - in lack of a closer equivalent - +;; `font-lock-builtin-face' or `font-lock-reference-face' in Emacs. +;; +;; o `c-doc-face-name' is `font-lock-doc-string-face' in XEmacs, +;; `font-lock-doc-face' in Emacs 21 and later, or +;; `font-lock-comment-face' in older Emacs (that since source +;; documentation are actually comments in these languages, as opposed +;; to elisp). +;; +;; o `c-invalid-face-name' is `font-lock-warning-face' in Emacs. In +;; older XEmacs there's no corresponding standard face, so there +;; it's mapped to a special `c-invalid-face'. +;; +;; TBD: We should probably provide real faces for the above uses and +;; instead initialize them from the standard faces. + +;;; Code: + +;; The faces that already have been put onto the text is tested in +;; various places to direct further fontifications. For this to work, +;; the following assumptions regarding the faces must hold (apart from +;; the dependencies on the font locking order): +;; +;; o `font-lock-comment-face' and the face in `c-doc-face-name' is +;; not used in anything but comments. +;; o If any face (e.g. `c-doc-markup-face-name') but those above is +;; used in comments, it doesn't replace them. +;; o `font-lock-string-face' is not used in anything but string +;; literals (single or double quoted). +;; o `font-lock-keyword-face' and the face in `c-label-face-name' are +;; never overlaid with other faces. + +(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) +(cc-require 'cc-engine) +(cc-require-when-compile 'cc-awk) ; Change from cc-require, 2003/6/18 to +;; prevent cc-awk being loaded when it's not needed. There is now a (require +;; 'cc-awk) in (defun awk-mode ..). + +;; Avoid repeated loading through the eval-after-load directive in +;; cc-mode.el. +(provide 'cc-fonts) + +(cc-external-require 'font-lock) + +(cc-bytecomp-defvar parse-sexp-lookup-properties) ; Emacs only. + +;; Need to declare these local symbols during compilation since +;; they're referenced from lambdas in `byte-compile' calls that are +;; executed at compile time. They don't need to have the proper +;; definitions, though, since the generated functions aren't called +;; during compilation. +(cc-bytecomp-defvar c-preprocessor-face-name) +(cc-bytecomp-defvar c-reference-face-name) +(cc-bytecomp-defun c-fontify-recorded-types-and-refs) +(cc-bytecomp-defun c-font-lock-declarators) +(cc-bytecomp-defun c-font-lock-objc-iip-decl) +(cc-bytecomp-defun c-font-lock-objc-method) +(cc-bytecomp-defun c-font-lock-invalid-string) + +;; Emacs 19 doesn't have `defface'. This "replacement" leaves a lot +;; to be wished for but at least it avoids any errors. +(cc-eval-when-compile + (or (fboundp 'defface) + (cc-bytecomp-defmacro defface (face spec doc &rest args) + `(make-face ',face)))) + + +;; Note that font-lock in XEmacs doesn't expand face names as +;; variables, so we have to use the (eval . FORM) in the font lock +;; matchers wherever we use these alias variables. + +(defconst c-preprocessor-face-name + (cond ((c-face-name-p 'font-lock-preprocessor-face) + ;; XEmacs has a font-lock-preprocessor-face. + 'font-lock-preprocessor-face) + ((c-face-name-p 'font-lock-builtin-face) + ;; In Emacs 20 and later font-lock-builtin-face has + ;; traditionally been used for preprocessor directives. + 'font-lock-builtin-face) + (t + 'font-lock-reference-face))) + +(cc-bytecomp-defvar font-lock-constant-face) + +(defconst c-label-face-name + (cond ((c-face-name-p 'font-lock-label-face) + ;; If it happens to occur in the future. (Well, the more + ;; pragmatic reason is to get unique faces for the test + ;; suite.) + 'font-lock-label-face) + ((and (c-face-name-p 'font-lock-constant-face) + (eq font-lock-constant-face 'font-lock-constant-face)) + ;; Test both if font-lock-constant-face exists and that it's + ;; not an alias for something else. This is important since + ;; we compare already set faces in various places. + 'font-lock-constant-face) + (t + 'font-lock-reference-face))) + +(defconst c-constant-face-name + (if (and (c-face-name-p 'font-lock-constant-face) + (eq font-lock-constant-face 'font-lock-constant-face)) + ;; This doesn't exist in XEmacs <= 20 and some earlier versions + ;; of XEmacs 21. + 'font-lock-constant-face + c-label-face-name)) + +(defconst c-reference-face-name + (if (and (c-face-name-p 'font-lock-reference-face) + (eq font-lock-reference-face 'font-lock-reference-face)) + ;; This is considered obsolete in Emacs 20 and later, but it + ;; still maps well to this use. (Another reason to do this is + ;; to get unique faces for the test suite.) + 'font-lock-reference-face + c-label-face-name)) + +;; This should not mapped to a face that also is used to fontify things +;; that aren't comments or string literals. +(defconst c-doc-face-name + (cond ((c-face-name-p 'font-lock-doc-string-face) + ;; XEmacs. + 'font-lock-doc-string-face) + ((c-face-name-p 'font-lock-doc-face) + ;; Emacs 21 and later. + 'font-lock-doc-face) + (t + 'font-lock-comment-face))) + +(defconst c-doc-markup-face-name + (if (c-face-name-p 'font-lock-doc-markup-face) + ;; If it happens to occur in the future. (Well, the more + ;; pragmatic reason is to get unique faces for the test + ;; suite.) + 'font-lock-doc-markup-face + c-label-face-name)) + +(defconst c-invalid-face-name + (if (c-face-name-p 'font-lock-warning-face) + ;; Emacs >= 20 and XEmacs >= 21 has a font-lock-warning-face. + 'font-lock-warning-face + ;; Otherwise we provide a face. + 'c-invalid-face)) + +(unless (c-face-name-p c-invalid-face-name) + (defconst c-invalid-face 'c-invalid-face) ; Necessary in Emacs 19. + (defface c-invalid-face + '((((class color) (background light)) (:foreground "red")) + (((class color)) (:foreground "hotpink")) + (t (:inverse-video t))) + "Face used to highlight invalid syntax." + :group 'c-fonts)) + +;; To make hard spaces visible an inverted version of +;; `c-invalid-face-name' is used. Since font-lock in Emacs expands +;; all face names in `font-lock-keywords' as variables we need to have +;; a variable for it that resolves to its own name. +(defconst c-nonbreakable-space-face 'c-nonbreakable-space-face) + +(cc-bytecomp-defun face-inverse-video-p) ; Only in Emacs. +(cc-bytecomp-defun face-property-instance) ; Only in XEmacs. + +(defun c-make-inverse-face (oldface newface) + ;; Emacs and XEmacs have completely different face manipulation + ;; routines. :P + ;; + ;; This function does not do any hidden buffer changes + (copy-face oldface newface) + (cond ((fboundp 'face-inverse-video-p) + ;; Emacs 20 and later. This only looks at the inverse flag + ;; in the current frame. Other display configurations might + ;; be different, but it can only show if the same Emacs has + ;; frames on e.g. a color and a monochrome display + ;; simultaneously. + (unless (face-inverse-video-p oldface) + (invert-face newface))) + ((fboundp 'face-property-instance) + ;; XEmacs. Same pitfall here. + (unless (face-property-instance oldface 'reverse) + (invert-face newface))) + (t + ;; Emacs 19 has no inverse flag at all. Just inverse the + ;; face and hope it wasn't inversed already. + (invert-face newface)))) + +(eval-and-compile + ;; We need the following functions during compilation since they're + ;; called when the `c-lang-defconst' initializers are evaluated. + ;; Define them at runtime too for the sake of derived modes. + + (defmacro c-put-font-lock-face (from to face) + ;; Put a face on a region (overriding any existing face) in the way + ;; font-lock would do it. In XEmacs that means putting an + ;; additional font-lock property, or else the font-lock package + ;; won't recognize it as fontified and might override it + ;; incorrectly. + (if (fboundp 'font-lock-set-face) + ;; Note: This function has no docstring in XEmacs so it might be + ;; considered internal. + `(font-lock-set-face ,from ,to ,face) + `(put-text-property ,from ,to 'face ,face))) + + (defmacro c-remove-font-lock-face (from to) + ;; This is the inverse of `c-put-font-lock-face'. + (if (fboundp 'font-lock-remove-face) + `(font-lock-remove-face ,from ,to) + `(remove-text-properties ,from ,to '(face nil)))) + + (defmacro c-put-font-lock-string-face (from to) + ;; Put `font-lock-string-face' on a string. The surrounding + ;; quotes are included in Emacs but not in XEmacs. The passed + ;; region should include them. + (if (featurep 'xemacs) + `(c-put-font-lock-face (1+ ,from) (1- ,to) 'font-lock-string-face) + `(c-put-font-lock-face ,from ,to 'font-lock-string-face))) + + (defmacro c-fontify-types-and-refs (varlist &rest body) + ;; Like `let', but additionally activates `c-record-type-identifiers' + ;; and `c-record-ref-identifiers', and fontifies the recorded ranges + ;; accordingly on exit. + `(let ((c-record-type-identifiers t) + c-record-ref-identifiers + ,@varlist) + (prog1 (progn ,@body) + (c-fontify-recorded-types-and-refs)))) + (put 'c-fontify-types-and-refs 'lisp-indent-function 1) + (eval-after-load "edebug" '(def-edebug-spec c-fontify-types-and-refs let*)) + + (defun c-skip-comments-and-strings (limit) + ;; If the point is within a region fontified as a comment or + ;; string literal skip to the end of it or to LIMIT, whichever + ;; comes first, and return t. Otherwise return nil. The match + ;; data is not clobbered. + (when (c-got-face-at (point) c-literal-faces) + (while (progn + (goto-char (next-single-property-change + (point) 'face nil limit)) + (and (< (point) limit) + (c-got-face-at (point) c-literal-faces)))) + t)) + + (defun c-make-font-lock-search-function (regexp &rest highlights) + ;; This function makes a byte compiled function that works much like + ;; a matcher element in `font-lock-keywords'. It cuts out a little + ;; bit of the overhead compared to a real matcher. The main reason + ;; is however to pass the real search limit to the anchored + ;; matcher(s), since most (if not all) font-lock implementations + ;; arbitrarily limits anchored matchers to the same line, and also + ;; to insulate against various other irritating differences between + ;; the different (X)Emacs font-lock packages. + ;; + ;; REGEXP is the matcher, which must be a regexp. Only matches + ;; where the beginning is outside any comment or string literal are + ;; significant. + ;; + ;; HIGHLIGHTS is a list of highlight specs, just like in + ;; `font-lock-keywords', with these limitations: The face is always + ;; overridden (no big disadvantage, since hits in comments etc are + ;; filtered anyway), there is no "laxmatch", and an anchored matcher + ;; is always a form which must do all the fontification directly. + ;; `limit' is a variable bound to the real limit in the context of + ;; the anchored matcher forms. + ;; + ;; This function does not do any hidden buffer changes, but the + ;; generated functions will. They are however used in places + ;; covered by the font-lock context. + + ;; Note: Replace `byte-compile' with `eval' to debug the generated + ;; lambda easier. + (byte-compile + `(lambda (limit) + (let (-match-end-pos- + ;; The font-lock package in Emacs is known to clobber + ;; `parse-sexp-lookup-properties' (when it exists). + (parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties)))) + (while (re-search-forward ,regexp limit t) + (setq -match-end-pos- (point)) + (unless (progn + (goto-char (match-beginning 0)) + (c-skip-comments-and-strings limit)) + (goto-char -match-end-pos-) + ,@(mapcar + (lambda (highlight) + (if (integerp (car highlight)) + (progn + (unless (nth 2 highlight) + (error + "The override flag must currently be set in %s" + highlight)) + (when (nth 3 highlight) + (error + "The laxmatch flag may currently not be set in %s" + highlight)) + `(save-match-data + (c-put-font-lock-face + (match-beginning ,(car highlight)) + (match-end ,(car highlight)) + ,(elt highlight 1)))) + (when (nth 3 highlight) + (error "Match highlights currently not supported in %s" + highlight)) + `(progn + ,(nth 1 highlight) + (save-match-data ,(car highlight)) + ,(nth 2 highlight)))) + highlights)))) + nil)))) + +(defun c-fontify-recorded-types-and-refs () + ;; Converts the ranges recorded on `c-record-type-identifiers' and + ;; `c-record-ref-identifiers' to fontification. + (let (elem) + (while (consp c-record-type-identifiers) + (setq elem (car c-record-type-identifiers) + c-record-type-identifiers (cdr c-record-type-identifiers)) + (c-put-font-lock-face (car elem) (cdr elem) + 'font-lock-type-face)) + (while c-record-ref-identifiers + (setq elem (car c-record-ref-identifiers) + c-record-ref-identifiers (cdr c-record-ref-identifiers)) + ;; Note that the reference face is a variable that is + ;; dereferenced, since it's an alias in Emacs. + (c-put-font-lock-face (car elem) (cdr elem) + c-reference-face-name)))) + +(c-lang-defconst c-cpp-matchers + "Font lock matchers for preprocessor directives and purely lexical +stuff. Used on level 1 and higher." + + ;; Note: `c-font-lock-declarations' assumes that no matcher here + ;; sets `font-lock-type-face' in languages where + ;; `c-recognize-<>-arglists' is set. + + t `(,@(when (c-lang-const c-opt-cpp-prefix) + (let* ((noncontinued-line-end "\\(\\=\\|\\(\\=\\|[^\\]\\)[\n\r]\\)") + (ncle-depth (c-regexp-opt-depth noncontinued-line-end)) + (sws-depth (c-lang-const c-syntactic-ws-depth))) + `(;; The stuff after #error and #warning is a message, so + ;; fontify it as a string. + (,(concat noncontinued-line-end + (c-lang-const c-opt-cpp-prefix) + "\\(error\\|warning\\)\\>\\s *\\(.*\\)$") + ,(+ ncle-depth 2) font-lock-string-face) + + ;; Fontify filenames in #include <...> as strings. + (,(concat noncontinued-line-end + (c-lang-const c-opt-cpp-prefix) + "\\(import\\|include\\)\\>" + (c-lang-const c-syntactic-ws) + "\\(<[^>\n\r]*>?\\)") + (,(+ ncle-depth sws-depth 2) + font-lock-string-face) + + ;; Use an anchored matcher to put paren syntax on the brackets. + (,(byte-compile + `(lambda (limit) + (let ((beg-pos + (match-beginning ,(+ ncle-depth sws-depth 2))) + (end-pos + (1- (match-end ,(+ ncle-depth sws-depth 2))))) + (if (eq (char-after end-pos) ?>) + (progn + (c-mark-<-as-paren beg-pos) + (c-mark->-as-paren end-pos)) + (c-clear-char-property beg-pos 'syntax-table))) + nil)))) + + ;; #define. + (,(c-make-font-lock-search-function + (concat + noncontinued-line-end + (c-lang-const c-opt-cpp-prefix) + "define\\>" + (c-lang-const c-syntactic-ws) + "\\(" (c-lang-const c-symbol-key) "\\)" ; 1 + ncle + sws + (concat "\\(" ; 2 + ncle + sws + c-sym-key + ;; Macro with arguments - a "function". + "\\(\(\\)" ; 3 + ncle + sws + c-sym-key + "\\|" + ;; Macro without arguments - a "variable". + "\\([^\(]\\|$\\)" + "\\)")) + `((if (match-beginning ,(+ 3 ncle-depth sws-depth + (c-lang-const c-symbol-key-depth))) + ;; "Function". Fontify the name and the arguments. + (save-restriction + (c-put-font-lock-face + (match-beginning ,(+ 1 ncle-depth sws-depth)) + (match-end ,(+ 1 ncle-depth sws-depth)) + 'font-lock-function-name-face) + (goto-char (match-end + ,(+ 3 ncle-depth sws-depth + (c-lang-const c-symbol-key-depth)))) + + (narrow-to-region (point-min) limit) + (while (and + (progn + (c-forward-syntactic-ws) + (looking-at c-symbol-key)) + (progn + (c-put-font-lock-face + (match-beginning 0) (match-end 0) + 'font-lock-variable-name-face) + (goto-char (match-end 0)) + (c-forward-syntactic-ws) + (eq (char-after) ?,))) + (forward-char))) + + ;; "Variable". + (c-put-font-lock-face + (match-beginning ,(+ 1 ncle-depth sws-depth)) + (match-end ,(+ 1 ncle-depth sws-depth)) + 'font-lock-variable-name-face))))) + + ;; Fontify cpp function names in preprocessor + ;; expressions in #if and #elif. + ,(when (c-lang-const c-cpp-defined-fns) + `(,(c-make-font-lock-search-function + (concat noncontinued-line-end + (c-lang-const c-opt-cpp-prefix) + "\\(if\\|elif\\)\\>" ; 1 + ncle-depth + ;; Match the whole logical line to look + ;; for the functions in. + "\\(\\\\\\(.\\|[\n\r]\\)\\|[^\n\r]\\)*") + `((let ((limit (match-end 0))) + (while (re-search-forward + ,(concat "\\<\\(" + (c-regexp-opt + (c-lang-const c-cpp-defined-fns) + nil) + "\\)\\>" + "\\s *\(?") + limit 'move) + (c-put-font-lock-face (match-beginning 1) + (match-end 1) + c-preprocessor-face-name))) + (goto-char (match-end ,(1+ ncle-depth))))))) + + ;; Fontify the directive names. + (,(c-make-font-lock-search-function + (concat noncontinued-line-end + "\\(" + (c-lang-const c-opt-cpp-prefix) + "[" (c-lang-const c-symbol-chars) "]+" + "\\)") + `(,(1+ ncle-depth) c-preprocessor-face-name t))) + ))) + + ,@(when (c-major-mode-is 'pike-mode) + `((eval . (list "\\`#![^\n\r]*" + 0 c-preprocessor-face-name)))) + + ;; Make hard spaces visible through an inverted `c-invalid-face-name'. + (eval . (list + "\240" + 0 (progn + (unless (c-face-name-p 'c-nonbreakable-space-face) + (c-make-inverse-face c-invalid-face-name + 'c-nonbreakable-space-face)) + 'c-nonbreakable-space-face))) + )) + +(defun c-font-lock-invalid-string () + ;; Assuming the point is after the opening character of a string, + ;; fontify that char with `c-invalid-face-name' if the string + ;; decidedly isn't terminated properly. Assumes the string already + ;; is syntactically fontified. + (let ((end (1+ (c-point 'eol)))) + (and (eq (get-text-property (point) 'face) 'font-lock-string-face) + (= (next-single-property-change (point) 'face nil end) end) + ;; We're at eol inside a string. The first check above is + ;; necessary in XEmacs since it doesn't fontify the string + ;; delimiters themselves. Thus an empty string won't have + ;; the string face anywhere. + (if (c-major-mode-is '(c-mode c++-mode objc-mode pike-mode)) + ;; There's no \ before the newline. + (not (eq (char-before (1- end)) ?\\)) + ;; Quoted newlines aren't supported. + t) + (if (c-major-mode-is 'pike-mode) + ;; There's no # before the string, so newlines + ;; aren't allowed. + (not (eq (char-before (1- (point))) ?#)) + t) + (c-put-font-lock-face (1- (point)) (point) c-invalid-face-name)))) + +(c-lang-defconst c-basic-matchers-before + "Font lock matchers for basic keywords, labels, references and various +other easily recognizable things that should be fontified before generic +casts and declarations are fontified. Used on level 2 and higher." + + ;; Note: `c-font-lock-declarations' assumes that no matcher here + ;; sets `font-lock-type-face' in languages where + ;; `c-recognize-<>-arglists' is set. + + t `(;; Put a warning face on the opener of unclosed strings that + ;; can't span lines. Later font + ;; lock packages have a `font-lock-syntactic-face-function' for + ;; this, but it doesn't give the control we want since any + ;; fontification done inside the function will be + ;; unconditionally overridden. + ,(c-make-font-lock-search-function + ;; Match a char before the string starter to make + ;; `c-skip-comments-and-strings' work correctly. + (concat ".\\(" c-string-limit-regexp "\\)") + '((c-font-lock-invalid-string))) + + ;; Fontify keyword constants. + ,@(when (c-lang-const c-constant-kwds) + (let ((re (c-make-keywords-re nil (c-lang-const c-constant-kwds)))) + (if (c-major-mode-is 'pike-mode) + ;; No symbol is a keyword after "->" in Pike. + `((eval . (list ,(concat "\\(\\=\\|\\(\\=\\|[^-]\\)[^>]\\)" + "\\<\\(" re "\\)\\>") + 3 c-constant-face-name))) + `((eval . (list ,(concat "\\<\\(" re "\\)\\>") + 1 c-constant-face-name)))))) + + ;; Fontify all keywords except the primitive types. + ,(if (c-major-mode-is 'pike-mode) + ;; No symbol is a keyword after "->" in Pike. + `(,(concat "\\(\\=\\|\\(\\=\\|[^-]\\)[^>]\\)" + "\\<" (c-lang-const c-regular-keywords-regexp)) + 3 font-lock-keyword-face) + `(,(concat "\\<" (c-lang-const c-regular-keywords-regexp)) + 1 font-lock-keyword-face)) + + ;; Fontify leading identifiers in fully qualified names like + ;; "foo::bar" in languages that supports such things. + ,@(when (c-lang-const c-opt-identifier-concat-key) + `((,(byte-compile + ;; Must use a function here since we match longer + ;; than we want to move before doing a new search. + ;; This is not necessary for XEmacs >= 20 since it + ;; restarts the search from the end of the first + ;; highlighted submatch (something that causes + ;; problems in other places). + `(lambda (limit) + (while (re-search-forward + ,(concat "\\(\\<" ; 1 + "\\(" (c-lang-const c-symbol-key) "\\)" ; 2 + "[ \t\n\r\f\v]*" + (c-lang-const c-opt-identifier-concat-key) + "[ \t\n\r\f\v]*" + "\\)" + "\\(" + (c-lang-const c-opt-after-id-concat-key) + "\\)") + limit t) + (unless (progn + (goto-char (match-beginning 0)) + (c-skip-comments-and-strings limit)) + (or (get-text-property (match-beginning 2) 'face) + (c-put-font-lock-face (match-beginning 2) + (match-end 2) + c-reference-face-name)) + (goto-char (match-end 1))))))))) + + ;; Fontify the special declarations in Objective-C. + ,@(when (c-major-mode-is 'objc-mode) + `(;; Fontify class names in the beginning of message expressions. + ,(c-make-font-lock-search-function + "\\[" + '((c-fontify-types-and-refs () + (c-forward-syntactic-ws limit) + (let ((start (point))) + ;; In this case we accept both primitive and known types. + (when (eq (c-forward-type) 'known) + (goto-char start) + (let ((c-promote-possible-types t)) + (c-forward-type)))) + (if (> (point) limit) (goto-char limit))))) + + ;; The @interface/@implementation/@protocol directives. + (,(concat "\\<" + (c-regexp-opt + '("@interface" "@implementation" "@protocol") + t) + "\\>") + (,(byte-compile + (lambda (limit) + (let (;; The font-lock package in Emacs is known to clobber + ;; `parse-sexp-lookup-properties' (when it exists). + (parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties)))) + (save-restriction + (narrow-to-region (point-min) limit) + (c-font-lock-objc-iip-decl))) + nil)))))) + )) + +(defun c-font-lock-complex-decl-prepare (limit) + ;; Called before any of the matchers in `c-complex-decl-matchers'. + ;; Nil is always returned. + + ;;(message "c-font-lock-complex-decl-prepare %s %s" (point) limit) + + ;; Clear the list of found types if we start from the start of the + ;; buffer, to make it easier to get rid of misspelled types and + ;; variables that has gotten recognized as types in malformed code. + (when (bobp) + (c-clear-found-types)) + + ;; Clear the c-type char properties in the region to recalculate + ;; them properly. This is necessary e.g. to handle constructs that + ;; might been required as declarations temporarily during editing. + ;; The interesting properties are anyway those put on the closest + ;; token before the region. + (c-clear-char-properties (point) limit 'c-type) + + ;; Update `c-state-cache' to the beginning of the region. This will + ;; make `c-beginning-of-syntax' go faster when it's used later on, + ;; and it's near the point most of the time. + (c-parse-state) + + ;; Check if the fontified region starts inside a declarator list so + ;; that `c-font-lock-declarators' should be called at the start. + (let ((prop (save-excursion + (c-backward-syntactic-ws) + (unless (bobp) + (c-get-char-property (1- (point)) 'c-type))))) + (when (memq prop '(c-decl-id-start c-decl-type-start)) + (c-forward-syntactic-ws limit) + (c-font-lock-declarators limit t (eq prop 'c-decl-type-start)))) + + nil) + +(defun c-font-lock-<>-arglists (limit) + ;; Fontify types and references in names containing angle bracket + ;; arglists from the point to LIMIT. This will also fontify cases + ;; like normal function calls on the form "foo (a < b, c > d)", but + ;; `c-font-lock-declarations' will undo that later. Nil is always + ;; returned. + + (let (;; The font-lock package in Emacs is known to clobber + ;; `parse-sexp-lookup-properties' (when it exists). + (parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties))) + id-start id-end pos kwd-sym) + + (while (and (< (point) limit) + (re-search-forward c-opt-<>-arglist-start limit t)) + + (setq id-start (match-beginning 1) + id-end (match-end 1) + pos (point)) + + (goto-char id-start) + (unless (c-skip-comments-and-strings limit) + (setq kwd-sym nil) + (if (or (not (eq (get-text-property id-start 'face) + 'font-lock-keyword-face)) + (when (looking-at c-opt-<>-sexp-key) + (setq kwd-sym (c-keyword-sym (match-string 1))))) + (progn + (goto-char (1- pos)) + ;; Check for comment/string both at the identifier and + ;; at the "<". + (unless (c-skip-comments-and-strings limit) + + (when (c-forward-<>-arglist (c-keyword-member kwd-sym + 'c-<>-type-kwds) + t) + (when (and c-opt-identifier-concat-key + (not (get-text-property id-start 'face))) + (c-forward-syntactic-ws) + (if (looking-at c-opt-identifier-concat-key) + (c-put-font-lock-face id-start id-end + c-reference-face-name) + (c-put-font-lock-face id-start id-end + 'font-lock-type-face)))) + + (goto-char pos))) + (goto-char pos))))) + nil) + +(defun c-font-lock-declarators (limit list types) + ;; Assuming the point is at the start of a declarator in a + ;; declaration, fontify it. If LIST is non-nil, fontify also all + ;; following declarators in a comma separated list (e.g. "foo" and + ;; "bar" in "int foo = 17, bar;"). Stop at LIMIT. If TYPES is + ;; non-nil, fontify all identifiers as types. Nil is always + ;; returned. + + ;;(message "c-font-lock-declarators from %s to %s" (point) limit) + (c-fontify-types-and-refs + ((pos (point)) next-pos id-start id-end + paren-depth + id-face got-init + c-last-identifier-range + (separator-prop (if types 'c-decl-type-start 'c-decl-id-start))) + + (while (and + pos + (< (point) limit) + + (let (got-identifier) + (setq paren-depth 0) + ;; Skip over type decl prefix operators. (Note similar + ;; code in `c-font-lock-declarations'.) + (while (and (looking-at c-type-decl-prefix-key) + (if (and (c-major-mode-is 'c++-mode) + (match-beginning 2)) + ;; If the second submatch matches in C++ then + ;; we're looking at an identifier that's a + ;; prefix only if it specifies a member pointer. + (progn + (setq id-start (point)) + (c-forward-name) + (if (looking-at "\\(::\\)") + ;; We only check for a trailing "::" and + ;; let the "*" that should follow be + ;; matched in the next round. + t + ;; It turned out to be the real identifier, + ;; so flag that and stop. + (setq got-identifier t) + nil)) + t)) + (if (eq (char-after) ?\() + (progn + (setq paren-depth (1+ paren-depth)) + (forward-char)) + (goto-char (match-end 1))) + (c-forward-syntactic-ws)) + + ;; If we didn't pass the identifier above already, do it now. + (unless got-identifier + (setq id-start (point)) + (c-forward-name)) + (setq id-end (point)) + + (/= id-end pos)) + + ;; Skip out of the parens surrounding the identifier. + (or (= paren-depth 0) + (c-safe (goto-char (scan-lists (point) 1 paren-depth)))) + + (<= (point) limit) + + ;; Search syntactically to the end of the declarator (";", + ;; ",", ")", ">" (for <> arglists), eob etc) or to the + ;; beginning of an initializer or function prototype ("=" + ;; or "\\s\("). + (c-syntactic-re-search-forward + "[\];,\{\}\[\)>]\\|\\'\\|\\(=\\|\\(\\s\(\\)\\)" limit t t)) + + (setq next-pos (match-beginning 0) + id-face (if (match-beginning 2) + 'font-lock-function-name-face + 'font-lock-variable-name-face) + got-init (match-beginning 1)) + + (if types + ;; Register and fontify the identifer as a type. + (let ((c-promote-possible-types t)) + (goto-char id-start) + (c-forward-type)) + ;; Fontify the last symbol in the identifier if it isn't fontified + ;; already. The check is necessary only in certain cases where this + ;; function is used "sloppily", e.g. in `c-simple-decl-matchers'. + (when (and c-last-identifier-range + (not (get-text-property (car c-last-identifier-range) + 'face))) + (c-put-font-lock-face (car c-last-identifier-range) + (cdr c-last-identifier-range) + id-face))) + + (goto-char next-pos) + (setq pos nil) + (when list + ;; Jump past any initializer or function prototype to see if + ;; there's a ',' to continue at. + + (cond ((eq id-face 'font-lock-function-name-face) + ;; Skip a parenthesized initializer (C++) or a function + ;; prototype. + (if (c-safe (c-forward-sexp 1) t) + (c-forward-syntactic-ws limit) + (goto-char limit))) + + (got-init + ;; Skip an initializer expression. + (if (c-syntactic-re-search-forward "[;,]" limit 'move t) + (backward-char))) + + (t (c-forward-syntactic-ws limit))) + + ;; If a ',' is found we set pos to the next declarator and iterate. + (when (and (< (point) limit) (looking-at ",")) + (c-put-char-property (point) 'c-type separator-prop) + (forward-char) + (c-forward-syntactic-ws limit) + (setq pos (point)))))) + nil) + +(defconst c-font-lock-maybe-decl-faces + ;; List of faces that might be put at the start of a type when + ;; `c-font-lock-declarations' runs. This needs to be evaluated to + ;; ensure that face name aliases in Emacs are resolved. + (list nil + font-lock-type-face + c-reference-face-name + font-lock-keyword-face)) + +;; Macro used inside `c-font-lock-declarations'. It ought to be a +;; defsubst or perhaps even a defun, but it contains lots of free +;; variables that refer to things inside `c-font-lock-declarations'. +(defmacro c-fl-shift-type-backward (&optional short) + ;; `c-font-lock-declarations' can consume an arbitrary length list + ;; of types when parsing a declaration, which means that it + ;; sometimes consumes the identifier in the declaration as a type. + ;; This is used to "backtrack" and make the last type be treated + ;; as an identifier instead. + `(progn + ,(unless short + ;; These identifiers are bound only in the inner let. + '(setq identifier-type at-type + identifier-start type-start + identifier-end type-end)) + (if (setq at-type (if (eq prev-at-type 'prefix) + t + prev-at-type)) + (setq type-start prev-type-start + type-end prev-type-end) + (setq type-start start-pos + type-end start-pos)) + ,(unless short + ;; These identifiers are bound only in the inner let. + '(setq start type-end + got-parens nil + got-identifier t + got-suffix t + got-suffix-after-parens t + paren-depth 0)))) + +(defun c-font-lock-declarations (limit) + ;; Fontify all the declarations and casts from the point to LIMIT. + ;; Assumes that strings and comments have been fontified already. + ;; Nil is always returned. + ;; + ;; This function can make hidden buffer changes, but the font-lock + ;; context covers that. + + ;;(message "c-font-lock-declarations search from %s to %s" (point) limit) + + (save-restriction + (let (start-pos + c-disallow-comma-in-<>-arglists + ;; Nonzero if the `c-decl-prefix-re' match is in an arglist context, + ;; as opposed to a statement-level context. The major difference is + ;; that "," works as declaration delimiter in an arglist context, + ;; whereas it only separates declarators in the same declaration in + ;; a statement context. If it's nonzero then the value is the + ;; matched char, e.g. ?\( or ?,. + arglist-match + ;; 'decl if we're in an arglist containing declarations (but if + ;; `c-recognize-paren-inits' is set it might also be an initializer + ;; arglist), '<> if the arglist is of angle bracket type, 'other if + ;; it's some other arglist, or nil if not in an arglist at all. + arglist-type + ;; Set to the result of `c-forward-type'. + at-type + ;; These record the start and end of the type or possible type found + ;; by `c-forward-type'. `type-start' is at the start of the first + ;; type token, and `type-end' is at the start of the first token + ;; after the type (and after any specifiers). + type-start type-end + ;; These store `at-type', `type-start' and `type-end' of the + ;; identifier before the one in those variables. The previous + ;; identifier might turn out to be the real type in a declaration if + ;; the last one has to be the declarator in it. If `prev-at-type' + ;; is nil then the other variables have undefined values. + prev-at-type prev-type-start prev-type-end + ;; Whether we've found a declaration or a cast. We might know this + ;; before we've found the type in it. + at-decl-or-cast + ;; Set when we need to back up to parse this as a declaration but + ;; not as a cast. + backup-if-not-cast + ;; Set if we've found a "typedef" specifier. The identifiers in the + ;; declaration are then fontified as types. + at-typedef + ;; Set if we've found a specifier that can start a declaration where + ;; there's no type. + maybe-typeless + ;; The position of the next token after the closing paren of the + ;; last fontified cast. + last-cast-end + ;; The same for the currently investigated cast. + cast-end + ;; The maximum of the end positions of all the checked type decl + ;; expressions in the successfully identified declarations. The + ;; position might be either before or after the syntactic whitespace + ;; following the last token in the type decl expression. + (max-type-decl-end 0) + ;; Same as `max-type-decl-*', but used when we're before + ;; `token-pos'. + (max-type-decl-end-before-token 0) + ;; Allow recording of identifier ranges in `c-forward-type' etc for + ;; later fontification. Not using `c-fontify-types-and-refs' here + ;; since the ranges should be fontified selectively only when a + ;; declaration or cast has been successfully recognized. + c-record-type-identifiers + c-record-ref-identifiers + ;; The font-lock package in Emacs is known to clobber + ;; `parse-sexp-lookup-properties' (when it exists). + (parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties)))) + + ;; Below we fontify a whole declaration even when it crosses the limit, + ;; to avoid gaps when lazy-lock fontifies the file a screenful at a + ;; time. That is however annoying during editing, e.g. the following is + ;; a common situation while the first line is being written: + ;; + ;; my_variable + ;; some_other_variable = 0; + ;; + ;; font-lock will put the limit at the beginning of the second line + ;; here, and if we go past it we'll fontify "my_variable" as a type and + ;; "some_other_variable" as an identifier, and the latter will not + ;; correct itself until the second line is changed. To avoid that we + ;; narrow to the limit if the region to fontify is a single line. + (when (<= limit (c-point 'bonl)) + (narrow-to-region + (point-min) + (save-excursion + ;; Narrow after any operator chars following the limit though, since + ;; those characters can be useful in recognizing a declaration (in + ;; particular the '{' that opens a function body after the header). + (goto-char limit) + (skip-chars-forward c-nonsymbol-chars) + (point)))) + + (c-find-decl-spots + limit + c-identifier-start + c-font-lock-maybe-decl-faces + + (lambda (match-pos inside-macro) + (catch 'false-alarm + ;; Don't do anything more if we're looking at a keyword + ;; that can't start a declaration. + (when (and (eq (get-text-property (point) 'face) + 'font-lock-keyword-face) + (looking-at c-not-decl-init-keywords)) + (throw 'false-alarm t)) + + ;; Set `arglist-match' and `arglist-type'. Look for "<" for the + ;; sake of C++-style template arglists. + (setq arglist-match (char-before match-pos)) + (if (memq arglist-match '(?\( ?, ?\[ ?<)) + + ;; Find out the type of the arglist. + (if (<= match-pos (point-min)) + (setq arglist-type 'other) + (let ((type (c-get-char-property (1- match-pos) 'c-type))) + (cond ((eq type 'c-decl-arg-start) + ;; Got a cached hit in a declaration arglist. + (setq arglist-type 'decl)) + ((or (eq type 'c-<>-arg-sep) + (eq arglist-match ?<)) + ;; Inside an angle bracket arglist. + (setq arglist-type '<>)) + (type + ;; Got a cached hit in some other type of arglist. + (setq arglist-type 'other)) + ((if inside-macro + (< match-pos max-type-decl-end-before-token) + (< match-pos max-type-decl-end)) + ;; The point is within the range of a previously + ;; encountered type decl expression, so the arglist + ;; is probably one that contains declarations. + ;; However, if `c-recognize-paren-inits' is set it + ;; might also be an initializer arglist. + (setq arglist-type 'decl) + ;; The result of this check is cached with a char + ;; property on the match token, so that we can look + ;; it up again when refontifying single lines in a + ;; multiline declaration. + (c-put-char-property (1- match-pos) + 'c-type 'c-decl-arg-start)) + (t + (setq arglist-type 'other))))) + + (setq arglist-match nil + arglist-type nil)) + + (setq at-type nil + at-decl-or-cast nil + backup-if-not-cast nil + at-typedef nil + maybe-typeless nil + c-record-type-identifiers t + c-record-ref-identifiers nil + ;; `start-pos' is used below to point to the start of the + ;; first type, i.e. after any leading specifiers. It might + ;; also point at the beginning of the preceding syntactic + ;; whitespace. + start-pos (point) + ;; If we're in a normal arglist context we don't want to + ;; recognize commas in nested angle bracket arglists since + ;; those commas could be part of our own arglist. + c-disallow-comma-in-<>-arglists + (and c-recognize-<>-arglists + (eq arglist-type 'other))) + + (when (and c-disallow-comma-in-<>-arglists + (/= arglist-match ?,)) + ;; We're standing at the start of a normal arglist so remove any + ;; angle bracket arglists containing commas that's been + ;; recognized inside it by the preceding slightly opportunistic + ;; scan in `c-font-lock-<>-arglists'. + (while (and (c-syntactic-re-search-forward + c-opt-<>-arglist-start-in-paren nil t t) + (match-beginning 1)) + (backward-char) + (when (save-match-data + (and (c-get-char-property (point) 'syntax-table) + (not (c-forward-<>-arglist nil t)))) + (c-remove-font-lock-face (match-beginning 2) (match-end 2)))) + (goto-char start-pos)) + + ;; Check for a type, but be prepared to skip over leading + ;; specifiers like "static". Unknown symbols are treated as + ;; possible types, but they could also be specifiers disguised + ;; through macros like __INLINE__, so we recognize both types and + ;; known specifiers after them too. + (while (let ((start (point)) + (res (unless (eq at-type t) + ;; Don't look for a type if we already found a + ;; positive one; we only loop for the + ;; `c-specifier-key' check then. + (c-forward-type)))) + + (when res + ;; Found a known or possible type or a prefix of a known + ;; type. + + (when at-type + ;; Got two identifiers with nothing but whitespace + ;; between them. That can only happen in + ;; declarations. + (setq at-decl-or-cast t) + + (when (eq at-type 'found) + ;; If the previous identifier is a found type we + ;; record it as a real one; it might be some sort of + ;; alias for a prefix like "unsigned". + (save-excursion + (goto-char type-start) + (let ((c-promote-possible-types t)) + (c-forward-type))))) + + (setq prev-at-type at-type + prev-type-start type-start + prev-type-end type-end + at-type res + type-start start + type-end (point)) + + ;; If the type isn't known we continue so that we'll + ;; jump over all specifiers and type identifiers. The + ;; reason to do this for a known type prefix is to make + ;; things like "unsigned INT16" work. + (setq res (not (eq res t)))) + + (if (looking-at c-specifier-key) + ;; Found a known specifier keyword. The specifier + ;; keywords are restrictive, so we check for them + ;; anywhere inside or around the type(s). We thereby + ;; avoid having special cases for specifiers like MSVC + ;; '__declspec' which can come after the type. + (progn + (setq at-decl-or-cast t) + (let ((kwd-sym (c-keyword-sym (match-string 1)))) + (when (c-keyword-member + kwd-sym 'c-typedef-decl-kwds) + (setq at-typedef t)) + (when (c-keyword-member + kwd-sym 'c-typeless-decl-kwds) + (setq maybe-typeless t))) + (c-forward-keyword-clause) + ;; Move type-end forward if we've passed a type, + ;; otherwise move start-pos forward. + (if at-type + (setq type-end (point)) + (setq start-pos (point)))) + + res))) + + (cond + ((eq at-type 'prefix) + ;; A prefix type is itself a primitive type when it's not + ;; followed by another type. + (setq at-type t)) + + ((not at-type) + ;; Got no type but set things up to continue anyway to handle the + ;; various cases when a declaration doesn't start with a type. + (setq type-end start-pos)) + + ((and (eq at-type 'maybe) + (c-major-mode-is 'c++-mode)) + ;; If it's C++ then check if the last "type" ends on the form + ;; "foo::foo" or "foo::~foo", i.e. if it's the name of a + ;; (con|de)structor. + (save-excursion + (let (name end-2 end-1) + (goto-char type-end) + (c-backward-syntactic-ws) + (setq end-2 (point)) + (when (and + (c-simple-skip-symbol-backward) + (progn + (setq name + (buffer-substring-no-properties (point) end-2)) + ;; Cheating in the handling of syntactic ws below. + (< (skip-chars-backward ":~ \t\n\r\v\f") 0)) + (progn + (setq end-1 (point)) + (c-simple-skip-symbol-backward)) + (>= (point) type-start) + (equal (buffer-substring-no-properties (point) end-1) + name)) + ;; It is a (con|de)structor name. In that case the + ;; declaration is typeless so zap out any preceding + ;; identifier(s) that we might have taken as types. + (goto-char type-start) + (setq at-type nil + prev-at-type nil + type-end type-start)))))) + + ;; Check for and step over a type decl expression after the thing + ;; that is or might be a type. This can't be skipped since we need + ;; the correct end position of the declarator for + ;; `max-type-decl-end-*'. + (let ((start (point)) (paren-depth 0) pos + ;; True if there's a non-open-paren match of + ;; `c-type-decl-prefix-key'. + got-prefix + ;; True if the declarator is surrounded by a parenthesis pair. + got-parens + ;; True if there is an identifier in the declarator. + got-identifier + ;; True if there's a non-close-paren match of + ;; `c-type-decl-suffix-key'. + got-suffix + ;; True if there's a prefix or suffix match outside the + ;; outermost paren pair that surrounds the declarator. + got-prefix-before-parens + got-suffix-after-parens + ;; True if we've parsed the type decl to a token that + ;; is known to end declarations in this context. + at-decl-end + ;; The earlier values of `at-type', `type-start' and + ;; `type-end' if we've shifted the type backwards. + identifier-type identifier-start identifier-end) + (goto-char type-end) + + ;; Skip over type decl prefix operators. (Note similar code in + ;; `c-font-lock-declarators'.) + (while (and (looking-at c-type-decl-prefix-key) + (if (and (c-major-mode-is 'c++-mode) + (match-beginning 2)) + ;; If the second submatch matches in C++ then + ;; we're looking at an identifier that's a prefix + ;; only if it specifies a member pointer. + (when (setq got-identifier (c-forward-name)) + (if (looking-at "\\(::\\)") + ;; We only check for a trailing "::" and + ;; let the "*" that should follow be + ;; matched in the next round. + (progn (setq got-identifier nil) t) + ;; It turned out to be the real identifier, + ;; so stop. + nil)) + t)) + (if (eq (char-after) ?\() + (progn + (setq paren-depth (1+ paren-depth)) + (forward-char)) + (unless got-prefix-before-parens + (setq got-prefix-before-parens (= paren-depth 0))) + (setq got-prefix t) + (goto-char (match-end 1))) + (c-forward-syntactic-ws)) + (setq got-parens (> paren-depth 0)) + + ;; Skip over an identifier. + (or got-identifier + (and (looking-at c-identifier-start) + (setq got-identifier (c-forward-name)))) + + ;; Skip over type decl suffix operators. + (while (if (looking-at c-type-decl-suffix-key) + (if (eq (char-after) ?\)) + (when (> paren-depth 0) + (setq paren-depth (1- paren-depth)) + (forward-char) + t) + (when (if (save-match-data (looking-at "\\s\(")) + (c-safe (c-forward-sexp 1) t) + (goto-char (match-end 1)) + t) + (unless got-suffix-after-parens + (setq got-suffix-after-parens (= paren-depth 0))) + (setq got-suffix t))) + ;; No suffix matched. We might have matched the + ;; identifier as a type and the open paren of a function + ;; arglist as a type decl prefix. In that case we + ;; should "backtrack": Reinterpret the last type as the + ;; identifier, move out of the arglist and continue + ;; searching for suffix operators. + ;; + ;; Do this even if there's no preceding type, to cope + ;; with old style function declarations in K&R C, + ;; (con|de)structors in C++ and `c-typeless-decl-kwds' + ;; style declarations. That isn't applicable in an + ;; arglist context, though. + (when (and (= paren-depth 1) + (not got-prefix-before-parens) + (not (eq at-type t)) + (or prev-at-type + maybe-typeless + (when c-recognize-typeless-decls + (not arglist-type))) + (setq pos (c-up-list-forward (point))) + (eq (char-before pos) ?\))) + (c-fl-shift-type-backward) + (goto-char pos) + t)) + (c-forward-syntactic-ws)) + + (when (and maybe-typeless + (not got-identifier) + (not got-prefix) + at-type + (not (eq at-type t))) + ;; Have found no identifier but `c-typeless-decl-kwds' has + ;; matched so we know we're inside a declaration. The + ;; preceding type must be the identifier instead. + (c-fl-shift-type-backward)) + + (setq + at-decl-or-cast + (catch 'at-decl-or-cast + + (when (> paren-depth 0) + ;; Encountered something inside parens that isn't matched by + ;; the `c-type-decl-*' regexps, so it's not a type decl + ;; expression. Try to skip out to the same paren depth to + ;; not confuse the cast check below. + (c-safe (goto-char (scan-lists (point) 1 paren-depth))) + (throw 'at-decl-or-cast nil)) + + (setq at-decl-end + (looking-at (cond ((eq arglist-type '<>) "[,>]") + (arglist-type "[,\)]") + (t "[,;]")))) + + ;; Now we've collected info about various characteristics of + ;; the construct we're looking at. Below follows a decision + ;; tree based on that. It's ordered to check more certain + ;; signs before less certain ones. + + (if got-identifier + (progn + + (when (and (or at-type maybe-typeless) + (not (or got-prefix got-parens))) + ;; Got another identifier directly after the type, so + ;; it's a declaration. + (throw 'at-decl-or-cast t)) + + (when (and got-parens + (not got-prefix) + (not got-suffix-after-parens) + (or prev-at-type maybe-typeless)) + ;; Got a declaration of the form "foo bar (gnu);" + ;; where we've recognized "bar" as the type and "gnu" + ;; as the declarator. In this case it's however more + ;; likely that "bar" is the declarator and "gnu" a + ;; function argument or initializer (if + ;; `c-recognize-paren-inits' is set), since the parens + ;; around "gnu" would be superfluous if it's a + ;; declarator. Shift the type one step backward. + (c-fl-shift-type-backward))) + + ;; Found no identifier. + + (if prev-at-type + (when (or (= (point) start) + (and got-suffix + (not got-prefix) + (not got-parens))) + ;; Got two types after each other, so if this isn't a + ;; cast then the latter probably is the identifier and + ;; we should back up to the previous type. + (setq backup-if-not-cast t) + (throw 'at-decl-or-cast t)) + + (when (eq at-type t) + ;; If the type is known we know that there can't be any + ;; identifier somewhere else, and it's only in + ;; declarations in e.g. function prototypes and in casts + ;; that the identifier may be left out. + (throw 'at-decl-or-cast t)) + + (when (= (point) start) + ;; Only got a single identifier (parsed as a type so + ;; far). + (if (and + ;; Check that the identifier isn't at the start of + ;; an expression. + at-decl-end + (cond + ((eq arglist-type 'decl) + ;; Inside an arglist that contains declarations. + ;; If K&R style declarations and parenthesis + ;; style initializers aren't allowed then the + ;; single identifier must be a type, else we + ;; require that it's known or found (primitive + ;; types are handled above). + (or (and (not c-recognize-knr-p) + (not c-recognize-paren-inits)) + (memq at-type '(known found)))) + ((eq arglist-type '<>) + ;; Inside a template arglist. Accept known and + ;; found types; other identifiers could just as + ;; well be constants in C++. + (memq at-type '(known found))))) + (throw 'at-decl-or-cast t) + (throw 'at-decl-or-cast nil)))) + + (if (and + got-parens + (not got-prefix) + (not arglist-type) + (not (eq at-type t)) + (or + prev-at-type + maybe-typeless + (when c-recognize-typeless-decls + (or (not got-suffix) + (not (looking-at + c-after-suffixed-type-maybe-decl-key)))))) + ;; Got an empty paren pair and a preceding type that + ;; probably really is the identifier. Shift the type + ;; backwards to make the last one the identifier. This + ;; is analogous to the "backtracking" done inside the + ;; `c-type-decl-suffix-key' loop above. + ;; + ;; Exception: In addition to the conditions in that + ;; "backtracking" code, do not shift backward if we're + ;; not looking at either `c-after-suffixed-type-decl-key' + ;; or "[;,]". Since there's no preceding type, the + ;; shift would mean that the declaration is typeless. + ;; But if the regexp doesn't match then we will simply + ;; fall through in the tests below and not recognize it + ;; at all, so it's better to try it as an abstract + ;; declarator instead. + (c-fl-shift-type-backward) + + ;; Still no identifier. + + (when (and got-prefix (or got-parens got-suffix)) + ;; Require `got-prefix' together with either + ;; `got-parens' or `got-suffix' to recognize it as an + ;; abstract declarator: `got-parens' only is probably an + ;; empty function call. `got-suffix' only can build an + ;; ordinary expression together with the preceding + ;; identifier which we've taken as a type. We could + ;; actually accept on `got-prefix' only, but that can + ;; easily occur temporarily while writing an expression + ;; so we avoid that case anyway. We could do a better + ;; job if we knew the point when the fontification was + ;; invoked. + (throw 'at-decl-or-cast t)))) + + (when at-decl-or-cast + ;; By now we've located the type in the declaration that we + ;; know we're in. + (throw 'at-decl-or-cast t)) + + (when (and got-identifier + (not arglist-type) + (looking-at c-after-suffixed-type-decl-key) + (if (and got-parens + (not got-prefix) + (not got-suffix) + (not (eq at-type t))) + ;; Shift the type backward in the case that + ;; there's a single identifier inside parens. + ;; That can only occur in K&R style function + ;; declarations so it's more likely that it + ;; really is a function call. Therefore we + ;; only do this after + ;; `c-after-suffixed-type-decl-key' has + ;; matched. + (progn (c-fl-shift-type-backward) t) + got-suffix-after-parens)) + ;; A declaration according to + ;; `c-after-suffixed-type-decl-key'. + (throw 'at-decl-or-cast t)) + + (when (and (or got-prefix (not got-parens)) + (memq at-type '(t known))) + ;; It's a declaration if a known type precedes it and it + ;; can't be a function call. + (throw 'at-decl-or-cast t)) + + ;; If we get here we can't tell if this is a type decl or a + ;; normal expression by looking at it alone. (That's under + ;; the assumption that normal expressions always can look like + ;; type decl expressions, which isn't really true but the + ;; cases where it doesn't hold are so uncommon (e.g. some + ;; placements of "const" in C++) it's not worth the effort to + ;; look for them.) + + (unless (or at-decl-end (looking-at "=[^=]")) + ;; If this is a declaration it should end here or its + ;; initializer(*) should start here, so check for allowed + ;; separation tokens. Note that this rule doesn't work + ;; e.g. with a K&R arglist after a function header. + ;; + ;; *) Don't check for C++ style initializers using parens + ;; since those already have been matched as suffixes. + (throw 'at-decl-or-cast nil)) + + ;; Below are tests that only should be applied when we're + ;; certain to not have parsed halfway through an expression. + + (when (memq at-type '(t known)) + ;; The expression starts with a known type so treat it as a + ;; declaration. + (throw 'at-decl-or-cast t)) + + (when (and (c-major-mode-is 'c++-mode) + ;; In C++ we check if the identifier is a known + ;; type, since (con|de)structors use the class name + ;; as identifier. We've always shifted over the + ;; identifier as a type and then backed up again in + ;; this case. + identifier-type + (or (eq identifier-type 'found) + (and (eq (char-after identifier-start) ?~) + ;; `at-type' probably won't be 'found for + ;; destructors since the "~" is then part + ;; of the type name being checked against + ;; the list of known types, so do a check + ;; without that operator. + (c-check-type (1+ identifier-start) + identifier-end)))) + (throw 'at-decl-or-cast t)) + + (if got-identifier + (progn + (when (and got-prefix-before-parens + at-type + (or at-decl-end (looking-at "=[^=]")) + (not arglist-type) + (not got-suffix)) + ;; Got something like "foo * bar;". Since we're not + ;; inside an arglist it would be a meaningless + ;; expression because the result isn't used. We + ;; therefore choose to recognize it as a declaration. + ;; Do not allow a suffix since it could then be a + ;; function call. + (throw 'at-decl-or-cast t)) + + (when (and (or got-suffix-after-parens + (looking-at "=[^=]")) + (eq at-type 'found) + (not (eq arglist-type 'other))) + ;; Got something like "a (*b) (c);" or "a (b) = c;". + ;; It could be an odd expression or it could be a + ;; declaration. Treat it as a declaration if "a" has + ;; been used as a type somewhere else (if it's a known + ;; type we won't get here). + (throw 'at-decl-or-cast t))) + + (when (and arglist-type + (or got-prefix + (and (eq arglist-type 'decl) + (not c-recognize-paren-inits) + (or got-parens got-suffix)))) + ;; Got a type followed by an abstract declarator. If + ;; `got-prefix' is set it's something like "a *" without + ;; anything after it. If `got-parens' or `got-suffix' is + ;; set it's "a()", "a[]", "a()[]", or similar, which we + ;; accept only if the context rules out expressions. + (throw 'at-decl-or-cast t))) + + ;; If we had a complete symbol table here (which rules out + ;; `c-found-types') we should return t due to the + ;; disambiguation rule (in at least C++) that anything that + ;; can be parsed as a declaration is a declaration. Now we're + ;; being more defensive and prefer to highlight things like + ;; "foo (bar);" as a declaration only if we're inside an + ;; arglist that contains declarations. + (eq arglist-type 'decl)))) + + ;; Point is now after the type decl expression. + + (cond + ;; Check for a cast. + ((save-excursion + (and + c-cast-parens + + ;; Should be the first type/identifier in a cast paren. + (memq arglist-match c-cast-parens) + + ;; The closing paren should follow. + (progn + (c-forward-syntactic-ws) + (looking-at "\\s\)")) + + ;; There should be a primary expression after it. + (let (pos) + (forward-char) + (c-forward-syntactic-ws) + (setq cast-end (point)) + (and (looking-at c-primary-expr-regexp) + (progn + (setq pos (match-end 0)) + (or + ;; Check if the expression begins with a prefix + ;; keyword. + (match-beginning 2) + (if (match-beginning 1) + ;; Expression begins with an ambiguous operator. + ;; Treat it as a cast if it's a type decl or if + ;; we've recognized the type somewhere else. + (or at-decl-or-cast + (memq at-type '(t known found))) + ;; Unless it's a keyword, it's the beginning of a + ;; primary expression. + (not (looking-at c-keywords-regexp))))) + ;; If `c-primary-expr-regexp' matched a nonsymbol + ;; token, check that it matched a whole one so that we + ;; don't e.g. confuse the operator '-' with '->'. It's + ;; ok if it matches further, though, since it e.g. can + ;; match the float '.5' while the operator regexp only + ;; matches '.'. + (or (not (looking-at c-nonsymbol-token-regexp)) + (<= (match-end 0) pos)))) + + ;; There should either be a cast before it or something that + ;; isn't an identifier or close paren. + (/= match-pos 0) + (progn + (goto-char (1- match-pos)) + (or (eq (point) last-cast-end) + (progn + (c-backward-syntactic-ws) + (if (< (skip-syntax-backward "w_") 0) + ;; It's a symbol. Accept it only if it's one of + ;; the keywords that can precede an expression + ;; (without surrounding parens). + (looking-at c-simple-stmt-key) + (and + ;; Check that it isn't a close paren (block close + ;; is ok, though). + (not (memq (char-before) '(?\) ?\]))) + ;; Check that it isn't a nonsymbol identifier. + (not (c-on-identifier))))))))) + + ;; Handle the cast. + (setq last-cast-end cast-end) + (when (and at-type (not (eq at-type t))) + (let ((c-promote-possible-types t)) + (goto-char type-start) + (c-forward-type)))) + + (at-decl-or-cast + ;; We're at a declaration. Highlight the type and the following + ;; declarators. + + (when backup-if-not-cast + (c-fl-shift-type-backward t)) + + (when (and (eq arglist-type 'decl) (looking-at ",")) + ;; Make sure to propagate the `c-decl-arg-start' property to + ;; the next argument if it's set in this one, to cope with + ;; interactive refontification. + (c-put-char-property (point) 'c-type 'c-decl-arg-start)) + + ;; Set `max-type-decl-end' or `max-type-decl-end-before-token' + ;; under the assumption that we're after the first type decl + ;; expression in the declaration now. That's not really true; we + ;; could also be after a parenthesized initializer expression in + ;; C++, but this is only used as a last resort to slant ambiguous + ;; expression/declarations, and overall it's worth the risk to + ;; occasionally fontify an expression as a declaration in an + ;; initializer expression compared to getting ambiguous things in + ;; normal function prototypes fontified as expressions. + (if inside-macro + (when (> (point) max-type-decl-end-before-token) + (setq max-type-decl-end-before-token (point))) + (when (> (point) max-type-decl-end) + (setq max-type-decl-end (point)))) + + (when (and at-type (not (eq at-type t))) + (let ((c-promote-possible-types t)) + (goto-char type-start) + (c-forward-type))) + + (goto-char type-end) + + (let ((decl-list + (if arglist-type + ;; Should normally not fontify a list of declarators + ;; inside an arglist, but the first argument in the + ;; ';' separated list of a "for" statement is an + ;; exception. + (when (and (eq arglist-match ?\() (/= match-pos 0)) + (save-excursion + (goto-char (1- match-pos)) + (c-backward-syntactic-ws) + (and (c-simple-skip-symbol-backward) + (looking-at c-paren-stmt-key)))) + t))) + + ;; Fix the `c-decl-id-start' or `c-decl-type-start' property + ;; before the first declarator if it's a list. + ;; `c-font-lock-declarators' handles the rest. + (when decl-list + (save-excursion + (c-backward-syntactic-ws) + (unless (bobp) + (c-put-char-property (1- (point)) 'c-type + (if at-typedef + 'c-decl-type-start + 'c-decl-id-start))))) + + (c-font-lock-declarators (point-max) decl-list at-typedef))) + + (t + ;; False alarm. Skip the fontification done below. + (throw 'false-alarm t))) + + ;; A cast or declaration has been successfully identified, so do + ;; all the fontification of types and refs that's been recorded by + ;; the calls to `c-forward-type' and `c-forward-name' above. + (c-fontify-recorded-types-and-refs) + nil))) + + nil))) + +(c-lang-defconst c-simple-decl-matchers + "Simple font lock matchers for types and declarations. These are used +on level 2 only and so aren't combined with `c-complex-decl-matchers'." + + t `(;; Objective-C methods. + ,@(when (c-major-mode-is 'objc-mode) + `((,(c-lang-const c-opt-method-key) + (,(byte-compile + (lambda (limit) + (let (;; The font-lock package in Emacs is known to clobber + ;; `parse-sexp-lookup-properties' (when it exists). + (parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties)))) + (save-restriction + (narrow-to-region (point-min) limit) + (c-font-lock-objc-method))) + nil)) + (goto-char (match-end 1)))))) + + ;; Fontify all type names and the identifiers in the + ;; declarations they might start. Use eval here since + ;; `c-known-type-key' gets its value from + ;; `*-font-lock-extra-types' on mode init. + (eval . (list ,(c-make-font-lock-search-function + 'c-known-type-key + '(1 'font-lock-type-face t) + '((c-font-lock-declarators limit t nil) + (save-match-data + (goto-char (match-end 1)) + (c-forward-syntactic-ws)) + (goto-char (match-end 1)))))) + + ;; Fontify types preceded by `c-type-prefix-kwds' and the + ;; identifiers in the declarations they might start. + ,@(when (c-lang-const c-type-prefix-kwds) + (let ((prefix-re (c-make-keywords-re nil + (c-lang-const c-type-prefix-kwds)))) + `((,(c-make-font-lock-search-function + (concat "\\<\\(" prefix-re "\\)" + "[ \t\n\r\f\v]+" + "\\(" (c-lang-const c-symbol-key) "\\)") + `(,(+ (c-regexp-opt-depth prefix-re) 2) + 'font-lock-type-face t) + '((c-font-lock-declarators limit t nil) + (save-match-data + (goto-char (match-end 2)) + (c-forward-syntactic-ws)) + (goto-char (match-end 2)))))))) + + ;; Fontify special declarations that lacks a type. + ,@(when (c-lang-const c-typeless-decl-kwds) + `((,(c-make-font-lock-search-function + (concat "\\<\\(" + (c-regexp-opt (c-lang-const c-typeless-decl-kwds)) + "\\)\\>") + '((c-font-lock-declarators limit t nil) + (save-match-data + (goto-char (match-end 1)) + (c-forward-syntactic-ws)) + (goto-char (match-end 1))))))) + )) + +(c-lang-defconst c-complex-decl-matchers + "Complex font lock matchers for types and declarations. Used on level +3 and higher." + + t `(;; Initialize some things before the search functions below. + c-font-lock-complex-decl-prepare + + ;; Fontify angle bracket arglists like templates in C++. + ,@(when (c-lang-const c-recognize-<>-arglists) + `(c-font-lock-<>-arglists)) + + ,@(if (c-major-mode-is 'objc-mode) + ;; Fontify method declarations in Objective-C, but first + ;; we have to put the `c-decl-end' `c-type' property on + ;; all the @-style directives that haven't been handled in + ;; `c-basic-matchers-before'. + `(,(c-make-font-lock-search-function + (c-make-keywords-re t + ;; Exclude "@class" since that directive ends with a + ;; semicolon anyway. + (delete "@class" + (append (c-lang-const c-protection-kwds) + (c-lang-const c-other-decl-kwds) + nil))) + '((c-put-char-property (1- (match-end 1)) + 'c-type 'c-decl-end))) + + c-font-lock-objc-methods) + + (when (c-lang-const c-opt-access-key) + `(,(c-make-font-lock-search-function + (c-lang-const c-opt-access-key) + '((c-put-char-property (1- (match-end 0)) + 'c-type 'c-decl-end)))))) + + ;; Fontify all declarations and casts. + c-font-lock-declarations + + ;; The first two rules here mostly find occurences that + ;; `c-font-lock-declarations' has found already, but not + ;; declarations containing blocks in the type (see note below). + ;; It's also useful to fontify these everywhere to show e.g. when + ;; a type keyword is accidentally used as an identifier. + + ;; Fontify basic types. + ,(let ((re (c-make-keywords-re nil + (c-lang-const c-primitive-type-kwds)))) + (if (c-major-mode-is 'pike-mode) + ;; No symbol is a keyword after "->" in Pike. + `(,(concat "\\(\\=\\|\\(\\=\\|[^-]\\)[^>]\\)" + "\\<\\(" re "\\)\\>") + 3 font-lock-type-face) + `(,(concat "\\<\\(" re "\\)\\>") + 1 'font-lock-type-face))) + + ;; Fontify types preceded by `c-type-prefix-kwds'. + ,@(when (c-lang-const c-type-prefix-kwds) + `((,(byte-compile + `(lambda (limit) + (c-fontify-types-and-refs + ((c-promote-possible-types t) + ;; The font-lock package in Emacs is known to clobber + ;; `parse-sexp-lookup-properties' (when it exists). + (parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties)))) + (save-restriction + ;; Narrow to avoid going past the limit in + ;; `c-forward-type'. + (narrow-to-region (point) limit) + (while (re-search-forward + ,(concat "\\<\\(" + (c-make-keywords-re nil + (c-lang-const c-type-prefix-kwds)) + "\\)\\>") + limit t) + (unless (c-skip-comments-and-strings limit) + (c-forward-syntactic-ws) + ;; Handle prefix declaration specifiers. + (when (looking-at c-specifier-key) + (c-forward-keyword-clause)) + ,(if (c-major-mode-is 'c++-mode) + `(when (and (c-forward-type) + (eq (char-after) ?=)) + ;; In C++ we additionally check for a "class + ;; X = Y" construct which is used in + ;; templates, to fontify Y as a type. + (forward-char) + (c-forward-syntactic-ws) + (c-forward-type)) + `(c-forward-type)) + ))))))))) + + ;; Fontify symbols after closing braces as declaration + ;; identifiers under the assumption that they are part of + ;; declarations like "class Foo { ... } foo;". It's too + ;; expensive to check this accurately by skipping past the + ;; brace block, so we use the heuristic that it's such a + ;; declaration if the first identifier is on the same line as + ;; the closing brace. `c-font-lock-declarations' will later + ;; override it if it turns out to be an new declaration, but + ;; it will be wrong if it's an expression (see the test + ;; decls-8.cc). + ,@(when (c-lang-const c-opt-block-decls-with-vars-key) + `((,(c-make-font-lock-search-function + (concat "}" + (c-lang-const c-single-line-syntactic-ws) + "\\(" ; 1 + c-single-line-syntactic-ws-depth + (c-lang-const c-type-decl-prefix-key) + "\\|" + (c-lang-const c-symbol-key) + "\\)") + `((c-font-lock-declarators limit t nil) + (progn + (c-put-char-property (match-beginning 0) 'c-type + 'c-decl-id-start) + (goto-char (match-beginning + ,(1+ (c-lang-const + c-single-line-syntactic-ws-depth))))) + (goto-char (match-end 0))))))) + + ;; Fontify the type in C++ "new" expressions. + ,@(when (c-major-mode-is 'c++-mode) + `(("\\<new\\>" + (c-font-lock-c++-new)))) + )) + +(defun c-font-lock-labels (limit) + ;; Fontify all the declarations from the point to LIMIT. Assumes + ;; that strings and comments have been fontified already. Nil is + ;; always returned. + ;; + ;; This function can make hidden buffer changes, but the font-lock + ;; context covers that. + + (let (continue-pos id-start + ;; The font-lock package in Emacs is known to clobber + ;; `parse-sexp-lookup-properties' (when it exists). + (parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties)))) + + (while (re-search-forward ":[^:]" limit t) + (setq continue-pos (point)) + (goto-char (match-beginning 0)) + (unless (c-skip-comments-and-strings limit) + + (c-backward-syntactic-ws) + (and (setq id-start (c-on-identifier)) + + (not (get-text-property id-start 'face)) + + (progn + (goto-char id-start) + (c-backward-syntactic-ws) + (or + ;; Check for a char that precedes a statement. + (memq (char-before) '(?\} ?\{ ?\;)) + ;; Check for a preceding label. We exploit the font + ;; locking made earlier by this function. + (and (eq (char-before) ?:) + (progn + (backward-char) + (c-backward-syntactic-ws) + (not (bobp))) + (eq (get-text-property (1- (point)) 'face) + c-label-face-name)) + ;; Check for a keyword that precedes a statement. + (c-after-conditional))) + + (progn + ;; Got a label. + (goto-char id-start) + (looking-at c-symbol-key) + (c-put-font-lock-face (match-beginning 0) (match-end 0) + c-label-face-name))) + + (goto-char continue-pos)))) + nil) + +(c-lang-defconst c-basic-matchers-after + "Font lock matchers for various things that should be fontified after +generic casts and declarations are fontified. Used on level 2 and +higher." + + t `(;; Fontify the identifiers inside enum lists. (The enum type + ;; name is handled by `c-simple-decl-matchers' or + ;; `c-complex-decl-matchers' below. + ,@(when (c-lang-const c-brace-id-list-kwds) + `((,(c-make-font-lock-search-function + (concat + "\\<\\(" + (c-make-keywords-re nil (c-lang-const c-brace-id-list-kwds)) + "\\)\\>" + ;; Disallow various common punctuation chars that can't come + ;; before the '{' of the enum list, to avoid searching too far. + "[^\]\[{}();,/#=]*" + "{") + '((c-font-lock-declarators limit t nil) + (save-match-data + (goto-char (match-end 0)) + (c-put-char-property (1- (point)) 'c-type + 'c-decl-id-start) + (c-forward-syntactic-ws)) + (goto-char (match-end 0))))))) + + ;; Fontify labels in languages that supports them. + ,@(when (c-lang-const c-label-key) + + `(;; Fontify labels after goto etc. + ;; (Got three different interpretation levels here, + ;; which makes it a bit complicated: 1) The backquote + ;; stuff is expanded when compiled or loaded, 2) the + ;; eval form is evaluated at font-lock setup (to + ;; substitute c-label-face-name correctly), and 3) the + ;; resulting structure is interpreted during + ;; fontification.) + (eval + . ,(let* ((c-before-label-re + (c-make-keywords-re nil + (c-lang-const c-before-label-kwds)))) + `(list + ,(concat "\\<\\(" c-before-label-re "\\)\\>" + "\\s *" + "\\(" ; identifier-offset + (c-lang-const c-symbol-key) + "\\)") + (list ,(+ (c-regexp-opt-depth c-before-label-re) 2) + c-label-face-name nil t)))) + + ;; Fontify normal labels. + c-font-lock-labels)) + + ;; Fontify the clauses after various keywords. + ,@(when (or (c-lang-const c-type-list-kwds) + (c-lang-const c-ref-list-kwds) + (c-lang-const c-colon-type-list-kwds) + (c-lang-const c-paren-type-kwds)) + `((,(c-make-font-lock-search-function + (concat "\\<\\(" + (c-make-keywords-re nil + (append (c-lang-const c-type-list-kwds) + (c-lang-const c-ref-list-kwds) + (c-lang-const c-colon-type-list-kwds) + (c-lang-const c-paren-type-kwds))) + "\\)\\>") + '((c-fontify-types-and-refs ((c-promote-possible-types t)) + (c-forward-keyword-clause) + (if (> (point) limit) (goto-char limit)))))))) + )) + +(c-lang-defconst c-matchers-1 + t (c-lang-const c-cpp-matchers)) + +(c-lang-defconst c-matchers-2 + t (append (c-lang-const c-matchers-1) + (c-lang-const c-basic-matchers-before) + (c-lang-const c-simple-decl-matchers) + (c-lang-const c-basic-matchers-after))) + +(c-lang-defconst c-matchers-3 + t (append (c-lang-const c-matchers-1) + (c-lang-const c-basic-matchers-before) + (c-lang-const c-complex-decl-matchers) + (c-lang-const c-basic-matchers-after))) + +(defun c-compose-keywords-list (base-list) + ;; Incorporate the font lock keyword lists according to + ;; `c-doc-comment-style' on the given keyword list and return it. + ;; This is used in the function bindings of the + ;; `*-font-lock-keywords-*' symbols since we have to build the list + ;; when font-lock is initialized. + + (unless (memq c-doc-face-name c-literal-faces) + (setq c-literal-faces (cons c-doc-face-name c-literal-faces))) + + (let* ((doc-keywords + (if (consp (car-safe c-doc-comment-style)) + (cdr-safe (or (assq c-buffer-is-cc-mode c-doc-comment-style) + (assq 'other c-doc-comment-style))) + c-doc-comment-style)) + (list (nconc (apply 'nconc + (mapcar + (lambda (doc-style) + (let ((sym (intern + (concat (symbol-name doc-style) + "-font-lock-keywords")))) + (cond ((fboundp sym) + (funcall sym)) + ((boundp sym) + (append (eval sym) nil))))) + (if (listp doc-keywords) + doc-keywords + (list doc-keywords)))) + base-list))) + + ;; Kludge: If `c-font-lock-complex-decl-prepare' is on the list we + ;; move it first since the doc comment font lockers might add + ;; `c-type' text properties so they have to be cleared before that. + (when (memq 'c-font-lock-complex-decl-prepare list) + (setq list (cons 'c-font-lock-complex-decl-prepare + (delq 'c-font-lock-complex-decl-prepare + (append list nil))))) + + list)) + +(defun c-override-default-keywords (def-var) + ;; This is used to override the value on a `*-font-lock-keywords' + ;; variable only if it's nil or has the same value as one of the + ;; `*-font-lock-keywords-*' variables. Older font-lock packages + ;; define a default value for `*-font-lock-keywords' which we want + ;; to override, but we should otoh avoid clobbering a user setting. + ;; This heuristic for that isn't perfect, but I can't think of any + ;; better. /mast + ;; + ;; This function does not do any hidden buffer changes. + (when (and (boundp def-var) + (memq (symbol-value def-var) + (cons nil + (mapcar + (lambda (suffix) + (let ((sym (intern (concat (symbol-name def-var) + suffix)))) + (and (boundp sym) (symbol-value sym)))) + '("-1" "-2" "-3"))))) + ;; The overriding is done by unbinding the variable so that the normal + ;; defvar will install its default value later on. + (makunbound def-var))) + + +;;; C. + +(c-override-default-keywords 'c-font-lock-keywords) + +(defconst c-font-lock-keywords-1 (c-lang-const c-matchers-1 c) + "Minimal font locking for C mode. +Fontifies only preprocessor directives (in addition to the syntactic +fontification of strings and comments).") + +(defconst c-font-lock-keywords-2 (c-lang-const c-matchers-2 c) + "Fast normal font locking for C mode. +In addition to `c-font-lock-keywords-1', this adds fontification of +keywords, simple types, declarations that are easy to recognize, the +user defined types on `c-font-lock-extra-types', and the doc comment +styles specified by `c-doc-comment-style'.") + +(defconst c-font-lock-keywords-3 (c-lang-const c-matchers-3 c) + "Accurate normal font locking for C mode. +Like `c-font-lock-keywords-2' but detects declarations in a more +accurate way that works in most cases for arbitrary types without the +need for `c-font-lock-extra-types'.") + +(defvar c-font-lock-keywords c-font-lock-keywords-3 + "Default expressions to highlight in C mode.") + +(defun c-font-lock-keywords-2 () + (c-compose-keywords-list c-font-lock-keywords-2)) +(defun c-font-lock-keywords-3 () + (c-compose-keywords-list c-font-lock-keywords-3)) +(defun c-font-lock-keywords () + (c-compose-keywords-list c-font-lock-keywords)) + + +;;; C++. + +(defun c-font-lock-c++-new (limit) + ;; Assuming point is after a "new" word, check that it isn't inside + ;; a string or comment, and if so try to fontify the type in the + ;; allocation expression. Nil is always returned. + ;; + ;; As usual, C++ takes the prize in coming up with a hard to parse + ;; syntax. :P + + (unless (c-skip-comments-and-strings limit) + (save-excursion + (catch 'false-alarm + ;; A "new" keyword is followed by one to three expressions, where + ;; the type is the middle one, and the only required part. + (let (expr1-pos expr2-pos + ;; Enable recording of identifier ranges in `c-forward-type' + ;; etc for later fontification. Not using + ;; `c-fontify-types-and-refs' here since the ranges should + ;; be fontified selectively only when an allocation + ;; expression is successfully recognized. + (c-record-type-identifiers t) + c-record-ref-identifiers + ;; The font-lock package in Emacs is known to clobber + ;; `parse-sexp-lookup-properties' (when it exists). + (parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties)))) + (c-forward-syntactic-ws) + + ;; The first placement arglist is always parenthesized, if it + ;; exists. + (when (eq (char-after) ?\() + (setq expr1-pos (1+ (point))) + (condition-case nil + (c-forward-sexp) + (scan-error (throw 'false-alarm t))) + (c-forward-syntactic-ws)) + + ;; The second expression is either a type followed by some "*" or + ;; "[...]" or similar, or a parenthesized type followed by a full + ;; identifierless declarator. + (setq expr2-pos (1+ (point))) + (cond ((eq (char-after) ?\()) + ((let ((c-promote-possible-types t)) + (c-forward-type))) + (t (setq expr2-pos nil))) + + (when expr1-pos + (cond + ((not expr2-pos) + ;; No second expression, so the first has to be a + ;; parenthesized type. + (goto-char expr1-pos) + (let ((c-promote-possible-types t)) + (c-forward-type))) + + ((eq (char-before expr2-pos) ?\() + ;; Got two parenthesized expressions, so we have to look + ;; closer at them to decide which is the type. No need to + ;; handle `c-record-ref-identifiers' since all references + ;; has already been handled by other fontification rules. + (let (expr1-res expr2-res) + + (goto-char expr1-pos) + (when (setq expr1-res (c-forward-type)) + (unless (looking-at + (cc-eval-when-compile + (concat (c-lang-const c-symbol-start c++) + "\\|[*:\)\[]"))) + ;; There's something after the would-be type that + ;; can't be there, so this is a placement arglist. + (setq expr1-res nil))) + + (goto-char expr2-pos) + (when (setq expr2-res (c-forward-type)) + (unless (looking-at + (cc-eval-when-compile + (concat (c-lang-const c-symbol-start c++) + "\\|[*:\)\[]"))) + ;; There's something after the would-be type that can't + ;; be there, so this is an initialization expression. + (setq expr2-res nil)) + (when (and (c-go-up-list-forward) + (progn (c-forward-syntactic-ws) + (eq (char-after) ?\())) + ;; If there's a third initialization expression + ;; then the second one is the type, so demote the + ;; first match. + (setq expr1-res nil))) + + ;; We fontify the most likely type, with a preference for + ;; the first argument since a placement arglist is more + ;; unusual than an initializer. + (cond ((memq expr1-res '(t known prefix))) + ((memq expr2-res '(t known prefix))) + ((eq expr1-res 'found) + (let ((c-promote-possible-types t)) + (goto-char expr1-pos) + (c-forward-type))) + ((eq expr2-res 'found) + (let ((c-promote-possible-types t)) + (goto-char expr2-pos) + (c-forward-type))) + ((and (eq expr1-res 'maybe) (not expr2-res)) + (let ((c-promote-possible-types t)) + (goto-char expr1-pos) + (c-forward-type))) + ((and (not expr1-res) (eq expr2-res 'maybe)) + (let ((c-promote-possible-types t)) + (goto-char expr2-pos) + (c-forward-type))) + ;; If both type matches are 'maybe then we're + ;; too uncertain to promote either of them. + ))))) + + ;; Fontify the type that now is recorded in + ;; `c-record-type-identifiers', if any. + (c-fontify-recorded-types-and-refs))))) + nil) + +(c-override-default-keywords 'c++-font-lock-keywords) + +(defconst c++-font-lock-keywords-1 (c-lang-const c-matchers-1 c++) + "Minimal font locking for C++ mode. +Fontifies only preprocessor directives (in addition to the syntactic +fontification of strings and comments).") + +(defconst c++-font-lock-keywords-2 (c-lang-const c-matchers-2 c++) + "Fast normal font locking for C++ mode. +In addition to `c++-font-lock-keywords-1', this adds fontification of +keywords, simple types, declarations that are easy to recognize, the +user defined types on `c++-font-lock-extra-types', and the doc comment +styles specified by `c-doc-comment-style'.") + +(defconst c++-font-lock-keywords-3 (c-lang-const c-matchers-3 c++) + "Accurate normal font locking for C++ mode. +Like `c++-font-lock-keywords-2' but detects declarations in a more +accurate way that works in most cases for arbitrary types without the +need for `c++-font-lock-extra-types'.") + +(defvar c++-font-lock-keywords c++-font-lock-keywords-3 + "Default expressions to highlight in C++ mode.") + +(defun c++-font-lock-keywords-2 () + (c-compose-keywords-list c++-font-lock-keywords-2)) +(defun c++-font-lock-keywords-3 () + (c-compose-keywords-list c++-font-lock-keywords-3)) +(defun c++-font-lock-keywords () + (c-compose-keywords-list c++-font-lock-keywords)) + + +;;; Objective-C. + +(defun c-font-lock-objc-iip-decl () + ;; Assuming the point is after an "@interface", "@implementation", + ;; "@protocol" declaration, fontify all the types in the directive. + ;; Return t if the directive was fully recognized. Point will then + ;; be at the end of it. + + (c-fontify-types-and-refs + (start-char + (c-promote-possible-types t) + ;; Turn off recognition of angle bracket arglists while parsing + ;; types here since the protocol reference list might then be + ;; considered part of the preceding name or superclass-name. + c-recognize-<>-arglists) + (catch 'break + + ;; Handle the name of the class itself. + (c-forward-syntactic-ws) + (unless (c-forward-type) (throw 'break nil)) + + ;; Look for ": superclass-name" or "( category-name )". + (when (looking-at "[:\(]") + (setq start-char (char-after)) + (forward-char) + (c-forward-syntactic-ws) + (unless (c-forward-type) (throw 'break nil)) + (when (eq start-char ?\() + (unless (eq (char-after) ?\)) (throw 'break nil)) + (forward-char) + (c-forward-syntactic-ws))) + + ;; Look for a protocol reference list. + (when (if (eq (char-after) ?<) + (progn + (setq c-recognize-<>-arglists t) + (c-forward-<>-arglist t t)) + t) + (c-put-char-property (1- (point)) 'c-type 'c-decl-end) + t)))) + +(defun c-font-lock-objc-method () + ;; Assuming the point is after the + or - that starts an Objective-C + ;; method declaration, fontify it. This must be done before normal + ;; casts, declarations and labels are fontified since they will get + ;; false matches in these things. + + (c-fontify-types-and-refs + ((first t) + (c-promote-possible-types t)) + + (while (and + (progn + (c-forward-syntactic-ws) + + ;; An optional method type. + (if (eq (char-after) ?\() + (progn + (forward-char) + (c-forward-syntactic-ws) + (c-forward-type) + (prog1 (c-go-up-list-forward) + (c-forward-syntactic-ws))) + t)) + + ;; The name. The first time it's the first part of + ;; the function name, the rest of the time it's an + ;; argument name. + (looking-at c-symbol-key) + (progn + (goto-char (match-end 0)) + (c-put-font-lock-face (match-beginning 0) + (point) + (if first + 'font-lock-function-name-face + 'font-lock-variable-name-face)) + (c-forward-syntactic-ws) + + ;; Another optional part of the function name. + (when (looking-at c-symbol-key) + (goto-char (match-end 0)) + (c-put-font-lock-face (match-beginning 0) + (point) + 'font-lock-function-name-face) + (c-forward-syntactic-ws)) + + ;; There's another argument if a colon follows. + (eq (char-after) ?:))) + (forward-char) + (setq first nil)))) + +(defun c-font-lock-objc-methods (limit) + ;; Fontify method declarations in Objective-C. Nil is always + ;; returned. + + (let (;; The font-lock package in Emacs is known to clobber + ;; `parse-sexp-lookup-properties' (when it exists). + (parse-sexp-lookup-properties + (cc-eval-when-compile + (boundp 'parse-sexp-lookup-properties)))) + + (c-find-decl-spots + limit + "[-+]" + nil + (lambda (match-pos inside-macro) + (forward-char) + (c-font-lock-objc-method)))) + nil) + +(c-override-default-keywords 'objc-font-lock-keywords) + +(defconst objc-font-lock-keywords-1 (c-lang-const c-matchers-1 objc) + "Minimal font locking for Objective-C mode. +Fontifies only compiler directives (in addition to the syntactic +fontification of strings and comments).") + +(defconst objc-font-lock-keywords-2 (c-lang-const c-matchers-2 objc) + "Fast normal font locking for Objective-C mode. +In addition to `objc-font-lock-keywords-1', this adds fontification of +keywords, simple types, declarations that are easy to recognize, the +user defined types on `objc-font-lock-extra-types', and the doc +comment styles specified by `c-doc-comment-style'.") + +(defconst objc-font-lock-keywords-3 (c-lang-const c-matchers-3 objc) + "Accurate normal font locking for Objective-C mode. +Like `objc-font-lock-keywords-2' but detects declarations in a more +accurate way that works in most cases for arbitrary types without the +need for `objc-font-lock-extra-types'.") + +(defvar objc-font-lock-keywords objc-font-lock-keywords-3 + "Default expressions to highlight in Objective-C mode.") + +(defun objc-font-lock-keywords-2 () + (c-compose-keywords-list objc-font-lock-keywords-2)) +(defun objc-font-lock-keywords-3 () + (c-compose-keywords-list objc-font-lock-keywords-3)) +(defun objc-font-lock-keywords () + (c-compose-keywords-list objc-font-lock-keywords)) + +;; Kludge to override the default value that +;; `objc-font-lock-extra-types' might have gotten from the font-lock +;; package. The value replaced here isn't relevant now anyway since +;; those types are builtin and therefore listed directly in +;; `c-primitive-type-kwds'. +(when (equal (sort (append objc-font-lock-extra-types nil) 'string-lessp) + '("BOOL" "Class" "IMP" "SEL")) + (setq objc-font-lock-extra-types + (cc-eval-when-compile (list (concat "[" c-upper "]\\sw*"))))) + + +;;; Java. + +(c-override-default-keywords 'java-font-lock-keywords) + +(defconst java-font-lock-keywords-1 (c-lang-const c-matchers-1 java) + "Minimal font locking for Java mode. +Fontifies nothing except the syntactic fontification of strings and +comments.") + +(defconst java-font-lock-keywords-2 (c-lang-const c-matchers-2 java) + "Fast normal font locking for Java mode. +In addition to `java-font-lock-keywords-1', this adds fontification of +keywords, simple types, declarations that are easy to recognize, the +user defined types on `java-font-lock-extra-types', and the doc +comment styles specified by `c-doc-comment-style'.") + +(defconst java-font-lock-keywords-3 (c-lang-const c-matchers-3 java) + "Accurate normal font locking for Java mode. +Like `java-font-lock-keywords-2' but detects declarations in a more +accurate way that works in most cases for arbitrary types without the +need for `java-font-lock-extra-types'.") + +(defvar java-font-lock-keywords java-font-lock-keywords-3 + "Default expressions to highlight in Java mode.") + +(defun java-font-lock-keywords-2 () + (c-compose-keywords-list java-font-lock-keywords-2)) +(defun java-font-lock-keywords-3 () + (c-compose-keywords-list java-font-lock-keywords-3)) +(defun java-font-lock-keywords () + (c-compose-keywords-list java-font-lock-keywords)) + + +;;; CORBA IDL. + +(c-override-default-keywords 'idl-font-lock-keywords) + +(defconst idl-font-lock-keywords-1 (c-lang-const c-matchers-1 idl) + "Minimal font locking for CORBA IDL mode. +Fontifies nothing except the syntactic fontification of strings and +comments.") + +(defconst idl-font-lock-keywords-2 (c-lang-const c-matchers-2 idl) + "Fast normal font locking for CORBA IDL mode. +In addition to `idl-font-lock-keywords-1', this adds fontification of +keywords, simple types, declarations that are easy to recognize, the +user defined types on `idl-font-lock-extra-types', and the doc comment +styles specified by `c-doc-comment-style'.") + +(defconst idl-font-lock-keywords-3 (c-lang-const c-matchers-3 idl) + "Accurate normal font locking for CORBA IDL mode. +Like `idl-font-lock-keywords-2' but detects declarations in a more +accurate way that works in most cases for arbitrary types without the +need for `idl-font-lock-extra-types'.") + +(defvar idl-font-lock-keywords idl-font-lock-keywords-3 + "Default expressions to highlight in CORBA IDL mode.") + +(defun idl-font-lock-keywords-2 () + (c-compose-keywords-list idl-font-lock-keywords-2)) +(defun idl-font-lock-keywords-3 () + (c-compose-keywords-list idl-font-lock-keywords-3)) +(defun idl-font-lock-keywords () + (c-compose-keywords-list idl-font-lock-keywords)) + + +;;; Pike. + +(c-override-default-keywords 'pike-font-lock-keywords) + +(defconst pike-font-lock-keywords-1 (c-lang-const c-matchers-1 pike) + "Minimal font locking for Pike mode. +Fontifies only preprocessor directives (in addition to the syntactic +fontification of strings and comments).") + +(defconst pike-font-lock-keywords-2 (c-lang-const c-matchers-2 pike) + "Fast normal font locking for Pike mode. +In addition to `pike-font-lock-keywords-1', this adds fontification of +keywords, simple types, declarations that are easy to recognize, the +user defined types on `pike-font-lock-extra-types', and the doc +comment styles specified by `c-doc-comment-style'.") + +(defconst pike-font-lock-keywords-3 (c-lang-const c-matchers-3 pike) + "Accurate normal font locking for Pike mode. +Like `pike-font-lock-keywords-2' but detects declarations in a more +accurate way that works in most cases for arbitrary types without the +need for `pike-font-lock-extra-types'.") + +(defvar pike-font-lock-keywords pike-font-lock-keywords-3 + "Default expressions to highlight in Pike mode.") + +(defun pike-font-lock-keywords-2 () + (c-compose-keywords-list pike-font-lock-keywords-2)) +(defun pike-font-lock-keywords-3 () + (c-compose-keywords-list pike-font-lock-keywords-3)) +(defun pike-font-lock-keywords () + (c-compose-keywords-list pike-font-lock-keywords)) + + +;;; Doc comments. + +(defun c-font-lock-doc-comments (prefix limit keywords) + ;; Fontify the comments between the point and LIMIT whose start + ;; matches PREFIX with `c-doc-face-name'. Assumes comments have been + ;; fontified with `font-lock-comment-face' already. nil is always + ;; returned. + ;; + ;; After the fontification of a matching comment, fontification + ;; according to KEYWORDS is applied inside it. It's a list like + ;; `font-lock-keywords' except that anchored matches and eval + ;; clauses aren't supported and that some abbreviated forms can't be + ;; used. The buffer is narrowed to the comment while KEYWORDS is + ;; applied; leading comment starters are included but trailing + ;; comment enders for block comment are not. + ;; + ;; Note that faces added through KEYWORDS should never replace the + ;; existing `c-doc-face-name' face since the existence of that face + ;; is used as a flag in other code to skip comments. + + (let (comment-beg region-beg) + (if (eq (get-text-property (point) 'face) + 'font-lock-comment-face) + ;; Handle the case when the fontified region starts inside a + ;; comment. + (let ((range (c-literal-limits))) + (setq region-beg (point)) + (when range + (goto-char (car range))) + (when (looking-at prefix) + (setq comment-beg (point))))) + + (while (or + comment-beg + + ;; Search for the prefix until a match is found at the start + ;; of a comment. + (while (when (re-search-forward prefix limit t) + (setq comment-beg (match-beginning 0)) + (or (not (c-got-face-at comment-beg + c-literal-faces)) + (and (/= comment-beg (point-min)) + (c-got-face-at (1- comment-beg) + c-literal-faces)))) + (setq comment-beg nil)) + (setq region-beg comment-beg)) + + (if (eq (elt (parse-partial-sexp comment-beg (+ comment-beg 2)) 7) t) + ;; Collect a sequence of doc style line comments. + (progn + (goto-char comment-beg) + (while (and (progn + (c-forward-single-comment) + (skip-syntax-forward " ") + (< (point) limit)) + (looking-at prefix)))) + (goto-char comment-beg) + (c-forward-single-comment)) + (if (> (point) limit) (goto-char limit)) + (setq comment-beg nil) + + (let ((region-end (point)) + (keylist keywords) keyword matcher highlights) + (c-put-font-lock-face region-beg region-end c-doc-face-name) + (save-restriction + ;; Narrow to the doc comment. Among other things, this + ;; helps by making "^" match at the start of the comment. + ;; Do not include a trailing block comment ender, though. + (and (> region-end (1+ region-beg)) + (progn (goto-char region-end) + (backward-char 2) + (looking-at "\\*/")) + (setq region-end (point))) + (narrow-to-region region-beg region-end) + + (while keylist + (setq keyword (car keylist) + keylist (cdr keylist) + matcher (car keyword)) + (goto-char region-beg) + (while (if (stringp matcher) + (re-search-forward matcher region-end t) + (funcall matcher region-end)) + (setq highlights (cdr keyword)) + (if (consp (car highlights)) + (while highlights + (font-lock-apply-highlight (car highlights)) + (setq highlights (cdr highlights))) + (font-lock-apply-highlight highlights)))) + + (goto-char region-end))))) + nil) +(put 'c-font-lock-doc-comments 'lisp-indent-function 2) + +(defun c-find-invalid-doc-markup (regexp limit) + ;; Used to fontify invalid markup in doc comments after the correct + ;; ones have been fontified: Find the first occurence of REGEXP + ;; between the point and LIMIT that only is fontified with + ;; `c-doc-face-name'. If a match is found then submatch 0 surrounds + ;; the first char and t is returned, otherwise nil is returned. + (let (start) + (while (if (re-search-forward regexp limit t) + (not (eq (get-text-property + (setq start (match-beginning 0)) 'face) + c-doc-face-name)) + (setq start nil))) + (when start + (store-match-data (list (copy-marker start) + (copy-marker (1+ start)))) + t))) + +(defun javadoc-font-lock-keywords () + (list + (byte-compile + `(lambda (limit) + (c-font-lock-doc-comments "/\\*\\*" limit + '(("{@[a-z]+[^}\n\r]*}" ; "{@foo ...}" markup. + 0 ,c-doc-markup-face-name prepend nil) + ("^\\(/\\*\\)?[ \t*]*\\(@[a-z]+\\)" ; "@foo ..." markup. + 2 ,c-doc-markup-face-name prepend nil) + (,(concat "</?\\sw" ; HTML tags. + "\\(" + (concat "\\sw\\|\\s \\|[=\n\r*.:]\\|" + "\"[^\"]*\"\\|'[^']*'") + "\\)*>") + 0 ,c-doc-markup-face-name prepend nil) + ("&\\(\\sw\\|[.:]\\)+;" ; HTML entities. + 0 ,c-doc-markup-face-name prepend nil) + ;; Fontify remaining markup characters as invalid. Note + ;; that the Javadoc spec is hazy about when "@" is allowed + ;; in non-markup use. + (,(lambda (limit) + (c-find-invalid-doc-markup "[<>&]\\|{@" limit)) + 0 ,c-invalid-face-name prepend nil) + )))))) + +(defconst autodoc-decl-keywords + ;; Adorned regexp matching the keywords that introduce declarations + ;; in Pike Autodoc. + (cc-eval-when-compile + (c-make-keywords-re t '("@decl" "@elem" "@index" "@member") 'pike-mode))) + +(defconst autodoc-decl-type-keywords + ;; Adorned regexp matching the keywords that are followed by a type. + (cc-eval-when-compile + (c-make-keywords-re t '("@elem" "@member") 'pike-mode))) + +(defun autodoc-font-lock-line-markup (limit) + ;; Fontify all line oriented keywords between the point and LIMIT. + ;; Nil is always returned. + + (let ((line-re (concat "^\\(\\(/\\*!\\|\\s *\\(" + c-current-comment-prefix + "\\)\\)\\s *\\)@[A-Za-z_-]+\\(\\s \\|$\\)")) + (markup-faces (list c-doc-markup-face-name c-doc-face-name))) + + (while (re-search-forward line-re limit t) + (goto-char (match-end 1)) + + (if (looking-at autodoc-decl-keywords) + (let* ((kwd-pos (point)) + (start (match-end 1)) + (pos start) + end) + + (c-put-font-lock-face (point) pos markup-faces) + + ;; Put a declaration end mark at the markup keyword and + ;; remove the faces from the rest of the line so that it + ;; gets refontified as a declaration later on by + ;; `c-font-lock-declarations'. + (c-put-char-property (1- pos) 'c-type 'c-decl-end) + (goto-char pos) + (while (progn + (end-of-line) + (setq end (point)) + (and (eq (char-before) ?@) + (not (eobp)) + (progn (forward-char) + (skip-chars-forward " \t") + (looking-at c-current-comment-prefix)))) + (goto-char (match-end 0)) + (c-remove-font-lock-face pos (1- end)) + (c-put-font-lock-face (1- end) end markup-faces) + (setq pos (point))) + + ;; Include the final newline in the removed area. This + ;; has no visual effect but it avoids some tricky special + ;; cases in the testsuite wrt the differences in string + ;; fontification in Emacs vs XEmacs. + (c-remove-font-lock-face pos (min (1+ (point)) (point-max))) + + ;; Must handle string literals explicitly inside the declaration. + (goto-char start) + (while (re-search-forward + "\"\\([^\\\"]\\|\\\\.\\)*\"\\|'\\([^\\']\\|\\\\.\\)*'" + end 'move) + (c-put-font-lock-string-face (match-beginning 0) + (point))) + + ;; Fontify types after keywords that always are followed + ;; by them. + (goto-char kwd-pos) + (when (looking-at autodoc-decl-type-keywords) + (c-fontify-types-and-refs ((c-promote-possible-types t)) + (goto-char start) + (c-forward-syntactic-ws) + (c-forward-type)))) + + ;; Mark each whole line as markup, as long as the logical line + ;; continues. + (while (progn + (c-put-font-lock-face (point) + (progn (end-of-line) (point)) + markup-faces) + (and (eq (char-before) ?@) + (not (eobp)) + (progn (forward-char) + (skip-chars-forward " \t") + (looking-at c-current-comment-prefix)))) + (goto-char (match-end 0)))))) + + nil) + +(defun autodoc-font-lock-keywords () + ;; Note that we depend on that `c-current-comment-prefix' has got + ;; its proper value here. + + ;; The `c-type' text property with `c-decl-end' is used to mark the + ;; end of the `autodoc-decl-keywords' occurrences to fontify the + ;; following declarations. + (setq c-type-decl-end-used t) + + (list + (byte-compile + `(lambda (limit) + (c-font-lock-doc-comments "/[*/]!" limit + '(("@\\(\\w+{\\|\\[\\([^\]@\n\r]\\|@@\\)*\\]\\|[@}]\\|$\\)" + ;; In-text markup. + 0 ,c-doc-markup-face-name prepend nil) + (autodoc-font-lock-line-markup) + ;; Fontify remaining markup characters as invalid. + (,(lambda (limit) + (c-find-invalid-doc-markup "@" limit)) + 0 ,c-invalid-face-name prepend nil) + )))))) + + +;; AWK. + +;; Awk regexps written with help from Peter Galbraith +;; <galbraith@mixing.qc.dfo.ca>. +;; Take GNU Emacs's 'words out of the following regexp-opts. They dont work +;; in Xemacs 21.4.4. acm 2002/9/19. +(eval-after-load "cc-awk" ; Evaluate while loading cc-fonts + `(defconst awk-font-lock-keywords ; Evaluate after loading cc-awk + ',(eval-when-compile ; Evaluate while compiling cc-fonts + (list + ;; Function names. + '("^[ \t]*\\(func\\(tion\\)?\\)\\>[ \t]*\\(\\sw+\\)?" + (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t)) + ;; + ;; Variable names. + (cons + (concat "\\<" + (c-regexp-opt + '("ARGC" "ARGIND" "ARGV" "BINMODE" "CONVFMT" "ENVIRON" + "ERRNO" "FIELDWIDTHS" "FILENAME" "FNR" "FS" "IGNORECASE" + "LINT" "NF" "NR" "OFMT" "OFS" "ORS" "PROCINFO" "RLENGTH" + "RS" "RSTART" "RT" "SUBSEP" "TEXTDOMAIN") t) "\\>") + 'font-lock-variable-name-face) + + ;; Special file names. (acm, 2002/7/22) + ;; The following regexp was created by first evaluating this in GNU Emacs 21.1: + ;; (c-regexp-opt '("/dev/stdin" "/dev/stdout" "/dev/stderr" "/dev/fd/n" "/dev/pid" + ;; "/dev/ppid" "/dev/pgrpid" "/dev/user") 'words) + ;; , removing the "?:" from each "\\(?:" (for backward compatibility with older Emacsen) + ;; , replacing the "n" in "dev/fd/n" with "[0-9]+" + ;; , removing the unwanted \\< at the beginning, and finally filling out the + ;; regexp so that a " must come before, and either a " or heuristic stuff after. + ;; The surrounding quotes are fontified along with the filename, since, semantically, + ;; they are an indivisible unit. + '("\\(\"/dev/\\(fd/[0-9]+\\|p\\(\\(\\(gr\\)?p\\)?id\\)\\|\ +std\\(err\\|in\\|out\\)\\|user\\)\\)\\>\ +\\(\\(\"\\)\\|\\([^\"/\n\r][^\"\n\r]*\\)?$\\)" + (1 font-lock-variable-name-face t) + (8 font-lock-variable-name-face t t)) + ;; Do the same (almost) with + ;; (c-regexp-opt '("/inet/tcp/lport/rhost/rport" "/inet/udp/lport/rhost/rport" + ;; "/inet/raw/lport/rhost/rport") 'words) + ;; This cannot be combined with the above pattern, because the match number + ;; for the (optional) closing \" would then exceed 9. + '("\\(\"/inet/\\(\\(raw\\|\\(tc\\|ud\\)p\\)/lport/rhost/rport\\)\\)\\>\ +\\(\\(\"\\)\\|\\([^\"/\n\r][^\"\n\r]*\\)?$\\)" + (1 font-lock-variable-name-face t) + (6 font-lock-variable-name-face t t)) + + ;; Keywords. + (concat "\\<" + (c-regexp-opt + '("BEGIN" "END" "break" "continue" "delete" "do" "else" + "exit" "for" "getline" "if" "in" "next" "nextfile" + "return" "while") + t) "\\>") + + ;; Builtins. + `(eval . (list + ,(concat + "\\<" + (c-regexp-opt + '("adump" "and" "asort" "atan2" "bindtextdomain" "close" + "compl" "cos" "dcgettext" "exp" "extension" "fflush" + "gensub" "gsub" "index" "int" "length" "log" "lshift" + "match" "mktime" "or" "print" "printf" "rand" "rshift" + "sin" "split" "sprintf" "sqrt" "srand" "stopme" + "strftime" "strtonum" "sub" "substr" "system" + "systime" "tolower" "toupper" "xor") t) + "\\>") + 0 c-preprocessor-face-name)) + + ;; gawk debugging keywords. (acm, 2002/7/21) + ;; (Removed, 2003/6/6. These functions are now fontified as built-ins) +;; (list (concat "\\<" (c-regexp-opt '("adump" "stopme") t) "\\>") +;; 0 'font-lock-warning-face) + + ;; User defined functions with an apparent spurious space before the + ;; opening parenthesis. acm, 2002/5/30. + `(,(concat "\\(\\w\\|_\\)" c-awk-escaped-nls* "[ \t]" + c-awk-escaped-nls*-with-space* "(") + (0 'font-lock-warning-face)) + + ;; Space after \ in what looks like an escaped newline. 2002/5/31 + '("\\\\[ \t]+$" 0 font-lock-warning-face t) + + ;; Unbalanced string (") or regexp (/) delimiters. 2002/02/16. + '("\\s|" 0 font-lock-warning-face t nil) + ;; gawk 3.1 localizable strings ( _"translate me!"). 2002/5/21 + '("\\(_\\)\\s|" 1 font-lock-warning-face) + '("\\(_\\)\\s\"" 1 font-lock-string-face) ; FIXME! not for XEmacs. 2002/10/6 + )) + "Default expressions to highlight in AWK mode.")) + + +(cc-provide 'cc-fonts) + +;;; cc-fonts.el ends here
--- a/lisp/progmodes/cc-langs.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-langs.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,9 @@ ;;; cc-langs.el --- language specific settings for CC Mode -;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1992-1997 Barry A. Warsaw +;; Authors: 1998- Martin Stjernholm +;; 1992-1999 Barry A. Warsaw ;; 1987 Dave Detlefs and Stewart Clamen ;; 1985 Richard M. Stallman ;; Maintainer: bug-cc-mode@gnu.org @@ -31,6 +30,87 @@ ;;; Commentary: +;; HACKERS NOTE: There's heavy macro magic here. If you need to make +;; changes in this or other files containing `c-lang-defconst' but +;; don't want to read through the longer discussion below then read +;; this: +;; +;; o A change in a `c-lang-defconst' or `c-lang-defvar' will not take +;; effect if the file containing the mode init function (typically +;; cc-mode.el) is byte compiled. +;; o To make changes show in font locking you need to reevaluate the +;; `*-font-lock-keywords-*' constants, which normally is easiest to +;; do with M-x eval-buffer in cc-fonts.el. +;; o In either case it's necessary to reinitialize the mode to make +;; the changes show in an existing buffer. + +;;; Introduction to the language dependent variable system: +;; +;; This file contains all the language dependent variables, except +;; those specific for font locking which reside in cc-fonts.el. As +;; far as possible, all the differences between the languages that CC +;; Mode supports are described with these variables only, so that the +;; code can be shared. +;; +;; The language constant system (see cc-defs.el) is used to specify +;; various language dependent info at a high level, such as lists of +;; keywords, and then from them generate - at compile time - the +;; various regexps and other low-level structures actually employed in +;; the code at runtime. +;; +;; This system is also designed to make it easy for developers of +;; derived modes to customize the source constants for new language +;; variants, without having to keep up with the exact regexps etc that +;; are used in each CC Mode version. It's possible from an external +;; package to add a new language by inheriting an existing one, and +;; then change specific constants as necessary for the new language. +;; The old values for those constants (and the values of all the other +;; high-level constants) may be used to build the new ones, and those +;; new values will in turn be used by the low-level definitions here +;; to build the runtime constants appropriately for the new language +;; in the current version of CC Mode. +;; +;; Like elsewhere in CC Mode, the existence of a doc string signifies +;; that a language constant is part of the external API, and that it +;; therefore can be used with a high confidence that it will continue +;; to work with future versions of CC Mode. Even so, it's not +;; unlikely that such constants will change meaning slightly as this +;; system is refined further; a certain degree of dependence on the CC +;; Mode version is unavoidable when hooking in at this level. Also +;; note that there's still work to be done to actually use these +;; constants everywhere inside CC Mode; there are still hardcoded +;; values in many places in the code. +;; +;; Separate packages will also benefit from the compile time +;; evaluation; the byte compiled file(s) for them will contain the +;; compiled runtime constants ready for use by (the byte compiled) CC +;; Mode, and the source definitions in this file don't have to be +;; loaded then. However, if a byte compiled package is loaded that +;; has been compiled with a different version of CC Mode than the one +;; currently loaded, then the compiled-in values will be discarded and +;; new ones will be built when the mode is initialized. That will +;; automatically trig a load of the file(s) containing the source +;; definitions (i.e. this file and/or cc-fonts.el) if necessary. +;; +;; A small example of a derived mode is available at +;; <http://cc-mode.sourceforge.net/derived-mode-ex.el>. It also +;; contains some useful hints for derived mode developers. + +;;; Using language variables: +;; +;; The `c-lang-defvar' forms in this file comprise the language +;; variables that CC Mode uses. It does not work to use +;; `c-lang-defvar' anywhere else (which isn't much of a limitation +;; since these variables sole purpose is to interface with the CC Mode +;; core functions). The values in these `c-lang-defvar's are not +;; evaluated right away but instead collected to a single large `setq' +;; that can be inserted for a particular language with the +;; `c-init-language-vars' macro. + +;; This file is only required at compile time, or when not running +;; from byte compiled files, or when the source definitions for the +;; language constants are requested. + ;;; Code: (eval-when-compile @@ -39,594 +119,102 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) (cc-require 'cc-defs) (cc-require 'cc-vars) -;; Some support functions that are used when the language specific -;; constants are built. Since the constants are built during compile -;; time, these need to be defined then too. - -(eval-and-compile - ;; `require' in XEmacs doesn't have the third NOERROR argument. - (condition-case nil (require 'regexp-opt) (file-error nil)) - - (if (fboundp 'regexp-opt) - (fset 'c-regexp-opt (symbol-function 'regexp-opt)) - ;; Emacs 19.34 doesn't have the regexp-opt package. - (defun c-regexp-opt (strings &optional paren) - (if paren - (concat "\\(" (mapconcat 'regexp-quote strings "\\|") "\\)") - (mapconcat 'regexp-quote strings "\\|")))) - - (if (fboundp 'regexp-opt-depth) - (fset 'c-regexp-opt-depth (symbol-function 'regexp-opt-depth)) - ;; Emacs 19.34 doesn't have the regexp-opt package. - (defun c-regexp-opt-depth (regexp) - ;; This is the definition of `regexp-opt-depth' in Emacs 20. - (save-match-data - ;; Hack to signal an error if REGEXP does not have balanced - ;; parentheses. - (string-match regexp "") - ;; Count the number of open parentheses in REGEXP. - (let ((count 0) start) - (while (string-match "\\\\(" regexp start) - (setq count (1+ count) start (match-end 0))) - count)))) - - (defun c-delete-duplicates (list) - (let ((tail list)) - (while tail - (setcdr tail (delete (car tail) (cdr tail))) - (setq tail (cdr tail))) - list)) - - (defun c-make-keywords-re (adorn &rest lists) - "Make a regexp that matches all the strings in all the lists. -Duplicates in the lists are removed. The regexp may contain zero or -more submatch expressions. If ADORN is non-nil there will be at least -one submatch which matches the whole keyword, and the regexp will also -not match a prefix of any identifier. Adorned regexps cannot be -appended." - (let ((list (copy-sequence (apply 'append lists)))) - (setq list (c-delete-duplicates list)) - (if list - (let ((re (c-regexp-opt list))) - ;; Add our own grouping parenthesis around re instead of - ;; passing adorn to regexp-opt, since it in XEmacs makes the - ;; top level grouping "shy". - (if adorn - (concat "\\(" re "\\)\\>\\([^_]\\|$\\)") - re)) - "\\<\\>" ; Matches nothing. - ))) - (put 'c-make-keywords-re 'lisp-indent-function 1) - ) - - -;; Building of constants that are parameterized on a per-language -;; basis. +;;; Setup for the `c-lang-defvar' system. (eval-and-compile - (defvar c-macroexpand-mode nil - ;; Dynamically bound to the mode symbol during `c-lang-defconst' - ;; so that `c-lang-var' can do the right expansion. - ) - - (defmacro c-lang-defconst (var &rest args) - ;; Sets the mode specific values of the constant VAR. The rest of - ;; the arguments are one or more repetitions of MODE VAL. MODE is - ;; the mode name without the "-mode" suffix, or a list of such - ;; mode names, or `all' as a shortcut for a list of all modes. - ;; VAL is evaluated (during compilation) for each mode with - ;; `c-macroexpand-mode' temporarily bound, so `c-lang-var' without - ;; an explicit mode may be used within it. The assignments in - ;; ARGS are processed in sequence, similar to `setq'. - (let* ((res (list 'progn)) - (res-tail res)) - (while args - (let ((mode (car args))) - (cond ((eq mode 'all) - (setq mode '(c c++ objc java idl pike))) - ((symbolp mode) - (setq mode (list mode)))) - (while mode - (let* ((c-macroexpand-mode - (intern (concat (symbol-name (car mode)) "-mode"))) - (val (eval (car (cdr args))))) - ;; Need to install the value also during compilation, - ;; since val might refer to earlier mode specific - ;; values. - (put var c-macroexpand-mode val) - (setcdr res-tail (list `(put ',var ',c-macroexpand-mode ',val))) - (setq res-tail (cdr res-tail))) - (setq mode (cdr mode)))) - (setq args (cdr (cdr args)))) - res)) - (put 'c-lang-defconst 'lisp-indent-function 1) - - (defmacro c-lang-var (var &optional mode) - ;; Get the mode specific value of the variable VAR in mode MODE. - ;; MODE is the mode name without the "-mode" suffix. It may also - ;; be nil to use the current value of `c-macroexpand-mode' (which - ;; is useful inside `c-lang-defconst') or `c-buffer-is-cc-mode' - ;; (which is useful inside `c-lang-defvar'). - `(get ',var ,(if (eq mode 'nil) - (if c-macroexpand-mode - ;; In the macro expansion of c-lang-defconst. - `(quote ,c-macroexpand-mode) - `c-buffer-is-cc-mode) - `(quote ,(intern (concat (symbol-name mode) "-mode")))))) - ;; These are used to collect the init forms from the subsequent - ;; `c-lang-defvar'. They become a big setq in the - ;; `c-init-lang-defvars' lambda below. - (defconst c-lang-defvar-init-form (list 'setq)) - (defvar c-lang-defvar-init-form-tail nil) - (setq c-lang-defvar-init-form-tail c-lang-defvar-init-form) - - (defmacro c-lang-defvar (var val) - ;; Declares the buffer local variable VAR to get the value VAL at - ;; mode initialization, at which point VAL is evaluated. - ;; `c-lang-var' is typically used in VAL to get the right value - ;; according to `c-buffer-is-cc-mode'. - (setcdr c-lang-defvar-init-form-tail (list var val)) - (setq c-lang-defvar-init-form-tail - (cdr (cdr c-lang-defvar-init-form-tail))) - `(progn - (defvar ,var nil) - (make-variable-buffer-local ',var))) - (put 'c-lang-defvar 'lisp-indent-function 1) - ) - -;; Regexp describing a `symbol' in all languages, not excluding -;; keywords. -(c-lang-defconst c-symbol-key - (c c++ objc java idl) - (if (string-match "[[:alpha:]]" "a") - "[[:alpha:]_][[:alnum:]_]*" ; Emacs 21. - ;; We cannot use just `word' syntax class since `_' cannot be - ;; in word class. Putting underscore in word class breaks - ;; forward word movement behavior that users are familiar - ;; with. Besides, it runs counter to Emacs convention. - "[a-zA-Z_]\\(\\w\\|_\\)*") - pike (concat "\\(" (c-lang-var c-symbol-key c) "\\|" - (c-make-keywords-re nil - '("`+" "`-" "`&" "`|" "`^" "`<<" "`>>" "`*" "`/" "`%" "`~" - "`==" "`<" "`>" "`!" "`[]" "`[]=" "`->" "`->=" "`()" "``+" - "``-" "``&" "``|" "``^" "``<<" "``>>" "``*" "``/" "``%" - "`+=")) - "\\)")) -(c-lang-defvar c-symbol-key (c-lang-var c-symbol-key)) - -;; Number of regexp grouping parens in c-symbol-key. -(c-lang-defvar c-symbol-key-depth (c-regexp-opt-depth c-symbol-key)) - -(defvar c-stmt-delim-chars "^;{}?:") -;; The characters that should be considered to bound statements. To -;; optimize c-crosses-statement-barrier-p somewhat, it's assumed to -;; begin with "^" to negate the set. If ? : operators should be -;; detected then the string must end with "?:". - -(defvar c-stmt-delim-chars-with-comma "^;,{}?:") -;; Variant of c-stmt-delim-chars that additionally contains ','. - -;; HELPME: Many of the following keyword lists are more or less bogus -;; for some languages (notably ObjC and IDL). The effects of the -;; erroneous values in the language handling are mostly negligible -;; since the constants that actually matter in the syntax detection -;; code are mostly correct in the situations they are used, but I'd -;; still appreciate help to get them correct for other uses. - -;; Primitive type keywords. -(c-lang-defconst c-primitive-type-kwds - (c c++ objc idl) '("char" "double" "float" "int" "long" "short" - "signed" "unsigned" "void") - java '("boolean" "byte" "char" "double" "float" "int" "long" "short" "void") - pike '("constant" "float" "int" "mapping" "multiset" "object" "program" - "string" "void")) + ;; `c-lang-defvar'. They are used to build the lambda in + ;; `c-make-init-lang-vars-fun' below. + (defconst c-lang-variable-inits (list nil)) + (defconst c-lang-variable-inits-tail c-lang-variable-inits)) -;; Declaration specifier keywords. -(c-lang-defconst c-specifier-kwds - c '("auto" "const" "extern" "register" "static" "volatile") - (c++ objc idl) (append '("friend" "inline" "virtual") - (c-lang-var c-specifier-kwds c)) - ;; Note: `const' is not used in Java, but it's still a reserved keyword. - java '("abstract" "const" "final" "native" "private" "protected" - "public" "static" "synchronized" "transient" "volatile") - pike '("final" "inline" "local" "nomask" "optional" "private" - "protected" "static" "variant")) - -;; Class/struct declaration keywords. -(c-lang-defconst c-class-kwds - c '("struct" "union") - c++ '("class" "struct" "union") - objc '("interface" "implementation") - java '("class" "interface") - idl '("interface" "valuetype" "class" "struct" "union") - pike '("class")) - -;; Regexp matching the start of a class. -(c-lang-defconst c-class-key - all (c-make-keywords-re t (c-lang-var c-class-kwds))) -(c-lang-defconst c-class-key ; ObjC needs some tuning of the regexp. - objc (concat "@" (c-lang-var c-class-key))) -(c-lang-defvar c-class-key (c-lang-var c-class-key)) - -;; Keywords introducing blocks besides classes that contain another -;; declaration level. -(c-lang-defconst c-other-decl-block-kwds - c '("extern") - c++ '("namespace" "extern") - idl '("module")) - -;; Regexp matching the start of blocks besides classes that contain -;; another declaration level. -(c-lang-defconst c-other-decl-block-key - all (c-make-keywords-re t (c-lang-var c-other-decl-block-kwds))) -(c-lang-defvar c-other-decl-block-key (c-lang-var c-other-decl-block-key)) - -;; Keywords introducing declarations that can contain a block which -;; might be followed by variable declarations, e.g. like "foo" in -;; "class Foo { ... } foo;". So if there is a block in a declaration -;; like that, it ends with the following ';' and not right away. -(c-lang-defconst c-block-decls-with-vars - c '("struct" "union" "enum" "typedef") - c++ '("class" "struct" "union" "enum" "typedef")) - -;; Regexp matching the `c-block-decls-with-vars' keywords, or nil in -;; languages without such constructs. -(c-lang-defconst c-opt-block-decls-with-vars-key - all (and (c-lang-var c-block-decls-with-vars) - (c-make-keywords-re t (c-lang-var c-block-decls-with-vars)))) -(c-lang-defvar c-opt-block-decls-with-vars-key - (c-lang-var c-opt-block-decls-with-vars-key)) - -;; Keywords introducing declarations that has not been accounted for -;; by any of the above. -(c-lang-defconst c-other-decl-kwds - ;; FIXME: Shouldn't "template" be moved to c-specifier-kwds for C++? - c++ '("template") - java '("import" "package") - pike '("import" "inherit")) +(defmacro c-lang-defvar (var val &optional doc) + "Declares the buffer local variable VAR to get the value VAL at mode +initialization, at which point VAL is evaluated. More accurately, VAL +is evaluated and bound to VAR when the result from the macro +`c-init-language-vars' is evaluated. -;; Keywords introducing extra declaration specifiers in the region -;; between the header and the body (i.e. the "K&R-region") in -;; declarations. -(c-lang-defconst c-decl-spec-kwds java '("extends" "implements" "throws")) - -;; Protection label keywords in classes. -(c-lang-defconst c-protection-kwds - (c++ objc) '("private" "protected" "public")) - -;; Statement keywords followed directly by a substatement. -(c-lang-defconst c-block-stmt-1-kwds - (c pike) '("do" "else") - (c++ objc) '("do" "else" "asm" "try") - java '("do" "else" "finally" "try")) - -;; Regexp matching the start of any statement followed directly by a -;; substatement (doesn't match a bare block, however). -(c-lang-defconst c-block-stmt-1-key - all (c-make-keywords-re t (c-lang-var c-block-stmt-1-kwds))) -(c-lang-defvar c-block-stmt-1-key (c-lang-var c-block-stmt-1-key)) - -;; Statement keywords followed by a paren sexp and then by a substatement. -(c-lang-defconst c-block-stmt-2-kwds - c '("for" "if" "switch" "while") - (c++ objc) '("for" "if" "switch" "while" "catch") - java '("for" "if" "switch" "while" "catch" "synchronized") - pike '("for" "if" "switch" "while" "foreach")) - -;; Regexp matching the start of any statement followed by a paren sexp -;; and then by a substatement. -(c-lang-defconst c-block-stmt-2-key - all (c-make-keywords-re t (c-lang-var c-block-stmt-2-kwds))) -(c-lang-defvar c-block-stmt-2-key (c-lang-var c-block-stmt-2-key)) +`c-lang-const' is typically used in VAL to get the right value for the +language being initialized, and such calls will be macro expanded to +the evaluated constant value at compile time. -;; Regexp matching the start of any statement that has a substatement -;; (except a bare block). Nil in languages that doesn't have such -;; constructs. -(c-lang-defconst c-opt-block-stmt-key - all (if (or (c-lang-var c-block-stmt-1-kwds) - (c-lang-var c-block-stmt-2-kwds)) - (c-make-keywords-re t - (c-lang-var c-block-stmt-1-kwds) - (c-lang-var c-block-stmt-2-kwds)))) -(c-lang-defvar c-opt-block-stmt-key (c-lang-var c-opt-block-stmt-key)) - -;; Statement keywords followed by an expression or nothing. -(c-lang-defconst c-simple-stmt-kwds - (c c++ objc) '("break" "continue" "goto" "return") - ;; Note: `goto' is not valid in Java, but the keyword is still reserved. - java '("break" "continue" "goto" "return" "throw") - pike '("break" "continue" "return")) - -;; Statement keywords followed by an assembler expression. -(c-lang-defconst c-asm-stmt-kwds - (c c++) '("asm" "__asm__")) - -;; Regexp matching the start of an assembler statement. Nil in -;; languages that doesn't support that. -(c-lang-defconst c-opt-asm-stmt-key - all (if (c-lang-var c-asm-stmt-kwds) - (c-make-keywords-re t (c-lang-var c-asm-stmt-kwds)))) -(c-lang-defvar c-opt-asm-stmt-key (c-lang-var c-opt-asm-stmt-key)) - -;; Keywords introducing labels in blocks. -(c-lang-defconst c-label-kwds (c c++ objc java pike) '("case" "default")) - -;; Regexp matching any keyword that introduces a label. -(c-lang-defconst c-label-kwds-regexp - all (c-make-keywords-re t (c-lang-var c-label-kwds))) -(c-lang-defvar c-label-kwds-regexp (c-lang-var c-label-kwds-regexp)) +This macro does not do any hidden buffer changes." -;; Keywords that can occur anywhere in expressions. -(c-lang-defconst c-expr-kwds - (c objc) '("sizeof") - c++ '("sizeof" "delete" "new" "operator" "this" "throw") - java '("instanceof" "new" "super" "this") - pike '("sizeof" "catch" "class" "gauge" "lambda" "predef")) - -;; Keywords that start lambda constructs, i.e. function definitions in -;; expressions. -(c-lang-defconst c-lambda-kwds pike '("lambda")) - -;; Regexp matching the start of lambda constructs, or nil in languages -;; that doesn't have such things. -(c-lang-defconst c-opt-lambda-key - pike (c-make-keywords-re t (c-lang-var c-lambda-kwds))) -(c-lang-defvar c-opt-lambda-key (c-lang-var c-opt-lambda-key)) - -;; Keywords that start constructs followed by statement blocks which -;; can be used in expressions (the gcc extension for this in C and C++ -;; is handled separately). -(c-lang-defconst c-inexpr-block-kwds pike '("catch" "gauge")) - -;; Regexp matching the start of in-expression statements, or nil in -;; languages that doesn't have such things. -(c-lang-defconst c-opt-inexpr-block-key - pike (c-make-keywords-re t (c-lang-var c-inexpr-block-kwds))) -(c-lang-defvar c-opt-inexpr-block-key (c-lang-var c-opt-inexpr-block-key)) - -;; Keywords that start classes in expressions. -(c-lang-defconst c-inexpr-class-kwds - java '("new") - pike '("class")) - -;; Regexp matching the start of a class in an expression, or nil in -;; languages that doesn't have such things. -(c-lang-defconst c-opt-inexpr-class-key - (java pike) (c-make-keywords-re t (c-lang-var c-inexpr-class-kwds))) -(c-lang-defvar c-opt-inexpr-class-key (c-lang-var c-opt-inexpr-class-key)) - -;; Regexp matching the start of any class, both at top level and in -;; expressions. -(c-lang-defconst c-any-class-key - all (c-make-keywords-re t - (c-lang-var c-class-kwds) - (c-lang-var c-inexpr-class-kwds))) -(c-lang-defconst c-any-class-key ; ObjC needs some tuning of the regexp. - objc (concat "@" (c-lang-var c-any-class-key))) -(c-lang-defvar c-any-class-key (c-lang-var c-any-class-key)) - -;; Regexp matching the start of any declaration-level block that -;; contain another declaration level, i.e. that isn't a function -;; block. -(c-lang-defconst c-decl-block-key - all (c-make-keywords-re t - (c-lang-var c-class-kwds) - (c-lang-var c-other-decl-block-kwds) - (c-lang-var c-inexpr-class-kwds))) -(c-lang-defconst c-decl-block-key ; ObjC needs some tuning of the regexp. - objc (concat "@" (c-lang-var c-decl-block-key))) -(c-lang-defvar c-decl-block-key (c-lang-var c-decl-block-key)) - -;; Keywords that can introduce bitfields. -(c-lang-defconst c-bitfield-kwds - (c c++) '("char" "int" "long" "signed" "unsigned")) - -;; Regexp matching the start of a bitfield (not uniquely), or nil in -;; languages without bitfield support. -(c-lang-defconst c-opt-bitfield-key - (c c++) (c-make-keywords-re t (c-lang-var c-bitfield-kwds))) -(c-lang-defvar c-opt-bitfield-key (c-lang-var c-opt-bitfield-key)) - -;; All keywords as a list. -(c-lang-defconst c-keywords - all (c-delete-duplicates - (append (c-lang-var c-primitive-type-kwds) - (c-lang-var c-specifier-kwds) - (c-lang-var c-class-kwds) - (c-lang-var c-other-decl-block-kwds) - (c-lang-var c-block-decls-with-vars) - (c-lang-var c-other-decl-kwds) - (c-lang-var c-decl-spec-kwds) - (c-lang-var c-protection-kwds) - (c-lang-var c-block-stmt-1-kwds) - (c-lang-var c-block-stmt-2-kwds) - (c-lang-var c-simple-stmt-kwds) - (c-lang-var c-asm-stmt-kwds) - (c-lang-var c-label-kwds) - (c-lang-var c-expr-kwds) - (c-lang-var c-lambda-kwds) - (c-lang-var c-inexpr-block-kwds) - (c-lang-var c-inexpr-class-kwds) - (c-lang-var c-bitfield-kwds) - nil))) -(c-lang-defvar c-keywords (c-lang-var c-keywords)) - -;; All keywords as an adorned regexp. -(c-lang-defconst c-keywords-regexp - all (c-make-keywords-re t (c-lang-var c-keywords))) -(c-lang-defvar c-keywords-regexp (c-lang-var c-keywords-regexp)) - -;; Regexp matching an access protection label in a class, or nil in -;; languages that doesn't have such things. -(c-lang-defconst c-opt-access-key - c++ (concat "\\(" - (c-make-keywords-re nil (c-lang-var c-protection-kwds)) - "\\)[ \t\n\r]*:")) -(c-lang-defconst c-opt-access-key - objc (concat "@" (c-make-keywords-re t (c-lang-var c-protection-kwds)))) -(c-lang-defvar c-opt-access-key (c-lang-var c-opt-access-key)) - -;; Regexp matching a normal label, i.e. not a label that's recognized -;; with a keyword, like switch labels. It's only used at the -;; beginning of a statement. -(c-lang-defconst c-label-key - all (concat (c-lang-var c-symbol-key) "[ \t\n\r]*:\\([^:]\\|$\\)")) -(c-lang-defvar c-label-key (c-lang-var c-label-key)) + (when (and (not doc) + (eq (car-safe val) 'c-lang-const) + (eq (nth 1 val) var) + (not (nth 2 val))) + ;; Special case: If there's no docstring and the value is a + ;; simple (c-lang-const foo) where foo is the same name as VAR + ;; then take the docstring from the language constant foo. + (setq doc (get (intern (symbol-name (nth 1 val)) c-lang-constants) + 'variable-documentation))) + (or (stringp doc) + (setq doc nil)) -;; Regexp matching the beginning of a declaration specifier in the -;; region between the header and the body of a declaration. -;; -;; FIXME: This is currently not used in a uniformly; c++-mode and -;; java-mode each have their own ways of using it. -(c-lang-defconst c-opt-decl-spec-key - c++ (concat ":?[ \t\n\r]*\\(virtual[ \t\n\r]+\\)?\\(" - (c-make-keywords-re nil (c-lang-var c-protection-kwds)) - "\\)[ \t\n\r]+" - (c-lang-var c-symbol-key)) - java (c-make-keywords-re t (c-lang-var c-decl-spec-kwds))) -(c-lang-defvar c-opt-decl-spec-key (c-lang-var c-opt-decl-spec-key)) - -;; Regexp describing friend declarations classes, or nil in languages -;; that doesn't have such things. -(c-lang-defconst c-opt-friend-key - ;; FIXME: Ought to use c-specifier-kwds or similar, and the template - ;; skipping isn't done properly. - c++ "friend[ \t]+\\|template[ \t]*<.+>[ \t]*friend[ \t]+") -(c-lang-defvar c-opt-friend-key (c-lang-var c-opt-friend-key)) - -;; Special regexp to match the start of methods. -(c-lang-defconst c-opt-method-key - objc (concat - "^\\s *[+-]\\s *" - "\\(([^)]*)\\)?" ; return type - ;; \\s- in objc syntax table does not include \n - ;; since it is considered the end of //-comments. - "[ \t\n]*" (c-lang-var c-symbol-key))) -(c-lang-defvar c-opt-method-key (c-lang-var c-opt-method-key)) - -;; Name of functions in cpp expressions that take an identifier as the -;; argument. -(c-lang-defconst c-cpp-defined-fns - (c c++) '("defined") - pike '("defined" "efun" "constant")) - -;; List of open- and close-chars that makes up a pike-style brace -;; list, i.e. for a `([ ])' list there should be a cons (?\[ . ?\]) in -;; this list. -(c-lang-defconst c-special-brace-lists pike '((?{ . ?}) - (?\[ . ?\]) - (?< . ?>))) -(c-lang-defvar c-special-brace-lists (c-lang-var c-special-brace-lists)) - -;; Non-nil means K&R style argument declarations are valid. -(c-lang-defconst c-recognize-knr-p c t) -(c-lang-defvar c-recognize-knr-p (c-lang-var c-recognize-knr-p)) - -;; Regexp to match the start of any type of comment. -;; -;; FIXME: Ought to use c-comment-prefix-regexp with some modifications -;; instead of this. -(c-lang-defconst c-comment-start-regexp - (c c++ objc idl pike) "/[/*]" - ;; We need to match all 3 Java style comments - ;; 1) Traditional C block; 2) javadoc /** ...; 3) C++ style - java "/\\(/\\|[*][*]?\\)") -(c-lang-defvar c-comment-start-regexp (c-lang-var c-comment-start-regexp)) - -;; Strings that starts and ends comments inserted with M-; etc. -;; comment-start and comment-end are initialized from these. -(c-lang-defconst comment-start - c "/* " - (c++ objc java idl pike) "// ") -(c-lang-defvar comment-start (c-lang-var comment-start)) -(c-lang-defconst comment-end - c "*/" - (c++ objc java idl pike) "") -(c-lang-defvar comment-end (c-lang-var comment-end)) + (let ((elem (assq var (cdr c-lang-variable-inits)))) + (if elem + (setcdr elem (list val doc)) + (setcdr c-lang-variable-inits-tail (list (list var val doc))) + (setq c-lang-variable-inits-tail (cdr c-lang-variable-inits-tail)))) -;; Regexp that matches when there is no syntactically significant text -;; before eol. Macros are regarded as syntactically significant text -;; here. -(c-lang-defvar c-syntactic-eol - (concat (concat - ;; Match horizontal whitespace and block comments that - ;; doesn't contain newlines. - "\\(\\s \\|" - (concat "/\\*" - "\\([^*\n\r]\\|\\*[^/\n\r]\\)*" - "\\*/") - "\\)*") - (concat - ;; Match eol (possibly inside a block comment), or the - ;; beginning of a line comment. Note: This has to be - ;; modified for awk where line comments start with '#'. - "\\(" - (concat "\\(" - "/\\*\\([^*\n\r]\\|\\*[^/\n\r]\\)*" - "\\)?" - "$") - "\\|//\\)"))) - -;; Regexp to append to paragraph-start. -(c-lang-defconst paragraph-start - (c c++ objc idl) "$" - java "\\(@[a-zA-Z]+\\>\\|$\\)" ; For Javadoc. - pike "\\(@[a-zA-Z]+\\>\\([^{]\\|$\\)\\|$\\)") ; For Pike refdoc. - -;; Regexp to append to paragraph-separate. -(c-lang-defconst paragraph-separate - (c c++ objc java idl) "$" - pike (c-lang-var paragraph-start)) + ;; Return the symbol, like the other def* forms. + `',var) -;; Prefix added to `c-current-comment-prefix' to set -;; `c-opt-in-comment-lc', or nil if it should be nil. -(c-lang-defconst c-in-comment-lc-prefix pike "@[\n\r]\\s *") - -;; Regexp to match in-comment line continuations, or nil in languages -;; where that isn't applicable. It's assumed that it only might match -;; from and including the last character on a line. Built from -;; *-in-comment-lc-prefix and the current value of -;; c-current-comment-prefix. -(c-lang-defvar c-opt-in-comment-lc - (if (c-lang-var c-in-comment-lc-prefix) - (concat (c-lang-var c-in-comment-lc-prefix) - c-current-comment-prefix))) - -(defconst c-init-lang-defvars - ;; Make a lambda of the collected `c-lang-defvar' initializations. - (cc-eval-when-compile - (if (cc-bytecomp-is-compiling) - (byte-compile-lambda `(lambda () ,c-lang-defvar-init-form)) - `(lambda () ,c-lang-defvar-init-form)))) - -(defun c-init-language-vars () - ;; Initialize all `c-lang-defvar' variables according to - ;; `c-buffer-is-cc-mode'. - (if (not (memq c-buffer-is-cc-mode - '(c-mode c++-mode objc-mode java-mode idl-mode pike-mode))) - (error "Cannot initialize language variables for unknown mode %s" - c-buffer-is-cc-mode)) - (funcall c-init-lang-defvars)) - -;; Regexp trying to describe the beginning of a Java top-level -;; definition. This is not used by CC Mode, nor is it maintained -;; since it's practically impossible to write a regexp that reliably -;; matches such a construct. Other tools are necessary. -(defconst c-Java-defun-prompt-regexp - "^[ \t]*\\(\\(\\(public\\|protected\\|private\\|const\\|abstract\\|synchronized\\|final\\|static\\|threadsafe\\|transient\\|native\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\)\\s-+\\)\\)?\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+\\)?\\s-*") +(put 'c-lang-defvar 'lisp-indent-function 'defun) +(eval-after-load "edebug" + '(def-edebug-spec c-lang-defvar + (&define name def-form &optional stringp))) -;; Syntax tables. +;;; Various mode specific values that aren't language related. + +(c-lang-defconst c-mode-menu + ;; The definition for the mode menu. The menu title is prepended to + ;; this before it's fed to `easy-menu-define'. + t `(["Comment Out Region" comment-region + (c-fn-region-is-active-p)] + ["Uncomment Region" (comment-region (region-beginning) + (region-end) '(4)) + (c-fn-region-is-active-p)] + ["Indent Expression" c-indent-exp + (memq (char-after) '(?\( ?\[ ?\{))] + ["Indent Line or Region" c-indent-line-or-region t] + ["Fill Comment Paragraph" c-fill-paragraph t] + "----" + ["Backward Statement" c-beginning-of-statement t] + ["Forward Statement" c-end-of-statement t] + ,@(when (c-lang-const c-opt-cpp-prefix) + ;; Only applicable if there's a cpp preprocessor. + `(["Up Conditional" c-up-conditional t] + ["Backward Conditional" c-backward-conditional t] + ["Forward Conditional" c-forward-conditional t] + "----" + ["Macro Expand Region" c-macro-expand + (c-fn-region-is-active-p)] + ["Backslashify" c-backslash-region + (c-fn-region-is-active-p)])) + "----" + ("Toggle..." + ["Syntactic indentation" c-toggle-syntactic-indentation t] + ["Auto newline" c-toggle-auto-state t] + ["Hungry delete" c-toggle-hungry-state t]))) + + +;;; Syntax tables. (defun c-populate-syntax-table (table) - ;; Populate the syntax TABLE + "Populate the given syntax table as necessary for a C-like language. +This includes setting ' and \" as string delimiters, and setting up +the comment syntax to handle both line style \"//\" and block style +\"/*\" \"*/\" comments." + (modify-syntax-entry ?_ "_" table) (modify-syntax-entry ?\\ "\\" table) (modify-syntax-entry ?+ "." table) @@ -638,101 +226,2078 @@ (modify-syntax-entry ?& "." table) (modify-syntax-entry ?| "." table) (modify-syntax-entry ?\' "\"" table) - ;; Set up block and line oriented comments. The new C standard - ;; mandates both comment styles even in C, so since all languages - ;; now require dual comments, we make this the default. + (modify-syntax-entry ?\240 "." table) + + ;; Set up block and line oriented comments. The new C + ;; standard mandates both comment styles even in C, so since + ;; all languages now require dual comments, we make this the + ;; default. (cond - ;; XEmacs 19 & 20 + ;; XEmacs ((memq '8-bit c-emacs-features) (modify-syntax-entry ?/ ". 1456" table) (modify-syntax-entry ?* ". 23" table)) - ;; Emacs 19 & 20 + ;; Emacs ((memq '1-bit c-emacs-features) (modify-syntax-entry ?/ ". 124b" table) (modify-syntax-entry ?* ". 23" table)) ;; incompatible - (t (error "CC Mode is incompatible with this version of Emacs")) - ) + (t (error "CC Mode is incompatible with this version of Emacs"))) + (modify-syntax-entry ?\n "> b" table) ;; Give CR the same syntax as newline, for selective-display (modify-syntax-entry ?\^m "> b" table)) -;;;###autoload -(defvar c-mode-syntax-table nil - "Syntax table used in c-mode buffers.") -(if c-mode-syntax-table - () - (setq c-mode-syntax-table (make-syntax-table)) - (c-populate-syntax-table c-mode-syntax-table)) +(c-lang-defconst c-make-mode-syntax-table + "Functions that generates the mode specific syntax tables. +The syntax tables aren't stored directly since they're quite large." + t `(lambda () + (let ((table (make-syntax-table))) + (c-populate-syntax-table table) + ;; Mode specific syntaxes. + ,(cond ((c-major-mode-is 'objc-mode) + `(modify-syntax-entry ?@ "_" table)) + ((c-major-mode-is 'pike-mode) + `(modify-syntax-entry ?@ "." table))) + table))) + +(c-lang-defconst c-mode-syntax-table + ;; The syntax tables in evaluated form. Only used temporarily when + ;; the constants in this file are evaluated. + t (funcall (c-lang-const c-make-mode-syntax-table))) + +(c-lang-defconst make-c++-template-syntax-table + ;; A variant of `c++-mode-syntax-table' that defines `<' and `>' as + ;; parenthesis characters. Used temporarily when template argument + ;; lists are parsed. Note that this encourages incorrect parsing of + ;; templates since they might contain normal operators that uses the + ;; '<' and '>' characters. Therefore this syntax table might go + ;; away when CC Mode handles templates correctly everywhere. + t nil + c++ `(lambda () + (let ((table (funcall ,(c-lang-const c-make-mode-syntax-table)))) + (modify-syntax-entry ?< "(>" table) + (modify-syntax-entry ?> ")<" table) + table))) +(c-lang-defvar c++-template-syntax-table + (and (c-lang-const make-c++-template-syntax-table) + (funcall (c-lang-const make-c++-template-syntax-table)))) + +(c-lang-defconst c-identifier-syntax-modifications + "A list that describes the modifications that should be done to the +mode syntax table to get a syntax table that matches all identifiers +and keywords as words. + +The list is just like the one used in `font-lock-defaults': Each +element is a cons where the car is the character to modify and the cdr +the new syntax, as accepted by `modify-syntax-entry'." + ;; The $ character is not allowed in most languages (one exception + ;; is Java which allows it for legacy reasons) but we still classify + ;; it as an indentifier character since it's often used in various + ;; machine generated identifiers. + t '((?_ . "w") (?$ . "w")) + objc (append '((?@ . "w")) + (c-lang-const c-identifier-syntax-modifications)) + awk '((?_ . "w"))) +(c-lang-defvar c-identifier-syntax-modifications + (c-lang-const c-identifier-syntax-modifications)) + +(c-lang-defvar c-identifier-syntax-table + (let ((table (copy-syntax-table (c-mode-var "mode-syntax-table"))) + (mods c-identifier-syntax-modifications) + mod) + (while mods + (setq mod (car mods) + mods (cdr mods)) + (modify-syntax-entry (car mod) (cdr mod) table)) + table) + "Syntax table built on the mode syntax table but additionally +classifies symbol constituents like '_' and '$' as word constituents, +so that all identifiers are recognized as words.") + + +;;; Lexer-level syntax (identifiers, tokens etc). + +(c-lang-defconst c-symbol-start + "Regexp that matches the start of a symbol, i.e. any identifier or +keyword. It's unspecified how far it matches. Does not contain a \\| +operator at the top level." + t (concat "[" c-alpha "_]") + pike (concat "[" c-alpha "_`]")) +(c-lang-defvar c-symbol-start (c-lang-const c-symbol-start)) + +(c-lang-defconst c-symbol-chars + "Set of characters that can be part of a symbol. +This is on the form that fits inside [ ] in a regexp." + ;; Pike note: With the backquote identifiers this would include most + ;; operator chars too, but they are handled with other means instead. + t (concat c-alnum "_$") + objc (concat c-alnum "_$@")) + +(c-lang-defconst c-symbol-key + "Regexp matching identifiers and keywords. Assumed to match if +`c-symbol-start' matches on the same position." + t (concat (c-lang-const c-symbol-start) + "[" (c-lang-const c-symbol-chars) "]*") + pike (concat + ;; Use the value from C here since the operator backquote is + ;; covered by the other alternative. + (c-lang-const c-symbol-key c) + "\\|" + (c-make-keywords-re nil + (c-lang-const c-overloadable-operators)))) +(c-lang-defvar c-symbol-key (c-lang-const c-symbol-key)) + +(c-lang-defconst c-symbol-key-depth + ;; Number of regexp grouping parens in `c-symbol-key'. + t (c-regexp-opt-depth (c-lang-const c-symbol-key))) + +(c-lang-defconst c-nonsymbol-chars + "This is the set of chars that can't be part of a symbol, i.e. the +negation of `c-symbol-chars'." + t (concat "^" (c-lang-const c-symbol-chars))) +(c-lang-defvar c-nonsymbol-chars (c-lang-const c-nonsymbol-chars)) + +(c-lang-defconst c-nonsymbol-key + "Regexp that matches any character that can't be part of a symbol. +It's usually appended to other regexps to avoid matching a prefix. +It's assumed to not contain any submatchers." + ;; The same thing regarding Unicode identifiers applies here as to + ;; `c-symbol-key'. + t (concat "[" (c-lang-const c-nonsymbol-chars) "]")) + +(c-lang-defconst c-opt-identifier-concat-key + "Regexp matching the operators that join symbols to fully qualified +identifiers, or nil in languages that don't have such things. Does +not contain a \\| operator at the top level." + t nil + c++ "::" + java "\\." + idl "::" + pike "\\(::\\|\\.\\)") +(c-lang-defvar c-opt-identifier-concat-key + (c-lang-const c-opt-identifier-concat-key) + 'dont-doc) + +(c-lang-defconst c-opt-after-id-concat-key + "Regexp that must match the token after `c-opt-identifier-concat-key' +for it to be considered an identifier concatenation operator (which +e.g. causes the preceding identifier to be fontified as a reference). +Assumed to be a string if `c-opt-identifier-concat-key' is." + t (if (c-lang-const c-opt-identifier-concat-key) + (c-lang-const c-symbol-start)) + c++ (concat (c-lang-const c-symbol-start) + "\\|[~*]") + java (concat (c-lang-const c-symbol-start) + "\\|\\*")) + +(c-lang-defconst c-identifier-start + "Regexp that matches the start of an \(optionally qualified) +identifier. It should also match all keywords. It's unspecified how +far it matches." + t (concat (c-lang-const c-symbol-start) + (if (c-lang-const c-opt-identifier-concat-key) + (concat "\\|" (c-lang-const c-opt-identifier-concat-key)) + "")) + c++ (concat (c-lang-const c-identifier-start) + "\\|" + "[~*][ \t\n\r\f\v]*" (c-lang-const c-symbol-start)) + ;; Java does not allow a leading qualifier operator. + java (c-lang-const c-symbol-start)) +(c-lang-defvar c-identifier-start (c-lang-const c-identifier-start)) -;;;###autoload -(defvar c++-mode-syntax-table nil - "Syntax table used in c++-mode buffers.") -(if c++-mode-syntax-table - () - (setq c++-mode-syntax-table (make-syntax-table)) - (c-populate-syntax-table c++-mode-syntax-table)) +(c-lang-defconst c-identifier-key + "Regexp matching a fully qualified identifier, like \"A::B::c\" in +C++. It does not recognize the full range of syntactic whitespace +between the tokens; `c-forward-name' has to be used for that." + t (c-lang-const c-symbol-key) ; Default to `c-symbol-key'. + ;; C++ allows a leading qualifier operator and a `~' before the last + ;; symbol. This regexp is more complex than strictly necessary to + ;; ensure that it can be matched with a minimum of backtracking. + c++ (concat + "\\(" (c-lang-const c-opt-identifier-concat-key) "[ \t\n\r\f\v]*\\)?" + (concat + "\\(" + ;; The submatch below is depth of `c-opt-identifier-concat-key' + 3. + "\\(" (c-lang-const c-symbol-key) "\\)" + (concat "\\(" + "[ \t\n\r\f\v]*" + (c-lang-const c-opt-identifier-concat-key) + "[ \t\n\r\f\v]*" + ;; The submatch below is: `c-symbol-key-depth' + + ;; 2 * depth of `c-opt-identifier-concat-key' + 5. + "\\(" (c-lang-const c-symbol-key) "\\)" + "\\)*") + (concat "\\(" + "[ \t\n\r\f\v]*" + (c-lang-const c-opt-identifier-concat-key) + "[ \t\n\r\f\v]*" + "[~*]" + "[ \t\n\r\f\v]*" + ;; The submatch below is: 2 * `c-symbol-key-depth' + + ;; 3 * depth of `c-opt-identifier-concat-key' + 7. + "\\(" (c-lang-const c-symbol-key) "\\)" + "\\)?") + "\\|" + "~[ \t\n\r\f\v]*" + ;; The submatch below is: 3 * `c-symbol-key-depth' + + ;; 3 * depth of `c-opt-identifier-concat-key' + 8. + "\\(" (c-lang-const c-symbol-key) "\\)" + "\\)")) + ;; IDL and Pike allows a leading qualifier operator. + (idl pike) (concat + "\\(" + (c-lang-const c-opt-identifier-concat-key) + "[ \t\n\r\f\v]*" + "\\)?" + ;; The submatch below is depth of + ;; `c-opt-identifier-concat-key' + 2. + "\\(" (c-lang-const c-symbol-key) "\\)" + (concat "\\(" + "[ \t\n\r\f\v]*" + (c-lang-const c-opt-identifier-concat-key) + "[ \t\n\r\f\v]*" + ;; The submatch below is: `c-symbol-key-depth' + + ;; 2 * depth of `c-opt-identifier-concat-key' + 4. + "\\(" (c-lang-const c-symbol-key) "\\)" + "\\)*")) + ;; Java does not allow a leading qualifier operator. If it ends + ;; with ".*" (used in import declarations) we also consider that as + ;; part of the name. ("*" is actually recognized in any position + ;; except the first by this regexp, but we don't bother.) + java (concat "\\(" (c-lang-const c-symbol-key) "\\)" ; 1 + (concat "\\(" + "[ \t\n\r\f\v]*" + (c-lang-const c-opt-identifier-concat-key) + "[ \t\n\r\f\v]*" + (concat "\\(" + ;; The submatch below is `c-symbol-key-depth' + + ;; depth of `c-opt-identifier-concat-key' + 4. + "\\(" (c-lang-const c-symbol-key) "\\)" + "\\|\\*\\)") + "\\)*"))) +(c-lang-defvar c-identifier-key (c-lang-const c-identifier-key)) -(defvar c++-template-syntax-table nil - "A variant of `c++-mode-syntax-table' that defines `<' and `>' as -parenthesis characters. Used temporarily when template argument lists -are parsed.") -(if c++-template-syntax-table - () - (setq c++-template-syntax-table - (copy-syntax-table c++-mode-syntax-table)) - (modify-syntax-entry ?< "(>" c++-template-syntax-table) - (modify-syntax-entry ?> ")<" c++-template-syntax-table)) +(c-lang-defconst c-identifier-last-sym-match + "Used to identify the submatch in `c-identifier-key' that surrounds +the last symbol in the qualified identifier. It's a list of submatch +numbers, of which the first that has a match is taken. It's assumed +that at least one does when the regexp has matched." + t '(0) + c++ (list (+ (* 3 (c-lang-const c-symbol-key-depth)) + (* 3 (c-regexp-opt-depth + (c-lang-const c-opt-identifier-concat-key))) + 8) + (+ (* 2 (c-lang-const c-symbol-key-depth)) + (* 3 (c-regexp-opt-depth + (c-lang-const c-opt-identifier-concat-key))) + 7) + (+ (c-lang-const c-symbol-key-depth) + (* 2 (c-regexp-opt-depth + (c-lang-const c-opt-identifier-concat-key))) + 5) + (+ (c-regexp-opt-depth + (c-lang-const c-opt-identifier-concat-key)) + 3)) + (idl pike) (list (+ (c-lang-const c-symbol-key-depth) + (* 2 (c-regexp-opt-depth + (c-lang-const c-opt-identifier-concat-key))) + 4) + (+ (c-regexp-opt-depth + (c-lang-const c-opt-identifier-concat-key)) + 2)) + java (list (+ (c-lang-const c-symbol-key-depth) + (c-regexp-opt-depth + (c-lang-const c-opt-identifier-concat-key)) + 4) + 1)) +(c-lang-defvar c-identifier-last-sym-match + (c-lang-const c-identifier-last-sym-match) + 'dont-doc) + +(c-lang-defconst c-opt-cpp-prefix + "Regexp matching the prefix of a cpp directive in the languages that +normally use that macro preprocessor. Tested at bol or at boi. +Assumed to not contain any submatches or \\| operators." + t "\\s *#\\s *" + (java awk) nil) +(c-lang-defvar c-opt-cpp-prefix (c-lang-const c-opt-cpp-prefix)) + +(c-lang-defconst c-opt-cpp-start + "Regexp matching the prefix of a cpp directive including the directive +name, or nil in languages without preprocessor support. The first +submatch surrounds the directive name." + t (if (c-lang-const c-opt-cpp-prefix) + (concat (c-lang-const c-opt-cpp-prefix) + "\\([" c-alnum "]+\\)")) + ;; Pike, being a scripting language, recognizes hash-bangs too. + pike (concat (c-lang-const c-opt-cpp-prefix) + "\\([" c-alnum "]+\\|!\\)")) +(c-lang-defvar c-opt-cpp-start (c-lang-const c-opt-cpp-start)) + +(c-lang-defconst c-cpp-defined-fns + ;; Name of functions in cpp expressions that take an identifier as + ;; the argument. + t (if (c-lang-const c-opt-cpp-prefix) + '("defined")) + pike '("defined" "efun" "constant")) + +(c-lang-defconst c-operators + "List describing all operators, along with their precedence and +associativity. The order in the list corresponds to the precedence of +the operators: The operators in each element is a group with the same +precedence, and the group has higher precedence than the groups in all +following elements. The car of each element describes the type of of +the operator group, and the cdr is a list of the operator tokens in +it. The operator group types are: + +'prefix Unary prefix operators. +'postfix Unary postfix operators. +'left-assoc Binary left associative operators (i.e. a+b+c means (a+b)+c). +'right-assoc Binary right associative operators (i.e. a=b=c means a=(b=c)). +'right-assoc-sequence + Right associative operator that constitutes of a + sequence of tokens that separate expressions. All the + tokens in the group are in this case taken as + describing the sequence in one such operator, and the + order between them is therefore significant. + +Operators containing a character with paren syntax are taken to match +with a corresponding open/close paren somewhere else. A postfix +operator with close paren syntax is taken to end a postfix expression +started somewhere earlier, rather than start a new one at point. Vice +versa for prefix operators with open paren syntax. + +Note that operators like \".\" and \"->\" which in language references +often are described as postfix operators are considered binary here, +since CC Mode treats every identifier as an expression." + + ;; There's currently no code in CC Mode that exploit all the info + ;; in this variable; precedence, associativity etc are present as a + ;; preparation for future work. + + t `(;; Preprocessor. + ,@(when (c-lang-const c-opt-cpp-prefix) + `((prefix "#" + ,@(when (c-major-mode-is '(c-mode c++-mode)) + '("%:" "??="))) + (left-assoc "##" + ,@(when (c-major-mode-is '(c-mode c++-mode)) + '("%:%:" "??=??="))))) + + ;; Primary. Info duplicated in `c-opt-identifier-concat-key' + ;; and `c-identifier-key'. + ,@(cond ((c-major-mode-is 'c++-mode) + `((postfix-if-paren "<" ">") ; Templates. + (prefix "~" "??-" "compl") + (right-assoc "::") + (prefix "::"))) + ((c-major-mode-is 'pike-mode) + `((left-assoc "::") + (prefix "::" "global" "predef"))) + ((c-major-mode-is 'java-mode) + `(;; Not necessary since it's also in the postfix group below. + ;;(left-assoc ".") + (prefix "super")))) + + ;; Postfix. + ,@(when (c-major-mode-is 'c++-mode) + ;; The following need special treatment. + `((prefix "dynamic_cast" "static_cast" + "reinterpret_cast" "const_cast" "typeid"))) + (left-assoc "." + ,@(unless (c-major-mode-is 'java-mode) + '("->"))) + (postfix "++" "--" "[" "]" "(" ")" + ,@(when (c-major-mode-is '(c-mode c++-mode)) + '("<:" ":>" "??(" "??)"))) -;;;###autoload -(defvar objc-mode-syntax-table nil - "Syntax table used in objc-mode buffers.") -(if objc-mode-syntax-table - () - (setq objc-mode-syntax-table (make-syntax-table)) - (c-populate-syntax-table objc-mode-syntax-table) - ;; add extra Objective-C only syntax - (modify-syntax-entry ?@ "_" objc-mode-syntax-table)) + ;; Unary. + (prefix "++" "--" "+" "-" "!" "~" + ,@(when (c-major-mode-is 'c++-mode) '("not" "compl")) + ,@(when (c-major-mode-is '(c-mode c++-mode)) + '("*" "&" "sizeof" "??-")) + ,@(when (c-major-mode-is 'objc-mode) + '("@selector" "@protocol" "@encode")) + ;; The following need special treatment. + ,@(cond ((c-major-mode-is 'c++-mode) + '("new" "delete")) + ((c-major-mode-is 'java-mode) + '("new")) + ((c-major-mode-is 'pike-mode) + '("class" "lambda" "catch" "throw" "gauge"))) + "(" ")" ; Cast. + ,@(when (c-major-mode-is 'pike-mode) + '("[" "]"))) ; Type cast. + + ;; Member selection. + ,@(when (c-major-mode-is 'c++-mode) + `((left-assoc ".*" "->*"))) + + ;; Multiplicative. + (left-assoc "*" "/" "%") + + ;; Additive. + (left-assoc "+" "-") + + ;; Shift. + (left-assoc "<<" ">>" + ,@(when (c-major-mode-is 'java-mode) + '(">>>"))) + + ;; Relational. + (left-assoc "<" ">" "<=" ">=" + ,@(when (c-major-mode-is 'java-mode) + '("instanceof"))) + + ;; Equality. + (left-assoc "==" "!=" + ,@(when (c-major-mode-is 'c++-mode) '("not_eq"))) + + ;; Bitwise and. + (left-assoc "&" + ,@(when (c-major-mode-is 'c++-mode) '("bitand"))) + + ;; Bitwise exclusive or. + (left-assoc "^" + ,@(when (c-major-mode-is '(c-mode c++-mode)) + '("??'")) + ,@(when (c-major-mode-is 'c++-mode) '("xor"))) + + ;; Bitwise or. + (left-assoc "|" + ,@(when (c-major-mode-is '(c-mode c++-mode)) + '("??!")) + ,@(when (c-major-mode-is 'c++-mode) '("bitor"))) + + ;; Logical and. + (left-assoc "&&" + ,@(when (c-major-mode-is 'c++-mode) '("and"))) + + ;; Logical or. + (left-assoc "||" + ,@(when (c-major-mode-is '(c-mode c++-mode)) + '("??!??!")) + ,@(when (c-major-mode-is 'c++-mode) '("or"))) + + ;; Conditional. + (right-assoc-sequence "?" ":") + + ;; Assignment. + (right-assoc "=" "*=" "/=" "%=" "+=" "-=" ">>=" "<<=" "&=" "^=" "|=" + ,@(when (c-major-mode-is 'java-mode) + '(">>>=")) + ,@(when (c-major-mode-is 'c++-mode) + '("and_eq" "or_eq" "xor_eq"))) + + ;; Exception. + ,@(when (c-major-mode-is 'c++-mode) + '((prefix "throw"))) + + ;; Sequence. + (left-assoc ",")) + + ;; IDL got its own definition since it has a much smaller operator + ;; set than the other languages. + idl `(;; Preprocessor. + (prefix "#") + (left-assoc "##") + ;; Primary. Info duplicated in `c-opt-identifier-concat-key' + ;; and `c-identifier-key'. + (left-assoc "::") + (prefix "::") + ;; Unary. + (prefix "+" "-" "~") + ;; Multiplicative. + (left-assoc "*" "/" "%") + ;; Additive. + (left-assoc "+" "-") + ;; Shift. + (left-assoc "<<" ">>") + ;; And. + (left-assoc "&") + ;; Xor. + (left-assoc "^") + ;; Or. + (left-assoc "|"))) + +(c-lang-defconst c-operator-list + ;; The operators as a flat list (without duplicates). + t (delete-duplicates (mapcan (lambda (elem) (append (cdr elem) nil)) + (c-lang-const c-operators)) + :test 'string-equal)) + +(c-lang-defconst c-overloadable-operators + "List of the operators that are overloadable, in their \"identifier form\"." + t nil + ;; The preceding "operator" keyword is treated separately in C++. + c++ '("new" "delete" ;; Can be followed by "[]" but we ignore that. + "+" "-" "*" "/" "%" + "^" "??'" "xor" "&" "bitand" "|" "??!" "bitor" "~" "??-" "compl" + "!" "=" "<" ">" "+=" "-=" "*=" "/=" "%=" "^=" + "??'=" "xor_eq" "&=" "and_eq" "|=" "??!=" "or_eq" + "<<" ">>" ">>=" "<<=" "==" "!=" "not_eq" "<=" ">=" + "&&" "and" "||" "??!??!" "or" "++" "--" "," "->*" "->" + "()" "[]" "<::>" "??(??)") + ;; These work like identifiers in Pike. + pike '("`+" "`-" "`&" "`|" "`^" "`<<" "`>>" "`*" "`/" "`%" "`~" + "`==" "`<" "`>" "`!" "`[]" "`[]=" "`->" "`->=" "`()" "``+" + "``-" "``&" "``|" "``^" "``<<" "``>>" "``*" "``/" "``%" + "`+=")) + +(c-lang-defconst c-overloadable-operators-regexp + ;; Regexp tested after an "operator" token in C++. + t nil + c++ (c-make-keywords-re nil (c-lang-const c-overloadable-operators))) +(c-lang-defvar c-overloadable-operators-regexp + (c-lang-const c-overloadable-operators-regexp)) + +(c-lang-defconst c-other-op-syntax-tokens + "List of the tokens made up of characters in the punctuation or +parenthesis syntax classes that have uses other than as expression +operators." + t '("{" "}" "(" ")" "[" "]" ";" ":" "," "=" "/*" "*/" "//") + (c c++ pike) (append '("#" "##" ; Used by cpp. + "::" "...") + (c-lang-const c-other-op-syntax-tokens)) + (c c++) (append '("<%" "%>" "<:" ":>" "%:" "%:%:" "*") + (c-lang-const c-other-op-syntax-tokens)) + c++ (append '("&") (c-lang-const c-other-op-syntax-tokens)) + objc (append '("#" "##" ; Used by cpp. + "+" "-") (c-lang-const c-other-op-syntax-tokens)) + idl (append '("#" "##") ; Used by cpp. + (c-lang-const c-other-op-syntax-tokens)) + pike (append '("..") + (c-lang-const c-other-op-syntax-tokens) + (c-lang-const c-overloadable-operators)) + awk '("{" "}" "(" ")" "[" "]" ";" "," "=" "/")) + +(c-lang-defconst c-nonsymbol-token-regexp + ;; Regexp matching all tokens in the punctuation and parenthesis + ;; syntax classes. Note that this also matches ".", which can start + ;; a float. + t (c-make-keywords-re nil + (c-with-syntax-table (c-lang-const c-mode-syntax-table) + (mapcan (lambda (op) + (if (string-match "\\`\\(\\s.\\|\\s\(\\|\\s\)\\)+\\'" op) + (list op))) + (append (c-lang-const c-other-op-syntax-tokens) + (c-lang-const c-operator-list)))))) +(c-lang-defvar c-nonsymbol-token-regexp + (c-lang-const c-nonsymbol-token-regexp)) + +(c-lang-defconst c-<-op-cont-regexp + ;; Regexp matching the second and subsequent characters of all + ;; multicharacter tokens that begin with "<". + t (c-make-keywords-re nil + (mapcan (lambda (op) + (if (string-match "\\`<." op) + (list (substring op 1)))) + (append (c-lang-const c-other-op-syntax-tokens) + (c-lang-const c-operator-list))))) +(c-lang-defvar c-<-op-cont-regexp (c-lang-const c-<-op-cont-regexp)) -;;;###autoload -(defvar java-mode-syntax-table nil - "Syntax table used in java-mode buffers.") -(if java-mode-syntax-table - () - (setq java-mode-syntax-table (make-syntax-table)) - (c-populate-syntax-table java-mode-syntax-table)) +(c-lang-defconst c->-op-cont-regexp + ;; Regexp matching the second and subsequent characters of all + ;; multicharacter tokens that begin with ">". + t (c-make-keywords-re nil + (mapcan (lambda (op) + (if (string-match "\\`>." op) + (list (substring op 1)))) + (append (c-lang-const c-other-op-syntax-tokens) + (c-lang-const c-operator-list))))) +(c-lang-defvar c->-op-cont-regexp (c-lang-const c->-op-cont-regexp)) + +(c-lang-defconst c-stmt-delim-chars + ;; The characters that should be considered to bound statements. To + ;; optimize `c-crosses-statement-barrier-p' somewhat, it's assumed to + ;; begin with "^" to negate the set. If ? : operators should be + ;; detected then the string must end with "?:". + t "^;{}?:" + awk "^;{}\n\r?:") ; The newline chars gets special treatment. +(c-lang-defvar c-stmt-delim-chars (c-lang-const c-stmt-delim-chars)) + +(c-lang-defconst c-stmt-delim-chars-with-comma + ;; Variant of `c-stmt-delim-chars' that additionally contains ','. + t "^;,{}?:" + awk "^;,{}\n\r?:") ; The newline chars gets special treatment. +(c-lang-defvar c-stmt-delim-chars-with-comma + (c-lang-const c-stmt-delim-chars-with-comma)) + + +;;; Syntactic whitespace. + +(c-lang-defconst c-comment-start-regexp + ;; Regexp to match the start of any type of comment. + ;; + ;; TODO: Ought to use `c-comment-prefix-regexp' with some + ;; modifications instead of this. + t "/[/*]" + awk "#") +(c-lang-defvar c-comment-start-regexp (c-lang-const c-comment-start-regexp)) + +(c-lang-defconst c-literal-start-regexp + ;; Regexp to match the start of comments and string literals. + t (concat (c-lang-const c-comment-start-regexp) + "\\|" + (if (memq 'gen-string-delim c-emacs-features) + "\"|" + "\""))) +(c-lang-defvar c-literal-start-regexp (c-lang-const c-literal-start-regexp)) + +(c-lang-defconst c-doc-comment-start-regexp + "Regexp to match the start of documentation comments." + t "\\<\\>" + ;; From font-lock.el: `doxygen' uses /*! while others use /**. + (c c++ objc) "/\\*[*!]" + java "/\\*\\*" + pike "/[/*]!") +(c-lang-defvar c-doc-comment-start-regexp + (c-lang-const c-doc-comment-start-regexp)) + +(c-lang-defconst comment-start + "String that starts comments inserted with M-; etc. +`comment-start' is initialized from this." + t "// " + c "/* " + awk "# ") +(c-lang-defvar comment-start (c-lang-const comment-start) + 'dont-doc) + +(c-lang-defconst comment-end + "String that ends comments inserted with M-; etc. +`comment-end' is initialized from this." + t "" + c " */") +(c-lang-defvar comment-end (c-lang-const comment-end) + 'dont-doc) + +(c-lang-defconst comment-start-skip + "Regexp to match the start of a comment plus everything up to its body. +`comment-start-skip' is initialized from this." + t "/\\*+ *\\|//+ *" + awk "#+ *") +(c-lang-defvar comment-start-skip (c-lang-const comment-start-skip) + 'dont-doc) + +(c-lang-defconst syntactic-ws-start + "Regexp matching any sequence that can start syntactic whitespace. +The only uncertain case is '#' when there are cpp directives." + t "[ \n\t\r\v\f#]\\|/[/*]\\|\\\\[\n\r]" + awk "[ \n\t\r\v\f#]\\|\\\\[\n\r]") +(c-lang-defvar c-syntactic-ws-start (c-lang-const syntactic-ws-start) + 'dont-doc) + +(c-lang-defconst syntactic-ws-end + "Regexp matching any single character that might end syntactic whitespace." + t "[ \n\t\r\v\f/]" + awk "[ \n\t\r\v\f]") +(c-lang-defvar c-syntactic-ws-end (c-lang-const syntactic-ws-end) + 'dont-doc) -;;;###autoload -(defvar idl-mode-syntax-table nil - "Syntax table used in idl-mode buffers.") -(if idl-mode-syntax-table - nil - (setq idl-mode-syntax-table (make-syntax-table)) - (c-populate-syntax-table idl-mode-syntax-table)) +(c-lang-defconst c-nonwhite-syntactic-ws + ;; Regexp matching a piece of syntactic whitespace that isn't a + ;; sequence of simple whitespace characters. As opposed to + ;; `c-(forward|backward)-syntactic-ws', this doesn't regard cpp + ;; directives as syntactic whitespace. + t (concat "/" (concat + "\\(" + "/[^\n\r]*[\n\r]" ; Line comment. + "\\|" + ;; Block comment. We intentionally don't allow line + ;; breaks in them to avoid going very far and risk + ;; running out of regexp stack; this regexp is + ;; intended to handle only short comments that + ;; might be put in the middle of limited constructs + ;; like declarations. + "\\*\\([^*\n\r]\\|\\*[^/\n\r]\\)*\\*/" + "\\)") + "\\|" + "\\\\[\n\r]") ; Line continuations. + awk ("#.*[\n\r]\\|\\\\[\n\r]")) + +(c-lang-defconst c-syntactic-ws + ;; Regexp matching syntactic whitespace, including possibly the + ;; empty string. As opposed to `c-(forward|backward)-syntactic-ws', + ;; this doesn't regard cpp directives as syntactic whitespace. Does + ;; not contain a \| operator at the top level. + t (concat "[ \t\n\r\f\v]*\\(" + "\\(" (c-lang-const c-nonwhite-syntactic-ws) "\\)" + "[ \t\n\r\f\v]*\\)*")) + +(c-lang-defconst c-syntactic-ws-depth + ;; Number of regexp grouping parens in `c-syntactic-ws'. + t (c-regexp-opt-depth (c-lang-const c-syntactic-ws))) + +(c-lang-defconst c-nonempty-syntactic-ws + ;; Regexp matching syntactic whitespace, which is at least one + ;; character long. As opposed to `c-(forward|backward)-syntactic-ws', + ;; this doesn't regard cpp directives as syntactic whitespace. Does + ;; not contain a \| operator at the top level. + t (concat "\\([ \t\n\r\f\v]\\|" + (c-lang-const c-nonwhite-syntactic-ws) + "\\)+")) + +(c-lang-defconst c-nonempty-syntactic-ws-depth + ;; Number of regexp grouping parens in `c-nonempty-syntactic-ws'. + t (c-regexp-opt-depth (c-lang-const c-nonempty-syntactic-ws))) -;;;###autoload -(defvar pike-mode-syntax-table nil - "Syntax table used in pike-mode buffers.") -(if pike-mode-syntax-table - () - (setq pike-mode-syntax-table (make-syntax-table)) - (c-populate-syntax-table pike-mode-syntax-table) - (modify-syntax-entry ?@ "." pike-mode-syntax-table)) +(c-lang-defconst c-single-line-syntactic-ws + ;; Regexp matching syntactic whitespace without any line breaks. As + ;; opposed to `c-(forward|backward)-syntactic-ws', this doesn't + ;; regard cpp directives as syntactic whitespace. Does not contain + ;; a \| operator at the top level. + t (concat "[ \t]*\\(" + "/\\*\\([^*\n\r]\\|\\*[^/\n\r]\\)*\\*/" ; Block comment + "[ \t]*\\)*") + awk ("[ \t]*\\(#.*$\\)?")) + +(c-lang-defconst c-single-line-syntactic-ws-depth + ;; Number of regexp grouping parens in `c-single-line-syntactic-ws'. + t (c-regexp-opt-depth (c-lang-const c-single-line-syntactic-ws))) + +(c-lang-defvar c-syntactic-eol + ;; Regexp that matches when there is no syntactically significant + ;; text before eol. Macros are regarded as syntactically + ;; significant text here. + (concat (concat + ;; Match horizontal whitespace and block comments that + ;; don't contain newlines. + "\\(\\s \\|" + (concat "/\\*" + "\\([^*\n\r]\\|\\*[^/\n\r]\\)*" + "\\*/") + "\\)*") + (concat + ;; Match eol (possibly inside a block comment or preceded + ;; by a line continuation backslash), or the beginning of a + ;; line comment. Note: This has to be modified for awk + ;; where line comments start with '#'. + "\\(" + (concat "\\(" + "/\\*\\([^*\n\r]\\|\\*[^/\n\r]\\)*" + "\\|" + "\\\\" + "\\)?" + "$") + "\\|//\\)"))) + + +;;; In-comment text handling. + +(c-lang-defconst c-paragraph-start + "Regexp to append to `paragraph-start'." + t "$" + java "\\(@[a-zA-Z]+\\>\\|$\\)" ; For Javadoc. + pike "\\(@[a-zA-Z_-]+\\>\\([^{]\\|$\\)\\|$\\)") ; For Pike refdoc. +(c-lang-defvar c-paragraph-start (c-lang-const c-paragraph-start)) + +(c-lang-defconst c-paragraph-separate + "Regexp to append to `paragraph-separate'." + t "$" + pike (c-lang-const c-paragraph-start)) +(c-lang-defvar c-paragraph-separate (c-lang-const c-paragraph-separate)) -;; internal state variables +;;; Keyword lists. + +;; Note: All and only all language constants containing keyword lists +;; should end with "-kwds"; they're automatically collected into the +;; `c-kwds-lang-consts' list below and used to build `c-keywords' etc. + +(c-lang-defconst c-primitive-type-kwds + "Primitive type keywords. As opposed to the other keyword lists, the +keywords listed here are fontified with the type face instead of the +keyword face. + +If any of these also are on `c-type-list-kwds', `c-ref-list-kwds', +`c-colon-type-list-kwds', `c-paren-nontype-kwds', `c-paren-type-kwds', +`c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses +will be handled. + +Do not try to modify this list for end user customizations; the +`*-font-lock-extra-types' variable, where `*' is the mode prefix, is +the appropriate place for that." + t '("char" "double" "float" "int" "long" "short" "signed" + "unsigned" "void") + c (append + '("_Bool" "_Complex" "_Imaginary") ; Conditionally defined in C99. + (c-lang-const c-primitive-type-kwds)) + c++ (append + '("bool" "wchar_t") + (c-lang-const c-primitive-type-kwds)) + ;; Objective-C extends C, but probably not the new stuff in C99. + objc (append + '("id" "Class" "SEL" "IMP" "BOOL") + (c-lang-const c-primitive-type-kwds)) + java '("boolean" "byte" "char" "double" "float" "int" "long" "short" "void") + idl '("Object" "ValueBase" "any" "boolean" "char" "double" "fixed" "float" + "long" "octet" "sequence" "short" "string" "void" "wchar" "wstring" + ;; In CORBA PSDL: + "ref" + ;; The following can't really end a type, but we have to specify them + ;; here due to the assumption in `c-primitive-type-prefix-kwds'. It + ;; doesn't matter that much. + "unsigned" "strong") + pike '(;; this_program isn't really a keyword, but it's practically + ;; used as a builtin type. + "array" "float" "function" "int" "mapping" "mixed" "multiset" + "object" "program" "string" "this_program" "void")) + +(c-lang-defconst c-primitive-type-key + ;; An adorned regexp that matches `c-primitive-type-kwds'. + t (c-make-keywords-re t (c-lang-const c-primitive-type-kwds))) +(c-lang-defvar c-primitive-type-key (c-lang-const c-primitive-type-key)) + +(c-lang-defconst c-primitive-type-prefix-kwds + "Keywords that might act as prefixes for primitive types. Assumed to +be a subset of `c-primitive-type-kwds'." + t nil + (c c++) '("long" "short" "signed" "unsigned") + idl '("long" "unsigned" + ;; In CORBA PSDL: + "strong")) + +(c-lang-defconst c-type-prefix-kwds + "Keywords where the following name - if any - is a type name, and +where the keyword together with the symbol works as a type in +declarations. + +Note that an alternative if the second part doesn't hold is +`c-type-list-kwds'. Keywords on this list are typically also present +on one of the `*-decl-kwds' lists." + t nil + c '("struct" "union" "enum") + c++ (append '("class" "typename") + (c-lang-const c-type-prefix-kwds c))) + +(c-lang-defconst c-type-prefix-key + ;; Adorned regexp matching `c-type-prefix-kwds'. + t (c-make-keywords-re t (c-lang-const c-type-prefix-kwds))) +(c-lang-defvar c-type-prefix-key (c-lang-const c-type-prefix-key)) + +(c-lang-defconst c-type-modifier-kwds + "Type modifier keywords. These can occur almost anywhere in types +but they don't build a type of themselves. Unlike the keywords on +`c-primitive-type-kwds', they are fontified with the keyword face and +not the type face." + t nil + c '("const" "restrict" "volatile") + c++ '("const" "volatile" "throw") + objc '("const" "volatile")) + +(c-lang-defconst c-opt-type-modifier-key + ;; Adorned regexp matching `c-type-modifier-kwds', or nil in + ;; languages without such keywords. + t (and (c-lang-const c-type-modifier-kwds) + (c-make-keywords-re t (c-lang-const c-type-modifier-kwds)))) +(c-lang-defvar c-opt-type-modifier-key (c-lang-const c-opt-type-modifier-key)) + +(c-lang-defconst c-opt-type-component-key + ;; An adorned regexp that matches `c-primitive-type-prefix-kwds' and + ;; `c-type-modifier-kwds', or nil in languages without any of them. + t (and (or (c-lang-const c-primitive-type-prefix-kwds) + (c-lang-const c-type-modifier-kwds)) + (c-make-keywords-re t + (append (c-lang-const c-primitive-type-prefix-kwds) + (c-lang-const c-type-modifier-kwds))))) +(c-lang-defvar c-opt-type-component-key + (c-lang-const c-opt-type-component-key)) + +(c-lang-defconst c-class-decl-kwds + "Keywords introducing declarations where the following block (if any) +contains another declaration level that should be considered a class. + +If any of these also are on `c-type-list-kwds', `c-ref-list-kwds', +`c-colon-type-list-kwds', `c-paren-nontype-kwds', `c-paren-type-kwds', +`c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses +will be handled. + +Note that presence on this list does not automatically treat the +following identifier as a type; the keyword must also be present on +`c-type-prefix-kwds' or `c-type-list-kwds' to accomplish that." + t nil + c '("struct" "union") + c++ '("class" "struct" "union") + objc '("struct" "union" + "@interface" "@implementation" "@protocol") + java '("class" "interface") + idl '("component" "eventtype" "exception" "home" "interface" "struct" + "union" "valuetype" + ;; In CORBA PSDL: + "storagehome" "storagetype" + ;; In CORBA CIDL: + "catalog" "executor" "manages" "segment") + pike '("class")) + +(c-lang-defconst c-class-key + ;; Regexp matching the start of a class. + t (c-make-keywords-re t (c-lang-const c-class-decl-kwds))) +(c-lang-defvar c-class-key (c-lang-const c-class-key)) + +(c-lang-defconst c-brace-list-decl-kwds + "Keywords introducing declarations where the following block (if +any) is a brace list. + +If any of these also are on `c-type-list-kwds', `c-ref-list-kwds', +`c-colon-type-list-kwds', `c-paren-nontype-kwds', `c-paren-type-kwds', +`c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses +will be handled." + t '("enum") + (java awk) nil) + +(c-lang-defconst c-brace-list-key + ;; Regexp matching the start of declarations where the following + ;; block is a brace list. + t (c-make-keywords-re t (c-lang-const c-brace-list-decl-kwds))) +(c-lang-defvar c-brace-list-key (c-lang-const c-brace-list-key)) + +(c-lang-defconst c-other-block-decl-kwds + "Keywords where the following block (if any) contain another +declaration level that should not be considered a class. + +If any of these also are on `c-type-list-kwds', `c-ref-list-kwds', +`c-colon-type-list-kwds', `c-paren-nontype-kwds', `c-paren-type-kwds', +`c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses +will be handled." + t nil + c '("extern") + c++ '("namespace" "extern") + idl '("module" + ;; In CORBA CIDL: + "composition")) + +(c-lang-defconst c-other-decl-block-key + ;; Regexp matching the start of blocks besides classes that contain + ;; another declaration level. + t (c-make-keywords-re t (c-lang-const c-other-block-decl-kwds))) +(c-lang-defvar c-other-decl-block-key (c-lang-const c-other-decl-block-key)) + +(c-lang-defconst c-typedef-decl-kwds + "Keywords introducing declarations where the identifiers are defined +to be types. + +If any of these also are on `c-type-list-kwds', `c-ref-list-kwds', +`c-colon-type-list-kwds', `c-paren-nontype-kwds', `c-paren-type-kwds', +`c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses +will be handled." + t '("typedef") + (java awk) nil) + +(c-lang-defconst c-typeless-decl-kwds + "Keywords introducing declarations where the identifier (declarator) +list follows directly after the keyword, without any type. + +If any of these also are on `c-type-list-kwds', `c-ref-list-kwds', +`c-colon-type-list-kwds', `c-paren-nontype-kwds', `c-paren-type-kwds', +`c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses +will be handled." + t nil + ;; Unlike most other languages, exception names are not handled as + ;; types in IDL since they only can occur in "raises" specs. + idl '("exception" "factory" "finder" "native" + ;; In CORBA PSDL: + "key" "stores" + ;; In CORBA CIDL: + ;; Note that "manages" here clashes with its presence on + ;; `c-type-list-kwds' for IDL. + "executor" "facet" "manages" "segment") + pike '("constant")) + +(c-lang-defconst c-modifier-kwds + "Keywords that can prefix normal declarations of identifiers +\(and typically acts as flags). Things like argument declarations +inside function headers are also considered declarations in this +sense. + +If any of these also are on `c-type-list-kwds', `c-ref-list-kwds', +`c-colon-type-list-kwds', `c-paren-nontype-kwds', `c-paren-type-kwds', +`c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses +will be handled." + t nil + (c c++) '("auto" "extern" "inline" "register" "static") + c++ (append '("explicit" "friend" "mutable" "template" "using" "virtual") + (c-lang-const c-modifier-kwds)) + objc '("auto" "bycopy" "byref" "extern" "in" "inout" "oneway" "out" "static") + ;; FIXME: Some of those below ought to be on `c-other-decl-kwds' instead. + idl '("abstract" "attribute" "const" "consumes" "custom" "emits" "import" + "in" "inout" "local" "multiple" "oneway" "out" "private" "provides" + "public" "publishes" "readonly" "typeid" "typeprefix" "uses" + ;; In CORBA PSDL: + "primary" "state" + ;; In CORBA CIDL: + "bindsTo" "delegatesTo" "implements" "proxy" "storedOn") + ;; Note: "const" is not used in Java, but it's still a reserved keyword. + java '("abstract" "const" "final" "native" "private" "protected" "public" + "static" "strictfp" "synchronized" "transient" "volatile") + pike '("final" "inline" "local" "nomask" "optional" "private" "protected" + "public" "static" "variant")) + +(c-lang-defconst c-other-decl-kwds + "Keywords that can start or prefix any declaration level construct, +besides those on `c-class-decl-kwds', `c-brace-list-decl-kwds', +`c-other-block-decl-kwds', `c-typedef-decl-kwds', +`c-typeless-decl-kwds' and `c-modifier-kwds'. In a declaration, these +keywords are also recognized inside or after the identifiers that +makes up the type. + +If any of these also are on `c-type-list-kwds', `c-ref-list-kwds', +`c-colon-type-list-kwds', `c-paren-nontype-kwds', `c-paren-type-kwds', +`c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses +will be handled." + t nil + (c c++) '("__declspec") ; MSVC extension. + objc '("@class" "@end" "@defs") + java '("import" "package") + pike '("import" "inherit")) + +(c-lang-defconst c-specifier-key + ;; Adorned regexp matching keywords that can start a declaration but + ;; not a type. + t (c-make-keywords-re t + (set-difference (append (c-lang-const c-class-decl-kwds) + (c-lang-const c-brace-list-decl-kwds) + (c-lang-const c-other-block-decl-kwds) + (c-lang-const c-typedef-decl-kwds) + (c-lang-const c-typeless-decl-kwds) + (c-lang-const c-modifier-kwds) + (c-lang-const c-other-decl-kwds)) + (append (c-lang-const c-primitive-type-kwds) + (c-lang-const c-type-prefix-kwds) + (c-lang-const c-type-modifier-kwds)) + :test 'string-equal))) +(c-lang-defvar c-specifier-key (c-lang-const c-specifier-key)) + +(c-lang-defconst c-protection-kwds + "Protection label keywords in classes." + t nil + c++ '("private" "protected" "public") + objc '("@private" "@protected" "@public")) + +(c-lang-defconst c-opt-access-key + ;; Regexp matching an access protection label in a class, or nil in + ;; languages that don't have such things. + t (if (c-lang-const c-protection-kwds) + (c-make-keywords-re t (c-lang-const c-protection-kwds))) + c++ (concat "\\(" + (c-make-keywords-re nil (c-lang-const c-protection-kwds)) + "\\)[ \t\n\r\f\v]*:")) +(c-lang-defvar c-opt-access-key (c-lang-const c-opt-access-key)) + +(c-lang-defconst c-block-decls-with-vars + "Keywords introducing declarations that can contain a block which +might be followed by variable declarations, e.g. like \"foo\" in +\"class Foo { ... } foo;\". So if there is a block in a declaration +like that, it ends with the following ';' and not right away. + +The keywords on list are assumed to also be present on one of the +`*-decl-kwds' lists." + t nil + (c objc) '("struct" "union" "enum" "typedef") + c++ '("class" "struct" "union" "enum" "typedef")) + +(c-lang-defconst c-opt-block-decls-with-vars-key + ;; Regexp matching the `c-block-decls-with-vars' keywords, or nil in + ;; languages without such constructs. + t (and (c-lang-const c-block-decls-with-vars) + (c-make-keywords-re t (c-lang-const c-block-decls-with-vars)))) +(c-lang-defvar c-opt-block-decls-with-vars-key + (c-lang-const c-opt-block-decls-with-vars-key)) + +(c-lang-defconst c-postfix-decl-spec-kwds + "Keywords introducing extra declaration specifiers in the region +between the header and the body \(i.e. the \"K&R-region\") in +declarations." + t nil + (c c++) '("__attribute__") ; GCC extension. + java '("extends" "implements" "throws") + idl '("context" "getraises" "manages" "primarykey" "raises" "setraises" + "supports" + ;; In CORBA PSDL: + "as" "const" "implements" "of" "ref")) -;; Internal state of hungry delete key feature -(defvar c-hungry-delete-key nil) -(make-variable-buffer-local 'c-hungry-delete-key) +(c-lang-defconst c-nonsymbol-sexp-kwds + "Keywords that may be followed by a nonsymbol sexp before whatever +construct it's part of continues." + t nil + (c c++ objc) '("extern")) + +(c-lang-defconst c-type-list-kwds + "Keywords that may be followed by a comma separated list of type +identifiers, where each optionally can be prefixed by keywords. (Can +also be used for the special case when the list can contain only one +element.) + +Assumed to be mutually exclusive with `c-ref-list-kwds'. There's no +reason to put keywords on this list if they are on `c-type-prefix-kwds'. +There's also no reason to add keywords that prefixes a normal +declaration consisting of a type followed by a declarator (list), so +the keywords on `c-modifier-kwds' should normally not be listed here +too. + +Note: Use `c-typeless-decl-kwds' for keywords followed by a function +or variable identifier (that's being defined)." + t '("struct" "union" "enum") + (c c++ awk) nil + objc (append '("@class" "@interface" "@implementation" "@protocol") + (c-lang-const c-type-list-kwds)) + java '("class" "import" "interface" "new" "extends" "implements" "throws") + idl (append '("component" "eventtype" "home" "interface" "manages" "native" + "primarykey" "supports" "valuetype" + ;; In CORBA PSDL: + "as" "implements" "of" "scope" "storagehome" "storagetype") + (c-lang-const c-type-list-kwds)) + pike '("class" "enum" "inherit")) + +(c-lang-defconst c-ref-list-kwds + "Keywords that may be followed by a comma separated list of +reference (i.e. namespace/scope/module) identifiers, where each +optionally can be prefixed by keywords. (Can also be used for the +special case when the list can contain only one element.) Assumed to +be mutually exclusive with `c-type-list-kwds'. + +Note: Use `c-typeless-decl-kwds' for keywords followed by a function +or variable identifier (that's being defined)." + t nil + c++ '("namespace") + java '("package") + idl '("import" "module" + ;; In CORBA CIDL: + "composition") + pike '("import")) + +(c-lang-defconst c-colon-type-list-kwds + "Keywords that may be followed (not necessarily directly) by a colon +and then a comma separated list of type identifiers, where each +optionally can be prefixed by keywords. (Can also be used for the +special case when the list can contain only one element.)" + t nil + c++ '("class" "struct") + idl '("component" "eventtype" "home" "interface" "valuetype" + ;; In CORBA PSDL: + "storagehome" "storagetype")) + +(c-lang-defconst c-colon-type-list-re + "Regexp matched after the keywords in `c-colon-type-list-kwds' to skip +forward to the colon. The end of the match is assumed to be directly +after the colon, so the regexp should end with \":\" although that +isn't necessary. Must be a regexp if `c-colon-type-list-kwds' isn't +nil." + t (if (c-lang-const c-colon-type-list-kwds) + ;; Disallow various common punctuation chars that can't come + ;; before the ":" that starts the inherit list after "class" + ;; or "struct" in C++. (Also used as default for other + ;; languages.) + "[^\]\[{}();,/#=:]*:")) +(c-lang-defvar c-colon-type-list-re (c-lang-const c-colon-type-list-re)) + +(c-lang-defconst c-paren-nontype-kwds + "Keywords that may be followed by a parenthesis expression that doesn't +contain type identifiers." + t nil + (c c++) '("__declspec")) ; MSVC extension. + +(c-lang-defconst c-paren-type-kwds + "Keywords that may be followed by a parenthesis expression containing +type identifiers separated by arbitrary tokens." + t nil + c++ '("throw") + objc '("@defs") + idl '("switch") + pike '("array" "function" "int" "mapping" "multiset" "object" "program")) + +(c-lang-defconst c-paren-any-kwds + t (delete-duplicates (append (c-lang-const c-paren-nontype-kwds) + (c-lang-const c-paren-type-kwds)) + :test 'string-equal)) + +(c-lang-defconst c-<>-type-kwds + "Keywords that may be followed by an angle bracket expression +containing type identifiers separated by \",\". The difference from +`c-<>-arglist-kwds' is that unknown names are taken to be types and +not other identifiers. `c-recognize-<>-arglists' is assumed to be set +if this isn't nil." + t nil + objc '("id") + idl '("sequence" + ;; In CORBA PSDL: + "ref")) + +(c-lang-defconst c-<>-arglist-kwds + "Keywords that can be followed by a C++ style template arglist; see +`c-recognize-<>-arglists' for details. That language constant is +assumed to be set if this isn't nil." + t nil + c++ '("template") + idl '("fixed" "string" "wstring")) + +(c-lang-defconst c-<>-sexp-kwds + ;; All keywords that can be followed by an angle bracket sexp. + t (delete-duplicates (append (c-lang-const c-<>-type-kwds) + (c-lang-const c-<>-arglist-kwds)) + :test 'string-equal)) + +(c-lang-defconst c-opt-<>-sexp-key + ;; Adorned regexp matching keywords that can be followed by an angle + ;; bracket sexp. + t (if (c-lang-const c-recognize-<>-arglists) + (c-make-keywords-re t (c-lang-const c-<>-sexp-kwds)))) +(c-lang-defvar c-opt-<>-sexp-key (c-lang-const c-opt-<>-sexp-key)) + +(c-lang-defconst c-brace-id-list-kwds + "Keywords that may be followed by a brace block containing a comma +separated list of identifier definitions, i.e. like the list of +identifiers that follows the type in a normal declaration." + t (c-lang-const c-brace-list-decl-kwds)) + +(c-lang-defconst c-block-stmt-1-kwds + "Statement keywords followed directly by a substatement." + t '("do" "else") + c++ '("do" "else" "try") + java '("do" "else" "finally" "try") + idl nil) + +(c-lang-defconst c-block-stmt-1-key + ;; Regexp matching the start of any statement followed directly by a + ;; substatement (doesn't match a bare block, however). + t (c-make-keywords-re t (c-lang-const c-block-stmt-1-kwds))) +(c-lang-defvar c-block-stmt-1-key (c-lang-const c-block-stmt-1-key)) + +(c-lang-defconst c-block-stmt-2-kwds + "Statement keywords followed by a paren sexp and then by a substatement." + t '("for" "if" "switch" "while") + c++ '("for" "if" "switch" "while" "catch") + java '("for" "if" "switch" "while" "catch" "synchronized") + idl nil + pike '("for" "if" "switch" "while" "foreach") + awk '("for" "if" "while")) + +(c-lang-defconst c-block-stmt-2-key + ;; Regexp matching the start of any statement followed by a paren sexp + ;; and then by a substatement. + t (c-make-keywords-re t (c-lang-const c-block-stmt-2-kwds))) +(c-lang-defvar c-block-stmt-2-key (c-lang-const c-block-stmt-2-key)) + +(c-lang-defconst c-opt-block-stmt-key + ;; Regexp matching the start of any statement that has a + ;; substatement (except a bare block). Nil in languages that + ;; don't have such constructs. + t (if (or (c-lang-const c-block-stmt-1-kwds) + (c-lang-const c-block-stmt-2-kwds)) + (c-make-keywords-re t + (append (c-lang-const c-block-stmt-1-kwds) + (c-lang-const c-block-stmt-2-kwds))))) +(c-lang-defvar c-opt-block-stmt-key (c-lang-const c-opt-block-stmt-key)) + +(c-lang-defconst c-simple-stmt-kwds + "Statement keywords followed by an expression or nothing." + t '("break" "continue" "goto" "return") + ;; Note: `goto' is not valid in Java, but the keyword is still reserved. + java '("break" "continue" "goto" "return" "throw") + idl nil + pike '("break" "continue" "return") + awk '(;; Not sure about "delete", "exit", "getline", etc. ; ACM 2002/5/30 + "break" "continue" "return" "delete" "exit" "getline" "next" + "nextfile" "print" "printf")) + +(c-lang-defconst c-simple-stmt-key + ;; Adorned regexp matching `c-simple-stmt-kwds'. + t (c-make-keywords-re t (c-lang-const c-simple-stmt-kwds))) +(c-lang-defvar c-simple-stmt-key (c-lang-const c-simple-stmt-key)) + +(c-lang-defconst c-paren-stmt-kwds + "Statement keywords followed by a parenthesis expression that +nevertheless contains a list separated with ';' and not ','." + t '("for") + idl nil) + +(c-lang-defconst c-paren-stmt-key + ;; Adorned regexp matching `c-paren-stmt-kwds'. + t (c-make-keywords-re t (c-lang-const c-paren-stmt-kwds))) +(c-lang-defvar c-paren-stmt-key (c-lang-const c-paren-stmt-key)) + +(c-lang-defconst c-asm-stmt-kwds + "Statement keywords followed by an assembler expression." + t nil + (c c++) '("asm" "__asm__")) ;; Not standard, but common. + +(c-lang-defconst c-opt-asm-stmt-key + ;; Regexp matching the start of an assembler statement. Nil in + ;; languages that don't support that. + t (if (c-lang-const c-asm-stmt-kwds) + (c-make-keywords-re t (c-lang-const c-asm-stmt-kwds)))) +(c-lang-defvar c-opt-asm-stmt-key (c-lang-const c-opt-asm-stmt-key)) + +(c-lang-defconst c-label-kwds + "Keywords introducing labels in blocks." + t '("case" "default") + awk nil) + +(c-lang-defconst c-before-label-kwds + "Keywords that might be followed by a label identifier." + t '("goto") + (java pike) (append '("break" "continue") + (c-lang-const c-before-label-kwds)) + idl nil + awk nil) + +(c-lang-defconst c-label-kwds-regexp + ;; Regexp matching any keyword that introduces a label. + t (c-make-keywords-re t (c-lang-const c-label-kwds))) +(c-lang-defvar c-label-kwds-regexp (c-lang-const c-label-kwds-regexp)) + +(c-lang-defconst c-constant-kwds + "Keywords for constants." + t nil + (c c++) '("NULL" ;; Not a keyword, but practically works as one. + "false" "true") ; Defined in C99. + objc '("nil" "Nil") + idl '("TRUE" "FALSE") + pike '("UNDEFINED")) ;; Not a keyword, but practically works as one. + +(c-lang-defconst c-primary-expr-kwds + "Keywords besides constants and operators that start primary expressions." + t nil + c++ '("operator" "this") + objc '("super" "self") + java '("this") + pike '("this")) ;; Not really a keyword, but practically works as one. + +(c-lang-defconst c-expr-kwds + ;; Keywords that can occur anywhere in expressions. Built from + ;; `c-primary-expr-kwds' and all keyword operators in `c-operators'. + t (delete-duplicates + (append (c-lang-const c-primary-expr-kwds) + (c-with-syntax-table (c-lang-const c-mode-syntax-table) + (mapcan (lambda (op) + (and (string-match "\\`\\(\\w\\|\\s_\\)+\\'" op) + (list op))) + (c-lang-const c-operator-list)))) + :test 'string-equal)) + +(c-lang-defconst c-lambda-kwds + "Keywords that start lambda constructs, i.e. function definitions in +expressions." + t nil + pike '("lambda")) + +(c-lang-defconst c-opt-lambda-key + ;; Adorned regexp matching the start of lambda constructs, or nil in + ;; languages that don't have such things. + t (and (c-lang-const c-lambda-kwds) + (c-make-keywords-re t (c-lang-const c-lambda-kwds)))) +(c-lang-defvar c-opt-lambda-key (c-lang-const c-opt-lambda-key)) + +(c-lang-defconst c-inexpr-block-kwds + "Keywords that start constructs followed by statement blocks which can +be used in expressions \(the gcc extension for this in C and C++ is +handled separately)." + t nil + pike '("catch" "gauge")) + +(c-lang-defconst c-opt-inexpr-block-key + ;; Regexp matching the start of in-expression statements, or nil in + ;; languages that don't have such things. + t nil + pike (c-make-keywords-re t (c-lang-const c-inexpr-block-kwds))) +(c-lang-defvar c-opt-inexpr-block-key (c-lang-const c-opt-inexpr-block-key)) + +(c-lang-defconst c-inexpr-class-kwds + "Keywords that can start classes inside expressions." + t nil + java '("new") + pike '("class")) + +(c-lang-defconst c-opt-inexpr-class-key + ;; Regexp matching the start of a class in an expression, or nil in + ;; languages that don't have such things. + t (and (c-lang-const c-inexpr-class-kwds) + (c-make-keywords-re t (c-lang-const c-inexpr-class-kwds)))) +(c-lang-defvar c-opt-inexpr-class-key (c-lang-const c-opt-inexpr-class-key)) + +(c-lang-defconst c-inexpr-brace-list-kwds + "Keywords that can start brace list blocks inside expressions. +Note that Java specific rules are currently applied to tell this from +`c-inexpr-class-kwds'." + t nil + java '("new")) + +(c-lang-defconst c-opt-inexpr-brace-list-key + ;; Regexp matching the start of a brace list in an expression, or + ;; nil in languages that don't have such things. This should not + ;; match brace lists recognized through `c-special-brace-lists'. + t (and (c-lang-const c-inexpr-brace-list-kwds) + (c-make-keywords-re t (c-lang-const c-inexpr-brace-list-kwds)))) +(c-lang-defvar c-opt-inexpr-brace-list-key + (c-lang-const c-opt-inexpr-brace-list-key)) + +(c-lang-defconst c-any-class-key + ;; Regexp matching the start of any class, both at top level and in + ;; expressions. + t (c-make-keywords-re t + (append (c-lang-const c-class-decl-kwds) + (c-lang-const c-inexpr-class-kwds)))) +(c-lang-defvar c-any-class-key (c-lang-const c-any-class-key)) -;; Internal state of auto newline feature. -(defvar c-auto-newline nil) -(make-variable-buffer-local 'c-auto-newline) +(c-lang-defconst c-decl-block-key + ;; Regexp matching the start of any declaration-level block that + ;; contain another declaration level, i.e. that isn't a function + ;; block or brace list. + t (c-make-keywords-re t + (append (c-lang-const c-class-decl-kwds) + (c-lang-const c-other-block-decl-kwds) + (c-lang-const c-inexpr-class-kwds))) + ;; In Pike modifiers might be followed by a block + ;; to apply to several declarations. + pike (concat (c-lang-const c-decl-block-key) + "\\|" + "\\(" (c-make-keywords-re nil + (c-lang-const c-modifier-kwds)) "\\)" + (c-lang-const c-syntactic-ws) + "{")) +(c-lang-defvar c-decl-block-key (c-lang-const c-decl-block-key)) + +(c-lang-defconst c-bitfield-kwds + "Keywords that can introduce bitfields." + t nil + (c c++ objc) '("char" "int" "long" "signed" "unsigned")) + +(c-lang-defconst c-opt-bitfield-key + ;; Regexp matching the start of a bitfield (not uniquely), or nil in + ;; languages without bitfield support. + t nil + (c c++) (c-make-keywords-re t (c-lang-const c-bitfield-kwds))) +(c-lang-defvar c-opt-bitfield-key (c-lang-const c-opt-bitfield-key)) + +(c-lang-defconst c-other-kwds + "Keywords not accounted for by any other `*-kwds' language constant." + t nil + idl '("truncatable" + ;; In CORBA CIDL: (These are declaration keywords that never + ;; can start a declaration.) + "entity" "process" "service" "session" "storage")) + + +;;; Constants built from keywords. + +;; Note: No `*-kwds' language constants may be defined below this point. + +(eval-and-compile + (defconst c-kwds-lang-consts + ;; List of all the language constants that contain keyword lists. + (let (list) + (mapatoms (lambda (sym) + (when (and (boundp sym) + (string-match "-kwds\\'" (symbol-name sym))) + ;; Make the list of globally interned symbols + ;; instead of ones interned in `c-lang-constants'. + (setq list (cons (intern (symbol-name sym)) list)))) + c-lang-constants) + list))) + +(c-lang-defconst c-keywords + ;; All keywords as a list. + t (delete-duplicates + (c-lang-defconst-eval-immediately + `(append ,@(mapcar (lambda (kwds-lang-const) + `(c-lang-const ,kwds-lang-const)) + c-kwds-lang-consts) + nil)) + :test 'string-equal)) + +(c-lang-defconst c-keywords-regexp + ;; All keywords as an adorned regexp. + t (c-make-keywords-re t (c-lang-const c-keywords))) +(c-lang-defvar c-keywords-regexp (c-lang-const c-keywords-regexp)) + +(c-lang-defconst c-keyword-member-alist + ;; An alist with all the keywords in the cars. The cdr for each + ;; keyword is a list of the symbols for the `*-kwds' lists that + ;; contains it. + t (let ((kwd-list-alist + (c-lang-defconst-eval-immediately + `(list ,@(mapcar (lambda (kwds-lang-const) + `(cons ',kwds-lang-const + (c-lang-const ,kwds-lang-const))) + c-kwds-lang-consts)))) + lang-const kwd-list kwd + result-alist elem) + (while kwd-list-alist + (setq lang-const (caar kwd-list-alist) + kwd-list (cdar kwd-list-alist) + kwd-list-alist (cdr kwd-list-alist)) + (while kwd-list + (setq kwd (car kwd-list) + kwd-list (cdr kwd-list)) + (unless (setq elem (assoc kwd result-alist)) + (setq result-alist (cons (setq elem (list kwd)) result-alist))) + (unless (memq lang-const (cdr elem)) + (setcdr elem (cons lang-const (cdr elem)))))) + result-alist)) + +(c-lang-defvar c-keywords-obarray + ;; An obarray containing all keywords as symbols. The property list + ;; of each symbol has a non-nil entry for the specific `*-kwds' + ;; lists it's a member of. + ;; + ;; E.g. to see whether the string str contains a keyword on + ;; `c-class-decl-kwds', one can do like this: + ;; (get (intern-soft str c-keyword-obarray) 'c-class-decl-kwds) + ;; Which preferably is written using the associated functions in + ;; cc-engine: + ;; (c-keyword-member (c-keyword-sym str) 'c-class-decl-kwds) + + ;; The obarray is not stored directly as a language constant since + ;; the printed representation for obarrays used in .elc files isn't + ;; complete. + + (let* ((alist (c-lang-const c-keyword-member-alist)) + kwd lang-const-list + (obarray (make-vector (* (length alist) 2) 0))) + (while alist + (setq kwd (caar alist) + lang-const-list (cdar alist) + alist (cdr alist)) + (setplist (intern kwd obarray) + ;; Emacs has an odd bug that causes `mapcan' to fail + ;; with unintelligible errors. (XEmacs >= 20 works.) + ;;(mapcan (lambda (lang-const) + ;; (list lang-const t)) + ;; lang-const-list) + (apply 'nconc (mapcar (lambda (lang-const) + (list lang-const t)) + lang-const-list)))) + obarray)) + +(c-lang-defconst c-regular-keywords-regexp + ;; Adorned regexp matching all keywords that aren't types or + ;; constants. + t (c-make-keywords-re t + (set-difference (c-lang-const c-keywords) + (append (c-lang-const c-primitive-type-kwds) + (c-lang-const c-constant-kwds)) + :test 'string-equal))) +(c-lang-defvar c-regular-keywords-regexp + (c-lang-const c-regular-keywords-regexp)) + +(c-lang-defconst c-not-decl-init-keywords + ;; Adorned regexp matching all keywords that can't appear at the + ;; start of a declaration. + t (c-make-keywords-re t + (set-difference (c-lang-const c-keywords) + (append (c-lang-const c-primitive-type-kwds) + (c-lang-const c-type-prefix-kwds) + (c-lang-const c-type-modifier-kwds) + (c-lang-const c-class-decl-kwds) + (c-lang-const c-brace-list-decl-kwds) + (c-lang-const c-other-block-decl-kwds) + (c-lang-const c-typedef-decl-kwds) + (c-lang-const c-typeless-decl-kwds) + (c-lang-const c-modifier-kwds) + (c-lang-const c-other-decl-kwds)) + :test 'string-equal))) +(c-lang-defvar c-not-decl-init-keywords + (c-lang-const c-not-decl-init-keywords)) + +(c-lang-defconst c-primary-expr-regexp + ;; Regexp matching the start of any primary expression, i.e. any + ;; literal, symbol, prefix operator, and '('. It doesn't need to + ;; exclude keywords; they are excluded afterwards unless the second + ;; submatch matches. If the first but not the second submatch + ;; matches then it is an ambiguous primary expression; it could also + ;; be a match of e.g. an infix operator. (The case with ambiguous + ;; keyword operators isn't handled.) + + t (c-with-syntax-table (c-lang-const c-mode-syntax-table) + (let* ((prefix-ops + (mapcan (lambda (op) + ;; Filter out the special case prefix + ;; operators that are close parens. + (unless (string-match "\\s\)" op) + (list op))) + (mapcan + (lambda (opclass) + (when (eq (car opclass) 'prefix) + (append (cdr opclass) nil))) + (c-lang-const c-operators)))) + + (nonkeyword-prefix-ops + (mapcan (lambda (op) + (unless (string-match "\\`\\(\\w\\|\\s_\\)+\\'" op) + (list op))) + prefix-ops)) + + (in-or-postfix-ops + (mapcan (lambda (opclass) + (when (memq (car opclass) + '(postfix + left-assoc + right-assoc + right-assoc-sequence)) + (append (cdr opclass) nil))) + (c-lang-const c-operators))) + + (unambiguous-prefix-ops (set-difference nonkeyword-prefix-ops + in-or-postfix-ops + :test 'string-equal)) + (ambiguous-prefix-ops (intersection nonkeyword-prefix-ops + in-or-postfix-ops + :test 'string-equal))) + + (concat + "\\(" + ;; Take out all symbol class operators from `prefix-ops' and make the + ;; first submatch from them together with `c-primary-expr-kwds'. + (c-make-keywords-re t + (append (c-lang-const c-primary-expr-kwds) + (set-difference prefix-ops nonkeyword-prefix-ops + :test 'string-equal))) + + "\\|" + ;; Match all ambiguous operators. + (c-make-keywords-re nil + (intersection nonkeyword-prefix-ops in-or-postfix-ops + :test 'string-equal)) + "\\)" + + "\\|" + ;; Now match all other symbols. + (c-lang-const c-symbol-start) + + "\\|" + ;; The chars that can start integer and floating point + ;; constants. + "\\.?[0-9]" + + "\\|" + ;; The nonambiguous operators from `prefix-ops'. + (c-make-keywords-re nil + (set-difference nonkeyword-prefix-ops in-or-postfix-ops + :test 'string-equal)) + + "\\|" + ;; Match string and character literals. + "\\s\"" + (if (memq 'gen-string-delim c-emacs-features) + "\\|\\s|" + ""))))) +(c-lang-defvar c-primary-expr-regexp (c-lang-const c-primary-expr-regexp)) + + +;;; Additional constants for parser-level constructs. + +(c-lang-defconst c-decl-prefix-re + "Regexp matching something that might precede a declaration or a cast, +such as the last token of a preceding statement or declaration. It +should not match bob, though. It can't require a match longer than +one token. The end of the token is taken to be at the end of the +first submatch. It must not include any following whitespace. It's +undefined whether identifier syntax (see `c-identifier-syntax-table') +is in effect or not." + ;; We match a sequence of characters to skip over things like \"};\" + ;; more quickly. We match ")" in C for K&R region declarations, and + ;; in all languages except Java for when a cpp macro definition + ;; begins with a declaration. + t "\\([\{\}\(\);,]+\\)" + java "\\([\{\}\(;,]+\\)" + ;; Match "<" in C++ to get the first argument in a template arglist. + ;; In that case there's an additional check in `c-find-decl-spots' + ;; that it got open paren syntax. + ;; + ;; Also match a single ":" for protection labels. We cheat a little + ;; and require a symbol immediately before to avoid false matches + ;; when starting directly on a single ":", which can be the start of + ;; the base class initializer list in a constructor. + c++ "\\([\{\}\(\);,<]+\\|\\(\\w\\|\\s_\\):\\)\\([^:]\\|\\'\\)" + ;; Additionally match the protection directives in Objective-C. + ;; Note that this doesn't cope with the longer directives, which we + ;; would have to match from start to end since they don't end with + ;; any easily recognized characters. + objc (concat "\\([\{\}\(\);,]+\\|" + (c-make-keywords-re nil (c-lang-const c-protection-kwds)) + "\\)") + ;; Match ":" for switch labels inside union declarations in IDL. + idl "\\([\{\}\(\);:,]+\\)\\([^:]\\|\\'\\)" + ;; Pike is like C but we also match "[" for multiple value + ;; assignments and type casts. + pike "\\([\{\}\(\)\[;,]+\\)") +(c-lang-defvar c-decl-prefix-re (c-lang-const c-decl-prefix-re) + 'dont-doc) + +(c-lang-defconst c-cast-parens + ;; List containing the paren characters that can open a cast, or nil in + ;; languages without casts. + t (c-with-syntax-table (c-lang-const c-mode-syntax-table) + (mapcan (lambda (opclass) + (when (eq (car opclass) 'prefix) + (mapcan (lambda (op) + (when (string-match "\\`\\s\(\\'" op) + (list (elt op 0)))) + (cdr opclass)))) + (c-lang-const c-operators)))) +(c-lang-defvar c-cast-parens (c-lang-const c-cast-parens)) -;; Internal auto-newline/hungry-delete designation string for mode line. -(defvar c-auto-hungry-string nil) -(make-variable-buffer-local 'c-auto-hungry-string) +(c-lang-defconst c-type-decl-prefix-key + "Regexp matching the operators that might precede the identifier in a +declaration, e.g. the \"*\" in \"char *argv\". This regexp should +match \"(\" if parentheses are valid in type declarations. The end of +the first submatch is taken as the end of the operator. Identifier +syntax is in effect when this is matched (see `c-identifier-syntax-table')." + t (if (c-lang-const c-type-modifier-kwds) + (concat (c-regexp-opt (c-lang-const c-type-modifier-kwds) t) "\\>") + ;; Default to a regexp that never matches. + "\\<\\>") + (c objc) (concat "\\(" + "[*\(]" + "\\|" + (c-lang-const c-type-decl-prefix-key) + "\\)" + "\\([^=]\\|$\\)") + c++ (concat "\\(" + "[*\(&]" + "\\|" + (concat "\\(" ; 2 + ;; If this matches there's special treatment in + ;; `c-font-lock-declarators' and + ;; `c-font-lock-declarations' that check for a + ;; complete name followed by ":: *". + (c-lang-const c-identifier-start) + "\\)") + "\\|" + (c-lang-const c-type-decl-prefix-key) + "\\)" + "\\([^=]\\|$\\)") + pike "\\([*\(!~]\\)\\([^=]\\|$\\)") +(c-lang-defvar c-type-decl-prefix-key (c-lang-const c-type-decl-prefix-key) + 'dont-doc) + +(c-lang-defconst c-type-decl-suffix-key + "Regexp matching the operators that might follow after the identifier +in a declaration, e.g. the \"[\" in \"char argv[]\". This regexp +should match \")\" if parentheses are valid in type declarations. If +it matches an open paren of some kind, the type declaration check +continues at the corresponding close paren, otherwise the end of the +first submatch is taken as the end of the operator. Identifier syntax +is in effect when this is matched (see `c-identifier-syntax-table')." + ;; Default to a regexp that matches `c-type-modifier-kwds' and a + ;; function argument list parenthesis. + t (if (c-lang-const c-type-modifier-kwds) + (concat "\\(\(\\|" + (c-regexp-opt (c-lang-const c-type-modifier-kwds) t) "\\>" + "\\)") + "\\(\(\\)") + (c c++ objc) (concat + "\\(" + "[\)\[\(]" + "\\|" + ;; "throw" in `c-type-modifier-kwds' is followed by a + ;; parenthesis list, but no extra measures are + ;; necessary to handle that. + (c-regexp-opt (c-lang-const c-type-modifier-kwds) t) "\\>" + "\\)") + (java idl) "\\([\[\(]\\)") +(c-lang-defvar c-type-decl-suffix-key (c-lang-const c-type-decl-suffix-key) + 'dont-doc) + +(c-lang-defconst c-after-suffixed-type-decl-key + "This regexp is matched after a type declaration expression where +`c-type-decl-suffix-key' has matched. If it matches then the +construct is taken as a declaration. It's typically used to match the +beginning of a function body or whatever might occur after the +function header in a function declaration or definition. It's +undefined whether identifier syntax (see `c-identifier-syntax-table') +is in effect or not. + +Note that it's used in cases like after \"foo (bar)\" so it should +only match when it's certain that it's a declaration, e.g \"{\" but +not \",\" or \";\"." + t "{" + ;; If K&R style declarations should be recognized then one could + ;; consider to match the start of any symbol since we want to match + ;; the start of the first declaration in the "K&R region". That + ;; could however produce false matches on code like "FOO(bar) x" + ;; where FOO is a cpp macro, so it's better to leave it out and rely + ;; on the other heuristics in that case. + t (if (c-lang-const c-postfix-decl-spec-kwds) + ;; Add on the keywords in `c-postfix-decl-spec-kwds'. + (concat (c-lang-const c-after-suffixed-type-decl-key) + "\\|" + (c-make-keywords-re t (c-lang-const c-postfix-decl-spec-kwds))) + (c-lang-const c-after-suffixed-type-decl-key)) + ;; Also match the colon that starts a base class initializer list in + ;; C++. That can be confused with a function call before the colon + ;; in a ? : operator, but we count on that `c-decl-prefix-re' won't + ;; match before such a thing (as a declaration-level construct; + ;; matches inside arglist contexts are already excluded). + c++ "[{:]") +(c-lang-defvar c-after-suffixed-type-decl-key + (c-lang-const c-after-suffixed-type-decl-key) + 'dont-doc) + +(c-lang-defconst c-after-suffixed-type-maybe-decl-key + ;; Regexp that in addition to `c-after-suffixed-type-decl-key' + ;; matches ";" and ",". + t (concat "\\(" (c-lang-const c-after-suffixed-type-decl-key) "\\)" + "\\|[;,]")) +(c-lang-defvar c-after-suffixed-type-maybe-decl-key + (c-lang-const c-after-suffixed-type-maybe-decl-key)) + +(c-lang-defconst c-opt-type-concat-key + "Regexp matching operators that concatenate types, e.g. the \"|\" in +\"int|string\" in Pike. The end of the first submatch is taken as the +end of the operator. nil in languages without such operators. It's +undefined whether identifier syntax (see `c-identifier-syntax-table') +is in effect or not." + t nil + pike "\\([|.&]\\)\\($\\|[^|.&]\\)") +(c-lang-defvar c-opt-type-concat-key (c-lang-const c-opt-type-concat-key) + 'dont-doc) + +(c-lang-defconst c-opt-type-suffix-key + "Regexp matching operators that might follow after a type, or nil in +languages that don't have such operators. The end of the first +submatch is taken as the end of the operator. This should not match +things like C++ template arglists if `c-recognize-<>-arglists' is set. +It's undefined whether identifier syntax (see `c-identifier-syntax-table') +is in effect or not." + t nil + (c c++ objc pike) "\\(\\.\\.\\.\\)" + java "\\(\\[[ \t\n\r\f\v]*\\]\\)") +(c-lang-defvar c-opt-type-suffix-key (c-lang-const c-opt-type-suffix-key)) + +(c-lang-defvar c-known-type-key + ;; Regexp matching the known type identifiers. This is initialized + ;; from the type keywords and `*-font-lock-extra-types'. The first + ;; submatch is the one that matches the type. Note that this regexp + ;; assumes that symbol constituents like '_' and '$' have word + ;; syntax. + (let ((extra-types (when (boundp (c-mode-symbol "font-lock-extra-types")) + (c-mode-var "font-lock-extra-types")))) + (concat "\\<\\(" + (c-make-keywords-re nil (c-lang-const c-primitive-type-kwds)) + (if (consp extra-types) + (concat "\\|" (mapconcat 'identity extra-types "\\|")) + "") + "\\)\\>"))) + +(c-lang-defconst c-special-brace-lists +"List of open- and close-chars that makes up a pike-style brace list, +i.e. for a ([ ]) list there should be a cons (?\\[ . ?\\]) in this +list." + t nil + pike '((?{ . ?}) (?\[ . ?\]) (?< . ?>))) +(c-lang-defvar c-special-brace-lists (c-lang-const c-special-brace-lists)) + +(c-lang-defconst c-recognize-knr-p + "Non-nil means K&R style argument declarations are valid." + t nil + c t) +(c-lang-defvar c-recognize-knr-p (c-lang-const c-recognize-knr-p)) + +(c-lang-defconst c-recognize-typeless-decls + "Non-nil means function declarations without return type should be +recognized. That can introduce an ambiguity with parenthesized macro +calls before a brace block. This setting does not affect declarations +that are preceded by a declaration starting keyword, so +e.g. `c-typeless-decl-kwds' may still be used when it's set to nil." + t nil + (c c++ objc) t) +(c-lang-defvar c-recognize-typeless-decls + (c-lang-const c-recognize-typeless-decls)) + +(c-lang-defconst c-recognize-<>-arglists + "Non-nil means C++ style template arglists should be handled. More +specifically, this means a comma separated list of types or +expressions surrounded by \"<\" and \">\". It's always preceded by an +identifier or one of the keywords on `c-<>-type-kwds' or +`c-<>-arglist-kwds'. If there's an identifier before then the whole +expression is considered to be a type." + t (or (consp (c-lang-const c-<>-type-kwds)) + (consp (c-lang-const c-<>-arglist-kwds)))) +(c-lang-defvar c-recognize-<>-arglists (c-lang-const c-recognize-<>-arglists)) + +(c-lang-defconst c-recognize-paren-inits + "Non-nil means that parenthesis style initializers exist, +i.e. constructs like + +Foo bar (gnu); + +in addition to the more classic + +Foo bar = gnu;" + t nil + c++ t) +(c-lang-defvar c-recognize-paren-inits (c-lang-const c-recognize-paren-inits)) + +(c-lang-defconst c-opt-<>-arglist-start + ;; Regexp matching the start of angle bracket arglists in languages + ;; where `c-recognize-<>-arglists' is set. Does not exclude + ;; keywords outside `c-<>-arglist-kwds'. The first submatch is + ;; assumed to surround the preceding symbol. The whole match is + ;; assumed to end directly after the opening "<". + t (if (c-lang-const c-recognize-<>-arglists) + (concat "\\(" + (c-lang-const c-symbol-key) + "\\)" + (c-lang-const c-syntactic-ws) + "<"))) +(c-lang-defvar c-opt-<>-arglist-start (c-lang-const c-opt-<>-arglist-start)) + +(c-lang-defconst c-opt-<>-arglist-start-in-paren + ;; Regexp that in addition to `c-opt-<>-arglist-start' matches close + ;; parens. The first submatch is assumed to surround + ;; `c-opt-<>-arglist-start'. + t (if (c-lang-const c-opt-<>-arglist-start) + (concat "\\(" + (c-lang-const c-opt-<>-arglist-start) + "\\)\\|\\s\)"))) +(c-lang-defvar c-opt-<>-arglist-start-in-paren + (c-lang-const c-opt-<>-arglist-start-in-paren)) + +(c-lang-defconst c-label-key + "Regexp matching a normal label, i.e. a label that doesn't begin with +a keyword like switch labels. It's only used at the beginning of a +statement." + t "\\<\\>" + (c c++ objc java pike) (concat "\\(" (c-lang-const c-symbol-key) "\\)" + "[ \t\n\r\f\v]*:\\([^:]\\|$\\)")) +(c-lang-defvar c-label-key (c-lang-const c-label-key) + 'dont-doc) + +(c-lang-defconst c-opt-postfix-decl-spec-key + ;; Regexp matching the beginning of a declaration specifier in the + ;; region between the header and the body of a declaration. + ;; + ;; TODO: This is currently not used uniformly; c++-mode and + ;; java-mode each have their own ways of using it. + t nil + c++ (concat ":?[ \t\n\r\f\v]*\\(virtual[ \t\n\r\f\v]+\\)?\\(" + (c-make-keywords-re nil (c-lang-const c-protection-kwds)) + "\\)[ \t\n\r\f\v]+" + "\\(" (c-lang-const c-symbol-key) "\\)") + java (c-make-keywords-re t (c-lang-const c-postfix-decl-spec-kwds))) +(c-lang-defvar c-opt-postfix-decl-spec-key + (c-lang-const c-opt-postfix-decl-spec-key)) + +(c-lang-defconst c-opt-friend-key + ;; Regexp describing friend declarations classes, or nil in + ;; languages that don't have such things. + ;; + ;; TODO: Ought to use `c-specifier-key' or similar, and the template + ;; skipping isn't done properly. This will disappear soon. + t nil + c++ "friend[ \t]+\\|template[ \t]*<.+>[ \t]*friend[ \t]+") +(c-lang-defvar c-opt-friend-key (c-lang-const c-opt-friend-key)) + +(c-lang-defconst c-opt-method-key + ;; Special regexp to match the start of Objective-C methods. The + ;; first submatch is assumed to end after the + or - key. + t nil + objc (concat + ;; TODO: Ought to use a better method than anchoring on bol. + "^[ \t]*\\([+-]\\)[ \t\n\r\f\v]*" + "\\(([^)]*)[ \t\n\r\f\v]*\\)?" ; return type + "\\(" (c-lang-const c-symbol-key) "\\)")) +(c-lang-defvar c-opt-method-key (c-lang-const c-opt-method-key)) + + +;;; Wrap up the `c-lang-defvar' system. + +;; Compile in the list of language variables that has been collected +;; with the `c-lang-defvar' macro. Note that the first element is +;; nil. +(defconst c-lang-variable-inits (cc-eval-when-compile c-lang-variable-inits)) + +(defun c-make-init-lang-vars-fun (mode) + "Create a function that initializes all the language dependent variables +for the given mode. + +This function should be evaluated at compile time, so that the +function it returns is byte compiled with all the evaluated results +from the language constants. Use the `c-init-language-vars' macro to +accomplish that conveniently. + +This function does not do any hidden buffer changes." + + (if (and (not load-in-progress) + (boundp 'byte-compile-dest-file) + (stringp byte-compile-dest-file)) + + ;; No need to byte compile this lambda since the byte compiler is + ;; smart enough to detect the `funcall' construct in the + ;; `c-init-language-vars' macro below and compile it all straight + ;; into the function that contains `c-init-language-vars'. + `(lambda () + + ;; This let sets up the context for `c-mode-var' and similar + ;; that could be in the result from `cl-macroexpand-all'. + (let ((c-buffer-is-cc-mode ',mode) + current-var) + (condition-case err + + (if (eq c-version-sym ',c-version-sym) + (setq ,@(let ((c-buffer-is-cc-mode mode) + (c-lang-const-expansion 'immediate)) + ;; `c-lang-const' will expand to the evaluated + ;; constant immediately in `cl-macroexpand-all' + ;; below. + (mapcan + (lambda (init) + `(current-var ',(car init) + ,(car init) ,(cl-macroexpand-all + (elt init 1)))) + (cdr c-lang-variable-inits)))) + + (unless (get ',mode 'c-has-warned-lang-consts) + (message ,(concat "%s compiled with CC Mode %s " + "but loaded with %s - evaluating " + "language constants from source") + ',mode ,c-version c-version) + (put ',mode 'c-has-warned-lang-consts t)) + + (require 'cc-langs) + (let ((init (cdr c-lang-variable-inits))) + (while init + (setq current-var (caar init)) + (set (caar init) (eval (cadar init))) + (setq init (cdr init))))) + + (error + (if current-var + (message "Eval error in the `c-lang-defvar' for `%s': %S" + current-var err) + (signal (car err) (cdr err))))))) + + ;; Being evaluated from source. Always use the dynamic method to + ;; work well when `c-lang-defvar's in this file are reevaluated + ;; interactively. + `(lambda () + (require 'cc-langs) + (let ((c-buffer-is-cc-mode ',mode) + (init (cdr c-lang-variable-inits)) + current-var) + (condition-case err + + (while init + (setq current-var (caar init)) + (set (caar init) (eval (cadar init))) + (setq init (cdr init))) + + (error + (if current-var + (message "Eval error in the `c-lang-defvar' for `%s': %S" + current-var err) + (signal (car err) (cdr err))))))) + )) + +(defmacro c-init-language-vars (mode) + "Initialize all the language dependent variables for the given mode. +This macro is expanded at compile time to a form tailored for the mode +in question, so MODE must be a constant. Therefore MODE is not +evaluated and should not be quoted. + +This macro does not do any hidden buffer changes." + `(funcall ,(c-make-init-lang-vars-fun mode))) (cc-provide 'cc-langs)
--- a/lisp/progmodes/cc-menus.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-menus.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,9 @@ ;;; cc-menus.el --- imenu support for CC Mode -;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1992-1997 Barry A. Warsaw +;; Authors: 1998- Martin Stjernholm +;; 1992-1999 Barry A. Warsaw ;; 1987 Dave Detlefs and Stewart Clamen ;; 1985 Richard M. Stallman ;; Maintainer: bug-cc-mode@gnu.org @@ -39,11 +38,14 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) + +(cc-require 'cc-defs) ;; The things referenced in imenu, which we don't require. (cc-bytecomp-defvar imenu-case-fold-search) (cc-bytecomp-defvar imenu-generic-expression) +(cc-bytecomp-defvar imenu-create-index-function) (cc-bytecomp-defun imenu-progress-message) @@ -71,10 +73,10 @@ (nil ,(concat "^\\<.*" - "[^a-zA-Z0-9_:<>~]" ; match any non-identifier char + "[^" c-alnum "_:<>~]" ; match any non-identifier char ; (note: this can be `\n') "\\(" - "\\([a-zA-Z0-9_:<>~]*::\\)?" ; match an operator + "\\([" c-alnum "_:<>~]*::\\)?" ; match an operator "operator\\>[ \t]*" "\\(()\\|[^(]*\\)" ; special case for `()' operator "\\)" @@ -93,7 +95,7 @@ (nil ,(concat "^" - "\\([a-zA-Z_][a-zA-Z0-9_:<>~]*\\)" ; match function name + "\\([" c-alpha "_][" c-alnum "_:<>~]*\\)" ; match function name "[ \t]*(" ; see above, BUT "[ \t]*\\([^ \t(*][^)]*\\)?)" ; the arg list must not start "[ \t]*[^ \t;(]" ; with an asterisk or parentheses @@ -103,8 +105,8 @@ ,(concat "^\\<" ; line MUST start with word char "[^()]*" ; no parentheses before - "[^a-zA-Z0-9_:<>~]" ; match any non-identifier char - "\\([a-zA-Z_][a-zA-Z0-9_:<>~]*\\)" ; match function name + "[^" c-alnum "_:<>~]" ; match any non-identifier char + "\\([" c-alpha "_][" c-alnum "_:<>~]*\\)" ; match function name "\\([ \t\n]\\|\\\\\n\\)*(" ; see above, BUT the arg list "\\([ \t\n]\\|\\\\\n\\)*\\([^ \t\n(*][^)]*\\)?)" ; must not start "\\([ \t\n]\\|\\\\\n\\)*[^ \t\n;(]" ; with an asterisk or parentheses @@ -117,27 +119,27 @@ `((nil ,(concat "^\\<.*" ; line MUST start with word char - "[^a-zA-Z0-9_]" ; match any non-identifier char - "\\([a-zA-Z_][a-zA-Z0-9_]*\\)" ; match function name + "[^" c-alnum "_]" ; match any non-identifier char + "\\([" c-alpha "_][" c-alnum "_]*\\)" ; match function name "[ \t]*" ; whitespace before macro name cc-imenu-c-prototype-macro-regexp "[ \t]*(" ; ws followed by first paren. "[ \t]*([^)]*)[ \t]*)[ \t]*[^ \t;]" ; see above ) 1))) ;; Class definitions - ("Class" + ("Class" ,(concat "^" ; beginning of line is required "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a `template <...>' "\\(class\\|struct\\)[ \t]+" "\\(" ; the string we want to get - "[a-zA-Z0-9_]+" ; class name + "[" c-alnum "_]+" ; class name "\\(<[^>]+>\\)?" ; possibly explicitly specialized "\\)" "\\([ \t\n]\\|\\\\\n\\)*[:{]" ) 3)) "Imenu generic expression for C++ mode. See `imenu-generic-expression'.") - + (defvar cc-imenu-c-generic-expression cc-imenu-c++-generic-expression "Imenu generic expression for C mode. See `imenu-generic-expression'.") @@ -145,21 +147,24 @@ (defvar cc-imenu-java-generic-expression `((nil ,(concat - "^\\([ \t]\\)*" - "\\([.A-Za-z0-9_-]+[ \t]+\\)?" ; type specs; there can be - "\\([.A-Za-z0-9_-]+[ \t]+\\)?" ; more than 3 tokens, right? - "\\([.A-Za-z0-9_-]+[ \t]*[[]?[]]?\\)" - "\\([ \t]\\)" - "\\([A-Za-z0-9_-]+\\)" ; the string we want to get - "\\([ \t]*\\)+(" - "[][a-zA-Z,_1-9\n \t]*" ; arguments - ")[ \t]*" -; "[^;(]" - "[,a-zA-Z_1-9\n \t]*{" - ) 6)) + "[" c-alpha "_][\]\[." c-alnum "_]+[ \t\n\r]+" ; type spec + "\\([" c-alpha "_][" c-alnum "_]+\\)" ; method name + "[ \t\n\r]*" + ;; An argument list that is either empty or contains at least + ;; two identifiers with only space between them. This avoids + ;; matching e.g. "else if (foo)". + (concat "([ \t\n\r]*" + "\\([\]\[.," c-alnum "_]+" + "[ \t\n\r]+" + "[\]\[.," c-alnum "_]" + "[\]\[.," c-alnum "_ \t\n\r]*" + "\\)?)") + "[.," c-alnum "_ \t\n\r]*" + "{" + ) 1)) "Imenu generic expression for Java mode. See `imenu-generic-expression'.") -;; *Warning for cc-mode developers* +;; *Warning for cc-mode developers* ;; ;; `cc-imenu-objc-generic-expression' elements depend on ;; `cc-imenu-c++-generic-expression'. So if you change this @@ -169,8 +174,8 @@ ;; order to know where the each regexp *group \\(foobar\\)* elements ;; are started. ;; -;; *-index variables are initialized during `cc-imenu-objc-generic-expression' -;; being initialized. +;; *-index variables are initialized during `cc-imenu-objc-generic-expression' +;; being initialized. ;; ;; Internal variables @@ -179,10 +184,10 @@ (defvar cc-imenu-objc-generic-expression-proto-index nil) (defvar cc-imenu-objc-generic-expression-objc-base-index nil) -(defvar cc-imenu-objc-generic-expression - (concat +(defvar cc-imenu-objc-generic-expression + (concat ;; - ;; For C + ;; For C ;; ;; > Special case to match a line like `main() {}' ;; > e.g. no return type, not even on the previous line. @@ -192,52 +197,53 @@ "\\|" ;; > General function name regexp ;; Pick a token by (match-string 3) - (car (cdr (nth 2 cc-imenu-c++-generic-expression))) ; -> index += 2 + (car (cdr (nth 2 cc-imenu-c++-generic-expression))) ; -> index += 5 (prog2 (setq cc-imenu-objc-generic-expression-general-func-index 3) "") ;; > Special case for definitions using phony prototype macros like: ;; > `int main _PROTO( (int argc,char *argv[]) )'. - ;; Pick a token by (match-string 5) + ;; Pick a token by (match-string 8) (if cc-imenu-c-prototype-macro-regexp - (concat + (concat "\\|" (car (cdr (nth 3 cc-imenu-c++-generic-expression))) ; -> index += 1 - (prog2 (setq cc-imenu-objc-generic-expression-objc-base-index 6) "") + (prog2 (setq cc-imenu-objc-generic-expression-objc-base-index 9) "") ) - (prog2 (setq cc-imenu-objc-generic-expression-objc-base-index 5) "") + (prog2 (setq cc-imenu-objc-generic-expression-objc-base-index 8) "") "") ; -> index += 0 - (prog2 (setq cc-imenu-objc-generic-expression-proto-index 5) "") + (prog2 (setq cc-imenu-objc-generic-expression-proto-index 8) "") ;; ;; For Objective-C - ;; Pick a token by (match-string 5 or 6) + ;; Pick a token by (match-string 8 or 9) ;; - "\\|\\(" - "^[-+][:a-zA-Z0-9()*_<>\n\t ]*[;{]" ; Methods - "\\|" - "^@interface[\t ]+[a-zA-Z0-9_]+[\t ]*:" - "\\|" - "^@interface[\t ]+[a-zA-Z0-9_]+[\t ]*([a-zA-Z0-9_]+)" - "\\|" + "\\|\\(" + "^[-+][:" c-alnum "()*_<>\n\t ]*[;{]" ; Methods + "\\|" + "^@interface[\t ]+[" c-alnum "_]+[\t ]*:" + "\\|" + "^@interface[\t ]+[" c-alnum "_]+[\t ]*([" c-alnum "_]+)" + "\\|" ;; For NSObject, NSProxy and Object... They don't have super class. - "^@interface[\t ]+[a-zA-Z0-9_]+[\t ]*.*$" - "\\|" - "^@implementation[\t ]+[a-zA-Z0-9_]+[\t ]*([a-zA-Z0-9_]+)" - "\\|" - "^@implementation[\t ]+[a-zA-Z0-9_]+" - "\\|" - "^@protocol[\t ]+[a-zA-Z0-9_]+" "\\)") + "^@interface[\t ]+[" c-alnum "_]+[\t ]*.*$" + "\\|" + "^@implementation[\t ]+[" c-alnum "_]+[\t ]*([" c-alnum "_]+)" + "\\|" + "^@implementation[\t ]+[" c-alnum "_]+" + "\\|" + "^@protocol[\t ]+[" c-alnum "_]+" "\\)") "Imenu generic expression for ObjC mode. See `imenu-generic-expression'.") ;; Imenu support for objective-c uses functions. (defsubst cc-imenu-objc-method-to-selector (method) "Return the objc selector style string of METHOD. -Example: +Example: - perform: (SEL)aSelector withObject: object1 withObject: object2; /* METHOD */ => -perform:withObject:withObject:withObject: /* selector */" + ;; This function does not do any hidden buffer changes. (let ((return "") ; String to be returned - (p 0) ; Current scanning position in METHOD - (pmax (length method)) ; + (p 0) ; Current scanning position in METHOD + (pmax (length method)) ; char ; Current scanning target (betweenparen 0) ; CHAR is in parentheses. argreq ; An argument is required. @@ -253,17 +259,17 @@ (and (<= ?A char) (<= char ?Z)) (and (<= ?0 char) (<= char ?9)) (= ?_ char))) - (if argreq + (if argreq (setq inargvar t argreq nil) (setq return (concat return (char-to-string char))))) ;; Or a white space? - ((and inargvar (or (eq ?\ char) (eq ?\n char)) + ((and inargvar (or (eq ?\ char) (eq ?\n char)) (setq inargvar nil))) ;; Or a method separator? ;; If a method separator, the next token will be an argument variable. - ((eq ?: char) - (setq argreq t + ((eq ?: char) + (setq argreq t return (concat return (char-to-string char)))) ;; Or an open parentheses? ((eq ?\( char) @@ -275,9 +281,10 @@ (defun cc-imenu-objc-remove-white-space (str) "Remove all spaces and tabs from STR." + ;; This function does not do any hidden buffer changes. (let ((return "") (p 0) - (max (length str)) + (max (length str)) char) (while (< p max) (setq char (aref str p)) @@ -289,12 +296,13 @@ (defun cc-imenu-objc-function () "imenu supports for objc-mode." + ;; This function does not do any hidden buffer changes. (let (methodlist clist ;; ;; OBJC, Cnoreturn, Cgeneralfunc, Cproto are constants. ;; - ;; *Warning for developers* + ;; *Warning for developers* ;; These constants depend on `cc-imenu-c++-generic-expression'. ;; (OBJC cc-imenu-objc-generic-expression-objc-base-index) @@ -310,13 +318,13 @@ toplist stupid str - str2 + str2 (intflen (length "@interface")) (implen (length "@implementation")) (prtlen (length "@protocol")) (func ;; - ;; Does this emacs has buffer-substring-no-properties? + ;; Does this emacs has buffer-substring-no-properties? ;; (if (fboundp 'buffer-substring-no-properties) 'buffer-substring-no-properties @@ -326,7 +334,7 @@ ;; (while (re-search-backward cc-imenu-objc-generic-expression nil t) (imenu-progress-message stupid) - (setq langnum (if (match-beginning OBJC) + (setq langnum (if (match-beginning OBJC) OBJC (cond ((match-beginning Cproto) Cproto) @@ -334,7 +342,7 @@ ((match-beginning Cnoreturn) Cnoreturn)))) (setq str (funcall func (match-beginning langnum) (match-end langnum))) ;; - (cond + (cond ;; ;; C ;; @@ -342,7 +350,7 @@ (setq clist (cons (cons str (match-beginning langnum)) clist))) ;; ;; ObjC - ;; + ;; ;; An instance Method ((eq (aref str 0) ?-) (setq str (concat "-" (cc-imenu-objc-method-to-selector str))) @@ -355,10 +363,10 @@ (setq methodlist (cons (cons str (match-beginning langnum)) methodlist))) - ;; Interface or implementation or protocol + ;; Interface or implementation or protocol ((eq (aref str 0) ?@) (setq classcount (1+ classcount)) - (cond + (cond ((and (> (length str) implen) (string= (substring str 0 implen) "@implementation")) (setq str (substring str implen) @@ -376,7 +384,7 @@ (setq toplist (cons nil (cons (cons str methodlist) toplist)) methodlist nil)))) - ;; + ;; (imenu-progress-message stupid 100) (if (eq (car toplist) nil) (setq toplist (cdr toplist))) @@ -395,7 +403,8 @@ (setq last (cdr last))) (setcdr last clist)))) ;; Add C lang tokens as a sub menu - (setq toplist (cons (cons "C" clist) toplist))) + (if clist + (setq toplist (cons (cons "C" clist) toplist)))) ;; toplist )) @@ -404,9 +413,13 @@ ; ()) ; FIXME: Please contribute one! -(defun cc-imenu-init (mode-generic-expression) +(defun cc-imenu-init (mode-generic-expression + &optional mode-create-index-function) + ;; This function does not do any hidden buffer changes. (setq imenu-generic-expression mode-generic-expression - imenu-case-fold-search nil)) + imenu-case-fold-search nil) + (when mode-create-index-function + (setq imenu-create-index-function mode-create-index-function))) (cc-provide 'cc-menus)
--- a/lisp/progmodes/cc-mode.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-mode.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,10 @@ -;;; cc-mode.el --- major mode for editing C, C++, Objective-C, and Java code +;;; cc-mode.el --- major mode for editing C and similar languages -;; Copyright (C) 1985,1987,1992-2001,2003 Free Software Foundation, Inc. +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1992-1997 Barry A. Warsaw +;; Authors: 2003- Alan Mackenzie +;; 1998- Martin Stjernholm +;; 1992-1999 Barry A. Warsaw ;; 1987 Dave Detlefs and Stewart Clamen ;; 1985 Richard M. Stallman ;; Maintainer: bug-cc-mode@gnu.org @@ -28,37 +28,28 @@ ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. -(defconst c-version "5.29" - "CC Mode version number.") +;;; Commentary: ;; NOTE: Read the commentary below for the right way to submit bug reports! ;; NOTE: See the accompanying texinfo manual for details on using this mode! - -;;; Commentary: +;; Note: The version string is in cc-defs. ;; This package provides GNU Emacs major modes for editing C, C++, -;; Objective-C, Java, IDL and Pike code. As of the latest Emacs and -;; XEmacs releases, it is the default package for editing these -;; languages. This package is called "CC Mode", and should be spelled -;; exactly this way. +;; Objective-C, Java, CORBA's IDL, Pike and AWK code. As of the +;; latest Emacs and XEmacs releases, it is the default package for +;; editing these languages. This package is called "CC Mode", and +;; should be spelled exactly this way. ;; CC Mode supports K&R and ANSI C, ANSI C++, Objective-C, Java, -;; CORBA's IDL, and Pike with a consistent indentation model across -;; all modes. This indentation model is intuitive and very flexible, -;; so that almost any desired style of indentation can be supported. -;; Installation, usage, and programming details are contained in an -;; accompanying texinfo manual. +;; CORBA's IDL, Pike and AWK with a consistent indentation model +;; across all modes. This indentation model is intuitive and very +;; flexible, so that almost any desired style of indentation can be +;; supported. Installation, usage, and programming details are +;; contained in an accompanying texinfo manual. ;; CC Mode's immediate ancestors were, c++-mode.el, cplus-md.el, and ;; cplus-md1.el.. -;; NOTE: This mode does not perform font-locking (a.k.a syntactic -;; coloring, keyword highlighting, etc.) for any of the supported -;; modes. Typically this is done by a package called font-lock.el -;; which we do *not* maintain. You should contact the Emacs or XEmacs -;; maintainers for questions about coloring or highlighting in any -;; language mode. - ;; To submit bug reports, type "C-c C-b". These will be sent to ;; bug-gnu-emacs@gnu.org (mirrored as the Usenet newsgroup ;; gnu.emacs.bug) as well as bug-cc-mode@gnu.org, which directly @@ -89,25 +80,40 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) (cc-require 'cc-defs) -(cc-require 'cc-menus) +(cc-require-when-compile 'cc-langs) (cc-require 'cc-vars) -(cc-require 'cc-langs) +(cc-require 'cc-engine) (cc-require 'cc-styles) -(cc-require 'cc-engine) (cc-require 'cc-cmds) (cc-require 'cc-align) +(cc-require 'cc-menus) -;; Silence the compiler. +;; SILENCE the compiler. (cc-bytecomp-defvar comment-line-break-function) ; (X)Emacs 20+ (cc-bytecomp-defvar adaptive-fill-first-line-regexp) ; Emacs 20+ (cc-bytecomp-defun set-keymap-parents) ; XEmacs +;; We set these variables during mode init, yet we don't require +;; font-lock. +(cc-bytecomp-defvar font-lock-defaults) +(cc-bytecomp-defvar font-lock-syntactic-keywords) + ;; Menu support for both XEmacs and Emacs. If you don't have easymenu ;; with your version of Emacs, you are incompatible! -(require 'easymenu) +(cc-external-require 'easymenu) + +;; Load cc-fonts first after font-lock is loaded, since it isn't +;; necessary until font locking is requested. +(eval-after-load "font-lock" + '(require 'cc-fonts)) + +;; cc-langs isn't loaded when we're byte compiled, so add autoload +;; directives for the interface functions. +(autoload 'c-make-init-lang-vars-fun "cc-langs") +(autoload 'c-init-language-vars "cc-langs" nil nil 'macro) ;; Other modes and packages which depend on CC Mode should do the @@ -118,14 +124,30 @@ ;; ;; And in the major mode function: ;; -;; (c-initialize-cc-mode) +;; (c-initialize-cc-mode t) +;; (c-init-language-vars some-mode) +;; (c-common-init 'some-mode) ; Or perhaps (c-basic-common-init 'some-mode) +;; +;; See cc-langs.el for further info. A small example of a derived mode +;; is also available at <http://cc-mode.sourceforge.net/ +;; derived-mode-ex.el>. (defun c-leave-cc-mode-mode () (setq c-buffer-is-cc-mode nil)) ;;;###autoload -(defun c-initialize-cc-mode () +(defun c-initialize-cc-mode (&optional new-style-init) + "Initialize CC Mode for use in the current buffer. +If the optional NEW-STYLE-INIT is nil or left out then all necessary +initialization to run CC Mode for the C language is done. Otherwise +only some basic setup is done, and a call to `c-init-language-vars', +is necessary too (which gives more control). See \"cc-mode.el\" for +more info." + ;; + ;; This function does not do any hidden buffer changes. + (setq c-buffer-is-cc-mode t) + (let ((initprop 'cc-mode-is-initialized) c-initialization-ok) (unless (get 'c-initialize-cc-mode initprop) @@ -140,21 +162,24 @@ (add-hook 'change-major-mode-hook 'c-leave-cc-mode-mode) (setq c-initialization-ok t)) ;; Will try initialization hooks again if they failed. - (put 'c-initialize-cc-mode initprop c-initialization-ok))) - )) + (put 'c-initialize-cc-mode initprop c-initialization-ok)))) + + (unless new-style-init + (c-init-c-language-vars))) -;; Common routines +;;; Common routines. + (defvar c-mode-base-map () "Keymap shared by all CC Mode related modes.") (defun c-make-inherited-keymap () (let ((map (make-sparse-keymap))) (cond - ;; XEmacs 19 & 20 + ;; XEmacs ((fboundp 'set-keymap-parents) (set-keymap-parents map c-mode-base-map)) - ;; Emacs 19 + ;; Emacs ((fboundp 'set-keymap-parent) (set-keymap-parent map c-mode-base-map)) ;; incompatible @@ -165,14 +190,16 @@ ;; Compatibility wrapper for `define-abbrev' which passes a non-nil ;; sixth argument for SYSTEM-FLAG in emacsen that support it ;; (currently only Emacs 21.2). - (define-abbrev-table name nil) - (let ((table (symbol-value name))) + (let ((table (or (symbol-value name) + (progn (define-abbrev-table name nil) + (symbol-value name))))) (while defs (condition-case nil (apply 'define-abbrev table (append (car defs) '(t))) (wrong-number-of-arguments (apply 'define-abbrev table (car defs)))) (setq defs (cdr defs))))) +(put 'c-define-abbrev-table 'lisp-indent-function 1) (if c-mode-base-map nil @@ -216,14 +243,22 @@ (substitute-key-definition 'indent-for-tab-command 'c-indent-command c-mode-base-map global-map) - ;; It doesn't suffice to put c-fill-paragraph on - ;; fill-paragraph-function due to the way it works. + + ;; It doesn't suffice to put `c-fill-paragraph' on + ;; `fill-paragraph-function' since `c-fill-paragraph' must be called + ;; before any fill prefix adaption is done. E.g. `filladapt-mode' + ;; replaces `fill-paragraph' and does the adaption before calling + ;; `fill-paragraph-function', and we have to mask comments etc + ;; before that. Also, `c-fill-paragraph' chains on to + ;; `fill-paragraph' and the value on `fill-parapgraph-function' to + ;; do the actual filling work. (substitute-key-definition 'fill-paragraph 'c-fill-paragraph c-mode-base-map global-map) ;; In XEmacs the default fill function is called ;; fill-paragraph-or-region. (substitute-key-definition 'fill-paragraph-or-region 'c-fill-paragraph c-mode-base-map global-map) + ;; Bind the electric deletion functions to C-d and DEL. Emacs 21 ;; automatically maps the [delete] and [backspace] keys to these two ;; depending on window system and user preferences. (In earlier @@ -237,13 +272,11 @@ ;; `delete-key-deletes-forward' to decide what [delete] should do. (define-key c-mode-base-map [delete] 'c-electric-delete) (define-key c-mode-base-map [backspace] 'c-electric-backspace)) - ;; these are new keybindings, with no counterpart to BOCM (define-key c-mode-base-map "," 'c-electric-semi&comma) (define-key c-mode-base-map "*" 'c-electric-star) (define-key c-mode-base-map "/" 'c-electric-slash) (define-key c-mode-base-map "\C-c\C-q" 'c-indent-defun) (define-key c-mode-base-map "\C-c\C-\\" 'c-backslash-region) - ;; TBD: where if anywhere, to put c-backward|forward-into-nomenclature (define-key c-mode-base-map "\C-c\C-a" 'c-toggle-auto-state) (define-key c-mode-base-map "\C-c\C-b" 'c-submit-bug-report) (define-key c-mode-base-map "\C-c\C-c" 'comment-region) @@ -256,45 +289,69 @@ ;;(define-key c-mode-base-map "\C-c\C-v" 'c-version) ) -(defvar c-c-menu nil) -(defvar c-c++-menu nil) -(defvar c-objc-menu nil) -(defvar c-java-menu nil) -(defvar c-pike-menu nil) - -(defun c-mode-menu (modestr) - (let ((m - '(["Comment Out Region" comment-region (c-fn-region-is-active-p)] - ["Uncomment Region" - (comment-region (region-beginning) (region-end) '(4)) - (c-fn-region-is-active-p)] - ["Fill Comment Paragraph" c-fill-paragraph t] - "----" - ["Indent Expression" c-indent-exp - (memq (char-after) '(?\( ?\[ ?\{))] - ["Indent Line or Region" c-indent-line-or-region t] - ["Up Conditional" c-up-conditional t] - ["Backward Conditional" c-backward-conditional t] - ["Forward Conditional" c-forward-conditional t] - ["Backward Statement" c-beginning-of-statement t] - ["Forward Statement" c-end-of-statement t] - "----" - ["Macro Expand Region" c-macro-expand (c-fn-region-is-active-p)] - ["Backslashify" c-backslash-region - (c-fn-region-is-active-p)] - "----" - ("Toggle..." - ["Syntactic indentation" c-toggle-syntactic-indentation t] - ["Auto newline" c-toggle-auto-state t] - ["Hungry delete" c-toggle-hungry-state t]) - ))) - (cons modestr m))) - ;; We don't require the outline package, but we configure it a bit anyway. (cc-bytecomp-defvar outline-level) -(defun c-common-init (mode) - ;; Common initializations for all modes. +(defun c-mode-menu (modestr) + "Return a menu spec suitable for `easy-menu-define' that is exactly +like the C mode menu except that the menu bar item name is MODESTR +instead of \"C\". + +This function is provided for compatibility only; derived modes should +preferably use the `c-mode-menu' language constant directly." + (cons modestr (c-lang-const c-mode-menu c))) + +;; Ugly hack to pull in the definition of `c-populate-syntax-table' +;; from cc-langs to make it available at runtime. It's either this or +;; moving the definition for it to cc-defs, but that would mean to +;; break up the syntax table setup over two files. +(defalias 'c-populate-syntax-table + (cc-eval-when-compile + (let ((f (symbol-function 'c-populate-syntax-table))) + (if (byte-code-function-p f) f (byte-compile f))))) + +(defun c-after-change (beg end len) + ;; Function put on `after-change-functions' to adjust various + ;; caches. Prefer speed to finesse here, since there will be an + ;; order of magnitude more calls to this function than any of the + ;; functions that use the caches. + ;; + ;; Note that care must be taken so that this is called before any + ;; font-lock callbacks since we might get calls to functions using + ;; these caches from inside them, and we must thus be sure that this + ;; has already been executed. + ;; + ;; This function does not do any hidden buffer changes. + + (c-save-buffer-state () + (when (> end (point-max)) + ;; Some emacsen might return positions past the end. This has been + ;; observed in Emacs 20.7 when rereading a buffer changed on disk + ;; (haven't been able to minimize it, but Emacs 21.3 appears to + ;; work). + (setq end (point-max)) + (when (> beg end) + (setq beg end))) + + (c-invalidate-sws-region-after beg end) + (c-invalidate-state-cache beg) + (c-invalidate-find-decl-cache beg))) + +(defun c-basic-common-init (mode default-style) + "Do the necessary initialization for the syntax handling routines +and the line breaking/filling code. Intended to be used by other +packages that embed CC Mode. + +MODE is the CC Mode flavor to set up, e.g. 'c-mode or 'java-mode. +DEFAULT-STYLE tells which indentation style to install. It has the +same format as `c-default-style'. + +Note that `c-init-language-vars' must be called before this function. +This function cannot do that since `c-init-language-vars' is a macro +that requires a literal mode spec at compile time." + ;; + ;; This function does not do any hidden buffer changes. + (setq c-buffer-is-cc-mode mode) ;; these variables should always be buffer local; they do not affect @@ -302,12 +359,9 @@ (make-local-variable 'parse-sexp-ignore-comments) (make-local-variable 'indent-line-function) (make-local-variable 'indent-region-function) - (make-local-variable 'outline-regexp) - (make-local-variable 'outline-level) (make-local-variable 'normal-auto-fill-function) (make-local-variable 'comment-start) (make-local-variable 'comment-end) - (make-local-variable 'comment-column) (make-local-variable 'comment-start-skip) (make-local-variable 'comment-multi-line) (make-local-variable 'paragraph-start) @@ -315,24 +369,12 @@ (make-local-variable 'paragraph-ignore-fill-prefix) (make-local-variable 'adaptive-fill-mode) (make-local-variable 'adaptive-fill-regexp) - (make-local-variable 'imenu-generic-expression) ;set in the mode functions - - ;; X/Emacs 20 only - (and (boundp 'comment-line-break-function) - (progn - (make-local-variable 'comment-line-break-function) - (setq comment-line-break-function - 'c-indent-new-comment-line))) ;; now set their values (setq parse-sexp-ignore-comments t indent-line-function 'c-indent-line indent-region-function 'c-indent-region - outline-regexp "[^#\n\^M]" - outline-level 'c-outline-level normal-auto-fill-function 'c-do-auto-fill - comment-column 32 - comment-start-skip "/\\*+ *\\|//+ *" comment-multi-line t) ;; Install `c-fill-paragraph' on `fill-paragraph-function' so that a @@ -341,20 +383,57 @@ (make-local-variable 'fill-paragraph-function) (setq fill-paragraph-function 'c-fill-paragraph) - ;; Set `require-final-newline' only if we should. - (let ((rfn (assq mode c-require-final-newline))) - (when rfn - (make-local-variable 'require-final-newline) - (setq require-final-newline (cdr rfn)))) + ;; (X)Emacs 20 and later. + (when (boundp 'comment-line-break-function) + (make-local-variable 'comment-line-break-function) + (setq comment-line-break-function + 'c-indent-new-comment-line)) + + ;; Emacs 20 and later. + (when (boundp 'parse-sexp-lookup-properties) + (make-local-variable 'parse-sexp-lookup-properties) + (setq parse-sexp-lookup-properties t)) + + ;; Same as above for XEmacs 21 (although currently undocumented). + (when (boundp 'lookup-syntax-properties) + (make-local-variable 'lookup-syntax-properties) + (setq lookup-syntax-properties t)) - ;; Fix keyword regexps. - (c-init-language-vars) + ;; Use this in Emacs 21 to avoid meddling with the rear-nonsticky + ;; property on each character. + (when (boundp 'text-property-default-nonsticky) + (make-local-variable 'text-property-default-nonsticky) + (let ((elem (assq 'syntax-table text-property-default-nonsticky))) + (if elem + (setcdr elem t) + (setq text-property-default-nonsticky + (cons '(syntax-table . t) + text-property-default-nonsticky)))) + (setq text-property-default-nonsticky + (cons '(c-type . t) + text-property-default-nonsticky))) - ;; now set the mode style based on c-default-style - (let ((style (if (stringp c-default-style) - c-default-style - (or (cdr (assq mode c-default-style)) - (cdr (assq 'other c-default-style)) + ;; In Emacs 21 and later it's possible to turn off the ad-hoc + ;; heuristic that open parens in column 0 are defun starters. Since + ;; we have c-state-cache that isn't useful and only causes trouble + ;; so turn it off. + (when (memq 'col-0-paren c-emacs-features) + (make-local-variable 'open-paren-in-column-0-is-defun-start) + (setq open-paren-in-column-0-is-defun-start nil)) + + ;; The `c-type' text property with `c-decl-end' is used to mark the + ;; ends of access keys to make interactive refontification work + ;; better. + (when c-opt-access-key + (setq c-type-decl-end-used t)) + + (c-clear-found-types) + + ;; now set the mode style based on default-style + (let ((style (if (stringp default-style) + default-style + (or (cdr (assq mode default-style)) + (cdr (assq 'other default-style)) "gnu")))) ;; Override style variables if `c-old-style-variable-behavior' is ;; set. Also override if we are using global style variables, @@ -378,28 +457,96 @@ (make-local-variable 'comment-indent-function) (setq comment-indent-function 'c-comment-indent) - ;; add menus to menubar - (easy-menu-add (c-mode-menu mode-name)) - ;; put auto-hungry designators onto minor-mode-alist, but only once (or (assq 'c-auto-hungry-string minor-mode-alist) (setq minor-mode-alist (cons '(c-auto-hungry-string c-auto-hungry-string) minor-mode-alist))) - ;; Install the function that ensures `c-state-cache' doesn't become - ;; invalid. - (make-local-variable 'after-change-functions) - (add-hook 'after-change-functions 'c-check-state-cache)) + ;; Install the functions that ensure that various internal caches + ;; don't become invalid due to buffer changes. + (make-local-hook 'after-change-functions) + (add-hook 'after-change-functions 'c-after-change nil t)) + +(defun c-after-font-lock-init () + ;; Put on `font-lock-mode-hook'. + (remove-hook 'after-change-functions 'c-after-change t) + (add-hook 'after-change-functions 'c-after-change nil t)) + +(defun c-font-lock-init () + "Set up the font-lock variables for using the font-lock support in CC Mode. +This does not load the font-lock package. Use after +`c-basic-common-init' and after cc-fonts has been loaded." + + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults + `(,(if (c-mode-is-new-awk-p) + ;; awk-mode currently has only one font lock level. + 'awk-font-lock-keywords + (mapcar 'c-mode-symbol + '("font-lock-keywords" "font-lock-keywords-1" + "font-lock-keywords-2" "font-lock-keywords-3"))) + nil nil + ,c-identifier-syntax-modifications + c-beginning-of-syntax + (font-lock-mark-block-function + . c-mark-function))) + + (make-local-hook 'font-lock-mode-hook) + (add-hook 'font-lock-mode-hook 'c-after-font-lock-init nil t)) + +(defun c-setup-doc-comment-style () + "Initialize the variables that depend on the value of `c-doc-comment-style'." + (when (and (featurep 'font-lock) + (symbol-value 'font-lock-mode)) + ;; Force font lock mode to reinitialize itself. + (font-lock-mode 0) + (font-lock-mode 1))) + +(defun c-common-init (&optional mode) + "Common initialization for all CC Mode modes. +In addition to the work done by `c-basic-common-init' and +`c-font-lock-init', this function sets up various other things as +customary in CC Mode modes but which aren't strictly necessary for CC +Mode to operate correctly. + +MODE is the symbol for the mode to initialize, like 'c-mode. See +`c-basic-common-init' for details. It's only optional to be +compatible with old code; callers should always specify it. + +This function does not do any hidden buffer changes." + + (unless mode + ;; Called from an old third party package. The fallback is to + ;; initialize for C. + (c-init-c-language-vars)) + + (c-basic-common-init mode c-default-style) + (when mode + ;; Only initialize font locking if we aren't called from an old package. + (c-font-lock-init)) + + (make-local-variable 'outline-regexp) + (make-local-variable 'outline-level) + (setq outline-regexp "[^#\n\^M]" + outline-level 'c-outline-level) + + (let ((rfn (assq mode c-require-final-newline))) + (when rfn + (make-local-variable 'require-final-newline) + (setq require-final-newline (cdr rfn))))) (defun c-postprocess-file-styles () - "Function that post processes relevant file local variables. + "Function that post processes relevant file local variables in CC Mode. Currently, this function simply applies any style and offset settings found in the file's Local Variable list. It first applies any style setting found in `c-file-style', then it applies any offset settings it finds in `c-file-offsets'. Note that the style variables are always made local to the buffer." + ;; + ;; This function does not do any hidden buffer changes. + ;; apply file styles and offsets (when c-buffer-is-cc-mode (if (or c-file-style c-file-offsets) @@ -419,6 +566,13 @@ ;; Support for C +;;;###autoload +(defvar c-mode-syntax-table nil + "Syntax table used in c-mode buffers.") +(or c-mode-syntax-table + (setq c-mode-syntax-table + (funcall (c-lang-const c-make-mode-syntax-table c)))) + (defvar c-mode-abbrev-table nil "Abbreviation table used in c-mode buffers.") (c-define-abbrev-table 'c-mode-abbrev-table @@ -435,7 +589,23 @@ ) (easy-menu-define c-c-menu c-mode-map "C Mode Commands" - (c-mode-menu "C")) + (cons "C" (c-lang-const c-mode-menu c))) + +;; In XEmacs >= 21.5 modes should add their own entries to +;; `auto-mode-alist'. The comment form of autoload is used to avoid +;; doing this on load. That since `add-to-list' prepends the value +;; which could cause it to clobber user settings. Later emacsen have +;; an append option, but it's not safe to use. +;;;###autoload (add-to-list 'auto-mode-alist '("\\.[ch]\\'" . c-mode)) + +;; NB: The following two associate yacc and lex files to C Mode, which +;; is not really suitable for those formats. Anyway, afaik there's +;; currently no better mode for them, and besides this is legacy. +;;;###autoload (add-to-list 'auto-mode-alist '("\\.y\\(acc\\)?\\'" . c-mode)) +;;;###autoload (add-to-list 'auto-mode-alist '("\\.lex\\'" . c-mode)) + +(defun c-init-c-language-vars () + (c-init-language-vars c-mode)) ;;;###autoload (defun c-mode () @@ -447,22 +617,23 @@ To see what version of CC Mode you are running, enter `\\[c-version]'. -The hook variable `c-mode-hook' is run with no args, if that value is -bound and has a non-nil value. Also the hook `c-mode-common-hook' is -run first. +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `c-mode-hook'. Key bindings: \\{c-mode-map}" (interactive) (kill-all-local-variables) - (c-initialize-cc-mode) + (c-initialize-cc-mode t) (set-syntax-table c-mode-syntax-table) (setq major-mode 'c-mode mode-name "C" local-abbrev-table c-mode-abbrev-table abbrev-mode t) (use-local-map c-mode-map) + (c-init-c-language-vars) (c-common-init 'c-mode) + (easy-menu-add c-c-menu) (cc-imenu-init cc-imenu-c-generic-expression) (run-hooks 'c-mode-common-hook) (run-hooks 'c-mode-hook) @@ -471,6 +642,13 @@ ;; Support for C++ +;;;###autoload +(defvar c++-mode-syntax-table nil + "Syntax table used in c++-mode buffers.") +(or c++-mode-syntax-table + (setq c++-mode-syntax-table + (funcall (c-lang-const c-make-mode-syntax-table c++)))) + (defvar c++-mode-abbrev-table nil "Abbreviation table used in c++-mode buffers.") (c-define-abbrev-table 'c++-mode-abbrev-table @@ -490,7 +668,11 @@ (define-key c++-mode-map ">" 'c-electric-lt-gt)) (easy-menu-define c-c++-menu c++-mode-map "C++ Mode Commands" - (c-mode-menu "C++")) + (cons "C++" (c-lang-const c-mode-menu c++))) + +;;;###autoload (add-to-list 'auto-mode-alist '("\\.\\(cc\\|hh\\)\\'" . c++-mode)) +;;;###autoload (add-to-list 'auto-mode-alist '("\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\'" . c++-mode)) +;;;###autoload (add-to-list 'auto-mode-alist '("\\.\\(CC?\\|HH?\\)\\'" . c++-mode)) ;;;###autoload (defun c++-mode () @@ -503,22 +685,23 @@ To see what version of CC Mode you are running, enter `\\[c-version]'. -The hook variable `c++-mode-hook' is run with no args, if that -variable is bound and has a non-nil value. Also the hook -`c-mode-common-hook' is run first. +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `c++-mode-hook'. Key bindings: \\{c++-mode-map}" (interactive) (kill-all-local-variables) - (c-initialize-cc-mode) + (c-initialize-cc-mode t) (set-syntax-table c++-mode-syntax-table) (setq major-mode 'c++-mode mode-name "C++" local-abbrev-table c++-mode-abbrev-table abbrev-mode t) (use-local-map c++-mode-map) + (c-init-language-vars c++-mode) (c-common-init 'c++-mode) + (easy-menu-add c-c++-menu) (cc-imenu-init cc-imenu-c++-generic-expression) (run-hooks 'c-mode-common-hook) (run-hooks 'c++-mode-hook) @@ -527,6 +710,13 @@ ;; Support for Objective-C +;;;###autoload +(defvar objc-mode-syntax-table nil + "Syntax table used in objc-mode buffers.") +(or objc-mode-syntax-table + (setq objc-mode-syntax-table + (funcall (c-lang-const c-make-mode-syntax-table objc)))) + (defvar objc-mode-abbrev-table nil "Abbreviation table used in objc-mode buffers.") (c-define-abbrev-table 'objc-mode-abbrev-table @@ -542,7 +732,9 @@ (define-key objc-mode-map "\C-c\C-e" 'c-macro-expand)) (easy-menu-define c-objc-menu objc-mode-map "ObjC Mode Commands" - (c-mode-menu "ObjC")) + (cons "ObjC" (c-lang-const c-mode-menu objc))) + +;;;###autoload (add-to-list 'auto-mode-alist '("\\.m\\'" . objc-mode)) ;;;###autoload (defun objc-mode () @@ -555,23 +747,27 @@ To see what version of CC Mode you are running, enter `\\[c-version]'. -The hook variable `objc-mode-hook' is run with no args, if that value -is bound and has a non-nil value. Also the hook `c-mode-common-hook' -is run first. +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `objc-mode-hook'. Key bindings: \\{objc-mode-map}" (interactive) (kill-all-local-variables) - (c-initialize-cc-mode) + (c-initialize-cc-mode t) (set-syntax-table objc-mode-syntax-table) (setq major-mode 'objc-mode mode-name "ObjC" local-abbrev-table objc-mode-abbrev-table abbrev-mode t) + ;; The `c-type' text property with `c-decl-end' is used to mark the + ;; end of the @-style directives. + (setq c-type-decl-end-used t) (use-local-map objc-mode-map) + (c-init-language-vars objc-mode) (c-common-init 'objc-mode) - (cc-imenu-init cc-imenu-objc-generic-expression) + (easy-menu-add c-objc-menu) + (cc-imenu-init nil 'cc-imenu-objc-function) (run-hooks 'c-mode-common-hook) (run-hooks 'objc-mode-hook) (c-update-modeline)) @@ -579,6 +775,13 @@ ;; Support for Java +;;;###autoload +(defvar java-mode-syntax-table nil + "Syntax table used in java-mode buffers.") +(or java-mode-syntax-table + (setq java-mode-syntax-table + (funcall (c-lang-const c-make-mode-syntax-table java)))) + (defvar java-mode-abbrev-table nil "Abbreviation table used in java-mode buffers.") (c-define-abbrev-table 'java-mode-abbrev-table @@ -595,8 +798,17 @@ ;; add bindings which are only useful for Java ) +;; Regexp trying to describe the beginning of a Java top-level +;; definition. This is not used by CC Mode, nor is it maintained +;; since it's practically impossible to write a regexp that reliably +;; matches such a construct. Other tools are necessary. +(defconst c-Java-defun-prompt-regexp + "^[ \t]*\\(\\(\\(public\\|protected\\|private\\|const\\|abstract\\|synchronized\\|final\\|static\\|threadsafe\\|transient\\|native\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\)\\s-+\\)\\)?\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f\v]*\\)+\\)?\\s-*") + (easy-menu-define c-java-menu java-mode-map "Java Mode Commands" - (c-mode-menu "Java")) + (cons "Java" (c-lang-const c-mode-menu java))) + +;;;###autoload (add-to-list 'auto-mode-alist '("\\.java\\'" . java-mode)) ;;;###autoload (defun java-mode () @@ -609,24 +821,23 @@ To see what version of CC Mode you are running, enter `\\[c-version]'. -The hook variable `java-mode-hook' is run with no args, if that value -is bound and has a non-nil value. Also the common hook -`c-mode-common-hook' is run first. Note that this mode automatically -sets the \"java\" style before calling any hooks so be careful if you -set styles in `c-mode-common-hook'. +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `java-mode-hook'. Key bindings: \\{java-mode-map}" (interactive) (kill-all-local-variables) - (c-initialize-cc-mode) + (c-initialize-cc-mode t) (set-syntax-table java-mode-syntax-table) (setq major-mode 'java-mode mode-name "Java" local-abbrev-table java-mode-abbrev-table abbrev-mode t) (use-local-map java-mode-map) + (c-init-language-vars java-mode) (c-common-init 'java-mode) + (easy-menu-add c-java-menu) (cc-imenu-init cc-imenu-java-generic-expression) (run-hooks 'c-mode-common-hook) (run-hooks 'java-mode-hook) @@ -635,6 +846,13 @@ ;; Support for CORBA's IDL language +;;;###autoload +(defvar idl-mode-syntax-table nil + "Syntax table used in idl-mode buffers.") +(or idl-mode-syntax-table + (setq idl-mode-syntax-table + (funcall (c-lang-const c-make-mode-syntax-table idl)))) + (defvar idl-mode-abbrev-table nil "Abbreviation table used in idl-mode buffers.") (c-define-abbrev-table 'idl-mode-abbrev-table nil) @@ -648,11 +866,13 @@ ) (easy-menu-define c-idl-menu idl-mode-map "IDL Mode Commands" - (c-mode-menu "IDL")) + (cons "IDL" (c-lang-const c-mode-menu idl))) + +;;;###autoload (add-to-list 'auto-mode-alist '("\\.idl\\'" . idl-mode)) ;;;###autoload (defun idl-mode () - "Major mode for editing CORBA's IDL code. + "Major mode for editing CORBA's IDL, PSDL and CIDL code. To submit a problem report, enter `\\[c-submit-bug-report]' from an idl-mode buffer. This automatically sets up a mail buffer with version information already added. You just need to add a description @@ -661,22 +881,23 @@ To see what version of CC Mode you are running, enter `\\[c-version]'. -The hook variable `idl-mode-hook' is run with no args, if that -variable is bound and has a non-nil value. Also the hook -`c-mode-common-hook' is run first. +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `idl-mode-hook'. Key bindings: \\{idl-mode-map}" (interactive) (kill-all-local-variables) - (c-initialize-cc-mode) + (c-initialize-cc-mode t) (set-syntax-table idl-mode-syntax-table) (setq major-mode 'idl-mode mode-name "IDL" local-abbrev-table idl-mode-abbrev-table) (use-local-map idl-mode-map) + (c-init-language-vars idl-mode) (c-common-init 'idl-mode) - ;;(cc-imenu-init cc-imenu-idl-generic-expression) ;FIXME + (easy-menu-add c-idl-menu) + ;;(cc-imenu-init cc-imenu-idl-generic-expression) ;TODO (run-hooks 'c-mode-common-hook) (run-hooks 'idl-mode-hook) (c-update-modeline)) @@ -684,6 +905,13 @@ ;; Support for Pike +;;;###autoload +(defvar pike-mode-syntax-table nil + "Syntax table used in pike-mode buffers.") +(or pike-mode-syntax-table + (setq pike-mode-syntax-table + (funcall (c-lang-const c-make-mode-syntax-table pike)))) + (defvar pike-mode-abbrev-table nil "Abbreviation table used in pike-mode buffers.") (c-define-abbrev-table 'pike-mode-abbrev-table @@ -699,7 +927,10 @@ (define-key pike-mode-map "\C-c\C-e" 'c-macro-expand)) (easy-menu-define c-pike-menu pike-mode-map "Pike Mode Commands" - (c-mode-menu "Pike")) + (cons "Pike" (c-lang-const c-mode-menu pike))) + +;;;###autoload (add-to-list 'auto-mode-alist '("\\.\\(pike\\|pmod\\(.in\\)?\\)\\'" . pike-mode)) +;;;###autoload (add-to-list 'interpreter-mode-alist '(("pike" . pike-mode))) ;;;###autoload (defun pike-mode () @@ -712,28 +943,128 @@ To see what version of CC Mode you are running, enter `\\[c-version]'. -The hook variable `pike-mode-hook' is run with no args, if that value -is bound and has a non-nil value. Also the common hook -`c-mode-common-hook' is run first. +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `pike-mode-hook'. Key bindings: \\{pike-mode-map}" (interactive) (kill-all-local-variables) - (c-initialize-cc-mode) + (c-initialize-cc-mode t) (set-syntax-table pike-mode-syntax-table) (setq major-mode 'pike-mode mode-name "Pike" local-abbrev-table pike-mode-abbrev-table abbrev-mode t) (use-local-map pike-mode-map) + (c-init-language-vars pike-mode) (c-common-init 'pike-mode) - ;;(cc-imenu-init cc-imenu-pike-generic-expression) ;FIXME + (easy-menu-add c-pike-menu) + ;;(cc-imenu-init cc-imenu-pike-generic-expression) ;TODO (run-hooks 'c-mode-common-hook) (run-hooks 'pike-mode-hook) (c-update-modeline)) +;; Support for awk. This is purposely disabled for older (X)Emacsen which +;; don't support syntax-table properties. + +(if (not (memq 'syntax-properties c-emacs-features)) + (autoload 'awk-mode "awk-mode.el" "Major mode for editing AWK code. +To submit a problem report, enter `\\[c-submit-bug-report]' from an +awk-mode buffer. This automatically sets up a mail buffer with version +information already added. You just need to add a description of the +problem, including a reproducible test case and send the message. + +To see what version of CC Mode you are running, enter `\\[c-version]'. + +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `awk-mode-hook'. +" t) + (defvar awk-mode-abbrev-table nil + "Abbreviation table used in awk-mode buffers.") + (c-define-abbrev-table 'awk-mode-abbrev-table + '(("else" "else" c-electric-continued-statement 0) + ("while" "while" c-electric-continued-statement 0))) + + (defvar awk-mode-map () + "Keymap used in awk-mode buffers.") + (if awk-mode-map + nil + (setq awk-mode-map (c-make-inherited-keymap)) + ;; add bindings which are only useful for awk. + (define-key awk-mode-map "#" 'self-insert-command) + (define-key awk-mode-map "/" 'self-insert-command) + (define-key awk-mode-map "*" 'self-insert-command) + (define-key awk-mode-map "\C-c\C-n" 'undefined) ; #if doesn't exist in awk. + (define-key awk-mode-map "\C-c\C-p" 'undefined) + (define-key awk-mode-map "\C-c\C-u" 'undefined) + (define-key awk-mode-map "\M-a" 'undefined) ; c-awk-beginning-of-statement isn't yet implemented. + (define-key awk-mode-map "\M-e" 'undefined) ; c-awk-end-of-statement isn't yet implemented. + (define-key awk-mode-map "\C-\M-a" 'c-awk-beginning-of-defun) + (define-key awk-mode-map "\C-\M-e" 'c-awk-end-of-defun)) + + (easy-menu-define c-awk-menu awk-mode-map "AWK Mode Commands" + (cons "AWK" (c-lang-const c-mode-menu awk))) + +;; In XEmacs >= 21.5 modes should add their own entries to +;; `auto-mode-alist' and `interpreter-mode-alist'. +;;;###autoload (add-to-list 'auto-mode-alist '("\\.awk\\'" . awk-mode)) +;;;###autoload (add-to-list 'interpreter-mode-alist '(("awk" . awk-mode) ("mawk" . awk-mode) ("nawk" . awk-mode) ("gawk" . awk-mode))) + +;;;###autoload + (defun awk-mode () + "Major mode for editing AWK code. +To submit a problem report, enter `\\[c-submit-bug-report]' from an +awk-mode buffer. This automatically sets up a mail buffer with version +information already added. You just need to add a description of the +problem, including a reproducible test case and send the message. + +To see what version of CC Mode you are running, enter `\\[c-version]'. + +The hook `c-mode-common-hook' is run with no args at mode +initialization, then `awk-mode-hook'. + +Key bindings: +\\{awk-mode-map}" + (interactive) + (require 'cc-awk) ; Added 2003/6/10. + (kill-all-local-variables) + (c-initialize-cc-mode t) + (set-syntax-table awk-mode-syntax-table) + (setq major-mode 'awk-mode + mode-name "AWK" + local-abbrev-table awk-mode-abbrev-table + abbrev-mode t) + (use-local-map awk-mode-map) + (c-init-language-vars awk-mode) + (c-common-init 'awk-mode) + ;; The rest of CC Mode does not (yet) use `font-lock-syntactic-keywords', + ;; so it's not set by `c-font-lock-init'. + (make-local-variable 'font-lock-syntactic-keywords) + (setq font-lock-syntactic-keywords + '((c-awk-set-syntax-table-properties + 0 (0) ; Everything on this line is a dummy. + nil t))) + (c-awk-unstick-NL-prop) + (add-hook 'before-change-functions 'c-awk-before-change nil t) + (add-hook 'after-change-functions 'c-awk-after-change nil t) + (c-save-buffer-state nil + (save-restriction + (widen) + (c-awk-clear-NL-props (point-min) (point-max)) + (c-awk-after-change (point-min) (point-max) 0))) ; Set syntax-table props. + + ;; Prevent Xemacs's buffer-syntactic-context being used. See the comment + ;; in cc-engine.el, just before (defun c-fast-in-literal ... + (defalias 'c-in-literal 'c-slow-in-literal) + + (run-hooks 'c-mode-common-hook) + (run-hooks 'awk-mode-hook) + (c-update-modeline)) +) ;; closes the (if (not (memq 'syntax-properties c-emacs-features)) + + ;; bug reporting (defconst c-mode-help-address @@ -764,51 +1095,57 @@ (and (if (y-or-n-p "Do you want to submit a report on CC Mode? ") t (message "") nil) - (require 'reporter) (reporter-submit-bug-report c-mode-help-address - (concat "CC Mode " c-version " (" - (cond ((eq major-mode 'c++-mode) "C++") - ((eq major-mode 'c-mode) "C") - ((eq major-mode 'objc-mode) "ObjC") - ((eq major-mode 'java-mode) "Java") - ((eq major-mode 'idl-mode) "IDL") - ((eq major-mode 'pike-mode) "Pike") - ) - ")") + (concat "CC Mode " c-version " (" mode-name ")") (let ((vars (append - ;; report only the vars that affect indentation c-style-variables - '(c-delete-function + '(c-buffer-is-cc-mode + c-tab-always-indent + c-syntactic-indentation + c-syntactic-indentation-in-macros + c-ignore-auto-fill + c-auto-align-backslashes + c-backspace-function + c-delete-function c-electric-pound-behavior - c-indent-comments-syntactically-p - c-tab-always-indent + c-default-style + c-enable-xemacs-performance-kludge-p + c-old-style-variable-behavior defun-prompt-regexp tab-width comment-column parse-sexp-ignore-comments + parse-sexp-lookup-properties + lookup-syntax-properties ;; A brain-damaged XEmacs only variable that, if ;; set to nil can cause all kinds of chaos. signal-error-on-buffer-boundary ;; Variables that affect line breaking and comments. + auto-fill-mode auto-fill-function filladapt-mode comment-multi-line comment-start-skip fill-prefix + fill-column paragraph-start adaptive-fill-mode adaptive-fill-regexp) nil))) - (delq 'c-special-indent-hook vars) - (mapcar (lambda (var) (unless (boundp var) (delq var vars))) + (mapcar (lambda (var) (unless (boundp var) + (setq vars (delq var vars)))) '(signal-error-on-buffer-boundary filladapt-mode - defun-prompt-regexp)) + defun-prompt-regexp + font-lock-mode + font-lock-maximum-decoration + parse-sexp-lookup-properties + lookup-syntax-properties)) vars) (lambda () (run-hooks 'c-prepare-bug-report-hooks) - (insert (format "Buffer Style: %s\n\nc-emacs-features: %s\n" + (insert (format "Buffer Style: %s\nc-emacs-features: %s\n" style c-features)))))))
--- a/lisp/progmodes/cc-styles.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-styles.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,9 @@ ;;; cc-styles.el --- support for styles in CC Mode -;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1992-1997 Barry A. Warsaw +;; Authors: 1998- Martin Stjernholm +;; 1992-1999 Barry A. Warsaw ;; 1987 Dave Detlefs and Stewart Clamen ;; 1985 Richard M. Stallman ;; Maintainer: bug-cc-mode@gnu.org @@ -39,10 +38,9 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) (cc-require 'cc-defs) -(cc-require 'cc-langs) (cc-require 'cc-vars) (cc-require 'cc-align) ;; cc-align is only indirectly required: Styles added with @@ -135,6 +133,12 @@ (namespace-open . +) (innamespace . c-lineup-whitesmith-in-block) (namespace-close . +) + (module-open . +) + (inmodule . c-lineup-whitesmith-in-block) + (module-close . +) + (composition-open . +) + (incomposition . c-lineup-whitesmith-in-block) + (composition-close . +) )) ) ("ellemtel" @@ -242,6 +246,8 @@ ;; Functions that manipulate styles (defun c-set-style-1 (conscell dont-override) ;; Set the style for one variable + ;; + ;; This function does not do any hidden buffer changes. (let ((attr (car conscell)) (val (cdr conscell))) (cond @@ -285,6 +291,8 @@ (defun c-get-style-variables (style basestyles) ;; Return all variables in a style by resolving inheritances. + ;; + ;; This function does not do any hidden buffer changes. (if (not style) (copy-alist c-fallback-style) (let ((vars (cdr (or (assoc (downcase style) c-style-alist) @@ -367,10 +375,10 @@ (c-keep-region-active)) ;;;###autoload -(defun c-add-style (style descrip &optional set-p) +(defun c-add-style (style description &optional set-p) "Adds a style to `c-style-alist', or updates an existing one. -STYLE is a string identifying the style to add or update. DESCRIP is -an association list describing the style and must be of the form: +STYLE is a string identifying the style to add or update. DESCRIPTION +is an association list describing the style and must be of the form: ([BASESTYLE] (VARIABLE . VALUE) [(VARIABLE . VALUE) ...]) @@ -380,14 +388,14 @@ (interactive (let ((stylename (completing-read "Style to add: " c-style-alist nil nil nil 'c-set-style-history)) - (description (eval-minibuffer "Style description: "))) - (list stylename description + (descr (eval-minibuffer "Style description: "))) + (list stylename descr (y-or-n-p "Set the style too? ")))) (setq style (downcase style)) (let ((s (assoc style c-style-alist))) (if s - (setcdr s (copy-alist descrip)) ; replace - (setq c-style-alist (cons (cons style descrip) c-style-alist)))) + (setcdr s (copy-alist description)) ; replace + (setq c-style-alist (cons (cons style description) c-style-alist)))) (and set-p (c-set-style style))) @@ -396,6 +404,8 @@ (defun c-read-offset (langelem) ;; read new offset value for LANGELEM from minibuffer. return a ;; legal value only + ;; + ;; This function does not do any hidden buffer changes. (let* ((oldoff (cdr-safe (or (assq langelem c-offsets-alist) (assq langelem (get 'c-offsets-alist 'c-stylevar-fallback))))) @@ -446,9 +456,10 @@ ;; on the syntactic analysis list for the current ;; line (and c-buffer-is-cc-mode - (let* ((syntax (c-guess-basic-syntax)) - (len (length syntax)) - (ic (format "%s" (car (nth (1- len) syntax))))) + (c-save-buffer-state + ((syntax (c-guess-basic-syntax)) + (len (length syntax)) + (ic (format "%s" (car (nth (1- len) syntax))))) (cons ic 0))) ))) (offset (c-read-offset langelem))) @@ -471,6 +482,9 @@ "Fix things up for paragraph recognition and filling inside comments by incorporating the value of `c-comment-prefix-regexp' in the relevant variables." + ;; + ;; This function does not do any hidden buffer changes. + (setq c-current-comment-prefix (if (listp c-comment-prefix-regexp) (cdr-safe (or (assoc major-mode c-comment-prefix-regexp) @@ -479,11 +493,11 @@ (let ((comment-line-prefix (concat "[ \t]*\\(" c-current-comment-prefix "\\)[ \t]*"))) (setq paragraph-start (concat comment-line-prefix - (c-lang-var paragraph-start) + c-paragraph-start "\\|" page-delimiter) paragraph-separate (concat comment-line-prefix - (c-lang-var paragraph-separate) + c-paragraph-separate "\\|" page-delimiter) paragraph-ignore-fill-prefix t @@ -521,6 +535,8 @@ ;; This function is intended to be used explicitly by the end user ;; only. ;; + ;; This function does not do any hidden buffer changes. + ;; The default configuration already handles C++ comments, but we ;; need to add handling of C block comments. A new filladapt token ;; `c-comment' is added for that. @@ -549,6 +565,8 @@ ;; crucial because future c-set-style calls will always reset the ;; variables first to the `cc-mode' style before instituting the new ;; style. Only do this once! + ;; + ;; This function does not do any hidden buffer changes. (unless (get 'c-initialize-builtin-style 'is-run) (put 'c-initialize-builtin-style 'is-run t) ;;(c-initialize-cc-mode) @@ -573,24 +591,16 @@ (defun c-make-styles-buffer-local (&optional this-buf-only-p) "Make all CC Mode style variables buffer local. -If you edit primarily one style of C (or C++, Objective-C, Java, etc) -code, you probably want style variables to be global. This is the -default. +If `this-buf-only-p' is non-nil, the style variables will be made +buffer local only in the current buffer. Otherwise they'll be made +permanently buffer local in any buffer that change their values. -If you edit many different styles of C (or C++, Objective-C, Java, -etc) at the same time, you probably want the CC Mode style variables -to be buffer local. If you do, it's advisable to set any CC Mode -style variables in a hook function (e.g. off of `c-mode-common-hook'), -instead of at the top level of your ~/.emacs file. +The buffer localness of the style variables are normally controlled +with the variable `c-style-variables-are-local-p', so there's seldom +any reason to call this function directly." + ;; + ;; This function does not do any hidden buffer changes. -This function makes all the CC Mode style variables buffer local. -Call it after CC Mode is loaded into your Emacs environment. -Conversely, set the variable `c-style-variables-are-local-p' to t in -your .emacs file, before CC Mode is loaded, and this function will be -automatically called when CC Mode is loaded. - -Optional argument, when non-nil, means use `make-local-variable' -instead of `make-variable-buffer-local'." ;; style variables (let ((func (if this-buf-only-p 'make-local-variable
--- a/lisp/progmodes/cc-vars.el Thu Jul 03 01:59:39 2003 +0000 +++ b/lisp/progmodes/cc-vars.el Thu Jul 03 12:30:59 2003 +0000 @@ -1,10 +1,9 @@ ;;; cc-vars.el --- user customization variables for CC Mode -;; Copyright (C) 1985,1987,1992-2001 Free Software Foundation, Inc. +;; Copyright (C) 1985,1987,1992-2003 Free Software Foundation, Inc. -;; Authors: 2000- Martin Stjernholm -;; 1998-1999 Barry A. Warsaw and Martin Stjernholm -;; 1992-1997 Barry A. Warsaw +;; Authors: 1998- Martin Stjernholm +;; 1992-1999 Barry A. Warsaw ;; 1987 Dave Detlefs and Stewart Clamen ;; 1985 Richard M. Stallman ;; Maintainer: bug-cc-mode@gnu.org @@ -39,7 +38,7 @@ (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) - (require 'cc-bytecomp))) + (load "cc-bytecomp" nil t))) (cc-require 'cc-defs) @@ -50,9 +49,27 @@ ;; Pull in custom if it exists and is recent enough (the one in Emacs ;; 19.34 isn't). -(eval-when-compile - (require 'custom) - (require 'wid-edit)) +(eval + (cc-eval-when-compile + (condition-case nil + (progn + (require 'custom) + (or (fboundp 'defcustom) (error "")) + (require 'widget) + '(progn ; Compile in the require's. + (require 'custom) + (require 'widget))) + (error + (message "Warning: Compiling without Customize support \ +since a (good enough) custom library wasn't found") + (cc-bytecomp-defmacro define-widget (name class doc &rest args)) + (cc-bytecomp-defmacro defgroup (symbol members doc &rest args)) + (cc-bytecomp-defmacro defcustom (symbol value doc &rest args) + `(defvar ,symbol ,value ,doc)) + (cc-bytecomp-defmacro custom-declare-variable (symbol value doc + &rest args) + `(defvar ,(eval symbol) ,(eval value) ,doc)) + nil)))) (cc-eval-when-compile ;; Need the function form of `backquote', which isn't standardized @@ -66,7 +83,7 @@ ;;; Helpers -;; This widget will show up in newer versions of the Custom library +;; This widget exists in newer versions of the Custom library (or (get 'other 'widget-type) (define-widget 'other 'sexp "Matches everything, but doesn't let the user edit the value. @@ -104,13 +121,51 @@ :tag "Optional integer" :match (lambda (widget value) (or (integerp value) (null value)))) +(define-widget 'c-symbol-list 'sexp + "A single symbol or a list of symbols." + :tag "Symbols separated by spaces" + :validate 'widget-field-validate + :match + (lambda (widget value) + (or (symbolp value) + (catch 'ok + (while (listp value) + (unless (symbolp (car value)) + (throw 'ok nil)) + (setq value (cdr value))) + (null value)))) + :value-to-internal + (lambda (widget value) + (cond ((null value) + "") + ((symbolp value) + (symbol-name value)) + ((consp value) + (mapconcat (lambda (symbol) + (symbol-name symbol)) + value + " ")) + (t + value))) + :value-to-external + (lambda (widget value) + (if (stringp value) + (let (list end) + (while (string-match "\\S +" value end) + (setq list (cons (intern (match-string 0 value)) list) + end (match-end 0))) + (if (and list (not (cdr list))) + (car list) + (nreverse list))) + value))) + (defvar c-style-variables '(c-basic-offset c-comment-only-line-offset c-indent-comment-alist c-indent-comments-syntactically-p c-block-comment-prefix - c-comment-prefix-regexp c-cleanup-list c-hanging-braces-alist - c-hanging-colons-alist c-hanging-semi&comma-criteria c-backslash-column - c-backslash-max-column c-special-indent-hook c-label-minimum-indentation - c-offsets-alist) + c-comment-prefix-regexp c-doc-comment-style c-cleanup-list + c-hanging-braces-alist c-hanging-colons-alist + c-hanging-semi&comma-criteria c-backslash-column c-backslash-max-column + c-special-indent-hook c-label-minimum-indentation c-offsets-alist) "List of the style variables.") (defvar c-fallback-style nil) @@ -152,6 +207,7 @@ (defun c-valid-offset (offset) "Return non-nil iff OFFSET is a valid offset for a syntactic symbol. See `c-offsets-alist'." + ;; This function does not do any hidden buffer changes. (or (eq offset '+) (eq offset '-) (eq offset '++) @@ -268,7 +324,7 @@ of the macro content. The default context inside the macro is the same as the top level, so if it contains \"bare\" statements they might be indented wrongly, although there are special cases that -handles this in most cases. If this problem occurs, it's usually +handle this in most cases. If this problem occurs, it's usually countered easily by surrounding the statements by a block \(or even better with the \"do { ... } while \(0)\" trick)." :type 'boolean @@ -434,7 +490,7 @@ should not match any surrounding whitespace. Note that CC Mode uses this variable to set many other variables that -handles the paragraph filling. That's done at mode initialization or +handle the paragraph filling. That's done at mode initialization or when you switch to a style which sets this variable. Thus, if you change it in some other way, e.g. interactively in a CC Mode buffer, you will need to do \\[c-mode] (or whatever mode you're currently @@ -466,6 +522,74 @@ (const :format "Other " other) (regexp :format "%v")))) :group 'c) +(defcustom-c-stylevar c-doc-comment-style + '((java-mode . javadoc) + (pike-mode . autodoc)) + "*Specifies documentation comment style(s) to recognize. +This is primarily used to fontify doc comments and the markup within +them, e.g. Javadoc comments. + +The value can be any of the following symbols for various known doc +comment styles: + + javadoc -- Javadoc style for \"/** ... */\" comments (default in Java mode). + autodoc -- Pike autodoc style for \"//! ...\" comments (default in Pike mode). + +The value may also be a list of doc comment styles, in which case all +of them are recognized simultaneously (presumably with markup cues +that don't conflict). + +The value may also be an association list to specify different doc +comment styles for different languages. The symbol for the major mode +is then looked up in the alist, and the value of that element is +interpreted as above if found. If it isn't found then the symbol +`other' is looked up and its value is used instead. + +Note that CC Mode uses this variable to set other variables that +handle fontification etc. That's done at mode initialization or when +you switch to a style which sets this variable. Thus, if you change +it in some other way, e.g. interactively in a CC Mode buffer, you will +need to do \\[java-mode] (or whatever mode you're currently using) to +reinitialize. + +Note also that when CC Mode starts up, the other variables are +modified before the mode hooks are run. If you change this variable +in a mode hook, you have to call `c-setup-doc-comment-style' +afterwards to redo that work." + ;; Symbols other than those documented above may be used on this + ;; variable. If a variable exists that has that name with + ;; "-font-lock-keywords" appended, it's value is prepended to the + ;; font lock keywords list. If it's a function then it's called and + ;; the result is prepended. + :type '(radio + (c-symbol-list :tag "Doc style(s) in all modes") + (list + :tag "Mode-specific doc styles" + (set + :inline t :format "%v" + (cons :format "%v" + (const :format "C " c-mode) + (c-symbol-list :format "%v")) + (cons :format "%v" + (const :format "C++ " c++-mode) + (c-symbol-list :format "%v")) + (cons :format "%v" + (const :format "ObjC " objc-mode) + (c-symbol-list :format "%v")) + (cons :format "%v" + (const :format "Java " java-mode) + (c-symbol-list :format "%v")) + (cons :format "%v" + (const :format "IDL " idl-mode) + (c-symbol-list :format "%v")) + (cons :format "%v" + (const :format "Pike " pike-mode) + (c-symbol-list :format "%v")) + (cons :format "%v" + (const :format "Other " other) + (c-symbol-list :format "%v"))))) + :group 'c) + (defcustom c-ignore-auto-fill '(string cpp code) "*List of contexts in which automatic filling never occurs. If Auto Fill mode is active, it will be temporarily disabled if point @@ -559,9 +683,13 @@ (defcustom-c-stylevar c-hanging-braces-alist '((brace-list-open) (brace-entry-open) + (statement-cont) (substatement-open after) (block-close . c-snug-do-while) (extern-lang-open after) + (namespace-open after) + (module-open after) + (composition-open after) (inexpr-class-open after) (inexpr-class-close before)) "*Controls the insertion of newlines before and after braces @@ -575,16 +703,13 @@ If the context is not found, the default is to insert a newline both before and after the brace. -SYNTACTIC-SYMBOL can be any of: defun-open, defun-close, class-open, -class-close, inline-open, inline-close, block-open, block-close, -substatement-open, statement-case-open, extern-lang-open, -extern-lang-close, brace-list-open, brace-list-close, -brace-list-intro, brace-entry-open, namespace-open, namespace-close, -inexpr-class-open, or inexpr-class-close. See `c-offsets-alist' for -details, except for inexpr-class-open and inexpr-class-close, which -doesn't have any corresponding symbols there. Those two symbols are -used for the opening and closing braces, respectively, of anonymous -inner classes in Java. +SYNTACTIC-SYMBOL can be statement-cont, brace-list-intro, +inexpr-class-open, inexpr-class-close, and any of the *-open and +*-close symbols. See `c-offsets-alist' for details, except for +inexpr-class-open and inexpr-class-close, which doesn't have any +corresponding symbols there. Those two symbols are used for the +opening and closing braces, respectively, of anonymous inner classes +in Java. ACTION can be either a function symbol or a list containing any combination of the symbols `before' or `after'. If the list is empty, @@ -616,11 +741,13 @@ class-open class-close inline-open inline-close block-open block-close - substatement-open statement-case-open - extern-lang-open extern-lang-close + statement-cont substatement-open statement-case-open brace-list-open brace-list-close brace-list-intro brace-entry-open + extern-lang-open extern-lang-close namespace-open namespace-close + module-open module-close + composition-open composition-close inexpr-class-open inexpr-class-close))) :group 'c) @@ -700,7 +827,7 @@ :group 'c) (defcustom c-delete-function 'delete-char - "*Function called by `c-electric-delete' when deleting forwards." + "*Function called by `c-electric-delete-forward' when deleting forwards." :type 'function :group 'c) @@ -928,11 +1055,11 @@ (arglist-cont . (c-lineup-gcc-asm-reg 0)) ;; Relpos: At the first token after the open paren. (arglist-cont-nonempty . (c-lineup-gcc-asm-reg c-lineup-arglist)) - ;; Relpos: Boi at the open paren, or at the first non-ws after - ;; the open paren of the surrounding sexp, whichever is later. + ;; Relpos: At the containing statement(*). + ;; 2nd pos: At the open paren. (arglist-close . +) - ;; Relpos: Boi at the open paren, or at the first non-ws after - ;; the open paren of the surrounding sexp, whichever is later. + ;; Relpos: At the containing statement(*). + ;; 2nd pos: At the open paren. (stream-op . c-lineup-streamop) ;; Relpos: Boi at the first stream op in the statement. (inclass . +) @@ -953,19 +1080,21 @@ (objc-method-call-cont . c-lineup-ObjC-method-call) ;; Relpos: At the open bracket. (extern-lang-open . 0) - ;; Relpos: Boi at the extern keyword. + (namespace-open . 0) + (module-open . 0) + (composition-open . 0) + ;; Relpos: Boi at the extern/namespace/etc keyword. (extern-lang-close . 0) - ;; Relpos: Boi at the corresponding extern keyword. + (namespace-close . 0) + (module-close . 0) + (composition-close . 0) + ;; Relpos: Boi at the corresponding extern/namespace/etc keyword. (inextern-lang . +) - ;; Relpos: At the extern block open brace if it's at boi, - ;; otherwise boi at the extern keyword. - (namespace-open . 0) - ;; Relpos: Boi at the namespace keyword. - (namespace-close . 0) - ;; Relpos: Boi at the corresponding namespace keyword. (innamespace . +) - ;; Relpos: At the namespace block open brace if it's at boi, - ;; otherwise boi at the namespace keyword. + (inmodule . +) + (incomposition . +) + ;; Relpos: At the extern/namespace/etc block open brace if it's + ;; at boi, otherwise boi at the keyword. (template-args-cont . (c-lineup-template-args +)) ;; Relpos: Boi at the decl start. This might be changed; the ;; logical position is clearly the opening '<'. @@ -1014,7 +1143,7 @@ positive or negative multiple of `c-basic-offset' is added; 1, -1, 2, -2, 0.5, and -0.5, respectively. -If OFFSET is a vector, its first element, which must be an integer, +If OFFSET is a vector, it's first element, which must be an integer, is used as an absolute indentation column. This overrides all relative offsets. If there are several syntactic elements which evaluates to absolute indentation columns, the first one takes @@ -1103,14 +1232,19 @@ objc-method-intro -- The first line of an Objective-C method definition. objc-method-args-cont -- Lines continuing an Objective-C method definition. objc-method-call-cont -- Lines continuing an Objective-C method call. - extern-lang-open -- Brace that opens an external language block. - extern-lang-close -- Brace that closes an external language block. + extern-lang-open -- Brace that opens an \"extern\" block. + extern-lang-close -- Brace that closes an \"extern\" block. inextern-lang -- Analogous to the `inclass' syntactic symbol, - but used inside extern constructs. - namespace-open -- Brace that opens a C++ namespace block. - namespace-close -- Brace that closes a C++ namespace block. - innamespace -- Analogous to the `inextern-lang' syntactic - symbol, but used inside C++ namespace constructs. + but used inside \"extern\" blocks. + namespace-open, namespace-close, innamespace + -- Similar to the three `extern-lang' symbols, but for + C++ \"namespace\" blocks. + module-open, module-close, inmodule + -- Similar to the three `extern-lang' symbols, but for + CORBA IDL \"module\" blocks. + composition-open, composition-close, incomposition + -- Similar to the three `extern-lang' symbols, but for + CORBA CIDL \"composition\" blocks. template-args-cont -- C++ template argument list continuations. inlambda -- In the header or body of a lambda function. lambda-intro-cont -- Continuation of the header of a lambda function. @@ -1144,18 +1278,24 @@ are made buffer local when this file is loaded, and once buffer localized, they cannot be made global again. +This variable must be set appropriately before CC Mode is loaded. + The list of variables to buffer localize are: - c-offsets-alist c-basic-offset c-comment-only-line-offset + c-indent-comment-alist + c-indent-comments-syntactically-p c-block-comment-prefix c-comment-prefix-regexp + c-doc-comment-style c-cleanup-list c-hanging-braces-alist c-hanging-colons-alist c-hanging-semi&comma-criteria c-backslash-column + c-backslash-max-column c-label-minimum-indentation + c-offsets-alist c-special-indent-hook c-indentation-style" :type 'boolean @@ -1193,7 +1333,7 @@ (defcustom c-mode-common-hook nil "*Hook called by all CC Mode modes for common initializations." - :type '(hook :format "%{CC Mode Common Hook%}:\n%v") + :type 'hook :group 'c) (defcustom c-initialization-hook nil @@ -1230,6 +1370,106 @@ state. Set this variable only if your configuration has stopped working due to this change.") +(define-widget 'c-extra-types-widget 'radio + ;; Widget for a list of regexps for the extra types. + :args '((const :tag "none" nil) + (repeat :tag "types" regexp))) + +(eval-and-compile + ;; XEmacs 19 evaluates this at compile time below, while most other + ;; versions delays the evaluation until the package is loaded. + (defun c-make-font-lock-extra-types-blurb (mode1 mode2 example) + (concat "\ +*List of extra types (aside from the type keywords) to recognize in " +mode1 " mode. +Each list item should be a regexp matching a single identifier. +" example " + +On decoration level 3 (and higher, where applicable), a method is used +that finds most types and declarations by syntax alone. This variable +is still used as a first step, but other types are recognized +correctly anyway in most cases. Therefore this variable should be +fairly restrictive and not contain patterns that are uncertain. + +Note that this variable is only consulted when the major mode is +initialized. If you change it later you have to reinitialize CC Mode +by doing \\[" mode2 "]. + +Despite the name, this variable is not only used for font locking but +also elsewhere in CC Mode to tell types from other identifiers."))) + +;; Note: Most of the variables below are also defined in font-lock.el +;; in older versions in Emacs, so depending on the load order we might +;; not install the values below. There's no kludge to cope with this +;; (as opposed to the *-font-lock-keywords-* variables) since the old +;; values works fairly well anyway. + +(defcustom c-font-lock-extra-types + '("FILE" "\\sw+_t" + "bool" "complex" "imaginary" ; Defined in C99. + ;; I do not appreciate the following very Emacs-specific luggage + ;; in the default value, but otoh it can hardly get in the way for + ;; other users, and removing it would cause unnecessary grief for + ;; the old timers that are used to it. /mast + "Lisp_Object") + (c-make-font-lock-extra-types-blurb "C" "c-mode" +"For example, a value of (\"FILE\" \"\\\\sw+_t\") means the word FILE +and words ending in _t are treated as type names.") + :type 'c-extra-types-widget + :group 'c) + +(defcustom c++-font-lock-extra-types + '("\\sw+_t" + "\\([iof]\\|str\\)+stream\\(buf\\)?" "ios" + "string" "rope" + "list" "slist" + "deque" "vector" "bit_vector" + "set" "multiset" + "map" "multimap" + "hash\\(_\\(m\\(ap\\|ulti\\(map\\|set\\)\\)\\|set\\)\\)?" + "stack" "queue" "priority_queue" + "type_info" + "iterator" "const_iterator" "reverse_iterator" "const_reverse_iterator" + "reference" "const_reference") + (c-make-font-lock-extra-types-blurb "C++" "c++-mode" +"For example, a value of (\"string\") means the word string is treated +as a type name.") + :type 'c-extra-types-widget + :group 'c) + +(defcustom objc-font-lock-extra-types + (list (concat "[" c-upper "]\\sw*[" c-lower "]\\sw*")) + (c-make-font-lock-extra-types-blurb "ObjC" "objc-mode" (concat +"For example, a value of (\"[" c-upper "]\\\\sw*[" c-lower "]\\\\sw*\") means +capitalized words are treated as type names (the requirement for a +lower case char is to avoid recognizing all-caps macro and constant +names).")) + :type 'c-extra-types-widget + :group 'c) + +(defcustom java-font-lock-extra-types + (list (concat "[" c-upper "]\\sw*[" c-lower "]\\sw*")) + (c-make-font-lock-extra-types-blurb "Java" "java-mode" (concat +"For example, a value of (\"[" c-upper "]\\\\sw*[" c-lower "]\\\\sw*\") means +capitalized words are treated as type names (the requirement for a +lower case char is to avoid recognizing all-caps constant names).")) + :type 'c-extra-types-widget + :group 'c) + +(defcustom idl-font-lock-extra-types nil + (c-make-font-lock-extra-types-blurb "IDL" "idl-mode" "") + :type 'c-extra-types-widget + :group 'c) + +(defcustom pike-font-lock-extra-types + (list (concat "[" c-upper "]\\sw*[" c-lower "]\\sw*")) + (c-make-font-lock-extra-types-blurb "Pike" "pike-mode" (concat +"For example, a value of (\"[" c-upper "]\\\\sw*[" c-lower "]\\\\sw*\") means +capitalized words are treated as type names (the requirement for a +lower case char is to avoid recognizing all-caps macro and constant +names).")) + :type 'c-extra-types-widget + :group 'c) ;; Non-customizable variables, still part of the interface to CC Mode @@ -1254,10 +1494,35 @@ as designated in the variable `c-file-style'.") (make-variable-buffer-local 'c-file-offsets) -(defvar c-syntactic-context nil - "Variable containing syntactic analysis list during indentation. -This is always bound dynamically. It should never be set statically -\(e.g. with `setq').") +;; It isn't possible to specify a docstring without specifying an +;; initial value with `defvar', so the following two variables have +;; only doc comments even though they are part of the API. It's +;; really good not to have an initial value for variables like these +;; that always should be dynamically bound, so it's worth the +;; inconvenience. + +(cc-bytecomp-defvar c-syntactic-context) +(defvar c-syntactic-context) +;; Variable containing the syntactic analysis list during indentation. +;; It is a list with one element for each found syntactic symbol. +;; Each element is a list with the symbol name in the first position, +;; followed by zero or more elements containing any additional info +;; associated with the syntactic symbol. Specifically, the second +;; element is the relpos (a.k.a. anchor position), or nil if there +;; isn't any. See the comments in the `c-offsets-alist' variable for +;; more detailed info about the data each syntactic symbol provides. +;; +;; This is always bound dynamically. It should never be set +;; statically (e.g. with `setq'). + +(cc-bytecomp-defvar c-syntactic-element) +(defvar c-syntactic-element) +;; Variable containing the info regarding the current syntactic +;; element during calls to the lineup functions. The value is one of +;; the elements in the list in `c-syntactic-context'. +;; +;; This is always bound dynamically. It should never be set +;; statically (e.g. with `setq'). (defvar c-indentation-style nil "Name of the currently installed style. @@ -1268,62 +1533,139 @@ Set from `c-comment-prefix-regexp' at mode initialization.") (make-variable-buffer-local 'c-current-comment-prefix) -(defvar c-buffer-is-cc-mode nil - "Non-nil for all buffers with a major mode derived from CC Mode. -Otherwise, this variable is nil. I.e. this variable is non-nil for -`c-mode', `c++-mode', `objc-mode', `java-mode', `idl-mode', -`pike-mode', and any other non-CC Mode mode that calls -`c-initialize-cc-mode' (e.g. `awk-mode'). The value is the mode -symbol itself (i.e. `c-mode' etc) of the original CC Mode mode, or -just t if it's not known.") -(make-variable-buffer-local 'c-buffer-is-cc-mode) - -;; Have to make `c-buffer-is-cc-mode' permanently local so that it -;; survives the initialization of the derived mode. -(put 'c-buffer-is-cc-mode 'permanent-local t) - ;; Figure out what features this Emacs has -;;;###autoload + +(cc-bytecomp-defvar open-paren-in-column-0-is-defun-start) + (defconst c-emacs-features - (let ((infodock-p (boundp 'infodock-version)) - (comments - ;; XEmacs 19 and beyond use 8-bit modify-syntax-entry flags. - ;; Emacs 19 uses a 1-bit flag. We will have to set up our - ;; syntax tables differently to handle this. - (let ((table (copy-syntax-table)) - entry) - (modify-syntax-entry ?a ". 12345678" table) - (cond - ;; XEmacs 19, and beyond Emacs 19.34 - ((arrayp table) - (setq entry (aref table ?a)) - ;; In Emacs, table entries are cons cells - (if (consp entry) (setq entry (car entry)))) - ;; XEmacs 20 - ((fboundp 'get-char-table) (setq entry (get-char-table ?a table))) - ;; before and including Emacs 19.34 - ((and (fboundp 'char-table-p) - (char-table-p table)) - (setq entry (car (char-table-range table [?a])))) - ;; incompatible - (t (error "CC Mode is incompatible with this version of Emacs"))) - (if (= (logand (lsh entry -16) 255) 255) - '8-bit - '1-bit)))) - (if infodock-p - (list comments 'infodock) - (list comments))) - "A list of features extant in the Emacs you are using. + (let (list) + + (if (boundp 'infodock-version) + ;; I've no idea what this actually is, but it's legacy. /mast + (setq list (cons 'infodock list))) + + ;; XEmacs 19 and beyond use 8-bit modify-syntax-entry flags. + ;; Emacs 19 uses a 1-bit flag. We will have to set up our + ;; syntax tables differently to handle this. + (let ((table (copy-syntax-table)) + entry) + (modify-syntax-entry ?a ". 12345678" table) + (cond + ;; XEmacs 19, and beyond Emacs 19.34 + ((arrayp table) + (setq entry (aref table ?a)) + ;; In Emacs, table entries are cons cells + (if (consp entry) (setq entry (car entry)))) + ;; XEmacs 20 + ((fboundp 'get-char-table) (setq entry (get-char-table ?a table))) + ;; before and including Emacs 19.34 + ((and (fboundp 'char-table-p) + (char-table-p table)) + (setq entry (car (char-table-range table [?a])))) + ;; incompatible + (t (error "CC Mode is incompatible with this version of Emacs"))) + (setq list (cons (if (= (logand (lsh entry -16) 255) 255) + '8-bit + '1-bit) + list))) + + (let ((buf (generate-new-buffer "test")) + parse-sexp-lookup-properties + parse-sexp-ignore-comments + lookup-syntax-properties) + (save-excursion + (set-buffer buf) + (set-syntax-table (make-syntax-table)) + + ;; For some reason we have to set some of these after the + ;; buffer has been made current. (Specifically, + ;; `parse-sexp-ignore-comments' in Emacs 21.) + (setq parse-sexp-lookup-properties t + parse-sexp-ignore-comments t + lookup-syntax-properties t) + + ;; Find out if the `syntax-table' text property works. + (modify-syntax-entry ?< ".") + (modify-syntax-entry ?> ".") + (insert "<()>") + (c-mark-<-as-paren 1) + (c-mark->-as-paren 4) + (goto-char 1) + (c-forward-sexp) + (if (= (point) 5) + (setq list (cons 'syntax-properties list))) + + ;; Find out if generic comment delimiters work. + (c-safe + (modify-syntax-entry ?x "!") + (if (string-match "\\s!" "x") + (setq list (cons 'gen-comment-delim list)))) + + ;; Find out if generic string delimiters work. + (c-safe + (modify-syntax-entry ?x "|") + (if (string-match "\\s|" "x") + (setq list (cons 'gen-string-delim list)))) + + ;; See if `open-paren-in-column-0-is-defun-start' exists and + ;; isn't buggy. + (when (boundp 'open-paren-in-column-0-is-defun-start) + (let ((open-paren-in-column-0-is-defun-start nil) + (parse-sexp-ignore-comments t)) + (set-syntax-table (make-syntax-table)) + (modify-syntax-entry ?\' "\"") + (cond + ;; XEmacs. Afaik this is currently an Emacs-only + ;; feature, but it's good to be prepared. + ((memq '8-bit list) + (modify-syntax-entry ?/ ". 1456") + (modify-syntax-entry ?* ". 23")) + ;; Emacs + ((memq '1-bit list) + (modify-syntax-entry ?/ ". 124b") + (modify-syntax-entry ?* ". 23"))) + (modify-syntax-entry ?\n "> b") + (insert "/* '\n () */") + (backward-sexp) + (if (bobp) + (setq list (cons 'col-0-paren list)))) + (kill-buffer buf)) + + (set-buffer-modified-p nil)) + (kill-buffer buf)) + + ;; See if `parse-partial-sexp' returns the eighth element. + (when (c-safe (>= (length (save-excursion (parse-partial-sexp 1 1))) 10)) + (setq list (cons 'pps-extended-state list))) + + ;; See if POSIX char classes work. + (when (string-match "[[:alpha:]]" "a") + (setq list (cons 'posix-char-classes list))) + + list) + "A list of certain features in the (X)Emacs you are using. There are many flavors of Emacs out there, each with different -features supporting those needed by CC Mode. Here's the current -supported list, along with the values for this variable: +features supporting those needed by CC Mode. The following values +might be present: - XEmacs 19, 20, 21: (8-bit) - Emacs 19, 20: (1-bit) +'8-bit 8 bit syntax entry flags (XEmacs style). +'1-bit 1 bit syntax entry flags (Emacs style). +'syntax-properties It works to override the syntax for specific characters + in the buffer with the 'syntax-table property. +'gen-comment-delim Generic comment delimiters work + (i.e. the syntax class `!'). +'gen-string-delim Generic string delimiters work + (i.e. the syntax class `|'). +'pps-extended-state `parse-partial-sexp' returns a list with at least 10 + elements, i.e. it contains the position of the + start of the last comment or string. +'posix-char-classes The regexp engine understands POSIX character classes. +'col-0-paren It's possible to turn off the ad-hoc rule that a paren + in column zero is the start of a defun. +'infodock This is Infodock (based on XEmacs). -Infodock (based on XEmacs) has an additional symbol on this list: -`infodock'.") +'8-bit and '1-bit are mutually exclusive.") (cc-provide 'cc-vars)