| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 | ;;; ob-oz.el --- Org-babel functions for Oz evaluation;; Copyright (C) 2009-2013 Torsten Anders and Eric Schulte;; Author: Torsten Anders and Eric Schulte;; Keywords: literate programming, reproducible research;; Homepage: http://orgmode.org;; Version: 0.02;; This file is not part of GNU Emacs.;; This program is free software; you can redistribute it and/or modify;; it under the terms of the GNU General Public License as published by;; the Free Software Foundation; either version 3, or (at your option);; any later version.;;;; This program is distributed in the hope that it will be useful,;; but WITHOUT ANY WARRANTY; without even the implied warranty of;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the;; GNU General Public License for more details.;;;; You should have received a copy of the GNU General Public License;; along with GNU Emacs; see the file COPYING.  If not, write to the;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,;; Boston, MA 02110-1301, USA.;;; Commentary:;; Org-Babel support for evaluating Oz source code.;;;; Oz code is always send to the Oz Programming Environment (OPI), the;; Emacs mode and compiler interface for Oz programs. Therefore, only;; session mode is supported. In practice, non-session code blocks are;; handled equally well by the session mode. However, only a single;; session is supported. Consequently, the :session header argument is;; ignored.;;;; The Org-babel header argument :results is interpreted as;; follows. :results output requires the respective code block to be;; an Oz statement and :results value requires an Oz;; expression. Currently, results are only supported for expressions;; (i.e. the result of :results output is always nil).;;;; Expression evaluation happens synchronously. Therefore there is an;; additional header argument :wait-time <number>, which specifies the;; maximum time to wait for the result of a given expression. nil;; means to wait as long as it takes to get a result (potentially wait;; forever).;;;; NOTE: Currently the copyright of this file may not be in a state to;;       permit inclusion as core software into Emacs or Org-mode.;;; Requirements:;; - Mozart Programming System, the implementation of the Oz;;   programming language (http://www.mozart-oz.org/), which includes;;   the major mode mozart for editing Oz programs.;;;; - StartOzServer.oz which is located in the contrib/scripts;;   directory of the Org-mode repository;;; TODO:;; - Decide: set communication to \\switch -threadedqueries?;;;; - Only start Oz compiler when required, e.g., load Org-babel only when needed?;;;; - Avoid synchronous evaluation to avoid blocking Emacs (complex;;   Strasheela programs can take long to find a result..). In order;;   to cleanly map code blocks to their associated results (which can;;   arrive then in any order) I could use IDs;;   (e.g. integers). However, how do I do concurrency in Emacs Lisp,;;   and how can I define org-babel-execute:oz concurrently.;;;; - Expressions are rarely used in Oz at the top-level, and using;;   them in documentation and Literate Programs will cause;;   confusion. Idea: hide expression from reader and instead show;;   them statement (e.g., MIDI output statement) and then include;;   result in Org file. Implementation: for expressions (:results;;   value) support an additional header argument that takes arbitrary;;   Oz code. This code is not seen by the reader, but will be used;;   for the actual expression at the end.  Alternative: feed all;;   relevant code as statement (:results output), then add expression;;   as extra code block which outputs, e.g., file name (so the file;;   name must be accessible by global var), but the code of this;;   extra codeblock is not seen.  Hm, in that case it might be even;;   more easy to manually add this link to the Org file.;;(require 'ob);;; major mode for editing Oz programs(require 'mozart);;;; Interface to communicate with Oz.;; (1) For statements without any results: oz-send-string;; (2) For expressions with a single result: oz-send-string-expression;;     (defined in org-babel-oz-ResultsValue.el);;;; oz-send-string-expression implements an additional very direct;; communication between Org-babel and the Oz compiler. Communication;; with the Oz server works already without this code via the function;; oz-send-string from mozart.el.in, but this function does not get;; back any results from Oz to Emacs. The following code creates a;; socket for sending code to the OPI compiler and results are;; returned by the same socket. On the Oz side, a socket is opened and;; conected to the compiler of the OPI (via oz-send-string). On the;; Emacs side, a connection to this socket is created for feeding code;; and receiving results. This additional communication channel to the;; OPI compiler ensures that results are returned cleanly (e.g., only;; the result of the sent code is returned, no parsing or any;; processing of *Oz Emulator* is required).;;;; There is no buffer, nor sentinel involved. Oz code is send;; directly, and results from Oz are send back, but Emacs Lisp;; requires a filter function for processing results.(defvar org-babel-oz-server-dir  (file-name-as-directory   (expand-file-name    "contrib/scripts"    (file-name-as-directory     (expand-file-name      "../../.."      (file-name-directory (or load-file-name buffer-file-name))))))  "Path to the contrib/scripts directory in whichStartOzServer.oz is located.")(defvar org-babel-oz-port 6001  "Port for communicating with Oz compiler.")(defvar org-babel-oz-OPI-socket nil  "Socket for communicating with OPI.")(defvar org-babel-oz-collected-result nil  "Aux var to hand result from org-babel-oz-filter to oz-send-string-expression.")(defun org-babel-oz-filter (proc string)  "Processes output from socket org-babel-oz-OPI-socket.";;   (setq org-babel-oz-collected-results (cons string org-babel-oz-collected-results))  (setq org-babel-oz-collected-result string)  )(defun org-babel-oz-create-socket ()  (message "Create OPI socket for evaluating expressions")  ;; Start Oz directly  (run-oz)  ;; Create socket on Oz side (after Oz was started).  (oz-send-string (concat "\\insert '" org-babel-oz-server-dir "StartOzServer.oz'"))  ;; Wait until socket is created before connecting to it.  ;; Quick hack: wait 3 sec  ;;  ;; extending time to 30 secs does not help when starting Emacs for  ;; the first time (and computer does nothing else)  (sit-for 3)  ;; connect to OPI socket  (setq org-babel-oz-OPI-socket	;; Creates a socket. I/O interface of Emacs sockets as for processes.	(open-network-stream "*Org-babel-OPI-socket*" nil "localhost" org-babel-oz-port))  ;; install filter  (set-process-filter org-babel-oz-OPI-socket #'org-babel-oz-filter));; communication with org-babel-oz-OPI-socket is asynchronous, but;; oz-send-string-expression turns is into synchronous...(defun oz-send-string-expression (string &optional wait-time)  "Similar to oz-send-string, oz-send-string-expression sends a string to the OPI compiler. However, string must be expression and this function returns the result of the expression (as string). oz-send-string-expression is synchronous, wait-time allows to specify a maximum wait time. After wait-time is over with no result, the function returns nil."  (if (not org-babel-oz-OPI-socket)      (org-babel-oz-create-socket))  (let ((polling-delay 0.1)	result)    (process-send-string org-babel-oz-OPI-socket string)    ;; wait for result    (if wait-time	(let ((waited 0))	  (unwind-protect	      (progn		(while		    ;; stop loop if org-babel-oz-collected-result \= nil or waiting time is over		    (not (or (not (equal org-babel-oz-collected-result nil))			     (> waited wait-time)))		  (progn		    (sit-for polling-delay);; 		    (message "org-babel-oz: next polling iteration")		    (setq waited (+ waited polling-delay))));; 		(message "org-babel-oz: waiting over, got result or waiting timed out");; 		(message (format "wait-time: %s, waited: %s" wait-time waited))		(setq result org-babel-oz-collected-result)		(setq org-babel-oz-collected-result nil))))      (unwind-protect	  (progn	    (while (equal org-babel-oz-collected-result nil)	      (sit-for polling-delay))	    (setq result org-babel-oz-collected-result)	    (setq org-babel-oz-collected-result nil))))    result))(defun org-babel-expand-body:oz (body params)  (let ((vars (mapcar #'cdr (org-babel-get-header params :var))))    (if vars	;; prepend code to define all arguments passed to the code block	(let ((var-string (mapcar (lambda (pair)				    (format "%s=%s"					    (car pair)					    (org-babel-oz-var-to-oz (cdr pair))))				  vars)))	  ;; only add var declarations if any variables are there	  (mapconcat #'identity		     (append (list "local") var-string (list "in" body "end"))		     "\n"))      body)))(defun org-babel-execute:oz (body params)  "Execute a block of Oz code with org-babel.  This function iscalled by `org-babel-execute-src-block' via multiple-value-bind."  (let* ((result-params (cdr (assoc :result-params params)))	 (full-body (org-babel-expand-body:oz body params))	 (wait-time (plist-get params :wait-time)))    ;; actually execute the source-code block    (org-babel-reassemble-table     (cond      ((member "output" result-params)       (message "Org-babel: executing Oz statement")       (oz-send-string full-body))      ((member "value" result-params)       (message "Org-babel: executing Oz expression")       (oz-send-string-expression full-body (or wait-time 1)))      (t (error "either 'output' or 'results' must be members of :results.")))     (org-babel-pick-name (cdr (assoc :colname-names params))			  (cdr (assoc :colnames params)))     (org-babel-pick-name (cdr (assoc :roname-names params))			  (cdr (assoc :rownames params))))));; This function should be used to assign any variables in params in;; the context of the session environment.(defun org-babel-prep-session:oz (session params)  "Prepare SESSION according to the header arguments specified in PARAMS."  (error "org-babel-prep-session:oz unimplemented"));; TODO: testing... (copied from org-babel-haskell.el);; (defun org-babel-prep-session:oz (session params);;   "Prepare SESSION according to the header arguments specified in PARAMS.";;   (save-window-excursion;;     (org-babel-oz-initiate-session session);;     (let* ((vars (org-babel-ref-variables params));;            (var-lines (mapconcat ;; define any variables;;                        (lambda (pair);;                          (format "%s=%s";;                                  (car pair);;                                  (org-babel-ruby-var-to-ruby (cdr pair))));;                        vars "\n"));;            (vars-file (concat (make-temp-file "org-babel-oz-vars") ".oz")));;       (when vars;;         (with-temp-buffer;;           (insert var-lines) (write-file vars-file);;           (oz-mode);; ;; 	  (inferior-oz-load-file) ; ??;; 	  ));;       (current-buffer))));;;; TODO: testing... (simplified version of def in org-babel-prep-session:ocaml);;;; BUG: does not work yet. Error: ad-Orig-error: buffer none doesn't exist or has no process;; UNUSED DEF(defun org-babel-oz-initiate-session (&optional session params)  "If there is not a current inferior-process-buffer in SESSIONthen create.  Return the initialized session."  (unless (string= session "none")    ;; TODO: make it possible to have multiple sessions    (save-window-excursion      ;; (run-oz)      (get-buffer oz-compiler-buffer))))(defun org-babel-oz-var-to-oz (var)  "Convert an elisp var into a string of Oz source codespecifying a var of the same value."  (if (listp var);;       (concat "[" (mapconcat #'org-babel-oz-var-to-oz var ", ") "]")      (eval var)    (format "%s" var) ; don't preserve string quotes.;;     (format "%s" var)    ));; TODO:(defun org-babel-oz-table-or-string (results)  "If the results look like a table, then convert them into anEmacs-lisp table, otherwise return the results as a string."  (error "org-babel-oz-table-or-string unimplemented"))(provide 'ob-oz);;; org-babel-oz.el ends here
 |