fez-lisp 1.2.62 → 1.3.0

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.
@@ -1,743 +1,783 @@
1
- import { TYPE, VALUE, WORD, KEYWORDS, FALSE, TRUE, TYPES } from './keywords.js'
2
- import { evaluate } from './evaluator.js'
3
- import { isForbiddenVariableName, stringifyArgs } from './utils.js'
4
- export const keywords = {
5
- [KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) => {
6
- if (args.length < 2)
7
- throw new RangeError(
8
- `Invalid number of arguments for (${
9
- KEYWORDS.REMAINDER_OF_DIVISION
10
- }), expected > 1 but got ${args.length}. (${
11
- KEYWORDS.REMAINDER_OF_DIVISION
12
- } ${stringifyArgs(args)})`
13
- )
14
- const a = evaluate(args[0], env)
15
- const b = evaluate(args[1], env)
16
- if (typeof a !== 'number' || typeof b !== 'number')
17
- throw new TypeError(
18
- `Not all arguments of (${KEYWORDS.REMAINDER_OF_DIVISION}) are (${
19
- KEYWORDS.NUMBER_TYPE
20
- }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
21
- )
22
- if (b === 0)
23
- throw new TypeError(
24
- `Second argument of (${
25
- KEYWORDS.REMAINDER_OF_DIVISION
26
- }) can't be a (0) (division by 0 is not allowed) (${
27
- KEYWORDS.REMAINDER_OF_DIVISION
28
- } ${stringifyArgs(args)})`
29
- )
30
-
31
- return a % b
32
- },
33
- [KEYWORDS.DIVISION]: (args, env) => {
34
- if (args.length === 1) {
35
- const number = evaluate(args[0], env)
36
- if (typeof number !== 'number')
37
- throw new TypeError(
38
- `Arguments of (${KEYWORDS.DIVISION}) is not a (${
39
- KEYWORDS.NUMBER_TYPE
40
- }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
41
- )
42
- if (number === 0)
43
- throw new TypeError(
44
- `Argument of (${
45
- KEYWORDS.DIVISION
46
- }) can't be a (0) (division by 0 is not allowed) (${
47
- KEYWORDS.DIVISION
48
- } ${stringifyArgs(args)})`
49
- )
50
- return 1 / number
51
- }
52
- const operands = args.map((x) => evaluate(x, env))
53
- if (operands.some((x) => typeof x !== 'number'))
54
- throw new TypeError(
55
- `Not all arguments of (${KEYWORDS.DIVISION}) are (${
56
- KEYWORDS.NUMBER_TYPE
57
- }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
58
- )
59
- if (operands.slice(1).some((x) => x === 0))
60
- throw new TypeError(
61
- `Argument of (${
62
- KEYWORDS.DIVISION
63
- }) can't be a (0) (division by 0 is not allowed) (${
64
- KEYWORDS.DIVISION
65
- } ${stringifyArgs(args)})`
66
- )
67
- return operands.reduce((a, b) => a / b)
68
- },
69
- [KEYWORDS.ARRAY_LENGTH]: (args, env) => {
70
- if (args.length !== 1)
71
- throw new RangeError(
72
- `Invalid number of arguments for (${
73
- KEYWORDS.ARRAY_LENGTH
74
- }) (= 1 required) (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
75
- )
76
- const array = evaluate(args[0], env)
77
- if (!Array.isArray(array))
78
- throw new TypeError(
79
- `First argument of (${KEYWORDS.ARRAY_LENGTH}) must be an ${
80
- KEYWORDS.ARRAY_TYPE
81
- } (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
82
- )
83
- return array.length
84
- },
85
- [KEYWORDS.IS_ATOM]: (args, env) => {
86
- if (args.length !== 1)
87
- throw new RangeError(
88
- `Invalid number of arguments for (${
89
- KEYWORDS.IS_ATOM
90
- }) (= 1 required) (${KEYWORDS.IS_ATOM} ${stringifyArgs(args)})`
91
- )
92
- return +(typeof evaluate(args[0], env) === 'number')
93
- },
94
- [KEYWORDS.IS_LAMBDA]: (args, env) => {
95
- if (args.length !== 1)
96
- throw new RangeError(
97
- `Invalid number of arguments for (${
98
- KEYWORDS.IS_LAMBDA
99
- }) (= 1 required) (${KEYWORDS.IS_LAMBDA} ${stringifyArgs(args)})`
100
- )
101
- return +(typeof evaluate(args[0], env) === 'function')
102
- },
103
- [KEYWORDS.ADDITION]: (args, env) => {
104
- if (args.length < 2)
105
- throw new RangeError(
106
- `Invalid number of arguments for (${
107
- KEYWORDS.ADDITION
108
- }), expected (or (> 1) (= 0)) but got ${args.length}. (${
109
- KEYWORDS.ADDITION
110
- } ${stringifyArgs(args)})`
111
- )
112
- const operands = args.map((x) => evaluate(x, env))
113
- if (operands.some((x) => typeof x !== 'number'))
114
- throw new TypeError(
115
- `Not all arguments of (${KEYWORDS.ADDITION}) are (${
116
- KEYWORDS.NUMBER_TYPE
117
- }) (${KEYWORDS.ADDITION} ${stringifyArgs(args)})`
118
- )
119
- return operands.reduce((a, b) => a + b)
120
- },
121
- [KEYWORDS.MULTIPLICATION]: (args, env) => {
122
- if (args.length < 2)
123
- throw new RangeError(
124
- `Invalid number of arguments for (${KEYWORDS.MULTIPLICATION}), expected (or (> 1) (= 0)) but got ${args.length}.`
125
- )
126
- const operands = args.map((x) => evaluate(x, env))
127
- if (operands.some((x) => typeof x !== 'number'))
128
- throw new TypeError(
129
- `Not all arguments of (${KEYWORDS.MULTIPLICATION}) are (${
130
- KEYWORDS.NUMBER_TYPE
131
- }) (${KEYWORDS.MULTIPLICATION} ${stringifyArgs(args)})`
132
- )
133
- return operands.reduce((a, b) => a * b)
134
- },
135
- [KEYWORDS.SUBTRACTION]: (args, env) => {
136
- if (!args.length)
137
- throw new RangeError(
138
- `Invalid number of arguments for (${
139
- KEYWORDS.SUBTRACTION
140
- }), expected >= 1 but got ${args.length}. (${
141
- KEYWORDS.SUBTRACTION
142
- } ${stringifyArgs(args)})`
143
- )
144
- const operands = args.map((x) => evaluate(x, env))
145
- if (operands.some((x) => typeof x !== 'number'))
146
- throw new TypeError(
147
- `Not all arguments of (${KEYWORDS.SUBTRACTION}) are (${
148
- KEYWORDS.NUMBER_TYPE
149
- }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)})`
150
- )
151
- return args.length === 1 ? -operands[0] : operands.reduce((a, b) => a - b)
152
- },
153
- [KEYWORDS.IF]: (args, env) => {
154
- if (args.length > 3 || args.length < 2)
155
- throw new RangeError(
156
- `Invalid number of arguments for (${
157
- KEYWORDS.IF
158
- }), expected (or (= 3) (= 2)) but got ${args.length} (${
159
- KEYWORDS.IF
160
- } ${stringifyArgs(args)})`
161
- )
162
- const condition = evaluate(args[0], env)
163
- if (condition !== FALSE && condition !== TRUE)
164
- throw new TypeError(
165
- `Condition of (${KEYWORDS.IF}) must be ${TRUE} or ${FALSE} but got (${
166
- KEYWORDS.IF
167
- } ${stringifyArgs(args)})`
168
- )
169
- return condition
170
- ? evaluate(args[1], env)
171
- : args.length === 3
172
- ? evaluate(args[2], env)
173
- : 0
174
- },
175
- [KEYWORDS.ARRAY_TYPE]: (args, env) => {
176
- return args.length ? args.map((x) => evaluate(x, env)) : []
177
- },
178
- [KEYWORDS.GET_ARRAY]: (args, env) => {
179
- if (args.length !== 2)
180
- throw new RangeError(
181
- `Invalid number of arguments for (${
182
- KEYWORDS.GET_ARRAY
183
- }) (= 2 required) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
184
- )
185
- const array = evaluate(args[0], env)
186
- if (!Array.isArray(array))
187
- throw new TypeError(
188
- `First argument of (${KEYWORDS.GET_ARRAY}) must be an (${
189
- KEYWORDS.ARRAY_TYPE
190
- })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
191
- )
192
- if (array.length === 0)
193
- throw new RangeError(
194
- `First argument of (${KEYWORDS.GET_ARRAY}) is an empty (${
195
- KEYWORDS.ARRAY_TYPE
196
- })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)}))`
197
- )
198
- const index = evaluate(args[1], env)
199
- if (!Number.isInteger(index))
200
- throw new TypeError(
201
- `Second argument of (${KEYWORDS.GET_ARRAY}) must be an (32 bit ${
202
- KEYWORDS.NUMBER_TYPE
203
- }) (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
204
- )
205
- if (index > array.length - 1 || index * -1 > array.length)
206
- throw new RangeError(
207
- `Second argument of (${KEYWORDS.GET_ARRAY}) is outside of (${
208
- KEYWORDS.ARRAY_TYPE
209
- }) bounds (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
210
- )
211
- const value = array.at(index)
212
- if (value == undefined)
213
- throw new RangeError(
214
- `Trying to get a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
215
- KEYWORDS.GET_ARRAY
216
- }) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
217
- )
218
- return value
219
- },
220
- [KEYWORDS.BLOCK]: (args, env) => {
221
- if (!args.length)
222
- throw new RangeError(
223
- `Invalid number of arguments to (${KEYWORDS.BLOCK}) (>= 1 required) (${
224
- KEYWORDS.BLOCK
225
- } ${stringifyArgs(args)})`
226
- )
227
- return args.reduce((_, x) => evaluate(x, env), 0)
228
- },
229
- [KEYWORDS.ANONYMOUS_FUNCTION]: (args, env) => {
230
- const params = args.slice(0, -1)
231
- const body = args.at(-1)
232
- return (props = [], scope) => {
233
- if (props.length !== params.length)
234
- throw new RangeError(
235
- `Incorrect number of arguments for (${
236
- KEYWORDS.ANONYMOUS_FUNCTION
237
- } ${stringifyArgs(params)}) are provided. (expects ${
238
- params.length
239
- } but got ${props.length}) (${
240
- KEYWORDS.ANONYMOUS_FUNCTION
241
- } ${stringifyArgs(args)})`
242
- )
243
- const localEnv = Object.create(env)
244
- // localEnv[KEYWORDS.BLOCK] = block[KEYWORDS.BLOCK]
245
- for (let i = 0; i < props.length; ++i) {
246
- const value = evaluate(props[i], scope)
247
- Object.defineProperty(localEnv, params[i][VALUE], {
248
- value,
249
- writable: true
250
- })
251
- }
252
- return evaluate(body, localEnv)
253
- }
254
- },
255
- [KEYWORDS.NOT]: (args, env) => {
256
- if (args.length !== 1)
257
- throw new RangeError(
258
- `Invalid number of arguments for (${KEYWORDS.NOT}) (= 1 required) (${
259
- KEYWORDS.NOT
260
- } ${stringifyArgs(args)})`
261
- )
262
- return +!evaluate(args[0], env)
263
- },
264
- [KEYWORDS.EQUAL]: (args, env) => {
265
- if (args.length !== 2)
266
- throw new RangeError(
267
- `Invalid number of arguments for (${KEYWORDS.EQUAL}) (= 2 required) (${
268
- KEYWORDS.EQUAL
269
- } ${stringifyArgs(args)})`
270
- )
271
- const a = evaluate(args[0], env)
272
- const b = evaluate(args[1], env)
273
- if (typeof a !== 'number')
274
- throw new TypeError(
275
- `Invalid use of (${KEYWORDS.EQUAL}), first argument is not an ${
276
- KEYWORDS.NUMBER_TYPE
277
- } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
278
- )
279
- if (typeof b !== 'number')
280
- throw new TypeError(
281
- `Invalid use of (${KEYWORDS.EQUAL}), second argument are not an ${
282
- KEYWORDS.NUMBER_TYPE
283
- } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
284
- )
285
- return +(a === b)
286
- },
287
- [KEYWORDS.LESS_THAN]: (args, env) => {
288
- if (args.length !== 2)
289
- throw new RangeError(
290
- `Invalid number of arguments for (${
291
- KEYWORDS.LESS_THAN
292
- }) (= 2 required) (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
293
- )
294
- const a = evaluate(args[0], env)
295
- const b = evaluate(args[1], env)
296
- if (typeof a !== 'number')
297
- throw new TypeError(
298
- `Invalid use of (${KEYWORDS.LESS_THAN}), first argument is not an ${
299
- KEYWORDS.NUMBER_TYPE
300
- } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
301
- )
302
- if (typeof b !== 'number')
303
- throw new TypeError(
304
- `Invalid use of (${KEYWORDS.LESS_THAN}), second argument are not an ${
305
- KEYWORDS.NUMBER_TYPE
306
- } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
307
- )
308
- return +(a < b)
309
- },
310
- [KEYWORDS.GREATHER_THAN]: (args, env) => {
311
- if (args.length !== 2)
312
- throw new RangeError(
313
- `Invalid number of arguments for (${
314
- KEYWORDS.GREATHER_THAN
315
- }) (= 2 required) (${KEYWORDS.GREATHER_THAN} ${stringifyArgs(args)})`
316
- )
317
- const a = evaluate(args[0], env)
318
- const b = evaluate(args[1], env)
319
- if (typeof a !== 'number')
320
- throw new TypeError(
321
- `Invalid use of (${KEYWORDS.GREATHER_THAN}), first argument is not an ${
322
- KEYWORDS.NUMBER_TYPE
323
- } (${KEYWORDS.GREATHER_THAN} ${stringifyArgs(args)})`
324
- )
325
- if (typeof b !== 'number')
326
- throw new TypeError(
327
- `Invalid use of (${
328
- KEYWORDS.GREATHER_THAN
329
- }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
330
- KEYWORDS.GREATHER_THAN
331
- } ${stringifyArgs(args)})`
332
- )
333
- return +(a > b)
334
- },
335
- [KEYWORDS.GREATHER_THAN_OR_EQUAL]: (args, env) => {
336
- if (args.length !== 2)
337
- throw new RangeError(
338
- `Invalid number of arguments for (${
339
- KEYWORDS.GREATHER_THAN_OR_EQUAL
340
- }) (= 2 required) (${KEYWORDS.GREATHER_THAN_OR_EQUAL} ${stringifyArgs(
341
- args
342
- )})`
343
- )
344
- const a = evaluate(args[0], env)
345
- const b = evaluate(args[1], env)
346
- if (typeof a !== 'number')
347
- throw new TypeError(
348
- `Invalid use of (${
349
- KEYWORDS.GREATHER_THAN_OR_EQUAL
350
- }), first argument is not an ${KEYWORDS.NUMBER_TYPE} (${
351
- KEYWORDS.GREATHER_THAN_OR_EQUAL
352
- } ${stringifyArgs(args)})`
353
- )
354
- if (typeof b !== 'number')
355
- throw new TypeError(
356
- `Invalid use of (${
357
- KEYWORDS.GREATHER_THAN_OR_EQUAL
358
- }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
359
- KEYWORDS.GREATHER_THAN_OR_EQUAL
360
- } ${stringifyArgs(args)})`
361
- )
362
- return +(a >= b)
363
- },
364
- [KEYWORDS.LESS_THAN_OR_EQUAL]: (args, env) => {
365
- if (args.length !== 2)
366
- throw new RangeError(
367
- `Invalid number of arguments for (${
368
- KEYWORDS.LESS_THAN_OR_EQUAL
369
- }) (= 2 required) (${KEYWORDS.LESS_THAN_OR_EQUAL} ${stringifyArgs(
370
- args
371
- )})`
372
- )
373
- const a = evaluate(args[0], env)
374
- const b = evaluate(args[1], env)
375
- if (typeof a !== 'number')
376
- throw new TypeError(
377
- `Invalid use of (${
378
- KEYWORDS.LESS_THAN_OR_EQUAL
379
- }), first argument is not an ${KEYWORDS.NUMBER_TYPE} (${
380
- KEYWORDS.LESS_THAN_OR_EQUAL
381
- } ${stringifyArgs(args)})`
382
- )
383
- if (typeof b !== 'number')
384
- throw new TypeError(
385
- `Invalid use of (${
386
- KEYWORDS.LESS_THAN_OR_EQUAL
387
- }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
388
- KEYWORDS.LESS_THAN_OR_EQUAL
389
- } ${stringifyArgs(args)})`
390
- )
391
- return +(a <= b)
392
- },
393
- [KEYWORDS.AND]: (args, env) => {
394
- if (args.length < 2)
395
- throw new RangeError(
396
- `Invalid number of arguments for (${KEYWORDS.AND}) (>= 2 required) (${
397
- KEYWORDS.AND
398
- } ${stringifyArgs(args)})`
399
- )
400
- let circuit
401
- for (let i = 0; i < args.length - 1; ++i) {
402
- circuit = evaluate(args[i], env)
403
- if (circuit !== FALSE && circuit !== TRUE)
404
- throw new TypeError(
405
- `Condition of (${
406
- KEYWORDS.AND
407
- }) must be ${TRUE} or ${FALSE} but got (${
408
- KEYWORDS.AND
409
- } ${stringifyArgs(args)})`
410
- )
411
- if (circuit) continue
412
- else return 0
413
- }
414
- const end = evaluate(args.at(-1), env)
415
- if (end !== FALSE && end !== TRUE)
416
- throw new TypeError(
417
- `Condition of (${KEYWORDS.AND}) must be ${TRUE} or ${FALSE} but got (${
418
- KEYWORDS.AND
419
- } ${stringifyArgs(args)})`
420
- )
421
- return end
422
- },
423
- [KEYWORDS.OR]: (args, env) => {
424
- if (args.length < 2)
425
- throw new RangeError(
426
- `Invalid number of arguments for (${KEYWORDS.OR}) (>= 2 required) (${
427
- KEYWORDS.OR
428
- } ${stringifyArgs(args)})`
429
- )
430
- let circuit
431
- for (let i = 0; i < args.length - 1; ++i) {
432
- circuit = evaluate(args[i], env)
433
- if (circuit !== FALSE && circuit !== TRUE)
434
- throw new TypeError(
435
- `Condition of (${KEYWORDS.OR}) must be ${TRUE} or ${FALSE} but got (${
436
- KEYWORDS.OR
437
- } ${stringifyArgs(args)})`
438
- )
439
- if (circuit) return 1
440
- else continue
441
- }
442
- const end = evaluate(args.at(-1), env)
443
- if (end !== FALSE && end !== TRUE)
444
- throw new TypeError(
445
- `Condition of (${KEYWORDS.OR}) must be ${TRUE} or ${FALSE} but got (${
446
- KEYWORDS.OR
447
- } ${stringifyArgs(args)})`
448
- )
449
- return end
450
- },
451
- [KEYWORDS.CALL_FUNCTION]: (args, env) => {
452
- if (!args.length)
453
- throw new RangeError(
454
- `Invalid number of arguments to (${
455
- KEYWORDS.CALL_FUNCTION
456
- }) (>= 1 required) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
457
- )
458
- const [first, ...rest] = args
459
- if (first[TYPE] === WORD && first[VALUE] in keywords)
460
- throw new TypeError(
461
- `Following argument of (${
462
- KEYWORDS.CALL_FUNCTION
463
- }) must not be an reserved word (${
464
- KEYWORDS.CALL_FUNCTION
465
- } ${stringifyArgs(args)})`
466
- )
467
- const apply = evaluate(first, env)
468
- if (typeof apply !== 'function')
469
- throw new TypeError(
470
- `First argument of (${KEYWORDS.CALL_FUNCTION}) must be a (${
471
- KEYWORDS.ANONYMOUS_FUNCTION
472
- }) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
473
- )
474
-
475
- return apply(rest, env)
476
- },
477
- [KEYWORDS.DEFINE_VARIABLE]: (args, env) => {
478
- if (args.length !== 2)
479
- throw new RangeError(
480
- `Invalid number of arguments to (${
481
- KEYWORDS.DEFINE_VARIABLE
482
- }) (= 2 required) (${KEYWORDS.DEFINE_VARIABLE} ${stringifyArgs(args)})`
483
- )
484
- const word = args[0]
485
- const type = word[TYPE]
486
- const name = word[VALUE]
487
- if (type !== WORD)
488
- throw new SyntaxError(
489
- `First argument of (${KEYWORDS.DEFINE_VARIABLE}) must be word but got ${
490
- TYPES[type]
491
- } (${KEYWORDS.DEFINE_VARIABLE} ${stringifyArgs(args)})`
492
- )
493
- else if (isForbiddenVariableName(name))
494
- throw new ReferenceError(
495
- `Variable name ${name} is forbidden at (${
496
- KEYWORDS.DEFINE_VARIABLE
497
- } ${stringifyArgs(args)})`
498
- )
499
- Object.defineProperty(env, name, {
500
- value: evaluate(args[1], env),
501
- writable: false
502
- })
503
- return env[name]
504
- },
505
- [KEYWORDS.BITWISE_AND]: (args, env) => {
506
- if (args.length < 2)
507
- throw new RangeError(
508
- `Invalid number of arguments to (${
509
- KEYWORDS.BITWISE_AND
510
- }) (>= 2 required). (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
511
- )
512
- const operands = args.map((a) => evaluate(a, env))
513
- if (operands.some((x) => typeof x !== 'number'))
514
- throw new TypeError(
515
- `Not all arguments of (${KEYWORDS.BITWISE_AND}) are ${
516
- KEYWORDS.NUMBER_TYPE
517
- } (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
518
- )
519
- return operands.reduce((acc, x) => acc & x)
520
- },
521
- [KEYWORDS.BITWISE_NOT]: (args, env) => {
522
- if (args.length !== 1)
523
- throw new RangeError(
524
- `Invalid number of arguments to (${
525
- KEYWORDS.BITWISE_NOT
526
- }) (= 1 required). (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
527
- )
528
- const operand = evaluate(args[0], env)
529
- if (typeof operand !== 'number')
530
- throw new TypeError(
531
- `Argument of (${KEYWORDS.BITWISE_NOT}) is not a (${
532
- KEYWORDS.NUMBER_TYPE
533
- }) (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
534
- )
535
- return ~operand
536
- },
537
- [KEYWORDS.BITWISE_OR]: (args, env) => {
538
- if (args.length < 2)
539
- throw new RangeError(
540
- `Invalid number of arguments to (${
541
- KEYWORDS.BITWISE_OR
542
- }) (>= 2 required). (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
543
- )
544
- const operands = args.map((a) => evaluate(a, env))
545
- if (operands.some((x) => typeof x !== 'number'))
546
- throw new TypeError(
547
- `Not all arguments of (${KEYWORDS.BITWISE_OR}) are (${
548
- KEYWORDS.NUMBER_TYPE
549
- }) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
550
- )
551
- return operands.reduce((acc, x) => acc | x)
552
- },
553
- [KEYWORDS.BITWISE_XOR]: (args, env) => {
554
- if (args.length < 2)
555
- throw new RangeError(
556
- `Invalid number of arguments to (${
557
- KEYWORDS.BITWISE_XOR
558
- }) (>= 2 required). (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
559
- )
560
- const operands = args.map((a) => evaluate(a, env))
561
- if (operands.some((x) => typeof x !== 'number'))
562
- throw new TypeError(
563
- `Not all arguments of (${KEYWORDS.BITWISE_XOR}) are (${
564
- KEYWORDS.NUMBER_TYPE
565
- }) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
566
- )
567
- return operands.reduce((acc, x) => acc ^ x)
568
- },
569
- [KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) => {
570
- if (args.length < 2)
571
- throw new RangeError(
572
- `Invalid number of arguments to (${
573
- KEYWORDS.BITWISE_LEFT_SHIFT
574
- }) (>= 2 required). (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(
575
- args
576
- )})`
577
- )
578
- const operands = args.map((a) => evaluate(a, env))
579
- if (operands.some((x) => typeof x !== 'number'))
580
- throw new TypeError(
581
- `Not all arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) are (${
582
- KEYWORDS.NUMBER_TYPE
583
- }) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)})`
584
- )
585
- return operands.reduce((acc, x) => acc << x)
586
- },
587
- [KEYWORDS.BITWISE_RIGHT_SHIFT]: (args, env) => {
588
- if (args.length < 2)
589
- throw new RangeError(
590
- `Invalid number of arguments to (${
591
- KEYWORDS.BITWISE_RIGHT_SHIFT
592
- }) (>= 2 required). (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(
593
- args
594
- )})`
595
- )
596
- const operands = args.map((a) => evaluate(a, env))
597
- if (operands.some((x) => typeof x !== 'number'))
598
- throw new TypeError(
599
- `Not all arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) are (${
600
- KEYWORDS.NUMBER_TYPE
601
- }) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)})`
602
- )
603
- return operands.reduce((acc, x) => acc >> x)
604
- },
605
- [KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT]: (args, env) => {
606
- if (args.length < 2)
607
- throw new RangeError(
608
- `Invalid number of arguments to (${
609
- KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
610
- }) (>= 2 required). (${
611
- KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
612
- } ${stringifyArgs(args)})`
613
- )
614
- const operands = args.map((a) => evaluate(a, env))
615
- if (operands.some((x) => typeof x !== 'number'))
616
- throw new TypeError(
617
- `Not all arguments of (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT}) are (${
618
- KEYWORDS.NUMBER_TYPE
619
- }) (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT} ${stringifyArgs(args)})`
620
- )
621
- return operands.reduce((acc, x) => acc >>> x)
622
- },
623
- [KEYWORDS.SET_ARRAY]: (args, env) => {
624
- if (args.length !== 1 && args.length !== 3)
625
- throw new RangeError(
626
- `Invalid number of arguments for (${
627
- KEYWORDS.SET_ARRAY
628
- }) (or 1 3) required (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
629
- )
630
- const array = evaluate(args[0], env)
631
- if (!Array.isArray(array))
632
- throw new TypeError(
633
- `First argument of (${KEYWORDS.SET_ARRAY}) must be an (${
634
- KEYWORDS.ARRAY_TYPE
635
- }) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
636
- )
637
- if (args.length === 1) {
638
- array.pop()
639
- } else {
640
- const index = evaluate(args[1], env)
641
- if (!Number.isInteger(index) || index < 0)
642
- throw new TypeError(
643
- `Second argument of (${KEYWORDS.SET_ARRAY}) must be a positive (${
644
- KEYWORDS.NUMBER_TYPE
645
- } integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
646
- )
647
- if (index > array.length)
648
- throw new RangeError(
649
- `Second argument of (${KEYWORDS.SET_ARRAY}) is outside of the (${
650
- KEYWORDS.ARRAY_TYPE
651
- }) bounds (index ${index} bounds ${array.length}) (${
652
- KEYWORDS.SET_ARRAY
653
- } ${stringifyArgs(args)})`
654
- )
655
- const value = evaluate(args[2], env)
656
- if (value == undefined)
657
- throw new RangeError(
658
- `Trying to set a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
659
- KEYWORDS.SET_ARRAY
660
- }). (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
661
- )
662
- array[index] = value
663
- }
664
- return array
665
- },
666
- [KEYWORDS.LOG]: (args, env) => {
667
- if (args.length !== 1)
668
- throw new RangeError(
669
- `Invalid number of arguments to (${KEYWORDS.LOG}) (= 1 required) (${
670
- KEYWORDS.LOG
671
- } ${stringifyArgs(args)})`
672
- )
673
- const expression = evaluate(args[0], env)
674
- console.log(expression)
675
- return expression
676
- },
677
- [KEYWORDS.LOG_STRING]: (args, env) => {
678
- if (args.length !== 1)
679
- throw new RangeError(
680
- `Invalid number of arguments to (${
681
- KEYWORDS.LOG_STRING
682
- }) (= 1 required) (${KEYWORDS.LOG_STRING} ${stringifyArgs(args)})`
683
- )
684
- const expression = evaluate(args[0], env)
685
- if (!Array.isArray(expression))
686
- throw new TypeError(
687
- `Argument of (${KEYWORDS.LOG_STRING}) must be an (${
688
- KEYWORDS.ARRAY_TYPE
689
- }) but got (${expression}) (${KEYWORDS.LOG_STRING} ${stringifyArgs(
690
- args
691
- )})`
692
- )
693
- console.log(expression.map((x) => String.fromCharCode(x)).join(''))
694
- return expression
695
- },
696
- [KEYWORDS.LOG_CHAR]: (args, env) => {
697
- if (args.length !== 1)
698
- throw new RangeError(
699
- `Invalid number of arguments to (${
700
- KEYWORDS.LOG_CHAR
701
- }) (= 1 required) (${KEYWORDS.LOG_CHAR} ${stringifyArgs(args)})`
702
- )
703
- const expression = evaluate(args[0], env)
704
- if (typeof expression !== 'number')
705
- throw new TypeError(
706
- `Argument of (${KEYWORDS.LOG_CHAR}) must be a (${
707
- KEYWORDS.NUMBER_TYPE
708
- }) but got (${expression}) (${KEYWORDS.LOG_CHAR} ${stringifyArgs(
709
- args
710
- )})`
711
- )
712
- console.log(String.fromCharCode(expression))
713
- return expression
714
- },
715
- [KEYWORDS.CLEAR_CONSOLE]: (args) => {
716
- if (args.length)
717
- throw new RangeError(
718
- `Invalid number of arguments to (${
719
- KEYWORDS.CLEAR_CONSOLE
720
- }) (= 0 required) (${KEYWORDS.CLEAR_CONSOLE} ${stringifyArgs(args)})`
721
- )
722
- console.clear()
723
- return 0
724
- },
725
-
726
- // Not sure about these
727
- [KEYWORDS.THROW]: (args, env) => {
728
- if (args.length !== 1)
729
- throw new RangeError(
730
- `Invalid number of arguments to (${KEYWORDS.THROW}) (= 1 required) (${
731
- KEYWORDS.THROW
732
- } ${stringifyArgs(args)})`
733
- )
734
- const expression = evaluate(args[0], env)
735
- if (!Array.isArray(expression))
736
- throw new TypeError(
737
- `Argument of (${KEYWORDS.THROW}) must be an (${
738
- KEYWORDS.ARRAY_TYPE
739
- }) but got (${expression}) (${KEYWORDS.THROW} ${stringifyArgs(args)})`
740
- )
741
- throw new Error(expression.map((x) => String.fromCharCode(x)).join(''))
742
- }
743
- }
1
+ import { TYPE, VALUE, WORD, KEYWORDS, FALSE, TRUE, TYPES } from './keywords.js'
2
+ import { evaluate } from './evaluator.js'
3
+ import { isForbiddenVariableName, stringifyArgs } from './utils.js'
4
+ export const keywords = {
5
+ [KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) => {
6
+ if (args.length < 2)
7
+ throw new RangeError(
8
+ `Invalid number of arguments for (${
9
+ KEYWORDS.REMAINDER_OF_DIVISION
10
+ }), expected > 1 but got ${args.length}. (${
11
+ KEYWORDS.REMAINDER_OF_DIVISION
12
+ } ${stringifyArgs(args)})`
13
+ )
14
+ const a = evaluate(args[0], env)
15
+ if (typeof a !== 'number')
16
+ throw new TypeError(
17
+ `First argument of (${KEYWORDS.REMAINDER_OF_DIVISION}) is not (${
18
+ KEYWORDS.NUMBER_TYPE
19
+ }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
20
+ )
21
+ const b = evaluate(args[1], env)
22
+ if (typeof b !== 'number')
23
+ throw new TypeError(
24
+ `Second argument of (${KEYWORDS.REMAINDER_OF_DIVISION}) is not (${
25
+ KEYWORDS.NUMBER_TYPE
26
+ }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
27
+ )
28
+ if (b === 0)
29
+ throw new TypeError(
30
+ `Second argument of (${
31
+ KEYWORDS.REMAINDER_OF_DIVISION
32
+ }) can't be a (0) (division by 0 is not allowed) (${
33
+ KEYWORDS.REMAINDER_OF_DIVISION
34
+ } ${stringifyArgs(args)})`
35
+ )
36
+
37
+ return a % b
38
+ },
39
+ [KEYWORDS.DIVISION]: (args, env) => {
40
+ if (args.length === 1) {
41
+ const number = evaluate(args[0], env)
42
+ if (typeof number !== 'number')
43
+ throw new TypeError(
44
+ `Arguments of (${KEYWORDS.DIVISION}) is not a (${
45
+ KEYWORDS.NUMBER_TYPE
46
+ }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
47
+ )
48
+ if (number === 0)
49
+ throw new TypeError(
50
+ `Argument of (${
51
+ KEYWORDS.DIVISION
52
+ }) can't be a (0) (division by 0 is not allowed) (${
53
+ KEYWORDS.DIVISION
54
+ } ${stringifyArgs(args)})`
55
+ )
56
+ return 1 / number
57
+ }
58
+ const a = evaluate(args[0], env)
59
+ if (typeof a !== 'number')
60
+ throw new TypeError(
61
+ `First argument of (${KEYWORDS.DIVISION}) is not (${
62
+ KEYWORDS.NUMBER_TYPE
63
+ }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
64
+ )
65
+ const b = evaluate(args[1], env)
66
+ if (typeof b !== 'number')
67
+ throw new TypeError(
68
+ `Second argument of (${KEYWORDS.DIVISION}) is not (${
69
+ KEYWORDS.NUMBER_TYPE
70
+ }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
71
+ )
72
+ if (b === 0)
73
+ throw new TypeError(
74
+ `Second Argument of (${
75
+ KEYWORDS.DIVISION
76
+ }) can't be a (0) (division by 0 is not allowed) (${
77
+ KEYWORDS.DIVISION
78
+ } ${stringifyArgs(args)})`
79
+ )
80
+ return a / b
81
+ },
82
+ [KEYWORDS.ARRAY_LENGTH]: (args, env) => {
83
+ if (args.length !== 1)
84
+ throw new RangeError(
85
+ `Invalid number of arguments for (${
86
+ KEYWORDS.ARRAY_LENGTH
87
+ }) (= 1 required) (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
88
+ )
89
+ const array = evaluate(args[0], env)
90
+ if (!Array.isArray(array))
91
+ throw new TypeError(
92
+ `First argument of (${KEYWORDS.ARRAY_LENGTH}) must be an ${
93
+ KEYWORDS.ARRAY_TYPE
94
+ } (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
95
+ )
96
+ return array.length
97
+ },
98
+ [KEYWORDS.IS_ATOM]: (args, env) => {
99
+ if (args.length !== 1)
100
+ throw new RangeError(
101
+ `Invalid number of arguments for (${
102
+ KEYWORDS.IS_ATOM
103
+ }) (= 1 required) (${KEYWORDS.IS_ATOM} ${stringifyArgs(args)})`
104
+ )
105
+ return +(typeof evaluate(args[0], env) === 'number')
106
+ },
107
+ [KEYWORDS.IS_LAMBDA]: (args, env) => {
108
+ if (args.length !== 1)
109
+ throw new RangeError(
110
+ `Invalid number of arguments for (${
111
+ KEYWORDS.IS_LAMBDA
112
+ }) (= 1 required) (${KEYWORDS.IS_LAMBDA} ${stringifyArgs(args)})`
113
+ )
114
+ return +(typeof evaluate(args[0], env) === 'function')
115
+ },
116
+ [KEYWORDS.ADDITION]: (args, env) => {
117
+ if (args.length !== 0 && args.length !== 2)
118
+ throw new RangeError(
119
+ `Invalid number of arguments for (${
120
+ KEYWORDS.ADDITION
121
+ }), expected (or (= 2) (= 0)) but got ${args.length}. (${
122
+ KEYWORDS.ADDITION
123
+ } ${stringifyArgs(args)})`
124
+ )
125
+ const a = evaluate(args[0], env)
126
+ if (typeof a !== 'number')
127
+ throw new TypeError(
128
+ `First arguments of (${KEYWORDS.ADDITION}) is not a (${
129
+ KEYWORDS.NUMBER_TYPE
130
+ }) (${KEYWORDS.ADDITION} ${stringifyArgs(args)})`
131
+ )
132
+ const b = evaluate(args[1], env)
133
+ if (typeof b !== 'number')
134
+ throw new TypeError(
135
+ `Second arguments of (${KEYWORDS.ADDITION}) is not a (${
136
+ KEYWORDS.NUMBER_TYPE
137
+ }) (${KEYWORDS.ADDITION} ${stringifyArgs(args)})`
138
+ )
139
+ return a + b
140
+ },
141
+ [KEYWORDS.MULTIPLICATION]: (args, env) => {
142
+ if (args.length !== 0 && args.length !== 2)
143
+ throw new RangeError(
144
+ `Invalid number of arguments for (${KEYWORDS.MULTIPLICATION}), expected (or (= 2) (= 0)) but got ${args.length}.`
145
+ )
146
+ const a = evaluate(args[0], env)
147
+ if (typeof a !== 'number')
148
+ throw new TypeError(
149
+ `First arguments of (${KEYWORDS.MULTIPLICATION}) is not a (${
150
+ KEYWORDS.NUMBER_TYPE
151
+ }) (${KEYWORDS.MULTIPLICATION} ${stringifyArgs(args)})`
152
+ )
153
+ const b = evaluate(args[1], env)
154
+ if (typeof b !== 'number')
155
+ throw new TypeError(
156
+ `Second arguments of (${KEYWORDS.MULTIPLICATION}) is not a (${
157
+ KEYWORDS.NUMBER_TYPE
158
+ }) (${KEYWORDS.MULTIPLICATION} ${stringifyArgs(args)})`
159
+ )
160
+ return a * b
161
+ },
162
+ [KEYWORDS.SUBTRACTION]: (args, env) => {
163
+ if (args.length !== 1 && args.length !== 2)
164
+ throw new RangeError(
165
+ `Invalid number of arguments for (${
166
+ KEYWORDS.SUBTRACTION
167
+ }), expected (or (= 1)) (= 2) but got ${args.length}. (${
168
+ KEYWORDS.SUBTRACTION
169
+ } ${stringifyArgs(args)})`
170
+ )
171
+ const a = evaluate(args[0], env)
172
+ if (typeof a !== 'number')
173
+ throw new TypeError(
174
+ `First argument of (${KEYWORDS.SUBTRACTION}) is not a (${
175
+ KEYWORDS.NUMBER_TYPE
176
+ }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)})`
177
+ )
178
+ if (args.length === 1) return -a
179
+ const b = evaluate(args[1], env)
180
+ if (typeof b !== 'number')
181
+ throw new TypeError(
182
+ `Second argument of (${KEYWORDS.SUBTRACTION}) is not a (${
183
+ KEYWORDS.NUMBER_TYPE
184
+ }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)})`
185
+ )
186
+ return a - b
187
+ },
188
+ [KEYWORDS.IF]: (args, env) => {
189
+ if (args.length > 3 || args.length < 2)
190
+ throw new RangeError(
191
+ `Invalid number of arguments for (${
192
+ KEYWORDS.IF
193
+ }), expected (or (= 3) (= 2)) but got ${args.length} (${
194
+ KEYWORDS.IF
195
+ } ${stringifyArgs(args)})`
196
+ )
197
+ const condition = evaluate(args[0], env)
198
+ if (condition !== FALSE && condition !== TRUE)
199
+ throw new TypeError(
200
+ `Condition of (${KEYWORDS.IF}) must be ${TRUE} or ${FALSE} but got (${
201
+ KEYWORDS.IF
202
+ } ${stringifyArgs(args)})`
203
+ )
204
+ return condition
205
+ ? evaluate(args[1], env)
206
+ : args.length === 3
207
+ ? evaluate(args[2], env)
208
+ : 0
209
+ },
210
+ [KEYWORDS.ARRAY_TYPE]: (args, env) => {
211
+ return args.length ? args.map((x) => evaluate(x, env)) : []
212
+ },
213
+ [KEYWORDS.GET_ARRAY]: (args, env) => {
214
+ if (args.length !== 2)
215
+ throw new RangeError(
216
+ `Invalid number of arguments for (${
217
+ KEYWORDS.GET_ARRAY
218
+ }) (= 2 required) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
219
+ )
220
+ const array = evaluate(args[0], env)
221
+ if (!Array.isArray(array))
222
+ throw new TypeError(
223
+ `First argument of (${KEYWORDS.GET_ARRAY}) must be an (${
224
+ KEYWORDS.ARRAY_TYPE
225
+ })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
226
+ )
227
+ if (array.length === 0)
228
+ throw new RangeError(
229
+ `First argument of (${KEYWORDS.GET_ARRAY}) is an empty (${
230
+ KEYWORDS.ARRAY_TYPE
231
+ })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)}))`
232
+ )
233
+ const index = evaluate(args[1], env)
234
+ if (!Number.isInteger(index))
235
+ throw new TypeError(
236
+ `Second argument of (${KEYWORDS.GET_ARRAY}) must be an (32 bit ${
237
+ KEYWORDS.NUMBER_TYPE
238
+ }) (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
239
+ )
240
+ if (index > array.length - 1 || index * -1 > array.length)
241
+ throw new RangeError(
242
+ `Second argument of (${KEYWORDS.GET_ARRAY}) is outside of (${
243
+ KEYWORDS.ARRAY_TYPE
244
+ }) bounds (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
245
+ )
246
+ const value = array.at(index)
247
+ if (value == undefined)
248
+ throw new RangeError(
249
+ `Trying to get a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
250
+ KEYWORDS.GET_ARRAY
251
+ }) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
252
+ )
253
+ return value
254
+ },
255
+ [KEYWORDS.BLOCK]: (args, env) => {
256
+ if (!args.length)
257
+ throw new RangeError(
258
+ `Invalid number of arguments to (${KEYWORDS.BLOCK}) (>= 1 required) (${
259
+ KEYWORDS.BLOCK
260
+ } ${stringifyArgs(args)})`
261
+ )
262
+ return args.reduce((_, x) => evaluate(x, env), 0)
263
+ },
264
+ [KEYWORDS.ANONYMOUS_FUNCTION]: (args, env) => {
265
+ const params = args.slice(0, -1)
266
+ const body = args.at(-1)
267
+ return (props = [], scope) => {
268
+ if (props.length !== params.length)
269
+ throw new RangeError(
270
+ `Incorrect number of arguments for (${
271
+ KEYWORDS.ANONYMOUS_FUNCTION
272
+ } ${stringifyArgs(params)}) are provided. (expects ${
273
+ params.length
274
+ } but got ${props.length}) (${
275
+ KEYWORDS.ANONYMOUS_FUNCTION
276
+ } ${stringifyArgs(args)})`
277
+ )
278
+ const localEnv = Object.create(env)
279
+ // localEnv[KEYWORDS.BLOCK] = block[KEYWORDS.BLOCK]
280
+ for (let i = 0; i < props.length; ++i) {
281
+ const value = evaluate(props[i], scope)
282
+ Object.defineProperty(localEnv, params[i][VALUE], {
283
+ value,
284
+ writable: true
285
+ })
286
+ }
287
+ return evaluate(body, localEnv)
288
+ }
289
+ },
290
+ [KEYWORDS.NOT]: (args, env) => {
291
+ if (args.length !== 1)
292
+ throw new RangeError(
293
+ `Invalid number of arguments for (${KEYWORDS.NOT}) (= 1 required) (${
294
+ KEYWORDS.NOT
295
+ } ${stringifyArgs(args)})`
296
+ )
297
+ return +!evaluate(args[0], env)
298
+ },
299
+ [KEYWORDS.EQUAL]: (args, env) => {
300
+ if (args.length !== 2)
301
+ throw new RangeError(
302
+ `Invalid number of arguments for (${KEYWORDS.EQUAL}) (= 2 required) (${
303
+ KEYWORDS.EQUAL
304
+ } ${stringifyArgs(args)})`
305
+ )
306
+ const a = evaluate(args[0], env)
307
+ const b = evaluate(args[1], env)
308
+ if (typeof a !== 'number')
309
+ throw new TypeError(
310
+ `Invalid use of (${KEYWORDS.EQUAL}), first argument is not an ${
311
+ KEYWORDS.NUMBER_TYPE
312
+ } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
313
+ )
314
+ if (typeof b !== 'number')
315
+ throw new TypeError(
316
+ `Invalid use of (${KEYWORDS.EQUAL}), second argument are not an ${
317
+ KEYWORDS.NUMBER_TYPE
318
+ } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
319
+ )
320
+ return +(a === b)
321
+ },
322
+ [KEYWORDS.LESS_THAN]: (args, env) => {
323
+ if (args.length !== 2)
324
+ throw new RangeError(
325
+ `Invalid number of arguments for (${
326
+ KEYWORDS.LESS_THAN
327
+ }) (= 2 required) (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
328
+ )
329
+ const a = evaluate(args[0], env)
330
+ const b = evaluate(args[1], env)
331
+ if (typeof a !== 'number')
332
+ throw new TypeError(
333
+ `Invalid use of (${KEYWORDS.LESS_THAN}), first argument is not an ${
334
+ KEYWORDS.NUMBER_TYPE
335
+ } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
336
+ )
337
+ if (typeof b !== 'number')
338
+ throw new TypeError(
339
+ `Invalid use of (${KEYWORDS.LESS_THAN}), second argument are not an ${
340
+ KEYWORDS.NUMBER_TYPE
341
+ } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
342
+ )
343
+ return +(a < b)
344
+ },
345
+ [KEYWORDS.GREATHER_THAN]: (args, env) => {
346
+ if (args.length !== 2)
347
+ throw new RangeError(
348
+ `Invalid number of arguments for (${
349
+ KEYWORDS.GREATHER_THAN
350
+ }) (= 2 required) (${KEYWORDS.GREATHER_THAN} ${stringifyArgs(args)})`
351
+ )
352
+ const a = evaluate(args[0], env)
353
+ const b = evaluate(args[1], env)
354
+ if (typeof a !== 'number')
355
+ throw new TypeError(
356
+ `Invalid use of (${KEYWORDS.GREATHER_THAN}), first argument is not an ${
357
+ KEYWORDS.NUMBER_TYPE
358
+ } (${KEYWORDS.GREATHER_THAN} ${stringifyArgs(args)})`
359
+ )
360
+ if (typeof b !== 'number')
361
+ throw new TypeError(
362
+ `Invalid use of (${
363
+ KEYWORDS.GREATHER_THAN
364
+ }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
365
+ KEYWORDS.GREATHER_THAN
366
+ } ${stringifyArgs(args)})`
367
+ )
368
+ return +(a > b)
369
+ },
370
+ [KEYWORDS.GREATHER_THAN_OR_EQUAL]: (args, env) => {
371
+ if (args.length !== 2)
372
+ throw new RangeError(
373
+ `Invalid number of arguments for (${
374
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
375
+ }) (= 2 required) (${KEYWORDS.GREATHER_THAN_OR_EQUAL} ${stringifyArgs(
376
+ args
377
+ )})`
378
+ )
379
+ const a = evaluate(args[0], env)
380
+ const b = evaluate(args[1], env)
381
+ if (typeof a !== 'number')
382
+ throw new TypeError(
383
+ `Invalid use of (${
384
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
385
+ }), first argument is not an ${KEYWORDS.NUMBER_TYPE} (${
386
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
387
+ } ${stringifyArgs(args)})`
388
+ )
389
+ if (typeof b !== 'number')
390
+ throw new TypeError(
391
+ `Invalid use of (${
392
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
393
+ }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
394
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
395
+ } ${stringifyArgs(args)})`
396
+ )
397
+ return +(a >= b)
398
+ },
399
+ [KEYWORDS.LESS_THAN_OR_EQUAL]: (args, env) => {
400
+ if (args.length !== 2)
401
+ throw new RangeError(
402
+ `Invalid number of arguments for (${
403
+ KEYWORDS.LESS_THAN_OR_EQUAL
404
+ }) (= 2 required) (${KEYWORDS.LESS_THAN_OR_EQUAL} ${stringifyArgs(
405
+ args
406
+ )})`
407
+ )
408
+ const a = evaluate(args[0], env)
409
+ const b = evaluate(args[1], env)
410
+ if (typeof a !== 'number')
411
+ throw new TypeError(
412
+ `Invalid use of (${
413
+ KEYWORDS.LESS_THAN_OR_EQUAL
414
+ }), first argument is not an ${KEYWORDS.NUMBER_TYPE} (${
415
+ KEYWORDS.LESS_THAN_OR_EQUAL
416
+ } ${stringifyArgs(args)})`
417
+ )
418
+ if (typeof b !== 'number')
419
+ throw new TypeError(
420
+ `Invalid use of (${
421
+ KEYWORDS.LESS_THAN_OR_EQUAL
422
+ }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
423
+ KEYWORDS.LESS_THAN_OR_EQUAL
424
+ } ${stringifyArgs(args)})`
425
+ )
426
+ return +(a <= b)
427
+ },
428
+ [KEYWORDS.AND]: (args, env) => {
429
+ if (args.length !== 2)
430
+ throw new RangeError(
431
+ `Invalid number of arguments for (${KEYWORDS.AND}) (= 2 required) (${
432
+ KEYWORDS.AND
433
+ } ${stringifyArgs(args)})`
434
+ )
435
+ let circuit
436
+ for (let i = 0; i < args.length - 1; ++i) {
437
+ circuit = evaluate(args[i], env)
438
+ if (circuit !== FALSE && circuit !== TRUE)
439
+ throw new TypeError(
440
+ `Condition of (${
441
+ KEYWORDS.AND
442
+ }) must be ${TRUE} or ${FALSE} but got (${
443
+ KEYWORDS.AND
444
+ } ${stringifyArgs(args)})`
445
+ )
446
+ if (circuit) continue
447
+ else return 0
448
+ }
449
+ const end = evaluate(args.at(-1), env)
450
+ if (end !== FALSE && end !== TRUE)
451
+ throw new TypeError(
452
+ `Condition of (${KEYWORDS.AND}) must be ${TRUE} or ${FALSE} but got (${
453
+ KEYWORDS.AND
454
+ } ${stringifyArgs(args)})`
455
+ )
456
+ return end
457
+ },
458
+ [KEYWORDS.OR]: (args, env) => {
459
+ if (args.length !== 2)
460
+ throw new RangeError(
461
+ `Invalid number of arguments for (${KEYWORDS.OR}) (= 2 required) (${
462
+ KEYWORDS.OR
463
+ } ${stringifyArgs(args)})`
464
+ )
465
+ let circuit
466
+ for (let i = 0; i < args.length - 1; ++i) {
467
+ circuit = evaluate(args[i], env)
468
+ if (circuit !== FALSE && circuit !== TRUE)
469
+ throw new TypeError(
470
+ `Condition of (${KEYWORDS.OR}) must be ${TRUE} or ${FALSE} but got (${
471
+ KEYWORDS.OR
472
+ } ${stringifyArgs(args)})`
473
+ )
474
+ if (circuit) return 1
475
+ else continue
476
+ }
477
+ const end = evaluate(args.at(-1), env)
478
+ if (end !== FALSE && end !== TRUE)
479
+ throw new TypeError(
480
+ `Condition of (${KEYWORDS.OR}) must be ${TRUE} or ${FALSE} but got (${
481
+ KEYWORDS.OR
482
+ } ${stringifyArgs(args)})`
483
+ )
484
+ return end
485
+ },
486
+ [KEYWORDS.CALL_FUNCTION]: (args, env) => {
487
+ if (!args.length)
488
+ throw new RangeError(
489
+ `Invalid number of arguments to (${
490
+ KEYWORDS.CALL_FUNCTION
491
+ }) (>= 1 required) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
492
+ )
493
+ const [first, ...rest] = args
494
+ if (first[TYPE] === WORD && first[VALUE] in keywords)
495
+ throw new TypeError(
496
+ `Following argument of (${
497
+ KEYWORDS.CALL_FUNCTION
498
+ }) must not be an reserved word (${
499
+ KEYWORDS.CALL_FUNCTION
500
+ } ${stringifyArgs(args)})`
501
+ )
502
+ const apply = evaluate(first, env)
503
+ if (typeof apply !== 'function')
504
+ throw new TypeError(
505
+ `First argument of (${KEYWORDS.CALL_FUNCTION}) must be a (${
506
+ KEYWORDS.ANONYMOUS_FUNCTION
507
+ }) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
508
+ )
509
+
510
+ return apply(rest, env)
511
+ },
512
+ [KEYWORDS.DEFINE_VARIABLE]: (args, env) => {
513
+ if (args.length !== 2)
514
+ throw new RangeError(
515
+ `Invalid number of arguments to (${
516
+ KEYWORDS.DEFINE_VARIABLE
517
+ }) (= 2 required) (${KEYWORDS.DEFINE_VARIABLE} ${stringifyArgs(args)})`
518
+ )
519
+ const word = args[0]
520
+ const type = word[TYPE]
521
+ const name = word[VALUE]
522
+ if (type !== WORD)
523
+ throw new SyntaxError(
524
+ `First argument of (${KEYWORDS.DEFINE_VARIABLE}) must be word but got ${
525
+ TYPES[type]
526
+ } (${KEYWORDS.DEFINE_VARIABLE} ${stringifyArgs(args)})`
527
+ )
528
+ else if (isForbiddenVariableName(name))
529
+ throw new ReferenceError(
530
+ `Variable name ${name} is forbidden at (${
531
+ KEYWORDS.DEFINE_VARIABLE
532
+ } ${stringifyArgs(args)})`
533
+ )
534
+ Object.defineProperty(env, name, {
535
+ value: evaluate(args[1], env),
536
+ writable: false
537
+ })
538
+ return env[name]
539
+ },
540
+ [KEYWORDS.BITWISE_AND]: (args, env) => {
541
+ if (args.length < 2)
542
+ throw new RangeError(
543
+ `Invalid number of arguments to (${
544
+ KEYWORDS.BITWISE_AND
545
+ }) (= 2 required). (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
546
+ )
547
+ const operands = args.map((a) => evaluate(a, env))
548
+ if (operands.some((x) => typeof x !== 'number'))
549
+ throw new TypeError(
550
+ `Not all arguments of (${KEYWORDS.BITWISE_AND}) are ${
551
+ KEYWORDS.NUMBER_TYPE
552
+ } (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
553
+ )
554
+ return operands.reduce((acc, x) => acc & x)
555
+ },
556
+ [KEYWORDS.BITWISE_NOT]: (args, env) => {
557
+ if (args.length !== 1)
558
+ throw new RangeError(
559
+ `Invalid number of arguments to (${
560
+ KEYWORDS.BITWISE_NOT
561
+ }) (= 1 required). (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
562
+ )
563
+ const operand = evaluate(args[0], env)
564
+ if (typeof operand !== 'number')
565
+ throw new TypeError(
566
+ `Argument of (${KEYWORDS.BITWISE_NOT}) is not a (${
567
+ KEYWORDS.NUMBER_TYPE
568
+ }) (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
569
+ )
570
+ return ~operand
571
+ },
572
+ [KEYWORDS.BITWISE_OR]: (args, env) => {
573
+ if (args.length !== 2)
574
+ throw new RangeError(
575
+ `Invalid number of arguments to (${
576
+ KEYWORDS.BITWISE_OR
577
+ }) (= 2 required). (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
578
+ )
579
+ const a = evaluate(args[0], env)
580
+ const b = evaluate(args[1], env)
581
+ if (typeof a !== 'number' || typeof b !== 'number')
582
+ throw new TypeError(
583
+ `Not all arguments of (${KEYWORDS.BITWISE_OR}) are (${
584
+ KEYWORDS.NUMBER_TYPE
585
+ }) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
586
+ )
587
+ return a | b
588
+ },
589
+ [KEYWORDS.BITWISE_XOR]: (args, env) => {
590
+ if (args.length !== 2)
591
+ throw new RangeError(
592
+ `Invalid number of arguments to (${
593
+ KEYWORDS.BITWISE_XOR
594
+ }) (= 2 required). (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
595
+ )
596
+ const a = evaluate(args[0], env)
597
+ const b = evaluate(args[1], env)
598
+ if (typeof a !== 'number' || typeof b !== 'number')
599
+ throw new TypeError(
600
+ `Not all arguments of (${KEYWORDS.BITWISE_XOR}) are (${
601
+ KEYWORDS.NUMBER_TYPE
602
+ }) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
603
+ )
604
+ return a ^ b
605
+ },
606
+ [KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) => {
607
+ if (args.length !== 2)
608
+ throw new RangeError(
609
+ `Invalid number of arguments to (${
610
+ KEYWORDS.BITWISE_LEFT_SHIFT
611
+ }) (= 2 required). (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(
612
+ args
613
+ )})`
614
+ )
615
+ const a = evaluate(args[0], env)
616
+ const b = evaluate(args[1], env)
617
+ if (typeof a !== 'number' || typeof b !== 'number')
618
+ throw new TypeError(
619
+ `Not all arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) are (${
620
+ KEYWORDS.NUMBER_TYPE
621
+ }) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)})`
622
+ )
623
+ return a << b
624
+ },
625
+ [KEYWORDS.BITWISE_RIGHT_SHIFT]: (args, env) => {
626
+ if (args.length !== 2)
627
+ throw new RangeError(
628
+ `Invalid number of arguments to (${
629
+ KEYWORDS.BITWISE_RIGHT_SHIFT
630
+ }) (= 2 required). (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(
631
+ args
632
+ )})`
633
+ )
634
+ const a = evaluate(args[0], env)
635
+ const b = evaluate(args[1], env)
636
+ if (typeof a !== 'number' || typeof b !== 'number')
637
+ throw new TypeError(
638
+ `Not all arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) are (${
639
+ KEYWORDS.NUMBER_TYPE
640
+ }) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)})`
641
+ )
642
+ return a >> b
643
+ },
644
+ [KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT]: (args, env) => {
645
+ if (args.length !== 2)
646
+ throw new RangeError(
647
+ `Invalid number of arguments to (${
648
+ KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
649
+ }) (= 2 required). (${
650
+ KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
651
+ } ${stringifyArgs(args)})`
652
+ )
653
+ const a = evaluate(args[0], env)
654
+ const b = evaluate(args[1], env)
655
+ if (typeof a !== 'number' || typeof b !== 'number')
656
+ throw new TypeError(
657
+ `Not all arguments of (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT}) are (${
658
+ KEYWORDS.NUMBER_TYPE
659
+ }) (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT} ${stringifyArgs(args)})`
660
+ )
661
+ return a >>> b
662
+ },
663
+ [KEYWORDS.SET_ARRAY]: (args, env) => {
664
+ if (args.length !== 1 && args.length !== 3)
665
+ throw new RangeError(
666
+ `Invalid number of arguments for (${
667
+ KEYWORDS.SET_ARRAY
668
+ }) (or 1 3) required (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
669
+ )
670
+ const array = evaluate(args[0], env)
671
+ if (!Array.isArray(array))
672
+ throw new TypeError(
673
+ `First argument of (${KEYWORDS.SET_ARRAY}) must be an (${
674
+ KEYWORDS.ARRAY_TYPE
675
+ }) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
676
+ )
677
+ if (args.length === 1) {
678
+ array.pop()
679
+ } else {
680
+ const index = evaluate(args[1], env)
681
+ if (!Number.isInteger(index) || index < 0)
682
+ throw new TypeError(
683
+ `Second argument of (${KEYWORDS.SET_ARRAY}) must be a positive (${
684
+ KEYWORDS.NUMBER_TYPE
685
+ } integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
686
+ )
687
+ if (index > array.length)
688
+ throw new RangeError(
689
+ `Second argument of (${KEYWORDS.SET_ARRAY}) is outside of the (${
690
+ KEYWORDS.ARRAY_TYPE
691
+ }) bounds (index ${index} bounds ${array.length}) (${
692
+ KEYWORDS.SET_ARRAY
693
+ } ${stringifyArgs(args)})`
694
+ )
695
+ const value = evaluate(args[2], env)
696
+ if (value == undefined)
697
+ throw new RangeError(
698
+ `Trying to set a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
699
+ KEYWORDS.SET_ARRAY
700
+ }). (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
701
+ )
702
+ array[index] = value
703
+ }
704
+ return array
705
+ },
706
+ [KEYWORDS.LOG]: (args, env) => {
707
+ if (args.length !== 1)
708
+ throw new RangeError(
709
+ `Invalid number of arguments to (${KEYWORDS.LOG}) (= 1 required) (${
710
+ KEYWORDS.LOG
711
+ } ${stringifyArgs(args)})`
712
+ )
713
+ const expression = evaluate(args[0], env)
714
+ console.log(expression)
715
+ return expression
716
+ },
717
+ [KEYWORDS.LOG_STRING]: (args, env) => {
718
+ if (args.length !== 1)
719
+ throw new RangeError(
720
+ `Invalid number of arguments to (${
721
+ KEYWORDS.LOG_STRING
722
+ }) (= 1 required) (${KEYWORDS.LOG_STRING} ${stringifyArgs(args)})`
723
+ )
724
+ const expression = evaluate(args[0], env)
725
+ if (!Array.isArray(expression))
726
+ throw new TypeError(
727
+ `Argument of (${KEYWORDS.LOG_STRING}) must be an (${
728
+ KEYWORDS.ARRAY_TYPE
729
+ }) but got (${expression}) (${KEYWORDS.LOG_STRING} ${stringifyArgs(
730
+ args
731
+ )})`
732
+ )
733
+ console.log(expression.map((x) => String.fromCharCode(x)).join(''))
734
+ return expression
735
+ },
736
+ [KEYWORDS.LOG_CHAR]: (args, env) => {
737
+ if (args.length !== 1)
738
+ throw new RangeError(
739
+ `Invalid number of arguments to (${
740
+ KEYWORDS.LOG_CHAR
741
+ }) (= 1 required) (${KEYWORDS.LOG_CHAR} ${stringifyArgs(args)})`
742
+ )
743
+ const expression = evaluate(args[0], env)
744
+ if (typeof expression !== 'number')
745
+ throw new TypeError(
746
+ `Argument of (${KEYWORDS.LOG_CHAR}) must be a (${
747
+ KEYWORDS.NUMBER_TYPE
748
+ }) but got (${expression}) (${KEYWORDS.LOG_CHAR} ${stringifyArgs(
749
+ args
750
+ )})`
751
+ )
752
+ console.log(String.fromCharCode(expression))
753
+ return expression
754
+ },
755
+ [KEYWORDS.CLEAR_CONSOLE]: (args) => {
756
+ if (args.length)
757
+ throw new RangeError(
758
+ `Invalid number of arguments to (${
759
+ KEYWORDS.CLEAR_CONSOLE
760
+ }) (= 0 required) (${KEYWORDS.CLEAR_CONSOLE} ${stringifyArgs(args)})`
761
+ )
762
+ console.clear()
763
+ return 0
764
+ },
765
+
766
+ // Not sure about these
767
+ [KEYWORDS.THROW]: (args, env) => {
768
+ if (args.length !== 1)
769
+ throw new RangeError(
770
+ `Invalid number of arguments to (${KEYWORDS.THROW}) (= 1 required) (${
771
+ KEYWORDS.THROW
772
+ } ${stringifyArgs(args)})`
773
+ )
774
+ const expression = evaluate(args[0], env)
775
+ if (!Array.isArray(expression))
776
+ throw new TypeError(
777
+ `Argument of (${KEYWORDS.THROW}) must be an (${
778
+ KEYWORDS.ARRAY_TYPE
779
+ }) but got (${expression}) (${KEYWORDS.THROW} ${stringifyArgs(args)})`
780
+ )
781
+ throw new Error(expression.map((x) => String.fromCharCode(x)).join(''))
782
+ }
783
+ }