Files
bara-lang/docs/en/02-architecture.md
T
dimgigov 4739e2c151 docs: highlight unique advantages — standalone, HAMT, multi-target
Update README and architecture docs to emphasize:
- Complete independence from Java ecosystem (JVM, GraalVM, Closure)
- Native HAMT persistent data structures built from scratch in Nim
- Multi-target compilation (native, shared lib, WASM, JS)
- AI-native tooling and concurrency without JVM threads

Updates both English and Bulgarian documentation.
2026-05-08 23:59:24 +03:00

142 lines
5.0 KiB
Markdown

[← Back to Index](index.md)
---
# Clojure/Nim Architecture
## Overview
Clojure/Nim is a **compiler**, not an interpreter. It follows the model of ClojureScript: Clojure source is read, macro-expanded, analyzed, and emitted as Nim source code, which then compiles to C and finally to a native binary.
## Compilation Pipeline
```
┌─────────────┐
│ .clj File │
└──────┬──────┘
┌────▼────┐
│ Reader │ ← EDN parser. Produces Clojure data structures.
└────┬────┘
┌────▼────┐
│ Macros │ ← defmacro expansion. Operates on Clojure data.
└────┬────┘
┌────▼────┐
│ Analyzer│ ← Special forms, locals, closure analysis.
└────┬────┘
┌────▼────┐
│ Emitter │ ← Generates Nim AST / source code.
└────┬────┘
┌────▼────┐
│ Nim CC │ ← Nim → C compilation.
└────┬────┘
┌────▼────┐
│ C CC │ ← C → machine code (GCC/Clang).
└────┬────┘
┌────▼────┐
│ Binary │ ← Single native executable.
└─────────┘
```
## Unique Advantages
### Independence from the Java Ecosystem
Clojure/Nim is the **only** Clojure dialect with absolutely no dependency on the Java ecosystem:
| Dialect | JVM Required | GraalVM | Google Closure | Java stdlib |
|---------|-------------|---------|----------------|-------------|
| Clojure (JVM) | ✅ | ❌ | ❌ | ✅ |
| ClojureScript | ❌ | ❌ | ✅ | ❌ |
| Babashka | ❌ | ✅ | ❌ | Partial |
| **Clojure/Nim** | ❌ | ❌ | ❌ | ❌ |
This means:
- **No JVM warmup** — binaries start instantly
- **No GraalVM complexity** — no native-image configuration
- **No Java installation required** — the compiler itself is a single binary
- **True standalone deployment** — one file, zero runtime dependencies
### Native HAMT Implementation
Our persistent data structures are built from scratch in Nim, optimized for Nim's ORC garbage collector:
- **32-way branching** like Clojure's `PersistentVector`, but without Java object overhead
- **Structural sharing** via copy-on-write HAMT nodes
- **O(log₃₂ n)** for `assoc`/`dissoc`/`nth` — same asymptotic complexity as JVM Clojure
- **Nim ref objects** instead of Java interfaces — simpler memory layout, better cache locality
### Multi-Target Compilation
The same Clojure source compiles to four different targets from one codebase:
1. **Native binary**`nim c` → C → machine code
2. **Shared library**`nim c --app:lib``.so` / `.dll` / `.dylib`
3. **WASM**`nim c -d:emscripten` → browser-native WebAssembly
4. **JavaScript**`nim js` → browser/Node.js
No other Clojure implementation offers this breadth of targets without external tools.
## Key Design Decisions
### 1. AOT Compiler
We compile ahead-of-time, like ClojureScript. This gives us:
- Fast runtime execution (C speed)
- Small binary size
- No interpreter overhead
The trade-off is that REPL compilation is slower (each form is compiled individually).
### 2. Clojure Macros on Clojure Data
Macro expansion happens **before** reaching Nim. Nim never sees Clojure macros:
```clojure
(defmacro unless [condition & body]
`(if (not ~condition)
(do ~@body)))
```
This macro operates on `CljVal` objects (Clojure lists, symbols), not Nim AST.
### 3. Runtime in Nim
The `lib/cljnim_runtime.nim` module provides:
- `CljVal` — tagged union representing all Clojure values
- `cljAdd`, `cljMul`, etc. — polymorphic arithmetic
- `cljRepr` — string representation
### 4. Nim Interop
Instead of Java interop, we have direct Nim interop:
```clojure
(nim/math/sin x)
(nim/strutils/toUpper s)
```
Nim modules are auto-imported when called via the `nim/module/fn` pattern.
## Module Responsibilities
| Module | Role |
|---|---|
| `src/reader.nim` | Parses `.clj` text into `CljVal` AST |
| `src/emitter.nim` | Transforms `CljVal` AST into Nim source |
| `src/repl.nim` | Human and AI REPL implementation |
| `src/eval.nim` | Tree-walking interpreter for fast in-memory eval |
| `src/deps.nim` | Dependency resolution (deps.edn format) |
| `src/core.nim` | Core runtime functions (AOT compiled) |
| `src/types.nim` | AST node types (used by reader/emitter) |
| `src/macros.nim` | Macro expansion engine |
| `src/runtime.nim` | Additional runtime helpers |
| `lib/cljnim_runtime.nim` | Core runtime library |
| `lib/cljnim_pvec.nim` | Persistent Vector (HAMT implementation) |
| `lib/cljnim_pmap.nim` | Persistent Hash Map (HAMT implementation) |
| `lib/cljnim_async.nim` | core.async channels runtime |
## Memory Model
- Uses Nim's ORC garbage collector
- `CljVal` is a `ref object` (heap-allocated)
- Persistent data structures (Vector, Map, Set) use structural sharing via HAMT