[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/d-mode bdd5d78 281/346: Replace d-forward-decl-or-cast-1 i
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/d-mode bdd5d78 281/346: Replace d-forward-decl-or-cast-1 implementation with a custom one |
Date: |
Sun, 29 Aug 2021 11:00:46 -0400 (EDT) |
branch: elpa/d-mode
commit bdd5d78d6bfe84cdfd087fc77b12f740314d09eb
Author: Vladimir Panteleev <git@thecybershadow.net>
Commit: Vladimir Panteleev <git@thecybershadow.net>
Replace d-forward-decl-or-cast-1 implementation with a custom one
Throw away the cc-mode infernal contraption and replace it with an
implementation describing the relevant D syntax, and nothing more.
---
d-mode.el | 1294 +++++++++-------------------------------------------
tests/I0095.d.html | 2 +-
tests/fonts.d | 3 +
tests/fonts.d.html | 3 +
4 files changed, 230 insertions(+), 1072 deletions(-)
diff --git a/d-mode.el b/d-mode.el
index d93e884..115d090 100644
--- a/d-mode.el
+++ b/d-mode.el
@@ -7,7 +7,7 @@
;; Maintainer: Russel Winder <russel@winder.org.uk>
;; Vladimir Panteleev <vladimir@thecybershadow.net>
;; Created: March 2007
-;; Version: 201911081553
+;; Version: 201911082245
;; Keywords: D programming language emacs cc-mode
;; Package-Requires: ((emacs "25.1"))
@@ -139,6 +139,9 @@
d "[[:alpha:]_@~]")
;; d "[[:alpha:]_@]")
+(c-lang-defconst d-decl-end-re
+ d "[,;=(]")
+
;; D has fixed arrays
(c-lang-defconst c-opt-type-suffix-key
d "\\(\\[[^]]*\\]\\|\\.\\.\\.\\|\\*\\)")
@@ -208,14 +211,20 @@ operators."
d '("bool" "byte" "ubyte" "char" "delegate" "double" "float"
"function" "int" "long" "short" "uint" "ulong" "ushort"
"cent" "ucent" "real" "ireal" "idouble" "ifloat" "creal" "cfloat"
"cdouble"
- "wchar" "dchar" "void" "string" "wstring" "dstring"))
-
-;; Keywords that can prefix normal declarations of identifiers
+ "wchar" "dchar" "void" "string" "wstring" "dstring" "__vector"))
+
+;; Keywords that can prefix normal declarations of identifiers.
+;; Union of StorageClass, Attribute, and ParameterAttributes in D grammar.
+;; References:
+;; - https://dlang.org/spec/grammar.html#Attribute
+;; - https://dlang.org/spec/declaration.html#StorageClass
+;; - https://dlang.org/spec/grammar.html#ParameterAttributes
(c-lang-defconst c-modifier-kwds
- d '("abstract" "deprecated" "extern"
- "final" "out" "lazy" "mixin" "override" "private"
- "protected" "package" "public" "ref" "scope" "static" "synchronized"
- "volatile" "__vector"))
+ d '("__gshared" "abstract" "align" "auto" "const" "deprecated"
+ "enum" "export" "extern" "final" "immutable" "in" "inout" "lazy"
+ "nothrow" "out" "override" "package" "pragma" "private"
+ "protected" "public" "pure" "ref" "return" "scope" "shared"
+ "static" "synchronized"))
(c-lang-defconst c-class-decl-kwds
;; Keywords introducing declarations where the following block (if any)
@@ -392,7 +401,7 @@ operators."
d (c-lang-const d-storage-class-kwds))
(c-lang-defconst c-decl-start-kwds
- d '("else"))
+ d '("debug" "else"))
(c-lang-defconst c-other-kwds
;; Keywords not accounted for by any other `*-kwds' language constant.
@@ -449,1087 +458,223 @@ operators."
(advice-add 'c-add-stmt-syntax :around #'d-around--c-add-stmt-syntax)
;;----------------------------------------------------------------------------
-;;; Implements handling of D constructors
-;;; Fixes e.g. indentation of contracts on constructors.
-
-;; Make it so that inside c-forward-decl-or-cast-1,
-;; "this" looks like a function identifier but not a type identifier.
-
-(defun d-forward-name ()
- "Wraps `c-forward-name' for d-mode.
-
-Fixes cc-mode handling of D constructors."
- (if (not (looking-at (d-make-keywords-re t '("this" "~this"))))
- (c-forward-name)
- (goto-char (match-end 1))
- t))
-
-;;----------------------------------------------------------------------------
(defun d-forward-decl-or-cast-1 (preceding-token-end context last-cast-end)
- "Modified version of `c-forward-decl-or-cast-1' for d-mode." ;;
checkdoc-params: (preceding-token-end context last-cast-end)
- ;; Move forward over a declaration or a cast if at the start of one.
- ;; The point is assumed to be at the start of some token. Nil is
- ;; returned if no declaration or cast is recognized, and the point
- ;; is clobbered in that case.
- ;;
- ;; If a declaration is parsed:
- ;;
- ;; The point is left at the first token after the first complete
- ;; declarator, if there is one. The return value is a list of 5 elements,
- ;; where the first is the position of the first token in the declarator.
- ;; (See below for the other four.)
- ;; Some examples:
- ;;
- ;; void foo (int a, char *b) stuff ...
- ;; car ^ ^ point
- ;; float (*a)[], b;
- ;; car ^ ^ point
- ;; unsigned int a = c_style_initializer, b;
- ;; car ^ ^ point
- ;; unsigned int a (cplusplus_style_initializer), b;
- ;; car ^ ^ point (might change)
- ;; class Foo : public Bar {}
- ;; car ^ ^ point
- ;; class PikeClass (int a, string b) stuff ...
- ;; car ^ ^ point
- ;; enum bool;
- ;; car ^ ^ point
- ;; enum bool flag;
- ;; car ^ ^ point
- ;; void cplusplus_function (int x) throw (Bad);
- ;; car ^ ^ point
- ;; Foo::Foo (int b) : Base (b) {}
- ;; car ^ ^ point
- ;;
- ;; auto foo = 5;
- ;; car ^ ^ point
- ;; auto cplusplus_11 (int a, char *b) -> decltype (bar):
- ;; car ^ ^ point
- ;;
- ;;
- ;;
- ;; 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 third element of the return value is non-nil when the declaration
- ;; parsed might be an expression. The fourth element is the position of
- ;; the start of the type identifier. The fifth element is t if either
- ;; CONTEXT was 'top, or the declaration is detected to be treated as top
- ;; level (e.g. with the keyword "extern").
- ;;
- ;; If a cast is parsed:
- ;;
- ;; The point is left at the first token after the closing paren of
- ;; the cast. The return value is `cast'. Note that the start
- ;; position must be at the first token inside the cast parenthesis
- ;; to recognize it.
- ;;
- ;; PRECEDING-TOKEN-END is the first position after the preceding
- ;; token, i.e. on the other side of the syntactic ws from the point.
- ;; Use a value less than or equal to (point-min) if the point is at
- ;; the first token in (the visible part of) the buffer.
- ;;
- ;; CONTEXT is a symbol that describes the context at the point:
- ;; 'decl In a comma-separated declaration context (typically
- ;; inside a function declaration arglist).
- ;; '<> In an angle bracket arglist.
- ;; 'arglist Some other type of arglist.
- ;; 'top Some other context and point is at the top-level (either
- ;; outside any braces or directly inside a class or namespace,
- ;; etc.)
- ;; nil Some other context or unknown context. Includes
- ;; within the parens of an if, for, ... construct.
- ;; 'not-decl This value is never supplied to this function. It
- ;; would mean we're definitely not in a declaration.
- ;;
- ;; LAST-CAST-END is the first token after the closing paren of a
- ;; preceding cast, or nil if none is known. If
- ;; `c-forward-decl-or-cast-1' is used in succession, it should be
- ;; the position after the closest preceding call where a cast was
- ;; matched. In that case it's used to discover chains of casts like
- ;; "(a) (b) c".
- ;;
- ;; This function records identifier ranges on
- ;; `c-record-type-identifiers' and `c-record-ref-identifiers' if
- ;; `c-record-type-identifiers' is non-nil.
- ;;
- ;; This function might do hidden buffer changes.
-
- ;; D: The "else" following a "version" or "static if" can start a
- ;; declaration even without a { } block. For this reason, "else" is
- ;; in `c-decl-start-kwds'.
- ;; However, cc-mode invokes `c-forward-decl-or-cast-1' with point
- ;; at the "else" keyword, which, when followed by a function call,
- ;; is mis-parsed as a function declaration.
- ;; Fix this by moving point forward, past the "else" keyword, to
- ;; put cc-mode on the right track.
- (when (looking-at (d-make-keywords-re t '("else")))
+ "D version of `c-forward-decl-or-cast-1'." ;; checkdoc-params:
(preceding-token-end context last-cast-end)
+
+ ;; D: Handle conditional compilation.
+ ;; The "debug" keyword, as well as the "else" keyword following a
+ ;; "version" or "static if", can start a declaration even without a
+ ;; { } block.
+ ;; For this reason, these keywords are in `c-decl-start-kwds'.
+ ;; However, `c-decl-start-kwds' are considered as part of the
+ ;; declaration, so `c-forward-decl-or-cast-1' will be invoked with
+ ;; point at the keyword. Handle this case here.
+ ;; Note that other cases (e.g. static if) are handled implicitly by
+ ;; their requirement of a parenthesis (')' is in `c-decl-prefix-re').
+ (while (looking-at (d-make-keywords-re t (c-lang-const c-decl-start-kwds d)))
(goto-char (match-end 1))
(c-forward-syntactic-ws))
- ;; D: Work around a cc-mode bug(?) in which the c-forward-annotation
- ;; calls in c-forward-decl-or-cast-1 do not advance the start
- ;; position, causing the annotation to be fontified as the function
- ;; name.
- (while (c-forward-annotation)
- (c-forward-syntactic-ws))
-
- (let (;; `start-pos' is used below to point to the start of the
- ;; first type, i.e. after any leading specifiers. It might
- ;; also point at the beginning of the preceding syntactic
- ;; whitespace.
- (start-pos (point))
- ;; Set to the result of `c-forward-type'.
- at-type
- ;; The position of the first token in what we currently
- ;; believe is the type in the declaration or cast, after any
- ;; specifiers and their associated clauses.
- type-start
- ;; The position of the first token in what we currently
- ;; believe is the declarator for the first identifier. Set
- ;; when the type is found, and moved forward over any
- ;; `c-decl-hangon-kwds' and their associated clauses that
- ;; occurs after the type.
- id-start
- ;; These store `at-type', `type-start' and `id-start' of the
- ;; identifier before the one in those variables. The previous
- ;; identifier might turn out to be the real type in a
- ;; declaration if the last one has to be the declarator in it.
- ;; If `backup-at-type' is nil then the other variables have
- ;; undefined values.
- backup-at-type backup-type-start backup-id-start
- ;; Set if we've found a specifier (apart from "typedef") that makes
- ;; the defined identifier(s) types.
- at-type-decl
- ;; Set if we've a "typedef" keyword.
- at-typedef
- ;; Set if we've found a specifier that can start a declaration
- ;; where there's no type.
- maybe-typeless
- ;; Save the value of kwd-sym between loops of the "Check for a
- ;; type" loop. Needed to distinguish a C++11 "auto" from a pre
- ;; C++11 one.
- prev-kwd-sym
- ;; If a specifier is found that also can be a type prefix,
- ;; these flags are set instead of those above. If we need to
- ;; back up an identifier, they are copied to the real flag
- ;; variables. Thus they only take effect if we fail to
- ;; interpret it as a type.
- backup-at-type-decl backup-maybe-typeless
- ;; Whether we've found a declaration or a cast. We might know
- ;; this before we've found the type in it. It's 'ids if we've
- ;; found two consecutive identifiers (usually a sure sign, but
- ;; we should allow that in labels too), and t if we've found a
- ;; specifier keyword (a 100% sure sign).
- at-decl-or-cast
- ;; Set when we need to back up to parse this as a declaration
- ;; but not as a cast.
- backup-if-not-cast
- ;; For casts, the return position.
- cast-end
- ;; Have we got a new-style C++11 "auto"?
- new-style-auto
- ;; Set when the symbol before `preceding-token-end' is known to
- ;; terminate the previous construct, or when we're at point-min.
- at-decl-start
- ;; Set when we have encountered a keyword (e.g. "extern") which
- ;; causes the following declaration to be treated as though top-level.
- make-top
- ;; Save `c-record-type-identifiers' and
- ;; `c-record-ref-identifiers' since ranges are recorded
- ;; speculatively and should be thrown away if it turns out
- ;; that it isn't a declaration or cast.
- (save-rec-type-ids c-record-type-identifiers)
- (save-rec-ref-ids c-record-ref-identifiers)
- ;; Set when we parse a declaration which might also be an expression,
- ;; such as "a *b". See CASE 16 and CASE 17.
- maybe-expression)
-
- (save-excursion
- (goto-char preceding-token-end)
- (setq at-decl-start
- (or (bobp)
- (let ((tok-end (point)))
- (c-backward-token-2)
- (member (buffer-substring-no-properties (point) tok-end)
- c-pre-start-tokens)))))
-
- ;; Check for a type. Unknown symbols are treated as possible
- ;; types, but they could also be specifiers disguised through
- ;; macros like __INLINE__, so we recognize both types and known
- ;; specifiers after them too.
- (while
- (let* ((start (point)) kwd-sym kwd-clause-end found-type noise-start)
-
- (cond
- ;; Look for a specifier keyword clause.
- ((or (and (looking-at c-make-top-level-key)
- (setq make-top t))
- (looking-at c-prefix-spec-kwds-re)
- (and (c-major-mode-is 'java-mode)
- (looking-at "@[A-Za-z0-9]+")))
- (save-match-data
- (if (looking-at c-typedef-key)
- (setq at-typedef t)))
- (setq kwd-sym (c-keyword-sym (match-string 1)))
- (save-excursion
- (c-forward-keyword-clause 1)
- (setq kwd-clause-end (point))))
- ((and c-opt-cpp-prefix
- (looking-at c-noise-macro-with-parens-name-re))
- (setq noise-start (point))
- (c-forward-noise-clause)
- (setq kwd-clause-end (point))))
-
- (when (setq found-type (c-forward-type t)) ; brace-block-too
- ;; Found a known or possible type or a prefix of a known type.
- (when (and (c-major-mode-is 'c++-mode) ; C++11 style "auto"?
- (eq prev-kwd-sym (c-keyword-sym "auto"))
- (looking-at "[=(]")) ; FIXME!!! proper regexp.
- (setq new-style-auto t)
- (setq found-type nil)
- (goto-char start)) ; position of foo in "auto foo"
-
- (when at-type
- ;; Got two identifiers with nothing but whitespace
- ;; between them. That can only happen in declarations.
- (setq at-decl-or-cast 'ids)
-
- (when (eq at-type 'found)
- ;; If the previous identifier is a found type we
- ;; record it as a real one; it might be some sort of
- ;; alias for a prefix like "unsigned".
- (save-excursion
- (goto-char type-start)
- (let ((c-promote-possible-types t))
- (c-forward-type)))))
-
- (setq backup-at-type at-type
- backup-type-start type-start
- backup-id-start id-start
- at-type found-type
- type-start start
- id-start (point)
- ;; The previous ambiguous specifier/type turned out
- ;; to be a type since we've parsed another one after
- ;; it, so clear these backup flags.
- backup-at-type-decl nil
- backup-maybe-typeless nil))
-
- (if (or kwd-sym noise-start)
- (progn
- ;; Handle known specifier keywords and
- ;; `c-decl-hangon-kwds' which can occur after known
- ;; types.
-
- (if (or (c-keyword-member kwd-sym 'c-decl-hangon-kwds)
- noise-start)
- ;; It's a hang-on keyword or noise clause that can occur
- ;; anywhere.
- (progn
- (if at-type
- ;; Move the identifier start position if
- ;; we've passed a type.
- (setq id-start kwd-clause-end)
- ;; Otherwise treat this as a specifier and
- ;; move the fallback position.
- (setq start-pos kwd-clause-end))
- (goto-char kwd-clause-end))
-
- ;; It's an ordinary specifier so we know that
- ;; anything before this can't be the type.
- (setq backup-at-type nil
- start-pos kwd-clause-end)
-
- (if found-type
- ;; It's ambiguous whether this keyword is a
- ;; specifier or a type prefix, so set the backup
- ;; flags. (It's assumed that `c-forward-type'
- ;; moved further than `c-forward-keyword-clause'.)
- (progn
- (when (c-keyword-member kwd-sym 'c-typedef-decl-kwds)
- (setq backup-at-type-decl t))
- (when (c-keyword-member kwd-sym 'c-typeless-decl-kwds)
- (setq backup-maybe-typeless t)))
-
- (when (c-keyword-member kwd-sym 'c-typedef-decl-kwds)
- ;; This test only happens after we've scanned a type.
- ;; So, with valid syntax, kwd-sym can't be 'typedef.
- (setq at-type-decl t))
- (when (c-keyword-member kwd-sym 'c-typeless-decl-kwds)
- (setq maybe-typeless t))
-
- ;; Haven't matched a type so it's an unambiguous
- ;; specifier keyword and we know we're in a
- ;; declaration.
- (setq at-decl-or-cast t)
- (setq prev-kwd-sym kwd-sym)
-
- (goto-char kwd-clause-end))))
-
- ;; If the type isn't known we continue so that we'll jump
- ;; over all specifiers and type identifiers. The reason
- ;; to do this for a known type prefix is to make things
- ;; like "unsigned INT16" work.
- (and found-type (not (eq found-type t))))))
+ (let (maybe-auto enum decl-start type-start id-start make-top)
+
+ (let (kind)
+ (while (setq kind (d-forward-attribute-or-storage-class))
+ (setq maybe-auto t
+ enum (eq kind 'enum))
+ ;; Skip over "public:" and similar specifiers.
+ ;; For some reason cc-mode wants us to do it here.
+ (when (looking-at ":")
+ (forward-char)
+ (c-forward-syntactic-ws))))
+
+ (setq decl-start (point))
+
+ ;; Discover what kind of enum declaration this is.
+ ;; (t if this is an actual list of enumerated values)
+ (setq enum
+ (and enum
+ (memq context '(top nil))
+ (save-excursion
+ (and
+ (d-forward-type)
+ (or (looking-at "[:{;]")
+ (and
+ (d-forward-identifier)
+ (progn
+ (c-forward-syntactic-ws)
+ (looking-at "[:{;]"))))))))
- (cond
- ((eq at-type t)
- ;; If a known type was found, we still need to skip over any
- ;; hangon keyword clauses after it. Otherwise it has already
- ;; been done in the loop above.
- (while
- (cond ((looking-at c-decl-hangon-key)
- (c-forward-keyword-clause 1))
- ((and c-opt-cpp-prefix
- (looking-at c-noise-macro-with-parens-name-re))
- (c-forward-noise-clause))))
- (setq id-start (point)))
-
- ((eq at-type 'prefix)
- ;; A prefix type is itself a primitive type when it's not
- ;; followed by another type.
- (setq at-type t))
-
- ((not at-type)
- ;; Got no type but set things up to continue anyway to handle
- ;; the various cases when a declaration doesn't start with a
- ;; type.
- (setq id-start start-pos))
-
- ((and (eq at-type 'maybe)
- (c-major-mode-is 'c++-mode))
- ;; If it's C++ then check if the last "type" ends on the form
- ;; "foo::foo" or "foo::~foo", i.e. if it's the name of a
- ;; (con|de)structor.
- (save-excursion
- (let (name end-2 end-1)
- (goto-char id-start)
- (c-backward-syntactic-ws)
- (setq end-2 (point))
- (when (and
- (c-simple-skip-symbol-backward)
- (progn
- (setq name
- (buffer-substring-no-properties (point) end-2))
- ;; Cheating in the handling of syntactic ws below.
- (< (skip-chars-backward ":~ \t\n\r\v\f") 0))
- (progn
- (setq end-1 (point))
- (c-simple-skip-symbol-backward))
- (>= (point) type-start)
- (equal (buffer-substring-no-properties (point) end-1)
- name)
- (goto-char end-2)
- (progn
- (c-forward-syntactic-ws)
- (eq (char-after) ?\()))
- ;; It is a (con|de)structor name. In that case the
- ;; declaration is typeless so zap out any preceding
- ;; identifier(s) that we might have taken as types.
- (goto-char type-start)
- (setq at-type nil
- backup-at-type nil
- id-start type-start))))))
-
- ;; Check for and step over a type decl expression after the thing
- ;; that is or might be a type. This can't be skipped since we
- ;; need the correct end position of the declarator for
- ;; `max-type-decl-end-*'.
- (let ((start (point)) (paren-depth 0) pos
- ;; True if there's a non-open-paren match of
- ;; `c-type-decl-prefix-key'.
- got-prefix
- ;; True if the declarator is surrounded by a parenthesis pair.
- got-parens
- ;; True if there is an identifier in the declarator.
- got-identifier
- ;; True if we find a number where an identifier was expected.
- got-number
- ;; True if there's a non-close-paren match of
- ;; `c-type-decl-suffix-key'.
- got-suffix
- ;; True if there's a prefix match outside the outermost
- ;; paren pair that surrounds the declarator.
- got-prefix-before-parens
- ;; True if there's a suffix match outside the outermost
- ;; paren pair that surrounds the declarator. The value is
- ;; the position of the first suffix match.
- got-suffix-after-parens
- ;; True if we've parsed the type decl to a token that is
- ;; known to end declarations in this context.
- at-decl-end
- ;; The earlier values of `at-type' and `type-start' if we've
- ;; shifted the type backwards.
- identifier-type identifier-start
- ;; If `c-parse-and-markup-<>-arglists' is set we need to
- ;; turn it off during the name skipping below to avoid
- ;; getting `c-type' properties that might be bogus. That
- ;; can happen since we don't know if
- ;; `c-restricted-<>-arglists' will be correct inside the
- ;; arglist paren that gets entered.
- c-parse-and-markup-<>-arglists
- ;; Start of the identifier for which `got-identifier' was set.
- name-start
- ;; Position after (innermost) open parenthesis encountered in the
- ;; prefix operators.
- after-paren-pos)
-
- (goto-char id-start)
-
- ;; Skip over type decl prefix operators. (Note similar code in
- ;; `c-forward-declarator'.)
- (if (and c-recognize-typeless-decls
- (equal c-type-decl-prefix-key "\\<\\>"))
- (when (eq (char-after) ?\()
- (progn
- (setq paren-depth (1+ paren-depth))
- (forward-char)
- (setq after-paren-pos (point))))
- (while (and (looking-at c-type-decl-prefix-key)
- (if (and (c-major-mode-is 'c++-mode)
- (match-beginning 3))
- ;; If the third submatch matches in C++ then
- ;; we're looking at an identifier that's a
- ;; prefix only if it specifies a member pointer.
- (when (progn (setq pos (point))
- (setq got-identifier (d-forward-name)))
- (setq name-start pos)
- (if (looking-at "\\(::\\)")
- ;; We only check for a trailing "::" and
- ;; let the "*" that should follow be
- ;; matched in the next round.
- (progn (setq got-identifier nil) t)
- ;; It turned out to be the real identifier,
- ;; so stop.
- nil))
- t))
-
- (if (eq (char-after) ?\()
- (progn
- (setq paren-depth (1+ paren-depth))
- (forward-char)
- (setq after-paren-pos (point)))
- (unless got-prefix-before-parens
- (setq got-prefix-before-parens (= paren-depth 0)))
- (setq got-prefix t)
- (goto-char (match-end 1)))
- (c-forward-syntactic-ws)))
+ (when
+ ;; The various kinds of declarations are handled here:
+ (cond
- (setq got-parens (> paren-depth 0))
+ ;; Aggregate declaration (class/struct ...)
+ ;; Handle enumerations here too.
+ ((and (memq context '(top nil))
+ (or enum
+ (looking-at (d-make-keywords-re t (c-lang-const
c-class-decl-kwds d)))))
- ;; Try to skip over an identifier.
- (or got-identifier
- (and (looking-at c-identifier-start)
- (setq pos (point))
- (setq got-identifier (d-forward-name))
- (setq name-start pos))
- (when (looking-at "[0-9]")
- (setq got-number t))) ; We've probably got an arithmetic expression.
+ (unless enum
+ (goto-char (match-end 1))
+ (c-forward-syntactic-ws))
+ (setq type-start (point))
+ (setq id-start type-start)
- ;; Skip over type decl suffix operators and trailing noise macros.
- (while
- (cond
- ((and c-opt-cpp-prefix
- (looking-at c-noise-macro-with-parens-name-re))
- (c-forward-noise-clause))
-
- ((and (looking-at c-type-decl-suffix-key)
- ;; We avoid recognizing foo(bar) or foo() at top level as a
- ;; construct here in C, since we want to recognize this as a
- ;; typeless function declaration.
- (not (and (c-major-mode-is 'c-mode)
- (or (eq context 'top) make-top)
- (eq (char-after) ?\)))))
- (if (eq (char-after) ?\))
- (when (> paren-depth 0)
- (setq paren-depth (1- paren-depth))
- (forward-char)
- t)
- (when (if (save-match-data (looking-at "\\s("))
- (c-safe (c-forward-sexp 1) t)
- (goto-char (match-end 1))
- t)
- (when (and (not got-suffix-after-parens)
- (= paren-depth 0))
- (setq got-suffix-after-parens (match-beginning 0)))
- (setq got-suffix t))))
+ (and
+ (d-forward-identifier)
+ (progn
+ (c-forward-syntactic-ws)
+ (looking-at "[:({;]"))))
- (t
- ;; No suffix matched. We might have matched the
- ;; identifier as a type and the open paren of a
- ;; function arglist as a type decl prefix. In that
- ;; case we should "backtrack": Reinterpret the last
- ;; type as the identifier, move out of the arglist and
- ;; continue searching for suffix operators.
- ;;
- ;; Do this even if there's no preceding type, to cope
- ;; with old style function declarations in K&R C,
- ;; (con|de)structors in C++ and `c-typeless-decl-kwds'
- ;; style declarations. That isn't applicable in an
- ;; arglist context, though.
- (when (and (= paren-depth 1)
- (not got-prefix-before-parens)
- (not (eq at-type t))
- (or backup-at-type
- maybe-typeless
- backup-maybe-typeless
- (when c-recognize-typeless-decls
- (and (memq context '(nil top))
- ;; Deal with C++11's "copy-initialization"
- ;; where we have <type>(<constant>), by
- ;; contrasting with a typeless
- ;; <name>(<type><parameter>, ...).
- (save-excursion
- (goto-char after-paren-pos)
- (c-forward-syntactic-ws)
- (or (c-forward-type)
- ;; Recognize a top-level typeless
- ;; function declaration in C.
- (and (c-major-mode-is 'c-mode)
- (or (eq context 'top) make-top)
- (eq (char-after) ?\))))))))
- (setq pos (c-up-list-forward (point)))
- (eq (char-before pos) ?\)))
- (c-fdoc-shift-type-backward)
- (goto-char pos)
- t)))
+ ;; Mixin templates
+ ((and (memq context '(top nil))
+ (looking-at (d-make-keywords-re t '("mixin"))))
+ (goto-char (match-end 1))
+ (c-forward-syntactic-ws)
+ (and
+ (looking-at (d-make-keywords-re t '("template")))
+ (progn
+ (goto-char (match-end 1))
+ (c-forward-syntactic-ws)
+ (setq type-start (point))
+ (setq id-start type-start)
+ (d-forward-identifier))
+ (progn
+ (c-forward-syntactic-ws)
+ (looking-at "("))))
- (c-forward-syntactic-ws))
+ ;; Constructors/destructors
+ ((and (eq context 'top)
+ (looking-at (d-make-keywords-re t '("this" "~this"))))
+ (setq id-start decl-start)
+ (goto-char (match-end 1))
+ t)
- (when (or (and new-style-auto
- (looking-at c-auto-ops-re))
- (and (or maybe-typeless backup-maybe-typeless)
- (not got-identifier)
- (not got-prefix)
- at-type))
- ;; Have found no identifier but `c-typeless-decl-kwds' has
- ;; matched so we know we're inside a declaration. The
- ;; preceding type must be the identifier instead.
- (c-fdoc-shift-type-backward))
-
- ;; Prepare the "-> type;" for fontification later on.
- (when (and new-style-auto
- (looking-at c-haskell-op-re))
- (save-excursion
- (goto-char (match-end 0))
+ ;; Alias declarations
+ ((and (memq context '(top nil))
+ (looking-at (d-make-keywords-re t '("alias"))))
+ (setq type-start decl-start) ; indicate declaration type for e.g.
imenu
+ (goto-char (match-end 1))
(c-forward-syntactic-ws)
- (setq type-start (point))
- (setq at-type (c-forward-type))))
+ (setq id-start (point))
+ (d-forward-type) ; alias name or value
+ (cond
+ ;; New style (alias name = value)
+ ((memq (char-after) '(?= ?\())
+ t)
+ ;; Old style (alias value name)
+ ((looking-at c-symbol-key)
+ (setq id-start (point))
+ t)))
+
+ ;; Function / variable / constant declaration, i.e. an
+ ;; (optional) type followed by an identifier.
+ ((and (memq context '(top nil))
+ ;; Declaration type, or identifier for auto
+ ;; declarations. Note that all identifiers
+ ;; are also valid types.
+ (d-forward-type))
+
+ (setq type-start decl-start)
+ (setq id-start (point))
- ;; Move forward over any "WS" ids (like "final" or "override" in C++)
- (while (looking-at c-type-decl-suffix-ws-ids-key)
- (goto-char (match-end 1))
- (c-forward-syntactic-ws))
+ (cond
+ ;; auto-declaration
+ ((and maybe-auto
+ (looking-at (c-lang-const d-decl-end-re)))
+ (setq id-start type-start)
+ (setq type-start nil)
+ t)
+ ;; regular declaration
+ ((and (d-forward-identifier)
+ (progn
+ (c-forward-syntactic-ws)
+ (looking-at (c-lang-const d-decl-end-re))))
+ t)))
+
+ ;; Function parameter list.
+ ;; Note: single (type-less) identifiers in parameter lists
+ ;; mean different things for function and lambda parameter
+ ;; lists. For functions, they indicate the type of an
+ ;; anonymous parameter; for lambdas, they indicate the name
+ ;; of a parameter with an inferred type.
+ ;; Currently we don't fontify them as either.
+ ((and (eq context 'arglist)
+ (d-forward-type))
+ (setq type-start decl-start)
+ (setq id-start (point))
+ (and (d-forward-identifier) ; parameter name
+ (progn
+ (c-forward-syntactic-ws)
+ (looking-at "[,=)]")))))
- (setq
- at-decl-or-cast
- (catch 'at-decl-or-cast
-
- ;; CASE 1
- (when (> paren-depth 0)
- ;; Encountered something inside parens that isn't matched by
- ;; the `c-type-decl-*' regexps, so it's not a type decl
- ;; expression. Try to skip out to the same paren depth to
- ;; not confuse the cast check below. If we don't manage this and
- ;; `at-decl-or-cast' is 'ids we might have an expression like
- ;; "foo bar ({ ..." which is a valid C++11 initialization.
- (if (and (not (c-safe (goto-char (scan-lists (point) 1
paren-depth))))
- (eq at-decl-or-cast 'ids))
- (c-fdoc-shift-type-backward))
- ;; If we've found a specifier keyword then it's a
- ;; declaration regardless.
- (throw 'at-decl-or-cast (memq at-decl-or-cast '(t ids))))
-
- (setq at-decl-end
- (looking-at (cond ((eq context '<>) "[,>]")
- ((not (memq context '(nil top))) "[,\)]")
- (t "[,;]"))))
-
- ;; Now we've collected info about various characteristics of
- ;; the construct we're looking at. Below follows a decision
- ;; tree based on that. It's ordered to check more certain
- ;; signs before less certain ones.
-
- (if got-identifier
- (progn
-
- ;; CASE 2
- (when (and (or at-type maybe-typeless)
- (not (or got-prefix got-parens)))
- ;; Got another identifier directly after the type, so it's a
- ;; declaration.
- (throw 'at-decl-or-cast t))
-
- (when (and got-parens
- (not got-prefix)
- ;; (not got-suffix-after-parens)
- (or backup-at-type
- maybe-typeless
- backup-maybe-typeless
- (eq at-decl-or-cast t)
- ;; Check whether we have "bar (gnu);" where we
- ;; are directly inside a class (etc.) called
"bar".
- (save-excursion
- (and
- (progn
- (goto-char name-start)
- (not (memq (c-forward-type) '(nil maybe))))
- (progn
- (goto-char id-start)
- (c-directly-in-class-called-p
- (buffer-substring
- type-start
- (progn
- (goto-char type-start)
- (c-forward-type)
- (c-backward-syntactic-ws)
- (point)))))))))
- ;; Got a declaration of the form "foo bar (gnu);" or "bar
- ;; (gnu);" where we've recognized "bar" as the type and "gnu"
- ;; as the declarator, and in the latter case, checked that
- ;; "bar (gnu)" appears directly inside the class "bar". In
- ;; this case it's however more likely that "bar" is the
- ;; declarator and "gnu" a function argument or initializer
- ;; (if `c-recognize-paren-inits' is set), since the parens
- ;; around "gnu" would be superfluous if it's a declarator.
- ;; Shift the type one step backward.
- (c-fdoc-shift-type-backward)))
-
- ;; Found no identifier.
-
- (if backup-at-type
- (progn
-
- ;; CASE 3
- (when (= (point) start)
- ;; Got a plain list of identifiers. If a colon follows it's
- ;; a valid label, or maybe a bitfield. Otherwise the last
- ;; one probably is the declared identifier and we should
- ;; back up to the previous type, providing it isn't a cast.
- (if (and (eq (char-after) ?:)
- (not (c-major-mode-is 'java-mode)))
- (cond
- ;; If we've found a specifier keyword then it's a
- ;; declaration regardless.
- ((eq at-decl-or-cast t)
- (throw 'at-decl-or-cast t))
- ((and c-has-bitfields
- (eq at-decl-or-cast 'ids)) ; bitfield.
- (setq backup-if-not-cast t)
- (throw 'at-decl-or-cast t)))
-
- (setq backup-if-not-cast t)
- (throw 'at-decl-or-cast t)))
-
- ;; CASE 4
- (when (and got-suffix
- (not got-prefix)
- (not got-parens))
- ;; Got a plain list of identifiers followed by some suffix.
- ;; If this isn't a cast then the last identifier probably is
- ;; the declared one and we should back up to the previous
- ;; type.
- (setq backup-if-not-cast t)
- (throw 'at-decl-or-cast t)))
-
- ;; CASE 5
- (when (eq at-type t)
- ;; If the type is known we know that there can't be any
- ;; identifier somewhere else, and it's only in declarations in
- ;; e.g. function prototypes and in casts that the identifier may
- ;; be left out.
- (throw 'at-decl-or-cast t))
-
- (when (= (point) start)
- ;; Only got a single identifier (parsed as a type so far).
- ;; CASE 6
- (if (and
- ;; Check that the identifier isn't at the start of an
- ;; expression.
- at-decl-end
- (cond
- ((eq context 'decl)
- ;; Inside an arglist that contains declarations. If K&R
- ;; style declarations and parenthesis style initializers
- ;; aren't allowed then the single identifier must be a
- ;; type, else we require that it's known or found
- ;; (primitive types are handled above).
- (or (and (not c-recognize-knr-p)
- (not c-recognize-paren-inits))
- (memq at-type '(known found))))
- ((eq context '<>)
- ;; Inside a template arglist. Accept known and found
- ;; types; other identifiers could just as well be
- ;; constants in C++.
- (memq at-type '(known found)))))
- (throw 'at-decl-or-cast t)
- ;; CASE 7
- ;; Can't be a valid declaration or cast, but if we've found a
- ;; specifier it can't be anything else either, so treat it as
- ;; an invalid/unfinished declaration or cast.
- (throw 'at-decl-or-cast at-decl-or-cast))))
-
- (if (and got-parens
- (not got-prefix)
- (memq context '(nil top))
- (not (eq at-type t))
- (or backup-at-type
- maybe-typeless
- backup-maybe-typeless
- (when c-recognize-typeless-decls
- (or (not got-suffix)
- (not (looking-at
- c-after-suffixed-type-maybe-decl-key))))))
- ;; Got an empty paren pair and a preceding type that probably
- ;; really is the identifier. Shift the type backwards to make
- ;; the last one the identifier. This is analogous to the
- ;; "backtracking" done inside the `c-type-decl-suffix-key' loop
- ;; above.
- ;;
- ;; Exception: In addition to the conditions in that
- ;; "backtracking" code, do not shift backward if we're not
- ;; looking at either `c-after-suffixed-type-decl-key' or "[;,]".
- ;; Since there's no preceding type, the shift would mean that
- ;; the declaration is typeless. But if the regexp doesn't match
- ;; then we will simply fall through in the tests below and not
- ;; recognize it at all, so it's better to try it as an abstract
- ;; declarator instead.
- (c-fdoc-shift-type-backward)
-
- ;; Still no identifier.
- ;; CASE 8
- (when (and got-prefix (or got-parens got-suffix))
- ;; Require `got-prefix' together with either `got-parens' or
- ;; `got-suffix' to recognize it as an abstract declarator:
- ;; `got-parens' only is probably an empty function call.
- ;; `got-suffix' only can build an ordinary expression together
- ;; with the preceding identifier which we've taken as a type.
- ;; We could actually accept on `got-prefix' only, but that can
- ;; easily occur temporarily while writing an expression so we
- ;; avoid that case anyway. We could do a better job if we knew
- ;; the point when the fontification was invoked.
- (throw 'at-decl-or-cast t))
-
- ;; CASE 9
- (when (and at-type
- (not got-prefix)
- (not got-parens)
- got-suffix-after-parens
- (eq (char-after got-suffix-after-parens) ?\())
- ;; Got a type, no declarator but a paren suffix. I.e. it's a
- ;; normal function call after all (or perhaps a C++ style object
- ;; instantiation expression).
- (throw 'at-decl-or-cast nil))))
-
- ;; CASE 9.5
- (when (and (not context) ; i.e. not at top level.
- (c-major-mode-is 'c++-mode)
- (eq at-decl-or-cast 'ids)
- after-paren-pos)
- ;; We've got something like "foo bar (...)" in C++ which isn't at
- ;; the top level. This is probably a uniform initialization of bar
- ;; to the contents of the parens. In this case the declarator ends
- ;; at the open paren.
- (goto-char (1- after-paren-pos))
- (throw 'at-decl-or-cast t))
-
- ;; CASE 10
- (when at-decl-or-cast
- ;; By now we've located the type in the declaration that we know
- ;; we're in.
- (throw 'at-decl-or-cast t))
-
- ;; CASE 11
- (when (and got-identifier
- (looking-at c-after-suffixed-type-decl-key)
- (or (eq context 'top)
- make-top
- (and (eq context nil)
- (match-beginning 1)))
- (if (and got-parens
- (not got-prefix)
- (not got-suffix)
- (not (eq at-type t)))
- ;; Shift the type backward in the case that there's a
- ;; single identifier inside parens. That can only
- ;; occur in K&R style function declarations so it's
- ;; more likely that it really is a function call.
- ;; Therefore we only do this after
- ;; `c-after-suffixed-type-decl-key' has matched.
- (progn (c-fdoc-shift-type-backward) t)
- got-suffix-after-parens))
- ;; A declaration according to `c-after-suffixed-type-decl-key'.
- (throw 'at-decl-or-cast t))
-
- ;; CASE 12
- (when (and (or got-prefix (not got-parens))
- (memq at-type '(t known)))
- ;; It's a declaration if a known type precedes it and it can't be a
- ;; function call.
- (throw 'at-decl-or-cast t))
-
- ;; If we get here we can't tell if this is a type decl or a normal
- ;; expression by looking at it alone. (That's under the assumption
- ;; that normal expressions always can look like type decl expressions,
- ;; which isn't really true but the cases where it doesn't hold are so
- ;; uncommon (e.g. some placements of "const" in C++) it's not worth
- ;; the effort to look for them.)
-
-;;; 2008-04-16: commented out the next form, to allow the function to
recognize
-;;; "foo (int bar)" in CC (an implicit type (in class foo) without a
semicolon)
-;;; as a(n almost complete) declaration, enabling it to be fontified.
- ;; CASE 13
- ;; (unless (or at-decl-end (looking-at "=[^=]"))
- ;; If this is a declaration it should end here or its initializer(*)
- ;; should start here, so check for allowed separation tokens. Note
- ;; that this rule doesn't work e.g. with a K&R arglist after a
- ;; function header.
- ;;
- ;; *) Don't check for C++ style initializers using parens
- ;; since those already have been matched as suffixes.
- ;;
- ;; If `at-decl-or-cast' is then we've found some other sign that
- ;; it's a declaration or cast, so then it's probably an
- ;; invalid/unfinished one.
- ;; (throw 'at-decl-or-cast at-decl-or-cast))
-
- ;; Below are tests that only should be applied when we're certain to
- ;; not have parsed halfway through an expression.
-
- ;; CASE 14
- (when (memq at-type '(t known))
- ;; The expression starts with a known type so treat it as a
- ;; declaration.
- (throw 'at-decl-or-cast t))
-
- ;; CASE 15
- (when (and (c-major-mode-is 'c++-mode)
- ;; In C++ we check if the identifier is a known type, since
- ;; (con|de)structors use the class name as identifier.
- ;; We've always shifted over the identifier as a type and
- ;; then backed up again in this case.
- identifier-type
- (or (memq identifier-type '(found known))
- (and (eq (char-after identifier-start) ?~)
- ;; `at-type' probably won't be 'found for
- ;; destructors since the "~" is then part of the
- ;; type name being checked against the list of
- ;; known types, so do a check without that
- ;; operator.
- (or (save-excursion
- (goto-char (1+ identifier-start))
- (c-forward-syntactic-ws)
- (c-with-syntax-table
- c-identifier-syntax-table
- (looking-at c-known-type-key)))
- (save-excursion
- (goto-char (1+ identifier-start))
- ;; We have already parsed the type earlier,
- ;; so it'd be possible to cache the end
- ;; position instead of redoing it here, but
- ;; then we'd need to keep track of another
- ;; position everywhere.
- (c-check-type (point)
- (progn (c-forward-type)
- (point))))))))
- (throw 'at-decl-or-cast t))
-
- (if got-identifier
- (progn
- ;; CASE 16
- (when (and got-prefix-before-parens
- at-type
- (or at-decl-end (looking-at "=[^=]"))
- (memq context '(nil top))
- (or (not got-suffix)
- at-decl-start))
- ;; Got something like "foo * bar;". Since we're not inside
- ;; an arglist it would be a meaningless expression because
- ;; the result isn't used. We therefore choose to recognize
- ;; it as a declaration. We only allow a suffix (which makes
- ;; the construct look like a function call) when
- ;; `at-decl-start' provides additional evidence that we do
- ;; have a declaration.
- (setq maybe-expression t)
- (throw 'at-decl-or-cast t))
-
- ;; CASE 17
- (when (and (or got-suffix-after-parens
- (looking-at "=[^=]"))
- (eq at-type 'found)
- (not (eq context 'arglist)))
- ;; Got something like "a (*b) (c);" or "a (b) = c;". It could
- ;; be an odd expression or it could be a declaration. Treat
- ;; it as a declaration if "a" has been used as a type
- ;; somewhere else (if it's a known type we won't get here).
- (setq maybe-expression t)
- (throw 'at-decl-or-cast t))
-
- ;; CASE 17.5
- (when (and c-asymmetry-fontification-flag
- got-prefix-before-parens
- at-type
- (or (not got-suffix)
- at-decl-start))
- (let ((space-before-id
- (save-excursion
- (goto-char name-start)
- (or (bolp) (memq (char-before) '(?\ ?\t)))))
- (space-after-type
- (save-excursion
- (goto-char type-start)
- (and (c-forward-type)
- (progn (c-backward-syntactic-ws) t)
- (or (eolp)
- (memq (char-after) '(?\ ?\t)))))))
- (when (not (eq (not space-before-id)
- (not space-after-type)))
- (setq maybe-expression t)
- (throw 'at-decl-or-cast t)))))
-
- ;; CASE 18
- (when (and (not (memq context '(nil top)))
- (or (and got-prefix (not got-number))
- (and (eq context 'decl)
- (not c-recognize-paren-inits)
- (or got-parens got-suffix))))
- ;; Got a type followed by an abstract declarator. If `got-prefix'
- ;; is set it's something like "a *" without anything after it. If
- ;; `got-parens' or `got-suffix' is set it's "a()", "a[]", "a()[]",
- ;; or similar, which we accept only if the context rules out
- ;; expressions.
- (throw 'at-decl-or-cast t)))
-
- ;; If we had a complete symbol table here (which rules out
- ;; `c-found-types') we should return t due to the disambiguation rule
- ;; (in at least C++) that anything that can be parsed as a declaration
- ;; is a declaration. Now we're being more defensive and prefer to
- ;; highlight things like "foo (bar);" as a declaration only if we're
- ;; inside an arglist that contains declarations. Update (2017-09): We
- ;; now recognize a top-level "foo(bar);" as a declaration in C.
- ;; CASE 19
- (or (eq context 'decl)
- (and (c-major-mode-is 'c-mode)
- (or (eq context 'top) make-top))))))
-
- ;; The point is now after the type decl expression.
+ ;; Valid declaration, process it.
- (cond
- ;; Check for a cast.
- ((save-excursion
- (and
- c-cast-parens
-
- ;; Should be the first type/identifier in a cast paren.
- (> preceding-token-end (point-min))
- (memq (char-before preceding-token-end) c-cast-parens)
-
- ;; The closing paren should follow.
- (progn
- (c-forward-syntactic-ws)
- (looking-at "\\s)"))
-
- ;; There should be a primary expression after it.
- (let (pos)
- (forward-char)
- (c-forward-syntactic-ws)
- (setq cast-end (point))
- (and (looking-at c-primary-expr-regexp)
- (progn
- (setq pos (match-end 0))
- (or
- ;; Check if the expression begins with a prefix keyword.
- (match-beginning 2)
- (if (match-beginning 1)
- ;; Expression begins with an ambiguous operator. Treat
- ;; it as a cast if it's a type decl or if we've
- ;; recognized the type somewhere else.
- (or at-decl-or-cast
- (memq at-type '(t known found)))
- ;; Unless it's a keyword, it's the beginning of a primary
- ;; expression.
- (not (looking-at c-keywords-regexp)))))
- ;; If `c-primary-expr-regexp' matched a nonsymbol token, check
- ;; that it matched a whole one so that we don't e.g. confuse
- ;; the operator '-' with '->'. It's ok if it matches further,
- ;; though, since it e.g. can match the float '.5' while the
- ;; operator regexp only matches '.'.
- (or (not (looking-at c-nonsymbol-token-regexp))
- (<= (match-end 0) pos))))
-
- ;; There should either be a cast before it or something that isn't an
- ;; identifier or close paren.
- (> preceding-token-end (point-min))
- (progn
- (goto-char (1- preceding-token-end))
- (or (eq (point) last-cast-end)
- (progn
- (c-backward-syntactic-ws)
- (if (< (skip-syntax-backward "w_") 0)
- ;; It's a symbol. Accept it only if it's one of the
- ;; keywords that can precede an expression (without
- ;; surrounding parens).
- (looking-at c-simple-stmt-key)
- (and
- ;; Check that it isn't a close paren (block close is ok,
- ;; though).
- (not (memq (char-before) '(?\) ?\])))
- ;; Check that it isn't a nonsymbol identifier.
- (not (c-on-identifier)))))))))
-
- ;; Handle the cast.
- (when (and c-record-type-identifiers at-type (not (eq at-type t)))
- (let ((c-promote-possible-types t))
- (goto-char type-start)
- (c-forward-type)))
-
- (goto-char cast-end)
- 'cast)
-
- (at-decl-or-cast
- ;; We're at a declaration. Highlight the type and the following
- ;; declarators.
-
- (when backup-if-not-cast
- (c-fdoc-shift-type-backward t))
-
- (when (and (eq context 'decl) (looking-at ","))
- ;; Make sure to propagate the `c-decl-arg-start' property to
- ;; the next argument if it's set in this one, to cope with
- ;; interactive refontification.
- (c-put-c-type-property (point) 'c-decl-arg-start))
-
- ;; Record the type's coordinates in `c-record-type-identifiers' for
- ;; later fontification.
- (when (and c-record-type-identifiers at-type ;; (not (eq at-type t))
- ;; There seems no reason to exclude a token from
- ;; fontification just because it's "a known type that can't
- ;; be a name or other expression". 2013-09-18.
- )
+ (when (and c-record-type-identifiers type-start)
(let ((c-promote-possible-types t))
(save-excursion
(goto-char type-start)
- (c-forward-type))))
+ (d-forward-type))))
(list id-start
- (and (or at-type-decl at-typedef)
- (cons at-type-decl at-typedef))
- maybe-expression
+ nil
+ nil
type-start
- (or (eq context 'top) make-top)))
+ (or (eq context 'top) make-top)))))
+
+
+(defun d-forward-identifier ()
+ "Advance point by one D identifier."
+ (when (and (not (looking-at c-keywords-regexp))
+ (looking-at c-symbol-key))
+ (goto-char (match-end 0))
+ t))
+
+
+(defun d-forward-attribute-or-storage-class ()
+ "Handle D attributes and storage classes in declarations.
- (t
- ;; False alarm. Restore the recorded ranges.
- (setq c-record-type-identifiers save-rec-type-ids
- c-record-ref-identifiers save-rec-ref-ids)
- nil))))
+Advance point and return non-nil if looking at something that may prefix a
+declaration (or follow the argument list, in case of functions)."
+ ;; Note that this includes UDAs.
+ (let ((start (point))
+ (kind t)
+ match-index)
+ (when
+ (cond
+ ((looking-at (d-make-keywords-re t '("enum")))
+ (setq match-index 1
+ kind 'enum))
+ ((looking-at (d-make-keywords-re t (c-lang-const d-type-modifier-kwds
d)))
+ (setq match-index 1
+ kind 'type-modifier))
+ ((looking-at (d-make-keywords-re t (c-lang-const c-modifier-kwds d)))
+ (setq match-index 1))
+ ((and (eq (char-after) ?@)
+ (looking-at c-symbol-key))
+ (setq match-index 0)))
+ (goto-char (match-end match-index))
+ (c-forward-syntactic-ws)
+ ;; Skip parameters, such as:
+ ;; - extern(C)
+ ;; - deprecated("...")
+ ;; - package(std)
+ ;; - @SomeUDA(...)
+ (if (looking-at "(")
+ ;; Distinguish between "const x" and "const(x)". In the
+ ;; former, "const" is an attribute, but in the latter it is
+ ;; part of a type. This distinction is important when parsing
+ ;; constructs where a type is required; a greedy attribute
+ ;; match would leave only "(x)" which will not make sense.
+ (if (eq kind 'type-modifier)
+ (progn
+ (goto-char start)
+ nil)
+ (c-go-list-forward)
+ (c-forward-syntactic-ws)
+ kind)
+ kind))))
;;----------------------------------------------------------------------------
@@ -2451,9 +1596,11 @@ The expression is added to
`compilation-error-regexp-alist' and
(point)))
(id-end (progn
(goto-char id-start)
- (when (d-forward-name)
- (c-backward-syntactic-ws)
- (point))))
+ (cond
+ ((d-forward-identifier)
+ (point))
+ ((looking-at (d-make-keywords-re t '("this"
"~this")))
+ (match-end 1)))))
(name (when id-end
(buffer-substring-no-properties id-start id-end)))
(id-prev-token (progn
@@ -2463,6 +1610,11 @@ The expression is added to
`compilation-error-regexp-alist' and
(when (c-simple-skip-symbol-backward)
(buffer-substring-no-properties
(point) end)))))
(type-start (cadddr decl-or-cast))
+ (type-token (and type-start
+ (progn
+ (goto-char type-start)
+ (looking-at c-symbol-key))
+ (match-string-no-properties 0)))
(type-prev-token (when type-start
(goto-char type-start)
(c-backward-syntactic-ws)
@@ -2490,7 +1642,7 @@ The expression is added to
`compilation-error-regexp-alist' and
'("Templates" t))
((equal id-prev-token "alias")
'("Aliases" nil))
- ((equal type-prev-token "alias")
+ ((equal type-token "alias")
'("Aliases" nil)) ; old-style alias
((memq next-char '(?\; ?= ?,))
nil) ; '("variable" nil))
diff --git a/tests/I0095.d.html b/tests/I0095.d.html
index c9ac7cf..a9f7452 100644
--- a/tests/I0095.d.html
+++ b/tests/I0095.d.html
@@ -1,6 +1,6 @@
<span class="comment-delimiter">// </span><span class="comment">#run:
(d-test-fontification)
</span>
-<span class="keyword">alias</span> <span class="type">Type</span> = <span
class="type">int</span>;
+<span class="keyword">alias</span> <span class="variable-name">Type</span> =
<span class="type">int</span>;
<span class="type">void</span> <span class="function-name">foo</span>(<span
class="keyword">const</span>(<span class="type">Type</span>) <span
class="variable-name">param</span>);
diff --git a/tests/fonts.d b/tests/fonts.d
index d93595f..26e320b 100644
--- a/tests/fonts.d
+++ b/tests/fonts.d
@@ -27,3 +27,6 @@ auto s = "enum Type {}";
assert(a !in b);
invariant {}
+
+class Foo : Bar {}
+enum Foo : Bar {}
diff --git a/tests/fonts.d.html b/tests/fonts.d.html
index 9d82476..51a0e36 100644
--- a/tests/fonts.d.html
+++ b/tests/fonts.d.html
@@ -27,3 +27,6 @@
<span class="keyword">assert</span>(a <span
class="negation-char">!</span><span class="keyword">in</span> b);
<span class="keyword">invariant</span> {}
+
+<span class="keyword">class</span> <span class="type">Foo</span> : <span
class="type">Bar</span> {}
+<span class="keyword">enum</span> <span class="type">Foo</span> : <span
class="type">Bar</span> {}
- [nongnu] elpa/d-mode 80fad30 345/346: Merge pull request #108 from CyberShadow/github-actions, (continued)
- [nongnu] elpa/d-mode 80fad30 345/346: Merge pull request #108 from CyberShadow/github-actions, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode e42c1c1 340/346: Implement r"..." string literal syntax, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode dee393b 228/346: Fix setting the mode menu, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode ac898c0 245/346: Fix parsing of scope-statements, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 459732e 243/346: Fix parsing associative arrays in function types, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 362be11 250/346: Fix imenu false positive with e.g. private{...}, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode ea32e73 264/346: Makefile: Test byte-compiled version, too, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 979c946 256/346: Fix testing multiple nested imenu entries, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 8ffe5ac 265/346: Remove doxygen-font-lock-*, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 80f2019 261/346: Don't nest imenu to arbitrary depths, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode bdd5d78 281/346: Replace d-forward-decl-or-cast-1 implementation with a custom one,
ELPA Syncer <=
- [nongnu] elpa/d-mode 02d1c7f 290/346: tests: Add more binary operation tests, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 09ecdaa 303/346: Add "make coverage", ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 166fac8 313/346: Fix fontification of second foreach variable, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 0d45ab2 315/346: Fix brace stack logic creating unbalanced stacks, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 55c8cb0 306/346: Fontify types in function parameter lists, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode c22a8c1 309/346: Fontify variables in foreach loops, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 3731f1b 316/346: Fontify built-in @-keywords as keywords, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode e70d89f 312/346: Fix fontification of catch statements, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode 2f7adb1 319/346: Fontify sole lambda params, ELPA Syncer, 2021/08/29
- [nongnu] elpa/d-mode b40a7ab 328/346: Unbundle undercover.el, ELPA Syncer, 2021/08/29