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.
- package/lib/baked/macros.js +29 -4
- package/lib/baked/std.js +1 -1
- package/package.json +2 -3
- package/src/compiler.js +32 -10
- package/src/interpreter.js +314 -329
- package/src/keywords.js +0 -13
- package/src/macros.js +406 -0
- package/src/utils.js +15 -374
package/src/interpreter.js
CHANGED
@@ -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.
|
6
|
-
if (args.length
|
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.
|
10
|
-
}), expected
|
11
|
-
KEYWORDS.
|
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
|
17
|
+
`First arguments of (${KEYWORDS.ADDITION}) is not a (${
|
18
18
|
KEYWORDS.NUMBER_TYPE
|
19
|
-
}) (${KEYWORDS.
|
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
|
24
|
+
`Second arguments of (${KEYWORDS.ADDITION}) is not a (${
|
25
25
|
KEYWORDS.NUMBER_TYPE
|
26
|
-
}) (${KEYWORDS.
|
26
|
+
}) (${KEYWORDS.ADDITION} ${stringifyArgs(args)})`
|
27
27
|
)
|
28
|
-
|
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
|
-
`
|
31
|
-
KEYWORDS.
|
32
|
-
})
|
33
|
-
|
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
|
-
|
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
|
41
|
-
|
42
|
-
|
43
|
-
|
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.
|
83
|
-
if (args.length !==
|
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.
|
87
|
-
}) (=
|
110
|
+
KEYWORDS.REMAINDER_OF_DIVISION
|
111
|
+
}), expected (= 2) but got ${args.length}. (${
|
112
|
+
KEYWORDS.REMAINDER_OF_DIVISION
|
113
|
+
} ${stringifyArgs(args)})`
|
88
114
|
)
|
89
|
-
const
|
90
|
-
if (
|
115
|
+
const a = evaluate(args[0], env)
|
116
|
+
if (typeof a !== 'number')
|
91
117
|
throw new TypeError(
|
92
|
-
`First argument of (${KEYWORDS.
|
93
|
-
KEYWORDS.
|
94
|
-
} (${KEYWORDS.
|
118
|
+
`First argument of (${KEYWORDS.REMAINDER_OF_DIVISION}) is not (${
|
119
|
+
KEYWORDS.NUMBER_TYPE
|
120
|
+
}) (${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
|
95
121
|
)
|
96
|
-
|
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.
|
99
|
-
if (args.length
|
140
|
+
[KEYWORDS.BITWISE_AND]: (args, env) => {
|
141
|
+
if (args.length < 2)
|
100
142
|
throw new RangeError(
|
101
|
-
`Invalid number of arguments
|
102
|
-
KEYWORDS.
|
103
|
-
}) (=
|
143
|
+
`Invalid number of arguments to (${
|
144
|
+
KEYWORDS.BITWISE_AND
|
145
|
+
}) (= 2 required). (${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
|
104
146
|
)
|
105
|
-
|
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.
|
156
|
+
[KEYWORDS.BITWISE_NOT]: (args, env) => {
|
108
157
|
if (args.length !== 1)
|
109
158
|
throw new RangeError(
|
110
|
-
`Invalid number of arguments
|
111
|
-
KEYWORDS.
|
112
|
-
}) (= 1 required) (${KEYWORDS.
|
159
|
+
`Invalid number of arguments to (${
|
160
|
+
KEYWORDS.BITWISE_NOT
|
161
|
+
}) (= 1 required). (${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
|
113
162
|
)
|
114
|
-
|
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.
|
117
|
-
if (args.length !==
|
172
|
+
[KEYWORDS.BITWISE_OR]: (args, env) => {
|
173
|
+
if (args.length !== 2)
|
118
174
|
throw new RangeError(
|
119
|
-
`Invalid number of arguments
|
120
|
-
KEYWORDS.
|
121
|
-
})
|
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
|
-
`
|
183
|
+
`Not all arguments of (${KEYWORDS.BITWISE_OR}) are (${
|
136
184
|
KEYWORDS.NUMBER_TYPE
|
137
|
-
}) (${KEYWORDS.
|
185
|
+
}) (${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
|
138
186
|
)
|
139
|
-
return a
|
187
|
+
return a | b
|
140
188
|
},
|
141
|
-
[KEYWORDS.
|
142
|
-
if (args.length !==
|
189
|
+
[KEYWORDS.BITWISE_XOR]: (args, env) => {
|
190
|
+
if (args.length !== 2)
|
143
191
|
throw new RangeError(
|
144
|
-
`Invalid number of arguments
|
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
|
-
`
|
200
|
+
`Not all arguments of (${KEYWORDS.BITWISE_XOR}) are (${
|
157
201
|
KEYWORDS.NUMBER_TYPE
|
158
|
-
}) (${KEYWORDS.
|
202
|
+
}) (${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
|
159
203
|
)
|
160
|
-
return a
|
204
|
+
return a ^ b
|
161
205
|
},
|
162
|
-
[KEYWORDS.
|
163
|
-
if (args.length !==
|
206
|
+
[KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) => {
|
207
|
+
if (args.length !== 2)
|
164
208
|
throw new RangeError(
|
165
|
-
`Invalid number of arguments
|
166
|
-
KEYWORDS.
|
167
|
-
})
|
168
|
-
|
169
|
-
|
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
|
-
|
216
|
+
const b = evaluate(args[1], env)
|
217
|
+
if (typeof a !== 'number' || typeof b !== 'number')
|
173
218
|
throw new TypeError(
|
174
|
-
`
|
219
|
+
`Not all arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) are (${
|
175
220
|
KEYWORDS.NUMBER_TYPE
|
176
|
-
}) (${KEYWORDS.
|
221
|
+
}) (${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(args)})`
|
177
222
|
)
|
178
|
-
|
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
|
-
`
|
238
|
+
`Not all arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) are (${
|
183
239
|
KEYWORDS.NUMBER_TYPE
|
184
|
-
}) (${KEYWORDS.
|
240
|
+
}) (${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(args)})`
|
185
241
|
)
|
186
|
-
return a
|
242
|
+
return a >> b
|
187
243
|
},
|
188
|
-
[KEYWORDS.
|
189
|
-
if (args.length
|
244
|
+
[KEYWORDS.BITWISE_UNSIGNED_RIGHT_SHIFT]: (args, env) => {
|
245
|
+
if (args.length !== 2)
|
190
246
|
throw new RangeError(
|
191
|
-
`Invalid number of arguments
|
192
|
-
KEYWORDS.
|
193
|
-
})
|
194
|
-
KEYWORDS.
|
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
|
198
|
-
|
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
|
-
`
|
201
|
-
KEYWORDS.
|
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
|
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.
|
256
|
-
if (
|
308
|
+
[KEYWORDS.SET_ARRAY]: (args, env) => {
|
309
|
+
if (args.length !== 1 && args.length !== 3)
|
257
310
|
throw new RangeError(
|
258
|
-
`Invalid number of arguments
|
259
|
-
KEYWORDS.
|
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
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
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
|
-
`
|
271
|
-
KEYWORDS.
|
272
|
-
} ${
|
273
|
-
|
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
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
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.
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
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.
|
547
|
-
if (args.length
|
629
|
+
[KEYWORDS.CALL_FUNCTION]: (args, env) => {
|
630
|
+
if (!args.length)
|
548
631
|
throw new RangeError(
|
549
632
|
`Invalid number of arguments to (${
|
550
|
-
KEYWORDS.
|
551
|
-
}) (
|
633
|
+
KEYWORDS.CALL_FUNCTION
|
634
|
+
}) (>= 1 required) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
|
552
635
|
)
|
553
|
-
const
|
554
|
-
if (
|
636
|
+
const [first, ...rest] = args
|
637
|
+
if (first[TYPE] === WORD && first[VALUE] in keywords)
|
555
638
|
throw new TypeError(
|
556
|
-
`
|
557
|
-
KEYWORDS.
|
558
|
-
}) (${
|
559
|
-
|
560
|
-
|
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
|
570
|
-
|
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
|
-
`
|
574
|
-
KEYWORDS.
|
575
|
-
}) (${KEYWORDS.
|
648
|
+
`First argument of (${KEYWORDS.CALL_FUNCTION}) must be a (${
|
649
|
+
KEYWORDS.ANONYMOUS_FUNCTION
|
650
|
+
}) (${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(args)})`
|
576
651
|
)
|
577
|
-
|
652
|
+
|
653
|
+
return apply(rest, env)
|
578
654
|
},
|
579
|
-
[KEYWORDS.
|
580
|
-
if (args.length
|
655
|
+
[KEYWORDS.BLOCK]: (args, env) => {
|
656
|
+
if (!args.length)
|
581
657
|
throw new RangeError(
|
582
|
-
`Invalid number of arguments to (${
|
583
|
-
KEYWORDS.
|
584
|
-
}
|
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
|
662
|
+
return args.reduce((_, x) => evaluate(x, env), 0)
|
595
663
|
},
|
596
|
-
[KEYWORDS.
|
597
|
-
if (args.length !==
|
664
|
+
[KEYWORDS.IS_ATOM]: (args, env) => {
|
665
|
+
if (args.length !== 1)
|
598
666
|
throw new RangeError(
|
599
|
-
`Invalid number of arguments
|
600
|
-
KEYWORDS.
|
601
|
-
}) (=
|
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
|
671
|
+
return +(typeof evaluate(args[0], env) === 'number')
|
614
672
|
},
|
615
|
-
[KEYWORDS.
|
616
|
-
if (args.length !==
|
673
|
+
[KEYWORDS.IS_LAMBDA]: (args, env) => {
|
674
|
+
if (args.length !== 1)
|
617
675
|
throw new RangeError(
|
618
|
-
`Invalid number of arguments
|
619
|
-
KEYWORDS.
|
620
|
-
}) (=
|
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
|
680
|
+
return +(typeof evaluate(args[0], env) === 'function')
|
633
681
|
},
|
634
|
-
|
635
|
-
|
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.
|
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
|
644
|
-
|
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
|
-
`
|
693
|
+
`Argument of (${KEYWORDS.THROW}) must be an (${
|
664
694
|
KEYWORDS.ARRAY_TYPE
|
665
|
-
}) but got (${
|
695
|
+
}) but got (${expression}) (${KEYWORDS.THROW} ${stringifyArgs(args)})`
|
666
696
|
)
|
667
|
-
|
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
|
}
|