fez-lisp 1.5.130 → 1.5.131
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 +1 -1
- package/src/check.js +172 -231
package/package.json
CHANGED
package/src/check.js
CHANGED
@@ -716,11 +716,145 @@ const checkReturnType = ({ exp, stack, name, env }) => {
|
|
716
716
|
stack
|
717
717
|
})
|
718
718
|
}
|
719
|
+
|
719
720
|
export const typeCheck = (ast) => {
|
720
|
-
let scopeIndex = 0
|
721
|
-
const root = structuredClone(SPECIAL_FORM_TYPES)
|
722
721
|
const Types = new Map()
|
723
722
|
const stack = new Brr()
|
723
|
+
let scopeIndex = 0
|
724
|
+
// TODO also handle casting
|
725
|
+
const match = ({ rest, args, i, env, scope, exp }) => {
|
726
|
+
const first = exp[0]
|
727
|
+
const actual =
|
728
|
+
rest[i][0][VALUE] === KEYWORDS.CREATE_ARRAY
|
729
|
+
? initArrayType({ rem: rest[i], env }) ?? env[rest[i][0][VALUE]][STATS]
|
730
|
+
: env[rest[i][0][VALUE]][STATS]
|
731
|
+
const expected = args[i][STATS]
|
732
|
+
retryArgs(args[i][STATS], stack, () =>
|
733
|
+
match({ rest, args, i, env, scope, exp })
|
734
|
+
)
|
735
|
+
if (!isUnknownType(expected) && !isUnknownReturn(actual))
|
736
|
+
if (!compareTypeWithReturn(expected, actual))
|
737
|
+
throw new TypeError(
|
738
|
+
`Incorrect type of argument (${i}) for (${
|
739
|
+
first[VALUE]
|
740
|
+
}). Expected (${toTypeNames(
|
741
|
+
getType(expected)
|
742
|
+
)}) but got (${toTypeNames(getReturn(actual))}) (${stringifyArgs(
|
743
|
+
exp
|
744
|
+
)}) (check #16)`
|
745
|
+
)
|
746
|
+
else if (notABooleanReturn(expected, actual)) {
|
747
|
+
throw new TypeError(
|
748
|
+
`Incorrect type of argument (${i}) for (${
|
749
|
+
first[VALUE]
|
750
|
+
}). Expected (${formatSubType(
|
751
|
+
getTypes(expected)
|
752
|
+
)}) but got (${formatSubType(getReturns(actual))}) (${stringifyArgs(
|
753
|
+
exp
|
754
|
+
)}) (check #206)`
|
755
|
+
)
|
756
|
+
} else {
|
757
|
+
switch (getType(expected)) {
|
758
|
+
// almost exclusively for anonymous lambdas
|
759
|
+
case APPLY:
|
760
|
+
{
|
761
|
+
const argsN = rest[i].length - 2
|
762
|
+
if (
|
763
|
+
env[rest[i][0][VALUE]][STATS][SIGNATURE] ===
|
764
|
+
KEYWORDS.ANONYMOUS_FUNCTION
|
765
|
+
) {
|
766
|
+
if (argsN !== args[i][STATS][ARG_COUNT])
|
767
|
+
throw new TypeError(
|
768
|
+
`Incorrect number of arguments for (${
|
769
|
+
args[i][STATS][SIGNATURE]
|
770
|
+
}) the (${KEYWORDS.ANONYMOUS_FUNCTION}) argument of (${
|
771
|
+
first[VALUE]
|
772
|
+
}) at position (${i}). Expected (= ${
|
773
|
+
args[i][STATS][ARG_COUNT]
|
774
|
+
}) but got ${argsN} (${stringifyArgs(exp)}) (check #777)`
|
775
|
+
)
|
776
|
+
else {
|
777
|
+
// ANONYMOUS LAMBDAS TYPE CHECKING
|
778
|
+
const local = Object.create(env)
|
779
|
+
const lambdaName = `${ANONYMOUS_FUNCTION_TYPE_PREFIX}${i}::${++scopeIndex}`
|
780
|
+
check(
|
781
|
+
[
|
782
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
783
|
+
[WORD, lambdaName],
|
784
|
+
rest[i]
|
785
|
+
],
|
786
|
+
local,
|
787
|
+
scope
|
788
|
+
)
|
789
|
+
// TODO delete this maybe
|
790
|
+
// #C2
|
791
|
+
// It will not be possilbe to know return type
|
792
|
+
const match1 = () => {
|
793
|
+
const actual = local[lambdaName]
|
794
|
+
const expected = args[i]
|
795
|
+
if (
|
796
|
+
!isUnknownReturn(expected[STATS]) &&
|
797
|
+
!isUnknownReturn(actual[STATS]) &&
|
798
|
+
!compareReturns(expected[STATS], actual[STATS])
|
799
|
+
)
|
800
|
+
throw new TypeError(
|
801
|
+
`Incorrect return type for (${
|
802
|
+
expected[STATS][SIGNATURE]
|
803
|
+
}) the (${KEYWORDS.ANONYMOUS_FUNCTION}) argument of (${
|
804
|
+
first[VALUE]
|
805
|
+
}) at position (${i}). Expected (${toTypeNames(
|
806
|
+
getReturn(expected[STATS])
|
807
|
+
)}) but got (${toTypeNames(
|
808
|
+
getReturn(actual[STATS])
|
809
|
+
)}) (${stringifyArgs(exp)}) (check #779)`
|
810
|
+
)
|
811
|
+
else retry(actual[STATS], stack, () => match1())
|
812
|
+
}
|
813
|
+
match1()
|
814
|
+
for (let j = 0; j < args[i][STATS][ARGUMENTS].length; ++j) {
|
815
|
+
const match2 = () => {
|
816
|
+
const actual = local[lambdaName][STATS][ARGUMENTS][j]
|
817
|
+
const expected = args[i][STATS][ARGUMENTS][j]
|
818
|
+
if (
|
819
|
+
!isUnknownType(actual[STATS]) &&
|
820
|
+
!isUnknownType(expected[STATS]) &&
|
821
|
+
!compareTypes(actual[STATS], expected[STATS])
|
822
|
+
)
|
823
|
+
throw new TypeError(
|
824
|
+
`Incorrect type for (${
|
825
|
+
KEYWORDS.ANONYMOUS_FUNCTION
|
826
|
+
}) (${
|
827
|
+
args[i][STATS][SIGNATURE]
|
828
|
+
}) argument at position (${j}) named as (${
|
829
|
+
local[lambdaName][STATS][ARGUMENTS][j][STATS][
|
830
|
+
SIGNATURE
|
831
|
+
]
|
832
|
+
}). Expected (${toTypeNames(
|
833
|
+
getType(expected[STATS])
|
834
|
+
)}) but got (${toTypeNames(
|
835
|
+
getType(actual[STATS])
|
836
|
+
)}) (${stringifyArgs(exp)}) (check #780)`
|
837
|
+
)
|
838
|
+
else retry(actual[STATS], stack, () => match2())
|
839
|
+
}
|
840
|
+
match2()
|
841
|
+
}
|
842
|
+
}
|
843
|
+
} else {
|
844
|
+
// TODO fix curry: lambdas enter here as undefined
|
845
|
+
}
|
846
|
+
}
|
847
|
+
break
|
848
|
+
// case ATOM:
|
849
|
+
// case COLLECTION:
|
850
|
+
// break
|
851
|
+
}
|
852
|
+
}
|
853
|
+
else if (isUnknownType(expected))
|
854
|
+
retry(args[i][STATS], stack, () =>
|
855
|
+
match({ rest, args, i, env, scope, exp })
|
856
|
+
)
|
857
|
+
}
|
724
858
|
const check = (exp, env, scope) => {
|
725
859
|
const [first, ...rest] = isLeaf(exp) ? [exp] : exp
|
726
860
|
if (first === undefined)
|
@@ -950,7 +1084,7 @@ export const typeCheck = (ast) => {
|
|
950
1084
|
const ret = isLeaf(rest[0]) ? rest[0] : rest[0][0]
|
951
1085
|
const ref = env[ret[VALUE]]
|
952
1086
|
if (!ref) break
|
953
|
-
const caster =
|
1087
|
+
const caster = SPECIAL_FORM_TYPES[first[VALUE]]
|
954
1088
|
if (ret[TYPE] === APPLY && isUnknownReturn(ref[STATS]))
|
955
1089
|
castReturn(ref[STATS], caster[STATS])
|
956
1090
|
else if (isUnknownType(ref[STATS]))
|
@@ -1284,235 +1418,42 @@ export const typeCheck = (ast) => {
|
|
1284
1418
|
} else {
|
1285
1419
|
const name = rest[i][0][VALUE]
|
1286
1420
|
if (!env[name]) continue
|
1287
|
-
if (
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
alternative[i] = rest[i][2]
|
1294
|
-
check([first, ...concequent], env, scope)
|
1295
|
-
check([first, ...alternative], env, scope)
|
1296
|
-
} else if (
|
1297
|
-
isUnknownReturn(env[name][STATS]) &&
|
1298
|
-
!env[name][STATS][IS_ARGUMENT]
|
1299
|
-
) {
|
1300
|
-
return retry(env[name][STATS], stack, () =>
|
1301
|
-
check(exp, env, scope)
|
1302
|
-
)
|
1303
|
-
} else if (
|
1304
|
-
!isUnknownType(args[i][STATS]) &&
|
1305
|
-
!isUnknownReturn(env[name][STATS]) &&
|
1306
|
-
!compareTypeWithReturn(
|
1307
|
-
args[i][STATS],
|
1308
|
-
env[name][STATS]
|
1309
|
-
)
|
1310
|
-
)
|
1311
|
-
throw new TypeError(
|
1312
|
-
`Incorrect type of argument (${i}) for (${
|
1313
|
-
first[VALUE]
|
1314
|
-
}). Expected (${toTypeNames(
|
1315
|
-
getType(args[i][STATS])
|
1316
|
-
)}) but got (${toTypeNames(
|
1317
|
-
getReturn(env[name][STATS])
|
1318
|
-
)}) (${stringifyArgs(exp)}) (check #1)`
|
1319
|
-
)
|
1320
|
-
else if (
|
1321
|
-
!isUnknownReturn(args[i][STATS]) &&
|
1322
|
-
!isUnknownReturn(env[name][STATS]) &&
|
1323
|
-
notABooleanReturn(args[i][STATS], env[name][STATS])
|
1421
|
+
if (
|
1422
|
+
isUnknownReturn(env[name][STATS]) &&
|
1423
|
+
!env[name][STATS][IS_ARGUMENT]
|
1424
|
+
)
|
1425
|
+
return retry(env[name][STATS], stack, () =>
|
1426
|
+
check(exp, env, scope)
|
1324
1427
|
)
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
)
|
1334
|
-
else {
|
1335
|
-
if (env[name] && getType(env[name][STATS]) === APPLY)
|
1336
|
-
switch (first[VALUE]) {
|
1337
|
-
case KEYWORDS.IF:
|
1338
|
-
break
|
1339
|
-
default:
|
1340
|
-
// TODO fix this assigment
|
1341
|
-
// It turns out it's not possible to determine return type of function here
|
1342
|
-
// what if it's a global function used elsewhere where the return type mwould be different
|
1343
|
-
// THIS willgive lambda return types but refactor is needed still
|
1344
|
-
if (!SPECIAL_FORMS_SET.has(name))
|
1345
|
-
setReturnRef(env[name][STATS], args[i][STATS])
|
1346
|
-
break
|
1347
|
-
}
|
1348
|
-
// TODO also handle casting
|
1349
|
-
}
|
1350
|
-
} else {
|
1351
|
-
const match = () => {
|
1352
|
-
const actual =
|
1353
|
-
rest[i][0][VALUE] === KEYWORDS.CREATE_ARRAY
|
1354
|
-
? initArrayType({ rem: rest[i], env }) ??
|
1355
|
-
env[rest[i][0][VALUE]][STATS]
|
1356
|
-
: env[rest[i][0][VALUE]][STATS]
|
1357
|
-
const expected = args[i][STATS]
|
1358
|
-
retryArgs(args[i][STATS], stack, () => match())
|
1359
|
-
if (
|
1360
|
-
!isUnknownType(expected) &&
|
1361
|
-
!isUnknownReturn(actual)
|
1362
|
-
)
|
1363
|
-
if (!compareTypeWithReturn(expected, actual))
|
1364
|
-
throw new TypeError(
|
1365
|
-
`Incorrect type of argument (${i}) for (${
|
1366
|
-
first[VALUE]
|
1367
|
-
}). Expected (${toTypeNames(
|
1368
|
-
getType(expected)
|
1369
|
-
)}) but got (${toTypeNames(
|
1370
|
-
getReturn(actual)
|
1371
|
-
)}) (${stringifyArgs(exp)}) (check #16)`
|
1372
|
-
)
|
1373
|
-
else if (notABooleanReturn(expected, actual)) {
|
1374
|
-
throw new TypeError(
|
1375
|
-
`Incorrect type of argument (${i}) for (${
|
1376
|
-
first[VALUE]
|
1377
|
-
}). Expected (${formatSubType(
|
1378
|
-
getTypes(expected)
|
1379
|
-
)}) but got (${formatSubType(
|
1380
|
-
getReturns(actual)
|
1381
|
-
)}) (${stringifyArgs(exp)}) (check #206)`
|
1382
|
-
)
|
1383
|
-
} else {
|
1384
|
-
switch (getType(expected)) {
|
1385
|
-
// almost exclusively for anonymous lambdas
|
1386
|
-
case APPLY:
|
1387
|
-
{
|
1388
|
-
const argsN = rest[i].length - 2
|
1389
|
-
if (
|
1390
|
-
env[rest[i][0][VALUE]][STATS][
|
1391
|
-
SIGNATURE
|
1392
|
-
] === KEYWORDS.ANONYMOUS_FUNCTION
|
1393
|
-
) {
|
1394
|
-
if (argsN !== args[i][STATS][ARG_COUNT])
|
1395
|
-
throw new TypeError(
|
1396
|
-
`Incorrect number of arguments for (${
|
1397
|
-
args[i][STATS][SIGNATURE]
|
1398
|
-
}) the (${
|
1399
|
-
KEYWORDS.ANONYMOUS_FUNCTION
|
1400
|
-
}) argument of (${
|
1401
|
-
first[VALUE]
|
1402
|
-
}) at position (${i}). Expected (= ${
|
1403
|
-
args[i][STATS][ARG_COUNT]
|
1404
|
-
}) but got ${argsN} (${stringifyArgs(
|
1405
|
-
exp
|
1406
|
-
)}) (check #777)`
|
1407
|
-
)
|
1408
|
-
else {
|
1409
|
-
// ANONYMOUS LAMBDAS TYPE CHECKING
|
1410
|
-
const local = Object.create(env)
|
1411
|
-
const lambdaName = `${ANONYMOUS_FUNCTION_TYPE_PREFIX}${i}::${++scopeIndex}`
|
1412
|
-
check(
|
1413
|
-
[
|
1414
|
-
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
1415
|
-
[WORD, lambdaName],
|
1416
|
-
rest[i]
|
1417
|
-
],
|
1418
|
-
local,
|
1419
|
-
scope
|
1420
|
-
)
|
1421
|
-
// TODO delete this maybe
|
1422
|
-
// #C2
|
1423
|
-
// It will not be possilbe to know return type
|
1424
|
-
const match1 = () => {
|
1425
|
-
const actual = local[lambdaName]
|
1426
|
-
const expected = args[i]
|
1427
|
-
if (
|
1428
|
-
!isUnknownReturn(expected[STATS]) &&
|
1429
|
-
!isUnknownReturn(actual[STATS]) &&
|
1430
|
-
!compareReturns(
|
1431
|
-
expected[STATS],
|
1432
|
-
actual[STATS]
|
1433
|
-
)
|
1434
|
-
)
|
1435
|
-
throw new TypeError(
|
1436
|
-
`Incorrect return type for (${
|
1437
|
-
expected[STATS][SIGNATURE]
|
1438
|
-
}) the (${
|
1439
|
-
KEYWORDS.ANONYMOUS_FUNCTION
|
1440
|
-
}) argument of (${
|
1441
|
-
first[VALUE]
|
1442
|
-
}) at position (${i}). Expected (${toTypeNames(
|
1443
|
-
getReturn(expected[STATS])
|
1444
|
-
)}) but got (${toTypeNames(
|
1445
|
-
getReturn(actual[STATS])
|
1446
|
-
)}) (${stringifyArgs(
|
1447
|
-
exp
|
1448
|
-
)}) (check #779)`
|
1449
|
-
)
|
1450
|
-
else
|
1451
|
-
retry(actual[STATS], stack, () =>
|
1452
|
-
match1()
|
1453
|
-
)
|
1454
|
-
}
|
1455
|
-
match1()
|
1456
|
-
for (
|
1457
|
-
let j = 0;
|
1458
|
-
j < args[i][STATS][ARGUMENTS].length;
|
1459
|
-
++j
|
1460
|
-
) {
|
1461
|
-
const match2 = () => {
|
1462
|
-
const actual =
|
1463
|
-
local[lambdaName][STATS][
|
1464
|
-
ARGUMENTS
|
1465
|
-
][j]
|
1466
|
-
const expected =
|
1467
|
-
args[i][STATS][ARGUMENTS][j]
|
1468
|
-
if (
|
1469
|
-
!isUnknownType(actual[STATS]) &&
|
1470
|
-
!isUnknownType(expected[STATS]) &&
|
1471
|
-
!compareTypes(
|
1472
|
-
actual[STATS],
|
1473
|
-
expected[STATS]
|
1474
|
-
)
|
1475
|
-
)
|
1476
|
-
throw new TypeError(
|
1477
|
-
`Incorrect type for (${
|
1478
|
-
KEYWORDS.ANONYMOUS_FUNCTION
|
1479
|
-
}) (${
|
1480
|
-
args[i][STATS][SIGNATURE]
|
1481
|
-
}) argument at position (${j}) named as (${
|
1482
|
-
local[lambdaName][STATS][
|
1483
|
-
ARGUMENTS
|
1484
|
-
][j][STATS][SIGNATURE]
|
1485
|
-
}). Expected (${toTypeNames(
|
1486
|
-
getType(expected[STATS])
|
1487
|
-
)}) but got (${toTypeNames(
|
1488
|
-
getType(actual[STATS])
|
1489
|
-
)}) (${stringifyArgs(
|
1490
|
-
exp
|
1491
|
-
)}) (check #780)`
|
1492
|
-
)
|
1493
|
-
else
|
1494
|
-
retry(actual[STATS], stack, () =>
|
1495
|
-
match2()
|
1496
|
-
)
|
1497
|
-
}
|
1498
|
-
match2()
|
1499
|
-
}
|
1500
|
-
}
|
1501
|
-
} else {
|
1502
|
-
// TODO fix curry: lambdas enter here as undefined
|
1503
|
-
}
|
1504
|
-
}
|
1505
|
-
break
|
1506
|
-
// case ATOM:
|
1507
|
-
// case COLLECTION:
|
1508
|
-
// break
|
1509
|
-
}
|
1510
|
-
}
|
1511
|
-
else if (isUnknownType(expected))
|
1512
|
-
retry(args[i][STATS], stack, () => match())
|
1513
|
-
}
|
1514
|
-
match()
|
1428
|
+
|
1429
|
+
if (isSpecial && name === KEYWORDS.IF) {
|
1430
|
+
const concequent = [...rest]
|
1431
|
+
const alternative = [...rest]
|
1432
|
+
concequent[i] = rest[i][1]
|
1433
|
+
alternative[i] = rest[i][2]
|
1434
|
+
check([first, ...concequent], env, scope)
|
1435
|
+
check([first, ...alternative], env, scope)
|
1515
1436
|
}
|
1437
|
+
|
1438
|
+
if (
|
1439
|
+
env[name] &&
|
1440
|
+
getType(env[name][STATS]) === APPLY &&
|
1441
|
+
!SPECIAL_FORMS_SET.has(name)
|
1442
|
+
)
|
1443
|
+
switch (first[VALUE]) {
|
1444
|
+
case KEYWORDS.IF:
|
1445
|
+
break
|
1446
|
+
default:
|
1447
|
+
// TODO fix this assigment
|
1448
|
+
// It turns out it's not possible to determine return type of function here
|
1449
|
+
// what if it's a global function used elsewhere where the return type mwould be different
|
1450
|
+
// THIS willgive lambda return types but refactor is needed still
|
1451
|
+
// if (!SPECIAL_FORMS_SET.has(name))
|
1452
|
+
setReturnRef(env[name][STATS], args[i][STATS])
|
1453
|
+
break
|
1454
|
+
}
|
1455
|
+
|
1456
|
+
match({ rest, args, i, env, scope, exp })
|
1516
1457
|
}
|
1517
1458
|
}
|
1518
1459
|
// REFACTORING
|
@@ -1538,7 +1479,7 @@ export const typeCheck = (ast) => {
|
|
1538
1479
|
}
|
1539
1480
|
}
|
1540
1481
|
const copy = JSON.parse(JSON.stringify(ast))
|
1541
|
-
check(copy,
|
1482
|
+
check(copy, SPECIAL_FORM_TYPES, copy)
|
1542
1483
|
while (stack.length) stack.cut()()
|
1543
1484
|
return [ast, Types]
|
1544
1485
|
}
|