Files
bara-lang/src/project.nim
T
dimgigov 7cb8aa1ee0 feat: project build system with lib/bin separation
- Add src/project.nim: parse bara.edn manifest (name, version, lib, bins)
- Add cljnim build / cljnim build --mono commands
- Compile lib modules once to target/nim/lib_*.nim with exported defs
- Cross-module symbol resolution via from/import nil + fully qualified names
- Emitter: lib mode with * export markers, variadic seq[CljVal] handling
2026-05-16 19:20:23 +03:00

100 lines
3.0 KiB
Nim

# Bara Lang Project Manifest Reader
# Reads bara.edn (Clojure/EDN format) for project configuration
import os
import types, reader
type
BinEntry* = object
name*: string
path*: string
LibEntry* = object
name*: string
path*: string
Project* = object
name*: string
version*: string
rootDir*: string
lib*: LibEntry
bins*: seq[BinEntry]
examples*: seq[BinEntry]
proc findProjectRoot*(startDir: string = getCurrentDir()): string =
## Walk up from startDir looking for bara.edn
var dir = absolutePath(startDir)
while true:
let baraEdn = dir / "bara.edn"
if fileExists(baraEdn):
return dir
let parent = parentDir(dir)
if parent == dir:
break
dir = parent
return ""
proc extractMapString(form: CljVal, key: string, defaultVal: string = ""): string =
if form.kind != ckMap: return defaultVal
for i in 0..<form.mapKeys.len:
let k = form.mapKeys[i]
if (k.kind == ckKeyword and k.kwName == key) or (k.kind == ckSymbol and k.symName == key):
let v = form.mapVals[i]
if v.kind == ckString: return v.strVal
return defaultVal
proc extractMapVector(form: CljVal, key: string): seq[CljVal] =
if form.kind != ckMap: return @[]
for i in 0..<form.mapKeys.len:
let k = form.mapKeys[i]
if (k.kind == ckKeyword and k.kwName == key) or (k.kind == ckSymbol and k.symName == key):
let v = form.mapVals[i]
if v.kind == ckVector: return v.items
if v.kind == ckList: return v.items
return @[]
proc parseBinEntry(form: CljVal): BinEntry =
result.name = extractMapString(form, "name")
result.path = extractMapString(form, "path")
proc parseLibEntry(form: CljVal): LibEntry =
result.name = extractMapString(form, "name")
result.path = extractMapString(form, "path")
proc loadProject*(dir: string = getCurrentDir()): Project =
let root = findProjectRoot(dir)
if root.len == 0:
raise newException(ValueError, "bara.edn not found in " & dir & " or parent directories")
let path = root / "bara.edn"
let source = readFile(path)
let forms = reader.readAll(source)
if forms.len == 0:
raise newException(ValueError, "Empty bara.edn")
let map = forms[0]
if map.kind != ckMap:
raise newException(ValueError, "bara.edn must contain a map at top level")
result.rootDir = root
result.name = extractMapString(map, "name", "unknown")
result.version = extractMapString(map, "version", "0.1.0")
let libVal = extractMapVector(map, "lib")
if libVal.len > 0:
result.lib = parseLibEntry(libVal[0])
elif true:
# Also check for single :lib map (not vector)
for i in 0..<map.mapKeys.len:
let k = map.mapKeys[i]
if (k.kind == ckKeyword and k.kwName == "lib") or (k.kind == ckSymbol and k.symName == "lib"):
let v = map.mapVals[i]
if v.kind == ckMap:
result.lib = parseLibEntry(v)
break
for item in extractMapVector(map, "bins"):
result.bins.add(parseBinEntry(item))
for item in extractMapVector(map, "examples"):
result.examples.add(parseBinEntry(item))