emacs-diffs
[Top][All Lists]
Advanced

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

master 77ca6aa56e: hideif.el: Support C99 and GNU style variadic macros


From: Luke Lee
Subject: master 77ca6aa56e: hideif.el: Support C99 and GNU style variadic macros
Date: Sun, 15 Jan 2023 01:08:29 -0500 (EST)

branch: master
commit 77ca6aa56e3425c87861cab8abce52bee3697cf4
Author: Luke Lee <luke.yx.lee@gmail.com>
Commit: Luke Lee <luke.yx.lee@gmail.com>

    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.
---
 lisp/progmodes/hideif.el | 374 +++++++++++++++++++++++++++++++++++------------
 1 file changed, 282 insertions(+), 92 deletions(-)

diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el
index 30893638f0..4405ce0fe0 100644
--- a/lisp/progmodes/hideif.el
+++ b/lisp/progmodes/hideif.el
@@ -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)))
-
-        ;; Token concatenation happens here, keep single 'hif-space
-        (hif-keep-single (hif-token-concatenation macro-body) 'hif-space))))
+
+      ;; 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
+
+          ((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))))))



reply via email to

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