fez-lisp 1.3.1 → 1.3.3

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.
@@ -2,59 +2,83 @@ import { TYPE, VALUE, WORD, KEYWORDS, FALSE, TRUE, TYPES } from './keywords.js'
2
2
  import { evaluate } from './evaluator.js'
3
3
  import { isForbiddenVariableName, stringifyArgs } from './utils.js'
4
4
  export const keywords = {
5
- [KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) => {
6
- if (args.length < 2)
5
+ [KEYWORDS.ADDITION]: (args, env) => {
6
+ if (args.length !== 0 && args.length !== 2)
7
7
  throw new RangeError(
8
8
  `Invalid number of arguments for (${
9
- KEYWORDS.REMAINDER_OF_DIVISION
10
- }), expected > 1 but got ${args.length}. (${
11
- KEYWORDS.REMAINDER_OF_DIVISION
9
+ KEYWORDS.ADDITION
10
+ }), expected (or (= 2) (= 0)) but got ${args.length}. (${
11
+ KEYWORDS.ADDITION
12
12
  } ${stringifyArgs(args)})`
13
13
  )
14
14
  const a = evaluate(args[0], env)
15
15
  if (typeof a !== 'number')
16
16
  throw new TypeError(
17
- `First argument of (${KEYWORDS.REMAINDER_OF_DIVISION}) is not (${
17
+ `First arguments of (${KEYWORDS.ADDITION}) is not a (${
18
18
  KEYWORDS.NUMBER_TYPE
19
- }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
19
+ }) (${KEYWORDS.ADDITION} ${stringifyArgs(args)})`
20
20
  )
21
21
  const b = evaluate(args[1], env)
22
22
  if (typeof b !== 'number')
23
23
  throw new TypeError(
24
- `Second argument of (${KEYWORDS.REMAINDER_OF_DIVISION}) is not (${
24
+ `Second arguments of (${KEYWORDS.ADDITION}) is not a (${
25
25
  KEYWORDS.NUMBER_TYPE
26
- }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
26
+ }) (${KEYWORDS.ADDITION} ${stringifyArgs(args)})`
27
27
  )
28
- if (b === 0)
28
+ return a + b
29
+ },
30
+ [KEYWORDS.MULTIPLICATION]: (args, env) => {
31
+ if (args.length !== 2)
32
+ throw new RangeError(
33
+ `Invalid number of arguments for (${KEYWORDS.MULTIPLICATION}), expected (= 2) but got ${args.length}.`
34
+ )
35
+ const a = evaluate(args[0], env)
36
+ if (typeof a !== 'number')
29
37
  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
38
+ `First arguments of (${KEYWORDS.MULTIPLICATION}) is not a (${
39
+ KEYWORDS.NUMBER_TYPE
40
+ }) (${KEYWORDS.MULTIPLICATION} ${stringifyArgs(args)})`
41
+ )
42
+ const b = evaluate(args[1], env)
43
+ if (typeof b !== 'number')
44
+ throw new TypeError(
45
+ `Second arguments of (${KEYWORDS.MULTIPLICATION}) is not a (${
46
+ KEYWORDS.NUMBER_TYPE
47
+ }) (${KEYWORDS.MULTIPLICATION} ${stringifyArgs(args)})`
48
+ )
49
+ return a * b
50
+ },
51
+ [KEYWORDS.SUBTRACTION]: (args, env) => {
52
+ if (args.length !== 1 && args.length !== 2)
53
+ throw new RangeError(
54
+ `Invalid number of arguments for (${
55
+ KEYWORDS.SUBTRACTION
56
+ }), expected (or (= 1)) (= 2) but got ${args.length}. (${
57
+ KEYWORDS.SUBTRACTION
34
58
  } ${stringifyArgs(args)})`
35
59
  )
36
-
37
- return a % b
60
+ const a = evaluate(args[0], env)
61
+ if (typeof a !== 'number')
62
+ throw new TypeError(
63
+ `First argument of (${KEYWORDS.SUBTRACTION}) is not a (${
64
+ KEYWORDS.NUMBER_TYPE
65
+ }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)})`
66
+ )
67
+ if (args.length === 1) return -a
68
+ const b = evaluate(args[1], env)
69
+ if (typeof b !== 'number')
70
+ throw new TypeError(
71
+ `Second argument of (${KEYWORDS.SUBTRACTION}) is not a (${
72
+ KEYWORDS.NUMBER_TYPE
73
+ }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)})`
74
+ )
75
+ return a - b
38
76
  },
39
77
  [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
- }
78
+ if (args.length !== 2)
79
+ throw new RangeError(
80
+ `Invalid number of arguments for (${KEYWORDS.DIVISION}), expected (= 2) but got ${args.length}.`
81
+ )
58
82
  const a = evaluate(args[0], env)
59
83
  if (typeof a !== 'number')
60
84
  throw new TypeError(
@@ -79,133 +103,162 @@ export const keywords = {
79
103
  )
80
104
  return a / b
81
105
  },
82
- [KEYWORDS.ARRAY_LENGTH]: (args, env) => {
83
- if (args.length !== 1)
106
+ [KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) => {
107
+ if (args.length !== 2)
84
108
  throw new RangeError(
85
109
  `Invalid number of arguments for (${
86
- KEYWORDS.ARRAY_LENGTH
87
- }) (= 1 required) (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
110
+ KEYWORDS.REMAINDER_OF_DIVISION
111
+ }), expected (= 2) but got ${args.length}. (${
112
+ KEYWORDS.REMAINDER_OF_DIVISION
113
+ } ${stringifyArgs(args)})`
88
114
  )
89
- const array = evaluate(args[0], env)
90
- if (!Array.isArray(array))
115
+ const a = evaluate(args[0], env)
116
+ if (typeof a !== 'number')
91
117
  throw new TypeError(
92
- `First argument of (${KEYWORDS.ARRAY_LENGTH}) must be an ${
93
- KEYWORDS.ARRAY_TYPE
94
- } (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
118
+ `First argument of (${KEYWORDS.REMAINDER_OF_DIVISION}) is not (${
119
+ KEYWORDS.NUMBER_TYPE
120
+ }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
95
121
  )
96
- return array.length
122
+ const b = evaluate(args[1], env)
123
+ if (typeof b !== 'number')
124
+ throw new TypeError(
125
+ `Second argument of (${KEYWORDS.REMAINDER_OF_DIVISION}) is not (${
126
+ KEYWORDS.NUMBER_TYPE
127
+ }) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
128
+ )
129
+ if (b === 0)
130
+ throw new TypeError(
131
+ `Second argument of (${
132
+ KEYWORDS.REMAINDER_OF_DIVISION
133
+ }) can't be a (0) (division by 0 is not allowed) (${
134
+ KEYWORDS.REMAINDER_OF_DIVISION
135
+ } ${stringifyArgs(args)})`
136
+ )
137
+
138
+ return a % b
97
139
  },
98
- [KEYWORDS.IS_ATOM]: (args, env) => {
99
- if (args.length !== 1)
140
+ [KEYWORDS.BITWISE_AND]: (args, env) => {
141
+ if (args.length < 2)
100
142
  throw new RangeError(
101
- `Invalid number of arguments for (${
102
- KEYWORDS.IS_ATOM
103
- }) (= 1 required) (${KEYWORDS.IS_ATOM} ${stringifyArgs(args)})`
143
+ `Invalid number of arguments to (${
144
+ KEYWORDS.BITWISE_AND
145
+ }) (= 2 required). (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
104
146
  )
105
- return +(typeof evaluate(args[0], env) === 'number')
147
+ const operands = args.map((a) => evaluate(a, env))
148
+ if (operands.some((x) => typeof x !== 'number'))
149
+ throw new TypeError(
150
+ `Not all arguments of (${KEYWORDS.BITWISE_AND}) are ${
151
+ KEYWORDS.NUMBER_TYPE
152
+ } (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
153
+ )
154
+ return operands.reduce((acc, x) => acc & x)
106
155
  },
107
- [KEYWORDS.IS_LAMBDA]: (args, env) => {
156
+ [KEYWORDS.BITWISE_NOT]: (args, env) => {
108
157
  if (args.length !== 1)
109
158
  throw new RangeError(
110
- `Invalid number of arguments for (${
111
- KEYWORDS.IS_LAMBDA
112
- }) (= 1 required) (${KEYWORDS.IS_LAMBDA} ${stringifyArgs(args)})`
159
+ `Invalid number of arguments to (${
160
+ KEYWORDS.BITWISE_NOT
161
+ }) (= 1 required). (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
113
162
  )
114
- return +(typeof evaluate(args[0], env) === 'function')
163
+ const operand = evaluate(args[0], env)
164
+ if (typeof operand !== 'number')
165
+ throw new TypeError(
166
+ `Argument of (${KEYWORDS.BITWISE_NOT}) is not a (${
167
+ KEYWORDS.NUMBER_TYPE
168
+ }) (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
169
+ )
170
+ return ~operand
115
171
  },
116
- [KEYWORDS.ADDITION]: (args, env) => {
117
- if (args.length !== 0 && args.length !== 2)
172
+ [KEYWORDS.BITWISE_OR]: (args, env) => {
173
+ if (args.length !== 2)
118
174
  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)})`
175
+ `Invalid number of arguments to (${
176
+ KEYWORDS.BITWISE_OR
177
+ }) (= 2 required). (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
124
178
  )
125
179
  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
180
  const b = evaluate(args[1], env)
133
- if (typeof b !== 'number')
181
+ if (typeof a !== 'number' || typeof b !== 'number')
134
182
  throw new TypeError(
135
- `Second arguments of (${KEYWORDS.ADDITION}) is not a (${
183
+ `Not all arguments of (${KEYWORDS.BITWISE_OR}) are (${
136
184
  KEYWORDS.NUMBER_TYPE
137
- }) (${KEYWORDS.ADDITION} ${stringifyArgs(args)})`
185
+ }) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
138
186
  )
139
- return a + b
187
+ return a | b
140
188
  },
141
- [KEYWORDS.MULTIPLICATION]: (args, env) => {
142
- if (args.length !== 0 && args.length !== 2)
189
+ [KEYWORDS.BITWISE_XOR]: (args, env) => {
190
+ if (args.length !== 2)
143
191
  throw new RangeError(
144
- `Invalid number of arguments for (${KEYWORDS.MULTIPLICATION}), expected (or (= 2) (= 0)) but got ${args.length}.`
192
+ `Invalid number of arguments to (${
193
+ KEYWORDS.BITWISE_XOR
194
+ }) (= 2 required). (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
145
195
  )
146
196
  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
197
  const b = evaluate(args[1], env)
154
- if (typeof b !== 'number')
198
+ if (typeof a !== 'number' || typeof b !== 'number')
155
199
  throw new TypeError(
156
- `Second arguments of (${KEYWORDS.MULTIPLICATION}) is not a (${
200
+ `Not all arguments of (${KEYWORDS.BITWISE_XOR}) are (${
157
201
  KEYWORDS.NUMBER_TYPE
158
- }) (${KEYWORDS.MULTIPLICATION} ${stringifyArgs(args)})`
202
+ }) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
159
203
  )
160
- return a * b
204
+ return a ^ b
161
205
  },
162
- [KEYWORDS.SUBTRACTION]: (args, env) => {
163
- if (args.length !== 1 && args.length !== 2)
206
+ [KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) => {
207
+ if (args.length !== 2)
164
208
  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)})`
209
+ `Invalid number of arguments to (${
210
+ KEYWORDS.BITWISE_LEFT_SHIFT
211
+ }) (= 2 required). (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(
212
+ args
213
+ )})`
170
214
  )
171
215
  const a = evaluate(args[0], env)
172
- if (typeof a !== 'number')
216
+ const b = evaluate(args[1], env)
217
+ if (typeof a !== 'number' || typeof b !== 'number')
173
218
  throw new TypeError(
174
- `First argument of (${KEYWORDS.SUBTRACTION}) is not a (${
219
+ `Not all arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) are (${
175
220
  KEYWORDS.NUMBER_TYPE
176
- }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)})`
221
+ }) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)})`
177
222
  )
178
- if (args.length === 1) return -a
223
+ return a << b
224
+ },
225
+ [KEYWORDS.BITWISE_RIGHT_SHIFT]: (args, env) => {
226
+ if (args.length !== 2)
227
+ throw new RangeError(
228
+ `Invalid number of arguments to (${
229
+ KEYWORDS.BITWISE_RIGHT_SHIFT
230
+ }) (= 2 required). (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(
231
+ args
232
+ )})`
233
+ )
234
+ const a = evaluate(args[0], env)
179
235
  const b = evaluate(args[1], env)
180
- if (typeof b !== 'number')
236
+ if (typeof a !== 'number' || typeof b !== 'number')
181
237
  throw new TypeError(
182
- `Second argument of (${KEYWORDS.SUBTRACTION}) is not a (${
238
+ `Not all arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) are (${
183
239
  KEYWORDS.NUMBER_TYPE
184
- }) (${KEYWORDS.SUBTRACTION} ${stringifyArgs(args)})`
240
+ }) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)})`
185
241
  )
186
- return a - b
242
+ return a >> b
187
243
  },
188
- [KEYWORDS.IF]: (args, env) => {
189
- if (args.length > 3 || args.length < 2)
244
+ [KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT]: (args, env) => {
245
+ if (args.length !== 2)
190
246
  throw new RangeError(
191
- `Invalid number of arguments for (${
192
- KEYWORDS.IF
193
- }), expected (or (= 3) (= 2)) but got ${args.length} (${
194
- KEYWORDS.IF
247
+ `Invalid number of arguments to (${
248
+ KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
249
+ }) (= 2 required). (${
250
+ KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
195
251
  } ${stringifyArgs(args)})`
196
252
  )
197
- const condition = evaluate(args[0], env)
198
- if (condition !== FALSE && condition !== TRUE)
253
+ const a = evaluate(args[0], env)
254
+ const b = evaluate(args[1], env)
255
+ if (typeof a !== 'number' || typeof b !== 'number')
199
256
  throw new TypeError(
200
- `Condition of (${KEYWORDS.IF}) must be ${TRUE} or ${FALSE} but got (${
201
- KEYWORDS.IF
202
- } ${stringifyArgs(args)})`
257
+ `Not all arguments of (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT}) are (${
258
+ KEYWORDS.NUMBER_TYPE
259
+ }) (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT} ${stringifyArgs(args)})`
203
260
  )
204
- return condition
205
- ? evaluate(args[1], env)
206
- : args.length === 3
207
- ? evaluate(args[2], env)
208
- : 0
261
+ return a >>> b
209
262
  },
