;;; ob-java.el --- org-babel functions for java evaluation -*- lexical-binding: t -*- ;; Copyright (C) 2011-2020 Free Software Foundation, Inc. ;; Author: Ian Martins ;; Keywords: literate programming, reproducible research ;; Homepage: https://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 . ;;; Commentary: ;; Org-Babel support for evaluating java source code. ;;; Code: (require 'ob) (defvar org-babel-temporary-directory) ; from ob-core (defvar org-babel-tangle-lang-exts) (add-to-list 'org-babel-tangle-lang-exts '("java" . "java")) (defvar org-babel-default-header-args:java '() "Default header args for java source blocks.") (defconst org-babel-header-args:java '((imports . :any)) "Java-specific header arguments.") (defvar org-babel-java-compiler-command "javac" "Name of the command to execute the java compiler.") (defvar org-babel-java-runtime-command "java" "Name of the command to run the java runtime.") (defcustom org-babel-java-hline-to "null" "Replace hlines in incoming tables with this when translating to java." :group 'org-babel :version "25.2" :package-version '(Org . "9.3") :type 'string) (defcustom org-babel-java-null-to 'hline "Replace `null' in java tables with this before returning." :group 'org-babel :version "25.2" :package-version '(Org . "9.3") :type 'symbol) (defun org-babel-execute:java (body params) "Execute a java source block with BODY code and PARAMS params." (let* (;; if true, run from babel temp directory (run-from-temp (not (assq :dir params))) ;; class and package (fullclassname (or (cdr (assq :classname params)) (org-babel-java-find-classname body))) ;; just the class name (classname (car (last (split-string fullclassname "\\.")))) ;; just the package name (packagename (if (seq-contains fullclassname ?.) (file-name-base fullclassname))) ;; the base dir that contains the top level package dir (basedir (file-name-as-directory (if run-from-temp org-babel-temporary-directory "."))) ;; the dir to write the source file (packagedir (if (and (not run-from-temp) packagename) (file-name-as-directory (concat basedir (replace-regexp-in-string "\\\." "/" packagename))) basedir)) ;; the filename of the source file (src-file (concat packagedir classname ".java")) ;; compiler flags (cmpflag (or (cdr (assq :cmpflag params)) "")) ;; runtime flags (cmdline (or (cdr (assq :cmdline params)) "")) ;; command line args (cmdargs (or (cdr (assq :cmdargs params)) "")) ;; the command to compile and run (cmd (concat org-babel-java-compiler-command " " cmpflag " " (org-babel-process-file-name src-file 'noquote) " && " org-babel-java-runtime-command " -cp " (org-babel-process-file-name basedir 'noquote) " " cmdline " " (if run-from-temp classname fullclassname) " " cmdargs)) ;; header args for result processing (result-type (cdr (assq :result-type params))) (result-params (cdr (assq :result-params params))) (result-file (and (eq result-type 'value) (org-babel-temp-file "java-"))) ;; the expanded body of the source block (full-body (org-babel-expand-body:java body params))) ;; created package-name directories if missing (unless (or (not packagedir) (file-exists-p packagedir)) (make-directory packagedir 'parents)) ;; write the source file (setq full-body (org-babel-java--expand-for-evaluation full-body run-from-temp result-type result-file)) (with-temp-file src-file (insert full-body)) ;; compile, run, process result (org-babel-reassemble-table (org-babel-java-evaluate cmd result-type result-params result-file) (org-babel-pick-name (cdr (assoc :colname-names params)) (cdr (assoc :colnames params))) (org-babel-pick-name (cdr (assoc :rowname-names params)) (cdr (assoc :rownames params)))))) ;; helper functions (defun org-babel-java-find-classname (body) "Try to find fully qualified class name in BODY. Look through BODY for the package and class. If found, put them together into a fully qualified class name and return. Else just return class name. If that isn't found either, default to Main." (let ((package (if (string-match "package \\\([^ ]*\\\);" body) (match-string 1 body))) (class (if (string-match "public class \\\([^ \n]*\\\)" body) (match-string 1 body)))) (or (and package class (concat package "." class)) (and class class) (and package (concat package ".Main")) "Main"))) (defconst org-babel-java--package-re "^[[:space:]]*package .*;$" "Regexp for the package statement.") (defconst org-babel-java--imports-re "^[[:space:]]*import .*;$" "Regexp for import statements.") (defconst org-babel-java--class-re "^public class [[:alnum:]_]+[[:space:]]*\n?[[:space:]]*{" "Regexp for the class declaration.") (defconst org-babel-java--main-re "public static void main(String\\(?:\\[]\\)? args\\(?:\\[]\\)?).*\n?[[:space:]]*{" "Regexp for the main method declaration.") (defconst org-babel-java--any-method-re "public .*(.*).*\n?[[:space:]]*{" "Regexp for any method.") (defconst org-babel-java--result-wrapper "\n public static String __toString(Object val) { if (val instanceof String) { return \"\\\"\" + val + \"\\\"\"; } else if (val == null) { return \"null\"; } else if (val.getClass().isArray()) { StringBuffer sb = new StringBuffer(); Object[] vals = (Object[])val; sb.append(\"[\"); for (int ii=0; ii