C++ structure comparator generator
[emacsstuff.git] / cc-ide / c++.el
1 ; Problem with this RE: a) If the line before the function declaration
2 ; is a preprocessor directive (like a #define) ending in one or more
3 ; c++ type keywords they will get included into the type spec.  b) if
4 ; you define a symbol like #define _const const the expression won't
5 ; work at all
6
7 ; Another possible regexp for c++-simple-type-regexp is "^.+". This
8 ; will make any text before the name of the function but in the same
9 ; line be the type of the function. Problem: Type cannot span multiple
10 ; lines.
11
12 (defvar c++-prefixes '("__inline__" "static"))
13
14 (defconst c++-simple-type-regexp "\\(\\([ \t\n\r]+\\(inline\\|explicit\\|unsigned\\|signed\\|short\\|long\\|const\\|static\\|friend\\)\\)*[ \t\n\r]+[a-zA-Z0-9_]+\\(<[a-zA-Z0-9_, \t\n\t]*>\\)?\\([ \t\n\r]+\\(const[ \t\n\r]+\\)\\)?\\([*&]\\|\\[[ \t\n\r]*[0-9]+[ \t\n\r]*\\]\\)*\\([ \t\n\r]+const\\)?\\)[ \t\n\r]*"
15   "*The RE for a simple type in C++ that is types that neither involve
16   blocks nor functions")
17
18 (defconst c++-function-regexp "[^a-zA-Z0-9_:]\\(\\([a-zA-Z0-9_]+\\(<[a-zA-Z0-9_, \t\n\r]*>\\)?::\\)*\\(\\(operator[ \t\n\r]*\\([-+*/.&^|=]\\|++\\|--\\|&&\\|||\\|new\\|delete\\|()\\|\\[\\]\\|->\\|[^();{}]+\\)=?\\)\\|~?[a-zA-Z0-e9_]+\\)\\)[ \t\n\r]*"
19   "The RE for a function definition or declaration")
20
21 (defconst c++-class-regexp "\\(class\\|namespace\\)[ \t\n\r]+\\([a-zA-Z0-9_:]+\\)\\([ \t\n\r]*:\\([ \t\n\r]*\\(public\\|protected\\|private\\)?[ \t\n\r]*\\([a-zA-Z0-9_]+\\(<[^>]*>\\)?\\(::\\)?\\)*[ \t\n\r]*,?\\)*\\)?[ \t\n\r]*"
22   "The RE for a class declaration")
23
24 (defconst c++-template-regexp "template[ \t\n\r]*<\\([^>]*\\)>[ \t\n\r]*"
25   "The RE for matching template clauses.")
26
27 (defconst c++-function-keywords 
28   '( "if" "while" "for" "repeat" "class" "struct" "union" "switch" )
29   "C++ Keywords which may introduce a block")
30
31 (defconst c++-keywords 
32   '( "if" "while" "for" "repeat" "class" "struct" "union" "typedef"
33      "char" "int" "float" "double" "signed" "unsigned" "long" "const"
34      "switch" "case" "repeat" "until" "do" "class" "public"
35      "protected" "private" "friend" "operator" "void" "static" "explicit" )
36   "C++ keywords")
37
38 (defvar c++-smart-wrap-column 80)
39
40 (require 'cc-cmds)
41 (require 'cc-engine)
42
43 (defun c++-scan-type-backward ()
44   "Scans backward to find the longest valid simple type ending at POINT.
45 Assumes POINT is at the end of a C++ simple type expression. 
46 Leaves POINT at the beginning of the type expression and returns 
47  ( TYPE-START . TYPE-END )"
48   (save-excursion
49     (let ((end (point))
50           start)
51       (re-search-backward c++-simple-type-regexp 'nil 't)
52       (catch 'exit
53         (while (and (re-search-forward c++-simple-type-regexp end 't)
54                     (< (abs (- end (match-end 0))) 2))
55           (goto-char (match-beginning 0))
56           (setq start (point))
57           (if (not (re-search-backward c++-simple-type-regexp 'nil 't)) 
58               (throw 'exit))))
59       (if start
60           (progn
61             (goto-char start)
62             (skip-chars-forward " \t\n\r")
63             (setq start (point))
64             (goto-char end)
65             (skip-chars-backward " \t\n\r" start)
66             (cons start (point)))
67         'nil ))))
68
69 (defun c++-get-function ()
70   "Get the last function declared or called at or after POINT.
71 Returns a list 
72         ( ( DECL-START . DECL-END ) 
73           ( TYPE-START . TYPE-END ) 
74           ( NAME-START . NAME_END ) 
75           ( ARGLIST-START . ARGLIST-END )
76           ( FLAGS-START . FLAGS-END ) )"
77   (save-excursion
78     (if (re-search-backward (concat c++-function-regexp "(") 'nil 'true)
79         (goto-char (match-end 0)))
80     (if (re-search-forward (concat c++-function-regexp "(") 'nil 't)
81         (let (type name arglist flags)
82           (setq name (cons (match-beginning 1) (match-end 1)))
83           (goto-char (1- (match-end 0)))
84           (setq arglist (cons (point) 'nil))
85           (if (condition-case nil
86                   (progn (forward-list 1) t)
87                 (scan-error nil))
88               (progn
89                 (setcdr arglist (point))
90                 (if (looking-at "\\([ \t\n\r]*\\(const\\|throw[ \t\n\r]*([^();{}]*)\\|__throw__[ \t\n\t]*(([^();{}]*))\\)\\)*")
91                     (progn
92                       (setq flags (cons (match-beginning 0) (match-end 0)))
93                       (goto-char (match-end 0)))
94                   (setq flags (cons (cdr arglist) (cdr arglist))))
95                 (if (looking-at "[ \t\n\r]*:[^;{]*")
96                     (goto-char (match-end 0)))
97                 (if (looking-at "[ \t\n\r]*[{;]")
98                     (progn
99                       (goto-char (car name))
100                       (setq type (c++-scan-type-backward))
101                       (if (not type) (setq type (cons (car name) (car name))))
102                       (list (cons (car type) (cdr flags)) type name arglist flags)))))))))
103
104 (defun c++-get-function-defn ()
105   "Get the function defined at POINT.
106 Returns a list 
107         ( ( DECL-START . DECL-END ) 
108           ( TYPE-START . TYPE-END ) 
109           ( NAME-START . NAME_END ) 
110           ( ARGLIST-START . ARGLIST-END ) 
111           ( FLAGS-START . FLAGS-END )
112           ( BODY-START . BODY-END) )"
113   (save-excursion
114     (let (body fn end)
115       (while (not fn)
116         (if (condition-case nil 
117                 (progn (up-list -1) t) 
118               (error (setq fn t) nil))
119             (save-excursion
120               (setq body (cons (point) (save-excursion 
121                                          (forward-list 1) 
122                                          (point))))
123               (save-excursion
124                 (while (condition-case nil
125                            (progn 
126                              (up-list -1) 
127                              (setq end (point))
128                              t)
129                          (scan-error nil))))
130               (while (re-search-backward (concat c++-function-regexp "(") end t)
131                 (let ((tryfn (c++-get-function)))
132                   (if tryfn
133                       (save-excursion
134                         (goto-char (cdar tryfn))
135                         (if (and (looking-at "[ \t\n\r]*\\(:[^;{]*\\)?{")
136                                  (eq (1- (match-end 0)) (car body)))
137                             (progn
138                               (if (match-beginning 1)
139                                   (setcar body (match-beginning 1)))
140                               (setq fn tryfn))))))))))
141       (if (eq fn t)
142           nil
143         (nconc fn (list body))))))
144
145 (defun c++-get-classname ()
146   "Get classname which is active at POINT"
147   (let (class
148         (re 't))
149     (save-excursion
150       (while re
151         (if (and (condition-case nil 
152                      (progn (up-list -1) 't) 
153                    (error (setq re 'nil)))
154                  (re-search-backward  (concat c++-class-regexp "\\=") 'nil 't))
155             (setq class (concat (match-string 2)
156                                 (if class "::" "")
157                                 class )))))
158     class))
159
160 (defun c++-get-current-class-prefix ()
161   "Get the class prefix currently active at POINT.
162 If within a class decl, returns that class name (nested classes
163 are supported). If within a function definition at global level,
164 returns the class prefix of this function. Returns 'nil if no
165 class prefix can be found"
166   (let ((x (c++-get-classname)))
167     (if x
168         x
169       (let ((x (or (c++-get-function-defn)
170                    (c++-get-function))))
171         (if x
172             (save-excursion
173               (goto-char (car (nth 2 x)))
174               (if (re-search-forward "\\=\\([a-zA-Z_0-9]+::\\)+")
175                   (buffer-substring (match-beginning 0) (- (match-end 0) 2))
176                 'nil))
177           'nil)))))
178             
179 (defun c++-split-template-arg (arg)
180   "Split ARG, a template argument list, and return list of arg names."
181   (let ((raw-args (split-string arg "[ \t\n\r]*,[ \t\n\r]")))
182     (loop for raw-arg in raw-args
183           if (string-match "[a-zA-Z0-9_-]+$" raw-arg)
184             collect (match-string 0 raw-arg)
185           else
186             collect raw-arg)))
187
188 (defun c++-get-classname-with-templates ()
189   (let (classname template-args
190         (re 't))
191     (save-excursion
192       (while re
193         (if (and (condition-case nil 
194                      (progn (up-list -1) 't) 
195                    (error (setq re 'nil)))
196                  (re-search-backward  (concat c++-class-regexp "\\=") nil t))
197             (let ((template-suffix "")
198                   (class (match-string 2)))
199               (if (re-search-backward (concat c++-template-regexp "\\=") nil t)
200                   (let* ((s (match-string 1))
201                          (args (c++-split-template-arg s))
202                          (raw-args (split-string s "[ \t\n\r]*,[ \t\n\r]")))
203                     (setq template-suffix
204                           (concat "<" (mapconcat 'identity args ",") ">"))
205                     (loop for arg in raw-args
206                           if (not (member arg template-args))
207                             do (setq template-args
208                                      (nconc template-args (list arg))))))
209               (setq classname (concat class
210                                       template-suffix
211                                       (if classname "::" "")
212                                       classname))))))
213     (and classname
214          (cons classname
215                (and template-args
216                     (mapconcat 'identity template-args ", "))))))
217
218 (defun c++-get-current-class-prefix-with-templates ()
219   "Get the class prefix currently active at POINT.
220 If within a class decl, returns that class name (nested classes
221 are supported). If within a function definition at global level,
222 returns the class prefix of this function. Returns 'nil if no
223 class prefix can be found"
224   (let ((x (c++-get-classname-with-templates)))
225     (if x
226         (car x)
227       (let ((x (or (c++-get-function-defn)
228                    (c++-get-function))))
229         (if x
230             (save-excursion
231               (goto-char (car (nth 2 x)))
232               (if (re-search-forward "\\=\\([a-zA-Z_0-9]+\\(<[a-zA-Z0-9_, \t\n\r]*>\\)?::\\)+")
233                   (buffer-substring (match-beginning 0) (- (match-end 0) 2))
234                 'nil))
235           'nil)))))
236
237 (defun c++-grab-inline-decl ()
238   "Grab the inline declaration at POINT and change it into a standard
239 declaration.  This function deletes the declaration found at POINT and
240 places the new declaration into the top of the kill ring"
241   (interactive)
242   (let ((fn (c++-get-function-defn))
243         (class (c++-get-classname-with-templates)))
244     (if (and fn class)
245         (progn
246           (kill-new (concat (if (cdr class)
247                                 (concat "template <" (cdr class) ">\n")
248                               "")
249                             "inline "
250                             (buffer-substring (car (nth 0 fn)) (car (nth 2 fn)))
251                             (car class) "::"
252                             (buffer-substring (car (nth 2 fn)) (cdr (nth 5 fn)))
253                             "\n"))
254           (delete-region (cdr (nth 4 fn)) (cdr (nth 5 fn)))
255           (goto-char (cdr (nth 4 fn)))
256           (insert ";")
257           (delete-blank-lines))
258       (if (interactive-p) 
259           (message "Not inside inline function definition body")))))
260
261 (defun c++-insert-class-prefix ()
262   "Insert the current class prefix at POINT.
263 See also c++-get-current-class-prefix"
264   (interactive)
265   (let ((x (c++-get-current-class-prefix-with-templates)))
266     (if x
267         (insert x "::")
268       (message "Not in scope of any class"))))
269
270 (defun c++-next-user-symbol ()
271   "Move POINT to next non-keyword symbol."
272   (interactive)
273   (let (pos)
274     (if (looking-at "[a-zA-Z_:]+")
275         (setq pos (re-search-forward "[a-zA-Z_:]+" 'nil 't)))
276     (while (and (setq pos (re-search-forward "[a-zA-Z_:]*[a-zA-Z_]" 'nil 't))
277                 (or (member (match-string 0) c++-keywords)
278                     (c-in-literal))))
279     (goto-char pos)))
280
281 (defun c++-previous-user-symbol ()
282   "Move POINT to previous non-keyword symbol."
283   (interactive)  
284   (while (and (re-search-backward "[a-zA-Z_]" 'nil 't)
285               (progn (skip-chars-backward "a-zA-Z_:") 
286                      (or (member (buffer-substring (point) (match-end 0)) 
287                                  c++-keywords)
288                          (c-in-literal))))))
289
290 (defun c++-next-function-call ()
291   "Move POINT to next function call"
292   (interactive)
293   (let ((start (point))
294         fn)
295     (while (and (setq fn (c++-get-function))
296                 (or (>= start (car (nth 0 fn)))
297                     (member (buffer-substring (car (nth 2 fn)) (cdr (nth 2 fn)))
298                             c++-function-keywords)
299                     (/= (car (nth 1 fn)) (car (nth 2 fn)))))                
300       (goto-char (cdr (nth 0 fn)))
301       (re-search-forward "{;" 'nil 't))
302     (goto-char (if fn (car (nth 0 fn)) start))))
303     
304 (defun c++-next-function-definition ()
305   "Move POINT to the next function definition or declaration"
306   (interactive)
307   (let ((start (point))
308         fn)
309     (while (and (setq fn (c++-get-function))
310                 (or (>= start (car (nth 0 fn)))
311                     (member (buffer-substring (car (nth 2 fn)) (cdr (nth 2 fn)))
312                             c++-function-keywords)
313                     (= (car (nth 1 fn)) (car (nth 2 fn)))))                 
314       (goto-char (cdr (nth 0 fn)))
315       (re-search-forward "[{;]" 'nil 't))
316     (goto-char (if fn (car (nth 0 fn)) start))))
317   
318 (defun c++-smart-yank ()
319   "Yank-pop top of kill ring and reformat the yanked object."
320   (interactive)
321   (push-mark)
322   (let ((text (current-kill 0))
323         end-mark line-start)
324     (save-excursion
325       (insert text)
326       (setq end-mark (point-marker)))
327     (while (< (point) (marker-position end-mark))
328       (beginning-of-line)
329       (c-indent-command)
330       (setq line-start (point))
331       (end-of-line)
332       (if (> (current-column) c++-smart-wrap-column)
333           (progn
334             (move-to-column c++-smart-wrap-column)
335             (if (search-backward ",")
336                 (progn
337                   (forward-char 1)
338                   (open-line 1)))))
339       (forward-line 1))))
340
341 (provide 'c++)