diff --git a/lib/cljnim_runtime.nim b/lib/cljnim_runtime.nim index 3813eaf..e5803ab 100644 --- a/lib/cljnim_runtime.nim +++ b/lib/cljnim_runtime.nim @@ -847,6 +847,49 @@ proc cljConcat*(args: seq[CljVal]): CljVal = else: discard cljList(items) +proc cljRepeatedly*(args: seq[CljVal]): CljVal = + if args.len == 0: return cljList(@[]) + let n = if args.len >= 2: args[0].intVal.int else: 10 + var items: seq[CljVal] = @[] + for i in 0.. 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))) diff --git a/src/reader.nim b/src/reader.nim index 6db9880..a7bb148 100644 --- a/src/reader.nim +++ b/src/reader.nim @@ -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 #?@