Walkthrough: live

Source walkthrough from src-doc/walkthrough/std_lang_02_live.clj

This page promotes the existing walkthrough source into the public Hara docs. The implementation source remains in src-doc/walkthrough/std_lang_02_live.clj; this page explains the intent and links it to the surrounding Hara layers.

1    Motivation

The walkthrough shows how hara.lang scripts define target contexts, how forms are emitted or executed, and how generated pointers connect Clojure authoring to target language code.

2    How to use it

Read the source file directly for the executable facts. The docs page keeps high-level explanation here and uses selected fact snippets below.

What each section demonstrates: the first shows !.js returning values instead of code strings; the second makes the emission visible with l/with:print-all; the third shows the identical hara.lang body running under Lua and Python; the last mixes live results from all three runtimes in one Clojure expression.

3    Walkthrough

3.1    Live JS execution

Adding :runtime :basic to l/script- makes !.js execute the generated code and return the result. You can define functions and call them like ordinary Clojure values.

evaluate JS arithmetic live

^{:refer hara.lang/script- :added "4.0"}
(do
  (l/script- :js
    {:runtime :basic
     :require [[xt.lang.spec-base :as xt]]})
  (!.js (+ 1 2 3)))
=> 6

define and call a JS function

^{:refer hara.lang/emit-ptr :added "4.0"}
(do
  (l/script- :js
    {:runtime :basic
     :require [[xt.lang.spec-base :as xt]]})
  (defn.js hello []
    (return (+ 1 2 3)))
  [(hello)
   (!.js (+ (-/hello) (-/hello)))])
=> [6 12]

3.2    Observing emitted code

l/with:print-all echoes the generated code that is sent to the runtime. Wrap it in with-out-str to capture the output as a string.

capture emitted JS with print-all

^{:refer hara.lang/with:print-all :added "4.0"}
(do
  (l/script- :js
    {:runtime :basic
     :require [[xt.lang.spec-base :as xt]]})
  (defn.js hello []
    (return (+ 1 2 3)))
  (string?
   (with-out-str
     (l/with:print-all
       (!.js (+ (-/hello) (-/hello)))))))
=> true

3.3    Live Lua and Python execution

The :basic runtime works for Lua and Python too. The same hara.lang function body runs in each target process.

evaluate Lua live

^{:refer hara.lang/script- :added "4.0"}
(do
  (l/script- :lua
    {:runtime :basic
     :require [[xt.lang.spec-base :as xt]]})
  (defn.lua world []
    (return (+ 1 2 3)))
  (world))
=> 6

evaluate Python live

^{:refer hara.lang/script- :added "4.0"}
(do
  (l/script- :python
    {:runtime :basic
     :require [[xt.lang.spec-base :as xt]]})
  (defn.py again []
    (return (+ 1 2 3)))
  (again))
=> 6

3.4    End-to-end: combine live results

Because each runtime returns Clojure values, you can mix results from several languages in a single Clojure expression.

sum results from live JS, Lua, and Python runtimes

(do
  (l/script- :js
    {:runtime :basic
     :require [[xt.lang.spec-base :as xt]]})
  (defn.js hello []
    (return 1))
  (l/script- :lua
    {:runtime :basic
     :require [[xt.lang.spec-base :as xt]]})
  (defn.lua world []
    (return 2))
  (l/script- :python
    {:runtime :basic
     :require [[xt.lang.spec-base :as xt]]})
  (defn.py again []
    (return 3))
  (+ (hello) (world) (again)))
=> 6

4    Source

(l/script- :js
  {:runtime :basic
   :require [[xt.lang.spec-base :as xt]]})

js runtime

^:hidden
  
(!.js
 (+ 1 2 3))
=> 6
  
(defn.js hello
  []
  (return
   (+ 1 2 3)))

(hello)
=> 6
  
(!.js (+ (-/hello)
         (-/hello)))
=> 12

;;
;; print out what was sent to the repl
;;
  
(std.concurrent.print/with-out-str
  (l/with:print-all
    (!.js (+ (-/hello)
             (-/hello)))))
=> string?
  
;;
;; `^*` is shortcut for print-all
;;
  
(std.concurrent.print/with-out-str
  ^*(!.js (+ (-/hello)
             (-/hello))))
=> string?
(l/script- :lua
  {:runtime :basic
   :require [[xt.lang.spec-base :as xt]]})

lua runtime

^:hidden
  
(!.lua
 (+ 1 2 3))
=> 6

(defn.lua world
  []
  (return
   (+ 1 2 3)))
  
(world)
=> 6

(!.lua (+ (-/world)
          (-/world)))
=> 12
  
(std.concurrent.print/with-out-str
  (l/with:print-all
    (!.lua (+ (-/world)
              (-/world)))))
=> string?
(l/script- :python
  {:runtime :basic
   :require [[xt.lang.spec-base :as xt]]})

python runtime

^:hidden
  
(!.py
 (+ 1 2 3))
=> 6

(defn.py again
  []
  (return
   (+ 1 2 3)))
  
(again)
=> 6

(!.py (+ (-/again)
         (-/again)))
=> 12

(std.concurrent.print/with-out-str
  (l/with:print-all
    (!.py (+ (-/again)
             (-/again)))))
=> string?
(l/script- :r
  {:runtime :basic
   :require [[xt.lang.spec-base :as xt]]})

r runtime

^:hidden
  
(!.R
 (+ 1 2 3))
=> 6

(def.R stuff
  (fn []
    (return
     (+ 1 2 3))))

(stuff)
=> 6

(!.R (+ (-/stuff)
        (-/stuff)))
=> 12

(std.concurrent.print/with-out-str
  (l/with:print-all
    (!.R (+ (-/stuff)
            (-/stuff)))))
=> string?

Altogether now

^:hidden

;;
;; execution on all 4 runtimes, then combining result with clojure
;;
  
(+ (-/hello)
   (-/world)
   (-/again)
   (-/stuff))
=> 24