changeset 85617:4cbfa6e02bcd

(f90-keywords-re, f90-keywords-level-3-re): Add `non_intrinsic'. (f90-constants-re): Add ieee modules. (f90-typedef-matcher, f90-typedec-matcher) (f90-imenu-type-matcher): New functions. (f90-font-lock-keywords-1): Give module procedures function-name face. Use `f90-typedef-matcher' for derived types. Fix `abstract interface'. Add `use, intrinsic'. (f90-font-lock-keywords-2): Use `f90-typedec-matcher' for derived types. Move start of `enum' blocks to separate entry. (f90-start-block-re): Fix `type', `abstract interface'. (f90-imenu-generic-expression): Use `f90-imenu-type-matcher' for derived types. (f90-mode-abbrev-table): Add `abstract interface', `asynchronous', `elemental', change `enumerator'. (f90-no-block-limit): Fix `abstract interface'.
author Glenn Morris <rgm@gnu.org>
date Thu, 25 Oct 2007 03:51:15 +0000
parents 2d1d8c03e736
children e2b55f3f0f2b
files lisp/progmodes/f90.el
diffstat 1 files changed, 155 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/progmodes/f90.el	Thu Oct 25 03:41:31 2007 +0000
+++ b/lisp/progmodes/f90.el	Thu Oct 25 03:51:15 2007 +0000
@@ -28,8 +28,7 @@
 
 ;; Major mode for editing F90 programs in FREE FORMAT.
 ;; The minor language revision F95 is also supported (with font-locking).
-;; Some aspects of F2003 are supported.  At present, there are some
-;; problems with derived types.
+;; Some/many (?) aspects of F2003 are supported.
 
 ;; Knows about continuation lines, named structured statements, and other
 ;; features in F90 including HPF (High Performance Fortran) structures.
@@ -156,12 +155,16 @@
 ;;; Code:
 
 ;; TODO
-;; Have "f90-mode" just recognize F90 syntax, then derived modes
+;; 1. Any missing F2003 syntax?
+;; 2. Have "f90-mode" just recognize F90 syntax, then derived modes
 ;; "f95-mode", "f2003-mode" for the language revisions.
-;; Support for align.
-;; OpenMP, preprocessor highlighting.
-;; F2003 syntax:
-;; problems with derived types.
+;; 3. Support for align.
+;; Font-locking:
+;; 1. OpenMP, OpenMPI?, preprocessor highlighting.
+;; 2. interface blah - Highlight "blah" in function-name face?
+;; Need to avoid "interface operator (+)" etc.
+;; 3. integer_name = 1
+;; 4. Labels for "else" statements (F2003)?
 
 (defvar comment-auto-fill-only-comments)
 (defvar font-lock-keywords)
@@ -312,8 +315,8 @@
                 ;; F2003
                 "abstract" "associate" "asynchronous" "bind" "class"
                 "deferred" "enum" "enumerator" "extends" "extends_type_of"
-                "final" "generic" "import" "non_overridable" "nopass" "pass"
-                "protected" "same_type_as" "value" "volatile"
+                "final" "generic" "import" "non_intrinsic" "non_overridable"
+                "nopass" "pass" "protected" "same_type_as" "value" "volatile"
                 ) 'words)
   "Regexp used by the function `f90-change-keywords'.")
 
@@ -329,7 +332,7 @@
      ;; F95 keywords.
      "elemental" "pure"
      ;; F2003. asynchronous separate.
-     "abstract" "deferred" "import" "final" "non_overridable"
+     "abstract" "deferred" "import" "final" "non_intrinsic" "non_overridable"
      "nopass" "pass" "protected" "value" "volatile"
      ) 'words)
   "Keyword-regexp for font-lock level >= 3.")
@@ -428,56 +431,145 @@
                 "c_new_line" "c_carriage_return" "c_horizontal_tab"
                 "c_vertical_tab"
                 "c_ptr" "c_funptr" "c_null_ptr" "c_null_funptr"
+                "ieee_exceptions"
+                "ieee_arithmetic"
+                "ieee_features"
                 ) 'words)
   "Regexp for Fortran intrinsic constants.")
 
