]> code.delx.au - gnu-emacs/blobdiff - lisp/cedet/semantic/lex-spp.el
Merge from origin/emacs-24
[gnu-emacs] / lisp / cedet / semantic / lex-spp.el
index 5f121d88ac6a98ddd3adb4f3ffde42ac5f6193fb..164454c481c395c04b0ed393ee3c9e8372bfad5c 100644 (file)
@@ -1,6 +1,6 @@
 ;;; semantic/lex-spp.el --- Semantic Lexical Pre-processor
 
-;; Copyright (C) 2006-201 Free Software Foundation, Inc.
+;; Copyright (C) 2006-2014 Free Software Foundation, Inc.
 
 ;; Author: Eric M. Ludlam <zappo@gnu.org>
 
@@ -30,7 +30,7 @@
 ;; If you use SPP in your language, be sure to specify this in your
 ;; semantic language setup function:
 ;;
-;; (add-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook nil t)
+;; (add-hook 'semantic-lex-reset-functions 'semantic-lex-spp-reset-hook nil t)
 ;;
 ;;
 ;; Special Lexical Tokens:
@@ -70,6 +70,8 @@
 (require 'semantic)
 (require 'semantic/lex)
 
+(declare-function semantic-c-end-of-macro "semantic/bovine/c")
+
 ;;; Code:
 (defvar semantic-lex-spp-macro-symbol-obarray nil
   "Table of macro keywords used by the Semantic Preprocessor.
@@ -497,7 +499,7 @@ and what valid VAL values are."
   ;;  (symbol "name" 569 . 573)
   ;;  (semantic-list "(int in)" 574 . 582))
   ;;
-  ;; In the second case, a macro with an argument list as the a rgs as the
+  ;; In the second case, a macro with an argument list as the args as the
   ;; first entry.
   ;;
   ;; CASE 3: Symbol text merge
@@ -527,16 +529,54 @@ and what valid VAL values are."
   ;;
   ;; Nested token FOO shows up in the table of macros, and gets replace
   ;; inline.  This is the same as case 2.
+  ;;
+  ;; CASE 5: Macros which open a scope without closing it
+  ;;
+  ;; #define __NAMESPACE_STD namespace std {
+  ;; #define __NAMESPACE_END }
+  ;;  ==>
+  ;; ((NAMESPACE "namespace" 140 . 149)
+  ;;  (symbol "std" 150 . 153)
+  ;;  (open-paren "{" 154 . 155))
+  ;;
+  ;; Note that we get a single 'open-paren' instead of a
+  ;; 'semantic-list', which is because we use
+  ;; 'semantic-lex-spp-paren-or-list' instead of
+  ;; 'semantic-lex-paren-or-list' in our spp-lexer.  To keep things
+  ;; reasonably simple, we assume that such an open scope will always
+  ;; be closed by another macro (see
+  ;; `semantic-lex-spp-find-closing-macro'). We generate a
+  ;; 'semantic-list' to this closing macro, and we leave an overlay
+  ;; which contains information how far we got into the macro's
+  ;; stream (since it might open several scopes).
+
+  (let* ((arglist (semantic-lex-spp-macro-with-args val))
+        (argalist nil)
+        (val-tmp nil)
+        (v nil)
+        (sppov (semantic-lex-spp-get-overlay beg))
+        (sppinfo (when sppov (overlay-get sppov 'semantic-spp))))
+
+    ;; First, check if we were already here and left information
+    (when sppinfo
+      ;; Advance in the tokens as far as we got last time
+      (when (numberp (car sppinfo))
+       (while (and val
+                   (>= (car sppinfo) (car (last (car val)))))
+           (setq val (cdr val))))
+      ;; And push an open paren
+      (semantic-lex-push-token
+       (semantic-lex-token 'open-paren beg (1+ beg) "{"))
+      (setq semantic-lex-current-depth (1+ semantic-lex-current-depth))
+      (unless val
+       ;; We reached the end of this macro, so delete overlay
+       (delete-overlay sppov)))
 
-  (let ((arglist (semantic-lex-spp-macro-with-args val))
-       (argalist nil)
-       (val-tmp nil)
-       (v nil)
-       )
     ;; CASE 2: Dealing with the arg list.
-    (when arglist
+    (when (and val arglist)
       ;;  Skip the arg list.
-      (setq val (cdr val))
+      (when (eq (caar val) 'spp-arg-list)
+       (setq val (cdr val)))
 
       ;; Push args into the replacement list.
       (let ((AV argvalues))
@@ -577,13 +617,7 @@ and what valid VAL values are."
        (cond
         ;; CASE 3: Merge symbols together.
         ((eq (semantic-lex-token-class v) 'spp-symbol-merge)
-         ;; We need to merge the tokens in the 'text segment together,
-         ;; and produce a single symbol from it.
-         (let ((newsym
-                (mapconcat (lambda (tok)
-                             (semantic-lex-spp-one-token-to-txt tok))
-                           txt
-                           "")))
+         (let ((newsym (semantic-lex-spp-symbol-merge txt)))
            (semantic-lex-push-token
             (semantic-lex-token 'symbol beg end newsym))
            ))
@@ -622,7 +656,32 @@ and what valid VAL values are."
          (semantic-lex-push-token
           (semantic-lex-token (semantic-lex-token-class v) beg end txt))
          )
-
+        ;; CASE 5: Macro which opens a scope
+        ((eq (semantic-lex-token-class v) 'open-paren)
+         ;; We assume that the scope will be closed by another macro.
+         ;; (Everything else would be a terrible idea anyway.)
+         (let* ((endpoint (semantic-lex-spp-find-closing-macro))
+                (ov (when endpoint
+                      (or sppov
+                          (make-overlay beg end)))))
+           (when ov
+             ;; Generate a semantic-list which spans to the end of
+             ;; the closing macro
+             (semantic-lex-push-token
+              (semantic-lex-token 'semantic-list beg endpoint))
+             ;; The rest of the current macro's stream will be parsed
+             ;; next time.
+             (setq val-tmp nil)
+             ;; Store our current state were we are in the macro and
+             ;; the endpoint.
+             (overlay-put ov 'semantic-spp
+                          (cons (car (last v)) endpoint)))))
+        ((eq (semantic-lex-token-class v) 'close-paren)
+         ;; Macro which closes a scope
+         ;; Just push the close paren, but also decrease depth
+         (semantic-lex-push-token
+          (semantic-lex-token 'close-paren beg end txt))
+         (setq semantic-lex-current-depth (1- semantic-lex-current-depth)))
         ;; CASE 1: Just another token in the stream.
         (t
          ;; Nothing new.
@@ -637,6 +696,58 @@ and what valid VAL values are."
       (semantic-lex-spp-symbol-pop A))
     ))
 
+(defun semantic-lex-spp-symbol-merge (txt)
+  "Merge the tokens listed in TXT.
+TXT might contain further 'spp-symbol-merge, which will
+be merged recursively."
+  ;; We need to merge the tokens in the 'text segment together,
+  ;; and produce a single symbol from it.
+  (mapconcat (lambda (tok)
+              (cond
+               ((eq (car tok) 'symbol)
+                (semantic-lex-spp-one-token-to-txt tok))
+               ((eq (car tok) 'spp-symbol-merge)
+                ;; Call recursively for multiple merges, like
+                ;; #define FOO(a) foo##a##bar
+                (semantic-lex-spp-symbol-merge (cadr tok)))
+               (t
+                (message "Invalid merge macro encountered; \
+will return empty string instead.")
+                "")))
+            txt
+            ""))
+
+(defun semantic-lex-spp-find-closing-macro ()
+  "Find next macro which closes a scope through a close-paren.
+Returns position with the end of that macro."
+  (let ((macros (semantic-lex-spp-macros))
+       (cmacro-regexp "\\(")
+       (case-fold-search nil))
+    ;; Build a regexp which search for all macros with a closing
+    ;; paren, and search for it.
+    (dolist (cur macros)
+      (let ((stream (symbol-value cur)))
+       (when (and (listp stream) (listp (car stream)))
+         (while stream
+           (if (and (eq (caar stream) 'close-paren)
+                    (string= (nth 1 (car stream)) "}"))
+               (setq cmacro-regexp (concat cmacro-regexp (symbol-name cur) "\\|")
+                     stream nil)
+             (setq stream (cdr-safe stream)))))))
+    (when cmacro-regexp
+      (save-excursion
+       (when (re-search-forward
+              (concat (substring cmacro-regexp 0 -2) "\\)[^0-9a-zA-Z_]") nil t)
+         (point))))))
+
+(defun semantic-lex-spp-get-overlay (&optional point)
+  "Return first overlay which has a 'semantic-spp property."
+  (let ((overlays (overlays-at (or point (point)))))
+    (while (and overlays
+               (null (overlay-get (car overlays) 'semantic-spp)))
+      (setq overlays (cdr overlays)))
+    (car-safe overlays)))
+
 ;;; Macro Merging
 ;;
 ;; Used when token streams from different macros include each other.
@@ -712,7 +823,7 @@ ARGVALUES are values for any arg list, or nil."
 ;; An analyzer that will push tokens from a macro in place
 ;; of the macro symbol.
 ;;
-(defun semantic-lex-spp-anlyzer-do-replace (sym val beg end)
+(defun semantic-lex-spp-analyzer-do-replace (sym val beg end)
   "Do the lexical replacement for SYM with VAL.
 Argument BEG and END specify the bounds of SYM in the buffer."
   (if (not val)
@@ -752,6 +863,9 @@ Argument BEG and END specify the bounds of SYM in the buffer."
       (setq semantic-lex-end-point end)
       )
     ))
+(define-obsolete-function-alias
+  'semantic-lex-spp-anlyzer-do-replace
+  'semantic-lex-spp-analyzer-do-replace "25.1")
 
 (defvar semantic-lex-spp-replacements-enabled t
   "Non-nil means do replacements when finding keywords.
@@ -809,8 +923,46 @@ STR occurs in the current buffer between BEG and END."
   "\\(\\sw\\|\\s_\\)+"
   (let ((str (match-string 0))
        (beg (match-beginning 0))
-       (end (match-end 0)))
-    (semantic-lex-spp-analyzer-push-tokens-for-symbol str beg end)))
+       (end (match-end 0))
+       sppov)
+      (semantic-lex-spp-analyzer-push-tokens-for-symbol str beg end)
+      (when (setq sppov (semantic-lex-spp-get-overlay beg))
+       (setq semantic-lex-end-point (cdr (overlay-get sppov 'semantic-spp))))))
+
+(define-lex-regex-analyzer semantic-lex-spp-paren-or-list
+  "Detect open parenthesis.
+Contrary to `semantic-lex-paren-or-list', this will push a single
+open-paren onto the stream if no closing paren can be found.
+This is important for macros which open a scope which is closed
+by another macro."
+  "\\s("
+  (if (or (not semantic-lex-maximum-depth)
+         (< semantic-lex-current-depth semantic-lex-maximum-depth))
+      (progn
+       (setq semantic-lex-current-depth (1+ semantic-lex-current-depth))
+       (semantic-lex-push-token
+        (semantic-lex-token
+         'open-paren (match-beginning 0) (match-end 0))))
+    (save-excursion
+      (let ((start (match-beginning 0))
+           (end (match-end 0))
+           (peom (save-excursion (semantic-c-end-of-macro) (point))))
+       (condition-case nil
+          (progn
+            ;; This will throw an error if no closing paren can be found.
+            (forward-list 1)
+            (when (> (point) peom)
+              ;; If we have left the macro, this is the wrong closing
+              ;; paren, so error out as well.
+              (error ""))
+            (semantic-lex-push-token
+             (semantic-lex-token
+              'semantic-list start (point))))
+         (error
+          ;; Only push a single open-paren.
+          (semantic-lex-push-token
+           (semantic-lex-token
+            'open-paren start end))))))))
 
 ;;; ANALYZERS FOR NEW MACROS
 ;;
@@ -869,7 +1021,14 @@ Parsing starts inside the parens, and ends at the end of TOKEN."
        (forward-char 1)
        (setq fresh-toks (semantic-lex-spp-stream-for-macro (1- end)))
        (dolist (tok fresh-toks)
-         (when (memq (semantic-lex-token-class tok) '(symbol semantic-list))
+         ;; march 2011: This is too restrictive!  For example "void"
+         ;; can't get through.  What elements was I trying to expunge
+         ;; to put this in here in the first place?  If I comment it
+         ;; out, does anything new break?
+         ;(when (memq (semantic-lex-token-class tok) '(symbol semantic-list))
+         ;; It appears the commas need to be dumped.  perhaps this is better,
+         ;; but will it cause more problems later?
+         (unless (eq (semantic-lex-token-class tok) 'punctuation)
            (setq toks (cons tok toks))))
 
        (nreverse toks)))))
@@ -890,6 +1049,7 @@ and variable state from the current buffer."
         (fresh-toks nil)
         (toks nil)
         (origbuff (current-buffer))
+        (analyzer semantic-lex-analyzer)
         (important-vars '(semantic-lex-spp-macro-symbol-obarray
                           semantic-lex-spp-project-macro-symbol-obarray
                           semantic-lex-spp-dynamic-macro-symbol-obarray
@@ -913,14 +1073,19 @@ and variable state from the current buffer."
            ;; Hack in mode-local
            (activate-mode-local-bindings)
 
+           ;; Call the major mode's setup function
+           (let ((entry (assq major-mode semantic-new-buffer-setup-functions)))
+             (when entry
+               (funcall (cdr entry))))
+
            ;; CHEATER!  The following 3 lines are from
            ;; `semantic-new-buffer-fcn', but we don't want to turn
            ;; on all the other annoying modes for this little task.
            (setq semantic-new-buffer-fcn-was-run t)
            (semantic-lex-init)
            (semantic-clear-toplevel-cache)
-           (remove-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook
-                        t)
+           (remove-hook 'semantic-lex-reset-functions
+                        'semantic-lex-spp-reset-hook t)
            ))
 
        ;; Second Cheat: copy key variables regarding macro state from the