# Clojure/Nim — AI-First Clojure Compiler import os, osproc, strutils, times import reader, emitter, types, repl, macros, deps, ai_assist, tui proc getLibPath(): string = let appDir = getAppDir() 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 return "lib" proc resolveNsToPath(nsName: string, searchPaths: seq[string]): string = # Convert namespace name to file path: my.app -> my/app.clj # Clojure convention: hyphens in ns names become underscores in filenames let relPath = nsName.replace("-", "_").replace(".", "/") & ".clj" for sp in searchPaths: let candidate = sp / relPath if fileExists(candidate): return candidate return "" proc extractRequires(forms: seq[CljVal]): seq[(string, string)] = # Extract require declarations: returns (namespace, alias) pairs result = @[] for form in forms: if form.kind == ckList and form.items.len >= 2 and form.items[0].kind == ckSymbol and form.items[0].symName == "ns": for ri in 2..
' Evaluate expression"
echo " cljnim ai '' Generate Clojure code with AI"
echo " cljnim tui Start interactive TUI"
echo ""
echo "REPL Commands:"
echo " :quit, :q Exit REPL"
echo " :defs List defined vars"
echo " :clear Clear definitions"
echo " :ns Show current namespace"
echo ""
echo "AI Mode (JSON):"
echo " cljnim repl --json"
echo " Input: {\"op\":\"eval\",\"form\":\"(+ 1 2)\"}"
echo " Output: {\"status\":\"ok\",\"result\":{...},\"meta\":{...}}"
quit(0)
let cmd = args[0]
# Handle -e flag
if cmd == "-e":
if args.len < 2:
stderr.writeLine("Error: Missing expression after -e")
quit(1)
let code = args[1]
let buildDir = makeTempDir()
let nimPath = buildDir / "expr.nim"
let binPath = buildDir / "expr"
let forms = reader.readAll(code)
let nimCode = emitter.emitProgram(forms)
writeFile(nimPath, nimCode)
let (compileResult, compileOut) = nimCompile(nimPath, binPath)
if compileResult != 0:
stderr.writeLine("Compilation failed")
stderr.writeLine(compileOut)
if ai_assist.hasAiConfig():
let aiRes = ai_assist.explainError(compileOut, code, "-e expression")
stderr.writeLine(ai_assist.formatSuggestion(aiRes))
try: removeDir(buildDir) except: discard
quit(1)
let runResult = execCmd(binPath)
try: removeDir(buildDir) except: discard
quit(runResult)
case cmd
of "compile":
if args.len < 2:
stderr.writeLine("Error: Missing input file")
quit(1)
let inputPath = args[1]
let outputPath = if args.len >= 3: args[2] else: inputPath.changeFileExt("nim")
compileFile(inputPath, outputPath)
of "compile-lib":
if args.len < 2:
stderr.writeLine("Error: Missing input file")
quit(1)
let inputPath = args[1]
let outputPath = if args.len >= 3: args[2] else: inputPath.changeFileExt("nim")
compileFileLib(inputPath, outputPath)
of "run":
if args.len < 2:
stderr.writeLine("Error: Missing input file")
quit(1)
runFile(args[1])
of "read":
if args.len < 2:
stderr.writeLine("Error: Missing input file")
quit(1)
let source = readFile(args[1])
let forms = reader.readAll(source)
for form in forms:
echo $form
of "repl":
var mode = rmHuman
var tcpPort = -1
for i in 1.. 0:
runTcpRepl(state, tcpPort)
else:
case mode
of rmHuman: runHumanRepl(state)
of rmJson: runJsonRepl(state)
of rmEdn: runJsonRepl(state)
finally:
state.cleanup()
of "deps":
let projectDir = getCurrentDir()
let depsPath = deps.findDepsFile(projectDir)
if depsPath.len == 0:
echo "No deps.edn or project.clj found"
quit(0)
echo "Found: ", depsPath
let depsFile = deps.parseDepsFile(depsPath)
echo "Dependencies: ", depsFile.deps.len
let paths = deps.resolveDeps(depsFile, depsPath.parentDir)
if paths.len > 0:
echo "Resolved paths:"
for p in paths:
echo " ", p
else:
echo "No dependencies to resolve"
of "ai":
if not ai_assist.hasAiConfig():
stderr.writeLine("Error: No AI API key configured.")
stderr.writeLine("Set DEEPSEEK_API_KEY, OPENAI_API_KEY, or MIMO_API_KEY environment variable.")
quit(1)
if args.len < 2:
stderr.writeLine("Error: Missing description for AI generation")
stderr.writeLine("Usage: cljnim ai 'function that reverses a list'")
quit(1)
let description = args[1]
echo "🤖 Asking AI to generate code..."
let aiRes = ai_assist.generateCode(description)
if aiRes.ok:
echo aiRes.suggestion
else:
stderr.writeLine(aiRes.suggestion)
quit(1)
of "tui":
runTui()
else:
stderr.writeLine("Unknown command: " & cmd)
quit(1)
when isMainModule:
main()