fez-lisp 1.5.50 → 1.5.51
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 +19 -87
- package/favicon.svg +5 -0
- package/logo.svg +15 -5
- package/package.json +1 -1
- package/src/check.js +7 -138
- package/src/evaluator.js +10 -16
- package/src/interpreter.js +0 -7
- package/src/keywords.js +1 -2
package/README.md
CHANGED
@@ -1,82 +1,9 @@
|
|
1
|
-
# Fez
|
1
|
+
# Fez Programming Language
|
2
2
|
|
3
3
|
<p align="center">
|
4
|
-
<img width="
|
4
|
+
<img width="128" src="./logo.svg"/>
|
5
5
|
</p>
|
6
6
|
|
7
|
-
```lisp
|
8
|
-
; 3 types only
|
9
|
-
; Numbers
|
10
|
-
; Arrays
|
11
|
-
; Functions
|
12
|
-
(do 42 (array 1 2 3) (lambda x (* x x)))
|
13
|
-
; Variables are immutable
|
14
|
-
(let x 42)
|
15
|
-
; But array items are not
|
16
|
-
(let arr (array 1 2 3))
|
17
|
-
(set! arr 0 10)
|
18
|
-
(set! arr (length arr) 100)
|
19
|
-
; arr is now will make it [10 2 3 100]
|
20
|
-
; No strings - instead they are array of charcodes
|
21
|
-
"Hello World!" ; This is syntactic suggar turning it into the one below
|
22
|
-
(array 72 101 108 108 111 32 87 111 114 108 100 33) ; "Hello World!"
|
23
|
-
; multiline strings support (it just captures whole string and adds new lines within the arrays)
|
24
|
-
"Hello
|
25
|
-
World
|
26
|
-
!"
|
27
|
-
; No Objects Sets Lists Classes etc. Yet all implemented using the 3 types above
|
28
|
-
(let object (new:map
|
29
|
-
(array "id" 16
|
30
|
-
"power" (lambda x (* x x))
|
31
|
-
"backpack" (array 100 100 200 300)
|
32
|
-
"unique-set-of-things"
|
33
|
-
(new:set (array "10" "232" "42" "32")))))
|
34
|
-
(apply (map:get object "power") (map:get object "id")) ; 256
|
35
|
-
; There are many useful functions in the STD library
|
36
|
-
; They get "tree shacked" - final program has only the functions it needs
|
37
|
-
(math:permutations (array 1 2 3))
|
38
|
-
; Pipe operator is syntactic sugar for readable function composition
|
39
|
-
(|> (math:range 1 10) (array:map math:square) (math:summation))
|
40
|
-
```
|
41
|
-
|
42
|
-
```js
|
43
|
-
import { parse, evaluate } from 'fez-lisp'
|
44
|
-
evaluate(
|
45
|
-
parse(`(let *input* "1721,979,366,299,675,1456")
|
46
|
-
(let solve (lambda arr cb
|
47
|
-
(array:fold arr (lambda a b (do
|
48
|
-
(let res (array:binary-search arr (cb b)))
|
49
|
-
(if (truthy? res) (array:merge a (array res)) a)))
|
50
|
-
())))
|
51
|
-
(|> *input*
|
52
|
-
(string:commas)
|
53
|
-
(array:map (lambda d (|> d (from:chars->digits) (from:digits->integer))))
|
54
|
-
(array:sort (lambda a b (> a b)))
|
55
|
-
(solve (lambda x (- 2020 x)))
|
56
|
-
(math:product)
|
57
|
-
(log))`)
|
58
|
-
)
|
59
|
-
```
|
60
|
-
|
61
|
-
```lisp
|
62
|
-
; https://leetcode.com/problems/maximum-count-of-positive-integer-and-negative-integer/description/
|
63
|
-
(let max-count-of (lambda nums
|
64
|
-
(math:max
|
65
|
-
(array:count-of nums math:positive?)
|
66
|
-
(array:count-of nums math:negative?))))
|
67
|
-
|
68
|
-
(|>
|
69
|
-
(array -2 -1 -1 0 0 1 2)
|
70
|
-
(max-count-of)
|
71
|
-
(log!)) ; 3
|
72
|
-
```
|
73
|
-
|
74
|
-
Installation:
|
75
|
-
|
76
|
-
```
|
77
|
-
npm i fez-lisp
|
78
|
-
```
|
79
|
-
|
80
7
|
```lisp
|
81
8
|
(let fizz-buzz (lambda n
|
82
9
|
(cond
|
@@ -85,23 +12,28 @@ npm i fez-lisp
|
|
85
12
|
(= (mod n 5) 0) "Buzz"
|
86
13
|
(*) (from:integer->string n))))
|
87
14
|
|
88
|
-
(|> (math:range 1 100) (array:map fizz-buzz) (array:
|
15
|
+
(|> (math:range 1 100) (array:map fizz-buzz) (array:spaces) (string))
|
89
16
|
```
|
90
17
|
|
91
|
-
|
92
|
-
import { parse, compile } from 'fez-lisp'
|
93
|
-
console.log(compile(parse("(+ 1 2)")))
|
94
|
-
// '(()=>{;return(()=>{return (1+2);})()})()'
|
95
|
-
console.log(compile(parse("(math:power 2 4)")))
|
96
|
-
// (()=>{;return(()=>{var math_power;return (math_power=((base,exp)=>{return (+(exp<0)?(+(base===0)?[]:(1/(base*math_power(base,((exp*-1)-1))))):(+(exp===0)?1:(+(exp===1)?base:(1?(base*math_power(base,(exp-1))):0))));}),math_power(2,4));})()})()
|
97
|
-
console.log(compile(parse("(|> [1 2 3 4] (array:map math:square) (math:summation))")))
|
98
|
-
/* (()=>{var __tco=fn=>(...args)=>{let result=fn(...args);while(typeof result==='function')result=result();return result},length=(arr)=>arr.length,alter_effect=function(array,index,value){if(arguments.length===1){array.pop()}else{array[index] = value};return array},get=(arr,i)=>arr[i];
|
99
|
-
;return(()=>{var math_summation,math_square,array_map,array_fold;return (math_summation=((xs)=>{return array_fold(xs,((a,b)=>{return (a+b);}),0);}),math_square=((x)=>{return (x*x);}),array_map=((xs,callback)=>{var recursive_array_map,recursive_9271675;return ((recursive_array_map=(__tco(recursive_9271675=(i,out)=>{return (+(length(xs)>i)?()=>recursive_9271675((i+1),alter_effect(out,length(out),callback(get(xs, i)))):out);}, recursive_9271675))),recursive_array_map(0,[]));}),array_fold=((xs,callback,initial)=>{var recursive_array_fold,recursive_927729;return ((recursive_array_fold=(__tco(recursive_927729=(i,out)=>{return (+(length(xs)>i)?()=>recursive_927729((i+1),callback(out,get(xs, i))):out);}, recursive_927729))),recursive_array_fold(0,initial));}),math_summation(array_map([1,2,3,4],math_square)));})()})() * /
|
100
|
-
```
|
18
|
+
## [Try it in online editor](https://at-290690.github.io/fez/)
|
101
19
|
|
102
20
|
```lisp
|
103
|
-
; Build-in
|
21
|
+
; Build-in keywords
|
104
22
|
(/ ...) (+ ...) (* ...) (- ...) (= ...) (< ...) (> ...) (>= ...) (<= ...) (& ...) (~ ...) (| ...) (^ ...) (<< ...) (>> ...)
|
105
23
|
(mod ...) (let ...) (if ...) (not ...) (and ...) (or ...) (atom? ...) (lambda? ...)
|
106
24
|
(length ...) (do ...) (array ...) (set! ...) (pop! ...) (get ...) (lambda ...) (apply ...) (throw ...)
|
107
25
|
```
|
26
|
+
|
27
|
+
## ⚠️ Important: Do not use this programming language in production!
|
28
|
+
|
29
|
+
Here is how to install the compiler:
|
30
|
+
|
31
|
+
```
|
32
|
+
npm i fez-lisp
|
33
|
+
```
|
34
|
+
|
35
|
+
```js
|
36
|
+
import { parse, compile } from 'fez-lisp'
|
37
|
+
console.log(compile(parse('(+ 1 2)')))
|
38
|
+
// '(()=>{;return(()=>{return (1+2);})()})()'
|
39
|
+
```
|
package/favicon.svg
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<path d="M12.9624 3.54516C12.5818 1.96655 1.39379 2.36647 0.792468 3.54516C0.191149 4.72386 0.792468 15.7151 0.792468 15.7151L12.9624 15.7151C12.9624 15.7151 13.3431 5.12378 12.9624 3.54516Z" fill="#B44637"/>
|
3
|
+
<path d="M12.9624 3.54516C12.5818 1.96655 1.39379 2.36647 0.792468 3.54516C0.191149 4.72386 0.792468 15.7151 0.792468 15.7151L12.9624 15.7151C12.9624 15.7151 13.3431 5.12378 12.9624 3.54516Z" fill="#B44637"/>
|
4
|
+
<path d="M14.9574 10.9932C11.603 9.9267 16.5755 1.79352 10 1.97363" stroke="#F9B949" stroke-width="2" stroke-linecap="round"/>
|
5
|
+
</svg>
|
package/logo.svg
CHANGED
@@ -1,6 +1,16 @@
|
|
1
|
-
<svg width="
|
2
|
-
<path d="
|
3
|
-
<
|
4
|
-
<
|
5
|
-
<
|
1
|
+
<svg width="61" height="79" viewBox="0 0 61 79" fill="none" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<path d="M58.8257 55.7684C63.4688 62.5468 57.2431 75.2357 42.5 78C34.5 79.5 2.00013 79.4982 2 64.3957C1.99984 45.77 28.6339 50.3503 39.5543 55.7684C56.8985 61.3234 54.329 49.2038 58.8257 55.7684Z" fill="#F9B949"/>
|
3
|
+
<circle cx="25.5" cy="35.5" r="25.5" fill="#F9B949"/>
|
4
|
+
<circle cx="36.5" cy="31.5" r="2.5" fill="#1F1B1B"/>
|
5
|
+
<circle cx="9.5" cy="21.5" r="2.5" fill="#1F1B1B"/>
|
6
|
+
<circle cx="10" cy="21" r="1" fill="#EBEBEB"/>
|
7
|
+
<circle cx="10" cy="21" r="1" fill="#EBEBEB"/>
|
8
|
+
<circle cx="10" cy="21" r="1" fill="#EBEBEB"/>
|
9
|
+
<circle cx="37" cy="31" r="1" fill="#EBEBEB"/>
|
10
|
+
<circle cx="37" cy="31" r="1" fill="#EBEBEB"/>
|
11
|
+
<circle cx="37" cy="31" r="1" fill="#EBEBEB"/>
|
12
|
+
<path d="M11.6564 26.818C17.5013 31.4502 17.7946 23.2377 23.0134 28.6252C28.2321 34.0127 30.2289 37.3689 19.8597 35.7179C9.49045 34.0669 5.8115 22.1858 11.6564 26.818Z" fill="#B44637"/>
|
13
|
+
<path d="M49.8808 7.37404C50.5137 5.27388 40.491 0.514532 39.3766 1.22816C38.2623 1.94179 33.2308 11.7323 33.2308 11.7323L43.7349 17.8782C43.7349 17.8782 49.2479 9.47421 49.8808 7.37404Z" fill="#B44637"/>
|
14
|
+
<path d="M49.8808 7.37404C50.5137 5.27388 40.491 0.514532 39.3766 1.22816C38.2623 1.94179 33.2308 11.7323 33.2308 11.7323L43.7349 17.8782C43.7349 17.8782 49.2479 9.47421 49.8808 7.37404Z" fill="#B44637"/>
|
15
|
+
<path d="M51 15C46 13.5 54.6472 7.06417 48.8171 5" stroke="#F9B949" stroke-width="2" stroke-linecap="round"/>
|
6
16
|
</svg>
|
package/package.json
CHANGED
package/src/check.js
CHANGED
@@ -541,13 +541,6 @@ export const typeCheck = (ast) => {
|
|
541
541
|
}
|
542
542
|
const errorStack = new Set()
|
543
543
|
const warningStack = new Set()
|
544
|
-
|
545
|
-
// const isDefinitionOfAFunction = (head, tail) =>
|
546
|
-
// head[TYPE] === APPLY &&
|
547
|
-
// head[VALUE] === KEYWORDS.DEFINE_VARIABLE &&
|
548
|
-
// tail.at(-1)[0][TYPE] === APPLY &&
|
549
|
-
// tail.at(-1)[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
|
550
|
-
|
551
544
|
const stack = []
|
552
545
|
const check = (exp, env, scope) => {
|
553
546
|
const [first, ...rest] = isLeaf(exp) ? [exp] : exp
|
@@ -563,12 +556,6 @@ export const typeCheck = (ast) => {
|
|
563
556
|
if (env[first[VALUE]] === undefined) {
|
564
557
|
errorStack.add(
|
565
558
|
`Trying to access undefined variable ${first[VALUE]} (check #11)`
|
566
|
-
|
567
|
-
// `Trying to access undefined variable ${
|
568
|
-
// first[VALUE]
|
569
|
-
// }\n${formatCallstack(
|
570
|
-
// key.chain.filter((x) => isNaN(Number(x[0])))
|
571
|
-
// )}\n(check #11)`
|
572
559
|
)
|
573
560
|
}
|
574
561
|
})
|
@@ -598,67 +585,30 @@ export const typeCheck = (ast) => {
|
|
598
585
|
case KEYWORDS.IF:
|
599
586
|
{
|
600
587
|
const re = rem.slice(2)
|
601
|
-
// If either is an ATOM then IF returns an ATOM
|
602
588
|
if (re[0][TYPE] === ATOM || re[1][TYPE] === ATOM) {
|
603
589
|
env[name][STATS][prop][0] = ATOM
|
604
|
-
// if (
|
605
|
-
// re[0][VALUE] === FALSE ||
|
606
|
-
// re[0][VALUE] === TRUE ||
|
607
|
-
// re[1][VALUE] === FALSE ||
|
608
|
-
// re[1][VALUE] === TRUE
|
609
|
-
// ) {
|
610
|
-
// env[name][STATS][RETURNS][1] = PREDICATE
|
611
|
-
// }
|
612
590
|
} else if (!isLeaf(re[0]) && env[re[0][0][VALUE]]) {
|
613
|
-
// const concequent = isLeaf(re[0])
|
614
|
-
// ? env[re[0][VALUE]]
|
615
|
-
// : env[re[0][0][VALUE]]
|
616
|
-
// const alternative = isLeaf(re[1])
|
617
|
-
// ? env[re[1][VALUE]]
|
618
|
-
// : env[re[1][0][VALUE]]
|
619
591
|
env[name][STATS][prop] =
|
620
592
|
env[re[0][0][VALUE]][STATS][RETURNS]
|
621
593
|
if (
|
622
594
|
re[0][0][TYPE] === APPLY &&
|
623
|
-
// turn off typechecks for optimized functions
|
624
595
|
!name.startsWith(OPTIMIZED_PREFIX)
|
625
596
|
) {
|
626
597
|
switch (re[0][0][VALUE]) {
|
627
598
|
case KEYWORDS.ANONYMOUS_FUNCTION:
|
628
|
-
// env[name][STATS][prop] =
|
629
|
-
// env[re[0][0][VALUE]][STATS][RETURNS]
|
630
|
-
// env[name][STATS][SUB_TYPE] =
|
631
|
-
// env[re[0][0][VALUE]][STATS][SUB_TYPE]
|
632
|
-
|
633
599
|
env[name][STATS][RETURNS] = [UNKNOWN]
|
634
600
|
env[name][STATS][ARGS_COUNT] =
|
635
601
|
re[0].length - 2
|
636
|
-
// check(
|
637
|
-
// [
|
638
|
-
// [APPLY, KEYWORDS.DEFINE_VARIABLE],
|
639
|
-
// [WORD, name],
|
640
|
-
// re[0]
|
641
|
-
// ],
|
642
|
-
// env,
|
643
|
-
// scope
|
644
|
-
// )
|
645
602
|
break
|
646
603
|
}
|
647
604
|
}
|
648
605
|
// env[name][STATS] = env[re[0][0][VALUE]][STATS]
|
649
|
-
} else {
|
650
|
-
|
651
|
-
env[
|
652
|
-
|
653
|
-
env[
|
654
|
-
|
655
|
-
// env[name][STATS] = env[name][STATS]
|
656
|
-
// env[re[0][VALUE]][STATS][SUB_TYPE]
|
657
|
-
} else {
|
658
|
-
env[name][STATS][prop] = [UNKNOWN]
|
659
|
-
// env[name][STATS][RETURNS] = APPLY
|
660
|
-
}
|
661
|
-
}
|
606
|
+
} else if (env[re[0][VALUE]]) {
|
607
|
+
env[name][STATS][prop][0] =
|
608
|
+
env[re[0][VALUE]][STATS][TYPE_PROP][0]
|
609
|
+
env[name][STATS][RETURNS][1] =
|
610
|
+
env[re[0][VALUE]][STATS][RETURNS][1]
|
611
|
+
} else env[name][STATS][prop] = [UNKNOWN]
|
662
612
|
}
|
663
613
|
break
|
664
614
|
default:
|
@@ -690,9 +640,6 @@ export const typeCheck = (ast) => {
|
|
690
640
|
env[name][STATS][RETURNS][1] =
|
691
641
|
fn[STATS][RETURNS][1]
|
692
642
|
} else {
|
693
|
-
// const body = rest.at(-1).at(-1).at(-1).at(-1)
|
694
|
-
// const rem = hasBlock(body) ? body.at(-1) : body
|
695
|
-
// const returns = isLeaf(rem) ? rem : rem[0]
|
696
643
|
const [returns, rem] = drillReturnType(
|
697
644
|
rest.at(-1).at(-1).at(-1),
|
698
645
|
(returns) =>
|
@@ -1003,7 +950,6 @@ export const typeCheck = (ast) => {
|
|
1003
950
|
}
|
1004
951
|
}
|
1005
952
|
// TODO overwrite return type check here
|
1006
|
-
// console.log(copy[SCOPE_NAME], env[copy[SCOPE_NAME]], copy)
|
1007
953
|
}
|
1008
954
|
}
|
1009
955
|
}
|
@@ -1056,15 +1002,9 @@ export const typeCheck = (ast) => {
|
|
1056
1002
|
if (args) {
|
1057
1003
|
for (let i = 0; i < args.length; ++i) {
|
1058
1004
|
// type check
|
1059
|
-
// todo finish this
|
1060
|
-
|
1061
1005
|
if (args[i][SUB] != undefined) {
|
1062
|
-
// first[TYPE] === APPLY &&
|
1063
|
-
// env[first[VALUE]][STATS][SUB_TYPE] === PREDICATE
|
1064
|
-
// args[i][SUB] = env[rest[i][VALUE]][SUB_TYPE]
|
1065
1006
|
if (isLeaf(rest[i])) {
|
1066
1007
|
if (rest[i][TYPE] === WORD) {
|
1067
|
-
// TODO finish this
|
1068
1008
|
if (
|
1069
1009
|
env[rest[i][VALUE]] &&
|
1070
1010
|
args[i][SUB] !==
|
@@ -1308,17 +1248,6 @@ export const typeCheck = (ast) => {
|
|
1308
1248
|
}
|
1309
1249
|
}
|
1310
1250
|
break
|
1311
|
-
// case APPLY:
|
1312
|
-
// errorStack.add(
|
1313
|
-
// `Incorrect type of arguments for (${
|
1314
|
-
// first[VALUE]
|
1315
|
-
// }). Expected (${toTypeNames(
|
1316
|
-
// expectedArgs[i][TYPE]
|
1317
|
-
// )}) but got (${toTypeNames(
|
1318
|
-
// rest[i][TYPE]
|
1319
|
-
// )}) (${stringifyArgs(exp)}) (check #5)`
|
1320
|
-
// )
|
1321
|
-
// break
|
1322
1251
|
case ATOM: {
|
1323
1252
|
if (rest[i][TYPE] !== expectedArgs[i][TYPE]) {
|
1324
1253
|
errorStack.add(
|
@@ -1335,53 +1264,6 @@ export const typeCheck = (ast) => {
|
|
1335
1264
|
}
|
1336
1265
|
}
|
1337
1266
|
}
|
1338
|
-
// if (
|
1339
|
-
// env[rest[i][VALUE]] &&
|
1340
|
-
// expectedArgs[i][TYPE] !== rest[i][TYPE]
|
1341
|
-
// ) {
|
1342
|
-
// switch (rest[i][TYPE]) {
|
1343
|
-
// // case UNKNOWN:
|
1344
|
-
// // env[first[VALUE]][STATS][TYPE_PROP][0] =
|
1345
|
-
// // expectedArgs[i][TYPE]
|
1346
|
-
// // break
|
1347
|
-
// case WORD:
|
1348
|
-
// const T =
|
1349
|
-
// env[rest[i][VALUE]][STATS][TYPE_PROP][0]
|
1350
|
-
// if (
|
1351
|
-
// T !== UNKNOWN &&
|
1352
|
-
// expectedArgs[i][TYPE] !== UNKNOWN &&
|
1353
|
-
// expectedArgs[i][TYPE] !== T
|
1354
|
-
// ) {
|
1355
|
-
// errorStack.add(
|
1356
|
-
// `Incorrect type of argument (${i}) for special form (${
|
1357
|
-
// first[VALUE]
|
1358
|
-
// }). Expected (${toTypeNames(
|
1359
|
-
// expectedArgs[i][TYPE]
|
1360
|
-
// )}) but got (${toTypeNames(
|
1361
|
-
// T
|
1362
|
-
// )}) (${stringifyArgs(exp)}) (check #3.1)`
|
1363
|
-
// )
|
1364
|
-
// } else {
|
1365
|
-
// env[rest[i][VALUE]][STATS][TYPE_PROP][0] =
|
1366
|
-
// expectedArgs[i][TYPE]
|
1367
|
-
// }
|
1368
|
-
// break
|
1369
|
-
// case APPLY:
|
1370
|
-
// case ATOM:
|
1371
|
-
// errorStack.add(
|
1372
|
-
// `Incorrect type of arguments for (${
|
1373
|
-
// first[VALUE]
|
1374
|
-
// }). Expected (${toTypeNames(
|
1375
|
-
// expectedArgs[i][TYPE]
|
1376
|
-
// )}) but got (${toTypeNames(
|
1377
|
-
// rest[i][TYPE]
|
1378
|
-
// )}) (${stringifyArgs(exp)}) (check #5)`
|
1379
|
-
// )
|
1380
|
-
// break
|
1381
|
-
// }
|
1382
|
-
// } else {
|
1383
|
-
// // TIDI fugyre iyt wgat ti di gere
|
1384
|
-
// }
|
1385
1267
|
}
|
1386
1268
|
}
|
1387
1269
|
// type checking
|
@@ -1452,20 +1334,7 @@ export const typeCheck = (ast) => {
|
|
1452
1334
|
)}) (${stringifyArgs(exp)}) (check #4)`
|
1453
1335
|
)
|
1454
1336
|
}
|
1455
|
-
// TODO figure out
|
1456
|
-
// else {
|
1457
|
-
// if (
|
1458
|
-
// rest[i].length &&
|
1459
|
-
// env[rest[i][0][VALUE]] &&
|
1460
|
-
// args[i][STATS][TYPE_PROP][0] === UNKNOWN &&
|
1461
|
-
// env[rest[i][0][VALUE]][STATS].retried < RETRY_COUNT
|
1462
|
-
// ) {
|
1463
|
-
// env[rest[i][0][VALUE]][STATS].retried += 1
|
1464
|
-
// if (!scope[SCOPE_NAME])
|
1465
|
-
// scope[SCOPE_NAME] = scope[1][VALUE]
|
1466
|
-
// stack.unshift(() => check(exp, env, scope))
|
1467
|
-
// }
|
1468
|
-
// }
|
1337
|
+
// TODO figure out what cann we do in this else ?
|
1469
1338
|
}
|
1470
1339
|
}
|
1471
1340
|
}
|
package/src/evaluator.js
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
import { keywords } from './interpreter.js'
|
2
|
-
import {
|
3
|
-
APPLY,
|
4
|
-
ATOM,
|
5
|
-
DEBUG,
|
6
|
-
KEYWORDS,
|
7
|
-
SPECIAL_FORMS_SET,
|
8
|
-
TYPE,
|
9
|
-
VALUE,
|
10
|
-
WORD
|
11
|
-
} from './keywords.js'
|
2
|
+
import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './keywords.js'
|
12
3
|
import { isLeaf } from './parser.js'
|
13
4
|
import { stringifyArgs } from './utils.js'
|
14
5
|
export const evaluate = (exp, env = keywords) => {
|
@@ -23,23 +14,26 @@ export const evaluate = (exp, env = keywords) => {
|
|
23
14
|
case WORD: {
|
24
15
|
const word = env[value]
|
25
16
|
if (word == undefined)
|
26
|
-
throw new ReferenceError(
|
17
|
+
throw new ReferenceError(
|
18
|
+
`Undefined variable ${value} (${stringifyArgs(exp)})`
|
19
|
+
)
|
27
20
|
return word
|
28
21
|
}
|
29
22
|
case APPLY: {
|
30
23
|
const apply = env[value]
|
31
24
|
if (apply == undefined)
|
32
25
|
throw new ReferenceError(
|
33
|
-
`Undefined (${
|
26
|
+
`Undefined (${
|
27
|
+
KEYWORDS.ANONYMOUS_FUNCTION
|
28
|
+
}) (${value}) (${stringifyArgs(exp)})`
|
34
29
|
)
|
35
30
|
if (typeof apply !== 'function')
|
36
31
|
throw new TypeError(
|
37
|
-
`${value} is not a (${KEYWORDS.ANONYMOUS_FUNCTION})
|
32
|
+
`${value} is not a (${KEYWORDS.ANONYMOUS_FUNCTION}) (${stringifyArgs(
|
33
|
+
exp
|
34
|
+
)})`
|
38
35
|
)
|
39
|
-
const isSpecial = SPECIAL_FORMS_SET.has(value)
|
40
36
|
const result = apply(tail, env, value)
|
41
|
-
if (!isSpecial && Array.isArray(env[DEBUG.CALLSTACK]))
|
42
|
-
env[DEBUG.CALLSTACK].pop()
|
43
37
|
return result
|
44
38
|
}
|
45
39
|
case ATOM:
|
package/src/interpreter.js
CHANGED
@@ -7,7 +7,6 @@ import {
|
|
7
7
|
TRUE,
|
8
8
|
TYPES,
|
9
9
|
RUNTIME_TYPES,
|
10
|
-
DEBUG,
|
11
10
|
STATIC_TYPES
|
12
11
|
} from './keywords.js'
|
13
12
|
import { evaluate } from './evaluator.js'
|
@@ -755,12 +754,6 @@ export const keywords = {
|
|
755
754
|
const value = evaluate(props[i], scope)
|
756
755
|
localEnv[params[i][VALUE]] = value
|
757
756
|
}
|
758
|
-
if (
|
759
|
-
name &&
|
760
|
-
Array.isArray(env[DEBUG.CALLSTACK]) &&
|
761
|
-
name !== env[DEBUG.CALLSTACK].at(-1)
|
762
|
-
)
|
763
|
-
env[DEBUG.CALLSTACK].push(name)
|
764
757
|
return evaluate(body, localEnv)
|
765
758
|
}
|
766
759
|
},
|
package/src/keywords.js
CHANGED
@@ -69,8 +69,7 @@ export const DEBUG = {
|
|
69
69
|
ASSERT: 'assert',
|
70
70
|
SIGNATURE: '?',
|
71
71
|
LIST_THEMES: 'theme?',
|
72
|
-
SET_THEME: 'theme!'
|
73
|
-
CALLSTACK: '(CALLSTACK)' // so that you can't use it in the code
|
72
|
+
SET_THEME: 'theme!'
|
74
73
|
}
|
75
74
|
|
76
75
|
export const SPECIAL_FORMS_SET = new Set(Object.values(KEYWORDS))
|