---------- Forwarded message ---------
From: Roland Coeurjoly <rolandcoeurj...@gmail.com>
Date: Sat, Apr 25, 2020 at 9:04 PM
Subject: Support compilation of Haskell in org mode babel blocks.
To: <bug-gnu-em...@gnu.org>


Haskell code can be both compiled (for example with ghc), or interpreted
(with ghci).

Until now, org babel had only support for interpretation.

Haskell is weird in that some code for the interpreter cannot be compiled
and viceversa.
For example, in ghci (the interpreter) you are required to use let to
declare functions
<https://stackoverflow.com/questions/28927716/org-babel-for-haskell-not-works-of-eval-haskell-block/40920873>
.

In this patch I add support for compilation with the header argument
:compile yes.
The function to compile haskell is almost a copy paste of the C funcion in
ob-C.el.

By default I retain the original behavior, i.e. interpreting the block.

I have tested this patch in emacs-27.0.91.


It is my first patch to GNU Emacs and I am a newbie with both elisp and
haskell.
From 091f470a278561a60fac1ee3ee658f6823bc2503 Mon Sep 17 00:00:00 2001
From: Roland Coeurjoly <rolandcoeurj...@gmail.com>
Date: Sat, 25 Apr 2020 20:35:22 +0200
Subject: [PATCH] Add Haskell specific header argument compile, to compile
 instead of interpret the body of source block

---
 lisp/org/ob-haskell.el | 76 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 71 insertions(+), 5 deletions(-)

diff --git a/lisp/org/ob-haskell.el b/lisp/org/ob-haskell.el
index e004a3405e..d32a2f7bc0 100644
--- a/lisp/org/ob-haskell.el
+++ b/lisp/org/ob-haskell.el
@@ -23,12 +23,13 @@
 
 ;;; Commentary:
 
-;; Org-Babel support for evaluating haskell source code.  This one will
-;; be sort of tricky because haskell programs must be compiled before
+;; Org-Babel support for evaluating Haskell source code.
+;; Haskell programs must be compiled before
 ;; they can be run, but haskell code can also be run through an
 ;; interactive interpreter.
 ;;
-;; For now lets only allow evaluation using the haskell interpreter.
+;; By default we evaluate using the Haskell interpreter.
+;; To use the compiler, specify :compile yes in the header.
 
 ;;; Requirements:
 
@@ -47,6 +48,7 @@
 (declare-function run-haskell "ext:inf-haskell" (&optional arg))
 (declare-function inferior-haskell-load-file
 		  "ext:inf-haskell" (&optional reload))
+(declare-function org-entry-get "org" (pom property &optional inherit literal-nil))
 
 (defvar org-babel-tangle-lang-exts)
 (add-to-list 'org-babel-tangle-lang-exts '("haskell" . "hs"))
@@ -60,8 +62,64 @@ org-babel-haskell-eoe
 
 (defvar haskell-prompt-regexp)
 
-(defun org-babel-execute:haskell (body params)
-  "Execute a block of Haskell code."
+(defcustom org-babel-Haskell-compiler "ghc"
+  "Command used to compile a Haskell source code file into an executable.
+May be either a command in the path, like ghc
+or an absolute path name, like /usr/local/bin/ghc
+parameter may be used, like ghc -v"
+  :group 'org-babel
+  :version "27.0"
+  :type 'string)
+
+(defconst org-babel-header-args:haskell '((compile . :any))
+  "Haskell-specific header arguments.")
+
+(defun org-babel-Haskell-execute (body params)
+  "This function should only be called by `org-babel-execute:haskell'"
+  (let* ((tmp-src-file (org-babel-temp-file
+			"Haskell-src-"
+                        ".hs"))
+         (tmp-bin-file
+          (org-babel-process-file-name
+           (org-babel-temp-file "Haskell-bin-" org-babel-exeext)))
+         (cmdline (cdr (assq :cmdline params)))
+         (cmdline (if cmdline (concat " " cmdline) ""))
+         (flags (cdr (assq :flags params)))
+         (flags (mapconcat 'identity
+		           (if (listp flags) flags (list flags)) " "))
+         (libs (org-babel-read
+	        (or (cdr (assq :libs params))
+	            (org-entry-get nil "libs" t))
+	        nil))
+         (libs (mapconcat #'identity
+		          (if (listp libs) libs (list libs))
+		          " ")))
+    (with-temp-file tmp-src-file (insert body))
+    (org-babel-eval
+     (format "%s -o %s %s %s %s"
+             org-babel-Haskell-compiler
+	     tmp-bin-file
+	     flags
+	     (org-babel-process-file-name tmp-src-file)
+	     libs) "")
+    (let ((results
+	   (org-babel-eval
+	    (concat tmp-bin-file cmdline) "")))
+      (when results
+        (setq results (org-trim (org-remove-indentation results)))
+        (org-babel-reassemble-table
+         (org-babel-result-cond (cdr (assq :result-params params))
+	   (org-babel-read results t)
+	   (let ((tmp-file (org-babel-temp-file "Haskell-")))
+	     (with-temp-file tmp-file (insert results))
+	     (org-babel-import-elisp-from-file tmp-file)))
+         (org-babel-pick-name
+	  (cdr (assq :colname-names params)) (cdr (assq :colnames params)))
+         (org-babel-pick-name
+	  (cdr (assq :rowname-names params)) (cdr (assq :rownames params)))))
+      )))
+
+(defun org-babel-interpret-Haskell (body params)
   (require 'inf-haskell)
   (add-hook 'inferior-haskell-hook
             (lambda ()
@@ -96,6 +154,14 @@ org-babel-execute:haskell
      (org-babel-pick-name (cdr (assq :rowname-names params))
 			  (cdr (assq :rowname-names params))))))
 
+
+(defun org-babel-execute:haskell (body params)
+  "Execute a block of Haskell code."
+  (setq compile (string= (cdr (assq :compile params)) "yes"))
+  (if (not compile)
+      (org-babel-interpret-Haskell body params)
+    (org-babel-Haskell-execute body params)))
+
 (defun org-babel-haskell-initiate-session (&optional _session _params)
   "Initiate a haskell session.
 If there is not a current inferior-process-buffer in SESSION
-- 
2.20.1

Reply via email to