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
@@ -1,240 +1,366 @@
1
1
  // Predicates & logical: nil?, true?, false?, truthy?, falsy?, not, not=,
2
2
  // number?, string?, boolean?, vector?, list?, map?, keyword?, symbol?, fn?,
3
3
  // coll?, some, every?
4
- import {
5
- isAFunction,
6
- isCollection,
7
- isEqual,
8
- isFalsy,
9
- isKeyword,
10
- isSeqable,
11
- isSymbol,
12
- isTruthy,
13
- isList,
14
- isVector,
15
- isMap,
16
- } from '../assertions'
17
- import { applyFunction } from '../evaluator'
4
+ import { is } from '../assertions'
18
5
  import { EvaluationError } from '../errors'
19
- import { cljBoolean, cljNativeFunction, cljNil, withDoc } from '../factories'
6
+ import { v } from '../factories'
20
7
  import { printString } from '../printer'
21
8
  import { toSeq } from '../transformations'
22
- import type { CljValue } from '../types'
9
+ import type { CljNumber, CljValue, Env, EvaluationContext } from '../types'
23
10
 
24
11
  export const predicateFunctions: Record<string, CljValue> = {
25
- 'nil?': withDoc(
26
- cljNativeFunction('nil?', (arg: CljValue) => {
27
- return cljBoolean(arg.kind === 'nil')
28
- }),
29
- 'Returns true if the value is nil, false otherwise.',
30
- [['arg']]
31
- ),
32
- 'true?': withDoc(
33
- cljNativeFunction('true?', (arg: CljValue) => {
12
+ 'nil?': v
13
+ .nativeFn('nil?', function nilPredImpl(arg: CljValue) {
14
+ return v.boolean(arg.kind === 'nil')
15
+ })
16
+ .doc('Returns true if the value is nil, false otherwise.', [['arg']]),
17
+ 'true?': v
18
+ .nativeFn('true?', function truePredImpl(arg: CljValue) {
34
19
  // returns true if the value is a boolean and true
35
20
  if (arg.kind !== 'boolean') {
36
- return cljBoolean(false)
21
+ return v.boolean(false)
37
22
  }
38
- return cljBoolean(arg.value === true)
39
- }),
40
- 'Returns true if the value is a boolean and true, false otherwise.',
41
- [['arg']]
42
- ),
43
- 'false?': withDoc(
44
- cljNativeFunction('false?', (arg: CljValue) => {
23
+ return v.boolean(arg.value === true)
24
+ })
25
+ .doc('Returns true if the value is a boolean and true, false otherwise.', [
26
+ ['arg'],
27
+ ]),
28
+ 'false?': v
29
+ .nativeFn('false?', function falsePredImpl(arg: CljValue) {
45
30
  // returns true if the value is a boolean and false
46
31
  if (arg.kind !== 'boolean') {
47
- return cljBoolean(false)
32
+ return v.boolean(false)
48
33
  }
49
- return cljBoolean(arg.value === false)
50
- }),
51
- 'Returns true if the value is a boolean and false, false otherwise.',
52
- [['arg']]
53
- ),
54
- 'truthy?': withDoc(
55
- cljNativeFunction('truthy?', (arg: CljValue) => {
56
- return cljBoolean(isTruthy(arg))
57
- }),
58
- 'Returns true if the value is not nil or false, false otherwise.',
59
- [['arg']]
60
- ),
61
- 'falsy?': withDoc(
62
- cljNativeFunction('falsy?', (arg: CljValue) => {
63
- return cljBoolean(isFalsy(arg))
64
- }),
65
- 'Returns true if the value is nil or false, false otherwise.',
66
- [['arg']]
67
- ),
68
- // not: withDoc(
69
- // cljNativeFunction('not', (arg: CljValue) => {
70
- // return cljBoolean(!isTruthy(arg))
71
- // }),
72
- // 'Returns the negation of the truthiness of the value.',
73
- // [['arg']]
74
- // ),
75
- 'not=': withDoc(
76
- cljNativeFunction('not=', (...vals: CljValue[]) => {
34
+ return v.boolean(arg.value === false)
35
+ })
36
+ .doc('Returns true if the value is a boolean and false, false otherwise.', [
37
+ ['arg'],
38
+ ]),
39
+ 'truthy?': v
40
+ .nativeFn('truthy?', function truthyPredImpl(arg: CljValue) {
41
+ return v.boolean(is.truthy(arg))
42
+ })
43
+ .doc('Returns true if the value is not nil or false, false otherwise.', [
44
+ ['arg'],
45
+ ]),
46
+ 'falsy?': v
47
+ .nativeFn('falsy?', function falsyPredImpl(arg: CljValue) {
48
+ return v.boolean(is.falsy(arg))
49
+ })
50
+ .doc('Returns true if the value is nil or false, false otherwise.', [
51
+ ['arg'],
52
+ ]),
53
+ 'not=': v
54
+ .nativeFn('not=', function notEqualImpl(...vals: CljValue[]) {
77
55
  if (vals.length < 2) {
78
56
  throw new EvaluationError('not= expects at least two arguments', {
79
57
  args: vals,
80
58
  })
81
59
  }
82
60
  for (let i = 1; i < vals.length; i++) {
83
- if (!isEqual(vals[i], vals[i - 1])) {
84
- return cljBoolean(true)
61
+ if (!is.equal(vals[i], vals[i - 1])) {
62
+ return v.boolean(true)
85
63
  }
86
64
  }
87
- return cljBoolean(false)
88
- }),
89
- 'Returns true if any two adjacent arguments are not equal, false otherwise.',
90
- [['&', 'vals']]
91
- ),
92
- 'number?': withDoc(
93
- cljNativeFunction('number?', (x: CljValue) =>
94
- cljBoolean(x !== undefined && x.kind === 'number')
65
+ return v.boolean(false)
66
+ })
67
+ .doc(
68
+ 'Returns true if any two adjacent arguments are not equal, false otherwise.',
69
+ [['&', 'vals']]
95
70
  ),
96
- 'Returns true if the value is a number, false otherwise.',
97
- [['x']]
98
- ),
71
+ 'number?': v
72
+ .nativeFn('number?', function numberPredImpl(x: CljValue) {
73
+ return v.boolean(x !== undefined && x.kind === 'number')
74
+ })
75
+ .doc('Returns true if the value is a number, false otherwise.', [['x']]),
99
76
 
100
- 'string?': withDoc(
101
- cljNativeFunction('string?', (x: CljValue) =>
102
- cljBoolean(x !== undefined && x.kind === 'string')
103
- ),
104
- 'Returns true if the value is a string, false otherwise.',
105
- [['x']]
106
- ),
77
+ 'string?': v
78
+ .nativeFn('string?', function stringPredImpl(x: CljValue) {
79
+ return v.boolean(x !== undefined && is.string(x))
80
+ })
81
+ .doc('Returns true if the value is a string, false otherwise.', [['x']]),
107
82
 
108
- 'boolean?': withDoc(
109
- cljNativeFunction('boolean?', (x: CljValue) =>
110
- cljBoolean(x !== undefined && x.kind === 'boolean')
111
- ),
112
- 'Returns true if the value is a boolean, false otherwise.',
113
- [['x']]
114
- ),
83
+ 'boolean?': v
84
+ .nativeFn('boolean?', function booleanPredImpl(x: CljValue) {
85
+ return v.boolean(x !== undefined && x.kind === 'boolean')
86
+ })
87
+ .doc('Returns true if the value is a boolean, false otherwise.', [['x']]),
115
88
 
116
- 'vector?': withDoc(
117
- cljNativeFunction('vector?', (x: CljValue) =>
118
- cljBoolean(x !== undefined && isVector(x))
119
- ),
120
- 'Returns true if the value is a vector, false otherwise.',
121
- [['x']]
122
- ),
89
+ 'vector?': v
90
+ .nativeFn('vector?', function vectorPredImpl(x: CljValue) {
91
+ return v.boolean(x !== undefined && is.vector(x))
92
+ })
93
+ .doc('Returns true if the value is a vector, false otherwise.', [['x']]),
123
94
 
124
- 'list?': withDoc(
125
- cljNativeFunction('list?', (x: CljValue) =>
126
- cljBoolean(x !== undefined && isList(x))
127
- ),
128
- 'Returns true if the value is a list, false otherwise.',
129
- [['x']]
130
- ),
95
+ 'list?': v
96
+ .nativeFn('list?', function listPredImpl(x: CljValue) {
97
+ return v.boolean(x !== undefined && is.list(x))
98
+ })
99
+ .doc('Returns true if the value is a list, false otherwise.', [['x']]),
131
100
 
132
- 'map?': withDoc(
133
- cljNativeFunction('map?', (x: CljValue) =>
134
- cljBoolean(x !== undefined && isMap(x))
135
- ),
136
- 'Returns true if the value is a map, false otherwise.',
137
- [['x']]
138
- ),
101
+ 'map?': v
102
+ .nativeFn('map?', function mapPredImpl(x: CljValue) {
103
+ return v.boolean(x !== undefined && is.map(x))
104
+ })
105
+ .doc('Returns true if the value is a map, false otherwise.', [['x']]),
139
106
 
140
- 'keyword?': withDoc(
141
- cljNativeFunction('keyword?', (x: CljValue) =>
142
- cljBoolean(x !== undefined && isKeyword(x))
143
- ),
144
- 'Returns true if the value is a keyword, false otherwise.',
145
- [['x']]
146
- ),
107
+ 'keyword?': v
108
+ .nativeFn('keyword?', function keywordPredImpl(x: CljValue) {
109
+ return v.boolean(x !== undefined && is.keyword(x))
110
+ })
111
+ .doc('Returns true if the value is a keyword, false otherwise.', [['x']]),
147
112
 
148
- 'qualified-keyword?': withDoc(
149
- cljNativeFunction('qualified-keyword?', (x: CljValue) =>
150
- cljBoolean(x !== undefined && isKeyword(x) && x.name.includes('/'))
151
- ),
152
- 'Returns true if the value is a qualified keyword, false otherwise.',
153
- [['x']]
154
- ),
113
+ 'qualified-keyword?': v
114
+ .nativeFn(
115
+ 'qualified-keyword?',
116
+ function qualifiedKeywordPredImpl(x: CljValue) {
117
+ return v.boolean(
118
+ x !== undefined && is.keyword(x) && x.name.includes('/')
119
+ )
120
+ }
121
+ )
122
+ .doc('Returns true if the value is a qualified keyword, false otherwise.', [
123
+ ['x'],
124
+ ]),
155
125
 
156
- 'symbol?': withDoc(
157
- cljNativeFunction('symbol?', (x: CljValue) =>
158
- cljBoolean(x !== undefined && isSymbol(x))
159
- ),
160
- 'Returns true if the value is a symbol, false otherwise.',
161
- [['x']]
162
- ),
126
+ 'symbol?': v
127
+ .nativeFn('symbol?', function symbolPredImpl(x: CljValue) {
128
+ return v.boolean(x !== undefined && is.symbol(x))
129
+ })
130
+ .doc('Returns true if the value is a symbol, false otherwise.', [['x']]),
163
131
 
164
- 'qualified-symbol?': withDoc(
165
- cljNativeFunction('qualified-symbol?', (x: CljValue) =>
166
- cljBoolean(x !== undefined && isSymbol(x) && x.name.includes('/'))
167
- ),
168
- 'Returns true if the value is a qualified symbol, false otherwise.',
169
- [['x']]
170
- ),
132
+ 'namespace?': v
133
+ .nativeFn('namespace?', function namespaceQImpl(x: CljValue) {
134
+ return v.boolean(x !== undefined && x.kind === 'namespace')
135
+ })
136
+ .doc('Returns true if x is a namespace.', [['x']]),
171
137
 
172
- 'fn?': withDoc(
173
- cljNativeFunction('fn?', (x: CljValue) =>
174
- cljBoolean(x !== undefined && isAFunction(x))
175
- ),
176
- 'Returns true if the value is a function, false otherwise.',
177
- [['x']]
178
- ),
179
-
180
- 'coll?': withDoc(
181
- cljNativeFunction('coll?', (x: CljValue) =>
182
- cljBoolean(x !== undefined && isCollection(x))
183
- ),
184
- 'Returns true if the value is a collection, false otherwise.',
185
- [['x']]
186
- ),
187
- some: withDoc(
188
- cljNativeFunction('some', (pred: CljValue, coll: CljValue): CljValue => {
189
- if (pred === undefined || !isAFunction(pred)) {
190
- throw new EvaluationError(
191
- `some expects a function as first argument${pred !== undefined ? `, got ${printString(pred)}` : ''}`,
192
- { pred }
138
+ 'qualified-symbol?': v
139
+ .nativeFn(
140
+ 'qualified-symbol?',
141
+ function qualifiedSymbolPredImpl(x: CljValue) {
142
+ return v.boolean(
143
+ x !== undefined && is.symbol(x) && x.name.includes('/')
193
144
  )
194
145
  }
195
- if (coll === undefined) {
196
- return cljNil()
197
- }
198
- if (!isSeqable(coll)) {
199
- throw new EvaluationError(
200
- `some expects a collection or string as second argument, got ${printString(coll)}`,
201
- { coll }
202
- )
146
+ )
147
+ .doc('Returns true if the value is a qualified symbol, false otherwise.', [
148
+ ['x'],
149
+ ]),
150
+
151
+ 'fn?': v
152
+ .nativeFn('fn?', function fnPredImpl(x: CljValue) {
153
+ return v.boolean(x !== undefined && is.aFunction(x))
154
+ })
155
+ .doc('Returns true if the value is a function, false otherwise.', [['x']]),
156
+
157
+ 'coll?': v
158
+ .nativeFn('coll?', function collPredImpl(x: CljValue) {
159
+ return v.boolean(x !== undefined && is.collection(x))
160
+ })
161
+ .doc('Returns true if the value is a collection, false otherwise.', [
162
+ ['x'],
163
+ ]),
164
+ some: v
165
+ .nativeFnCtx(
166
+ 'some',
167
+ function someImpl(
168
+ ctx: EvaluationContext,
169
+ callEnv: Env,
170
+ pred: CljValue,
171
+ coll: CljValue
172
+ ): CljValue {
173
+ if (pred === undefined || !is.aFunction(pred)) {
174
+ throw EvaluationError.atArg(
175
+ `some expects a function as first argument${pred !== undefined ? `, got ${printString(pred)}` : ''}`,
176
+ { pred },
177
+ 0
178
+ )
179
+ }
180
+ if (coll === undefined) {
181
+ return v.nil()
182
+ }
183
+ if (!is.seqable(coll)) {
184
+ throw EvaluationError.atArg(
185
+ `some expects a collection or string as second argument, got ${printString(coll)}`,
186
+ { coll },
187
+ 1
188
+ )
189
+ }
190
+ for (const item of toSeq(coll)) {
191
+ const result = ctx.applyFunction(pred, [item], callEnv)
192
+ if (is.truthy(result)) {
193
+ return result
194
+ }
195
+ }
196
+ return v.nil()
203
197
  }
204
- for (const item of toSeq(coll)) {
205
- const result = applyFunction(pred, [item])
206
- if (isTruthy(result)) {
207
- return result
198
+ )
199
+ .doc(
200
+ 'Returns the first truthy result of applying pred to each item in coll, or nil if no item satisfies pred.',
201
+ [['pred', 'coll']]
202
+ ),
203
+
204
+ 'every?': v
205
+ .nativeFnCtx(
206
+ 'every?',
207
+ function everyPredImpl(
208
+ ctx: EvaluationContext,
209
+ callEnv: Env,
210
+ pred: CljValue,
211
+ coll: CljValue
212
+ ): CljValue {
213
+ if (pred === undefined || !is.aFunction(pred)) {
214
+ throw EvaluationError.atArg(
215
+ `every? expects a function as first argument${pred !== undefined ? `, got ${printString(pred)}` : ''}`,
216
+ { pred },
217
+ 0
218
+ )
208
219
  }
220
+ if (coll === undefined || !is.seqable(coll)) {
221
+ throw EvaluationError.atArg(
222
+ `every? expects a collection or string as second argument${coll !== undefined ? `, got ${printString(coll)}` : ''}`,
223
+ { coll },
224
+ 1
225
+ )
226
+ }
227
+ for (const item of toSeq(coll)) {
228
+ if (is.falsy(ctx.applyFunction(pred, [item], callEnv))) {
229
+ return v.boolean(false)
230
+ }
231
+ }
232
+ return v.boolean(true)
209
233
  }
210
- return cljNil()
211
- }),
212
- 'Returns the first truthy result of applying pred to each item in coll, or nil if no item satisfies pred.',
213
- [['pred', 'coll']]
214
- ),
215
-
216
- 'every?': withDoc(
217
- cljNativeFunction('every?', (pred: CljValue, coll: CljValue): CljValue => {
218
- if (pred === undefined || !isAFunction(pred)) {
219
- throw new EvaluationError(
220
- `every? expects a function as first argument${pred !== undefined ? `, got ${printString(pred)}` : ''}`,
221
- { pred }
222
- )
234
+ )
235
+ .doc('Returns true if all items in coll satisfy pred, false otherwise.', [
236
+ ['pred', 'coll'],
237
+ ]),
238
+
239
+ 'identical?': v
240
+ .nativeFn(
241
+ 'identical?',
242
+ function identicalPredImpl(x: CljValue, y: CljValue) {
243
+ return v.boolean(x === y)
223
244
  }
224
- if (coll === undefined || !isSeqable(coll)) {
245
+ )
246
+ .doc('Tests if 2 arguments are the same object (reference equality).', [
247
+ ['x', 'y'],
248
+ ]),
249
+
250
+ 'seqable?': v
251
+ .nativeFn('seqable?', function seqablePredImpl(x: CljValue) {
252
+ return v.boolean(x !== undefined && is.seqable(x))
253
+ })
254
+ .doc('Return true if the seq function is supported for x.', [['x']]),
255
+
256
+ 'sequential?': v
257
+ .nativeFn('sequential?', function sequentialPredImpl(x: CljValue) {
258
+ return v.boolean(x !== undefined && (is.list(x) || is.vector(x)))
259
+ })
260
+ .doc('Returns true if coll is a sequential collection (list or vector).', [
261
+ ['coll'],
262
+ ]),
263
+
264
+ 'associative?': v
265
+ .nativeFn('associative?', function associativePredImpl(x: CljValue) {
266
+ return v.boolean(x !== undefined && (is.map(x) || is.vector(x)))
267
+ })
268
+ .doc('Returns true if coll implements Associative (map or vector).', [
269
+ ['coll'],
270
+ ]),
271
+
272
+ 'counted?': v
273
+ .nativeFn('counted?', function countedPredImpl(x: CljValue) {
274
+ return v.boolean(
275
+ x !== undefined &&
276
+ (is.list(x) ||
277
+ is.vector(x) ||
278
+ is.map(x) ||
279
+ x.kind === 'set' ||
280
+ is.string(x))
281
+ )
282
+ })
283
+ .doc('Returns true if coll implements count in constant time.', [['coll']]),
284
+
285
+ 'int?': v
286
+ .nativeFn('int?', function intPredImpl(x: CljValue) {
287
+ return v.boolean(
288
+ x !== undefined &&
289
+ x.kind === 'number' &&
290
+ Number.isInteger((x as import('../types').CljNumber).value)
291
+ )
292
+ })
293
+ .doc('Return true if x is a fixed precision integer.', [['x']]),
294
+
295
+ 'double?': v
296
+ .nativeFn('double?', function doublePredImpl(x: CljValue) {
297
+ return v.boolean(x !== undefined && x.kind === 'number')
298
+ })
299
+ .doc('Return true if x is a Double (all numbers in JS are doubles).', [
300
+ ['x'],
301
+ ]),
302
+
303
+ 'NaN?': v
304
+ .nativeFn('NaN?', function nanPredImpl(x: CljValue) {
305
+ return v.boolean(
306
+ x !== undefined && x.kind === 'number' && isNaN((x as CljNumber).value)
307
+ )
308
+ })
309
+ .doc('Returns true if num is NaN, else false.', [['num']]),
310
+
311
+ 'infinite?': v
312
+ .nativeFn('infinite?', function infinitePredImpl(x: CljValue) {
313
+ return v.boolean(
314
+ x !== undefined &&
315
+ x.kind === 'number' &&
316
+ !isFinite((x as CljNumber).value)
317
+ )
318
+ })
319
+ .doc('Returns true if num is positive or negative infinity, else false.', [
320
+ ['num'],
321
+ ]),
322
+
323
+ compare: v
324
+ .nativeFn(
325
+ 'compare',
326
+ function compareImpl(x: CljValue, y: CljValue): CljValue {
327
+ if (is.nil(x) && is.nil(y)) return v.number(0)
328
+ if (is.nil(x)) return v.number(-1)
329
+ if (is.nil(y)) return v.number(1)
330
+ if (is.number(x) && is.number(y)) {
331
+ return v.number(
332
+ (x as CljNumber).value < (y as CljNumber).value
333
+ ? -1
334
+ : (x as CljNumber).value > (y as CljNumber).value
335
+ ? 1
336
+ : 0
337
+ )
338
+ }
339
+ if (is.string(x) && is.string(y)) {
340
+ return v.number(x.value < y.value ? -1 : x.value > y.value ? 1 : 0)
341
+ }
342
+ if (is.keyword(x) && is.keyword(y)) {
343
+ return v.number(x.name < y.name ? -1 : x.name > y.name ? 1 : 0)
344
+ }
225
345
  throw new EvaluationError(
226
- `every? expects a collection or string as second argument${coll !== undefined ? `, got ${printString(coll)}` : ''}`,
227
- { coll }
346
+ `compare: cannot compare ${printString(x)} to ${printString(y)}`,
347
+ { x, y }
228
348
  )
229
349
  }
230
- for (const item of toSeq(coll)) {
231
- if (isFalsy(applyFunction(pred, [item]))) {
232
- return cljBoolean(false)
233
- }
350
+ )
351
+ .doc('Comparator. Returns a negative number, zero, or a positive number.', [
352
+ ['x', 'y'],
353
+ ]),
354
+
355
+ hash: v
356
+ .nativeFn('hash', function hashImpl(x: CljValue) {
357
+ // Simple hash — consistent within a session, not cryptographic
358
+ const s = printString(x)
359
+ let h = 0
360
+ for (let i = 0; i < s.length; i++) {
361
+ h = (Math.imul(31, h) + s.charCodeAt(i)) | 0
234
362
  }
235
- return cljBoolean(true)
236
- }),
237
- 'Returns true if all items in coll satisfy pred, false otherwise.',
238
- [['pred', 'coll']]
239
- ),
363
+ return v.number(h)
364
+ })
365
+ .doc('Returns the hash code of its argument.', [['x']]),
240
366
  }