fez-lisp 1.0.7 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
package/src/tokeniser.js CHANGED
@@ -17,14 +17,14 @@ const keywords = {
17
17
  keywords.CONCATENATION
18
18
  }), expected > 1 but got ${args.length}. (${
19
19
  keywords.CONCATENATION
20
- } ${stringifyArgs(args)}).`
20
+ } ${stringifyArgs(args)})`
21
21
  )
22
22
  const operands = args.map((x) => evaluate(x, env))
23
23
  if (operands.some((x) => typeof x !== 'string'))
24
24
  throw new TypeError(
25
25
  `Not all arguments of (${KEYWORDS.CONCATENATION}) are (${
26
26
  KEYWORDS.STRING_TYPE
27
- }) (${KEYWORDS.CONCATENATION} ${stringifyArgs(args)}).`
27
+ }) (${KEYWORDS.CONCATENATION} ${stringifyArgs(args)})`
28
28
  )
29
29
  return operands.reduce((a, b) => a + b, '')
30
30
  },
@@ -35,14 +35,14 @@ const keywords = {
35
35
  KEYWORDS.REMAINDER_OF_DIVISION
36
36
  }), expected > 1 but got ${args.length}. (${
37
37
  KEYWORDS.REMAINDER_OF_DIVISION
38
- } ${stringifyArgs(args)}).`
38
+ } ${stringifyArgs(args)})`
39
39
  )
40
40
  const [a, b] = args.map((x) => evaluate(x, env))
41
41
  if (typeof a !== 'number' || typeof b !== 'number')
42
42
  throw new TypeError(
43
43
  `Not all arguments of (${KEYWORDS.REMAINDER_OF_DIVISION}) are (${
44
44
  KEYWORDS.NUMBER_TYPE
45
- }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)}).`
45
+ }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
46
46
  )
47
47
  if (b === 0)
48
48
  throw new TypeError(
@@ -50,7 +50,7 @@ const keywords = {
50
50
  KEYWORDS.REMAINDER_OF_DIVISION
51
51
  }) can't be a (0) (division by 0 is not allowed) (${
52
52
  KEYWORDS.REMAINDER_OF_DIVISION
53
- } ${stringifyArgs(args)}).`
53
+ } ${stringifyArgs(args)})`
54
54
  )
55
55
 
56
56
  return a % b
@@ -63,7 +63,7 @@ const keywords = {
63
63
  throw new TypeError(
64
64
  `Arguments of (${KEYWORDS.DIVISION}) is not a (${
65
65
  KEYWORDS.NUMBER_TYPE
66
- }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)}).`
66
+ }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
67
67
  )
68
68
  if (number === 0)
69
69
  throw new TypeError(
@@ -71,7 +71,7 @@ const keywords = {
71
71
  KEYWORDS.DIVISION
72
72
  }) can't be a (0) (division by 0 is not allowed) (${
73
73
  KEYWORDS.DIVISION
74
- } ${stringifyArgs(args)}).`
74
+ } ${stringifyArgs(args)})`
75
75
  )
76
76
  return 1 / number
77
77
  }
@@ -80,7 +80,7 @@ const keywords = {
80
80
  throw new TypeError(
81
81
  `Not all arguments of (${KEYWORDS.DIVISION}) are (${
82
82
  KEYWORDS.NUMBER_TYPE
83
- }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)}).`
83
+ }) (${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
84
84
  )
85
85
  return operands.reduce((a, b) => a / b)
86
86
  },
@@ -91,7 +91,7 @@ const keywords = {
91
91
  KEYWORDS.ARRAY_OR_STRING_LENGTH
92
92
  }) (1 required) (${KEYWORDS.ARRAY_OR_STRING_LENGTH} ${stringifyArgs(
93
93
  args
94
- )}).`
94
+ )})`
95
95
  )
96
96
  const array = evaluate(args[0], env)
97
97
  if (!(Array.isArray(array) || typeof array === 'string'))
@@ -100,7 +100,7 @@ const keywords = {
100
100
  KEYWORDS.ARRAY_OR_STRING_LENGTH
101
101
  }) must be an (or ${KEYWORDS.ARRAY_TYPE} ${KEYWORDS.STRING_TYPE}) (${
102
102
  KEYWORDS.ARRAY_OR_STRING_LENGTH
103
- } ${stringifyArgs(args)}).`
103
+ } ${stringifyArgs(args)})`
104
104
  )
105
105
  return array.length
106
106
  },
@@ -109,7 +109,7 @@ const keywords = {
109
109
  throw new RangeError(
110
110
  `Invalid number of arguments for (${KEYWORDS.IS_ARRAY}) (1 required) (${
111
111
  KEYWORDS.IS_ARRAY
112
- } ${stringifyArgs(args)}).`
112
+ } ${stringifyArgs(args)})`
113
113
  )
