emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master a057d41c75: CC Mode: Handle C++20 modules


From: Alan Mackenzie
Subject: master a057d41c75: CC Mode: Handle C++20 modules
Date: Thu, 15 Sep 2022 15:57:41 -0400 (EDT)

branch: master
commit a057d41c7577c0e7089dd259fd8edf75f636c7a1
Author: Alan Mackenzie <acm@muc.de>
Commit: Alan Mackenzie <acm@muc.de>

    CC Mode: Handle C++20 modules
    
    * lisp/progmodes/cc-engine.el (c-before-after-change-check-c++-modules): New
    function.
    (c-forward-<>-arglist): Add special handling for "import <...>".
    
    * lisp/progmodes/cc-fonts.el (c-preprocessor-face-name): Add extra 
"fallback"
    face after font-lock-reference-face, namely font-lock-constant-face.
    (c-cpp-matchers): Don't fontify the <> delimiters for XEmacs in #include 
<..>.
    (c-basic-matchers-before): Add c-font-lock-c++-modules to the C++ value.
    (c-forward-c++-module-name, c-forward-c++-module-partition-name)
    (c-font-lock-c++-modules): New functions.
    
    * lisp/progmodes/cc-langs.el (c-get-state-before-change-functions)
    (c-before-font-lock-functions): Include
    c-before-after-change-check-c++-modules in the C++ value of these variables.
    (c-module-name-re): New c-lang-const/var.
    (c-other-decl-kwds): Add a C++ value "export".
    (c-<>-sexp-kwds): Add a new component c-import-<>-kwds.
    (c-import-<>-kwds, c-module-kwds): New c-lang-consts.
    (c-module-key): New c-lang-const/var.
---
 lisp/progmodes/cc-engine.el |  87 +++++++++++++++++-----
 lisp/progmodes/cc-fonts.el  | 173 +++++++++++++++++++++++++++++++++++++++++++-
 lisp/progmodes/cc-langs.el  |  35 ++++++++-
 3 files changed, 271 insertions(+), 24 deletions(-)

diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 94225d6e3e..1127ffe249 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -8156,6 +8156,40 @@ multi-line strings (but not C++, for example)."
     (c-truncate-lit-pos-cache c-neutralize-pos)))
 
 
