fez-lisp 1.5.37 → 1.5.39
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/lib/baked/std.js +1 -1
- package/package.json +1 -1
- package/src/check.js +134 -61
- package/src/compiler.js +1 -1
- package/src/interpreter.js +1 -1
- package/src/utils.js +11 -4
package/package.json
CHANGED
package/src/check.js
CHANGED
@@ -2,16 +2,18 @@ import {
|
|
2
2
|
APPLY,
|
3
3
|
ATOM,
|
4
4
|
DEBUG,
|
5
|
+
FALSE,
|
5
6
|
KEYWORDS,
|
6
7
|
PLACEHOLDER,
|
7
8
|
PREDICATE_SUFFIX,
|
8
9
|
SPECIAL_FORMS_SET,
|
10
|
+
TRUE,
|
9
11
|
TYPE,
|
10
12
|
VALUE,
|
11
13
|
WORD
|
12
14
|
} from './keywords.js'
|
13
15
|
import { isLeaf } from './parser.js'
|
14
|
-
import { hasBlock, stringifyArgs } from './utils.js'
|
16
|
+
import { hasApplyLambdaBlock, hasBlock, stringifyArgs } from './utils.js'
|
15
17
|
const ARGS_COUNT = 'n'
|
16
18
|
const VARIADIC = '...'
|
17
19
|
const STATS = '__stats__'
|
@@ -19,10 +21,11 @@ const ARGS = 'args'
|
|
19
21
|
const UNKNOWN = -1
|
20
22
|
const RETURNS = 'returns'
|
21
23
|
const SCOPE_NAME = '__scope__'
|
22
|
-
const
|
24
|
+
const SUB_RETURN_TYPE = 'sub_return_type'
|
23
25
|
const PREDICATE = 3
|
24
26
|
const RETRY_COUNT = 1
|
25
27
|
const DEFINITON_RETRY_COUNT = 1
|
28
|
+
const SUB = 2
|
26
29
|
const toTypeNames = (type) => {
|
27
30
|
switch (type) {
|
28
31
|
case APPLY:
|
@@ -130,8 +133,7 @@ export const typeCheck = (ast) => {
|
|
130
133
|
[ATOM, PLACEHOLDER, PREDICATE],
|
131
134
|
[UNKNOWN, PLACEHOLDER]
|
132
135
|
],
|
133
|
-
[RETURNS]: ATOM
|
134
|
-
[SUBTYPE]: PREDICATE
|
136
|
+
[RETURNS]: ATOM
|
135
137
|
}
|
136
138
|
},
|
137
139
|
[KEYWORDS.ADDITION]: {
|
@@ -326,7 +328,7 @@ export const typeCheck = (ast) => {
|
|
326
328
|
[ARGS_COUNT]: 1,
|
327
329
|
[ARGS]: [[ATOM, PLACEHOLDER, PREDICATE]],
|
328
330
|
[RETURNS]: ATOM,
|
329
|
-
[
|
331
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
330
332
|
}
|
331
333
|
},
|
332
334
|
[KEYWORDS.EQUAL]: {
|
@@ -339,7 +341,7 @@ export const typeCheck = (ast) => {
|
|
339
341
|
[ATOM, PLACEHOLDER]
|
340
342
|
],
|
341
343
|
[RETURNS]: ATOM,
|
342
|
-
[
|
344
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
343
345
|
}
|
344
346
|
},
|
345
347
|
[KEYWORDS.LESS_THAN]: {
|
@@ -352,7 +354,7 @@ export const typeCheck = (ast) => {
|
|
352
354
|
[ATOM, PLACEHOLDER]
|
353
355
|
],
|
354
356
|
[RETURNS]: ATOM,
|
355
|
-
[
|
357
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
356
358
|
}
|
357
359
|
},
|
358
360
|
[KEYWORDS.GREATHER_THAN]: {
|
@@ -365,7 +367,7 @@ export const typeCheck = (ast) => {
|
|
365
367
|
[ATOM, PLACEHOLDER]
|
366
368
|
],
|
367
369
|
[RETURNS]: ATOM,
|
368
|
-
[
|
370
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
369
371
|
}
|
370
372
|
},
|
371
373
|
[KEYWORDS.GREATHER_THAN_OR_EQUAL]: {
|
@@ -378,7 +380,7 @@ export const typeCheck = (ast) => {
|
|
378
380
|
[ATOM, PLACEHOLDER]
|
379
381
|
],
|
380
382
|
[RETURNS]: ATOM,
|
381
|
-
[
|
383
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
382
384
|
}
|
383
385
|
},
|
384
386
|
[KEYWORDS.LESS_THAN_OR_EQUAL]: {
|
@@ -391,7 +393,7 @@ export const typeCheck = (ast) => {
|
|
391
393
|
[ATOM, PLACEHOLDER]
|
392
394
|
],
|
393
395
|
[RETURNS]: ATOM,
|
394
|
-
[
|
396
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
395
397
|
}
|
396
398
|
},
|
397
399
|
[KEYWORDS.AND]: {
|
@@ -404,7 +406,7 @@ export const typeCheck = (ast) => {
|
|
404
406
|
[ATOM, PLACEHOLDER, PREDICATE]
|
405
407
|
],
|
406
408
|
[RETURNS]: ATOM,
|
407
|
-
[
|
409
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
408
410
|
}
|
409
411
|
},
|
410
412
|
[KEYWORDS.OR]: {
|
@@ -417,7 +419,7 @@ export const typeCheck = (ast) => {
|
|
417
419
|
[ATOM, PLACEHOLDER, PREDICATE]
|
418
420
|
],
|
419
421
|
[RETURNS]: ATOM,
|
420
|
-
[
|
422
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
421
423
|
}
|
422
424
|
},
|
423
425
|
[KEYWORDS.IS_ATOM]: {
|
@@ -427,7 +429,7 @@ export const typeCheck = (ast) => {
|
|
427
429
|
[ARGS_COUNT]: 1,
|
428
430
|
[ARGS]: [[UNKNOWN, PLACEHOLDER]],
|
429
431
|
[RETURNS]: ATOM,
|
430
|
-
[
|
432
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
431
433
|
}
|
432
434
|
},
|
433
435
|
[KEYWORDS.IS_LAMBDA]: {
|
@@ -437,7 +439,7 @@ export const typeCheck = (ast) => {
|
|
437
439
|
[ARGS_COUNT]: 1,
|
438
440
|
[ARGS]: [[UNKNOWN, PLACEHOLDER]],
|
439
441
|
[RETURNS]: ATOM,
|
440
|
-
[
|
442
|
+
[SUB_RETURN_TYPE]: PREDICATE
|
441
443
|
}
|
442
444
|
},
|
443
445
|
[KEYWORDS.ERROR]: {
|
@@ -451,6 +453,8 @@ export const typeCheck = (ast) => {
|
|
451
453
|
}
|
452
454
|
}
|
453
455
|
const errorStack = new Map()
|
456
|
+
const warningStack = new Set()
|
457
|
+
|
454
458
|
// const isDefinitionOfAFunction = (head, tail) =>
|
455
459
|
// head[TYPE] === APPLY &&
|
456
460
|
// head[VALUE] === KEYWORDS.DEFINE_VARIABLE &&
|
@@ -487,6 +491,12 @@ export const typeCheck = (ast) => {
|
|
487
491
|
errorStack.set(
|
488
492
|
key.str,
|
489
493
|
`Trying to access undefined variable ${first[VALUE]} (check #11)`
|
494
|
+
|
495
|
+
// `Trying to access undefined variable ${
|
496
|
+
// first[VALUE]
|
497
|
+
// }\n${formatCallstack(
|
498
|
+
// key.chain.filter((x) => isNaN(Number(x[0])))
|
499
|
+
// )}\n(check #11)`
|
490
500
|
)
|
491
501
|
}
|
492
502
|
})
|
@@ -522,49 +532,88 @@ export const typeCheck = (ast) => {
|
|
522
532
|
}
|
523
533
|
}
|
524
534
|
const checkReturnType = () => {
|
525
|
-
if (name[name.length - 1] === PREDICATE_SUFFIX) {
|
535
|
+
// if (name[name.length - 1] === PREDICATE_SUFFIX) {
|
536
|
+
// env[name][STATS][RETURNS] = ATOM
|
537
|
+
// env[name][STATS][SUB_RETURN_TYPE] = PREDICATE
|
538
|
+
// } else {
|
539
|
+
const isPredicate =
|
540
|
+
name[name.length - 1] === PREDICATE_SUFFIX
|
541
|
+
const last = rest.at(-1).at(-1)
|
542
|
+
const body = hasApplyLambdaBlock(last)
|
543
|
+
? last.at(-1).at(-1)
|
544
|
+
: last
|
545
|
+
const rem = hasBlock(body) ? body.at(-1) : body
|
546
|
+
const returns = isLeaf(rem) ? rem : rem[0]
|
547
|
+
if (returns[TYPE] === ATOM) {
|
526
548
|
env[name][STATS][RETURNS] = ATOM
|
527
|
-
env[name][STATS][SUBTYPE] = PREDICATE
|
528
549
|
} else {
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
550
|
+
switch (returns[VALUE]) {
|
551
|
+
case KEYWORDS.IF:
|
552
|
+
const re = rem.slice(2)
|
553
|
+
if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM) {
|
554
|
+
env[name][STATS][RETURNS] = ATOM
|
555
|
+
// if (
|
556
|
+
// re[0][VALUE] === FALSE ||
|
557
|
+
// re[0][VALUE] === TRUE ||
|
558
|
+
// re[1][VALUE] === FALSE ||
|
559
|
+
// re[1][VALUE] === TRUE
|
560
|
+
// ) {
|
561
|
+
// env[name][STATS][SUB_RETURN_TYPE] = PREDICATE
|
562
|
+
// }
|
563
|
+
} else if (!isLeaf(re[0]) && env[re[0][0][VALUE]]) {
|
564
|
+
env[name][STATS][RETURNS] =
|
565
|
+
env[re[0][0][VALUE]][STATS][RETURNS]
|
566
|
+
env[name][STATS][SUB_RETURN_TYPE] =
|
567
|
+
env[re[0][0][VALUE]][STATS][SUB_RETURN_TYPE]
|
568
|
+
} else {
|
569
|
+
if (env[re[0][VALUE]]) {
|
541
570
|
env[name][STATS][RETURNS] =
|
542
|
-
env[re[0][
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
// env[name][STATS][SUBTYPE] =
|
556
|
-
// env[returns[VALUE]][STATS][SUBTYPE]
|
557
|
-
} else {
|
558
|
-
env[name][STATS][RETURNS] =
|
559
|
-
env[returns[VALUE]].type
|
560
|
-
}
|
571
|
+
env[re[0][VALUE]][STATS].type
|
572
|
+
env[name][STATS][SUB_RETURN_TYPE] =
|
573
|
+
env[re[0][VALUE]][STATS][SUB_RETURN_TYPE]
|
574
|
+
} else env[name][STATS][RETURNS] = UNKNOWN
|
575
|
+
}
|
576
|
+
break
|
577
|
+
default:
|
578
|
+
if (env[returns[VALUE]]) {
|
579
|
+
if (env[returns[VALUE]][STATS].type === APPLY) {
|
580
|
+
env[name][STATS][RETURNS] =
|
581
|
+
env[returns[VALUE]][STATS][RETURNS]
|
582
|
+
env[name][STATS][SUB_RETURN_TYPE] =
|
583
|
+
env[returns[VALUE]][STATS][SUB_RETURN_TYPE]
|
561
584
|
} else {
|
562
|
-
env[name][STATS][RETURNS] =
|
585
|
+
env[name][STATS][RETURNS] =
|
586
|
+
env[returns[VALUE]][STATS].type
|
587
|
+
env[name][STATS][SUB_RETURN_TYPE] =
|
588
|
+
env[returns[VALUE]][SUB_RETURN_TYPE]
|
563
589
|
}
|
564
|
-
|
565
|
-
|
590
|
+
} else {
|
591
|
+
env[name][STATS][RETURNS] = UNKNOWN
|
592
|
+
}
|
593
|
+
break
|
566
594
|
}
|
567
595
|
}
|
596
|
+
if (
|
597
|
+
isPredicate &&
|
598
|
+
env[name][STATS][RETURNS] !== UNKNOWN &&
|
599
|
+
env[name][STATS][SUB_RETURN_TYPE] !== PREDICATE
|
600
|
+
) {
|
601
|
+
warningStack.add(
|
602
|
+
`${name} ends in (${PREDICATE_SUFFIX}) and is expected to return (Predicate) but it doesn't (try wrapping it in a (true?) or (false?)) (check #7)`
|
603
|
+
)
|
604
|
+
} else if (
|
605
|
+
!isPredicate &&
|
606
|
+
env[name][STATS][SUB_RETURN_TYPE] === PREDICATE
|
607
|
+
) {
|
608
|
+
warningStack.add(
|
609
|
+
`${name} should end in (${PREDICATE_SUFFIX}) because it return (Predicate) (try adding ? at the end of the lambda name) (check #8)`
|
610
|
+
)
|
611
|
+
}
|
612
|
+
if (isPredicate) {
|
613
|
+
env[name][STATS][RETURNS] = ATOM
|
614
|
+
env[name][STATS][SUB_RETURN_TYPE] = PREDICATE
|
615
|
+
}
|
616
|
+
// }
|
568
617
|
// if (
|
569
618
|
// env[name][STATS][RETURNS] === UNKNOWN &&
|
570
619
|
// env[name][STATS].retried < RETRY_COUNT
|
@@ -630,12 +679,20 @@ export const typeCheck = (ast) => {
|
|
630
679
|
.toString()
|
631
680
|
.replace('.', 0)
|
632
681
|
}
|
633
|
-
for (
|
682
|
+
for (let i = 0; i < params.length; ++i) {
|
683
|
+
const param = params[i]
|
634
684
|
copy[param[VALUE]] = {
|
635
685
|
[STATS]: { type: UNKNOWN, retried: 0 }
|
636
686
|
}
|
637
|
-
if (env[copy[SCOPE_NAME]])
|
638
|
-
env[copy[SCOPE_NAME]][STATS][ARGS]
|
687
|
+
if (env[copy[SCOPE_NAME]]) {
|
688
|
+
env[copy[SCOPE_NAME]][STATS][ARGS][i] = copy[param[VALUE]]
|
689
|
+
if (
|
690
|
+
param[VALUE][param[VALUE].length - 1] === PREDICATE_SUFFIX
|
691
|
+
) {
|
692
|
+
copy[param[VALUE]][STATS][RETURNS] = ATOM
|
693
|
+
copy[param[VALUE]][STATS][SUB_RETURN_TYPE] = PREDICATE
|
694
|
+
}
|
695
|
+
}
|
639
696
|
}
|
640
697
|
check(rest.at(-1), copy, copy)
|
641
698
|
}
|
@@ -662,7 +719,7 @@ export const typeCheck = (ast) => {
|
|
662
719
|
env[first[VALUE]][STATS][ARGS_COUNT]
|
663
720
|
}) but got ${rest.length} (${stringifyArgs(
|
664
721
|
exp
|
665
|
-
)}) (check #
|
722
|
+
)}) (check #15)`
|
666
723
|
)
|
667
724
|
} else {
|
668
725
|
const isSpecial = SPECIAL_FORMS_SET.has(first[VALUE])
|
@@ -696,10 +753,12 @@ export const typeCheck = (ast) => {
|
|
696
753
|
if (expectedArgs[i][TYPE] === UNKNOWN) continue
|
697
754
|
if (!isLeaf(rest[i])) {
|
698
755
|
const CAR = rest[i][0][VALUE]
|
699
|
-
|
756
|
+
const isKnown =
|
700
757
|
env[CAR] &&
|
701
758
|
env[CAR][STATS][RETURNS] != undefined &&
|
702
|
-
env[CAR][STATS][RETURNS] !== UNKNOWN
|
759
|
+
env[CAR][STATS][RETURNS] !== UNKNOWN
|
760
|
+
if (
|
761
|
+
isKnown &&
|
703
762
|
env[CAR][STATS][RETURNS] !==
|
704
763
|
expectedArgs[i][TYPE]
|
705
764
|
) {
|
@@ -714,10 +773,24 @@ export const typeCheck = (ast) => {
|
|
714
773
|
env[CAR][STATS][RETURNS]
|
715
774
|
)}) (${stringifyArgs(exp)}) (check #1)`
|
716
775
|
)
|
776
|
+
} else if (
|
777
|
+
isKnown &&
|
778
|
+
expectedArgs[i][SUB] &&
|
779
|
+
env[CAR][STATS][SUB_RETURN_TYPE] !==
|
780
|
+
expectedArgs[i][SUB]
|
781
|
+
) {
|
782
|
+
errorStack.set(
|
783
|
+
key.str,
|
784
|
+
`Incorrect type of arguments for special form (${
|
785
|
+
first[VALUE]
|
786
|
+
}). Expected (${toTypeNames(
|
787
|
+
expectedArgs[i][SUB]
|
788
|
+
)}) but got (${toTypeNames(
|
789
|
+
env[CAR][STATS][SUB_RETURN_TYPE] ??
|
790
|
+
env[CAR][STATS][RETURNS]
|
791
|
+
)}) (${stringifyArgs(exp)}) (check #13)`
|
792
|
+
)
|
717
793
|
}
|
718
|
-
// else {
|
719
|
-
// console.log(env[CAR])
|
720
|
-
// }
|
721
794
|
}
|
722
795
|
if (
|
723
796
|
env[rest[i][VALUE]] &&
|
@@ -885,7 +958,7 @@ export const typeCheck = (ast) => {
|
|
885
958
|
copy[SCOPE_NAME] = 'root'
|
886
959
|
check(copy, root, copy)
|
887
960
|
while (stack.length) stack.pop()()
|
888
|
-
|
889
|
-
|
961
|
+
const issues = [...new Set(errorStack.values()), ...warningStack]
|
962
|
+
if (issues.length) throw new TypeError(issues.join('\n'))
|
890
963
|
return ast
|
891
964
|
}
|
package/src/compiler.js
CHANGED
package/src/interpreter.js
CHANGED
@@ -17,7 +17,7 @@ export const keywords = {
|
|
17
17
|
if (args.length != 2)
|
18
18
|
throw new RangeError(`Wrong number of args to ${KEYWORDS.LOOP}`)
|
19
19
|
while (evaluate(args[0], env) === TRUE) evaluate(args[1], env)
|
20
|
-
return
|
20
|
+
return -1
|
21
21
|
},
|
22
22
|
[KEYWORDS.ADDITION]: (args, env) => {
|
23
23
|
if (args.length !== 2)
|
package/src/utils.js
CHANGED
@@ -11,11 +11,13 @@ import {
|
|
11
11
|
export const logError = (error) =>
|
12
12
|
console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
|
13
13
|
export const logSuccess = (output) => console.log('\x1b[32m', output, '\x1b[0m')
|
14
|
-
export const
|
15
|
-
|
14
|
+
export const formatCallstack = (callstack) =>
|
15
|
+
callstack
|
16
16
|
.reverse()
|
17
17
|
.map((x, i) => `${Array(i + 2).join(' ')}(${x} ...)`)
|
18
|
-
.join('\n')
|
18
|
+
.join('\n')
|
19
|
+
export const formatErrorWithCallstack = (error, callstack) => {
|
20
|
+
return `${error.message}\n${formatCallstack(callstack)}`
|
19
21
|
}
|
20
22
|
export const removeNoCode = (source) =>
|
21
23
|
source
|
@@ -193,7 +195,12 @@ const deepShake = (tree, deps, visited = new Set(), ignored = new Set()) => {
|
|
193
195
|
|
194
196
|
export const hasBlock = (body) =>
|
195
197
|
body[0] && body[0][TYPE] === APPLY && body[0][VALUE] === KEYWORDS.BLOCK
|
196
|
-
|
198
|
+
export const hasApplyLambdaBlock = (body) =>
|
199
|
+
body[0] &&
|
200
|
+
body[0][TYPE] === APPLY &&
|
201
|
+
body[0][VALUE] === KEYWORDS.CALL_FUNCTION &&
|
202
|
+
body[1][0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION &&
|
203
|
+
body[1][1][0][VALUE] === KEYWORDS.BLOCK
|
197
204
|
const extractDeps = (visited, deps) =>
|
198
205
|
[...visited]
|
199
206
|
.map((x) => deps.get(x))
|