fez-lisp 1.0.7 → 1.0.8

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(
@@ -445,6 +432,17 @@ const keywords = {
445
432
  )
446
433
  return +!evaluate(args[0], env)
447
434
  },
435
+ [KEYWORDS.EQUALITY]: (args, env) => {
436
+ if (args.length !== 2)
437
+ throw new RangeError(
438
+ `Invalid number of arguments for (${KEYWORDS.EQUAL}) (2 required) (${
439
+ KEYWORDS.EQUAL
440
+ } ${stringifyArgs(args)})`
441
+ )
442
+ const a = evaluate(args[0], env)
443
+ const b = evaluate(args[1], env)
444
+ return +(a === b)
445
+ },
448
446
  [KEYWORDS.EQUAL]: (args, env) => {
449
447
  if (args.length !== 2)
450
448
  throw new RangeError(
@@ -454,15 +452,16 @@ const keywords = {
454
452
  )
455
453
  const a = evaluate(args[0], env)
456
454
  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
- )
455
+ if (typeof a !== 'number')
463
456
  throw new TypeError(
464
- `Invalid use of (${KEYWORDS.EQUAL}), some arguments are not an ${
465
- KEYWORDS.ATOM
457
+ `Invalid use of (${KEYWORDS.EQUAL}), first arguments are not an ${
458
+ KEYWORDS.NUMBER_TYPE
459
+ } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
460
+ )
461
+ if (typeof b !== 'number')
462
+ throw new TypeError(
463
+ `Invalid use of (${KEYWORDS.EQUAL}), second argument are not an ${
464
+ KEYWORDS.NUMBER_TYPE
466
465
  } (${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
467
466
  )
468
467
  return +(a === b)
@@ -476,15 +475,16 @@ const keywords = {
476
475
  )
477
476
  const a = evaluate(args[0], env)
478
477
  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
- )
478
+ if (typeof a !== 'number')
479
+ throw new TypeError(
480
+ `Invalid use of (${KEYWORDS.LESS_THAN}), first arguments are not an ${
481
+ KEYWORDS.NUMBER_TYPE
482
+ } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
483
+ )
484
+ if (typeof b !== 'number')
485
485
  throw new TypeError(
486
- `Invalid use of (${KEYWORDS.LESS_THAN}), some arguments are not an ${
487
- KEYWORDS.ATOM
486
+ `Invalid use of (${KEYWORDS.LESS_THAN}), second argument are not an ${
487
+ KEYWORDS.NUMBER_TYPE
488
488
  } (${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
489
489
  )
490
490
  return +(a < b)
@@ -498,16 +498,19 @@ const keywords = {
498
498
  )
499
499
  const a = evaluate(args[0], env)
500
500
  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
- )
501
+ if (typeof a !== 'number')
502
+ throw new TypeError(
503
+ `Invalid use of (${
504
+ KEYWORDS.GREATHER_THAN
505
+ }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
506
+ KEYWORDS.GREATHER_THAN
507
+ } ${stringifyArgs(args)})`
508
+ )
509
+ if (typeof b !== 'number')
507
510
  throw new TypeError(
508
511
  `Invalid use of (${
509
512
  KEYWORDS.GREATHER_THAN
510
- }), some arguments are not an ${KEYWORDS.ATOM} (${
513
+ }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
511
514
  KEYWORDS.GREATHER_THAN
512
515
  } ${stringifyArgs(args)})`
513
516
  )
@@ -524,16 +527,19 @@ const keywords = {
524
527
  )
525
528
  const a = evaluate(args[0], env)
526
529
  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
- )
530
+ if (typeof a !== 'number')
533
531
  throw new TypeError(
534
532
  `Invalid use of (${
535
533
  KEYWORDS.GREATHER_THAN_OR_EQUAL
536
- }), some arguments are not an ${KEYWORDS.ATOM} (${
534
+ }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
535
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
536
+ } ${stringifyArgs(args)})`
537
+ )
538
+ if (typeof b !== 'number')
539
+ throw new TypeError(
540
+ `Invalid use of (${
541
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
542
+ }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
537
543
  KEYWORDS.GREATHER_THAN_OR_EQUAL
538
544
  } ${stringifyArgs(args)})`
539
545
  )
@@ -548,16 +554,19 @@ const keywords = {
548
554
  )
549
555
  const a = evaluate(args[0], env)
550
556
  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
- )
557
+ if (typeof a !== 'number')
557
558
  throw new TypeError(
558
559
  `Invalid use of (${
559
560
  KEYWORDS.LESS_THAN_OR_EQUAL
560
- }), some arguments are not an ${KEYWORDS.ATOM} (${
561
+ }), first arguments are not an ${KEYWORDS.NUMBER_TYPE} (${
562
+ KEYWORDS.LESS_THAN_OR_EQUAL
563
+ } ${stringifyArgs(args)})`
564
+ )
565
+ if (typeof b !== 'number')
566
+ throw new TypeError(
567
+ `Invalid use of (${
568
+ KEYWORDS.LESS_THAN_OR_EQUAL
569
+ }), second argument are not an ${KEYWORDS.NUMBER_TYPE} (${
561
570
  KEYWORDS.LESS_THAN_OR_EQUAL
562
571
  } ${stringifyArgs(args)})`
563
572
  )