+(defun c-before-after-change-check-c++-modules (beg end &optional _old_len)
+  ;; Extend the region (c-new-BEG c-new-END) as needed to enclose complete
+  ;; C++20 module statements.  This function is called solely from
+  ;; `c-get-state-before-change-functions' and `c-before-font-lock-functions'
+  ;; as part of the before-change and after-change processing for C++.
+  ;;
+  ;; Point is undefined both on entry and exit, and the return value has no
+  ;; significance.
+  (c-save-buffer-state (res bos lit-start)
+    (goto-char end)
+    (if (setq lit-start (c-literal-start))
+       (goto-char lit-start))
+    (when (>= (point) beg)
+      (setq res (c-beginning-of-statement-1 nil t)) ; t is IGNORE-LABELS
+      (setq bos (point))
+      (when (and (memq res '(same previous))
+                (looking-at c-module-key))
+       (setq c-new-BEG (min c-new-BEG (point)))
+       (if (c-syntactic-re-search-forward
+            ";" (min (+ (point) 500) (point-max)) t)
+           (setq c-new-END (max c-new-END (point))))))
+    (when (or (not bos) (< beg bos))
+      (goto-char beg)
+      (when (not (c-literal-start))
+       (setq res (c-beginning-of-statement-1 nil t))
+       (setq bos (point))
+       (when (and (memq res '(same previous))
+                  (looking-at c-module-key))
+         (setq c-new-BEG (min c-new-BEG (point)))
+         (if (c-syntactic-re-search-forward
+              ";" (min (+ (point) 500) (point-max)) t)
+             (setq c-new-END (max c-new-END (point)))))))))
+
+
 ;; Handling of small scale constructs like types and names.
 
 ;; Dynamically bound variable that instructs `c-forward-type' to also
@@ -8474,25 +8508,40 @@ multi-line strings (but not C++, for example)."
        ;; recording of any found types that constitute an argument in
        ;; the arglist.
        (c-record-found-types (if c-record-type-identifiers t)))
-    (if (catch 'angle-bracket-arglist-escape
-         (setq c-record-found-types
-               (c-forward-<>-arglist-recur all-types)))
-       (progn
-         (when (consp c-record-found-types)
-           (let ((cur c-record-found-types))
-             (while (consp (car-safe cur))
-               (c-fontify-new-found-type
-                (buffer-substring-no-properties (caar cur) (cdar cur)))
-               (setq cur (cdr cur))))
-           (setq c-record-type-identifiers
-                 ;; `nconc' doesn't mind that the tail of
-                 ;; `c-record-found-types' is t.
-                 (nconc c-record-found-types c-record-type-identifiers)))
-         t)
-
-      (setq c-found-types old-found-types)
-      (goto-char start)
-      nil)))
+    ;; Special handling for C++20's "import <...>" operator.
+    (if (and (c-major-mode-is 'c++-mode)
+            (save-excursion
+              (and (zerop (c-backward-token-2))
+                   (looking-at "import\\>\\(?:[^_$]\\|$\\)"))))
+       (when (looking-at "<\\(?:\\\\.\\|[^\\\n\r\t>]\\)*\\(>\\)?")
+         (if (match-beginning 1)       ; A terminated <..>
+             (progn
+               (when c-parse-and-markup-<>-arglists
+                 (c-mark-<-as-paren (point))
+                 (c-mark->-as-paren (match-beginning 1))
+                 (c-truncate-lit-pos-cache (point)))
+               (goto-char (match-end 1))
+               t)
+           nil))
+      (if (catch 'angle-bracket-arglist-escape
+           (setq c-record-found-types
+                 (c-forward-<>-arglist-recur all-types)))
+         (progn
+           (when (consp c-record-found-types)
+             (let ((cur c-record-found-types))
+               (while (consp (car-safe cur))
+                 (c-fontify-new-found-type
+                  (buffer-substring-no-properties (caar cur) (cdar cur)))
+                 (setq cur (cdr cur))))
+             (setq c-record-type-identifiers
+                   ;; `nconc' doesn't mind that the tail of
+                   ;; `c-record-found-types' is t.
+                   (nconc c-record-found-types c-record-type-identifiers)))
+           t)
+
+       (setq c-found-types old-found-types)
+       (goto-char start)
+       nil))))
 
 (defun c-forward-<>-arglist-recur (all-types)
   ;; Recursive part of `c-forward-<>-arglist'.
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index f34f7f177d..c52f4a8416 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -112,8 +112,10 @@
         ;; In Emacs font-lock-builtin-face has traditionally been
         ;; used for preprocessor directives.
         'font-lock-builtin-face)
-       (t
-        'font-lock-reference-face)))
+       ((and (c-face-name-p 'font-lock-reference-face)
+             (eq font-lock-reference-face 'font-lock-reference-face))
+        'font-lock-reference-face)
+       (t 'font-lock-constant-face)))
 
 (cc-bytecomp-defvar font-lock-constant-face)
 
@@ -558,8 +560,10 @@ stuff.  Used on level 1 and higher."
                                 (c-lang-const c-opt-cpp-prefix)
                                 re
                                 (c-lang-const c-syntactic-ws)
-                                "\\(<[^>\n\r]*>?\\)")
-                        `(,(+ ncle-depth re-depth sws-depth 1)
+                                "\\(<\\([^>\n\r]*\\)>?\\)")
+                        `(,(+ ncle-depth re-depth sws-depth
+                              (if (featurep 'xemacs) 2 1)
+                              )
                           font-lock-string-face t)
                         `((let ((beg (match-beginning
                                       ,(+ ncle-depth re-depth sws-depth 1)))
@@ -878,6 +882,10 @@ casts and declarations are fontified.  Used on level 2 and 
higher."
                                                  c-reference-face-name))
                        (goto-char (match-end 1))))))))))
 
+      ;; Module declarations (e.g. in C++20).
+      ,@(when (c-major-mode-is 'c++-mode)
+         '(c-font-lock-c++-modules))
+
       ;; Fontify the special declarations in Objective-C.
       ,@(when (c-major-mode-is 'objc-mode)
          `(;; Fontify class names in the beginning of message expressions.
@@ -1909,6 +1917,163 @@ casts and declarations are fontified.  Used on level 2 
and higher."
            (forward-char))))) ; over the terminating "]" or other close paren.
   nil)
 
+(defun c-forward-c++-module-name (limit)
+  ;; Is there a C++20 module name at point?  If so, return a cons of the start
+  ;; and end of that name, in which case point will be moved over the name and
+  ;; following whitespace.  Otherwise nil will be returned and point will be
+  ;; unmoved.  This function doesn't regard a partition as part of the name.
+  ;; The entire construct must end not after LIMIT.
+  (when (and
+        (looking-at c-module-name-re)
+        (<= (match-end 0) limit)
+        (not (looking-at c-keywords-regexp)))
+    (goto-char (match-end 0))
+    (prog1 (cons (match-beginning 0) (match-end 0))
+      (c-forward-syntactic-ws limit))))
+
+(defun c-forward-c++-module-partition-name (limit)
+  ;; Is there a C++20 module partition name (starting with its colon) at
+  ;; point?  If so return a cons of the start and end of the name, not
+  ;; including the colon, in which case point will be move to after the name
+  ;; and following whitespace.  Otherwise nil will be returned and point not
+  ;; moved.  The entire construct must end not after LIMIT.
+  (when (and
+        (eq (char-after) ?:)
+        (progn
+          (forward-char)
+          (c-forward-syntactic-ws limit)
+          (looking-at c-module-name-re))
+        (<= (match-end 0) limit)
+        (not (looking-at c-keywords-regexp)))
+    (goto-char (match-end 0))
+    (prog1 (cons (match-beginning 0) (match-end 0))
+      (c-forward-syntactic-ws limit))))
+
+(defun c-font-lock-c++-modules (limit)
+  ;; Fontify the C++20 module stanzas, characterised by the keywords `module',
+  ;; `export' and `import'.  Note that this has to be done by a function (as
+  ;; opposed to regexps) due to the presence of optional C++ attributes.
+  ;;
+  ;; 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".
+  (while (and (< (point) limit)
+             (re-search-forward 
+              "\\<\\(module\\|export\\|import\\)\\>\\(?:[^_$]\\|$\\)"
+              limit t))
+    (goto-char (match-end 1))
+    (let (name-bounds pos beg end
+                     module-names)     ; A list of conses of start and end
+                                       ; of pertinent module names
+      (unless (c-skip-comments-and-strings limit)
+       (when
+           (cond
+            ;; module foo...; Note we don't handle module; or module
+            ;; :private; here, since they don't really need handling.
+            ((save-excursion
+               (when (equal (match-string-no-properties 1) "export")
+                 (c-forward-syntactic-ws limit)
+                 (re-search-forward "\\=\\(module\\)\\>\\(?:[^_$]\\|$\\)"
+                                    limit t))
+               (and (equal (match-string-no-properties 1) "module")
+                    (< (point) limit)
+                    (progn (c-forward-syntactic-ws limit)
+                           (setq name-bounds (c-forward-c++-module-name
+                                              limit)))
+                    (setq pos (point))))
+             (push name-bounds module-names)
+             (goto-char pos)
+             ;; Is there a partition name?
+             (when (setq name-bounds (c-forward-c++-module-partition-name
+                                      limit))
+               (push name-bounds module-names))
+             t)
+
+            ;; import
+            ((save-excursion
+               (when (equal (match-string-no-properties 1) "export")
+                 (c-forward-syntactic-ws limit)
+                 (re-search-forward "\\=\\(import\\)\\>\\(?:[^_$]\\|$\\)"
+                                    limit t))
+               (and (equal (match-string-no-properties 1) "import")
+                    (< (point) limit)
+                    (progn (c-forward-syntactic-ws limit)
+                           (setq pos (point)))))
+             (goto-char pos)
+             (cond
+              ;; import foo;
+              ((setq name-bounds (c-forward-c++-module-name limit))
+               (push name-bounds module-names)
+               t)
+              ;; import :foo;
+              ((setq name-bounds (c-forward-c++-module-partition-name limit))
+               (push name-bounds module-names)
+               t)
+              ;; import "foo";
+              ((and (eq (char-after) ?\")
+                    (setq pos (point))
+                    (c-safe (c-forward-sexp) t)) ; Should already have string 
face.
+               (when (eq (char-before) ?\")
+                 (setq beg pos
+                       end (point)))
+               (c-forward-syntactic-ws limit)
+               t)
+              ;; import <foo>;
+              ((and (looking-at "<\\(?:\\\\.\\|[^\\\n\r\t>]\\)*\\(>\\)?")
+                    (< (match-end 0) limit))
+               (setq beg (point))
+               (goto-char (match-end 0))
+               (when (match-end 1)
+                 (setq end (point)))
+               (if (featurep 'xemacs)
+                   (c-put-font-lock-face
+                    (1+ beg) (if end (1- end) (point)) font-lock-string-face)
+                 (c-put-font-lock-face
+                  beg (or end (point)) font-lock-string-face))
+               (c-forward-syntactic-ws limit)
+               t)
+              (t nil)))
+
+            ;; export
+            ;; There is no fontification to be done here, but we need to
+            ;; skip over the declaration or declaration sequence.
+            ((save-excursion
+               (when (equal (match-string-no-properties 0) "export")
+                 (c-forward-syntactic-ws limit)
+                 (setq pos (point))))
+             (goto-char (point))
+             (if (eq (char-after) ?{)
+                 ;; Declaration sequence.
+                 (unless (and (c-go-list-forward nil limit)
+                              (eq (char-before) ?}))
+                   (goto-char limit)
+                   nil)
+               ;; Single declaration
+               (unless (c-end-of-decl-1)
+                 (goto-char limit)
+                 nil))))               ; Nothing more to do, here.
+
+         ;; Optional attributes?
+         (while (and (c-looking-at-c++-attribute)
+                     (< (match-end 0) limit))
+           (goto-char (match-end 0))
+           (c-forward-syntactic-ws limit))
+         ;; Finally, there must be a semicolon.
+         (if (and (< (point) limit)
+                  (eq (char-after) ?\;))
+             (progn
+               (forward-char)
+               ;; Fontify any module names we've encountered.
+               (dolist (name module-names)
+                 (c-put-font-lock-face (car name) (cdr name)
+                                       c-reference-face-name)))
+           ;; No semicolon, so put warning faces on any delimiters.
+           (when beg
+             (c-put-font-lock-face beg (1+ beg) font-lock-warning-face))
+           (when end
+             (c-put-font-lock-face (1- end) end font-lock-warning-face))))))))
 
 (c-lang-defconst c-simple-decl-matchers
   "Simple font lock matchers for types and declarations.  These are used
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index bf7eee2283..d33ed4bcda 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -456,6 +456,7 @@ so that all identifiers are recognized as words.")
        c-depropertize-CPP
        c-before-change-check-ml-strings
        c-before-change-check-<>-operators
+       c-before-after-change-check-c++-modules
        c-truncate-bs-cache
        c-before-change-check-unbalanced-strings
        c-parse-quotes-before-change
@@ -516,6 +517,7 @@ parameters \(point-min) and \(point-max).")
        c-parse-quotes-after-change
        c-after-change-mark-abnormal-strings
        c-extend-font-lock-region-for-macros
+       c-before-after-change-check-c++-modules
        c-neutralize-syntax-in-CPP
        c-restore-<>-properties
        c-change-expand-fl-region)
@@ -1018,6 +1020,16 @@ e.g. identifiers with template arguments such as 
\"A<X,Y>\" in C++."
              "")))
 (c-lang-defvar c-identifier-key (c-lang-const c-identifier-key))
 
+(c-lang-defconst c-module-name-re
+  "This regexp matches (a component of) a module name.
+Currently (2022-09) just C++ Mode uses this."
+  t nil
+  c++ (concat (c-lang-const c-symbol-key)
+             "\\(?:\\."
+             (c-lang-const c-symbol-key)
+             "\\)*"))
+(c-lang-defvar c-module-name-re (c-lang-const c-module-name-re))
+
 (c-lang-defconst c-identifier-last-sym-match
   ;; This was a docstring constant in 5.30 but it's no longer used.
   ;; It's only kept to avoid breaking third party code.
@@ -2624,6 +2636,7 @@ If any of these also are on `c-type-list-kwds', 
`c-ref-list-kwds',
 `c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses
 will be handled."
   t       nil
+  c++     '("export")
   objc    '("@class" "@defs" "@end" "@property" "@dynamic" "@synthesize"
            "@compatibility_alias")
   java    '("import" "package")
@@ -2937,7 +2950,8 @@ assumed to be set if this isn't nil."
 (c-lang-defconst c-<>-sexp-kwds
   ;; All keywords that can be followed by an angle bracket sexp.
   t (c--delete-duplicates (append (c-lang-const c-<>-type-kwds)
-                                 (c-lang-const c-<>-arglist-kwds))
+                                 (c-lang-const c-<>-arglist-kwds)
+                                 (c-lang-const c-import-<>-kwds))
                          :test 'string-equal))
 
 (c-lang-defconst c-opt-<>-sexp-key
@@ -3099,6 +3113,25 @@ This construct is \"<keyword> <expression> :\"."
   idl  nil
   awk  nil)
 
+(c-lang-defconst c-import-<>-kwds
+  "Keywords which can start an expression like \"import <...>\" in C++20.
+The <, and > operators are like those of #include <...>, they are
+not really template operators."
+  t nil
+  c++ '("import"))
+
+(c-lang-defconst c-module-kwds
+  "The keywords which introduce module constructs in C++20 onwards."
+  t nil
+  c++ '("module" "import" "export"))
+
+(c-lang-defconst c-module-key
+  ;; Adorned regexp matching module declaration keywords, or nil if there are
+  ;; none.
+  t (if (c-lang-const c-module-kwds)
+       (c-make-keywords-re t (c-lang-const c-module-kwds))))
+(c-lang-defvar c-module-key (c-lang-const c-module-key))
+
 (c-lang-defconst c-constant-kwds
   "Keywords for constants."
   t       nil



reply via email to

[Prev in Thread] Current Thread [Next in Thread]