210
263
  [KEYWORDS.ARRAY_TYPE]: (args, env) => {
211
264
  return args.length ? args.map((x) => evaluate(x, env)) : []
@@ -252,40 +305,86 @@ export const keywords = {
252
305
  )
253
306
  return value
254
307
  },
255
- [KEYWORDS.BLOCK]: (args, env) => {
256
- if (!args.length)
308
+ [KEYWORDS.SET_ARRAY]: (args, env) => {
309
+ if (args.length !== 1 && args.length !== 3)
257
310
  throw new RangeError(
258
- `Invalid number of arguments to (${KEYWORDS.BLOCK}) (>= 1 required) (${
259
- KEYWORDS.BLOCK
260
- } ${stringifyArgs(args)})`
311
+ `Invalid number of arguments for (${
312
+ KEYWORDS.SET_ARRAY
313
+ }) (or 1 3) required (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
261
314
  )
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)
315
+ const array = evaluate(args[0], env)
316
+ if (!Array.isArray(array))
317
+ throw new TypeError(
318
+ `First argument of (${KEYWORDS.SET_ARRAY}) must be an (${
319
+ KEYWORDS.ARRAY_TYPE
320
+ }) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
321
+ )
322
+ if (args.length === 1) {
323
+ array.pop()
324
+ } else {
325
+ const index = evaluate(args[1], env)
326
+ if (!Number.isInteger(index) || index < 0)
327
+ throw new TypeError(
328
+ `Second argument of (${KEYWORDS.SET_ARRAY}) must be a positive (${
329
+ KEYWORDS.NUMBER_TYPE
330
+ } integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
331
+ )
332
+ if (index > array.length)
269
333
  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
334
+ `Second argument of (${KEYWORDS.SET_ARRAY}) is outside of the (${
335
+ KEYWORDS.ARRAY_TYPE
336
+ }) bounds (index ${index} bounds ${array.length}) (${
337
+ KEYWORDS.SET_ARRAY
276
338
  } ${stringifyArgs(args)})`
277
339
  )
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)
340
+ const value = evaluate(args[2], env)
341
+ if (value == undefined)
342
+ throw new RangeError(
343
+ `Trying to set a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
344
+ KEYWORDS.SET_ARRAY
345
+ }). (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
346
+ )
347
+ array[index] = value
288
348
  }
349
+ return array
350
+ },
351
+ [KEYWORDS.ARRAY_LENGTH]: (args, env) => {
352
+ if (args.length !== 1)
353
+ throw new RangeError(
354
+ `Invalid number of arguments for (${
355
+ KEYWORDS.ARRAY_LENGTH
356
+ }) (= 1 required) (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
357
+ )
358
+ const array = evaluate(args[0], env)
359
+ if (!Array.isArray(array))
360
+ throw new TypeError(
361
+ `First argument of (${KEYWORDS.ARRAY_LENGTH}) must be an ${
362
+ KEYWORDS.ARRAY_TYPE
363
+ } (${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
364
+ )
365
+ return array.length
366
+ },
367
+ [KEYWORDS.IF]: (args, env) => {
368
+ if (args.length > 3 || args.length < 2)
369
+ throw new RangeError(
370
+ `Invalid number of arguments for (${
371
+ KEYWORDS.IF
372
+ }), expected (or (= 3) (= 2)) but got ${args.length} (${
373
+ KEYWORDS.IF
374
+ } ${stringifyArgs(args)})`
375
+ )
376
+ const condition = evaluate(args[0], env)
377
+ if (condition !== FALSE && condition !== TRUE)
378
+ throw new TypeError(
379
+ `Condition of (${KEYWORDS.IF}) must be ${TRUE} or ${FALSE} but got (${
380
+ KEYWORDS.IF
381
+ } ${stringifyArgs(args)})`
382
+ )
383
+ return condition
384
+ ? evaluate(args[1], env)
385
+ : args.length === 3
386
+ ? evaluate(args[2], env)
387
+ : 0
289
388
  },
290
389
  [KEYWORDS.NOT]: (args, env) => {
291
390
  if (args.length !== 1)
@@ -473,32 +572,6 @@ export const keywords = {
473
572
  )
474
573
  return b
475
574
  },
476
- [KEYWORDS.CALL_FUNCTION]: (args, env) => {
477
- if (!args.length)
478
- throw new RangeError(
479
- `Invalid number of arguments to (${
480
- KEYWORDS.CALL_FUNCTION
481
- }) (>= 1 required) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
482
- )
483
- const [first, ...rest] = args
484
- if (first[TYPE] === WORD && first[VALUE] in keywords)
485
- throw new TypeError(
486
- `Following argument of (${
487
- KEYWORDS.CALL_FUNCTION
488
- }) must not be an reserved word (${
489
- KEYWORDS.CALL_FUNCTION
490
- } ${stringifyArgs(args)})`
491
- )
492
- const apply = evaluate(first, env)
493
- if (typeof apply !== 'function')
494
- throw new TypeError(
495
- `First argument of (${KEYWORDS.CALL_FUNCTION}) must be a (${
496
- KEYWORDS.ANONYMOUS_FUNCTION
497
- }) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
498
- )
499
-
500
- return apply(rest, env)
501
- },
502
575
  [KEYWORDS.DEFINE_VARIABLE]: (args, env) => {
503
576
  if (args.length !== 2)
504
577
  throw new RangeError(
@@ -527,171 +600,101 @@ export const keywords = {
527
600
  })
528
601
  return env[name]
529
602
  },
530
- [KEYWORDS.BITWISE_AND]: (args, env) => {
531
- if (args.length < 2)
532
- throw new RangeError(
533
- `Invalid number of arguments to (${
534
- KEYWORDS.BITWISE_AND
535
- }) (= 2 required). (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
536
- )
537
- const operands = args.map((a) => evaluate(a, env))
538
- if (operands.some((x) => typeof x !== 'number'))
539
- throw new TypeError(
540
- `Not all arguments of (${KEYWORDS.BITWISE_AND}) are ${
541
- KEYWORDS.NUMBER_TYPE
542
- } (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
543
- )
544
- return operands.reduce((acc, x) => acc & x)
603
+ [KEYWORDS.ANONYMOUS_FUNCTION]: (args, env) => {
604
+ const params = args.slice(0, -1)
605
+ const body = args.at(-1)
606
+ return (props = [], scope) => {
607
+ if (props.length !== params.length)
608
+ throw new RangeError(
609
+ `Incorrect number of arguments for (${
610
+ KEYWORDS.ANONYMOUS_FUNCTION
611
+ } ${stringifyArgs(params)}) are provided. (expects ${
612
+ params.length
613
+ } but got ${props.length}) (${
614
+ KEYWORDS.ANONYMOUS_FUNCTION
615
+ } ${stringifyArgs(args)})`
616
+ )
617
+ const localEnv = Object.create(env)
618
+ // localEnv[KEYWORDS.BLOCK] = block[KEYWORDS.BLOCK]
619
+ for (let i = 0; i < props.length; ++i) {
620
+ const value = evaluate(props[i], scope)
621
+ Object.defineProperty(localEnv, params[i][VALUE], {
622
+ value,
623
+ writable: true
624
+ })
625
+ }
626
+ return evaluate(body, localEnv)
627
+ }
545
628
  },
546
- [KEYWORDS.BITWISE_NOT]: (args, env) => {
547
- if (args.length !== 1)
629
+ [KEYWORDS.CALL_FUNCTION]: (args, env) => {
630
+ if (!args.length)
548
631
  throw new RangeError(
549
632
  `Invalid number of arguments to (${
550
- KEYWORDS.BITWISE_NOT
551
- }) (= 1 required). (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
633
+ KEYWORDS.CALL_FUNCTION
634
+ }) (>= 1 required) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
552
635
  )
553
- const operand = evaluate(args[0], env)
554
- if (typeof operand !== 'number')
636
+ const [first, ...rest] = args
637
+ if (first[TYPE] === WORD && first[VALUE] in keywords)
555
638
  throw new TypeError(
556
- `Argument of (${KEYWORDS.BITWISE_NOT}) is not a (${
557
- KEYWORDS.NUMBER_TYPE
558
- }) (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
559
- )
560
- return ~operand
561
- },
562
- [KEYWORDS.BITWISE_OR]: (args, env) => {
563
- if (args.length !== 2)
564
- throw new RangeError(
565
- `Invalid number of arguments to (${
566
- KEYWORDS.BITWISE_OR
567
- }) (= 2 required). (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
639
+ `Following argument of (${
640
+ KEYWORDS.CALL_FUNCTION
641
+ }) must not be an reserved word (${
642
+ KEYWORDS.CALL_FUNCTION
643
+ } ${stringifyArgs(args)})`
568
644
  )
569
- const a = evaluate(args[0], env)
570
- const b = evaluate(args[1], env)
571
- if (typeof a !== 'number' || typeof b !== 'number')
645
+ const apply = evaluate(first, env)
646
+ if (typeof apply !== 'function')
572
647
  throw new TypeError(
573
- `Not all arguments of (${KEYWORDS.BITWISE_OR}) are (${
574
- KEYWORDS.NUMBER_TYPE
575
- }) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
648
+ `First argument of (${KEYWORDS.CALL_FUNCTION}) must be a (${
649
+ KEYWORDS.ANONYMOUS_FUNCTION
650
+ }) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
576
651
  )
577
- return a | b
652
+
653
+ return apply(rest, env)
578
654
  },
579
- [KEYWORDS.BITWISE_XOR]: (args, env) => {
580
- if (args.length !== 2)
655
+ [KEYWORDS.BLOCK]: (args, env) => {
656
+ if (!args.length)
581
657
  throw new RangeError(
582
- `Invalid number of arguments to (${
583
- KEYWORDS.BITWISE_XOR
584
- }) (= 2 required). (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
585
- )
586
- const a = evaluate(args[0], env)
587
- const b = evaluate(args[1], env)
588
- if (typeof a !== 'number' || typeof b !== 'number')
589
- throw new TypeError(
590
- `Not all arguments of (${KEYWORDS.BITWISE_XOR}) are (${
591
- KEYWORDS.NUMBER_TYPE
592
- }) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
658
+ `Invalid number of arguments to (${KEYWORDS.BLOCK}) (>= 1 required) (${
659
+ KEYWORDS.BLOCK
660
+ } ${stringifyArgs(args)})`
593
661
  )
594
- return a ^ b
662
+ return args.reduce((_, x) => evaluate(x, env), 0)
595
663
  },
596
- [KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) => {
597
- if (args.length !== 2)
664
+ [KEYWORDS.IS_ATOM]: (args, env) => {
665
+ if (args.length !== 1)
598
666
  throw new RangeError(
599
- `Invalid number of arguments to (${
600
- KEYWORDS.BITWISE_LEFT_SHIFT
601
- }) (= 2 required). (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(
602
- args
603
- )})`
604
- )
605
- const a = evaluate(args[0], env)
606
- const b = evaluate(args[1], env)
607
- if (typeof a !== 'number' || typeof b !== 'number')
608
- throw new TypeError(
609
- `Not all arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) are (${
610
- KEYWORDS.NUMBER_TYPE
611
- }) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)})`
667
+ `Invalid number of arguments for (${
668
+ KEYWORDS.IS_ATOM
669
+ }) (= 1 required) (${KEYWORDS.IS_ATOM} ${stringifyArgs(args)})`
612
670
  )
613
- return a << b
671
+ return +(typeof evaluate(args[0], env) === 'number')
614
672
  },
615
- [KEYWORDS.BITWISE_RIGHT_SHIFT]: (args, env) => {
616
- if (args.length !== 2)
673
+ [KEYWORDS.IS_LAMBDA]: (args, env) => {
674
+ if (args.length !== 1)
617
675
  throw new RangeError(
618
- `Invalid number of arguments to (${
619
- KEYWORDS.BITWISE_RIGHT_SHIFT
620
- }) (= 2 required). (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(
621
- args
622
- )})`
623
- )
624
- const a = evaluate(args[0], env)
625
- const b = evaluate(args[1], env)
626
- if (typeof a !== 'number' || typeof b !== 'number')
627
- throw new TypeError(
628
- `Not all arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) are (${
629
- KEYWORDS.NUMBER_TYPE
630
- }) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)})`
676
+ `Invalid number of arguments for (${
677
+ KEYWORDS.IS_LAMBDA
678
+ }) (= 1 required) (${KEYWORDS.IS_LAMBDA} ${stringifyArgs(args)})`
631
679
  )
632
- return a >> b
680
+ return +(typeof evaluate(args[0], env) === 'function')
633
681
  },
634
- [KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT]: (args, env) => {
635
- if (args.length !== 2)
682
+ // Not sure about these
683
+ [KEYWORDS.THROW]: (args, env) => {
684
+ if (args.length !== 1)
636
685
  throw new RangeError(
637
- `Invalid number of arguments to (${
638
- KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
639
- }) (= 2 required). (${
640
- KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT
686
+ `Invalid number of arguments to (${KEYWORDS.THROW}) (= 1 required) (${
687
+ KEYWORDS.THROW
641
688
  } ${stringifyArgs(args)})`
642
689
  )
643
- const a = evaluate(args[0], env)
644
- const b = evaluate(args[1], env)
645
- if (typeof a !== 'number' || typeof b !== 'number')
646
- throw new TypeError(
647
- `Not all arguments of (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT}) are (${
648
- KEYWORDS.NUMBER_TYPE
649
- }) (${KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT} ${stringifyArgs(args)})`
650
- )
651
- return a >>> b
652
- },
653
- [KEYWORDS.SET_ARRAY]: (args, env) => {
654
- if (args.length !== 1 && args.length !== 3)
655
- throw new RangeError(
656
- `Invalid number of arguments for (${
657
- KEYWORDS.SET_ARRAY
658
- }) (or 1 3) required (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
659
- )
660
- const array = evaluate(args[0], env)
661
- if (!Array.isArray(array))
690
+ const expression = evaluate(args[0], env)
691
+ if (!Array.isArray(expression))
662
692
  throw new TypeError(
663
- `First argument of (${KEYWORDS.SET_ARRAY}) must be an (${
693
+ `Argument of (${KEYWORDS.THROW}) must be an (${
664
694
  KEYWORDS.ARRAY_TYPE
665
- }) but got (${array}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
695
+ }) but got (${expression}) (${KEYWORDS.THROW} ${stringifyArgs(args)})`
666
696
  )
667
- if (args.length === 1) {
668
- array.pop()
669
- } else {
670
- const index = evaluate(args[1], env)
671
- if (!Number.isInteger(index) || index < 0)
672
- throw new TypeError(
673
- `Second argument of (${KEYWORDS.SET_ARRAY}) must be a positive (${
674
- KEYWORDS.NUMBER_TYPE
675
- } integer) (${index}) (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
676
- )
677
- if (index > array.length)
678
- throw new RangeError(
679
- `Second argument of (${KEYWORDS.SET_ARRAY}) is outside of the (${
680
- KEYWORDS.ARRAY_TYPE
681
- }) bounds (index ${index} bounds ${array.length}) (${
682
- KEYWORDS.SET_ARRAY
683
- } ${stringifyArgs(args)})`
684
- )
685
- const value = evaluate(args[2], env)
686
- if (value == undefined)
687
- throw new RangeError(
688
- `Trying to set a null value in (${KEYWORDS.ARRAY_TYPE}) at (${
689
- KEYWORDS.SET_ARRAY
690
- }). (${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
691
- )
692
- array[index] = value
693
- }
694
- return array
697
+ throw new Error(expression.map((x) => String.fromCharCode(x)).join(''))
695
698
  },
696
699
  [KEYWORDS.LOG]: (args, env) => {
697
700
  if (args.length !== 1)
@@ -751,23 +754,5 @@ export const keywords = {
751
754
  )
752
755
  console.clear()
753
756
  return 0
754
- },
755
-
756
- // Not sure about these
757
- [KEYWORDS.THROW]: (args, env) => {
758
- if (args.length !== 1)
759
- throw new RangeError(
760
- `Invalid number of arguments to (${KEYWORDS.THROW}) (= 1 required) (${
761
- KEYWORDS.THROW
762
- } ${stringifyArgs(args)})`
763
- )
764
- const expression = evaluate(args[0], env)
765
- if (!Array.isArray(expression))
766
- throw new TypeError(
767
- `Argument of (${KEYWORDS.THROW}) must be an (${
768
- KEYWORDS.ARRAY_TYPE
769
- }) but got (${expression}) (${KEYWORDS.THROW} ${stringifyArgs(args)})`
770
- )
771
- throw new Error(expression.map((x) => String.fromCharCode(x)).join(''))
772
757
  }
773
758
  }