conjure-js 0.0.11 → 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 (80) hide show
  1. package/dist-cli/conjure-js.mjs +9336 -5028
  2. package/dist-vite-plugin/index.mjs +10455 -0
  3. package/package.json +9 -2
  4. package/src/bin/cli.ts +2 -2
  5. package/src/bin/nrepl-symbol.ts +150 -0
  6. package/src/bin/nrepl.ts +301 -157
  7. package/src/bin/version.ts +1 -1
  8. package/src/clojure/core.clj +764 -29
  9. package/src/clojure/core.clj.d.ts +76 -4
  10. package/src/clojure/demo/math.clj +5 -1
  11. package/src/clojure/generated/builtin-namespace-registry.ts +4 -0
  12. package/src/clojure/generated/clojure-core-source.ts +765 -29
  13. package/src/clojure/generated/clojure-set-source.ts +136 -0
  14. package/src/clojure/generated/clojure-walk-source.ts +72 -0
  15. package/src/clojure/set.clj +132 -0
  16. package/src/clojure/set.clj.d.ts +20 -0
  17. package/src/clojure/string.clj.d.ts +14 -0
  18. package/src/clojure/walk.clj +68 -0
  19. package/src/clojure/walk.clj.d.ts +7 -0
  20. package/src/core/assertions.ts +114 -6
  21. package/src/core/bootstrap.ts +337 -0
  22. package/src/core/conversions.ts +48 -31
  23. package/src/core/core-module.ts +303 -0
  24. package/src/core/env.ts +42 -7
  25. package/src/core/errors.ts +8 -0
  26. package/src/core/evaluator/apply.ts +40 -25
  27. package/src/core/evaluator/arity.ts +8 -8
  28. package/src/core/evaluator/async-evaluator.ts +565 -0
  29. package/src/core/evaluator/collections.ts +30 -4
  30. package/src/core/evaluator/destructure.ts +180 -69
  31. package/src/core/evaluator/dispatch.ts +24 -14
  32. package/src/core/evaluator/evaluate.ts +22 -20
  33. package/src/core/evaluator/expand.ts +45 -15
  34. package/src/core/evaluator/form-parsers.ts +178 -0
  35. package/src/core/evaluator/index.ts +7 -9
  36. package/src/core/evaluator/js-interop.ts +189 -0
  37. package/src/core/evaluator/quasiquote.ts +14 -8
  38. package/src/core/evaluator/recur-check.ts +6 -6
  39. package/src/core/evaluator/special-forms.ts +380 -173
  40. package/src/core/factories.ts +182 -3
  41. package/src/core/index.ts +55 -5
  42. package/src/core/module.ts +136 -0
  43. package/src/core/ns-forms.ts +107 -0
  44. package/src/core/positions.ts +9 -2
  45. package/src/core/printer.ts +371 -11
  46. package/src/core/reader.ts +127 -29
  47. package/src/core/registry.ts +209 -0
  48. package/src/core/runtime.ts +376 -0
  49. package/src/core/session.ts +263 -478
  50. package/src/core/stdlib/arithmetic.ts +516 -215
  51. package/src/core/stdlib/async-fns.ts +132 -0
  52. package/src/core/stdlib/atoms.ts +286 -63
  53. package/src/core/stdlib/errors.ts +54 -50
  54. package/src/core/stdlib/hof.ts +74 -173
  55. package/src/core/stdlib/js-namespace.ts +344 -0
  56. package/src/core/stdlib/lazy.ts +34 -0
  57. package/src/core/stdlib/maps-sets.ts +322 -0
  58. package/src/core/stdlib/meta.ts +109 -28
  59. package/src/core/stdlib/predicates.ts +322 -196
  60. package/src/core/stdlib/regex.ts +126 -98
  61. package/src/core/stdlib/seq.ts +564 -0
  62. package/src/core/stdlib/strings.ts +164 -135
  63. package/src/core/stdlib/transducers.ts +95 -100
  64. package/src/core/stdlib/utils.ts +283 -147
  65. package/src/core/stdlib/vars.ts +27 -27
  66. package/src/core/stdlib/vectors.ts +122 -0
  67. package/src/core/tokenizer.ts +13 -3
  68. package/src/core/transformations.ts +117 -9
  69. package/src/core/types.ts +118 -6
  70. package/src/host/node-host-module.ts +74 -0
  71. package/src/nrepl/relay.ts +432 -0
  72. package/src/vite-plugin-clj/codegen.ts +87 -95
  73. package/src/vite-plugin-clj/index.ts +242 -18
  74. package/src/vite-plugin-clj/namespace-utils.ts +39 -0
  75. package/src/vite-plugin-clj/static-analysis.ts +211 -0
  76. package/src/clojure/demo.clj +0 -63
  77. package/src/clojure/demo.clj.d.ts +0 -0
  78. package/src/core/core-env.ts +0 -60
  79. package/src/core/stdlib/collections.ts +0 -784
  80. 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,5 +1,6 @@