114
114
  const array = evaluate(args[0], env)
115
115
  return +Array.isArray(array)
@@ -119,7 +119,7 @@ const keywords = {
119
119
  throw new RangeError(
120
120
  `Invalid number of arguments for (${
121
121
  KEYWORDS.IS_NUMBER
122
- }) (1 required) (${KEYWORDS.IS_NUMBER} ${stringifyArgs(args)}).`
122
+ }) (1 required) (${KEYWORDS.IS_NUMBER} ${stringifyArgs(args)})`
123
123
  )
124
124
  return +(typeof evaluate(args[0], env) === 'number')
125
125
  },
@@ -128,7 +128,7 @@ const keywords = {
128
128
  throw new RangeError(
129
129
  `Invalid number of arguments for (${
130
130
  KEYWORDS.IS_STRING
131
- }) (1 required) (${KEYWORDS.IS_STRING} ${stringifyArgs(args)}).`
131
+ }) (1 required) (${KEYWORDS.IS_STRING} ${stringifyArgs(args)})`
132
132
  )
133
133
  return +(typeof evaluate(args[0], env) === 'string')
134
134
  },
@@ -137,30 +137,31 @@ const keywords = {
137
137
  throw new RangeError(
138
138
  `Invalid number of arguments for (${
139
139
  KEYWORDS.IS_FUNCTION
140
- }) (1 required) (${KEYWORDS.IS_FUNCTION} ${stringifyArgs(args)}).`
140
+ }) (1 required) (${KEYWORDS.IS_FUNCTION} ${stringifyArgs(args)})`
141
141
  )
142
142
  return +(typeof evaluate(args[0], env) === 'function')
143
143
  },
144
144
  [KEYWORDS.ADDITION]: (args, env) => {
145
+ if (!args.length) return 0 // identity
145
146
  if (args.length < 2)
146
147
  throw new RangeError(
147
148
  `Invalid number of arguments for (${
148
149
  KEYWORDS.ADDITION
149
- }), expected > 1 but got ${args.length}. (${
150
+ }), expected (or (> 1) (= 0)) but got ${args.length}. (${
150
151
  KEYWORDS.ADDITION
151
- } ${stringifyArgs(args)}).`
152
+ } ${stringifyArgs(args)})`
152
153
  )
153
154
  const operands = args.map((x) => evaluate(x, env))
154
155
  if (operands.some((x) => typeof x !== 'number'))
155
156
  throw new TypeError(
156
157
  `Not all arguments of (${KEYWORDS.ADDITION}) are (${
157
158
  KEYWORDS.NUMBER_TYPE
158
- }) (${KEYWORDS.ADDITION} ${stringifyArgs(args)}).`
159
+ }) (${KEYWORDS.ADDITION} ${stringifyArgs(args)})`
159
160
  )
160
161
  return operands.reduce((a, b) => a + b)
161
162
  },
162
163
  [KEYWORDS.MULTIPLICATION]: (args, env) => {
163
- if (!args.length) return 1
164
+ if (!args.length) return 1 // identity
164
165
  if (args.length < 2)
165
166
  throw new RangeError(
166
167
  `Invalid number of arguments for (${KEYWORDS.MULTIPLICATION}), expected (or (> 1) (= 0)) but got ${args.length}.`
@@ -170,7 +171,7 @@ const keywords = {
170
171
  throw new TypeError(
171
172
  `Not all arguments of (${KEYWORDS.MULTIPLICATION}) are (${
172
173
  KEYWORDS.NUMBER_TYPE
173
- }) (${KEYWORDS.MULTIPLICATION} ${stringifyArgs(args)}).`
174
+ }) (${KEYWORDS.MULTIPLICATION} ${stringifyArgs(args)})`
174
175
  )
175
176
  return operands.reduce((a, b) => a * b)
176
177
  },
@@ -181,14 +182,14 @@ const keywords = {
181
182
  KEYWORDS.SUBTRACTION
182
183
  }), expected >= 1 but got ${args.length}. (${
183
184
  KEYWORDS.SUBTRACTION
184
- } ${stringifyArgs(args)}).`
185
+ } ${stringifyArgs(args)})`
185
186
  )
186
187
  const operands = args.map((x) => evaluate(x, env))
187
188
  if (operands.some((x) => typeof x !== 'number'))
