nandi/clonimpublic Fork
⑂ a6f57fd
Commits
⬇ Clone ▾
git clone https://git.rickub.com/nandi/clonim.git
git clone ssh://git@rickub.com/nandi/clonim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

perf: pass call arguments as openArray, not a heap seq

Every call built a `@[x]` seq on the heap for its argument list, which a
sequence pipeline pays once per element per stage -- roughly 2M allocations
for the seqs benchmark. An openArray parameter takes a stack array literal
instead, so the arguments never leave the frame.

This was on the perf branch and got dropped in the port; it is independent of
laziness and of how values are represented, and it is worth the same here as
it was there.

  seqs   341 ms -> 292 ms      (filter stage 108 -> 70)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-20T19:24:47-07:00 Browse files
a6f57fd parent: 75fc33e
modified src/compiler.nim +8 -8
@@ -406,7 +406,7 @@ proc genFn(name: string, clauses: seq[FnClause], selfIdent: string, env: Env,
406406 if boxes: directEnv.intFnBoxes.incl key
407407
408408 let argsIdent = c.gensym("args")
409- c.line(dst & " = mkFn(" & nimStr(name) & ", proc (" & argsIdent & ": seq[Value]): Value =")
409+ c.line(dst & " = mkFn(" & nimStr(name) & ", proc (" & argsIdent & ": openArray[Value]): Value =")
410410 c.push
411411 var first = true
412412 for ci, cl in clauses:
@@ -495,7 +495,7 @@ proc genLet(bindings: Value, body: seq[Value], dst: string, env: Env, c: Ctx) =
495495 lenv.locals[restSym] = id
496496 break
497497 let id = c.gensym("l" & mangle(symName(p)))
498- c.line("var " & id & ": Value = call(getVar(\"nth\"), @[" & v & ", mkInt(" &
498+ c.line("var " & id & ": Value = call(getVar(\"nth\"), [" & v & ", mkInt(" &
499499 $idx & "), NilV])")
500500 lenv.locals[symName(p)] = id
501501 inc idx; inc j
@@ -506,14 +506,14 @@ proc genLet(bindings: Value, body: seq[Value], dst: string, env: Env, c: Ctx) =
506506 for ks in valForm.items:
507507 let nm = symName(ks)
508508 let id = c.gensym("l" & mangle(nm))
509- c.line("var " & id & ": Value = call(getVar(\"get\"), @[" & v &
509+ c.line("var " & id & ": Value = call(getVar(\"get\"), [" & v &
510510 ", mkKeyword(" & nimStr(nm) & ")])")
511511 lenv.locals[nm] = id
512512 else:
513513 let nm = symName(k)
514514 let id = c.gensym("l" & mangle(nm))
515515 let kv = genExpr(valForm, lenv, c)
516- c.line("var " & id & ": Value = call(getVar(\"get\"), @[" & v & ", " & kv & "])")
516+ c.line("var " & id & ": Value = call(getVar(\"get\"), [" & v & ", " & kv & "])")
517517 lenv.locals[nm] = id
518518 else:
519519 err("Unsupported binding form: " & prStr(target))
@@ -602,7 +602,7 @@ proc genCall(f: Value, args: seq[Value], dst: string, env: Env, c: Ctx) =
602602 c.line("else:")
603603 c.push
604604 c.line(dst & " = call(cellGet(" & d.cell & "), " &
605- (if argIdents.len == 0: "emptyArgs" else: "@[" & argIdents.join(", ") & "]") & ")")
605+ (if argIdents.len == 0: "emptyArgs" else: "[" & argIdents.join(", ") & "]") & ")")
606606 c.pop
607607 return
608608 let key = f.s & "/" & $args.len
@@ -623,7 +623,7 @@ proc genCall(f: Value, args: seq[Value], dst: string, env: Env, c: Ctx) =
623623 c.pop
624624 c.line("else:")
625625 c.push
626- c.line(dst & " = call(cellGet(" & cell & "), @[" & argIdents.join(", ") & "])")
626+ c.line(dst & " = call(cellGet(" & cell & "), [" & argIdents.join(", ") & "])")
627627 c.pop
628628 return
629629 let fv = genExprTemp(f, env, c)
@@ -632,7 +632,7 @@ proc genCall(f: Value, args: seq[Value], dst: string, env: Env, c: Ctx) =
632632 if argIdents.len == 0:
633633 c.line(dst & " = call(" & fv & ", emptyArgs)")
634634 else:
635- c.line(dst & " = call(" & fv & ", @[" & argIdents.join(", ") & "])")
635+ c.line(dst & " = call(" & fv & ", [" & argIdents.join(", ") & "])")
636636
637637 ## ------------------------------------------------------- int specialisation
638638 ##
@@ -774,7 +774,7 @@ proc tryExpr(f: Value, env: Env, c: Ctx): string =
774774 let hv = tryExpr(head, env, c)
775775 if hv.len == 0: return ""
776776 "call(" & hv & ", " &
777- (if ids.len == 0: "emptyArgs" else: "@[" & ids.join(", ") & "]") & ")"
777+ (if ids.len == 0: "emptyArgs" else: "[" & ids.join(", ") & "]") & ")"
778778 of kFn, kCons, kChunk, kLazy:
779779 ""
780780
@@ -406,7 +406,7 @@ proc genFn(name: string, clauses: seq[FnClause], selfIdent: string, env: Env,
406 if boxes: directEnv.intFnBoxes.incl key406 if boxes: directEnv.intFnBoxes.incl key
407 407
408 let argsIdent = c.gensym("args")408 let argsIdent = c.gensym("args")
409- c.line(dst & " = mkFn(" & nimStr(name) & ", proc (" & argsIdent & ": seq[Value]): Value =")409+ c.line(dst & " = mkFn(" & nimStr(name) & ", proc (" & argsIdent & ": openArray[Value]): Value =")
410 c.push410 c.push
411 var first = true411 var first = true
412 for ci, cl in clauses:412 for ci, cl in clauses:
@@ -495,7 +495,7 @@ proc genLet(bindings: Value, body: seq[Value], dst: string, env: Env, c: Ctx) =
495 lenv.locals[restSym] = id495 lenv.locals[restSym] = id
496 break496 break
497 let id = c.gensym("l" & mangle(symName(p)))497 let id = c.gensym("l" & mangle(symName(p)))
498- c.line("var " & id & ": Value = call(getVar(\"nth\"), @[" & v & ", mkInt(" &498+ c.line("var " & id & ": Value = call(getVar(\"nth\"), [" & v & ", mkInt(" &
499 $idx & "), NilV])")499 $idx & "), NilV])")
500 lenv.locals[symName(p)] = id500 lenv.locals[symName(p)] = id
501 inc idx; inc j501 inc idx; inc j
@@ -506,14 +506,14 @@ proc genLet(bindings: Value, body: seq[Value], dst: string, env: Env, c: Ctx) =
506 for ks in valForm.items:506 for ks in valForm.items:
507 let nm = symName(ks)507 let nm = symName(ks)
508 let id = c.gensym("l" & mangle(nm))508 let id = c.gensym("l" & mangle(nm))
509- c.line("var " & id & ": Value = call(getVar(\"get\"), @[" & v &509+ c.line("var " & id & ": Value = call(getVar(\"get\"), [" & v &
510 ", mkKeyword(" & nimStr(nm) & ")])")510 ", mkKeyword(" & nimStr(nm) & ")])")
511 lenv.locals[nm] = id511 lenv.locals[nm] = id
512 else:512 else:
513 let nm = symName(k)513 let nm = symName(k)
514 let id = c.gensym("l" & mangle(nm))514 let id = c.gensym("l" & mangle(nm))
515 let kv = genExpr(valForm, lenv, c)515 let kv = genExpr(valForm, lenv, c)
516- c.line("var " & id & ": Value = call(getVar(\"get\"), @[" & v & ", " & kv & "])")516+ c.line("var " & id & ": Value = call(getVar(\"get\"), [" & v & ", " & kv & "])")
517 lenv.locals[nm] = id517 lenv.locals[nm] = id
518 else:518 else:
519 err("Unsupported binding form: " & prStr(target))519 err("Unsupported binding form: " & prStr(target))
@@ -602,7 +602,7 @@ proc genCall(f: Value, args: seq[Value], dst: string, env: Env, c: Ctx) =
602 c.line("else:")602 c.line("else:")
603 c.push603 c.push
604 c.line(dst & " = call(cellGet(" & d.cell & "), " &604 c.line(dst & " = call(cellGet(" & d.cell & "), " &
605- (if argIdents.len == 0: "emptyArgs" else: "@[" & argIdents.join(", ") & "]") & ")")605+ (if argIdents.len == 0: "emptyArgs" else: "[" & argIdents.join(", ") & "]") & ")")
606 c.pop606 c.pop
607 return607 return
608 let key = f.s & "/" & $args.len608 let key = f.s & "/" & $args.len
@@ -623,7 +623,7 @@ proc genCall(f: Value, args: seq[Value], dst: string, env: Env, c: Ctx) =
623 c.pop623 c.pop
624 c.line("else:")624 c.line("else:")
625 c.push625 c.push
626- c.line(dst & " = call(cellGet(" & cell & "), @[" & argIdents.join(", ") & "])")626+ c.line(dst & " = call(cellGet(" & cell & "), [" & argIdents.join(", ") & "])")
627 c.pop627 c.pop
628 return628 return
629 let fv = genExprTemp(f, env, c)629 let fv = genExprTemp(f, env, c)
@@ -632,7 +632,7 @@ proc genCall(f: Value, args: seq[Value], dst: string, env: Env, c: Ctx) =
632 if argIdents.len == 0:632 if argIdents.len == 0:
633 c.line(dst & " = call(" & fv & ", emptyArgs)")633 c.line(dst & " = call(" & fv & ", emptyArgs)")
634 else:634 else:
635- c.line(dst & " = call(" & fv & ", @[" & argIdents.join(", ") & "])")635+ c.line(dst & " = call(" & fv & ", [" & argIdents.join(", ") & "])")
636 636
637 ## ------------------------------------------------------- int specialisation637 ## ------------------------------------------------------- int specialisation
638 ##638 ##
@@ -774,7 +774,7 @@ proc tryExpr(f: Value, env: Env, c: Ctx): string =
774 let hv = tryExpr(head, env, c)774 let hv = tryExpr(head, env, c)
775 if hv.len == 0: return ""775 if hv.len == 0: return ""
776 "call(" & hv & ", " &776 "call(" & hv & ", " &
777- (if ids.len == 0: "emptyArgs" else: "@[" & ids.join(", ") & "]") & ")"777+ (if ids.len == 0: "emptyArgs" else: "[" & ids.join(", ") & "]") & ")"
778 of kFn, kCons, kChunk, kLazy:778 of kFn, kCons, kChunk, kLazy:
779 ""779 ""
780 780
modified src/core.nim +174 -174
@@ -8,7 +8,7 @@ proc num(v: Value): float64 =
88 of kFloat: v.f
99 else: err("Not a number: " & prStr(v))
1010
11-proc isFloaty(vs: seq[Value]): bool =
11+proc isFloaty(vs: openArray[Value]): bool =
1212 for v in vs:
1313 if v.kind == kFloat: return true
1414 false
@@ -19,7 +19,7 @@ proc intOf(v: Value): int64 =
1919 of kFloat: int64(v.f)
2020 else: err("Not a number: " & prStr(v))
2121
22-proc arith(name: string, args: seq[Value], unit: int64,
22+proc arith(name: string, args: openArray[Value], unit: int64,
2323 fi: proc (a, b: int64): int64, ff: proc (a, b: float64): float64): Value =
2424 if args.len == 0: return mkInt(unit)
2525 if isFloaty(args):
@@ -32,7 +32,7 @@ proc arith(name: string, args: seq[Value], unit: int64,
3232 for i in start ..< args.len: acc = fi(acc, args[i].i)
3333 mkInt(acc)
3434
35-proc cmpChain(args: seq[Value], ok: proc (c: int): bool): Value =
35+proc cmpChain(args: openArray[Value], ok: proc (c: int): bool): Value =
3636 for i in 0 ..< args.len - 1:
3737 let a = num(args[i])
3838 let b = num(args[i + 1])
@@ -103,37 +103,37 @@ proc dec1*(a: Value): Value {.inline.} =
103103 ## Guarded forms: the whole call site, cell check included, as one expression,
104104 ## for the call sites where a def in the program can still rebind the name.
105105 proc add2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
106- if cellIs(c, k): add2(a, b) else: call(cellGet(c), @[a, b])
106+ if cellIs(c, k): add2(a, b) else: call(cellGet(c), [a, b])
107107
108108 proc sub2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
109- if cellIs(c, k): sub2(a, b) else: call(cellGet(c), @[a, b])
109+ if cellIs(c, k): sub2(a, b) else: call(cellGet(c), [a, b])
110110
111111 proc mul2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
112- if cellIs(c, k): mul2(a, b) else: call(cellGet(c), @[a, b])
112+ if cellIs(c, k): mul2(a, b) else: call(cellGet(c), [a, b])
113113
114114 proc lt2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
115- if cellIs(c, k): lt2(a, b) else: call(cellGet(c), @[a, b])
115+ if cellIs(c, k): lt2(a, b) else: call(cellGet(c), [a, b])
116116
117117 proc gt2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
118- if cellIs(c, k): gt2(a, b) else: call(cellGet(c), @[a, b])
118+ if cellIs(c, k): gt2(a, b) else: call(cellGet(c), [a, b])
119119
120120 proc le2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
121- if cellIs(c, k): le2(a, b) else: call(cellGet(c), @[a, b])
121+ if cellIs(c, k): le2(a, b) else: call(cellGet(c), [a, b])
122122
123123 proc ge2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
124- if cellIs(c, k): ge2(a, b) else: call(cellGet(c), @[a, b])
124+ if cellIs(c, k): ge2(a, b) else: call(cellGet(c), [a, b])
125125
126126 proc eq2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
127- if cellIs(c, k): eq2(a, b) else: call(cellGet(c), @[a, b])
127+ if cellIs(c, k): eq2(a, b) else: call(cellGet(c), [a, b])
128128
129129 proc ne2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
130- if cellIs(c, k): ne2(a, b) else: call(cellGet(c), @[a, b])
130+ if cellIs(c, k): ne2(a, b) else: call(cellGet(c), [a, b])
131131
132132 proc inc1g*(c: VarCell, k: Value, a: Value): Value {.inline.} =
133- if cellIs(c, k): inc1(a) else: call(cellGet(c), @[a])
133+ if cellIs(c, k): inc1(a) else: call(cellGet(c), [a])
134134
135135 proc dec1g*(c: VarCell, k: Value, a: Value): Value {.inline.} =
136- if cellIs(c, k): dec1(a) else: call(cellGet(c), @[a])
136+ if cellIs(c, k): dec1(a) else: call(cellGet(c), [a])
137137
138138 proc getIn(coll, k, dflt: Value): Value =
139139 if coll.isNil or coll.kind == kNil: return dflt
@@ -206,7 +206,7 @@ proc lazyMap(f: Value, c: Cursor): Value =
206206 var cc = cur
207207 var xs = newSeqOfCap[Value](ChunkSize)
208208 while xs.len < ChunkSize and hasNext(cc):
209- xs.add call(f, @[next(cc)])
209+ xs.add call(f, [next(cc)])
210210 if xs.len == 0: return NilV
211211 mkChunk(xs, 0, lazyMap(f, cc)))
212212
@@ -226,7 +226,7 @@ proc lazyMapIndexed(f: Value, i: int64, c: Cursor): Value =
226226 var cc = cur
227227 if not hasNext(cc): return NilV
228228 let x = next(cc)
229- mkCons(call(f, @[mkInt(i), x]), lazyMapIndexed(f, i + 1, cc)))
229+ mkCons(call(f, [mkInt(i), x]), lazyMapIndexed(f, i + 1, cc)))
230230
231231 proc lazyFilter(pred: Value, c: Cursor, keep: bool): Value =
232232 ## Draws up to ChunkSize source elements per step and emits whichever pass,
@@ -240,7 +240,7 @@ proc lazyFilter(pred: Value, c: Cursor, keep: bool): Value =
240240 var drawn = 0
241241 while drawn < ChunkSize and hasNext(cc):
242242 let x = next(cc)
243- if truthy(call(pred, @[x])) == keep: xs.add x
243+ if truthy(call(pred, [x])) == keep: xs.add x
244244 inc drawn
245245 if xs.len > 0: return mkChunk(xs, 0, lazyFilter(pred, cc, keep))
246246 if drawn == 0: return NilV)
@@ -270,7 +270,7 @@ proc lazyTakeWhile(pred: Value, c: Cursor): Value =
270270 var cc = cur
271271 if not hasNext(cc): return NilV
272272 let x = next(cc)
273- if not truthy(call(pred, @[x])): return NilV
273+ if not truthy(call(pred, [x])): return NilV
274274 mkCons(x, lazyTakeWhile(pred, cc)))
275275
276276 proc lazyDropWhile(pred: Value, c: Cursor): Value =
@@ -281,7 +281,7 @@ proc lazyDropWhile(pred: Value, c: Cursor): Value =
281281 var peek = cc
282282 if not hasNext(peek): return NilV
283283 let x = next(peek)
284- if not truthy(call(pred, @[x])): return mkCons(x, lazyOf(peek))
284+ if not truthy(call(pred, [x])): return mkCons(x, lazyOf(peek))
285285 cc = peek)
286286
287287 proc lazyRange(i, hi, step: int64, bounded: bool): Value =
@@ -299,7 +299,7 @@ proc lazyRange(i, hi, step: int64, bounded: bool): Value =
299299 mkChunk(xs, 0, lazyRange(cur, hi, step, bounded)))
300300
301301 proc lazyIterate(f, x: Value): Value =
302- mkLazy(proc (): Value = mkCons(x, lazyIterate(f, call(f, @[x]))))
302+ mkLazy(proc (): Value = mkCons(x, lazyIterate(f, call(f, [x]))))
303303
304304 proc lazyRepeat(x: Value, n: int64, bounded: bool): Value =
305305 mkLazy(proc (): Value =
@@ -309,7 +309,7 @@ proc lazyRepeat(x: Value, n: int64, bounded: bool): Value =
309309 proc lazyRepeatedly(f: Value, n: int64, bounded: bool): Value =
310310 mkLazy(proc (): Value =
311311 if bounded and n <= 0: return NilV
312- mkCons(call(f, @[]), lazyRepeatedly(f, n - 1, bounded)))
312+ mkCons(call(f, []), lazyRepeatedly(f, n - 1, bounded)))
313313
314314 proc lazyCycle(orig: Value, c: Cursor): Value =
315315 let cur = c
@@ -332,86 +332,86 @@ proc lazyConcat(colls: seq[Value], i: int, c: Cursor): Value =
332332 let x = next(cc)
333333 mkCons(x, lazyConcat(colls, k, cc)))
334334
335-proc def(name: string, f: proc (args: seq[Value]): Value {.closure.}) =
335+proc def(name: string, f: proc (args: openArray[Value]): Value {.closure.}) =
336336 setVar(name, mkFn(name, f))
337337
338338 proc registerCore*() =
339339 # ---- arithmetic
340- def "+", proc (a: seq[Value]): Value =
340+ def "+", proc (a: openArray[Value]): Value =
341341 arith("+", a, 0, proc (x, y: int64): int64 = x + y, proc (x, y: float64): float64 = x + y)
342- def "-", proc (a: seq[Value]): Value =
342+ def "-", proc (a: openArray[Value]): Value =
343343 arith("-", a, 0, proc (x, y: int64): int64 = x - y, proc (x, y: float64): float64 = x - y)
344- def "*", proc (a: seq[Value]): Value =
344+ def "*", proc (a: openArray[Value]): Value =
345345 arith("*", a, 1, proc (x, y: int64): int64 = x * y, proc (x, y: float64): float64 = x * y)
346- def "/", proc (a: seq[Value]): Value =
346+ def "/", proc (a: openArray[Value]): Value =
347347 if isFloaty(a) or a.len == 1:
348348 arith("/", a, 1, proc (x, y: int64): int64 = x div y, proc (x, y: float64): float64 = x / y)
349349 else:
350350 for i in 1 ..< a.len:
351351 if a[i].kind == kInt and a[i].i == 0: err("Divide by zero")
352352 arith("/", a, 1, proc (x, y: int64): int64 = x div y, proc (x, y: float64): float64 = x / y)
353- def "quot", proc (a: seq[Value]): Value = mkInt(idiv(intOf(a[0]), intOf(a[1])))
354- def "rem", proc (a: seq[Value]): Value = mkInt(irem(intOf(a[0]), intOf(a[1])))
355- def "mod", proc (a: seq[Value]): Value =
353+ def "quot", proc (a: openArray[Value]): Value = mkInt(idiv(intOf(a[0]), intOf(a[1])))
354+ def "rem", proc (a: openArray[Value]): Value = mkInt(irem(intOf(a[0]), intOf(a[1])))
355+ def "mod", proc (a: openArray[Value]): Value =
356356 let x = intOf(a[0]); let y = intOf(a[1])
357357 var r = irem(x, y)
358358 if r != 0 and ((r < 0) != (y < 0)): r += y
359359 mkInt(r)
360- def "inc", proc (a: seq[Value]): Value =
360+ def "inc", proc (a: openArray[Value]): Value =
361361 (if a[0].kind == kFloat: mkFloat(a[0].f + 1.0) else: mkInt(a[0].i + 1))
362- def "dec", proc (a: seq[Value]): Value =
362+ def "dec", proc (a: openArray[Value]): Value =
363363 (if a[0].kind == kFloat: mkFloat(a[0].f - 1.0) else: mkInt(a[0].i - 1))
364- def "max", proc (a: seq[Value]): Value =
364+ def "max", proc (a: openArray[Value]): Value =
365365 result = a[0]
366366 for x in a: (if num(x) > num(result): result = x)
367- def "min", proc (a: seq[Value]): Value =
367+ def "min", proc (a: openArray[Value]): Value =
368368 result = a[0]
369369 for x in a: (if num(x) < num(result): result = x)
370- def "abs", proc (a: seq[Value]): Value =
370+ def "abs", proc (a: openArray[Value]): Value =
371371 (if a[0].kind == kFloat: mkFloat(abs(a[0].f)) else: mkInt(abs(a[0].i)))
372- def "Math/sqrt", proc (a: seq[Value]): Value = mkFloat(sqrt(num(a[0])))
373- def "Math/pow", proc (a: seq[Value]): Value = mkFloat(pow(num(a[0]), num(a[1])))
374- def "rand-int", proc (a: seq[Value]): Value = mkInt(rand(int(intOf(a[0])) - 1))
375- def "double", proc (a: seq[Value]): Value = mkFloat(num(a[0]))
376- def "int", proc (a: seq[Value]): Value = mkInt(intOf(a[0]))
372+ def "Math/sqrt", proc (a: openArray[Value]): Value = mkFloat(sqrt(num(a[0])))
373+ def "Math/pow", proc (a: openArray[Value]): Value = mkFloat(pow(num(a[0]), num(a[1])))
374+ def "rand-int", proc (a: openArray[Value]): Value = mkInt(rand(int(intOf(a[0])) - 1))
375+ def "double", proc (a: openArray[Value]): Value = mkFloat(num(a[0]))
376+ def "int", proc (a: openArray[Value]): Value = mkInt(intOf(a[0]))
377377
378378 # ---- comparison / predicates
379- def "=", proc (a: seq[Value]): Value =
379+ def "=", proc (a: openArray[Value]): Value =
380380 for i in 0 ..< a.len - 1:
381381 if not equals(a[i], a[i + 1]): return FalseV
382382 TrueV
383- def "not=", proc (a: seq[Value]): Value =
383+ def "not=", proc (a: openArray[Value]): Value =
384384 for i in 0 ..< a.len - 1:
385385 if not equals(a[i], a[i + 1]): return TrueV
386386 FalseV
387- def "<", proc (a: seq[Value]): Value = cmpChain(a, proc (c: int): bool = c < 0)
388- def ">", proc (a: seq[Value]): Value = cmpChain(a, proc (c: int): bool = c > 0)
389- def "<=", proc (a: seq[Value]): Value = cmpChain(a, proc (c: int): bool = c <= 0)
390- def ">=", proc (a: seq[Value]): Value = cmpChain(a, proc (c: int): bool = c >= 0)
391- def "not", proc (a: seq[Value]): Value = mkBool(not truthy(a[0]))
392- def "nil?", proc (a: seq[Value]): Value = mkBool(a[0].isNil or a[0].kind == kNil)
393- def "some?", proc (a: seq[Value]): Value = mkBool(not (a[0].isNil or a[0].kind == kNil))
394- def "true?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kBool and a[0].b)
395- def "false?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kBool and not a[0].b)
396- def "zero?", proc (a: seq[Value]): Value = mkBool(num(a[0]) == 0.0)
397- def "pos?", proc (a: seq[Value]): Value = mkBool(num(a[0]) > 0.0)
398- def "neg?", proc (a: seq[Value]): Value = mkBool(num(a[0]) < 0.0)
399- def "even?", proc (a: seq[Value]): Value = mkBool(intOf(a[0]) mod 2 == 0)
400- def "odd?", proc (a: seq[Value]): Value = mkBool(intOf(a[0]) mod 2 != 0)
401- def "string?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kStr)
402- def "number?", proc (a: seq[Value]): Value = mkBool(a[0].kind in {kInt, kFloat})
403- def "int?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kInt)
404- def "keyword?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kKeyword)
405- def "symbol?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kSymbol)
406- def "vector?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kVector)
407- def "list?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kList)
408- def "map?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kMap)
409- def "set?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kSet)
410- def "coll?", proc (a: seq[Value]): Value =
387+ def "<", proc (a: openArray[Value]): Value = cmpChain(a, proc (c: int): bool = c < 0)
388+ def ">", proc (a: openArray[Value]): Value = cmpChain(a, proc (c: int): bool = c > 0)
389+ def "<=", proc (a: openArray[Value]): Value = cmpChain(a, proc (c: int): bool = c <= 0)
390+ def ">=", proc (a: openArray[Value]): Value = cmpChain(a, proc (c: int): bool = c >= 0)
391+ def "not", proc (a: openArray[Value]): Value = mkBool(not truthy(a[0]))
392+ def "nil?", proc (a: openArray[Value]): Value = mkBool(a[0].isNil or a[0].kind == kNil)
393+ def "some?", proc (a: openArray[Value]): Value = mkBool(not (a[0].isNil or a[0].kind == kNil))
394+ def "true?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kBool and a[0].b)
395+ def "false?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kBool and not a[0].b)
396+ def "zero?", proc (a: openArray[Value]): Value = mkBool(num(a[0]) == 0.0)
397+ def "pos?", proc (a: openArray[Value]): Value = mkBool(num(a[0]) > 0.0)
398+ def "neg?", proc (a: openArray[Value]): Value = mkBool(num(a[0]) < 0.0)
399+ def "even?", proc (a: openArray[Value]): Value = mkBool(intOf(a[0]) mod 2 == 0)
400+ def "odd?", proc (a: openArray[Value]): Value = mkBool(intOf(a[0]) mod 2 != 0)
401+ def "string?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kStr)
402+ def "number?", proc (a: openArray[Value]): Value = mkBool(a[0].kind in {kInt, kFloat})
403+ def "int?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kInt)
404+ def "keyword?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kKeyword)
405+ def "symbol?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kSymbol)
406+ def "vector?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kVector)
407+ def "list?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kList)
408+ def "map?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kMap)
409+ def "set?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kSet)
410+ def "coll?", proc (a: openArray[Value]): Value =
411411 mkBool(a[0].kind in {kList, kVector, kMap, kSet})
412- def "fn?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kFn)
413- def "empty?", proc (a: seq[Value]): Value = mkBool(seqIsEmpty(a[0]))
414- def "contains?", proc (a: seq[Value]): Value =
412+ def "fn?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kFn)
413+ def "empty?", proc (a: openArray[Value]): Value = mkBool(seqIsEmpty(a[0]))
414+ def "contains?", proc (a: openArray[Value]): Value =
415415 let c = a[0]
416416 if c.isNil or c.kind == kNil: return FalseV
417417 case c.kind
@@ -421,97 +421,97 @@ proc registerCore*() =
421421 else: FalseV
422422
423423 # ---- strings / IO
424- def "str", proc (a: seq[Value]): Value =
424+ def "str", proc (a: openArray[Value]): Value =
425425 var s = ""
426426 for x in a: s &= str(x)
427427 mkStr(s)
428- def "pr-str", proc (a: seq[Value]): Value =
428+ def "pr-str", proc (a: openArray[Value]): Value =
429429 var parts: seq[string] = @[]
430430 for x in a: parts.add prStr(x)
431431 mkStr(parts.join(" "))
432- def "println", proc (a: seq[Value]): Value =
432+ def "println", proc (a: openArray[Value]): Value =
433433 var parts: seq[string] = @[]
434434 for x in a: parts.add str(x)
435435 echo parts.join(" ")
436436 NilV
437- def "prn", proc (a: seq[Value]): Value =
437+ def "prn", proc (a: openArray[Value]): Value =
438438 var parts: seq[string] = @[]
439439 for x in a: parts.add prStr(x)
440440 echo parts.join(" ")
441441 NilV
442- def "print", proc (a: seq[Value]): Value =
442+ def "print", proc (a: openArray[Value]): Value =
443443 var parts: seq[string] = @[]
444444 for x in a: parts.add str(x)
445445 stdout.write parts.join(" ")
446446 NilV
447- def "name", proc (a: seq[Value]): Value =
447+ def "name", proc (a: openArray[Value]): Value =
448448 case a[0].kind
449449 of kKeyword, kSymbol, kStr: mkStr(a[0].s)
450450 else: err("name expects keyword/symbol/string")
451- def "keyword", proc (a: seq[Value]): Value = mkKeyword(str(a[0]))
452- def "symbol", proc (a: seq[Value]): Value = mkSymbol(str(a[0]))
453- def "subs", proc (a: seq[Value]): Value =
451+ def "keyword", proc (a: openArray[Value]): Value = mkKeyword(str(a[0]))
452+ def "symbol", proc (a: openArray[Value]): Value = mkSymbol(str(a[0]))
453+ def "subs", proc (a: openArray[Value]): Value =
454454 let s = a[0].s
455455 let st = int(intOf(a[1]))
456456 let en = (if a.len > 2: int(intOf(a[2])) else: s.len)
457457 mkStr(s[st ..< en])
458- def "clojure.string/upper-case", proc (a: seq[Value]): Value = mkStr(a[0].s.toUpperAscii)
459- def "clojure.string/lower-case", proc (a: seq[Value]): Value = mkStr(a[0].s.toLowerAscii)
460- def "clojure.string/trim", proc (a: seq[Value]): Value = mkStr(a[0].s.strip)
461- def "clojure.string/split", proc (a: seq[Value]): Value =
458+ def "clojure.string/upper-case", proc (a: openArray[Value]): Value = mkStr(a[0].s.toUpperAscii)
459+ def "clojure.string/lower-case", proc (a: openArray[Value]): Value = mkStr(a[0].s.toLowerAscii)
460+ def "clojure.string/trim", proc (a: openArray[Value]): Value = mkStr(a[0].s.strip)
461+ def "clojure.string/split", proc (a: openArray[Value]): Value =
462462 var r: seq[Value] = @[]
463463 for piece in a[0].s.split(a[1].s): r.add mkStr(piece)
464464 mkVector(r)
465- def "clojure.string/join", proc (a: seq[Value]): Value =
465+ def "clojure.string/join", proc (a: openArray[Value]): Value =
466466 let sep = (if a.len > 1: str(a[0]) else: "")
467467 let coll = (if a.len > 1: a[1] else: a[0])
468468 var parts: seq[string] = @[]
469469 for x in elems(coll): parts.add str(x)
470470 mkStr(parts.join(sep))
471- def "read-line", proc (a: seq[Value]): Value =
471+ def "read-line", proc (a: openArray[Value]): Value =
472472 try: mkStr(stdin.readLine()) except CatchableError: NilV
473- def "slurp", proc (a: seq[Value]): Value = mkStr(readFile(a[0].s))
474- def "spit", proc (a: seq[Value]): Value =
473+ def "slurp", proc (a: openArray[Value]): Value = mkStr(readFile(a[0].s))
474+ def "spit", proc (a: openArray[Value]): Value =
475475 writeFile(a[0].s, str(a[1])); NilV
476- def "now-ms", proc (a: seq[Value]): Value = mkInt(int64(epochTime() * 1000))
476+ def "now-ms", proc (a: openArray[Value]): Value = mkInt(int64(epochTime() * 1000))
477477
478478 # ---- collections
479- def "list", proc (a: seq[Value]): Value = mkList(a)
480- def "vector", proc (a: seq[Value]): Value = mkVector(a)
481- def "hash-map", proc (a: seq[Value]): Value =
479+ def "list", proc (a: openArray[Value]): Value = mkList(a)
480+ def "vector", proc (a: openArray[Value]): Value = mkVector(a)
481+ def "hash-map", proc (a: openArray[Value]): Value =
482482 var m = emptyPMap()
483483 var i = 0
484484 while i + 1 < a.len:
485485 m = mapAssoc(m, a[i], a[i + 1]); i += 2
486486 mkMapOf(m)
487- def "hash-set", proc (a: seq[Value]): Value = mkSet(a)
488- def "set", proc (a: seq[Value]): Value = mkSet(toSeq(a[0]))
489- def "vec", proc (a: seq[Value]): Value = mkVector(toSeq(a[0]))
490- def "seq", proc (a: seq[Value]): Value =
487+ def "hash-set", proc (a: openArray[Value]): Value = mkSet(a)
488+ def "set", proc (a: openArray[Value]): Value = mkSet(toSeq(a[0]))
489+ def "vec", proc (a: openArray[Value]): Value = mkVector(toSeq(a[0]))
490+ def "seq", proc (a: openArray[Value]): Value =
491491 # does not realize a lazy seq — just asks whether it has a first element
492492 (if seqIsEmpty(a[0]): NilV else: a[0])
493- def "count", proc (a: seq[Value]): Value =
493+ def "count", proc (a: openArray[Value]): Value =
494494 if a[0].isNil or a[0].kind == kNil: return mkInt(0)
495495 mkInt(count(a[0]))
496- def "conj", proc (a: seq[Value]): Value =
496+ def "conj", proc (a: openArray[Value]): Value =
497497 result = a[0]
498498 for i in 1 ..< a.len: result = conjOne(result, a[i])
499- def "cons", proc (a: seq[Value]): Value = mkCons(a[0], a[1])
500- def "first", proc (a: seq[Value]): Value =
499+ def "cons", proc (a: openArray[Value]): Value = mkCons(a[0], a[1])
500+ def "first", proc (a: openArray[Value]): Value =
501501 if a[0].kind == kVector:
502502 return (if a[0].vec.cnt == 0: NilV else: vecNth(a[0].vec, 0))
503503 seqFirst(a[0])
504- def "second", proc (a: seq[Value]): Value = seqFirst(seqRest(a[0]))
505- def "last", proc (a: seq[Value]): Value =
504+ def "second", proc (a: openArray[Value]): Value = seqFirst(seqRest(a[0]))
505+ def "last", proc (a: openArray[Value]): Value =
506506 if a[0].kind == kVector:
507507 return (if a[0].vec.cnt == 0: NilV else: vecNth(a[0].vec, a[0].vec.cnt - 1))
508508 result = NilV
509509 for x in elems(a[0]): result = x
510- def "rest", proc (a: seq[Value]): Value = seqRest(a[0])
511- def "next", proc (a: seq[Value]): Value =
510+ def "rest", proc (a: openArray[Value]): Value = seqRest(a[0])
511+ def "next", proc (a: openArray[Value]): Value =
512512 let r = seqRest(a[0])
513513 (if seqIsEmpty(r): NilV else: r)
514- def "nth", proc (a: seq[Value]): Value =
514+ def "nth", proc (a: openArray[Value]): Value =
515515 let i = int(intOf(a[1]))
516516 if a[0].kind == kVector:
517517 # O(log32 n) straight through the trie, no intermediate seq
@@ -528,39 +528,39 @@ proc registerCore*() =
528528 dec k
529529 if a.len > 2: a[2]
530530 else: err("Index out of bounds: " & $i)
531- def "get", proc (a: seq[Value]): Value =
531+ def "get", proc (a: openArray[Value]): Value =
532532 getIn(a[0], a[1], (if a.len > 2: a[2] else: NilV))
533- def "get-in", proc (a: seq[Value]): Value =
533+ def "get-in", proc (a: openArray[Value]): Value =
534534 var cur = a[0]
535535 for k in toSeq(a[1]):
536536 cur = getIn(cur, k, NilV)
537537 (if (cur.isNil or cur.kind == kNil) and a.len > 2: a[2] else: cur)
538- def "assoc", proc (a: seq[Value]): Value =
538+ def "assoc", proc (a: openArray[Value]): Value =
539539 result = a[0]
540540 var i = 1
541541 while i + 1 < a.len:
542542 result = assocOne(result, a[i], a[i + 1]); i += 2
543- def "dissoc", proc (a: seq[Value]): Value =
543+ def "dissoc", proc (a: openArray[Value]): Value =
544544 var m = a[0].m
545545 for i in 1 ..< a.len: m = mapDissoc(m, a[i])
546546 mkMapOf(m)
547- def "update", proc (a: seq[Value]): Value =
547+ def "update", proc (a: openArray[Value]): Value =
548548 let cur = getIn(a[0], a[1], NilV)
549- assocOne(a[0], a[1], call(a[2], @[cur] & a[3 .. ^1]))
550- def "keys", proc (a: seq[Value]): Value =
549+ assocOne(a[0], a[1], call(a[2], @[cur] & @(a[3 .. ^1])))
550+ def "keys", proc (a: openArray[Value]): Value =
551551 var r: seq[Value] = @[]
552552 for e in mapEntries(a[0].m): r.add e.key
553553 (if r.len == 0: NilV else: mkList(r))
554- def "vals", proc (a: seq[Value]): Value =
554+ def "vals", proc (a: openArray[Value]): Value =
555555 var r: seq[Value] = @[]
556556 for e in mapEntries(a[0].m): r.add e.val
557557 (if r.len == 0: NilV else: mkList(r))
558- def "reverse", proc (a: seq[Value]): Value =
558+ def "reverse", proc (a: openArray[Value]): Value =
559559 let s = toSeq(a[0])
560560 var r: seq[Value] = @[]
561561 for i in countdown(s.len - 1, 0): r.add s[i]
562562 mkList(r)
563- def "range", proc (a: seq[Value]): Value =
563+ def "range", proc (a: openArray[Value]): Value =
564564 var lo: int64 = 0
565565 var hi: int64 = 0
566566 var step: int64 = 1
@@ -570,25 +570,25 @@ proc registerCore*() =
570570 if a.len > 2: step = intOf(a[2])
571571 # (range) with no bound is infinite; everything else stops at hi
572572 lazyRange(lo, hi, step, bounded = a.len > 0)
573- def "take", proc (a: seq[Value]): Value =
573+ def "take", proc (a: openArray[Value]): Value =
574574 lazyTake(int(intOf(a[0])), cursor(a[1]))
575- def "drop", proc (a: seq[Value]): Value =
575+ def "drop", proc (a: openArray[Value]): Value =
576576 lazyDrop(int(intOf(a[0])), cursor(a[1]))
577- def "concat", proc (a: seq[Value]): Value =
578- lazyConcat(a, 0, cursor(NilV))
579- def "iterate", proc (a: seq[Value]): Value = lazyIterate(a[0], a[1])
580- def "repeat", proc (a: seq[Value]): Value =
577+ def "concat", proc (a: openArray[Value]): Value =
578+ lazyConcat(@a, 0, cursor(NilV))
579+ def "iterate", proc (a: openArray[Value]): Value = lazyIterate(a[0], a[1])
580+ def "repeat", proc (a: openArray[Value]): Value =
581581 (if a.len == 1: lazyRepeat(a[0], 0, bounded = false)
582582 else: lazyRepeat(a[1], intOf(a[0]), bounded = true))
583- def "repeatedly", proc (a: seq[Value]): Value =
583+ def "repeatedly", proc (a: openArray[Value]): Value =
584584 (if a.len == 1: lazyRepeatedly(a[0], 0, bounded = false)
585585 else: lazyRepeatedly(a[1], intOf(a[0]), bounded = true))
586- def "cycle", proc (a: seq[Value]): Value = lazyCycle(a[0], cursor(a[0]))
587- def "doall", proc (a: seq[Value]): Value = mkList(toSeq(a[0]))
588- def "dorun", proc (a: seq[Value]): Value =
586+ def "cycle", proc (a: openArray[Value]): Value = lazyCycle(a[0], cursor(a[0]))
587+ def "doall", proc (a: openArray[Value]): Value = mkList(toSeq(a[0]))
588+ def "dorun", proc (a: openArray[Value]): Value =
589589 for x in elems(a[0]): discard
590590 NilV
591- def "sort", proc (a: seq[Value]): Value =
591+ def "sort", proc (a: openArray[Value]): Value =
592592 var s = toSeq(a[^1])
593593 let cmpFn = (if a.len > 1: a[0] else: NilV)
594594 # insertion sort keeps it simple and stable
@@ -596,25 +596,25 @@ proc registerCore*() =
596596 var j = i
597597 while j > 0:
598598 let before =
599- if cmpFn.kind == kFn: truthy(call(cmpFn, @[s[j], s[j - 1]]))
599+ if cmpFn.kind == kFn: truthy(call(cmpFn, [s[j], s[j - 1]]))
600600 elif s[j].kind == kStr: s[j].s < s[j - 1].s
601601 else: num(s[j]) < num(s[j - 1])
602602 if not before: break
603603 swap(s[j], s[j - 1]); dec j
604604 mkList(s)
605- def "sort-by", proc (a: seq[Value]): Value =
605+ def "sort-by", proc (a: openArray[Value]): Value =
606606 var s = toSeq(a[^1])
607607 let kf = a[0]
608608 for i in 1 ..< s.len:
609609 var j = i
610610 while j > 0:
611- let ka = call(kf, @[s[j]])
612- let kb = call(kf, @[s[j - 1]])
611+ let ka = call(kf, [s[j]])
612+ let kb = call(kf, [s[j - 1]])
613613 let before = (if ka.kind == kStr: ka.s < kb.s else: num(ka) < num(kb))
614614 if not before: break
615615 swap(s[j], s[j - 1]); dec j
616616 mkList(s)
617- def "distinct", proc (a: seq[Value]): Value =
617+ def "distinct", proc (a: openArray[Value]): Value =
618618 var r: seq[Value] = @[]
619619 for x in elems(a[0]):
620620 var dup = false
@@ -622,13 +622,13 @@ proc registerCore*() =
622622 if equals(x, y): dup = true; break
623623 if not dup: r.add x
624624 mkList(r)
625- def "interpose", proc (a: seq[Value]): Value =
625+ def "interpose", proc (a: openArray[Value]): Value =
626626 var r: seq[Value] = @[]
627627 for x in elems(a[1]):
628628 if r.len > 0: r.add a[0]
629629 r.add x
630630 mkList(r)
631- def "partition", proc (a: seq[Value]): Value =
631+ def "partition", proc (a: openArray[Value]): Value =
632632 let n = int(intOf(a[0]))
633633 let s = toSeq(a[^1])
634634 var r: seq[Value] = @[]
@@ -638,27 +638,27 @@ proc registerCore*() =
638638 mkList(r)
639639
640640 # ---- higher order
641- def "apply", proc (a: seq[Value]): Value =
641+ def "apply", proc (a: openArray[Value]): Value =
642642 var callArgs: seq[Value] = @[]
643643 for i in 1 ..< a.len - 1: callArgs.add a[i]
644644 callArgs.add toSeq(a[^1])
645645 call(a[0], callArgs)
646- def "map", proc (a: seq[Value]): Value =
646+ def "map", proc (a: openArray[Value]): Value =
647647 if a.len == 2: return lazyMap(a[0], cursor(a[1]))
648648 var cs: seq[Cursor] = @[]
649649 for i in 1 ..< a.len: cs.add cursor(a[i])
650650 lazyMapN(a[0], cs)
651- def "mapv", proc (a: seq[Value]): Value =
651+ def "mapv", proc (a: openArray[Value]): Value =
652652 var r: seq[Value] = @[]
653- for x in elems(a[1]): r.add call(a[0], @[x])
653+ for x in elems(a[1]): r.add call(a[0], [x])
654654 mkVector(r)
655- def "map-indexed", proc (a: seq[Value]): Value =
655+ def "map-indexed", proc (a: openArray[Value]): Value =
656656 lazyMapIndexed(a[0], 0, cursor(a[1]))
657- def "filter", proc (a: seq[Value]): Value =
657+ def "filter", proc (a: openArray[Value]): Value =
658658 lazyFilter(a[0], cursor(a[1]), keep = true)
659- def "remove", proc (a: seq[Value]): Value =
659+ def "remove", proc (a: openArray[Value]): Value =
660660 lazyFilter(a[0], cursor(a[1]), keep = false)
661- def "reduce", proc (a: seq[Value]): Value =
661+ def "reduce", proc (a: openArray[Value]): Value =
662662 ## Streams the source rather than materializing it, so folding a lazy seq
663663 ## holds one chunk at a time instead of the whole sequence.
664664 let f = a[0]
@@ -667,74 +667,74 @@ proc registerCore*() =
667667 var first = true
668668 for x in elems(a[1]):
669669 if first: acc = x; first = false
670- else: acc = call(f, @[acc, x])
671- if first: return call(f, @[])
670+ else: acc = call(f, [acc, x])
671+ if first: return call(f, [])
672672 return acc
673673 var acc = a[1]
674- for x in elems(a[2]): acc = call(f, @[acc, x])
674+ for x in elems(a[2]): acc = call(f, [acc, x])
675675 acc
676- def "some", proc (a: seq[Value]): Value =
676+ def "some", proc (a: openArray[Value]): Value =
677677 for x in elems(a[1]):
678- let r = call(a[0], @[x])
678+ let r = call(a[0], [x])
679679 if truthy(r): return r
680680 NilV
681- def "every?", proc (a: seq[Value]): Value =
681+ def "every?", proc (a: openArray[Value]): Value =
682682 for x in elems(a[1]):
683- if not truthy(call(a[0], @[x])): return FalseV
683+ if not truthy(call(a[0], [x])): return FalseV
684684 TrueV
685- def "take-while", proc (a: seq[Value]): Value =
685+ def "take-while", proc (a: openArray[Value]): Value =
686686 lazyTakeWhile(a[0], cursor(a[1]))
687- def "drop-while", proc (a: seq[Value]): Value =
687+ def "drop-while", proc (a: openArray[Value]): Value =
688688 lazyDropWhile(a[0], cursor(a[1]))
689- def "group-by", proc (a: seq[Value]): Value =
689+ def "group-by", proc (a: openArray[Value]): Value =
690690 var m = emptyPMap()
691691 for x in elems(a[1]):
692- let k = call(a[0], @[x])
692+ let k = call(a[0], [x])
693693 m = mapAssoc(m, k, conjOne(mapGet(m, k, mkVector(@[])), x))
694694 mkMapOf(m)
695- def "frequencies", proc (a: seq[Value]): Value =
695+ def "frequencies", proc (a: openArray[Value]): Value =
696696 var m = emptyPMap()
697697 for x in elems(a[0]):
698698 m = mapAssoc(m, x, mkInt(mapGet(m, x, mkInt(0)).i + 1))
699699 mkMapOf(m)
700- def "identity", proc (a: seq[Value]): Value = a[0]
701- def "comp", proc (a: seq[Value]): Value =
702- let fs = a
703- mkFn("comp", proc (args: seq[Value]): Value =
700+ def "identity", proc (a: openArray[Value]): Value = a[0]
701+ def "comp", proc (a: openArray[Value]): Value =
702+ let fs = @a
703+ mkFn("comp", proc (args: openArray[Value]): Value =
704704 if fs.len == 0: return argAt(args, 0)
705705 var v = call(fs[^1], args)
706- for i in countdown(fs.len - 2, 0): v = call(fs[i], @[v])
706+ for i in countdown(fs.len - 2, 0): v = call(fs[i], [v])
707707 v)
708- def "partial", proc (a: seq[Value]): Value =
708+ def "partial", proc (a: openArray[Value]): Value =
709709 let f = a[0]
710710 let bound = a[1 .. ^1]
711- mkFn("partial", proc (args: seq[Value]): Value = call(f, bound & args))
712- def "juxt", proc (a: seq[Value]): Value =
713- let fs = a
714- mkFn("juxt", proc (args: seq[Value]): Value =
711+ mkFn("partial", proc (args: openArray[Value]): Value = call(f, bound & @args))
712+ def "juxt", proc (a: openArray[Value]): Value =
713+ let fs = @a
714+ mkFn("juxt", proc (args: openArray[Value]): Value =
715715 var r: seq[Value] = @[]
716716 for f in fs: r.add call(f, args)
717717 mkVector(r))
718- def "constantly", proc (a: seq[Value]): Value =
718+ def "constantly", proc (a: openArray[Value]): Value =
719719 let v = a[0]
720- mkFn("constantly", proc (args: seq[Value]): Value = v)
720+ mkFn("constantly", proc (args: openArray[Value]): Value = v)
721721
722722 # ---- atoms (mutable boxes, modelled as a 1-slot vector)
723- def "atom", proc (a: seq[Value]): Value =
723+ def "atom", proc (a: openArray[Value]): Value =
724724 var cell = a[0]
725- mkFn("atom", proc (args: seq[Value]): Value =
725+ mkFn("atom", proc (args: openArray[Value]): Value =
726726 # (a) -> deref
727727 # (a :set v) -> reset
728728 if args.len == 0: return cell
729729 cell = args[1]
730730 cell)
731- def "deref", proc (a: seq[Value]): Value = call(a[0], @[])
732- def "reset!", proc (a: seq[Value]): Value = call(a[0], @[mkKeyword("set"), a[1]])
733- def "swap!", proc (a: seq[Value]): Value =
734- let cur = call(a[0], @[])
735- let nv = call(a[1], @[cur] & a[2 .. ^1])
736- call(a[0], @[mkKeyword("set"), nv])
737-
738- def "throw", proc (a: seq[Value]): Value = err(str(a[0]))
739- def "ex-info", proc (a: seq[Value]): Value = mkStr(str(a[0]))
740- def "time-ms", proc (a: seq[Value]): Value = mkInt(int64(epochTime() * 1000))
731+ def "deref", proc (a: openArray[Value]): Value = call(a[0], [])
732+ def "reset!", proc (a: openArray[Value]): Value = call(a[0], [mkKeyword("set"), a[1]])
733+ def "swap!", proc (a: openArray[Value]): Value =
734+ let cur = call(a[0], [])
735+ let nv = call(a[1], @[cur] & @(a[2 .. ^1]))
736+ call(a[0], [mkKeyword("set"), nv])
737+
738+ def "throw", proc (a: openArray[Value]): Value = err(str(a[0]))
739+ def "ex-info", proc (a: openArray[Value]): Value = mkStr(str(a[0]))
740+ def "time-ms", proc (a: openArray[Value]): Value = mkInt(int64(epochTime() * 1000))
@@ -8,7 +8,7 @@ proc num(v: Value): float64 =
8 of kFloat: v.f8 of kFloat: v.f
9 else: err("Not a number: " & prStr(v))9 else: err("Not a number: " & prStr(v))
10 10
11-proc isFloaty(vs: seq[Value]): bool =11+proc isFloaty(vs: openArray[Value]): bool =
12 for v in vs:12 for v in vs:
13 if v.kind == kFloat: return true13 if v.kind == kFloat: return true
14 false14 false
@@ -19,7 +19,7 @@ proc intOf(v: Value): int64 =
19 of kFloat: int64(v.f)19 of kFloat: int64(v.f)
20 else: err("Not a number: " & prStr(v))20 else: err("Not a number: " & prStr(v))
21 21
22-proc arith(name: string, args: seq[Value], unit: int64,22+proc arith(name: string, args: openArray[Value], unit: int64,
23 fi: proc (a, b: int64): int64, ff: proc (a, b: float64): float64): Value =23 fi: proc (a, b: int64): int64, ff: proc (a, b: float64): float64): Value =
24 if args.len == 0: return mkInt(unit)24 if args.len == 0: return mkInt(unit)
25 if isFloaty(args):25 if isFloaty(args):
@@ -32,7 +32,7 @@ proc arith(name: string, args: seq[Value], unit: int64,
32 for i in start ..< args.len: acc = fi(acc, args[i].i)32 for i in start ..< args.len: acc = fi(acc, args[i].i)
33 mkInt(acc)33 mkInt(acc)
34 34
35-proc cmpChain(args: seq[Value], ok: proc (c: int): bool): Value =35+proc cmpChain(args: openArray[Value], ok: proc (c: int): bool): Value =
36 for i in 0 ..< args.len - 1:36 for i in 0 ..< args.len - 1:
37 let a = num(args[i])37 let a = num(args[i])
38 let b = num(args[i + 1])38 let b = num(args[i + 1])
@@ -103,37 +103,37 @@ proc dec1*(a: Value): Value {.inline.} =
103 ## Guarded forms: the whole call site, cell check included, as one expression,103 ## Guarded forms: the whole call site, cell check included, as one expression,
104 ## for the call sites where a def in the program can still rebind the name.104 ## for the call sites where a def in the program can still rebind the name.
105 proc add2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =105 proc add2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
106- if cellIs(c, k): add2(a, b) else: call(cellGet(c), @[a, b])106+ if cellIs(c, k): add2(a, b) else: call(cellGet(c), [a, b])
107 107
108 proc sub2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =108 proc sub2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
109- if cellIs(c, k): sub2(a, b) else: call(cellGet(c), @[a, b])109+ if cellIs(c, k): sub2(a, b) else: call(cellGet(c), [a, b])
110 110
111 proc mul2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =111 proc mul2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
112- if cellIs(c, k): mul2(a, b) else: call(cellGet(c), @[a, b])112+ if cellIs(c, k): mul2(a, b) else: call(cellGet(c), [a, b])
113 113
114 proc lt2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =114 proc lt2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
115- if cellIs(c, k): lt2(a, b) else: call(cellGet(c), @[a, b])115+ if cellIs(c, k): lt2(a, b) else: call(cellGet(c), [a, b])
116 116
117 proc gt2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =117 proc gt2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
118- if cellIs(c, k): gt2(a, b) else: call(cellGet(c), @[a, b])118+ if cellIs(c, k): gt2(a, b) else: call(cellGet(c), [a, b])
119 119
120 proc le2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =120 proc le2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
121- if cellIs(c, k): le2(a, b) else: call(cellGet(c), @[a, b])121+ if cellIs(c, k): le2(a, b) else: call(cellGet(c), [a, b])
122 122
123 proc ge2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =123 proc ge2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
124- if cellIs(c, k): ge2(a, b) else: call(cellGet(c), @[a, b])124+ if cellIs(c, k): ge2(a, b) else: call(cellGet(c), [a, b])
125 125
126 proc eq2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =126 proc eq2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
127- if cellIs(c, k): eq2(a, b) else: call(cellGet(c), @[a, b])127+ if cellIs(c, k): eq2(a, b) else: call(cellGet(c), [a, b])
128 128
129 proc ne2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =129 proc ne2g*(c: VarCell, k: Value, a, b: Value): Value {.inline.} =
130- if cellIs(c, k): ne2(a, b) else: call(cellGet(c), @[a, b])130+ if cellIs(c, k): ne2(a, b) else: call(cellGet(c), [a, b])
131 131
132 proc inc1g*(c: VarCell, k: Value, a: Value): Value {.inline.} =132 proc inc1g*(c: VarCell, k: Value, a: Value): Value {.inline.} =
133- if cellIs(c, k): inc1(a) else: call(cellGet(c), @[a])133+ if cellIs(c, k): inc1(a) else: call(cellGet(c), [a])
134 134
135 proc dec1g*(c: VarCell, k: Value, a: Value): Value {.inline.} =135 proc dec1g*(c: VarCell, k: Value, a: Value): Value {.inline.} =
136- if cellIs(c, k): dec1(a) else: call(cellGet(c), @[a])136+ if cellIs(c, k): dec1(a) else: call(cellGet(c), [a])
137 137
138 proc getIn(coll, k, dflt: Value): Value =138 proc getIn(coll, k, dflt: Value): Value =
139 if coll.isNil or coll.kind == kNil: return dflt139 if coll.isNil or coll.kind == kNil: return dflt
@@ -206,7 +206,7 @@ proc lazyMap(f: Value, c: Cursor): Value =
206 var cc = cur206 var cc = cur
207 var xs = newSeqOfCap[Value](ChunkSize)207 var xs = newSeqOfCap[Value](ChunkSize)
208 while xs.len < ChunkSize and hasNext(cc):208 while xs.len < ChunkSize and hasNext(cc):
209- xs.add call(f, @[next(cc)])209+ xs.add call(f, [next(cc)])
210 if xs.len == 0: return NilV210 if xs.len == 0: return NilV
211 mkChunk(xs, 0, lazyMap(f, cc)))211 mkChunk(xs, 0, lazyMap(f, cc)))
212 212
@@ -226,7 +226,7 @@ proc lazyMapIndexed(f: Value, i: int64, c: Cursor): Value =
226 var cc = cur226 var cc = cur
227 if not hasNext(cc): return NilV227 if not hasNext(cc): return NilV
228 let x = next(cc)228 let x = next(cc)
229- mkCons(call(f, @[mkInt(i), x]), lazyMapIndexed(f, i + 1, cc)))229+ mkCons(call(f, [mkInt(i), x]), lazyMapIndexed(f, i + 1, cc)))
230 230
231 proc lazyFilter(pred: Value, c: Cursor, keep: bool): Value =231 proc lazyFilter(pred: Value, c: Cursor, keep: bool): Value =
232 ## Draws up to ChunkSize source elements per step and emits whichever pass,232 ## Draws up to ChunkSize source elements per step and emits whichever pass,
@@ -240,7 +240,7 @@ proc lazyFilter(pred: Value, c: Cursor, keep: bool): Value =
240 var drawn = 0240 var drawn = 0
241 while drawn < ChunkSize and hasNext(cc):241 while drawn < ChunkSize and hasNext(cc):
242 let x = next(cc)242 let x = next(cc)
243- if truthy(call(pred, @[x])) == keep: xs.add x243+ if truthy(call(pred, [x])) == keep: xs.add x
244 inc drawn244 inc drawn
245 if xs.len > 0: return mkChunk(xs, 0, lazyFilter(pred, cc, keep))245 if xs.len > 0: return mkChunk(xs, 0, lazyFilter(pred, cc, keep))
246 if drawn == 0: return NilV)246 if drawn == 0: return NilV)
@@ -270,7 +270,7 @@ proc lazyTakeWhile(pred: Value, c: Cursor): Value =
270 var cc = cur270 var cc = cur
271 if not hasNext(cc): return NilV271 if not hasNext(cc): return NilV
272 let x = next(cc)272 let x = next(cc)
273- if not truthy(call(pred, @[x])): return NilV273+ if not truthy(call(pred, [x])): return NilV
274 mkCons(x, lazyTakeWhile(pred, cc)))274 mkCons(x, lazyTakeWhile(pred, cc)))
275 275
276 proc lazyDropWhile(pred: Value, c: Cursor): Value =276 proc lazyDropWhile(pred: Value, c: Cursor): Value =
@@ -281,7 +281,7 @@ proc lazyDropWhile(pred: Value, c: Cursor): Value =
281 var peek = cc281 var peek = cc
282 if not hasNext(peek): return NilV282 if not hasNext(peek): return NilV
283 let x = next(peek)283 let x = next(peek)
284- if not truthy(call(pred, @[x])): return mkCons(x, lazyOf(peek))284+ if not truthy(call(pred, [x])): return mkCons(x, lazyOf(peek))
285 cc = peek)285 cc = peek)
286 286
287 proc lazyRange(i, hi, step: int64, bounded: bool): Value =287 proc lazyRange(i, hi, step: int64, bounded: bool): Value =
@@ -299,7 +299,7 @@ proc lazyRange(i, hi, step: int64, bounded: bool): Value =
299 mkChunk(xs, 0, lazyRange(cur, hi, step, bounded)))299 mkChunk(xs, 0, lazyRange(cur, hi, step, bounded)))
300 300
301 proc lazyIterate(f, x: Value): Value =301 proc lazyIterate(f, x: Value): Value =
302- mkLazy(proc (): Value = mkCons(x, lazyIterate(f, call(f, @[x]))))302+ mkLazy(proc (): Value = mkCons(x, lazyIterate(f, call(f, [x]))))
303 303
304 proc lazyRepeat(x: Value, n: int64, bounded: bool): Value =304 proc lazyRepeat(x: Value, n: int64, bounded: bool): Value =
305 mkLazy(proc (): Value =305 mkLazy(proc (): Value =
@@ -309,7 +309,7 @@ proc lazyRepeat(x: Value, n: int64, bounded: bool): Value =
309 proc lazyRepeatedly(f: Value, n: int64, bounded: bool): Value =309 proc lazyRepeatedly(f: Value, n: int64, bounded: bool): Value =
310 mkLazy(proc (): Value =310 mkLazy(proc (): Value =
311 if bounded and n <= 0: return NilV311 if bounded and n <= 0: return NilV
312- mkCons(call(f, @[]), lazyRepeatedly(f, n - 1, bounded)))312+ mkCons(call(f, []), lazyRepeatedly(f, n - 1, bounded)))
313 313
314 proc lazyCycle(orig: Value, c: Cursor): Value =314 proc lazyCycle(orig: Value, c: Cursor): Value =
315 let cur = c315 let cur = c
@@ -332,86 +332,86 @@ proc lazyConcat(colls: seq[Value], i: int, c: Cursor): Value =
332 let x = next(cc)332 let x = next(cc)
333 mkCons(x, lazyConcat(colls, k, cc)))333 mkCons(x, lazyConcat(colls, k, cc)))
334 334
335-proc def(name: string, f: proc (args: seq[Value]): Value {.closure.}) =335+proc def(name: string, f: proc (args: openArray[Value]): Value {.closure.}) =
336 setVar(name, mkFn(name, f))336 setVar(name, mkFn(name, f))
337 337
338 proc registerCore*() =338 proc registerCore*() =
339 # ---- arithmetic339 # ---- arithmetic
340- def "+", proc (a: seq[Value]): Value =340+ def "+", proc (a: openArray[Value]): Value =
341 arith("+", a, 0, proc (x, y: int64): int64 = x + y, proc (x, y: float64): float64 = x + y)341 arith("+", a, 0, proc (x, y: int64): int64 = x + y, proc (x, y: float64): float64 = x + y)
342- def "-", proc (a: seq[Value]): Value =342+ def "-", proc (a: openArray[Value]): Value =
343 arith("-", a, 0, proc (x, y: int64): int64 = x - y, proc (x, y: float64): float64 = x - y)343 arith("-", a, 0, proc (x, y: int64): int64 = x - y, proc (x, y: float64): float64 = x - y)
344- def "*", proc (a: seq[Value]): Value =344+ def "*", proc (a: openArray[Value]): Value =
345 arith("*", a, 1, proc (x, y: int64): int64 = x * y, proc (x, y: float64): float64 = x * y)345 arith("*", a, 1, proc (x, y: int64): int64 = x * y, proc (x, y: float64): float64 = x * y)
346- def "/", proc (a: seq[Value]): Value =346+ def "/", proc (a: openArray[Value]): Value =
347 if isFloaty(a) or a.len == 1:347 if isFloaty(a) or a.len == 1:
348 arith("/", a, 1, proc (x, y: int64): int64 = x div y, proc (x, y: float64): float64 = x / y)348 arith("/", a, 1, proc (x, y: int64): int64 = x div y, proc (x, y: float64): float64 = x / y)
349 else:349 else:
350 for i in 1 ..< a.len:350 for i in 1 ..< a.len:
351 if a[i].kind == kInt and a[i].i == 0: err("Divide by zero")351 if a[i].kind == kInt and a[i].i == 0: err("Divide by zero")
352 arith("/", a, 1, proc (x, y: int64): int64 = x div y, proc (x, y: float64): float64 = x / y)352 arith("/", a, 1, proc (x, y: int64): int64 = x div y, proc (x, y: float64): float64 = x / y)
353- def "quot", proc (a: seq[Value]): Value = mkInt(idiv(intOf(a[0]), intOf(a[1])))353+ def "quot", proc (a: openArray[Value]): Value = mkInt(idiv(intOf(a[0]), intOf(a[1])))
354- def "rem", proc (a: seq[Value]): Value = mkInt(irem(intOf(a[0]), intOf(a[1])))354+ def "rem", proc (a: openArray[Value]): Value = mkInt(irem(intOf(a[0]), intOf(a[1])))
355- def "mod", proc (a: seq[Value]): Value =355+ def "mod", proc (a: openArray[Value]): Value =
356 let x = intOf(a[0]); let y = intOf(a[1])356 let x = intOf(a[0]); let y = intOf(a[1])
357 var r = irem(x, y)357 var r = irem(x, y)
358 if r != 0 and ((r < 0) != (y < 0)): r += y358 if r != 0 and ((r < 0) != (y < 0)): r += y
359 mkInt(r)359 mkInt(r)
360- def "inc", proc (a: seq[Value]): Value =360+ def "inc", proc (a: openArray[Value]): Value =
361 (if a[0].kind == kFloat: mkFloat(a[0].f + 1.0) else: mkInt(a[0].i + 1))361 (if a[0].kind == kFloat: mkFloat(a[0].f + 1.0) else: mkInt(a[0].i + 1))
362- def "dec", proc (a: seq[Value]): Value =362+ def "dec", proc (a: openArray[Value]): Value =
363 (if a[0].kind == kFloat: mkFloat(a[0].f - 1.0) else: mkInt(a[0].i - 1))363 (if a[0].kind == kFloat: mkFloat(a[0].f - 1.0) else: mkInt(a[0].i - 1))
364- def "max", proc (a: seq[Value]): Value =364+ def "max", proc (a: openArray[Value]): Value =
365 result = a[0]365 result = a[0]
366 for x in a: (if num(x) > num(result): result = x)366 for x in a: (if num(x) > num(result): result = x)
367- def "min", proc (a: seq[Value]): Value =367+ def "min", proc (a: openArray[Value]): Value =
368 result = a[0]368 result = a[0]
369 for x in a: (if num(x) < num(result): result = x)369 for x in a: (if num(x) < num(result): result = x)
370- def "abs", proc (a: seq[Value]): Value =370+ def "abs", proc (a: openArray[Value]): Value =
371 (if a[0].kind == kFloat: mkFloat(abs(a[0].f)) else: mkInt(abs(a[0].i)))371 (if a[0].kind == kFloat: mkFloat(abs(a[0].f)) else: mkInt(abs(a[0].i)))
372- def "Math/sqrt", proc (a: seq[Value]): Value = mkFloat(sqrt(num(a[0])))372+ def "Math/sqrt", proc (a: openArray[Value]): Value = mkFloat(sqrt(num(a[0])))
373- def "Math/pow", proc (a: seq[Value]): Value = mkFloat(pow(num(a[0]), num(a[1])))373+ def "Math/pow", proc (a: openArray[Value]): Value = mkFloat(pow(num(a[0]), num(a[1])))
374- def "rand-int", proc (a: seq[Value]): Value = mkInt(rand(int(intOf(a[0])) - 1))374+ def "rand-int", proc (a: openArray[Value]): Value = mkInt(rand(int(intOf(a[0])) - 1))
375- def "double", proc (a: seq[Value]): Value = mkFloat(num(a[0]))375+ def "double", proc (a: openArray[Value]): Value = mkFloat(num(a[0]))
376- def "int", proc (a: seq[Value]): Value = mkInt(intOf(a[0]))376+ def "int", proc (a: openArray[Value]): Value = mkInt(intOf(a[0]))
377 377
378 # ---- comparison / predicates378 # ---- comparison / predicates
379- def "=", proc (a: seq[Value]): Value =379+ def "=", proc (a: openArray[Value]): Value =
380 for i in 0 ..< a.len - 1:380 for i in 0 ..< a.len - 1:
381 if not equals(a[i], a[i + 1]): return FalseV381 if not equals(a[i], a[i + 1]): return FalseV
382 TrueV382 TrueV
383- def "not=", proc (a: seq[Value]): Value =383+ def "not=", proc (a: openArray[Value]): Value =
384 for i in 0 ..< a.len - 1:384 for i in 0 ..< a.len - 1:
385 if not equals(a[i], a[i + 1]): return TrueV385 if not equals(a[i], a[i + 1]): return TrueV
386 FalseV386 FalseV
387- def "<", proc (a: seq[Value]): Value = cmpChain(a, proc (c: int): bool = c < 0)387+ def "<", proc (a: openArray[Value]): Value = cmpChain(a, proc (c: int): bool = c < 0)
388- def ">", proc (a: seq[Value]): Value = cmpChain(a, proc (c: int): bool = c > 0)388+ def ">", proc (a: openArray[Value]): Value = cmpChain(a, proc (c: int): bool = c > 0)
389- def "<=", proc (a: seq[Value]): Value = cmpChain(a, proc (c: int): bool = c <= 0)389+ def "<=", proc (a: openArray[Value]): Value = cmpChain(a, proc (c: int): bool = c <= 0)
390- def ">=", proc (a: seq[Value]): Value = cmpChain(a, proc (c: int): bool = c >= 0)390+ def ">=", proc (a: openArray[Value]): Value = cmpChain(a, proc (c: int): bool = c >= 0)
391- def "not", proc (a: seq[Value]): Value = mkBool(not truthy(a[0]))391+ def "not", proc (a: openArray[Value]): Value = mkBool(not truthy(a[0]))
392- def "nil?", proc (a: seq[Value]): Value = mkBool(a[0].isNil or a[0].kind == kNil)392+ def "nil?", proc (a: openArray[Value]): Value = mkBool(a[0].isNil or a[0].kind == kNil)
393- def "some?", proc (a: seq[Value]): Value = mkBool(not (a[0].isNil or a[0].kind == kNil))393+ def "some?", proc (a: openArray[Value]): Value = mkBool(not (a[0].isNil or a[0].kind == kNil))
394- def "true?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kBool and a[0].b)394+ def "true?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kBool and a[0].b)
395- def "false?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kBool and not a[0].b)395+ def "false?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kBool and not a[0].b)
396- def "zero?", proc (a: seq[Value]): Value = mkBool(num(a[0]) == 0.0)396+ def "zero?", proc (a: openArray[Value]): Value = mkBool(num(a[0]) == 0.0)
397- def "pos?", proc (a: seq[Value]): Value = mkBool(num(a[0]) > 0.0)397+ def "pos?", proc (a: openArray[Value]): Value = mkBool(num(a[0]) > 0.0)
398- def "neg?", proc (a: seq[Value]): Value = mkBool(num(a[0]) < 0.0)398+ def "neg?", proc (a: openArray[Value]): Value = mkBool(num(a[0]) < 0.0)
399- def "even?", proc (a: seq[Value]): Value = mkBool(intOf(a[0]) mod 2 == 0)399+ def "even?", proc (a: openArray[Value]): Value = mkBool(intOf(a[0]) mod 2 == 0)
400- def "odd?", proc (a: seq[Value]): Value = mkBool(intOf(a[0]) mod 2 != 0)400+ def "odd?", proc (a: openArray[Value]): Value = mkBool(intOf(a[0]) mod 2 != 0)
401- def "string?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kStr)401+ def "string?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kStr)
402- def "number?", proc (a: seq[Value]): Value = mkBool(a[0].kind in {kInt, kFloat})402+ def "number?", proc (a: openArray[Value]): Value = mkBool(a[0].kind in {kInt, kFloat})
403- def "int?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kInt)403+ def "int?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kInt)
404- def "keyword?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kKeyword)404+ def "keyword?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kKeyword)
405- def "symbol?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kSymbol)405+ def "symbol?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kSymbol)
406- def "vector?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kVector)406+ def "vector?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kVector)
407- def "list?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kList)407+ def "list?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kList)
408- def "map?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kMap)408+ def "map?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kMap)
409- def "set?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kSet)409+ def "set?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kSet)
410- def "coll?", proc (a: seq[Value]): Value =410+ def "coll?", proc (a: openArray[Value]): Value =
411 mkBool(a[0].kind in {kList, kVector, kMap, kSet})411 mkBool(a[0].kind in {kList, kVector, kMap, kSet})
412- def "fn?", proc (a: seq[Value]): Value = mkBool(a[0].kind == kFn)412+ def "fn?", proc (a: openArray[Value]): Value = mkBool(a[0].kind == kFn)
413- def "empty?", proc (a: seq[Value]): Value = mkBool(seqIsEmpty(a[0]))413+ def "empty?", proc (a: openArray[Value]): Value = mkBool(seqIsEmpty(a[0]))
414- def "contains?", proc (a: seq[Value]): Value =414+ def "contains?", proc (a: openArray[Value]): Value =
415 let c = a[0]415 let c = a[0]
416 if c.isNil or c.kind == kNil: return FalseV416 if c.isNil or c.kind == kNil: return FalseV
417 case c.kind417 case c.kind
@@ -421,97 +421,97 @@ proc registerCore*() =
421 else: FalseV421 else: FalseV
422 422
423 # ---- strings / IO423 # ---- strings / IO
424- def "str", proc (a: seq[Value]): Value =424+ def "str", proc (a: openArray[Value]): Value =
425 var s = ""425 var s = ""
426 for x in a: s &= str(x)426 for x in a: s &= str(x)
427 mkStr(s)427 mkStr(s)
428- def "pr-str", proc (a: seq[Value]): Value =428+ def "pr-str", proc (a: openArray[Value]): Value =
429 var parts: seq[string] = @[]429 var parts: seq[string] = @[]
430 for x in a: parts.add prStr(x)430 for x in a: parts.add prStr(x)
431 mkStr(parts.join(" "))431 mkStr(parts.join(" "))
432- def "println", proc (a: seq[Value]): Value =432+ def "println", proc (a: openArray[Value]): Value =
433 var parts: seq[string] = @[]433 var parts: seq[string] = @[]
434 for x in a: parts.add str(x)434 for x in a: parts.add str(x)
435 echo parts.join(" ")435 echo parts.join(" ")
436 NilV436 NilV
437- def "prn", proc (a: seq[Value]): Value =437+ def "prn", proc (a: openArray[Value]): Value =
438 var parts: seq[string] = @[]438 var parts: seq[string] = @[]
439 for x in a: parts.add prStr(x)439 for x in a: parts.add prStr(x)
440 echo parts.join(" ")440 echo parts.join(" ")
441 NilV441 NilV
442- def "print", proc (a: seq[Value]): Value =442+ def "print", proc (a: openArray[Value]): Value =
443 var parts: seq[string] = @[]443 var parts: seq[string] = @[]
444 for x in a: parts.add str(x)444 for x in a: parts.add str(x)
445 stdout.write parts.join(" ")445 stdout.write parts.join(" ")
446 NilV446 NilV
447- def "name", proc (a: seq[Value]): Value =447+ def "name", proc (a: openArray[Value]): Value =
448 case a[0].kind448 case a[0].kind
449 of kKeyword, kSymbol, kStr: mkStr(a[0].s)449 of kKeyword, kSymbol, kStr: mkStr(a[0].s)
450 else: err("name expects keyword/symbol/string")450 else: err("name expects keyword/symbol/string")
451- def "keyword", proc (a: seq[Value]): Value = mkKeyword(str(a[0]))451+ def "keyword", proc (a: openArray[Value]): Value = mkKeyword(str(a[0]))
452- def "symbol", proc (a: seq[Value]): Value = mkSymbol(str(a[0]))452+ def "symbol", proc (a: openArray[Value]): Value = mkSymbol(str(a[0]))
453- def "subs", proc (a: seq[Value]): Value =453+ def "subs", proc (a: openArray[Value]): Value =
454 let s = a[0].s454 let s = a[0].s
455 let st = int(intOf(a[1]))455 let st = int(intOf(a[1]))
456 let en = (if a.len > 2: int(intOf(a[2])) else: s.len)456 let en = (if a.len > 2: int(intOf(a[2])) else: s.len)
457 mkStr(s[st ..< en])457 mkStr(s[st ..< en])
458- def "clojure.string/upper-case", proc (a: seq[Value]): Value = mkStr(a[0].s.toUpperAscii)458+ def "clojure.string/upper-case", proc (a: openArray[Value]): Value = mkStr(a[0].s.toUpperAscii)
459- def "clojure.string/lower-case", proc (a: seq[Value]): Value = mkStr(a[0].s.toLowerAscii)459+ def "clojure.string/lower-case", proc (a: openArray[Value]): Value = mkStr(a[0].s.toLowerAscii)
460- def "clojure.string/trim", proc (a: seq[Value]): Value = mkStr(a[0].s.strip)460+ def "clojure.string/trim", proc (a: openArray[Value]): Value = mkStr(a[0].s.strip)
461- def "clojure.string/split", proc (a: seq[Value]): Value =461+ def "clojure.string/split", proc (a: openArray[Value]): Value =
462 var r: seq[Value] = @[]462 var r: seq[Value] = @[]
463 for piece in a[0].s.split(a[1].s): r.add mkStr(piece)463 for piece in a[0].s.split(a[1].s): r.add mkStr(piece)
464 mkVector(r)464 mkVector(r)
465- def "clojure.string/join", proc (a: seq[Value]): Value =465+ def "clojure.string/join", proc (a: openArray[Value]): Value =
466 let sep = (if a.len > 1: str(a[0]) else: "")466 let sep = (if a.len > 1: str(a[0]) else: "")
467 let coll = (if a.len > 1: a[1] else: a[0])467 let coll = (if a.len > 1: a[1] else: a[0])
468 var parts: seq[string] = @[]468 var parts: seq[string] = @[]
469 for x in elems(coll): parts.add str(x)469 for x in elems(coll): parts.add str(x)
470 mkStr(parts.join(sep))470 mkStr(parts.join(sep))
471- def "read-line", proc (a: seq[Value]): Value =471+ def "read-line", proc (a: openArray[Value]): Value =
472 try: mkStr(stdin.readLine()) except CatchableError: NilV472 try: mkStr(stdin.readLine()) except CatchableError: NilV
473- def "slurp", proc (a: seq[Value]): Value = mkStr(readFile(a[0].s))473+ def "slurp", proc (a: openArray[Value]): Value = mkStr(readFile(a[0].s))
474- def "spit", proc (a: seq[Value]): Value =474+ def "spit", proc (a: openArray[Value]): Value =
475 writeFile(a[0].s, str(a[1])); NilV475 writeFile(a[0].s, str(a[1])); NilV
476- def "now-ms", proc (a: seq[Value]): Value = mkInt(int64(epochTime() * 1000))476+ def "now-ms", proc (a: openArray[Value]): Value = mkInt(int64(epochTime() * 1000))
477 477
478 # ---- collections478 # ---- collections
479- def "list", proc (a: seq[Value]): Value = mkList(a)479+ def "list", proc (a: openArray[Value]): Value = mkList(a)
480- def "vector", proc (a: seq[Value]): Value = mkVector(a)480+ def "vector", proc (a: openArray[Value]): Value = mkVector(a)
481- def "hash-map", proc (a: seq[Value]): Value =481+ def "hash-map", proc (a: openArray[Value]): Value =
482 var m = emptyPMap()482 var m = emptyPMap()
483 var i = 0483 var i = 0
484 while i + 1 < a.len:484 while i + 1 < a.len:
485 m = mapAssoc(m, a[i], a[i + 1]); i += 2485 m = mapAssoc(m, a[i], a[i + 1]); i += 2
486 mkMapOf(m)486 mkMapOf(m)
487- def "hash-set", proc (a: seq[Value]): Value = mkSet(a)487+ def "hash-set", proc (a: openArray[Value]): Value = mkSet(a)
488- def "set", proc (a: seq[Value]): Value = mkSet(toSeq(a[0]))488+ def "set", proc (a: openArray[Value]): Value = mkSet(toSeq(a[0]))
489- def "vec", proc (a: seq[Value]): Value = mkVector(toSeq(a[0]))489+ def "vec", proc (a: openArray[Value]): Value = mkVector(toSeq(a[0]))
490- def "seq", proc (a: seq[Value]): Value =490+ def "seq", proc (a: openArray[Value]): Value =
491 # does not realize a lazy seq — just asks whether it has a first element491 # does not realize a lazy seq — just asks whether it has a first element
492 (if seqIsEmpty(a[0]): NilV else: a[0])492 (if seqIsEmpty(a[0]): NilV else: a[0])
493- def "count", proc (a: seq[Value]): Value =493+ def "count", proc (a: openArray[Value]): Value =
494 if a[0].isNil or a[0].kind == kNil: return mkInt(0)494 if a[0].isNil or a[0].kind == kNil: return mkInt(0)
495 mkInt(count(a[0]))495 mkInt(count(a[0]))
496- def "conj", proc (a: seq[Value]): Value =496+ def "conj", proc (a: openArray[Value]): Value =
497 result = a[0]497 result = a[0]
498 for i in 1 ..< a.len: result = conjOne(result, a[i])498 for i in 1 ..< a.len: result = conjOne(result, a[i])
499- def "cons", proc (a: seq[Value]): Value = mkCons(a[0], a[1])499+ def "cons", proc (a: openArray[Value]): Value = mkCons(a[0], a[1])
500- def "first", proc (a: seq[Value]): Value =500+ def "first", proc (a: openArray[Value]): Value =
501 if a[0].kind == kVector:501 if a[0].kind == kVector:
502 return (if a[0].vec.cnt == 0: NilV else: vecNth(a[0].vec, 0))502 return (if a[0].vec.cnt == 0: NilV else: vecNth(a[0].vec, 0))
503 seqFirst(a[0])503 seqFirst(a[0])
504- def "second", proc (a: seq[Value]): Value = seqFirst(seqRest(a[0]))504+ def "second", proc (a: openArray[Value]): Value = seqFirst(seqRest(a[0]))
505- def "last", proc (a: seq[Value]): Value =505+ def "last", proc (a: openArray[Value]): Value =
506 if a[0].kind == kVector:506 if a[0].kind == kVector:
507 return (if a[0].vec.cnt == 0: NilV else: vecNth(a[0].vec, a[0].vec.cnt - 1))507 return (if a[0].vec.cnt == 0: NilV else: vecNth(a[0].vec, a[0].vec.cnt - 1))
508 result = NilV508 result = NilV
509 for x in elems(a[0]): result = x509 for x in elems(a[0]): result = x
510- def "rest", proc (a: seq[Value]): Value = seqRest(a[0])510+ def "rest", proc (a: openArray[Value]): Value = seqRest(a[0])
511- def "next", proc (a: seq[Value]): Value =511+ def "next", proc (a: openArray[Value]): Value =
512 let r = seqRest(a[0])512 let r = seqRest(a[0])
513 (if seqIsEmpty(r): NilV else: r)513 (if seqIsEmpty(r): NilV else: r)
514- def "nth", proc (a: seq[Value]): Value =514+ def "nth", proc (a: openArray[Value]): Value =
515 let i = int(intOf(a[1]))515 let i = int(intOf(a[1]))
516 if a[0].kind == kVector:516 if a[0].kind == kVector:
517 # O(log32 n) straight through the trie, no intermediate seq517 # O(log32 n) straight through the trie, no intermediate seq
@@ -528,39 +528,39 @@ proc registerCore*() =
528 dec k528 dec k
529 if a.len > 2: a[2]529 if a.len > 2: a[2]
530 else: err("Index out of bounds: " & $i)530 else: err("Index out of bounds: " & $i)
531- def "get", proc (a: seq[Value]): Value =531+ def "get", proc (a: openArray[Value]): Value =
532 getIn(a[0], a[1], (if a.len > 2: a[2] else: NilV))532 getIn(a[0], a[1], (if a.len > 2: a[2] else: NilV))
533- def "get-in", proc (a: seq[Value]): Value =533+ def "get-in", proc (a: openArray[Value]): Value =
534 var cur = a[0]534 var cur = a[0]
535 for k in toSeq(a[1]):535 for k in toSeq(a[1]):
536 cur = getIn(cur, k, NilV)536 cur = getIn(cur, k, NilV)
537 (if (cur.isNil or cur.kind == kNil) and a.len > 2: a[2] else: cur)537 (if (cur.isNil or cur.kind == kNil) and a.len > 2: a[2] else: cur)
538- def "assoc", proc (a: seq[Value]): Value =538+ def "assoc", proc (a: openArray[Value]): Value =
539 result = a[0]539 result = a[0]
540 var i = 1540 var i = 1
541 while i + 1 < a.len:541 while i + 1 < a.len:
542 result = assocOne(result, a[i], a[i + 1]); i += 2542 result = assocOne(result, a[i], a[i + 1]); i += 2
543- def "dissoc", proc (a: seq[Value]): Value =543+ def "dissoc", proc (a: openArray[Value]): Value =
544 var m = a[0].m544 var m = a[0].m
545 for i in 1 ..< a.len: m = mapDissoc(m, a[i])545 for i in 1 ..< a.len: m = mapDissoc(m, a[i])
546 mkMapOf(m)546 mkMapOf(m)
547- def "update", proc (a: seq[Value]): Value =547+ def "update", proc (a: openArray[Value]): Value =
548 let cur = getIn(a[0], a[1], NilV)548 let cur = getIn(a[0], a[1], NilV)
549- assocOne(a[0], a[1], call(a[2], @[cur] & a[3 .. ^1]))549+ assocOne(a[0], a[1], call(a[2], @[cur] & @(a[3 .. ^1])))
550- def "keys", proc (a: seq[Value]): Value =550+ def "keys", proc (a: openArray[Value]): Value =
551 var r: seq[Value] = @[]551 var r: seq[Value] = @[]
552 for e in mapEntries(a[0].m): r.add e.key552 for e in mapEntries(a[0].m): r.add e.key
553 (if r.len == 0: NilV else: mkList(r))553 (if r.len == 0: NilV else: mkList(r))
554- def "vals", proc (a: seq[Value]): Value =554+ def "vals", proc (a: openArray[Value]): Value =
555 var r: seq[Value] = @[]555 var r: seq[Value] = @[]
556 for e in mapEntries(a[0].m): r.add e.val556 for e in mapEntries(a[0].m): r.add e.val
557 (if r.len == 0: NilV else: mkList(r))557 (if r.len == 0: NilV else: mkList(r))
558- def "reverse", proc (a: seq[Value]): Value =558+ def "reverse", proc (a: openArray[Value]): Value =
559 let s = toSeq(a[0])559 let s = toSeq(a[0])
560 var r: seq[Value] = @[]560 var r: seq[Value] = @[]
561 for i in countdown(s.len - 1, 0): r.add s[i]561 for i in countdown(s.len - 1, 0): r.add s[i]
562 mkList(r)562 mkList(r)
563- def "range", proc (a: seq[Value]): Value =563+ def "range", proc (a: openArray[Value]): Value =
564 var lo: int64 = 0564 var lo: int64 = 0
565 var hi: int64 = 0565 var hi: int64 = 0
566 var step: int64 = 1566 var step: int64 = 1
@@ -570,25 +570,25 @@ proc registerCore*() =
570 if a.len > 2: step = intOf(a[2])570 if a.len > 2: step = intOf(a[2])
571 # (range) with no bound is infinite; everything else stops at hi571 # (range) with no bound is infinite; everything else stops at hi
572 lazyRange(lo, hi, step, bounded = a.len > 0)572 lazyRange(lo, hi, step, bounded = a.len > 0)
573- def "take", proc (a: seq[Value]): Value =573+ def "take", proc (a: openArray[Value]): Value =
574 lazyTake(int(intOf(a[0])), cursor(a[1]))574 lazyTake(int(intOf(a[0])), cursor(a[1]))
575- def "drop", proc (a: seq[Value]): Value =575+ def "drop", proc (a: openArray[Value]): Value =
576 lazyDrop(int(intOf(a[0])), cursor(a[1]))576 lazyDrop(int(intOf(a[0])), cursor(a[1]))
577- def "concat", proc (a: seq[Value]): Value =577+ def "concat", proc (a: openArray[Value]): Value =
578- lazyConcat(a, 0, cursor(NilV))578+ lazyConcat(@a, 0, cursor(NilV))
579- def "iterate", proc (a: seq[Value]): Value = lazyIterate(a[0], a[1])579+ def "iterate", proc (a: openArray[Value]): Value = lazyIterate(a[0], a[1])
580- def "repeat", proc (a: seq[Value]): Value =580+ def "repeat", proc (a: openArray[Value]): Value =
581 (if a.len == 1: lazyRepeat(a[0], 0, bounded = false)581 (if a.len == 1: lazyRepeat(a[0], 0, bounded = false)
582 else: lazyRepeat(a[1], intOf(a[0]), bounded = true))582 else: lazyRepeat(a[1], intOf(a[0]), bounded = true))
583- def "repeatedly", proc (a: seq[Value]): Value =583+ def "repeatedly", proc (a: openArray[Value]): Value =
584 (if a.len == 1: lazyRepeatedly(a[0], 0, bounded = false)584 (if a.len == 1: lazyRepeatedly(a[0], 0, bounded = false)
585 else: lazyRepeatedly(a[1], intOf(a[0]), bounded = true))585 else: lazyRepeatedly(a[1], intOf(a[0]), bounded = true))
586- def "cycle", proc (a: seq[Value]): Value = lazyCycle(a[0], cursor(a[0]))586+ def "cycle", proc (a: openArray[Value]): Value = lazyCycle(a[0], cursor(a[0]))
587- def "doall", proc (a: seq[Value]): Value = mkList(toSeq(a[0]))587+ def "doall", proc (a: openArray[Value]): Value = mkList(toSeq(a[0]))
588- def "dorun", proc (a: seq[Value]): Value =588+ def "dorun", proc (a: openArray[Value]): Value =
589 for x in elems(a[0]): discard589 for x in elems(a[0]): discard
590 NilV590 NilV
591- def "sort", proc (a: seq[Value]): Value =591+ def "sort", proc (a: openArray[Value]): Value =
592 var s = toSeq(a[^1])592 var s = toSeq(a[^1])
593 let cmpFn = (if a.len > 1: a[0] else: NilV)593 let cmpFn = (if a.len > 1: a[0] else: NilV)
594 # insertion sort keeps it simple and stable594 # insertion sort keeps it simple and stable
@@ -596,25 +596,25 @@ proc registerCore*() =
596 var j = i596 var j = i
597 while j > 0:597 while j > 0:
598 let before =598 let before =
599- if cmpFn.kind == kFn: truthy(call(cmpFn, @[s[j], s[j - 1]]))599+ if cmpFn.kind == kFn: truthy(call(cmpFn, [s[j], s[j - 1]]))
600 elif s[j].kind == kStr: s[j].s < s[j - 1].s600 elif s[j].kind == kStr: s[j].s < s[j - 1].s
601 else: num(s[j]) < num(s[j - 1])601 else: num(s[j]) < num(s[j - 1])
602 if not before: break602 if not before: break
603 swap(s[j], s[j - 1]); dec j603 swap(s[j], s[j - 1]); dec j
604 mkList(s)604 mkList(s)
605- def "sort-by", proc (a: seq[Value]): Value =605+ def "sort-by", proc (a: openArray[Value]): Value =
606 var s = toSeq(a[^1])606 var s = toSeq(a[^1])
607 let kf = a[0]607 let kf = a[0]
608 for i in 1 ..< s.len:608 for i in 1 ..< s.len:
609 var j = i609 var j = i
610 while j > 0:610 while j > 0:
611- let ka = call(kf, @[s[j]])611+ let ka = call(kf, [s[j]])
612- let kb = call(kf, @[s[j - 1]])612+ let kb = call(kf, [s[j - 1]])
613 let before = (if ka.kind == kStr: ka.s < kb.s else: num(ka) < num(kb))613 let before = (if ka.kind == kStr: ka.s < kb.s else: num(ka) < num(kb))
614 if not before: break614 if not before: break
615 swap(s[j], s[j - 1]); dec j615 swap(s[j], s[j - 1]); dec j
616 mkList(s)616 mkList(s)
617- def "distinct", proc (a: seq[Value]): Value =617+ def "distinct", proc (a: openArray[Value]): Value =
618 var r: seq[Value] = @[]618 var r: seq[Value] = @[]
619 for x in elems(a[0]):619 for x in elems(a[0]):
620 var dup = false620 var dup = false
@@ -622,13 +622,13 @@ proc registerCore*() =
622 if equals(x, y): dup = true; break622 if equals(x, y): dup = true; break
623 if not dup: r.add x623 if not dup: r.add x
624 mkList(r)624 mkList(r)
625- def "interpose", proc (a: seq[Value]): Value =625+ def "interpose", proc (a: openArray[Value]): Value =
626 var r: seq[Value] = @[]626 var r: seq[Value] = @[]
627 for x in elems(a[1]):627 for x in elems(a[1]):
628 if r.len > 0: r.add a[0]628 if r.len > 0: r.add a[0]
629 r.add x629 r.add x
630 mkList(r)630 mkList(r)
631- def "partition", proc (a: seq[Value]): Value =631+ def "partition", proc (a: openArray[Value]): Value =
632 let n = int(intOf(a[0]))632 let n = int(intOf(a[0]))
633 let s = toSeq(a[^1])633 let s = toSeq(a[^1])
634 var r: seq[Value] = @[]634 var r: seq[Value] = @[]
@@ -638,27 +638,27 @@ proc registerCore*() =
638 mkList(r)638 mkList(r)
639 639
640 # ---- higher order640 # ---- higher order
641- def "apply", proc (a: seq[Value]): Value =641+ def "apply", proc (a: openArray[Value]): Value =
642 var callArgs: seq[Value] = @[]642 var callArgs: seq[Value] = @[]
643 for i in 1 ..< a.len - 1: callArgs.add a[i]643 for i in 1 ..< a.len - 1: callArgs.add a[i]
644 callArgs.add toSeq(a[^1])644 callArgs.add toSeq(a[^1])
645 call(a[0], callArgs)645 call(a[0], callArgs)
646- def "map", proc (a: seq[Value]): Value =646+ def "map", proc (a: openArray[Value]): Value =
647 if a.len == 2: return lazyMap(a[0], cursor(a[1]))647 if a.len == 2: return lazyMap(a[0], cursor(a[1]))
648 var cs: seq[Cursor] = @[]648 var cs: seq[Cursor] = @[]
649 for i in 1 ..< a.len: cs.add cursor(a[i])649 for i in 1 ..< a.len: cs.add cursor(a[i])
650 lazyMapN(a[0], cs)650 lazyMapN(a[0], cs)
651- def "mapv", proc (a: seq[Value]): Value =651+ def "mapv", proc (a: openArray[Value]): Value =
652 var r: seq[Value] = @[]652 var r: seq[Value] = @[]
653- for x in elems(a[1]): r.add call(a[0], @[x])653+ for x in elems(a[1]): r.add call(a[0], [x])
654 mkVector(r)654 mkVector(r)
655- def "map-indexed", proc (a: seq[Value]): Value =655+ def "map-indexed", proc (a: openArray[Value]): Value =
656 lazyMapIndexed(a[0], 0, cursor(a[1]))656 lazyMapIndexed(a[0], 0, cursor(a[1]))
657- def "filter", proc (a: seq[Value]): Value =657+ def "filter", proc (a: openArray[Value]): Value =
658 lazyFilter(a[0], cursor(a[1]), keep = true)658 lazyFilter(a[0], cursor(a[1]), keep = true)
659- def "remove", proc (a: seq[Value]): Value =659+ def "remove", proc (a: openArray[Value]): Value =
660 lazyFilter(a[0], cursor(a[1]), keep = false)660 lazyFilter(a[0], cursor(a[1]), keep = false)
661- def "reduce", proc (a: seq[Value]): Value =661+ def "reduce", proc (a: openArray[Value]): Value =
662 ## Streams the source rather than materializing it, so folding a lazy seq662 ## Streams the source rather than materializing it, so folding a lazy seq
663 ## holds one chunk at a time instead of the whole sequence.663 ## holds one chunk at a time instead of the whole sequence.
664 let f = a[0]664 let f = a[0]
@@ -667,74 +667,74 @@ proc registerCore*() =
667 var first = true667 var first = true
668 for x in elems(a[1]):668 for x in elems(a[1]):
669 if first: acc = x; first = false669 if first: acc = x; first = false
670- else: acc = call(f, @[acc, x])670+ else: acc = call(f, [acc, x])
671- if first: return call(f, @[])671+ if first: return call(f, [])
672 return acc672 return acc
673 var acc = a[1]673 var acc = a[1]
674- for x in elems(a[2]): acc = call(f, @[acc, x])674+ for x in elems(a[2]): acc = call(f, [acc, x])
675 acc675 acc
676- def "some", proc (a: seq[Value]): Value =676+ def "some", proc (a: openArray[Value]): Value =
677 for x in elems(a[1]):677 for x in elems(a[1]):
678- let r = call(a[0], @[x])678+ let r = call(a[0], [x])
679 if truthy(r): return r679 if truthy(r): return r
680 NilV680 NilV
681- def "every?", proc (a: seq[Value]): Value =681+ def "every?", proc (a: openArray[Value]): Value =
682 for x in elems(a[1]):682 for x in elems(a[1]):
683- if not truthy(call(a[0], @[x])): return FalseV683+ if not truthy(call(a[0], [x])): return FalseV
684 TrueV684 TrueV
685- def "take-while", proc (a: seq[Value]): Value =685+ def "take-while", proc (a: openArray[Value]): Value =
686 lazyTakeWhile(a[0], cursor(a[1]))686 lazyTakeWhile(a[0], cursor(a[1]))
687- def "drop-while", proc (a: seq[Value]): Value =687+ def "drop-while", proc (a: openArray[Value]): Value =
688 lazyDropWhile(a[0], cursor(a[1]))688 lazyDropWhile(a[0], cursor(a[1]))
689- def "group-by", proc (a: seq[Value]): Value =689+ def "group-by", proc (a: openArray[Value]): Value =
690 var m = emptyPMap()690 var m = emptyPMap()
691 for x in elems(a[1]):691 for x in elems(a[1]):
692- let k = call(a[0], @[x])692+ let k = call(a[0], [x])
693 m = mapAssoc(m, k, conjOne(mapGet(m, k, mkVector(@[])), x))693 m = mapAssoc(m, k, conjOne(mapGet(m, k, mkVector(@[])), x))
694 mkMapOf(m)694 mkMapOf(m)
695- def "frequencies", proc (a: seq[Value]): Value =695+ def "frequencies", proc (a: openArray[Value]): Value =
696 var m = emptyPMap()696 var m = emptyPMap()
697 for x in elems(a[0]):697 for x in elems(a[0]):
698 m = mapAssoc(m, x, mkInt(mapGet(m, x, mkInt(0)).i + 1))698 m = mapAssoc(m, x, mkInt(mapGet(m, x, mkInt(0)).i + 1))
699 mkMapOf(m)699 mkMapOf(m)
700- def "identity", proc (a: seq[Value]): Value = a[0]700+ def "identity", proc (a: openArray[Value]): Value = a[0]
701- def "comp", proc (a: seq[Value]): Value =701+ def "comp", proc (a: openArray[Value]): Value =
702- let fs = a702+ let fs = @a
703- mkFn("comp", proc (args: seq[Value]): Value =703+ mkFn("comp", proc (args: openArray[Value]): Value =
704 if fs.len == 0: return argAt(args, 0)704 if fs.len == 0: return argAt(args, 0)
705 var v = call(fs[^1], args)705 var v = call(fs[^1], args)
706- for i in countdown(fs.len - 2, 0): v = call(fs[i], @[v])706+ for i in countdown(fs.len - 2, 0): v = call(fs[i], [v])
707 v)707 v)
708- def "partial", proc (a: seq[Value]): Value =708+ def "partial", proc (a: openArray[Value]): Value =
709 let f = a[0]709 let f = a[0]
710 let bound = a[1 .. ^1]710 let bound = a[1 .. ^1]
711- mkFn("partial", proc (args: seq[Value]): Value = call(f, bound & args))711+ mkFn("partial", proc (args: openArray[Value]): Value = call(f, bound & @args))
712- def "juxt", proc (a: seq[Value]): Value =712+ def "juxt", proc (a: openArray[Value]): Value =
713- let fs = a713+ let fs = @a
714- mkFn("juxt", proc (args: seq[Value]): Value =714+ mkFn("juxt", proc (args: openArray[Value]): Value =
715 var r: seq[Value] = @[]715 var r: seq[Value] = @[]
716 for f in fs: r.add call(f, args)716 for f in fs: r.add call(f, args)
717 mkVector(r))717 mkVector(r))
718- def "constantly", proc (a: seq[Value]): Value =718+ def "constantly", proc (a: openArray[Value]): Value =
719 let v = a[0]719 let v = a[0]
720- mkFn("constantly", proc (args: seq[Value]): Value = v)720+ mkFn("constantly", proc (args: openArray[Value]): Value = v)
721 721
722 # ---- atoms (mutable boxes, modelled as a 1-slot vector)722 # ---- atoms (mutable boxes, modelled as a 1-slot vector)
723- def "atom", proc (a: seq[Value]): Value =723+ def "atom", proc (a: openArray[Value]): Value =
724 var cell = a[0]724 var cell = a[0]
725- mkFn("atom", proc (args: seq[Value]): Value =725+ mkFn("atom", proc (args: openArray[Value]): Value =
726 # (a) -> deref726 # (a) -> deref
727 # (a :set v) -> reset727 # (a :set v) -> reset
728 if args.len == 0: return cell728 if args.len == 0: return cell
729 cell = args[1]729 cell = args[1]
730 cell)730 cell)
731- def "deref", proc (a: seq[Value]): Value = call(a[0], @[])731+ def "deref", proc (a: openArray[Value]): Value = call(a[0], [])
732- def "reset!", proc (a: seq[Value]): Value = call(a[0], @[mkKeyword("set"), a[1]])732+ def "reset!", proc (a: openArray[Value]): Value = call(a[0], [mkKeyword("set"), a[1]])
733- def "swap!", proc (a: seq[Value]): Value =733+ def "swap!", proc (a: openArray[Value]): Value =
734- let cur = call(a[0], @[])734+ let cur = call(a[0], [])
735- let nv = call(a[1], @[cur] & a[2 .. ^1])735+ let nv = call(a[1], @[cur] & @(a[2 .. ^1]))
736- call(a[0], @[mkKeyword("set"), nv])736+ call(a[0], [mkKeyword("set"), nv])
737-737+
738- def "throw", proc (a: seq[Value]): Value = err(str(a[0]))738+ def "throw", proc (a: openArray[Value]): Value = err(str(a[0]))
739- def "ex-info", proc (a: seq[Value]): Value = mkStr(str(a[0]))739+ def "ex-info", proc (a: openArray[Value]): Value = mkStr(str(a[0]))
740- def "time-ms", proc (a: seq[Value]): Value = mkInt(int64(epochTime() * 1000))740+ def "time-ms", proc (a: openArray[Value]): Value = mkInt(int64(epochTime() * 1000))
modified src/runtime.nim +14 -8
@@ -81,7 +81,7 @@ type
8181 cached*: Value
8282 forced*: bool
8383 of kFn:
84- fn*: proc (args: seq[Value]): Value {.closure.}
84+ fn*: proc (args: openArray[Value]): Value {.closure.}
8585 name*: string
8686
8787 CljError* = object of CatchableError
@@ -404,7 +404,13 @@ proc mkSet*(xs: seq[Value]): Value =
404404 if not mapContains(m, x): m = mapAssoc(m, x, x)
405405 Value(kind: kSet, m: m)
406406
407-proc mkFn*(name: string, f: proc (args: seq[Value]): Value {.closure.}): Value =
407+# openArray overloads, so a builtin can pass its argument list straight through
408+# without first copying it into a seq.
409+proc mkList*(xs: openArray[Value]): Value = mkList(@xs)
410+proc mkVector*(xs: openArray[Value]): Value = mkVector(@xs)
411+proc mkSet*(xs: openArray[Value]): Value = mkSet(@xs)
412+
413+proc mkFn*(name: string, f: proc (args: openArray[Value]): Value {.closure.}): Value =
408414 Value(kind: kFn, fn: f, name: name)
409415
410416 # --------------------------------------------------------------- lazy seqs
@@ -737,7 +743,7 @@ proc hasVar*(name: string): bool =
737743 globals.hasKey(name) and globals[name].bound
738744
739745 # ---------------------------------------------------------------- calling
740-proc call*(f: Value, args: seq[Value]): Value =
746+proc call*(f: Value, args: openArray[Value]): Value =
741747 if f.isNil: err("Can't call nil")
742748 case f.kind
743749 of kFn: f.fn(args)
@@ -755,14 +761,14 @@ proc call*(f: Value, args: seq[Value]): Value =
755761 vecNth(f.vec, int(args[0].i))
756762 else: err("Can't call value of kind " & $f.kind & ": " & prStr(f))
757763
758-proc argAt*(args: seq[Value], i: int): Value =
764+proc argAt*(args: openArray[Value], i: int): Value =
759765 if i < args.len: args[i] else: NilV
760766
761-proc restArgs*(args: seq[Value], i: int): Value =
767+proc restArgs*(args: openArray[Value], i: int): Value =
762768 if i >= args.len: return NilV
763- mkList(args[i .. ^1])
769+ mkList(@(args[i .. ^1]))
764770
765-proc arity*(name: string, args: seq[Value], n: int) =
771+proc arity*(name: string, args: openArray[Value], n: int) =
766772 if args.len != n:
767773 err("Wrong number of args (" & $args.len & ") passed to " & name)
768774
@@ -782,7 +788,7 @@ proc toSeq*(v: Value): seq[Value] =
782788 r
783789 else: err("Don't know how to create seq from: " & prStr(v))
784790
785-let emptyArgs*: seq[Value] = @[]
791+let emptyArgs*: array[0, Value] = []
786792
787793 ## True while a var still holds the exact fn a call site was compiled against.
788794 ## Call sites that bind a known-arity fn or an inlined primitive directly guard
@@ -81,7 +81,7 @@ type
81 cached*: Value81 cached*: Value
82 forced*: bool82 forced*: bool
83 of kFn:83 of kFn:
84- fn*: proc (args: seq[Value]): Value {.closure.}84+ fn*: proc (args: openArray[Value]): Value {.closure.}
85 name*: string85 name*: string
86 86
87 CljError* = object of CatchableError87 CljError* = object of CatchableError
@@ -404,7 +404,13 @@ proc mkSet*(xs: seq[Value]): Value =
404 if not mapContains(m, x): m = mapAssoc(m, x, x)404 if not mapContains(m, x): m = mapAssoc(m, x, x)
405 Value(kind: kSet, m: m)405 Value(kind: kSet, m: m)
406 406
407-proc mkFn*(name: string, f: proc (args: seq[Value]): Value {.closure.}): Value =407+# openArray overloads, so a builtin can pass its argument list straight through
408+# without first copying it into a seq.
409+proc mkList*(xs: openArray[Value]): Value = mkList(@xs)
410+proc mkVector*(xs: openArray[Value]): Value = mkVector(@xs)
411+proc mkSet*(xs: openArray[Value]): Value = mkSet(@xs)
412+
413+proc mkFn*(name: string, f: proc (args: openArray[Value]): Value {.closure.}): Value =
408 Value(kind: kFn, fn: f, name: name)414 Value(kind: kFn, fn: f, name: name)
409 415
410 # --------------------------------------------------------------- lazy seqs416 # --------------------------------------------------------------- lazy seqs
@@ -737,7 +743,7 @@ proc hasVar*(name: string): bool =
737 globals.hasKey(name) and globals[name].bound743 globals.hasKey(name) and globals[name].bound
738 744
739 # ---------------------------------------------------------------- calling745 # ---------------------------------------------------------------- calling
740-proc call*(f: Value, args: seq[Value]): Value =746+proc call*(f: Value, args: openArray[Value]): Value =
741 if f.isNil: err("Can't call nil")747 if f.isNil: err("Can't call nil")
742 case f.kind748 case f.kind
743 of kFn: f.fn(args)749 of kFn: f.fn(args)
@@ -755,14 +761,14 @@ proc call*(f: Value, args: seq[Value]): Value =
755 vecNth(f.vec, int(args[0].i))761 vecNth(f.vec, int(args[0].i))
756 else: err("Can't call value of kind " & $f.kind & ": " & prStr(f))762 else: err("Can't call value of kind " & $f.kind & ": " & prStr(f))
757 763
758-proc argAt*(args: seq[Value], i: int): Value =764+proc argAt*(args: openArray[Value], i: int): Value =
759 if i < args.len: args[i] else: NilV765 if i < args.len: args[i] else: NilV
760 766
761-proc restArgs*(args: seq[Value], i: int): Value =767+proc restArgs*(args: openArray[Value], i: int): Value =
762 if i >= args.len: return NilV768 if i >= args.len: return NilV
763- mkList(args[i .. ^1])769+ mkList(@(args[i .. ^1]))
764 770
765-proc arity*(name: string, args: seq[Value], n: int) =771+proc arity*(name: string, args: openArray[Value], n: int) =
766 if args.len != n:772 if args.len != n:
767 err("Wrong number of args (" & $args.len & ") passed to " & name)773 err("Wrong number of args (" & $args.len & ") passed to " & name)
768 774
@@ -782,7 +788,7 @@ proc toSeq*(v: Value): seq[Value] =
782 r788 r
783 else: err("Don't know how to create seq from: " & prStr(v))789 else: err("Don't know how to create seq from: " & prStr(v))
784 790
785-let emptyArgs*: seq[Value] = @[]791+let emptyArgs*: array[0, Value] = []
786 792
787 ## True while a var still holds the exact fn a call site was compiled against.793 ## True while a var still holds the exact fn a call site was compiled against.
788 ## Call sites that bind a known-arity fn or an inlined primitive directly guard794 ## Call sites that bind a known-arity fn or an inlined primitive directly guard