fez-lisp 1.6.28 → 1.6.30

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/README.md CHANGED
@@ -28,8 +28,17 @@
28
28
 
29
29
  ```lisp
30
30
  ; Lisp programming language. It's not exactly like other Lisps.
31
+ ; This is a CUSTOM lisp language that does not fully follow the general Lisp conventions
32
+
33
+ ; Plase strictly follow the language rules as described in this document
34
+
31
35
  ; Everything is an expression.
32
36
 
37
+ ; Build-in keywords
38
+ (/ ...) (+ ...) (* ...) (- ...) (= ...) (< ...) (> ...) (>= ...) (<= ...) (& ...) (~ ...) (| ...) (^ ...) (<< ...) (>> ...)
39
+ (mod ...) (let ...) (if ...) (not ...) (and ...) (or ...) (atom? ...) (lambda? ...)
40
+ (length ...) (do ...) (array ...) (set! ...) (pop! ...) (get ...) (lambda ...) (apply ...)
41
+
33
42
  ; Important Note:
34
43
  ; In this programming language, parentheses are used to group expressions and define the structure of code.
35
44
  ; It is essential to keep the number of opening and closing parentheses balanced.
@@ -83,7 +92,7 @@
83
92
  (array:push! xs (length xs) 10) ; add the value 10 at the end of array xs
84
93
  (array:get xs 0) ; get the first element of array xs
85
94
 
86
- ; Note: array:set! and array:pop! are functions that update arrays (array:set! xs idx value, array:pop! xs).
95
+ ; Note: set! and pop! are functions that update arrays (set! xs idx value, pop! xs).
87
96
  ; If you want to update variables (scalars), use the variable helpers: var:def to define, var:set! to update, and var:get to retrieve the value.
88
97
 
89
98
  ; Mathematical operations
@@ -164,7 +173,7 @@
164
173
  ; IMPORTANT: Variable Handling and set! Usage
165
174
  ; ===========================================
166
175
  ;
167
- ; array:set! is ONLY for arrays - it cannot be used to update scalar variables.
176
+ ; set! is ONLY for arrays - it cannot be used to update scalar variables.
168
177
  ; If you want to update variables (scalars), use the appropriate variable helper functions.
169
178
  ;
170
179
  ; There are three types of variable systems in this language:
@@ -226,8 +235,8 @@
226
235
  xs)))
227
236
  (let arr:merge (lambda a b (do
228
237
  (let out (array)) initialize an empty array for output
229
- (arr:for a (lambda x (do (array:set! out (length out) x))))
230
- (arr:for b (lambda x (do (array:set! out (length out) x)))) out)))
238
+ (arr:for a (lambda x (do (set! out (length out) x))))
239
+ (arr:for b (lambda x (do (set! out (length out) x)))) out)))
231
240
  (let arr:reverse (lambda xs (do
232
241
  (let tail-call:arr:reverse (lambda i out (do
233
242
  (if (> (length xs) i)
@@ -256,4 +265,24 @@
256
265
  ; pipe operator with destructuring
257
266
 
258
267
  "Hello World!" ; syntactic suggar for string but it's array of character codes
268
+
269
+ ; syntactic suggar for variables
270
+
271
+ (let xs [])
272
+ (variable i 0) ; define number variables
273
+ (get i) ; getting nubmer variable
274
+ (loop (< (get i) 10) (do
275
+ (array:push! xs (get i))
276
+ (++ i) ; increment number variaable
277
+ ))
278
+
279
+ (boolean x false) ; define boolean variable as false
280
+ (boolean y true) ; define boolean variable as true
281
+ (boole-set x true) ; set boolean variable
282
+ (and (boole:true? x) (boole:true? y)) ; check if boolean variable is true (this is using boole:* from std)
283
+ (variable n 10) ; define number variable
284
+ (++ n) ; increment number variable by 1
285
+ (+= n 10) ; increment number variable by 10
286
+ (get n) ; get number variable
287
+
259
288
  ```
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.6.28",
5
+ "version": "1.6.30",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
package/src/debugger.js CHANGED
@@ -1,4 +1,7 @@
1
- import { serialise } from '../editor/utils.js'
1
+ import stdT from '../lib/baked/std-T.js'
2
+ import std from '../lib/baked/std.js'
3
+ import { typeCheck } from './check.js'
4
+ import { enhance } from './enhance.js'
2
5
  import {
3
6
  APPLY,
4
7
  ATOM,
@@ -8,85 +11,817 @@ import {
8
11
  WORD,
9
12
  TRUE,
10
13
  FALSE,
11
- STATIC_TYPES
14
+ STATIC_TYPES,
15
+ DEBUG,
16
+ SPECIAL_FORMS_SET
12
17
  } from './keywords.js'
13
18
  import { isLeaf, LISP } from './parser.js'
19
+ import { definedTypes, filteredDefinedTypes, withCtxTypes } from './types.js'
20
+ import { isForbiddenVariableName } from './utils.js'
14
21
  const keywords = {
15
- [KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) =>
16
- evaluate(args[0], env) % evaluate(args[1], env),
17
- [KEYWORDS.DIVISION]: (args, env) =>
18
- evaluate(args[0], env) / evaluate(args[1], env),
19
- [KEYWORDS.ARRAY_LENGTH]: (args, env) => evaluate(args[0], env).length,
20
- [KEYWORDS.IS_ATOM]: (args, env) =>
21
- +(typeof evaluate(args[0], env) === 'number'),
22
- [KEYWORDS.IS_LAMBDA]: (args, env) =>
23
- +(typeof evaluate(args[0], env) === 'function'),
24
- [KEYWORDS.ADDITION]: (args, env) =>
25
- evaluate(args[0], env) + evaluate(args[1], env),
26
- [KEYWORDS.MULTIPLICATION]: (args, env) =>
27
- evaluate(args[0], env) * evaluate(args[1], env),
28
- [KEYWORDS.SUBTRACTION]: (args, env) =>
29
- evaluate(args[0], env) - evaluate(args[1], env),
30
- [KEYWORDS.CREATE_ARRAY]: (args, env) =>
31
- args.length ? args.map((x) => evaluate(x, env)) : [],
32
- [KEYWORDS.GET_ARRAY]: (args, env) =>
33
- evaluate(args[0], env)[evaluate(args[1], env)],
34
- [KEYWORDS.BLOCK]: (args, env) =>
35
- args.reduce((_, x) => evaluate(x, env), FALSE),
36
- [KEYWORDS.NOT]: (args, env) => +!evaluate(args[0], env),
37
- [KEYWORDS.EQUAL]: (args, env) =>
38
- +(evaluate(args[0], env) === evaluate(args[1], env)),
39
- [KEYWORDS.LESS_THAN]: (args, env) =>
40
- +(evaluate(args[0], env) < evaluate(args[1], env)),
41
- [KEYWORDS.GREATHER_THAN]: (args, env) =>
42
- +(evaluate(args[0], env) > evaluate(args[1], env)),
43
- [KEYWORDS.GREATHER_THAN_OR_EQUAL]: (args, env) =>
44
- +(evaluate(args[0], env) >= evaluate(args[1], env)),
45
- [KEYWORDS.LESS_THAN_OR_EQUAL]: (args, env) =>
46
- +(evaluate(args[0], env) <= evaluate(args[1], env)),
47
- [KEYWORDS.AND]: (args, env) =>
48
- !evaluate(args[0], env) ? FALSE : evaluate(args[1], env),
49
- [KEYWORDS.OR]: (args, env) =>
50
- evaluate(args[0], env) ? TRUE : evaluate(args[1], env),
51
- [KEYWORDS.CALL_FUNCTION]: (args, env) => evaluate(args.pop(), env)(args, env),
52
- [KEYWORDS.DEFINE_VARIABLE]: (args, env) =>
53
- (env[args[0][VALUE]] = evaluate(args[1], env)),
54
- [KEYWORDS.BITWISE_AND]: (args, env) =>
55
- evaluate(args[0], env) & evaluate(args[1], env),
56
- [KEYWORDS.BITWISE_NOT]: (args, env) => ~evaluate(args[0], env),
57
- [KEYWORDS.BITWISE_OR]: (args, env) =>
58
- evaluate(args[0], env) | evaluate(args[1], env),
59
- [KEYWORDS.BITWISE_XOR]: (args, env) =>
60
- evaluate(args[0], env) ^ evaluate(args[1], env),
61
- [KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) =>
62
- evaluate(args[0], env) << evaluate(args[1], env),
63
- [KEYWORDS.BITWISE_RIGHT_SHIFT]: (args, env) =>
64
- evaluate(args[0], env) >> evaluate(args[1], env),
65
- [KEYWORDS.IF]: (args, env) =>
66
- evaluate(args[0], env) ? evaluate(args[1], env) : evaluate(args[2], env),
67
22
  [KEYWORDS.LOOP]: (args, env) => {
23
+ if (args.length != 2)
24
+ throw new RangeError(`Wrong number of args to ${KEYWORDS.LOOP}`)
68
25
  while (evaluate(args[0], env) === TRUE) evaluate(args[1], env)
69
26
  return -1
70
27
  },
28
+ [KEYWORDS.ADDITION]: (args, env) => {
29
+ if (args.length !== 2)
30
+ throw new RangeError(
31
+ `Invalid number of arguments for (${
32
+ KEYWORDS.ADDITION
33
+ }), expected (= 2) but got ${args.length}\n\n(${
34
+ KEYWORDS.ADDITION
35
+ } ${stringifyArgs(args)})`
36
+ )
37
+ const a = evaluate(args[0], env)
38
+ if (typeof a !== 'number')
39
+ throw new TypeError(
40
+ `First arguments of (${KEYWORDS.ADDITION}) must be a (${
41
+ RUNTIME_TYPES.NUMBER
42
+ }) but ${LISP.source(args[0])} is not\n\n(${
43
+ KEYWORDS.ADDITION
44
+ } ${stringifyArgs(args)})`
45
+ )
46
+ const b = evaluate(args[1], env)
47
+ if (typeof b !== 'number')
48
+ throw new TypeError(
49
+ `Second arguments of (${KEYWORDS.ADDITION}) must be a (${
50
+ RUNTIME_TYPES.NUMBER
51
+ }) but ${LISP.source(args[1])} is not\n\n(${
52
+ KEYWORDS.ADDITION
53
+ } ${stringifyArgs(args)})`
54
+ )
55
+ return a + b
56
+ },
57
+ [KEYWORDS.MULTIPLICATION]: (args, env) => {
58
+ if (args.length !== 2)
59
+ throw new RangeError(
60
+ `Invalid number of arguments for (${
61
+ KEYWORDS.MULTIPLICATION
62
+ }), expected (= 2) but got ${args.length}\n\n(${
63
+ KEYWORDS.MULTIPLICATION
64
+ } ${stringifyArgs(args)})`
65
+ )
66
+ const a = evaluate(args[0], env)
67
+ if (typeof a !== 'number')
68
+ throw new TypeError(
69
+ `First arguments of (${KEYWORDS.MULTIPLICATION}) must be a (${
70
+ RUNTIME_TYPES.NUMBER
71
+ }) but ${LISP.source(args[0])} is not\n\n(${
72
+ KEYWORDS.MULTIPLICATION
73
+ } ${stringifyArgs(args)})`
74
+ )
75
+ const b = evaluate(args[1], env)
76
+ if (typeof b !== 'number')
77
+ throw new TypeError(
78
+ `Second arguments of (${KEYWORDS.MULTIPLICATION}) must be a (${
79
+ RUNTIME_TYPES.NUMBER
80
+ }) but ${LISP.source(args[1])} is not\n\n(${
81
+ KEYWORDS.MULTIPLICATION
82
+ } ${stringifyArgs(args)})`
83
+ )
84
+ return a * b
85
+ },
86
+ [KEYWORDS.SUBTRACTION]: (args, env) => {
87
+ if (args.length !== 2)
88
+ throw new RangeError(
89
+ `Invalid number of arguments for (${
90
+ KEYWORDS.SUBTRACTION
91
+ }), expected (= 2) but got ${args.length}\n\n(${
92
+ KEYWORDS.SUBTRACTION
93
+ } ${stringifyArgs(args)})`
94
+ )
95
+ const a = evaluate(args[0], env)
96
+ if (typeof a !== 'number')
97
+ throw new TypeError(
98
+ `First argument of (${KEYWORDS.SUBTRACTION}) must be a (${
99
+ RUNTIME_TYPES.NUMBER
100
+ }) but ${LISP.source(args[0])} is not\n\n(${
101
+ KEYWORDS.SUBTRACTION
102
+ } ${stringifyArgs(args)})`
103
+ )
104
+ const b = evaluate(args[1], env)
105
+ if (typeof b !== 'number')
106
+ throw new TypeError(
107
+ `Second argument of (${KEYWORDS.SUBTRACTION}) must be a (${
108
+ RUNTIME_TYPES.NUMBER
109
+ }) but ${LISP.source(args[1])} is not\n\n(${
110
+ KEYWORDS.SUBTRACTION
111
+ } ${stringifyArgs(args)})`
112
+ )
113
+ return a - b
114
+ },
115
+ [KEYWORDS.DIVISION]: (args, env) => {
116
+ if (args.length !== 2)
117
+ throw new RangeError(
118
+ `Invalid number of arguments for (${
119
+ KEYWORDS.DIVISION
120
+ }), expected (= 2) but got ${args.length}\n\n(${
121
+ KEYWORDS.DIVISION
122
+ } ${stringifyArgs(args)})`
123
+ )
124
+ const a = evaluate(args[0], env)
125
+ if (typeof a !== 'number')
126
+ throw new TypeError(
127
+ `First argument of (${KEYWORDS.DIVISION}) is not (${
128
+ RUNTIME_TYPES.NUMBER
129
+ }) but ${LISP.source(args[0])} is not\n\n(${
130
+ KEYWORDS.DIVISION
131
+ } ${stringifyArgs(args)})`
132
+ )
133
+ const b = evaluate(args[1], env)
134
+ if (typeof b !== 'number')
135
+ throw new TypeError(
136
+ `Second argument of (${KEYWORDS.DIVISION}) is not (${
137
+ RUNTIME_TYPES.NUMBER
138
+ }) but ${LISP.source(args[1])} is not\n\n(${
139
+ KEYWORDS.DIVISION
140
+ } ${stringifyArgs(args)})`
141
+ )
142
+ if (b === 0)
143
+ throw new TypeError(
144
+ `Second Argument of (${
145
+ KEYWORDS.DIVISION
146
+ }) can't be a 0 (division by 0 is not allowed) but ${LISP.source(
147
+ args[1]
148
+ )} is 0\n\n(${KEYWORDS.DIVISION} ${stringifyArgs(args)})`
149
+ )
150
+ return a / b
151
+ },
152
+ [KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) => {
153
+ if (args.length !== 2)
154
+ throw new RangeError(
155
+ `Invalid number of arguments for (${
156
+ KEYWORDS.REMAINDER_OF_DIVISION
157
+ }), expected (= 2) but got ${args.length}\n\n(${
158
+ KEYWORDS.REMAINDER_OF_DIVISION
159
+ } ${stringifyArgs(args)})`
160
+ )
161
+ const a = evaluate(args[0], env)
162
+ if (typeof a !== 'number')
163
+ throw new TypeError(
164
+ `First argument of (${KEYWORDS.REMAINDER_OF_DIVISION}) is not (${
165
+ RUNTIME_TYPES.NUMBER
166
+ }) but ${LISP.source(args[0])} is not\n\n(${
167
+ KEYWORDS.REMAINDER_OF_DIVISION
168
+ } ${stringifyArgs(args)})`
169
+ )
170
+ const b = evaluate(args[1], env)
171
+ if (typeof b !== 'number')
172
+ throw new TypeError(
173
+ `Second argument of (${KEYWORDS.REMAINDER_OF_DIVISION}) is not (${
174
+ RUNTIME_TYPES.NUMBER
175
+ }) but ${LISP.source(args[1])} is not\n\n(${
176
+ KEYWORDS.REMAINDER_OF_DIVISION
177
+ } ${stringifyArgs(args)})`
178
+ )
179
+ if (b === 0)
180
+ throw new TypeError(
181
+ `Second argument of (${
182
+ KEYWORDS.REMAINDER_OF_DIVISION
183
+ }) can't be a 0 (division by 0 is not allowed) but ${LISP.source(
184
+ args[1]
185
+ )} is 0\n\n(${KEYWORDS.REMAINDER_OF_DIVISION} ${stringifyArgs(args)})`
186
+ )
187
+
188
+ return a % b
189
+ },
190
+ [KEYWORDS.BITWISE_AND]: (args, env) => {
191
+ if (args.length !== 2)
192
+ throw new RangeError(
193
+ `Invalid number of arguments to (${
194
+ KEYWORDS.BITWISE_AND
195
+ }) (= 2 required)\n\n(${KEYWORDS.BITWISE_AND} ${stringifyArgs(args)})`
196
+ )
197
+ const a = evaluate(args[0], env)
198
+ if (typeof a !== 'number')
199
+ throw new TypeError(
200
+ `First arguments of (${KEYWORDS.BITWISE_AND}) must be a (${
201
+ RUNTIME_TYPES.NUMBER
202
+ }) but ${LISP.source(args[0])} is not\n\n(${
203
+ KEYWORDS.BITWISE_AND
204
+ } ${stringifyArgs(args)})`
205
+ )
206
+ const b = evaluate(args[1], env)
207
+ if (typeof b !== 'number')
208
+ throw new TypeError(
209
+ `Second arguments of (${KEYWORDS.BITWISE_AND}) must be a (${
210
+ RUNTIME_TYPES.NUMBER
211
+ }) but ${LISP.source(args[1])} is not\n\n(${
212
+ KEYWORDS.BITWISE_AND
213
+ } ${stringifyArgs(args)})`
214
+ )
215
+ return a & b
216
+ },
217
+ [KEYWORDS.BITWISE_NOT]: (args, env) => {
218
+ if (args.length !== 1)
219
+ throw new RangeError(
220
+ `Invalid number of arguments to (${
221
+ KEYWORDS.BITWISE_NOT
222
+ }) (= 1 required)\n\n(${KEYWORDS.BITWISE_NOT} ${stringifyArgs(args)})`
223
+ )
224
+ const operand = evaluate(args[0], env)
225
+ if (typeof operand !== 'number')
226
+ throw new TypeError(
227
+ `Argument of (${KEYWORDS.BITWISE_NOT}) must be a (${
228
+ RUNTIME_TYPES.NUMBER
229
+ }) but ${LISP.source(args[0])} is not\n\n(${
230
+ KEYWORDS.BITWISE_NOT
231
+ } ${stringifyArgs(args)})`
232
+ )
233
+ return ~operand
234
+ },
235
+ [KEYWORDS.BITWISE_OR]: (args, env) => {
236
+ if (args.length !== 2)
237
+ throw new RangeError(
238
+ `Invalid number of arguments to (${
239
+ KEYWORDS.BITWISE_OR
240
+ }) (= 2 required)\n\n(${KEYWORDS.BITWISE_OR} ${stringifyArgs(args)})`
241
+ )
242
+ const a = evaluate(args[0], env)
243
+ if (typeof a !== 'number')
244
+ throw new TypeError(
245
+ `First arguments of (${KEYWORDS.BITWISE_OR}) must be a (${
246
+ RUNTIME_TYPES.NUMBER
247
+ }) but ${LISP.source(args[0])} is not\n\n(${
248
+ KEYWORDS.BITWISE_OR
249
+ } ${stringifyArgs(args)})`
250
+ )
251
+ const b = evaluate(args[1], env)
252
+ if (typeof b !== 'number')
253
+ throw new TypeError(
254
+ `Second arguments of (${KEYWORDS.BITWISE_OR}) must be a (${
255
+ RUNTIME_TYPES.NUMBER
256
+ }) but ${LISP.source(args[1])} is not\n\n(${
257
+ KEYWORDS.BITWISE_OR
258
+ } ${stringifyArgs(args)})`
259
+ )
260
+ return a | b
261
+ },
262
+ [KEYWORDS.BITWISE_XOR]: (args, env) => {
263
+ if (args.length !== 2)
264
+ throw new RangeError(
265
+ `Invalid number of arguments to (${
266
+ KEYWORDS.BITWISE_XOR
267
+ }) (= 2 required)\n\n(${KEYWORDS.BITWISE_XOR} ${stringifyArgs(args)})`
268
+ )
269
+ const a = evaluate(args[0], env)
270
+ if (typeof a !== 'number')
271
+ throw new TypeError(
272
+ `First arguments of (${KEYWORDS.BITWISE_XOR}) must be a (${
273
+ RUNTIME_TYPES.NUMBER
274
+ }) but ${LISP.source(args[0])} is not\n\n(${
275
+ KEYWORDS.BITWISE_XOR
276
+ } ${stringifyArgs(args)})`
277
+ )
278
+ const b = evaluate(args[1], env)
279
+ if (typeof b !== 'number')
280
+ throw new TypeError(
281
+ `Second arguments of (${KEYWORDS.BITWISE_XOR}) must be a (${
282
+ RUNTIME_TYPES.NUMBER
283
+ }) but ${LISP.source(args[1])} is not\n\n(${
284
+ KEYWORDS.BITWISE_XOR
285
+ } ${stringifyArgs(args)})`
286
+ )
287
+ return a ^ b
288
+ },
289
+ [KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) => {
290
+ if (args.length !== 2)
291
+ throw new RangeError(
292
+ `Invalid number of arguments to (${
293
+ KEYWORDS.BITWISE_LEFT_SHIFT
294
+ }) (= 2 required)\n\n(${KEYWORDS.BITWISE_LEFT_SHIFT} ${stringifyArgs(
295
+ args
296
+ )})`
297
+ )
298
+ const a = evaluate(args[0], env)
299
+ if (typeof a !== 'number')
300
+ throw new TypeError(
301
+ `First arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) must be a (${
302
+ RUNTIME_TYPES.NUMBER
303
+ }) but ${LISP.source(args[0])} is not\n\n(${
304
+ KEYWORDS.BITWISE_LEFT_SHIFT
305
+ } ${stringifyArgs(args)})`
306
+ )
307
+ const b = evaluate(args[1], env)
308
+ if (typeof b !== 'number')
309
+ throw new TypeError(
310
+ `Second arguments of (${KEYWORDS.BITWISE_LEFT_SHIFT}) must be a (${
311
+ RUNTIME_TYPES.NUMBER
312
+ }) but ${LISP.source(args[1])} is not\n\n(${
313
+ KEYWORDS.BITWISE_LEFT_SHIFT
314
+ } ${stringifyArgs(args)})`
315
+ )
316
+ return a << b
317
+ },
318
+ [KEYWORDS.BITWISE_RIGHT_SHIFT]: (args, env) => {
319
+ if (args.length !== 2)
320
+ throw new RangeError(
321
+ `Invalid number of arguments to (${
322
+ KEYWORDS.BITWISE_RIGHT_SHIFT
323
+ }) (= 2 required)\n\n(${KEYWORDS.BITWISE_RIGHT_SHIFT} ${stringifyArgs(
324
+ args
325
+ )})`
326
+ )
327
+ const a = evaluate(args[0], env)
328
+ if (typeof a !== 'number')
329
+ throw new TypeError(
330
+ `First arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) must be a (${
331
+ RUNTIME_TYPES.NUMBER
332
+ }) but ${LISP.source(args[0])} is not\n\n(${
333
+ KEYWORDS.BITWISE_RIGHT_SHIFT
334
+ } ${stringifyArgs(args)})`
335
+ )
336
+ const b = evaluate(args[1], env)
337
+ if (typeof b !== 'number')
338
+ throw new TypeError(
339
+ `Second arguments of (${KEYWORDS.BITWISE_RIGHT_SHIFT}) must be a (${
340
+ RUNTIME_TYPES.NUMBER
341
+ }) but ${LISP.source(args[1])} is not\n\n(${
342
+ KEYWORDS.BITWISE_RIGHT_SHIFT
343
+ } ${stringifyArgs(args)})`
344
+ )
345
+ return a >> b
346
+ },
347
+ [KEYWORDS.CREATE_ARRAY]: (args, env) => {
348
+ return args.length ? args.map((x) => evaluate(x, env)) : []
349
+ },
350
+ [KEYWORDS.GET_ARRAY]: (args, env) => {
351
+ if (args.length !== 2)
352
+ throw new RangeError(
353
+ `Invalid number of arguments for (${
354
+ KEYWORDS.GET_ARRAY
355
+ }) (= 2 required)\n\n(${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
356
+ )
357
+ const array = evaluate(args[0], env)
358
+ if (!Array.isArray(array))
359
+ throw new TypeError(
360
+ `First argument of (${KEYWORDS.GET_ARRAY}) must be an (${
361
+ RUNTIME_TYPES.ARRAY
362
+ })\n\n(${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
363
+ )
364
+ if (array.length === 0)
365
+ throw new RangeError(
366
+ `First argument of (${KEYWORDS.GET_ARRAY}) is an empty (${
367
+ RUNTIME_TYPES.ARRAY
368
+ })\n\n(${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
369
+ )
370
+ const index = evaluate(args[1], env)
371
+ if (!Number.isInteger(index) || index < 0)
372
+ throw new TypeError(
373
+ `Second argument of (${
374
+ KEYWORDS.GET_ARRAY
375
+ }) must be a positive (interger ${
376
+ RUNTIME_TYPES.NUMBER
377
+ }) (= i ${index})\n\n(${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
378
+ )
379
+ if (index > array.length - 1)
380
+ throw new RangeError(
381
+ `Second argument of (${KEYWORDS.GET_ARRAY}) is outside of (${
382
+ RUNTIME_TYPES.ARRAY
383
+ }) bounds (= i ${index}) expected (and (>= i 0) (< i ${
384
+ array.length
385
+ }))\n\n(${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
386
+ )
387
+ const value = array.at(index)
388
+ if (value == undefined)
389
+ throw new RangeError(
390
+ `Trying to get a null value in (${RUNTIME_TYPES.ARRAY}) at (${
391
+ KEYWORDS.GET_ARRAY
392
+ })\n\n(${KEYWORDS.GET_ARRAY} ${stringifyArgs(args)})`
393
+ )
394
+ return value
395
+ },
71
396
  [KEYWORDS.SET_ARRAY]: (args, env) => {
397
+ if (args.length !== 3)
398
+ throw new RangeError(
399
+ `Invalid number of arguments for (${
400
+ KEYWORDS.SET_ARRAY
401
+ }) (= 3) required\n\n(${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
402
+ )
72
403
  const array = evaluate(args[0], env)
73
- array[evaluate(args[1], env)] = evaluate(args[2], env)
404
+ if (!Array.isArray(array))
405
+ throw new TypeError(
406
+ `First argument of (${KEYWORDS.SET_ARRAY}) must be an (${
407
+ RUNTIME_TYPES.ARRAY
408
+ }) but ${LISP.source(args[0])} is not\n\n(${
409
+ KEYWORDS.SET_ARRAY
410
+ } ${stringifyArgs(args)})`
411
+ )
412
+ const index = evaluate(args[1], env)
413
+ if (!Number.isInteger(index) || index < 0)
414
+ throw new TypeError(
415
+ `Second argument of (${KEYWORDS.SET_ARRAY}) must be a positive (${
416
+ RUNTIME_TYPES.NUMBER
417
+ } integer) (= i ${index}) but ${LISP.source(args[1])} is not\n\n(${
418
+ KEYWORDS.SET_ARRAY
419
+ } ${stringifyArgs(args)})`
420
+ )
421
+ if (index > array.length)
422
+ throw new RangeError(
423
+ `Second argument of (${KEYWORDS.SET_ARRAY}) is outside of the (${
424
+ RUNTIME_TYPES.ARRAY
425
+ }) bounds (${index}) expected (and (>= i 0) (< i ${
426
+ array.length
427
+ })) but ${LISP.source(args[1])} is not\n\n(${
428
+ KEYWORDS.SET_ARRAY
429
+ } ${stringifyArgs(args)})`
430
+ )
431
+ const value = evaluate(args[2], env)
432
+ if (value == undefined)
433
+ throw new RangeError(
434
+ `Trying to set a null value in (${RUNTIME_TYPES.ARRAY}) at (${
435
+ KEYWORDS.SET_ARRAY
436
+ })\n\n(${KEYWORDS.SET_ARRAY} ${stringifyArgs(args)})`
437
+ )
438
+ array[index] = value
74
439
  return array
75
440
  },
76
441
  [KEYWORDS.POP_ARRAY]: (args, env) => {
442
+ if (args.length !== 1)
443
+ throw new RangeError(
444
+ `Invalid number of arguments for (${
445
+ KEYWORDS.POP_ARRAY
446
+ }) (= 1) required\n\n(${KEYWORDS.POP_ARRAY} ${stringifyArgs(args)})`
447
+ )
77
448
  const array = evaluate(args[0], env)
449
+ if (!Array.isArray(array))
450
+ throw new TypeError(
451
+ `First argument of (${KEYWORDS.POP_ARRAY}) must be an (${
452
+ RUNTIME_TYPES.ARRAY
453
+ }) but ${LISP.source(args[0])} is not\n\n(${
454
+ KEYWORDS.POP_ARRAY
455
+ } ${stringifyArgs(args)})`
456
+ )
78
457
  array.pop()
79
458
  return array
80
459
  },
460
+ [KEYWORDS.ARRAY_LENGTH]: (args, env) => {
461
+ if (args.length !== 1)
462
+ throw new RangeError(
463
+ `Invalid number of arguments for (${
464
+ KEYWORDS.ARRAY_LENGTH
465
+ }) (= 1 required)\n\n(${KEYWORDS.ARRAY_LENGTH} ${stringifyArgs(args)})`
466
+ )
467
+ const array = evaluate(args[0], env)
468
+ if (!Array.isArray(array))
469
+ throw new TypeError(
470
+ `First argument of (${KEYWORDS.ARRAY_LENGTH}) must be an ${
471
+ RUNTIME_TYPES.ARRAY
472
+ } but ${LISP.source(args[0])} is not\n\n(${
473
+ KEYWORDS.ARRAY_LENGTH
474
+ } ${stringifyArgs(args)})`
475
+ )
476
+ return array.length
477
+ },
478
+ [KEYWORDS.IF]: (args, env) => {
479
+ if (args.length !== 3)
480
+ throw new RangeError(
481
+ `Invalid number of arguments for (${
482
+ KEYWORDS.IF
483
+ }), expected (= 3) but got ${args.length}\n\n(${
484
+ KEYWORDS.IF
485
+ } ${stringifyArgs(args)})`
486
+ )
487
+ const condition = evaluate(args[0], env)
488
+ if (condition !== FALSE && condition !== TRUE)
489
+ throw new TypeError(
490
+ `Condition of (${
491
+ KEYWORDS.IF
492
+ }) must be ${TRUE} or ${FALSE} but ${LISP.source(args[0])} is not\n\n(${
493
+ KEYWORDS.IF
494
+ } ${stringifyArgs(args)})`
495
+ )
496
+ return condition ? evaluate(args[1], env) : evaluate(args[2], env)
497
+ },
498
+ [KEYWORDS.NOT]: (args, env) => {
499
+ if (args.length !== 1)
500
+ throw new RangeError(
501
+ `Invalid number of arguments for (${KEYWORDS.NOT}) (= 1 required)\n\n(${
502
+ KEYWORDS.NOT
503
+ } ${stringifyArgs(args)})`
504
+ )
505
+ const operand = evaluate(args[0], env)
506
+ if (operand !== FALSE && operand !== TRUE)
507
+ throw new TypeError(
508
+ `Condition of (${
509
+ KEYWORDS.NOT
510
+ }) must be ${TRUE} or ${FALSE} but ${LISP.source(args[0])} is not\n\n(${
511
+ KEYWORDS.NOT
512
+ } ${stringifyArgs(args)})`
513
+ )
514
+ return +!operand
515
+ },
516
+ [KEYWORDS.EQUAL]: (args, env) => {
517
+ if (args.length !== 2)
518
+ throw new RangeError(
519
+ `Invalid number of arguments for (${
520
+ KEYWORDS.EQUAL
521
+ }) (= 2 required)\n\n(${KEYWORDS.EQUAL} ${stringifyArgs(args)})`
522
+ )
523
+ const a = evaluate(args[0], env)
524
+ const b = evaluate(args[1], env)
525
+ if (typeof a !== 'number')
526
+ throw new TypeError(
527
+ `First argument of (${KEYWORDS.EQUAL}) must be a ${
528
+ RUNTIME_TYPES.NUMBER
529
+ } but ${LISP.source(args[0])} is not\n\n(${
530
+ KEYWORDS.EQUAL
531
+ } ${stringifyArgs(args)})`
532
+ )
533
+ if (typeof b !== 'number')
534
+ throw new TypeError(
535
+ `Second argument of (${KEYWORDS.EQUAL}) must be a ${
536
+ RUNTIME_TYPES.NUMBER
537
+ } but ${LISP.source(args[1])} is not\n\n(${
538
+ KEYWORDS.EQUAL
539
+ } ${stringifyArgs(args)})`
540
+ )
541
+ return +(a === b)
542
+ },
543
+ [KEYWORDS.LESS_THAN]: (args, env) => {
544
+ if (args.length !== 2)
545
+ throw new RangeError(
546
+ `Invalid number of arguments for (${
547
+ KEYWORDS.LESS_THAN
548
+ }) (= 2 required)\n\n(${KEYWORDS.LESS_THAN} ${stringifyArgs(args)})`
549
+ )
550
+ const a = evaluate(args[0], env)
551
+ const b = evaluate(args[1], env)
552
+ if (typeof a !== 'number')
553
+ throw new TypeError(
554
+ `First argument of (${KEYWORDS.LESS_THAN}) must be a ${
555
+ RUNTIME_TYPES.NUMBER
556
+ } but ${LISP.source(args[0])} is not\n\n(${
557
+ KEYWORDS.LESS_THAN
558
+ } ${stringifyArgs(args)})`
559
+ )
560
+ if (typeof b !== 'number')
561
+ throw new TypeError(
562
+ `Second argument of (${KEYWORDS.LESS_THAN}) must be a ${
563
+ RUNTIME_TYPES.NUMBER
564
+ } but ${LISP.source(args[1])} is not\n\n(${
565
+ KEYWORDS.LESS_THAN
566
+ } ${stringifyArgs(args)})`
567
+ )
568
+ return +(a < b)
569
+ },
570
+ [KEYWORDS.GREATHER_THAN]: (args, env) => {
571
+ if (args.length !== 2)
572
+ throw new RangeError(
573
+ `Invalid number of arguments for (${
574
+ KEYWORDS.GREATHER_THAN
575
+ }) (= 2 required)\n\n(${KEYWORDS.GREATHER_THAN} ${stringifyArgs(args)})`
576
+ )
577
+ const a = evaluate(args[0], env)
578
+ const b = evaluate(args[1], env)
579
+ if (typeof a !== 'number')
580
+ throw new TypeError(
581
+ `First argument of (${KEYWORDS.GREATHER_THAN}) must be a ${
582
+ RUNTIME_TYPES.NUMBER
583
+ } but ${LISP.source(args[0])} is not\n\n(${
584
+ KEYWORDS.GREATHER_THAN
585
+ } ${stringifyArgs(args)})`
586
+ )
587
+ if (typeof b !== 'number')
588
+ throw new TypeError(
589
+ `Second argument of (${KEYWORDS.GREATHER_THAN}) must be a ${
590
+ RUNTIME_TYPES.NUMBER
591
+ } but ${LISP.source(args[1])} is not\n\n(${
592
+ KEYWORDS.GREATHER_THAN
593
+ } ${stringifyArgs(args)})`
594
+ )
595
+ return +(a > b)
596
+ },
597
+ [KEYWORDS.GREATHER_THAN_OR_EQUAL]: (args, env) => {
598
+ if (args.length !== 2)
599
+ throw new RangeError(
600
+ `Invalid number of arguments for (${
601
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
602
+ }) (= 2 required)\n\n(${
603
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
604
+ } ${stringifyArgs(args)})`
605
+ )
606
+ const a = evaluate(args[0], env)
607
+ const b = evaluate(args[1], env)
608
+ if (typeof a !== 'number')
609
+ throw new TypeError(
610
+ `First argument of (${KEYWORDS.GREATHER_THAN_OR_EQUAL}) must be a ${
611
+ RUNTIME_TYPES.NUMBER
612
+ } but ${LISP.source(args[0])} is not\n\n(${
613
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
614
+ } ${stringifyArgs(args)})`
615
+ )
616
+ if (typeof b !== 'number')
617
+ throw new TypeError(
618
+ `Second argument of (${KEYWORDS.GREATHER_THAN_OR_EQUAL}) must be a ${
619
+ RUNTIME_TYPES.NUMBER
620
+ } but ${LISP.source(args[1])} is not\n\n(${
621
+ KEYWORDS.GREATHER_THAN_OR_EQUAL
622
+ } ${stringifyArgs(args)})`
623
+ )
624
+ return +(a >= b)
625
+ },
626
+ [KEYWORDS.LESS_THAN_OR_EQUAL]: (args, env) => {
627
+ if (args.length !== 2)
628
+ throw new RangeError(
629
+ `Invalid number of arguments for (${
630
+ KEYWORDS.LESS_THAN_OR_EQUAL
631
+ }) (= 2 required)\n\n(${KEYWORDS.LESS_THAN_OR_EQUAL} ${stringifyArgs(
632
+ args
633
+ )})`
634
+ )
635
+ const a = evaluate(args[0], env)
636
+ const b = evaluate(args[1], env)
637
+ if (typeof a !== 'number')
638
+ throw new TypeError(
639
+ `First argument of (${KEYWORDS.LESS_THAN_OR_EQUAL}) must be a ${
640
+ RUNTIME_TYPES.NUMBER
641
+ } but ${LISP.source(args[0])} is not\n\n(${
642
+ KEYWORDS.LESS_THAN_OR_EQUAL
643
+ } ${stringifyArgs(args)})`
644
+ )
645
+ if (typeof b !== 'number')
646
+ throw new TypeError(
647
+ `Second argument of (${KEYWORDS.LESS_THAN_OR_EQUAL}) must be a ${
648
+ RUNTIME_TYPES.NUMBER
649
+ } but ${LISP.source(args[1])} is not\n\n(${
650
+ KEYWORDS.LESS_THAN_OR_EQUAL
651
+ } ${stringifyArgs(args)})`
652
+ )
653
+ return +(a <= b)
654
+ },
655
+ [KEYWORDS.AND]: (args, env) => {
656
+ if (args.length !== 2)
657
+ throw new RangeError(
658
+ `Invalid number of arguments for (${KEYWORDS.AND}) (= 2 required)\n\n(${
659
+ KEYWORDS.AND
660
+ } ${stringifyArgs(args)})`
661
+ )
662
+ const a = evaluate(args[0], env)
663
+ if (a !== FALSE && a !== TRUE)
664
+ throw new TypeError(
665
+ `Condition of (${
666
+ KEYWORDS.AND
667
+ }) must be ${TRUE} or ${FALSE} but got\n\n(${
668
+ KEYWORDS.AND
669
+ } ${stringifyArgs(args)})`
670
+ )
671
+ if (!a) return FALSE
672
+ const b = evaluate(args[1], env)
673
+ if (b !== FALSE && b !== TRUE)
674
+ throw new TypeError(
675
+ `Condition of (${
676
+ KEYWORDS.AND
677
+ }) must be ${TRUE} or ${FALSE} but got\n\n(${
678
+ KEYWORDS.AND
679
+ } ${stringifyArgs(args)})`
680
+ )
681
+ return b
682
+ },
683
+ [KEYWORDS.OR]: (args, env) => {
684
+ if (args.length !== 2)
685
+ throw new RangeError(
686
+ `Invalid number of arguments for (${KEYWORDS.OR}) (= 2 required)\n\n(${
687
+ KEYWORDS.OR
688
+ } ${stringifyArgs(args)})`
689
+ )
690
+ const a = evaluate(args[0], env)
691
+ if (a !== FALSE && a !== TRUE)
692
+ throw new TypeError(
693
+ `Condition of (${
694
+ KEYWORDS.OR
695
+ }) must be ${TRUE} or ${FALSE} but got\n\n(${
696
+ KEYWORDS.OR
697
+ } ${stringifyArgs(args)})`
698
+ )
699
+ if (a) return TRUE
700
+ const b = evaluate(args[1], env)
701
+ if (b !== FALSE && b !== TRUE)
702
+ throw new TypeError(
703
+ `Condition of (${
704
+ KEYWORDS.OR
705
+ }) must be ${TRUE} or ${FALSE} but got\n\n(${
706
+ KEYWORDS.OR
707
+ } ${stringifyArgs(args)})`
708
+ )
709
+ return b
710
+ },
711
+ [KEYWORDS.DEFINE_VARIABLE]: (args, env) => {
712
+ if (args.length !== 2)
713
+ throw new RangeError(
714
+ `Invalid number of arguments to (${
715
+ KEYWORDS.DEFINE_VARIABLE
716
+ }) (= 2 required)\n\n(${KEYWORDS.DEFINE_VARIABLE} ${stringifyArgs(
717
+ args
718
+ )})`
719
+ )
720
+ const word = args[0]
721
+ const type = word[TYPE]
722
+ const name = word[VALUE]
723
+ if (type !== WORD)
724
+ throw new SyntaxError(
725
+ `First argument of (${KEYWORDS.DEFINE_VARIABLE}) must be word but got ${
726
+ TYPES[type]
727
+ }\n\n(${KEYWORDS.DEFINE_VARIABLE} ${stringifyArgs(args)})`
728
+ )
729
+ else if (isForbiddenVariableName(name))
730
+ throw new ReferenceError(
731
+ `Variable name ${name} is forbidden \n\n(${
732
+ KEYWORDS.DEFINE_VARIABLE
733
+ } ${stringifyArgs(args)})`
734
+ )
735
+ env[name] = evaluate(args[1], env)
736
+ return env[name]
737
+ },
81
738
  [KEYWORDS.ANONYMOUS_FUNCTION]: (args, env) => {
739
+ if (!args.length)
740
+ throw new RangeError(
741
+ `At lest one argument (the body) is required for (${KEYWORDS.ANONYMOUS_FUNCTION})`
742
+ )
82
743
  const params = args.slice(0, -1)
83
- return (props = [], scope) => {
744
+ const body = args.at(-1)
745
+ return (props = [], scope, name) => {
746
+ if (props.length !== params.length)
747
+ throw new RangeError(
748
+ `Incorrect number of arguments for (${KEYWORDS.ANONYMOUS_FUNCTION}${
749
+ name ? ` ${name}` : ''
750
+ }) are provided (expects ${params.length} but got ${
751
+ props.length
752
+ })\n\n${
753
+ name
754
+ ? `(${name} ${stringifyArgs(params)})`
755
+ : `(${KEYWORDS.ANONYMOUS_FUNCTION} ${stringifyArgs(params)})`
756
+ }`
757
+ )
84
758
  const localEnv = Object.create(env)
85
- for (let i = 0; i < props.length; ++i)
86
- localEnv[params[i][VALUE]] = evaluate(props[i], scope)
87
- return evaluate(args.at(-1), localEnv)
759
+ for (let i = 0; i < props.length; ++i) {
760
+ const value = evaluate(props[i], scope)
761
+ localEnv[params[i][VALUE]] = value
762
+ }
763
+ return evaluate(body, localEnv)
88
764
  }
89
765
  },
766
+ [KEYWORDS.CALL_FUNCTION]: (args, env) => {
767
+ if (!args.length)
768
+ throw new RangeError(
769
+ `Invalid number of arguments to (${
770
+ KEYWORDS.CALL_FUNCTION
771
+ }) (>= 1 required)\n\n(${KEYWORDS.CALL_FUNCTION} ${stringifyArgs(
772
+ args
773
+ )})`
774
+ )
775
+ const first = args.at(-1)
776
+ if (first[TYPE] === WORD && first[VALUE] in keywords)
777
+ throw new TypeError(
778
+ `Preceeding arguments of (${
779
+ KEYWORDS.CALL_FUNCTION
780
+ }) must not be an reserved word\n\n(${
781
+ KEYWORDS.CALL_FUNCTION
782
+ } ${stringifyArgs(args)})`
783
+ )
784
+ const apply = evaluate(first, env)
785
+ if (typeof apply !== 'function')
786
+ throw new TypeError(
787
+ `Last argument of (${KEYWORDS.CALL_FUNCTION}) must be a (${
788
+ KEYWORDS.ANONYMOUS_FUNCTION
789
+ }) but got ${LISP.stringify(apply)}\n\n(${
790
+ KEYWORDS.CALL_FUNCTION
791
+ } ${stringifyArgs(args)})`
792
+ )
793
+
794
+ return apply(args.slice(0, -1), env)
795
+ },
796
+ [KEYWORDS.BLOCK]: (args, env) => {
797
+ if (!args.length)
798
+ throw new RangeError(
799
+ `Invalid number of arguments to (${
800
+ KEYWORDS.BLOCK
801
+ }) (>= 1 required)\n\n(${KEYWORDS.BLOCK} ${stringifyArgs(args)})`
802
+ )
803
+ let out = FALSE
804
+ for (const exp of args) out = evaluate(exp, env)
805
+ return out
806
+ },
807
+ [KEYWORDS.IS_ATOM]: (args, env) => {
808
+ if (args.length !== 1)
809
+ throw new RangeError(
810
+ `Invalid number of arguments for (${
811
+ KEYWORDS.IS_ATOM
812
+ }) (= 1 required)\n\n(${KEYWORDS.IS_ATOM} ${stringifyArgs(args)})`
813
+ )
814
+ return +(typeof evaluate(args[0], env) === 'number')
815
+ },
816
+ [KEYWORDS.IS_LAMBDA]: (args, env) => {
817
+ if (args.length !== 1)
818
+ throw new RangeError(
819
+ `Invalid number of arguments for (${
820
+ KEYWORDS.IS_LAMBDA
821
+ }) (= 1 required)\n\n(${KEYWORDS.IS_LAMBDA} ${stringifyArgs(args)})`
822
+ )
823
+ return +(typeof evaluate(args[0], env) === 'function')
824
+ },
90
825
  // Only for type checking
91
826
  [STATIC_TYPES.UNKNOWN]: (args, env) => evaluate(args[0], env),
92
827
  [STATIC_TYPES.ANY]: (args, env) => evaluate(args[0], env),
@@ -126,7 +861,7 @@ const evaluate = (exp, env = keywords) => {
126
861
  // typeof res === 'function' ? '(lambda)' : serialise(res)
127
862
  // }\x1b[0m`
128
863
  // )
129
- const out = typeof res === 'function' ? '(lambda)' : serialise(res)
864
+ const out = typeof res === 'function' ? '(lambda)' : LISP.serialise(res)
130
865
  if (debugStack.at(-1)?.result !== out)
131
866
  debugStack.push({
132
867
  function: value,
@@ -163,3 +898,294 @@ export const startDebug = (ast, speed = 250, start, end) => {
163
898
  }
164
899
  return stack
165
900
  }
901
+
902
+ // const types = typeCheck(std[0], withCtxTypes(definedTypes(stdT)))[1]
903
+ const __debugStack__ = []
904
+ export const debug = (ast, checkTypes = true, userDefinedTypes) => {
905
+ let types = new Map()
906
+ const debugEnv = {
907
+ ...keywords,
908
+ [STATIC_TYPES.ABSTRACTION]: (args, env) => {
909
+ const T = evaluate(args[0], env)
910
+ const t = typeof T
911
+ if (t !== 'function')
912
+ throw new TypeError(
913
+ `Argument of (${STATIC_TYPES.ABSTRACTION}) must be an (${
914
+ RUNTIME_TYPES.LAMBDA
915
+ }) but got something else (${
916
+ STATIC_TYPES.ABSTRACTION
917
+ } ${stringifyArgs(args)})`
918
+ )
919
+ return T
920
+ },
921
+ [STATIC_TYPES.ATOM]: (args, env) => {
922
+ const T = evaluate(args[0], env)
923
+ const t = typeof T
924
+ if (t !== 'number')
925
+ throw new TypeError(
926
+ `Argument of (${STATIC_TYPES.ATOM}) must be an (${
927
+ RUNTIME_TYPES.NUMBER
928
+ }) but got something else (${STATIC_TYPES.ATOM} ${stringifyArgs(
929
+ args
930
+ )})`
931
+ )
932
+ return T
933
+ },
934
+ [STATIC_TYPES.COLLECTION]: (args, env) => {
935
+ const T = evaluate(args[0], env)
936
+ if (!Array.isArray(T))
937
+ throw new TypeError(
938
+ `Argument of (${STATIC_TYPES.COLLECTION}) must be an (${
939
+ RUNTIME_TYPES.ARRAY
940
+ }) but got something else (${STATIC_TYPES.COLLECTION} ${stringifyArgs(
941
+ args
942
+ )})`
943
+ )
944
+ return T
945
+ },
946
+ [DEBUG.TYPE_SIGNATURE]: (args, env) => {
947
+ if (args.length !== 2)
948
+ throw new RangeError(
949
+ `Invalid number of arguments to (${DEBUG.TYPE_SIGNATURE}) (= 1) (${
950
+ DEBUG.TYPE_SIGNATURE
951
+ } ${stringifyArgs(args)})`
952
+ )
953
+ const name =
954
+ Array.isArray(args[0]) && args[0][0][VALUE] === DEBUG.STRING
955
+ ? args[0][1]
956
+ .slice(1)
957
+ .map((x) => String.fromCharCode(x[VALUE]))
958
+ .join('')
959
+ : args[0][VALUE]
960
+ const option = args[1][VALUE]
961
+ const wildcard = name === '*'
962
+ if (option === 'Scope') {
963
+ if (wildcard) {
964
+ return [...types.entries()]
965
+ .sort((a, b) => a[0].localeCompare(b[0]))
966
+ .map(([k, v]) => `${k}\n${v()}`)
967
+ .join('\n\n')
968
+ }
969
+ const t = types.get(`; 1 ${name}`)
970
+ return t ? t() : ''
971
+ } else if (option === 'Search') {
972
+ return [...types.entries()]
973
+ .filter((x) => x[0].includes(name))
974
+ .sort((a, b) => a[0].localeCompare(b[0]))
975
+ .map(([k, v]) => `${k}\n${v()}`)
976
+ .join('\n\n')
977
+ } else if (option === 'Special') {
978
+ return formatType(name, SPECIAL_FORM_TYPES)
979
+ } else if (option === 'Type') {
980
+ const [from, to] = name.split(KEYWORDS.BLOCK).map((x) => x.trim())
981
+ return [...types.entries()]
982
+ .filter(([k, v]) => {
983
+ const T = v()
984
+ if (T && T.includes(KEYWORDS.BLOCK)) {
985
+ const [left, right] = T.split(KEYWORDS.BLOCK).map((x) => x.trim())
986
+ return left.includes(from) && right.includes(to)
987
+ }
988
+ })
989
+ .sort((a, b) => a[0].length - b[0].length)
990
+ .map(([k, v]) => `${k}\n${v()}`)
991
+ .join('\n\n')
992
+ } else if (option === 'Library') {
993
+ types = typeCheck(std[0], withCtxTypes(definedTypes(stdT)))[1]
994
+ const matches = wildcard
995
+ ? [...types.entries()]
996
+ : [...types.entries()].filter(([k, v]) => v().includes(name))
997
+ return matches
998
+ .sort((a, b) => a[0].length - b[0].length)
999
+ .map(([k, v]) => `${k}\n${v()}`)
1000
+ .join('\n\n')
1001
+ } else {
1002
+ return ''
1003
+ }
1004
+ },
1005
+ [DEBUG.SIGNATURE]: (args, env) => {
1006
+ const name =
1007
+ Array.isArray(args[0]) && args[0][0][VALUE] === DEBUG.STRING
1008
+ ? args[0][1]
1009
+ .slice(1)
1010
+ .map((x) => String.fromCharCode(x[VALUE]))
1011
+ .join('')
1012
+ : args[0][VALUE]
1013
+ const signatures =
1014
+ args.length === 0
1015
+ ? std[0][1][1].slice(1)
1016
+ : std[0][1][1].filter(
1017
+ (x) =>
1018
+ x[0][TYPE] === APPLY &&
1019
+ x[0][VALUE] === KEYWORDS.DEFINE_VARIABLE &&
1020
+ x[1][TYPE] === WORD &&
1021
+ x[1][VALUE].toString().includes(name)
1022
+ )
1023
+ return signatures.length === 0
1024
+ ? 'Not defined in library'
1025
+ : signatures.map(LISP.source).join('\n\n')
1026
+ },
1027
+ [DEBUG.STRING]: (args, env) => {
1028
+ if (args.length !== 1)
1029
+ throw new RangeError(
1030
+ `Invalid number of arguments to (${DEBUG.STRING}) (= 1) (${
1031
+ DEBUG.STRING
1032
+ } but got (${args.length}) ${stringifyArgs(args)})`
1033
+ )
1034
+ const expression = evaluate(args[0], env)
1035
+ if (!Array.isArray(expression))
1036
+ throw new TypeError(
1037
+ `Argument of (${DEBUG.STRING}) must be an (${
1038
+ RUNTIME_TYPES.ARRAY
1039
+ }) but got (${expression}) (${DEBUG.STRING} ${stringifyArgs(args)})`
1040
+ )
1041
+ return `"${expression.map((x) => String.fromCharCode(x)).join('')}"`
1042
+ },
1043
+ [DEBUG.UNQUOTED_STRING]: (args, env) => {
1044
+ if (args.length !== 1)
1045
+ throw new RangeError(
1046
+ `Invalid number of arguments to (${DEBUG.UNQUOTED_STRING}) (= 1) (${
1047
+ DEBUG.UNQUOTED_STRING
1048
+ } but got (${args.length}) ${stringifyArgs(args)})`
1049
+ )
1050
+ const expression = evaluate(args[0], env)
1051
+ if (!Array.isArray(expression))
1052
+ throw new TypeError(
1053
+ `Argument of (${DEBUG.UNQUOTED_STRING}) must be an (${
1054
+ RUNTIME_TYPES.ARRAY
1055
+ }) but got (${expression}) (${DEBUG.UNQUOTED_STRING} ${stringifyArgs(
1056
+ args
1057
+ )})`
1058
+ )
1059
+ return `${expression.map((x) => String.fromCharCode(x)).join('')}`
1060
+ },
1061
+ [DEBUG.LOG]: (args, env) => {
1062
+ if (args.length !== 1 && args.length !== 2)
1063
+ throw new RangeError(
1064
+ `Invalid number of arguments to (${DEBUG.LOG}) (or (= 1) (= 2)) (${
1065
+ DEBUG.LOG
1066
+ } ${stringifyArgs(args)})`
1067
+ )
1068
+ const expression = evaluate(args[0], env)
1069
+ if (args.length === 2) {
1070
+ const option = evaluate(args[1], env)
1071
+ if (!Array.isArray(option)) {
1072
+ throw new TypeError(
1073
+ `Second argument of (${DEBUG.LOG}) must be an (${
1074
+ RUNTIME_TYPES.ARRAY
1075
+ }) but got (${expression}) (${DEBUG.LOG} ${stringifyArgs(args)})`
1076
+ )
1077
+ }
1078
+ const type = option.map((x) => String.fromCharCode(x)).join('')
1079
+ switch (type) {
1080
+ case 'string':
1081
+ case 'str':
1082
+ {
1083
+ if (!Array.isArray(expression))
1084
+ throw new TypeError(
1085
+ `Argument of (${DEBUG.LOG}) must be an (${
1086
+ RUNTIME_TYPES.ARRAY
1087
+ }) in the case ${type} but got (${expression}) (${
1088
+ DEBUG.LOG
1089
+ } ${stringifyArgs(args)})`
1090
+ )
1091
+ console.log(
1092
+ expression.map((x) => String.fromCharCode(x)).join('')
1093
+ )
1094
+ }
1095
+ break
1096
+ case 'char':
1097
+ case 'ch':
1098
+ {
1099
+ if (typeof expression !== 'number')
1100
+ throw new TypeError(
1101
+ `Argument argument of (${DEBUG.LOG}) must be a (${
1102
+ RUNTIME_TYPES.NUMBER
1103
+ }) in the case ${type} but got (${expression}) (${
1104
+ DEBUG.LOG
1105
+ } ${stringifyArgs(args)})`
1106
+ )
1107
+ console.log(String.fromCharCode(expression))
1108
+ }
1109
+
1110
+ break
1111
+ case '*':
1112
+ console.log(expression)
1113
+ break
1114
+ case '!':
1115
+ __debugStack__.push(structuredClone(expression))
1116
+ break
1117
+ default:
1118
+ throw new TypeError(
1119
+ `Invalid option to (${DEBUG.LOG}) got ${option} ${stringifyArgs(
1120
+ args
1121
+ )})`
1122
+ )
1123
+ }
1124
+ } else console.log(expression)
1125
+ return expression
1126
+ }
1127
+ }
1128
+ try {
1129
+ types = checkTypes
1130
+ ? typeCheck(
1131
+ ast,
1132
+ withCtxTypes(
1133
+ userDefinedTypes
1134
+ ? {
1135
+ ...definedTypes(filteredDefinedTypes(ast, std, stdT)),
1136
+ ...definedTypes(LISP.parse(removeNoCode(userDefinedTypes)))
1137
+ }
1138
+ : definedTypes(filteredDefinedTypes(ast, std, stdT))
1139
+ )
1140
+ )[1]
1141
+ : new Map()
1142
+ const evaluated = evaluate(enhance(ast), debugEnv)
1143
+ const exp = ast.at(-1).at(-1).at(-1)
1144
+ const [head, ...rest] = isLeaf(exp) ? [exp] : exp
1145
+ let type = ''
1146
+ switch (head[TYPE]) {
1147
+ case ATOM:
1148
+ type = STATIC_TYPES.ATOM
1149
+ break
1150
+ case WORD:
1151
+ case APPLY:
1152
+ switch (head[VALUE]) {
1153
+ case DEBUG.TYPE_SIGNATURE:
1154
+ break
1155
+ case KEYWORDS.DEFINE_VARIABLE:
1156
+ type = debugEnv[DEBUG.TYPE_SIGNATURE]([rest[0], [WORD, 'Scope']])
1157
+ break
1158
+ default:
1159
+ if (SPECIAL_FORMS_SET.has(head[VALUE])) {
1160
+ // type = debugEnv[DEBUG.TYPE_SIGNATURE]([head, [WORD, 'Special']])
1161
+ type = `${debugEnv[DEBUG.TYPE_SIGNATURE]([
1162
+ head,
1163
+ [WORD, 'Special']
1164
+ ])}`
1165
+ } else
1166
+ type = `${debugEnv[DEBUG.TYPE_SIGNATURE]([
1167
+ head,
1168
+ [WORD, 'Scope']
1169
+ ])}`
1170
+ break
1171
+ }
1172
+
1173
+ break
1174
+ }
1175
+ type = type.split('\n').pop()
1176
+ return {
1177
+ type,
1178
+ evaluated,
1179
+ error: null
1180
+ }
1181
+ } catch (error) {
1182
+ // console.log(error)
1183
+ return {
1184
+ type: null,
1185
+ evaluated: null,
1186
+ error: {
1187
+ message: error.message
1188
+ }
1189
+ }
1190
+ }
1191
+ }
package/src/keywords.js CHANGED
@@ -76,8 +76,6 @@ export const DEBUG = {
76
76
  LOG: 'log',
77
77
  ASSERT: 'assert',
78
78
  SIGNATURE: 'Info',
79
- LIST_THEMES: 'theme?',
80
- SET_THEME: 'theme!',
81
79
  TYPE_SIGNATURE: 'T'
82
80
  }
83
81
 
package/src/parser.js CHANGED
@@ -42,6 +42,15 @@ export const LISP = {
42
42
  .join(' ')})`
43
43
  else return array
44
44
  },
45
+ serialise: (arg) => {
46
+ if (typeof arg === 'number' || typeof arg === 'string')
47
+ return arg.toString()
48
+ else if (Array.isArray(arg))
49
+ return arg.length
50
+ ? `[${arg.map((a) => LISP.serialise(a)).join(' ')}]`
51
+ : '[]'
52
+ else return '(lambda)'
53
+ },
45
54
  json: (item) => {
46
55
  if (item === null) return 0
47
56
  else if (typeof item === 'boolean') return item
package/src/types.js CHANGED
@@ -464,24 +464,6 @@ export const SPECIAL_FORM_TYPES = {
464
464
  [RETURNS]: [UNKNOWN]
465
465
  }
466
466
  },
467
- [DEBUG.LIST_THEMES]: {
468
- [STATS]: {
469
- [TYPE_PROP]: [APPLY],
470
- [SIGNATURE]: DEBUG.LIST_THEMES,
471
- retried: Infinity,
472
- [ARG_COUNT]: VARIADIC,
473
- [RETURNS]: [UNKNOWN]
474
- }
475
- },
476
- [DEBUG.SET_THEME]: {
477
- [STATS]: {
478
- [TYPE_PROP]: [APPLY],
479
- [SIGNATURE]: DEBUG.SET_THEME,
480
- retried: Infinity,
481
- [ARG_COUNT]: VARIADIC,
482
- [RETURNS]: [UNKNOWN]
483
- }
484
- },
485
467
  [KEYWORDS.BLOCK]: {
486
468
  [STATS]: {
487
469
  [TYPE_PROP]: [APPLY],
package/src/utils.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  withCtxTypes
27
27
  } from './types.js'
28
28
  import { compile } from './compiler.js'
29
- import { startDebug } from './debugger.js'
29
+ import { debugStackToString, startDebug, debug } from './debugger.js'
30
30
  export const logError = (error) =>
31
31
  console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
32
32
  export const logSuccess = (output) => console.log('\x1b[32m', output, '\x1b[0m')
@@ -366,7 +366,9 @@ export const isInputVariable = (x) =>
366
366
  x[1][VALUE] === 'INPUT'
367
367
 
368
368
  export const UTILS = {
369
+ debug,
369
370
  startDebug,
371
+ debugStackToString,
370
372
  handleUnbalancedQuotes,
371
373
  handleUnbalancedParens,
372
374
  logError,