diff options
| author | Kyle Meyer | 2021-09-29 18:48:59 -0400 |
|---|---|---|
| committer | Kyle Meyer | 2021-09-29 23:21:21 -0400 |
| commit | bf9ec3d91a79414deac039f7bf83352a9b0a9a85 (patch) | |
| tree | 5e636992801ca408a26f7b7532c666d24c80020e /lisp/org/ob-java.el | |
| parent | dc94ca7b2b878c9a88be72fea118bf6557259ffd (diff) | |
| download | emacs-bf9ec3d91a79414deac039f7bf83352a9b0a9a85.tar.gz emacs-bf9ec3d91a79414deac039f7bf83352a9b0a9a85.zip | |
Update to Org 9.5
Diffstat (limited to 'lisp/org/ob-java.el')
| -rw-r--r-- | lisp/org/ob-java.el | 480 |
1 files changed, 442 insertions, 38 deletions
diff --git a/lisp/org/ob-java.el b/lisp/org/ob-java.el index b1d517e94aa..60ef33bc6e4 100644 --- a/lisp/org/ob-java.el +++ b/lisp/org/ob-java.el | |||
| @@ -1,8 +1,10 @@ | |||
| 1 | ;;; ob-java.el --- Babel Functions for Java -*- lexical-binding: t; -*- | 1 | ;;; ob-java.el --- org-babel functions for java evaluation -*- lexical-binding: t -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2011-2021 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2011-2021 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | ;; Author: Eric Schulte | 5 | ;; Authors: Eric Schulte |
| 6 | ;; Dan Davison | ||
| 7 | ;; Maintainer: Ian Martins <ianxm@jhu.edu> | ||
| 6 | ;; Keywords: literate programming, reproducible research | 8 | ;; Keywords: literate programming, reproducible research |
| 7 | ;; Homepage: https://orgmode.org | 9 | ;; Homepage: https://orgmode.org |
| 8 | 10 | ||
| @@ -23,8 +25,7 @@ | |||
| 23 | 25 | ||
| 24 | ;;; Commentary: | 26 | ;;; Commentary: |
| 25 | 27 | ||
| 26 | ;; Currently this only supports the external compilation and execution | 28 | ;; Org-Babel support for evaluating java source code. |
| 27 | ;; of java code blocks (i.e., no session support). | ||
| 28 | 29 | ||
| 29 | ;;; Code: | 30 | ;;; Code: |
| 30 | (require 'ob) | 31 | (require 'ob) |
| @@ -32,52 +33,455 @@ | |||
| 32 | (defvar org-babel-tangle-lang-exts) | 33 | (defvar org-babel-tangle-lang-exts) |
| 33 | (add-to-list 'org-babel-tangle-lang-exts '("java" . "java")) | 34 | (add-to-list 'org-babel-tangle-lang-exts '("java" . "java")) |
| 34 | 35 | ||
| 36 | (defvar org-babel-temporary-directory) ; from ob-core | ||
| 37 | |||
| 38 | (defvar org-babel-default-header-args:java '((:results . "output") | ||
| 39 | (:dir . ".")) | ||
| 40 | "Default header args for java source blocks. | ||
| 41 | The docs say functional mode should be the default [1], but | ||
| 42 | ob-java didn't originally support functional mode, so we keep | ||
| 43 | scripting mode as the default for now to maintain previous | ||
| 44 | behavior. | ||
| 45 | |||
| 46 | Most languages write tempfiles to babel's temporary directory, | ||
| 47 | but ob-java originally had to write them to the current | ||
| 48 | directory, so we keep that as the default behavior. | ||
| 49 | |||
| 50 | [1] https://orgmode.org/manual/Results-of-Evaluation.html") | ||
| 51 | |||
| 52 | (defconst org-babel-header-args:java '((imports . :any)) | ||
| 53 | "Java-specific header arguments.") | ||
| 54 | |||
| 35 | (defcustom org-babel-java-command "java" | 55 | (defcustom org-babel-java-command "java" |
| 36 | "Name of the java command. | 56 | "Name of the java command. |
| 37 | May be either a command in the path, like java | 57 | May be either a command in the path, like java or an absolute |
| 38 | or an absolute path name, like /usr/local/bin/java | 58 | path name, like /usr/local/bin/java. Parameters may be used, |
| 39 | parameters may be used, like java -verbose" | 59 | like java -verbose." |
| 40 | :group 'org-babel | 60 | :group 'org-babel |
| 41 | :version "24.3" | 61 | :package-version '(Org . "9.5") |
| 42 | :type 'string) | 62 | :type 'string) |
| 43 | 63 | ||
| 44 | (defcustom org-babel-java-compiler "javac" | 64 | (defcustom org-babel-java-compiler "javac" |
| 45 | "Name of the java compiler. | 65 | "Name of the java compiler. |
| 46 | May be either a command in the path, like javac | 66 | May be either a command in the path, like javac or an absolute |
| 47 | or an absolute path name, like /usr/local/bin/javac | 67 | path name, like /usr/local/bin/javac. Parameters may be used, |
| 48 | parameters may be used, like javac -verbose" | 68 | like javac -verbose." |
| 69 | :group 'org-babel | ||
| 70 | :package-version '(Org . "9.5") | ||
| 71 | :type 'string) | ||
| 72 | |||
| 73 | (defcustom org-babel-java-hline-to "null" | ||
| 74 | "Replace hlines in incoming tables with this when translating to java." | ||
| 49 | :group 'org-babel | 75 | :group 'org-babel |
| 50 | :version "24.3" | 76 | :package-version '(Org . "9.5") |
| 51 | :type 'string) | 77 | :type 'string) |
| 52 | 78 | ||
| 79 | (defcustom org-babel-java-null-to 'hline | ||
| 80 | "Replace `null' in java tables with this before returning." | ||
| 81 | :group 'org-babel | ||
| 82 | :package-version '(Org . "9.5") | ||
| 83 | :type 'symbol) | ||
| 84 | |||
| 85 | (defconst org-babel-java--package-re (rx line-start (0+ space) "package" | ||
| 86 | (1+ space) (group (1+ (in alnum ?_ ?.))) ; capture the package name | ||
| 87 | (0+ space) ?\; line-end) | ||
| 88 | "Regexp for the package statement.") | ||
| 89 | (defconst org-babel-java--imports-re (rx line-start (0+ space) "import" | ||
| 90 | (opt (1+ space) "static") | ||
| 91 | (1+ space) (group (1+ (in alnum ?_ ?. ?*))) ; capture the fully qualified class name | ||
| 92 | (0+ space) ?\; line-end) | ||
| 93 | "Regexp for import statements.") | ||
| 94 | (defconst org-babel-java--class-re (rx line-start (0+ space) (opt (seq "public" (1+ space))) | ||
| 95 | "class" (1+ space) | ||
| 96 | (group (1+ (in alnum ?_))) ; capture the class name | ||
| 97 | (0+ space) ?{) | ||
| 98 | "Regexp for the class declaration.") | ||
| 99 | (defconst org-babel-java--main-re (rx line-start (0+ space) "public" | ||
| 100 | (1+ space) "static" | ||
| 101 | (1+ space) "void" | ||
| 102 | (1+ space) "main" | ||
| 103 | (0+ space) ?\( | ||
| 104 | (0+ space) "String" | ||
| 105 | (0+ space) (1+ (in alnum ?_ ?\[ ?\] space)) ; "[] args" or "args[]" | ||
| 106 | (0+ space) ?\) | ||
| 107 | (0+ space) (opt "throws" (1+ (in alnum ?_ ?, ?. space))) | ||
| 108 | ?{) | ||
| 109 | "Regexp for the main method declaration.") | ||
| 110 | (defconst org-babel-java--any-method-re (rx line-start | ||
| 111 | (0+ space) (opt (seq (1+ alnum) (1+ space))) ; visibility | ||
| 112 | (opt (seq "static" (1+ space))) ; binding | ||
| 113 | (1+ (in alnum ?_ ?\[ ?\])) ; return type | ||
| 114 | (1+ space) (1+ (in alnum ?_)) ; method name | ||
| 115 | (0+ space) ?\( | ||
| 116 | (0+ space) (0+ (in alnum ?_ ?\[ ?\] ?, space)) ; params | ||
| 117 | (0+ space) ?\) | ||
| 118 | (0+ space) (opt "throws" (1+ (in alnum ?_ ?, ?. space))) | ||
| 119 | ?{) | ||
| 120 | "Regexp for any method.") | ||
| 121 | (defconst org-babel-java--result-wrapper "\n public static String __toString(Object val) { | ||
| 122 | if (val instanceof String) { | ||
| 123 | return \"\\\"\" + val + \"\\\"\"; | ||
| 124 | } else if (val == null) { | ||
| 125 | return \"null\"; | ||
| 126 | } else if (val.getClass().isArray()) { | ||
| 127 | StringBuffer sb = new StringBuffer(); | ||
| 128 | Object[] vals = (Object[])val; | ||
| 129 | sb.append(\"[\"); | ||
| 130 | for (int ii=0; ii<vals.length; ii++) { | ||
| 131 | sb.append(__toString(vals[ii])); | ||
| 132 | if (ii<vals.length-1) | ||
| 133 | sb.append(\",\"); | ||
| 134 | } | ||
| 135 | sb.append(\"]\"); | ||
| 136 | return sb.toString(); | ||
| 137 | } else if (val instanceof List) { | ||
| 138 | StringBuffer sb = new StringBuffer(); | ||
| 139 | List vals = (List)val; | ||
| 140 | sb.append(\"[\"); | ||
| 141 | for (int ii=0; ii<vals.size(); ii++) { | ||
| 142 | sb.append(__toString(vals.get(ii))); | ||
| 143 | if (ii<vals.size()-1) | ||
| 144 | sb.append(\",\"); | ||
| 145 | } | ||
| 146 | sb.append(\"]\"); | ||
| 147 | return sb.toString(); | ||
| 148 | } else { | ||
| 149 | return String.valueOf(val); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | public static void main(String[] args) throws IOException { | ||
| 154 | BufferedWriter output = new BufferedWriter(new FileWriter(\"%s\")); | ||
| 155 | output.write(__toString(_main(args))); | ||
| 156 | output.close(); | ||
| 157 | }" | ||
| 158 | "Code to inject into a class so that we can capture the value it returns. | ||
| 159 | This implementation was inspired by ob-python, although not as | ||
| 160 | elegant. This modified the source block to write out the value | ||
| 161 | it wants to return to a temporary file so that ob-java can read | ||
| 162 | it back. The name of the temporary file to write must be | ||
| 163 | replaced in this string.") | ||
| 164 | |||
| 53 | (defun org-babel-execute:java (body params) | 165 | (defun org-babel-execute:java (body params) |
| 54 | (let* ((classname (or (cdr (assq :classname params)) | 166 | "Execute a java source block with BODY code and PARAMS params." |
| 55 | (error | 167 | (let* (;; allow header overrides |
| 56 | "Can't compile a java block without a classname"))) | 168 | (org-babel-java-compiler |
| 57 | (packagename (file-name-directory classname)) | 169 | (or (cdr (assq :javac params)) |
| 58 | (src-file (concat classname ".java")) | 170 | org-babel-java-compiler)) |
| 59 | (cmpflag (or (cdr (assq :cmpflag params)) "")) | 171 | (org-babel-java-command |
| 60 | (cmdline (or (cdr (assq :cmdline params)) "")) | 172 | (or (cdr (assq :java params)) |
| 61 | (cmdargs (or (cdr (assq :cmdargs params)) "")) | 173 | org-babel-java-command)) |
| 62 | (full-body (org-babel-expand-body:generic body params))) | 174 | ;; if true, run from babel temp directory |
| 63 | (with-temp-file src-file (insert full-body)) | 175 | (run-from-temp (not (cdr (assq :dir params)))) |
| 64 | (org-babel-eval | 176 | ;; class and package |
| 65 | (concat org-babel-java-compiler " " cmpflag " " src-file) "") | 177 | (fullclassname (or (cdr (assq :classname params)) |
| 178 | (org-babel-java-find-classname body))) | ||
| 179 | ;; just the class name | ||
| 180 | (classname (car (last (split-string fullclassname "\\.")))) | ||
| 181 | ;; just the package name | ||
| 182 | (packagename (if (string-match-p "\\." fullclassname) | ||
| 183 | (file-name-base fullclassname))) | ||
| 184 | ;; the base dir that contains the top level package dir | ||
| 185 | (basedir (file-name-as-directory (if run-from-temp | ||
| 186 | (if (file-remote-p default-directory) | ||
| 187 | (concat | ||
| 188 | (file-remote-p default-directory) | ||
| 189 | org-babel-remote-temporary-directory) | ||
| 190 | org-babel-temporary-directory) | ||
| 191 | default-directory))) | ||
| 192 | ;; the dir to write the source file | ||
| 193 | (packagedir (if (and (not run-from-temp) packagename) | ||
| 194 | (file-name-as-directory | ||
| 195 | (concat basedir (replace-regexp-in-string "\\\." "/" packagename))) | ||
| 196 | basedir)) | ||
| 197 | ;; the filename of the source file | ||
| 198 | (src-file (concat packagedir classname ".java")) | ||
| 199 | ;; compiler flags | ||
| 200 | (cmpflag (or (cdr (assq :cmpflag params)) "")) | ||
| 201 | ;; runtime flags | ||
| 202 | (cmdline (or (cdr (assq :cmdline params)) "")) | ||
| 203 | ;; command line args | ||
| 204 | (cmdargs (or (cdr (assq :cmdargs params)) "")) | ||
| 205 | ;; the command to compile and run | ||
| 206 | (cmd (concat org-babel-java-compiler " " cmpflag " " | ||
| 207 | (org-babel-process-file-name src-file 'noquote) | ||
| 208 | " && " org-babel-java-command | ||
| 209 | " -cp " (org-babel-process-file-name basedir 'noquote) | ||
| 210 | " " cmdline " " (if run-from-temp classname fullclassname) | ||
| 211 | " " cmdargs)) | ||
| 212 | ;; header args for result processing | ||
| 213 | (result-type (cdr (assq :result-type params))) | ||
| 214 | (result-params (cdr (assq :result-params params))) | ||
| 215 | (result-file (and (eq result-type 'value) | ||
| 216 | (org-babel-temp-file "java-"))) | ||
| 217 | ;; the expanded body of the source block | ||
| 218 | (full-body (org-babel-expand-body:java body params))) | ||
| 219 | |||
| 66 | ;; created package-name directories if missing | 220 | ;; created package-name directories if missing |
| 67 | (unless (or (not packagename) (file-exists-p packagename)) | 221 | (unless (or (not packagedir) (file-exists-p packagedir)) |
| 68 | (make-directory packagename 'parents)) | 222 | (make-directory packagedir 'parents)) |
| 69 | (let ((results (org-babel-eval (concat org-babel-java-command | 223 | |
| 70 | " " cmdline " " classname " " cmdargs) ""))) | 224 | ;; write the source file |
| 71 | (org-babel-reassemble-table | 225 | (setq full-body (org-babel-java--expand-for-evaluation |
| 72 | (org-babel-result-cond (cdr (assq :result-params params)) | 226 | full-body run-from-temp result-type result-file)) |
| 73 | (org-babel-read results t) | 227 | (with-temp-file src-file (insert full-body)) |
| 74 | (let ((tmp-file (org-babel-temp-file "c-"))) | 228 | |
| 75 | (with-temp-file tmp-file (insert results)) | 229 | ;; compile, run, process result |
| 76 | (org-babel-import-elisp-from-file tmp-file))) | 230 | (org-babel-reassemble-table |
| 77 | (org-babel-pick-name | 231 | (org-babel-java-evaluate cmd result-type result-params result-file) |
| 78 | (cdr (assq :colname-names params)) (cdr (assq :colnames params))) | 232 | (org-babel-pick-name |
| 79 | (org-babel-pick-name | 233 | (cdr (assoc :colname-names params)) (cdr (assoc :colnames params))) |
| 80 | (cdr (assq :rowname-names params)) (cdr (assq :rownames params))))))) | 234 | (org-babel-pick-name |
| 235 | (cdr (assoc :rowname-names params)) (cdr (assoc :rownames params)))))) | ||
| 236 | |||
| 237 | ;; helper functions | ||
| 238 | |||
| 239 | (defun org-babel-java-find-classname (body) | ||
| 240 | "Try to find fully qualified class name in BODY. | ||
| 241 | Look through BODY for the package and class. If found, put them | ||
| 242 | together into a fully qualified class name and return. Else just | ||
| 243 | return class name. If that isn't found either, default to Main." | ||
| 244 | (let ((package (if (string-match org-babel-java--package-re body) | ||
| 245 | (match-string 1 body))) | ||
| 246 | (class (if (string-match org-babel-java--class-re body) | ||
| 247 | (match-string 1 body)))) | ||
| 248 | (or (and package class (concat package "." class)) | ||
| 249 | (and class class) | ||
| 250 | (and package (concat package ".Main")) | ||
| 251 | "Main"))) | ||
| 252 | |||
| 253 | (defun org-babel-java--expand-for-evaluation (body suppress-package-p result-type result-file) | ||
| 254 | "Expand source block for evaluation. | ||
| 255 | In order to return a value we have to add a __toString method. | ||
| 256 | In order to prevent classes without main methods from erroring we | ||
| 257 | add a dummy main method if one is not provided. These | ||
| 258 | manipulations are done outside of `org-babel--expand-body' so | ||
| 259 | that they are hidden from tangles. | ||
| 260 | |||
| 261 | BODY is the file content before instrumentation. | ||
| 262 | |||
| 263 | SUPPRESS-PACKAGE-P if true, suppress the package statement. | ||
| 264 | |||
| 265 | RESULT-TYPE is taken from params. | ||
| 266 | |||
| 267 | RESULT-FILE is the temp file to write the result." | ||
| 268 | (with-temp-buffer | ||
| 269 | (insert body) | ||
| 270 | |||
| 271 | ;; suppress package statement | ||
| 272 | (goto-char (point-min)) | ||
| 273 | (when (and suppress-package-p | ||
| 274 | (re-search-forward org-babel-java--package-re nil t)) | ||
| 275 | (replace-match "")) | ||
| 276 | |||
| 277 | ;; add a dummy main method if needed | ||
| 278 | (goto-char (point-min)) | ||
| 279 | (when (not (re-search-forward org-babel-java--main-re nil t)) | ||
| 280 | (org-babel-java--move-past org-babel-java--class-re) | ||
| 281 | (insert "\n public static void main(String[] args) { | ||
| 282 | System.out.print(\"success\"); | ||
| 283 | }\n\n")) | ||
| 284 | |||
| 285 | ;; special handling to return value | ||
| 286 | (when (eq result-type 'value) | ||
| 287 | (goto-char (point-min)) | ||
| 288 | (org-babel-java--move-past org-babel-java--class-re) | ||
| 289 | (insert (format org-babel-java--result-wrapper | ||
| 290 | (org-babel-process-file-name result-file 'noquote))) | ||
| 291 | (search-forward "public static void main(") ; rename existing main | ||
| 292 | (replace-match "public static Object _main(")) | ||
| 293 | |||
| 294 | ;; add imports | ||
| 295 | (org-babel-java--import-maybe "java.util" "List") | ||
| 296 | (org-babel-java--import-maybe "java.util" "Arrays") | ||
| 297 | (org-babel-java--import-maybe "java.io" "BufferedWriter") | ||
| 298 | (org-babel-java--import-maybe "java.io" "FileWriter") | ||
| 299 | (org-babel-java--import-maybe "java.io" "IOException") | ||
| 300 | |||
| 301 | (buffer-string))) | ||
| 302 | |||
| 303 | (defun org-babel-java--move-past (re) | ||
| 304 | "Move point past the first occurrence of the given regexp RE." | ||
| 305 | (while (re-search-forward re nil t) | ||
| 306 | (goto-char (1+ (match-end 0))))) | ||
| 307 | |||
| 308 | (defun org-babel-java--import-maybe (package class) | ||
| 309 | "Import from PACKAGE the given CLASS if it is used and not already imported." | ||
| 310 | (let (class-found import-found) | ||
| 311 | (goto-char (point-min)) | ||
| 312 | (setq class-found (re-search-forward class nil t)) | ||
| 313 | (goto-char (point-min)) | ||
| 314 | (setq import-found | ||
| 315 | (re-search-forward (concat "^import .*" package ".*\\(?:\\*\\|" class "\\);") nil t)) | ||
| 316 | (when (and class-found (not import-found)) | ||
| 317 | (org-babel-java--move-past org-babel-java--package-re) | ||
| 318 | (insert (concat "import " package "." class ";\n"))))) | ||
| 319 | |||
| 320 | (defun org-babel-expand-body:java (body params) | ||
| 321 | "Expand BODY with PARAMS. | ||
| 322 | BODY could be a few statements, or could include a full class | ||
| 323 | definition specifying package, imports, and class. Because we | ||
| 324 | allow this flexibility in what the source block can contain, it | ||
| 325 | is simplest to expand the code block from the inside out." | ||
| 326 | (let* ((fullclassname (or (cdr (assq :classname params)) ; class and package | ||
| 327 | (org-babel-java-find-classname body))) | ||
| 328 | (classname (car (last (split-string fullclassname "\\.")))) ; just class name | ||
| 329 | (packagename (if (string-match-p "\\." fullclassname) ; just package name | ||
| 330 | (file-name-base fullclassname))) | ||
| 331 | (var-lines (org-babel-variable-assignments:java params)) | ||
| 332 | (imports-val (assq :imports params)) | ||
| 333 | (imports (if imports-val | ||
| 334 | (split-string (org-babel-read (cdr imports-val) nil) " ") | ||
| 335 | nil))) | ||
| 336 | (with-temp-buffer | ||
| 337 | (insert body) | ||
| 338 | |||
| 339 | ;; wrap main. If there are methods defined, but no main method | ||
| 340 | ;; and no class, wrap everything in a generic main method. | ||
| 341 | (goto-char (point-min)) | ||
| 342 | (when (and (not (re-search-forward org-babel-java--main-re nil t)) | ||
| 343 | (not (re-search-forward org-babel-java--any-method-re nil t))) | ||
| 344 | (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it | ||
| 345 | (org-babel-java--move-past org-babel-java--imports-re) ; if imports are defined, move past them | ||
| 346 | (insert "public static void main(String[] args) {\n") | ||
| 347 | (indent-code-rigidly (point) (point-max) 4) | ||
| 348 | (goto-char (point-max)) | ||
| 349 | (insert "\n}")) | ||
| 350 | |||
| 351 | ;; wrap class. If there's no class, wrap everything in a | ||
| 352 | ;; generic class. | ||
| 353 | (goto-char (point-min)) | ||
| 354 | (when (not (re-search-forward org-babel-java--class-re nil t)) | ||
| 355 | (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it | ||
| 356 | (org-babel-java--move-past org-babel-java--imports-re) ; if imports are defined, move past them | ||
| 357 | (insert (concat "\npublic class " (file-name-base classname) " {\n")) | ||
| 358 | (indent-code-rigidly (point) (point-max) 4) | ||
| 359 | (goto-char (point-max)) | ||
| 360 | (insert "\n}")) | ||
| 361 | (goto-char (point-min)) | ||
| 362 | |||
| 363 | ;; insert variables from source block headers | ||
| 364 | (when var-lines | ||
| 365 | (goto-char (point-min)) | ||
| 366 | (org-babel-java--move-past org-babel-java--class-re) ; move inside class | ||
| 367 | (insert (mapconcat 'identity var-lines "\n")) | ||
| 368 | (insert "\n")) | ||
| 369 | |||
| 370 | ;; add imports from source block headers | ||
| 371 | (when imports | ||
| 372 | (goto-char (point-min)) | ||
| 373 | (org-babel-java--move-past org-babel-java--package-re) ; if package is defined, move past it | ||
| 374 | (insert (mapconcat (lambda (package) (concat "import " package ";")) imports "\n") "\n")) | ||
| 375 | |||
| 376 | ;; add package at the top | ||
| 377 | (goto-char (point-min)) | ||
| 378 | (when (and packagename (not (re-search-forward org-babel-java--package-re nil t))) | ||
| 379 | (insert (concat "package " packagename ";\n"))) | ||
| 380 | |||
| 381 | ;; return expanded body | ||
| 382 | (buffer-string)))) | ||
| 383 | |||
| 384 | (defun org-babel-variable-assignments:java (params) | ||
| 385 | "Return a list of java statements assigning the block's variables. | ||
| 386 | variables are contained in PARAMS." | ||
| 387 | (mapcar | ||
| 388 | (lambda (pair) | ||
| 389 | (let* ((type-data (org-babel-java-val-to-type (cdr pair))) | ||
| 390 | (basetype (car type-data)) | ||
| 391 | (var-to-java (lambda (var) (funcall #'org-babel-java-var-to-java var basetype)))) | ||
| 392 | (format " static %s %s = %s;" | ||
| 393 | (cdr type-data) ; type | ||
| 394 | (car pair) ; name | ||
| 395 | (funcall var-to-java (cdr pair))))) ; value | ||
| 396 | (org-babel--get-vars params))) | ||
| 397 | |||
| 398 | (defun org-babel-java-var-to-java (var basetype) | ||
| 399 | "Convert an elisp value to a java variable. | ||
| 400 | Convert an elisp value, VAR, of type BASETYPE into a string of | ||
| 401 | java source code specifying a variable of the same value." | ||
| 402 | (cond ((and (sequencep var) (not (stringp var))) | ||
| 403 | (let ((var-to-java (lambda (var) (funcall #'org-babel-java-var-to-java var basetype)))) | ||
| 404 | (concat "Arrays.asList(" (mapconcat var-to-java var ", ") ")"))) | ||
| 405 | ((eq var 'hline) org-babel-java-hline-to) | ||
| 406 | ((eq basetype 'integerp) (format "%d" var)) | ||
| 407 | ((eq basetype 'floatp) (format "%f" var)) | ||
| 408 | ((eq basetype 'stringp) (if (and (stringp var) (string-match-p ".\n+." var)) | ||
| 409 | (error "Java does not support multiline string literals") | ||
| 410 | (format "\"%s\"" var))))) | ||
| 411 | |||
| 412 | (defun org-babel-java-val-to-type (val) | ||
| 413 | "Determine the type of VAL. | ||
| 414 | Return (BASETYPE . LISTTYPE), where BASETYPE is a symbol | ||
| 415 | representing the type of the individual items in VAL, and | ||
| 416 | LISTTYPE is a string name of the type parameter for a container | ||
| 417 | for BASETYPE items." | ||
| 418 | (let* ((basetype (org-babel-java-val-to-base-type val)) | ||
| 419 | (basetype-str (pcase basetype | ||
| 420 | (`integerp "Integer") | ||
| 421 | (`floatp "Double") | ||
| 422 | (`stringp "String") | ||
| 423 | (_ (error "Unknown type %S" basetype))))) | ||
| 424 | (cond | ||
| 425 | ((and (listp val) (listp (car val))) ; a table | ||
| 426 | (cons basetype (format "List<List<%s>>" basetype-str))) | ||
| 427 | ((or (listp val) (vectorp val)) ; a list declared in the source block header | ||
| 428 | (cons basetype (format "List<%s>" basetype-str))) | ||
| 429 | (t ; return base type | ||
| 430 | (cons basetype basetype-str))))) | ||
| 431 | |||
| 432 | (defun org-babel-java-val-to-base-type (val) | ||
| 433 | "Determine the base type of VAL. | ||
| 434 | VAL may be | ||
| 435 | `integerp' if all base values are integers | ||
| 436 | `floatp' if all base values are either floating points or integers | ||
| 437 | `stringp' otherwise." | ||
| 438 | (cond | ||
| 439 | ((integerp val) 'integerp) | ||
| 440 | ((floatp val) 'floatp) | ||
| 441 | ((or (listp val) (vectorp val)) | ||
| 442 | (let ((type nil)) | ||
| 443 | (mapc (lambda (v) | ||
| 444 | (pcase (org-babel-java-val-to-base-type v) | ||
| 445 | (`stringp (setq type 'stringp)) | ||
| 446 | (`floatp | ||
| 447 | (when (or (not type) (eq type 'integerp)) | ||
| 448 | (setq type 'floatp))) | ||
| 449 | (`integerp | ||
| 450 | (unless type (setq type 'integerp))))) | ||
| 451 | val) | ||
| 452 | type)) | ||
| 453 | (t 'stringp))) | ||
| 454 | |||
| 455 | (defun org-babel-java-table-or-string (results) | ||
| 456 | "Convert RESULTS into an appropriate elisp value. | ||
| 457 | If the results look like a list or vector, then convert them into an | ||
| 458 | Emacs-lisp table, otherwise return the results as a string." | ||
| 459 | (let ((res (org-babel-script-escape results))) | ||
| 460 | (if (listp res) | ||
| 461 | (mapcar (lambda (el) (if (eq 'null el) | ||
| 462 | org-babel-java-null-to | ||
| 463 | el)) | ||
| 464 | res) | ||
| 465 | res))) | ||
| 466 | |||
| 467 | (defun org-babel-java-evaluate (cmd result-type result-params result-file) | ||
| 468 | "Evaluate using an external java process. | ||
| 469 | CMD the command to execute. | ||
| 470 | |||
| 471 | If RESULT-TYPE equals `output' then return standard output as a | ||
| 472 | string. If RESULT-TYPE equals `value' then return the value | ||
| 473 | returned by the source block, as elisp. | ||
| 474 | |||
| 475 | RESULT-PARAMS input params used to format the response. | ||
| 476 | |||
| 477 | RESULT-FILE filename of the tempfile to store the returned value in | ||
| 478 | for `value' RESULT-TYPE. Not used for `output' RESULT-TYPE." | ||
| 479 | (let ((raw (pcase result-type | ||
| 480 | (`output (org-babel-eval cmd "")) | ||
| 481 | (`value (org-babel-eval cmd "") | ||
| 482 | (org-babel-eval-read-file result-file))))) | ||
| 483 | (org-babel-result-cond result-params raw | ||
| 484 | (org-babel-java-table-or-string raw)))) | ||
| 81 | 485 | ||
| 82 | (provide 'ob-java) | 486 | (provide 'ob-java) |
| 83 | 487 | ||