;; 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))
(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))))
(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)
(and c-special-brace-lists
(c-looking-at-special-brace-list)))
nil
- (cons 'inexpr-statement (point))))
+ (cons 'inexpr-statement (point)))))
res))))
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".)
((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) ?<))
(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'."
,@(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).
;; 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
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
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.
(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)))
(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
;; 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
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)