+;; cf f90-looking-at-type-like.
+(defun f90-typedef-matcher (limit)
+  "Search for the start/end of the definition of a derived type, up to LIMIT.
+Set the match data so that subexpression 1,2 are the TYPE, and
+type-name parts, respectively."
+  (let (found l)
+    (while (and (re-search-forward "\\<\\(\\(?:end[ \t]*\\)?type\\)[ \t]*"
+                                   limit t)
+                (not (setq found
+                           (progn
+                             (setq l (match-data))
+                             (unless (looking-at "\\(is\\>\\|(\\)")
+                               (when (if (looking-at "\\(\\sw+\\)")
+                                         (goto-char (match-end 0))
+                                       (re-search-forward
+                                        "[ \t]*::[ \t]*\\(\\sw+\\)"
+                                        (line-end-position) t))
+                                 ;; 0 is wrong, but we don't use it.
+                                 (set-match-data
+                                  (append l (list (match-beginning 1)
+                                                  (match-end 1))))
+                                 t)))))))
+    found))
+
 (defvar f90-font-lock-keywords-1
   (list
    ;; Special highlighting of "module procedure".
-   '("\\<\\(module[ \t]*procedure\\)\\>" (1 font-lock-keyword-face))
+   '("\\<\\(module[ \t]*procedure\\)\\>\\([^()\n]*::\\)?[ \t]*\\([^&!\n]*\\)"
+     (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
    ;; Highlight definition of derived type.
-   ;; FIXME F2003 use a function, same as looking-at-type-like?
-   '("\\<\\(\\(?:end[ \t]*\\)?type\\)\\>\\([^()\n]*::\\)?[ \t]*\\(\\sw+\\)"
-     (1 font-lock-keyword-face) (3 font-lock-function-name-face))
+;;;    '("\\<\\(\\(?:end[ \t]*\\)?type\\)\\>\\([^()\n]*::\\)?[ \t]*\\(\\sw+\\)"
+;;;      (1 font-lock-keyword-face) (3 font-lock-function-name-face))
+   '(f90-typedef-matcher
+     (1 font-lock-keyword-face) (2 font-lock-function-name-face))
    ;; Other functions and declarations.
    '("\\<\\(\\(?:end[ \t]*\\)?\\(program\\|module\\|function\\|associate\\|\
 subroutine\\)\\|use\\|call\\)\\>[ \t]*\\(\\sw+\\)?"
      (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
-   ;; "abstract interface" is F2003.
-   "\\<\\(\\(end[ \t]*\\)?\\(\\(?:abstract[ \t]+\\)?interface\\|\
-block[ \t]*data\\)\\|contains\\)\\>")
+   ;; F2003.
+   '("\\<\\(use\\)[ \t]*,[ \t]*\\(\\(?:non_\\)?intrinsic\\)[ \t]*::[ \t]*\
+\\(\\sw+\\)"
+     (1 font-lock-keyword-face) (2 font-lock-keyword-face)
+     (3 font-lock-function-name-face))
+   "\\<\\(\\(end[ \t]*\\)?block[ \t]*data\\|contains\\|\
+end[ \t]*interface\\)\\>"
+   ;; "abstract interface" is F2003. Must come after previous entry.
+   '("\\<\\(\\(?:abstract[ \t]*\\)?interface\\)\\>"
+     ;; [ \t]*\\(\\(\\sw+\\)[ \t]*[^(]\\)?"
+     ;; (2) messes up "interface operator ()", etc.
+     (1 font-lock-keyword-face))) ;(2 font-lock-function-name-face nil t)))
   "This does fairly subdued highlighting of comments and function calls.")
 
