Hara examples

Generated project examples from src-build/play.

The play projects demonstrate hara.lang as a project generator: C pthreads, Go modules, typed xtalk declarations, TypeScript packages, OpenResty Lua, and Blessed terminal UIs.

1    Generated projects

Use src-build/play/*/main.clj for authored source and src-build/play/*/build.clj for generated project configuration. The build namespaces use std.make to create Makefiles, package files, generated source files, and runnable project layouts.

2    Representative examples

Start with Go and TypeScript user-directory examples for typed data, OpenResty examples for Lua runtime integration, and TUI examples for JS/Blessed UI output. Cross-link the xtalk examples from the xt section where relevant.

3    Walkthrough

3.1    Generating Go source

l/script- :go installs the Go book into the current namespace. Once installed, defn.go creates a function entry and l/emit-ptr emits its generated source.

define and emit a Go function

^{:refer hara.lang/script- :added "4.0"}
(do
  (l/script- :go)
  (defn.go ^{:- [:string]}
    FormatUserKey
    [:string orgId
     :string userId]
    (return (+ orgId ":" userId)))
  (l/emit-ptr FormatUserKey))
=> "func FormatUserKey(orgId string, userId string)  string {\n  return orgId + \":\" + userId\n}"

3.2    Generating JavaScript source

The same pattern works for JavaScript. l/script- :js sets up the JS context, then defn.js defines a function.

define and emit a JavaScript function

^{:refer hara.lang/script- :added "4.0"}
(do
  (l/script- :js
    {:require [[xt.lang.spec-base :as xt]]})
  (defn.js lookupUser
    [users id]
    (return (. users [id])))
  (l/emit-ptr lookupUser))
=> "export function lookupUser(users,id){\n  return users[id];\n}"

3.3    Cross-language emission

For one-off snippets, l/emit-as converts a vector of Clojure forms directly to a target language string without needing to define entries.

emit the same helper in Go, JavaScript, and Lua

^{:refer hara.lang/emit-as :added "4.0"}
[(l/emit-as :go '[(defn Add [a b] (return (+ a b)))])
 (l/emit-as :js '[(defn add [a b] (return (+ a b)))])
 (l/emit-as :lua '[(defn add [a b] (return (+ a b)))])]
=> ["func Add(a, b) {\n  return a + b\n}"
    "function add(a,b){\n  return a + b;\n}"
    "local function add(a,b)\n  return a + b\nend"]

3.4    Inspecting generated libraries

l/grammar returns the grammar map for a language, and l/lib:overview returns a data structure describing all modules currently loaded for that language.

inspect the Go grammar and library overview

^{:refer hara.lang/grammar :added "4.0"}
(let [g (l/grammar :go)]
  (every? #(contains? g %) [:macros :reserved :emit :structure]))
=> true

^{:refer hara.lang/lib:overview :added "4.0"}
(map? (l/lib:overview :go))
=> true

3.5    Scaffolding a project

The play projects wrap generated modules in a std.make project. A def.make declaration describes the repository, build sections, and output modules; make/build-all materialises the files. The build step writes to .build/, so it is shown without running.

a minimal std.make project for a Go module

(do
  (def.make PROJECT
    {:github   {:repo "example.com/play.go-000-user-directory"
                :description "Simple Go project generated from Clojure"}
     :orgfile  "Main.org"
     :triggers '#{play.go-000-user-directory.main}
     :sections {:setup [{:type :gitignore
                         :main ["bin"]}
                        {:type :makefile
                         :main [[:.PHONY {:- ["build" "test"]}]
                                [:build ["go build ./..."]]
                                [:test ["go test ./..."]]]}]}
     :default [{:type :module.single
                :lang :go
                :main 'play.go-000-user-directory.main
                :file "user_directory.go"
                :header "package userdirectory"}]})

  (make/build-all PROJECT))