188
189
  throw new TypeError(
189
190
  `Not all arguments of (${KEYWORDS.SUBTRACTION}) are (${
190
191
  KEYWORDS.NUMBER_TYPE
191
- }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)}).`
192
+ }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)})`
192
193
  )
193
194
  return args.length === 1 ? -operands[0] : operands.reduce((a, b) => a - b)
194
195
  },
@@ -199,7 +200,7 @@ const keywords = {
199
200
  KEYWORDS.IF
200
201
  }), expected (= 3) but got ${args.length} (${
201
202
  KEYWORDS.IF
202
- } ${stringifyArgs(args)}).`
203
+ } ${stringifyArgs(args)})`
203
204
  )
204
205
  return evaluate(args[0], env)
205
206
  ? evaluate(args[1], env)
@@ -212,7 +213,7 @@ const keywords = {
212
213
  KEYWORDS.UNLESS
213
214
  }), expected (= 3) but got ${args.length} (${
214
215
  KEYWORDS.UNLESS
215
- } ${stringifyArgs(args)}).`
216
+ } ${stringifyArgs(args)})`
216
217
  )
217
218
  return evaluate(args[0], env)
218
219
  ? evaluate(args[2], env)
@@ -225,7 +226,7 @@ const keywords = {
225
226
  KEYWORDS.WHEN
226
227
  }), expected 2 but got ${args.length} (${KEYWORDS.WHEN} ${stringifyArgs(
227
228
  args
228
- )}).`
229
+ )})`
229
230
  )
230
231
  return evaluate(args[0], env) ? evaluate(args[1], env) : 0
231
232
  },
@@ -236,7 +237,7 @@ const keywords = {
236
237
  KEYWORDS.OTHERWISE
237
238
  }), expected 2 but got ${args.length} (${
238
239
  KEYWORDS.OTHERWISE
239
- } ${stringifyArgs(args)}).`
240
+ } ${stringifyArgs(args)})`
240
241
  )
241
242
  return evaluate(args[0], env) ? 0 : evaluate(args[1], env)
242
243
  },
@@ -247,7 +248,7 @@ const keywords = {
247
248
  KEYWORDS.CONDITION
248
249
  }), expected (> 2 required) but got ${args.length} (${
249
250
  KEYWORDS.CONDITION
250
- } ${stringifyArgs(args)}).`
251
+ } ${stringifyArgs(args)})`
251
252
  )
252
253
  for (let i = 0; i < args.length; i += 2) {
253
254
  if (evaluate(args[i], env)) return evaluate(args[i + 1], env)
@@ -274,14 +275,14 @@ const keywords = {
274
275
  )
275
276
  return new Array(N).fill(0)
276
277
  }
277
- return Object.freeze(args.map((x) => evaluate(x, env)))
278
+ return args.map((x) => evaluate(x, env))
278
279
  },
279
280
  [KEYWORDS.IS_ATOM]: (args, env) => {
280
281
  if (args.length !== 1)
281
282
  throw new RangeError(
282
283
  `Invalid number of arguments for (${KEYWORDS.IS_ATOM}) (1 required) (${
283
284
  KEYWORDS.IS_ATOM
284
- } ${stringifyArgs(args)}).`
285
+ } ${stringifyArgs(args)})`
285
286
  )
286
287
  return isAtom(args[0], env)
287
288
  },
@@ -290,27 +291,27 @@ const keywords = {
290
291
  throw new RangeError(
291
292
  `Invalid number of arguments for (${
292
293
  KEYWORDS.FIRST_ARRAY
293
- }) (1 required) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)}).`
294
+ }) (1 required) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)})`
294
295
  )
295
296
  const array = evaluate(args[0], env)
296
297
  if (!Array.isArray(array))
297
298
  throw new TypeError(
298
299
  `Argument of (${KEYWORDS.FIRST_ARRAY}) must be an (${
299
300
  KEYWORDS.ARRAY_TYPE
300
- }) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)}).`
301
+ }) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)})`
301
302
  )
302
303
  if (array.length === 0)
303
304
  throw new RangeError(
304
305
  `Argument of (${KEYWORDS.FIRST_ARRAY}) is an empty (${
305
306
  KEYWORDS.ARRAY_TYPE
306
- }) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)}).`
307
+ }) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)})`
307
308
  )
308
309
  const value = array.at(0)
309
310
  if (value == undefined)
310
311
  throw new RangeError(
311
312
  `Trying to get a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
312
313
  KEYWORDS.FIRST_ARRAY
313
- }) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)}).`
314
+ }) (${KEYWORDS.FIRST_ARRAY} ${stringifyArgs(args)})`
314
315
  )
315
316
  return value
316
317
  },
