fez-lisp 1.5.16 → 1.5.17

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,732 @@
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
+ const key = withScope(name, scope)
416
+ if (errorStack.has(key)) errorStack.delete(key)
417
+ check(rest.at(-1), env, scope)
418
+ }
419
+ }
420
+ break
421
+ case KEYWORDS.ANONYMOUS_FUNCTION:
422
+ {
423
+ if (exp.length === 1) {
424
+ throw new TypeError(
425
+ `Incorrect number of arguments for (${
426
+ first[VALUE]
427
+ }). Expected at least 1 (the lambda body) but got 1 (${stringifyArgs(
428
+ exp
429
+ )})`
430
+ )
431
+ }
432
+ const params = exp.slice(1, -1)
433
+ const copy = Object.create(env)
434
+ if (isLeaf(scope[1])) {
435
+ copy[SCOPE_NAME] = scope[1][VALUE]
436
+ } else
437
+ copy[SCOPE_NAME] = performance
438
+ .now()
439
+ .toString()
440
+ .replace('.', 0)
441
+ for (const param of params) {
442
+ copy[param[VALUE]] = { [STATS]: { type: UNKNOWN } }
443
+ if (env[copy[SCOPE_NAME]])
444
+ env[copy[SCOPE_NAME]][STATS][ARGS].push(copy[param[VALUE]])
445
+ }
446
+ check(rest.at(-1), copy, scope)
447
+ }
448
+ break
449
+ default:
450
+ stack.push(() => {
451
+ const key = withScope(first[VALUE], scope)
452
+ if (env[first[VALUE]] === undefined)
453
+ errorStack.set(
454
+ key,
455
+ `Trying to call undefined (lambda) ${first[VALUE]}`
456
+ )
457
+ else if (
458
+ env[first[VALUE]][STATS].type === APPLY &&
459
+ env[first[VALUE]][STATS][ARGS_COUNT] !== VARIADIC &&
460
+ !env[first[VALUE]][STATS][ARGS_COUNT].has(rest.length)
461
+ ) {
462
+ const argCount = [...env[first[VALUE]][STATS][ARGS_COUNT]]
463
+ errorStack.set(
464
+ key,
465
+ `Incorrect number of arguments for (${
466
+ first[VALUE]
467
+ }). Expected ${
468
+ argCount.length > 1
469
+ ? `(or ${argCount.map((x) => `(= ${x})`).join(' ')})`
470
+ : `(= ${argCount[0]})`
471
+ } but got ${rest.length} (${stringifyArgs(exp)})`
472
+ )
473
+ } else {
474
+ const isSpecial = SPECIAL_FORMS_SET.has(first[VALUE])
475
+
476
+ if (first[TYPE] === APPLY && !isSpecial) {
477
+ if (!env[first[VALUE]][STATS][ARGS_COUNT]) {
478
+ env[first[VALUE]][STATS][RETURNS] = UNKNOWN
479
+ env[first[VALUE]][STATS].type = APPLY
480
+ env[first[VALUE]][STATS][ARGS_COUNT] = new Set([
481
+ rest.length
482
+ ])
483
+ }
484
+ }
485
+ // also type of arg
486
+ const args = env[first[VALUE]][STATS][ARGS]
487
+ if (args) {
488
+ for (let i = 0; i < args.length; ++i) {
489
+ if (
490
+ args[i][STATS] &&
491
+ args[i][STATS].type === APPLY &&
492
+ env[rest[i][VALUE]] &&
493
+ env[rest[i][VALUE]][STATS] &&
494
+ env[rest[i][VALUE]][STATS][ARGS_COUNT]
495
+ ) {
496
+ const argCount = [...args[i][STATS][ARGS_COUNT]]
497
+ if (
498
+ xor(
499
+ args[i][STATS][ARGS_COUNT],
500
+ env[rest[i][VALUE]][STATS][ARGS_COUNT]
501
+ ).size !== 0
502
+ ) {
503
+ errorStack.set(
504
+ key,
505
+ `Incorrect number of arguments for (${
506
+ first[VALUE]
507
+ }). Expected ${
508
+ argCount.length > 1
509
+ ? `(or ${argCount
510
+ .map((x) => `(= ${x})`)
511
+ .join(' ')})`
512
+ : `(= ${argCount[0]})`
513
+ } but got ${rest.length} (${stringifyArgs(exp)})`
514
+ )
515
+ }
516
+ } else if (
517
+ args[i][STATS] &&
518
+ args[i][STATS].type === APPLY &&
519
+ !isLeaf(rest[i]) &&
520
+ rest[i][0][TYPE] === APPLY &&
521
+ rest[i][0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
522
+ ) {
523
+ const argCount = [...args[i][STATS][ARGS_COUNT]]
524
+ if (!args[i][STATS][ARGS_COUNT].has(rest[i].length - 2))
525
+ errorStack.set(
526
+ key,
527
+ `Incorrect number of arguments for (${
528
+ first[VALUE]
529
+ }). Expected ${
530
+ argCount.length > 1
531
+ ? `(or ${argCount
532
+ .map((x) => `(= ${x})`)
533
+ .join(' ')})`
534
+ : `(= ${argCount[0]})`
535
+ } but got ${rest.length} (${stringifyArgs(exp)})`
536
+ )
537
+ }
538
+
539
+ // type check
540
+ if (
541
+ first[TYPE] === APPLY &&
542
+ isSpecial &&
543
+ env[first[VALUE]][STATS][ARGS_COUNT] !== VARIADIC
544
+ ) {
545
+ const expectedArgs = env[first[VALUE]][STATS][ARGS]
546
+ for (let i = 0; i < rest.length; ++i) {
547
+ if (expectedArgs[i][TYPE] === UNKNOWN) continue
548
+ if (!isLeaf(rest[i])) {
549
+ const CAR = rest[i][0][VALUE]
550
+ if (
551
+ env[CAR] &&
552
+ env[CAR][STATS][RETURNS] != undefined &&
553
+ env[CAR][STATS][RETURNS] !== UNKNOWN &&
554
+ env[CAR][STATS][RETURNS] !== expectedArgs[i][TYPE]
555
+ ) {
556
+ // console.log(env[CAR][STATS], expectedArgs[i][TYPE])
557
+ errorStack.set(
558
+ key,
559
+ `Incorrect type of arguments for special form (${
560
+ first[VALUE]
561
+ }). Expected (${toTypeNames(
562
+ expectedArgs[i][TYPE]
563
+ )}) but got (${toTypeNames(
564
+ env[CAR][STATS][RETURNS]
565
+ )}) (${stringifyArgs(exp)})`
566
+ )
567
+ }
568
+ // else {
569
+ // console.log(env[CAR])
570
+ // }
571
+ }
572
+ if (
573
+ env[rest[i][VALUE]] &&
574
+ expectedArgs[i][TYPE] !== rest[i][TYPE]
575
+ ) {
576
+ switch (rest[i][TYPE]) {
577
+ case UNKNOWN:
578
+ env[first[VALUE]][STATS].type =
579
+ expectedArgs[i][TYPE]
580
+ break
581
+ case WORD:
582
+ const T = env[rest[i][VALUE]][STATS].type
583
+ if (Array.isArray(T)) {
584
+ const TT = T[VALUE]
585
+ if (
586
+ env[TT][STATS][RETURNS] &&
587
+ env[TT][STATS][RETURNS] !== UNKNOWN &&
588
+ expectedArgs[i][TYPE] !==
589
+ env[TT][STATS][RETURNS]
590
+ )
591
+ errorStack.set(
592
+ key,
593
+ `Incorrect type of arguments for (${
594
+ first[VALUE]
595
+ }). Expected (${toTypeNames(
596
+ expectedArgs[i][TYPE]
597
+ )}) but got (${toTypeNames(
598
+ rest[i][TYPE]
599
+ )}) (${stringifyArgs(exp)})`
600
+ )
601
+ } else if (
602
+ T !== UNKNOWN &&
603
+ expectedArgs[i][TYPE] !== UNKNOWN &&
604
+ expectedArgs[i][TYPE] !== T
605
+ ) {
606
+ errorStack.set(
607
+ key,
608
+ `Incorrect type of arguments for (${
609
+ first[VALUE]
610
+ }). Expected (${toTypeNames(
611
+ expectedArgs[i][TYPE]
612
+ )}) but got (${toTypeNames(
613
+ rest[i][TYPE]
614
+ )}) (${stringifyArgs(exp)})`
615
+ )
616
+ } else {
617
+ env[rest[i][VALUE]][STATS].type =
618
+ expectedArgs[i][TYPE]
619
+ }
620
+ break
621
+ case APPLY:
622
+ case ATOM:
623
+ errorStack.set(
624
+ key,
625
+ `Incorrect type of arguments for (${
626
+ first[VALUE]
627
+ }). Expected (${toTypeNames(
628
+ expectedArgs[i][TYPE]
629
+ )}) but got (${toTypeNames(
630
+ rest[i][TYPE]
631
+ )}) (${stringifyArgs(exp)})`
632
+ )
633
+ break
634
+ }
635
+ }
636
+ }
637
+ }
638
+ // type checking
639
+ else if (
640
+ rest[i] &&
641
+ args[i][STATS] &&
642
+ rest[i][TYPE] !== args[i][STATS].type
643
+ ) {
644
+ if (isLeaf(rest[i])) {
645
+ const T =
646
+ rest[i][TYPE] === WORD && env[rest[i][VALUE]]
647
+ ? env[rest[i][VALUE]][STATS].type
648
+ : rest[i][TYPE]
649
+ if (
650
+ (args[i][STATS].type !== UNKNOWN &&
651
+ T === ATOM &&
652
+ args[i][STATS].type !== ATOM) ||
653
+ (env[rest[i][VALUE]] &&
654
+ env[rest[i][VALUE]][STATS].type !== UNKNOWN &&
655
+ args[i][STATS].type !== UNKNOWN &&
656
+ env[rest[i][VALUE]][STATS].type !==
657
+ args[i][STATS].type)
658
+ ) {
659
+ errorStack.set(
660
+ key,
661
+ `Incorrect type of arguments ${i} for (${
662
+ first[VALUE]
663
+ }). Expected (${toTypeNames(
664
+ args[i][STATS].type
665
+ )}) but got (${toTypeNames(T)}) (${stringifyArgs(
666
+ exp
667
+ )})`
668
+ )
669
+ } else {
670
+ if (
671
+ !args[i][STATS].retried &&
672
+ args[i][STATS].type === UNKNOWN
673
+ ) {
674
+ args[i][STATS].retried = true
675
+ if (!scope[SCOPE_NAME])
676
+ scope[SCOPE_NAME] = scope[1][VALUE]
677
+ stack.unshift(() => check(exp, env, scope))
678
+ }
679
+ // console.log(
680
+ // first[VALUE],
681
+ // env[first[VALUE]][STATS],
682
+ // rest[i][TYPE],
683
+ // args[i][STATS].type
684
+ // )
685
+ }
686
+ } else if (
687
+ rest[i].length &&
688
+ SPECIAL_FORMS_SET.has(rest[i][0][VALUE]) &&
689
+ env[rest[i][0][VALUE]] &&
690
+ env[rest[i][0][VALUE]][STATS][RETURNS] !== UNKNOWN &&
691
+ args[i][STATS].type !== UNKNOWN &&
692
+ env[rest[i][0][VALUE]][STATS][RETURNS] !==
693
+ args[i][STATS].type
694
+ ) {
695
+ errorStack.set(
696
+ key,
697
+ `Incorrect type of arguments ${i} for (${
698
+ first[VALUE]
699
+ }). Expected (${toTypeNames(
700
+ args[i][STATS].type
701
+ )}) but got (${toTypeNames(
702
+ env[rest[i][0][VALUE]][STATS][RETURNS]
703
+ )}) (${stringifyArgs(exp)})`
704
+ )
705
+ } else {
706
+ if (
707
+ args[i][STATS].type === UNKNOWN &&
708
+ !args[i][STATS].retried
709
+ ) {
710
+ args[i][STATS].retried = true
711
+ if (!scope[SCOPE_NAME])
712
+ scope[SCOPE_NAME] = scope[1][VALUE]
713
+ stack.unshift(() => check(exp, env, scope))
714
+ }
715
+ }
716
+ }
717
+ }
718
+ }
719
+ }
720
+ })
721
+ for (const r of rest) check(r, env, scope)
722
+ break
723
+ }
724
+ }
725
+ }
726
+ }
727
+ }
728
+ check(ast, root, ast)
729
+ while (stack.length) stack.pop()()
730
+ if (errorStack.size) throw new TypeError([...errorStack.values()].join('\n'))
731
+ return ast
732
+ }