From 4031fb7bac75dabf6c801721ef044a1d71fe6596 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Sun, 24 Aug 2014 20:50:11 +0000 Subject: [PATCH] Handle C++11's "auto" and "decltype" constructions. cc-engine.el (c-forward-type): Enhance to recognise and return 'decltype. (c-forward-decl-or-cast-1): New let variables backup-kwd-sym, prev-kwd-sym, new-style-auto. Enhance to handle the new "auto" keyword. cc-fonts.el (c-font-lock-declarations): Handle the "decltype" keyword. (c-font-lock-c++-new): Handle "decltype" constructions. cc-langs.el (c-auto-ops, c-auto-ops-re): New c-lang-defconsts/defvars. (c-haskell-op, c-haskell-op-re): New c-lang-defconsts/defvars. (c-typeof-kwds, c-typeof-key): New c-lang-defconsts/defvars. (c-typeless-decl-kwds): Append "auto" onto the C++ value. (c-not-decl-init-keywords): Also exclude c-typeof-kwds from value. --- lisp/ChangeLog | 16 +++++++++ lisp/progmodes/cc-engine.el | 69 ++++++++++++++++++++++++++++++++----- lisp/progmodes/cc-fonts.el | 12 ++++--- lisp/progmodes/cc-langs.el | 36 +++++++++++++++++-- 4 files changed, 118 insertions(+), 15 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 5b1c0b1b386..0b347f5a63a 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,21 @@ 2014-08-24 Alan Mackenzie + Handle C++11's "auto" and "decltype" constructions. + * progmodes/cc-engine.el (c-forward-type): Enhance to recognise + and return 'decltype. + (c-forward-decl-or-cast-1): New let variables backup-kwd-sym, + prev-kwd-sym, new-style-auto. Enhance to handle the new "auto" + keyword. + * progmodes/cc-fonts.el (c-font-lock-declarations): Handle the + "decltype" keyword. + (c-font-lock-c++-new): Handle "decltype" constructions. + * progmodes/cc-langs.el (c-auto-ops, c-auto-ops-re): New + c-lang-defconsts/defvars. + (c-haskell-op, c-haskell-op-re): New c-lang-defconsts/defvars. + (c-typeof-kwds, c-typeof-key): New c-lang-defconsts/defvars. + (c-typeless-decl-kwds): Append "auto" onto the C++ value. + (c-not-decl-init-keywords): Also exclude c-typeof-kwds from value. + Make ">>" act as double template ender in C++ Mode. * progmodes/cc-langs.el (c->-op-cont-tokens): New lang-const split off from c->-op-cont-re. diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 8283bb38eae..9eb95f69c48 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -6286,7 +6286,8 @@ comment at the start of cc-engine.el for more info." ;; `*-font-lock-extra-types'); ;; o - 'prefix if it's a known prefix of a type; ;; o - 'found if it's a type that matches one in `c-found-types'; - ;; o - 'maybe if it's an identifier that might be a type; or + ;; o - 'maybe if it's an identfier that might be a type; + ;; o - 'decltype if it's a decltype(variable) declaration; - or ;; o - 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. @@ -6316,6 +6317,16 @@ comment at the start of cc-engine.el for more info." (setq res 'prefix))) (cond + ((looking-at c-typeof-key) ; e.g. C++'s "decltype". + (goto-char (match-end 1)) + (c-forward-syntactic-ws) + (setq res (and (eq (char-after) ?\() + (c-safe (c-forward-sexp)) + 'decltype)) + (if res + (c-forward-syntactic-ws) + (goto-char start))) + ((looking-at c-type-prefix-key) ; e.g. "struct", "class", but NOT ; "typedef". (goto-char (match-end 1)) @@ -6442,7 +6453,7 @@ comment at the start of cc-engine.el for more info." ;; 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 + (when c-opt-type-suffix-key ; e.g. "..." (while (looking-at c-opt-type-suffix-key) (goto-char (match-end 1)) (c-forward-syntactic-ws))) @@ -6654,6 +6665,13 @@ comment at the start of cc-engine.el for more info." ;; Foo::Foo (int b) : Base (b) {} ;; car ^ ^ point ;; + ;; auto foo = 5; + ;; car ^ ^ point + ;; auto cplusplus_11 (int a, char *b) -> decltype (bar): + ;; car ^ ^ point + ;; + ;; + ;; ;; The cdr of the return value is non-nil when a ;; `c-typedef-decl-kwds' specifier is found in the declaration. ;; Specifically it is a dotted pair (A . B) where B is t when a @@ -6719,6 +6737,10 @@ comment at the start of cc-engine.el for more info." ;; If `backup-at-type' is nil then the other variables have ;; undefined values. backup-at-type backup-type-start backup-id-start + ;; This stores `kwd-sym' of the symbol before the current one. + ;; This is needed to distinguish the C++11 version of "auto" from + ;; the pre C++11 meaning. + backup-kwd-sym ;; Set if we've found a specifier (apart from "typedef") that makes ;; the defined identifier(s) types. at-type-decl @@ -6727,6 +6749,10 @@ comment at the start of cc-engine.el for more info." ;; Set if we've found a specifier that can start a declaration ;; where there's no type. maybe-typeless + ;; Save the value of kwd-sym between loops of the "Check for a + ;; type" loop. Needed to distinguish a C++11 "auto" from a pre + ;; C++11 one. + prev-kwd-sym ;; If a specifier is found that also can be a type prefix, ;; these flags are set instead of those above. If we need to ;; back up an identifier, they are copied to the real flag @@ -6744,6 +6770,8 @@ comment at the start of cc-engine.el for more info." backup-if-not-cast ;; For casts, the return position. cast-end + ;; Have we got a new-style C++11 "auto"? + new-style-auto ;; Save `c-record-type-identifiers' and ;; `c-record-ref-identifiers' since ranges are recorded ;; speculatively and should be thrown away if it turns out @@ -6762,11 +6790,12 @@ comment at the start of cc-engine.el for more info." (let* ((start (point)) kwd-sym kwd-clause-end found-type) ;; Look for a specifier keyword clause. - (when (or (looking-at c-prefix-spec-kwds-re) + (when (or (looking-at c-prefix-spec-kwds-re) ;FIXME!!! includes auto (and (c-major-mode-is 'java-mode) (looking-at "@[A-Za-z0-9]+"))) - (if (looking-at c-typedef-key) - (setq at-typedef t)) + (save-match-data + (if (looking-at c-typedef-key) + (setq at-typedef t))) (setq kwd-sym (c-keyword-sym (match-string 1))) (save-excursion (c-forward-keyword-clause 1) @@ -6774,6 +6803,12 @@ comment at the start of cc-engine.el for more info." (when (setq found-type (c-forward-type t)) ; brace-block-too ;; Found a known or possible type or a prefix of a known type. + (when (and (c-major-mode-is 'c++-mode) ; C++11 style "auto"? + (eq prev-kwd-sym (c-keyword-sym "auto")) + (looking-at "[=(]")) ; FIXME!!! proper regexp. + (setq new-style-auto t) + (setq found-type nil) + (goto-char start)) ; position of foo in "auto foo" (when at-type ;; Got two identifiers with nothing but whitespace @@ -6792,6 +6827,7 @@ comment at the start of cc-engine.el for more info." (setq backup-at-type at-type backup-type-start type-start backup-id-start id-start + backup-kwd-sym kwd-sym at-type found-type type-start start id-start (point) @@ -6847,6 +6883,7 @@ comment at the start of cc-engine.el for more info." ;; specifier keyword and we know we're in a ;; declaration. (setq at-decl-or-cast t) + (setq prev-kwd-sym kwd-sym) (goto-char kwd-clause-end)))) @@ -7038,15 +7075,26 @@ comment at the start of cc-engine.el for more info." (c-forward-syntactic-ws)) - (when (and (or maybe-typeless backup-maybe-typeless) - (not got-identifier) - (not got-prefix) - at-type) + (when (or (and new-style-auto + (looking-at c-auto-ops-re)) + (and (or maybe-typeless backup-maybe-typeless) + (not got-identifier) + (not got-prefix) + at-type)) ;; 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-fdoc-shift-type-backward)) + ;; Prepare the "-> type;" for fontification later on. + (when (and new-style-auto + (looking-at c-haskell-op-re)) + (save-excursion + (goto-char (match-end 0)) + (c-forward-syntactic-ws) + (setq type-start (point)) + (setq at-type (c-forward-type)))) + (setq at-decl-or-cast (catch 'at-decl-or-cast @@ -7371,6 +7419,7 @@ comment at the start of cc-engine.el for more info." ;; 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. + ;; CASE 19 (eq context 'decl)))) ;; The point is now after the type decl expression. @@ -7460,6 +7509,8 @@ comment at the start of cc-engine.el for more info." ;; interactive refontification. (c-put-c-type-property (point) 'c-decl-arg-start)) + ;; Record the type's coordinates in `c-record-type-identifiers' for + ;; later fontification. (when (and c-record-type-identifiers at-type ;; (not (eq at-type t)) ;; There seems no reason to exclude a token from ;; fontification just because it's "a known type that can't diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index ceb86b45fb1..c056091ca46 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -1306,14 +1306,15 @@ casts and declarations are fontified. Used on level 2 and higher." (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?<))) (setq context nil c-restricted-<>-arglists nil)) - ;; A control flow expression + ;; A control flow expression or a decltype ((and (eq (char-before match-pos) ?\() (save-excursion (goto-char match-pos) (backward-char) (c-backward-token-2) (or (looking-at c-block-stmt-2-key) - (looking-at c-block-stmt-1-2-key)))) + (looking-at c-block-stmt-1-2-key) + (looking-at c-typeof-key)))) (setq context nil c-restricted-<>-arglists t)) ;; Near BOB. @@ -1513,7 +1514,7 @@ casts and declarations are fontified. Used on level 2 and higher." (goto-char (match-end 0)) (c-forward-syntactic-ws)) ;; At a real declaration? - (if (memq (c-forward-type t) '(t known found)) + (if (memq (c-forward-type t) '(t known found decltype)) (progn (c-font-lock-declarators limit t is-typedef) nil) @@ -2130,7 +2131,7 @@ need for `c-font-lock-extra-types'.") ;; 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. + ;; have already been handled by other fontification rules. (let (expr1-res expr2-res) (goto-char expr1-pos) @@ -2165,6 +2166,9 @@ need for `c-font-lock-extra-types'.") ;; unusual than an initializer. (cond ((memq expr1-res '(t known prefix))) ((memq expr2-res '(t known prefix))) + ;; Presumably 'decltype's will be fontified elsewhere. + ((eq expr1-res 'decltype)) + ((eq expr2-res 'decltype)) ((eq expr1-res 'found) (let ((c-promote-possible-types t)) (goto-char expr1-pos) diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 2bf660a32eb..73b75dc671a 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -940,10 +940,13 @@ 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 + ;; There's currently no code in CC Mode that exploits all the info ;; in this variable; precedence, associativity etc are present as a ;; preparation for future work. + ;; FIXME!!! C++11's "auto" operators "=" and "->" need to go in here + ;; somewhere. 2012-03-24. + t `(;; Preprocessor. ,@(when (c-lang-const c-opt-cpp-prefix) `((prefix "#" @@ -1266,6 +1269,21 @@ operators." (c-lang-defvar c-stmt-delim-chars-with-comma (c-lang-const c-stmt-delim-chars-with-comma)) +(c-lang-defconst c-auto-ops + ;; Ops which signal C++11's new auto uses. + t nil + c++ '("=" "->")) +(c-lang-defconst c-auto-ops-re + t (c-make-keywords-re nil (c-lang-const c-auto-ops))) +(c-lang-defvar c-auto-ops-re (c-lang-const c-auto-ops-re)) + +(c-lang-defconst c-haskell-op + ;; Op used in the new C++11 auto function definition, indicating type. + t nil + c++ '("->")) +(c-lang-defconst c-haskell-op-re + t (c-make-keywords-re nil (c-lang-const c-haskell-op))) +(c-lang-defvar c-haskell-op-re (c-lang-const c-haskell-op-re)) ;;; Syntactic whitespace. @@ -1673,6 +1691,18 @@ of a variable declaration." t (c-make-keywords-re t (c-lang-const c-typedef-kwds))) (c-lang-defvar c-typedef-key (c-lang-const c-typedef-key)) +(c-lang-defconst c-typeof-kwds + "Keywords followed by a parenthesized expression, which stands for +the type of that expression." + t nil + c '("typeof") ; longstanding GNU C(++) extension. + c++ '("decltype" "typeof")) + +(c-lang-defconst c-typeof-key + ;; Adorned regexp matching `c-typeof-kwds'. + t (c-make-keywords-re t (c-lang-const c-typeof-kwds))) +(c-lang-defvar c-typeof-key (c-lang-const c-typeof-key)) + (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 @@ -1856,6 +1886,7 @@ will be handled." ;; {...}"). t (append (c-lang-const c-class-decl-kwds) (c-lang-const c-brace-list-decl-kwds)) + c++ (append (c-lang-const c-typeless-decl-kwds) '("auto")) ; C++11. ;; Note: "manages" for CORBA CIDL clashes with its presence on ;; `c-type-list-kwds' for IDL. idl (append (c-lang-const c-typeless-decl-kwds) @@ -2005,7 +2036,8 @@ one of `c-type-list-kwds', `c-ref-list-kwds', t (c-make-keywords-re t (set-difference (c-lang-const c-keywords) (append (c-lang-const c-type-start-kwds) - (c-lang-const c-prefix-spec-kwds)) + (c-lang-const c-prefix-spec-kwds) + (c-lang-const c-typeof-kwds)) :test 'string-equal))) (c-lang-defvar c-not-decl-init-keywords (c-lang-const c-not-decl-init-keywords)) -- 2.39.5