fix: reader #" #uuid dispatch, emitter metadata/fn/def fixes, runtime stubs
Reader: #" regex literals and #uuid"..." dispatch macros Emitter: named fn support, fn metadata stripping, def len!=3 graceful handling, loop binding metadata stripping, list-head-is-list call support Runtime: cljRepeatedly, cljMakeHierarchy, cljDerive/Underive, cljPrintlnStr, cljPrnStr, cljBinding, cljAset, cljVectorFn stubs Results: 164/233 passed (70%), clojure.string 8/8 (100%)
This commit is contained in:
+42
-5
@@ -263,6 +263,15 @@ proc runtimeName(op: string): string =
|
||||
of "fnil": "cljFnil"
|
||||
of "intern": "cljIntern"
|
||||
of "to-array": "cljToArray"
|
||||
of "repeatedly": "cljRepeatedly"
|
||||
of "make-hierarchy": "cljMakeHierarchy"
|
||||
of "derive": "cljDerive"
|
||||
of "underive": "cljUnderive"
|
||||
of "println-str": "cljPrintlnStr"
|
||||
of "prn-str": "cljPrnStr"
|
||||
of "binding": "cljBinding"
|
||||
of "aset": "cljAset"
|
||||
of "vector": "cljVectorFn"
|
||||
# ---- Type conversion ----
|
||||
of "float": "cljToFloat"
|
||||
of "int": "cljToInt"
|
||||
@@ -279,7 +288,12 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
||||
let sp = indentStr(indent)
|
||||
let head = items[0]
|
||||
if head.kind != ckSymbol:
|
||||
raise newException(EmitterError, "List head must be a symbol, got " & $head.kind)
|
||||
# Head is not a symbol - evaluate as function call: ((fn ...) args...)
|
||||
var argParts: seq[string] = @[]
|
||||
for i in 1..<items.len:
|
||||
argParts.add(emitExpr(items[i], indent))
|
||||
let fnCode = emitExpr(head, 0)
|
||||
return sp & "cljApply(" & fnCode & ", cljList(@[" & argParts.join(", ") & "]))"
|
||||
let op = resolveNsAlias(head.symName)
|
||||
|
||||
# ---- Special forms (language constructs) ----
|
||||
@@ -436,8 +450,17 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
||||
return sp & "discard cljNil()"
|
||||
|
||||
of "def":
|
||||
if items.len != 3:
|
||||
raise newException(EmitterError, "def requires exactly 2 arguments")
|
||||
if items.len < 3:
|
||||
return sp & "cljNil()"
|
||||
if items.len > 3:
|
||||
# (def name docstring value) or similar - use last arg as value
|
||||
let nameItem = items[1]
|
||||
var valItem = items[^1]
|
||||
if nameItem.kind == ckSymbol:
|
||||
let mangled = mangleName(nameItem.symName)
|
||||
let valCode = emitExpr(valItem, 0)
|
||||
return sp & "let " & mangled & " = " & valCode
|
||||
return sp & "cljNil()"
|
||||
var name = items[1]
|
||||
# Strip metadata: (with-meta sym meta) -> sym
|
||||
if name.kind == ckList and name.items.len == 3 and
|
||||
@@ -518,7 +541,17 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
||||
of "fn":
|
||||
if items.len < 3:
|
||||
raise newException(EmitterError, "fn requires params and body")
|
||||
let params = items[1]
|
||||
var paramsIdx = 1
|
||||
# Handle named fn: (fn name [params] body)
|
||||
if items[1].kind == ckSymbol:
|
||||
paramsIdx = 2
|
||||
if paramsIdx >= items.len:
|
||||
raise newException(EmitterError, "fn requires params and body")
|
||||
var params = items[paramsIdx]
|
||||
# Strip metadata from params
|
||||
if params.kind == ckList and params.items.len == 3 and
|
||||
params.items[0].kind == ckSymbol and params.items[0].symName == "with-meta":
|
||||
params = params.items[1]
|
||||
if params.kind != ckVector:
|
||||
raise newException(EmitterError, "fn params must be a vector")
|
||||
var paramNames: seq[string] = @[]
|
||||
@@ -675,8 +708,12 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
||||
var loopParams: seq[(string, string)] = @[]
|
||||
var li = 0
|
||||
while li < bindings.items.len:
|
||||
let lname = bindings.items[li]
|
||||
var lname = bindings.items[li]
|
||||
let lval = bindings.items[li+1]
|
||||
# Strip metadata: (with-meta sym meta) -> sym
|
||||
if lname.kind == ckList and lname.items.len == 3 and
|
||||
lname.items[0].kind == ckSymbol and lname.items[0].symName == "with-meta":
|
||||
lname = lname.items[1]
|
||||
if lname.kind != ckSymbol:
|
||||
raise newException(EmitterError, "loop binding name must be a symbol")
|
||||
loopParams.add((mangleName(lname.symName), emitExpr(lval, 0)))
|
||||
|
||||
@@ -291,6 +291,35 @@ proc readDispatch(s: string, i: var int): CljVal =
|
||||
inc i
|
||||
discard readForm(s, i)
|
||||
return nil
|
||||
of '"':
|
||||
# #"regex" — treat as string for now
|
||||
inc i
|
||||
var regexStr = ""
|
||||
while i < s.len and s[i] != '"':
|
||||
if s[i] == '\\' and i + 1 < s.len:
|
||||
regexStr.add(s[i])
|
||||
regexStr.add(s[i+1])
|
||||
inc i
|
||||
else:
|
||||
regexStr.add(s[i])
|
||||
inc i
|
||||
if i < s.len: inc i # skip closing "
|
||||
return cljString(regexStr)
|
||||
of 'u':
|
||||
# #uuid"..." — read as string
|
||||
inc i
|
||||
if i + 4 < s.len and s[i..i+3] == "uuid":
|
||||
i += 4
|
||||
while i < s.len and s[i] == ' ': inc i
|
||||
if i < s.len and s[i] == '"':
|
||||
inc i
|
||||
var uuidStr = ""
|
||||
while i < s.len and s[i] != '"':
|
||||
uuidStr.add(s[i])
|
||||
inc i
|
||||
if i < s.len: inc i
|
||||
return cljString(uuidStr)
|
||||
raise newException(ReaderError, "Unknown dispatch: #u")
|
||||
of '?':
|
||||
# Reader conditional: #?(:clj expr :cljs expr :default expr)
|
||||
# Read the next char - if '@' it's splicing version #?@
|
||||
|
||||
Reference in New Issue
Block a user