Initial Commit
[packages] / xemacs-packages / oo-browser / br-c++.el
1 ;;!emacs
2 ;;
3 ;; FILE:         br-c++.el
4 ;; SUMMARY:      Support routines for C++ inheritance browsing.
5 ;; USAGE:        GNU Emacs Lisp Library
6 ;; KEYWORDS:     c, oop, tools
7 ;;
8 ;; AUTHOR:       Bob Weiner
9 ;; ORG:          BeOpen.com
10 ;;
11 ;; ORIG-DATE:     7-Dec-89
12 ;; LAST-MOD:      9-Jun-99 at 18:03:29 by Bob Weiner
13 ;;
14 ;; Copyright (C) 1990-1999  BeOpen.com
15 ;; See the file BR-COPY for license information.
16 ;;
17 ;; This file is part of the OO-Browser.
18 ;;
19 ;; DESCRIPTION:  
20 ;; DESCRIP-END.
21
22 ;;; ************************************************************************
23 ;;; Other required Elisp libraries
24 ;;; ************************************************************************
25
26 (mapcar 'require '(br-lib hypb br-c-ft))
27
28 ;;; ************************************************************************
29 ;;; User visible variables
30 ;;; ************************************************************************
31
32 (defconst c++-class-name-modifier
33   "\\([_a-zA-Z][_a-zA-Z0-9]*[ \t\n\r]+\\)?"
34   "Regexp for an optional #define keyword preceding the name of a class within a class declaration.
35 Some class libraries use this technique.")
36
37 (defvar c++-class-keyword
38   (concat "\\(class\\|struct\\|union\\)[ \t\n\r]+"
39           c++-class-name-modifier)
40   "*Keyword regexp preceding a C++ class declaration or definition.")
41
42 (defvar   c++-lib-search-dirs nil
43   "List of directories below which C++ Library source files are found.
44 Subdirectories of Library source are also searched.  A Library is a stable
45 group of classes.")
46
47 (defvar   c++-sys-search-dirs nil
48   "List of directories below which C++ System source files are found.
49 Subdirectories of System source are also searched.  A System class is one
50 that is not yet reusable and is likely to change before release.")
51
52
53 (defconst c++-narrow-view-to-class nil
54  "*Non-nil means narrow buffer to just the matching class definition when displayed.")
55
56 ;;; ************************************************************************
57 ;;; Internal functions
58 ;;; ************************************************************************
59
60 (defun c++-get-classes-from-source (filename &optional skip-tags
61                                     skip-tags-cleanup)
62   "Scans FILENAME and returns cons of class list with parents-class alist.
63 Handles multiple inheritance.  Assumes file existence and readability have
64 already been checked.
65    With optional SKIP-TAGS non-nil, does not compute and store lookup tags
66 for member definitions.  If SKIP-TAGS is nil, normally a cleanup
67 function is called after scanning the members.  SKIP-TAGS-CLEANUP
68 non-nil suppresses this action."
69   (let (class-name-end classes class has-parents open-brace-point
70         parents parent-cons signatures)
71     (funcall br-view-file-function filename)
72     (setq buffer-read-only nil)
73     (save-excursion
74       (save-restriction
75         (widen)
76         (br-buffer-delete-c-comments)
77         (goto-char (point-min))
78         (or skip-tags
79             (progn (setq signatures (c++-scan-features))
80                    (goto-char (point-min))))
81         (while (re-search-forward c++-class-def-regexp nil t)
82           (setq has-parents
83                 (= ?: (char-after
84                        (match-beginning c++-class-def-derived-grpn)))
85                 class-name-end (match-end c++-class-def-name-grpn)
86                 ;;
87                 ;; Now since we've saved all the match expressions we need
88                 ;; from our last regexp match, we can call functions which
89                 ;; change the match data below here.
90                 class (c++-normalize-class-match t)
91                 parent-cons (cons (if has-parents
92                                       ;; Return parents as a list.
93                                       (c++-scan-parents))
94                                   class))
95           (setq classes (cons class classes)
96                 parents (cons parent-cons parents))
97           (or skip-tags
98               ;; Scan members defined within class
99               (progn (goto-char class-name-end)
100                      (if (search-forward "\{" nil t)
101                          (progn (setq open-brace-point (point))
102                                 (backward-char)
103                                 ;; Move to class close brace but ignore
104                                 ;; any error if braces are unbalanced.
105                                 ;; Let the compiler tell the user about
106                                 ;; this.
107                                 (if (condition-case ()
108                                         (progn (forward-sexp) t)
109                                       (error nil))
110                                     (setq signatures
111                                           (append
112                                            signatures
113                                            (c++-scan-features-in-class
114                                             class open-brace-point
115                                             (point))))))))))))
116     (if skip-tags
117         nil
118       (c++-output-feature-tags filename signatures)
119       (or skip-tags-cleanup (br-feature-build-htables)))
120     (set-buffer-modified-p nil)
121     (cons classes (delq nil parents))))
122
123 (defun c++-class-definition-regexp (class &optional regexp-flag)
124   "Return regexp to uniquely match the definition of CLASS name.
125 Optional REGEXP-FLAG non-nil means CLASS has already been quoted for use in a
126 regular expression."
127   (let ((template-args-regexp (c++-template-args-regexp class)))
128     (concat "^[ \t]*"
129             (if template-args-regexp
130                 ;; Only match to a class definition with the same number of
131                 ;; template parameters as <class> since some modules use #ifdef
132                 ;; to define classes with the same name but a different number
133                 ;; of template parameters.
134                 (format "\\(template[ \t\n\r]*%s[ \t\n\r]*\\)"
135                         template-args-regexp))
136             c++-class-keyword
137             c++-class-name-modifier
138             (if regexp-flag
139                 (c++-class-non-template-name class)
140               (regexp-quote (c++-class-non-template-name class)))
141             c++-class-name-after)))
142
143 (defun c++-template-args-regexp (class)
144   "Return a regexp matching the number of template args in CLASS or nil when there are no such arguments."
145   (if (string-match "\<[^!]+\>\\'" class)
146       (let* ((param "[^,<>]+")
147              (comma (concat "," param)))
148         (format "<%s%s>"
149                 param (mapconcat
150                        (function (lambda (c) (if (= c ?\,) comma)))
151                        (substring class (1+ (match-beginning 0))
152                                   (1- (match-end 0)))
153                        "")))))
154
155 ;; Remove only *trailing* template identifiers when class name is looked up.
156 (defun c++-class-non-template-name (class)
157   "Return CLASS name sans any trailing <template> component.
158 Does not remove whitespace from CLASS."
159   (if (and (stringp class) (string-match "\<[^!]+\>\\'" class))
160       (substring class 0 (match-beginning 0))
161     class))
162
163 (defun c++-get-class-name (class-name template-signature rename-arguments-flag)
164   "Return a possibly parameterized class identifier built from CLASS-NAME and TEMPLATE-SIGNATURE.
165 If RENAME-ARGUMENTS-FLAG is non-nil, template class argument names are
166 normalized also to T1,T2,T3, etc.
167 TEMPLATE-SIGNATURE may be of any of the following forms:
168    nil                              =>  class-name
169    template <class T>               =>  class-name<T>
170    template <class T1, class T2>    =>  class-name<T1,T2>
171    <class T1, class T2>             =>  class-name<T1,T2>
172    <int = 0>                        =>  class-name<int>
173    <int size = 0>                   =>  class-name<size>."
174   (cond ((null template-signature)
175          class-name)
176         ((stringp template-signature)
177          (setq template-signature
178                (if rename-arguments-flag
179                    (progn
180                      ;; Remove any text prior to template arguments.
181                      (if (string-match "\<" template-signature)
182                          (setq template-signature
183                                (substring template-signature
184                                           (match-beginning 0))))
185                      (c++-normalize-template-arguments template-signature))
186                  (c++-template-argument-names template-signature)))
187          (if (null template-signature)
188              class-name
189            (setq class-name
190                  (format "%s%s" class-name template-signature))))
191         (t (error "(c++-get-class-name): Second argument, `%s', must be a string or nil."
192                   template-signature))))
193
194 (defun c++-template-argument-names (template-signature)
195   "Return a delimited string of the template argument names from TEMPLATE-SIGNATURE."
196   (if (or (null template-signature)
197           (not (string-match "\<" template-signature)))
198       ;; No type parameters.
199       nil
200     (setq template-signature (br-delete-space template-signature))
201     (let ((depth 0) (args) (arg ""))
202       (mapcar
203        (function
204         (lambda (c)
205           (cond ((eq c ?\<)
206                  (setq depth (1+ depth))
207                  (cond ((= depth 1)
208                         (setq args (concat args "\<")))
209                        ((> depth 1)
210                         (setq arg (concat arg (char-to-string c))))))
211                 ((zerop depth))
212                 ((= depth 1)
213                  (cond ((memq c '(?, ?\>))
214                         (if (string-match
215                              c++-template-parameter-regexp arg)
216                             (setq arg (substring arg
217                                        (match-beginning
218                                         c++-template-parameter-grpn)
219                                        (match-end
220                                         c++-template-parameter-grpn))))
221                         (setq args (concat args (br-delete-space arg)
222                                            (char-to-string c))
223                               arg "")
224                         (if (eq c ?\>) (setq depth (1- depth))))
225                        (t (setq arg (concat arg (char-to-string c))))))
226                 ((eq c ?\>)
227                  (setq depth (1- depth)
228                        arg (concat arg (char-to-string c))))
229                 (t (setq arg (concat arg (char-to-string c)))))))
230        template-signature)
231       args)))
232
233 (defun c++-list-template-arguments (template-signature)
234   "Return a list of the template arguments within TEMPLATE-SIGNATURE."
235   (if (or (null template-signature)
236           (not (string-match "\<" template-signature)))
237       ;; No type parameters.
238       nil
239     (setq template-signature (br-delete-space template-signature))
240     (let ((depth 0) (args) (arg ""))
241       (mapcar
242        (function
243         (lambda (c)
244           (cond ((eq c ?\<)
245                  (setq depth (1+ depth))
246                  (if (> depth 1)
247                      (setq arg (concat arg (char-to-string c)))))
248                 ((zerop depth))
249                 ((= depth 1)
250                  (cond ((eq c ?,)
251                         (setq args (cons (br-delete-space arg) args)
252                               arg ""))
253                        ((eq c ?\>)
254                         (setq args (cons (br-delete-space arg) args)
255                               arg ""
256                               depth (1- depth)))
257                        (t (setq arg (concat arg (char-to-string c))))))
258                 ((eq c ?\>)
259                  (setq depth (1- depth)
260                        arg (concat arg (char-to-string c))))
261                 (t (setq arg (concat arg (char-to-string c)))))))
262        template-signature)
263       (nreverse args))))
264
265 (defun c++-normalize-class-match (rename-arguments-flag)
266   "After a regexp match to a class definition, return the matching class name.
267 Class name is normalized for use in OO-Browser lookups.
268 If RENAME-ARGUMENTS-FLAG is non-nil, template class argument names are
269 normalized also to T1,T2,T3, etc."
270  (c++-get-class-name
271   (br-buffer-substring (match-beginning c++-class-def-name-grpn)
272                        (match-end c++-class-def-name-grpn))
273   (if (match-beginning c++-class-def-template-grpn)
274       (br-buffer-substring
275        (match-beginning c++-class-def-template-grpn)
276        (match-end c++-class-def-template-grpn)))
277   rename-arguments-flag))
278
279 (defun c++-normalize-template-arguments (class)
280   "Return CLASS with any template arguments renamed to <T> or <T1,T2,T3>."
281   (cond ((null class) nil)
282         ((not (string-match "\<" class))
283          ;; No type parameters.
284          (br-delete-space class))
285         (t (setq class (br-delete-space class))
286            (let ((depth 0) (arg-num 0))
287              (mapconcat
288               (function
289                (lambda (c)
290                  (cond ((eq c ?<)
291                         (setq depth (1+ depth))
292                         (if (= depth 1) "<"))
293                        ((zerop depth) (char-to-string c))
294                        ((= depth 1)
295                         (cond ((eq c ?,)
296                                (setq arg-num (1+ arg-num))
297                                (format "T%d," arg-num))
298                               ((eq c ?>)
299                                (setq arg-num (1+ arg-num)
300                                      depth (1- depth))
301                                (if (= arg-num 1)
302                                    "T>"
303                                  (format "T%d>" arg-num)))))
304                        ((eq c ?>)
305                         (setq depth (1- depth))
306                         nil))))
307               class
308               "")))))
309
310 (defun c++-scan-parents ()
311   "Return list of parents names from a C++ class definition.
312 Point must be after the colon that begins the parent list and before the
313 first parent entry when this function is called."
314   (let ((parent-list) (again t)
315         parent)
316     (while (and again (re-search-forward c++-parent-regexp nil t))
317       (setq parent
318             (c++-parse-buffer-template-arguments
319              (br-delete-space
320               (br-buffer-substring (match-beginning c++-parent-name-grpn)
321                                    (match-end c++-parent-name-grpn)))))
322       (if (looking-at (concat c++-comment-regexp "[#,\{\;]"))
323           (goto-char (match-end 0)))
324       (setq again (eq ?, (preceding-char))
325             parent-list (cons parent parent-list)))
326     (nreverse parent-list)))
327
328 (defun c++-parse-buffer-template-arguments (class)
329   "Return CLASS with any template arguments following point renamed to <T> or <T1,T2,T3>.
330 Leaves point after the closing angle bracket."
331 ;; We need to handle class definitions like this:
332 ;;   template <class T> class PtrList : private List<type-name> {}
333 ;; where the parent class is an instantiation of a parameterized class.
334 ;; For now, we change the type name to <T> or <T1,T2,T3> when there are 3
335 ;; parameters, for purposes of class name matching.
336 ;;      
337 ;; Test cases:
338 ;;
339 ;;    '("par <class _T1=myclass , class _T2 = you >" "parent"
340 ;;      "class<_T1,T2>" "class< __me , int>" "" "<template>"
341 ;;      "par<_template>")
342 ;;   Should yield:
343 ;;     ("par<T1,T2>" "parent" "class<T1,T2>" "class<T1,T2>" "" "<template>"
344 ;;      "par<T>")
345 ;;
346   (if (not (eq (following-char) ?\<))
347       class
348     (let ((depth 1) (arg-num 0) (args "\<")
349           (continue t) c)
350       (while continue
351         (forward-char 1)
352         (setq c (following-char))
353         (cond ((eq c ?<)
354                (setq depth (1+ depth)))
355               ((= depth 1)
356                (cond ((eq c ?,)
357                       (setq arg-num (1+ arg-num)
358                             args (concat args (format "T%d," arg-num))))
359                      ((eq c ?>)
360                       (setq arg-num (1+ arg-num)
361                             depth (1- depth)
362                             continue nil)
363                       (setq args (concat args
364                                          (if (= arg-num 1)
365                                              "T>"
366                                            (format "T%d>" arg-num)))))))
367               ((eq c ?>)
368                (setq depth (1- depth)))
369               ((zerop depth)
370                (setq continue nil))))
371       ;; Move past closing angle bracket.
372       (forward-char 1)
373       ;; Return class with normalized args.
374       (concat class args))))
375
376 (defun c++-get-parents-from-source (filename class-name)
377   "Scan source in FILENAME and return list of parents of CLASS-NAME.
378 Assume file existence has already been checked."
379     (or (null class-name)
380         (car (car (br-rassoc
381                    class-name
382                    (cdr (c++-get-classes-from-source filename t)))))))
383
384 (defun c++-select-path (paths-htable-elt &optional feature-p)
385   "Select proper pathname from PATHS-HTABLE-ELT based upon value of optional FEATURE-P.
386 Selection is between path of class definition and path for features associated
387 with the class."
388   (let ((elt (cdr paths-htable-elt)))
389     (if (consp elt) 
390         (if feature-p (cdr elt) (car elt))
391       ;; Both paths are the same.
392       elt)))
393
394 (defun c++-set-case (type)
395   "Return string TYPE identifier for use as a class name."
396   type)
397
398 (defun c++-set-case-type (class-name)
399   "Return string CLASS-NAME for use as a type identifier."
400   class-name)
401
402 (defun c++-to-class-end ()
403   "Assuming point is at start of class, move to start of line after end of class."
404   (interactive)
405   (condition-case ()
406       (forward-list)
407     (error (progn (or (re-search-forward "^}" nil t)
408                       (goto-char (point-max))))))
409   (forward-line 1))
410
411 (defalias 'c++-to-comments-begin 'br-c-to-comments-begin)
412
413 ;;; ************************************************************************
414 ;;; Internal variables
415 ;;; ************************************************************************
416
417 (defconst c++-template-prefix
418   "\\(template[ \t\n\r]*\<[^\>\;.{}]+\>[ \t\n\r]*\\)?"
419   "Regexp matching a template class or element definition or declaration.
420 Entire expression is an optional match, so it may be added as a conditional
421 expression to other regexps.")
422
423 (defconst c++-class-name-before
424   (concat "^[ \t]*" c++-template-prefix c++-class-keyword)
425   "Regexp preceding the class name in a class definition.")
426
427 (defconst c++-comment-regexp "\\([ \t\n\r]*//.*[\n\r]\\|[ \t\n\r]*/\\*.*\\*/\\)*[ \t\n\r]*")
428
429 (defconst c++-class-name-after
430   (concat c++-comment-regexp "\\([\{:]\\)")
431   "Regexp following the class name in a class definition.
432 Last character matched is either the colon preceding the list of class
433 parents, or the curly brace beginning the class body definition.")
434
435 (defconst c++-identifier-chars "_~<>a-zA-Z0-9"
436   "String of chars and char ranges that may be used within a C++ or G++ identifier.")
437
438 (defconst c++-template-identifier-chars "_a-zA-Z0-9"
439   "String of chars and char ranges that may be used within a standard C++ template identifier.
440 This excludes the template arguments.")
441
442 (defconst c++-return-type-chars "_<>a-zA-Z0-9"
443   "String of chars and char ranges that may be used within a C++ or G++ return type identifier.")
444
445 ;; Modified on 3/28/95 to handle C++ names with multiple template
446 ;; parameters, e.g. class<T1,T2,T3>.
447 (defconst c++-identifier (concat
448                           "\\([_~\<a-zA-Z][" c++-template-identifier-chars "]*"
449                           "[ \t\n\r]*\<[^\>\;{}]+[ \t\n\r\>]*\>\\|[_~\<a-zA-Z]["
450                           c++-identifier-chars "]*\\)")
451   "Regular expression matching a C++ or G++ identifier.")
452
453 (defconst c++-class-def-regexp
454   (concat c++-class-name-before c++-identifier c++-class-name-after)
455   "Regular expression used to match to class definitions in source text.
456 Class name identifier is grouping `c++-class-def-name-grpn'.  Optional
457 class template parameter signature is grouping `c++-class-def-template-grpn'.
458 `:' derived class indicator begins grouping `c++-class-def-derived-grpn,'
459 unless the class is not derived, in which case this grouping begins with
460 `{'.")
461
462 (defconst c++-class-def-template-grpn 1)
463 (defconst c++-class-def-name-grpn 4)
464 (defconst c++-class-def-derived-grpn 6)
465
466 (defconst c++-lang-prefix "c++-"
467  "Prefix string that starts \"br-c++.el\" symbol names.")
468
469 (defconst c++-non-template-identifier
470   (concat "\\([_~\<a-zA-Z][" c++-template-identifier-chars "]*"
471           "[ \t\n\r]*\\|[_~\<a-zA-Z][" c++-identifier-chars "]*\\)")
472   "Match a C++ identifier up until the start of any template arguments.")
473
474 (defconst c++-parent-regexp
475   (concat c++-comment-regexp
476           "\\(\\(public\\|private\\|protected\\|virtual\\)[ \t\n\r]+"
477           "\\(\\(public\\|private\\|protected\\|virtual\\)[ \t\n\r]+\\)?\\)?"
478           ;; match c++-identifier up until start of any template arguments
479           c++-non-template-identifier)
480   "Parent identifier (sans any template arguments) is group `c++-parent-name-grpn'.")
481
482 (defconst c++-parent-name-grpn 6)
483
484 (defconst c++-template-parameter-regexp
485   "\\([^= \t\n\r]+\\)[ \t\n\r]*\\(=[^,\>]+\\)?\\'"
486   "Regexp matching a single C++ <template> specifier argument name within a
487 single template argument.  For example in `class T', T is the parameter name
488 and in `int size = 0', size is the parameter name.  The parameter name is
489 grouping `c++-template-parameter-grpn'.")
490
491 (defconst c++-template-parameter-grpn 1)
492
493 ;; Ellemtel C++ recommendations specify that inline definition files should
494 ;; use the suffix ".icc" and other people use ".I" for such files, so those
495 ;; suffixes are included here.
496 (defconst c++-src-file-regexp
497   "[^.]\\.\\([chCH][xX][xX]\\|[chCH][chpCHP]?[pP]?\\|[iI][cC][cC]\\|I\\|[iI][nN][cC]\\)$"
498   "Regular expression matching a unique part of C++ source or header file name and no others.")
499
500 (defconst c++-header-file-regexp
501   "\\.\\([hH][xX][xX]\\|[hH][hpHP]?[pP]?\\|[iI][nN][cC]\\)$"
502   "Regular expression matching the . and suffix of a C++ or C header file.")
503
504 (defvar c++-children-htable nil
505   "Htable whose elements are of the form: (LIST-OF-CHILD-CLASSES . CLASS-NAME).
506 Used to traverse C++ inheritance graph.  `br-build-children-htable' builds
507 this list.")
508 (defvar c++-parents-htable nil
509   "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
510 Used to traverse C++ inheritance graph.  `br-build-parents-htable' builds
511 this list.")
512 (defvar c++-paths-htable nil
513   "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
514 FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
515 `br-build-paths-htable' builds this list.")
516
517
518 (defvar c++-lib-parents-htable nil
519   "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
520 Only classes from stable software libraries are used to build the list.")
521 (defvar c++-lib-paths-htable nil
522   "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
523 FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
524 Only classes from stable software libraries are used to build the list.")
525
526 (defvar c++-sys-parents-htable nil
527   "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
528 Only classes from systems that are likely to change are used to build the list.")
529 (defvar c++-sys-paths-htable nil
530   "Alist whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
531 FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
532 Only classes from systems that are likely to change are used to build the
533 list.")
534
535 (defvar c++-lib-prev-search-dirs nil
536   "Used to check if `c++-lib-classes-htable' must be regenerated.")
537 (defvar c++-sys-prev-search-dirs nil
538   "Used to check if `c++-sys-classes-htable' must be regenerated.")
539
540 (defvar c++-env-spec nil
541   "Non-nil value means Environment specification has been given but not yet built.
542 Nil means current Environment has been built, though it may still require updating.")
543
544 (provide 'br-c++)