@@ -326,13 +327,13 @@ const keywords = {
326
327
  throw new TypeError(
327
328
  `Argument of (${KEYWORDS.REST_ARRAY}) must be an (${
328
329
  KEYWORDS.ARRAY_TYPE
329
- }) (${KEYWORDS.REST_ARRAY} ${stringifyArgs(args)}).`
330
+ }) (${KEYWORDS.REST_ARRAY} ${stringifyArgs(args)})`
330
331
  )
331
332
  if (array.length === 0)
332
333
  throw new RangeError(
333
334
  `Argument of (${KEYWORDS.REST_ARRAY}) is an empty (${
334
335
  KEYWORDS.ARRAY_TYPE
335
- }) (${KEYWORDS.REST_ARRAY} ${stringifyArgs(args)}).`
336
+ }) (${KEYWORDS.REST_ARRAY} ${stringifyArgs(args)})`
336
337
  )
337
338
  return array.slice(1)
338
339
  },
@@ -348,33 +349,33 @@ const keywords = {
348
349
  throw new TypeError(
349
350
  `First argument of (${KEYWORDS.GET_ARRAY}) must be an (${
350
351
  KEYWORDS.ARRAY_TYPE
351
- })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)}).`
352
+ })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
352
353
  )
353
354
  if (array.length === 0)
354
355
  throw new RangeError(
355
356
  `First argument of (${KEYWORDS.GET_ARRAY}) is an empty (${
356
357
  KEYWORDS.ARRAY_TYPE
357
- })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})).`
358
+ })) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)}))`
358
359
  )
359
360
  const index = evaluate(args[1], env)
360
361
  if (!Number.isInteger(index))
361
362
  throw new TypeError(
362
363
  `Second argument of (${KEYWORDS.GET_ARRAY}) must be an (32 bit ${
363
364
  KEYWORDS.NUMBER_TYPE
364
- }) (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)}).`
365
+ }) (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
365
366
  )
366
367
  if (index > array.length - 1 || index * -1 > array.length)
367
368
  throw new RangeError(
368
369
  `Second argument of (${KEYWORDS.GET_ARRAY}) is outside of (${
369
370
  KEYWORDS.ARRAY_TYPE
370
- }) bounds (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)}).`
371
+ }) bounds (${index}) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
371
372
  )
372
373
  const value = array.at(index)
373
374
  if (value == undefined)
374
375
  throw new RangeError(
375
376
  `Trying to get a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
376
377
  KEYWORDS.GET_ARRAY
377
- }) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)}).`
378
+ }) (${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
378
379
  )
379
380
  return value
380
381
  },
@@ -389,20 +390,6 @@ const keywords = {
389
390
  console.log(...expressions)
390
391
  return expressions.at(-1)
391
392
  },
392
- [KEYWORDS.READ]: (args, env) => {
393
- if (args.length)
394
- throw new RangeError(
395
- `Invalid number of arguments to (${KEYWORDS.READ}) (= 0 required) (${
396
- KEYWORDS.READ
397
- } ${stringifyArgs(args)})`
398
- )
399
- const inp = env[KEYWORDS.INPUT]
400
- if (inp.length) return inp
401
- else
402
- throw new ReferenceError(
403
- `${KEYWORDS.INPUT} is empty! at (${KEYWORDS.READ})`
404
- )
405
- },
406
393
  [KEYWORDS.BLOCK]: (args, env) => {
407
394
  if (!args.length)
408
395
  throw new RangeError(
@@ -454,15 +441,16 @@ const keywords = {
454
441
  )
455
442
  const a = evaluate(args[0], env)
456
443
  const b = evaluate(args[1], env)
457
- if (
458
- Array.isArray(a) ||
459
- Array.isArray(b) ||
460
- typeof a === 'function' ||
461
- typeof b === 'function'
462
- )
444
+ if (typeof a !== 'number')
463
445
  throw new TypeError(
464
- `Invalid use of (${KEYWORDS.EQUAL}), some arguments are not an ${
465
- KEYWORDS.ATOM
446
+ `Invalid use of (${KEYWORDS.EQUAL}), first arguments are not an ${
447
+ KEYWORDS.NUMBER_TYPE
448
+ } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
449
+ )
450
+ if (typeof b !== 'number')
451
+ throw new TypeError(
452
+ `Invalid use of (${KEYWORDS.EQUAL}), second argument are not an ${
453
+ KEYWORDS.NUMBER_TYPE
466
454
  } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
467
455
  )
468
456
  return +(a === b)
@@ -476,15 +464,16 @@ const keywords = {
476
464
  )
477
465
  const a = evaluate(args[0], env)
478
466
  const b = evaluate(args[1], env)
