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:
+56
-8
@@ -1,6 +1,18 @@
|
||||
# Clojure/Nim Compiler
|
||||
import os, strutils, osproc
|
||||
import reader, emitter, types
|
||||
import os, osproc
|
||||
import reader, emitter, types, macros
|
||||
|
||||
proc getLibPath(): string =
|
||||
let appDir = getAppDir()
|
||||
# Try relative to binary location
|
||||
let candidate1 = appDir / "lib"
|
||||
let candidate2 = appDir.parentDir / "lib"
|
||||
let candidate3 = getCurrentDir() / "lib"
|
||||
if dirExists(candidate1): return candidate1
|
||||
if dirExists(candidate2): return candidate2
|
||||
if dirExists(candidate3): return candidate3
|
||||
# Fallback: assume lib is in current dir
|
||||
return "lib"
|
||||
|
||||
proc compileFile*(inputPath: string, outputPath: string) =
|
||||
let source = readFile(inputPath)
|
||||
@@ -14,6 +26,16 @@ proc compileFile*(inputPath: string, outputPath: string) =
|
||||
writeFile(outputPath, nimCode)
|
||||
echo "Generated: ", outputPath
|
||||
|
||||
proc nimCompile(nimPath: string, binPath: string, release: bool = false): int =
|
||||
let libPath = getLibPath()
|
||||
var cmd = "nim c"
|
||||
if release:
|
||||
cmd.add(" -d:release")
|
||||
cmd.add(" --path:" & quoteShell(libPath))
|
||||
cmd.add(" -o:" & quoteShell(binPath) & " " & quoteShell(nimPath))
|
||||
echo "Compiling: ", cmd
|
||||
execCmd(cmd)
|
||||
|
||||
proc runFile*(inputPath: string) =
|
||||
let tmpDir = getTempDir()
|
||||
let baseName = inputPath.splitFile.name
|
||||
@@ -22,22 +44,18 @@ proc runFile*(inputPath: string) =
|
||||
|
||||
compileFile(inputPath, nimPath)
|
||||
|
||||
# Compile generated Nim code
|
||||
let compileCmd = "nim c -o:" & binPath & " " & nimPath
|
||||
echo "Compiling: ", compileCmd
|
||||
let compileResult = execCmd(compileCmd)
|
||||
let compileResult = nimCompile(nimPath, binPath)
|
||||
if compileResult != 0:
|
||||
stderr.writeLine("Compilation failed")
|
||||
quit(1)
|
||||
|
||||
# Run
|
||||
echo "Running: ", binPath
|
||||
let runResult = execCmd(binPath)
|
||||
if runResult != 0:
|
||||
stderr.writeLine("Execution failed")
|
||||
quit(1)
|
||||
|
||||
proc main() =
|
||||
initBuiltinMacros()
|
||||
let args = commandLineParams()
|
||||
|
||||
if args.len == 0:
|
||||
@@ -46,10 +64,40 @@ proc main() =
|
||||
echo " cljnim compile <file.clj> [output.nim] Compile to Nim"
|
||||
echo " cljnim run <file.clj> Compile and run"
|
||||
echo " cljnim read <file.clj> Parse and print AST"
|
||||
echo " cljnim -e '<code>' Evaluate expression"
|
||||
echo " cljnim -M -e '<code>' Evaluate with full runtime"
|
||||
quit(0)
|
||||
|
||||
let cmd = args[0]
|
||||
|
||||
# Handle -e and -M -e flags
|
||||
if cmd == "-e" or cmd == "-M":
|
||||
var code = ""
|
||||
var idx = 1
|
||||
if cmd == "-M" and args.len > 1 and args[1] == "-e":
|
||||
idx = 2
|
||||
elif cmd == "-e":
|
||||
idx = 1
|
||||
else:
|
||||
stderr.writeLine("Usage: cljnim [-M] -e '<code>'")
|
||||
quit(1)
|
||||
if idx >= args.len:
|
||||
stderr.writeLine("Error: Missing expression after -e")
|
||||
quit(1)
|
||||
code = args[idx]
|
||||
let tmpDir = getTempDir()
|
||||
let nimPath = tmpDir / "cljnim_expr.nim"
|
||||
let binPath = tmpDir / "cljnim_expr"
|
||||
let forms = reader.readAll(code)
|
||||
let nimCode = emitter.emitProgram(forms)
|
||||
writeFile(nimPath, nimCode)
|
||||
let compileResult = nimCompile(nimPath, binPath)
|
||||
if compileResult != 0:
|
||||
stderr.writeLine("Compilation failed")
|
||||
quit(1)
|
||||
let runResult = execCmd(binPath)
|
||||
quit(runResult)
|
||||
|
||||
case cmd
|
||||
of "compile":
|
||||
if args.len < 2:
|
||||
|
||||
Reference in New Issue
Block a user