1;;; ob-maxima.el --- Babel Functions for Maxima      -*- lexical-binding: t; -*-
2
3;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
4
5;; Author: Eric S Fraga
6;;	Eric Schulte
7;; Keywords: literate programming, reproducible research, maxima
8;; Homepage: 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 maxima entries.
28;;
29;; This differs from most standard languages in that
30;; 1) there is no such thing as a "session" in maxima
31;; 2) we are adding the "cmdline" header argument
32
33;;; Code:
34(require 'ob)
35
36(defvar org-babel-tangle-lang-exts)
37(add-to-list 'org-babel-tangle-lang-exts '("maxima" . "max"))
38
39(defvar org-babel-default-header-args:maxima '())
40
41(defcustom org-babel-maxima-command
42  (if (boundp 'maxima-command) maxima-command "maxima")
43  "Command used to call maxima on the shell."
44  :group 'org-babel
45  :type 'string)
46
47(defun org-babel-maxima-expand (body params)
48  "Expand a block of Maxima code according to its header arguments."
49  (let ((vars (org-babel--get-vars params))
50	(epilogue (cdr (assq :epilogue params)))
51	(prologue (cdr (assq :prologue params))))
52    (mapconcat 'identity
53	       (list
54		;; Any code from the specified prologue at the start.
55		prologue
56		;; graphic output
57		(let ((graphic-file (ignore-errors (org-babel-graphical-output-file params))))
58		  (if graphic-file
59		      (format
60		       "set_plot_option ([gnuplot_term, png]); set_plot_option ([gnuplot_out_file, %S]);"
61		       graphic-file)
62		    ""))
63		;; variables
64		(mapconcat 'org-babel-maxima-var-to-maxima vars "\n")
65		;; body
66		body
67		;; Any code from the specified epilogue at the end.
68		epilogue
69		"gnuplot_close ()$")
70	       "\n")))
71
72(defun org-babel-execute:maxima (body params)
73  "Execute a block of Maxima entries with org-babel.
74This function is called by `org-babel-execute-src-block'."
75  (message "executing Maxima source code block")
76  (let ((result-params (split-string (or (cdr (assq :results params)) "")))
77	(result
78	 (let* ((cmdline (or (cdr (assq :cmdline params)) ""))
79		(in-file (org-babel-temp-file "maxima-" ".max"))
80		(cmd (format "%s --very-quiet -r 'batchload(%S)$' %s"
81			     org-babel-maxima-command in-file cmdline)))
82	   (with-temp-file in-file (insert (org-babel-maxima-expand body params)))
83	   (message cmd)
84           ;; " | grep -v batch | grep -v 'replaced' | sed '/^$/d' "
85	   (let ((raw (org-babel-eval cmd "")))
86             (mapconcat
87              #'identity
88              (delq nil
89                    (mapcar (lambda (line)
90                              (unless (or (string-match "batch" line)
91                                          (string-match "^rat: replaced .*$" line)
92                                          (string-match "^;;; Loading #P" line)
93                                          (= 0 (length line)))
94                                line))
95                            (split-string raw "[\r\n]"))) "\n")))))
96    (if (ignore-errors (org-babel-graphical-output-file params))
97	nil
98      (org-babel-result-cond result-params
99	result
100	(let ((tmp-file (org-babel-temp-file "maxima-res-")))
101	  (with-temp-file tmp-file (insert result))
102	  (org-babel-import-elisp-from-file tmp-file))))))
103
104
105(defun org-babel-prep-session:maxima (_session _params)
106  (error "Maxima does not support sessions"))
107
108(defun org-babel-maxima-var-to-maxima (pair)
109  "Convert an elisp val into a string of maxima code specifying a var
110of the same value."
111  (let ((var (car pair))
112        (val (cdr pair)))
113    (when (symbolp val)
114      (setq val (symbol-name val))
115      (when (= (length val) 1)
116        (setq val (string-to-char val))))
117    (format "%S: %s$" var
118	    (org-babel-maxima-elisp-to-maxima val))))
119
120(defun org-babel-maxima-elisp-to-maxima (val)
121  "Return a string of maxima code which evaluates to VAL."
122  (if (listp val)
123      (concat "[" (mapconcat #'org-babel-maxima-elisp-to-maxima val ", ") "]")
124    (format "%s" val)))
125
126(provide 'ob-maxima)
127
128;;; ob-maxima.el ends here
129