fez-lisp 1.3.2 → 1.3.4

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