@@ -671,7 +680,7 @@ const keywords = {
671
680
  KEYWORDS.NUMBER_TYPE
672
681
  } ("${value}") to a ${KEYWORDS.NUMBER_TYPE} at (${
673
682
  KEYWORDS.CAST_TYPE
674
- }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)}).`
683
+ }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)})`
675
684
  )
676
685
  return num
677
686
  }
@@ -681,14 +690,14 @@ const keywords = {
681
690
  return +!!value
682
691
  case KEYWORDS.ARRAY_TYPE: {
683
692
  if (typeof value === 'number')
684
- return Object.freeze([...Number(value).toString()].map(Number))
693
+ return [...Number(value).toString()].map(Number)
685
694
  else if (typeof value[Symbol.iterator] !== 'function')
686
695
  throw new TypeError(
687
696
  `Arguments are not iterable for ${KEYWORDS.ARRAY_TYPE} at (${
688
697
  KEYWORDS.CAST_TYPE
689
- }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)}).`
698
+ }) (${KEYWORDS.CAST_TYPE} ${stringifyArgs(args)})`
690
699
  )
691
- return Object.freeze([...value])
700
+ return [...value]
692
701
  }
693
702
  case KEYWORDS.CHAR_TYPE: {
694
703
  const index = evaluate(args[0], env)
@@ -698,7 +707,7 @@ const keywords = {
698
707
  KEYWORDS.CHAR_TYPE
699
708
  } at (${KEYWORDS.CAST_TYPE}) (${
700
709
  KEYWORDS.CAST_TYPE
701
- } ${stringifyArgs(args)}).`
710
+ } ${stringifyArgs(args)})`
702
711
  )
703
712
  return String.fromCharCode(index)
704
713
  }
@@ -710,7 +719,7 @@ const keywords = {
710
719
  KEYWORDS.CHAR_CODE_TYPE
711
720
  } at (${KEYWORDS.CAST_TYPE}) (${
712
721
  KEYWORDS.CAST_TYPE
713
- } ${stringifyArgs(args)}).`
722
+ } ${stringifyArgs(args)})`
714
723
  )
715
724
  if (string.length !== 1)
716
725
  throw new RangeError(
@@ -718,7 +727,7 @@ const keywords = {
718
727
  KEYWORDS.CHAR_CODE_TYPE
719
728
  } at (${KEYWORDS.CAST_TYPE}) (${
720
729
  KEYWORDS.CAST_TYPE
721
- } ${stringifyArgs(args)}).`
730
+ } ${stringifyArgs(args)})`
722
731
  )
723
732
  return string.charCodeAt(0)
724
733
  }
@@ -730,7 +739,7 @@ const keywords = {
730
739
  KEYWORDS.CHAR_TYPE
731
740
  } ${KEYWORDS.CHAR_CODE_TYPE}) at (${KEYWORDS.CAST_TYPE}) (${
732
741
  KEYWORDS.CAST_TYPE
733
- } ${stringifyArgs(args)}).`
742
+ } ${stringifyArgs(args)})`
734
743
  )
735
744
  }
736
745
  }
@@ -747,7 +756,7 @@ const keywords = {
747
756
  throw new TypeError(
748
757
  `Not all arguments of (${KEYWORDS.BITWISE_AND}) are ${
749
758
  KEYWORDS.NUMBER_TYPE
750
- } (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)}).`
759
+ } (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
751
760
  )
752
761
  return operands.reduce((acc, x) => acc & x)
753
762
  },
@@ -763,7 +772,7 @@ const keywords = {
763
772
  throw new TypeError(
764
773
  `Argument of (${KEYWORDS.BITWISE_NOT}) is not a (${
765
774
  KEYWORDS.NUMBER_TYPE
766
- }) (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)}).`
775
+ }) (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
767
776
  )
768
777
  return ~operand
769
778
  },
@@ -779,7 +788,7 @@ const keywords = {
779
788
  throw new TypeError(
780
789
  `Not all arguments of (${KEYWORDS.BITWISE_OR}) are (${
781
790
  KEYWORDS.NUMBER_TYPE
782
- }) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)}).`
791
+ }) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
783
792
  )
784
793
  return operands.reduce((acc, x) => acc | x)
785
794
  },
@@ -788,14 +797,14 @@ const keywords = {
788
797
  throw new RangeError(
789
798
  `Invalid number of arguments to (${
790
799
  KEYWORDS.BITWISE_XOR
791
- }) (>= 2 required). (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)}).`
800
+ }) (>= 2 required). (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
792
801
  )
793
802
  const operands = args.map((a) => evaluate(a, env))
794
803
  if (operands.some((x) => typeof x !== 'number'))
795
804
  throw new TypeError(
796
805
  `Not all arguments of (${KEYWORDS.BITWISE_XOR}) are (${
797
806
  KEYWORDS.NUMBER_TYPE
798
- }) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)}).`
807
+ }) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
799
808
  )
800
809
  return operands.reduce((acc, x) => acc ^ x)
801
810
  },
@@ -806,14 +815,14 @@ const keywords = {
806
815
  KEYWORDS.BITWISE_LEFT_SHIFT
807
816
  }) (>= 2 required). (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(
808
817
  args
809
- )}).`
818
+ )})`
810
819
  )
811
820
  const operands = args.map((a) => evaluate(a, env))
812
821
  if (operands.some((x) => typeof x !== 'number'))
813
822
  throw new TypeError(
814
823
  `Not all arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) are (${
815
824
  KEYWORDS.NUMBER_TYPE
816
- }) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)}).`
825
+ }) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)})`
817
826
  )
