conjure-js 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist-cli/conjure-js.mjs +9360 -5298
  2. package/dist-vite-plugin/index.mjs +9463 -5185
  3. package/package.json +3 -1
  4. package/src/bin/cli.ts +2 -2
  5. package/src/bin/nrepl-symbol.ts +150 -0
  6. package/src/bin/nrepl.ts +289 -167
  7. package/src/bin/version.ts +1 -1
  8. package/src/clojure/core.clj +757 -29
  9. package/src/clojure/core.clj.d.ts +75 -131
  10. package/src/clojure/generated/builtin-namespace-registry.ts +4 -0
  11. package/src/clojure/generated/clojure-core-source.ts +758 -29
  12. package/src/clojure/generated/clojure-set-source.ts +136 -0
  13. package/src/clojure/generated/clojure-walk-source.ts +72 -0
  14. package/src/clojure/set.clj +132 -0
  15. package/src/clojure/set.clj.d.ts +20 -0
  16. package/src/clojure/string.clj.d.ts +14 -0
  17. package/src/clojure/walk.clj +68 -0
  18. package/src/clojure/walk.clj.d.ts +7 -0
  19. package/src/core/assertions.ts +114 -6
  20. package/src/core/bootstrap.ts +337 -0
  21. package/src/core/conversions.ts +48 -31
  22. package/src/core/core-module.ts +303 -0
  23. package/src/core/env.ts +20 -6
  24. package/src/core/evaluator/apply.ts +40 -25
  25. package/src/core/evaluator/arity.ts +8 -8
  26. package/src/core/evaluator/async-evaluator.ts +565 -0
  27. package/src/core/evaluator/collections.ts +28 -5
  28. package/src/core/evaluator/destructure.ts +180 -69
  29. package/src/core/evaluator/dispatch.ts +12 -14
  30. package/src/core/evaluator/evaluate.ts +22 -20
  31. package/src/core/evaluator/expand.ts +45 -15
  32. package/src/core/evaluator/form-parsers.ts +178 -0
  33. package/src/core/evaluator/index.ts +7 -9
  34. package/src/core/evaluator/js-interop.ts +189 -0
  35. package/src/core/evaluator/quasiquote.ts +14 -8
  36. package/src/core/evaluator/recur-check.ts +6 -6
  37. package/src/core/evaluator/special-forms.ts +234 -191
  38. package/src/core/factories.ts +182 -3
  39. package/src/core/index.ts +54 -4
  40. package/src/core/module.ts +136 -0
  41. package/src/core/ns-forms.ts +107 -0
  42. package/src/core/printer.ts +371 -11
  43. package/src/core/reader.ts +84 -33
  44. package/src/core/registry.ts +209 -0
  45. package/src/core/runtime.ts +376 -0
  46. package/src/core/session.ts +253 -487
  47. package/src/core/stdlib/arithmetic.ts +528 -194
  48. package/src/core/stdlib/async-fns.ts +132 -0
  49. package/src/core/stdlib/atoms.ts +291 -56
  50. package/src/core/stdlib/errors.ts +54 -50
  51. package/src/core/stdlib/hof.ts +82 -166
  52. package/src/core/stdlib/js-namespace.ts +344 -0
  53. package/src/core/stdlib/lazy.ts +34 -0
  54. package/src/core/stdlib/maps-sets.ts +322 -0
  55. package/src/core/stdlib/meta.ts +61 -30
  56. package/src/core/stdlib/predicates.ts +325 -187
  57. package/src/core/stdlib/regex.ts +126 -98
  58. package/src/core/stdlib/seq.ts +564 -0
  59. package/src/core/stdlib/strings.ts +164 -135
  60. package/src/core/stdlib/transducers.ts +95 -100
  61. package/src/core/stdlib/utils.ts +292 -130
  62. package/src/core/stdlib/vars.ts +27 -27
  63. package/src/core/stdlib/vectors.ts +122 -0
  64. package/src/core/tokenizer.ts +2 -2
  65. package/src/core/transformations.ts +117 -9
  66. package/src/core/types.ts +98 -2
  67. package/src/host/node-host-module.ts +74 -0
  68. package/src/{vite-plugin-clj/nrepl-relay.ts → nrepl/relay.ts} +72 -11
  69. package/src/vite-plugin-clj/codegen.ts +87 -95
  70. package/src/vite-plugin-clj/index.ts +178 -23
  71. package/src/vite-plugin-clj/namespace-utils.ts +39 -0
  72. package/src/vite-plugin-clj/static-analysis.ts +211 -0
  73. package/src/clojure/demo.clj +0 -72
  74. package/src/clojure/demo.clj.d.ts +0 -0
  75. package/src/core/core-env.ts +0 -61
  76. package/src/core/stdlib/collections.ts +0 -739
  77. package/src/host/node.ts +0 -55
