diff lisp/oobr/br-objc.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 4103f0995bd7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/oobr/br-objc.el	Mon Aug 13 08:45:50 2007 +0200
@@ -0,0 +1,386 @@
+;;!emacs
+;;
+;; FILE:         br-objc.el
+;; SUMMARY:      Support routines for Objective-C inheritance browsing.
+;; USAGE:        GNU Emacs Lisp Library
+;; KEYWORDS:     c, oop, tools
+;;
+;; AUTHOR:       Bob Weiner
+;; ORG:          Motorola Inc.
+;;
+;; ORIG-DATE:     7-Dec-89
+;; LAST-MOD:     21-Sep-95 at 12:31:05 by Bob Weiner
+;;
+;; Copyright (C) 1989-1995  Free Software Foundation, Inc.
+;; See the file BR-COPY for license information.
+;;
+;; This file is part of the OO-Browser.
+;;
+;; DESCRIPTION:  
+;;
+;;   See 'objc-class-def-regexp' for regular expression that matches class
+;;   definitions.
+;;            
+;; DESCRIP-END.
+
+;;; ************************************************************************
+;;; Other required Elisp libraries
+;;; ************************************************************************
+
+(mapcar 'require '(br-lib br-c-ft))
+
+;;; ************************************************************************
+;;; Public variables
+;;; ************************************************************************
+
+(defvar objc-lib-search-dirs nil
+  "List of directories below which Objective-C Library source files are found.
+Subdirectories of Library source are also searched.  A Library is a stable
+group of classes.")
+
+(defvar objc-sys-search-dirs nil
+  "List of directories below which Objective-C System source files are found.
+Subdirectories of System source are also searched.  A System class is one
+that is not yet reusable and is likely to change before release.")
+
+(defconst objc-narrow-view-to-class nil
+ "*Non-nil means narrow buffer to just the matching class definition when displayed.")
+
+;;; ************************************************************************
+;;; Public functions
+;;; ************************************************************************
+
+(defun objc-get-classes-from-source (filename &optional skip-tags
+					      skip-tags-cleanup)
+  "Scans FILENAME and returns cons of class list with parents-class alist.
+Assumes file existence and readability have already been checked.
+   With optional SKIP-TAGS non-nil, does not compute and store lookup tags
+for feature definitions.  If SKIP-TAGS is nil, normally a cleanup
+routine is called after scanning the features.  SKIP-TAGS-CLEANUP
+non-nil suppresses this action."
+  (let ((no-kill (get-file-buffer filename))
+	(parents-and-class)
+	(signatures)
+	class class-of-category class-separator class-type
+	classes category def-match-data in-comment-flag parent-list
+	protocol-list)
+    (if no-kill
+	(set-buffer no-kill)
+      (funcall br-view-file-function filename))
+    (save-excursion
+      (save-restriction
+	(widen)
+	(goto-char (point-min))
+	(if skip-tags
+	    nil
+	  ;; Get all method definitions within this file.
+	  (setq signatures (objc-scan-features))
+	  (goto-char (point-min)))
+	;; Search for class or protocol interface specification.
+	(while (re-search-forward objc-class-def-regexp nil t)
+	  (setq class nil class-type nil
+		category nil parent-list nil protocol-list nil
+		def-match-data (match-data))
+	  ;;
+	  ;; If definition is within a C comment, ignore it.
+	  ;; Regexp used for matching a def precludes any "//"
+	  ;; comment.
+	  (if (setq in-comment-flag
+		    (and (c-within-comment-p) (search-forward "*/" nil t)))
+	      nil
+	    (store-match-data def-match-data)
+	    (setq class-type (buffer-substring
+			      (match-beginning objc-class-def-type-grpn)
+			      (match-end objc-class-def-type-grpn))
+		  class-separator
+		  (if (match-beginning objc-class-def-separator-grpn)
+		      (buffer-substring
+		       (match-beginning objc-class-def-separator-grpn)
+		       (match-end objc-class-def-separator-grpn)))))
+	  ;;
+	  (cond (in-comment-flag) ;; Ignore
+		;;
+		((string-equal class-type "@interface")
+		 ;; Class or category definition
+		 (setq class (buffer-substring
+			      (match-beginning objc-class-name-grpn)
+			      (match-end objc-class-name-grpn)))
+		 (cond ((null class-separator)
+			;; top class definition without any protocols,
+			;; nothing more to do
+			)
+		       ((string-equal class-separator ":")
+			;; class definition with parent
+			(if (re-search-forward objc-parent-regexp nil t)
+			    (setq parent-list
+				  (list (buffer-substring
+					 (match-beginning
+					  objc-parent-name-grpn)
+					 (match-end objc-parent-name-grpn))))
+			  (error "(objc-get-classes-from-source): '%s' parent definition is invalid."
+				 class))
+			;; Check if class conforms to protocol list
+			(if (and (null skip-tags) (= (following-char) ?\<))
+			    (setq protocol-list (objc-scan-protocol-list))))
+		       ;;
+		       ((string-equal class-separator "\(")
+			;; class category definition
+			(if (null skip-tags)
+			    ;; Check if class conforms to protocol list
+			    (progn
+			      (skip-chars-forward " \t\n\r")
+			      (setq class-of-category
+				    (buffer-substring
+				     (match-beginning objc-class-name-grpn)
+				     (match-end objc-class-name-grpn))
+				    category
+				    (if (looking-at objc-identifier)
+					(progn
+					  (goto-char (match-end 0))
+					  (skip-chars-forward "\) \t\n\r")
+					  (concat
+					   "\(" (buffer-substring
+						 (match-beginning
+						  objc-identifier-grpn)
+						 (match-end 
+						  objc-identifier-grpn))
+					   "\)"))
+				      ;; If get here, there is a problem.
+				      (error "(objc-get-classes-from-source): '%s' class contains invalid category () delimiters"))
+				    class (concat class-of-category category)
+				    signatures
+				    ;; Add this category def to the default
+				    ;; categories class.
+				    (cons (objc-feature-normalize
+					   ;; Yes, this net line should be
+					   ;; (category)class-of-category.
+					   (concat category class-of-category)
+					   objc-default-category-class)
+				    ;; Add a category tag to
+				    ;; class-of-category.
+					  (cons (objc-feature-normalize
+						 category
+						 class-of-category)
+						signatures)))
+			      ;; Check if category conforms to protocol list
+			      (if (= (following-char) ?\<)
+				  (setq protocol-list
+					(objc-scan-protocol-list))))))
+		       ;;
+		       ((string-equal class-separator "\<")
+			;; top class definition conforming to protocols
+			(if (null skip-tags)
+			    (setq protocol-list (objc-scan-protocol-list))))
+		       ;;
+		       ;; If get here, there is a bug, so signal an error.
+		       (t (error "(objc-get-classes-from-source): '%s' class uses '%s' unhandled definition separator"
+				 class class-separator))))
+		;;
+		(t
+		 ;;
+		 ;; Protocol definition
+		 ;;
+		 ;;   Record '<'protocol-name '>' as a class along with its
+		 ;;   parent protocols, if any.
+		 ;;   If not skip-tags, add the protocol's method
+		 ;;   *declarations* as feature tags.
+		 (setq class (concat "<"
+				     (buffer-substring
+				      (match-beginning objc-class-name-grpn)
+				      (match-end objc-class-name-grpn))
+				     ">")
+		       parent-list
+		       (if (string-equal class-separator "\<")
+			   (objc-scan-protocol-list)))
+		 (if (null skip-tags)
+		     (setq signatures
+			   ;; Add this protocol def to the default protocols
+			   ;; class.
+			   (cons (objc-feature-normalize
+				  class objc-default-protocol-class)
+				 signatures)))))
+	  (if (null class-type)
+	      nil
+	    (if class (setq classes (cons class classes)
+			    parents-and-class
+			    (cons (cons parent-list class)
+				  parents-and-class)))
+	    (if protocol-list
+		;; record all of class' protocols as tags
+		(setq signatures
+		      (nconc signatures
+			     (mapcar
+			      (function (lambda (protocol)
+					  (objc-feature-normalize
+					   protocol class)))
+			      protocol-list))))))))
+    (if skip-tags
+	nil
+      (objc-get-feature-tags buffer-file-name signatures)
+      (or skip-tags-cleanup (br-feature-tags-save)))
+    (or no-kill (kill-buffer (current-buffer)))
+    (cons classes (delq nil parents-and-class))))
+
+(defun objc-get-parents-from-source (filename class-name)
+  "Scan source in FILENAME and return list of parents of CLASS-NAME.
+Assume file existence has already been checked."
+    (or (null class-name)
+	(car (car (br-rassoc
+		   class-name
+		   (cdr (objc-get-classes-from-source filename t)))))))
+
+(defun objc-select-path (paths-htable-elt &optional feature-p)
+  "Select proper pathname from PATHS-HTABLE-ELT based upon value of optional FEATURE-P.
+Selection is between path of class definition and path for features associated
+with the class."
+  (let ((elt (cdr paths-htable-elt)))
+    (if (consp elt) 
+	(if feature-p (cdr elt) (car elt))
+      ;; Both paths are the same.
+      elt)))
+
+(defun objc-set-case (type)
+  "Return string TYPE identifier for use as a class name."
+  type)
+
+(defun objc-set-case-type (class-name)
+  "Return string CLASS-NAME for use as a type identifier."
+  class-name)
+
+(defun objc-to-class-end ()
+  "Assuming point is at start of class, move to start of line after end of class."
+  (interactive)
+  (condition-case ()
+      (forward-list)
+    (error (progn (or (re-search-forward "^}" nil t)
+		      (goto-char (point-max))))))
+  (forward-line 1))
+
+(defun objc-to-comments-begin ()
+  "Skip back from current point past any preceding Objective-C comments.
+Presumes no \"/*\" strings are nested within multi-line comments."
+  (let ((opoint))
+    (while
+	(progn (setq opoint (point))
+	       ;; To previous line
+	       (if (= 0 (forward-line -1))
+		   (cond
+		     ;; If begins with "//" or ends with "*/", then is a comment.
+		     ((looking-at "[ \t]*\\(//\\|$\\)"))
+		     ((looking-at ".*\\*/[ \t]*$")
+		      (progn (end-of-line)
+			     (search-backward "/*" nil t)))
+		     (nil)))))
+    (goto-char opoint)
+    ;; Skip past whitespace
+    (skip-chars-forward " \t\n")
+    (beginning-of-line)))
+
+;;; ************************************************************************
+;;; Private variables
+;;; ************************************************************************
+
+(defconst objc-class-keyword
+  "\\(@interface\\|@protocol\\)[ \t\n]+"
+  "Keyword regexp preceding an Objective-C class or protocol definition.
+Type of definition is indicated by grouping 'objc-class-def-type-grpn'.")
+
+(defconst objc-class-def-type-grpn 1)
+
+(defconst objc-class-name-before
+  (concat "^[ \t]*" objc-class-keyword)
+  "Regexp preceding the class name in a class definition.")
+
+(defconst objc-class-name-after
+  "\\([ \t\n]+//.*[\n]\\)*[ \t\n]*\\([:\<\(]\\)?"
+  "Regexp following the class name in a class definition.")
+
+(defconst objc-interface-before
+  "^[ \t]*\\(@interface\\)[ \t\n]+"
+  "Regexp preceding the class name in a non-protocol class definition.")
+
+(defconst objc-implementation-before
+  "^[ \t]*\\(@implementation\\)[ \t\n]+"
+  "Regexp preceding the class name in a class method definition section.")
+
+(defconst objc-protocol-before
+  "^[ \t]*\\(@protocol\\)[ \t\n]+"
+  "Regexp preceding the protocol name in a formal protocol definition.")
+
+(defconst objc-identifier-chars "_a-zA-Z0-9"
+  "String of chars and char ranges that may be used within an Objective-C identifier.")
+
+(defconst objc-identifier
+  (concat "\\([_a-zA-Z][" objc-identifier-chars "]*\\)")
+  "Regular expression matching an Objective-C identifier.
+The identifier is grouping 'objc-identifier-grpn'.")
+
+(defconst objc-identifier-grpn 1)
+
+(defconst objc-class-def-regexp
+  (concat objc-class-name-before objc-identifier objc-class-name-after)
+  "Regular expression used to match to class definitions in source text.
+Type of definition is indicated by grouping 'objc-class-def-type-grpn'.
+Class name identifier is grouping 'objc-class-name-grpn'.  Entire grouped
+expression ends with one of the following (optional grouping
+'objc-class-def-separator-grpn'):
+  a ':', indicating that class inherits from parent class following the colon;
+  a '\(', indicating a class category definition;
+  a '<', indicating protocols to which class conforms;
+  no grouping match, indicating that this is a root class with no parent.")
+
+(defconst objc-class-def-separator-grpn 4)
+
+(defconst objc-lang-prefix "objc-"
+ "Prefix string that starts \"br-objc.el\" symbol names.")
+
+(defconst objc-parent-regexp
+  (concat "[ \t\n]*" objc-identifier "\\([ \t\n]+//.*[\n]\\)?[ \t\n]*")
+  "Parent identifier is grouping 'objc-parent-name-grpn'.")
+
+(defconst objc-parent-name-grpn 1)
+
+(defconst objc-src-file-regexp ".\\.[hcmHCM]$"
+  "Regular expression matching a unique part of Objective-C source or header file name and no others.")
+
+(defvar objc-children-htable nil
+  "Htable whose elements are of the form: (LIST-OF-CHILD-CLASSES . CLASS-NAME).
+Used to traverse Objective-C inheritance graph.  'br-build-children-htable' builds
+this list.")
+(defvar objc-parents-htable nil
+  "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
+Used to traverse Objective-C inheritance graph.  'br-build-parents-htable' builds
+this list.")
+(defvar objc-paths-htable nil
+  "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
+FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
+'br-build-paths-htable' builds this list.")
+
+
+(defvar objc-lib-parents-htable nil
+  "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
+Only classes from stable software libraries are used to build the list.")
+(defvar objc-lib-paths-htable nil
+  "Htable whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
+FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
+Only classes from stable software libraries are used to build the list.")
+
+(defvar objc-sys-parents-htable nil
+  "Htable whose elements are of the form: (LIST-OF-PARENT-CLASSES . CLASS-NAME).
+Only classes from systems that are likely to change are used to build the list.")
+(defvar objc-sys-paths-htable nil
+  "Alist whose elements are of the form: (LIST-OF-CLASS-NAMES . FILE-PATH).
+FILE-PATH gives the location of classes found in LIST-OF-CLASS-NAMES.
+Only classes from systems that are likely to change are used to build the
+list.")
+
+(defvar objc-lib-prev-search-dirs nil
+  "Used to check if 'objc-lib-classes-htable' must be regenerated.")
+(defvar objc-sys-prev-search-dirs nil
+  "Used to check if 'objc-sys-classes-htable' must be regenerated.")
+
+(defvar objc-env-spec nil
+  "Non-nil value means Environment specification has been given but not yet built.
+Nil means current Environment has been built, though it may still require updating.")
+
+(provide 'br-objc)