+;; NB not explicitly handling this, yet it seems to work.
+;; type(...) function foo()
+(defun f90-typedec-matcher (limit)
+  "Search for the declaration of variables of derived type, up to LIMIT.
+Set the match data so that subexpression 1,2 are the TYPE(...),
+and variable-name parts, respectively."
+  ;; Matcher functions must return nil only when there are no more
+  ;; matches within the search range.
+  (let (found l)
+    (while (and (re-search-forward "\\<\\(type\\|class\\)[ \t]*(" limit t)
+                (not
+                 (setq found
+                       (condition-case nil
+                           (progn
+                             ;; Set l after this to just highlight
+                             ;; the "type" part.
+                             (backward-char 1)
+                             ;; Needed for: type( foo(...) ) :: bar
+                             (forward-sexp)
+                             (setq l (list (match-beginning 0) (point)))
+                             (skip-chars-forward " \t")
+                             (when
+                                 (re-search-forward
+                                  ;; type (foo) bar, qux
+                                  (if (looking-at "\\sw+")
+                                      "\\([^&!\n]+\\)"
+                                    ;; type (foo), stuff :: bar, qux
+                                    "::[ \t]*\\([^&!\n]+\\)")
+                                  (line-end-position) t)
+                               (set-match-data
+                                (append (list (car l) (match-end 1))
+                                        l (list (match-beginning 1)
+                                                (match-end 1))))
+                               t))
+                         (error nil))))))
+    found))
+
 (defvar f90-font-lock-keywords-2
   (append
    f90-font-lock-keywords-1
    (list
     ;; Variable declarations (avoid the real function call).
-    ;; FIXME type( rational_t( this_k)), intent( in) :: a, b
-    ;; maybe type should just work like integer.
-    ;; Or use forward-sexp.
-    '("^[ \t0-9]*\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|\
-enumerator\\|generic\\|procedure\\|\
-logical\\|double[ \t]*precision\\|\
-\\(?:type\\|class\\)[ \t]*([ \t]*\\sw+[ \t]*)\\)\
+    ;; NB by accident (?), this correctly fontifies the "integer" in:
+    ;; integer () function foo ()
+    ;; because "() function foo ()" matches \\3.
+    ;; The "pure" part does not really belong here, but was added to
+    ;; exploit that hack.
+    ;; The "function foo" bit is correctly fontified by keywords-1.
+    ;; TODO ? actually check for balanced parens in that case.
+    '("^[ \t0-9]*\\(?:pure\\|elemental\\)?[ \t]*\
+\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|\
+enumerator\\|generic\\|procedure\\|logical\\|double[ \t]*precision\\)\
 \\(.*::\\|[ \t]*(.*)\\)?\\([^&!\n]*\\)"
       (1 font-lock-type-face t) (4 font-lock-variable-name-face t))
+    ;; Derived type/class variables.
+    ;; TODO ? If we just highlighted the "type" part, rather than
+    ;; "type(...)", this could be in the previous expression. And this
+    ;; would be consistent with integer( kind=8 ), etc.
+    '(f90-typedec-matcher
+      (1 font-lock-type-face) (2 font-lock-variable-name-face))
     ;; "real function foo (args)". Must override previous.  Note hack
     ;; to get "args" unhighlighted again. Might not always be right,
     ;; but probably better than leaving them as variables.
-    ;; FIXME in F2003, can specify kinds.
+    ;; NB not explicitly handling this case:
     ;; integer( kind=1 ) function foo()
+    ;; thanks to the happy accident described above.
+    ;; Not anchored, so don't need to worry about "pure" etc.
     '("\\<\\(\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|\
 logical\\|double[ \t]*precision\\|\
 \\(?:type\\|class\\)[ \t]*([ \t]*\\sw+[ \t]*)\\)[ \t]*\\)\
 \\(function\\)\\>[ \t]*\\(\\sw+\\)[ \t]*\\(([^&!\n]*)\\)"
       (1 font-lock-type-face t) (4 font-lock-keyword-face t)
       (5 font-lock-function-name-face t) (6 'default t))
-    ;; end do, if, enum (F2003), select, where, and forall constructs.
+    ;; enum (F2003; cf type in -1).
+    '("\\<\\(enum\\)\\>\\([^()\n]*::\\)?[ \t]*\\(\\sw+\\)"
+      (1 font-lock-keyword-face) (3 font-lock-function-name-face))
+    ;; end do, enum (F2003), if, select, where, and forall constructs.
     '("\\<\\(end[ \t]*\\(do\\|if\\|enum\\|select\\|forall\\|where\\)\\)\\>\
 \\([ \t]+\\(\\sw+\\)\\)?"
       (1 font-lock-keyword-face) (3 font-lock-constant-face nil t))
-    '("^[ \t0-9]*\\(\\(\\sw+\\)[ \t]*:[ \t]*\\)?\\(\\(if\\|enum\\|\
+    '("^[ \t0-9]*\\(\\(\\sw+\\)[ \t]*:[ \t]*\\)?\\(\\(if\\|\
 do\\([ \t]*while\\)?\\|select[ \t]*\\(?:case\\|type\\)\\|where\\|\
 forall\\)\\)\\>"
       (2 font-lock-constant-face nil t) (3 font-lock-keyword-face))
@@ -751,10 +843,12 @@
    ;; Avoid F2003 "type is" in "select type",
    ;; and also variables of derived type "type (foo)".
    ;; "type, foo" must be a block (?).
