emacs-elpa-diffs
[Top][All Lists]
Advanced

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

[nongnu] elpa/macrostep 03d4d7b 096/110: Add basic C macro expansion via


From: ELPA Syncer
Subject: [nongnu] elpa/macrostep 03d4d7b 096/110: Add basic C macro expansion via cmacexp.el
Date: Sat, 7 Aug 2021 09:18:10 -0400 (EDT)

branch: elpa/macrostep
commit 03d4d7bb420b5694b9d0b1e5c702b3c0c6c2e734
Author: joddie <jonxfield@gmail.com>
Commit: joddie <jonxfield@gmail.com>

    Add basic C macro expansion via cmacexp.el
---
 Makefile          |  12 ++--
 macrostep-c.el    | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 macrostep-test.el |  72 ++++++++++++++++++++++-
 3 files changed, 243 insertions(+), 9 deletions(-)

diff --git a/Makefile b/Makefile
index 1af7050..0e75d41 100644
--- a/Makefile
+++ b/Makefile
@@ -1,17 +1,17 @@
 EMACS ?= emacs
 
-all: macrostep.elc
+all: macrostep.elc macrostep-c.elc
 
 clean:
-       rm -f macrostep.elc macrostep-test.elc
+       rm -f *.elc
 
-test: macrostep.elc
+test: all
        $(EMACS) --batch -L . --load macrostep-test.el
 
-sandbox: macrostep.elc
-       $(EMACS) -Q -L . --load macrostep.elc
+sandbox: all
+       $(EMACS) -Q -L . --load macrostep.elc --load macrostep-c.elc
 
 %.elc: %.el
-       $(EMACS) --batch --funcall batch-byte-compile "$<"
+       $(EMACS) --batch -L . --funcall batch-byte-compile "$<"
 
 .PHONY: test all clean
