]> git.eshelyaron.com Git - emacs.git/commitdiff
Handle C++11 lambda functions.
authorAlan Mackenzie <acm@muc.de>
Mon, 15 Aug 2016 11:52:32 +0000 (11:52 +0000)
committerAlan Mackenzie <acm@muc.de>
Mon, 15 Aug 2016 11:52:32 +0000 (11:52 +0000)
* lisp/progmodes/cc-engine.el (c-looking-at-inexpr-block): Enhance also to
handle C++ lambda functions.
(c-looking-at-c++-lambda-capture-list): New function.

* lisp/progmodes/cc-fonts.el (c-font-lock-declarations): Recognize the
parameter list of a lambda function and set `context' and
`c-restricted-<>-arglists' suitably for it.
(c-font-lock-c++-lambda-captures): New function.
(c-complex-decl-matchers): Insert c-font-lock-c++-lambda-captures into it.

* lisp/progmodes/cc-langs.el (c-pre-lambda-tokens, c-pre-lambda-tokens-re):
New language constants/variables.
(c-paren-nontype-kwds): Include "noexcept" in the C++ value.

* lisp/progmodes/cc-mode.el (c-fl-decl-start): Handle being in a C++ lambda
function capture list.

lisp/progmodes/cc-engine.el
lisp/progmodes/cc-fonts.el
lisp/progmodes/cc-langs.el
lisp/progmodes/cc-mode.el

