mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-23 07:19:15 +00:00
CC Mode: Handle C++20 concepts
* lisp/progmodes/cc-align.el (c-lineup-topmost-intro-cont): Amend so as not to indent lines following a requires line. * lisp/progmodes/cc-engine.el (c-forward-primary-expression) (c-forward-c++-requires-clause): New functions. (c-forward-declarator): Skip forward over any trailing requires clause. (c-forward-decl-or-cast-1): Skip requires clauses before and after the type. Amend the second element of the return list to include information on two consecutive identifiers in <...>. (c-looking-at-or-maybe-in-bracelist): Don't recognize braces in requires expressions as brace lists. (c-guess-basic-syntax): CASE 5D.7: New case to handle the continuation of a "concept foo = " line. * lisp/progmodes/cc-fonts.el (c-basic-matchers-before): Add a new clause to handle the declaration of a concept. (c-get-fontification-context): Treat the arglist of a requires construct as a declaration arglist. * lisp/progmodes/cc-langs.el (c-equals-nontype-decl-kwds/key) (c-fun-name-substitute-kwds/key, c-pre-concept-<>-kwds/key): New c-lang-consts/vars. (c-constant-key): New c-lang-var. (c-type-decl-suffix-key): Include "requires" in the keywords matched. * lisp/progmodes/cc-mode.el (c-fl-decl-start): Fix an off by one error. Use equal rather than eq to compare two syntax contexts.
This commit is contained in:
parent
bb83fb5f62
commit
07e6bbb9bc
@ -85,11 +85,14 @@ statement-cont.)
|
||||
Works with: topmost-intro-cont."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(c-backward-syntactic-ws (c-langelem-pos langelem))
|
||||
(if (and (memq (char-before) '(?} ?,))
|
||||
(not (and c-overloadable-operators-regexp
|
||||
(c-after-special-operator-id))))
|
||||
c-basic-offset)))
|
||||
(unless (re-search-forward c-fun-name-substitute-key
|
||||
(c-point 'eol) t)
|
||||
(beginning-of-line)
|
||||
(c-backward-syntactic-ws (c-langelem-pos langelem))
|
||||
(if (and (memq (char-before) '(?} ?,))
|
||||
(not (and c-overloadable-operators-regexp
|
||||
(c-after-special-operator-id))))
|
||||
c-basic-offset))))
|
||||
|
||||
(defun c-lineup-gnu-DEFUN-intro-cont (langelem)
|
||||
"Line up the continuation lines of a DEFUN macro in the Emacs C source.
|
||||
|
@ -9512,6 +9512,84 @@ point unchanged and return nil."
|
||||
|
||||
;; Handling of large scale constructs like statements and declarations.
|
||||
|
||||
(defun c-forward-primary-expression (&optional limit)
|
||||
;; Go over the primary expression (if any) at point, moving to the next
|
||||
;; token and return non-nil. If we're not at a primary expression leave
|
||||
;; point unchanged and return nil.
|
||||
;;
|
||||
;; Note that this function is incomplete, handling only those cases expected
|
||||
;; to be common in a C++20 requires clause.
|
||||
(let ((here (point))
|
||||
(c-restricted-<>-arglists t)
|
||||
(c-parse-and-markup-<>-arglists nil)
|
||||
)
|
||||
(if (cond
|
||||
((looking-at c-constant-key)
|
||||
(goto-char (match-end 1))
|
||||
(c-forward-syntactic-ws limit)
|
||||
t)
|
||||
((eq (char-after) ?\()
|
||||
(and (c-go-list-forward (point) limit)
|
||||
(eq (char-before) ?\))
|
||||
(progn (c-forward-syntactic-ws limit)
|
||||
t)))
|
||||
((c-forward-over-compound-identifier)
|
||||
(c-forward-syntactic-ws limit)
|
||||
(while (cond
|
||||
((looking-at "<")
|
||||
(prog1
|
||||
(c-forward-<>-arglist nil)
|
||||
(c-forward-syntactic-ws limit)))
|
||||
((looking-at c-opt-identifier-concat-key)
|
||||
(and
|
||||
(zerop (c-forward-token-2 1 nil limit))
|
||||
(prog1
|
||||
(c-forward-over-compound-identifier)
|
||||
(c-forward-syntactic-ws limit))))))
|
||||
t)
|
||||
((looking-at c-fun-name-substitute-key) ; "requires"
|
||||
(goto-char (match-end 1))
|
||||
(c-forward-syntactic-ws limit)
|
||||
(and
|
||||
(or (not (eq (char-after) ?\())
|
||||
(prog1
|
||||
(and (c-go-list-forward (point) limit)
|
||||
(eq (char-before) ?\)))
|
||||
(c-forward-syntactic-ws)))
|
||||
(eq (char-after) ?{)
|
||||
(and (c-go-list-forward (point) limit)
|
||||
(eq (char-before) ?}))
|
||||
(progn
|
||||
(c-forward-syntactic-ws limit)
|
||||
t))))
|
||||
t
|
||||
(goto-char here)
|
||||
nil)))
|
||||
|
||||
(defun c-forward-c++-requires-clause (&optional limit)
|
||||
;; Point is at the keyword "requires". Move forward over the requires
|
||||
;; clause to the next token after it and return non-nil. If there is no
|
||||
;; valid requires clause at point, leave point unmoved and return nil.
|
||||
(let ((here (point))
|
||||
final-point)
|
||||
(or limit (setq limit (point-max)))
|
||||
(if (and
|
||||
(zerop (c-forward-token-2 1 nil limit)) ; over "requires".
|
||||
(prog1
|
||||
(c-forward-primary-expression limit)
|
||||
(setq final-point (point))
|
||||
(while
|
||||
(and (looking-at "\\(?:&&\\|||\\)")
|
||||
(progn (goto-char (match-end 0))
|
||||
(c-forward-syntactic-ws limit)
|
||||
(and (< (point) limit)
|
||||
(c-forward-primary-expression limit))))
|
||||
(setq final-point (point)))))
|
||||
(progn (goto-char final-point)
|
||||
t)
|
||||
(goto-char here)
|
||||
nil)))
|
||||
|
||||
(defun c-forward-declarator (&optional limit accept-anon)
|
||||
;; Assuming point is at the start of a declarator, move forward over it,
|
||||
;; leaving point at the next token after it (e.g. a ) or a ; or a ,), or at
|
||||
@ -9565,7 +9643,7 @@ point unchanged and return nil."
|
||||
((and (looking-at c-type-decl-prefix-key)
|
||||
(if (and (c-major-mode-is 'c++-mode)
|
||||
(match-beginning 4)) ; Was 3 - 2021-01-01
|
||||
;; If the third submatch matches in C++ then
|
||||
;; If the fourth submatch matches in C++ then
|
||||
;; we're looking at an identifier that's a
|
||||
;; prefix only if it specifies a member pointer.
|
||||
(progn
|
||||
@ -9621,6 +9699,11 @@ point unchanged and return nil."
|
||||
(while (cond
|
||||
((looking-at c-decl-hangon-key)
|
||||
(c-forward-keyword-clause 1))
|
||||
((looking-at c-type-decl-suffix-key)
|
||||
(if (save-match-data
|
||||
(looking-at c-fun-name-substitute-key))
|
||||
(c-forward-c++-requires-clause)
|
||||
(c-forward-keyword-clause 1)))
|
||||
((and c-opt-cpp-prefix
|
||||
(looking-at c-noise-macro-with-parens-name-re))
|
||||
(c-forward-noise-clause))))
|
||||
@ -9890,13 +9973,13 @@ This function might do hidden buffer changes."
|
||||
;;
|
||||
;;
|
||||
;;
|
||||
;; The second element 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
|
||||
;; `c-typedef-kwds' ("typedef") is present, and A is t when some
|
||||
;; other `c-typedef-decl-kwds' (e.g. class, struct, enum)
|
||||
;; specifier is present. I.e., (some of) the declared
|
||||
;; identifier(s) are types.
|
||||
;; The second element of the return value is non-nil when something
|
||||
;; indicating the identifier is a type occurs in the declaration.
|
||||
;; Specifically it is nil, or a three element list (A B C) where C is t
|
||||
;; when context is '<> and the "identifier" is a found type, B is t when a
|
||||
;; `c-typedef-kwds' ("typedef") is present, and A is t when some other
|
||||
;; `c-typedef-declkwds' (e.g. class, struct, enum) specifier is present.
|
||||
;; I.e., (some of) the declared identifier(s) are types.
|
||||
;;
|
||||
;; The third element of the return value is non-nil when the declaration
|
||||
;; parsed might be an expression. The fourth element is the position of
|
||||
@ -9972,6 +10055,9 @@ This function might do hidden buffer changes."
|
||||
at-type-decl
|
||||
;; Set if we've a "typedef" keyword.
|
||||
at-typedef
|
||||
;; Set if `context' is '<> and the identifier is definitely a type, or
|
||||
;; has already been recorded as a found type.
|
||||
at-<>-type
|
||||
;; Set if we've found a specifier that can start a declaration
|
||||
;; where there's no type.
|
||||
maybe-typeless
|
||||
@ -10050,6 +10136,11 @@ This function might do hidden buffer changes."
|
||||
(setq kwd-sym (c-keyword-sym (match-string 1)))
|
||||
(save-excursion
|
||||
(c-forward-keyword-clause 1)
|
||||
(when (and (c-major-mode-is 'c++-mode)
|
||||
(c-keyword-member kwd-sym 'c-<>-sexp-kwds)
|
||||
(save-match-data
|
||||
(looking-at c-fun-name-substitute-key)))
|
||||
(c-forward-c++-requires-clause))
|
||||
(setq kwd-clause-end (point))))
|
||||
((and c-opt-cpp-prefix
|
||||
(looking-at c-noise-macro-with-parens-name-re))
|
||||
@ -10089,6 +10180,11 @@ This function might do hidden buffer changes."
|
||||
(point))))
|
||||
found-type-list))
|
||||
|
||||
;; Might we have a C++20 concept? i.e. template<foo bar>?
|
||||
(setq at-<>-type
|
||||
(and (eq context '<>)
|
||||
(memq found-type '(t known prefix found))))
|
||||
|
||||
;; Signal a type declaration for "struct foo {".
|
||||
(when (and backup-at-type-decl
|
||||
(eq (char-after) ?{))
|
||||
@ -10377,8 +10473,11 @@ This function might do hidden buffer changes."
|
||||
t)
|
||||
(when (if (save-match-data (looking-at "\\s("))
|
||||
(c-safe (c-forward-sexp 1) t)
|
||||
(goto-char (match-end 1))
|
||||
t)
|
||||
(if (save-match-data
|
||||
(looking-at c-fun-name-substitute-key)) ; requires
|
||||
(c-forward-c++-requires-clause)
|
||||
(goto-char (match-end 1))
|
||||
t))
|
||||
(when (and (not got-suffix-after-parens)
|
||||
(= paren-depth 0))
|
||||
(setq got-suffix-after-parens (match-beginning 0)))
|
||||
@ -10971,8 +11070,8 @@ This function might do hidden buffer changes."
|
||||
(c-forward-type))))
|
||||
|
||||
(list id-start
|
||||
(and (or at-type-decl at-typedef)
|
||||
(cons at-type-decl at-typedef))
|
||||
(and (or at-type-decl at-typedef at-<>-type)
|
||||
(list at-type-decl at-typedef at-<>-type))
|
||||
maybe-expression
|
||||
type-start
|
||||
(or (eq context 'top) make-top)))
|
||||
@ -12429,6 +12528,8 @@ comment at the start of cc-engine.el for more info."
|
||||
in-paren 'in-paren))
|
||||
((looking-at c-pre-brace-non-bracelist-key)
|
||||
(setq braceassignp nil))
|
||||
((looking-at c-fun-name-substitute-key)
|
||||
(setq braceassignp nil))
|
||||
((looking-at c-return-key))
|
||||
((and (looking-at c-symbol-start)
|
||||
(not (looking-at c-keywords-regexp)))
|
||||
@ -12439,6 +12540,11 @@ comment at the start of cc-engine.el for more info."
|
||||
(setq after-type-id-pos (point))))
|
||||
((eq (char-after) ?\()
|
||||
(setq parens-before-brace t)
|
||||
;; Have we a requires with a parenthesis list?
|
||||
(when (save-excursion
|
||||
(and (zerop (c-backward-token-2 1 nil lim))
|
||||
(looking-at c-fun-name-substitute-key)))
|
||||
(setq braceassignp nil))
|
||||
nil)
|
||||
(t nil))
|
||||
(save-excursion
|
||||
@ -14201,6 +14307,25 @@ comment at the start of cc-engine.el for more info."
|
||||
(goto-char placeholder)
|
||||
(c-add-syntax 'inher-cont (c-point 'boi)))
|
||||
|
||||
;; CASE 5D.7: Continuation of a "concept foo =" line in C++20 (or
|
||||
;; similar).
|
||||
((and c-equals-nontype-decl-key
|
||||
(save-excursion
|
||||
(prog1
|
||||
(and (zerop (c-backward-token-2 1 nil lim))
|
||||
(looking-at c-operator-re)
|
||||
(equal (match-string 0) "=")
|
||||
(zerop (c-backward-token-2 1 nil lim))
|
||||
(looking-at c-symbol-start)
|
||||
(not (looking-at c-keywords-regexp))
|
||||
(zerop (c-backward-token-2 1 nil lim))
|
||||
(looking-at c-equals-nontype-decl-key)
|
||||
(eq (c-beginning-of-statement-1 lim) 'same))
|
||||
(setq placeholder (point)))))
|
||||
(goto-char placeholder)
|
||||
(c-add-stmt-syntax 'topmost-intro-cont nil nil containing-sexp
|
||||
paren-state))
|
||||
|
||||
;; CASE 5D.5: Continuation of the "expression part" of a
|
||||
;; top level construct. Or, perhaps, an unrecognized construct.
|
||||
(t
|
||||
|
@ -887,6 +887,23 @@ casts and declarations are fontified. Used on level 2 and higher."
|
||||
,@(when (c-major-mode-is 'c++-mode)
|
||||
'(c-font-lock-c++-modules))
|
||||
|
||||
;; The next regexp is highlighted with narrowing. This is so that the
|
||||
;; final "context" bit of the regexp, "\\(?:[^=]\\|$\\)", which cannot
|
||||
;; match anything non-empty at LIMIT, will match "$" instead.
|
||||
,@(when (c-lang-const c-equals-nontype-decl-kwds)
|
||||
`((,(byte-compile
|
||||
`(lambda (limit)
|
||||
(save-restriction
|
||||
(narrow-to-region (point-min) limit)
|
||||
,(c-make-font-lock-search-form
|
||||
(concat (c-lang-const c-equals-nontype-decl-key) ;no \\(
|
||||
(c-lang-const c-simple-ws) "+\\("
|
||||
(c-lang-const c-symbol-key) "\\)"
|
||||
(c-lang-const c-simple-ws) "*"
|
||||
"=\\(?:[^=]\\|$\\)")
|
||||
`((,(+ 1 (c-lang-const c-simple-ws-depth))
|
||||
font-lock-type-face t)))))))))
|
||||
|
||||
;; Fontify the special declarations in Objective-C.
|
||||
,@(when (c-major-mode-is 'objc-mode)
|
||||
`(;; Fontify class names in the beginning of message expressions.
|
||||
@ -1278,15 +1295,19 @@ casts and declarations are fontified. Used on level 2 and higher."
|
||||
(or (memq type '(c-decl-arg-start c-decl-type-start))
|
||||
(and
|
||||
(progn (c-backward-syntactic-ws) t)
|
||||
(c-back-over-compound-identifier)
|
||||
(progn
|
||||
(c-backward-syntactic-ws)
|
||||
(or (bobp)
|
||||
(progn
|
||||
(setq type (c-get-char-property (1- (point))
|
||||
'c-type))
|
||||
(memq type '(c-decl-arg-start
|
||||
c-decl-type-start))))))))))
|
||||
(or
|
||||
(and
|
||||
(c-back-over-compound-identifier)
|
||||
(progn
|
||||
(c-backward-syntactic-ws)
|
||||
(or (bobp)
|
||||
(progn
|
||||
(setq type (c-get-char-property (1- (point))
|
||||
'c-type))
|
||||
(memq type '(c-decl-arg-start
|
||||
c-decl-type-start))))))
|
||||
(and (zerop (c-backward-token-2))
|
||||
(looking-at c-fun-name-substitute-key))))))))
|
||||
(cons 'decl nil))
|
||||
(t (cons 'arglist t)))))
|
||||
|
||||
|
@ -2593,6 +2593,35 @@ will be handled."
|
||||
t (c-make-keywords-re t (c-lang-const c-equals-type-clause-kwds)))
|
||||
(c-lang-defvar c-equals-type-clause-key (c-lang-const c-equals-type-clause-key))
|
||||
|
||||
(c-lang-defconst c-equals-nontype-decl-kwds
|
||||
"Keywords which are followed by an identifier then an \"=\"
|
||||
sign, which declares the identifier to be something other than a
|
||||
type."
|
||||
t nil
|
||||
c++ '("concept"))
|
||||
|
||||
(c-lang-defconst c-equals-nontype-decl-key
|
||||
;; An unadorned regular expression which matches any member of
|
||||
;; `c-equals-decl-kwds', or nil if such don't exist in the current language.
|
||||
t (when (c-lang-const c-equals-nontype-decl-kwds)
|
||||
(c-make-keywords-re nil (c-lang-const c-equals-nontype-decl-kwds))))
|
||||
(c-lang-defvar c-equals-nontype-decl-key
|
||||
(c-lang-const c-equals-nontype-decl-key))
|
||||
|
||||
(c-lang-defconst c-fun-name-substitute-kwds
|
||||
"Keywords which take the place of type+declarator at the beginning
|
||||
of a function-like structure, such as a C++20 \"requires\"
|
||||
clause. An arglist may or may not follow such a keyword."
|
||||
t nil
|
||||
c++ '("requires"))
|
||||
|
||||
(c-lang-defconst c-fun-name-substitute-key
|
||||
;; An adorned regular expression which matches any member of
|
||||
;; `c-fun-name-substitute-kwds'.
|
||||
t (c-make-keywords-re t (c-lang-const c-fun-name-substitute-kwds)))
|
||||
(c-lang-defvar c-fun-name-substitute-key
|
||||
(c-lang-const c-fun-name-substitute-key))
|
||||
|
||||
(c-lang-defconst c-modifier-kwds
|
||||
"Keywords that can prefix normal declarations of identifiers
|
||||
\(and typically act as flags). Things like argument declarations
|
||||
@ -2938,6 +2967,17 @@ if this isn't nil."
|
||||
;; In CORBA PSDL:
|
||||
"ref"))
|
||||
|
||||
(c-lang-defconst c-pre-concept-<>-kwds
|
||||
"Keywords that may be followed by an angle bracket expression containing
|
||||
uses of \"concepts\". This is currently (2022-09) used only by C++."
|
||||
t nil
|
||||
c++ '("template"))
|
||||
|
||||
(c-lang-defconst c-pre-concept-<>-key
|
||||
;; Regexp matching any element of `c-pre-concept-<>-kwds'.
|
||||
t (c-make-keywords-re t (c-lang-const c-pre-concept-<>-kwds)))
|
||||
(c-lang-defvar c-pre-concept-<>-key (c-lang-const c-pre-concept-<>-key))
|
||||
|
||||
(c-lang-defconst c-<>-arglist-kwds
|
||||
"Keywords that can be followed by a C++ style template arglist; see
|
||||
`c-recognize-<>-arglists' for details. That language constant is
|
||||
@ -3146,6 +3186,10 @@ not really template operators."
|
||||
java '("true" "false" "null") ; technically "literals", not keywords
|
||||
pike '("UNDEFINED")) ;; Not a keyword, but practically works as one.
|
||||
|
||||
(c-lang-defconst c-constant-key
|
||||
t (c-make-keywords-re t (c-lang-const c-constant-kwds)))
|
||||
(c-lang-defvar c-constant-key (c-lang-const c-constant-key))
|
||||
|
||||
(c-lang-defconst c-primary-expr-kwds
|
||||
"Keywords besides constants and operators that start primary expressions."
|
||||
t nil
|
||||
@ -3781,7 +3825,10 @@ is in effect when this is matched (see `c-identifier-syntax-table')."
|
||||
;; "throw" in `c-type-modifier-kwds' is followed
|
||||
;; by a parenthesis list, but no extra measures
|
||||
;; are necessary to handle that.
|
||||
(regexp-opt (c-lang-const c-type-modifier-kwds) t)
|
||||
(regexp-opt
|
||||
(append (c-lang-const c-fun-name-substitute-kwds)
|
||||
(c-lang-const c-type-modifier-kwds))
|
||||
t)
|
||||
"\\>")
|
||||
"")
|
||||
"\\)")
|
||||
|
@ -2403,7 +2403,7 @@ with // and /*, not more generic line and block comments."
|
||||
(setq pseudo (c-cheap-inside-bracelist-p (c-parse-state)))))))
|
||||
(goto-char pseudo))
|
||||
t)
|
||||
(> (point) bod-lim)
|
||||
(>= (point) bod-lim)
|
||||
(progn (c-forward-syntactic-ws)
|
||||
;; Have we got stuck in a comment at EOB?
|
||||
(not (and (eobp)
|
||||
@ -2427,7 +2427,8 @@ with // and /*, not more generic line and block comments."
|
||||
(and (> (point) bod-lim)
|
||||
(or (memq (char-before) '(?\( ?\[))
|
||||
(and (eq (char-before) ?\<)
|
||||
(eq (c-get-char-property
|
||||
(equal
|
||||
(c-get-char-property
|
||||
(1- (point)) 'syntax-table)
|
||||
c-<-as-paren-syntax))
|
||||
(and (eq (char-before) ?{)
|
||||
|
Loading…
Reference in New Issue
Block a user