;;; f90.el --- Fortran-90 mode (free format)
-;; Copyright (C) 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005,
-;; 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+;; Copyright (C) 1995-1997, 2000-2012 Free Software Foundation, Inc.
-;; Author: Torbj\"orn Einarsson <Torbjorn.Einarsson@era.ericsson.se>
+;; Author: Torbjรถrn Einarsson <Torbjorn.Einarsson@era.ericsson.se>
;; Maintainer: Glenn Morris <rgm@gnu.org>
;; Keywords: fortran, f90, languages
;; Major mode for editing F90 programs in FREE FORMAT.
;; The minor language revision F95 is also supported (with font-locking).
;; Some/many (?) aspects of F2003 are supported.
+;; Some aspects of F2008 are supported.
;; Knows about continuation lines, named structured statements, and other
;; features in F90 including HPF (High Performance Fortran) structures.
;; To customize f90-mode for your taste, use, for example:
;; (you don't have to specify values for all the parameters below)
;;
-;;(add-hook 'f90-mode-hook
-;; ;; These are the default values.
-;; '(lambda () (setq f90-do-indent 3
+;; (add-hook 'f90-mode-hook
+;; ;; These are the default values.
+;; (lambda () (setq f90-do-indent 3
;; f90-if-indent 3
;; f90-type-indent 3
;; f90-program-indent 2
:group 'f90-indent
:version "23.1")
+(defcustom f90-critical-indent 2
+ "Extra indentation applied to BLOCK, CRITICAL blocks."
+ :type 'integer
+ :safe 'integerp
+ :group 'f90-indent
+ :version "24.1")
+
(defcustom f90-continuation-indent 5
"Extra indentation applied to continuation lines."
:type 'integer
"deferred" "enum" "enumerator" "extends" "extends_type_of"
"final" "generic" "import" "non_intrinsic" "non_overridable"
"nopass" "pass" "protected" "same_type_as" "value" "volatile"
+ ;; F2008.
+ "contiguous" "submodule" "concurrent" "codimension"
+ "sync all" "sync memory" "critical" "image_index"
) 'words)
"Regexp used by the function `f90-change-keywords'.")
;; F2003. asynchronous separate.
"abstract" "deferred" "import" "final" "non_intrinsic" "non_overridable"
"nopass" "pass" "protected" "value" "volatile"
+ ;; F2008.
+ ;; "concurrent" is only in the sense of "do [,] concurrent", but given
+ ;; the [,] it's simpler to just do every instance (cf "do while").
+ "contiguous" "concurrent" "codimension" "sync all" "sync memory"
) 'words)
"Keyword-regexp for font-lock level >= 3.")
;; F2003 iso_c_binding intrinsic module.
"c_loc" "c_funloc" "c_associated" "c_f_pointer"
"c_f_procpointer"
+ ;; F2008.
+ "bge" "bgt" "ble" "blt" "dshiftl" "dshiftr" "leadz" "popcnt"
+ "poppar" "trailz" "maskl" "maskr" "shifta" "shiftl" "shiftr"
+ "merge_bits" "iall" "iany" "iparity" "storage_size"
+ "bessel_j0" "bessel_j1" "bessel_jn"
+ "bessel_y0" "bessel_y1" "bessel_yn"
+ "erf" "erfc" "erfc_scaled" "gamma" "hypot" "log_gamma"
+ "norm2" "parity" "findloc" "is_contiguous"
+ "sync images" "lock" "unlock" "image_index"
+ "lcobound" "ucobound" "num_images" "this_image"
+ ;; F2008 iso_fortran_env module.
+ "compiler_options" "compiler_version"
+ ;; F2008 iso_c_binding module.
+ "c_sizeof"
) t)
;; A left parenthesis to avoid highlighting non-procedures.
"[ \t]*(")
"ieee_exceptions"
"ieee_arithmetic"
"ieee_features"
+ ;; F2008 iso_fortran_env constants.
+ "character_kinds" "int8" "int16" "int32" "int64"
+ "integer_kinds" "iostat_inquire_internal_unit"
+ "logical_kinds" "real_kinds" "real32" "real64" "real128"
+ "lock_type" "atomic_int_kind" "atomic_logical_kind"
) 'words)
"Regexp for Fortran intrinsic constants.")
;;; (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))
- ;; F2003. Prevent operators being highlighted as functions.
- '("\\<\\(\\(?:end[ \t]*\\)?interface[ \t]*\\(?:assignment\\|operator\\|\
+ ;; F2003. Prevent operators being highlighted as functions.
+ '("\\<\\(\\(?:end[ \t]*\\)?interface[ \t]*\\(?:assignment\\|operator\\|\
read\\|write\\)\\)[ \t]*(" (1 font-lock-keyword-face t))
;; Other functions and declarations. Named interfaces = F2003.
- '("\\<\\(\\(?:end[ \t]*\\)?\\(program\\|module\\|function\\|associate\\|\
-subroutine\\|interface\\)\\|use\\|call\\)\\>[ \t]*\\(\\sw+\\)?"
+ ;; F2008: end submodule submodule_name.
+ '("\\<\\(\\(?:end[ \t]*\\)?\\(program\\|\\(?:sub\\)?module\\|\
+function\\|associate\\|subroutine\\|interface\\)\\|use\\|call\\)\
+\\>[ \t]*\\(\\sw+\\)?"
(1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
+ ;; F2008: submodule (parent_name) submodule_name.
+ '("\\<\\(submodule\\)\\>[ \t]*([^)\n]+)[ \t]*\\(\\sw+\\)?"
+ (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t))
;; F2003.
'("\\<\\(use\\)[ \t]*,[ \t]*\\(\\(?:non_\\)?intrinsic\\)[ \t]*::[ \t]*\
\\(\\sw+\\)"
;; enum (F2003; must be followed by ", bind(C)").
'("\\<\\(enum\\)[ \t]*," (1 font-lock-keyword-face))
;; end do, enum (F2003), if, select, where, and forall constructs.
- '("\\<\\(end[ \t]*\\(do\\|if\\|enum\\|select\\|forall\\|where\\)\\)\\>\
+ ;; block, critical (F2008).
+ ;; Note that "block data" may get somewhat mixed up with F2008 blocks,
+ ;; but since the former is obsolete I'm not going to worry about it.
+ '("\\<\\(end[ \t]*\\(do\\|if\\|enum\\|select\\|forall\\|where\\|\
+block\\|critical\\)\\)\\>\
\\([ \t]+\\(\\sw+\\)\\)?"
(1 font-lock-keyword-face) (3 font-lock-constant-face nil t))
'("^[ \t0-9]*\\(\\(\\sw+\\)[ \t]*:[ \t]*\\)?\\(\\(if\\|\
do\\([ \t]*while\\)?\\|select[ \t]*\\(?:case\\|type\\)\\|where\\|\
-forall\\)\\)\\>"
+forall\\|block\\|critical\\)\\)\\>"
(2 font-lock-constant-face nil t) (3 font-lock-keyword-face))
;; Implicit declaration.
'("\\<\\(implicit\\)[ \t]*\\(real\\|integer\\|c\\(haracter\\|omplex\\)\
(modify-syntax-entry ?= "." table)
(modify-syntax-entry ?* "." table)
(modify-syntax-entry ?/ "." table)
+ (modify-syntax-entry ?% "." table) ; bug#8820
;; I think that the f95 standard leaves the behavior of \
;; unspecified, but that f2k will require it to be non-special.
;; Use `f90-backslash-not-special' to change.
["Reset to Saved" Custom-reset-saved :active t
:help "Reset all edited or set settings to saved"]
["Reset to Standard Settings" Custom-reset-standard :active t
- :help "Erase all cusomizations in buffer"]
+ :help "Erase all customizations in buffer"]
)
"--"
["Indent Subprogram" f90-indent-subprogram t]
(regexp-opt '("do" "if" "interface" "function" "module" "program"
"select" "subroutine" "type" "where" "forall"
;; F2003.
- "enum" "associate"))
+ "enum" "associate"
+ ;; F2008.
+ "submodule" "block" "critical"))
"\\)\\>")
"Regexp potentially indicating a \"block\" of F90 code.")
(defconst f90-program-block-re
- (regexp-opt '("program" "module" "subroutine" "function") 'paren)
+ (regexp-opt '("program" "module" "subroutine" "function" "submodule") 'paren)
"Regexp used to locate the start/end of a \"subprogram\".")
;; "class is" is F2003.
;; type word
;; type :: word
;; type, stuff :: word
+ ;; type, bind(c) :: word
;; NOT "type ("
- "\\<\\(type\\)\\>\\(?:[^()\n]*::\\)?[ \t]*\\(\\sw+\\)"
+ "\\<\\(type\\)\\>\\(?:\\(?:[^()\n]*\\|\
+.*,[ \t]*bind[ \t]*([ \t]*c[ \t]*)[ \t]*\\)::\\)?[ \t]*\\(\\sw+\\)"
"Regexp matching the definition of a derived type.")
(defconst f90-typeis-re
(concat "^[ \t0-9]*\\<end[ \t]*"
(regexp-opt '("do" "if" "forall" "function" "interface"
"module" "program" "select" "subroutine"
- "type" "where" "enum" "associate") t)
+ "type" "where" "enum" "associate" "submodule"
+ "block" "critical") t)
"\\>")
"Regexp matching the end of an F90 \"block\", from the line start.
Used in the F90 entry in `hs-special-modes-alist'.")
"[^i(!\n\"\& \t]\\|" ; not-i(
"i[^s!\n\"\& \t]\\|" ; i not-s
"is\\sw\\)\\|"
- ;; "abstract interface" is F2003.
- "program\\|\\(?:abstract[ \t]*\\)?interface\\|module\\|"
+ ;; "abstract interface" is F2003; "submodule" is F2008.
+ "program\\|\\(?:abstract[ \t]*\\)?interface\\|\\(?:sub\\)?module\\|"
;; "enum", but not "enumerator".
- "function\\|subroutine\\|enum[^e]\\|associate"
+ "function\\|subroutine\\|enum[^e]\\|associate\\|block\\|critical"
"\\)"
"[ \t]*")
"Regexp matching the start of an F90 \"block\", from the line start.
)
(list
'(nil "^[ \t0-9]*program[ \t]+\\(\\sw+\\)" 1)
+ '("Submodules" "^[ \t0-9]*submodule[ \t]*([^)\n]+)[ \t]*\
+\\(\\sw+\\)[ \t]*\\(!\\|$\\)" 1)
'("Modules" "^[ \t0-9]*module[ \t]+\\(\\sw+\\)[ \t]*\\(!\\|$\\)" 1)
(list "Types" 'f90-imenu-type-matcher 1)
;; Does not handle: "type[, stuff] :: foo".
("`asy" . "asynchronous" )
("`ba" . "backspace" )
("`bd" . "block data" )
+ ("`bl" . "block" )
("`c" . "character" )
("`cl" . "close" )
("`cm" . "common" )
("`cx" . "complex" )
("`cn" . "contains" )
+ ("`cr" . "critical" )
("`cy" . "cycle" )
("`de" . "deallocate" )
("`df" . "define" )
`f90-program-indent'
Extra indentation within program/module/subroutine/function blocks
(default 2).
+`f90-associate-indent'
+ Extra indentation within associate blocks (default 2).
+`f90-critical-indent'
+ Extra indentation within critical/block blocks (default 2).
`f90-continuation-indent'
Extra indentation applied to continuation lines (default 5).
`f90-comment-region'
(if (looking-at "\\<\\(associate\\)[ \t]*(")
(list (match-string 1))))
+(defsubst f90-looking-at-critical ()
+ "Return (KIND NAME) if a critical or block block starts after point."
+ (if (looking-at "\\(\\(\\sw+\\)[ \t]*:\\)?[ \t]*\\(critical\\|block\\)\\>")
+ (let ((struct (match-string 3))
+ (label (match-string 2)))
+ (if (or (not (string-equal "block" struct))
+ (save-excursion
+ (skip-chars-forward " \t")
+ (not (looking-at "data\\>"))))
+ (list struct label)))))
+
+(defsubst f90-looking-at-end-critical ()
+ "Return non-nil if a critical or block block ends after point."
+ (if (looking-at "end[ \t]*\\(critical\\|block\\)\\>")
+ (or (not (string-equal "block" (match-string 1)))
+ (save-excursion
+ (skip-chars-forward " \t")
+ (not (looking-at "data\\>"))))))
+
(defsubst f90-looking-at-where-or-forall ()
"Return (KIND NAME) if a where or forall block starts after point.
NAME is nil if the statement has no label."
((and (not (looking-at "module[ \t]*procedure\\>"))
(looking-at "\\(module\\)[ \t]+\\(\\sw+\\)\\>"))
(list (match-string 1) (match-string 2)))
+ ((looking-at "\\(submodule\\)[ \t]*([^)\n]+)[ \t]*\\(\\sw+\\)\\>")
+ (list (match-string 1) (match-string 2)))
((and (not (looking-at "end[ \t]*\\(function\\|subroutine\\)"))
(looking-at "[^!'\"\&\n]*\\(function\\|subroutine\\)[ \t]+\
\\(\\sw+\\)"))
(save-excursion
(not (or (looking-at "end")
(looking-at "\\(do\\|if\\|else\\(if\\|where\\)?\
-\\|select[ \t]*\\(case\\|type\\)\\|case\\|where\\|forall\\)\\>")
- (looking-at "\\(program\\|module\\|\
+\\|select[ \t]*\\(case\\|type\\)\\|case\\|where\\|forall\\|\
+block\\|critical\\)\\>")
+ (looking-at "\\(program\\|\\(?:sub\\)?module\\|\
\\(?:abstract[ \t]*\\)?interface\\|block[ \t]*data\\)\\>")
(looking-at "\\(contains\\|\\sw+[ \t]*:\\)")
(looking-at f90-type-def-re)
(defun f90-get-correct-indent ()
"Get correct indent for a line starting with line number.
Does not check type and subprogram indentation."
- (let ((epnt (line-end-position)) icol cont)
+ (let ((epnt (line-end-position)) icol)
(save-excursion
(while (and (f90-previous-statement)
- (or (memq (setq cont (f90-present-statement-cont))
- '(middle end))
+ (or (memq (f90-present-statement-cont) '(middle end))
(looking-at "[ \t]*[0-9]"))))
(setq icol (current-indentation))
(beginning-of-line)
(f90-looking-at-where-or-forall)
(f90-looking-at-select-case))
(setq icol (+ icol f90-if-indent)))
+ ;; FIXME this makes no sense, because this section/function is
+ ;; only for if/do/select/where/forall ?
((f90-looking-at-associate)
(setq icol (+ icol f90-associate-indent))))
(end-of-line))
(f90-looking-at-where-or-forall)
(f90-looking-at-select-case))
(setq icol (+ icol f90-if-indent)))
+ ;; FIXME this makes no sense, because this section/function is
+ ;; only for if/do/select/where/forall ?
((f90-looking-at-associate)
(setq icol (+ icol f90-associate-indent)))
((looking-at f90-end-if-re)
(setq icol (- icol f90-if-indent)))
((looking-at f90-end-associate-re)
(setq icol (- icol f90-associate-indent)))
+ ((f90-looking-at-end-critical)
+ (setq icol (- icol f90-critical-indent)))
((looking-at "end[ \t]*do\\>")
(setq icol (- icol f90-do-indent))))
(end-of-line))
(if (not (f90-previous-statement))
;; If f90-previous-statement returns nil, we must have been
;; called from on or before the first line of the first statement.
- (setq icol (if (save-excursion
- ;; f90-previous-statement has moved us over
- ;; comment/blank lines, so we need to get
- ;; back to the first code statement.
- (when (looking-at "[ \t]*\\([!#]\\|$\\)")
- (f90-next-statement))
- (skip-chars-forward " \t0-9")
- (f90-looking-at-program-block-start))
+ (setq icol (if (or (save-excursion
+ (goto-char pnt)
+ (beginning-of-line)
+ ;; Preprocessor line before code statement.
+ (looking-at "[ \t]*#"))
+ (progn
+ ;; f90-previous-statement has moved us over
+ ;; comment/blank lines, so we need to get
+ ;; back to the first code statement.
+ (when (looking-at "[ \t]*\\([!#]\\|$\\)")
+ (f90-next-statement))
+ (skip-chars-forward " \t0-9")
+ (f90-looking-at-program-block-start)))
0
;; No explicit PROGRAM start statement.
f90-program-indent))
(setq icol (+ icol f90-type-indent)))
((f90-looking-at-associate)
(setq icol (+ icol f90-associate-indent)))
+ ((f90-looking-at-critical)
+ (setq icol (+ icol f90-critical-indent)))
((or (f90-looking-at-program-block-start)
(looking-at "contains[ \t]*\\($\\|!\\)"))
(setq icol (+ icol f90-program-indent)))))
(setq icol (- icol f90-type-indent)))
((looking-at f90-end-associate-re)
(setq icol (- icol f90-associate-indent)))
+ ((f90-looking-at-end-critical)
+ (setq icol (- icol f90-critical-indent)))
((or (looking-at "contains[ \t]*\\(!\\|$\\)")
(f90-looking-at-program-block-end))
(setq icol (- icol f90-program-indent))))))))))
(while (and (setq not-last-statement
(and (zerop (forward-line 1))
(not (eobp))))
- (looking-at "[ \t0-9]*\\(!\\|$\\)")))
+ (looking-at "[ \t0-9]*\\(!\\|$\\|#\\)")))
not-last-statement))
(defun f90-beginning-of-subprogram ()
(f90-looking-at-select-case)
(f90-looking-at-type-like)
(f90-looking-at-associate)
+ (f90-looking-at-critical)
(f90-looking-at-program-block-start)
(f90-looking-at-if-then)
(f90-looking-at-where-or-forall)))
(f90-looking-at-select-case)
(f90-looking-at-type-like)
(f90-looking-at-associate)
+ (f90-looking-at-critical)
(f90-looking-at-program-block-start)
(f90-looking-at-if-then)
(f90-looking-at-where-or-forall)))
(f90-looking-at-select-case)
(f90-looking-at-type-like)
(f90-looking-at-associate)
+ (f90-looking-at-critical)
(f90-looking-at-program-block-start)
(f90-looking-at-if-then)
(f90-looking-at-where-or-forall))
(and (< (point) pos)
(goto-char pos))
(if auto-fill-function
- ;; GM NO-UPDATE not honoured, since this calls f90-update-line.
+ ;; GM NO-UPDATE not honored, since this calls f90-update-line.
(f90-do-auto-fill)
(or no-update (f90-update-line)))
(set-marker pos nil)))
f90-type-indent)
((setq struct (f90-looking-at-associate))
f90-associate-indent)
+ ((setq struct (f90-looking-at-critical))
+ f90-critical-indent)
((or (setq struct (f90-looking-at-program-block-start))
(looking-at "contains[ \t]*\\($\\|!\\)"))
f90-program-indent)))
f90-type-indent)
((setq struct (f90-looking-at-associate))
f90-associate-indent)
+ ((setq struct (f90-looking-at-critical))
+ f90-critical-indent)
((setq struct (f90-looking-at-program-block-start))
f90-program-indent)))
(setq ind-curr ind-lev)
((looking-at f90-end-type-re) f90-type-indent)
((looking-at f90-end-associate-re)
f90-associate-indent)
+ ((f90-looking-at-end-critical) f90-critical-indent)
((f90-looking-at-program-block-end)
f90-program-indent)))
(if ind-b (setq ind-lev (- ind-lev ind-b)))
(cond ((f90-in-string)
(insert "&\n&"))
((f90-in-comment)
- (delete-horizontal-space 'backwards) ; remove trailing whitespace
+ (delete-horizontal-space) ; remove trailing whitespace
(insert "\n" (f90-get-present-comment-type)))
(t (insert "&")
(or no-update (f90-update-line))
(defun f90-find-breakpoint ()
"From `fill-column', search backward for break-delimiter."
- (re-search-backward f90-break-delimiters (line-beginning-position))
- (if (not f90-break-before-delimiters)
- (forward-char (if (looking-at f90-no-break-re) 2 1))
- (backward-char)
- (or (looking-at f90-no-break-re)
- (forward-char))))
+ ;; Commented text more likely than commented code.
+ (if (f90-in-comment)
+ (re-search-backward "\\s-" (line-beginning-position))
+ (re-search-backward f90-break-delimiters (line-beginning-position))
+ (if (not f90-break-before-delimiters)
+ (forward-char (if (looking-at f90-no-break-re) 2 1))
+ (backward-char)
+ (or (looking-at f90-no-break-re)
+ (forward-char)))))
(defun f90-do-auto-fill ()
"Break line if non-white characters beyond `fill-column'.
(f90-looking-at-select-case)
(f90-looking-at-type-like)
(f90-looking-at-associate)
+ (f90-looking-at-critical)
(f90-looking-at-program-block-start)
;; Interpret a single END without a block
;; start to be the END of a program block
(save-excursion
(nth 1 (f90-beginning-of-subprogram))))
-
(defun f90-backslash-not-special (&optional all)
"Make the backslash character (\\) be non-special in the current buffer.
With optional argument ALL, change the default for all present
(provide 'f90)
-;; arch-tag: fceac97c-c147-44bd-aec0-172d4b560ef8
+;; Local Variables:
+;; coding: utf-8
+;; lexical-binding: t
+;; End:
+
;;; f90.el ends here