dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

ob-ocaml.el (6312B)


      1 ;;; ob-ocaml.el --- Babel Functions for Ocaml        -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2009-2023 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 a block of Ocaml code with Babel."
     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   (require '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   (mapcar
    126    (lambda (pair) (format "let %s = %s;;" (car pair)
    127 			  (org-babel-ocaml-elisp-to-ocaml (cdr pair))))
    128    (org-babel--get-vars params)))
    129 
    130 (defun org-babel-ocaml-elisp-to-ocaml (val)
    131   "Return a string of ocaml code which evaluates to VAL."
    132   (if (listp val)
    133       (concat "[|" (mapconcat #'org-babel-ocaml-elisp-to-ocaml val "; ") "|]")
    134     (format "%S" val)))
    135 
    136 (defun org-babel-ocaml-parse-output (value type)
    137   "Parse VALUE of type TYPE.
    138 VALUE and TYPE are string output from an ocaml process."
    139   (cond
    140    ((string= "string" type)
    141     (org-babel-read value))
    142    ((or (string= "int" type)
    143 	(string= "float" type))
    144     (string-to-number value))
    145    ((string-match "list" type)
    146     (org-babel-ocaml-read-list value))
    147    ((string-match "array" type)
    148     (org-babel-ocaml-read-array value))
    149    (t (message "don't recognize type %s" type) value)))
    150 
    151 (defun org-babel-ocaml-read-list (results)
    152   "Convert RESULTS into an elisp table or string.
    153 If the results look like a table, then convert them into an
    154 Emacs-lisp table, otherwise return the results as a string."
    155   ;; XXX: This probably does not behave as expected when a semicolon
    156   ;; is in a string in a list.  The same comment applies to
    157   ;; `org-babel-ocaml-read-array' below (with even more failure
    158   ;; modes).
    159   (org-babel-script-escape (replace-regexp-in-string ";" "," results)))
    160 
    161 (defun org-babel-ocaml-read-array (results)
    162   "Convert RESULTS into an elisp table or string.
    163 If the results look like a table, then convert them into an
    164 Emacs-lisp table, otherwise return the results as a string."
    165   (org-babel-script-escape
    166    (replace-regexp-in-string
    167     "\\[|" "[" (replace-regexp-in-string
    168 		"|\\]" "]" (replace-regexp-in-string
    169 			    "; " "," results)))))
    170 
    171 (provide 'ob-ocaml)
    172 
    173 ;;; ob-ocaml.el ends here