diff options
| author | Luke Lee | 2014-06-26 13:47:33 +0800 |
|---|---|---|
| committer | Luke Lee | 2014-06-26 13:47:33 +0800 |
| commit | c269730462ab74967ed2cde73da7c74545a2118c (patch) | |
| tree | 71419ec5710af4f6eb176824a42e29291fb280e4 | |
| parent | cb6ce5eee811b547506cf37bb9da78ff908a82ff (diff) | |
| download | emacs-c269730462ab74967ed2cde73da7c74545a2118c.tar.gz emacs-c269730462ab74967ed2cde73da7c74545a2118c.zip | |
HideIfDef mode bug fixes and enhancements. This is #2 of 3 patches based
on the completed work posted on http://www.emacswiki.org/emacs/HideIfDef.
- Supporting argumented macro expansion.
- Stringification, tokenization and concatenation of strings and tokens.
- Add functions to find defines and parse argumented macros into a macro
tree containing macro name, formal parameters and macro body.
- On macro evaluation, macros will be applied with actual parameters and
then got expanded recursively.
- Merge main trunk changes
* lisp/progmodes/hideif.el (hif-string-to-number): Merge changes from
main trunk.
(hif-simple-token-only, hif-tokenize): Commentted in detail mainly for
performance enhancements.
(hif-parse-if-exp): Rename to `hif-parse-exp'. Enhanced for macro
expansion.
(hif-factor, hif-string-concatenation, intern-safe): Support string
concatenation and argumented macro expansion.
(hif-if-valid-identifier-p, hif-define-operator, hif-flatten)
(hif-expand-token-list, hif-get-argument-list, hif-define-macro)
(hif-delimit, hif-macro-supply-arguments, hif-invoke, hif-canonicalize)
(hif-canonicalize-tokens, hif-looking-at-elif, hif-place-macro-invocation)
(hif-parse-macro-arglist): Mostly new functions for supporting argumented
macro expansion.
(hif-string-concatenation, hif-stringify, hif-token-concat)
(hif-token-stringification, hif-token-concatenation): Stringify and
concatentation.
(hif-find-next-relevant): Fix comments
(hif-ifdef-to-endif, hif-looking-at-elif, hif-hide-line): Bug fix for
some cases involving #elif.
(hif-find-define, hif-add-new-defines): New functions for automatically
scanning of defined symbols.
(hide-ifdef-guts): Fix for auto defined symbol scanning.
(hide-ifdef-undef): Fix behavior to match CPP.
| -rw-r--r-- | lisp/progmodes/hideif.el | 623 |
1 files changed, 577 insertions, 46 deletions
diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el index 39ad676f593..b0ca4f0cdd0 100644 --- a/lisp/progmodes/hideif.el +++ b/lisp/progmodes/hideif.el | |||
| @@ -36,6 +36,8 @@ | |||
| 36 | ;; | 36 | ;; |
| 37 | ;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't | 37 | ;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't |
| 38 | ;; pass through. Support complete C/C++ expression and precedence. | 38 | ;; pass through. Support complete C/C++ expression and precedence. |
| 39 | ;; It will automatically scans for new #define symbols and macros on the way | ||
| 40 | ;; parsing. | ||
| 39 | ;; | 41 | ;; |
| 40 | ;; The hidden code is marked by ellipses (...). Be | 42 | ;; The hidden code is marked by ellipses (...). Be |
| 41 | ;; cautious when editing near ellipses, since the hidden text is | 43 | ;; cautious when editing near ellipses, since the hidden text is |
| @@ -97,11 +99,12 @@ | |||
| 97 | ;; Extensively modified by Daniel LaLiberte (while at Gould). | 99 | ;; Extensively modified by Daniel LaLiberte (while at Gould). |
| 98 | ;; | 100 | ;; |
| 99 | ;; Extensively modified by Luke Lee in 2013 to support complete C expression | 101 | ;; Extensively modified by Luke Lee in 2013 to support complete C expression |
| 100 | ;; evaluation. | 102 | ;; evaluation and argumented macro expansion. |
| 101 | 103 | ||
| 102 | ;;; Code: | 104 | ;;; Code: |
| 103 | 105 | ||
| 104 | (require 'cc-mode) | 106 | (require 'cc-mode) |
| 107 | (require 'cl-lib) | ||
| 105 | 108 | ||
| 106 | (defgroup hide-ifdef nil | 109 | (defgroup hide-ifdef nil |
| 107 | "Hide selected code within `ifdef'." | 110 | "Hide selected code within `ifdef'." |
| @@ -133,6 +136,9 @@ | |||
| 133 | :group 'hide-ifdef | 136 | :group 'hide-ifdef |
| 134 | :version "23.1") | 137 | :version "23.1") |
| 135 | 138 | ||
| 139 | (defcustom hide-ifdef-exclude-define-regexp nil | ||
| 140 | "Ignore #define names if those names match this exclusion pattern." | ||
| 141 | :type 'string) | ||
| 136 | 142 | ||
| 137 | (defvar hide-ifdef-mode-submap | 143 | (defvar hide-ifdef-mode-submap |
| 138 | ;; Set up the submap that goes after the prefix key. | 144 | ;; Set up the submap that goes after the prefix key. |
| @@ -356,12 +362,32 @@ that form should be displayed.") | |||
| 356 | ;;; The code that understands what ifs and ifdef in files look like. | 362 | ;;; The code that understands what ifs and ifdef in files look like. |
| 357 | 363 | ||
| 358 | (defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*") | 364 | (defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*") |
| 365 | (defconst hif-ifxdef-regexp (concat hif-cpp-prefix "if\\(n\\)?def")) | ||
| 359 | (defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef")) | 366 | (defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef")) |
| 360 | (defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+")) | 367 | (defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+")) |
| 368 | (defconst hif-elif-regexp (concat hif-cpp-prefix "elif")) | ||
| 361 | (defconst hif-else-regexp (concat hif-cpp-prefix "else")) | 369 | (defconst hif-else-regexp (concat hif-cpp-prefix "else")) |
| 362 | (defconst hif-endif-regexp (concat hif-cpp-prefix "endif")) | 370 | (defconst hif-endif-regexp (concat hif-cpp-prefix "endif")) |
| 363 | (defconst hif-ifx-else-endif-regexp | 371 | (defconst hif-ifx-else-endif-regexp |
| 364 | (concat hif-ifx-regexp "\\|" hif-else-regexp "\\|" hif-endif-regexp)) | 372 | (concat hif-ifx-regexp "\\|" hif-elif-regexp "\\|" hif-else-regexp "\\|" |
| 373 | hif-endif-regexp)) | ||
| 374 | (defconst hif-macro-expr-prefix-regexp | ||
| 375 | (concat hif-cpp-prefix "\\(if\\(n?def\\)?\\|elif\\|define\\)[ \t]+")) | ||
| 376 | |||
| 377 | (defconst hif-white-regexp "[ \t]*") | ||
| 378 | (defconst hif-define-regexp | ||
| 379 | (concat hif-cpp-prefix "\\(define\\|undef\\)")) | ||
| 380 | (defconst hif-id-regexp | ||
| 381 | (concat "[[:alpha:]_][[:alnum:]_]*")) | ||
| 382 | (defconst hif-macroref-regexp | ||
| 383 | (concat hif-white-regexp "\\(" hif-id-regexp "\\)" hif-white-regexp | ||
| 384 | "\\(" | ||
| 385 | "(" hif-white-regexp | ||
| 386 | "\\(" hif-id-regexp "\\)?" hif-white-regexp | ||
| 387 | "\\(" "," hif-white-regexp hif-id-regexp hif-white-regexp "\\)*" | ||
| 388 | "\\(\\.\\.\\.\\)?" hif-white-regexp | ||
| 389 | ")" | ||
| 390 | "\\)?" )) | ||
| 365 | 391 | ||
| 366 | ;; Used to store the current token and the whole token list during parsing. | 392 | ;; Used to store the current token and the whole token list during parsing. |
| 367 | ;; Only bound dynamically. | 393 | ;; Only bound dynamically. |
| @@ -397,7 +423,12 @@ that form should be displayed.") | |||
| 397 | ("/" . hif-divide) | 423 | ("/" . hif-divide) |
| 398 | ("%" . hif-modulo) | 424 | ("%" . hif-modulo) |
| 399 | ("?" . hif-conditional) | 425 | ("?" . hif-conditional) |
| 400 | (":" . hif-colon))) | 426 | (":" . hif-colon) |
| 427 | ("," . hif-comma) | ||
| 428 | ("#" . hif-stringify) | ||
| 429 | ("..." . hif-etc))) | ||
| 430 | |||
| 431 | (defconst hif-valid-token-list (mapcar 'cdr hif-token-alist)) | ||
| 401 | 432 | ||
| 402 | (defconst hif-token-regexp | 433 | (defconst hif-token-regexp |
| 403 | (concat (regexp-opt (mapcar 'car hif-token-alist)) | 434 | (concat (regexp-opt (mapcar 'car hif-token-alist)) |
| @@ -407,10 +438,29 @@ that form should be displayed.") | |||
| 407 | 438 | ||
| 408 | (defconst hif-string-literal-regexp "\\(\"\\(?:[^\"\\]\\|\\\\.\\)*\"\\)") | 439 | (defconst hif-string-literal-regexp "\\(\"\\(?:[^\"\\]\\|\\\\.\\)*\"\\)") |
| 409 | 440 | ||
| 441 | (defun hif-string-to-number (string &optional base) | ||
| 442 | "Like `string-to-number', but it understands non-decimal floats." | ||
| 443 | (if (or (not base) (= base 10)) | ||
| 444 | (string-to-number string base) | ||
| 445 | (let* ((parts (split-string string "\\." t "[ \t]+")) | ||
| 446 | (frac (cadr parts)) | ||
| 447 | (fraclen (length frac)) | ||
| 448 | (quot (expt (if (zerop fraclen) | ||
| 449 | base | ||
| 450 | (* base 1.0)) fraclen))) | ||
| 451 | (/ (string-to-number (concat (car parts) frac) base) quot)))) | ||
| 452 | |||
| 453 | ;; The dynamic binding variable `hif-simple-token-only' is shared only by | ||
| 454 | ;; `hif-tokenize' and `hif-find-define'. The purpose is to prevent `hif-tokenize' | ||
| 455 | ;; from returning one more value to indicate a simple token is scanned. This help | ||
| 456 | ;; speeding up macro evaluation on those very simple cases like integers or | ||
| 457 | ;; literals. | ||
| 458 | ;; Check the long comments before `hif-find-define' for more details. [lukelee] | ||
| 410 | 459 | ||
| 411 | (defun hif-tokenize (start end) | 460 | (defun hif-tokenize (start end) |
| 412 | "Separate string between START and END into a list of tokens." | 461 | "Separate string between START and END into a list of tokens." |
| 413 | (let ((token-list nil)) | 462 | (let ((token-list nil)) |
| 463 | (setq hif-simple-token-only t) | ||
| 414 | (with-syntax-table hide-ifdef-syntax-table | 464 | (with-syntax-table hide-ifdef-syntax-table |
| 415 | (save-excursion | 465 | (save-excursion |
| 416 | (goto-char start) | 466 | (goto-char start) |
| @@ -423,8 +473,10 @@ that form should be displayed.") | |||
| 423 | ((looking-at hif-string-literal-regexp) | 473 | ((looking-at hif-string-literal-regexp) |
| 424 | (push (substring-no-properties (match-string 1)) token-list) | 474 | (push (substring-no-properties (match-string 1)) token-list) |
| 425 | (goto-char (match-end 0))) | 475 | (goto-char (match-end 0))) |
| 476 | |||
| 426 | ((looking-at hif-token-regexp) | 477 | ((looking-at hif-token-regexp) |
| 427 | (let ((token (buffer-substring (point) (match-end 0)))) | 478 | (let ((token (buffer-substring-no-properties |
| 479 | (point) (match-end 0)))) | ||
| 428 | (goto-char (match-end 0)) | 480 | (goto-char (match-end 0)) |
| 429 | ;; (message "token: %s" token) (sit-for 1) | 481 | ;; (message "token: %s" token) (sit-for 1) |
| 430 | (push | 482 | (push |
| @@ -432,22 +484,22 @@ that form should be displayed.") | |||
| 432 | (if (string-equal token "defined") 'hif-defined) | 484 | (if (string-equal token "defined") 'hif-defined) |
| 433 | ;; TODO: | 485 | ;; TODO: |
| 434 | ;; 1. postfix 'l', 'll', 'ul' and 'ull' | 486 | ;; 1. postfix 'l', 'll', 'ul' and 'ull' |
| 435 | ;; 2. floating number formats | 487 | ;; 2. floating number formats (like 1.23e4) |
| 436 | ;; 3. hexadecimal/octal floats | 488 | ;; 3. 098 is interpreted as octal conversion error |
| 437 | ;; 4. 098 is interpreted as octal conversion error | ||
| 438 | ;; FIXME: string-to-number does not convert hex floats | ||
| 439 | (if (string-match "0x\\([0-9a-fA-F]+\\.?[0-9a-fA-F]*\\)" | 489 | (if (string-match "0x\\([0-9a-fA-F]+\\.?[0-9a-fA-F]*\\)" |
| 440 | token) | 490 | token) |
| 441 | (string-to-number (match-string 1 token) 16)) ;; hex | 491 | (hif-string-to-number (match-string 1 token) 16)) ;; hex |
| 442 | ;; FIXME: string-to-number does not convert octal floats | ||
| 443 | (if (string-match "\\`0[0-9]+\\(\\.[0-9]+\\)?\\'" token) | 492 | (if (string-match "\\`0[0-9]+\\(\\.[0-9]+\\)?\\'" token) |
| 444 | (string-to-number token 8)) ;; octal | 493 | (hif-string-to-number token 8)) ;; octal |
| 445 | (if (string-match "\\`[1-9][0-9]*\\(\\.[0-9]+\\)?\\'" | 494 | (if (string-match "\\`[1-9][0-9]*\\(\\.[0-9]+\\)?\\'" |
| 446 | token) | 495 | token) |
| 447 | (string-to-number token)) ;; decimal | 496 | (string-to-number token)) ;; decimal |
| 448 | (intern token)) | 497 | (prog1 (intern token) |
| 498 | (setq hif-simple-token-only nil))) | ||
| 449 | token-list))) | 499 | token-list))) |
| 500 | |||
| 450 | (t (error "Bad #if expression: %s" (buffer-string))))))) | 501 | (t (error "Bad #if expression: %s" (buffer-string))))))) |
| 502 | |||
| 451 | (nreverse token-list))) | 503 | (nreverse token-list))) |
| 452 | 504 | ||
| 453 | ;;------------------------------------------------------------------------ | 505 | ;;------------------------------------------------------------------------ |
| @@ -482,9 +534,115 @@ that form should be displayed.") | |||
| 482 | "Pop the next token from token-list into the let variable `hif-token'." | 534 | "Pop the next token from token-list into the let variable `hif-token'." |
| 483 | (setq hif-token (pop hif-token-list))) | 535 | (setq hif-token (pop hif-token-list))) |
| 484 | 536 | ||
| 485 | (defun hif-parse-if-exp (token-list) | 537 | (defsubst hif-if-valid-identifier-p (id) |
| 486 | "Parse the TOKEN-LIST. Return translated list in prefix form." | 538 | (not (or (numberp id) |
| 487 | (let ((hif-token-list token-list)) | 539 | (stringp id)))) |
| 540 | |||
| 541 | (defun hif-define-operator (tokens) | ||
| 542 | "`Upgrade' hif-define xxx to '(hif-define xxx)' so that it won't be | ||
| 543 | subsitituted" | ||
| 544 | (let ((result nil) | ||
| 545 | (tok nil)) | ||
| 546 | (while (setq tok (pop tokens)) | ||
| 547 | (push | ||
| 548 | (if (eq tok 'hif-defined) | ||
| 549 | (progn | ||
| 550 | (setq tok (cadr tokens)) | ||
| 551 | (if (eq (car tokens) 'hif-lparen) | ||
| 552 | (if (and (hif-if-valid-identifier-p tok) | ||
| 553 | (eq (caddr tokens) 'hif-rparen)) | ||
| 554 | (setq tokens (cdddr tokens)) | ||
| 555 | (error "#define followed by non-identifier: %S" tok)) | ||
| 556 | (setq tok (car tokens) | ||
| 557 | tokens (cdr tokens)) | ||
| 558 | (unless (hif-if-valid-identifier-p tok) | ||
| 559 | (error "#define followed by non-identifier: %S" tok))) | ||
| 560 | (list 'hif-defined 'hif-lparen tok 'hif-rparen)) | ||
| 561 | tok) | ||
| 562 | result)) | ||
| 563 | (nreverse result))) | ||
| 564 | |||
| 565 | (defun hif-flatten (l) | ||
| 566 | "Flatten a tree" | ||
| 567 | (apply #'nconc | ||
| 568 | (mapcar (lambda (x) (if (listp x) | ||
| 569 | (hif-flatten x) | ||
| 570 | (list x))) l))) | ||
| 571 | |||
| 572 | (defun hif-expand-token-list (tokens &optional macroname expand_list) | ||
| 573 | "Perform expansion till everything expanded. No self-reference expansion. | ||
| 574 | EXPAND_LIST is the list of macro names currently being expanded." | ||
| 575 | (catch 'self-referencing | ||
| 576 | (let ((expanded nil) | ||
| 577 | (remains (hif-define-operator | ||
| 578 | (hif-token-concatenation | ||
| 579 | (hif-token-stringification tokens)))) | ||
| 580 | tok rep) | ||
| 581 | (if macroname | ||
| 582 | (setq expand_list (cons macroname expand_list))) | ||
| 583 | ;; Expanding all tokens till list exhausted | ||
| 584 | (while (setq tok (pop remains)) | ||
| 585 | (if (memq tok expand_list) | ||
| 586 | ;; For self-referencing tokens, don't expand it | ||
| 587 | (throw 'self-referencing tokens)) | ||
| 588 | (push | ||
| 589 | (cond | ||
| 590 | ((or (memq tok hif-valid-token-list) | ||
| 591 | (numberp tok) | ||
| 592 | (stringp tok)) | ||
| 593 | tok) | ||
| 594 | |||
| 595 | ((setq rep (hif-lookup tok)) | ||
| 596 | (if (and (listp rep) | ||
| 597 | (eq (car rep) 'hif-define-macro)) ;; a defined macro | ||
| 598 | ;; Recursively expand it | ||
| 599 | (if (cadr rep) ;; Argument list is not nil | ||
| 600 | (if (not (eq (car remains) 'hif-lparen)) | ||
| 601 | ;; No argument, no invocation | ||
| 602 | tok | ||
| 603 | ;; Argumented macro, get arguments and invoke it. | ||
| 604 | ;; Dynamically bind hif-token-list and hif-token | ||
| 605 | ;; for hif-macro-supply-arguments | ||
| 606 | (let* ((hif-token-list (cdr remains)) | ||
| 607 | (hif-token nil) | ||
| 608 | (parmlist (mapcar 'hif-expand-token-list | ||
| 609 | (hif-get-argument-list | ||
| 610 | tok))) | ||
| 611 | (result | ||
| 612 | (hif-expand-token-list | ||
| 613 | (hif-macro-supply-arguments tok parmlist) | ||
| 614 | tok expand_list))) | ||
| 615 | (setq remains (cons hif-token hif-token-list)) | ||
| 616 | result)) | ||
| 617 | ;; Argument list is nil, direct expansion | ||
| 618 | (setq rep (hif-expand-token-list | ||
| 619 | (caddr rep) ;; Macro's token list | ||
| 620 | tok expand_list)) | ||
| 621 | ;; Replace all remaining references immediately | ||
| 622 | (setq remains (substitute tok rep remains)) | ||
| 623 | rep) | ||
| 624 | ;; Lookup tok returns an atom | ||
| 625 | rep)) | ||
| 626 | |||
| 627 | ;;[2013-10-22 16:06:12 +0800] Must keep the token, removing | ||
| 628 | ;; this token might results in an incomplete expression that | ||
| 629 | ;; cannot be parsed further. | ||
| 630 | ;;((= 1 (hif-defined tok)) ;; defined (hif-defined tok)=1, | ||
| 631 | ;; ;;but empty (hif-lookup tok)=nil, thus remove this token | ||
| 632 | ;; (setq remains (delete tok remains)) | ||
| 633 | ;; nil) | ||
| 634 | |||
| 635 | (t ;; Usual IDs | ||
| 636 | tok)) | ||
| 637 | |||
| 638 | expanded)) | ||
| 639 | |||
| 640 | (hif-flatten (nreverse expanded))))) | ||
| 641 | |||
| 642 | (defun hif-parse-exp (token-list &optional macroname) | ||
| 643 | "Parse the TOKEN-LIST. Return translated list in prefix form. MACRONAME | ||
| 644 | is applied when invoking macros to prevent self-referencing macros." | ||
| 645 | (let ((hif-token-list (hif-expand-token-list token-list macroname))) | ||
| 488 | (hif-nexttoken) | 646 | (hif-nexttoken) |
| 489 | (prog1 | 647 | (prog1 |
| 490 | (and hif-token | 648 | (and hif-token |
| @@ -574,7 +732,8 @@ that form should be displayed.") | |||
| 574 | "Parse a comp-expr : logshift | comp-expr `<'|`>'|`>='|`<=' logshift." | 732 | "Parse a comp-expr : logshift | comp-expr `<'|`>'|`>='|`<=' logshift." |
| 575 | (let ((result (hif-logshift-expr)) | 733 | (let ((result (hif-logshift-expr)) |
| 576 | (comp-token nil)) | 734 | (comp-token nil)) |
| 577 | (while (memq hif-token '(hif-greater hif-less hif-greater-equal hif-less-equal)) | 735 | (while (memq hif-token '(hif-greater hif-less hif-greater-equal |
| 736 | hif-less-equal)) | ||
| 578 | (setq comp-token hif-token) | 737 | (setq comp-token hif-token) |
| 579 | (hif-nexttoken) | 738 | (hif-nexttoken) |
| 580 | (setq result (list comp-token result (hif-logshift-expr)))) | 739 | (setq result (list comp-token result (hif-logshift-expr)))) |
| @@ -613,7 +772,8 @@ that form should be displayed.") | |||
| 613 | result)) | 772 | result)) |
| 614 | 773 | ||
| 615 | (defun hif-factor () | 774 | (defun hif-factor () |
| 616 | "Parse a factor: '!' factor | '~' factor | '(' expr ')' | 'defined(' id ')' | 'id(parmlist)' | strings | id." | 775 | "Parse a factor: '!' factor | '~' factor | '(' expr ')' | |
| 776 | 'defined(' id ')' | 'id(parmlist)' | strings | id." | ||
| 617 | (cond | 777 | (cond |
| 618 | ((eq hif-token 'hif-not) | 778 | ((eq hif-token 'hif-not) |
| 619 | (hif-nexttoken) | 779 | (hif-nexttoken) |
| @@ -646,6 +806,8 @@ that form should be displayed.") | |||
| 646 | 806 | ||
| 647 | ((numberp hif-token) | 807 | ((numberp hif-token) |
| 648 | (prog1 hif-token (hif-nexttoken))) | 808 | (prog1 hif-token (hif-nexttoken))) |
| 809 | ((stringp hif-token) | ||
| 810 | (hif-string-concatenation)) | ||
| 649 | 811 | ||
| 650 | ;; Unary plus/minus. | 812 | ;; Unary plus/minus. |
| 651 | ((memq hif-token '(hif-minus hif-plus)) | 813 | ((memq hif-token '(hif-minus hif-plus)) |
| @@ -653,10 +815,91 @@ that form should be displayed.") | |||
| 653 | 815 | ||
| 654 | (t ; identifier | 816 | (t ; identifier |
| 655 | (let ((ident hif-token)) | 817 | (let ((ident hif-token)) |
| 656 | (if (memq ident '(or and)) | ||
| 657 | (error "Error: missing identifier")) | ||
| 658 | (hif-nexttoken) | 818 | (hif-nexttoken) |
| 659 | `(hif-lookup (quote ,ident)))))) | 819 | (if (eq hif-token 'hif-lparen) |
| 820 | (hif-place-macro-invocation ident) | ||
| 821 | `(hif-lookup (quote ,ident))))))) | ||
| 822 | |||
| 823 | (defun hif-get-argument-list (ident) | ||
| 824 | (let ((nest 0) | ||
| 825 | (parmlist nil) ;; A "token" list of parameters, will later be parsed | ||
| 826 | (parm nil)) | ||
| 827 | |||
| 828 | (while (or (not (eq (hif-nexttoken) 'hif-rparen)) | ||
| 829 | (/= nest 0)) | ||
| 830 | (if (eq (car (last parm)) 'hif-comma) | ||
| 831 | (setq parm nil)) | ||
| 832 | (cond | ||
| 833 | ((eq hif-token 'hif-lparen) | ||
| 834 | (setq nest (1+ nest))) | ||
| 835 | ((eq hif-token 'hif-rparen) | ||
| 836 | (setq nest (1- nest))) | ||
| 837 | ((and (eq hif-token 'hif-comma) | ||
| 838 | (= nest 0)) | ||
| 839 | (push (nreverse parm) parmlist) | ||
| 840 | (setq parm nil))) | ||
| 841 | (push hif-token parm)) | ||
| 842 | |||
| 843 | (push (nreverse parm) parmlist) ;; Okay even if parm is nil | ||
| 844 | (hif-nexttoken) ;; Drop the hif-rparen, get next token | ||
| 845 | (nreverse parmlist))) | ||
| 846 | |||
| 847 | (defun hif-place-macro-invocation (ident) | ||
| 848 | (let ((parmlist (hif-get-argument-list ident))) | ||
| 849 | `(hif-invoke (quote ,ident) (quote ,parmlist)))) | ||
| 850 | |||
| 851 | (defun hif-string-concatenation () | ||
| 852 | "Parse concatenated strings: string | strings string" | ||
| 853 | (let ((result (substring-no-properties hif-token))) | ||
| 854 | (while (stringp (hif-nexttoken)) | ||
| 855 | (setq result (concat | ||
| 856 | (substring result 0 -1) ; remove trailing '"' | ||
| 857 | (substring hif-token 1)))) ; remove leading '"' | ||
| 858 | result)) | ||
| 859 | |||
| 860 | (defun hif-define-macro (parmlist token-body) | ||
| 861 | "A marker for defined macro with arguments, cannot be evaluated alone with | ||
| 862 | no parameters inputed." | ||
| 863 | ;;TODO: input arguments at run time, use minibuffer to query all arguments | ||
| 864 | (error | ||
| 865 | "Argumented macro cannot be evaluated without passing any parameter.")) | ||
| 866 | |||
| 867 | (defun hif-stringify (a) | ||
| 868 | "Stringify a number, string or symbol." | ||
| 869 | (cond | ||
| 870 | ((numberp a) | ||
| 871 | (number-to-string a)) | ||
| 872 | ((atom a) | ||
| 873 | (symbol-name a)) | ||
| 874 | ((stringp a) | ||
| 875 | (concat "\"" a "\"")) | ||
| 876 | (t | ||
| 877 | (error "Invalid token to stringify")))) | ||
| 878 | |||
| 879 | (defun intern-safe (str) | ||
| 880 | (if (stringp str) | ||
| 881 | (intern str))) | ||
| 882 | |||
| 883 | (defun hif-token-concat (a b) | ||
| 884 | "Concatenate two tokens into a longer token, currently support only simple | ||
| 885 | token concatenation. Also support weird (but valid) token concatenation like | ||
| 886 | '>' ## '>' becomes '>>'. Here we take care only those that can be evaluated | ||
| 887 | during preprocessing time and ignore all those that can only be evaluated at | ||
| 888 | C(++) runtime (like '++', '--' and '+='...)." | ||
| 889 | (if (or (memq a hif-valid-token-list) | ||
| 890 | (memq b hif-valid-token-list)) | ||
| 891 | (let* ((ra (car (rassq a hif-token-alist))) | ||
| 892 | (rb (car (rassq b hif-token-alist))) | ||
| 893 | (result (and ra rb | ||
| 894 | (cdr (assoc (concat ra rb) hif-token-alist))))) | ||
| 895 | (or result | ||
| 896 | ;;(error "Invalid token to concatenate") | ||
| 897 | (error "Concatenating \"%s\" and \"%s\" does not give a valid \ | ||
| 898 | preprocessing token." | ||
| 899 | (or ra (symbol-name a)) | ||
| 900 | (or rb (symbol-name b))))) | ||
| 901 | (intern-safe (concat (hif-stringify a) | ||
| 902 | (hif-stringify b))))) | ||
| 660 | 903 | ||
| 661 | (defun hif-mathify (val) | 904 | (defun hif-mathify (val) |
| 662 | "Treat VAL as a number: if it's t or nil, use 1 or 0." | 905 | "Treat VAL as a number: if it's t or nil, use 1 or 0." |
| @@ -719,23 +962,157 @@ that form should be displayed.") | |||
| 719 | (setq result (funcall hide-ifdef-evaluator e)))) | 962 | (setq result (funcall hide-ifdef-evaluator e)))) |
| 720 | result)) | 963 | result)) |
| 721 | 964 | ||
| 965 | (defun hif-token-stringification (l) | ||
| 966 | "Scan token list for 'hif-stringify' ('#') token and stringify the next | ||
| 967 | token." | ||
| 968 | (let (result) | ||
| 969 | (while l | ||
| 970 | (push (if (eq (car l) 'hif-stringify) | ||
| 971 | (prog1 | ||
| 972 | (if (cadr l) | ||
| 973 | (hif-stringify (cadr l)) | ||
| 974 | (error "No token to stringify")) | ||
| 975 | (setq l (cdr l))) | ||
| 976 | (car l)) | ||
| 977 | result) | ||
| 978 | (setq l (cdr l))) | ||
| 979 | (nreverse result))) | ||
| 980 | |||
| 981 | (defun hif-token-concatenation (l) | ||
| 982 | "Scan token list for 'hif-token-concat' ('##') token and concatenate two | ||
| 983 | tokens." | ||
| 984 | (let ((prev nil) | ||
| 985 | result) | ||
| 986 | (while l | ||
| 987 | (while (eq (car l) 'hif-token-concat) | ||
| 988 | (unless prev | ||
| 989 | (error "No token before ## to concatenate")) | ||
| 990 | (unless (cdr l) | ||
| 991 | (error "No token after ## to concatenate")) | ||
| 992 | (setq prev (hif-token-concat prev (cadr l))) | ||
| 993 | (setq l (cddr l))) | ||
| 994 | (if prev | ||
| 995 | (setq result (append result (list prev)))) | ||
| 996 | (setq prev (car l) | ||
| 997 | l (cdr l))) | ||
| 998 | (if prev | ||
| 999 | (append result (list prev)) | ||
| 1000 | result))) | ||
| 1001 | |||
| 1002 | (defun hif-delimit (lis atom) | ||
| 1003 | (nconc (mapcan (lambda (l) (list l atom)) | ||
| 1004 | (butlast lis)) | ||
| 1005 | (last lis))) | ||
| 1006 | |||
| 1007 | ;; Perform token replacement: | ||
| 1008 | (defun hif-macro-supply-arguments (macro-name actual-parms) | ||
| 1009 | "Expand a macro call, replace ACTUAL-PARMS in the macro body." | ||
| 1010 | (let* ((SA (assoc macro-name hide-ifdef-env)) | ||
| 1011 | (macro (and SA | ||
| 1012 | (cdr SA) | ||
| 1013 | (eq (cadr SA) 'hif-define-macro) | ||
| 1014 | (cddr SA))) | ||
| 1015 | (formal-parms (and macro (car macro))) | ||
| 1016 | (macro-body (and macro (cadr macro))) | ||
| 1017 | (hide-ifdef-local-env nil) ; dynamic binding local table | ||
| 1018 | actual-count | ||
| 1019 | formal-count | ||
| 1020 | actual | ||
| 1021 | formal | ||
| 1022 | etc) | ||
| 1023 | |||
| 1024 | (when (and actual-parms formal-parms macro-body) | ||
| 1025 | ;; For each actual parameter, evaluate each one and associate it | ||
| 1026 | ;; with the associated actual parameter, put it into local table and finally | ||
| 1027 | ;; evaluate the macro body. | ||
| 1028 | (if (setq etc (eq (car formal-parms) 'hif-etc)) | ||
| 1029 | ;; Take care of 'hif-etc first. Prefix 'hif-comma back if needed. | ||
| 1030 | (setq formal-parms (cdr formal-parms))) | ||
| 1031 | (setq formal-count (length formal-parms) | ||
| 1032 | actual-count (length actual-parms)) | ||
| 1033 | |||
| 1034 | (if (> formal-count actual-count) | ||
| 1035 | (error "Too few parmameter for macro %S" macro-name) | ||
| 1036 | (if (< formal-count actual-count) | ||
| 1037 | (or etc | ||
| 1038 | (error "Too many parameters for macro %S" macro-name)))) | ||
| 1039 | |||
| 1040 | ;; Perform token replacement on the macro-body on the parameters | ||
| 1041 | (while (setq formal (pop formal-parms)) | ||
| 1042 | ;; Prevent repetitive substitutation, thus cannot use 'subst' | ||
| 1043 | ;; for example: | ||
| 1044 | ;; #define mac(a,b) (a+b) | ||
| 1045 | ;; #define testmac mac(b,y) | ||
| 1046 | ;; testmac should expand to (b+y): replace of argument a and b | ||
| 1047 | ;; occurs simultaneously, not sequentially. If sequentially, | ||
| 1048 | ;; according to the argument order, it will become: | ||
| 1049 | ;; 1. formal parm #1 'a' replaced by actual parm 'b', thus (a+b) | ||
| 1050 | ;; becomes (b+b) | ||
| 1051 | ;; 2. formal parm #2 'b' replaced by actual parm 'y', thus (b+b) | ||
| 1052 | ;; becomes (y+y). | ||
| 1053 | (setq macro-body | ||
| 1054 | ;; Unlike 'subst', 'substitute' replace only the top level | ||
| 1055 | ;; instead of the whole tree; more importantly, it's not | ||
| 1056 | ;; destructive. | ||
| 1057 | (substitute (if (and etc (null formal-parms)) | ||
| 1058 | (hif-delimit actual-parms 'hif-comma) | ||
| 1059 | (car actual-parms)) | ||
| 1060 | formal macro-body)) | ||
| 1061 | (setq actual-parms (cdr actual-parms))) | ||
| 1062 | |||
| 1063 | ;; Replacement completed, flatten the whole token list | ||
| 1064 | (setq macro-body (hif-flatten macro-body)) | ||
| 1065 | |||
| 1066 | ;; Stringification and token concatenation happens here | ||
| 1067 | (hif-token-concatenation (hif-token-stringification macro-body))))) | ||
| 1068 | |||
| 1069 | (defun hif-invoke (macro-name actual-parms) | ||
| 1070 | "Invoke a macro by first expanding it, then reparse the macro-body, | ||
| 1071 | finally invoke the macro." | ||
| 1072 | ;; Reparse the macro body and evaluate it | ||
| 1073 | (funcall hide-ifdef-evaluator | ||
| 1074 | (hif-parse-exp | ||
| 1075 | (hif-macro-supply-arguments macro-name actual-parms) | ||
| 1076 | macro-name))) | ||
| 722 | 1077 | ||
| 723 | ;;;----------- end of parser ----------------------- | 1078 | ;;;----------- end of parser ----------------------- |
| 724 | 1079 | ||
| 725 | 1080 | ||
| 726 | (defun hif-canonicalize () | 1081 | (defun hif-canonicalize-tokens (regexp) ;; for debugging |
| 727 | "When at beginning of #ifX, return a Lisp expression for its condition." | 1082 | "Return the expanded result of the scanned tokens." |
| 728 | (save-excursion | 1083 | (save-excursion |
| 729 | (let ((negate (looking-at hif-ifndef-regexp))) | 1084 | (re-search-forward regexp) |
| 730 | (re-search-forward hif-ifx-regexp) | 1085 | (let* ((curr-regexp (match-string 0)) |
| 731 | (let* ((tokens (hif-tokenize (point) | 1086 | (defined (string-match hif-ifxdef-regexp curr-regexp)) |
| 732 | (progn (hif-end-of-line) (point)))) | 1087 | (negate (and defined |
| 733 | (expr (hif-parse-if-exp tokens))) | 1088 | (string= (match-string 2 curr-regexp) "n"))) |
| 734 | ;; (message "hif-canonicalized: %s" expr) | 1089 | (hif-simple-token-only nil) ;; Dynamic binding var for `hif-tokenize' |
| 735 | (if negate | 1090 | (tokens (hif-tokenize (point) |
| 736 | (list 'hif-not expr) | 1091 | (progn (hif-end-of-line) (point))))) |
| 737 | expr))))) | 1092 | (if defined |
| 738 | 1093 | (setq tokens (list 'hif-defined tokens))) | |
| 1094 | (if negate | ||
| 1095 | (setq tokens (list 'hif-not tokens))) | ||
| 1096 | tokens))) | ||
| 1097 | |||
| 1098 | (defun hif-canonicalize (regexp) | ||
| 1099 | "When at beginning of `regexp' (i.e. #ifX), return a Lisp expression for | ||
| 1100 | its condition." | ||
| 1101 | (let ((case-fold-search nil)) | ||
| 1102 | (save-excursion | ||
| 1103 | (re-search-forward regexp) | ||
| 1104 | (let* ((curr-regexp (match-string 0)) | ||
| 1105 | (defined (string-match hif-ifxdef-regexp curr-regexp)) | ||
| 1106 | (negate (and defined | ||
| 1107 | (string= (match-string 2 curr-regexp) "n"))) | ||
| 1108 | (hif-simple-token-only nil) ;; Dynamic binding for `hif-tokenize' | ||
| 1109 | (tokens (hif-tokenize (point) | ||
| 1110 | (progn (hif-end-of-line) (point))))) | ||
| 1111 | (if defined | ||
| 1112 | (setq tokens (list 'hif-defined tokens))) | ||
| 1113 | (if negate | ||
| 1114 | (setq tokens (list 'hif-not tokens))) | ||
| 1115 | (hif-parse-exp tokens))))) | ||
| 739 | 1116 | ||
| 740 | (defun hif-find-any-ifX () | 1117 | (defun hif-find-any-ifX () |
| 741 | "Move to next #if..., or #ifndef, at point or after." | 1118 | "Move to next #if..., or #ifndef, at point or after." |
| @@ -746,10 +1123,10 @@ that form should be displayed.") | |||
| 746 | 1123 | ||
| 747 | 1124 | ||
| 748 | (defun hif-find-next-relevant () | 1125 | (defun hif-find-next-relevant () |
| 749 | "Move to next #if..., #else, or #endif, after the current line." | 1126 | "Move to next #if..., #elif..., #else, or #endif, after the current line." |
| 750 | ;; (message "hif-find-next-relevant at %d" (point)) | 1127 | ;; (message "hif-find-next-relevant at %d" (point)) |
| 751 | (end-of-line) | 1128 | (end-of-line) |
| 752 | ;; avoid infinite recursion by only going to beginning of line if match found | 1129 | ;; Avoid infinite recursion by only going to line-beginning if match found |
| 753 | (if (re-search-forward hif-ifx-else-endif-regexp (point-max) t) | 1130 | (if (re-search-forward hif-ifx-else-endif-regexp (point-max) t) |
| 754 | (beginning-of-line))) | 1131 | (beginning-of-line))) |
| 755 | 1132 | ||
| @@ -757,7 +1134,7 @@ that form should be displayed.") | |||
| 757 | "Move to previous #if..., #else, or #endif, before the current line." | 1134 | "Move to previous #if..., #else, or #endif, before the current line." |
| 758 | ;; (message "hif-find-previous-relevant at %d" (point)) | 1135 | ;; (message "hif-find-previous-relevant at %d" (point)) |
| 759 | (beginning-of-line) | 1136 | (beginning-of-line) |
| 760 | ;; avoid infinite recursion by only going to beginning of line if match found | 1137 | ;; Avoid infinite recursion by only going to line-beginning if match found |
| 761 | (if (re-search-backward hif-ifx-else-endif-regexp (point-min) t) | 1138 | (if (re-search-backward hif-ifx-else-endif-regexp (point-min) t) |
| 762 | (beginning-of-line))) | 1139 | (beginning-of-line))) |
| 763 | 1140 | ||
| @@ -769,15 +1146,19 @@ that form should be displayed.") | |||
| 769 | (defun hif-looking-at-else () | 1146 | (defun hif-looking-at-else () |
| 770 | (looking-at hif-else-regexp)) | 1147 | (looking-at hif-else-regexp)) |
| 771 | 1148 | ||
| 1149 | (defun hif-looking-at-elif () | ||
| 1150 | (looking-at hif-elif-regexp)) | ||
| 772 | 1151 | ||
| 773 | 1152 | ||
| 774 | (defun hif-ifdef-to-endif () | 1153 | (defun hif-ifdef-to-endif () |
| 775 | "If positioned at #ifX or #else form, skip to corresponding #endif." | 1154 | "If positioned at #ifX, #elif, or #else form, skip to corresponding #endif." |
| 776 | ;; (message "hif-ifdef-to-endif at %d" (point)) (sit-for 1) | 1155 | ;; (message "hif-ifdef-to-endif at %d" (point)) (sit-for 1) |
| 777 | (hif-find-next-relevant) | 1156 | (hif-find-next-relevant) |
| 778 | (cond ((hif-looking-at-ifX) | 1157 | (cond ((hif-looking-at-ifX) |
| 779 | (hif-ifdef-to-endif) ; find endif of nested if | 1158 | (hif-ifdef-to-endif) ; find endif of nested if |
| 780 | (hif-ifdef-to-endif)) ; find outer endif or else | 1159 | (hif-ifdef-to-endif)) ; find outer endif or else |
| 1160 | ((hif-looking-at-elif) | ||
| 1161 | (hif-ifdef-to-endif)) | ||
| 781 | ((hif-looking-at-else) | 1162 | ((hif-looking-at-else) |
| 782 | (hif-ifdef-to-endif)) ; find endif following else | 1163 | (hif-ifdef-to-endif)) ; find endif following else |
| 783 | ((hif-looking-at-endif) | 1164 | ((hif-looking-at-endif) |
| @@ -950,7 +1331,7 @@ Point is left unchanged." | |||
| 950 | ;;; A bit slimy. | 1331 | ;;; A bit slimy. |
| 951 | 1332 | ||
| 952 | (defun hif-hide-line (point) | 1333 | (defun hif-hide-line (point) |
| 953 | "Hide the line containing point. Does nothing if `hide-ifdef-lines' is nil." | 1334 | "Hide the line containing point. Does nothing if `hide-ifdef-lines' is nil." |
| 954 | (when hide-ifdef-lines | 1335 | (when hide-ifdef-lines |
| 955 | (save-excursion | 1336 | (save-excursion |
| 956 | (goto-char point) | 1337 | (goto-char point) |
| @@ -994,7 +1375,7 @@ Point is left unchanged." | |||
| 994 | "Called at #ifX expression, this hides those parts that should be hidden. | 1375 | "Called at #ifX expression, this hides those parts that should be hidden. |
| 995 | It uses the judgment of `hide-ifdef-evaluator'." | 1376 | It uses the judgment of `hide-ifdef-evaluator'." |
| 996 | ;; (message "hif-possibly-hide") (sit-for 1) | 1377 | ;; (message "hif-possibly-hide") (sit-for 1) |
| 997 | (let ((test (hif-canonicalize)) | 1378 | (let ((test (hif-canonicalize hif-ifx-regexp)) |
| 998 | (range (hif-find-range))) | 1379 | (range (hif-find-range))) |
| 999 | ;; (message "test = %s" test) (sit-for 1) | 1380 | ;; (message "test = %s" test) (sit-for 1) |
| 1000 | 1381 | ||
| @@ -1022,16 +1403,145 @@ It uses the judgment of `hide-ifdef-evaluator'." | |||
| 1022 | (goto-char (hif-range-end range)) | 1403 | (goto-char (hif-range-end range)) |
| 1023 | (end-of-line))) | 1404 | (end-of-line))) |
| 1024 | 1405 | ||
| 1406 | (defun hif-parse-macro-arglist (str) | ||
| 1407 | "Parse argument list formatted as '( arg1 [ , argn] [...] )', including | ||
| 1408 | the '...'. Return a list of the arguments, if '...' exists the first arg | ||
| 1409 | will be hif-etc." | ||
| 1410 | (let* ((hif-simple-token-only nil) ;; Dynamic binding var for `hif-tokenize' | ||
| 1411 | (tokenlist | ||
| 1412 | (cdr (hif-tokenize | ||
| 1413 | (- (point) (length str)) (point)))) ; remove hif-lparen | ||
| 1414 | etc result token) | ||
| 1415 | (while (not (eq (setq token (pop tokenlist)) 'hif-rparen)) | ||
| 1416 | (cond | ||
| 1417 | ((eq token 'hif-etc) | ||
| 1418 | (setq etc t)) | ||
| 1419 | ((eq token 'hif-comma) | ||
| 1420 | t) | ||
| 1421 | (t | ||
| 1422 | (push token result)))) | ||
| 1423 | (if etc | ||
| 1424 | (cons 'hif-etc (nreverse result)) | ||
| 1425 | (nreverse result)))) | ||
| 1426 | |||
| 1427 | ;; The original version of hideif evaluates the macro early and store the | ||
| 1428 | ;; final values for the defined macro into the symbol database (aka | ||
| 1429 | ;; `hide-ifdef-env'). The evaluation process is "strings -> tokens -> parsed | ||
| 1430 | ;; tree -> [value]". (The square bracket refers to what's stored in in our | ||
| 1431 | ;; `hide-ifdef-env'.) | ||
| 1432 | ;; | ||
| 1433 | ;; This forbids the evaluation of an argumented macro since the parameters | ||
| 1434 | ;; are applied at run time. In order to support argumented macro I then | ||
| 1435 | ;; postponed the evaluation process one stage and store the "parsed tree" | ||
| 1436 | ;; into symbol database. The evaluation process was then "strings -> tokens | ||
| 1437 | ;; -> [parsed tree] -> value". Hideif therefore run slower since it need to | ||
| 1438 | ;; evaluate the parsed tree everytime when trying to expand the symbol. These | ||
| 1439 | ;; temporarily code changes are obsolete and not in Emacs source repository. | ||
| 1440 | ;; | ||
| 1441 | ;; Furthermore, CPP did allow partial expression to be defined in several | ||
| 1442 | ;; macros and later got concatenated into a complete expression and then | ||
| 1443 | ;; evaluate it. In order to match this behavior I had to postpone one stage | ||
| 1444 | ;; further, otherwise those partial expression will be fail on parsing and | ||
| 1445 | ;; we'll miss all macros that reference it. The evaluation process thus | ||
| 1446 | ;; became "strings -> [tokens] -> parsed tree -> value." This degraded the | ||
| 1447 | ;; performance since we need to parse tokens and evaluate them everytime | ||
| 1448 | ;; when that symbol is referenced. | ||
| 1449 | ;; | ||
| 1450 | ;; In real cases I found a lot portion of macros are "simple macros" that | ||
| 1451 | ;; expand to literals like integers or other symbols. In order to enhance | ||
| 1452 | ;; the performance I use this `hif-simple-token-only' to notify my code and | ||
| 1453 | ;; save the final [value] into symbol database. [lukelee] | ||
| 1025 | 1454 | ||
| 1455 | (defun hif-find-define (&optional min max) | ||
| 1456 | "Parse texts and retrieve all defines within the region MIN and MAX." | ||
| 1457 | (interactive) | ||
| 1458 | (and min (goto-char min)) | ||
| 1459 | (and (re-search-forward hif-define-regexp max t) | ||
| 1460 | (or | ||
| 1461 | (let* ((defining (string= "define" (match-string 2))) | ||
| 1462 | (name (and (re-search-forward hif-macroref-regexp max t) | ||
| 1463 | (match-string 1))) | ||
| 1464 | (parsed nil) | ||
| 1465 | (parmlist (and (match-string 3) ;; First arg id found | ||
| 1466 | (hif-parse-macro-arglist (match-string 2))))) | ||
| 1467 | (if defining | ||
| 1468 | ;; Ignore name (still need to return 't), or define the name | ||
| 1469 | (or (and hide-ifdef-exclude-define-regexp | ||
| 1470 | (string-match hide-ifdef-exclude-define-regexp | ||
| 1471 | name)) | ||
| 1472 | |||
| 1473 | (let* ((start (point)) | ||
| 1474 | (end (progn (hif-end-of-line) (point))) | ||
| 1475 | (hif-simple-token-only nil) ;; Dynamic binding | ||
| 1476 | (tokens | ||
| 1477 | (and name | ||
| 1478 | ;; `hif-simple-token-only' is set/clear | ||
| 1479 | ;; only in this block | ||
| 1480 | (condition-case nil | ||
| 1481 | ;; Prevent C statements like | ||
| 1482 | ;; 'do { ... } while (0)' | ||
| 1483 | (hif-tokenize start end) | ||
| 1484 | (error | ||
| 1485 | ;; We can't just return nil here since | ||
| 1486 | ;; this will stop hideif from searching | ||
| 1487 | ;; for more #defines. | ||
| 1488 | (setq hif-simple-token-only t) | ||
| 1489 | (buffer-substring-no-properties | ||
| 1490 | start end))))) | ||
| 1491 | ;; For simple tokens we save only the parsed result; | ||
| 1492 | ;; otherwise we save the tokens and parse it after | ||
| 1493 | ;; parameter replacement | ||
| 1494 | (expr (and tokens | ||
| 1495 | ;; `hif-simple-token-only' is checked only | ||
| 1496 | ;; here. | ||
| 1497 | (or (and hif-simple-token-only | ||
| 1498 | (listp tokens) | ||
| 1499 | (= (length tokens) 1) | ||
| 1500 | (hif-parse-exp tokens)) | ||
| 1501 | `(hif-define-macro ,parmlist | ||
| 1502 | ,tokens)))) | ||
| 1503 | (SA (and name | ||
| 1504 | (assoc (intern name) hide-ifdef-env)))) | ||
| 1505 | (and name | ||
| 1506 | (if SA | ||
| 1507 | (or (setcdr SA expr) t) | ||
| 1508 | ;; Lazy evaluation, eval only if hif-lookup find it. | ||
| 1509 | ;; Define it anyway, even if nil it's still in list | ||
| 1510 | ;; and therefore considerred defined | ||
| 1511 | (push (cons (intern name) expr) hide-ifdef-env))))) | ||
| 1512 | ;; #undef | ||
| 1513 | (and name | ||
| 1514 | (hif-undefine-symbol (intern name)))))) | ||
| 1515 | t)) | ||
| 1516 | |||
| 1517 | |||
| 1518 | (defun hif-add-new-defines (&optional min max) | ||
| 1519 | "Scan and add all #define macros between MIN and MAX" | ||
| 1520 | (interactive) | ||
| 1521 | (save-excursion | ||
| 1522 | (save-restriction | ||
| 1523 | ;; (mark-region min max) ;; for debugging | ||
| 1524 | (while (hif-find-define min max) | ||
| 1525 | (setf min (point))) | ||
| 1526 | (if max (goto-char max) | ||
| 1527 | (goto-char (point-max)))))) | ||
| 1026 | 1528 | ||
| 1027 | (defun hide-ifdef-guts () | 1529 | (defun hide-ifdef-guts () |
| 1028 | "Does most of the work of `hide-ifdefs'. | 1530 | "Does most of the work of `hide-ifdefs'. |
| 1029 | It does not do the work that's pointless to redo on a recursive entry." | 1531 | It does not do the work that's pointless to redo on a recursive entry." |
| 1030 | ;; (message "hide-ifdef-guts") | 1532 | ;; (message "hide-ifdef-guts") |
| 1031 | (save-excursion | 1533 | (save-excursion |
| 1534 | (let ((case-fold-search nil) | ||
| 1535 | min max) | ||
| 1032 | (goto-char (point-min)) | 1536 | (goto-char (point-min)) |
| 1033 | (while (hif-find-any-ifX) | 1537 | (setf min (point)) |
| 1034 | (hif-possibly-hide)))) | 1538 | (loop do |
| 1539 | (setf max (hif-find-any-ifX)) | ||
| 1540 | (hif-add-new-defines min max) | ||
| 1541 | (if max | ||
| 1542 | (hif-possibly-hide)) | ||
| 1543 | (setf min (point)) | ||
| 1544 | while max)))) | ||
| 1035 | 1545 | ||
| 1036 | ;;===%%SF%% hide-ifdef-hiding (End) === | 1546 | ;;===%%SF%% hide-ifdef-hiding (End) === |
| 1037 | 1547 | ||
| @@ -1045,7 +1555,8 @@ It does not do the work that's pointless to redo on a recursive entry." | |||
| 1045 | (message "Hide-Read-Only %s" | 1555 | (message "Hide-Read-Only %s" |
| 1046 | (if hide-ifdef-read-only "ON" "OFF")) | 1556 | (if hide-ifdef-read-only "ON" "OFF")) |
| 1047 | (if hide-ifdef-hiding | 1557 | (if hide-ifdef-hiding |
| 1048 | (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only))) | 1558 | (setq buffer-read-only (or hide-ifdef-read-only |
| 1559 | hif-outside-read-only))) | ||
| 1049 | (force-mode-line-update)) | 1560 | (force-mode-line-update)) |
| 1050 | 1561 | ||
| 1051 | (defun hide-ifdef-toggle-outside-read-only () | 1562 | (defun hide-ifdef-toggle-outside-read-only () |
| @@ -1081,12 +1592,32 @@ It does not do the work that's pointless to redo on a recursive entry." | |||
| 1081 | (hif-set-var var 1) | 1592 | (hif-set-var var 1) |
| 1082 | (if hide-ifdef-hiding (hide-ifdefs))) | 1593 | (if hide-ifdef-hiding (hide-ifdefs))) |
| 1083 | 1594 | ||
| 1084 | (defun hide-ifdef-undef (var) | 1595 | (defun hif-undefine-symbol (var) |
| 1085 | "Undefine a VAR so that #ifdef VAR would not be included." | 1596 | (setq hide-ifdef-env |
| 1086 | (interactive "SUndefine what? ") | 1597 | (delete (assoc var hide-ifdef-env) hide-ifdef-env))) |
| 1087 | (hif-set-var var nil) | ||
| 1088 | (if hide-ifdef-hiding (hide-ifdefs))) | ||
| 1089 | 1598 | ||
| 1599 | ;;(defun hide-ifdef-undef (var) | ||
| 1600 | ;; "Undefine a VAR so that #ifdef VAR would not be included." | ||
| 1601 | ;; (interactive "SUndefine what? ") | ||
| 1602 | ;; ;;(hif-set-var var nil);;Luke fixed: set it nil is still considered | ||
| 1603 | ;; ;;defined so #ifdef VAR is still true. | ||
| 1604 | ;; (hif-undefine-symbol var) | ||
| 1605 | ;; (if hide-ifdef-hiding (hide-ifdefs))) | ||
| 1606 | |||
| 1607 | (defun hide-ifdef-undef (start end) | ||
| 1608 | "Undefine a VAR so that #ifdef VAR would not be included." | ||
| 1609 | (interactive "r") | ||
| 1610 | (let* ((symstr | ||
| 1611 | (or (and mark-active | ||
| 1612 | (buffer-substring-no-properties start end)) | ||
| 1613 | (read-string "Undefine what? " (current-word)))) | ||
| 1614 | (sym (and symstr | ||
| 1615 | (intern symstr)))) | ||
| 1616 | (if (zerop (hif-defined sym)) | ||
| 1617 | (message "`%s' not defined, no need to undefine it" symstr) | ||
| 1618 | (hif-undefine-symbol sym) | ||
| 1619 | (if hide-ifdef-hiding (hide-ifdefs)) | ||
| 1620 | (message "`%S' undefined" sym)))) | ||
| 1090 | 1621 | ||
| 1091 | (defun hide-ifdefs (&optional nomsg) | 1622 | (defun hide-ifdefs (&optional nomsg) |
| 1092 | "Hide the contents of some #ifdefs. | 1623 | "Hide the contents of some #ifdefs. |