Phase 1-4: Reader, Runtime, Macros, Nim Interop — 543x faster than JVM Clojure

- Reader: maps, sets, syntax-quote, dispatch macros, metadata
- Runtime: CljVal type system, 80+ core functions (collections, strings, math, IO)
- Emitter: full CljVal-based code generation, macro expansion, inline fns
- Macros: defmacro with compile-time evaluator, ->, ->>, and, or, when, cond, for, doseq
- Nim Interop: nim/module/function syntax, auto-import, type mapping
- CLI: cljnim -e '<code>' for quick evaluation
- Tests: 60 unit tests (reader + emitter)
- Benchmarks: AOT suite showing 543x startup, 679x factorial vs JVM Clojure
- CI: GitLab CI pipeline
- Runtime library: lib/cljnim_runtime.nim (1070+ lines)
This commit is contained in:
2026-05-08 16:34:39 +03:00
parent f89b381fdb
commit 87d6028487
24 changed files with 4244 additions and 275 deletions
+175
View File
@@ -0,0 +1,175 @@
import unittest
import strutils
import ../src/types
import ../src/reader
import ../src/emitter
suite "Emitter - Basic Values":
test "emit nil":
check emitExpr(cljNil()) == "cljNil()"
test "emit bool true":
check emitExpr(cljBool(true)) == "cljBool(true)"
test "emit bool false":
check emitExpr(cljBool(false)) == "cljBool(false)"
test "emit int":
check emitExpr(cljInt(42)) == "cljInt(42)"
test "emit float":
check "cljFloat(3.14)" in emitExpr(cljFloat(3.14))
test "emit string":
check emitExpr(cljString("hello")) == "cljString(\"hello\")"
test "emit keyword":
check "cljKeyword" in emitExpr(cljKeyword("key"))
test "emit symbol":
check emitExpr(cljSymbol("foo")) == "foo"
test "emit mangled symbol":
check mangleName("my-fn?") == "my_fn_Q"
test "emit vector":
let v = cljVector(@[cljInt(1), cljInt(2), cljInt(3)])
check "cljVector" in emitExpr(v)
check "cljInt(1)" in emitExpr(v)
test "emit empty list":
check emitExpr(cljList(@[])) == "cljList(@[])"
suite "Emitter - Special Forms":
test "emit println":
let v = read("(println \"hello\")")
let code = emitExpr(v)
check "cljPrintln" in code
check "discard" in code
test "emit def":
let v = read("(def x 42)")
let code = emitExpr(v)
check "let x = cljInt(42)" in code
test "emit defn":
let v = read("(defn square [x] (* x x))")
let code = emitExpr(v)
check "proc square" in code
check "CljVal" in code
test "emit if":
let v = read("(if true 1 2)")
let code = emitExpr(v)
check "cljIsTruthy" in code
check "else:" in code
test "emit when":
let v = read("(when true (println \"yes\"))")
let code = emitExpr(v)
check "cljIsTruthy" in code
test "emit let":
let v = read("(let [x 1] x)")
let code = emitExpr(v)
check "block:" in code
check "let x = cljInt(1)" in code
test "emit cond":
let v = read("(cond true 1 :else 2)")
let code = emitExpr(v)
check "cljIsTruthy" in code
check "else:" in code
test "emit fn":
let v = read("(fn [x] x)")
let code = emitExpr(v)
check "proc" in code
check "CljVal" in code
test "emit do":
let v = read("(do 1 2)")
let code = emitExpr(v)
check "cljInt" in code
suite "Emitter - Operators":
test "emit addition":
let v = read("(+ 1 2)")
let code = emitExpr(v)
check "cljAdd" in code
test "emit subtraction":
let v = read("(- 5 3)")
let code = emitExpr(v)
check "cljSub" in code
test "emit multiplication":
let v = read("(* 2 3)")
let code = emitExpr(v)
check "cljMul" in code
test "emit equality":
let v = read("(= 1 1)")
let code = emitExpr(v)
check "cljNumEq" in code
test "emit not=":
let v = read("(not= 1 2)")
let code = emitExpr(v)
check "cljNotEq" in code
test "emit not":
let v = read("(not true)")
let code = emitExpr(v)
check "cljNot" in code
suite "Emitter - Program":
test "emitProgram with defs and main":
let forms = readAll("(def x 10)\n(println x)")
let prog = emitProgram(forms)
check "let x = cljInt(10)" in prog
check "when isMainModule:" in prog
check "cljPrintln" in prog
test "emitProgram multiple defs":
let forms = readAll("(defn add [a b] (+ a b))\n(println (add 1 2))")
let prog = emitProgram(forms)
check "proc add" in prog
check "add(cljInt(1), cljInt(2))" in prog
suite "Emitter - Map Literals":
test "emit empty map":
let v = cljMap(@[], @[])
let code = emitExpr(v)
check "cljMap" in code
test "emit map with entries":
let v = cljMapFromPairs(@[
(cljKeyword("a"), cljInt(1)),
(cljKeyword("b"), cljInt(2))
])
let code = emitExpr(v)
check "cljMap" in code
suite "Emitter - Higher-order":
test "emit map with symbol fn":
let v = read("(map inc [1 2 3])")
let code = emitExpr(v)
check "cljMap" in code
check "cljFn" in code
test "emit filter with inline fn":
let v = read("(filter (fn [x] (> x 2)) [1 2 3])")
let code = emitExpr(v)
check "cljFilter" in code
check "cljFn" in code
test "emit reduce":
let v = read("(reduce + 0 [1 2 3])")
let code = emitExpr(v)
check "cljReduce" in code