From 88a04f8b67a5fdc5e2d11e17cff7331ed1cdc833 Mon Sep 17 00:00:00 2001 From: dimgigov Date: Sat, 9 May 2026 20:14:31 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20+11=20more=20tests=20(194/233,=2083%)?= =?UTF-8?q?=20=E2=80=94=20array=20stubs,=20cons/atom/cycle=20variadic,=20s?= =?UTF-8?q?tring=20escaping,=20empty/case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/cljnim_runtime.nim | 81 +++++++++++++++++++++++++++++++++++++++--- src/emitter.nim | 22 ++++++++---- 2 files changed, 92 insertions(+), 11 deletions(-) diff --git a/lib/cljnim_runtime.nim b/lib/cljnim_runtime.nim index c27a24c..7e6ab59 100644 --- a/lib/cljnim_runtime.nim +++ b/lib/cljnim_runtime.nim @@ -631,7 +631,10 @@ proc cljConj*(coll: CljVal, item: CljVal): CljVal = else: cljList(@[item]) -proc cljCons*(item: CljVal, coll: CljVal): CljVal = +proc cljCons*(args: seq[CljVal]): CljVal = + if args.len < 2: return cljList(@[]) + let item = args[0] + let coll = args[1] if coll.isNil: return cljList(@[item]) case coll.kind @@ -713,6 +716,51 @@ proc cljObjectArray*(n: CljVal): CljVal = items.add(cljNil()) return cljList(items) +proc cljIntArray*(args: seq[CljVal]): CljVal = + if args.len == 0: return cljList(@[]) + var size = 0 + if args[0].kind == ckInt: size = args[0].intVal.int + var items: seq[CljVal] = @[] + for i in 0..= 0 and i < a.listItems.len: + return a.listItems[i] + cljNil() + +proc cljIdentical*(args: seq[CljVal]): CljVal = + if args.len < 2: return cljBool(false) + cljBool(args[0] == args[1]) + +proc cljEmptyColl*(args: seq[CljVal]): CljVal = + if args.len == 0: return cljNil() + let v = args[0] + if v.isNil: return cljNil() + case v.kind + of ckList: cljList(@[]) + of ckVector: cljVector(@[]) + of ckMap: cljMap(@[], @[]) + of ckSet: cljSet(@[]) + of ckString: cljString("") + else: cljNil() + proc cljSortedMap*(args: seq[CljVal]): CljVal = # Fallback to regular hash-map cljHashMap(args) @@ -1447,8 +1495,8 @@ proc cljIdentity*(args: seq[CljVal]): CljVal = if args.len == 0: cljNil() else: args[0] -proc cljConstantly*(v: CljVal): proc(args: seq[CljVal]): CljVal = - proc(args: seq[CljVal]): CljVal = v +proc cljConstantly*(v: CljVal): CljVal = + cljFn(proc(args: seq[CljVal]): CljVal = v) proc cljType*(v: CljVal): CljVal = if v.isNil: return cljKeyword("nil") @@ -1504,11 +1552,30 @@ proc cljWithMeta*(v: CljVal, m: CljVal): CljVal = proc cljAtom*(v: CljVal): CljVal = CljVal(kind: ckAtom, atomVal: v) +proc cljAtom*(args: seq[CljVal]): CljVal = + if args.len == 0: return CljVal(kind: ckAtom, atomVal: cljNil()) + let val = args[0] + var a = CljVal(kind: ckAtom, atomVal: val) + var i = 1 + while i + 1 < args.len: + if args[i].kind == ckKeyword: + case args[i].kwName + of "validator": discard + of "meta": a.meta = args[i+1] + else: discard + i += 2 + a + proc cljPromise*(args: seq[CljVal]): CljVal = cljAtom(cljNil()) proc cljFuture*(args: seq[CljVal]): CljVal = - cljAtom(cljNil()) + if args.len == 0: return cljAtom(cljNil()) + let f = args[0] + if f.kind == ckFn: + cljAtom(f.fnProc(@[])) + else: + cljAtom(cljNil()) proc cljDeref*(a: CljVal): CljVal = if a.kind == ckAtom: a.atomVal @@ -1768,6 +1835,9 @@ proc cljRepeat*(n: CljVal, x: CljVal): CljVal = items.add(x) cljList(items) +proc cljRepeat*(x: CljVal): CljVal = + cljRepeat(cljInt(1000), x) + proc cljCycle*(n: CljVal, coll: CljVal): CljVal = if n.kind != ckInt: raise newException(CatchableError, "cycle requires an integer count") var srcItems: seq[CljVal] = @[] @@ -1781,6 +1851,9 @@ proc cljCycle*(n: CljVal, coll: CljVal): CljVal = items.add(srcItems[i mod srcItems.len]) cljList(items) +proc cljCycle*(coll: CljVal): CljVal = + cljCycle(cljInt(1000), coll) + proc cljIterate*(n: CljVal, f: CljVal, x: CljVal): CljVal = if n.kind != ckInt: raise newException(CatchableError, "iterate requires an integer count") if f.kind != ckFn: raise newException(CatchableError, "iterate requires a function") diff --git a/src/emitter.nim b/src/emitter.nim index 248734d..93b557b 100644 --- a/src/emitter.nim +++ b/src/emitter.nim @@ -265,6 +265,12 @@ proc runtimeName(op: string): string = of "promise": "cljPromise" of "future": "cljFuture" of "create-ns": "cljCreateNs" + of "aclone": "cljAclone" + of "alength": "cljAlength" + of "aget": "cljAget" + of "int-array": "cljIntArray" + of "identical?": "cljIdentical" + of "empty": "cljEmptyColl" of "doall": "cljDoall" of "dorun": "cljDorun" of "drop-last": "cljDropLast" @@ -585,7 +591,7 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string = raise newException(EmitterError, "fn params must be symbols") addToScope(p.symName) paramNames.add(mangleName(p.symName) & ": CljVal") - let body = items[2..^1] + let body = items[(paramsIdx+1)..^1] var bodyCode = "" if body.len == 1: bodyCode = emitExpr(body[0], indent + 1) @@ -862,7 +868,7 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string = let isSpecial = symName in ["case", "defprotocol", "defrecord", "deftype", "defmulti", "defmethod", "var", "bound-fn", "bound-fn*", "promise", "delay", "future", "sorted-map-by", "sorted-set-by", "compare-and-set!", - "empty", "delay"] + "empty", "aclone", "int-array", "identical?"] let exists = runtimeName(symName).len > 0 or isLocalVar(symName) or isSpecial if exists: let body = items[2..^1] @@ -1397,13 +1403,14 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string = # Variadic functions take seq[CljVal] let variadic = op in ["+", "-", "*", "/", "=", ">", "<", ">=", "<=", "not=", "println", "prn", "print", "str", "pr-str", - "concat", "min", "max", "merge", "interleave", - "zipmap", "hash-map", "hash-set", "sorted-map", "sorted-set", + "atom", "concat", "min", "max", "merge", "interleave", + "zipmap", "hash-map", "hash-set", "sorted-map", "sorted-set", "cons", "array-map", "inf", "nan", "float", "int", "double", "long", "short", "byte", "boolean", "num", "number", "make-hierarchy", "derive", "underive", "ancestors", "descendants", "parents", "isa?", "promise", "create-ns", "future", + "aclone", "alength", "aget", "int-array", "identical?", "empty", "drop-last", "shuffle", "repeatedly", "fnil", "intern", "println-str", "prn-str", "binding", "aset", "volatile!", "deliver", "doall", "dorun", @@ -1469,7 +1476,8 @@ proc emitExpr*(v: CljVal, indent: int = 0): string = of ckFloat: return sp & "cljFloat(" & $v.floatVal & ")" of ckString: - return sp & "cljString(\"" & v.strVal.replace("\"", "\\\"") & "\")" + let escaped = v.strVal.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t") + return sp & "cljString(\"" & escaped & "\")" of ckKeyword: return sp & "cljKeyword(\"" & v.kwName & "\")" of ckSymbol: @@ -1479,8 +1487,8 @@ proc emitExpr*(v: CljVal, indent: int = 0): string = # Check if the runtime function is variadic (takes seq[CljVal]) let variadic = symName in ["+", "-", "*", "/", "=", ">", "<", ">=", "<=", "not=", "println", "prn", "print", "str", "pr-str", - "concat", "min", "max", "merge", "interleave", - "zipmap", "hash-map", "hash-set", "sorted-map", "sorted-set", + "atom", "concat", "min", "max", "merge", "interleave", + "zipmap", "hash-map", "hash-set", "sorted-map", "sorted-set", "cons", "array-map", "inf", "nan", "float", "int", "double", "long", "short", "byte", "boolean", "num", "number",