ob-lisp.el (5325B)
1 ;;; ob-lisp.el --- Babel Functions for Common Lisp -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2009-2024 Free Software Foundation, Inc. 4 5 ;; Authors: Joel Boehland 6 ;; Eric Schulte 7 ;; David T. O'Toole <dto@gnu.org> 8 ;; Keywords: literate programming, reproducible research 9 ;; URL: https://orgmode.org 10 11 ;; This file is part of GNU Emacs. 12 13 ;; GNU Emacs is free software: you can redistribute it and/or modify 14 ;; it under the terms of the GNU General Public License as published by 15 ;; the Free Software Foundation, either version 3 of the License, or 16 ;; (at your option) any later version. 17 18 ;; GNU Emacs is distributed in the hope that it will be useful, 19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 ;; GNU General Public License for more details. 22 23 ;; You should have received a copy of the GNU General Public License 24 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 25 26 ;;; Commentary: 27 28 ;;; Support for evaluating Common Lisp code, relies on SLY or SLIME 29 ;;; for all eval. 30 31 ;;; Requirements: 32 33 ;; Requires SLY (Sylvester the Cat's Common Lisp IDE) or SLIME 34 ;; (Superior Lisp Interaction Mode for Emacs). See: 35 ;; - https://github.com/capitaomorte/sly 36 ;; - https://common-lisp.net/project/slime/ 37 38 ;;; Code: 39 40 (require 'org-macs) 41 (org-assert-version) 42 43 (require 'ob) 44 (require 'org-macs) 45 46 (declare-function sly-eval "ext:sly" (sexp &optional package)) 47 (declare-function slime-eval "ext:slime" (sexp &optional package)) 48 49 (defvar org-babel-tangle-lang-exts) 50 (add-to-list 'org-babel-tangle-lang-exts '("lisp" . "lisp")) 51 52 (defvar org-babel-default-header-args:lisp '()) 53 (defvar org-babel-header-args:lisp '((package . :any))) 54 55 (defcustom org-babel-lisp-eval-fn #'slime-eval 56 "The function to be called to evaluate code on the Lisp side. 57 Valid values include `slime-eval' and `sly-eval'." 58 :group 'org-babel 59 :version "26.1" 60 :package-version '(Org . "9.0") 61 :type 'symbol) 62 63 (defcustom org-babel-lisp-dir-fmt 64 "(let ((*default-pathname-defaults* #P%S\n)) %%s\n)" 65 "Format string used to wrap code bodies to set the current directory. 66 For example a value of \"(progn ;; %s\\n %%s)\" would ignore the 67 current directory string." 68 :group 'org-babel 69 :version "24.1" 70 :type 'string) 71 72 (defun org-babel-expand-body:lisp (body params) 73 "Expand BODY according to PARAMS, return the expanded body." 74 (let* ((vars (org-babel--get-vars params)) 75 (result-params (cdr (assq :result-params params))) 76 (print-level nil) (print-length nil) 77 (prologue (cdr (assq :prologue params))) 78 (epilogue (cdr (assq :epilogue params))) 79 (body (if (null vars) (org-trim body) 80 (concat "(let (" 81 (mapconcat 82 (lambda (var) 83 (format "(%S (quote %S))" (car var) (cdr var))) 84 vars "\n ") 85 ")\n" 86 (and prologue (concat prologue "\n")) 87 body 88 (and epilogue (concat "\n" epilogue "\n")) 89 ")")))) 90 (if (or (member "code" result-params) 91 (member "pp" result-params)) 92 (format "(pprint %s)" body) 93 body))) 94 95 (defun org-babel-execute:lisp (body params) 96 "Execute a block of Common Lisp code with Babel. 97 BODY is the contents of the block, as a string. PARAMS is 98 a property list containing the parameters of the block." 99 (let (eval-and-grab-output) 100 (pcase org-babel-lisp-eval-fn 101 (`slime-eval (org-require-package 'slime "SLIME") 102 (setq eval-and-grab-output 'swank:eval-and-grab-output)) 103 (`sly-eval (org-require-package 'sly "SLY") 104 (setq eval-and-grab-output 'slynk:eval-and-grab-output))) 105 (org-babel-reassemble-table 106 (let ((result 107 (funcall (if (member "output" (cdr (assq :result-params params))) 108 #'car #'cadr) 109 (with-temp-buffer 110 (insert (org-babel-expand-body:lisp body params)) 111 (funcall org-babel-lisp-eval-fn 112 `(,eval-and-grab-output 113 ,(let ((dir (if (assq :dir params) 114 (cdr (assq :dir params)) 115 default-directory))) 116 (format 117 (if dir (format org-babel-lisp-dir-fmt dir) 118 "(progn %s\n)") 119 (buffer-substring-no-properties 120 (point-min) (point-max))))) 121 (cdr (assq :package params))))))) 122 (org-babel-result-cond (cdr (assq :result-params params)) 123 (org-strip-quotes result) 124 (condition-case nil 125 (read (org-babel-lisp-vector-to-list result)) 126 (error result)))) 127 (org-babel-pick-name (cdr (assq :colname-names params)) 128 (cdr (assq :colnames params))) 129 (org-babel-pick-name (cdr (assq :rowname-names params)) 130 (cdr (assq :rownames params)))))) 131 132 (defun org-babel-lisp-vector-to-list (results) 133 "Convert #(...) values in RESULTS string into a (...) list." 134 ;; TODO: better would be to replace #(...) with [...] 135 (replace-regexp-in-string "#(" "(" results)) 136 137 (provide 'ob-lisp) 138 139 ;;; ob-lisp.el ends here