ob-ocaml.el (6359B)
1 ;;; ob-ocaml.el --- Babel Functions for Ocaml -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2009-2024 Free Software Foundation, Inc. 4 5 ;; Author: Eric Schulte 6 ;; Keywords: literate programming, reproducible research 7 ;; URL: https://orgmode.org 8 9 ;; This file is part of GNU Emacs. 10 11 ;; GNU Emacs is free software: you can redistribute it and/or modify 12 ;; it under the terms of the GNU General Public License as published by 13 ;; the Free Software Foundation, either version 3 of the License, or 14 ;; (at your option) any later version. 15 16 ;; GNU Emacs is distributed in the hope that it will be useful, 17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 ;; GNU General Public License for more details. 20 21 ;; You should have received a copy of the GNU General Public License 22 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 23 24 ;;; Commentary: 25 26 ;; Org-Babel support for evaluating ocaml source code. This one will 27 ;; be sort of tricky because ocaml programs must be compiled before 28 ;; they can be run, but ocaml code can also be run through an 29 ;; interactive interpreter. 30 ;; 31 ;; For now lets only allow evaluation using the ocaml interpreter. 32 33 ;;; Requirements: 34 35 ;; - tuareg-mode :: https://elpa.nongnu.org/nongnu/tuareg.html 36 37 ;;; Code: 38 39 (require 'org-macs) 40 (org-assert-version) 41 42 (require 'ob) 43 (require 'comint) 44 (require 'org-macs) 45 46 (declare-function tuareg-run-caml "ext:tuareg" ()) 47 (declare-function tuareg-run-ocaml "ext:tuareg" ()) 48 (declare-function tuareg-interactive-send-input "ext:tuareg" ()) 49 50 (defvar org-babel-tangle-lang-exts) 51 (add-to-list 'org-babel-tangle-lang-exts '("ocaml" . "ml")) 52 53 (defvar org-babel-default-header-args:ocaml '()) 54 55 (defvar org-babel-ocaml-eoe-indicator "\"org-babel-ocaml-eoe\";;") 56 (defvar org-babel-ocaml-eoe-output "org-babel-ocaml-eoe") 57 58 (defcustom org-babel-ocaml-command "ocaml" 59 "Name of the command for executing Ocaml code." 60 :version "24.4" 61 :package-version '(Org . "8.0") 62 :group 'org-babel 63 :type 'string) 64 65 (defun org-babel-execute:ocaml (body params) 66 "Execute Ocaml BODY according to PARAMS." 67 (let* ((full-body (org-babel-expand-body:generic 68 body params 69 (org-babel-variable-assignments:ocaml params))) 70 (session (org-babel-prep-session:ocaml 71 (cdr (assq :session params)) params)) 72 (raw (org-babel-comint-with-output 73 (session org-babel-ocaml-eoe-output nil full-body) 74 (insert 75 (concat 76 (org-babel-chomp full-body) ";;\n" 77 org-babel-ocaml-eoe-indicator)) 78 (tuareg-interactive-send-input))) 79 (clean 80 (car (let ((re (regexp-quote org-babel-ocaml-eoe-output)) out) 81 (delq nil (mapcar (lambda (line) 82 (if out 83 (progn (setq out nil) line) 84 (when (string-match re line) 85 (progn (setq out t) nil)))) 86 (mapcar #'org-trim (reverse raw))))))) 87 (raw (org-trim clean)) 88 (result-params (cdr (assq :result-params params)))) 89 (string-match 90 "\\(\\(.*\n\\)*\\)[^:\n]+ : \\([^=\n]+\\) =[[:space:]]+\\(\\(.\\|\n\\)+\\)$" 91 raw) 92 (let ((output (match-string 1 raw)) 93 (type (match-string 3 raw)) 94 (value (match-string 4 raw))) 95 (org-babel-reassemble-table 96 (org-babel-result-cond result-params 97 (cond 98 ((member "verbatim" result-params) raw) 99 ((member "output" result-params) output) 100 (t raw)) 101 (if (and value type) 102 (org-babel-ocaml-parse-output value type) 103 raw)) 104 (org-babel-pick-name 105 (cdr (assq :colname-names params)) (cdr (assq :colnames params))) 106 (org-babel-pick-name 107 (cdr (assq :rowname-names params)) (cdr (assq :rownames params))))))) 108 109 (defvar tuareg-interactive-buffer-name) 110 (defun org-babel-prep-session:ocaml (session _params) 111 "Prepare SESSION according to the header arguments in PARAMS." 112 (org-require-package 'tuareg) 113 (let ((tuareg-interactive-buffer-name (if (and (not (string= session "none")) 114 (not (string= session "default")) 115 (stringp session)) 116 session 117 tuareg-interactive-buffer-name))) 118 (save-window-excursion (if (fboundp 'tuareg-run-process-if-needed) 119 (tuareg-run-process-if-needed org-babel-ocaml-command) 120 (tuareg-run-caml))) 121 (get-buffer tuareg-interactive-buffer-name))) 122 123 (defun org-babel-variable-assignments:ocaml (params) 124 "Return list of ocaml statements assigning the block's variables. 125 The variables are defined in PARAMS." 126 (mapcar 127 (lambda (pair) (format "let %s = %s;;" (car pair) 128 (org-babel-ocaml-elisp-to-ocaml (cdr pair)))) 129 (org-babel--get-vars params))) 130 131 (defun org-babel-ocaml-elisp-to-ocaml (val) 132 "Return a string of ocaml code which evaluates to VAL." 133 (if (listp val) 134 (concat "[|" (mapconcat #'org-babel-ocaml-elisp-to-ocaml val "; ") "|]") 135 (format "%S" val))) 136 137 (defun org-babel-ocaml-parse-output (value type) 138 "Parse VALUE of type TYPE. 139 VALUE and TYPE are string output from an ocaml process." 140 (cond 141 ((string= "string" type) 142 (org-babel-read value)) 143 ((or (string= "int" type) 144 (string= "float" type)) 145 (string-to-number value)) 146 ((string-match "list" type) 147 (org-babel-ocaml-read-list value)) 148 ((string-match "array" type) 149 (org-babel-ocaml-read-array value)) 150 (t (message "don't recognize type %s" type) value))) 151 152 (defun org-babel-ocaml-read-list (results) 153 "Convert RESULTS into an elisp table or string. 154 If the results look like a table, then convert them into an 155 Emacs-lisp table, otherwise return the results as a string." 156 ;; XXX: This probably does not behave as expected when a semicolon 157 ;; is in a string in a list. The same comment applies to 158 ;; `org-babel-ocaml-read-array' below (with even more failure 159 ;; modes). 160 (org-babel-script-escape (replace-regexp-in-string ";" "," results))) 161 162 (defun org-babel-ocaml-read-array (results) 163 "Convert RESULTS into an elisp table or string. 164 If the results look like a table, then convert them into an 165 Emacs-lisp table, otherwise return the results as a string." 166 (org-babel-script-escape 167 (replace-regexp-in-string 168 "\\[|" "[" (replace-regexp-in-string 169 "|\\]" "]" (replace-regexp-in-string 170 "; " "," results))))) 171 172 (provide 'ob-ocaml) 173 174 ;;; ob-ocaml.el ends here