summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Mackenzie <acm@muc.de>2016-08-15 11:52:32 +0000
committerAlan Mackenzie <acm@muc.de>2016-08-15 11:52:32 +0000
commitce1ed9c8116e280c69f04a455176f6097ca0855c (patch)
tree75e3dffe10372dee3d44466eb8be58ebbacc1d3c
parent9c2ce57719d0db8ac0a01b65d7e8d7ccc3f2d6ca (diff)
Handle C++11 lambda functions.
* 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.
-rw-r--r--lisp/progmodes/cc-engine.el85
-rw-r--r--lisp/progmodes/cc-fonts.el101
-rw-r--r--lisp/progmodes/cc-langs.el24
-rw-r--r--lisp/progmodes/cc-mode.el46
4 files changed, 243 insertions, 13 deletions
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index e22b98dbc4..4a29896b4a 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -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".)
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index b45686c81b..ae18d0a943 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -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).
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index ec894f619a..934186da7b 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -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))
;;; 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)))
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index 0747601335..f630b053ed 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -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)