818
827
  return operands.reduce((acc, x) => acc << x)
819
828
  },
@@ -824,14 +833,14 @@ const keywords = {
824
833
  KEYWORDS.BITWISE_RIGHT_SHIFT
825
834
  }) (>= 2 required). (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(
826
835
  args
827
- )}).`
836
+ )})`
828
837
  )
829
838
  const operands = args.map((a) => evaluate(a, env))
830
839
  if (operands.some((x) => typeof x !== 'number'))
831
840
  throw new TypeError(
832
841
  `Not all arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) are (${
833
842
  KEYWORDS.NUMBER_TYPE
834
- }) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)}).`
843
+ }) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)})`
835
844
  )
836
845
  return operands.reduce((acc, x) => acc >> x)
837
846
  },
@@ -842,14 +851,14 @@ const keywords = {
842
851
  KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
843
852
  }) (>= 2 required). (${
844
853
  KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
845
- } ${stringifyArgs(args)}).`
854
+ } ${stringifyArgs(args)})`
846
855
  )
847
856
  const operands = args.map((a) => evaluate(a, env))
848
857
  if (operands.some((x) => typeof x !== 'number'))
849
858
  throw new TypeError(
850
859
  `Not all arguments of (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT}) are (${
851
860
  KEYWORDS.NUMBER_TYPE
852
- }) (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT} ${stringifyArgs(args)}).`
861
+ }) (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT} ${stringifyArgs(args)})`
853
862
  )
