emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
blob bfe7d1c6369706c31b2ba148afdadf190762454e 7478 bytes (raw)
name: contrib/lisp/ob-rust.el 	 # note: path name is non-authoritative(*)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
 
;;; ob-rust.el --- Babel Functions for rust -*- lexical-binding: t; -*-

;; Copyright (C) 2017 Free Software Foundation, Inc.

;; Author: Andrés Saraos Luna
;; Keywords: literate programming, reproducible research
;; Homepage: http://orgmode.org

;; This file is part of GNU Emacs.

;; GNU Emacs 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 of the License, or
;; (at your option) any later version.

;; GNU Emacs 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.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; Org-Babel support for evaluating rust code.
;;
;; A currently very limited implementation:
;;  - arrays, vecs, lists or tables are not yet supported as header
;;  arguments
;;  - no error handling
;;  - only :results output is supported
;;  - cargo is completely ignored

(require 'ob)

(defvar org-babel-tangle-lang-exts)
(add-to-list 'org-babel-tangle-lang-exts '("rust" . "rs"))

(defcustom org-babel-rust-command "rustc"
  "Name of the rust command."
  :group 'org-babel
  :type 'string)

(defun org-babel-execute:rust (body params)
  (let* ((full-body (org-babel-expand-body:rust body params))
         (cmpflag (or (cdr (assq :cmpflag params)) ""))
         (cmdline (or (cdr (assq :cmdline params)) ""))
         (default-directory org-babel-temporary-directory)
         (src-file (org-babel-temp-file "rust-src-" ".rs"))
         (exe-file (org-babel-rust-exe-file src-file cmpflag))
         (results))
    (with-temp-file src-file
      (insert full-body)
      (when (require 'rust-mode nil t)
        (rust-format-buffer)))
    (org-babel-eval
     (format "%s %s %s" org-babel-rust-command cmpflag src-file) "")
    (setq results (org-babel-eval (format "%s %s" exe-file cmdline) ""))
    (org-babel-reassemble-table
     (org-babel-result-cond (cdr (assq :result-params params))
       (org-babel-read results)
       (let ((tmp-file (org-babel-temp-file "rs-")))
         (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-expand-body:rust (body params)
  "Expand a block of rust code with org-babel according to its
header arguments."
  (let* ((main-p (not (string= (cdr (assq :main params)) "no")))
         (uses (org-babel-read (cdr (assq :use params)) nil))
         (vars (org-babel--get-vars params)))
    (when (stringp uses)
      (setq uses (split-string uses)))
    (mapconcat
     'identity
     (list
      ;; uses
      (mapconcat
       (lambda (use) (format "use %s;" use))
       uses
       "\n")
      ;; main vith vars if present
      (org-babel-rust-ensure-main-wrap body vars))
     "\n\t")))

(defun org-babel-prep-session:rust (_session _params)
  "This function does nothing as C is a compiled language with no
support for sessions"
  (error "no support for sessions"))

(defun org-babel-load-session:rust (_session _body _params)
  "This function does nothing as C is a compiled language with no
support for sessions"
  (error "no support for sessions"))

;;; Helper functions.

(defun org-babel-rust-exe-file (src-file cmpflag)
  "Compute the executable name according to the parameters given
to the command line. It assumes that the source file has been
created at (org-babel-temporary-directory). For spaces to be
correctly recognized they need to be escaped."
  (if (string= cmpflag "")
      (file-name-sans-extension src-file)
    (let* ((flag-list (split-string cmpflag " "))
           (out-file (nth 1 (member "-o" flag-list)))
           (out-dir (nth 1 (member "--out-dir" flag-list))))
      (cond
       (out-file
        (if (string-match-p "^/" out-file) ;naive absolute file path detection
            (expand-file-name out-file "/")
          (expand-file-name out-file org-babel-temporary-directory)))
       (out-dir
        (expand-file-name (file-name-base src-file) (file-name-as-directory out-dir)))
       (t
        (file-name-sans-extension src-file))))))

(defun org-babel-rust-ensure-main-wrap (body vars)
  "Wrap BODY in a \"main\" function call if none exist. Inserts
the variables right after the main declaration, regardless of the
\"main\" existence."
  (let ((rust-main-regexp "^[ \t]*fn[ \t\n\r]*main[ \t]*()[ \t\n]*{[ \t]*")
        (rust-main-wrapper "fn main() {\n\t%s\n\t%s\n}")
        (pos nil))
    (if (string-match rust-main-regexp body)
        (progn
          (setq pos (match-end 0))
          (concat
           (substring body 0 pos)
           "\n"
           (mapconcat 'org-babel-rust-var-to-rust vars "\n")
           (substring body pos nil)))
      (format
       rust-main-wrapper
       (mapconcat 'org-babel-rust-var-to-rust vars "\n")
       body))))

(defun org-babel-rust-val-to-rust-type (val)
  "Infers the correct rust data type from the value of the given
argument."
  (cond
   ((symbolp val)
    (cond
     ((= (length (symbol-name val)) 1) 'char)
     ((or (string= val "true") (string= val "false")) 'bool)
     (t '&str)))
   ((stringp val)
    (cond
     ((or (string= val "true") (string= val "false")) 'bool)
     (t '&str)))
   ((integerp val)
    'isize)
   ((floatp val)
    'f64)
   (t
    nil)))

(defun org-babel-rust-var-to-rust (var-pairs)
  "Formats a given variable name, variable value pair according
to its type in correct rust.

The variable name follows the following rules :

- if the name starts with \"mut_\", the variable will be declared
as mutable in rust code, and be referenced by its name minus the
\"mut\",

- if the name is followed by a \":\", the text preceding the
\"=\" sign will be treated as its type. If no type is given one
will be infered."
  (let* ((var (car var-pairs))
         (val (cdr var-pairs))
         (value-type (org-babel-rust-val-to-rust-type val))
         (var-s (symbol-name var))
         (var-regexp "\\(^mut_\\)?\\([[:alnum:]_]+\\)\\(: ?[[:alnum:]]+\\)?[ \t]*$")
         (mut
          (progn
            (string-match var-regexp var-s)
            (match-string 1 var-s)))
         (var-name
          (progn
            (string-match var-regexp var-s)
            (match-string 2 var-s)))
         (var-type
          (or
           (progn
             (string-match var-regexp var-s)
             (match-string 3 var-s))
           (format ":%s" (symbol-name (org-babel-rust-val-to-rust-type val)))))
         (pre (format "let %s"
                      (if (string-match "^mut_" var-s)
                          (concat "mut " (substring var-s (match-end 0) nil))
                        var)))
         (value (cond
                 ((string-match-p ": ?[iuf]" var-type) (format "%s" val))
                 ((string-match-p ": ?bool" var-type) (format "%s" val))
                 ((string-match-p ": ?char" var-type) (format "'%s'" val))
                 (t (format "\"%s\"" val)))))
    (setq mut (when mut "mut "))
    (concat "let " mut var-name var-type " = " value ";")))

(provide 'ob-rust)

debug log:

solving daa206228 ...
found daa206228 in https://list.orgmode.org/orgmode/e6762cad-e681-4ea3-b168-7c37cd69b170@getmailbird.com/

applying [1/1] https://list.orgmode.org/orgmode/e6762cad-e681-4ea3-b168-7c37cd69b170@getmailbird.com/
diff --git a/contrib/lisp/ob-rust.el b/contrib/lisp/ob-rust.el
new file mode 100644
index 000000000..daa206228

Checking patch contrib/lisp/ob-rust.el...
Applied patch contrib/lisp/ob-rust.el cleanly.

index at:
100644 bfe7d1c6369706c31b2ba148afdadf190762454e	contrib/lisp/ob-rust.el

(*) Git path names are given by the tree(s) the blob belongs to.
    Blobs themselves have no identifier aside from the hash of its contents.^

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).