$30 off During Our Annual Pro Sale. View Details »

Babashka and the Small Clojure Interpreter @ ClojureD 2020

Babashka and the Small Clojure Interpreter @ ClojureD 2020

Michiel Borkent

February 29, 2020
Tweet

More Decks by Michiel Borkent

Other Decks in Programming

Transcript

  1. And the Small Clojure Interpreter
    Michiel Borkent

    @borkdude

    2020-02-29

    View Slide

  2. • CLI tools with instant startup! (< 10ms)

    • clj-kondo: a linter for Clojure that sparks joy

    • jet: convert between JSON, EDN and Transit

    • Jan Stępień, ClojureD 2019

    • No eval: dynamic classloader not supported!
    +

    View Slide

  3. DSL -> scripting
    • Added a query DSL to jet, a GraalVM CLI:


    $ jet --query '(map :id)' <<< '[{:id 1} {:id 2}]'

    [1 2]

    • Extend this DSL to significant subset of Clojure?


    $ ??? '(->> [{:id 1} {:id 2}] (map :id))'

    (1 2)


    View Slide

  4. • Native Clojure scripting tool, single binary, no JVM

    • Can be used to replace “the grey areas” of bash

    • Installable via script, brew (macOS, linux), aur (linux), scoop
    (Windows)
    $ time bb '(+ 1 2 3)'

    6

    0.00s user 0.00s system 67% cpu 0.013 total

    View Slide

  5. CLJ scripting
    Runtime Impl Startup* Interop Windows Execution Threads
    clojure JVM Java ~1.5s + + Compiled +
    planck JSCore CLJS / JS ~ 1s + - Compiled -
    joker Native Go ~50ms** - + Interpreted -
    babashka Native GraalVM ~13ms + + Interpreted +
    *) https://stuartsierra.com/2019/12/21/clojure-start-time-in-2019 **) faster startup in progress

    View Slide

  6. Babashka goals
    • Low latency Clojure scripting alternative for JVM Clojure

    • Easy installation: README ⟶ grab binary ⟶ run within seconds
    • Familiar and portable: JVM clojure ⟷ bb, #{linux, macOS, Windows}
    • Interop with commonly used classes (System, File, java.time.*, java.nio.*)

    • Multi-threading support (pmap, future)

    • Batteries included (tools.cli, cheshire) + external libraries

    View Slide

  7. Shell interaction
    $ ls | bb -i '(filter #(-> % io/file .isDirectory) *input*)'
    ("doc" "examples" "logo" ...)

    View Slide

  8. Predefine functions
    $ export BABASHKA_PRELOADS="(defn is-dir? [f] (-> f io/file .isDirectory))"


    $ ls | bb -i '(filter is-dir? *input*)'
    ("doc" "examples" "logo" ...)

    View Slide

  9. Scripts
    $ pst.clj

    04:58
    #!/usr/bin/env bb
    (def now (java.time.ZonedDateTime/now))
    (def LA-timezone (java.time.ZoneId/of "America/Los_Angeles"))
    (def LA-time (.withZoneSameInstant now LA-timezone))
    (def pattern (java.time.format.DateTimeFormatter/ofPattern "HH:mm"))
    (println (.format LA-time pattern))

    View Slide

  10. Also works on Windows

    View Slide

  11. Included libs / namespaces
    • clojure.{core, edn, java.shell, java.io, set, string, test, walk}

    • clojure.tools.cli

    • clojure.core.async (thread ops work, go WIP)

    • clojure.data.csv

    • cheshire.core (JSON)

    • babashka.{wait, signal} (wait for port to open or file to exist)

    • TBD: clojure.xml, yaml, http client, ...

    View Slide

  12. Compatible libs and scripts
    • spartan.spec: clojure.spec.alpha (1) for bb

    • deps.clj: a port of the clojure bash script to babashka

    • clj-http-lite: lighter fork of cli-http-lite

    • medley: "missing" clojure utility functions

    • regal: create regular expressions from EDN/hiccup

    • limit-break: REPL debugging tool

    • clojure-csv: another CSV library

    View Slide

  13. Classpath
    ;; spec.clj

    (require '[spartan.spec :as s])

    (s/explain (s/cat :x int? :y keyword?) [1 #{:foo}])
    $ BABASHKA_CLASSPATH=$(clojure -Spath ...)
    $ bb spec.clj

    #{:foo} - failed: keyword? in: [1] at: [:y]

    View Slide

  14. Decomplecting babashka
    Libraries coming out of babashka:

    • edamame: EDN/Clojure parser

    • sci: a Small Clojure Interpreter

    View Slide

  15. edamame
    (def parsed (edamame/parse-string "#(+ 1 2 %)" {:fn true}))
    ;;=> (fn* [%1] (+ 1 2 %1))
    (meta parsed)
    ;;=> {:row 1, :col 1, :end-row 1, :end-col 11}
    - EDN/code parser
    - GraalVM compatible (no eval!)
    - location metadata
    - opt-in code-like features

    View Slide

  16. Small Clojure Interpreter
    (def f (sci/eval-string "#(+ 1 2 %)"))
    (f 1)
    ;;=> 4
    - Clojure interpreter
    - Works on JVM / GraalVM / JS
    - Sandboxing

    - Works in CLJS advanced compiled apps

    - Comes with Java and JS APIs (available on NPM)

    View Slide

  17. Malli: serializable schemas
    (def my-schema
    [:and
    [:map
    [:x int?]
    [:y int?]]
    [:fn '(fn [{:keys [x y]}] (> x y))]])
    (m/validate my-schema {:x 1, :y 0})
    ; => true
    (m/validate my-schema {:x 1, :y 2})
    ; => false

    View Slide

  18. Function CLI args
    $ jet --edn-reader-opts "{:readers {'foo (fn [x] [:foo x])}}" \

    <<< '#foo{:a 1}'

    [:foo {:a 1}]
    $ jet --from json --keywordize '(comp keyword str/upper-case)' \

    <<< '{"a": 1}'
    {:A 1}

    View Slide

  19. Sci from JavaScript
    https://observablehq.com/@jeroenvandijk/untitled/5
    $ npm install @borkdude/sci

    $ node

    > const { evalString, toJS } = require('@borkdude/sci');

    > x = evalString("(assoc {:a 1} :b 2)")

    > toJS(x)
    { a: 1, b: 2 }

    View Slide

  20. Sci: adding libs
    (require '[cheshire.core :as json])


    (def sci-opts

    {:namespaces

    {'cheshire.core

    {'generate-string json/generate-string}}})

    (sci/eval-string
    "(require '[cheshire.core :as json])
    (json/generate-string {:a 1})"
    sci-opts)

    ;;=> "{\"a\":1}"

    View Slide

  21. Projects using sci

    View Slide

  22. Companies* using**
    babashka / sci
    Github #254
    Add your company to the list:
    * At least one person

    ** Or evaluating

    View Slide

  23. Conclusion
    Clojure might not be the best language for everything, like
    scripting

    Clojure is the best language for scripting.

    View Slide

  24. Thank you
    https://github.com/borkdude/babashka

    https://github.com/borkdude/sci
    And the Small Clojure Interpreter

    View Slide