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>
a6f57fd parent: 75fc33e modified
src/compiler.nim +8 -8 | @@ -406,7 +406,7 @@ proc genFn(name: string, clauses: seq[FnClause], selfIdent: string, env: Env, | ||
| 406 | 406 | if boxes: directEnv.intFnBoxes.incl key |
| 407 | 407 | |
| 408 | 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 | 410 | c.push |
| 411 | 411 | var first = true |
| 412 | 412 | for ci, cl in clauses: |
| @@ -495,7 +495,7 @@ proc genLet(bindings: Value, body: seq[Value], dst: string, env: Env, c: Ctx) = | ||
| 495 | 495 | lenv.locals[restSym] = id |
| 496 | 496 | break |
| 497 | 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 | 499 | $idx & "), NilV])") |
| 500 | 500 | lenv.locals[symName(p)] = id |
| 501 | 501 | inc idx; inc j |
| @@ -506,14 +506,14 @@ proc genLet(bindings: Value, body: seq[Value], dst: string, env: Env, c: Ctx) = | ||
| 506 | 506 | for ks in valForm.items: |
| 507 | 507 | let nm = symName(ks) |
| 508 | 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 | 510 | ", mkKeyword(" & nimStr(nm) & ")])") |
| 511 | 511 | lenv.locals[nm] = id |
| 512 | 512 | else: |
| 513 | 513 | let nm = symName(k) |
| 514 | 514 | let id = c.gensym("l" & mangle(nm)) |
| 515 | 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 | 517 | lenv.locals[nm] = id |
| 518 | 518 | else: |
| 519 | 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 | 602 | c.line("else:") |
| 603 | 603 | c.push |
| 604 | 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 | 606 | c.pop |
| 607 | 607 | return |
| 608 | 608 | let key = f.s & "/" & $args.len |
| @@ -623,7 +623,7 @@ proc genCall(f: Value, args: seq[Value], dst: string, env: Env, c: Ctx) = | ||
| 623 | 623 | c.pop |
| 624 | 624 | c.line("else:") |
| 625 | 625 | c.push |
| 626 | - c.line(dst & " = call(cellGet(" & cell & "), @[" & argIdents.join(", ") & "])") | |
| 626 | + c.line(dst & " = call(cellGet(" & cell & "), [" & argIdents.join(", ") & "])") | |
| 627 | 627 | c.pop |
| 628 | 628 | return |
| 629 | 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 | 632 | if argIdents.len == 0: |
| 633 | 633 | c.line(dst & " = call(" & fv & ", emptyArgs)") |
| 634 | 634 | else: |
| 635 | - c.line(dst & " = call(" & fv & ", @[" & argIdents.join(", ") & "])") | |
| 635 | + c.line(dst & " = call(" & fv & ", [" & argIdents.join(", ") & "])") | |
| 636 | 636 | |
| 637 | 637 | ## ------------------------------------------------------- int specialisation |
| 638 | 638 | ## |
| @@ -774,7 +774,7 @@ proc tryExpr(f: Value, env: Env, c: Ctx): string = | ||
| 774 | 774 | let hv = tryExpr(head, env, c) |
| 775 | 775 | if hv.len == 0: return "" |
| 776 | 776 | "call(" & hv & ", " & |
| 777 | - (if ids.len == 0: "emptyArgs" else: "@[" & ids.join(", ") & "]") & ")" | |
| 777 | + (if ids.len == 0: "emptyArgs" else: "[" & ids.join(", ") & "]") & ")" | |
| 778 | 778 | of kFn, kCons, kChunk, kLazy: |
| 779 | 779 | "" |
| 780 | 780 | |
| @@ -406,7 +406,7 @@ proc genFn(name: string, clauses: seq[FnClause], selfIdent: string, env: Env, | |||
| 406 | if boxes: directEnv.intFnBoxes.incl key | 406 | 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.push | 410 | c.push |
| 411 | var first = true | 411 | 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] = id | 495 | lenv.locals[restSym] = id |
| 496 | break | 496 | 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)] = id | 500 | lenv.locals[symName(p)] = id |
| 501 | inc idx; inc j | 501 | 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] = id | 511 | 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] = id | 517 | 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.push | 603 | 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.pop | 606 | c.pop |
| 607 | return | 607 | return |
| 608 | let key = f.s & "/" & $args.len | 608 | 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.pop | 623 | c.pop |
| 624 | c.line("else:") | 624 | c.line("else:") |
| 625 | c.push | 625 | c.push |
| 626 | - c.line(dst & " = call(cellGet(" & cell & "), @[" & argIdents.join(", ") & "])") | 626 | + c.line(dst & " = call(cellGet(" & cell & "), [" & argIdents.join(", ") & "])") |
| 627 | c.pop | 627 | c.pop |
| 628 | return | 628 | 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 specialisation | 637 | ## ------------------------------------------------------- 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 = | ||
| 8 | 8 | of kFloat: v.f |
| 9 | 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 | 12 | for v in vs: |
| 13 | 13 | if v.kind == kFloat: return true |
| 14 | 14 | false |
| @@ -19,7 +19,7 @@ proc intOf(v: Value): int64 = | ||
| 19 | 19 | of kFloat: int64(v.f) |
| 20 | 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 | 23 | fi: proc (a, b: int64): int64, ff: proc (a, b: float64): float64): Value = |
| 24 | 24 | if args.len == 0: return mkInt(unit) |
| 25 | 25 | if isFloaty(args): |
| @@ -32,7 +32,7 @@ proc arith(name: string, args: seq[Value], unit: int64, | ||
| 32 | 32 | for i in start ..< args.len: acc = fi(acc, args[i].i) |
| 33 | 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 | 36 | for i in 0 ..< args.len - 1: |
| 37 | 37 | let a = num(args[i]) |
| 38 | 38 | let b = num(args[i + 1]) |
| @@ -103,37 +103,37 @@ proc dec1*(a: Value): Value {.inline.} = | ||
| 103 | 103 | ## Guarded forms: the whole call site, cell check included, as one expression, |
| 104 | 104 | ## for the call sites where a def in the program can still rebind the name. |
| 105 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 138 | proc getIn(coll, k, dflt: Value): Value = |
| 139 | 139 | if coll.isNil or coll.kind == kNil: return dflt |
| @@ -206,7 +206,7 @@ proc lazyMap(f: Value, c: Cursor): Value = | ||
| 206 | 206 | var cc = cur |
| 207 | 207 | var xs = newSeqOfCap[Value](ChunkSize) |
| 208 | 208 | while xs.len < ChunkSize and hasNext(cc): |
| 209 | - xs.add call(f, @[next(cc)]) | |
| 209 | + xs.add call(f, [next(cc)]) | |
| 210 | 210 | if xs.len == 0: return NilV |
| 211 | 211 | mkChunk(xs, 0, lazyMap(f, cc))) |
| 212 | 212 | |
| @@ -226,7 +226,7 @@ proc lazyMapIndexed(f: Value, i: int64, c: Cursor): Value = | ||
| 226 | 226 | var cc = cur |
| 227 | 227 | if not hasNext(cc): return NilV |
| 228 | 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 | 231 | proc lazyFilter(pred: Value, c: Cursor, keep: bool): Value = |
| 232 | 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 | 240 | var drawn = 0 |
| 241 | 241 | while drawn < ChunkSize and hasNext(cc): |
| 242 | 242 | let x = next(cc) |
| 243 | - if truthy(call(pred, @[x])) == keep: xs.add x | |
| 243 | + if truthy(call(pred, [x])) == keep: xs.add x | |
| 244 | 244 | inc drawn |
| 245 | 245 | if xs.len > 0: return mkChunk(xs, 0, lazyFilter(pred, cc, keep)) |
| 246 | 246 | if drawn == 0: return NilV) |
| @@ -270,7 +270,7 @@ proc lazyTakeWhile(pred: Value, c: Cursor): Value = | ||
| 270 | 270 | var cc = cur |
| 271 | 271 | if not hasNext(cc): return NilV |
| 272 | 272 | let x = next(cc) |
| 273 | - if not truthy(call(pred, @[x])): return NilV | |
| 273 | + if not truthy(call(pred, [x])): return NilV | |
| 274 | 274 | mkCons(x, lazyTakeWhile(pred, cc))) |
| 275 | 275 | |
| 276 | 276 | proc lazyDropWhile(pred: Value, c: Cursor): Value = |
| @@ -281,7 +281,7 @@ proc lazyDropWhile(pred: Value, c: Cursor): Value = | ||
| 281 | 281 | var peek = cc |
| 282 | 282 | if not hasNext(peek): return NilV |
| 283 | 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 | 285 | cc = peek) |
| 286 | 286 | |
| 287 | 287 | proc lazyRange(i, hi, step: int64, bounded: bool): Value = |
| @@ -299,7 +299,7 @@ proc lazyRange(i, hi, step: int64, bounded: bool): Value = | ||
| 299 | 299 | mkChunk(xs, 0, lazyRange(cur, hi, step, bounded))) |
| 300 | 300 | |
| 301 | 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 | 304 | proc lazyRepeat(x: Value, n: int64, bounded: bool): Value = |
| 305 | 305 | mkLazy(proc (): Value = |
| @@ -309,7 +309,7 @@ proc lazyRepeat(x: Value, n: int64, bounded: bool): Value = | ||
| 309 | 309 | proc lazyRepeatedly(f: Value, n: int64, bounded: bool): Value = |
| 310 | 310 | mkLazy(proc (): Value = |
| 311 | 311 | 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 | 314 | proc lazyCycle(orig: Value, c: Cursor): Value = |
| 315 | 315 | let cur = c |
| @@ -332,86 +332,86 @@ proc lazyConcat(colls: seq[Value], i: int, c: Cursor): Value = | ||
| 332 | 332 | let x = next(cc) |
| 333 | 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 | 336 | setVar(name, mkFn(name, f)) |
| 337 | 337 | |
| 338 | 338 | proc registerCore*() = |
| 339 | 339 | # ---- arithmetic |
| 340 | - def "+", proc (a: seq[Value]): Value = | |
| 340 | + def "+", proc (a: openArray[Value]): Value = | |
| 341 | 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 | 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 | 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 | 347 | if isFloaty(a) or a.len == 1: |
| 348 | 348 | arith("/", a, 1, proc (x, y: int64): int64 = x div y, proc (x, y: float64): float64 = x / y) |
| 349 | 349 | else: |
| 350 | 350 | for i in 1 ..< a.len: |
| 351 | 351 | if a[i].kind == kInt and a[i].i == 0: err("Divide by zero") |
| 352 | 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]))) | |
| 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 = | |
| 356 | 356 | let x = intOf(a[0]); let y = intOf(a[1]) |
| 357 | 357 | var r = irem(x, y) |
| 358 | 358 | if r != 0 and ((r < 0) != (y < 0)): r += y |
| 359 | 359 | mkInt(r) |
| 360 | - def "inc", proc (a: seq[Value]): Value = | |
| 360 | + def "inc", proc (a: openArray[Value]): Value = | |
| 361 | 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 | 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 | 365 | result = a[0] |
| 366 | 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 | 368 | result = a[0] |
| 369 | 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 | 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]))) | |
| 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])) | |
| 377 | 377 | |
| 378 | 378 | # ---- comparison / predicates |
| 379 | - def "=", proc (a: seq[Value]): Value = | |
| 379 | + def "=", proc (a: openArray[Value]): Value = | |
| 380 | 380 | for i in 0 ..< a.len - 1: |
| 381 | 381 | if not equals(a[i], a[i + 1]): return FalseV |
| 382 | 382 | TrueV |
| 383 | - def "not=", proc (a: seq[Value]): Value = | |
| 383 | + def "not=", proc (a: openArray[Value]): Value = | |
| 384 | 384 | for i in 0 ..< a.len - 1: |
| 385 | 385 | if not equals(a[i], a[i + 1]): return TrueV |
| 386 | 386 | 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 = | |
| 411 | 411 | 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 = | |
| 415 | 415 | let c = a[0] |
| 416 | 416 | if c.isNil or c.kind == kNil: return FalseV |
| 417 | 417 | case c.kind |
| @@ -421,97 +421,97 @@ proc registerCore*() = | ||
| 421 | 421 | else: FalseV |
| 422 | 422 | |
| 423 | 423 | # ---- strings / IO |
| 424 | - def "str", proc (a: seq[Value]): Value = | |
| 424 | + def "str", proc (a: openArray[Value]): Value = | |
| 425 | 425 | var s = "" |
| 426 | 426 | for x in a: s &= str(x) |
| 427 | 427 | mkStr(s) |
| 428 | - def "pr-str", proc (a: seq[Value]): Value = | |
| 428 | + def "pr-str", proc (a: openArray[Value]): Value = | |
| 429 | 429 | var parts: seq[string] = @[] |
| 430 | 430 | for x in a: parts.add prStr(x) |
| 431 | 431 | mkStr(parts.join(" ")) |
| 432 | - def "println", proc (a: seq[Value]): Value = | |
| 432 | + def "println", proc (a: openArray[Value]): Value = | |
| 433 | 433 | var parts: seq[string] = @[] |
| 434 | 434 | for x in a: parts.add str(x) |
| 435 | 435 | echo parts.join(" ") |
| 436 | 436 | NilV |
| 437 | - def "prn", proc (a: seq[Value]): Value = | |
| 437 | + def "prn", proc (a: openArray[Value]): Value = | |
| 438 | 438 | var parts: seq[string] = @[] |
| 439 | 439 | for x in a: parts.add prStr(x) |
| 440 | 440 | echo parts.join(" ") |
| 441 | 441 | NilV |
| 442 | - def "print", proc (a: seq[Value]): Value = | |
| 442 | + def "print", proc (a: openArray[Value]): Value = | |
| 443 | 443 | var parts: seq[string] = @[] |
| 444 | 444 | for x in a: parts.add str(x) |
| 445 | 445 | stdout.write parts.join(" ") |
| 446 | 446 | NilV |
| 447 | - def "name", proc (a: seq[Value]): Value = | |
| 447 | + def "name", proc (a: openArray[Value]): Value = | |
| 448 | 448 | case a[0].kind |
| 449 | 449 | of kKeyword, kSymbol, kStr: mkStr(a[0].s) |
| 450 | 450 | 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 = | |
| 454 | 454 | let s = a[0].s |
| 455 | 455 | let st = int(intOf(a[1])) |
| 456 | 456 | let en = (if a.len > 2: int(intOf(a[2])) else: s.len) |
| 457 | 457 | 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 = | |
| 462 | 462 | var r: seq[Value] = @[] |
| 463 | 463 | for piece in a[0].s.split(a[1].s): r.add mkStr(piece) |
| 464 | 464 | mkVector(r) |
| 465 | - def "clojure.string/join", proc (a: seq[Value]): Value = | |
| 465 | + def "clojure.string/join", proc (a: openArray[Value]): Value = | |
| 466 | 466 | let sep = (if a.len > 1: str(a[0]) else: "") |
| 467 | 467 | let coll = (if a.len > 1: a[1] else: a[0]) |
| 468 | 468 | var parts: seq[string] = @[] |
| 469 | 469 | for x in elems(coll): parts.add str(x) |
| 470 | 470 | mkStr(parts.join(sep)) |
| 471 | - def "read-line", proc (a: seq[Value]): Value = | |
| 471 | + def "read-line", proc (a: openArray[Value]): Value = | |
| 472 | 472 | 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 = | |
| 475 | 475 | 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 | 478 | # ---- 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 = | |
| 482 | 482 | var m = emptyPMap() |
| 483 | 483 | var i = 0 |
| 484 | 484 | while i + 1 < a.len: |
| 485 | 485 | m = mapAssoc(m, a[i], a[i + 1]); i += 2 |
| 486 | 486 | 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 = | |
| 491 | 491 | # does not realize a lazy seq — just asks whether it has a first element |
| 492 | 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 | 494 | if a[0].isNil or a[0].kind == kNil: return mkInt(0) |
| 495 | 495 | mkInt(count(a[0])) |
| 496 | - def "conj", proc (a: seq[Value]): Value = | |
| 496 | + def "conj", proc (a: openArray[Value]): Value = | |
| 497 | 497 | result = a[0] |
| 498 | 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]) | |
| 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 = | |
| 501 | 501 | if a[0].kind == kVector: |
| 502 | 502 | return (if a[0].vec.cnt == 0: NilV else: vecNth(a[0].vec, 0)) |
| 503 | 503 | 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 = | |
| 506 | 506 | if a[0].kind == kVector: |
| 507 | 507 | return (if a[0].vec.cnt == 0: NilV else: vecNth(a[0].vec, a[0].vec.cnt - 1)) |
| 508 | 508 | result = NilV |
| 509 | 509 | 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 = | |
| 512 | 512 | let r = seqRest(a[0]) |
| 513 | 513 | (if seqIsEmpty(r): NilV else: r) |
| 514 | - def "nth", proc (a: seq[Value]): Value = | |
| 514 | + def "nth", proc (a: openArray[Value]): Value = | |
| 515 | 515 | let i = int(intOf(a[1])) |
| 516 | 516 | if a[0].kind == kVector: |
| 517 | 517 | # O(log32 n) straight through the trie, no intermediate seq |
| @@ -528,39 +528,39 @@ proc registerCore*() = | ||
| 528 | 528 | dec k |
| 529 | 529 | if a.len > 2: a[2] |
| 530 | 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 | 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 | 534 | var cur = a[0] |
| 535 | 535 | for k in toSeq(a[1]): |
| 536 | 536 | cur = getIn(cur, k, NilV) |
| 537 | 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 | 539 | result = a[0] |
| 540 | 540 | var i = 1 |
| 541 | 541 | while i + 1 < a.len: |
| 542 | 542 | 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 | 544 | var m = a[0].m |
| 545 | 545 | for i in 1 ..< a.len: m = mapDissoc(m, a[i]) |
| 546 | 546 | mkMapOf(m) |
| 547 | - def "update", proc (a: seq[Value]): Value = | |
| 547 | + def "update", proc (a: openArray[Value]): Value = | |
| 548 | 548 | 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 = | |
| 551 | 551 | var r: seq[Value] = @[] |
| 552 | 552 | for e in mapEntries(a[0].m): r.add e.key |
| 553 | 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 | 555 | var r: seq[Value] = @[] |
| 556 | 556 | for e in mapEntries(a[0].m): r.add e.val |
| 557 | 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 | 559 | let s = toSeq(a[0]) |
| 560 | 560 | var r: seq[Value] = @[] |
| 561 | 561 | for i in countdown(s.len - 1, 0): r.add s[i] |
| 562 | 562 | mkList(r) |
| 563 | - def "range", proc (a: seq[Value]): Value = | |
| 563 | + def "range", proc (a: openArray[Value]): Value = | |
| 564 | 564 | var lo: int64 = 0 |
| 565 | 565 | var hi: int64 = 0 |
| 566 | 566 | var step: int64 = 1 |
| @@ -570,25 +570,25 @@ proc registerCore*() = | ||
| 570 | 570 | if a.len > 2: step = intOf(a[2]) |
| 571 | 571 | # (range) with no bound is infinite; everything else stops at hi |
| 572 | 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 | 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 | 576 | 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 = | |
| 581 | 581 | (if a.len == 1: lazyRepeat(a[0], 0, bounded = false) |
| 582 | 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 | 584 | (if a.len == 1: lazyRepeatedly(a[0], 0, bounded = false) |
| 585 | 585 | 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 = | |
| 589 | 589 | for x in elems(a[0]): discard |
| 590 | 590 | NilV |
| 591 | - def "sort", proc (a: seq[Value]): Value = | |
| 591 | + def "sort", proc (a: openArray[Value]): Value = | |
| 592 | 592 | var s = toSeq(a[^1]) |
| 593 | 593 | let cmpFn = (if a.len > 1: a[0] else: NilV) |
| 594 | 594 | # insertion sort keeps it simple and stable |
| @@ -596,25 +596,25 @@ proc registerCore*() = | ||
| 596 | 596 | var j = i |
| 597 | 597 | while j > 0: |
| 598 | 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 | 600 | elif s[j].kind == kStr: s[j].s < s[j - 1].s |
| 601 | 601 | else: num(s[j]) < num(s[j - 1]) |
| 602 | 602 | if not before: break |
| 603 | 603 | swap(s[j], s[j - 1]); dec j |
| 604 | 604 | mkList(s) |
| 605 | - def "sort-by", proc (a: seq[Value]): Value = | |
| 605 | + def "sort-by", proc (a: openArray[Value]): Value = | |
| 606 | 606 | var s = toSeq(a[^1]) |
| 607 | 607 | let kf = a[0] |
| 608 | 608 | for i in 1 ..< s.len: |
| 609 | 609 | var j = i |
| 610 | 610 | 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]]) | |
| 613 | 613 | let before = (if ka.kind == kStr: ka.s < kb.s else: num(ka) < num(kb)) |
| 614 | 614 | if not before: break |
| 615 | 615 | swap(s[j], s[j - 1]); dec j |
| 616 | 616 | mkList(s) |
| 617 | - def "distinct", proc (a: seq[Value]): Value = | |
| 617 | + def "distinct", proc (a: openArray[Value]): Value = | |
| 618 | 618 | var r: seq[Value] = @[] |
| 619 | 619 | for x in elems(a[0]): |
| 620 | 620 | var dup = false |
| @@ -622,13 +622,13 @@ proc registerCore*() = | ||
| 622 | 622 | if equals(x, y): dup = true; break |
| 623 | 623 | if not dup: r.add x |
| 624 | 624 | mkList(r) |
| 625 | - def "interpose", proc (a: seq[Value]): Value = | |
| 625 | + def "interpose", proc (a: openArray[Value]): Value = | |
| 626 | 626 | var r: seq[Value] = @[] |
| 627 | 627 | for x in elems(a[1]): |
| 628 | 628 | if r.len > 0: r.add a[0] |
| 629 | 629 | r.add x |
| 630 | 630 | mkList(r) |
| 631 | - def "partition", proc (a: seq[Value]): Value = | |
| 631 | + def "partition", proc (a: openArray[Value]): Value = | |
| 632 | 632 | let n = int(intOf(a[0])) |
| 633 | 633 | let s = toSeq(a[^1]) |
| 634 | 634 | var r: seq[Value] = @[] |
| @@ -638,27 +638,27 @@ proc registerCore*() = | ||
| 638 | 638 | mkList(r) |
| 639 | 639 | |
| 640 | 640 | # ---- higher order |
| 641 | - def "apply", proc (a: seq[Value]): Value = | |
| 641 | + def "apply", proc (a: openArray[Value]): Value = | |
| 642 | 642 | var callArgs: seq[Value] = @[] |
| 643 | 643 | for i in 1 ..< a.len - 1: callArgs.add a[i] |
| 644 | 644 | callArgs.add toSeq(a[^1]) |
| 645 | 645 | call(a[0], callArgs) |
| 646 | - def "map", proc (a: seq[Value]): Value = | |
| 646 | + def "map", proc (a: openArray[Value]): Value = | |
| 647 | 647 | if a.len == 2: return lazyMap(a[0], cursor(a[1])) |
| 648 | 648 | var cs: seq[Cursor] = @[] |
| 649 | 649 | for i in 1 ..< a.len: cs.add cursor(a[i]) |
| 650 | 650 | lazyMapN(a[0], cs) |
| 651 | - def "mapv", proc (a: seq[Value]): Value = | |
| 651 | + def "mapv", proc (a: openArray[Value]): Value = | |
| 652 | 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 | 654 | mkVector(r) |
| 655 | - def "map-indexed", proc (a: seq[Value]): Value = | |
| 655 | + def "map-indexed", proc (a: openArray[Value]): Value = | |
| 656 | 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 | 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 | 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 | 662 | ## Streams the source rather than materializing it, so folding a lazy seq |
| 663 | 663 | ## holds one chunk at a time instead of the whole sequence. |
| 664 | 664 | let f = a[0] |
| @@ -667,74 +667,74 @@ proc registerCore*() = | ||
| 667 | 667 | var first = true |
| 668 | 668 | for x in elems(a[1]): |
| 669 | 669 | 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, []) | |
| 672 | 672 | return acc |
| 673 | 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 | 675 | acc |
| 676 | - def "some", proc (a: seq[Value]): Value = | |
| 676 | + def "some", proc (a: openArray[Value]): Value = | |
| 677 | 677 | for x in elems(a[1]): |
| 678 | - let r = call(a[0], @[x]) | |
| 678 | + let r = call(a[0], [x]) | |
| 679 | 679 | if truthy(r): return r |
| 680 | 680 | NilV |
| 681 | - def "every?", proc (a: seq[Value]): Value = | |
| 681 | + def "every?", proc (a: openArray[Value]): Value = | |
| 682 | 682 | 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 | |
| 684 | 684 | TrueV |
| 685 | - def "take-while", proc (a: seq[Value]): Value = | |
| 685 | + def "take-while", proc (a: openArray[Value]): Value = | |
| 686 | 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 | 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 | 690 | var m = emptyPMap() |
| 691 | 691 | for x in elems(a[1]): |
| 692 | - let k = call(a[0], @[x]) | |
| 692 | + let k = call(a[0], [x]) | |
| 693 | 693 | m = mapAssoc(m, k, conjOne(mapGet(m, k, mkVector(@[])), x)) |
| 694 | 694 | mkMapOf(m) |
| 695 | - def "frequencies", proc (a: seq[Value]): Value = | |
| 695 | + def "frequencies", proc (a: openArray[Value]): Value = | |
| 696 | 696 | var m = emptyPMap() |
| 697 | 697 | for x in elems(a[0]): |
| 698 | 698 | m = mapAssoc(m, x, mkInt(mapGet(m, x, mkInt(0)).i + 1)) |
| 699 | 699 | 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 = | |
| 704 | 704 | if fs.len == 0: return argAt(args, 0) |
| 705 | 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 | 707 | v) |
| 708 | - def "partial", proc (a: seq[Value]): Value = | |
| 708 | + def "partial", proc (a: openArray[Value]): Value = | |
| 709 | 709 | let f = a[0] |
| 710 | 710 | 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 = | |
| 715 | 715 | var r: seq[Value] = @[] |
| 716 | 716 | for f in fs: r.add call(f, args) |
| 717 | 717 | mkVector(r)) |
| 718 | - def "constantly", proc (a: seq[Value]): Value = | |
| 718 | + def "constantly", proc (a: openArray[Value]): Value = | |
| 719 | 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 | 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 | 724 | var cell = a[0] |
| 725 | - mkFn("atom", proc (args: seq[Value]): Value = | |
| 725 | + mkFn("atom", proc (args: openArray[Value]): Value = | |
| 726 | 726 | # (a) -> deref |
| 727 | 727 | # (a :set v) -> reset |
| 728 | 728 | if args.len == 0: return cell |
| 729 | 729 | cell = args[1] |
| 730 | 730 | 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.f | 8 | 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 true | 13 | if v.kind == kFloat: return true |
| 14 | false | 14 | 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 dflt | 139 | if coll.isNil or coll.kind == kNil: return dflt |
| @@ -206,7 +206,7 @@ proc lazyMap(f: Value, c: Cursor): Value = | |||
| 206 | var cc = cur | 206 | 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 NilV | 210 | 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 = cur | 226 | var cc = cur |
| 227 | if not hasNext(cc): return NilV | 227 | 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 = 0 | 240 | 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 x | 243 | + if truthy(call(pred, [x])) == keep: xs.add x |
| 244 | inc drawn | 244 | 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 = cur | 270 | var cc = cur |
| 271 | if not hasNext(cc): return NilV | 271 | if not hasNext(cc): return NilV |
| 272 | let x = next(cc) | 272 | let x = next(cc) |
| 273 | - if not truthy(call(pred, @[x])): return NilV | 273 | + 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 = cc | 281 | var peek = cc |
| 282 | if not hasNext(peek): return NilV | 282 | 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 NilV | 311 | 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 = c | 315 | 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 | # ---- arithmetic | 339 | # ---- 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 += y | 358 | 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 / predicates | 378 | # ---- 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 FalseV | 381 | if not equals(a[i], a[i + 1]): return FalseV |
| 382 | TrueV | 382 | 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 TrueV | 385 | if not equals(a[i], a[i + 1]): return TrueV |
| 386 | FalseV | 386 | 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 FalseV | 416 | if c.isNil or c.kind == kNil: return FalseV |
| 417 | case c.kind | 417 | case c.kind |
| @@ -421,97 +421,97 @@ proc registerCore*() = | |||
| 421 | else: FalseV | 421 | else: FalseV |
| 422 | 422 | ||
| 423 | # ---- strings / IO | 423 | # ---- 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 | NilV | 436 | 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 | NilV | 441 | 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 | NilV | 446 | NilV |
| 447 | - def "name", proc (a: seq[Value]): Value = | 447 | + def "name", proc (a: openArray[Value]): Value = |
| 448 | case a[0].kind | 448 | 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].s | 454 | 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: NilV | 472 | 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])); NilV | 475 | 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 | # ---- collections | 478 | # ---- 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 = 0 | 483 | 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 += 2 | 485 | 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 element | 491 | # 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 = NilV | 508 | result = NilV |
| 509 | for x in elems(a[0]): result = x | 509 | 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 seq | 517 | # O(log32 n) straight through the trie, no intermediate seq |
| @@ -528,39 +528,39 @@ proc registerCore*() = | |||
| 528 | dec k | 528 | 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 = 1 | 540 | 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 += 2 | 542 | 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].m | 544 | 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.key | 552 | 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.val | 556 | 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 = 0 | 564 | var lo: int64 = 0 |
| 565 | var hi: int64 = 0 | 565 | var hi: int64 = 0 |
| 566 | var step: int64 = 1 | 566 | 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 hi | 571 | # (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]): discard | 589 | for x in elems(a[0]): discard |
| 590 | NilV | 590 | 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 stable | 594 | # insertion sort keeps it simple and stable |
| @@ -596,25 +596,25 @@ proc registerCore*() = | |||
| 596 | var j = i | 596 | 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].s | 600 | 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: break | 602 | if not before: break |
| 603 | swap(s[j], s[j - 1]); dec j | 603 | 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 = i | 609 | 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: break | 614 | if not before: break |
| 615 | swap(s[j], s[j - 1]); dec j | 615 | 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 = false | 620 | var dup = false |
| @@ -622,13 +622,13 @@ proc registerCore*() = | |||
| 622 | if equals(x, y): dup = true; break | 622 | if equals(x, y): dup = true; break |
| 623 | if not dup: r.add x | 623 | 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 x | 629 | 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 order | 640 | # ---- 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 seq | 662 | ## 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 = true | 667 | var first = true |
| 668 | for x in elems(a[1]): | 668 | for x in elems(a[1]): |
| 669 | if first: acc = x; first = false | 669 | 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 acc | 672 | 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 | acc | 675 | 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 r | 679 | if truthy(r): return r |
| 680 | NilV | 680 | 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 FalseV | 683 | + if not truthy(call(a[0], [x])): return FalseV |
| 684 | TrueV | 684 | 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 = a | 702 | + 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 = a | 713 | + 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) -> deref | 726 | # (a) -> deref |
| 727 | # (a :set v) -> reset | 727 | # (a :set v) -> reset |
| 728 | if args.len == 0: return cell | 728 | 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 | ||
| 81 | 81 | cached*: Value |
| 82 | 82 | forced*: bool |
| 83 | 83 | of kFn: |
| 84 | - fn*: proc (args: seq[Value]): Value {.closure.} | |
| 84 | + fn*: proc (args: openArray[Value]): Value {.closure.} | |
| 85 | 85 | name*: string |
| 86 | 86 | |
| 87 | 87 | CljError* = object of CatchableError |
| @@ -404,7 +404,13 @@ proc mkSet*(xs: seq[Value]): Value = | ||
| 404 | 404 | if not mapContains(m, x): m = mapAssoc(m, x, x) |
| 405 | 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 | 414 | Value(kind: kFn, fn: f, name: name) |
| 409 | 415 | |
| 410 | 416 | # --------------------------------------------------------------- lazy seqs |
| @@ -737,7 +743,7 @@ proc hasVar*(name: string): bool = | ||
| 737 | 743 | globals.hasKey(name) and globals[name].bound |
| 738 | 744 | |
| 739 | 745 | # ---------------------------------------------------------------- calling |
| 740 | -proc call*(f: Value, args: seq[Value]): Value = | |
| 746 | +proc call*(f: Value, args: openArray[Value]): Value = | |
| 741 | 747 | if f.isNil: err("Can't call nil") |
| 742 | 748 | case f.kind |
| 743 | 749 | of kFn: f.fn(args) |
| @@ -755,14 +761,14 @@ proc call*(f: Value, args: seq[Value]): Value = | ||
| 755 | 761 | vecNth(f.vec, int(args[0].i)) |
| 756 | 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 | 765 | 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 | 768 | 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 | 772 | if args.len != n: |
| 767 | 773 | err("Wrong number of args (" & $args.len & ") passed to " & name) |
| 768 | 774 | |
| @@ -782,7 +788,7 @@ proc toSeq*(v: Value): seq[Value] = | ||
| 782 | 788 | r |
| 783 | 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 | 793 | ## True while a var still holds the exact fn a call site was compiled against. |
| 788 | 794 | ## Call sites that bind a known-arity fn or an inlined primitive directly guard |
| @@ -81,7 +81,7 @@ type | |||
| 81 | cached*: Value | 81 | cached*: Value |
| 82 | forced*: bool | 82 | 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*: string | 85 | name*: string |
| 86 | 86 | ||
| 87 | CljError* = object of CatchableError | 87 | 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 seqs | 416 | # --------------------------------------------------------------- lazy seqs |
| @@ -737,7 +743,7 @@ proc hasVar*(name: string): bool = | |||
| 737 | globals.hasKey(name) and globals[name].bound | 743 | globals.hasKey(name) and globals[name].bound |
| 738 | 744 | ||
| 739 | # ---------------------------------------------------------------- calling | 745 | # ---------------------------------------------------------------- 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.kind | 748 | 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: NilV | 765 | 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 NilV | 768 | 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 | r | 788 | 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 guard | 794 | ## Call sites that bind a known-arity fn or an inlined primitive directly guard |