fez-lisp 1.0.51 → 1.0.52

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.
package/src/tokeniser.js DELETED
@@ -1,1145 +0,0 @@
1
- import std from '../lib/baked/std.js'
2
- import { TYPE, VALUE, WORD, KEYWORDS, APPLY } from './enums.js'
3
- import { evaluate, isAtom } from './interpreter.js'
4
- import { LISP } from './parser.js'
5
- import {
6
- isEqual,
7
- isEqualTypes,
8
- isForbiddenVariableName,
9
- stringifyArgs
10
- } from './utils.js'
11
-
12
- const keywords = {
13
- [KEYWORDS.CONCATENATION]: (args, env) => {
14
- if (args.length < 2)
15
- throw new RangeError(
16
- `Invalid number of arguments for (${
17
- KEYWORDS.CONCATENATION
18
- }), expected > 1 but got ${args.length}. (${
19
- KEYWORDS.CONCATENATION
20
- } ${stringifyArgs(args)})`
21
- )
22
- const operands = args.map((x) => evaluate(x, env))
23
- if (operands.some((x) => typeof x !== 'string'))
24
- throw new TypeError(
25
- `Not all arguments of (${KEYWORDS.CONCATENATION}) are (${
26
- KEYWORDS.STRING_TYPE
27
- }) (${KEYWORDS.CONCATENATION} ${stringifyArgs(args)})`
28
- )
29
- return operands.reduce((a, b) => a + b, '')
30
- },
31
- [KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) => {
32
- if (args.length < 2)
33
- throw new RangeError(
34
- `Invalid number of arguments for (${
35
- KEYWORDS.REMAINDER_OF_DIVISION
36
- }), expected > 1 but got ${args.length}. (${
37
- KEYWORDS.REMAINDER_OF_DIVISION
38
- } ${stringifyArgs(args)})`
39
- )
40
- const [a, b] = args.map((x) => evaluate(x, env))
41
- if (typeof a !== 'number' || typeof b !== 'number')
42
- throw new TypeError(
43
- `Not all arguments of (${KEYWORDS.REMAINDER_OF_DIVISION}) are (${
44
- KEYWORDS.NUMBER_TYPE
45
- }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
46
- )
47
- if (b === 0)
48
- throw new TypeError(
49
- `Second argument of (${
50
- KEYWORDS.REMAINDER_OF_DIVISION
51
- }) can't be a (0) (division by 0 is not allowed) (${
52
- KEYWORDS.REMAINDER_OF_DIVISION
53
- } ${stringifyArgs(args)})`
54
- )
55
-
56
- return a % b
57
- },
58
- [KEYWORDS.DIVISION]: (args, env) => {
59
- if (!args.length) return 0
60
- if (args.length === 1) {
61
- const number = evaluate(args[0], env)
62
- if (typeof number !== 'number')
63
- throw new TypeError(
64
- `Arguments of (${KEYWORDS.DIVISION}) is not a (${
65
- KEYWORDS.NUMBER_TYPE
66
- }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
67
- )
68
- if (number === 0)
69
- throw new TypeError(
70
- `Argument of (${
71
- KEYWORDS.DIVISION
72
- }) can't be a (0) (division by 0 is not allowed) (${
73
- KEYWORDS.DIVISION
74
- } ${stringifyArgs(args)})`
75
- )
76
- return 1 / number
77
- }
78
- const operands = args.map((x) => evaluate(x, env))
79
- if (operands.some((x) => typeof x !== 'number'))
80
- throw new TypeError(
81
- `Not all arguments of (${KEYWORDS.DIVISION}) are (${
82
- KEYWORDS.NUMBER_TYPE
83
- }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
84
- )
85
- if (operands.slice(1).some((x) => x === 0))
86
- throw new TypeError(
87
- `Argument of (${
88
- KEYWORDS.DIVISION
89
- }) can't be a (0) (division by 0 is not allowed) (${
90
- KEYWORDS.DIVISION
91
- } ${stringifyArgs(args)})`
92
- )
93
- return operands.reduce((a, b) => a / b)
94
- },
95
- [KEYWORDS.ARRAY_OR_STRING_LENGTH]: (args, env) => {
96
- if (args.length !== 1)
97
- throw new RangeError(
98
- `Invalid number of arguments for (${
99
- KEYWORDS.ARRAY_OR_STRING_LENGTH
100
- }) (= 1 required) (${KEYWORDS.ARRAY_OR_STRING_LENGTH} ${stringifyArgs(
101
- args
102
- )})`
103
- )
104
- const array = evaluate(args[0], env)
105
- if (!(Array.isArray(array) || typeof array === 'string'))
106
- throw new TypeError(
107
- `First argument of (${
108
- KEYWORDS.ARRAY_OR_STRING_LENGTH
109
- }) must be an (or ${KEYWORDS.ARRAY_TYPE} ${KEYWORDS.STRING_TYPE}) (${
110
- KEYWORDS.ARRAY_OR_STRING_LENGTH
111
- } ${stringifyArgs(args)})`
112
- )
113
- return array.length
114
- },
115
- [KEYWORDS.IS_ARRAY]: (args, env) => {
116
- if (args.length !== 1)
117
- throw new RangeError(
118
- `Invalid number of arguments for (${
119
- KEYWORDS.IS_ARRAY
120
- }) (= 1 required) (${KEYWORDS.IS_ARRAY} ${stringifyArgs(args)})`
121
- )
122
- const array = evaluate(args[0], env)
123
- return +Array.isArray(array)
124
- },
125
- [KEYWORDS.IS_NUMBER]: (args, env) => {
126
- if (args.length !== 1)
127
- throw new RangeError(
128
- `Invalid number of arguments for (${
129
- KEYWORDS.IS_NUMBER
130
- }) (= 1 required) (${KEYWORDS.IS_NUMBER} ${stringifyArgs(args)})`
131
- )
132
- return +(typeof evaluate(args[0], env) === 'number')
133
- },
134
- [KEYWORDS.IS_STRING]: (args, env) => {
135
- if (args.length !== 1)
136
- throw new RangeError(
137
- `Invalid number of arguments for (${
138
- KEYWORDS.IS_STRING
139
- }) (= 1 required) (${KEYWORDS.IS_STRING} ${stringifyArgs(args)})`
140
- )
141
- return +(typeof evaluate(args[0], env) === 'string')
142
- },
143
- [KEYWORDS.IS_FUNCTION]: (args, env) => {
144
- if (args.length !== 1)
145
- throw new RangeError(
146
- `Invalid number of arguments for (${
147
- KEYWORDS.IS_FUNCTION
148
- }) (= 1 required) (${KEYWORDS.IS_FUNCTION} ${stringifyArgs(args)})`
149
- )
150
- return +(typeof evaluate(args[0], env) === 'function')
151
- },
152
- [KEYWORDS.ADDITION]: (args, env) => {
153
- if (!args.length) return 0 // identity
154
- if (args.length < 2)
155
- throw new RangeError(
156
- `Invalid number of arguments for (${
157
- KEYWORDS.ADDITION
158
- }), expected (or (> 1) (= 0)) but got ${args.length}. (${
159
- KEYWORDS.ADDITION
160
- } ${stringifyArgs(args)})`
161
- )
162
- const operands = args.map((x) => evaluate(x, env))
163
- if (operands.some((x) => typeof x !== 'number'))
164
- throw new TypeError(
165
- `Not all arguments of (${KEYWORDS.ADDITION}) are (${
166
- KEYWORDS.NUMBER_TYPE
167
- }) (${KEYWORDS.ADDITION} ${stringifyArgs(args)})`
168
- )
169
- return operands.reduce((a, b) => a + b)
170
- },
171
- [KEYWORDS.MULTIPLICATION]: (args, env) => {
172
- if (!args.length) return 1 // identity
173
- if (args.length < 2)
174
- throw new RangeError(
175
- `Invalid number of arguments for (${KEYWORDS.MULTIPLICATION}), expected (or (> 1) (= 0)) but got ${args.length}.`
176
- )
177
- const operands = args.map((x) => evaluate(x, env))
178
- if (operands.some((x) => typeof x !== 'number'))
179
- throw new TypeError(
180
- `Not all arguments of (${KEYWORDS.MULTIPLICATION}) are (${
181
- KEYWORDS.NUMBER_TYPE
182
- }) (${KEYWORDS.MULTIPLICATION} ${stringifyArgs(args)})`
183
- )
184
- return operands.reduce((a, b) => a * b)
185
- },
186
- [KEYWORDS.SUBTRACTION]: (args, env) => {
187
- if (!args.length)
188
- throw new RangeError(
189
- `Invalid number of arguments for (${
190
- KEYWORDS.SUBTRACTION
191
- }), expected >= 1 but got ${args.length}. (${
192
- KEYWORDS.SUBTRACTION
193
- } ${stringifyArgs(args)})`
194
- )
195
- const operands = args.map((x) => evaluate(x, env))
196
- if (operands.some((x) => typeof x !== 'number'))
197
- throw new TypeError(
198
- `Not all arguments of (${KEYWORDS.SUBTRACTION}) are (${
199
- KEYWORDS.NUMBER_TYPE
200
- }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)})`
201
- )
202
- return args.length === 1 ? -operands[0] : operands.reduce((a, b) => a - b)
203
- },
204
- [KEYWORDS.IF]: (args, env) => {
205
- if (args.length !== 3)
206
- throw new RangeError(
207
- `Invalid number of arguments for (${
208
- KEYWORDS.IF
209
- }), expected (= 3) but got ${args.length} (${
210
- KEYWORDS.IF
211
- } ${stringifyArgs(args)})`
212
- )
213
- return evaluate(args[0], env)
214
- ? evaluate(args[1], env)
215
- : evaluate(args[2], env)
216
- },
217
- [KEYWORDS.UNLESS]: (args, env) => {
218
- if (args.length !== 3)
219
- throw new RangeError(
220
- `Invalid number of arguments for (${
221
- KEYWORDS.UNLESS
222
- }), expected (= 3) but got ${args.length} (${
223
- KEYWORDS.UNLESS
224
- } ${stringifyArgs(args)})`
225
- )
226
- return evaluate(args[0], env)
227
- ? evaluate(args[2], env)
228
- : evaluate(args[1], env)
229
- },
230
- [KEYWORDS.WHEN]: (args, env) => {
231
- if (args.length !== 2)
232
- throw new RangeError(
233
- `Invalid number of arguments for (${
234
- KEYWORDS.WHEN
235
- }), expected 2 but got ${args.length} (${KEYWORDS.WHEN} ${stringifyArgs(
236
- args
237
- )})`
238
- )
239
- return evaluate(args[0], env) ? evaluate(args[1], env) : 0
240
- },
241
- [KEYWORDS.OTHERWISE]: (args, env) => {
242
- if (args.length !== 2)
243
- throw new RangeError(
244
- `Invalid number of arguments for (${
245
- KEYWORDS.OTHERWISE
246
- }), expected 2 but got ${args.length} (${
247
- KEYWORDS.OTHERWISE
248
- } ${stringifyArgs(args)})`
249
- )
250
- return evaluate(args[0], env) ? 0 : evaluate(args[1], env)
251
- },
252
- [KEYWORDS.CONDITION]: (args, env) => {
253
- if (args.length < 2)
254
- throw new RangeError(
255
- `Invalid number of arguments for (${
256
- KEYWORDS.CONDITION
257
- }), expected (> 2 required) but got ${args.length} (${
258
- KEYWORDS.CONDITION
259
- } ${stringifyArgs(args)})`
260
- )
261
- for (let i = 0; i < args.length; i += 2)
262
- if (evaluate(args[i], env)) return evaluate(args[i + 1], env)
263
- return 0
264
- },
265
- [KEYWORDS.ARRAY_TYPE]: (args, env) => {
266
- if (!args.length) return []
267
- const isCapacity =
268
- args.length === 2 && args[1][TYPE] === WORD && args[1][VALUE] === 'length'
269
- if (isCapacity) {
270
- if (args.length !== 2)
271
- throw new RangeError(
272
- `Invalid number of arguments for (${
273
- KEYWORDS.ARRAY_TYPE
274
- }) (= 2 required) (${KEYWORDS.ARRAY_TYPE} ${stringifyArgs(args)})`
275
- )
276
- const N = evaluate(args[0], env)
277
- if (!Number.isInteger(N))
278
- throw new TypeError(
279
- `Size argument for (${KEYWORDS.ARRAY_TYPE}) has to be an (32 bit ${
280
- KEYWORDS.NUMBER_TYPE
281
- }) (${KEYWORDS.ARRAY_TYPE} ${stringifyArgs(args)})`
282
- )
283
- return new Array(N).fill(0)
284
- }
285
- return args.map((x) => evaluate(x, env))
286
- },
287
- [KEYWORDS.IS_ATOM]: (args, env) => {
288
- if (args.length !== 1)
289
- throw new RangeError(
290
- `Invalid number of arguments for (${
291
- KEYWORDS.IS_ATOM
292
- }) (= 1 required) (${KEYWORDS.IS_ATOM} ${stringifyArgs(args)})`
293
- )
294
- return isAtom(args[0], env)
295
- },
296
- [KEYWORDS.FIRST_ARRAY]: (args, env) => {
297
- if (args.length !== 1)
298
- throw new RangeError(
299
- `Invalid number of arguments for (${
300
- KEYWORDS.FIRST_ARRAY
301
- }) (= 1 required) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)})`
302
- )
303
- const array = evaluate(args[0], env)
304
- if (!Array.isArray(array))
305
- throw new TypeError(
306
- `Argument of (${KEYWORDS.FIRST_ARRAY}) must be an (${
307
- KEYWORDS.ARRAY_TYPE
308
- }) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)})`
309
- )
310
- if (array.length === 0)
311
- throw new RangeError(
312
- `Argument of (${KEYWORDS.FIRST_ARRAY}) is an empty (${
313
- KEYWORDS.ARRAY_TYPE
314
- }) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)})`
315
- )
316
- const value = array.at(0)
317
- if (value == undefined)
318
- throw new RangeError(
319
- `Trying to get a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
320
- KEYWORDS.FIRST_ARRAY
321
- }) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)})`
322
- )
323
- return value
324
- },
325
- [KEYWORDS.REST_ARRAY]: (args, env) => {
326
- if (args.length !== 1)
327
- throw new RangeError(
328
- `Invalid number of arguments for (${
329
- KEYWORDS.REST_ARRAY
330
- }) (= 1 required) (${KEYWORDS.REST_ARRAY} ${stringifyArgs(args)})`
331
- )
332
- const array = evaluate(args[0], env)
333
- if (!Array.isArray(array))
334
- throw new TypeError(
335
- `Argument of (${KEYWORDS.REST_ARRAY}) must be an (${
336
- KEYWORDS.ARRAY_TYPE
337
- }) (${KEYWORDS.REST_ARRAY} ${stringifyArgs(args)})`
338
- )
339
- if (array.length === 0)
340
- throw new RangeError(
341
- `Argument of (${KEYWORDS.REST_ARRAY}) is an empty (${
342
- KEYWORDS.ARRAY_TYPE
343
- }) (${KEYWORDS.REST_ARRAY} ${stringifyArgs(args)})`
344
- )
345
- return array.slice(1)
346
- },
347
- [KEYWORDS.GET_ARRAY]: (args, env) => {
348
- if (args.length !== 2)
349
- throw new RangeError(
350
- `Invalid number of arguments for (${
351
- KEYWORDS.GET_ARRAY
352
- }) (= 2 required) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
353
- )
354
- const array = evaluate(args[0], env)
355
- if (!Array.isArray(array))
356
- throw new TypeError(
357
- `First argument of (${KEYWORDS.GET_ARRAY}) must be an (${
358
- KEYWORDS.ARRAY_TYPE
359
- })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
360
- )
361
- if (array.length === 0)
362
- throw new RangeError(
363
- `First argument of (${KEYWORDS.GET_ARRAY}) is an empty (${
364
- KEYWORDS.ARRAY_TYPE
365
- })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)}))`
366
- )
367
- const index = evaluate(args[1], env)
368
- if (!Number.isInteger(index))
369
- throw new TypeError(
370
- `Second argument of (${KEYWORDS.GET_ARRAY}) must be an (32 bit ${
371
- KEYWORDS.NUMBER_TYPE
372
- }) (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
373
- )
374
- if (index > array.length - 1 || index * -1 > array.length)
375
- throw new RangeError(
376
- `Second argument of (${KEYWORDS.GET_ARRAY}) is outside of (${
377
- KEYWORDS.ARRAY_TYPE
378
- }) bounds (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
379
- )
380
- const value = array.at(index)
381
- if (value == undefined)
382
- throw new RangeError(
383
- `Trying to get a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
384
- KEYWORDS.GET_ARRAY
385
- }) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
386
- )
387
- return value
388
- },
389
- [KEYWORDS.BLOCK]: (args, env) => {
390
- if (!args.length)
391
- throw new RangeError(
392
- `Invalid number of arguments to (${KEYWORDS.BLOCK}) (>= 1 required) (${
393
- KEYWORDS.BLOCK
394
- } ${stringifyArgs(args)})`
395
- )
396
- return args.reduce((_, x) => evaluate(x, env), 0)
397
- },
398
- [KEYWORDS.ANONYMOUS_FUNCTION]: (args, env) => {
399
- const params = args.slice(0, -1)
400
- const body = args.at(-1)
401
- return (props = [], scope) => {
402
- if (props.length !== params.length)
403
- throw new RangeError(
404
- `Incorrect number of arguments for (${
405
- KEYWORDS.ANONYMOUS_FUNCTION
406
- } ${params.map((x) => x[VALUE]).join(' ')}) are provided. (expects ${
407
- params.length
408
- } but got ${props.length}) (${
409
- KEYWORDS.ANONYMOUS_FUNCTION
410
- } ${stringifyArgs(args)})`
411
- )
412
- const localEnv = Object.create(env)
413
- for (let i = 0; i < props.length; ++i) {
414
- Object.defineProperty(localEnv, params[i][VALUE], {
415
- value: evaluate(props[i], scope),
416
- writable: true
417
- })
418
- }
419
- return evaluate(body, localEnv)
420
- }
421
- },
422
- [KEYWORDS.NOT]: (args, env) => {
423
- if (args.length !== 1)
424
- throw new RangeError(
425
- `Invalid number of arguments for (${KEYWORDS.NOT}) (= 1 required) (${
426
- KEYWORDS.NOT
427
- } ${stringifyArgs(args)})`
428
- )
429
- return +!evaluate(args[0], env)
430
- },
431
- [KEYWORDS.EQUAL]: (args, env) => {
432
- if (args.length !== 2)
433
- throw new RangeError(
434
- `Invalid number of arguments for (${KEYWORDS.EQUAL}) (= 2 required) (${
435
- KEYWORDS.EQUAL
436
- } ${stringifyArgs(args)})`
437
- )
438
- const a = evaluate(args[0], env)
439
- const b = evaluate(args[1], env)
440
- if (typeof a !== 'number')
441
- throw new TypeError(
442
- `Invalid use of (${KEYWORDS.EQUAL}), first arguments are not an ${
443
- KEYWORDS.NUMBER_TYPE
444
- } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
445
- )
446
- if (typeof b !== 'number')
447
- throw new TypeError(
448
- `Invalid use of (${KEYWORDS.EQUAL}), second argument are not an ${
449
- KEYWORDS.NUMBER_TYPE
450
- } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
451
- )
452
- return +(a === b)
453
- },
454
- [KEYWORDS.LESS_THAN]: (args, env) => {
455
- if (args.length !== 2)
456
- throw new RangeError(
457
- `Invalid number of arguments for (${
458
- KEYWORDS.LESS_THAN
459
- }) (= 2 required) (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
460
- )
461
- const a = evaluate(args[0], env)
462
- const b = evaluate(args[1], env)
463
- if (typeof a !== 'number')
464
- throw new TypeError(
465
- `Invalid use of (${KEYWORDS.LESS_THAN}), first arguments are not an ${
466
- KEYWORDS.NUMBER_TYPE
467
- } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
468
- )
469
- if (typeof b !== 'number')
470
- throw new TypeError(
471
- `Invalid use of (${KEYWORDS.LESS_THAN}), second argument are not an ${
472
- KEYWORDS.NUMBER_TYPE
473
- } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
474
- )
475
- return +(a < b)
476
- },
477
- [KEYWORDS.GREATHER_THAN]: (args, env) => {
478
- if (args.length !== 2)
479
- throw new RangeError(
480
- `Invalid number of arguments for (${
481
- KEYWORDS.GREATHER_THAN
482
- }) (= 2 required) (${KEYWORDS.GREATHER_THAN} ${stringifyArgs(args)})`
483
- )
484
- const a = evaluate(args[0], env)
485
- const b = evaluate(args[1], env)
486
- if (typeof a !== 'number')
487
- throw new TypeError(
488
- `Invalid use of (${
489
- KEYWORDS.GREATHER_THAN
490
- }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
491
- KEYWORDS.GREATHER_THAN
492
- } ${stringifyArgs(args)})`
493
- )
494
- if (typeof b !== 'number')
495
- throw new TypeError(
496
- `Invalid use of (${
497
- KEYWORDS.GREATHER_THAN
498
- }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
499
- KEYWORDS.GREATHER_THAN
500
- } ${stringifyArgs(args)})`
501
- )
502
- return +(a > b)
503
- },
504
- [KEYWORDS.GREATHER_THAN_OR_EQUAL]: (args, env) => {
505
- if (args.length !== 2)
506
- throw new RangeError(
507
- `Invalid number of arguments for (${
508
- KEYWORDS.GREATHER_THAN_OR_EQUAL
509
- }) (= 2 required) (${KEYWORDS.GREATHER_THAN_OR_EQUAL} ${stringifyArgs(
510
- args
511
- )})`
512
- )
513
- const a = evaluate(args[0], env)
514
- const b = evaluate(args[1], env)
515
- if (typeof a !== 'number')
516
- throw new TypeError(
517
- `Invalid use of (${
518
- KEYWORDS.GREATHER_THAN_OR_EQUAL
519
- }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
520
- KEYWORDS.GREATHER_THAN_OR_EQUAL
521
- } ${stringifyArgs(args)})`
522
- )
523
- if (typeof b !== 'number')
524
- throw new TypeError(
525
- `Invalid use of (${
526
- KEYWORDS.GREATHER_THAN_OR_EQUAL
527
- }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
528
- KEYWORDS.GREATHER_THAN_OR_EQUAL
529
- } ${stringifyArgs(args)})`
530
- )
531
- return +(a >= b)
532
- },
533
- [KEYWORDS.LESS_THAN_OR_EQUAL]: (args, env) => {
534
- if (args.length !== 2)
535
- throw new RangeError(
536
- `Invalid number of arguments for (${
537
- KEYWORDS.LESS_THAN_OR_EQUAL
538
- }) (= 2 required) (${KEYWORDS.LESS_THAN_OR_EQUAL} ${stringifyArgs(
539
- args
540
- )})`
541
- )
542
- const a = evaluate(args[0], env)
543
- const b = evaluate(args[1], env)
544
- if (typeof a !== 'number')
545
- throw new TypeError(
546
- `Invalid use of (${
547
- KEYWORDS.LESS_THAN_OR_EQUAL
548
- }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
549
- KEYWORDS.LESS_THAN_OR_EQUAL
550
- } ${stringifyArgs(args)})`
551
- )
552
- if (typeof b !== 'number')
553
- throw new TypeError(
554
- `Invalid use of (${
555
- KEYWORDS.LESS_THAN_OR_EQUAL
556
- }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
557
- KEYWORDS.LESS_THAN_OR_EQUAL
558
- } ${stringifyArgs(args)})`
559
- )
560
- return +(a <= b)
561
- },
562
- [KEYWORDS.AND]: (args, env) => {
563
- if (args.length < 2)
564
- throw new RangeError(
565
- `Invalid number of arguments for (${KEYWORDS.AND}) (>= 2 required) (${
566
- KEYWORDS.AND
567
- } ${stringifyArgs(args)})`
568
- )
569
- let circuit
570
- for (let i = 0; i < args.length - 1; ++i) {
571
- circuit = evaluate(args[i], env)
572
- if (circuit) continue
573
- else return circuit
574
- }
575
- return evaluate(args.at(-1), env)
576
- },
577
- [KEYWORDS.OR]: (args, env) => {
578
- if (args.length < 2)
579
- throw new RangeError(
580
- `Invalid number of arguments for (${KEYWORDS.OR}) (>= 2 required) (${
581
- KEYWORDS.OR
582
- } ${stringifyArgs(args)})`
583
- )
584
- let circuit
585
- for (let i = 0; i < args.length - 1; ++i) {
586
- circuit = evaluate(args[i], env)
587
- if (circuit) return circuit
588
- else continue
589
- }
590
- return evaluate(args.at(-1), env)
591
- },
592
- [KEYWORDS.CALL_FUNCTION]: (args, env) => {
593
- if (!args.length)
594
- throw new RangeError(
595
- `Invalid number of arguments to (${
596
- KEYWORDS.CALL_FUNCTION
597
- }) (>= 1 required) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
598
- )
599
- const [first, ...rest] = args
600
- if (first[TYPE] === WORD && first[VALUE] in keywords)
601
- throw new TypeError(
602
- `Following argument of (${
603
- KEYWORDS.CALL_FUNCTION
604
- }) must not be an reserved word (${
605
- KEYWORDS.CALL_FUNCTION
606
- } ${stringifyArgs(args)})`
607
- )
608
- const apply = evaluate(first, env)
609
- if (typeof apply !== 'function')
610
- throw new TypeError(
611
- `First argument of (${KEYWORDS.CALL_FUNCTION}) must be a (${
612
- KEYWORDS.ANONYMOUS_FUNCTION
613
- }) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
614
- )
615
-
616
- return apply(rest, env)
617
- },
618
- [KEYWORDS.DEFINE_VARIABLE]: (args, env) => {
619
- if (args.length !== 2)
620
- throw new RangeError(
621
- `Invalid number of arguments to (${
622
- KEYWORDS.DEFINE_VARIABLE
623
- }) (= 2 required) (${KEYWORDS.DEFINE_VARIABLE} ${stringifyArgs(args)})`
624
- )
625
- let name
626
- const word = args[0]
627
- if (word[TYPE] !== WORD)
628
- throw new SyntaxError(
629
- `First argument of (${KEYWORDS.DEFINE_VARIABLE}) must be word but got ${
630
- word[TYPE]
631
- } (${KEYWORDS.DEFINE_VARIABLE} ${stringifyArgs(args)})`
632
- )
633
- else if (isForbiddenVariableName(word[VALUE]))
634
- throw new ReferenceError(
635
- `Variable name ${word[VALUE]} is forbidden at (${
636
- KEYWORDS.DEFINE_VARIABLE
637
- } ${stringifyArgs(args)})`
638
- )
639
- name = word[VALUE]
640
- Object.defineProperty(env, name, {
641
- value: evaluate(args[1], env),
642
- writable: false
643
- })
644
- return env[name]
645
- },
646
- [KEYWORDS.STRING_TYPE]: () => '',
647
- [KEYWORDS.NUMBER_TYPE]: () => 0,
648
- [KEYWORDS.BOOLEAN_TYPE]: () => 1,
649
- [KEYWORDS.CAST_TYPE]: (args, env) => {
650
- if (args.length !== 2)
651
- throw new RangeError(
652
- `Invalid number of arguments for (${KEYWORDS.CAST_TYPE}) ${args.length}`
653
- )
654
- const type = args[1][VALUE]
655
- const value = evaluate(args[0], env)
656
- if (value == undefined)
657
- throw ReferenceError(
658
- `Trying to access undefined value at (${KEYWORDS.CAST_TYPE})`
659
- )
660
- if (args.length === 2) {
661
- switch (type) {
662
- case KEYWORDS.NUMBER_TYPE: {
663
- const num = Number(value)
664
- if (isNaN(num))
665
- throw new TypeError(
666
- `Attempting to convert Not a ${
667
- KEYWORDS.NUMBER_TYPE
668
- } ("${value}") to a ${KEYWORDS.NUMBER_TYPE} at (${
669
- KEYWORDS.CAST_TYPE
670
- }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)})`
671
- )
672
- return num
673
- }
674
- case KEYWORDS.STRING_TYPE:
675
- return value.toString()
676
- case KEYWORDS.BOOLEAN_TYPE:
677
- return +!!value
678
- case KEYWORDS.ARRAY_TYPE: {
679
- if (typeof value === 'number')
680
- return [...Number(value).toString()].map(Number)
681
- else if (typeof value[Symbol.iterator] !== 'function')
682
- throw new TypeError(
683
- `Arguments are not iterable for ${KEYWORDS.ARRAY_TYPE} at (${
684
- KEYWORDS.CAST_TYPE
685
- }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)})`
686
- )
687
- return [...value]
688
- }
689
- case KEYWORDS.CHAR_TYPE: {
690
- const index = evaluate(args[0], env)
691
- if (!Number.isInteger(index) || index < 0)
692
- throw new TypeError(
693
- `Arguments are not (+ ${KEYWORDS.NUMBER_TYPE}) for ${
694
- KEYWORDS.CHAR_TYPE
695
- } at (${KEYWORDS.CAST_TYPE}) (${
696
- KEYWORDS.CAST_TYPE
697
- } ${stringifyArgs(args)})`
698
- )
699
- return String.fromCharCode(index)
700
- }
701
- case KEYWORDS.CHAR_CODE_TYPE: {
702
- const string = evaluate(args[0], env)
703
- if (typeof string !== 'string')
704
- throw new TypeError(
705
- `Argument is not (${KEYWORDS.STRING_TYPE}) for ${
706
- KEYWORDS.CHAR_CODE_TYPE
707
- } at (${KEYWORDS.CAST_TYPE}) (${
708
- KEYWORDS.CAST_TYPE
709
- } ${stringifyArgs(args)})`
710
- )
711
- if (string.length !== 1)
712
- throw new RangeError(
713
- `Argument is not of (= (length ${KEYWORDS.STRING_TYPE}) 1) for ${
714
- KEYWORDS.CHAR_CODE_TYPE
715
- } at (${KEYWORDS.CAST_TYPE}) (${
716
- KEYWORDS.CAST_TYPE
717
- } ${stringifyArgs(args)})`
718
- )
719
- return string.charCodeAt(0)
720
- }
721
- default:
722
- throw new TypeError(
723
- `Can only cast (or ${KEYWORDS.NUMBER_TYPE} ${
724
- KEYWORDS.STRING_TYPE
725
- } ${KEYWORDS.ARRAY_TYPE} ${KEYWORDS.BOOLEAN_TYPE} ${
726
- KEYWORDS.CHAR_TYPE
727
- } ${KEYWORDS.CHAR_CODE_TYPE}) at (${KEYWORDS.CAST_TYPE}) (${
728
- KEYWORDS.CAST_TYPE
729
- } ${stringifyArgs(args)})`
730
- )
731
- }
732
- }
733
- },
734
- [KEYWORDS.BITWISE_AND]: (args, env) => {
735
- if (args.length < 2)
736
- throw new RangeError(
737
- `Invalid number of arguments to (${
738
- KEYWORDS.BITWISE_AND
739
- }) (>= 2 required). (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
740
- )
741
- const operands = args.map((a) => evaluate(a, env))
742
- if (operands.some((x) => typeof x !== 'number'))
743
- throw new TypeError(
744
- `Not all arguments of (${KEYWORDS.BITWISE_AND}) are ${
745
- KEYWORDS.NUMBER_TYPE
746
- } (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
747
- )
748
- return operands.reduce((acc, x) => acc & x)
749
- },
750
- [KEYWORDS.BITWISE_NOT]: (args, env) => {
751
- if (args.length !== 1)
752
- throw new RangeError(
753
- `Invalid number of arguments to (${
754
- KEYWORDS.BITWISE_NOT
755
- }) (= 1 required). (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
756
- )
757
- const operand = evaluate(args[0], env)
758
- if (typeof operand !== 'number')
759
- throw new TypeError(
760
- `Argument of (${KEYWORDS.BITWISE_NOT}) is not a (${
761
- KEYWORDS.NUMBER_TYPE
762
- }) (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
763
- )
764
- return ~operand
765
- },
766
- [KEYWORDS.BITWISE_OR]: (args, env) => {
767
- if (args.length < 2)
768
- throw new RangeError(
769
- `Invalid number of arguments to (${
770
- KEYWORDS.BITWISE_OR
771
- }) (>= 2 required). (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
772
- )
773
- const operands = args.map((a) => evaluate(a, env))
774
- if (operands.some((x) => typeof x !== 'number'))
775
- throw new TypeError(
776
- `Not all arguments of (${KEYWORDS.BITWISE_OR}) are (${
777
- KEYWORDS.NUMBER_TYPE
778
- }) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
779
- )
780
- return operands.reduce((acc, x) => acc | x)
781
- },
782
- [KEYWORDS.BITWISE_XOR]: (args, env) => {
783
- if (args.length < 2)
784
- throw new RangeError(
785
- `Invalid number of arguments to (${
786
- KEYWORDS.BITWISE_XOR
787
- }) (>= 2 required). (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
788
- )
789
- const operands = args.map((a) => evaluate(a, env))
790
- if (operands.some((x) => typeof x !== 'number'))
791
- throw new TypeError(
792
- `Not all arguments of (${KEYWORDS.BITWISE_XOR}) are (${
793
- KEYWORDS.NUMBER_TYPE
794
- }) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
795
- )
796
- return operands.reduce((acc, x) => acc ^ x)
797
- },
798
- [KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) => {
799
- if (args.length < 2)
800
- throw new RangeError(
801
- `Invalid number of arguments to (${
802
- KEYWORDS.BITWISE_LEFT_SHIFT
803
- }) (>= 2 required). (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(
804
- args
805
- )})`
806
- )
807
- const operands = args.map((a) => evaluate(a, env))
808
- if (operands.some((x) => typeof x !== 'number'))
809
- throw new TypeError(
810
- `Not all arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) are (${
811
- KEYWORDS.NUMBER_TYPE
812
- }) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)})`
813
- )
814
- return operands.reduce((acc, x) => acc << x)
815
- },
816
- [KEYWORDS.BITWISE_RIGHT_SHIFT]: (args, env) => {
817
- if (args.length < 2)
818
- throw new RangeError(
819
- `Invalid number of arguments to (${
820
- KEYWORDS.BITWISE_RIGHT_SHIFT
821
- }) (>= 2 required). (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(
822
- args
823
- )})`
824
- )
825
- const operands = args.map((a) => evaluate(a, env))
826
- if (operands.some((x) => typeof x !== 'number'))
827
- throw new TypeError(
828
- `Not all arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) are (${
829
- KEYWORDS.NUMBER_TYPE
830
- }) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)})`
831
- )
832
- return operands.reduce((acc, x) => acc >> x)
833
- },
834
- [KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT]: (args, env) => {
835
- if (args.length < 2)
836
- throw new RangeError(
837
- `Invalid number of arguments to (${
838
- KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
839
- }) (>= 2 required). (${
840
- KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
841
- } ${stringifyArgs(args)})`
842
- )
843
- const operands = args.map((a) => evaluate(a, env))
844
- if (operands.some((x) => typeof x !== 'number'))
845
- throw new TypeError(
846
- `Not all arguments of (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT}) are (${
847
- KEYWORDS.NUMBER_TYPE
848
- }) (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT} ${stringifyArgs(args)})`
849
- )
850
- return operands.reduce((acc, x) => acc >>> x)
851
- },
852
- [KEYWORDS.PIPE]: (args, env) => {
853
- if (args.length < 1)
854
- throw new RangeError(
855
- `Invalid number of arguments to (${KEYWORDS.PIPE}) (>= 1 required). (${
856
- KEYWORDS.PIPE
857
- } ${stringifyArgs(args)})`
858
- )
859
- let inp = args[0]
860
- for (let i = 1; i < args.length; ++i) {
861
- if (!args[i].length || args[i][0][TYPE] !== APPLY)
862
- throw new TypeError(
863
- `Argument at position (${i}) of (${
864
- KEYWORDS.PIPE
865
- }) is not an invoked (${KEYWORDS.ANONYMOUS_FUNCTION}). (${
866
- KEYWORDS.PIPE
867
- } ${stringifyArgs(args)})`
868
- )
869
- const [first, ...rest] = args[i]
870
- const arr = [first, inp, ...rest]
871
- inp = arr
872
- }
873
- return evaluate(inp, env)
874
- },
875
- [KEYWORDS.MERGE]: (args, env) => {
876
- if (args.length < 2)
877
- throw new RangeError(
878
- `Invalid number of arguments to (${KEYWORDS.MERGE}) (>= 2 required). (${
879
- KEYWORDS.MERGE
880
- } ${stringifyArgs(args)})`
881
- )
882
- const arrays = args.map((arg) => evaluate(arg, env))
883
- if (arrays.some((maybe) => !Array.isArray(maybe)))
884
- throw new TypeError(
885
- `Arguments of (${KEYWORDS.MERGE}) must be (${KEYWORDS.ARRAY_TYPE}) (${
886
- KEYWORDS.MERGE
887
- } ${stringifyArgs(args)})`
888
- )
889
- return arrays.reduce((a, b) => a.concat(b), [])
890
- },
891
- [KEYWORDS.CONS]: (args, env) => {
892
- if (args.length !== 2)
893
- throw new RangeError(
894
- `Invalid number of arguments to (${KEYWORDS.CONS}) (= 2 required). (${
895
- KEYWORDS.CONS
896
- } ${stringifyArgs(args)})`
897
- )
898
- const array = evaluate(args[0], env)
899
- if (!Array.isArray(array))
900
- throw new TypeError(
901
- `First Argument of (${KEYWORDS.CONS}) must be (${
902
- KEYWORDS.ARRAY_TYPE
903
- }) (${KEYWORDS.CONS} ${stringifyArgs(args)})`
904
- )
905
- const other = evaluate(args[1], env)
906
- if (!Array.isArray(other))
907
- throw new TypeError(
908
- `Second Argument of (${KEYWORDS.CONS}) must be (${
909
- KEYWORDS.ARRAY_TYPE
910
- }) (${KEYWORDS.CONS} ${stringifyArgs(args)})`
911
- )
912
- return array.concat(other)
913
- },
914
- [KEYWORDS.IMMUTABLE_FUNCTION]: (args, env) => {
915
- if (!args.length)
916
- throw new RangeError(
917
- `Invalid number of arguments to (${
918
- KEYWORDS.IMMUTABLE_FUNCTION
919
- }) (>= 2 required). (${KEYWORDS.IMMUTABLE_FUNCTION} ${stringifyArgs(
920
- args
921
- )})`
922
- )
923
- const [definition, ...functionArgs] = args
924
- const token = definition[VALUE]
925
- if (!(token in keywords))
926
- throw new ReferenceError(
927
- `There is no such keyword ${token} at (${
928
- KEYWORDS.IMMUTABLE_FUNCTION
929
- } ${stringifyArgs(args)})`
930
- )
931
-
932
- const params = functionArgs.slice(0, -1)
933
- const body = functionArgs.at(-1)
934
- return (props = [], scope) => {
935
- if (props.length !== params.length)
936
- throw new RangeError(
937
- `Incorrect number of arguments for (${KEYWORDS.IMMUTABLE_FUNCTION} ${
938
- KEYWORDS.ANONYMOUS_FUNCTION
939
- } ${params.map((x) => x[VALUE]).join(' ')}) are provided. (expects ${
940
- params.length
941
- } but got ${props.length}) (${KEYWORDS.IMMUTABLE_FUNCTION} ${
942
- KEYWORDS.ANONYMOUS_FUNCTION
943
- } ${stringifyArgs(args)})`
944
- )
945
- const localEnv = Object.create({ ...keywords })
946
- for (let i = 0; i < props.length; ++i) {
947
- Object.defineProperty(localEnv, params[i][VALUE], {
948
- value: evaluate(props[i], scope),
949
- writable: true
950
- })
951
- }
952
- return evaluate(body, localEnv)
953
- }
954
- },
955
- [KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION]: (args, env) => {
956
- if (!args.length)
957
- throw new RangeError(
958
- `Invalid number of arguments to (${
959
- KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION
960
- }) (>= 2 required). (${
961
- KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION
962
- } ${stringifyArgs(args)})`
963
- )
964
- // TODO: Add validation for TCO recursion
965
- return keywords[KEYWORDS.DEFINE_VARIABLE](args, env)
966
- },
967
- [KEYWORDS.TEST_CASE]: (args, env) => {
968
- if (args.length !== 3)
969
- throw new RangeError(
970
- `Invalid number of arguments to (${
971
- KEYWORDS.TEST_CASE
972
- }) (= 3 required) (${KEYWORDS.TEST_CASE} ${stringifyArgs(args)})`
973
- )
974
- const description = evaluate(args[0], env)
975
- const a = evaluate(args[1], env)
976
- const b = evaluate(args[2], env)
977
- return !isEqualTypes(a, b) || !isEqual(a, b)
978
- ? [0, description, stringifyArgs([args[1]]), b, a]
979
- : [1, description, stringifyArgs([args[1]]), a]
980
- },
981
- [KEYWORDS.TEST_BED]: (args, env) => {
982
- let tests = []
983
- try {
984
- if (
985
- args.some(
986
- ([[type, car]]) => !(type === APPLY && car === KEYWORDS.TEST_CASE)
987
- )
988
- )
989
- throw new TypeError(
990
- `Arguments of (${KEYWORDS.TEST_BED}) must be (${
991
- KEYWORDS.TEST_CASE
992
- }) (${KEYWORDS.TEST_BED} ${stringifyArgs(args)})`
993
- )
994
- tests = args.map((x) => evaluate(x, env))
995
- tests.forEach(([state, describe, ...rest]) =>
996
- !state
997
- ? console.log(
998
- '\x1b[31m',
999
- `${describe} Failed:\n`,
1000
- `${rest[0]} => ${LISP.stringify(rest[1])} != ${LISP.stringify(
1001
- rest[2]
1002
- )}`,
1003
- '\n',
1004
- '\x1b[0m'
1005
- )
1006
- : console.log(
1007
- '\x1b[32m',
1008
- `${describe} Passed:\n`,
1009
- `${rest[0]} => ${LISP.stringify(rest[1])}`,
1010
- '\n',
1011
- '\x1b[0m'
1012
- )
1013
- )
1014
- } catch (err) {
1015
- console.log('\x1b[31m', 'Tests failed: \n', err.toString())
1016
- }
1017
- const result = !tests.length || tests.some(([t]) => !t)
1018
- result
1019
- ? console.log('\x1b[31m', 'Some tests failed!', '\n', '\x1b[0m')
1020
- : console.log('\x1b[32m', 'All tests passed!', '\n', '\x1b[0m')
1021
- return +!result
1022
- },
1023
- [KEYWORDS.SET_ARRAY]: (args, env) => {
1024
- if (args.length !== 2 && args.length !== 3)
1025
- throw new RangeError(
1026
- `Invalid number of arguments for (${
1027
- KEYWORDS.SET_ARRAY
1028
- }) (or 2 3) required (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
1029
- )
1030
- const array = evaluate(args[0], env)
1031
- if (!Array.isArray(array))
1032
- throw new TypeError(
1033
- `First argument of (${KEYWORDS.SET_ARRAY}) must be an (${
1034
- KEYWORDS.ARRAY_TYPE
1035
- }) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
1036
- )
1037
- const index = evaluate(args[1], env)
1038
- if (!Number.isInteger(index))
1039
- throw new TypeError(
1040
- `Second argument of (${KEYWORDS.SET_ARRAY}) must be an (${
1041
- KEYWORDS.NUMBER_TYPE
1042
- } integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
1043
- )
1044
- if (index > array.length)
1045
- throw new RangeError(
1046
- `Second argument of (${KEYWORDS.SET_ARRAY}) is outside of the (${
1047
- KEYWORDS.ARRAY_TYPE
1048
- }) bounds (index ${index} bounds ${array.length}) (${
1049
- KEYWORDS.SET_ARRAY
1050
- } ${stringifyArgs(args)})`
1051
- )
1052
- if (index < 0) {
1053
- if (args.length !== 2)
1054
- throw new RangeError(
1055
- `Invalid number of arguments for (${
1056
- KEYWORDS.SET_ARRAY
1057
- }) (if (< index 0) then 2 required) (${
1058
- KEYWORDS.SET_ARRAY
1059
- } ${stringifyArgs(args)})`
1060
- )
1061
- if (index * -1 > array.length)
1062
- throw new RangeError(
1063
- `Second argument of (${KEYWORDS.SET_ARRAY}) is outside of the (${
1064
- KEYWORDS.ARRAY_TYPE
1065
- }) bounds (index ${index} bounds ${array.length}) (${
1066
- KEYWORDS.SET_ARRAY
1067
- } ${stringifyArgs(args)})`
1068
- )
1069
- const target = array.length + index
1070
- while (array.length !== target) array.pop()
1071
- } else {
1072
- if (args.length !== 3)
1073
- throw new RangeError(
1074
- `Invalid number of arguments for (${
1075
- KEYWORDS.SET_ARRAY
1076
- }) (if (>= index 0) then 3 required) (${
1077
- KEYWORDS.SET_ARRAY
1078
- } ${stringifyArgs(args)})`
1079
- )
1080
- const value = evaluate(args[2], env)
1081
- if (value == undefined)
1082
- throw new RangeError(
1083
- `Trying to set a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
1084
- KEYWORDS.SET_ARRAY
1085
- }). (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
1086
- )
1087
- array[index] = value
1088
- }
1089
- return array
1090
- },
1091
- [KEYWORDS.LOG]: (args, env) => {
1092
- if (!args.length)
1093
- throw new RangeError(
1094
- `Invalid number of arguments to (${KEYWORDS.LOG}) (>= 1 required) (${
1095
- KEYWORDS.LOG
1096
- } ${stringifyArgs(args)})`
1097
- )
1098
- const expressions = args.map((x) => evaluate(x, env))
1099
- console.log(...expressions)
1100
- return expressions.at(-1)
1101
- },
1102
- [KEYWORDS.CLEAR_CONSOLE]: (args) => {
1103
- if (args.length)
1104
- throw new RangeError(
1105
- `Invalid number of arguments to (${
1106
- KEYWORDS.CLEAR_CONSOLE
1107
- }) (= 0 required) (${KEYWORDS.CLEAR_CONSOLE} ${stringifyArgs(args)})`
1108
- )
1109
- console.clear()
1110
- return 0
1111
- }
1112
- }
1113
- keywords[KEYWORDS.NOT_COMPILED_BLOCK] = keywords[KEYWORDS.BLOCK]
1114
- keywords[KEYWORDS.DOC] = (args, env) => {
1115
- if (args.length !== 1)
1116
- throw new RangeError(
1117
- `Invalid number of arguments to (${KEYWORDS.DOC}) (= 1 required) (${
1118
- KEYWORDS.DOC
1119
- } ${stringifyArgs(args)})`
1120
- )
1121
- const lib = evaluate(args[0], env)
1122
- const kw = Object.keys(env).map((x) => [x])
1123
- const standard = std.map(([_, [_0, name], [_1, ...arg]]) => {
1124
- const args = arg
1125
- .slice(0, -1)
1126
- .map((x) => x[VALUE])
1127
- .filter((x) => x !== 'lambda')
1128
-
1129
- return [name, ...args]
1130
- })
1131
- const all = [...kw, ...standard]
1132
- switch (lib) {
1133
- case '*':
1134
- return all.map((x) => `(${x.join(' ')})`)
1135
- case 'keywords':
1136
- return kw.map((x) => `(${x.join(' ')})`)
1137
- case 'std':
1138
- return standard.map((x) => `(${x.join(' ')})`)
1139
- default:
1140
- return all
1141
- .filter((name) => name[0].includes(lib))
1142
- .map((x) => `(${x.join(' ')})`)
1143
- }
1144
- }
1145
- export { keywords }