semantic.el 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. ;;; srecode/semantic.el --- Semantic specific extensions to SRecode.
  2. ;; Copyright (C) 2007-2012 Free Software Foundation, Inc.
  3. ;; Author: Eric M. Ludlam <eric@siege-engine.com>
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. ;; Semantic specific extensions to the Semantic Recoder.
  18. ;;
  19. ;; I realize it is the "Semantic Recoder", but most of srecode
  20. ;; is a template library and set of user interfaces unrelated to
  21. ;; semantic in the specific.
  22. ;;
  23. ;; This file defines the following:
  24. ;; - :tag argument handling.
  25. ;; - <more goes here>
  26. ;;; Code:
  27. (require 'srecode/insert)
  28. (require 'srecode/dictionary)
  29. (require 'semantic/find)
  30. (require 'semantic/format)
  31. (require 'semantic/senator)
  32. (require 'ring)
  33. ;;; The SEMANTIC TAG inserter
  34. ;;
  35. ;; Put a tag into the dictionary that can be used w/ arbitrary
  36. ;; lisp expressions.
  37. (defclass srecode-semantic-tag (srecode-dictionary-compound-value)
  38. ((prime :initarg :prime
  39. :type semantic-tag
  40. :documentation
  41. "This is the primary insertion tag.")
  42. )
  43. "Wrap up a collection of semantic tag information.
  44. This class will be used to derive dictionary values.")
  45. (defmethod srecode-compound-toString((cp srecode-semantic-tag)
  46. function
  47. dictionary)
  48. "Convert the compound dictionary value CP to a string.
  49. If FUNCTION is non-nil, then FUNCTION is somehow applied to an
  50. aspect of the compound value."
  51. (if (not function)
  52. ;; Just format it in some handy dandy way.
  53. (semantic-format-tag-prototype (oref cp :prime))
  54. ;; Otherwise, apply the function to the tag itself.
  55. (funcall function (oref cp :prime))
  56. ))
  57. ;;; Managing the `current' tag
  58. ;;
  59. (defvar srecode-semantic-selected-tag nil
  60. "The tag selected by a :tag template argument.
  61. If this is nil, then `senator-tag-ring' is used.")
  62. (defun srecode-semantic-tag-from-kill-ring ()
  63. "Create an `srecode-semantic-tag' from the senator kill ring."
  64. (if (ring-empty-p senator-tag-ring)
  65. (error "You must use `senator-copy-tag' to provide a tag to this template"))
  66. (ring-ref senator-tag-ring 0))
  67. ;;; TAG in a DICTIONARY
  68. ;;
  69. (defvar srecode-semantic-apply-tag-augment-hook nil
  70. "A function called for each tag added to a dictionary.
  71. The hook is called with two arguments, the TAG and DICT
  72. to be augmented.")
  73. (define-overload srecode-semantic-apply-tag-to-dict (tagobj dict)
  74. "Insert features of TAGOBJ into the dictionary DICT.
  75. TAGOBJ is an object of class `srecode-semantic-tag'. This class
  76. is a compound inserter value.
  77. DICT is a dictionary object.
  78. At a minimum, this function will create dictionary macro for NAME.
  79. It is also likely to create macros for TYPE (data type), function arguments,
  80. variable default values, and other things."
  81. )
  82. (defun srecode-semantic-apply-tag-to-dict-default (tagobj dict)
  83. "Insert features of TAGOBJ into dictionary DICT."
  84. ;; Store the sst into the dictionary.
  85. (srecode-dictionary-set-value dict "TAG" tagobj)
  86. ;; Pull out the tag for the individual pieces.
  87. (let ((tag (oref tagobj :prime)))
  88. (srecode-dictionary-set-value dict "NAME" (semantic-tag-name tag))
  89. (srecode-dictionary-set-value dict "TYPE" (semantic-format-tag-type tag nil))
  90. (run-hook-with-args 'srecode-semantic-apply-tag-augment-hook tag dict)
  91. (cond
  92. ;;
  93. ;; FUNCTION
  94. ;;
  95. ((eq (semantic-tag-class tag) 'function)
  96. ;; FCN ARGS
  97. (let ((args (semantic-tag-function-arguments tag)))
  98. (while args
  99. (let ((larg (car args))
  100. (subdict (srecode-dictionary-add-section-dictionary
  101. dict "ARGS")))
  102. ;; Clean up elements in the arg list.
  103. (if (stringp larg)
  104. (setq larg (semantic-tag-new-variable
  105. larg nil nil)))
  106. ;; Apply the sub-argument to the subdictionary.
  107. (srecode-semantic-apply-tag-to-dict
  108. (srecode-semantic-tag (semantic-tag-name larg)
  109. :prime larg)
  110. subdict)
  111. )
  112. ;; Next!
  113. (setq args (cdr args))))
  114. ;; PARENTS
  115. (let ((p (semantic-tag-function-parent tag)))
  116. (when p
  117. (srecode-dictionary-set-value dict "PARENT" p)
  118. ))
  119. ;; EXCEPTIONS (java/c++)
  120. (let ((exceptions (semantic-tag-get-attribute tag :throws)))
  121. (while exceptions
  122. (let ((subdict (srecode-dictionary-add-section-dictionary
  123. dict "THROWS")))
  124. (srecode-dictionary-set-value subdict "NAME" (car exceptions))
  125. )
  126. (setq exceptions (cdr exceptions)))
  127. )
  128. )
  129. ;;
  130. ;; VARIABLE
  131. ;;
  132. ((eq (semantic-tag-class tag) 'variable)
  133. (when (semantic-tag-variable-default tag)
  134. (let ((subdict (srecode-dictionary-add-section-dictionary
  135. dict "HAVEDEFAULT")))
  136. (srecode-dictionary-set-value
  137. subdict "VALUE" (semantic-tag-variable-default tag))))
  138. )
  139. ;;
  140. ;; TYPE
  141. ;;
  142. ((eq (semantic-tag-class tag) 'type)
  143. (dolist (p (semantic-tag-type-superclasses tag))
  144. (let ((sd (srecode-dictionary-add-section-dictionary
  145. dict "PARENTS")))
  146. (srecode-dictionary-set-value sd "NAME" p)
  147. ))
  148. (dolist (i (semantic-tag-type-interfaces tag))
  149. (let ((sd (srecode-dictionary-add-section-dictionary
  150. dict "INTERFACES")))
  151. (srecode-dictionary-set-value sd "NAME" i)
  152. ))
  153. ; NOTE : The members are too complicated to do via a template.
  154. ; do it via the insert-tag solution instead.
  155. ;
  156. ; (dolist (mem (semantic-tag-type-members tag))
  157. ; (let ((subdict (srecode-dictionary-add-section-dictionary
  158. ; dict "MEMBERS")))
  159. ; (when (stringp mem)
  160. ; (setq mem (semantic-tag-new-variable mem nil nil)))
  161. ; (srecode-semantic-apply-tag-to-dict
  162. ; (srecode-semantic-tag (semantic-tag-name mem)
  163. ; :prime mem)
  164. ; subdict)))
  165. ))))
  166. ;;; ARGUMENT HANDLERS
  167. ;;; :tag ARGUMENT HANDLING
  168. ;;
  169. ;; When a :tag argument is required, identify the current :tag,
  170. ;; and apply its parts into the dictionary.
  171. (defun srecode-semantic-handle-:tag (dict)
  172. "Add macros into the dictionary DICT based on the current :tag."
  173. ;; We have a tag, start adding "stuff" into the dictionary.
  174. (let ((tag (or srecode-semantic-selected-tag
  175. (srecode-semantic-tag-from-kill-ring))))
  176. (when (not tag)
  177. "No tag for current template. Use the semantic kill-ring.")
  178. (srecode-semantic-apply-tag-to-dict
  179. (srecode-semantic-tag (semantic-tag-name tag)
  180. :prime tag)
  181. dict)))
  182. ;;; :tagtype ARGUMENT HANDLING
  183. ;;
  184. ;; When a :tagtype argument is required, identify the current tag, of
  185. ;; cf class 'type. Apply those parameters to the dictionary.
  186. (defun srecode-semantic-handle-:tagtype (dict)
  187. "Add macros into the dictionary DICT based on a tag of class type at point.
  188. Assumes the cursor is in a tag of class type. If not, throw an error."
  189. (let ((typetag (or srecode-semantic-selected-tag
  190. (semantic-current-tag-of-class 'type))))
  191. (when (not typetag)
  192. (error "Cursor is not in a TAG of class 'type"))
  193. (srecode-semantic-apply-tag-to-dict
  194. typetag
  195. dict)))
  196. ;;; INSERT A TAG API
  197. ;;
  198. ;; Routines that take a tag, and insert into a buffer.
  199. (define-overload srecode-semantic-find-template (class prototype ctxt)
  200. "Find a template for a tag of class CLASS based on context.
  201. PROTOTYPE is non-nil if we want a prototype template instead."
  202. )
  203. (defun srecode-semantic-find-template-default (class prototype ctxt)
  204. "Find a template for tag CLASS based on context.
  205. PROTOTYPE is non-nil if we need a prototype.
  206. CTXT is the pre-calculated context."
  207. (let* ((top (car ctxt))
  208. (tname (if (stringp class)
  209. class
  210. (symbol-name class)))
  211. (temp nil)
  212. )
  213. ;; Try to find a template.
  214. (setq temp (or
  215. (when prototype
  216. (srecode-template-get-table (srecode-table)
  217. (concat tname "-tag-prototype")
  218. top))
  219. (when prototype
  220. (srecode-template-get-table (srecode-table)
  221. (concat tname "-prototype")
  222. top))
  223. (srecode-template-get-table (srecode-table)
  224. (concat tname "-tag")
  225. top)
  226. (srecode-template-get-table (srecode-table)
  227. tname
  228. top)
  229. (when (and (not (string= top "declaration"))
  230. prototype)
  231. (srecode-template-get-table (srecode-table)
  232. (concat tname "-prototype")
  233. "declaration"))
  234. (when (and (not (string= top "declaration"))
  235. prototype)
  236. (srecode-template-get-table (srecode-table)
  237. (concat tname "-tag-prototype")
  238. "declaration"))
  239. (when (not (string= top "declaration"))
  240. (srecode-template-get-table (srecode-table)
  241. (concat tname "-tag")
  242. "declaration"))
  243. (when (not (string= top "declaration"))
  244. (srecode-template-get-table (srecode-table)
  245. tname
  246. "declaration"))
  247. ))
  248. temp))
  249. (defun srecode-semantic-insert-tag (tag &optional style-option
  250. point-insert-fcn
  251. &rest dict-entries)
  252. "Insert TAG into a buffer using srecode templates at point.
  253. Optional STYLE-OPTION is a list of minor configuration of styles,
  254. such as the symbol 'prototype for prototype functions, or
  255. 'system for system includes, and 'doxygen, for a doxygen style
  256. comment.
  257. Optional third argument POINT-INSERT-FCN is a hook that is run after
  258. TAG is inserted that allows an opportunity to fill in the body of
  259. some thing. This hook function is called with one argument, the TAG
  260. being inserted.
  261. The rest of the arguments are DICT-ENTRIES. DICT-ENTRIES
  262. is of the form ( NAME1 VALUE1 NAME2 VALUE2 ... NAMEn VALUEn).
  263. The exact template used is based on the current context.
  264. The template used is found within the toplevel context as calculated
  265. by `srecode-calculate-context', such as `declaration', `classdecl',
  266. or `code'.
  267. For various conditions, this function looks for a template with
  268. the name CLASS-tag, where CLASS is the tag class. If it cannot
  269. find that, it will look for that template in the `declaration'
  270. context (if the current context was not `declaration').
  271. If PROTOTYPE is specified, it will first look for templates with
  272. the name CLASS-tag-prototype, or CLASS-prototype as above.
  273. See `srecode-semantic-apply-tag-to-dict' for details on what is in
  274. the dictionary when the templates are called.
  275. This function returns to location in the buffer where the
  276. inserted tag ENDS, and will leave point inside the inserted
  277. text based on any occurrence of a point-inserter. Templates such
  278. as `function' will leave point where code might be inserted."
  279. (srecode-load-tables-for-mode major-mode)
  280. (let* ((ctxt (srecode-calculate-context))
  281. (top (car ctxt))
  282. (tname (symbol-name (semantic-tag-class tag)))
  283. (dict (srecode-create-dictionary))
  284. (temp nil)
  285. (errtype tname)
  286. (prototype (memq 'prototype style-option))
  287. )
  288. ;; Try some special cases.
  289. (cond ((and (semantic-tag-of-class-p tag 'function)
  290. (semantic-tag-get-attribute tag :constructor-flag))
  291. (setq temp (srecode-semantic-find-template
  292. "constructor" prototype ctxt))
  293. )
  294. ((and (semantic-tag-of-class-p tag 'function)
  295. (semantic-tag-get-attribute tag :destructor-flag))
  296. (setq temp (srecode-semantic-find-template
  297. "destructor" prototype ctxt))
  298. )
  299. ((and (semantic-tag-of-class-p tag 'function)
  300. (semantic-tag-function-parent tag))
  301. (setq temp (srecode-semantic-find-template
  302. "method" prototype ctxt))
  303. )
  304. ((and (semantic-tag-of-class-p tag 'variable)
  305. (semantic-tag-get-attribute tag :constant-flag))
  306. (setq temp (srecode-semantic-find-template
  307. "variable-const" prototype ctxt))
  308. )
  309. )
  310. (when (not temp)
  311. ;; Try the basics
  312. (setq temp (srecode-semantic-find-template
  313. tname prototype ctxt)))
  314. ;; Try some backup template names.
  315. (when (not temp)
  316. (cond
  317. ;; Types might split things up based on the type's type.
  318. ((and (eq (semantic-tag-class tag) 'type)
  319. (semantic-tag-type tag))
  320. (setq temp (srecode-semantic-find-template
  321. (semantic-tag-type tag) prototype ctxt))
  322. (setq errtype (concat errtype " or " (semantic-tag-type tag)))
  323. )
  324. ;; A function might be an externally declared method.
  325. ((and (eq (semantic-tag-class tag) 'function)
  326. (semantic-tag-function-parent tag))
  327. (setq temp (srecode-semantic-find-template
  328. "method" prototype ctxt)))
  329. (t
  330. nil)
  331. ))
  332. ;; Can't find one? Drat!
  333. (when (not temp)
  334. (error "Cannot find template %s in %s for inserting tag %S"
  335. errtype top (semantic-format-tag-summarize tag)))
  336. ;; Resolve arguments
  337. (let ((srecode-semantic-selected-tag tag))
  338. (srecode-resolve-arguments temp dict))
  339. ;; Resolve TAG into the dictionary. We may have a :tag arg
  340. ;; from the macro such that we don't need to do this.
  341. (when (not (srecode-dictionary-lookup-name dict "TAG"))
  342. (let ((tagobj (srecode-semantic-tag (semantic-tag-name tag) :prime tag))
  343. )
  344. (srecode-semantic-apply-tag-to-dict tagobj dict)))
  345. ;; Insert dict-entries into the dictionary LAST so that previous
  346. ;; items can be overridden.
  347. (let ((entries dict-entries))
  348. (while entries
  349. (srecode-dictionary-set-value dict
  350. (car entries)
  351. (car (cdr entries)))
  352. (setq entries (cdr (cdr entries)))))
  353. ;; Insert the template.
  354. (let ((endpt (srecode-insert-fcn temp dict nil t)))
  355. (run-hook-with-args 'point-insert-fcn tag)
  356. ;;(sit-for 1)
  357. (cond
  358. ((semantic-tag-of-class-p tag 'type)
  359. ;; Insert all the members at the current insertion point.
  360. (dolist (m (semantic-tag-type-members tag))
  361. (when (stringp m)
  362. (setq m (semantic-tag-new-variable m nil nil)))
  363. ;; We do prototypes w/in the class decl?
  364. (let ((me (srecode-semantic-insert-tag m '(prototype))))
  365. (goto-char me))
  366. ))
  367. )
  368. endpt)
  369. ))
  370. (provide 'srecode/semantic)
  371. ;;; srecode/semantic.el ends here