479
- if (
480
- Array.isArray(a) ||
481
- Array.isArray(b) ||
482
- typeof a === 'function' ||
483
- typeof b === 'function'
484
- )
467
+ if (typeof a !== 'number')
468
+ throw new TypeError(
469
+ `Invalid use of (${KEYWORDS.LESS_THAN}), first arguments are not an ${
470
+ KEYWORDS.NUMBER_TYPE
471
+ } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
472
+ )
473
+ if (typeof b !== 'number')
485
474
  throw new TypeError(
486
- `Invalid use of (${KEYWORDS.LESS_THAN}), some arguments are not an ${
487
- KEYWORDS.ATOM
475
+ `Invalid use of (${KEYWORDS.LESS_THAN}), second argument are not an ${
476
+ KEYWORDS.NUMBER_TYPE
488
477
  } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
489
478
  )
490
479
  return +(a < b)
@@ -498,16 +487,19 @@ const keywords = {
498
487
  )
499
488
  const a = evaluate(args[0], env)
500
489
  const b = evaluate(args[1], env)
501
- if (
502
- Array.isArray(a) ||
503
- Array.isArray(b) ||
504
- typeof a === 'function' ||
505
- typeof b === 'function'
506
- )
490
+ if (typeof a !== 'number')
507
491
  throw new TypeError(
508
492
  `Invalid use of (${
509
493
  KEYWORDS.GREATHER_THAN
510
- }), some arguments are not an ${KEYWORDS.ATOM} (${
494
+ }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
495
+ KEYWORDS.GREATHER_THAN
496
+ } ${stringifyArgs(args)})`
497
+ )
498
+ if (typeof b !== 'number')
499
+ throw new TypeError(
500
+ `Invalid use of (${
501
+ KEYWORDS.GREATHER_THAN
502
+ }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
511
503
  KEYWORDS.GREATHER_THAN
512
504
  } ${stringifyArgs(args)})`
513
505
  )
@@ -524,16 +516,19 @@ const keywords = {
524
516
  )
525
517
  const a = evaluate(args[0], env)
526
518
  const b = evaluate(args[1], env)
527
- if (
528
- Array.isArray(a) ||
529
- Array.isArray(b) ||
530
- typeof a === 'function' ||
531
- typeof b === 'function'
532
- )
519
+ if (typeof a !== 'number')
520
+ throw new TypeError(
521
+ `Invalid use of (${
522
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
523
+ }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
524
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
525
+ } ${stringifyArgs(args)})`
526
+ )
527
+ if (typeof b !== 'number')
533
528
  throw new TypeError(
534
529
  `Invalid use of (${
535
530
  KEYWORDS.GREATHER_THAN_OR_EQUAL
536
- }), some arguments are not an ${KEYWORDS.ATOM} (${
531
+ }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
537
532
  KEYWORDS.GREATHER_THAN_OR_EQUAL
538
533
  } ${stringifyArgs(args)})`
539
534
  )
@@ -548,16 +543,19 @@ const keywords = {
548
543
  )
549
544
  const a = evaluate(args[0], env)
550
545
  const b = evaluate(args[1], env)
551
- if (
552
- Array.isArray(a) ||
553
- Array.isArray(b) ||
554
- typeof a === 'function' ||
555
- typeof b === 'function'
556
- )
546
+ if (typeof a !== 'number')
557
547
  throw new TypeError(
558
548
  `Invalid use of (${
559
549
  KEYWORDS.LESS_THAN_OR_EQUAL
560
- }), some arguments are not an ${KEYWORDS.ATOM} (${
550
+ }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
551
+ KEYWORDS.LESS_THAN_OR_EQUAL
552
+ } ${stringifyArgs(args)})`
553
+ )
554
+ if (typeof b !== 'number')
555
+ throw new TypeError(
556
+ `Invalid use of (${
557
+ KEYWORDS.LESS_THAN_OR_EQUAL
558
+ }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
561
559
  KEYWORDS.LESS_THAN_OR_EQUAL
562
560
  } ${stringifyArgs(args)})`
563
561
  )
@@ -671,7 +669,7 @@ const keywords = {
671
669
  KEYWORDS.NUMBER_TYPE
672
670
  } ("${value}") to a ${KEYWORDS.NUMBER_TYPE} at (${
673
671
  KEYWORDS.CAST_TYPE
674
- }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)}).`
672
+ }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)})`
675
673
  )
676
674
  return num
677
675
  }
@@ -681,14 +679,14 @@ const keywords = {
681
679
  return +!!value
682
680
  case KEYWORDS.ARRAY_TYPE: {
683
681
  if (typeof value === 'number')
684
- return Object.freeze([...Number(value).toString()].map(Number))
682
+ return [...Number(value).toString()].map(Number)
685
683
  else if (typeof value[Symbol.iterator] !== 'function')
686
684
  throw new TypeError(
687
685
  `Arguments are not iterable for ${KEYWORDS.ARRAY_TYPE} at (${
688
686
  KEYWORDS.CAST_TYPE
689
- }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)}).`
687
+ }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)})`
690
688
  )
