[← Към индекса](index.md) --- # Архитектура на Clojure/Nim ## Общ Преглед Clojure/Nim е **компилатор**, не интерпретатор. Следва модела на ClojureScript: Clojure изходният код се чете, разширява с макроси, анализира и се генерира като Nim изходен код, който после се компилира до C и накрая до native бинарен файл. ## Компилационен Пайплайн ``` ┌─────────────┐ │ .clj Файл │ └──────┬──────┘ │ ┌────▼────┐ │ Reader │ ← EDN парсер. Произвежда Clojure структури от данни. └────┬────┘ │ ┌────▼────┐ │ Макроси │ ← Разширение на defmacro. Работи върху Clojure данни. └────┬────┘ │ ┌────▼────┐ │Анализатор│ ← Специални форми, locals, анализ на closures. └────┬────┘ │ ┌────▼────┐ │ Генератор│ ← Генерира Nim AST / изходен код. └────┬────┘ │ ┌────▼────┐ │ Nim CC │ ← Nim → C компилация. └────┬────┘ │ ┌────▼────┐ │ C CC │ ← C → машинен код (GCC/Clang). └────┬────┘ │ ┌────▼────┐ │ Бинарен│ ← Единичен native изпълним файл. └─────────┘ ``` ## Ключови Дизайн Решения ### 1. AOT Компилатор Компилираме предварително (ahead-of-time), като ClojureScript. Това ни дава: - Бързо изпълнение (скорост на C) - Малък размер на бинарния файл - Без overhead на интерпретатор Компромисът е, че компилацията в REPL е по-бавна (всяка форма се компилира индивидуално). ### 2. Clojure Макроси върху Clojure Данни Разширяването на макроси става **преди** да стигнем до Nim. Nim никога не вижда Clojure макроси: ```clojure (defmacro unless [condition & body] `(if (not ~condition) (do ~@body))) ``` Този макро оперира върху `CljVal` обекти (Clojure списъци, символи), не върху Nim AST. ### 3. Runtime в Nim Модулът `lib/cljnim_runtime.nim` предоставя: - `CljVal` — tagged union, представящ всички Clojure стойности - `cljAdd`, `cljMul`, и т.н. — полиморфна аритметика - `cljRepr` — текстово представяне ### 4. Nim Interop Вместо Java interop, имаме директен Nim interop: ```clojure (nim/math/sin x) (nim/strutils/toUpper s) ``` Nim модулите се импортират автоматично при извикване през `nim/module/fn` шаблона. ## Отговорности на Модулите | Модул | Роля | |---|---| | `src/reader.nim` | Парсира `.clj` текст към `CljVal` AST | | `src/emitter.nim` | Трансформира `CljVal` AST в Nim изходен код | | `src/repl.nim` | Имплементация на human и AI REPL | | `src/eval.nim` | Tree-walking interpreter за бързо in-memory eval | | `src/deps.nim` | Резолюция на зависимости (deps.edn формат) | | `src/core.nim` | Core runtime функции (AOT компилирани) | | `src/types.nim` | Типове на AST възли (използват се от reader/emitter) | | `src/macros.nim` | Двигател за разширяване на макроси | | `src/runtime.nim` | Допълнителни runtime помощници | | `lib/cljnim_runtime.nim` | Основна runtime библиотека | | `lib/cljnim_pvec.nim` | Persistent Vector (HAMT имплементация) | | `lib/cljnim_pmap.nim` | Persistent Hash Map (HAMT имплементация) | | `lib/cljnim_async.nim` | core.async channels runtime | ## Модел на Паметта - Използва Nim's ORC garbage collector - `CljVal` е `ref object` (заделя се на heap) - Persistent структури от данни (Vector, Map, Set) използват структурно споделяне през HAMT