147 lines
4.2 KiB
Nim
147 lines
4.2 KiB
Nim
# Clojure/Nim — AI-First Clojure Compiler
|
|
import os, osproc, strutils
|
|
import reader, emitter, types, repl
|
|
|
|
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 compileFile*(inputPath: string, outputPath: string) =
|
|
let source = readFile(inputPath)
|
|
let forms = reader.readAll(source)
|
|
|
|
if forms.len == 0:
|
|
stderr.writeLine("Error: No forms found in " & inputPath)
|
|
quit(1)
|
|
|
|
let nimCode = emitter.emitProgram(forms)
|
|
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
|
|
let nimPath = tmpDir / baseName & "_generated.nim"
|
|
let binPath = tmpDir / baseName & "_generated"
|
|
|
|
compileFile(inputPath, nimPath)
|
|
|
|
let compileResult = nimCompile(nimPath, binPath)
|
|
if compileResult != 0:
|
|
stderr.writeLine("Compilation failed")
|
|
quit(1)
|
|
|
|
let runResult = execCmd(binPath)
|
|
if runResult != 0:
|
|
stderr.writeLine("Execution failed")
|
|
quit(1)
|
|
|
|
proc main() =
|
|
let args = commandLineParams()
|
|
|
|
if args.len == 0:
|
|
echo "Clojure/Nim — AI-First Clojure Compiler"
|
|
echo ""
|
|
echo "Usage:"
|
|
echo " cljnim compile <file.clj> [output.nim] Compile to Nim source"
|
|
echo " cljnim run <file.clj> Compile and run binary"
|
|
echo " cljnim read <file.clj> Parse and print AST"
|
|
echo " cljnim repl [--json] Start REPL (human or AI mode)"
|
|
echo " cljnim -e '<code>' Evaluate expression"
|
|
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 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:
|
|
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 "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
|
|
for i in 1..<args.len:
|
|
if args[i] == "--json":
|
|
mode = rmJson
|
|
elif args[i] == "--edn":
|
|
mode = rmEdn
|
|
var state = initReplState(mode)
|
|
try:
|
|
case mode
|
|
of rmHuman: runHumanRepl(state)
|
|
of rmJson: runJsonRepl(state)
|
|
of rmEdn: runJsonRepl(state)
|
|
finally:
|
|
state.cleanup()
|
|
|
|
else:
|
|
stderr.writeLine("Unknown command: " & cmd)
|
|
quit(1)
|
|
|
|
when isMainModule:
|
|
main()
|