4 ;; SUMMARY: Support routines for Objective-C inheritance browsing.
5 ;; USAGE: GNU Emacs Lisp Library
6 ;; KEYWORDS: c, oop, tools
11 ;; ORIG-DATE: 7-Dec-89
12 ;; LAST-MOD: 9-Jun-99 at 19:55:10 by Bob Weiner
14 ;; Copyright (C) 1989-1995, 1997 BeOpen.com
15 ;; See the file BR-COPY for license information.
17 ;; This file is part of the OO-Browser.
21 ;; See `objc-class-def-regexp' for regular expression that matches class
26 ;;; ************************************************************************
27 ;;; Other required Elisp libraries
28 ;;; ************************************************************************
35 ;;; ************************************************************************
37 ;;; ************************************************************************
39 (defvar objc-lib-search-dirs nil
40 "List of directories below which Objective-C Library source files are found.
41 Subdirectories of Library source are also searched. A Library is a stable
44 (defvar objc-sys-search-dirs nil
45 "List of directories below which Objective-C System source files are found.
46 Subdirectories of System source are also searched. A System class is one
47 that is not yet reusable and is likely to change before release.")
49 (defconst objc-narrow-view-to-class nil
50 "*Non-nil means narrow buffer to just the matching class definition when displayed.")
52 ;;; ************************************************************************
54 ;;; ************************************************************************
56 (defun objc-get-classes-from-source (filename &optional skip-tags
58 "Scans FILENAME and returns cons of class list with parents-class alist.
59 Assumes file existence and readability have already been checked.
60 With optional SKIP-TAGS non-nil, does not compute and store lookup tags
61 for feature definitions. If SKIP-TAGS is nil, normally a cleanup
62 routine is called after scanning the features. SKIP-TAGS-CLEANUP
63 non-nil suppresses this action."
64 (let ((no-kill (get-file-buffer filename))
67 class class-of-category class-separator class-type
68 classes category def-match-data in-comment-flag parent-list
72 (funcall br-view-file-function filename))
76 (goto-char (point-min))
79 ;; Get all method definitions within this file.
80 (setq signatures (objc-scan-features))
81 (goto-char (point-min)))
82 ;; Search for class or protocol interface specification.
83 (while (re-search-forward objc-class-def-regexp nil t)
84 (setq class nil class-type nil
85 category nil parent-list nil protocol-list nil
86 def-match-data (match-data))
88 ;; If definition is within a C comment, ignore it.
89 ;; Regexp used for matching a def precludes any "//"
91 (if (setq in-comment-flag
92 (and (c-within-comment-p) (search-forward "*/" nil t)))
94 (store-match-data def-match-data)
95 (setq class-type (buffer-substring
96 (match-beginning objc-class-def-type-grpn)
97 (match-end objc-class-def-type-grpn))
99 (if (match-beginning objc-class-def-separator-grpn)
101 (match-beginning objc-class-def-separator-grpn)
102 (match-end objc-class-def-separator-grpn)))))
104 (cond (in-comment-flag) ;; Ignore
106 ((string-equal class-type "@interface")
107 ;; Class or category definition
108 (setq class (br-buffer-substring
109 (match-beginning objc-class-name-grpn)
110 (match-end objc-class-name-grpn)))
111 (cond ((null class-separator)
112 ;; top class definition without any protocols,
113 ;; nothing more to do
115 ((string-equal class-separator ":")
116 ;; class definition with parent
117 (if (re-search-forward objc-parent-regexp nil t)
119 (list (br-buffer-substring
121 objc-parent-name-grpn)
122 (match-end objc-parent-name-grpn))))
123 (error "(objc-get-classes-from-source): `%s' parent definition is invalid."
125 ;; Check if class conforms to protocol list
126 (if (and (null skip-tags) (eq (following-char) ?<))
127 (setq protocol-list (objc-scan-protocol-list))))
129 ((string-equal class-separator "\(")
130 ;; class category definition
132 ;; Check if class conforms to protocol list
134 (skip-chars-forward " \t\n\r")
135 (setq class-of-category
137 (match-beginning objc-class-name-grpn)
138 (match-end objc-class-name-grpn))
140 (if (looking-at objc-identifier)
142 (goto-char (match-end 0))
143 (skip-chars-forward "\) \t\n\r")
145 "\(" (br-buffer-substring
147 objc-identifier-grpn)
149 objc-identifier-grpn))
151 ;; If get here, there is a problem.
152 (error "(objc-get-classes-from-source): `%s' class contains invalid category () delimiters"))
153 class (concat class-of-category category)
155 ;; Add this category def to the default
157 (cons (objc-feature-normalize
158 ;; Yes, this net line should be
159 ;; (category)class-of-category.
160 (concat category class-of-category)
161 objc-default-category-class)
162 ;; Add a category tag to
163 ;; class-of-category.
164 (cons (objc-feature-normalize
168 ;; Check if category conforms to protocol list
169 (if (eq (following-char) ?<)
171 (objc-scan-protocol-list))))))
173 ((string-equal class-separator "<")
174 ;; top class definition conforming to protocols
176 (setq protocol-list (objc-scan-protocol-list))))
178 ;; If get here, there is a bug, so signal an error.
179 (t (error "(objc-get-classes-from-source): `%s' class uses `%s' unhandled definition separator"
180 class class-separator))))
184 ;; Protocol definition
186 ;; Record `<'protocol-name `>' as a class along with its
187 ;; parent protocols, if any.
188 (setq class (concat "<"
190 (match-beginning objc-class-name-grpn)
191 (match-end objc-class-name-grpn))
194 (if (string-equal class-separator "<")
195 (objc-scan-protocol-list)))
198 ;; Add this protocol def to the default protocols
200 (cons (objc-feature-normalize
201 class objc-default-protocol-class)
204 ;; Add the protocol's method *declarations* as
206 signatures (nconc signatures
207 (objc-scan-protocol-signatures))))))
208 (if (null class-type)
210 (if class (setq classes (cons class classes)
212 (cons (cons (nconc parent-list protocol-list) class)
213 parents-and-class)))))))
216 (objc-output-feature-tags filename signatures)
217 (or skip-tags-cleanup (br-feature-build-htables)))
218 (or no-kill (kill-buffer (current-buffer)))
219 (cons classes (delq nil parents-and-class))))
221 (defun objc-get-parents-from-source (filename class-name)
222 "Scan source in FILENAME and return list of parents of CLASS-NAME.
223 Assume file existence has already been checked."
224 (or (null class-name)
227 (cdr (objc-get-classes-from-source filename t)))))))
229 (defun objc-select-path (paths-htable-elt &optional feature-p)
230 "Select proper pathname from PATHS-HTABLE-ELT based upon value of optional FEATURE-P.
231 Selection is between path of class definition and path for features associated
233 (let ((elt (cdr paths-htable-elt)))
235 (if feature-p (cdr elt) (car elt))
236 ;; Both paths are the same.
239 (defun objc-set-case (type)
240 "Return string TYPE identifier for use as a class name."
243 (defun objc-set-case-type (class-name)
244 "Return string CLASS-NAME for use as a type identifier."
247 (defun objc-to-class-end ()
248 "Assuming point is at start of class, move to start of line after end of class."
252 (error (progn (or (re-search-forward "^}" nil t)
253 (goto-char (point-max))))))
256 (defalias 'objc-to-comments-begin 'br-c-to-comments-begin)
258 ;;; ************************************************************************
259 ;;; Private variables
260 ;;; ************************************************************************
262 (defconst objc-class-keyword
263 "\\(@interface\\|@protocol\\)[ \t\n\r]+"
264 "Keyword regexp preceding an Objective-C class or protocol definition.
265 Type of definition is indicated by grouping `objc-class-def-type-grpn'.")
267 (defconst objc-class-def-type-grpn 1)
269 (defconst objc-class-name-before
270 (concat "^[ \t]*" objc-class-keyword)
271 "Regexp preceding the class name in a class definition.")
273 (defconst objc-class-name-after
274 "\\([ \t\n\r]+//.*[\n]\\)*[ \t\n\r]*\\([:\<\(]\\)?"
275 "Regexp following the class name in a class definition.")
277 (defconst objc-interface-before
278 "^[ \t]*\\(@interface\\)[ \t\n\r]+"
279 "Regexp preceding the class name in a non-protocol class definition.")
281 (defconst objc-implementation-before
282 "^[ \t]*\\(@implementation\\)[ \t\n\r]+"
283 "Regexp preceding the class name in a class method definition section.")
285 (defconst objc-protocol-before
286 "^[ \t]*\\(@protocol\\)[ \t\n\r]+"
287 "Regexp preceding the protocol name in a formal protocol definition.")
289 (defconst objc-identifier-chars "_a-zA-Z0-9"
290 "String of chars and char ranges that may be used within an Objective-C identifier.")
292 (defconst objc-identifier
293 (concat "\\([_a-zA-Z][" objc-identifier-chars "]*\\)")
294 "Regular expression matching an Objective-C identifier.
295 The identifier is grouping `objc-identifier-grpn'.")
297 (defconst objc-identifier-grpn 1)
299 (defconst objc-class-def-regexp
300 (concat objc-class-name-before objc-identifier objc-class-name-after)
301 "Regular expression used to match to class definitions in source text.
302 Type of definition is indicated by grouping `objc-class-def-type-grpn'.
303 Class name identifier is grouping `objc-class-name-grpn'. Entire grouped
304 expression ends with one of the following (optional grouping
305 `objc-class-def-separator-grpn'):
306 a `:', indicating that class inherits from parent class following the colon;
307 a `\(', indicating a class category definition;
308 a `<', indicating protocols to which class conforms;
309 no grouping match, indicating that this is a root class with no parent.")
311 (defconst objc-class-def-separator-grpn 4)
313 (defconst objc-lang-prefix "objc-"
314 "Prefix string that starts \"br-objc.el\" symbol names.")
316 (defconst objc-parent-regexp
317 (concat "[ \t\n\r]*" objc-identifier "\\([ \t\n\r]+//.*[\n]\\)?[ \t\n\r]*")
318 "Parent identifier is grouping `objc-parent-name-grpn'.")
320 (defconst objc-parent-name-grpn 1)
322 (defconst objc-src-file-regexp ".\\.[hcmHCM]$"
323 "Regular expression matching a unique part of Objective-C source or header file name and no others.")
325 (defvar objc-children-htable nil
326 "Htable whose elements are of the form: (LIST-OF-CHILD-CLASSES . CLASS-NAME).
327 Used to traverse Objective-C inheritance graph. `br-build-children-htable' builds
329 (defvar objc-parents-htable nil
330 "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
331 Used to traverse Objective-C inheritance graph. `br-build-parents-htable' builds
333 (defvar objc-paths-htable nil
334 "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
335 FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
336 `br-build-paths-htable' builds this list.")
339 (defvar objc-lib-parents-htable nil
340 "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
341 Only classes from stable software libraries are used to build the list.")
342 (defvar objc-lib-paths-htable nil
343 "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
344 FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
345 Only classes from stable software libraries are used to build the list.")
347 (defvar objc-sys-parents-htable nil
348 "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
349 Only classes from systems that are likely to change are used to build the list.")
350 (defvar objc-sys-paths-htable nil
351 "Alist whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
352 FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
353 Only classes from systems that are likely to change are used to build the
356 (defvar objc-lib-prev-search-dirs nil
357 "Used to check if `objc-lib-classes-htable' must be regenerated.")
358 (defvar objc-sys-prev-search-dirs nil
359 "Used to check if `objc-sys-classes-htable' must be regenerated.")
361 (defvar objc-env-spec nil
362 "Non-nil value means Environment specification has been given but not yet built.
363 Nil means current Environment has been built, though it may still require updating.")