691
- return Object.freeze([...value])
689
+ return [...value]
692
690
  }
693
691
  case KEYWORDS.CHAR_TYPE: {
694
692
  const index = evaluate(args[0], env)
@@ -698,7 +696,7 @@ const keywords = {
698
696
  KEYWORDS.CHAR_TYPE
699
697
  } at (${KEYWORDS.CAST_TYPE}) (${
700
698
  KEYWORDS.CAST_TYPE
701
- } ${stringifyArgs(args)}).`
699
+ } ${stringifyArgs(args)})`
702
700
  )
703
701
  return String.fromCharCode(index)
704
702
  }
@@ -710,7 +708,7 @@ const keywords = {
710
708
  KEYWORDS.CHAR_CODE_TYPE
711
709
  } at (${KEYWORDS.CAST_TYPE}) (${
712
710
  KEYWORDS.CAST_TYPE
713
- } ${stringifyArgs(args)}).`
711
+ } ${stringifyArgs(args)})`
714
712
  )
715
713
  if (string.length !== 1)
716
714
  throw new RangeError(
@@ -718,7 +716,7 @@ const keywords = {
718
716
  KEYWORDS.CHAR_CODE_TYPE
719
717
  } at (${KEYWORDS.CAST_TYPE}) (${
720
718
  KEYWORDS.CAST_TYPE
721
- } ${stringifyArgs(args)}).`
719
+ } ${stringifyArgs(args)})`
722
720
  )
723
721
  return string.charCodeAt(0)
724
722
  }
@@ -730,7 +728,7 @@ const keywords = {
730
728
  KEYWORDS.CHAR_TYPE
731
729
  } ${KEYWORDS.CHAR_CODE_TYPE}) at (${KEYWORDS.CAST_TYPE}) (${
732
730
  KEYWORDS.CAST_TYPE
733
- } ${stringifyArgs(args)}).`
731
+ } ${stringifyArgs(args)})`
734
732
  )
735
733
  }
736
734
  }
@@ -747,7 +745,7 @@ const keywords = {
747
745
  throw new TypeError(
748
746
  `Not all arguments of (${KEYWORDS.BITWISE_AND}) are ${
749
747
  KEYWORDS.NUMBER_TYPE
750
- } (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)}).`
748
+ } (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
751
749
  )
752
750
  return operands.reduce((acc, x) => acc & x)
753
751
  },
@@ -763,7 +761,7 @@ const keywords = {
763
761
  throw new TypeError(
764
762
  `Argument of (${KEYWORDS.BITWISE_NOT}) is not a (${
765
763
  KEYWORDS.NUMBER_TYPE
766
- }) (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)}).`
764
+ }) (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
767
765
  )
768
766
  return ~operand
769
767
  },
@@ -779,7 +777,7 @@ const keywords = {
779
777
  throw new TypeError(
780
778
  `Not all arguments of (${KEYWORDS.BITWISE_OR}) are (${
781
779
  KEYWORDS.NUMBER_TYPE
782
- }) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)}).`
780
+ }) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
783
781
  )
784
782
  return operands.reduce((acc, x) => acc | x)
785
783
  },
@@ -788,14 +786,14 @@ const keywords = {
788
786
  throw new RangeError(
789
787
  `Invalid number of arguments to (${
790
788
  KEYWORDS.BITWISE_XOR
791
- }) (>= 2 required). (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)}).`
789
+ }) (>= 2 required). (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
792
790
  )
793
791
  const operands = args.map((a) => evaluate(a, env))
794
792
  if (operands.some((x) => typeof x !== 'number'))
795
793
  throw new TypeError(
796
794
  `Not all arguments of (${KEYWORDS.BITWISE_XOR}) are (${
797
795
  KEYWORDS.NUMBER_TYPE
798
- }) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)}).`
796
+ }) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
799
797
  )
800
798
  return operands.reduce((acc, x) => acc ^ x)
801
799
  },
@@ -806,14 +804,14 @@ const keywords = {
806
804
  KEYWORDS.BITWISE_LEFT_SHIFT
807
805
  }) (>= 2 required). (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(
808
806
  args
809
- )}).`
807
+ )})`
810
808
  )
811
809
  const operands = args.map((a) => evaluate(a, env))
812
810
  if (operands.some((x) => typeof x !== 'number'))
