hideif.el 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003
  1. ;;; hideif.el --- hides selected code within ifdef -*- lexical-binding:t -*-
  2. ;; Copyright (C) 1988, 1994, 2001-2015 Free Software Foundation, Inc.
  3. ;; Author: Brian Marick
  4. ;; Daniel LaLiberte <liberte@holonexus.org>
  5. ;; Maintainer: Luke Lee <luke.yx.lee@gmail.com>
  6. ;; Keywords: c, outlines
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; To initialize, toggle the hide-ifdef minor mode with
  20. ;;
  21. ;; M-x hide-ifdef-mode
  22. ;;
  23. ;; This will set up key bindings and call hide-ifdef-mode-hook if it
  24. ;; has a value. To explicitly hide ifdefs using a buffer-local
  25. ;; define list (default empty), type
  26. ;;
  27. ;; M-x hide-ifdefs or C-c @ h
  28. ;;
  29. ;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't
  30. ;; pass through. Support complete C/C++ expression and precedence.
  31. ;; It will automatically scan for new #define symbols and macros on the way
  32. ;; parsing.
  33. ;;
  34. ;; The hidden code is marked by ellipses (...). Be
  35. ;; cautious when editing near ellipses, since the hidden text is
  36. ;; still in the buffer, and you can move the point into it and modify
  37. ;; text unawares.
  38. ;; You can make your buffer read-only while hide-ifdef-hiding by setting
  39. ;; hide-ifdef-read-only to a non-nil value. You can toggle this
  40. ;; variable with hide-ifdef-toggle-read-only (C-c @ C-q).
  41. ;;
  42. ;; You can undo the effect of hide-ifdefs by typing
  43. ;;
  44. ;; M-x show-ifdefs or C-c @ s
  45. ;;
  46. ;; Use M-x hide-ifdef-define (C-c @ d) to define a symbol.
  47. ;; Use M-x hide-ifdef-undef (C-c @ u) to undefine a symbol.
  48. ;;
  49. ;; If you define or undefine a symbol while hide-ifdef-mode is in effect,
  50. ;; the display will be updated. Only the define list for the current
  51. ;; buffer will be affected. You can save changes to the local define
  52. ;; list with hide-ifdef-set-define-alist. This adds entries
  53. ;; to hide-ifdef-define-alist.
  54. ;;
  55. ;; If you have defined a hide-ifdef-mode-hook, you can set
  56. ;; up a list of symbols that may be used by hide-ifdefs as in the
  57. ;; following example:
  58. ;;
  59. ;; (add-hook 'hide-ifdef-mode-hook
  60. ;; (lambda ()
  61. ;; (unless hide-ifdef-define-alist
  62. ;; (setq hide-ifdef-define-alist
  63. ;; '((list1 ONE TWO)
  64. ;; (list2 TWO THREE))))
  65. ;; (hide-ifdef-use-define-alist 'list2))) ; use list2 by default
  66. ;;
  67. ;; You can call hide-ifdef-use-define-alist (C-c @ U) at any time to specify
  68. ;; another list to use.
  69. ;;
  70. ;; To cause ifdefs to be hidden as soon as hide-ifdef-mode is called,
  71. ;; set hide-ifdef-initially to non-nil.
  72. ;;
  73. ;; If you set hide-ifdef-lines to t, hide-ifdefs hides all the #ifdef lines.
  74. ;; In the absence of highlighting, that might be a bad idea. If you set
  75. ;; hide-ifdef-lines to nil (the default), the surrounding preprocessor
  76. ;; lines will be displayed. That can be confusing in its own
  77. ;; right. Other variations on display are possible, but not much
  78. ;; better.
  79. ;;
  80. ;; You can explicitly hide or show individual ifdef blocks irrespective
  81. ;; of the define list by using hide-ifdef-block and show-ifdef-block.
  82. ;;
  83. ;; You can move the point between ifdefs with forward-ifdef, backward-ifdef,
  84. ;; up-ifdef, down-ifdef, next-ifdef, and previous-ifdef.
  85. ;;
  86. ;; If you have minor-mode-alist in your mode line (the default) two labels
  87. ;; may appear. "Ifdef" will appear when hide-ifdef-mode is active. "Hiding"
  88. ;; will appear when text may be hidden ("hide-ifdef-hiding" is non-nil).
  89. ;;
  90. ;; Written by Brian Marick, at Gould, Computer Systems Division, Urbana IL.
  91. ;; Extensively modified by Daniel LaLiberte (while at Gould).
  92. ;;
  93. ;; Extensively modified by Luke Lee in 2013 to support complete C expression
  94. ;; evaluation and argumented macro expansion.
  95. ;;; Code:
  96. (require 'cc-mode)
  97. (require 'cl-lib)
  98. (defgroup hide-ifdef nil
  99. "Hide selected code within `ifdef'."
  100. :group 'c)
  101. (defcustom hide-ifdef-initially nil
  102. "Non-nil means call `hide-ifdefs' when Hide-Ifdef mode is first activated."
  103. :type 'boolean
  104. :group 'hide-ifdef)
  105. (defcustom hide-ifdef-read-only nil
  106. "Set to non-nil if you want buffer to be read-only while hiding text."
  107. :type 'boolean
  108. :group 'hide-ifdef)
  109. (defcustom hide-ifdef-lines nil
  110. "Non-nil means hide the #ifX, #else, and #endif lines."
  111. :type 'boolean
  112. :group 'hide-ifdef)
  113. (defcustom hide-ifdef-shadow nil
  114. "Non-nil means shadow text instead of hiding it."
  115. :type 'boolean
  116. :group 'hide-ifdef
  117. :version "23.1")
  118. (defface hide-ifdef-shadow '((t (:inherit shadow)))
  119. "Face for shadowing ifdef blocks."
  120. :group 'hide-ifdef
  121. :version "23.1")
  122. (defcustom hide-ifdef-exclude-define-regexp nil
  123. "Ignore #define names if those names match this exclusion pattern."
  124. :type 'string
  125. :version "25.1")
  126. (defcustom hide-ifdef-expand-reinclusion-protection t
  127. "Non-nil means don't hide an entire header file enclosed by #ifndef...#endif.
  128. Most C/C++ headers are usually wrapped with ifdefs to prevent re-inclusion:
  129. ----- beginning of file -----
  130. #ifndef _XXX_HEADER_FILE_INCLUDED_
  131. #define _XXX_HEADER_FILE_INCLUDED_
  132. xxx
  133. xxx
  134. xxx...
  135. #endif
  136. ----- end of file -----
  137. The first time we visit such a file, _XXX_HEADER_FILE_INCLUDED_ is
  138. undefined, and so nothing is hidden. The next time we visit it, everything will
  139. be hidden.
  140. This behavior is generally undesirable. If this option is non-nil, the outermost
  141. #if is always visible."
  142. :type 'boolean
  143. :version "25.1")
  144. (defcustom hide-ifdef-header-regexp
  145. "\\.h\\(h\\|xx\\|pp\\)?\\'"
  146. "C/C++ header file name patterns to determine if current buffer is a header.
  147. Effective only if `hide-ifdef-expand-reinclusion-protection' is t."
  148. :type 'string
  149. :group 'hide-ifdef
  150. :version "25.1")
  151. (defvar hide-ifdef-mode-submap
  152. ;; Set up the submap that goes after the prefix key.
  153. (let ((map (make-sparse-keymap)))
  154. (define-key map "d" 'hide-ifdef-define)
  155. (define-key map "u" 'hide-ifdef-undef)
  156. (define-key map "D" 'hide-ifdef-set-define-alist)
  157. (define-key map "U" 'hide-ifdef-use-define-alist)
  158. (define-key map "h" 'hide-ifdefs)
  159. (define-key map "s" 'show-ifdefs)
  160. (define-key map "\C-d" 'hide-ifdef-block)
  161. (define-key map "\C-s" 'show-ifdef-block)
  162. (define-key map "e" 'hif-evaluate-macro)
  163. (define-key map "C" 'hif-clear-all-ifdef-defined)
  164. (define-key map "\C-q" 'hide-ifdef-toggle-read-only)
  165. (define-key map "\C-w" 'hide-ifdef-toggle-shadowing)
  166. (substitute-key-definition
  167. 'read-only-mode 'hide-ifdef-toggle-outside-read-only map)
  168. ;; `toggle-read-only' is obsoleted by `read-only-mode'.
  169. (substitute-key-definition
  170. 'toggle-read-only 'hide-ifdef-toggle-outside-read-only map)
  171. map)
  172. "Keymap used by `hide-ifdef-mode' under `hide-ifdef-mode-prefix-key'.")
  173. (defconst hide-ifdef-mode-prefix-key "\C-c@"
  174. "Prefix key for all Hide-Ifdef mode commands.")
  175. (defvar hide-ifdef-mode-map
  176. ;; Set up the mode's main map, which leads via the prefix key to the submap.
  177. (let ((map (make-sparse-keymap)))
  178. (define-key map hide-ifdef-mode-prefix-key hide-ifdef-mode-submap)
  179. map)
  180. "Keymap used with `hide-ifdef-mode'.")
  181. (easy-menu-define hide-ifdef-mode-menu hide-ifdef-mode-map
  182. "Menu for `hide-ifdef-mode'."
  183. '("Hide-Ifdef"
  184. ["Hide some ifdefs" hide-ifdefs
  185. :help "Hide the contents of some #ifdefs"]
  186. ["Show all ifdefs" show-ifdefs
  187. :help "Cancel the effects of `hide-ifdef': show the contents of all #ifdefs"]
  188. ["Hide ifdef block" hide-ifdef-block
  189. :help "Hide the ifdef block (true or false part) enclosing or before the cursor"]
  190. ["Show ifdef block" show-ifdef-block
  191. :help "Show the ifdef block (true or false part) enclosing or before the cursor"]
  192. ["Define a variable..." hide-ifdef-define
  193. :help "Define a VAR so that #ifdef VAR would be included"]
  194. ["Undefine a variable..." hide-ifdef-undef
  195. :help "Undefine a VAR so that #ifdef VAR would not be included"]
  196. ["Define an alist..." hide-ifdef-set-define-alist
  197. :help "Set the association for NAME to `hide-ifdef-env'"]
  198. ["Use an alist..." hide-ifdef-use-define-alist
  199. :help "Set `hide-ifdef-env' to the define list specified by NAME"]
  200. ["Toggle read only" hide-ifdef-toggle-read-only
  201. :style toggle :selected hide-ifdef-read-only
  202. :help "Buffer should be read-only while hiding text"]
  203. ["Toggle shadowing" hide-ifdef-toggle-shadowing
  204. :style toggle :selected hide-ifdef-shadow
  205. :help "Text should be shadowed instead of hidden"]))
  206. (defvar hide-ifdef-hiding nil
  207. "Non-nil when text may be hidden.")
  208. (or (assq 'hide-ifdef-hiding minor-mode-alist)
  209. (setq minor-mode-alist
  210. (cons '(hide-ifdef-hiding " Hiding")
  211. minor-mode-alist)))
  212. ;; Fix c-mode syntax table so we can recognize whole symbols.
  213. (defvar hide-ifdef-syntax-table
  214. (let ((st (copy-syntax-table c-mode-syntax-table)))
  215. (modify-syntax-entry ?_ "w" st)
  216. (modify-syntax-entry ?& "." st)
  217. (modify-syntax-entry ?\| "." st)
  218. st)
  219. "Syntax table used for tokenizing #if expressions.")
  220. (defvar hide-ifdef-env nil
  221. "An alist of defined symbols and their values.")
  222. (defvar hide-ifdef-env-backup nil
  223. "This variable is a backup of the previously cleared `hide-ifdef-env'.
  224. This backup prevents any accidental clearance of `hide-fidef-env' by
  225. `hif-clear-all-ifdef-defined'.")
  226. (defvar hif-outside-read-only nil
  227. "Internal variable. Saves the value of `buffer-read-only' while hiding.")
  228. ;;;###autoload
  229. (define-minor-mode hide-ifdef-mode
  230. "Toggle features to hide/show #ifdef blocks (Hide-Ifdef mode).
  231. With a prefix argument ARG, enable Hide-Ifdef mode if ARG is
  232. positive, and disable it otherwise. If called from Lisp, enable
  233. the mode if ARG is omitted or nil.
  234. Hide-Ifdef mode is a buffer-local minor mode for use with C and
  235. C-like major modes. When enabled, code within #ifdef constructs
  236. that the C preprocessor would eliminate may be hidden from view.
  237. Several variables affect how the hiding is done:
  238. `hide-ifdef-env'
  239. An association list of defined and undefined symbols for the
  240. current project. Initially, the global value of `hide-ifdef-env'
  241. is used. This variable was a buffer-local variable, which limits
  242. hideif to parse only one C/C++ file at a time. We've extended
  243. hideif to support parsing a C/C++ project containing multiple C/C++
  244. source files opened simultaneously in different buffers. Therefore
  245. `hide-ifdef-env' can no longer be buffer local but must be global.
  246. `hide-ifdef-define-alist'
  247. An association list of defined symbol lists.
  248. Use `hide-ifdef-set-define-alist' to save the current `hide-ifdef-env'
  249. and `hide-ifdef-use-define-alist' to set the current `hide-ifdef-env'
  250. from one of the lists in `hide-ifdef-define-alist'.
  251. `hide-ifdef-lines'
  252. Set to non-nil to not show #if, #ifdef, #ifndef, #else, and
  253. #endif lines when hiding.
  254. `hide-ifdef-initially'
  255. Indicates whether `hide-ifdefs' should be called when Hide-Ifdef mode
  256. is activated.
  257. `hide-ifdef-read-only'
  258. Set to non-nil if you want to make buffers read only while hiding.
  259. After `show-ifdefs', read-only status is restored to previous value.
  260. \\{hide-ifdef-mode-map}"
  261. :group 'hide-ifdef :lighter " Ifdef"
  262. (if hide-ifdef-mode
  263. (progn
  264. ;; inherit global values
  265. ;; `hide-ifdef-env' is now a global variable.
  266. ;; We can still simulate the behavior of older hideif versions (i.e.
  267. ;; `hide-ifdef-env' being buffer local) by clearing this variable
  268. ;; (C-c @ C) everytime before hiding current buffer.
  269. ;; (set (make-local-variable 'hide-ifdef-env)
  270. ;; (default-value 'hide-ifdef-env))
  271. (set 'hide-ifdef-env (default-value 'hide-ifdef-env))
  272. ;; Some C/C++ headers might have other ways to prevent reinclusion and
  273. ;; thus would like `hide-ifdef-expand-reinclusion-protection' to be nil.
  274. (set (make-local-variable 'hide-ifdef-expand-reinclusion-protection)
  275. (default-value 'hide-ifdef-expand-reinclusion-protection))
  276. (set (make-local-variable 'hide-ifdef-hiding)
  277. (default-value 'hide-ifdef-hiding))
  278. (set (make-local-variable 'hif-outside-read-only) buffer-read-only)
  279. (set (make-local-variable 'line-move-ignore-invisible) t)
  280. (add-hook 'change-major-mode-hook
  281. (lambda () (hide-ifdef-mode -1)) nil t)
  282. (add-to-invisibility-spec '(hide-ifdef . t))
  283. (if hide-ifdef-initially
  284. (hide-ifdefs)
  285. (show-ifdefs)))
  286. ;; else end hide-ifdef-mode
  287. (kill-local-variable 'line-move-ignore-invisible)
  288. (remove-from-invisibility-spec '(hide-ifdef . t))
  289. (when hide-ifdef-hiding
  290. (show-ifdefs))))
  291. (defun hif-clear-all-ifdef-defined ()
  292. "Clears all symbols defined in `hide-ifdef-env'.
  293. It will backup this variable to `hide-ifdef-env-backup' before clearing to
  294. prevent accidental clearance."
  295. (interactive)
  296. (when (y-or-n-p "Clear all #defined symbols? ")
  297. (setq hide-ifdef-env-backup hide-ifdef-env)
  298. (setq hide-ifdef-env nil)))
  299. (defun hif-show-all ()
  300. "Show all of the text in the current buffer."
  301. (interactive)
  302. (hif-show-ifdef-region (point-min) (point-max)))
  303. ;; By putting this on after-revert-hook, we arrange that it only
  304. ;; does anything when revert-buffer avoids turning off the mode.
  305. ;; (That can happen in VC.)
  306. (defun hif-after-revert-function ()
  307. (and hide-ifdef-mode hide-ifdef-hiding
  308. (hide-ifdefs t)))
  309. (add-hook 'after-revert-hook 'hif-after-revert-function)
  310. (defun hif-end-of-line ()
  311. (end-of-line)
  312. (while (= (logand 1 (skip-chars-backward "\\\\")) 1)
  313. (end-of-line 2)))
  314. (defun hif-merge-ifdef-region (start end)
  315. "This function merges nearby ifdef regions to form a bigger overlay.
  316. The region is defined by START and END. This will decrease the number of
  317. overlays created."
  318. ;; Generally there is no need to call itself recursively since there should
  319. ;; originally exists no un-merged regions; however, if a part of the file is
  320. ;; hidden with `hide-ifdef-lines' equals to nil while another part with 't,
  321. ;; this case happens.
  322. ;; TODO: Should we merge? or just create a container overlay? -- this can
  323. ;; prevent `hideif-show-ifdef' expanding too many hidden contents since there
  324. ;; is only a big overlay exists there without any smaller overlays.
  325. (save-restriction
  326. (widen) ; Otherwise `point-min' and `point-max' will be restricted and thus
  327. ; fail to find neighbor overlays
  328. (let ((begovrs (overlays-in
  329. (max (- start 2) (point-min))
  330. (max (- start 1) (point-min))))
  331. (endovrs (overlays-in
  332. (min (+ end 1) (point-max))
  333. (min (+ end 2) (point-max))))
  334. (ob nil)
  335. (oe nil)
  336. b e)
  337. ;; Merge overlays before START
  338. (dolist (o begovrs)
  339. (when (overlay-get o 'hide-ifdef)
  340. (setq b (min start (overlay-start o))
  341. e (max end (overlay-end o)))
  342. (move-overlay o b e)
  343. (hif-merge-ifdef-region b e)
  344. (setq ob o)))
  345. ;; Merge overlays after END
  346. (dolist (o endovrs)
  347. (when (overlay-get o 'hide-ifdef)
  348. (setq b (min start (overlay-start o))
  349. e (max end (overlay-end o)))
  350. (move-overlay o b e)
  351. (hif-merge-ifdef-region b e)
  352. (setf oe o)))
  353. ;; If both START and END merging happens, merge into bigger one
  354. (when (and ob oe)
  355. (let ((b (min (overlay-start ob) (overlay-start oe)))
  356. (e (max (overlay-end ob) (overlay-end oe))))
  357. (delete-overlay oe)
  358. (move-overlay ob b e)
  359. (hif-merge-ifdef-region b e)))
  360. (or ob oe))))
  361. (defun hide-ifdef-region-internal (start end)
  362. (unless (hif-merge-ifdef-region start end)
  363. (let ((o (make-overlay start end)))
  364. (overlay-put o 'hide-ifdef t)
  365. (if hide-ifdef-shadow
  366. (overlay-put o 'face 'hide-ifdef-shadow)
  367. (overlay-put o 'invisible 'hide-ifdef)))))
  368. (defun hide-ifdef-region (start end)
  369. "START is the start of a #if, #elif, or #else form. END is the ending part.
  370. Everything including these lines is made invisible."
  371. (save-excursion
  372. (goto-char start) (hif-end-of-line) (setq start (point))
  373. (goto-char end) (hif-end-of-line) (setq end (point))
  374. (hide-ifdef-region-internal start end)))
  375. (defun hif-show-ifdef-region (start end)
  376. "Everything between START and END is made visible."
  377. (let ((onum (length (overlays-in start end))))
  378. (remove-overlays start end 'hide-ifdef t)
  379. (/= onum (length (overlays-in start end)))))
  380. ;;===%%SF%% evaluation (Start) ===
  381. ;; It is not useful to set this to anything but `eval'.
  382. ;; In fact, the variable might as well be eliminated.
  383. (defvar hide-ifdef-evaluator 'eval
  384. "The function to use to evaluate a form.
  385. The evaluator is given a canonical form and returns t if text under
  386. that form should be displayed.")
  387. (defvar hif-undefined-symbol nil
  388. "...is by default considered to be false.")
  389. (defun hif-set-var (var value)
  390. "Prepend (VAR VALUE) pair to `hide-ifdef-env'."
  391. (setq hide-ifdef-env (cons (cons var value) hide-ifdef-env)))
  392. (declare-function semantic-c-hideif-lookup "semantic/bovine/c" (var))
  393. (declare-function semantic-c-hideif-defined "semantic/bovine/c" (var))
  394. (defun hif-lookup (var)
  395. (or (when (bound-and-true-p semantic-c-takeover-hideif)
  396. (semantic-c-hideif-lookup var))
  397. (let ((val (assoc var hide-ifdef-env)))
  398. (if val
  399. (cdr val)
  400. hif-undefined-symbol))))
  401. (defun hif-defined (var)
  402. (cond
  403. ((bound-and-true-p semantic-c-takeover-hideif)
  404. (semantic-c-hideif-defined var))
  405. ((assoc var hide-ifdef-env) 1)
  406. (t 0)))
  407. ;;===%%SF%% evaluation (End) ===
  408. ;;===%%SF%% parsing (Start) ===
  409. ;;; The code that understands what ifs and ifdef in files look like.
  410. (defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*")
  411. (defconst hif-ifxdef-regexp (concat hif-cpp-prefix "if\\(n\\)?def"))
  412. (defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef"))
  413. (defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+"))
  414. (defconst hif-elif-regexp (concat hif-cpp-prefix "elif"))
  415. (defconst hif-else-regexp (concat hif-cpp-prefix "else"))
  416. (defconst hif-endif-regexp (concat hif-cpp-prefix "endif"))
  417. (defconst hif-ifx-else-endif-regexp
  418. (concat hif-ifx-regexp "\\|" hif-elif-regexp "\\|" hif-else-regexp "\\|"
  419. hif-endif-regexp))
  420. (defconst hif-macro-expr-prefix-regexp
  421. (concat hif-cpp-prefix "\\(if\\(n?def\\)?\\|elif\\|define\\)[ \t]+"))
  422. (defconst hif-white-regexp "[ \t]*")
  423. (defconst hif-define-regexp (concat hif-cpp-prefix "\\(define\\|undef\\)"))
  424. (defconst hif-id-regexp (concat "[[:alpha:]_][[:alnum:]_]*"))
  425. (defconst hif-macroref-regexp
  426. (concat hif-white-regexp "\\(" hif-id-regexp "\\)" hif-white-regexp
  427. "\\("
  428. "(" hif-white-regexp
  429. "\\(" hif-id-regexp "\\)?" hif-white-regexp
  430. "\\(" "," hif-white-regexp hif-id-regexp hif-white-regexp "\\)*"
  431. "\\(\\.\\.\\.\\)?" hif-white-regexp
  432. ")"
  433. "\\)?" ))
  434. ;; Store the current token and the whole token list during parsing.
  435. ;; Bound dynamically.
  436. (defvar hif-token)
  437. (defvar hif-token-list)
  438. (defconst hif-token-alist
  439. '(("||" . hif-or)
  440. ("&&" . hif-and)
  441. ("|" . hif-logior)
  442. ("^" . hif-logxor)
  443. ("&" . hif-logand)
  444. ("<<" . hif-shiftleft)
  445. (">>" . hif-shiftright)
  446. ("==" . hif-equal)
  447. ;; Note: we include tokens like `=' which aren't supported by CPP's
  448. ;; expression syntax, because they are still relevant for the tokenizer,
  449. ;; especially in conjunction with ##.
  450. ("=" . hif-assign)
  451. ("!=" . hif-notequal)
  452. ("##" . hif-token-concat)
  453. ("!" . hif-not)
  454. ("~" . hif-lognot)
  455. ("(" . hif-lparen)
  456. (")" . hif-rparen)
  457. (">" . hif-greater)
  458. ("<" . hif-less)
  459. (">=" . hif-greater-equal)
  460. ("<=" . hif-less-equal)
  461. ("+" . hif-plus)
  462. ("-" . hif-minus)
  463. ("*" . hif-multiply)
  464. ("/" . hif-divide)
  465. ("%" . hif-modulo)
  466. ("?" . hif-conditional)
  467. (":" . hif-colon)
  468. ("," . hif-comma)
  469. ("#" . hif-stringify)
  470. ("..." . hif-etc)))
  471. (defconst hif-valid-token-list (mapcar 'cdr hif-token-alist))
  472. (defconst hif-token-regexp
  473. (concat (regexp-opt (mapcar 'car hif-token-alist))
  474. "\\|0x[0-9a-fA-F]+\\.?[0-9a-fA-F]*"
  475. "\\|[0-9]+\\.?[0-9]*" ;; decimal/octal
  476. "\\|\\w+"))
  477. (defconst hif-string-literal-regexp "\\(\"\\(?:[^\"\\]\\|\\\\.\\)*\"\\)")
  478. (defun hif-string-to-number (string &optional base)
  479. "Like `string-to-number', but it understands non-decimal floats."
  480. (if (or (not base) (= base 10))
  481. (string-to-number string base)
  482. (let* ((parts (split-string string "\\." t "[ \t]+"))
  483. (frac (cadr parts))
  484. (fraclen (length frac))
  485. (quot (expt (if (zerop fraclen)
  486. base
  487. (* base 1.0)) fraclen)))
  488. (/ (string-to-number (concat (car parts) frac) base) quot))))
  489. ;; The dynamic binding variable `hif-simple-token-only' is shared only by
  490. ;; `hif-tokenize' and `hif-find-define'. The purpose is to prevent `hif-tokenize'
  491. ;; from returning one more value to indicate a simple token is scanned. This help
  492. ;; speeding up macro evaluation on those very simple cases like integers or
  493. ;; literals.
  494. ;; Check the long comments before `hif-find-define' for more details. [lukelee]
  495. (defvar hif-simple-token-only)
  496. (defun hif-tokenize (start end)
  497. "Separate string between START and END into a list of tokens."
  498. (let ((token-list nil))
  499. (setq hif-simple-token-only t)
  500. (with-syntax-table hide-ifdef-syntax-table
  501. (save-excursion
  502. (goto-char start)
  503. (while (progn (forward-comment (point-max)) (< (point) end))
  504. ;; (message "expr-start = %d" expr-start) (sit-for 1)
  505. (cond
  506. ((looking-at "\\\\\n")
  507. (forward-char 2))
  508. ((looking-at hif-string-literal-regexp)
  509. (push (substring-no-properties (match-string 1)) token-list)
  510. (goto-char (match-end 0)))
  511. ((looking-at hif-token-regexp)
  512. (let ((token (buffer-substring-no-properties
  513. (point) (match-end 0))))
  514. (goto-char (match-end 0))
  515. ;; (message "token: %s" token) (sit-for 1)
  516. (push
  517. (or (cdr (assoc token hif-token-alist))
  518. (if (string-equal token "defined") 'hif-defined)
  519. ;; TODO:
  520. ;; 1. postfix 'l', 'll', 'ul' and 'ull'
  521. ;; 2. floating number formats (like 1.23e4)
  522. ;; 3. 098 is interpreted as octal conversion error
  523. (if (string-match "0x\\([0-9a-fA-F]+\\.?[0-9a-fA-F]*\\)"
  524. token)
  525. (hif-string-to-number (match-string 1 token) 16)) ;; hex
  526. (if (string-match "\\`0[0-9]+\\(\\.[0-9]+\\)?\\'" token)
  527. (hif-string-to-number token 8)) ;; octal
  528. (if (string-match "\\`[1-9][0-9]*\\(\\.[0-9]+\\)?\\'"
  529. token)
  530. (string-to-number token)) ;; decimal
  531. (prog1 (intern token)
  532. (setq hif-simple-token-only nil)))
  533. token-list)))
  534. ((looking-at "\r") ; Sometimes MS-Windows user will leave CR in
  535. (forward-char 1)) ; the source code. Let's not get stuck here.
  536. (t (error "Bad #if expression: %s" (buffer-string)))))))
  537. (nreverse token-list)))
  538. ;;------------------------------------------------------------------------
  539. ;; Translate C preprocessor #if expressions using recursive descent.
  540. ;; This parser was limited to the operators &&, ||, !, and "defined".
  541. ;; Added ==, !=, +, and -. Gary Oberbrunner, garyo@avs.com, 8/9/94
  542. ;;
  543. ;; Implement the C language operator precedence table. Add all those
  544. ;; missing operators that could be used in macros. Luke Lee 2013-09-04
  545. ;; | Operator Type | Operator | Associativity |
  546. ;; +----------------------+-----------------------------+---------------+
  547. ;; | Primary Expression | () [] . -> expr++ expr-- | left-to-right |
  548. ;; | Unary Operators | * & + - ! ~ ++expr --expr | right-to-left |
  549. ;; | | (typecast) sizeof | |
  550. ;; | Binary Operators | * / % | left-to-right |
  551. ;; | | + - | |
  552. ;; | | >> << | |
  553. ;; | | < > <= >= | |
  554. ;; | | == != | |
  555. ;; | | & | |
  556. ;; | | ^ | |
  557. ;; | | | | |
  558. ;; | | && | |
  559. ;; | | || | |
  560. ;; | Ternary Operator | ?: | right-to-left |
  561. ;; x| Assignment Operators | = += -= *= /= %= >>= <<= &= | right-to-left |
  562. ;; | | ^= = | |
  563. ;; | Comma | , | left-to-right |
  564. (defsubst hif-nexttoken ()
  565. "Pop the next token from token-list into the let variable `hif-token'."
  566. (setq hif-token (pop hif-token-list)))
  567. (defsubst hif-if-valid-identifier-p (id)
  568. (not (or (numberp id)
  569. (stringp id))))
  570. (defun hif-define-operator (tokens)
  571. "`Upgrade' hif-define xxx to '(hif-define xxx)' so it won't be substituted."
  572. (let ((result nil)
  573. (tok nil))
  574. (while (setq tok (pop tokens))
  575. (push
  576. (if (eq tok 'hif-defined)
  577. (progn
  578. (setq tok (cadr tokens))
  579. (if (eq (car tokens) 'hif-lparen)
  580. (if (and (hif-if-valid-identifier-p tok)
  581. (eq (nth 2 tokens) 'hif-rparen))
  582. (setq tokens (cl-cdddr tokens))
  583. (error "#define followed by non-identifier: %S" tok))
  584. (setq tok (car tokens)
  585. tokens (cdr tokens))
  586. (unless (hif-if-valid-identifier-p tok)
  587. (error "#define followed by non-identifier: %S" tok)))
  588. (list 'hif-defined 'hif-lparen tok 'hif-rparen))
  589. tok)
  590. result))
  591. (nreverse result)))
  592. (defun hif-flatten (l)
  593. "Flatten a tree."
  594. (apply #'nconc
  595. (mapcar (lambda (x) (if (listp x)
  596. (hif-flatten x)
  597. (list x))) l)))
  598. (defun hif-expand-token-list (tokens &optional macroname expand_list)
  599. "Perform expansion on TOKENS till everything expanded.
  600. Self-reference (directly or indirectly) tokens are not expanded.
  601. EXPAND_LIST is the list of macro names currently being expanded, used for
  602. detecting self-reference."
  603. (catch 'self-referencing
  604. (let ((expanded nil)
  605. (remains (hif-define-operator
  606. (hif-token-concatenation
  607. (hif-token-stringification tokens))))
  608. tok rep)
  609. (if macroname
  610. (setq expand_list (cons macroname expand_list)))
  611. ;; Expanding all tokens till list exhausted
  612. (while (setq tok (pop remains))
  613. (if (memq tok expand_list)
  614. ;; For self-referencing tokens, don't expand it
  615. (throw 'self-referencing tokens))
  616. (push
  617. (cond
  618. ((or (memq tok hif-valid-token-list)
  619. (numberp tok)
  620. (stringp tok))
  621. tok)
  622. ((setq rep (hif-lookup tok))
  623. (if (and (listp rep)
  624. (eq (car rep) 'hif-define-macro)) ; A defined macro
  625. ;; Recursively expand it
  626. (if (cadr rep) ; Argument list is not nil
  627. (if (not (eq (car remains) 'hif-lparen))
  628. ;; No argument, no invocation
  629. tok
  630. ;; Argumented macro, get arguments and invoke it.
  631. ;; Dynamically bind hif-token-list and hif-token
  632. ;; for hif-macro-supply-arguments
  633. (let* ((hif-token-list (cdr remains))
  634. (hif-token nil)
  635. (parmlist (mapcar #'hif-expand-token-list
  636. (hif-get-argument-list)))
  637. (result
  638. (hif-expand-token-list
  639. (hif-macro-supply-arguments tok parmlist)
  640. tok expand_list)))
  641. (setq remains (cons hif-token hif-token-list))
  642. result))
  643. ;; Argument list is nil, direct expansion
  644. (setq rep (hif-expand-token-list
  645. (nth 2 rep) ; Macro's token list
  646. tok expand_list))
  647. ;; Replace all remaining references immediately
  648. (setq remains (cl-substitute tok rep remains))
  649. rep)
  650. ;; Lookup tok returns an atom
  651. rep))
  652. ;;[2013-10-22 16:06:12 +0800] Must keep the token, removing
  653. ;; this token might results in an incomplete expression that
  654. ;; cannot be parsed further.
  655. ;;((= 1 (hif-defined tok)) ; defined (hif-defined tok)=1,
  656. ;; ;;but empty (hif-lookup tok)=nil, thus remove this token
  657. ;; (setq remains (delete tok remains))
  658. ;; nil)
  659. (t ; Usual IDs
  660. tok))
  661. expanded))
  662. (hif-flatten (nreverse expanded)))))
  663. (defun hif-parse-exp (token-list &optional macroname)
  664. "Parse the TOKEN-LIST.
  665. Return translated list in prefix form. MACRONAME is applied when invoking
  666. macros to prevent self-reference."
  667. (let ((hif-token-list (hif-expand-token-list token-list macroname)))
  668. (hif-nexttoken)
  669. (prog1
  670. (and hif-token
  671. (hif-exprlist))
  672. (if hif-token ; is there still a token?
  673. (error "Error: unexpected token: %s" hif-token)))))
  674. (defun hif-exprlist ()
  675. "Parse an exprlist: expr { ',' expr}."
  676. (let ((result (hif-expr)))
  677. (if (eq hif-token 'hif-comma)
  678. (let ((temp (list result)))
  679. (while
  680. (progn
  681. (hif-nexttoken)
  682. (push (hif-expr) temp)
  683. (eq hif-token 'hif-comma)))
  684. (cons 'hif-comma (nreverse temp)))
  685. result)))
  686. (defun hif-expr ()
  687. "Parse an expression as found in #if.
  688. expr : or-expr | or-expr '?' expr ':' expr."
  689. (let ((result (hif-or-expr))
  690. middle)
  691. (while (eq hif-token 'hif-conditional)
  692. (hif-nexttoken)
  693. (setq middle (hif-expr))
  694. (if (eq hif-token 'hif-colon)
  695. (progn
  696. (hif-nexttoken)
  697. (setq result (list 'hif-conditional result middle (hif-expr))))
  698. (error "Error: unexpected token: %s" hif-token)))
  699. result))
  700. (defun hif-or-expr ()
  701. "Parse an or-expr : and-expr | or-expr '||' and-expr."
  702. (let ((result (hif-and-expr)))
  703. (while (eq hif-token 'hif-or)
  704. (hif-nexttoken)
  705. (setq result (list 'hif-or result (hif-and-expr))))
  706. result))
  707. (defun hif-and-expr ()
  708. "Parse an and-expr : logior-expr | and-expr '&&' logior-expr."
  709. (let ((result (hif-logior-expr)))
  710. (while (eq hif-token 'hif-and)
  711. (hif-nexttoken)
  712. (setq result (list 'hif-and result (hif-logior-expr))))
  713. result))
  714. (defun hif-logior-expr ()
  715. "Parse a logor-expr : logxor-expr | logor-expr '|' logxor-expr."
  716. (let ((result (hif-logxor-expr)))
  717. (while (eq hif-token 'hif-logior)
  718. (hif-nexttoken)
  719. (setq result (list 'hif-logior result (hif-logxor-expr))))
  720. result))
  721. (defun hif-logxor-expr ()
  722. "Parse a logxor-expr : logand-expr | logxor-expr '^' logand-expr."
  723. (let ((result (hif-logand-expr)))
  724. (while (eq hif-token 'hif-logxor)
  725. (hif-nexttoken)
  726. (setq result (list 'hif-logxor result (hif-logand-expr))))
  727. result))
  728. (defun hif-logand-expr ()
  729. "Parse a logand-expr : eq-expr | logand-expr '&' eq-expr."
  730. (let ((result (hif-eq-expr)))
  731. (while (eq hif-token 'hif-logand)
  732. (hif-nexttoken)
  733. (setq result (list 'hif-logand result (hif-eq-expr))))
  734. result))
  735. (defun hif-eq-expr ()
  736. "Parse an eq-expr : comp | eq-expr `=='|`!=' comp."
  737. (let ((result (hif-comp-expr))
  738. (eq-token nil))
  739. (while (memq hif-token '(hif-equal hif-notequal))
  740. (setq eq-token hif-token)
  741. (hif-nexttoken)
  742. (setq result (list eq-token result (hif-comp-expr))))
  743. result))
  744. (defun hif-comp-expr ()
  745. "Parse a comp-expr : logshift | comp-expr `<'|`>'|`>='|`<=' logshift."
  746. (let ((result (hif-logshift-expr))
  747. (comp-token nil))
  748. (while (memq hif-token '(hif-greater hif-less hif-greater-equal
  749. hif-less-equal))
  750. (setq comp-token hif-token)
  751. (hif-nexttoken)
  752. (setq result (list comp-token result (hif-logshift-expr))))
  753. result))
  754. (defun hif-logshift-expr ()
  755. "Parse a logshift : math | logshift `<<'|`>>' math."
  756. (let ((result (hif-math))
  757. (shift-token nil))
  758. (while (memq hif-token '(hif-shiftleft hif-shiftright))
  759. (setq shift-token hif-token)
  760. (hif-nexttoken)
  761. (setq result (list shift-token result (hif-math))))
  762. result))
  763. (defun hif-math ()
  764. "Parse an expression with + or -.
  765. math : muldiv | math '+|-' muldiv."
  766. (let ((result (hif-muldiv-expr))
  767. (math-op nil))
  768. (while (memq hif-token '(hif-plus hif-minus))
  769. (setq math-op hif-token)
  770. (hif-nexttoken)
  771. (setq result (list math-op result (hif-muldiv-expr))))
  772. result))
  773. (defun hif-muldiv-expr ()
  774. "Parse an expression with *,/,%.
  775. muldiv : factor | muldiv '*|/|%' factor."
  776. (let ((result (hif-factor))
  777. (math-op nil))
  778. (while (memq hif-token '(hif-multiply hif-divide hif-modulo))
  779. (setq math-op hif-token)
  780. (hif-nexttoken)
  781. (setq result (list math-op result (hif-factor))))
  782. result))
  783. (defun hif-factor ()
  784. "Parse a factor.
  785. factor : '!' factor | '~' factor | '(' expr ')' | 'defined(' id ')' |
  786. 'id(parmlist)' | strings | id."
  787. (cond
  788. ((eq hif-token 'hif-not)
  789. (hif-nexttoken)
  790. (list 'hif-not (hif-factor)))
  791. ((eq hif-token 'hif-lognot)
  792. (hif-nexttoken)
  793. (list 'hif-lognot (hif-factor)))
  794. ((eq hif-token 'hif-lparen)
  795. (hif-nexttoken)
  796. (let ((result (hif-exprlist)))
  797. (if (not (eq hif-token 'hif-rparen))
  798. (error "Bad token in parenthesized expression: %s" hif-token)
  799. (hif-nexttoken)
  800. result)))
  801. ((eq hif-token 'hif-defined)
  802. (hif-nexttoken)
  803. (let ((paren (when (eq hif-token 'hif-lparen) (hif-nexttoken) t))
  804. (ident hif-token))
  805. (if (memq hif-token '(or and not hif-defined hif-lparen hif-rparen))
  806. (error "Error: unexpected token: %s" hif-token))
  807. (when paren
  808. (hif-nexttoken)
  809. (unless (eq hif-token 'hif-rparen)
  810. (error "Error: expected \")\" after identifier")))
  811. (hif-nexttoken)
  812. `(hif-defined (quote ,ident))))
  813. ((numberp hif-token)
  814. (prog1 hif-token (hif-nexttoken)))
  815. ((stringp hif-token)
  816. (hif-string-concatenation))
  817. ;; Unary plus/minus.
  818. ((memq hif-token '(hif-minus hif-plus))
  819. (list (prog1 hif-token (hif-nexttoken)) 0 (hif-factor)))
  820. (t ; identifier
  821. (let ((ident hif-token))
  822. (hif-nexttoken)
  823. (if (eq hif-token 'hif-lparen)
  824. (hif-place-macro-invocation ident)
  825. `(hif-lookup (quote ,ident)))))))
  826. (defun hif-get-argument-list ()
  827. (let ((nest 0)
  828. (parmlist nil) ; A "token" list of parameters, will later be parsed
  829. (parm nil))
  830. (while (or (not (eq (hif-nexttoken) 'hif-rparen))
  831. (/= nest 0))
  832. (if (eq (car (last parm)) 'hif-comma)
  833. (setq parm nil))
  834. (cond
  835. ((eq hif-token 'hif-lparen)
  836. (setq nest (1+ nest)))
  837. ((eq hif-token 'hif-rparen)
  838. (setq nest (1- nest)))
  839. ((and (eq hif-token 'hif-comma)
  840. (= nest 0))
  841. (push (nreverse parm) parmlist)
  842. (setq parm nil)))
  843. (push hif-token parm))
  844. (push (nreverse parm) parmlist) ; Okay even if PARM is nil
  845. (hif-nexttoken) ; Drop the `hif-rparen', get next token
  846. (nreverse parmlist)))
  847. (defun hif-place-macro-invocation (ident)
  848. (let ((parmlist (hif-get-argument-list)))
  849. `(hif-invoke (quote ,ident) (quote ,parmlist))))
  850. (defun hif-string-concatenation ()
  851. "Parse concatenated strings: string | strings string."
  852. (let ((result (substring-no-properties hif-token)))
  853. (while (stringp (hif-nexttoken))
  854. (setq result (concat
  855. (substring result 0 -1) ; remove trailing '"'
  856. (substring hif-token 1)))) ; remove leading '"'
  857. result))
  858. (defun hif-define-macro (_parmlist _token-body)
  859. "A marker for defined macro with arguments.
  860. This macro cannot be evaluated alone without parameters input."
  861. ;;TODO: input arguments at run time, use minibuffer to query all arguments
  862. (error
  863. "Argumented macro cannot be evaluated without passing any parameter"))
  864. (defun hif-stringify (a)
  865. "Stringify a number, string or symbol."
  866. (cond
  867. ((numberp a)
  868. (number-to-string a))
  869. ((atom a)
  870. (symbol-name a))
  871. ((stringp a)
  872. (concat "\"" a "\""))
  873. (t
  874. (error "Invalid token to stringify"))))
  875. (defun intern-safe (str)
  876. (if (stringp str)
  877. (intern str)))
  878. (defun hif-token-concat (a b)
  879. "Concatenate two tokens into a longer token.
  880. Currently support only simple token concatenation. Also support weird (but
  881. valid) token concatenation like '>' ## '>' becomes '>>'. Here we take care only
  882. those that can be evaluated during preprocessing time and ignore all those that
  883. can only be evaluated at C(++) runtime (like '++', '--' and '+='...)."
  884. (if (or (memq a hif-valid-token-list)
  885. (memq b hif-valid-token-list))
  886. (let* ((ra (car (rassq a hif-token-alist)))
  887. (rb (car (rassq b hif-token-alist)))
  888. (result (and ra rb
  889. (cdr (assoc (concat ra rb) hif-token-alist)))))
  890. (or result
  891. ;;(error "Invalid token to concatenate")
  892. (error "Concatenating \"%s\" and \"%s\" does not give a valid \
  893. preprocessing token"
  894. (or ra (symbol-name a))
  895. (or rb (symbol-name b)))))
  896. (intern-safe (concat (hif-stringify a)
  897. (hif-stringify b)))))
  898. (defun hif-mathify (val)
  899. "Treat VAL as a number: if it's t or nil, use 1 or 0."
  900. (cond ((eq val t) 1)
  901. ((null val) 0)
  902. (t val)))
  903. (defun hif-conditional (a b c)
  904. (if (not (zerop (hif-mathify a))) (hif-mathify b) (hif-mathify c)))
  905. (defun hif-and (a b)
  906. (and (not (zerop (hif-mathify a))) (not (zerop (hif-mathify b)))))
  907. (defun hif-or (a b)
  908. (or (not (zerop (hif-mathify a))) (not (zerop (hif-mathify b)))))
  909. (defun hif-not (a)
  910. (zerop (hif-mathify a)))
  911. (defun hif-lognot (a)
  912. (lognot (hif-mathify a)))
  913. (defmacro hif-mathify-binop (fun)
  914. `(lambda (a b)
  915. ,(format "Like `%s' but treat t and nil as 1 and 0." fun)
  916. (,fun (hif-mathify a) (hif-mathify b))))
  917. (defun hif-shiftleft (a b)
  918. (setq a (hif-mathify a))
  919. (setq b (hif-mathify b))
  920. (if (< a 0)
  921. (ash a b)
  922. (lsh a b)))
  923. (defun hif-shiftright (a b)
  924. (setq a (hif-mathify a))
  925. (setq b (hif-mathify b))
  926. (if (< a 0)
  927. (ash a (- b))
  928. (lsh a (- b))))
  929. (defalias 'hif-multiply (hif-mathify-binop *))
  930. (defalias 'hif-divide (hif-mathify-binop /))
  931. (defalias 'hif-modulo (hif-mathify-binop %))
  932. (defalias 'hif-plus (hif-mathify-binop +))
  933. (defalias 'hif-minus (hif-mathify-binop -))
  934. (defalias 'hif-equal (hif-mathify-binop =))
  935. (defalias 'hif-notequal (hif-mathify-binop /=))
  936. (defalias 'hif-greater (hif-mathify-binop >))
  937. (defalias 'hif-less (hif-mathify-binop <))
  938. (defalias 'hif-greater-equal (hif-mathify-binop >=))
  939. (defalias 'hif-less-equal (hif-mathify-binop <=))
  940. (defalias 'hif-logior (hif-mathify-binop logior))
  941. (defalias 'hif-logxor (hif-mathify-binop logxor))
  942. (defalias 'hif-logand (hif-mathify-binop logand))
  943. (defun hif-comma (&rest expr)
  944. "Evaluate a list of EXPR, return the result of the last item."
  945. (let ((result nil))
  946. (dolist (e expr)
  947. (ignore-errors
  948. (setq result (funcall hide-ifdef-evaluator e))))
  949. result))
  950. (defun hif-token-stringification (l)
  951. "Scan token list for `hif-stringify' ('#') token and stringify the next token."
  952. (let (result)
  953. (while l
  954. (push (if (eq (car l) 'hif-stringify)
  955. (prog1
  956. (if (cadr l)
  957. (hif-stringify (cadr l))
  958. (error "No token to stringify"))
  959. (setq l (cdr l)))
  960. (car l))
  961. result)
  962. (setq l (cdr l)))
  963. (nreverse result)))
  964. (defun hif-token-concatenation (l)
  965. "Scan token list for `hif-token-concat' ('##') token and concatenate two tokens."
  966. (let ((prev nil)
  967. result)
  968. (while l
  969. (while (eq (car l) 'hif-token-concat)
  970. (unless prev
  971. (error "No token before ## to concatenate"))
  972. (unless (cdr l)
  973. (error "No token after ## to concatenate"))
  974. (setq prev (hif-token-concat prev (cadr l)))
  975. (setq l (cddr l)))
  976. (if prev
  977. (setq result (append result (list prev))))
  978. (setq prev (car l)
  979. l (cdr l)))
  980. (if prev
  981. (append result (list prev))
  982. result)))
  983. (defun hif-delimit (lis atom)
  984. (nconc (cl-mapcan (lambda (l) (list l atom))
  985. (butlast lis))
  986. (last lis)))
  987. ;; Perform token replacement:
  988. (defun hif-macro-supply-arguments (macro-name actual-parms)
  989. "Expand a macro call, replace ACTUAL-PARMS in the macro body."
  990. (let* ((SA (assoc macro-name hide-ifdef-env))
  991. (macro (and SA
  992. (cdr SA)
  993. (eq (cadr SA) 'hif-define-macro)
  994. (cddr SA)))
  995. (formal-parms (and macro (car macro)))
  996. (macro-body (and macro (cadr macro)))
  997. actual-count
  998. formal-count
  999. formal
  1000. etc)
  1001. (when (and actual-parms formal-parms macro-body)
  1002. ;; For each actual parameter, evaluate each one and associate it
  1003. ;; with an actual parameter, put it into local table and finally
  1004. ;; evaluate the macro body.
  1005. (if (setq etc (eq (car formal-parms) 'hif-etc))
  1006. ;; Take care of `hif-etc' first. Prefix `hif-comma' back if needed.
  1007. (setq formal-parms (cdr formal-parms)))
  1008. (setq formal-count (length formal-parms)
  1009. actual-count (length actual-parms))
  1010. (if (> formal-count actual-count)
  1011. (error "Too few parameters for macro %S" macro-name)
  1012. (if (< formal-count actual-count)
  1013. (or etc
  1014. (error "Too many parameters for macro %S" macro-name))))
  1015. ;; Perform token replacement on the MACRO-BODY with the parameters
  1016. (while (setq formal (pop formal-parms))
  1017. ;; Prevent repetitive substitution, thus cannot use `subst'
  1018. ;; for example:
  1019. ;; #define mac(a,b) (a+b)
  1020. ;; #define testmac mac(b,y)
  1021. ;; testmac should expand to (b+y): replace of argument a and b
  1022. ;; occurs simultaneously, not sequentially. If sequentially,
  1023. ;; according to the argument order, it will become:
  1024. ;; 1. formal parm #1 'a' replaced by actual parm 'b', thus (a+b)
  1025. ;; becomes (b+b)
  1026. ;; 2. formal parm #2 'b' replaced by actual parm 'y', thus (b+b)
  1027. ;; becomes (y+y).
  1028. (setq macro-body
  1029. ;; Unlike `subst', `substitute' replace only the top level
  1030. ;; instead of the whole tree; more importantly, it's not
  1031. ;; destructive.
  1032. (cl-substitute (if (and etc (null formal-parms))
  1033. (hif-delimit actual-parms 'hif-comma)
  1034. (car actual-parms))
  1035. formal macro-body))
  1036. (setq actual-parms (cdr actual-parms)))
  1037. ;; Replacement completed, flatten the whole token list
  1038. (setq macro-body (hif-flatten macro-body))
  1039. ;; Stringification and token concatenation happens here
  1040. (hif-token-concatenation (hif-token-stringification macro-body)))))
  1041. (defun hif-invoke (macro-name actual-parms)
  1042. "Invoke a macro by expanding it, reparse macro-body and finally invoke it."
  1043. ;; Reparse the macro body and evaluate it
  1044. (funcall hide-ifdef-evaluator
  1045. (hif-parse-exp
  1046. (hif-macro-supply-arguments macro-name actual-parms)
  1047. macro-name)))
  1048. ;;;----------- end of parser -----------------------
  1049. (defun hif-canonicalize-tokens (regexp) ; For debugging
  1050. "Return the expanded result of the scanned tokens."
  1051. (save-excursion
  1052. (re-search-forward regexp)
  1053. (let* ((curr-regexp (match-string 0))
  1054. (defined (string-match hif-ifxdef-regexp curr-regexp))
  1055. (negate (and defined
  1056. (string= (match-string 2 curr-regexp) "n")))
  1057. (hif-simple-token-only nil) ;; Dynamic binding var for `hif-tokenize'
  1058. (tokens (hif-tokenize (point)
  1059. (progn (hif-end-of-line) (point)))))
  1060. (if defined
  1061. (setq tokens (list 'hif-defined tokens)))
  1062. (if negate
  1063. (setq tokens (list 'hif-not tokens)))
  1064. tokens)))
  1065. (defun hif-canonicalize (regexp)
  1066. "Return a Lisp expression for its condition by scanning current buffer.
  1067. Do this when cursor is at the beginning of `regexp' (i.e. #ifX)."
  1068. (let ((case-fold-search nil))
  1069. (save-excursion
  1070. (re-search-forward regexp)
  1071. (let* ((curr-regexp (match-string 0))
  1072. (defined (string-match hif-ifxdef-regexp curr-regexp))
  1073. (negate (and defined
  1074. (string= (match-string 2 curr-regexp) "n")))
  1075. (hif-simple-token-only nil) ; Dynamic binding for `hif-tokenize'
  1076. (tokens (hif-tokenize (point)
  1077. (progn (hif-end-of-line) (point)))))
  1078. (if defined
  1079. (setq tokens (list 'hif-defined tokens)))
  1080. (if negate
  1081. (setq tokens (list 'hif-not tokens)))
  1082. (hif-parse-exp tokens)))))
  1083. (defun hif-find-any-ifX ()
  1084. "Move to next #if..., or #ifndef, at point or after."
  1085. ;; (message "find ifX at %d" (point))
  1086. (prog1
  1087. (re-search-forward hif-ifx-regexp (point-max) t)
  1088. (beginning-of-line)))
  1089. (defun hif-find-next-relevant ()
  1090. "Move to next #if..., #elif..., #else, or #endif, after the current line."
  1091. ;; (message "hif-find-next-relevant at %d" (point))
  1092. (end-of-line)
  1093. ;; Avoid infinite recursion by only going to line-beginning if match found
  1094. (if (re-search-forward hif-ifx-else-endif-regexp (point-max) t)
  1095. (beginning-of-line)))
  1096. (defun hif-find-previous-relevant ()
  1097. "Move to previous #if..., #else, or #endif, before the current line."
  1098. ;; (message "hif-find-previous-relevant at %d" (point))
  1099. (beginning-of-line)
  1100. ;; Avoid infinite recursion by only going to line-beginning if match found
  1101. (if (re-search-backward hif-ifx-else-endif-regexp (point-min) t)
  1102. (beginning-of-line)))
  1103. (defun hif-looking-at-ifX ()
  1104. (looking-at hif-ifx-regexp)) ; Should eventually see #if
  1105. (defun hif-looking-at-endif ()
  1106. (looking-at hif-endif-regexp))
  1107. (defun hif-looking-at-else ()
  1108. (looking-at hif-else-regexp))
  1109. (defun hif-looking-at-elif ()
  1110. (looking-at hif-elif-regexp))
  1111. (defun hif-ifdef-to-endif ()
  1112. "If positioned at #ifX, #elif, or #else form, skip to corresponding #endif."
  1113. ;; (message "hif-ifdef-to-endif at %d" (point)) (sit-for 1)
  1114. (hif-find-next-relevant)
  1115. (cond ((hif-looking-at-ifX)
  1116. (hif-ifdef-to-endif) ; Find endif of nested if
  1117. (hif-ifdef-to-endif)) ; Find outer endif or else
  1118. ((hif-looking-at-elif)
  1119. (hif-ifdef-to-endif))
  1120. ((hif-looking-at-else)
  1121. (hif-ifdef-to-endif)) ; Find endif following else
  1122. ((hif-looking-at-endif)
  1123. 'done)
  1124. (t
  1125. (error "Mismatched #ifdef #endif pair"))))
  1126. (defun hif-endif-to-ifdef ()
  1127. "If positioned at #endif form, skip backward to corresponding #ifX."
  1128. ;; (message "hif-endif-to-ifdef at %d" (point))
  1129. (let ((start (point)))
  1130. (hif-find-previous-relevant)
  1131. (if (= start (point))
  1132. (error "Mismatched #ifdef #endif pair")))
  1133. (cond ((hif-looking-at-endif)
  1134. (hif-endif-to-ifdef) ; Find beginning of nested if
  1135. (hif-endif-to-ifdef)) ; Find beginning of outer if or else
  1136. ((hif-looking-at-elif)
  1137. (hif-endif-to-ifdef))
  1138. ((hif-looking-at-else)
  1139. (hif-endif-to-ifdef))
  1140. ((hif-looking-at-ifX)
  1141. 'done)
  1142. (t
  1143. (error "Mismatched #endif")))) ; never gets here
  1144. (defun forward-ifdef (&optional arg)
  1145. "Move point to beginning of line of the next ifdef-endif.
  1146. With argument, do this that many times."
  1147. (interactive "p")
  1148. (or arg (setq arg 1))
  1149. (if (< arg 0) (backward-ifdef (- arg))
  1150. (while (< 0 arg)
  1151. (setq arg (- arg))
  1152. (let ((start (point)))
  1153. (unless (hif-looking-at-ifX)
  1154. (hif-find-next-relevant))
  1155. (if (hif-looking-at-ifX)
  1156. (hif-ifdef-to-endif)
  1157. (goto-char start)
  1158. (error "No following #ifdef"))))))
  1159. (defun backward-ifdef (&optional arg)
  1160. "Move point to beginning of the previous ifdef-endif.
  1161. With argument, do this that many times."
  1162. (interactive "p")
  1163. (or arg (setq arg 1))
  1164. (if (< arg 0) (forward-ifdef (- arg))
  1165. (while (< 0 arg)
  1166. (setq arg (1- arg))
  1167. (beginning-of-line)
  1168. (let ((start (point)))
  1169. (unless (hif-looking-at-endif)
  1170. (hif-find-previous-relevant))
  1171. (if (hif-looking-at-endif)
  1172. (hif-endif-to-ifdef)
  1173. (goto-char start)
  1174. (error "No previous #ifdef"))))))
  1175. (defun down-ifdef ()
  1176. "Move point to beginning of nested ifdef or else-part."
  1177. (interactive)
  1178. (let ((start (point)))
  1179. (hif-find-next-relevant)
  1180. (if (or (hif-looking-at-ifX) (hif-looking-at-else))
  1181. ()
  1182. (goto-char start)
  1183. (error "No following #ifdef"))))
  1184. (defun up-ifdef ()
  1185. "Move point to beginning of enclosing ifdef or else-part."
  1186. (interactive)
  1187. (beginning-of-line)
  1188. (let ((start (point)))
  1189. (unless (hif-looking-at-endif)
  1190. (hif-find-previous-relevant))
  1191. (if (hif-looking-at-endif)
  1192. (hif-endif-to-ifdef))
  1193. (if (= start (point))
  1194. (error "No previous #ifdef"))))
  1195. (defun next-ifdef (&optional arg)
  1196. "Move to the beginning of the next #ifX, #else, or #endif.
  1197. With argument, do this that many times."
  1198. (interactive "p")
  1199. (or arg (setq arg 1))
  1200. (if (< arg 0) (previous-ifdef (- arg))
  1201. (while (< 0 arg)
  1202. (setq arg (1- arg))
  1203. (hif-find-next-relevant)
  1204. (when (eolp)
  1205. (beginning-of-line)
  1206. (error "No following #ifdefs, #elses, or #endifs")))))
  1207. (defun previous-ifdef (&optional arg)
  1208. "Move to the beginning of the previous #ifX, #else, or #endif.
  1209. With argument, do this that many times."
  1210. (interactive "p")
  1211. (or arg (setq arg 1))
  1212. (if (< arg 0) (next-ifdef (- arg))
  1213. (while (< 0 arg)
  1214. (setq arg (1- arg))
  1215. (let ((start (point)))
  1216. (hif-find-previous-relevant)
  1217. (if (= start (point))
  1218. (error "No previous #ifdefs, #elses, or #endifs"))))))
  1219. ;;===%%SF%% parsing (End) ===
  1220. ;;===%%SF%% hide-ifdef-hiding (Start) ===
  1221. ;; A range is a structure with four components:
  1222. ;; START The start of the range. (beginning of line)
  1223. ;; ELSE The else marker (beginning of line)
  1224. ;; END The end of the range. (beginning of line)
  1225. ;; ELIF A sequence of #elif markers (beginning of line)
  1226. (defsubst hif-make-range (start end &optional else elif)
  1227. (list start else end elif))
  1228. (defsubst hif-range-start (range) (elt range 0))
  1229. (defsubst hif-range-else (range) (elt range 1))
  1230. (defsubst hif-range-end (range) (elt range 2))
  1231. (defsubst hif-range-elif (range) (elt range 3))
  1232. ;; Find-Range
  1233. ;; The workhorse, it delimits the #if region. Reasonably simple:
  1234. ;; Skip until an #else or #endif is found, remembering positions. If
  1235. ;; an #else was found, skip some more, looking for the true #endif.
  1236. (defun hif-find-range ()
  1237. "Return a Range structure describing the current #if region.
  1238. Point is left unchanged."
  1239. ;; (message "hif-find-range at %d" (point))
  1240. (save-excursion
  1241. (beginning-of-line)
  1242. (let ((start (point))
  1243. (elif nil)
  1244. (else nil)
  1245. (end nil))
  1246. ;; Part one. Look for either #elif, #else or #endif.
  1247. ;; This loop-and-a-half dedicated to E. Dijkstra.
  1248. (while (and (not else) (not end))
  1249. (while (progn
  1250. (hif-find-next-relevant)
  1251. (hif-looking-at-ifX)) ; Skip nested ifdef
  1252. (hif-ifdef-to-endif))
  1253. ;; Found either a #else, #elif, or an #endif.
  1254. (cond ((hif-looking-at-elif)
  1255. (setq elif (nconc elif (list (point)))))
  1256. ((hif-looking-at-else)
  1257. (setq else (point)))
  1258. (t
  1259. (setq end (point)))))
  1260. ;; If found #else, look for #endif.
  1261. (when else
  1262. (while (progn
  1263. (hif-find-next-relevant)
  1264. (hif-looking-at-ifX)) ; Skip nested ifdef
  1265. (hif-ifdef-to-endif))
  1266. (if (hif-looking-at-else)
  1267. (error "Found two elses in a row? Broken!"))
  1268. (setq end (point))) ; (line-end-position)
  1269. (hif-make-range start end else elif))))
  1270. ;; A bit slimy.
  1271. (defun hif-hide-line (point)
  1272. "Hide the line containing point.
  1273. Does nothing if `hide-ifdef-lines' is nil."
  1274. (when hide-ifdef-lines
  1275. (save-excursion
  1276. (goto-char point)
  1277. (hide-ifdef-region-internal
  1278. (line-beginning-position) (progn (hif-end-of-line) (point))))))
  1279. ;; Hif-Possibly-Hide
  1280. ;; There are four cases. The #ifX expression is "taken" if it
  1281. ;; the hide-ifdef-evaluator returns T. Presumably, this means the code
  1282. ;; inside the #ifdef would be included when the program was
  1283. ;; compiled.
  1284. ;;
  1285. ;; Case 1: #ifX taken, and there's an #else.
  1286. ;; The #else part must be hidden. The #if (then) part must be
  1287. ;; processed for nested #ifX's.
  1288. ;; Case 2: #ifX taken, and there's no #else.
  1289. ;; The #if part must be processed for nested #ifX's.
  1290. ;; Case 3: #ifX not taken, and there's an #elif
  1291. ;; The #if part must be hidden, and then evaluate
  1292. ;; the #elif condition like a new #ifX.
  1293. ;; Case 4: #ifX not taken, and there's just an #else.
  1294. ;; The #if part must be hidden. The #else part must be processed
  1295. ;; for nested #ifs.
  1296. ;; Case 5: #ifX not taken, and there's no #else.
  1297. ;; The #ifX part must be hidden.
  1298. ;;
  1299. ;; Further processing is done by narrowing to the relevant region
  1300. ;; and just recursively calling hide-ifdef-guts.
  1301. ;;
  1302. ;; When hif-possibly-hide returns, point is at the end of the
  1303. ;; possibly-hidden range.
  1304. (defvar hif-recurse-level 0)
  1305. (defun hif-recurse-on (start end &optional dont-go-eol)
  1306. "Call `hide-ifdef-guts' after narrowing to end of START line and END line."
  1307. (save-excursion
  1308. (save-restriction
  1309. (goto-char start)
  1310. (unless dont-go-eol
  1311. (end-of-line))
  1312. (narrow-to-region (point) end)
  1313. (let ((hif-recurse-level (1+ hif-recurse-level)))
  1314. (hide-ifdef-guts)))))
  1315. (defun hif-possibly-hide (expand-reinclusion)
  1316. "Called at #ifX expression, this hides those parts that should be hidden.
  1317. It uses the judgment of `hide-ifdef-evaluator'. EXPAND-REINCLUSION is a flag
  1318. indicating that we should expand the #ifdef even if it should be hidden.
  1319. Refer to `hide-ifdef-expand-reinclusion-protection' for more details."
  1320. ;; (message "hif-possibly-hide") (sit-for 1)
  1321. (let* ((case-fold-search nil)
  1322. (test (hif-canonicalize hif-ifx-regexp))
  1323. (range (hif-find-range))
  1324. (elifs (hif-range-elif range))
  1325. (if-part t) ; Everytime we start from if-part
  1326. (complete nil))
  1327. ;; (message "test = %s" test) (sit-for 1)
  1328. (hif-hide-line (hif-range-end range))
  1329. (while (not complete)
  1330. (if (and (not (and expand-reinclusion if-part))
  1331. (hif-not (funcall hide-ifdef-evaluator test)))
  1332. ;; ifX/elif is FALSE
  1333. (if elifs
  1334. ;; Case 3 - Hide the #ifX and eval #elif
  1335. (let ((newstart (car elifs)))
  1336. (hif-hide-line (hif-range-start range))
  1337. (hide-ifdef-region (hif-range-start range)
  1338. (1- newstart))
  1339. (setcar range newstart)
  1340. (goto-char newstart)
  1341. (setq elifs (cdr elifs))
  1342. (setq test (hif-canonicalize hif-elif-regexp)))
  1343. ;; Check for #else
  1344. (cond ((hif-range-else range)
  1345. ;; Case 4 - #else block visible
  1346. (hif-hide-line (hif-range-else range))
  1347. (hide-ifdef-region (hif-range-start range)
  1348. (1- (hif-range-else range)))
  1349. (hif-recurse-on (hif-range-else range)
  1350. (hif-range-end range)))
  1351. (t
  1352. ;; Case 5 - No #else block, hide #ifX
  1353. (hide-ifdef-region (point)
  1354. (1- (hif-range-end range)))))
  1355. (setq complete t))
  1356. ;; ifX/elif is TRUE
  1357. (cond (elifs
  1358. ;; Luke fix: distinguish from #elif..#elif to #elif..#else
  1359. (let ((elif (car elifs)))
  1360. ;; hide all elifs
  1361. (hif-hide-line elif)
  1362. (hide-ifdef-region elif (1- (hif-range-end range)))
  1363. (hif-recurse-on (hif-range-start range)
  1364. elif)))
  1365. ((hif-range-else range)
  1366. ;; Case 1 - Hide #elif and #else blocks, recurse #ifX
  1367. (hif-hide-line (hif-range-else range))
  1368. (hide-ifdef-region (hif-range-else range)
  1369. (1- (hif-range-end range)))
  1370. (hif-recurse-on (hif-range-start range)
  1371. (hif-range-else range)))
  1372. (t
  1373. ;; Case 2 - No #else, just recurse #ifX
  1374. (hif-recurse-on (hif-range-start range)
  1375. (hif-range-end range))))
  1376. (setq complete t))
  1377. (setq if-part nil))
  1378. ;; complete = t
  1379. (hif-hide-line (hif-range-start range)) ; Always hide start.
  1380. (goto-char (hif-range-end range))
  1381. (end-of-line)))
  1382. (defun hif-evaluate-region (start end)
  1383. (let* ((tokens (ignore-errors ; Prevent C statement things like
  1384. ; 'do { ... } while (0)'
  1385. (hif-tokenize start end)))
  1386. (expr (and tokens
  1387. (condition-case nil
  1388. (hif-parse-exp tokens)
  1389. (error
  1390. tokens))))
  1391. (result (funcall hide-ifdef-evaluator expr)))
  1392. result))
  1393. (defun hif-evaluate-macro (rstart rend)
  1394. "Evaluate the macro expansion result for a region.
  1395. If no region active, find the current #ifdefs and evaluate the result.
  1396. Currently it supports only math calculations, strings or argumented macros can
  1397. not be expanded."
  1398. (interactive "r")
  1399. (let ((case-fold-search nil))
  1400. (save-excursion
  1401. (unless mark-active
  1402. (setq rstart nil rend nil)
  1403. (beginning-of-line)
  1404. (when (and (re-search-forward hif-macro-expr-prefix-regexp nil t)
  1405. (string= "define" (match-string 2)))
  1406. (re-search-forward hif-macroref-regexp nil t)))
  1407. (let* ((start (or rstart (point)))
  1408. (end (or rend (progn (hif-end-of-line) (point))))
  1409. (defined nil)
  1410. (simple 't)
  1411. (tokens (ignore-errors ; Prevent C statement things like
  1412. ; 'do { ... } while (0)'
  1413. (hif-tokenize start end)))
  1414. (expr (or (and (<= (length tokens) 1) ; Simple token
  1415. (setq defined (assoc (car tokens) hide-ifdef-env))
  1416. (setq simple (atom (hif-lookup (car tokens))))
  1417. (hif-lookup (car tokens)))
  1418. (and tokens
  1419. (condition-case nil
  1420. (hif-parse-exp tokens)
  1421. (error
  1422. nil)))))
  1423. (result (funcall hide-ifdef-evaluator expr))
  1424. (exprstring (replace-regexp-in-string
  1425. ;; Trim off leading/trailing whites
  1426. "^[ \t]*\\([^ \t]+\\)[ \t]*" "\\1"
  1427. (replace-regexp-in-string
  1428. "\\(//.*\\)" "" ; Trim off end-of-line comments
  1429. (buffer-substring-no-properties start end)))))
  1430. (cond
  1431. ((and (<= (length tokens) 1) simple) ; Simple token
  1432. (if defined
  1433. (message "%S <= `%s'" result exprstring)
  1434. (message "`%s' is not defined" exprstring)))
  1435. ((integerp result)
  1436. (if (or (= 0 result) (= 1 result))
  1437. (message "%S <= `%s'" result exprstring)
  1438. (message "%S (0x%x) <= `%s'" result result exprstring)))
  1439. ((null result) (message "%S <= `%s'" 'false exprstring))
  1440. ((eq t result) (message "%S <= `%s'" 'true exprstring))
  1441. (t (message "%S <= `%s'" result exprstring)))
  1442. result))))
  1443. (defun hif-parse-macro-arglist (str)
  1444. "Parse argument list formatted as '( arg1 [ , argn] [...] )'.
  1445. The '...' is also included. Return a list of the arguments, if '...' exists the
  1446. first arg will be `hif-etc'."
  1447. (let* ((hif-simple-token-only nil) ; Dynamic binding var for `hif-tokenize'
  1448. (tokenlist
  1449. (cdr (hif-tokenize
  1450. (- (point) (length str)) (point)))) ; Remove `hif-lparen'
  1451. etc result token)
  1452. (while (not (eq (setq token (pop tokenlist)) 'hif-rparen))
  1453. (cond
  1454. ((eq token 'hif-etc)
  1455. (setq etc t))
  1456. ((eq token 'hif-comma)
  1457. t)
  1458. (t
  1459. (push token result))))
  1460. (if etc
  1461. (cons 'hif-etc (nreverse result))
  1462. (nreverse result))))
  1463. ;; The original version of hideif evaluates the macro early and store the
  1464. ;; final values for the defined macro into the symbol database (aka
  1465. ;; `hide-ifdef-env'). The evaluation process is "strings -> tokens -> parsed
  1466. ;; tree -> [value]". (The square bracket refers to what's stored in in our
  1467. ;; `hide-ifdef-env'.)
  1468. ;;
  1469. ;; This forbids the evaluation of an argumented macro since the parameters
  1470. ;; are applied at run time. In order to support argumented macro I then
  1471. ;; postponed the evaluation process one stage and store the "parsed tree"
  1472. ;; into symbol database. The evaluation process was then "strings -> tokens
  1473. ;; -> [parsed tree] -> value". Hideif therefore run slower since it need to
  1474. ;; evaluate the parsed tree everytime when trying to expand the symbol. These
  1475. ;; temporarily code changes are obsolete and not in Emacs source repository.
  1476. ;;
  1477. ;; Furthermore, CPP did allow partial expression to be defined in several
  1478. ;; macros and later got concatenated into a complete expression and then
  1479. ;; evaluate it. In order to match this behavior I had to postpone one stage
  1480. ;; further, otherwise those partial expression will be fail on parsing and
  1481. ;; we'll miss all macros that reference it. The evaluation process thus
  1482. ;; became "strings -> [tokens] -> parsed tree -> value." This degraded the
  1483. ;; performance since we need to parse tokens and evaluate them everytime
  1484. ;; when that symbol is referenced.
  1485. ;;
  1486. ;; In real cases I found a lot portion of macros are "simple macros" that
  1487. ;; expand to literals like integers or other symbols. In order to enhance
  1488. ;; the performance I use this `hif-simple-token-only' to notify my code and
  1489. ;; save the final [value] into symbol database. [lukelee]
  1490. (defun hif-find-define (&optional min max)
  1491. "Parse texts and retrieve all defines within the region MIN and MAX."
  1492. (interactive)
  1493. (and min (goto-char min))
  1494. (and (re-search-forward hif-define-regexp max t)
  1495. (or
  1496. (let* ((defining (string= "define" (match-string 2)))
  1497. (name (and (re-search-forward hif-macroref-regexp max t)
  1498. (match-string 1)))
  1499. (parmlist (and (match-string 3) ; First arg id found
  1500. (hif-parse-macro-arglist (match-string 2)))))
  1501. (if defining
  1502. ;; Ignore name (still need to return 't), or define the name
  1503. (or (and hide-ifdef-exclude-define-regexp
  1504. (string-match hide-ifdef-exclude-define-regexp
  1505. name))
  1506. (let* ((start (point))
  1507. (end (progn (hif-end-of-line) (point)))
  1508. (hif-simple-token-only nil) ; Dynamic binding
  1509. (tokens
  1510. (and name
  1511. ;; `hif-simple-token-only' is set/clear
  1512. ;; only in this block
  1513. (condition-case nil
  1514. ;; Prevent C statements like
  1515. ;; 'do { ... } while (0)'
  1516. (hif-tokenize start end)
  1517. (error
  1518. ;; We can't just return nil here since
  1519. ;; this will stop hideif from searching
  1520. ;; for more #defines.
  1521. (setq hif-simple-token-only t)
  1522. (buffer-substring-no-properties
  1523. start end)))))
  1524. ;; For simple tokens we save only the parsed result;
  1525. ;; otherwise we save the tokens and parse it after
  1526. ;; parameter replacement
  1527. (expr (and tokens
  1528. ;; `hif-simple-token-only' is checked only
  1529. ;; here.
  1530. (or (and hif-simple-token-only
  1531. (listp tokens)
  1532. (= (length tokens) 1)
  1533. (hif-parse-exp tokens))
  1534. `(hif-define-macro ,parmlist
  1535. ,tokens))))
  1536. (SA (and name
  1537. (assoc (intern name) hide-ifdef-env))))
  1538. (and name
  1539. (if SA
  1540. (or (setcdr SA expr) t)
  1541. ;; Lazy evaluation, eval only if hif-lookup find it.
  1542. ;; Define it anyway, even if nil it's still in list
  1543. ;; and therefore considered defined.
  1544. (push (cons (intern name) expr) hide-ifdef-env)))))
  1545. ;; #undef
  1546. (and name
  1547. (hif-undefine-symbol (intern name))))))
  1548. t))
  1549. (defun hif-add-new-defines (&optional min max)
  1550. "Scan and add all #define macros between MIN and MAX."
  1551. (interactive)
  1552. (save-excursion
  1553. (save-restriction
  1554. ;; (mark-region min max) ;; for debugging
  1555. (while (hif-find-define min max)
  1556. (setf min (point)))
  1557. (if max (goto-char max)
  1558. (goto-char (point-max))))))
  1559. (defun hide-ifdef-guts ()
  1560. "Does most of the work of `hide-ifdefs'.
  1561. It does not do the work that's pointless to redo on a recursive entry."
  1562. ;; (message "hide-ifdef-guts")
  1563. (save-excursion
  1564. (let* ((case-fold-search t) ; Ignore case for `hide-ifdef-header-regexp'
  1565. (expand-header (and hide-ifdef-expand-reinclusion-protection
  1566. (string-match hide-ifdef-header-regexp
  1567. (buffer-file-name))
  1568. (zerop hif-recurse-level)))
  1569. (case-fold-search nil)
  1570. min max)
  1571. (goto-char (point-min))
  1572. (setf min (point))
  1573. (cl-loop do
  1574. (setf max (hif-find-any-ifX))
  1575. (hif-add-new-defines min max)
  1576. (if max
  1577. (hif-possibly-hide expand-header))
  1578. (setf min (point))
  1579. while max))))
  1580. ;;===%%SF%% hide-ifdef-hiding (End) ===
  1581. ;;===%%SF%% exports (Start) ===
  1582. (defun hide-ifdef-toggle-read-only ()
  1583. "Toggle `hide-ifdef-read-only'."
  1584. (interactive)
  1585. (setq hide-ifdef-read-only (not hide-ifdef-read-only))
  1586. (message "Hide-Read-Only %s"
  1587. (if hide-ifdef-read-only "ON" "OFF"))
  1588. (if hide-ifdef-hiding
  1589. (setq buffer-read-only (or hide-ifdef-read-only
  1590. hif-outside-read-only)))
  1591. (force-mode-line-update))
  1592. (defun hide-ifdef-toggle-outside-read-only ()
  1593. "Replacement for `read-only-mode' within Hide-Ifdef mode."
  1594. (interactive)
  1595. (setq hif-outside-read-only (not hif-outside-read-only))
  1596. (message "Read only %s"
  1597. (if hif-outside-read-only "ON" "OFF"))
  1598. (setq buffer-read-only
  1599. (or (and hide-ifdef-hiding hide-ifdef-read-only)
  1600. hif-outside-read-only))
  1601. (force-mode-line-update))
  1602. (defun hide-ifdef-toggle-shadowing ()
  1603. "Toggle shadowing."
  1604. (interactive)
  1605. (set (make-local-variable 'hide-ifdef-shadow) (not hide-ifdef-shadow))
  1606. (message "Shadowing %s" (if hide-ifdef-shadow "ON" "OFF"))
  1607. (save-restriction
  1608. (widen)
  1609. (dolist (overlay (overlays-in (point-min) (point-max)))
  1610. (when (overlay-get overlay 'hide-ifdef)
  1611. (if hide-ifdef-shadow
  1612. (progn
  1613. (overlay-put overlay 'invisible nil)
  1614. (overlay-put overlay 'face 'hide-ifdef-shadow))
  1615. (overlay-put overlay 'face nil)
  1616. (overlay-put overlay 'invisible 'hide-ifdef))))))
  1617. (defun hide-ifdef-define (var &optional val)
  1618. "Define a VAR to VAL (default 1) in `hide-ifdef-env'.
  1619. This allows #ifdef VAR to be hidden."
  1620. (interactive
  1621. (let* ((default (save-excursion
  1622. (beginning-of-line)
  1623. (cond ((looking-at hif-ifx-else-endif-regexp)
  1624. (forward-word 2)
  1625. (current-word 'strict))
  1626. (t
  1627. nil))))
  1628. (var (read-minibuffer "Define what? " default))
  1629. (val (read-from-minibuffer (format "Set %s to? (default 1): " var)
  1630. nil nil t nil "1")))
  1631. (list var val)))
  1632. (hif-set-var var (or val 1))
  1633. (message "%s set to %s" var (or val 1))
  1634. (sleep-for 1)
  1635. (if hide-ifdef-hiding (hide-ifdefs)))
  1636. (defun hif-undefine-symbol (var)
  1637. (setq hide-ifdef-env
  1638. (delete (assoc var hide-ifdef-env) hide-ifdef-env)))
  1639. (defun hide-ifdef-undef (start end)
  1640. "Undefine a VAR so that #ifdef VAR would not be included."
  1641. (interactive "r")
  1642. (let* ((symstr
  1643. (or (and mark-active
  1644. (buffer-substring-no-properties start end))
  1645. (read-string "Undefine what? " (current-word))))
  1646. (sym (and symstr
  1647. (intern symstr))))
  1648. (if (zerop (hif-defined sym))
  1649. (message "`%s' not defined, no need to undefine it" symstr)
  1650. (hif-undefine-symbol sym)
  1651. (if hide-ifdef-hiding (hide-ifdefs))
  1652. (message "`%S' undefined" sym))))
  1653. (defun hide-ifdefs (&optional nomsg)
  1654. "Hide the contents of some #ifdefs.
  1655. Assume that defined symbols have been added to `hide-ifdef-env'.
  1656. The text hidden is the text that would not be included by the C
  1657. preprocessor if it were given the file with those symbols defined.
  1658. With prefix command presents it will also hide the #ifdefs themselves.
  1659. Turn off hiding by calling `show-ifdefs'."
  1660. (interactive)
  1661. (let ((hide-ifdef-lines current-prefix-arg))
  1662. (or nomsg
  1663. (message "Hiding..."))
  1664. (setq hif-outside-read-only buffer-read-only)
  1665. (unless hide-ifdef-mode (hide-ifdef-mode 1)) ; Turn on hide-ifdef-mode
  1666. (if hide-ifdef-hiding
  1667. (show-ifdefs)) ; Otherwise, deep confusion.
  1668. (setq hide-ifdef-hiding t)
  1669. (hide-ifdef-guts)
  1670. (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only))
  1671. (or nomsg
  1672. (message "Hiding done"))))
  1673. (defun show-ifdefs ()
  1674. "Cancel the effects of `hide-ifdef': show the contents of all #ifdefs."
  1675. (interactive)
  1676. (setq buffer-read-only hif-outside-read-only)
  1677. (hif-show-all)
  1678. (setq hide-ifdef-hiding nil))
  1679. (defun hif-find-ifdef-block ()
  1680. "Utility to hide and show ifdef block.
  1681. Return as (TOP . BOTTOM) the extent of ifdef block."
  1682. (let (max-bottom)
  1683. (cons (save-excursion
  1684. (beginning-of-line)
  1685. (unless (or (hif-looking-at-else) (hif-looking-at-ifX))
  1686. (up-ifdef))
  1687. (prog1 (point)
  1688. (hif-ifdef-to-endif)
  1689. (setq max-bottom (1- (point)))))
  1690. (save-excursion
  1691. (beginning-of-line)
  1692. (unless (hif-looking-at-endif)
  1693. (hif-find-next-relevant))
  1694. (while (hif-looking-at-ifX)
  1695. (hif-ifdef-to-endif)
  1696. (hif-find-next-relevant))
  1697. (min max-bottom (1- (point)))))))
  1698. (defun hide-ifdef-block (&optional arg start end)
  1699. "Hide the ifdef block (true or false part) enclosing or before the cursor.
  1700. With optional prefix argument ARG, also hide the #ifdefs themselves."
  1701. (interactive "P\nr")
  1702. (let ((hide-ifdef-lines arg))
  1703. (if mark-active
  1704. (let ((hif-recurse-level (1+ hif-recurse-level)))
  1705. (hif-recurse-on start end t)
  1706. (setq mark-active nil))
  1707. (unless hide-ifdef-mode (hide-ifdef-mode 1))
  1708. (let ((top-bottom (hif-find-ifdef-block)))
  1709. (hide-ifdef-region (car top-bottom) (cdr top-bottom))
  1710. (when hide-ifdef-lines
  1711. (hif-hide-line (car top-bottom))
  1712. (hif-hide-line (1+ (cdr top-bottom))))
  1713. (setq hide-ifdef-hiding t))
  1714. (setq buffer-read-only
  1715. (or hide-ifdef-read-only hif-outside-read-only)))))
  1716. (defun show-ifdef-block (&optional start end)
  1717. "Show the ifdef block (true or false part) enclosing or before the cursor."
  1718. (interactive "r")
  1719. (if mark-active
  1720. (progn
  1721. (dolist (o (overlays-in start end))
  1722. (if (overlay-get o 'hide-ifdef)
  1723. (delete-overlay o)))
  1724. (setq mark-active nil))
  1725. (let ((top-bottom (condition-case nil
  1726. (hif-find-ifdef-block)
  1727. (error
  1728. nil)))
  1729. (ovrs (overlays-in (max (point-min) (1- (point)))
  1730. (min (point-max) (1+ (point)))))
  1731. (del nil))
  1732. (if top-bottom
  1733. (if hide-ifdef-lines
  1734. (hif-show-ifdef-region
  1735. (save-excursion
  1736. (goto-char (car top-bottom)) (line-beginning-position))
  1737. (save-excursion
  1738. (goto-char (1+ (cdr top-bottom)))
  1739. (hif-end-of-line) (point)))
  1740. (setf del (hif-show-ifdef-region
  1741. (1- (car top-bottom)) (cdr top-bottom)))))
  1742. (if (not (and top-bottom
  1743. del))
  1744. (dolist (o ovrs)
  1745. ;;(dolist (o (overlays-in (1- (point)) (1+ (point))))
  1746. ;; (if (overlay-get o 'hide-ifdef) (message "%S" o)))
  1747. (if (overlay-get o 'hide-ifdef)
  1748. (delete-overlay o)))))))
  1749. ;;; definition alist support
  1750. (defvar hide-ifdef-define-alist nil
  1751. "A global assoc list of pre-defined symbol lists.")
  1752. (defun hif-compress-define-list (env)
  1753. "Compress the define list ENV into a list of defined symbols only."
  1754. (let ((new-defs nil))
  1755. (dolist (def env new-defs)
  1756. (if (hif-lookup (car def)) (push (car def) new-defs)))))
  1757. (defun hide-ifdef-set-define-alist (name)
  1758. "Set the association for NAME to `hide-ifdef-env'."
  1759. (interactive "SSet define list: ")
  1760. (push (cons name (hif-compress-define-list hide-ifdef-env))
  1761. hide-ifdef-define-alist))
  1762. (defun hide-ifdef-use-define-alist (name)
  1763. "Set `hide-ifdef-env' to the define list specified by NAME."
  1764. (interactive
  1765. (list (completing-read "Use define list: "
  1766. (mapcar (lambda (x) (symbol-name (car x)))
  1767. hide-ifdef-define-alist)
  1768. nil t)))
  1769. (if (stringp name) (setq name (intern name)))
  1770. (let ((define-list (assoc name hide-ifdef-define-alist)))
  1771. (if define-list
  1772. (setq hide-ifdef-env
  1773. (mapcar (lambda (arg) (cons arg t))
  1774. (cdr define-list)))
  1775. (error "No define list for %s" name))
  1776. (if hide-ifdef-hiding (hide-ifdefs))))
  1777. (provide 'hideif)
  1778. ;;; hideif.el ends here