mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-16 17:24:23 +00:00
hideif.el: Support C99 and GNU style variadic macros
* lisp/progmodes/hideif.el (hif-end-of-line, hif-cpp-prefix) (hif-ifx-regexp, hif-macro-expr-prefix-regexp, hif-white-regexp) (hif-macroref-regexp, hif-tokenize, hif-find-any-ifX) (hif-find-next-relevant, hif-find-previous-relevant, hif-find-range) (hif-parse-macro-arglist, hif-add-new-defines, hide-ifdef-guts): Variadic macro parsing, comments and multi-line parsing. (hif-line-concat, hif-etc-regexp): New regexp for better macro scans. (hif-expand-token-list, hif-get-argument-list, hif-delimit) (hif-macro-supply-arguments, hif-canonicalize, hif-find-define): Variadic macro argument replacement and expansion. (hif-display-macro): Display variadic macros. (hif-is-in-comment, hif-search-ifX-regexp): New functions to better handle macros in comments and comments in macros.
This commit is contained in:
parent
db836637b0
commit
77ca6aa56e
1 changed files with 280 additions and 90 deletions
|
|
@ -113,6 +113,7 @@
|
|||
;; Various floating point types and operations are also supported but the
|
||||
;; actual precision is limited by the Emacs internal floating representation,
|
||||
;; which is the C data type "double" or IEEE binary64 format.
|
||||
;; C99 and GNU style variadic arguments support is completed in 2022/E.
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
|
@ -392,8 +393,10 @@ If there is a marked region from START to END it only shows the symbols within."
|
|||
(add-hook 'after-revert-hook 'hif-after-revert-function)
|
||||
|
||||
(defun hif-end-of-line ()
|
||||
"Find the end-point of line concatenation."
|
||||
(end-of-line)
|
||||
(while (= (logand 1 (skip-chars-backward "\\\\")) 1)
|
||||
(while (progn (skip-chars-backward " \t" (line-beginning-position))
|
||||
(= ?\\ (char-before)))
|
||||
(end-of-line 2)))
|
||||
|
||||
(defun hif-merge-ifdef-region (start end)
|
||||
|
|
@ -536,10 +539,10 @@ that form should be displayed.")
|
|||
;;===%%SF%% parsing (Start) ===
|
||||
;;; The code that understands what ifs and ifdef in files look like.
|
||||
|
||||
(defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*")
|
||||
(defconst hif-cpp-prefix "\\(^\\|\r\\)?[ \t]*#[ \t]*")
|
||||
(defconst hif-ifxdef-regexp (concat hif-cpp-prefix "if\\(n\\)?def"))
|
||||
(defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef"))
|
||||
(defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+"))
|
||||
(defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\((\\|\\(n?def\\)?[ \t]+\\)"))
|
||||
(defconst hif-elif-regexp (concat hif-cpp-prefix "elif"))
|
||||
(defconst hif-else-regexp (concat hif-cpp-prefix "else"))
|
||||
(defconst hif-endif-regexp (concat hif-cpp-prefix "endif"))
|
||||
|
|
@ -547,18 +550,23 @@ that form should be displayed.")
|
|||
(concat hif-ifx-regexp "\\|" hif-elif-regexp "\\|" hif-else-regexp "\\|"
|
||||
hif-endif-regexp))
|
||||
(defconst hif-macro-expr-prefix-regexp
|
||||
(concat hif-cpp-prefix "\\(if\\(n?def\\)?\\|elif\\|define\\)[ \t]+"))
|
||||
(concat hif-cpp-prefix "\\(if(\\|if\\(n?def\\)?[ \t]+\\|elif\\|define[ \t]+\\)"))
|
||||
|
||||
(defconst hif-white-regexp "[ \t]*")
|
||||
(defconst hif-line-concat "\\\\[ \t]*[\n\r]")
|
||||
;; If `hif-white-regexp' is modified, `hif-tokenize' might need to be modified
|
||||
;; accordingly.
|
||||
(defconst hif-white-regexp (concat "\\(?:\\(?:[ \t]\\|/\\*.*\\*/\\)*"
|
||||
"\\(?:" hif-line-concat "\\)?\\)*"))
|
||||
(defconst hif-define-regexp (concat hif-cpp-prefix "\\(define\\|undef\\)"))
|
||||
(defconst hif-id-regexp (concat "[[:alpha:]_][[:alnum:]_]*"))
|
||||
(defconst hif-etc-regexp "\\.\\.\\.")
|
||||
(defconst hif-macroref-regexp
|
||||
(concat hif-white-regexp "\\(" hif-id-regexp "\\)"
|
||||
"\\("
|
||||
"(" hif-white-regexp
|
||||
"\\(" hif-id-regexp "\\)?" hif-white-regexp
|
||||
"\\(" "," hif-white-regexp hif-id-regexp hif-white-regexp "\\)*"
|
||||
"\\(\\.\\.\\.\\)?" hif-white-regexp
|
||||
"\\(" "," hif-white-regexp "\\)?" "\\(" hif-etc-regexp "\\)?" hif-white-regexp
|
||||
")"
|
||||
"\\)?" ))
|
||||
|
||||
|
|
@ -936,7 +944,11 @@ Assuming we've just performed a `hif-token-regexp' lookup."
|
|||
(defun hif-tokenize (start end)
|
||||
"Separate string between START and END into a list of tokens."
|
||||
(let ((token-list nil)
|
||||
(white-regexp "[ \t]+")
|
||||
;; Similar to `hif-white-regexp' but keep the spaces if there are
|
||||
(white-regexp (concat "\\(?:"
|
||||
"\\(?:\\([ \t]+\\)\\|\\(?:/\\*.*\\*/\\)?\\)*"
|
||||
"\\(?:" hif-line-concat "\\)?"
|
||||
"\\)*"))
|
||||
token)
|
||||
(setq hif-simple-token-only t)
|
||||
(with-syntax-table hide-ifdef-syntax-table
|
||||
|
|
@ -956,29 +968,31 @@ Assuming we've just performed a `hif-token-regexp' lookup."
|
|||
(forward-char 2))
|
||||
|
||||
((looking-at hif-string-literal-regexp)
|
||||
(setq token (substring-no-properties (match-string 1)))
|
||||
(setq token (match-string-no-properties 1))
|
||||
(goto-char (match-end 0))
|
||||
(when (looking-at white-regexp)
|
||||
(add-text-properties 0 1 '(hif-space t) token)
|
||||
(if (not (zerop (length (match-string-no-properties 1))))
|
||||
(add-text-properties 0 1 '(hif-space t) token))
|
||||
(goto-char (match-end 0)))
|
||||
(push token token-list))
|
||||
|
||||
((looking-at hif-token-regexp)
|
||||
(goto-char (match-end 0))
|
||||
(setq token (hif-strtok
|
||||
(substring-no-properties (match-string 0))))
|
||||
(setq token (hif-strtok (match-string-no-properties 0)))
|
||||
(push token token-list)
|
||||
(when (looking-at white-regexp)
|
||||
;; We can't just append a space to the token string, otherwise
|
||||
;; `0xf0 ' ## `01' will become `0xf0 01' instead of the expected
|
||||
;; `0xf001', hence a standalone `hif-space' is placed instead.
|
||||
(push 'hif-space token-list)
|
||||
(if (not (zerop (length (match-string-no-properties 1))))
|
||||
;; We can't just append a space to the token string,
|
||||
;; otherwise `0xf0 ' ## `01' will become `0xf0 01' instead
|
||||
;; of the expected `0xf001', hence a standalone `hif-space'
|
||||
;; is placed instead.
|
||||
(push 'hif-space token-list))
|
||||
(goto-char (match-end 0))))
|
||||
|
||||
((looking-at "\r") ; Sometimes MS-Windows user will leave CR in
|
||||
(forward-char 1)) ; the source code. Let's not get stuck here.
|
||||
|
||||
(t (error "Bad #if expression: %s" (buffer-string)))))))
|
||||
(t (error "Bad preprocessor expression: %s" (buffer-string)))))))
|
||||
(if (eq 'hif-space (car token-list))
|
||||
(setq token-list (cdr token-list))) ;; remove trailing white space
|
||||
(nreverse token-list))))
|
||||
|
|
@ -1126,7 +1140,7 @@ this is to emulate the stringification behavior of C++ preprocessor."
|
|||
(and (eq (car remains) 'hif-space)
|
||||
(eq (cadr remains) 'hif-lparen)
|
||||
(setq remains (cdr remains)))))
|
||||
;; No argument, no invocation
|
||||
;; No argument list, no invocation
|
||||
tok
|
||||
;; Argumented macro, get arguments and invoke it.
|
||||
;; Dynamically bind `hif-token-list' and `hif-token'
|
||||
|
|
@ -1369,8 +1383,9 @@ factor : `!' factor | `~' factor | `(' exprlist `)' | `defined(' id `)' |
|
|||
(parmlist nil) ; A "token" list of parameters, will later be parsed
|
||||
(parm nil))
|
||||
|
||||
(while (or (not (eq (hif-nexttoken keep-space) 'hif-rparen))
|
||||
(/= nest 0))
|
||||
(while (and (or (not (eq (hif-nexttoken keep-space) 'hif-rparen))
|
||||
(/= nest 0))
|
||||
hif-token)
|
||||
(if (eq (car (last parm)) 'hif-comma)
|
||||
(setq parm nil))
|
||||
(cond
|
||||
|
|
@ -1384,6 +1399,8 @@ factor : `!' factor | `~' factor | `(' exprlist `)' | `defined(' id `)' |
|
|||
(setq parm nil)))
|
||||
(push hif-token parm))
|
||||
|
||||
(if (equal parm '(hif-comma)) ;; missing the last argument
|
||||
(setq parm '(nil)))
|
||||
(push (nreverse parm) parmlist) ; Okay even if PARM is nil
|
||||
(hif-nexttoken keep-space) ; Drop the `hif-rparen', get next token
|
||||
(nreverse parmlist)))
|
||||
|
|
@ -1609,11 +1626,21 @@ and `+='...)."
|
|||
;; no need to reassemble the list if no `##' presents
|
||||
l))
|
||||
|
||||
(defun hif-delimit (lis atom)
|
||||
(nconc (mapcan (lambda (l) (list l atom))
|
||||
(defun hif-delimit (lis elem)
|
||||
(nconc (mapcan (lambda (l) (list l elem))
|
||||
(butlast lis))
|
||||
(last lis)))
|
||||
|
||||
(defun hif-delete-nth (n lst)
|
||||
"Non-destructively delete the nth item from a list."
|
||||
(if (zerop n)
|
||||
(cdr lst)
|
||||
;; non-destructive
|
||||
(let* ((duplst (copy-sequence lst))
|
||||
(node (nthcdr (1- n) duplst)))
|
||||
(setcdr node (cddr node))
|
||||
duplst)))
|
||||
|
||||
;; Perform token replacement:
|
||||
(defun hif-macro-supply-arguments (macro-name actual-parms)
|
||||
"Expand a macro call, replace ACTUAL-PARMS in the macro body."
|
||||
|
|
@ -1633,49 +1660,160 @@ and `+='...)."
|
|||
;; For each actual parameter, evaluate each one and associate it
|
||||
;; with an actual parameter, put it into local table and finally
|
||||
;; evaluate the macro body.
|
||||
(if (setq etc (eq (car formal-parms) 'hif-etc))
|
||||
(if (setq etc (or (eq (car formal-parms) 'hif-etc)
|
||||
(and (eq (car formal-parms) 'hif-etc-c99) 'c99)))
|
||||
;; Take care of `hif-etc' first. Prefix `hif-comma' back if needed.
|
||||
(setq formal-parms (cdr formal-parms)))
|
||||
(setq formal-count (length formal-parms)
|
||||
actual-count (length actual-parms))
|
||||
|
||||
(if (> formal-count actual-count)
|
||||
(error "Too few parameters for macro %S" macro-name)
|
||||
(if (< formal-count actual-count)
|
||||
(or etc
|
||||
(error "Too many parameters for macro %S" macro-name))))
|
||||
;; Fix empty arguments applied
|
||||
(if (and (= formal-count 1)
|
||||
(null (car formal-parms)))
|
||||
(setq formal-parms nil
|
||||
formal-count (1- formal-count)))
|
||||
(if (and (= actual-count 1)
|
||||
(or (null (car actual-parms))
|
||||
;; white space as the only argument
|
||||
(equal '(hif-space) (car actual-parms))))
|
||||
(setq actual-parms nil
|
||||
actual-count (1- actual-count)))
|
||||
|
||||
;; Basic error checking
|
||||
(if etc
|
||||
(if (eq etc 'c99)
|
||||
(if (and (> formal-count 1) ; f(a,b,...)
|
||||
(< actual-count formal-count))
|
||||
(error "C99 variadic argument macro %S need at least %d arguments"
|
||||
macro-name formal-count))
|
||||
;; GNU style variadic argument
|
||||
(if (and (> formal-count 1)
|
||||
(< actual-count (1- formal-count)))
|
||||
(error "GNU variadic argument macro %S need at least %d arguments"
|
||||
macro-name (1- formal-count))))
|
||||
(if (> formal-count actual-count)
|
||||
(error "Too few parameters for macro %S; %d instead of %d"
|
||||
macro-name actual-count formal-count)
|
||||
(if (< formal-count actual-count)
|
||||
(error "Too many parameters for macro %S; %d instead of %d"
|
||||
macro-name actual-count formal-count))))
|
||||
|
||||
;; Perform token replacement on the MACRO-BODY with the parameters
|
||||
(while (setq formal (pop formal-parms))
|
||||
;; Prevent repetitive substitution, thus cannot use `subst'
|
||||
;; for example:
|
||||
;; #define mac(a,b) (a+b)
|
||||
;; #define testmac mac(b,y)
|
||||
;; testmac should expand to (b+y): replace of argument a and b
|
||||
;; occurs simultaneously, not sequentially. If sequentially,
|
||||
;; according to the argument order, it will become:
|
||||
;; 1. formal parm #1 'a' replaced by actual parm 'b', thus (a+b)
|
||||
;; becomes (b+b)
|
||||
;; 2. formal parm #2 'b' replaced by actual parm 'y', thus (b+b)
|
||||
;; becomes (y+y).
|
||||
(setq macro-body
|
||||
;; Unlike `subst', `substitute' replace only the top level
|
||||
;; instead of the whole tree; more importantly, it's not
|
||||
;; destructive.
|
||||
(cl-substitute (if (and etc (null formal-parms))
|
||||
(hif-delimit actual-parms 'hif-comma)
|
||||
(car actual-parms))
|
||||
formal macro-body))
|
||||
(setq actual-parms (cdr actual-parms)))
|
||||
|
||||
;; Replacement completed, stringifiy and concatenate the token list.
|
||||
;; Stringification happens must take place before flattening, otherwise
|
||||
;; only the first token will be stringified.
|
||||
(setq macro-body
|
||||
(flatten-tree (hif-token-stringification macro-body)))
|
||||
;; Every substituted argument in the macro-body must be in list form so
|
||||
;; that it won't again be substituted incorrectly in later iterations.
|
||||
;; Finally we will flatten the list to fix that.
|
||||
(cl-loop
|
||||
do
|
||||
;; Note that C99 '...' and GNU 'x...' allow empty match
|
||||
(setq formal (pop formal-parms))
|
||||
;;
|
||||
;; Prevent repetitive substitution, thus cannot use `subst'
|
||||
;; for example:
|
||||
;; #define mac(a,b) (a+b)
|
||||
;; #define testmac mac(b,y)
|
||||
;; testmac should expand to (b+y): replace of argument a and b
|
||||
;; occurs simultaneously, not sequentially. If sequentially,
|
||||
;; according to the argument order, it will become:
|
||||
;; 1. formal parm #1 'a' replaced by actual parm 'b', thus (a+b)
|
||||
;; becomes (b+b)
|
||||
;; 2. formal parm #2 'b' replaced by actual parm 'y', thus (b+b)
|
||||
;; becomes (y+y).
|
||||
;; Unlike `subst', `cl-substitute' replace only the top level
|
||||
;; instead of the whole tree; more importantly, it's not
|
||||
;; destructive.
|
||||
;;
|
||||
(if (not (and (null formal-parms) etc))
|
||||
;; One formal with one actual
|
||||
(setq macro-body
|
||||
(cl-substitute (car actual-parms) formal macro-body))
|
||||
;; `formal-parms' used up, now take care of '...'
|
||||
(cond
|
||||
|
||||
;; Token concatenation happens here, keep single 'hif-space
|
||||
(hif-keep-single (hif-token-concatenation macro-body) 'hif-space))))
|
||||
((eq etc 'c99) ; C99 __VA_ARGS__ style '...'
|
||||
(when formal
|
||||
(setq macro-body
|
||||
(cl-substitute (car actual-parms) formal macro-body))
|
||||
;; Now the whole __VA_ARGS__ represents the whole
|
||||
;; remaining actual params
|
||||
(pop actual-parms))
|
||||
;; Replace if __VA_ARGS__ presents:
|
||||
;; if yes, see if it's prefixed with ", ##" or not,
|
||||
;; if yes, remove the "##", then if actual-params is
|
||||
;; exhausted, remove the prefixed ',' as well.
|
||||
;; Prepare for destructive operation
|
||||
(let ((rem-body (copy-sequence macro-body))
|
||||
new-body va left part)
|
||||
;; Find each __VA_ARGS__ and remove its immediate prefixed '##'
|
||||
;; and comma if presents and if `formal_param' is exhausted
|
||||
(while (setq va (cl-position '__VA_ARGS__ rem-body))
|
||||
;; Split REM-BODY @ __VA_ARGS__ into LEFT and right
|
||||
(setq part nil)
|
||||
(if (zerop va)
|
||||
(setq left nil ; __VA_ARGS__ trimed
|
||||
rem-body (cdr rem-body))
|
||||
(setq left rem-body
|
||||
rem-body (cdr (nthcdr va rem-body))) ; _V_ removed
|
||||
(setcdr (nthcdr va left) nil) ; now _V_ be the last in LEFT
|
||||
;; now LEFT=(, w? ## w? _V_) rem=(W X Y) where w = white space
|
||||
(setq left (cdr (nreverse left)))) ; left=(w? ## w? ,)
|
||||
|
||||
;; Try to recognize w?##w? and remove ", ##" if found
|
||||
;; (remember head = __VA_ARGS__ is temporarily removed)
|
||||
(while (and left (eq 'hif-space (car left))) ; skip whites
|
||||
(setq part (cons 'hif-space part)
|
||||
left (cdr left)))
|
||||
|
||||
(if (eq (car left) 'hif-token-concat) ; match '##'
|
||||
(if actual-parms
|
||||
;; Keep everything
|
||||
(setq part (append part (cdr left)))
|
||||
;; `actual-params' exhausted, delete ',' if presents
|
||||
(while (and left (eq 'hif-space (car left))) ; skip whites
|
||||
(setq part (cons 'hif-space part)
|
||||
left (cdr left)))
|
||||
(setq part
|
||||
(append part
|
||||
(if (eq (car left) 'hif-comma) ; match ','
|
||||
(cdr left)
|
||||
left))))
|
||||
;; No immediate '##' found
|
||||
(setq part (append part left)))
|
||||
|
||||
;; Insert __VA_ARGS__ as a list
|
||||
(push (hif-delimit actual-parms 'hif-comma) part)
|
||||
;; Reverse `left' back
|
||||
(setq left (nreverse part)
|
||||
new-body (append new-body left)))
|
||||
|
||||
;; Replacement of __VA_ARGS__ done here, add rem-body back
|
||||
(setq macro-body (append new-body rem-body)
|
||||
actual-parms nil)))
|
||||
|
||||
(etc ; GNU style '...', substitute last argument
|
||||
(if (null actual-parms)
|
||||
;; Must be non-destructive otherwise the original function
|
||||
;; definition defined in `hide-ifdef-env' will be destroyed.
|
||||
(setq macro-body (remove formal macro-body))
|
||||
(setq macro-body
|
||||
(cl-substitute (hif-delimit actual-parms 'hif-comma)
|
||||
formal macro-body)
|
||||
actual-parms nil)))
|
||||
|
||||
(t
|
||||
(error "Interal error: impossible case."))))
|
||||
|
||||
(pop actual-parms)
|
||||
while actual-parms) ; end cl-loop
|
||||
|
||||
;; Replacement completed, stringifiy and concatenate the token list.
|
||||
;; Stringification happens must take place before flattening, otherwise
|
||||
;; only the first token will be stringified.
|
||||
(setq macro-body
|
||||
(flatten-tree (hif-token-stringification macro-body))))
|
||||
|
||||
;; Token concatenation happens here, keep single 'hif-space
|
||||
(hif-keep-single (hif-token-concatenation macro-body) 'hif-space)))
|
||||
|
||||
(defun hif-invoke (macro-name actual-parms)
|
||||
"Invoke a macro by expanding it, reparse macro-body and finally invoke it."
|
||||
|
|
@ -1710,7 +1848,9 @@ and `+='...)."
|
|||
Do this when cursor is at the beginning of `regexp' (i.e. #ifX)."
|
||||
(let ((case-fold-search nil))
|
||||
(save-excursion
|
||||
(re-search-forward regexp)
|
||||
(if (re-search-forward regexp)
|
||||
(if (= ?\( (char-before)) ;; "#if(" found
|
||||
(goto-char (1- (point)))))
|
||||
(let* ((curr-regexp (match-string 0))
|
||||
(defined (string-match hif-ifxdef-regexp curr-regexp))
|
||||
(negate (and defined
|
||||
|
|
@ -1724,29 +1864,48 @@ Do this when cursor is at the beginning of `regexp' (i.e. #ifX)."
|
|||
(setq tokens (list 'hif-not tokens)))
|
||||
(hif-parse-exp tokens)))))
|
||||
|
||||
(defun hif-is-in-comment ()
|
||||
"Check if we're currently within a C(++) comment."
|
||||
(or (nth 4 (syntax-ppss))
|
||||
(looking-at "/[/*]")))
|
||||
|
||||
(defun hif-search-ifX-regexp (hif-regexp &optional backward)
|
||||
"Search for a valid ifX regexp defined in hideif."
|
||||
(let ((start (point))
|
||||
(re-search-func (if backward
|
||||
#'re-search-backward
|
||||
#'re-search-forward))
|
||||
(limit (if backward (point-min) (point-max)))
|
||||
found)
|
||||
(while (and (setq found
|
||||
(funcall re-search-func hif-regexp limit t))
|
||||
(hif-is-in-comment)))
|
||||
;; Jump to the pattern if found
|
||||
(if found
|
||||
(unless backward
|
||||
(setq found
|
||||
(goto-char (- (point) (length (match-string 0))))))
|
||||
(goto-char start))
|
||||
found))
|
||||
|
||||
(defun hif-find-any-ifX ()
|
||||
"Move to next #if..., or #ifndef, at point or after."
|
||||
;; (message "find ifX at %d" (point))
|
||||
(prog1
|
||||
(re-search-forward hif-ifx-regexp (point-max) t)
|
||||
(beginning-of-line)))
|
||||
|
||||
(hif-search-ifX-regexp hif-ifx-regexp))
|
||||
|
||||
(defun hif-find-next-relevant ()
|
||||
"Move to next #if..., #elif..., #else, or #endif, after the current line."
|
||||
;; (message "hif-find-next-relevant at %d" (point))
|
||||
(end-of-line)
|
||||
;; Avoid infinite recursion by only going to line-beginning if match found
|
||||
(if (re-search-forward hif-ifx-else-endif-regexp (point-max) t)
|
||||
(beginning-of-line)))
|
||||
;; Avoid infinite recursion by going to the pattern only if a match is found
|
||||
(hif-search-ifX-regexp hif-ifx-else-endif-regexp))
|
||||
|
||||
(defun hif-find-previous-relevant ()
|
||||
"Move to previous #if..., #else, or #endif, before the current line."
|
||||
;; (message "hif-find-previous-relevant at %d" (point))
|
||||
(beginning-of-line)
|
||||
;; Avoid infinite recursion by only going to line-beginning if match found
|
||||
(if (re-search-backward hif-ifx-else-endif-regexp (point-min) t)
|
||||
(beginning-of-line)))
|
||||
;; Avoid infinite recursion by going to the pattern only if a match is found
|
||||
(hif-search-ifX-regexp hif-ifx-else-endif-regexp 't))
|
||||
|
||||
|
||||
(defun hif-looking-at-ifX ()
|
||||
|
|
@ -1931,6 +2090,7 @@ Point is left unchanged."
|
|||
((hif-looking-at-else)
|
||||
(setq else (point)))
|
||||
(t
|
||||
(beginning-of-line) ; otherwise #endif line will be hidden
|
||||
(setq end (point)))))
|
||||
;; If found #else, look for #endif.
|
||||
(when else
|
||||
|
|
@ -1940,6 +2100,7 @@ Point is left unchanged."
|
|||
(hif-ifdef-to-endif))
|
||||
(if (hif-looking-at-else)
|
||||
(error "Found two elses in a row? Broken!"))
|
||||
(beginning-of-line) ; otherwise #endif line will be hidden
|
||||
(setq end (point))) ; (line-end-position)
|
||||
(hif-make-range start end else elif))))
|
||||
|
||||
|
|
@ -2085,16 +2246,20 @@ Refer to `hide-ifdef-expand-reinclusion-guard' for more details."
|
|||
(eq (car def) 'hif-define-macro))
|
||||
(let ((cdef (concat "#define " name))
|
||||
(parmlist (cadr def))
|
||||
s)
|
||||
p s etc)
|
||||
(setq def (caddr def))
|
||||
;; parmlist
|
||||
(when parmlist
|
||||
(setq cdef (concat cdef "("))
|
||||
(while (car parmlist)
|
||||
(setq cdef (concat cdef (symbol-name (car parmlist))
|
||||
(if (cdr parmlist) ","))
|
||||
(if (setq etc (or (eq (setq p (car parmlist)) 'hif-etc)
|
||||
(and (eq p 'hif-etc-c99) 'c99)))
|
||||
(pop parmlist))
|
||||
(while (setq p (car parmlist))
|
||||
(setq cdef (concat cdef (symbol-name p) (if (cdr parmlist) ","))
|
||||
parmlist (cdr parmlist)))
|
||||
(setq cdef (concat cdef ")")))
|
||||
(setq cdef (concat cdef
|
||||
(if etc (concat (if (eq etc 'c99) ",") "..."))
|
||||
")")))
|
||||
(setq cdef (concat cdef " "))
|
||||
;; body
|
||||
(while def
|
||||
|
|
@ -2221,25 +2386,38 @@ however, when this command is prefixed, it will display the error instead."
|
|||
result))))
|
||||
|
||||
(defun hif-parse-macro-arglist (str)
|
||||
"Parse argument list formatted as `( arg1 [ , argn] [...] )'.
|
||||
"Parse argument list formatted as `( arg1 [ , argn] [,] [...] )'.
|
||||
The `...' is also included. Return a list of the arguments, if `...' exists the
|
||||
first arg will be `hif-etc'."
|
||||
(let* ((hif-simple-token-only nil) ; Dynamic binding var for `hif-tokenize'
|
||||
(tokenlist
|
||||
(cdr (hif-tokenize
|
||||
(- (point) (length str)) (point)))) ; Remove `hif-lparen'
|
||||
etc result token)
|
||||
(while (not (eq (setq token (pop tokenlist)) 'hif-rparen))
|
||||
etc result token prevtok prev2tok)
|
||||
(while (not (eq (setq prev2tok prevtok
|
||||
prevtok token
|
||||
token (pop tokenlist)) 'hif-rparen))
|
||||
(cond
|
||||
((eq token 'hif-etc)
|
||||
(setq etc t))
|
||||
;; GNU type "..." or C99 type
|
||||
(setq etc (if (or (null prevtok)
|
||||
(eq prevtok 'hif-comma)
|
||||
(and (eq prevtok 'hif-space)
|
||||
(eq prev2tok 'hif-comma)))
|
||||
'c99 t)))
|
||||
((eq token 'hif-comma)
|
||||
t)
|
||||
(if etc
|
||||
(error "Syntax error: no comma allowed after `...'.")))
|
||||
(t
|
||||
(push token result))))
|
||||
(if etc
|
||||
(cons 'hif-etc (nreverse result))
|
||||
(nreverse result))))
|
||||
(setq result (nreverse result))
|
||||
(cond
|
||||
((eq etc 'c99)
|
||||
(cons 'hif-etc-c99 result))
|
||||
((eq etc t)
|
||||
(cons 'hif-etc result))
|
||||
(t
|
||||
result))))
|
||||
|
||||
;; The original version of hideif evaluates the macro early and store the
|
||||
;; final values for the defined macro into the symbol database (aka
|
||||
|
|
@ -2280,9 +2458,11 @@ first arg will be `hif-etc'."
|
|||
(let* ((defining (string= "define" (match-string 2)))
|
||||
(name (and (re-search-forward hif-macroref-regexp max t)
|
||||
(match-string 1)))
|
||||
(parmlist (or (and (match-string 3) ; First arg id found
|
||||
(parmlist (or (and (or (match-string 3) ; First arg id found
|
||||
(match-string 6)) ; '...' found
|
||||
(delq 'hif-space
|
||||
(hif-parse-macro-arglist (match-string 2))))
|
||||
(hif-parse-macro-arglist
|
||||
(match-string 2))))
|
||||
(and (match-string 2) ; empty arglist
|
||||
(list nil)))))
|
||||
(if defining
|
||||
|
|
@ -2325,7 +2505,8 @@ first arg will be `hif-etc'."
|
|||
(expr (and tokens
|
||||
;; `hif-simple-token-only' is checked only
|
||||
;; here.
|
||||
(or (and hif-simple-token-only
|
||||
(or (and (null parmlist)
|
||||
hif-simple-token-only
|
||||
(listp tokens)
|
||||
(= (length tokens) 1)
|
||||
(hif-parse-exp tokens))
|
||||
|
|
@ -2354,13 +2535,22 @@ first arg will be `hif-etc'."
|
|||
(save-excursion
|
||||
(save-restriction
|
||||
;; (mark-region min max) ;; for debugging
|
||||
(and min (goto-char min))
|
||||
(setq hif-verbose-define-count 0)
|
||||
(forward-comment (point-max))
|
||||
(while (hif-find-define min max)
|
||||
(forward-comment (point-max))
|
||||
(setf min (point)))
|
||||
(setq min (point))
|
||||
(let ((breakloop nil))
|
||||
(while (and (not breakloop)
|
||||
(hif-find-define min max))
|
||||
(forward-comment (point-max))
|
||||
(if (and max
|
||||
(> (point) max))
|
||||
(setq max (point)
|
||||
breakloop t))
|
||||
(setq min (point))))
|
||||
(if max (goto-char max)
|
||||
(goto-char (point-max))))))
|
||||
(goto-char (point-max))
|
||||
nil))))
|
||||
|
||||
(defun hide-ifdef-guts ()
|
||||
"Does most of the work of `hide-ifdefs'.
|
||||
|
|
@ -2376,7 +2566,7 @@ It does not do the work that's pointless to redo on a recursive entry."
|
|||
min max)
|
||||
(setq hif-__COUNTER__ 0)
|
||||
(goto-char (point-min))
|
||||
(setf min (point))
|
||||
(setq min (point))
|
||||
;; Without this `condition-case' it would be easier to see which
|
||||
;; operation went wrong thru the backtrace `iff' user realize
|
||||
;; the underlying meaning of all hif-* operation; for example,
|
||||
|
|
@ -2384,11 +2574,11 @@ It does not do the work that's pointless to redo on a recursive entry."
|
|||
;; operation arguments would be invalid.
|
||||
(condition-case err
|
||||
(cl-loop do
|
||||
(setf max (hif-find-any-ifX))
|
||||
(hif-add-new-defines min max)
|
||||
(setq max (hif-find-any-ifX))
|
||||
(setq max (hif-add-new-defines min max))
|
||||
(if max
|
||||
(hif-possibly-hide expand-header))
|
||||
(setf min (point))
|
||||
(setq min (point))
|
||||
while max)
|
||||
(error (error "Error: failed at line %d %S"
|
||||
(line-number-at-pos) err))))))
|
||||
|
|
|
|||
Loading…
Reference in a new issue