Phase 7: ns declaration + multi-file compilation
T7.1: Namespace declaration parsing (ns my.app (:require [lib :as l])) with :require/:as support Hyphen-to-underscore filename convention (math-utils -> math_utils.clj) T7.2: Multi-file compilation Resolves requires, recursively loads dependencies Inlines all defs into single Nim file Namespace alias resolution (mu/square -> square) 86 tests pass, all examples work.
This commit is contained in:
+50
-3
@@ -4,6 +4,21 @@ import types
|
||||
import macros
|
||||
|
||||
var requiredImports* = initHashSet[string]()
|
||||
var nsAliases*: seq[(string, string)] = @[] # (alias, namespace)
|
||||
|
||||
proc setNsAliases*(aliases: seq[(string, string)]) =
|
||||
nsAliases = aliases
|
||||
|
||||
proc resolveNsAlias*(name: string): string =
|
||||
# Resolve mu/square -> square (strip namespace prefix if alias exists)
|
||||
let slashIdx = name.find('/')
|
||||
if slashIdx < 0: return name
|
||||
let prefix = name[0..<slashIdx]
|
||||
let suffix = name[slashIdx+1..^1]
|
||||
for (alias, ns) in nsAliases:
|
||||
if prefix == alias:
|
||||
return suffix
|
||||
return name
|
||||
|
||||
type
|
||||
EmitterError* = object of CatchableError
|
||||
@@ -130,10 +145,41 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
||||
let head = items[0]
|
||||
if head.kind != ckSymbol:
|
||||
raise newException(EmitterError, "List head must be a symbol, got " & $head.kind)
|
||||
let op = head.symName
|
||||
let op = resolveNsAlias(head.symName)
|
||||
|
||||
# ---- Special forms (language constructs) ----
|
||||
case op
|
||||
of "ns":
|
||||
# Namespace declaration: (ns my.app (:require [other.lib :as lib]))
|
||||
if items.len < 2:
|
||||
raise newException(EmitterError, "ns requires a namespace name")
|
||||
let nsName = items[1]
|
||||
if nsName.kind != ckSymbol:
|
||||
raise newException(EmitterError, "ns name must be a symbol")
|
||||
var lines: seq[string] = @[]
|
||||
lines.add(sp & "# Namespace: " & nsName.symName)
|
||||
# Process require clauses
|
||||
for ri in 2..<items.len:
|
||||
let clause = items[ri]
|
||||
let isRequire = (clause.kind == ckList and clause.items.len > 0 and
|
||||
((clause.items[0].kind == ckSymbol and clause.items[0].symName == ":require") or
|
||||
(clause.items[0].kind == ckKeyword and clause.items[0].kwName == "require")))
|
||||
if isRequire:
|
||||
for ci in 1..<clause.items.len:
|
||||
let req = clause.items[ci]
|
||||
if req.kind == ckVector and req.items.len >= 1:
|
||||
let libName = req.items[0]
|
||||
if libName.kind == ckSymbol:
|
||||
var alias = libName.symName
|
||||
# Check for :as
|
||||
if req.items.len >= 3 and req.items[1].kind == ckKeyword and req.items[1].kwName == "as":
|
||||
if req.items[2].kind == ckSymbol:
|
||||
alias = req.items[2].symName
|
||||
# Convert namespace to file path: my.app -> my/app
|
||||
let filePath = libName.symName.replace(".", "/") & ".clj"
|
||||
lines.add(sp & "# require: " & libName.symName & " as " & alias & " from " & filePath)
|
||||
return lines.join("\n")
|
||||
|
||||
of "defmacro":
|
||||
# Register user-defined macro
|
||||
if items.len < 4:
|
||||
@@ -938,11 +984,12 @@ proc emitExpr*(v: CljVal, indent: int = 0): string =
|
||||
of ckKeyword:
|
||||
return sp & "cljKeyword(\"" & v.kwName & "\")"
|
||||
of ckSymbol:
|
||||
let rn = runtimeName(v.symName)
|
||||
let symName = resolveNsAlias(v.symName)
|
||||
let rn = runtimeName(symName)
|
||||
if rn.len > 0:
|
||||
# Known function symbol — emit as runtime fn reference
|
||||
return sp & "cljFn(proc(args: seq[CljVal]): CljVal = " & rn & "(args))"
|
||||
return sp & mangleName(v.symName)
|
||||
return sp & mangleName(symName)
|
||||
of ckList:
|
||||
if v.items.len == 0:
|
||||
return sp & "cljList(@[])"
|
||||
|
||||
Reference in New Issue
Block a user