[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"))
-
-
- [nongnu] elpa/macrostep a0ae61c 073/110: Properly handle forms not present in the expansion, (continued)
- [nongnu] elpa/macrostep a0ae61c 073/110: Properly handle forms not present in the expansion, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 817322b 074/110: Properly place the macrostep[-compiler]-macro-face, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep aa40d97 076/110: Test expansion within Elisp macro-defining macros, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 1edee85 080/110: Reorganise and comment, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep bbfb033 081/110: Reorganise and document generic interface, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 2bdc946 082/110: Remove dynamic binding of `macrostep-environment'., ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 31a23eb 085/110: Toggle separate-buffer expansion with prefix (#8), ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 47cbacb 087/110: Define `macrostep-propertize` before using it, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep a8e730e 089/110: Improve Makefile, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 2473a6f 094/110: Pass START and END args to sexp-at-point-function, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 03d4d7b 096/110: Add basic C macro expansion via cmacexp.el,
ELPA Syncer <=
- [nongnu] elpa/macrostep 9a6b04a 100/110: Restore Emacs 23 compatibility, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep d48e52b 101/110: Add tests for compiler-macro expansion, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep aa59895 103/110: Add .travis.yml, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 7b2c1f3 108/110: Load all autoloaded macros, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 4d75baf 003/110: Bump version number, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 8a85acc 022/110: Refactor backquote handling and text properties., ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 2d216ba 109/110: Merge pull request #19 from fice-t/autoload, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 83b2a0a 015/110: Tweak visible highlight, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 3f815fb 031/110: Test for normal defmacro expansion, ELPA Syncer, 2021/08/07
- [nongnu] elpa/macrostep 9d2c58c 040/110: Add option to expand in a separate buffer, ELPA Syncer, 2021/08/07