emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/ob-haxe ce15a4f 2/6: Add initial implementation and tes


From: Stefan Monnier
Subject: [elpa] externals/ob-haxe ce15a4f 2/6: Add initial implementation and tests
Date: Thu, 21 Jan 2021 17:09:46 -0500 (EST)

branch: externals/ob-haxe
commit ce15a4f61e3447087e921451262a5dee8a14cd6d
Author: Ian Martins <ianxm@jhu.edu>
Commit: Ian Martins <ianxm@jhu.edu>

    Add initial implementation and tests
---
 .gitignore      |   1 +
 README.md       |   2 -
 README.org      |   4 +
 ob-haxe.el      | 388 +++++++++++++++++++++++++++++++++++++++
 test-ob-haxe.el | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 945 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c531d98
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.elc
diff --git a/README.md b/README.md
deleted file mode 100644
index 45a2886..0000000
--- a/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# ob-haxe.el
-org babel functions for haxe evaluation
diff --git a/README.org b/README.org
new file mode 100644
index 0000000..a8b53f5
--- /dev/null
+++ b/README.org
@@ -0,0 +1,4 @@
+* ob-haxe.el
+Org babel functions for haxe evaluation.
+
+Full documentation will be available on 
[[https://orgmode.org/worg/org-contrib/babel/languages/index.html][worg]] (when 
I write it).
diff --git a/ob-haxe.el b/ob-haxe.el
new file mode 100644
index 0000000..f2e463f
--- /dev/null
+++ b/ob-haxe.el
@@ -0,0 +1,388 @@
+;;; ob-haxe.el --- org-babel functions for haxe evaluation -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
+
+;; Author: Ian Martins
+;; Keywords: literate programming, reproducible research
+;; Homepage: https://orgmode.org
+
+;; This file is not 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 haxe source code.
+
+;;; Code:
+(require 'ob)
+
+(defvar org-babel-tangle-lang-exts)
+(add-to-list 'org-babel-tangle-lang-exts '("haxe" . "hx"))
+
+(defvar org-babel-temporary-directory) ; from ob-core
+
+(defvar org-babel-default-header-args:haxe '()
+  "Default header args for haxe source blocks.")
+
+(defconst org-babel-header-args:haxe '((imports . :any))
+  "Haxe-specific header arguments.")
+
+(defcustom org-babel-neko-command "neko"
+  "Name of the neko command.
+May be either a command in the path, like neko or an absolute
+path name, like /usr/local/bin/neko."
+  :group 'org-babel
+  :package-version '(Org . "9.5")
+  :type 'string)
+
+(defcustom org-babel-haxe-compiler "haxe"
+  "Name of the haxe compiler.
+May be either a command in the path, like haxe or an absolute
+path name, like /usr/local/bin/haxe.  Parameters may be used,
+like haxe --verbose."
+  :group 'org-babel
+  :package-version '(Org . "9.5")
+  :type 'string)
+
+(defcustom org-babel-haxe-hline-to "null"
+  "Replace hlines in incoming tables with this when translating to haxe."
+  :group 'org-babel
+  :package-version '(Org . "9.5")
+  :type 'string)
+
+(defcustom org-babel-haxe-null-to 'hline
+  "Replace `null' in haxe tables with this before returning."
+  :group 'org-babel
+  :package-version '(Org . "9.5")
+  :type 'symbol)
+
+(defconst org-babel-haxe--package-re (rx line-start (0+ space) "package"
+                                         (1+ space) (group (1+ (in alnum ?_ 
?.))) ; capture the package name
+                                         (0+ space) ?\; line-end)
+  "Regexp for the package statement.")
+(defconst org-babel-haxe--imports-re (rx line-start (0+ space) "import"
+                                         (1+ space) (group (1+ (in alnum ?_ 
?.))) ; capture the fully qualified class name
+                                         (0+ space) ?\; line-end)
+  "Regexp for import statements.")
+(defconst org-babel-haxe--class-re (rx line-start (0+ space) "class" (1+ space)
+                                       (group (1+ (in alnum ?_))) ; capture 
the class name
+                                       (0+ space) ?{)
+  "Regexp for the class declaration.")
+(defconst org-babel-haxe--main-re (rx line-start (0+ space)
+                                      (opt "public" (1+ space))
+                                      "static"
+                                      (1+ space) "function"
+                                      (1+ space) "main"
+                                      (0+ space) ?\(
+                                      (0+ space) ?\)
+                                      (0+ space) ?{)
+  "Regexp for the main method declaration.")
+(defconst org-babel-haxe--any-method-re (rx line-start
+                                            (0+ space) (opt (seq (1+ alnum) 
(1+ space)))   ; visibility
+                                            (opt (seq "static" (1+ space)))    
            ; binding
+                                            "function"                         
            ; function
+                                            (1+ space) (1+ (in alnum ?_))      
            ; method name
+                                            (0+ space) ?\(
+                                            (0+ space) (0+ (in alnum ?_ ?\[ 
?\] ?, space)) ; params
+                                            (0+ space) ?\)
+                                            (0+ space) (opt ?: (0+ space) (1+ 
(in alnum ?_ ?\[ ?\]))) ; return type
+                                            (0+ space) ?{)
+  "Regexp for any method.")
+(defconst org-babel-haxe--result-wrapper "
+    public static function main() {
+        var output = File.write(\"%s\");
+        output.writeString(haxe.Json.stringify(_main()));
+        output.close();
+    }\n"
+  "Code to inject into a class so that we can capture the value it returns.
+This implementation was inspired by ob-python, although not as
+elegant.  This modified the source block to write out the value
+it wants to return to a temporary file so that ob-haxe can read
+it back.  The name of the temporary file to write must be
+replaced in this string.")
+
+(defun org-babel-execute:haxe (body params)
+  "Execute a haxe source block with BODY code and PARAMS params."
+  (let* (;; if true, run from babel temp directory
+         (run-from-temp (not (alist-get :dir params)))
+         ;; class and package
+         (fullclassname (or (cdr (assq :classname params))
+                            (org-babel-haxe-find-classname body)))
+         ;; just the class name
+         (classname (car (last (split-string fullclassname "\\."))))
+         ;; just the package name
+         (packagename (if (string-match-p "\\." fullclassname)
+                          (file-name-base fullclassname)))
+         ;; the base dir that contains the top level package dir
+         (basedir (file-name-as-directory (if run-from-temp
+                                              (if (file-remote-p 
default-directory)
+                                                  (concat
+                                                   (file-remote-p 
default-directory)
+                                                   
org-babel-remote-temporary-directory)
+                                                org-babel-temporary-directory)
+                                            default-directory)))
+         (basedir-processed (org-babel-process-file-name basedir 'noquote))
+         ;; 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))
+         ;; runtime flags
+         (cmdline (or (cdr (assq :cmdline params)) ""))
+         ;; compilation target
+         (target-name (cdr (assq :target params)))
+         (target (pcase target-name
+                   ("neko"
+                    (format "-neko %smain.n -cmd \"neko %smain.n %s\""
+                            basedir-processed basedir-processed cmdline))
+                   ("hashlink"
+                    (format "-hl %smain.hl -cmd \"hl %smain.hl %s\""
+                            basedir-processed basedir-processed cmdline))
+                   (_
+                    (if (> (length cmdline) 0)
+                        (error "Cmdline args not allowed for interp target")
+                      "--interp"))))
+         ;; the command to compile and run
+         (cmd (concat org-babel-haxe-compiler
+                      " -p " basedir
+                      " -main " (if run-from-temp classname fullclassname) " " 
target))
+         ;; 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 "haxe-")))
+         ;; the expanded body of the source block
+         (full-body (org-babel-expand-body:haxe 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-haxe--expand-for-evaluation
+                     full-body run-from-temp result-type result-file))
+    (with-temp-file (concat (file-name-as-directory packagedir)
+                            classname ".hx")
+      (insert full-body))
+
+    ;; compile, run, process result
+    (org-babel-reassemble-table
+     (org-babel-haxe-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-haxe-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 org-babel-haxe--package-re body)
+                     (match-string 1 body)))
+        (class (if (string-match org-babel-haxe--class-re body)
+                   (match-string 1 body))))
+    (or (and package class (concat package "." class))
+        (and class class)
+        (and package (concat package ".Main"))
+        "Main")))
+
+(defun org-babel-haxe--expand-for-evaluation (body suppress-package-p 
result-type result-file)
+  "Expand source block for evaluation.
+In order to return a value we have to add a __toString method.
+In order to prevent classes without main methods from erroring we
+add a dummy main method if one is not provided.  These
+manipulations are done outside of `org-babel--expand-body' so
+that they are hidden from tangles.
+
+BODY is the file content before instrumentation.
+
+SUPPRESS-PACKAGE-P if true, suppress the package statement.
+
+RESULT-TYPE is taken from params.
+
+RESULT-FILE is the temp file to write the result."
+  (with-temp-buffer
+    (insert body)
+
+    ;; suppress package statement
+    (goto-char (point-min))
+    (when (and suppress-package-p
+               (re-search-forward org-babel-haxe--package-re nil t))
+      (replace-match ""))
+
+    ;; add a dummy main method if needed
+    (goto-char (point-min))
+    (when (not (re-search-forward org-babel-haxe--main-re nil t))
+      (org-babel-haxe--move-past org-babel-haxe--class-re)
+      (insert "\n    public static function main() {
+        Sys.print(\"success\");
+    }\n\n"))
+
+    ;; special handling to return value
+    (when (eq result-type 'value)
+      (goto-char (point-min))
+      (org-babel-haxe--move-past org-babel-haxe--class-re)
+      (insert (format org-babel-haxe--result-wrapper
+                      (org-babel-process-file-name result-file 'noquote)))
+      (search-forward "public static function main(") ; rename existing main
+      (replace-match "public static function _main("))
+
+    ;; add imports
+    (org-babel-haxe--import-maybe "sys.io" "File")
+
+    (buffer-string)))
+
+(defun org-babel-haxe--move-past (re)
+  "Move point past the first occurrence of the given regexp RE."
+  (while (re-search-forward re nil t)
+    (goto-char (1+ (match-end 0)))))
+
+(defun org-babel-haxe--import-maybe (package class)
+  "Import from PACKAGE the given CLASS if it is used and not already imported."
+  (let (class-found import-found)
+    (goto-char (point-min))
+    (setq class-found (re-search-forward class nil t))
+    (goto-char (point-min))
+    (setq import-found (re-search-forward (concat "^import .*" package ".*" 
class ";") nil t))
+    (when (and class-found (not import-found))
+      (org-babel-haxe--move-past org-babel-haxe--package-re)
+      (insert (concat "import " package "." class ";\n")))))
+
+(defun org-babel-expand-body:haxe (body params)
+  "Expand BODY with PARAMS.
+BODY could be a few statements, or could include a full class
+definition specifying package, imports, and class.  Because we
+allow this flexibility in what the source block can contain, it
+is simplest to expand the code block from the inside out."
+  (let* ((fullclassname (or (cdr (assq :classname params)) ; class and package
+                            (org-babel-haxe-find-classname body)))
+         (classname (car (last (split-string fullclassname "\\.")))) ; just 
class name
+         (packagename (if (string-match-p "\\." fullclassname)       ; just 
package name
+                          (file-name-base fullclassname)))
+         (var-lines (org-babel-variable-assignments:haxe params))
+         (imports-val (assq :imports params))
+         (imports (if imports-val
+                      (split-string (org-babel-read (cdr imports-val) nil) " ")
+                    nil)))
+    (with-temp-buffer
+      (insert body)
+
+      ;; wrap main.  If there are methods defined, but no main method
+      ;; and no class, wrap everything in a generic main method.
+      (goto-char (point-min))
+      (when (and (not (re-search-forward org-babel-haxe--main-re nil t))
+                 (not (re-search-forward org-babel-haxe--any-method-re nil t)))
+        (org-babel-haxe--move-past org-babel-haxe--package-re) ; if package is 
defined, move past it
+        (org-babel-haxe--move-past org-babel-haxe--imports-re) ; if imports 
are defined, move past them
+        (insert "public static function main() {\n")
+        (indent-code-rigidly (point) (point-max) 4)
+        (goto-char (point-max))
+        (insert "\n}"))
+
+      ;; wrap class.  If there's no class, wrap everything in a
+      ;; generic class.
+      (goto-char (point-min))
+      (when (not (re-search-forward org-babel-haxe--class-re nil t))
+        (org-babel-haxe--move-past org-babel-haxe--package-re) ; if package is 
defined, move past it
+        (org-babel-haxe--move-past org-babel-haxe--imports-re) ; if imports 
are defined, move past them
+        (insert (concat "\nclass " (file-name-base classname) " {\n"))
+        (indent-code-rigidly (point) (point-max) 4)
+        (goto-char (point-max))
+        (insert "\n}"))
+      (goto-char (point-min))
+
+      ;; insert variables from source block headers
+      (when var-lines
+        (goto-char (point-min))
+        (org-babel-haxe--move-past org-babel-haxe--class-re)   ; move inside 
class
+        (insert (mapconcat 'identity var-lines "\n"))
+        (insert "\n"))
+
+      ;; add imports from source block headers
+      (when imports
+        (goto-char (point-min))
+        (org-babel-haxe--move-past org-babel-haxe--package-re) ; if package is 
defined, move past it
+        (insert (mapconcat (lambda (package) (concat "import " package ";")) 
imports "\n") "\n"))
+
+      ;; add package at the top
+      (goto-char (point-min))
+      (when (and packagename (not (re-search-forward 
org-babel-haxe--package-re nil t)))
+        (insert (concat "package " packagename ";\n")))
+
+      ;; return expanded body
+      (buffer-string))))
+
+(defun org-babel-variable-assignments:haxe (params)
+  "Return a list of haxe statements assigning the block's variables.
+variables are contained in PARAMS."
+  (mapcar
+   (lambda (pair)
+     (format "    static var %s %s = %s;"
+             (car pair)                                ; name
+             (if (and (sequencep (cdr pair))           ; type
+                      (not (stringp (cdr pair))))
+                 ":Array<Dynamic> " "")
+             (org-babel-haxe-var-to-haxe (cdr pair)))) ; value
+   (org-babel--get-vars params)))
+
+(defun org-babel-haxe-var-to-haxe (var)
+  "Convert an elisp value to a haxe variable.
+Convert an elisp value, VAR, into a string of haxe source code
+specifying a variable of the same value."
+  (cond ((and (sequencep var)
+              (not (stringp var)))
+         (concat "[" (mapconcat #'org-babel-haxe-var-to-haxe var ", ") "]"))
+        ((equal var 'hline)
+         org-babel-haxe-hline-to)
+        (t
+         (format "%S" (if (stringp var) (substring-no-properties var) var)))))
+
+(defun org-babel-haxe-table-or-string (results)
+  "Convert RESULTS into an appropriate elisp value.
+If the results look like a list or vector, then convert them into an
+Emacs-lisp table, otherwise return the results as a string."
+  (let ((res (org-babel-script-escape results)))
+    (if (listp res)
+        (mapcar (lambda (el) (if (eq 'null el)
+                                 org-babel-haxe-null-to
+                               el))
+                res)
+      res)))
+
+(defun org-babel-haxe-evaluate (cmd result-type result-params result-file)
+  "Evaluate using an external haxe process.
+CMD the command to execute.
+
+If RESULT-TYPE equals `output' then return standard output as a
+string.  If RESULT-TYPE equals `value' then return the value
+returned by the source block, as elisp.
+
+RESULT-PARAMS input params used to format the reponse.
+
+RESULT-FILE filename of the tempfile to store the returned value in
+for `value' RESULT-TYPE.  Not used for `output' RESULT-TYPE."
+  (let ((raw (pcase result-type
+               (`output (org-babel-eval cmd ""))
+               (`value (org-babel-eval cmd "")
+                       (org-babel-eval-read-file result-file)))))
+    (org-babel-result-cond result-params raw
+      (org-babel-haxe-table-or-string raw))))
+
+(provide 'ob-haxe)
+
+;;; ob-haxe.el ends here
diff --git a/test-ob-haxe.el b/test-ob-haxe.el
new file mode 100644
index 0000000..e347500
--- /dev/null
+++ b/test-ob-haxe.el
@@ -0,0 +1,552 @@
+;;; test-ob-haxe.el --- tests for ob-haxe.el
+
+;; Copyright (c) 2020-2021 Free Software Foundation, Inc.
+;; Author: Ian Martins
+
+;; 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 of the License, 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+(require 'org-test)
+
+(require 'ob-core)
+(defvar org-babel-temporary-directory ; from ob-core
+  (if (boundp 'org-babel-temporary-directory)
+    org-babel-temporary-directory
+  (temporary-file-directory)))
+
+(org-test-for-executable "haxe")
+(org-test-for-executable "neko")
+(org-test-for-executable "hl")
+(unless (featurep 'ob-haxe)
+  (signal 'missing-test-dependency "Support for haxe code blocks"))
+
+; simple tests
+
+(ert-deftest ob-haxe/simple ()
+  "Hello world program that writes output."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+Sys.print(42);
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-bracket ()
+  "Hello world program that outputs an open square bracket."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+Sys.print(\"[42\");
+#+end_src"
+   (should (string= "[42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-quote ()
+  "Hello world program that writes quotes."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+Sys.print(\"\\\"42\\\"\");
+#+end_src"
+   (should (string= "\"42\"" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-return-int ()
+  "Hello world program that returns an int value.  Also tests
+that ob-haxe defaults to scripting mode."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil silent
+return 42;
+#+end_src"
+   (should (eq 42 (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-return-float ()
+  "Hello world program that returns a float value."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results value silent
+return 42.1;
+#+end_src"
+   (should (equal 42.1 (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-return-string ()
+  "Hello world program that returns a string value."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results value silent
+return \"forty two\";
+#+end_src"
+    (should (string= "forty two" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-return-int-neko ()
+  "Hello world program that returns an int value.  Also tests
+that ob-haxe defaults to scripting mode."
+  (org-test-with-temp-text
+      "#+begin_src haxe :target neko :dir 'nil silent
+return 42;
+#+end_src"
+   (should (eq 42 (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-return-int-hl ()
+  "Hello world program that returns an int value.  Also tests
+that ob-haxe defaults to scripting mode."
+  (org-test-with-temp-text
+      "#+begin_src haxe :target hl :dir 'nil silent
+return 42;
+#+end_src"
+   (should (eq 42 (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-main ()
+  "Hello world program that defines a main function."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+public static function main() {
+    Sys.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-two-methods ()
+  "Hello world program with two methods and no class."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+public static function main() {
+    Sys.print(foo());
+}
+public static function foo() {
+    return 42;
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-no-main ()
+  "Hello world program with no main method.  Babel adds a dummy one so it can 
run without error."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+public static function foo() {
+    return 42;
+}
+#+end_src"
+    (should (string= "success" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-main-args-array ()
+  "Hello world program that defines a main function with the square brackets 
after `args'."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+public static function main() {
+    Sys.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-main-whitespace ()
+  "Hello world program that defines a main function with the square brackets 
after `args'."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+public
+static
+function
+main
+ (
+)
+{
+    Sys.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-class ()
+  "Hello world program that defines a class."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+class Simple {
+    public static function main() {
+        Sys.print(42);
+    }
+}
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-class-and-package ()
+  "Hello world program that defines a class and package."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent
+package pkg;
+class Simple {
+    public static function main() {
+        Sys.print(42);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-class-attr ()
+  "Hello world program with class header attribute."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent :classname Simple
+public static function main() {
+    Sys.print(42);
+}
+#+end_src"
+   (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/simple-with-class-attr-with-package ()
+  "Hello world program with class attr with package."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output silent :classname pkg.Simple
+public static function main() {
+    Sys.print(42);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+
+;; var tests
+
+(ert-deftest ob-haxe/integer-var ()
+  "Read and write an integer variable."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=42 :results output silent
+Sys.print(a);
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/var-with-main ()
+  "Read and write an integer variable, with main function provided."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=42 :results output silent
+public static function main() {
+    Sys.print(a);
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/var-with-class ()
+  "Read and write an integer variable, with class provided."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=42 :results output silent
+class Main {
+    public static function main() {
+        Sys.print(a);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/var-with-class-and-package ()
+  "Read and write an integer variable, with class and package provided."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=42 :results output silent
+package pkg;
+class Main {
+    public static function main() {
+        Sys.print(a);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/var-with-class-and-hanging-curlies ()
+  "Read and write an integer variable, with class with hanging curlies."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=42 :results output silent
+class Main
+{
+    public static function main()
+    {
+        Sys.print(a);
+    }
+}
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/two-vars ()
+  "Read two integer variables, combine and write them."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=21 b=2 :results output silent
+Sys.print(a*b);
+#+end_src"
+    (should (string= "42" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/string-var ()
+  "Read and write a string variable."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=\"forty two\" :results output silent
+Sys.print('$a, len=${a.length}');
+#+end_src"
+    (should (string= "forty two, len=9" (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/multiline-string-var ()
+  "Haxe doesn't support multiline string literals, so this errors."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=\"forty\ntwo\" :results output silent
+Sys.print(String.format(\"%s, len=%d\", a, a.length()));
+#+end_src"
+    (should-error (org-babel-execute-src-block)))
+  :type 'error)
+
+;; return array
+
+(ert-deftest ob-haxe/return-vector-using-array ()
+  "Return a vector using an array."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results value vector silent
+return [[4], [2]];
+#+end_src"
+    (should (equal '((4) (2))
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/read-return-array ()
+  "Read and return an array."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=haxe_list :results value silent
+return [a[0][0], a[1][0]];
+#+end_src
+
+#+name: haxe_list
+- forty
+- two"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/read-return-array-with-package ()
+  "Read and return an array with package."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=haxe_list :results value silent
+package pkg;
+return [a[0][0], a[1][0]];
+#+end_src
+
+#+name: haxe_list
+- forty
+- two"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/output-list-with-spaces ()
+  "Return a vector."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :results output list raw silent
+Sys.println(\"forty two\");
+Sys.println(\"forty two\");
+#+end_src"
+    (should (equal "forty two\nforty two\n"
+                   (org-babel-execute-src-block)))))
+
+;; list vars
+
+(ert-deftest ob-haxe/list-var ()
+  "Read and write a list variable."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a='(\"forty\" \"two\") :results value 
silent
+var b = a;
+return b;
+#+end_src"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/vector-var ()
+  "Read and write a vector variable."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a='[\"forty\" \"two\"] :results value 
silent
+var b = a;
+return b;
+#+end_src"
+    (should (equal '("forty" "two")
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/matrix-var ()
+  "Read and write matrix variable."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=haxe_matrix :results value silent
+var b = [[a[0][0], a[1][0]],
+         [a[0][1], a[1][1]]];
+return b; // transpose
+#+end_src
+
+#+name: haxe_matrix
+| 2 | 1 |
+| 4 | 2 |"
+    (should (equal '((2 4) (1 2))
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/matrix-var-with-header ()
+  "Read matrix variable and write it with header."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=haxe_matrix :results value table 
silent
+var b = [[\"col1\", \"col2\"],
+         null,
+         [a[0][0], a[1][0]],
+         [a[0][1], a[1][1]]];
+return b; // transpose
+#+end_src
+
+#+name: haxe_matrix
+| 2 | 1 |
+| 4 | 2 |"
+    (should (equal '(("col1" "col2") hline (2 4) (1 2))
+                   (org-babel-execute-src-block)))))
+
+;; output table
+
+(ert-deftest ob-haxe/output-table-with-header ()
+  "Write a table that includes a header."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=haxe_matrix :results output raw table 
silent
+Sys.println(\"|col1|col2|\");
+Sys.println(\"|-\");
+for (ii in 0...a.length) {
+    for (jj in 0...a[0].length) {
+        Sys.print('|${a[ii][jj]}');
+    }
+    Sys.println(\"\");
+ }
+#+end_src
+
+#+name: haxe_matrix
+| 2 | 1 |
+| 4 | 2 |"
+    (should (equal "|col1|col2|\n|-\n|2|1\n|4|2\n"
+                   (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/inhomogeneous_table ()
+  "Read and write an inhomogeneous table."
+  (org-test-with-temp-text
+      "#+begin_src haxe :dir 'nil :var a=haxe_table :results value silent
+return [[a[0][0], a[0][1]*2],
+        [a[1][0], a[1][1]*2]];
+#+end_src
+
+#+name: haxe_table
+  | string | number |
+  |--------+--------|
+  | forty  |      2 |
+  | two    |      1 |"
+   (should (equal
+            '(("forty" 4) ("two" 2))
+            (org-babel-execute-src-block)))))
+
+;; imports
+
+(ert-deftest ob-haxe/import_library ()
+  "Import a standard haxe library."
+  (org-test-with-temp-text
+      "#+begin_src haxe :results output silent :imports haxe.crypto.Base64 
haxe.io.Bytes
+  var encoded = Base64.encode(Bytes.ofString(\"42\"));
+  var decoded = Base64.decode(encoded);
+  Sys.print('encoded=$encoded, decoded=$decoded');
+#+end_src"
+   (should (string=
+            "encoded=NDI=, decoded=42"
+            (org-babel-execute-src-block)))))
+
+(ert-deftest ob-haxe/import_library_inline ()
+  "Import a standard haxe library."
+  (org-test-with-temp-text
+      "#+begin_src haxe :results output silent
+  import haxe.crypto.Base64;
+  import haxe.io.Bytes;
+  var encoded = Base64.encode(Bytes.ofString(\"42\"));
+  var decoded = Base64.decode(encoded);
+  Sys.print('encoded=$encoded, decoded=$decoded');
+#+end_src"
+   (should (string=
+            "encoded=NDI=, decoded=42"
+            (org-babel-execute-src-block)))))
+
+;; tangle
+
+(ert-deftest ob-haxe/tangle ()
+  "Tangle a source block."
+  (org-test-with-temp-text-in-file
+      "#+begin_src haxe :dir 'nil :tangle \"Tangle.hx\" :results value 
:classname Tangle
+return \"tangled\";
+#+end_src"
+    (should
+     (string=
+      "class Tangle {
+    public static function main() {
+        return \"tangled\";
+    }
+}
+"
+      (unwind-protect
+          (progn (org-babel-tangle)
+                 (with-temp-buffer
+                   (insert-file-contents "Tangle.hx")
+                   (untabify (point-min) (point-max))
+                   (buffer-string)))
+        (delete-file "Tangle.hx"))))))
+
+(ert-deftest ob-haxe/tangle-with-package ()
+  "Tangle a source block."
+  (org-test-with-temp-text-in-file
+      "#+begin_src haxe :dir 'nil :tangle \"tangle/Tangle.hx\" :results value 
:classname tangle.Tangle
+return \"tangled\";
+#+end_src"
+    (should
+     (string=
+      "package tangle;
+
+class Tangle {
+    public static function main() {
+        return \"tangled\";
+    }
+}
+"
+      (unwind-protect
+          (progn
+            (make-directory "tangle")
+            (org-babel-tangle)
+            (with-temp-buffer
+              (insert-file-contents "tangle/Tangle.hx")
+              (untabify (point-min) (point-max))
+              (buffer-string)))
+        (delete-file "tangle/Tangle.hx")
+        (delete-directory "tangle"))))))
+
+
+;; specify output dir
+
+(ert-deftest ob-haxe/simple-dir ()
+  "Hello world program that writes output."
+  (org-test-with-temp-text
+      (format  "#+begin_src haxe :dir %s :results output silent
+Sys.print(42);
+#+end_src" org-babel-temporary-directory)
+    (should (string=
+             "42"
+             (unwind-protect
+                 (org-babel-execute-src-block)
+               (delete-file (concat (file-name-as-directory 
org-babel-temporary-directory)
+                                    "Main.hx")))))))
+
+(ert-deftest ob-haxe/simple-dir-with-package ()
+  "Hello world program that writes output."
+  (org-test-with-temp-text
+      (format "#+begin_src haxe :dir %s :results output silent
+package pkg;
+
+class Main {
+    public static function main() {
+      Sys.print(42);
+    }
+}
+#+end_src" org-babel-temporary-directory)
+    (should (string=
+             "42"
+             (unwind-protect
+                 (org-babel-execute-src-block)
+               (delete-file (concat (file-name-as-directory 
org-babel-temporary-directory)
+                                    "pkg/Main.hx"))
+               (delete-directory (concat (file-name-as-directory 
org-babel-temporary-directory)
+                                         "pkg")))))))
+
+
+;;; test-ob-haxe.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]