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,361 +1,662 @@
1
+ import { is } from '../assertions'
1
2
  import { EvaluationError } from '../errors'
2
- import { cljBoolean, cljNativeFunction, cljNumber, withDoc } from '../factories'
3
- import { isEqual } from '../assertions'
3
+ import { v } from '../factories'
4
4
  import { printString } from '../printer'
5
- import type { CljNumber, CljValue } from '../types'
5
+ import { toSeq } from '../transformations'
6
+ import type { CljList, CljNumber, CljValue, CljVector } from '../types'
6
7
 
7
8
  export const arithmeticFunctions: Record<string, CljValue> = {
8
- '+': withDoc(
9
- cljNativeFunction('+', (...nums: CljValue[]) => {
9
+ '+': v
10
+ .nativeFn('+', function add(...nums: CljValue[]) {
10
11
  if (nums.length === 0) {
11
- return cljNumber(0)
12
- }
13
- if (nums.some((arg) => arg.kind !== 'number')) {
14
- throw new EvaluationError('+ expects all arguments to be numbers', {
15
- args: nums,
16
- })
12
+ return v.number(0)
13
+ }
14
+ const badIdx = nums.findIndex(function isNotNumber(a) {
15
+ return a.kind !== 'number'
16
+ })
17
+ if (badIdx !== -1) {
18
+ throw EvaluationError.atArg(
19
+ '+ expects all arguments to be numbers',
20
+ { args: nums },
21
+ badIdx
22
+ )
17
23
  }
18
- return nums.reduce((acc, arg) => {
19
- return cljNumber((acc as CljNumber).value + (arg as CljNumber).value)
20
- }, cljNumber(0))
21
- }),
22
- 'Returns the sum of the arguments. Throws on non-number arguments.',
23
- [['&', 'nums']]
24
- ),
24
+ return nums.reduce(function sumNumbers(acc, arg) {
25
+ return v.number((acc as CljNumber).value + (arg as CljNumber).value)
26
+ }, v.number(0))
27
+ })
28
+ .doc('Returns the sum of the arguments. Throws on non-number arguments.', [
29
+ ['&', 'nums'],
30
+ ]),
25
31
 
26
- '-': withDoc(
27
- cljNativeFunction('-', (...nums: CljValue[]) => {
32
+ '-': v
33
+ .nativeFn('-', function subtract(...nums: CljValue[]) {
28
34
  if (nums.length === 0) {
29
35
  throw new EvaluationError('- expects at least one argument', {
30
36
  args: nums,
31
37
  })
32
38
  }
33
- if (nums.some((arg) => arg.kind !== 'number')) {
34
- throw new EvaluationError('- expects all arguments to be numbers', {
35
- args: nums,
36
- })
39
+ const badIdx = nums.findIndex(function isNotNumber(a) {
40
+ return a.kind !== 'number'
41
+ })
42
+ if (badIdx !== -1) {
43
+ throw EvaluationError.atArg(
44
+ '- expects all arguments to be numbers',
45
+ { args: nums },
46
+ badIdx
47
+ )
37
48
  }
38
- return nums.slice(1).reduce((acc, arg) => {
39
- return cljNumber((acc as CljNumber).value - (arg as CljNumber).value)
49
+ return nums.slice(1).reduce(function subtractNumbers(acc, arg) {
50
+ return v.number((acc as CljNumber).value - (arg as CljNumber).value)
40
51
  }, nums[0] as CljNumber)
41
- }),
42
- 'Returns the difference of the arguments. Throws on non-number arguments.',
43
- [['&', 'nums']]
44
- ),
52
+ })
53
+ .doc(
54
+ 'Returns the difference of the arguments. Throws on non-number arguments.',
55
+ [['&', 'nums']]
56
+ ),
45
57
 
46
- '*': withDoc(
47
- cljNativeFunction('*', (...nums: CljValue[]) => {
58
+ '*': v
59
+ .nativeFn('*', function multiply(...nums: CljValue[]) {
48
60
  if (nums.length === 0) {
49
- return cljNumber(1)
50
- }
51
- if (nums.some((arg) => arg.kind !== 'number')) {
52
- throw new EvaluationError('* expects all arguments to be numbers', {
53
- args: nums,
54
- })
61
+ return v.number(1)
62
+ }
63
+ const badIdx = nums.findIndex(function isNotNumber(a) {
64
+ return a.kind !== 'number'
65
+ })
66
+ if (badIdx !== -1) {
67
+ throw EvaluationError.atArg(
68
+ '* expects all arguments to be numbers',
69
+ { args: nums },
70
+ badIdx
71
+ )
55
72
  }
56
- return nums.slice(1).reduce((acc, arg) => {
57
- return cljNumber((acc as CljNumber).value * (arg as CljNumber).value)
73
+ return nums.slice(1).reduce(function multiplyNumbers(acc, arg) {
74
+ return v.number((acc as CljNumber).value * (arg as CljNumber).value)
58
75
  }, nums[0] as CljNumber)
59
- }),
60
- 'Returns the product of the arguments. Throws on non-number arguments.',
61
- [['&', 'nums']]
62
- ),
76
+ })
77
+ .doc(
78
+ 'Returns the product of the arguments. Throws on non-number arguments.',
79
+ [['&', 'nums']]
80
+ ),
63
81
 
64
- '/': withDoc(
65
- cljNativeFunction('/', (...nums: CljValue[]) => {
82
+ '/': v
83
+ .nativeFn('/', function divide(...nums: CljValue[]) {
66
84
  if (nums.length === 0) {
67
85
  throw new EvaluationError('/ expects at least one argument', {
68
86
  args: nums,
69
87
  })
70
88
  }
71
- if (nums.some((arg) => arg.kind !== 'number')) {
72
- throw new EvaluationError('/ expects all arguments to be numbers', {
73
- args: nums,
74
- })
89
+ const badIdx = nums.findIndex(function isNotNumber(a) {
90
+ return a.kind !== 'number'
91
+ })
92
+ if (badIdx !== -1) {
93
+ throw EvaluationError.atArg(
94
+ '/ expects all arguments to be numbers',
95
+ { args: nums },
96
+ badIdx
97
+ )
75
98
  }
76
- return nums.slice(1).reduce((acc, arg) => {
99
+ return nums.slice(1).reduce(function divideNumbers(acc, arg, reduceIdx) {
77
100
  if ((arg as CljNumber).value === 0) {
78
- throw new EvaluationError('division by zero', { args: nums })
101
+ const err = new EvaluationError('division by zero', { args: nums })
102
+ err.data = { argIndex: reduceIdx + 1 }
103
+ throw err
79
104
  }
80
- return cljNumber((acc as CljNumber).value / (arg as CljNumber).value)
105
+ return v.number((acc as CljNumber).value / (arg as CljNumber).value)
81
106
  }, nums[0] as CljNumber)
82
- }),
83
- 'Returns the quotient of the arguments. Throws on non-number arguments or division by zero.',
84
- [['&', 'nums']]
85
- ),
107
+ })
108
+ .doc(
109
+ 'Returns the quotient of the arguments. Throws on non-number arguments or division by zero.',
110
+ [['&', 'nums']]
111
+ ),
86
112
 
87
- '>': withDoc(
88
- cljNativeFunction('>', (...nums: CljValue[]) => {
113
+ '>': v
114
+ .nativeFn('>', function greaterThan(...nums: CljValue[]) {
89
115
  if (nums.length < 2) {
90
116
  throw new EvaluationError('> expects at least two arguments', {
91
117
  args: nums,
92
118
  })
93
119
  }
94
- if (nums.some((arg) => arg.kind !== 'number')) {
95
- throw new EvaluationError('> expects all arguments to be numbers', {
96
- args: nums,
97
- })
120
+ const badIdx = nums.findIndex(function isNotNumber(a) {
121
+ return a.kind !== 'number'
122
+ })
123
+ if (badIdx !== -1) {
124
+ throw EvaluationError.atArg(
125
+ '> expects all arguments to be numbers',
126
+ { args: nums },
127
+ badIdx
128
+ )
98
129
  }
99
130
  for (let i = 1; i < nums.length; i++) {
100
131
  if ((nums[i] as CljNumber).value >= (nums[i - 1] as CljNumber).value) {
101
- return cljBoolean(false)
132
+ return v.boolean(false)
102
133
  }
103
134
  }
104
- return cljBoolean(true)
105
- }),
106
- 'Compares adjacent arguments left to right, returns true if all values are in ascending order, false otherwise.',
107
- [['&', 'nums']]
108
- ),
135
+ return v.boolean(true)
136
+ })
137
+ .doc(
138
+ 'Compares adjacent arguments left to right, returns true if all values are in ascending order, false otherwise.',
139
+ [['&', 'nums']]
140
+ ),
109
141
 
110
- '<': withDoc(
111
- cljNativeFunction('<', (...nums: CljValue[]) => {
142
+ '<': v
143
+ .nativeFn('<', function lessThan(...nums: CljValue[]) {
112
144
  if (nums.length < 2) {
113
145
  throw new EvaluationError('< expects at least two arguments', {
114
146
  args: nums,
115
147
  })
116
148
  }
117
- if (nums.some((arg) => arg.kind !== 'number')) {
118
- throw new EvaluationError('< expects all arguments to be numbers', {
119
- args: nums,
120
- })
149
+ const badIdx = nums.findIndex(function isNotNumber(a) {
150
+ return a.kind !== 'number'
151
+ })
152
+ if (badIdx !== -1) {
153
+ throw EvaluationError.atArg(
154
+ '< expects all arguments to be numbers',
155
+ { args: nums },
156
+ badIdx
157
+ )
121
158
  }
122
159
  for (let i = 1; i < nums.length; i++) {
123
160
  if ((nums[i] as CljNumber).value <= (nums[i - 1] as CljNumber).value) {
124
- return cljBoolean(false)
161
+ return v.boolean(false)
125
162
  }
126
163
  }
127
- return cljBoolean(true)
128
- }),
129
- 'Compares adjacent arguments left to right, returns true if all values are in descending order, false otherwise.',
130
- [['&', 'nums']]
131
- ),
164
+ return v.boolean(true)
165
+ })
166
+ .doc(
167
+ 'Compares adjacent arguments left to right, returns true if all values are in descending order, false otherwise.',
168
+ [['&', 'nums']]
169
+ ),
132
170
 
133
- '>=': withDoc(
134
- cljNativeFunction('>=', (...nums: CljValue[]) => {
171
+ '>=': v
172
+ .nativeFn('>=', function greaterThanOrEqual(...nums: CljValue[]) {
135
173
  if (nums.length < 2) {
136
174
  throw new EvaluationError('>= expects at least two arguments', {
137
175
  args: nums,
138
176
  })
139
177
  }
140
- if (nums.some((arg) => arg.kind !== 'number')) {
141
- throw new EvaluationError('>= expects all arguments to be numbers', {
142
- args: nums,
143
- })
178
+ const badIdx = nums.findIndex(function isNotNumber(a) {
179
+ return a.kind !== 'number'
180
+ })
181
+ if (badIdx !== -1) {
182
+ throw EvaluationError.atArg(
183
+ '>= expects all arguments to be numbers',
184
+ { args: nums },
185
+ badIdx
186
+ )
144
187
  }
145
188
  for (let i = 1; i < nums.length; i++) {
146
189
  if ((nums[i] as CljNumber).value > (nums[i - 1] as CljNumber).value) {
147
- return cljBoolean(false)
190
+ return v.boolean(false)
148
191
  }
149
192
  }
150
- return cljBoolean(true)
151
- }),
152
- 'Compares adjacent arguments left to right, returns true if all comparisons returns true for greater than or equal to checks, false otherwise.',
153
- [['&', 'nums']]
154
- ),
193
+ return v.boolean(true)
194
+ })
195
+ .doc(
196
+ 'Compares adjacent arguments left to right, returns true if all comparisons returns true for greater than or equal to checks, false otherwise.',
197
+ [['&', 'nums']]
198
+ ),
155
199
 
156
- '<=': withDoc(
157
- cljNativeFunction('<=', (...nums: CljValue[]) => {
200
+ '<=': v
201
+ .nativeFn('<=', function lessThanOrEqual(...nums: CljValue[]) {
158
202
  if (nums.length < 2) {
159
203
  throw new EvaluationError('<= expects at least two arguments', {
160
204
  args: nums,
161
205
  })
162
206
  }
163
- if (nums.some((arg) => arg.kind !== 'number')) {
164
- throw new EvaluationError('<= expects all arguments to be numbers', {
165
- args: nums,
166
- })
207
+ const badIdx = nums.findIndex(function isNotNumber(a) {
208
+ return a.kind !== 'number'
209
+ })
210
+ if (badIdx !== -1) {
211
+ throw EvaluationError.atArg(
212
+ '<= expects all arguments to be numbers',
213
+ { args: nums },
214
+ badIdx
215
+ )
167
216
  }
168
217
  for (let i = 1; i < nums.length; i++) {
169
218
  if ((nums[i] as CljNumber).value < (nums[i - 1] as CljNumber).value) {
170
- return cljBoolean(false)
219
+ return v.boolean(false)
171
220
  }
172
221
  }
173
- return cljBoolean(true)
174
- }),
175
- 'Compares adjacent arguments left to right, returns true if all comparisons returns true for less than or equal to checks, false otherwise.',
176
- [['&', 'nums']]
177
- ),
222
+ return v.boolean(true)
223
+ })
224
+ .doc(
225
+ 'Compares adjacent arguments left to right, returns true if all comparisons returns true for less than or equal to checks, false otherwise.',
226
+ [['&', 'nums']]
227
+ ),
178
228
 
179
- '=': withDoc(
180
- cljNativeFunction('=', (...vals: CljValue[]) => {
229
+ '=': v
230
+ .nativeFn('=', function equals(...vals: CljValue[]) {
181
231
  if (vals.length < 2) {
182
232
  throw new EvaluationError('= expects at least two arguments', {
183
233
  args: vals,
184
234
  })
185
235
  }
186
236
  for (let i = 1; i < vals.length; i++) {
187
- if (!isEqual(vals[i], vals[i - 1])) {
188
- return cljBoolean(false)
237
+ if (!is.equal(vals[i], vals[i - 1])) {
238
+ return v.boolean(false)
189
239
  }
190
240
  }
191
- return cljBoolean(true)
192
- }),
193
- 'Compares adjacent arguments left to right, returns true if all values are structurally equal, false otherwise.',
194
- [['&', 'vals']]
195
- ),
241
+ return v.boolean(true)
242
+ })
243
+ .doc(
244
+ 'Compares adjacent arguments left to right, returns true if all values are structurally equal, false otherwise.',
245
+ [['&', 'vals']]
246
+ ),
196
247
 
197
- inc: withDoc(
198
- cljNativeFunction('inc', (x: CljValue) => {
248
+ inc: v
249
+ .nativeFn('inc', function increment(x: CljValue) {
199
250
  if (x === undefined || x.kind !== 'number') {
200
- throw new EvaluationError(
251
+ throw EvaluationError.atArg(
201
252
  `inc expects a number${x !== undefined ? `, got ${printString(x)}` : ''}`,
202
- { x }
253
+ { x },
254
+ 0
203
255
  )
204
256
  }
205
- return cljNumber((x as CljNumber).value + 1)
206
- }),
207
- 'Returns the argument incremented by 1. Throws on non-number arguments.',
208
- [['x']]
209
- ),
257
+ return v.number((x as CljNumber).value + 1)
258
+ })
259
+ .doc(
260
+ 'Returns the argument incremented by 1. Throws on non-number arguments.',
261
+ [['x']]
262
+ ),
210
263
 
211
- dec: withDoc(
212
- cljNativeFunction('dec', (x: CljValue) => {
264
+ dec: v
265
+ .nativeFn('dec', function decrement(x: CljValue) {
213
266
  if (x === undefined || x.kind !== 'number') {
214
- throw new EvaluationError(
267
+ throw EvaluationError.atArg(
215
268
  `dec expects a number${x !== undefined ? `, got ${printString(x)}` : ''}`,
216
- { x }
269
+ { x },
270
+ 0
217
271
  )
218
272
  }
219
- return cljNumber((x as CljNumber).value - 1)
220
- }),
221
- 'Returns the argument decremented by 1. Throws on non-number arguments.',
222
- [['x']]
223
- ),
273
+ return v.number((x as CljNumber).value - 1)
274
+ })
275
+ .doc(
276
+ 'Returns the argument decremented by 1. Throws on non-number arguments.',
277
+ [['x']]
278
+ ),
224
279
 
225
- max: withDoc(
226
- cljNativeFunction('max', (...nums: CljValue[]) => {
280
+ max: v
281
+ .nativeFn('max', function maximum(...nums: CljValue[]) {
227
282
  if (nums.length === 0) {
228
283
  throw new EvaluationError('max expects at least one argument', {
229
284
  args: nums,
230
285
  })
231
286
  }
232
- if (nums.some((arg) => arg.kind !== 'number')) {
233
- throw new EvaluationError('max expects all arguments to be numbers', {
234
- args: nums,
235
- })
287
+ const badIdx = nums.findIndex(function isNotNumber(a) {
288
+ return a.kind !== 'number'
289
+ })
290
+ if (badIdx !== -1) {
291
+ throw EvaluationError.atArg(
292
+ 'max expects all arguments to be numbers',
293
+ { args: nums },
294
+ badIdx
295
+ )
236
296
  }
237
- return nums.reduce((best, arg) =>
238
- (arg as CljNumber).value > (best as CljNumber).value ? arg : best
239
- )
240
- }),
241
- 'Returns the largest of the arguments. Throws on non-number arguments.',
242
- [['&', 'nums']]
243
- ),
297
+ return nums.reduce(function findMax(best, arg) {
298
+ return (arg as CljNumber).value > (best as CljNumber).value ? arg : best
299
+ })
300
+ })
301
+ .doc(
302
+ 'Returns the largest of the arguments. Throws on non-number arguments.',
303
+ [['&', 'nums']]
304
+ ),
244
305
 
245
- min: withDoc(
246
- cljNativeFunction('min', (...nums: CljValue[]) => {
306
+ min: v
307
+ .nativeFn('min', function minimum(...nums: CljValue[]) {
247
308
  if (nums.length === 0) {
248
309
  throw new EvaluationError('min expects at least one argument', {
249
310
  args: nums,
250
311
  })
251
312
  }
252
- if (nums.some((arg) => arg.kind !== 'number')) {
253
- throw new EvaluationError('min expects all arguments to be numbers', {
254
- args: nums,
255
- })
313
+ const badIdx = nums.findIndex(function isNotNumber(a) {
314
+ return a.kind !== 'number'
315
+ })
316
+ if (badIdx !== -1) {
317
+ throw EvaluationError.atArg(
318
+ 'min expects all arguments to be numbers',
319
+ { args: nums },
320
+ badIdx
321
+ )
256
322
  }
257
- return nums.reduce((best, arg) =>
258
- (arg as CljNumber).value < (best as CljNumber).value ? arg : best
259
- )
260
- }),
261
- 'Returns the smallest of the arguments. Throws on non-number arguments.',
262
- [['&', 'nums']]
263
- ),
323
+ return nums.reduce(function findMin(best, arg) {
324
+ return (arg as CljNumber).value < (best as CljNumber).value ? arg : best
325
+ })
326
+ })
327
+ .doc(
328
+ 'Returns the smallest of the arguments. Throws on non-number arguments.',
329
+ [['&', 'nums']]
330
+ ),
264
331
 
265
- mod: withDoc(
266
- cljNativeFunction('mod', (n: CljValue, d: CljValue) => {
332
+ mod: v
333
+ .nativeFn('mod', function modulo(n: CljValue, d: CljValue) {
267
334
  if (n === undefined || n.kind !== 'number') {
268
- throw new EvaluationError(
335
+ throw EvaluationError.atArg(
269
336
  `mod expects a number as first argument${n !== undefined ? `, got ${printString(n)}` : ''}`,
270
- { n }
337
+ { n },
338
+ 0
271
339
  )
272
340
  }
273
341
  if (d === undefined || d.kind !== 'number') {
274
- throw new EvaluationError(
342
+ throw EvaluationError.atArg(
275
343
  `mod expects a number as second argument${d !== undefined ? `, got ${printString(d)}` : ''}`,
276
- { d }
344
+ { d },
345
+ 1
277
346
  )
278
347
  }
279
348
  if ((d as CljNumber).value === 0) {
280
- throw new EvaluationError('mod: division by zero', { n, d })
349
+ const err = new EvaluationError('mod: division by zero', { n, d })
350
+ err.data = { argIndex: 1 }
351
+ throw err
281
352
  }
282
353
  // Clojure mod always returns non-negative when divisor is positive
283
354
  const result = (n as CljNumber).value % (d as CljNumber).value
284
- return cljNumber(
355
+ return v.number(
285
356
  result < 0 ? result + Math.abs((d as CljNumber).value) : result
286
357
  )
287
- }),
288
- 'Returns the remainder of the first argument divided by the second argument. Throws on non-number arguments or division by zero.',
289
- [['n', 'd']]
290
- ),
358
+ })
359
+ .doc(
360
+ 'Returns the remainder of the first argument divided by the second argument. Throws on non-number arguments or division by zero.',
361
+ [['n', 'd']]
362
+ ),
291
363
 
292
- 'even?': withDoc(
293
- cljNativeFunction('even?', (n: CljValue) => {
364
+ 'even?': v
365
+ .nativeFn('even?', function isEven(n: CljValue) {
294
366
  if (n === undefined || n.kind !== 'number') {
295
- throw new EvaluationError(
367
+ throw EvaluationError.atArg(
296
368
  `even? expects a number${n !== undefined ? `, got ${printString(n)}` : ''}`,
297
- { n }
369
+ { n },
370
+ 0
298
371
  )
299
372
  }
300
- return cljBoolean((n as CljNumber).value % 2 === 0)
301
- }),
302
- 'Returns true if the argument is an even number, false otherwise.',
303
- [['n']]
304
- ),
373
+ return v.boolean((n as CljNumber).value % 2 === 0)
374
+ })
375
+ .doc('Returns true if the argument is an even number, false otherwise.', [
376
+ ['n'],
377
+ ]),
305
378
 
306
- 'odd?': withDoc(
307
- cljNativeFunction('odd?', (n: CljValue) => {
379
+ 'odd?': v
380
+ .nativeFn('odd?', function isOdd(n: CljValue) {
308
381
  if (n === undefined || n.kind !== 'number') {
309
- throw new EvaluationError(
382
+ throw EvaluationError.atArg(
310
383
  `odd? expects a number${n !== undefined ? `, got ${printString(n)}` : ''}`,
311
- { n }
384
+ { n },
385
+ 0
312
386
  )
313
387
  }
314
- return cljBoolean(Math.abs((n as CljNumber).value) % 2 !== 0)
315
- }),
316
- 'Returns true if the argument is an odd number, false otherwise.',
317
- [['n']]
318
- ),
388
+ return v.boolean(Math.abs((n as CljNumber).value) % 2 !== 0)
389
+ })
390
+ .doc('Returns true if the argument is an odd number, false otherwise.', [
391
+ ['n'],
392
+ ]),
319
393
 
320
- 'pos?': withDoc(
321
- cljNativeFunction('pos?', (n: CljValue) => {
394
+ 'pos?': v
395
+ .nativeFn('pos?', function isPositive(n: CljValue) {
322
396
  if (n === undefined || n.kind !== 'number') {
323
- throw new EvaluationError(
397
+ throw EvaluationError.atArg(
324
398
  `pos? expects a number${n !== undefined ? `, got ${printString(n)}` : ''}`,
325
- { n }
399
+ { n },
400
+ 0
326
401
  )
327
402
  }
328
- return cljBoolean((n as CljNumber).value > 0)
329
- }),
330
- 'Returns true if the argument is a positive number, false otherwise.',
331
- [['n']]
332
- ),
403
+ return v.boolean((n as CljNumber).value > 0)
404
+ })
405
+ .doc(
406
+ 'Returns true if the argument is a positive number, false otherwise.',
407
+ [['n']]
408
+ ),
333
409
 
334
- 'neg?': withDoc(
335
- cljNativeFunction('neg?', (n: CljValue) => {
410
+ 'neg?': v
411
+ .nativeFn('neg?', function isNegative(n: CljValue) {
336
412
  if (n === undefined || n.kind !== 'number') {
337
- throw new EvaluationError(
413
+ throw EvaluationError.atArg(
338
414
  `neg? expects a number${n !== undefined ? `, got ${printString(n)}` : ''}`,
339
- { n }
415
+ { n },
416
+ 0
340
417
  )
341
418
  }
342
- return cljBoolean((n as CljNumber).value < 0)
343
- }),
344
- 'Returns true if the argument is a negative number, false otherwise.',
345
- [['n']]
346
- ),
419
+ return v.boolean((n as CljNumber).value < 0)
420
+ })
421
+ .doc(
422
+ 'Returns true if the argument is a negative number, false otherwise.',
423
+ [['n']]
424
+ ),
347
425
 
348
- 'zero?': withDoc(
349
- cljNativeFunction('zero?', (n: CljValue) => {
426
+ 'zero?': v
427
+ .nativeFn('zero?', function isZero(n: CljValue) {
350
428
  if (n === undefined || n.kind !== 'number') {
351
- throw new EvaluationError(
429
+ throw EvaluationError.atArg(
352
430
  `zero? expects a number${n !== undefined ? `, got ${printString(n)}` : ''}`,
353
- { n }
431
+ { n },
432
+ 0
354
433
  )
355
434
  }
356
- return cljBoolean((n as CljNumber).value === 0)
357
- }),
358
- 'Returns true if the argument is zero, false otherwise.',
359
- [['n']]
360
- ),
435
+ return v.boolean((n as CljNumber).value === 0)
436
+ })
437
+ .doc('Returns true if the argument is zero, false otherwise.', [['n']]),
438
+
439
+ abs: v
440
+ .nativeFn('abs', function absImpl(n: CljValue) {
441
+ if (n === undefined || n.kind !== 'number') {
442
+ throw EvaluationError.atArg(
443
+ `abs expects a number${n !== undefined ? `, got ${printString(n)}` : ''}`,
444
+ { n },
445
+ 0
446
+ )
447
+ }
448
+ return v.number(Math.abs((n as CljNumber).value))
449
+ })
450
+ .doc('Returns the absolute value of a.', [['a']]),
451
+
452
+ quot: v
453
+ .nativeFn('quot', function quotImpl(num: CljValue, div: CljValue) {
454
+ if (num === undefined || num.kind !== 'number') {
455
+ throw EvaluationError.atArg(
456
+ `quot expects a number as first argument`,
457
+ { num },
458
+ 0
459
+ )
460
+ }
461
+ if (div === undefined || div.kind !== 'number') {
462
+ throw EvaluationError.atArg(
463
+ `quot expects a number as second argument`,
464
+ { div },
465
+ 1
466
+ )
467
+ }
468
+ if ((div as CljNumber).value === 0) {
469
+ throw new EvaluationError('quot: division by zero', { num, div })
470
+ }
471
+ return v.number(
472
+ Math.trunc((num as CljNumber).value / (div as CljNumber).value)
473
+ )
474
+ })
475
+ .doc('quot[ient] of dividing numerator by denominator.', [['num', 'div']]),
476
+
477
+ rem: v
478
+ .nativeFn('rem', function remImpl(num: CljValue, div: CljValue) {
479
+ if (num === undefined || num.kind !== 'number') {
480
+ throw EvaluationError.atArg(
481
+ `rem expects a number as first argument`,
482
+ { num },
483
+ 0
484
+ )
485
+ }
486
+ if (div === undefined || div.kind !== 'number') {
487
+ throw EvaluationError.atArg(
488
+ `rem expects a number as second argument`,
489
+ { div },
490
+ 1
491
+ )
492
+ }
493
+ if ((div as CljNumber).value === 0) {
494
+ throw new EvaluationError('rem: division by zero', { num, div })
495
+ }
496
+ return v.number((num as CljNumber).value % (div as CljNumber).value)
497
+ })
498
+ .doc('remainder of dividing numerator by denominator.', [['num', 'div']]),
499
+
500
+ rand: v
501
+ .nativeFn('rand', function randImpl(...args: CljValue[]) {
502
+ if (args.length === 0) return v.number(Math.random())
503
+ if (args[0].kind !== 'number') {
504
+ throw EvaluationError.atArg(`rand expects a number`, { n: args[0] }, 0)
505
+ }
506
+ return v.number(Math.random() * (args[0] as CljNumber).value)
507
+ })
508
+ .doc(
509
+ 'Returns a random floating point number between 0 (inclusive) and n (default 1) (exclusive).',
510
+ [[], ['n']]
511
+ ),
512
+
513
+ 'rand-int': v
514
+ .nativeFn('rand-int', function randIntImpl(n: CljValue) {
515
+ if (n === undefined || n.kind !== 'number') {
516
+ throw EvaluationError.atArg(`rand-int expects a number`, { n }, 0)
517
+ }
518
+ return v.number(Math.floor(Math.random() * (n as CljNumber).value))
519
+ })
520
+ .doc('Returns a random integer between 0 (inclusive) and n (exclusive).', [
521
+ ['n'],
522
+ ]),
523
+
524
+ 'rand-nth': v
525
+ .nativeFn('rand-nth', function randNthImpl(coll: CljValue) {
526
+ if (coll === undefined || (!is.list(coll) && !is.vector(coll))) {
527
+ throw EvaluationError.atArg(
528
+ `rand-nth expects a list or vector`,
529
+ { coll },
530
+ 0
531
+ )
532
+ }
533
+ const items = (coll as CljList | CljVector).value
534
+ if (items.length === 0) {
535
+ throw new EvaluationError('rand-nth called on empty collection', {
536
+ coll,
537
+ })
538
+ }
539
+ return items[Math.floor(Math.random() * items.length)]
540
+ })
541
+ .doc('Return a random element of the (sequential) collection.', [['coll']]),
542
+
543
+ shuffle: v
544
+ .nativeFn('shuffle', function shuffleImpl(coll: CljValue) {
545
+ if (coll === undefined || coll.kind === 'nil') return v.vector([])
546
+ if (!is.seqable(coll)) {
547
+ throw EvaluationError.atArg(
548
+ `shuffle expects a collection, got ${printString(coll)}`,
549
+ { coll },
550
+ 0
551
+ )
552
+ }
553
+ const arr = [...toSeq(coll)]
554
+ for (let i = arr.length - 1; i > 0; i--) {
555
+ const j = Math.floor(Math.random() * (i + 1))
556
+ ;[arr[i], arr[j]] = [arr[j], arr[i]]
557
+ }
558
+ return v.vector(arr)
559
+ })
560
+ .doc('Return a random permutation of coll.', [['coll']]),
561
+
562
+ 'bit-and': v
563
+ .nativeFn('bit-and', function bitAndImpl(x: CljValue, y: CljValue) {
564
+ if (x?.kind !== 'number')
565
+ throw EvaluationError.atArg('bit-and expects numbers', { x }, 0)
566
+ if (y?.kind !== 'number')
567
+ throw EvaluationError.atArg('bit-and expects numbers', { y }, 1)
568
+ return v.number((x as CljNumber).value & (y as CljNumber).value)
569
+ })
570
+ .doc('Bitwise and', [['x', 'y']]),
571
+
572
+ 'bit-or': v
573
+ .nativeFn('bit-or', function bitOrImpl(x: CljValue, y: CljValue) {
574
+ if (x?.kind !== 'number')
575
+ throw EvaluationError.atArg('bit-or expects numbers', { x }, 0)
576
+ if (y?.kind !== 'number')
577
+ throw EvaluationError.atArg('bit-or expects numbers', { y }, 1)
578
+ return v.number((x as CljNumber).value | (y as CljNumber).value)
579
+ })
580
+ .doc('Bitwise or', [['x', 'y']]),
581
+
582
+ 'bit-xor': v
583
+ .nativeFn('bit-xor', function bitXorImpl(x: CljValue, y: CljValue) {
584
+ if (x?.kind !== 'number')
585
+ throw EvaluationError.atArg('bit-xor expects numbers', { x }, 0)
586
+ if (y?.kind !== 'number')
587
+ throw EvaluationError.atArg('bit-xor expects numbers', { y }, 1)
588
+ return v.number((x as CljNumber).value ^ (y as CljNumber).value)
589
+ })
590
+ .doc('Bitwise exclusive or', [['x', 'y']]),
591
+
592
+ 'bit-not': v
593
+ .nativeFn('bit-not', function bitNotImpl(x: CljValue) {
594
+ if (x?.kind !== 'number')
595
+ throw EvaluationError.atArg('bit-not expects a number', { x }, 0)
596
+ return v.number(~(x as CljNumber).value)
597
+ })
598
+ .doc('Bitwise complement', [['x']]),
599
+
600
+ 'bit-shift-left': v
601
+ .nativeFn(
602
+ 'bit-shift-left',
603
+ function bitShiftLeftImpl(x: CljValue, n: CljValue) {
604
+ if (x?.kind !== 'number')
605
+ throw EvaluationError.atArg(
606
+ 'bit-shift-left expects numbers',
607
+ { x },
608
+ 0
609
+ )
610
+ if (n?.kind !== 'number')
611
+ throw EvaluationError.atArg(
612
+ 'bit-shift-left expects numbers',
613
+ { n },
614
+ 1
615
+ )
616
+ return v.number((x as CljNumber).value << (n as CljNumber).value)
617
+ }
618
+ )
619
+ .doc('Bitwise shift left', [['x', 'n']]),
620
+
621
+ 'bit-shift-right': v
622
+ .nativeFn(
623
+ 'bit-shift-right',
624
+ function bitShiftRightImpl(x: CljValue, n: CljValue) {
625
+ if (x?.kind !== 'number')
626
+ throw EvaluationError.atArg(
627
+ 'bit-shift-right expects numbers',
628
+ { x },
629
+ 0
630
+ )
631
+ if (n?.kind !== 'number')
632
+ throw EvaluationError.atArg(
633
+ 'bit-shift-right expects numbers',
634
+ { n },
635
+ 1
636
+ )
637
+ return v.number((x as CljNumber).value >> (n as CljNumber).value)
638
+ }
639
+ )
640
+ .doc('Bitwise shift right', [['x', 'n']]),
641
+
642
+ 'unsigned-bit-shift-right': v
643
+ .nativeFn(
644
+ 'unsigned-bit-shift-right',
645
+ function unsignedBitShiftRightImpl(x: CljValue, n: CljValue) {
646
+ if (x?.kind !== 'number')
647
+ throw EvaluationError.atArg(
648
+ 'unsigned-bit-shift-right expects numbers',
649
+ { x },
650
+ 0
651
+ )
652
+ if (n?.kind !== 'number')
653
+ throw EvaluationError.atArg(
654
+ 'unsigned-bit-shift-right expects numbers',
655
+ { n },
656
+ 1
657
+ )
658
+ return v.number((x as CljNumber).value >>> (n as CljNumber).value)
659
+ }
660
+ )
661
+ .doc('Bitwise shift right, without sign-extension', [['x', 'n']]),
361
662
  }