diff --git a/macrostep-c.el b/macrostep-c.el
new file mode 100644
index 0000000..3bf0a5d
--- /dev/null
+++ b/macrostep-c.el
@@ -0,0 +1,168 @@
+;;; macrostep-c.el --- macrostep interface to C preprocessor
+
+;; Copyright (C) 2015 Jon Oddie <j.j.oddie@gmail.com>
+
+;; Author:     Jon Oddie <j.j.oddie@gmail.com>
+;; Maintainer: Jon Oddie <j.j.oddie@gmail.com>
+;; Created:    27 November 2015
+;; Updated:    27 November 2015
+;; Version:    0.9
+;; Keywords:   c, languages, macro, debugging
+;; Url:        https://github.com/joddie/macrostep
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see `http://www.gnu.org/licenses/'.
+
+;;; Commentary:
+
+;; A thin wrapper around Emacs's built-in `cmacexp' library to provide
+;; basic support for expanding C macros using the `macrostep' user
+;; interface.  To use, position point on a macro use in a C buffer and
+;; type `M-x macrostep-expand'.  The variables `c-macro-preprocessor'
+;; and especially `c-macro-cppflags' may need to be set correctly for
+;; accurate expansion.
+
+;; This is fairly basic compared to the Emacs Lisp `macrostep'.  In
+;; particular, there is no step-by-step expansion, since C macros are
+;; expanded in a single "cpp" pass, and no pretty-printing.
+
+;; To hide the buffer containing "cpp" warnings (not recommended), you
+;; could do something like:
+;;
+;; (push `(,(regexp-quote macrostep-c-warning-buffer)
+;;          (display-buffer-no-window))
+;;       display-buffer-alist)
+
+;;; Code:
+
+(require 'macrostep)
+(require 'cmacexp)
+(require 'subr-x)                       ; string-trim
+(require 'cl-lib)
+
+(define-error 'macrostep-c-non-macro
+    "Text around point is not a macro call.")
+
+(define-error 'macrostep-c-expansion-failed
+    "Macro-expansion failed.")
+
+(defvar macrostep-c-warning-buffer "*Macroexpansion Warnings*")
+
+;;;###autoload
+(defun macrostep-c-mode-hook ()
+  (setq macrostep-sexp-bounds-function
+        #'macrostep-c-sexp-bounds)
+  (setq macrostep-sexp-at-point-function
+        #'macrostep-c-sexp-at-point)
+  (setq macrostep-environment-at-point-function
+        #'ignore)
+  (setq macrostep-expand-1-function
+        #'macrostep-c-expand-1)
+  (setq macrostep-print-function
+        #'macrostep-c-print-function)
+  (add-hook 'macrostep-mode-off-hook
+            #'macrostep-c-mode-off nil t))
+
+(defun macrostep-c-mode-off (&rest ignore)
+  (when (derived-mode-p 'c-mode)
+    (let ((warning-window
+           (get-buffer-window macrostep-c-warning-buffer)))
+      (when warning-window
+        (quit-window nil warning-window)))))
+
+;;;###autoload
+(add-hook 'c-mode-hook #'macrostep-c-mode-hook)
+
+(defun macrostep-c-sexp-bounds ()
+  (save-excursion
+    (cl-loop
+     (let ((region (macrostep-c-sexp-bounds-1)))
+       (cond
+         ((null region)
+          (signal 'macrostep-c-non-macro nil))
+         ((macrostep-c-expandable-p region)
+          (cl-return region))
+         (t
+          (condition-case nil
+              (progn
+                (backward-up-list)
+                (skip-syntax-backward "-"))
+            (scan-error
+             (signal 'macrostep-c-non-macro nil)))))))))
+
+(defun macrostep-c-sexp-bounds-1 ()
+  (let ((region (bounds-of-thing-at-point 'symbol)))
+    (when region
+      (cl-destructuring-bind (symbol-start . symbol-end) region
+        (save-excursion
+          (goto-char symbol-end)
+          (if (looking-at "[[:space:]]*(")
+              (cons symbol-start (scan-sexps symbol-end 1))
+              region))))))
+
+(defun macrostep-c-expandable-p (region)
+  (cl-destructuring-bind (start . end) region
+    (condition-case nil
+        (cl-destructuring-bind (expansion warnings)
+            (macrostep-c-expand-region start end)
+          (declare (ignore warnings))
+          (and (cl-plusp (length expansion))
+               (not (string= expansion (buffer-substring start end)))))
+      (macrostep-c-expansion-failed nil))))
+
+(defun macrostep-c-sexp-at-point (start end)
+  (cons start end))
+
+(defun macrostep-c-expand-1 (region _ignore)
+  (cl-destructuring-bind (start . end) region
+    (cl-destructuring-bind (expansion warnings)
+        (macrostep-c-expand-region start end)
+      (when (cl-plusp (length warnings))
+        (with-current-buffer
+            (get-buffer-create macrostep-c-warning-buffer)
+          (let ((inhibit-read-only t))
+            (erase-buffer)
+            (insert warnings)
+            (goto-char (point-min)))
+          (special-mode)
+          (display-buffer (current-buffer)
+                          '(display-buffer-pop-up-window
+                            (inhibit-same-window . t)
+                            (allow-no-window . t)))))
+      expansion)))
+
+(defun macrostep-c-expand-region (start end)
+  (let ((expansion
+         (condition-case nil
+             (c-macro-expansion start end
+                                (concat c-macro-preprocessor " "
+                                        c-macro-cppflags))
+           (search-failed
+            (signal 'macrostep-c-expansion-failed nil)))))
+    (with-temp-buffer
+      (save-excursion
+        (insert expansion))
+      (when (looking-at (regexp-quote "/*"))
+        (search-forward "*/"))
+      (let ((warnings (buffer-substring (point-min) (point)))
+            (expansion (buffer-substring (point) (point-max))))
+        (mapcar #'string-trim (list expansion warnings))))))
+
+(defun macrostep-c-print-function (expansion &rest _ignore)
+  (insert expansion))
+
+(provide 'macrostep-c)
+
+;;; macrostep-c.el ends here
diff --git a/macrostep-test.el b/macrostep-test.el
index 1af2836..6ca3a60 100644
--- a/macrostep-test.el
+++ b/macrostep-test.el
@@ -1,6 +1,6 @@
 ;;; macrostep-test.el --- tests for macrostep.el
 
-;; Copyright (C) 2014 Jon Oddie <j.j.oddie@gmail.com>
+;; Copyright (C) 2014-2015 Jon Oddie <j.j.oddie@gmail.com>
 
 ;; This file is NOT part of GNU Emacs.
 
@@ -17,6 +17,11 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with this program.  If not, see `http://www.gnu.org/licenses/'.
 
+(require 'ert)
+(require 'macrostep)
+(require 'macrostep-c)
+(require 'cl-lib)
+
 
 ;;;; Conveniences for defining tests
 
@@ -336,9 +341,70 @@
         (should (equal (read (copy-marker (point)))
                        '(dummy-macro-2 (some (arguments)))))))))
 
+
+;;;; Tests for C macro expansion
+
+(defun macrostep-lax-looking-at (string)
+  (let* ((string-sans-whitespace
+          (replace-regexp-in-string (rx (one-or-more whitespace)) "" string))
+         (regexp
+          (cl-loop
+           for char across string-sans-whitespace
+           concat (rx-to-string char t)
+           concat "[[:space:]]*")))
+    (looking-at regexp)))
+
+(defmacro macrostep-lax-should-expand (string)
+  `(progn
+     (macrostep-expand)
+     (should (macrostep-lax-looking-at ,string))
+     (macrostep-collapse)))
+
+(ert-deftest macrostep-expand-c-macros ()
+  (with-temp-buffer
+    (insert
+     ;; A random example adapted from Emacs's src/lisp.h.
+     "
+#define eassert(cond) ((void) (false && (cond))) /* Check COND compiles.  */
+#define lisp_h_XLI(o) (o)
+#define lisp_h_XUNTAG(a, type) ((void *) (intptr_t) (XLI (a) - (type)))
+#define XLI(o) lisp_h_XLI (o)
+#define XUNTAG(a, type) lisp_h_XUNTAG (a, type)
+
+INLINE struct Lisp_String *
+XSTRING (Lisp_Object a)
+{
+  eassert (STRINGP (a));
+  return XUNTAG (a, Lisp_String);
+}")
+    (c-mode)
+
+     ;; Test macro-expansion with point at the beginning of the macro
+    (macrostep-goto "eassert (STRINGP (a))" t)
+    (macrostep-lax-should-expand
+     "((void) (false && (STRINGP (a))))")
+
+    ;; Test with point inside a nested macro call: result should be
+    ;; the same, since point will move up before the outermost macro
+    (macrostep-goto "STRINGP")
+    (macrostep-lax-should-expand
+     "((void) (false && (STRINGP (a))))")
+
+    ;; Test with point in the middle of a symbol
+    (macrostep-goto "XUNTAG (a, Lisp_String)" t)
+    (forward-char 3)
+    (macrostep-lax-should-expand
+     "((void *) (intptr_t) ((a) - (  Lisp_String)))")
+
+    ;; Test with point at symbol-end
+    (macrostep-goto "XUNTAG (a, Lisp_String)" t)
+    (forward-sexp)
+    (macrostep-lax-should-expand
+     "((void *) (intptr_t) ((a) - (  Lisp_String)))")))
+
+
+
 (when noninteractive
   (load-file (expand-file-name "macrostep.el"
                                (file-name-directory load-file-name)))
   (ert-run-tests-batch "^macrostep"))
-
-



reply via email to

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