854
863
  return operands.reduce((acc, x) => acc >>> x)
855
864
  },
@@ -879,14 +888,14 @@ const keywords = {
879
888
  throw new RangeError(
880
889
  `Invalid number of arguments to (${
881
890
  KEYWORDS.THROW_ERROR
882
- }) (1 required). (${KEYWORDS.THROW_ERROR} ${stringifyArgs(args)}).`
891
+ }) (1 required). (${KEYWORDS.THROW_ERROR} ${stringifyArgs(args)})`
883
892
  )
884
893
  const string = evaluate(args[0], env)
885
894
  if (typeof string !== 'string')
886
895
  throw new TypeError(
887
896
  `First argument of (${KEYWORDS.THROW_ERROR}) must be an (${
888
897
  KEYWORDS.STRING_TYPE
889
- }) (${KEYWORDS.THROW_ERROR} ${stringifyArgs(args)}).`
898
+ }) (${KEYWORDS.THROW_ERROR} ${stringifyArgs(args)})`
890
899
  )
891
900
  throw new Error(string)
892
901
  },
@@ -895,16 +904,16 @@ const keywords = {
895
904
  throw new RangeError(
896
905
  `Invalid number of arguments to (${KEYWORDS.MERGE}) (>= 2 required). (${
897
906
  KEYWORDS.MERGE
898
- } ${stringifyArgs(args)}).`
907
+ } ${stringifyArgs(args)})`
899
908
  )
900
909
  const arrays = args.map((arg) => evaluate(arg, env))
901
910
  if (arrays.some((maybe) => !Array.isArray(maybe)))
902
911
  throw new TypeError(
903
912
  `Arguments of (${KEYWORDS.MERGE}) must be (${KEYWORDS.ARRAY_TYPE}) (${
904
913
  KEYWORDS.MERGE
905
- } ${stringifyArgs(args)}).`
914
+ } ${stringifyArgs(args)})`
906
915
  )
907
- return Object.freeze(arrays.reduce((a, b) => a.concat(b), []))
916
+ return arrays.reduce((a, b) => a.concat(b), [])
908
917
  },
909
918
  [KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION]: (args, env) => {
910
919
  if (!args.length)
@@ -913,7 +922,7 @@ const keywords = {
913
922
  KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION
914
923
  }) (>= 2 required). (${
915
924
  KEYWORDS.TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION
916
- } ${stringifyArgs(args)}).`
925
+ } ${stringifyArgs(args)})`
917
926
  )
918
927
  // TODO: Add validation for TCO recursion
919
928
  return keywords[KEYWORDS.DEFINE_VARIABLE](args, env)
@@ -925,7 +934,7 @@ const keywords = {
925
934
  KEYWORDS.IMMUTABLE_FUNCTION
926
935
  }) (>= 2 required). (${KEYWORDS.IMMUTABLE_FUNCTION} ${stringifyArgs(
927
936
  args
928
- )}).`
937
+ )})`
929
938
  )
930
939
  const [definition, ...functionArgs] = args
931
940
  const token = definition[VALUE]
@@ -1024,14 +1033,14 @@ const keywords = {
1024
1033
  throw new TypeError(
1025
1034
  `First argument of (${KEYWORDS.SET_ARRAY}) must be an (${
1026
1035
  KEYWORDS.ARRAY_TYPE
1027
- }) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)}).`
1036
+ }) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
1028
1037
  )
1029
1038
  const index = evaluate(args[1], env)
1030
1039
  if (!Number.isInteger(index))
1031
1040
  throw new TypeError(
1032
1041
  `Second argument of (${KEYWORDS.SET_ARRAY}) must be an (${
1033
1042
  KEYWORDS.NUMBER_TYPE
1034
- } integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)}).`
1043
+ } integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
1035
1044
  )
1036
1045
  if (index > array.length)