813
811
  throw new TypeError(
814
812
  `Not all arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) are (${
815
813
  KEYWORDS.NUMBER_TYPE
816
- }) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)}).`
814
+ }) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)})`
817
815
  )
818
816
  return operands.reduce((acc, x) => acc << x)
819
817
  },
@@ -824,14 +822,14 @@ const keywords = {
824
822
  KEYWORDS.BITWISE_RIGHT_SHIFT
825
823
  }) (>= 2 required). (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(
826
824
  args
827
- )}).`
825
+ )})`
828
826
  )
829
827
  const operands = args.map((a) => evaluate(a, env))
830
828
  if (operands.some((x) => typeof x !== 'number'))
831
829
  throw new TypeError(
832
830
  `Not all arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) are (${
833
831
  KEYWORDS.NUMBER_TYPE
834
- }) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)}).`
832
+ }) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)})`
835
833
  )
836
834
  return operands.reduce((acc, x) => acc >> x)
837
835
  },
@@ -842,14 +840,14 @@ const keywords = {
842
840
  KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
843
841
  }) (>= 2 required). (${
844
842
  KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
845
- } ${stringifyArgs(args)}).`
843
+ } ${stringifyArgs(args)})`
846
844
  )
847
845
  const operands = args.map((a) => evaluate(a, env))
848
846
  if (operands.some((x) => typeof x !== 'number'))
849
847
  throw new TypeError(
850
848
  `Not all arguments of (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT}) are (${
851
849
  KEYWORDS.NUMBER_TYPE
852
- }) (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT} ${stringifyArgs(args)}).`
850
+ }) (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT} ${stringifyArgs(args)})`
853
851
  )
854
852
  return operands.reduce((acc, x) => acc >>> x)
855
853
  },
@@ -879,14 +877,14 @@ const keywords = {
879
877
  throw new RangeError(
880
878
  `Invalid number of arguments to (${
881
879
  KEYWORDS.THROW_ERROR
882
- }) (1 required). (${KEYWORDS.THROW_ERROR} ${stringifyArgs(args)}).`
880
+ }) (1 required). (${KEYWORDS.THROW_ERROR} ${stringifyArgs(args)})`
883
881
  )
884
882
  const string = evaluate(args[0], env)
885
883
  if (typeof string !== 'string')
886
884
  throw new TypeError(
887
885
  `First argument of (${KEYWORDS.THROW_ERROR}) must be an (${
888
886
  KEYWORDS.STRING_TYPE
889
- }) (${KEYWORDS.THROW_ERROR} ${stringifyArgs(args)}).`
887
+ }) (${KEYWORDS.THROW_ERROR} ${stringifyArgs(args)})`
890
888
  )
891
889
  throw new Error(string)
892
890
  },
@@ -895,16 +893,16 @@ const keywords = {
895
893
  throw new RangeError(
896
894
  `Invalid number of arguments to (${KEYWORDS.MERGE}) (>= 2 required). (${
897
895
  KEYWORDS.MERGE
898
- } ${stringifyArgs(args)}).`
896
+ } ${stringifyArgs(args)})`
899
897
  )
900
898
  const arrays = args.map((arg) => evaluate(arg, env))
901
899
  if (arrays.some((maybe) => !Array.isArray(maybe)))
