ob-fortran.el (6398B)
1 ;;; ob-fortran.el --- Babel Functions for Fortran -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2011-2023 Free Software Foundation, Inc. 4 5 ;; Authors: Sergey Litvinov 6 ;; Eric Schulte 7 ;; Keywords: literate programming, reproducible research, fortran 8 ;; URL: https://orgmode.org 9 10 ;; This file is part of GNU Emacs. 11 ;; 12 ;; GNU Emacs is free software: you can redistribute it and/or modify 13 ;; it under the terms of the GNU General Public License as published by 14 ;; the Free Software Foundation, either version 3 of the License, or 15 ;; (at your option) any later version. 16 17 ;; GNU Emacs is distributed in the hope that it will be useful, 18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 ;; GNU General Public License for more details. 21 22 ;; You should have received a copy of the GNU General Public License 23 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 24 25 ;;; Commentary: 26 27 ;; Org-Babel support for evaluating fortran code. 28 29 ;;; Code: 30 31 (require 'org-macs) 32 (org-assert-version) 33 34 (require 'ob) 35 (require 'org-macs) 36 (require 'cc-mode) 37 (require 'cl-lib) 38 39 (declare-function org-entry-get "org" 40 (pom property &optional inherit literal-nil)) 41 42 (defvar org-babel-tangle-lang-exts) 43 (add-to-list 'org-babel-tangle-lang-exts '("fortran" . "F90")) 44 45 (defvar org-babel-default-header-args:fortran '()) 46 47 (defcustom org-babel-fortran-compiler "gfortran" 48 "Fortran command used to compile Fortran source code file." 49 :group 'org-babel 50 :package-version '(Org . "9.5") 51 :type 'string) 52 53 (defun org-babel-execute:fortran (body params) 54 "This function should only be called by `org-babel-execute:fortran'." 55 (let* ((tmp-src-file (org-babel-temp-file "fortran-src-" ".F90")) 56 (tmp-bin-file (org-babel-temp-file "fortran-bin-" org-babel-exeext)) 57 (cmdline (cdr (assq :cmdline params))) 58 (flags (cdr (assq :flags params))) 59 (full-body (org-babel-expand-body:fortran body params))) 60 (with-temp-file tmp-src-file (insert full-body)) 61 (org-babel-eval 62 (format "%s -o %s %s %s" 63 org-babel-fortran-compiler 64 (org-babel-process-file-name tmp-bin-file) 65 (mapconcat 'identity 66 (if (listp flags) flags (list flags)) " ") 67 (org-babel-process-file-name tmp-src-file)) "") 68 (let ((results 69 (org-trim 70 (org-remove-indentation 71 (org-babel-eval 72 (concat tmp-bin-file (if cmdline (concat " " cmdline) "")) ""))))) 73 (org-babel-reassemble-table 74 (org-babel-result-cond (cdr (assq :result-params params)) 75 (org-babel-read results) 76 (let ((tmp-file (org-babel-temp-file "f-"))) 77 (with-temp-file tmp-file (insert results)) 78 (org-babel-import-elisp-from-file tmp-file))) 79 (org-babel-pick-name 80 (cdr (assq :colname-names params)) (cdr (assq :colnames params))) 81 (org-babel-pick-name 82 (cdr (assq :rowname-names params)) (cdr (assq :rownames params))))))) 83 84 (defun org-babel-expand-body:fortran (body params) 85 "Expand a block of fortran or fortran code with org-babel according to 86 its header arguments." 87 (let ((vars (org-babel--get-vars params)) 88 (main-p (not (string= (cdr (assq :main params)) "no"))) 89 (includes (or (cdr (assq :includes params)) 90 (org-babel-read (org-entry-get nil "includes" t)))) 91 (defines (org-babel-read 92 (or (cdr (assq :defines params)) 93 (org-babel-read (org-entry-get nil "defines" t)))))) 94 (mapconcat 'identity 95 (list 96 ;; includes 97 (mapconcat 98 (lambda (inc) (format "#include %s" inc)) 99 (if (listp includes) includes (list includes)) "\n") 100 ;; defines 101 (mapconcat 102 (lambda (inc) (format "#define %s" inc)) 103 (if (listp defines) defines (list defines)) "\n") 104 ;; body 105 (if main-p 106 (org-babel-fortran-ensure-main-wrap 107 (concat 108 ;; variables 109 (mapconcat 'org-babel-fortran-var-to-fortran vars "\n") 110 body) 111 params) 112 body) "\n") "\n"))) 113 114 (defun org-babel-fortran-ensure-main-wrap (body params) 115 "Wrap body in a \"program ... end program\" block if none exists." 116 (if (string-match "^[ \t]*program\\>" (capitalize body)) 117 (let ((vars (org-babel--get-vars params))) 118 (when vars (error "Cannot use :vars if `program' statement is present")) 119 body) 120 (format "program main\n%s\nend program main\n" body))) 121 122 (defun org-babel-prep-session:fortran (_session _params) 123 "This function does nothing as fortran is a compiled language with no 124 support for sessions." 125 (error "Fortran is a compiled languages -- no support for sessions")) 126 127 (defun org-babel-load-session:fortran (_session _body _params) 128 "This function does nothing as fortran is a compiled language with no 129 support for sessions." 130 (error "Fortran is a compiled languages -- no support for sessions")) 131 132 ;; helper functions 133 134 (defun org-babel-fortran-var-to-fortran (pair) 135 "Convert an elisp val into a string of fortran code specifying a var 136 of the same value." 137 ;; TODO list support 138 (let ((var (car pair)) 139 (val (cdr pair))) 140 (when (symbolp val) 141 (setq val (symbol-name val)) 142 (when (= (length val) 1) 143 (setq val (string-to-char val)))) 144 (cond 145 ((integerp val) 146 (format "integer, parameter :: %S = %S\n" var val)) 147 ((floatp val) 148 (format "real, parameter :: %S = %S\n" var val)) 149 ((or (integerp val)) 150 (format "character, parameter :: %S = '%S'\n" var val)) 151 ((stringp val) 152 (format "character(len=%d), parameter :: %S = '%s'\n" 153 (length val) var val)) 154 ;; val is a matrix 155 ((and (listp val) (cl-every #'listp val)) 156 (format "real, parameter :: %S(%d,%d) = transpose( reshape( %s , (/ %d, %d /) ) )\n" 157 var (length val) (length (car val)) 158 (org-babel-fortran-transform-list val) 159 (length (car val)) (length val))) 160 ((listp val) 161 (format "real, parameter :: %S(%d) = %s\n" 162 var (length val) (org-babel-fortran-transform-list val))) 163 (t 164 (error "The type of parameter %s is not supported by ob-fortran" var))))) 165 166 (defun org-babel-fortran-transform-list (val) 167 "Return a fortran representation of enclose syntactic lists." 168 (if (listp val) 169 (concat "(/" (mapconcat #'org-babel-fortran-transform-list val ", ") "/)") 170 (format "%S" val))) 171 172 (provide 'ob-fortran) 173 174 ;;; ob-fortran.el ends here