1
1
  import { EvaluationError } from './errors'
2
- import type { CljNamespace, CljValue, CljVar, Env } from './types'
2
+ import type { CljNamespace, CljMap, CljValue, CljVar, Env } from './types'
3
+ import { v } from './factories'
3
4
 
4
5
  class EnvError extends Error {
5
6
  context: any
@@ -11,11 +12,21 @@ class EnvError extends Error {
11
12
  }
12
13
 
13
14
  export function derefValue(val: CljValue): CljValue {
14
- return val.kind === 'var' ? val.value : val
15
+ if (val.kind !== 'var') return val
16
+ if (val.dynamic && val.bindingStack && val.bindingStack.length > 0) {
17
+ return val.bindingStack[val.bindingStack.length - 1]
18
+ }
19
+ return val.value
15
20
  }
16
21
 
17
22
  export function makeNamespace(name: string): CljNamespace {
18
- 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
+ }
19
30
  }
20
31
 
21
32
  export function makeEnv(outer?: Env): Env {
@@ -29,9 +40,12 @@ export function lookup(name: string, env: Env): CljValue {
29
40
  let current: Env | null = env
30
41
  while (current) {
31
42
  const raw = current.bindings.get(name)
32
- 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
33
46
  const v = current.ns?.vars.get(name)
34
- if (v !== undefined) return v.value
47
+ // Namespace vars are always auto-deref'd: `foo` resolves to the var's current value.
48
+ if (v !== undefined) return derefValue(v)
35
49
  current = current.outer
36
50
  }
37
51
  throw new EvaluationError(`Symbol ${name} not found`, { name })
@@ -41,14 +55,35 @@ export function tryLookup(name: string, env: Env): CljValue | undefined {
41
55
  let current: Env | null = env
42
56
  while (current) {
43
57
  const raw = current.bindings.get(name)
44
- if (raw !== undefined) return derefValue(raw)
58
+ if (raw !== undefined) return raw
45
59
  const v = current.ns?.vars.get(name)
46
- if (v !== undefined) return v.value
60
+ if (v !== undefined) return derefValue(v)
47
61
  current = current.outer
48
62
  }
49
63
  return undefined
50
64
  }
51
65
 
66
+ /**
67
+ * Interns a value as a Var in the namespace attached to `nsEnv`.
68
+ * Re-def: mutates the existing var's value in place.
69
+ * New def: creates a new CljVar and stores it in ns.vars.
70
+ */
71
+ export function internVar(
72
+ name: string,
73
+ value: CljValue,
74
+ nsEnv: Env,
75
+ meta?: CljMap
76
+ ) {
77
+ const ns = nsEnv.ns!
78
+ const existing = ns.vars.get(name)
79
+ if (existing) {
80
+ existing.value = value
81
+ if (meta) existing.meta = meta
82
+ } else {
83
+ ns.vars.set(name, v.var(ns.name, name, value, meta))
84
+ }
85
+ }
86
+
52
87
  export function lookupVar(name: string, env: Env): CljVar | undefined {
53
88
  let current: Env | null = env
54
89
  while (current) {
@@ -23,12 +23,20 @@ export class ReaderError extends Error {
23
23
  export class EvaluationError extends Error {
24
24
  context: unknown
25
25
  pos?: Pos
26
+ data?: Record<string, unknown>
26
27
  constructor(message: string, context: unknown, pos?: Pos) {
27
28
  super(message)
28
29
  this.name = 'EvaluationError'
29
30
  this.context = context
30
31
  this.pos = pos
31
32
  }
33
+
34
+ /** Convenience factory: create an error that points at a specific argument. */
35
+ static atArg(message: string, context: unknown, argIndex: number): EvaluationError {
36
+ const err = new EvaluationError(message, context)
37
+ err.data = { argIndex }
38
+ return err
39
+ }
32
40
  }
33
41
 
34
42
  export class CljThrownSignal {
@@ -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()])