1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-06 03:40:56 -08:00

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.
This commit is contained in:
Alan Mackenzie 2016-08-15 11:52:32 +00:00
parent 9c2ce57719
commit ce1ed9c811
4 changed files with 243 additions and 13 deletions

View 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".)

View 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).

View 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))
;;; 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)))

View 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)