@@ -0,0 +1,303 @@
1
+ import type {
2
+ RuntimeModule,
3
+ VarDeclaration,
4
+ VarMap,
5
+ ModuleContext,
6
+ } from './module'
7
+ import { buildPrintContext, prettyPrintString, printString, withPrintContext } from './printer'
8
+ import { derefValue } from './env'
9
+ import { valueToString } from './transformations'
10
+ import type { CljMap, CljValue, Env, EvaluationContext } from './types'
11
+ import { arithmeticFunctions } from './stdlib/arithmetic'
12
+ import { atomFunctions } from './stdlib/atoms'
13
+ import { mapsSetsFunctions } from './stdlib/maps-sets'
14
+ import { seqFunctions } from './stdlib/seq'
15
+ import { vectorFunctions } from './stdlib/vectors'
16
+ import { errorFunctions } from './stdlib/errors'
17
+ import { hofFunctions } from './stdlib/hof'
18
+ import { metaFunctions } from './stdlib/meta'
19
+ import { predicateFunctions } from './stdlib/predicates'
20
+ import { regexFunctions } from './stdlib/regex'
21
+ import { stringFunctions } from './stdlib/strings'
22
+ import { transducerFunctions } from './stdlib/transducers'
23
+ import { utilFunctions } from './stdlib/utils'
24
+ import { lazyFunctions } from './stdlib/lazy'
25
+ import { varFunctions } from './stdlib/vars'
26
+ // --- ASYNC (experimental) ---
27
+ import { asyncFunctions } from './stdlib/async-fns'
28
+ import { v } from './factories'
29
+ import { is } from './assertions'
30
+ import { EvaluationError } from './errors'
31
+ import { cljToJs as cljToJsDeep, jsToClj as jsToCljDeep, type FunctionApplier } from './conversions'
32
+ // --- END ASYNC ---
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Native function registry — installed as the initial clojure.core binding
36
+ // set by createRuntime.
37
+ //
38
+ // INTENTIONAL BOOTSTRAP OVERRIDES:
39
+ // Several functions below are redefined by clojure.core.clj after bootstrap.
40
+ // They serve as scaffolding during the bootstrap phase only. The Clojure
41
+ // source versions (lazy / transducer-aware) become authoritative once loaded.
42
+ // Overridden by clojure.core.clj:
43
+ // concat → lazy recursive version (shadows eager native)
44
+ // map → lazy + transducer 2-arity
45
+ // filter → lazy + transducer 2-arity
46
+ // take → lazy + stateful transducer
47
+ // drop → lazy + stateful transducer
48
+ // take-while → lazy + stateless transducer
49
+ // drop-while → lazy + stateful transducer
50
+ // map-indexed → lazy + stateful transducer
51
+ // keep → lazy + transducer
52
+ // keep-indexed→ lazy + stateful transducer
53
+ // mapcat → lazy + transducer
54
+ // partition-by→ lazy + stateful transducer
55
+ // iterate → lazy infinite sequence
56
+ // repeatedly → lazy infinite sequence
57
+ // cycle → lazy infinite sequence
58
+ // repeat → lazy infinite (delegates to repeat* for finite arity)
59
+ // range → lazy infinite (delegates to range* for finite arity)
60
+ // into → 2-arity uses reduce+conj; 3-arity uses transduce
61
+ // sequence → materialise via into
62
+ // completing → 0-arity init + 1-arity completion wrapper
63
+ // newline → redefined as (defn newline [] (println ""))
64
+ // not → redefined as pure Clojure (if x false true)
65
+ // dorun → redefined in Clojure
66
+ // doall → redefined in Clojure
67
+ //
68
+ // Dynamic vars declared here (NOT overridden by clojure.core.clj):
69
+ // *out* → nil by default; bound by with-out-str to capture stdout
70
+ // *err* → nil by default; bound by with-err-str to capture stderr
71
+ // *print-length*, *print-level* → print control
72
+ //
73
+ // range* and repeat* are intentionally kept — clojure.core.clj calls them
74
+ // explicitly as private native helpers for finite-arity range/repeat.
75
+ // ---------------------------------------------------------------------------
76
+
77
+ const nativeFunctions = {
78
+ ...arithmeticFunctions,
79
+ ...atomFunctions,
80
+ ...seqFunctions,
81
+ ...vectorFunctions,
82
+ ...mapsSetsFunctions,
83
+ ...errorFunctions,
84
+ ...predicateFunctions,
85
+ ...hofFunctions,
86
+ ...metaFunctions,
87
+ ...transducerFunctions,
88
+ ...regexFunctions,
89
+ ...stringFunctions,
90
+ ...utilFunctions,
91
+ ...varFunctions,
92
+ ...lazyFunctions,
93
+ // --- ASYNC (experimental) ---
94
+ ...asyncFunctions,
95
+ // --- END ASYNC ---
96
+ }
97
+
98
+
99
+ /**
100
+ * Emit text to the current output channel.
101
+ * If *out* is dynamically bound to a callable (e.g. inside with-out-str),
102
+ * invoke it. Otherwise fall back to ctx.io.stdout.
103
+ *
104
+ * NOTE: We look up *out* via ctx.resolveNs('clojure.core') rather than
105
+ * tryLookup(callEnv) because Clojure functions close over the original
106
+ * snapshot env. After a snapshot restore, those closure envs point to the
107
+ * old CljVar objects, not the session's freshly cloned ones. resolveNs goes
108
+ * through the runtime registry and always returns the session's own var.
109
+ */
110
+ function emitToOut(ctx: EvaluationContext, callEnv: Env, text: string): void {
111
+ const outVar = ctx.resolveNs('clojure.core')?.vars.get('*out*')
112
+ const out = outVar ? derefValue(outVar) : undefined
113
+ if (out && (out.kind === 'function' || out.kind === 'native-function')) {
114
+ ctx.applyCallable(out, [v.string(text)], callEnv)
115
+ } else {
116
+ ctx.io.stdout(text)
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Emit text to the current error channel.
122
+ * If *err* is dynamically bound to a callable (e.g. inside with-err-str),
123
+ * invoke it. Otherwise fall back to ctx.io.stderr.
124
+ * Same snapshot-env rationale as emitToOut.
125
+ */
126
+ function emitToErr(ctx: EvaluationContext, callEnv: Env, text: string): void {
127
+ const errVar = ctx.resolveNs('clojure.core')?.vars.get('*err*')
128
+ const err = errVar ? derefValue(errVar) : undefined
129
+ if (err && (err.kind === 'function' || err.kind === 'native-function')) {
130
+ ctx.applyCallable(err, [v.string(text)], callEnv)
131
+ } else {
132
+ ctx.io.stderr(text)
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Returns the full clojure.core RuntimeModule.
138
+ *
139
+ * IO functions (println, print, newline, pr, prn, pprint) read ctx.io.stdout
140
+ * at call time instead of closing over an emit callback. This means:
141
+ * - No output parameter needed here
142
+ * - Snapshot clones automatically use the correct output without reinstalling
143
+ * any IO vars (restoreRuntime no longer needs makeIOModule)
144
+ */
145
+ export function makeCoreModule(): RuntimeModule {
146
+ return {
147
+ id: 'clojure/core',
148
+ declareNs: [
149
+ {
150
+ name: 'clojure.core',
151
+ vars(_ctx: ModuleContext): VarMap {
152
+ const map = new Map<string, VarDeclaration>()
153
+
154
+ // Pure stdlib functions (all have .meta via .doc())
155
+ for (const [name, fn] of Object.entries(nativeFunctions)) {
156
+ const meta = (fn as { meta?: CljMap }).meta
157
+ map.set(name, { value: fn, ...(meta ? { meta } : {}) })
158
+ }
159
+
160
+ // IO functions — route through emitToOut/emitToErr so that
161
+ // *out*/*err* dynamic bindings (e.g. inside with-out-str) are honoured.
162
+ map.set('println', {
163
+ value: v.nativeFnCtx(
164
+ 'println',
165
+ (ctx, callEnv, ...args: CljValue[]) => {
166
+ withPrintContext(buildPrintContext(ctx), () => {
167
+ emitToOut(
168
+ ctx,
169
+ callEnv,
170
+ args.map(valueToString).join(' ') + '\n'
171
+ )
172
+ })
173
+ return v.nil()
174
+ }
175
+ ),
176
+ })
177
+ map.set('print', {
178
+ value: v.nativeFnCtx(
179
+ 'print',
180
+ (ctx, callEnv, ...args: CljValue[]) => {
181
+ withPrintContext(buildPrintContext(ctx), () => {
182
+ emitToOut(ctx, callEnv, args.map(valueToString).join(' '))
183
+ })
184
+ return v.nil()
185
+ }
186
+ ),
187
+ })
188
+ map.set('newline', {
189
+ value: v.nativeFnCtx('newline', (ctx, callEnv) => {
190
+ emitToOut(ctx, callEnv, '\n')
191
+ return v.nil()
192
+ }),
193
+ })
194
+ map.set('pr', {
195
+ value: v.nativeFnCtx('pr', (ctx, callEnv, ...args: CljValue[]) => {
196
+ withPrintContext(buildPrintContext(ctx), () => {
197
+ emitToOut(
198
+ ctx,
199
+ callEnv,
200
+ args.map((v) => printString(v)).join(' ')
201
+ )
202
+ })
203
+ return v.nil()
204
+ }),
205
+ })
206
+ map.set('prn', {
207
+ value: v.nativeFnCtx('prn', (ctx, callEnv, ...args: CljValue[]) => {
208
+ withPrintContext(buildPrintContext(ctx), () => {
209
+ emitToOut(
210
+ ctx,
211
+ callEnv,
212
+ args.map((v) => printString(v)).join(' ') + '\n'
213
+ )
214
+ })
215
+ return v.nil()
216
+ }),
217
+ })
218
+ map.set('pprint', {
219
+ value: v.nativeFnCtx(
220
+ 'pprint',
221
+ (ctx, callEnv, form: CljValue, widthArg?: CljValue) => {
222
+ if (form === undefined) return v.nil()
223
+ const maxWidth =
224
+ widthArg?.kind === 'number' ? widthArg.value : 80
225
+ withPrintContext(buildPrintContext(ctx), () => {
226
+ emitToOut(
227
+ ctx,
228
+ callEnv,
229
+ prettyPrintString(form, maxWidth) + '\n'
230
+ )
231
+ })
232
+ return v.nil()
233
+ }
234
+ ),
235
+ })
236
+ map.set('warn', {
237
+ value: v.nativeFnCtx(
238
+ 'warn',
239
+ (ctx, callEnv, ...args: CljValue[]) => {
240
+ withPrintContext(buildPrintContext(ctx), () => {
241
+ emitToErr(
242
+ ctx,
243
+ callEnv,
244
+ args.map(valueToString).join(' ') + '\n'
245
+ )
246
+ })
247
+ return v.nil()
248
+ }
249
+ ),
250
+ })
251
+
252
+ // Dynamic output-channel vars. IO functions check these first before
253
+ // falling back to ctx.io.stdout / ctx.io.stderr. Bound by with-out-str
254
+ // and with-err-str macros defined in clojure.core.
255
+ map.set('*out*', { value: v.nil(), dynamic: true })
256
+ map.set('*err*', { value: v.nil(), dynamic: true })
257
+
258
+ // Dynamic print-control vars
259
+ map.set('*print-length*', { value: v.nil(), dynamic: true })
260
+ map.set('*print-level*', { value: v.nil(), dynamic: true })
261
+
262
+ // Compatibility var for IDE tooling
263
+ map.set('*compiler-options*', { value: v.map([]) })
264
+
265
+ // JS interop — deep conversion functions
266
+ map.set('clj->js', {
267
+ value: v.nativeFnCtx('clj->js', (ctx: EvaluationContext, callEnv: Env, val: CljValue) => {
268
+ if (is.jsValue(val)) return val
269
+ const applier: FunctionApplier = {
270
+ applyFunction: (fn, args) => ctx.applyCallable(fn, args, callEnv),
271
+ }
272
+ return v.jsValue(cljToJsDeep(val, applier))
273
+ }),
274
+ })
275
+
276
+ map.set('js->clj', {
277
+ value: v.nativeFn('js->clj', (val: CljValue, opts?: CljValue) => {
278
+ if (val.kind === 'nil') return val
279
+ if (!is.jsValue(val)) {
280
+ throw new EvaluationError(
281
+ `js->clj expects a js-value, got ${val.kind}`,
282
+ { val }
283
+ )
284
+ }
285
+ const keywordizeKeys = (() => {
286
+ if (!opts || opts.kind !== 'map') return false
287
+ for (const [k, flag] of opts.entries) {
288
+ if (k.kind === 'keyword' && k.name === ':keywordize-keys') {
289
+ return flag.kind !== 'boolean' || flag.value !== false
290
+ }
291
+ }
292
+ return false
293
+ })()
294
+ return jsToCljDeep(val.value, { keywordizeKeys })
295
+ }),
296
+ })
297
+
298
+ return map
299
+ },
300
+ },
301
+ ],
302
+ }
303
+ }
package/src/core/env.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { EvaluationError } from './errors'
2
2
  import type { CljNamespace, CljMap, CljValue, CljVar, Env } from './types'
3
- import { cljVar } from './factories'
3
+ import { v } from './factories'
4
4
 
5
5
  class EnvError extends Error {
6
6
  context: any
@@ -20,7 +20,13 @@ export function derefValue(val: CljValue): CljValue {
20
20
  }
21
21
 
22
22
  export function makeNamespace(name: string): CljNamespace {
23
- return { name, vars: new Map(), aliases: new Map(), readerAliases: new Map() }
23
+ return {
24
+ kind: 'namespace',
25
+ name,
26
+ vars: new Map(),
27
+ aliases: new Map(),
28
+ readerAliases: new Map(),
29
+ }
24
30
  }
25
31
 
26
32
  export function makeEnv(outer?: Env): Env {
@@ -34,8 +40,11 @@ export function lookup(name: string, env: Env): CljValue {
34
40
  let current: Env | null = env
35
41
  while (current) {
36
42
  const raw = current.bindings.get(name)
37
- if (raw !== undefined) return derefValue(raw)
43
+ // Local bindings are stored as plain values — do NOT auto-deref.
44
+ // A var stored in a local binding (e.g. from `(var foo)`) is a first-class value.
45
+ if (raw !== undefined) return raw
38
46
  const v = current.ns?.vars.get(name)
47
+ // Namespace vars are always auto-deref'd: `foo` resolves to the var's current value.
39
48
  if (v !== undefined) return derefValue(v)
40
49
  current = current.outer
41
50
  }
@@ -46,7 +55,7 @@ export function tryLookup(name: string, env: Env): CljValue | undefined {
46
55
  let current: Env | null = env
47
56
  while (current) {
48
57
  const raw = current.bindings.get(name)
49
- if (raw !== undefined) return derefValue(raw)
58
+ if (raw !== undefined) return raw
50
59
  const v = current.ns?.vars.get(name)
51
60
  if (v !== undefined) return derefValue(v)
52
61
  current = current.outer
@@ -59,14 +68,19 @@ export function tryLookup(name: string, env: Env): CljValue | undefined {
59
68
  * Re-def: mutates the existing var's value in place.
60
69
  * New def: creates a new CljVar and stores it in ns.vars.
61
70
  */
62
- export function internVar(name: string, value: CljValue, nsEnv: Env, meta?: CljMap) {
71
+ export function internVar(
72
+ name: string,
73
+ value: CljValue,
74
+ nsEnv: Env,
75
+ meta?: CljMap
76
+ ) {
63
77
  const ns = nsEnv.ns!
64
78
  const existing = ns.vars.get(name)
65
79
  if (existing) {
66
80
  existing.value = value
67
81
  if (meta) existing.meta = meta
68
82
  } else {
69
- ns.vars.set(name, cljVar(ns.name, name, value, meta))
83
+ ns.vars.set(name, v.var(ns.name, name, value, meta))
70
84
  }
71
85
  }
72
86
 
@@ -1,4 +1,4 @@
1
- import { isAFunction, isEqual, isKeyword, isMap } from '../assertions'
1
+ import { is } from '../assertions'
2
2
  import { EvaluationError } from '../errors'
3
3
  import { cljNil } from '../factories'
4
4
  import { printString } from '../printer'
@@ -11,6 +11,7 @@ import type {
11
11
  EvaluationContext,
12
12
  } from '../types'
13
13
  import { bindParams, RecurSignal, resolveArity } from './arity'
14
+ import { cljToJs, jsToClj } from './js-interop'
14
15
 
15
16
  export function applyFunctionWithContext(
16
17
  fn: CljFunction | CljNativeFunction,
@@ -58,6 +59,23 @@ export function applyFunctionWithContext(
58
59
  )
59
60
  }
60
61
 
62
+ export function applyMacroWithContext(
63
+ macro: CljMacro,
64
+ rawArgs: CljValue[],
65
+ ctx: EvaluationContext
66
+ ): CljValue {
67
+ const arity = resolveArity(macro.arities, rawArgs.length)
68
+ const localEnv = bindParams(
69
+ arity.params,
70
+ arity.restParam,
71
+ rawArgs,
72
+ macro.env,
73
+ ctx,
74
+ macro.env
75
+ )
76
+ return ctx.evaluateForms(arity.body, localEnv)
77
+ }
78
+
61
79
  /**
62
80
  * Invokes any IFn value — functions, native functions, keywords, and maps.
63
81
  * Used by comp, partial, and any other HOF that needs to call an arbitrary
@@ -69,25 +87,39 @@ export function applyCallableWithContext(
69
87
  ctx: EvaluationContext,
70
88
  callEnv: Env
71
89
  ): CljValue {
72
- if (isAFunction(fn)) {
90
+ if (is.aFunction(fn)) {
73
91
  return applyFunctionWithContext(fn, args, ctx, callEnv)
74
92
  }
75
- if (isKeyword(fn)) {
93
+ if (is.jsValue(fn)) {
94
+ if (typeof fn.value !== 'function') {
95
+ throw new EvaluationError(
96
+ `js-value is not callable: ${typeof fn.value}`,
97
+ { fn, args }
98
+ )
99
+ }
100
+ const jsArgs = args.map((a) => cljToJs(a, ctx, callEnv))
101
+ const rawResult = (fn.value as (...a: unknown[]) => unknown)(...jsArgs)
102
+ return jsToClj(rawResult)
103
+ }
104
+ if (is.keyword(fn)) {
76
105
  const target = args[0]
77
106
  const defaultVal = args.length > 1 ? args[1] : cljNil()
78
- if (isMap(target)) {
79
- const entry = target.entries.find(([k]) => isEqual(k, fn))
107
+ if (is.map(target)) {
108
+ const entry = target.entries.find(([k]) => is.equal(k, fn))
80
109
  return entry ? entry[1] : defaultVal
81
110
  }
82
111
  return defaultVal
83
112
  }
84
- if (isMap(fn)) {
113
+ if (is.map(fn)) {
85
114
  if (args.length === 0) {
86
- throw new EvaluationError('Map used as function requires at least one argument', { fn, args })
115
+ throw new EvaluationError(
116
+ 'Map used as function requires at least one argument',
117
+ { fn, args }
118
+ )
87
119
  }
88
120
  const key = args[0]
89
121
  const defaultVal = args.length > 1 ? args[1] : cljNil()
90
- const entry = fn.entries.find(([k]) => isEqual(k, key))
122
+ const entry = fn.entries.find(([k]) => is.equal(k, key))
91
123
  return entry ? entry[1] : defaultVal
92
124
  }
93
125
  throw new EvaluationError(`${printString(fn)} is not a callable value`, {
@@ -95,20 +127,3 @@ export function applyCallableWithContext(
95
127
  args,
96
128
  })
97
129
  }
98
-
99
- export function applyMacroWithContext(
100
- macro: CljMacro,
101
- rawArgs: CljValue[],
102
- ctx: EvaluationContext
103
- ): CljValue {
104
- const arity = resolveArity(macro.arities, rawArgs.length)
105
- const localEnv = bindParams(
106
- arity.params,
107
- arity.restParam,
108
- rawArgs,
109
- macro.env,
110
- ctx,
111
- macro.env
112
- )
113
- return ctx.evaluateForms(arity.body, localEnv)
114
- }
@@ -1,4 +1,4 @@
1
- import { isList, isMap, isSymbol, isVector } from '../assertions'
1
+ import { is } from '../assertions'
2
2
  import { extend } from '../env'
3
3
  import { EvaluationError } from '../errors'
4
4
  import { cljList, cljNil } from '../factories'
@@ -23,14 +23,14 @@ export function parseParamVector(
23
23
  args: CljVector,
24
24
  env: Env
25
25
  ): { params: DestructurePattern[]; restParam: DestructurePattern | null } {
26
- const ampIdx = args.value.findIndex((a) => isSymbol(a) && a.name === '&')
26
+ const ampIdx = args.value.findIndex((a) => is.symbol(a) && a.name === '&')
27
27
  let params: DestructurePattern[] = []
28
28
  let restParam: DestructurePattern | null = null
29
29
  if (ampIdx === -1) {
30
30
  params = args.value as DestructurePattern[]
31
31
  } else {
32
32
  const ampsCount = args.value.filter(
33
- (a) => isSymbol(a) && a.name === '&'
33
+ (a) => is.symbol(a) && a.name === '&'
34
34
  ).length
35
35
  if (ampsCount > 1) {
36
36
  throw new EvaluationError('& can only appear once', { args, env })
@@ -58,23 +58,23 @@ export function parseArities(forms: CljValue[], env: Env): Arity[] {
58
58
  )
59
59
  }
60
60
 
61
- if (isVector(forms[0])) {
61
+ if (is.vector(forms[0])) {
62
62
  const paramVec = forms[0]
63
63
  const { params, restParam } = parseParamVector(paramVec, env)
64
64
  return [{ params, restParam, body: forms.slice(1) }]
65
65
  }
66
66
 
67
- if (isList(forms[0])) {
67
+ if (is.list(forms[0])) {
68
68
  const arities: Arity[] = []
69
69
  for (const form of forms) {
70
- if (!isList(form) || form.value.length === 0) {
70
+ if (!is.list(form) || form.value.length === 0) {
71
71
  throw new EvaluationError(
72
72
  'Multi-arity clause must be a list starting with a parameter vector',
73
73
  { form, env }
74
74
  )
75
75
  }
76
76
  const paramVec = form.value[0]
77
- if (!isVector(paramVec)) {
77
+ if (!is.vector(paramVec)) {
78
78
  throw new EvaluationError(
79
79
  'First element of arity clause must be a parameter vector',
80
80
  { paramVec, env }
@@ -134,7 +134,7 @@ export function bindParams(
134
134
  if (restParam !== null) {
135
135
  const restArgs = args.slice(params.length)
136
136
  let restValue: CljValue
137
- if (isMap(restParam) && restArgs.length > 0) {
137
+ if (is.map(restParam) && restArgs.length > 0) {
138
138
  const entries: [CljValue, CljValue][] = []
139
139
  for (let i = 0; i < restArgs.length; i += 2) {
140
140
  entries.push([restArgs[i], restArgs[i + 1] ?? cljNil()])