1037
1046
  throw new RangeError(
@@ -1039,7 +1048,7 @@ const keywords = {
1039
1048
  KEYWORDS.ARRAY_TYPE
1040
1049
  }) bounds (index ${index} bounds ${array.length}) (${
1041
1050
  KEYWORDS.SET_ARRAY
1042
- } ${stringifyArgs(args)}).`
1051
+ } ${stringifyArgs(args)})`
1043
1052
  )
1044
1053
  if (index < 0) {
1045
1054
  if (args.length !== 2)
@@ -1080,6 +1089,86 @@ const keywords = {
1080
1089
  }
1081
1090
  return array
1082
1091
  },
1092
+
1093
+ [KEYWORDS.SET_IMMUTABLE_ARRAY]: (args, env) => {
1094
+ if (args.length !== 2 && args.length !== 3)
1095
+ throw new RangeError(
1096
+ `Invalid number of arguments for (${
1097
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1098
+ }) (or 2 3) required (${KEYWORDS.SET_IMMUTABLE_ARRAY} ${stringifyArgs(
1099
+ args
1100
+ )})`
1101
+ )
1102
+ let array = evaluate(args[0], env)
1103
+ if (!Array.isArray(array))
1104
+ throw new TypeError(
1105
+ `First argument of (${KEYWORDS.SET_IMMUTABLE_ARRAY}) must be an (${
1106
+ KEYWORDS.ARRAY_TYPE
1107
+ }) but got (${array}) (${KEYWORDS.SET_IMMUTABLE_ARRAY} ${stringifyArgs(
1108
+ args
1109
+ )})`
1110
+ )
1111
+ array = [...array]
1112
+ const index = evaluate(args[1], env)
1113
+ if (!Number.isInteger(index))
1114
+ throw new TypeError(
1115
+ `Second argument of (${KEYWORDS.SET_IMMUTABLE_ARRAY}) must be an (${
1116
+ KEYWORDS.NUMBER_TYPE
1117
+ } integer) (${index}) (${KEYWORDS.SET_IMMUTABLE_ARRAY} ${stringifyArgs(
1118
+ args
1119
+ )})`
1120
+ )
1121
+ if (index > array.length)
1122
+ throw new RangeError(
1123
+ `Second argument of (${
1124
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1125
+ }) is outside of the (${
1126
+ KEYWORDS.ARRAY_TYPE
1127
+ }) bounds (index ${index} bounds ${array.length}) (${
1128
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1129
+ } ${stringifyArgs(args)})`
1130
+ )
1131
+ if (index < 0) {
1132
+ if (args.length !== 2)
1133
+ throw new RangeError(
1134
+ `Invalid number of arguments for (${
1135
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1136
+ }) (if (< index 0) then 2 required) (${
1137
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1138
+ } ${stringifyArgs(args)})`
1139
+ )
1140
+ if (index * -1 > array.length)
1141
+ throw new RangeError(
1142
+ `Second argument of (${
1143
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1144
+ }) is outside of the (${
1145
+ KEYWORDS.ARRAY_TYPE
1146
+ }) bounds (index ${index} bounds ${array.length}) (${
1147
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1148
+ } ${stringifyArgs(args)})`
1149
+ )
1150
+ const target = array.length + index
1151
+ while (array.length !== target) array.pop()
1152
+ } else {
1153
+ if (args.length !== 3)
1154
+ throw new RangeError(
1155
+ `Invalid number of arguments for (${
1156
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1157
+ }) (if (>= index 0) then 3 required) (${
1158
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1159
+ } ${stringifyArgs(args)})`
1160
+ )
1161
+ const value = evaluate(args[2], env)
1162
+ if (value == undefined)
1163
+ throw new RangeError(
1164
+ `Trying to set a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
1165
+ KEYWORDS.SET_IMMUTABLE_ARRAY
1166
+ }). (${KEYWORDS.SET_IMMUTABLE_ARRAY} ${stringifyArgs(args)})`
1167
+ )
1168
+ array[index] = value
1169
+ }
1170
+ return array
1171
+ },
1083
1172
  }
1084
1173
  keywords[KEYWORDS.NOT_COMPILED_BLOCK] = keywords[KEYWORDS.BLOCK]
1085
1174
  export { keywords }