index e22b98dbc4d7681133320a13098f4b6fba2be37d..4a29896b4a5ed48ff7110fd048e9d3bfcdaf8dc8 100644 (file)
@@ -10005,12 +10005,27 @@ comment at the start of cc-engine.el for more info."
   ;; This function might do hidden buffer changes.
 
   (save-excursion
-    (let ((res 'maybe) passed-paren
+    (let ((res 'maybe) (passed-bracket-pairs 0) bracket-pos passed-paren
+         haskell-op-pos
          (closest-lim (or containing-sexp lim (point-min)))
          ;; Look at the character after point only as a last resort
          ;; when we can't disambiguate.
          (block-follows (and (eq (char-after) ?{) (point))))
 
+      ;; Search for a C++11 "->" which suggests a lambda declaration.
+      (when (and (c-major-mode-is 'c++-mode)
+                (setq haskell-op-pos
+                      (save-excursion
+                        (while
+                            (progn
+                              (c-syntactic-skip-backward "^;=}>" closest-lim t)
+                              (and (eq (char-before) ?>)
+                                   (c-backward-token-2)
+                                   (not (looking-at c-haskell-op-re)))))
+                        (and (looking-at c-haskell-op-re)
+                             (point)))))
+       (goto-char haskell-op-pos))
+
       (while (and (eq res 'maybe)
                  (progn (c-backward-syntactic-ws)
                         (> (point) closest-lim))
@@ -10048,6 +10063,11 @@ comment at the start of cc-engine.el for more info."
                                             (zerop (c-forward-token-2 1 t)))
                                      (eq (char-after) ?\())))
                           (cons 'inexpr-class (point))))
+                    ((c-keyword-member kw-sym 'c-paren-any-kwds) ; e.g. C++11 "throw" or "noexcept"
+                     (setq passed-paren nil)
+                     (setq passed-bracket-pairs 0)
+                     (setq bracket-pos nil)
+                     'maybe)
                     ((c-keyword-member kw-sym 'c-inexpr-block-kwds)
                      (when (not passed-paren)
                        (cons 'inexpr-statement (point))))
@@ -10062,20 +10082,49 @@ comment at the start of cc-engine.el for more info."
 
                (if (looking-at "\\s(")
                    (if passed-paren
-                       (if (and (eq passed-paren ?\[)
-                                (eq (char-after) ?\[))
-                           ;; Accept several square bracket sexps for
-                           ;; Java array initializations.
-                           'maybe)
-                     (setq passed-paren (char-after))
+                       (cond
+                        ((and (eq passed-paren ?\[)
+                              (eq (char-after) ?\[)
+                              (not (eq (char-after (1+ (point))) ?\[))) ; C++ attribute.
+                         ;; Accept several square bracket sexps for
+                         ;; Java array initializations.
+                         (setq passed-bracket-pairs (1+ passed-bracket-pairs))
+                         'maybe)
+                        ((and (eq passed-paren ?\()
+                              (eq (char-after) ?\[)
+                              (not (eq (char-after (1+ (point))) ?\[))
+                              (eq passed-bracket-pairs 0))
+                         ;; C++11 lambda function declaration
+                         (setq passed-bracket-pairs 1)
+                         (setq bracket-pos (point))
+                         'maybe)
+                        (t nil))
+                     (when (not (looking-at "\\[\\["))
+                       (setq passed-paren (char-after))
+                       (when (eq passed-paren ?\[)
+                         (setq passed-bracket-pairs 1)
+                         (setq bracket-pos (point))))
                      'maybe)
                  'maybe))))
 
       (if (eq res 'maybe)
-         (when (and c-recognize-paren-inexpr-blocks
-                    block-follows
-                    containing-sexp
-                    (eq (char-after containing-sexp) ?\())
+         (cond
+          ((and (c-major-mode-is 'c++-mode)
+                block-follows
+                (eq passed-bracket-pairs 1)
+                (save-excursion
+                  (goto-char bracket-pos)
+                  (or (<= (point) (or lim (point-min)))
+                      (progn
+                        (c-backward-token-2 1 nil lim)
+                        (and
+                         (not (c-on-identifier))
+                         (not (looking-at c-opt-op-identifier-prefix)))))))
+           (cons 'inlambda bracket-pos))
+          ((and c-recognize-paren-inexpr-blocks
+                block-follows
+                containing-sexp
+                (eq (char-after containing-sexp) ?\())
            (goto-char containing-sexp)
            (if (or (save-excursion
                      (c-backward-syntactic-ws lim)
@@ -10089,7 +10138,7 @@ comment at the start of cc-engine.el for more info."
                    (and c-special-brace-lists
                         (c-looking-at-special-brace-list)))
                nil
-             (cons 'inexpr-statement (point))))
+             (cons 'inexpr-statement (point)))))
 
        res))))
 
@@ -10115,6 +10164,18 @@ comment at the start of cc-engine.el for more info."
                                                    paren-state)
                                   containing-sexp)))))
 
+(defun c-looking-at-c++-lambda-capture-list ()
+  ;; Return non-nil if we're at the opening "[" of the capture list of a C++
+  ;; lambda function, nil otherwise.
+  (and
+   (eq (char-after) ?\[)
+   (not (eq (char-before) ?\[))
+   (not (eq (char-after (1+ (point))) ?\[))
+   (save-excursion
+     (or (eq (c-backward-token-2 1) 1)
+        (looking-at c-pre-lambda-tokens-re)))
+   (not (c-in-literal))))
+
 (defun c-at-macro-vsemi-p (&optional pos)
   ;; Is there a "virtual semicolon" at POS or point?
   ;; (See cc-defs.el for full details of "virtual semicolons".)
index b45686c81b03d83f79453722a3f438c6c486dae6..ae18d0a943655f1447a5b885b54f155844f8969a 100644 (file)
@@ -1242,6 +1242,20 @@ casts and declarations are fontified.  Used on level 2 and higher."
                    ((eq type 'c-decl-arg-start)
                     (setq context 'decl
                           c-restricted-<>-arglists nil))
+                   ;; Inside a C++11 lambda function arglist.
+                   ((and (c-major-mode-is 'c++-mode)
+                         (eq (char-before match-pos) ?\()
+                         (save-excursion
+                           (goto-char match-pos)
+                           (c-backward-token-2)
+                           (and
+                            (c-safe (goto-char (scan-sexps (point) -1)))
+                            (c-looking-at-c++-lambda-capture-list))))
+                    (setq context 'decl
+                          c-restricted-<>-arglists nil)
+                    (c-put-char-property (1- match-pos) 'c-type
+                                         'c-decl-arg-start))
+
                    ;; Inside an angle bracket arglist.
                    ((or (eq type 'c-<>-arg-sep)
                         (eq (char-before match-pos) ?<))
@@ -1583,6 +1597,90 @@ casts and declarations are fontified.  Used on level 2 and higher."
                (setq raw-id (match-string-no-properties 2)))))))))
   nil)
 
+(defun c-font-lock-c++-lambda-captures (limit)
+  ;; Fontify the lambda capture component of C++ lambda declarations.
+  ;;
+  ;; This function will be called from font-lock for a region bounded by POINT
+  ;; and LIMIT, as though it were to identify a keyword for
+  ;; font-lock-keyword-face.  It always returns NIL to inhibit this and
+  ;; prevent a repeat invocation.  See elisp/lispref page "Search-based
+  ;; Fontification".
+  (let (mode capture-default id-start id-end declaration sub-begin sub-end)
+    (while (and (< (point) limit)
+               (search-forward "[" limit t))
+      (when (progn (backward-char)
+                  (prog1
+                      (c-looking-at-c++-lambda-capture-list)
+                    (forward-char)))
+       (c-forward-syntactic-ws)
+       (setq mode (and (memq (char-after) '(?= ?&))
+                       (char-after)))
+       ;; Is the first element of the list a bare "=" or "&"?
+       (when mode
+         (forward-char)
+         (c-forward-syntactic-ws)
+         (if (memq (char-after) '(?, ?\]))
+             (progn
+               (setq capture-default mode)
+               (when (eq (char-after) ?,)
+                 (forward-char)
+                 (c-forward-syntactic-ws)))
+           (c-backward-token-2)))
+
+       ;; Go round the following loop once per captured item.
+       (while (and (not (eq (char-after) ?\]))
+                   (< (point) limit))
+         (if (eq (char-after) ?&)
+             (progn (setq mode ?&)
+                    (forward-char)
+                    (c-forward-syntactic-ws))
+           (setq mode ?=))
+         (if (c-on-identifier)
+             (progn
+               (setq id-start (point))
+               (forward-char)
+               (c-end-of-current-token)
+               (setq id-end (point))
+               (c-forward-syntactic-ws)
+
+               (setq declaration (eq (char-after) ?=))
+               (when declaration
+                 (forward-char)        ; over "="
+                 (c-forward-syntactic-ws)
+                 (setq sub-begin (point)))
+               (if (or (and (< (point) limit)
+                            (c-syntactic-re-search-forward "," limit t t))
+                       (and (c-go-up-list-forward nil limit)
+                            (eq (char-before) ?\])))
+                   (backward-char)
+                 (goto-char limit))
+               (when declaration
+                 (save-excursion
+                   (setq sub-end (point))
+                   (goto-char sub-begin)
+                   (c-font-lock-c++-lambda-captures sub-end)))
+
+               (c-put-font-lock-face id-start id-end
+                                     (cond
+                                      (declaration
+                                       'font-lock-variable-name-face)
+                                      ((and capture-default
+                                            (eq mode capture-default))
+                                       'font-lock-warning-face)
+                                      ((eq mode ?=) font-lock-constant-face)
+                                      (t 'font-lock-variable-name-face))))
+           (c-syntactic-re-search-forward "," limit 'bound t))
+
+         (c-forward-syntactic-ws)
+         (when (eq (char-after) ?,)
+           (forward-char)
+           (c-forward-syntactic-ws)))
+
+       (setq capture-default nil)
+       (forward-char))))                       ; over the terminating "]".
+  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'."
@@ -1700,6 +1798,9 @@ on level 2 only and so aren't combined with `c-complex-decl-matchers'."
       ,@(when (c-lang-const c-recognize-<>-arglists)
          `(c-font-lock-<>-arglists))
 
+      ,@(when (c-major-mode-is 'c++-mode)
+         `(c-font-lock-c++-lambda-captures))
+
       ;; The first two rules here mostly find occurrences that
       ;; `c-font-lock-declarations' has found already, but not
       ;; declarations containing blocks in the type (see note below).
index ec894f619a8d4e5b64aec01471057f14fbf5fc34..934186da7bde57d19cf85f254670a4c48cccade2 100644 (file)
@@ -474,6 +474,7 @@ so that all identifiers are recognized as words.")
   ;; The value here may be a list of functions or a single function.
   t nil
   c++ '(c-extend-region-for-CPP
+;      c-before-after-change-extend-region-for-lambda-capture ; doesn't seem needed.
        c-before-change-check-raw-strings
        c-before-change-check-<>-operators
        c-depropertize-CPP
@@ -517,6 +518,7 @@ parameters \(point-min) and \(point-max).")
             c-change-expand-fl-region)
   c++ '(c-depropertize-new-text
        c-extend-font-lock-region-for-macros
+;      c-before-after-change-extend-region-for-lambda-capture ; doens't seem needed.
        c-before-after-change-digit-quote
        c-after-change-re-mark-raw-strings
        c-neutralize-syntax-in-and-mark-CPP
@@ -1360,6 +1362,25 @@ operators."
   t '(";" "{" "}"))
 (c-lang-defvar c-pre-start-tokens (c-lang-const c-pre-start-tokens))
 
+(c-lang-defconst c-pre-lambda-tokens
+  "List of tokens which may precede a lambda declaration.
+In C++ this is something like \"[a,b] (foo, bar) -> int { ... };\".
+Currently (2016-08) only used in C++ mode."
+  t (c--set-difference
+     (c--delete-duplicates
+      (append (c-lang-const c-operator-list)
+             (c-lang-const c-other-op-syntax-tokens)))
+     (append
+      '("#" "%:" "??=" "##" "%:%:" "??=??=" "::" "." "->"
+       "]" "<:" ":>" "??(" "??)" "??-" "new" "delete"
+       ")" ".*" "->*" "??'" "??!" "??!??!" "??!=" "??'=")
+      '("<%" "%>" "<:" ":>" "%:" "%:%:" "#" "##" "::" "..."))
+     :test #'string-equal))
+
+(c-lang-defconst c-pre-lambda-tokens-re
+  ;; Regexp matching any token in the list `c-pre-lambda-tokens'.
+  t (regexp-opt (c-lang-const c-pre-lambda-tokens)))
+(c-lang-defvar c-pre-lambda-tokens-re (c-lang-const c-pre-lambda-tokens-re))
 \f
 ;;; Syntactic whitespace.
 
@@ -2284,7 +2305,8 @@ contain type identifiers."
   (c c++) '(;; GCC extension.
            "__attribute__"
            ;; MSVC extension.
-           "__declspec"))
+           "__declspec")
+  c++ (append (c-lang-const c-paren-nontype-kwds) '("noexcept")))
 
 (c-lang-defconst c-paren-nontype-key
   t (c-make-keywords-re t (c-lang-const c-paren-nontype-kwds)))
index 07476013354863fdc85d0da049deab9800dfeaf8..f630b053edc8d347638cc9c2578f770dbc2f5272 100644 (file)
@@ -1142,6 +1142,38 @@ Note that the style variables are always made local to the buffer."
       (goto-char try-end)
       (setq num-begin (point)))))
 
+;; The following doesn't seem needed at the moment (2016-08-15).
+;; (defun c-before-after-change-extend-region-for-lambda-capture
+;;     (_beg _end &optional _old-len)
+;;   ;; In C++ Mode, extend the region (c-new-BEG c-new-END) to cover any lambda
+;;   ;; function capture lists we happen to be inside.  This function is expected
+;;   ;; to be called both as a before-change and after change function.
+;;   ;;
+;;   ;; Note that these things _might_ be nested, with a capture list looking
+;;   ;; like:
+;;   ;;
+;;   ;;     [ ...., &foo = [..](){...}(..), ... ]
+;;   ;;
+;;   ;; .  What a wonderful language is C++.  ;-)
+;;   (c-save-buffer-state (paren-state pos)
+;;     (goto-char c-new-BEG)
+;;     (setq paren-state (c-parse-state))
+;;     (while (setq pos (c-pull-open-brace paren-state))
+;;       (goto-char pos)
+;;       (when (c-looking-at-c++-lambda-capture-list)
+;;     (setq c-new-BEG (min c-new-BEG pos))
+;;     (if (c-go-list-forward)
+;;         (setq c-new-END (max c-new-END (point))))))
+
+;;     (goto-char c-new-END)
+;;     (setq paren-state (c-parse-state))
+;;     (while (setq pos (c-pull-open-brace paren-state))
+;;       (goto-char pos)
+;;       (when (c-looking-at-c++-lambda-capture-list)
+;;     (setq c-new-BEG (min c-new-BEG pos))
+;;     (if (c-go-list-forward)
+;;         (setq c-new-END (max c-new-END (point))))))))
+
 (defun c-before-change (beg end)
   ;; Function to be put on `before-change-functions'.  Primarily, this calls
   ;; the language dependent `c-get-state-before-change-functions'.  It is
@@ -1329,12 +1361,24 @@ Note that the style variables are always made local to the buffer."
   ;; lock context (etc.) fontification.
   (let ((lit-start (c-literal-start))
        (new-pos pos)
+       capture-opener
        bod-lim bo-decl)
     (goto-char (c-point 'bol new-pos))
     (when lit-start                    ; Comment or string.
       (goto-char lit-start))
     (setq bod-lim (c-determine-limit 500))
 
+    ;; In C++ Mode, first check if we are within a (possibly nested) lambda
+    ;; form capture list.
+    (when (c-major-mode-is 'c++-mode)
+      (let ((paren-state (c-parse-state))
+           opener)
+       (save-excursion
+         (while (setq opener (c-pull-open-brace paren-state))
+           (goto-char opener)
+           (if (c-looking-at-c++-lambda-capture-list)
+               (setq capture-opener (point)))))))
+
     (while
        ;; Go to a less nested declaration each time round this loop.
        (and
@@ -1361,6 +1405,8 @@ Note that the style variables are always made local to the buffer."
                             c-<-as-paren-syntax)))))
         (not (bobp)))
       (backward-char))                 ; back over (, [, <.
+    (when (and capture-opener (< capture-opener new-pos))
+      (setq new-pos capture-opener))
     (and (/= new-pos pos) new-pos)))
 
 (defun c-change-expand-fl-region (_beg _end _old-len)