902
900
  throw new TypeError(
903
901
  `Arguments of (${KEYWORDS.MERGE}) must be (${KEYWORDS.ARRAY_TYPE}) (${
904
902
  KEYWORDS.MERGE
905
- } ${stringifyArgs(args)}).`
903
+ } ${stringifyArgs(args)})`
906
904
  )
907
- return Object.freeze(arrays.reduce((a, b) => a.concat(b), []))
905
+ return arrays.reduce((a, b) => a.concat(b), [])
908
906
  },
909
907
  [KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION]: (args, env) => {
910
908
  if (!args.length)
@@ -913,7 +911,7 @@ const keywords = {
913
911
  KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION
914
912
  }) (>= 2 required). (${
915
913
  KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION
916
- } ${stringifyArgs(args)}).`
914
+ } ${stringifyArgs(args)})`
917
915
  )
918
916
  // TODO: Add validation for TCO recursion
919
917
  return keywords[KEYWORDS.DEFINE_VARIABLE](args, env)
@@ -925,7 +923,7 @@ const keywords = {
925
923
  KEYWORDS.IMMUTABLE_FUNCTION
926
924
  }) (>= 2 required). (${KEYWORDS.IMMUTABLE_FUNCTION} ${stringifyArgs(
927
925
  args
928
- )}).`
926
+ )})`
929
927
  )
930
928
  const [definition, ...functionArgs] = args
931
929
  const token = definition[VALUE]
@@ -1024,14 +1022,14 @@ const keywords = {
1024
1022
  throw new TypeError(
1025
1023
  `First argument of (${KEYWORDS.SET_ARRAY}) must be an (${
1026
1024
  KEYWORDS.ARRAY_TYPE
1027
- }) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)}).`
1025
+ }) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
1028
1026
  )
1029
1027
  const index = evaluate(args[1], env)
1030
1028
  if (!Number.isInteger(index))
1031
1029
  throw new TypeError(
1032
1030
  `Second argument of (${KEYWORDS.SET_ARRAY}) must be an (${
1033
1031
  KEYWORDS.NUMBER_TYPE
1034
- } integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)}).`
1032
+ } integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
1035
1033
  )
1036
1034
  if (index > array.length)
1037
1035
  throw new RangeError(
@@ -1039,7 +1037,7 @@ const keywords = {
1039
1037
  KEYWORDS.ARRAY_TYPE
1040
1038
  }) bounds (index ${index} bounds ${array.length}) (${
1041
1039
  KEYWORDS.SET_ARRAY
1042
- } ${stringifyArgs(args)}).`
1040
+ } ${stringifyArgs(args)})`
1043
1041
  )
1044
1042
  if (index < 0) {
1045
1043
  if (args.length !== 2)
@@ -1080,6 +1078,86 @@ const keywords = {
1080
1078
  }
1081
1079
  return array
1082
1080
  },
1081
+
1082
+ [KEYWORDS.SET_IMMUTABLE_ARRAY]: (args, env) => {
1083
+ if (args.length !== 2 && args.length !== 3)
1084
+ throw new RangeError(
1085
+ `Invalid number of arguments for (${
1086
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1087
+ }) (or 2 3) required (${KEYWORDS.SET_IMMUTABLE_ARRAY} ${stringifyArgs(
1088
+ args
1089
+ )})`
1090
+ )
1091
+ let array = evaluate(args[0], env)
1092
+ if (!Array.isArray(array))
1093
+ throw new TypeError(
1094
+ `First argument of (${KEYWORDS.SET_IMMUTABLE_ARRAY}) must be an (${
1095
+ KEYWORDS.ARRAY_TYPE
1096
+ }) but got (${array}) (${KEYWORDS.SET_IMMUTABLE_ARRAY} ${stringifyArgs(
1097
+ args
1098
+ )})`
1099
+ )
1100
+ array = [...array]
1101
+ const index = evaluate(args[1], env)
1102
+ if (!Number.isInteger(index))
1103
+ throw new TypeError(
1104
+ `Second argument of (${KEYWORDS.SET_IMMUTABLE_ARRAY}) must be an (${
1105
+ KEYWORDS.NUMBER_TYPE
1106
+ } integer) (${index}) (${KEYWORDS.SET_IMMUTABLE_ARRAY} ${stringifyArgs(
1107
+ args
1108
+ )})`
1109
+ )
1110
+ if (index > array.length)
1111
+ throw new RangeError(
1112
+ `Second argument of (${
1113
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1114
+ }) is outside of the (${
1115
+ KEYWORDS.ARRAY_TYPE
1116
+ }) bounds (index ${index} bounds ${array.length}) (${
1117
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1118
+ } ${stringifyArgs(args)})`
1119
+ )
1120
+ if (index < 0) {
1121
+ if (args.length !== 2)
1122
+ throw new RangeError(
1123
+ `Invalid number of arguments for (${
1124
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1125
+ }) (if (< index 0) then 2 required) (${
1126
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1127
+ } ${stringifyArgs(args)})`
1128
+ )
1129
+ if (index * -1 > array.length)
1130
+ throw new RangeError(
1131
+ `Second argument of (${
1132
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1133
+ }) is outside of the (${
1134
+ KEYWORDS.ARRAY_TYPE
1135
+ }) bounds (index ${index} bounds ${array.length}) (${
1136
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1137
+ } ${stringifyArgs(args)})`
1138
+ )
1139
+ const target = array.length + index
1140
+ while (array.length !== target) array.pop()
1141
+ } else {
1142
+ if (args.length !== 3)
1143
+ throw new RangeError(
1144
+ `Invalid number of arguments for (${
1145
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1146
+ }) (if (>= index 0) then 3 required) (${
1147
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1148
+ } ${stringifyArgs(args)})`
1149
+ )
1150
+ const value = evaluate(args[2], env)
1151
+ if (value == undefined)
1152
+ throw new RangeError(
1153
+ `Trying to set a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
1154
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1155
+ }). (${KEYWORDS.SET_IMMUTABLE_ARRAY} ${stringifyArgs(args)})`
1156
+ )
1157
+ array[index] = value
1158
+ }
1159
+ return array
1160
+ },
1083
1161
  }
1084
1162
  keywords[KEYWORDS.NOT_COMPILED_BLOCK] = keywords[KEYWORDS.BLOCK]
1085
1163
  export { keywords }