fez-lisp 1.5.16 → 1.5.18

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/src/check.js ADDED
@@ -0,0 +1,743 @@
1
+ import {
2
+ APPLY,
3
+ ATOM,
4
+ KEYWORDS,
5
+ PLACEHOLDER,
6
+ PREDICATE_SUFFIX,
7
+ SPECIAL_FORMS_SET,
8
+ TYPE,
9
+ VALUE,
10
+ WORD
11
+ } from './keywords.js'
12
+ import { isLeaf } from './parser.js'
13
+ import { stringifyArgs } from './utils.js'
14
+ const ARGS_COUNT = 'n'
15
+ const VARIADIC = '...'
16
+ const STATS = '__stats__'
17
+ const ARGS = 'args'
18
+ const UNKNOWN = -1
19
+ const RETURNS = 'returns'
20
+ const SCOPE_NAME = '__scope__'
21
+ const SUBTYPE = 'subtype'
22
+ const PREDICATE = 3
23
+ const xor = (A, B) => {
24
+ const out = new Set()
25
+ B.forEach((element) => !A.has(element) && out.add(element))
26
+ A.forEach((element) => !B.has(element) && out.add(element))
27
+ return out
28
+ }
29
+ const toTypeNames = (type) => {
30
+ switch (type) {
31
+ case APPLY:
32
+ return 'Application'
33
+ case ATOM:
34
+ return 'Atom'
35
+ case UNKNOWN:
36
+ return 'Uknown'
37
+ case PREDICATE:
38
+ return 'Predicate'
39
+ }
40
+ }
41
+ export const typeCheck = (ast) => {
42
+ const root = {
43
+ [SCOPE_NAME]: performance.now().toString().replace('.', 0),
44
+ [KEYWORDS.BLOCK]: {
45
+ [STATS]: { type: APPLY, [ARGS_COUNT]: VARIADIC, [RETURNS]: UNKNOWN }
46
+ },
47
+ [KEYWORDS.ANONYMOUS_FUNCTION]: {
48
+ [STATS]: { type: APPLY, [ARGS_COUNT]: VARIADIC, [RETURNS]: APPLY }
49
+ },
50
+ [KEYWORDS.CALL_FUNCTION]: {
51
+ [STATS]: { type: APPLY, [ARGS_COUNT]: VARIADIC, [RETURNS]: UNKNOWN }
52
+ },
53
+ [KEYWORDS.CREATE_ARRAY]: {
54
+ [STATS]: { type: APPLY, [ARGS_COUNT]: VARIADIC, [RETURNS]: APPLY }
55
+ },
56
+ [KEYWORDS.LOOP]: {
57
+ [STATS]: {
58
+ type: APPLY,
59
+ [ARGS_COUNT]: new Set([2]),
60
+ [ARGS]: [
61
+ [ATOM, PLACEHOLDER, PREDICATE],
62
+ [UNKNOWN, PLACEHOLDER]
63
+ ],
64
+ [RETURNS]: ATOM,
65
+ [SUBTYPE]: PREDICATE
66
+ }
67
+ },
68
+ [KEYWORDS.ADDITION]: {
69
+ [STATS]: {
70
+ type: APPLY,
71
+ [ARGS_COUNT]: new Set([2]),
72
+ [ARGS]: [
73
+ [ATOM, PLACEHOLDER],
74
+ [ATOM, PLACEHOLDER]
75
+ ],
76
+ [RETURNS]: ATOM
77
+ }
78
+ },
79
+ [KEYWORDS.MULTIPLICATION]: {
80
+ [STATS]: {
81
+ type: APPLY,
82
+ [ARGS_COUNT]: new Set([2]),
83
+ [ARGS]: [
84
+ [ATOM, PLACEHOLDER],
85
+ [ATOM, PLACEHOLDER]
86
+ ],
87
+ [RETURNS]: ATOM
88
+ }
89
+ },
90
+ [KEYWORDS.SUBTRACTION]: {
91
+ [STATS]: {
92
+ type: APPLY,
93
+ [ARGS_COUNT]: new Set([1, 2]),
94
+ [ARGS]: [
95
+ [ATOM, PLACEHOLDER],
96
+ [ATOM, PLACEHOLDER]
97
+ ],
98
+ [RETURNS]: ATOM
99
+ }
100
+ },
101
+ [KEYWORDS.DIVISION]: {
102
+ [STATS]: {
103
+ type: APPLY,
104
+ [ARGS_COUNT]: new Set([2]),
105
+ [ARGS]: [
106
+ [ATOM, PLACEHOLDER],
107
+ [ATOM, PLACEHOLDER]
108
+ ],
109
+ [RETURNS]: ATOM
110
+ }
111
+ },
112
+ [KEYWORDS.REMAINDER_OF_DIVISION]: {
113
+ [STATS]: {
114
+ type: APPLY,
115
+ [ARGS_COUNT]: new Set([2]),
116
+ [ARGS]: [
117
+ [ATOM, PLACEHOLDER],
118
+ [ATOM, PLACEHOLDER]
119
+ ],
120
+ [RETURNS]: ATOM
121
+ }
122
+ },
123
+ [KEYWORDS.BITWISE_AND]: {
124
+ [STATS]: {
125
+ type: APPLY,
126
+ [ARGS_COUNT]: new Set([2]),
127
+ [ARGS]: [
128
+ [ATOM, PLACEHOLDER],
129
+ [ATOM, PLACEHOLDER]
130
+ ],
131
+ [RETURNS]: ATOM
132
+ }
133
+ },
134
+ [KEYWORDS.BITWISE_NOT]: {
135
+ [STATS]: {
136
+ type: APPLY,
137
+ [ARGS_COUNT]: new Set([1]),
138
+ [ARGS]: [[ATOM, PLACEHOLDER]],
139
+ [RETURNS]: ATOM
140
+ }
141
+ },
142
+ [KEYWORDS.BITWISE_OR]: {
143
+ [STATS]: {
144
+ type: APPLY,
145
+ [ARGS_COUNT]: new Set([2]),
146
+ [ARGS]: [
147
+ [ATOM, PLACEHOLDER],
148
+ [ATOM, PLACEHOLDER]
149
+ ],
150
+ [RETURNS]: ATOM
151
+ }
152
+ },
153
+ [KEYWORDS.BITWISE_XOR]: {
154
+ [STATS]: {
155
+ type: APPLY,
156
+ [ARGS_COUNT]: new Set([2]),
157
+ [ARGS]: [
158
+ [ATOM, PLACEHOLDER],
159
+ [ATOM, PLACEHOLDER]
160
+ ],
161
+ [RETURNS]: ATOM
162
+ }
163
+ },
164
+ [KEYWORDS.BITWISE_LEFT_SHIFT]: {
165
+ [STATS]: {
166
+ type: APPLY,
167
+ [ARGS_COUNT]: new Set([2]),
168
+ [ARGS]: [
169
+ [ATOM, PLACEHOLDER],
170
+ [ATOM, PLACEHOLDER]
171
+ ],
172
+ [RETURNS]: ATOM
173
+ }
174
+ },
175
+ [KEYWORDS.BITWISE_RIGHT_SHIFT]: {
176
+ [STATS]: {
177
+ type: APPLY,
178
+ [ARGS_COUNT]: new Set([2]),
179
+ [ARGS]: [
180
+ [ATOM, PLACEHOLDER],
181
+ [ATOM, PLACEHOLDER]
182
+ ],
183
+ [RETURNS]: ATOM
184
+ }
185
+ },
186
+ [KEYWORDS.GET_ARRAY]: {
187
+ [STATS]: {
188
+ type: APPLY,
189
+ [ARGS_COUNT]: new Set([2]),
190
+ [ARGS]: [
191
+ [UNKNOWN, PLACEHOLDER],
192
+ [ATOM, PLACEHOLDER]
193
+ ],
194
+ [RETURNS]: UNKNOWN
195
+ }
196
+ },
197
+ [KEYWORDS.SET_ARRAY]: {
198
+ [STATS]: {
199
+ type: APPLY,
200
+ [ARGS_COUNT]: new Set([1, 3]),
201
+ [ARGS]: [
202
+ [UNKNOWN, PLACEHOLDER],
203
+ [ATOM, PLACEHOLDER],
204
+ [UNKNOWN, PLACEHOLDER]
205
+ ],
206
+ [RETURNS]: UNKNOWN
207
+ }
208
+ },
209
+ [KEYWORDS.ARRAY_LENGTH]: {
210
+ [STATS]: {
211
+ type: APPLY,
212
+ [ARGS_COUNT]: new Set([1]),
213
+ [ARGS]: [[UNKNOWN, PLACEHOLDER]],
214
+ [RETURNS]: ATOM
215
+ }
216
+ },
217
+ [KEYWORDS.IF]: {
218
+ [STATS]: {
219
+ type: APPLY,
220
+ [ARGS_COUNT]: new Set([2, 3]),
221
+ [ARGS]: [
222
+ [ATOM, PLACEHOLDER, PREDICATE],
223
+ [UNKNOWN, PLACEHOLDER],
224
+ [UNKNOWN, PLACEHOLDER]
225
+ ],
226
+ [RETURNS]: ATOM
227
+ }
228
+ },
229
+ [KEYWORDS.NOT]: {
230
+ [STATS]: {
231
+ type: APPLY,
232
+ [ARGS_COUNT]: new Set([1]),
233
+ [ARGS]: [[ATOM, PLACEHOLDER, PREDICATE]],
234
+ [RETURNS]: ATOM,
235
+ [SUBTYPE]: PREDICATE
236
+ }
237
+ },
238
+ [KEYWORDS.EQUAL]: {
239
+ [STATS]: {
240
+ type: APPLY,
241
+ [ARGS_COUNT]: new Set([2]),
242
+ [ARGS]: [
243
+ [ATOM, PLACEHOLDER],
244
+ [ATOM, PLACEHOLDER]
245
+ ],
246
+ [RETURNS]: ATOM,
247
+ [SUBTYPE]: PREDICATE
248
+ }
249
+ },
250
+ [KEYWORDS.LESS_THAN]: {
251
+ [STATS]: {
252
+ type: APPLY,
253
+ [ARGS_COUNT]: new Set([2]),
254
+ [ARGS]: [
255
+ [ATOM, PLACEHOLDER],
256
+ [ATOM, PLACEHOLDER]
257
+ ],
258
+ [RETURNS]: ATOM,
259
+ [SUBTYPE]: PREDICATE
260
+ }
261
+ },
262
+ [KEYWORDS.GREATHER_THAN]: {
263
+ [STATS]: {
264
+ type: APPLY,
265
+ [ARGS_COUNT]: new Set([2]),
266
+ [ARGS]: [
267
+ [ATOM, PLACEHOLDER],
268
+ [ATOM, PLACEHOLDER]
269
+ ],
270
+ [RETURNS]: ATOM,
271
+ [SUBTYPE]: PREDICATE
272
+ }
273
+ },
274
+ [KEYWORDS.GREATHER_THAN_OR_EQUAL]: {
275
+ [STATS]: {
276
+ type: APPLY,
277
+ [ARGS_COUNT]: new Set([2]),
278
+ [ARGS]: [
279
+ [ATOM, PLACEHOLDER],
280
+ [ATOM, PLACEHOLDER]
281
+ ],
282
+ [RETURNS]: ATOM,
283
+ [SUBTYPE]: PREDICATE
284
+ }
285
+ },
286
+ [KEYWORDS.LESS_THAN_OR_EQUAL]: {
287
+ [STATS]: {
288
+ type: APPLY,
289
+ [ARGS_COUNT]: new Set([2]),
290
+ [ARGS]: [
291
+ [ATOM, PLACEHOLDER],
292
+ [ATOM, PLACEHOLDER]
293
+ ],
294
+ [RETURNS]: ATOM,
295
+ [SUBTYPE]: PREDICATE
296
+ }
297
+ },
298
+ [KEYWORDS.AND]: {
299
+ [STATS]: {
300
+ type: APPLY,
301
+ [ARGS_COUNT]: new Set([2]),
302
+ [ARGS]: [
303
+ [ATOM, PLACEHOLDER, PREDICATE],
304
+ [ATOM, PLACEHOLDER, PREDICATE]
305
+ ],
306
+ [RETURNS]: ATOM,
307
+ [SUBTYPE]: PREDICATE
308
+ }
309
+ },
310
+ [KEYWORDS.OR]: {
311
+ [STATS]: {
312
+ type: APPLY,
313
+ [ARGS_COUNT]: new Set([2]),
314
+ [ARGS]: [
315
+ [ATOM, PLACEHOLDER, PREDICATE],
316
+ [ATOM, PLACEHOLDER, PREDICATE]
317
+ ],
318
+ [RETURNS]: ATOM,
319
+ [SUBTYPE]: PREDICATE
320
+ }
321
+ },
322
+ [KEYWORDS.IS_ATOM]: {
323
+ [STATS]: {
324
+ type: APPLY,
325
+ [ARGS_COUNT]: new Set([1]),
326
+ [ARGS]: [[UNKNOWN, PLACEHOLDER]],
327
+ [RETURNS]: ATOM,
328
+ [SUBTYPE]: PREDICATE
329
+ }
330
+ },
331
+ [KEYWORDS.IS_LAMBDA]: {
332
+ [STATS]: {
333
+ type: APPLY,
334
+ [ARGS_COUNT]: new Set([1]),
335
+ [ARGS]: [[UNKNOWN, PLACEHOLDER]],
336
+ [RETURNS]: ATOM,
337
+ [SUBTYPE]: PREDICATE
338
+ }
339
+ },
340
+ [KEYWORDS.ERROR]: {
341
+ [STATS]: {
342
+ type: APPLY,
343
+ [ARGS_COUNT]: new Set([1]),
344
+ [ARGS]: [[UNKNOWN, PLACEHOLDER]],
345
+ [RETURNS]: UNKNOWN
346
+ }
347
+ }
348
+ }
349
+ const errorStack = new Map()
350
+ const withScope = (name, env) =>
351
+ `${env[SCOPE_NAME] ?? root[SCOPE_NAME]}_${name}`
352
+
353
+ const stack = []
354
+ const check = (exp, env, scope) => {
355
+ const [first, ...rest] = isLeaf(exp) ? [exp] : exp
356
+ if (first != undefined) {
357
+ switch (first[TYPE]) {
358
+ case WORD:
359
+ {
360
+ const key = withScope(first[VALUE], scope)
361
+ if (env[first[VALUE]] === undefined) {
362
+ errorStack.set(
363
+ key,
364
+ `Trying to access undefined variable ${first[VALUE]}`
365
+ )
366
+ }
367
+ // else if (errorStack.has(key)) errorStack.delete(key)
368
+ }
369
+ break
370
+ case ATOM:
371
+ break
372
+ case APPLY: {
373
+ switch (first[VALUE]) {
374
+ case KEYWORDS.DEFINE_VARIABLE:
375
+ {
376
+ if (
377
+ rest.length &&
378
+ rest.at(-1).length &&
379
+ rest.at(-1)[0][TYPE] === APPLY &&
380
+ rest.at(-1)[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
381
+ ) {
382
+ const name = rest[0][VALUE]
383
+ const n = rest.at(-1).length
384
+ env[name] = {
385
+ [STATS]: {
386
+ type: APPLY,
387
+ [ARGS_COUNT]: new Set([n - 2]),
388
+ [ARGS]: []
389
+ }
390
+ }
391
+ if (name[name.length - 1] === PREDICATE_SUFFIX)
392
+ env[name][STATS][SUBTYPE] = PREDICATE
393
+
394
+ scope = exp
395
+ if (env[SCOPE_NAME]) {
396
+ const key = withScope(name, scope)
397
+ if (errorStack.has(key)) errorStack.delete(key)
398
+ }
399
+ check(rest.at(-1), env, scope)
400
+ } else {
401
+ const name = rest[0][VALUE]
402
+ if (!(name in env)) {
403
+ if (rest[1][TYPE] === WORD) env[name] = env[rest[1][VALUE]]
404
+ else
405
+ env[name] = {
406
+ [STATS]: {
407
+ type: isLeaf(rest.at(-1))
408
+ ? rest.at(-1)[TYPE]
409
+ : env[rest.at(-1)[0]?.[VALUE]]?.[STATS]?.[
410
+ RETURNS
411
+ ] ?? UNKNOWN
412
+ }
413
+ }
414
+ }
415
+ // if (env[SCOPE_NAME]) {
416
+ // const key = withScope(name, scope)
417
+ // if (errorStack.has(key)) errorStack.delete(key)
418
+ // }
419
+ check(rest.at(-1), env, scope)
420
+ }
421
+ }
422
+ break
423
+ case KEYWORDS.ANONYMOUS_FUNCTION:
424
+ {
425
+ if (exp.length === 1) {
426
+ throw new TypeError(
427
+ `Incorrect number of arguments for (${
428
+ first[VALUE]
429
+ }). Expected at least 1 (the lambda body) but got 1 (${stringifyArgs(
430
+ exp
431
+ )})`
432
+ )
433
+ }
434
+ const params = exp.slice(1, -1)
435
+ const copy = Object.create(env)
436
+ if (isLeaf(scope[1])) {
437
+ copy[SCOPE_NAME] = scope[1][VALUE]
438
+ } else
439
+ copy[SCOPE_NAME] = performance
440
+ .now()
441
+ .toString()
442
+ .replace('.', 0)
443
+ for (const param of params) {
444
+ copy[param[VALUE]] = { [STATS]: { type: UNKNOWN } }
445
+ if (env[copy[SCOPE_NAME]])
446
+ env[copy[SCOPE_NAME]][STATS][ARGS].push(copy[param[VALUE]])
447
+ }
448
+ check(rest.at(-1), copy, scope)
449
+ }
450
+ break
451
+ default:
452
+ stack.push(() => {
453
+ const key = withScope(first[VALUE], scope)
454
+ if (env[first[VALUE]] === undefined)
455
+ errorStack.set(
456
+ key,
457
+ `Trying to call undefined (lambda) ${first[VALUE]}`
458
+ )
459
+ else if (
460
+ env[first[VALUE]][STATS].type === APPLY &&
461
+ env[first[VALUE]][STATS][ARGS_COUNT] !== VARIADIC &&
462
+ !env[first[VALUE]][STATS][ARGS_COUNT].has(rest.length)
463
+ ) {
464
+ const argCount = [...env[first[VALUE]][STATS][ARGS_COUNT]]
465
+ errorStack.set(
466
+ key,
467
+ `Incorrect number of arguments for (${
468
+ first[VALUE]
469
+ }). Expected ${
470
+ argCount.length > 1
471
+ ? `(or ${argCount.map((x) => `(= ${x})`).join(' ')})`
472
+ : `(= ${argCount[0]})`
473
+ } but got ${rest.length} (${stringifyArgs(exp)})`
474
+ )
475
+ } else {
476
+ const isSpecial = SPECIAL_FORMS_SET.has(first[VALUE])
477
+
478
+ if (first[TYPE] === APPLY && !isSpecial) {
479
+ if (!env[first[VALUE]][STATS][ARGS_COUNT]) {
480
+ env[first[VALUE]][STATS][RETURNS] = UNKNOWN
481
+ env[first[VALUE]][STATS].type = APPLY
482
+ env[first[VALUE]][STATS][ARGS_COUNT] = new Set([
483
+ rest.length
484
+ ])
485
+ }
486
+ }
487
+ // also type of arg
488
+ const args = env[first[VALUE]][STATS][ARGS]
489
+ if (args) {
490
+ for (let i = 0; i < args.length; ++i) {
491
+ if (
492
+ args[i][STATS] &&
493
+ args[i][STATS].type === APPLY &&
494
+ env[rest[i][VALUE]] &&
495
+ env[rest[i][VALUE]][STATS] &&
496
+ env[rest[i][VALUE]][STATS][ARGS_COUNT] &&
497
+ args[i][STATS][ARGS_COUNT] !== VARIADIC &&
498
+ env[rest[i][VALUE]][STATS][ARGS_COUNT] !== VARIADIC
499
+ ) {
500
+ const argCount = [...args[i][STATS][ARGS_COUNT]]
501
+ if (
502
+ xor(
503
+ args[i][STATS][ARGS_COUNT],
504
+ env[rest[i][VALUE]][STATS][ARGS_COUNT]
505
+ ).size !== 0
506
+ ) {
507
+ errorStack.set(
508
+ key,
509
+ `Incorrect number of arguments for (${
510
+ first[VALUE]
511
+ }). Expected ${
512
+ argCount.length > 1
513
+ ? `(or ${argCount
514
+ .map((x) => `(= ${x})`)
515
+ .join(' ')})`
516
+ : `(= ${argCount[0]})`
517
+ } but got ${rest.length} (${stringifyArgs(exp)})`
518
+ )
519
+ }
520
+ } else if (
521
+ args[i][STATS] &&
522
+ args[i][STATS].type === APPLY &&
523
+ !isLeaf(rest[i]) &&
524
+ rest[i][0][TYPE] === APPLY &&
525
+ rest[i][0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
526
+ ) {
527
+ const argCount = [...args[i][STATS][ARGS_COUNT]]
528
+ if (!args[i][STATS][ARGS_COUNT].has(rest[i].length - 2))
529
+ errorStack.set(
530
+ key,
531
+ `Incorrect number of arguments for (${
532
+ first[VALUE]
533
+ }). Expected ${
534
+ argCount.length > 1
535
+ ? `(or ${argCount
536
+ .map((x) => `(= ${x})`)
537
+ .join(' ')})`
538
+ : `(= ${argCount[0]})`
539
+ } but got ${rest.length} (${stringifyArgs(exp)})`
540
+ )
541
+ }
542
+
543
+ // type check
544
+ if (
545
+ first[TYPE] === APPLY &&
546
+ isSpecial &&
547
+ env[first[VALUE]][STATS][ARGS_COUNT] !== VARIADIC
548
+ ) {
549
+ const expectedArgs = env[first[VALUE]][STATS][ARGS]
550
+ for (let i = 0; i < rest.length; ++i) {
551
+ if (expectedArgs[i][TYPE] === UNKNOWN) continue
552
+ if (!isLeaf(rest[i])) {
553
+ const CAR = rest[i][0][VALUE]
554
+ if (
555
+ env[CAR] &&
556
+ env[CAR][STATS][RETURNS] != undefined &&
557
+ env[CAR][STATS][RETURNS] !== UNKNOWN &&
558
+ env[CAR][STATS][RETURNS] !== expectedArgs[i][TYPE]
559
+ ) {
560
+ // console.log(env[CAR][STATS], expectedArgs[i][TYPE])
561
+ errorStack.set(
562
+ key,
563
+ `Incorrect type of arguments for special form (${
564
+ first[VALUE]
565
+ }). Expected (${toTypeNames(
566
+ expectedArgs[i][TYPE]
567
+ )}) but got (${toTypeNames(
568
+ env[CAR][STATS][RETURNS]
569
+ )}) (${stringifyArgs(exp)})`
570
+ )
571
+ }
572
+ // else {
573
+ // console.log(env[CAR])
574
+ // }
575
+ }
576
+ if (
577
+ env[rest[i][VALUE]] &&
578
+ expectedArgs[i][TYPE] !== rest[i][TYPE]
579
+ ) {
580
+ switch (rest[i][TYPE]) {
581
+ case UNKNOWN:
582
+ env[first[VALUE]][STATS].type =
583
+ expectedArgs[i][TYPE]
584
+ break
585
+ case WORD:
586
+ const T = env[rest[i][VALUE]][STATS].type
587
+ if (Array.isArray(T)) {
588
+ const TT = T[VALUE]
589
+ if (
590
+ env[TT][STATS][RETURNS] &&
591
+ env[TT][STATS][RETURNS] !== UNKNOWN &&
592
+ expectedArgs[i][TYPE] !==
593
+ env[TT][STATS][RETURNS]
594
+ )
595
+ errorStack.set(
596
+ key,
597
+ `Incorrect type of arguments for (${
598
+ first[VALUE]
599
+ }). Expected (${toTypeNames(
600
+ expectedArgs[i][TYPE]
601
+ )}) but got (${toTypeNames(
602
+ rest[i][TYPE]
603
+ )}) (${stringifyArgs(exp)})`
604
+ )
605
+ } else if (
606
+ T !== UNKNOWN &&
607
+ expectedArgs[i][TYPE] !== UNKNOWN &&
608
+ expectedArgs[i][TYPE] !== T
609
+ ) {
610
+ errorStack.set(
611
+ key,
612
+ `Incorrect type of arguments for (${
613
+ first[VALUE]
614
+ }). Expected (${toTypeNames(
615
+ expectedArgs[i][TYPE]
616
+ )}) but got (${toTypeNames(
617
+ rest[i][TYPE]
618
+ )}) (${stringifyArgs(exp)})`
619
+ )
620
+ } else {
621
+ env[rest[i][VALUE]][STATS].type =
622
+ expectedArgs[i][TYPE]
623
+ }
624
+ break
625
+ case APPLY:
626
+ case ATOM:
627
+ errorStack.set(
628
+ key,
629
+ `Incorrect type of arguments for (${
630
+ first[VALUE]
631
+ }). Expected (${toTypeNames(
632
+ expectedArgs[i][TYPE]
633
+ )}) but got (${toTypeNames(
634
+ rest[i][TYPE]
635
+ )}) (${stringifyArgs(exp)})`
636
+ )
637
+ break
638
+ }
639
+ }
640
+ }
641
+ }
642
+ // type checking
643
+ else if (
644
+ rest[i] &&
645
+ args[i][STATS] &&
646
+ rest[i][TYPE] !== args[i][STATS].type
647
+ ) {
648
+ if (isLeaf(rest[i])) {
649
+ const T =
650
+ rest[i][TYPE] === WORD && env[rest[i][VALUE]]
651
+ ? env[rest[i][VALUE]][STATS].type
652
+ : rest[i][TYPE]
653
+ if (
654
+ (args[i][STATS].type !== UNKNOWN &&
655
+ T === ATOM &&
656
+ args[i][STATS].type !== ATOM) ||
657
+ (env[rest[i][VALUE]] &&
658
+ env[rest[i][VALUE]][STATS].type !== UNKNOWN &&
659
+ args[i][STATS].type !== UNKNOWN &&
660
+ env[rest[i][VALUE]][STATS].type !==
661
+ args[i][STATS].type)
662
+ ) {
663
+ errorStack.set(
664
+ key,
665
+ `Incorrect type of arguments ${i} for (${
666
+ first[VALUE]
667
+ }). Expected (${toTypeNames(
668
+ args[i][STATS].type
669
+ )}) but got (${toTypeNames(T)}) (${stringifyArgs(
670
+ exp
671
+ )})`
672
+ )
673
+ } else {
674
+ // env[rest[i][VALUE]][STATS] THiss SHOULD BE
675
+ const retry = env[rest[i][VALUE]]
676
+ if (
677
+ retry &&
678
+ !retry.retried &&
679
+ args[i][STATS].type === UNKNOWN
680
+ ) {
681
+ retry.retried = true
682
+ if (!scope[SCOPE_NAME])
683
+ scope[SCOPE_NAME] = scope[1][VALUE]
684
+ stack.unshift(() => check(exp, env, scope))
685
+ }
686
+ // console.log(
687
+ // first[VALUE],
688
+ // env[first[VALUE]][STATS],
689
+ // rest[i][TYPE],
690
+ // args[i][STATS].type
691
+ // )
692
+ }
693
+ } else if (
694
+ rest[i].length &&
695
+ SPECIAL_FORMS_SET.has(rest[i][0][VALUE]) &&
696
+ env[rest[i][0][VALUE]] &&
697
+ env[rest[i][0][VALUE]][STATS][RETURNS] !== UNKNOWN &&
698
+ args[i][STATS].type !== UNKNOWN &&
699
+ env[rest[i][0][VALUE]][STATS][RETURNS] !==
700
+ args[i][STATS].type
701
+ ) {
702
+ errorStack.set(
703
+ key,
704
+ `Incorrect type of arguments ${i} for (${
705
+ first[VALUE]
706
+ }). Expected (${toTypeNames(
707
+ args[i][STATS].type
708
+ )}) but got (${toTypeNames(
709
+ env[rest[i][0][VALUE]][STATS][RETURNS]
710
+ )}) (${stringifyArgs(exp)})`
711
+ )
712
+ } else {
713
+ if (
714
+ rest[i].length &&
715
+ env[rest[i][0][VALUE]] &&
716
+ args[i][STATS].type === UNKNOWN &&
717
+ !env[rest[i][0][VALUE]].retried
718
+ ) {
719
+ env[rest[i][0][VALUE]].retried = true
720
+ if (!scope[SCOPE_NAME])
721
+ scope[SCOPE_NAME] = scope[1][VALUE]
722
+ stack.unshift(() => check(exp, env, scope))
723
+ }
724
+ }
725
+ }
726
+ }
727
+ }
728
+ }
729
+ })
730
+ for (const r of rest) check(r, env, scope)
731
+ break
732
+ }
733
+ }
734
+ }
735
+ }
736
+ }
737
+ const copy = JSON.parse(JSON.stringify(ast))
738
+ check(copy, root, copy)
739
+ while (stack.length) stack.pop()()
740
+ if (errorStack.size)
741
+ throw new TypeError([...new Set(errorStack.values())].join('\n'))
742
+ return ast
743
+ }