-   "type[ \t,]\\([^(is]\\|[^(i].\\|[^(][^s]\\|is\\sw\\)"
-   "\\|"
+   "type[ \t,]\\("
+   "[^i(!\n\"\& \t]\\|"                 ; not-i(
+   "i[^s!\n\"\& \t]\\|"                 ; i not-s
+   "is\\sw\\)\\|"
    ;; "abstract interface" is F2003.
-   "program\\|\\(?:abstract[ \t]+\\)?interface\\|module\\|"
+   "program\\|\\(?:abstract[ \t]*\\)?interface\\|module\\|"
    ;; "enum", but not "enumerator".
    "function\\|subroutine\\|enum[^e]\\|associate"
    "\\)"
@@ -771,14 +865,37 @@
 
 
 ;; Imenu support.
-;; FIXME F2003
+;; FIXME trivial to extend this to enum. Worth it?
+(defun f90-imenu-type-matcher ()
+  "Search backward for the start of a derived type.
+Set subexpression 1 in the match-data to the name of the type."
+  (let (found l)
+    (while (and (re-search-backward "^[ \t0-9]*type[ \t]*" nil t)
+                (not (setq found
+                           (save-excursion
+                             (goto-char (match-end 0))
+                             (unless (looking-at "\\(is\\>\\|(\\)")
+                               (or (looking-at "\\(\\sw+\\)")
+                                   (re-search-forward
+                                    "[ \t]*::[ \t]*\\(\\sw+\\)"
+                                    (line-end-position) t))))))))
+    found))
+
 (defvar f90-imenu-generic-expression
   (let ((good-char "[^!\"\&\n \t]") (not-e "[^e!\n\"\& \t]")
-        (not-n "[^n!\n\"\& \t]") (not-d "[^d!\n\"\& \t]"))
+        (not-n "[^n!\n\"\& \t]") (not-d "[^d!\n\"\& \t]")
+        (not-ib "[^i(!\n\"\& \t]") (not-s "[^s!\n\"\& \t]"))
     (list
      '(nil "^[ \t0-9]*program[ \t]+\\(\\sw+\\)" 1)
      '("Modules" "^[ \t0-9]*module[ \t]+\\(\\sw+\\)[ \t]*\\(!\\|$\\)" 1)
-     '("Types" "^[ \t0-9]*type[ \t]+\\(\\sw+\\)" 1)
+     (list "Types" 'f90-imenu-type-matcher 1)
+     ;; Does not handle: "type[, stuff] :: foo".
+;;;      (format "^[ \t0-9]*type[ \t]+\\(\\(%s\\|i%s\\|is\\sw\\)\\sw*\\)"
+;;;              not-ib not-s)
+;;;      1)
+     ;; Can't get the subexpression numbers to match in the two branches.
+;;;      (format "^[ \t0-9]*type\\([ \t]*,.*\\(::\\)[ \t]*\\(\\sw+\\)\\|[ \t]+\\(\\(%s\\|i%s\\|is\\sw\\)\\sw*\\)\\)" not-ib not-s)
+;;;      3)
      (list
       "Procedures"
       (concat
@@ -827,9 +944,9 @@
                          (append element '(nil 0)))))))
    '(("`al"  "allocate"     )
      ("`ab"  "allocatable"  )
+     ("`ai"  "abstract interface")
      ("`as"  "assignment"   )
-;     ("`at"  "abstract"     )
-;     ("`ay"  "asynchronous" )
+     ("`asy" "asynchronous" )
      ("`ba"  "backspace"    )
      ("`bd"  "block data"   )
      ("`c"   "character"    )
@@ -846,8 +963,8 @@
      ("`el"  "else"         )
      ("`eli" "else if"      )
      ("`elw" "elsewhere"    )
-;     ("`em"  "elemental"    )
-     ("`en"  "enumerator"   )
+     ("`em"  "elemental"    )
+     ("`e"   "enumerator"   )
      ("`eq"  "equivalence"  )
      ("`ex"  "external"     )
      ("`ey"  "entry"        )
@@ -1206,7 +1323,7 @@
              (looking-at "\\(do\\|if\\|else\\(if\\|where\\)?\
 \\|select[ \t]*\\(case\\|type\\)\\|case\\|where\\|forall\\)\\>")
              (looking-at "\\(program\\|module\\|\
-\\(?:abstract[ \t]+\\)?interface\\|block[ \t]*data\\)\\>")
+\\(?:abstract[ \t]*\\)?interface\\|block[ \t]*data\\)\\>")
              (looking-at "\\(contains\\|\\sw+[ \t]*:\\)")
              (looking-at f90-type-def-re)
              (re-search-forward "\\(function\\|subroutine\\)"