fez-lisp 1.5.83 → 1.5.85
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/index.js +2 -1
- package/lib/baked/std.js +1 -1
- package/package.json +1 -1
- package/src/check.js +88 -402
- package/src/compiler.js +0 -1
- package/src/enchance.js +231 -0
- package/src/macros.js +0 -202
- package/src/utils.js +2 -2
package/src/compiler.js
CHANGED
package/src/enchance.js
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
import { AST, isLeaf } from './parser.js'
|
2
|
+
import {
|
3
|
+
APPLY,
|
4
|
+
ATOM,
|
5
|
+
KEYWORDS,
|
6
|
+
PREDICATE_SUFFIX,
|
7
|
+
TYPE,
|
8
|
+
VALUE,
|
9
|
+
WORD
|
10
|
+
} from './keywords.js'
|
11
|
+
import { getSuffix, shake, wrapInBlock } from './utils.js'
|
12
|
+
import std from '../lib/baked/std.js'
|
13
|
+
export const OPTIMIZATIONS = {
|
14
|
+
RECURSION: 'recursive',
|
15
|
+
CACHE: 'memoized'
|
16
|
+
}
|
17
|
+
export const OPTIMIZED_PREFIX = 'optimized-lambda::'
|
18
|
+
const deepTransform = (predicate, transform, tree) => {
|
19
|
+
if (!isLeaf(tree))
|
20
|
+
for (const leaf of tree) {
|
21
|
+
// Figure out a non mutable solution so
|
22
|
+
// I can get rid of deep clone AST.parse(AST.stringify(ast))
|
23
|
+
if (predicate(leaf)) transform(leaf)
|
24
|
+
else deepTransform(predicate, transform, leaf)
|
25
|
+
}
|
26
|
+
}
|
27
|
+
export const enhance = (ast) => {
|
28
|
+
const evaluate = (exp) => {
|
29
|
+
const [first, ...rest] = isLeaf(exp) ? [exp] : exp
|
30
|
+
if (first != undefined) {
|
31
|
+
switch (first[TYPE]) {
|
32
|
+
case WORD:
|
33
|
+
break
|
34
|
+
case ATOM:
|
35
|
+
break
|
36
|
+
case APPLY:
|
37
|
+
{
|
38
|
+
switch (first[VALUE]) {
|
39
|
+
case KEYWORDS.DEFINE_VARIABLE:
|
40
|
+
{
|
41
|
+
const last = exp.at(-1)
|
42
|
+
if (
|
43
|
+
!isLeaf(last) &&
|
44
|
+
Array.isArray(last) &&
|
45
|
+
last[0] &&
|
46
|
+
last[0][TYPE] === APPLY &&
|
47
|
+
last[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
|
48
|
+
) {
|
49
|
+
const name = exp[1][VALUE]
|
50
|
+
const prefix = name.split(':')[0]
|
51
|
+
if (prefix === OPTIMIZATIONS.RECURSION) {
|
52
|
+
const args = last.slice(1, -1)
|
53
|
+
const newName = `${OPTIMIZED_PREFIX}${name}::*${performance
|
54
|
+
.now()
|
55
|
+
.toString()
|
56
|
+
.replace('.', 0)}*`
|
57
|
+
deepTransform(
|
58
|
+
(leaf) =>
|
59
|
+
Array.isArray(leaf) &&
|
60
|
+
leaf[0] &&
|
61
|
+
leaf[0][TYPE] === APPLY &&
|
62
|
+
leaf[0][VALUE] === name,
|
63
|
+
(leaf) => {
|
64
|
+
const copy = [...leaf]
|
65
|
+
leaf.length = 0
|
66
|
+
copy[0][VALUE] = newName
|
67
|
+
leaf.push([APPLY, KEYWORDS.ANONYMOUS_FUNCTION], copy)
|
68
|
+
},
|
69
|
+
last
|
70
|
+
)
|
71
|
+
|
72
|
+
exp[exp.length - 1] = [
|
73
|
+
[APPLY, KEYWORDS.CALL_FUNCTION],
|
74
|
+
[
|
75
|
+
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
76
|
+
[
|
77
|
+
[APPLY, KEYWORDS.BLOCK],
|
78
|
+
[
|
79
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
80
|
+
[WORD, newName],
|
81
|
+
last
|
82
|
+
],
|
83
|
+
[
|
84
|
+
[APPLY, KEYWORDS.CALL_FUNCTION],
|
85
|
+
[WORD, newName],
|
86
|
+
[
|
87
|
+
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
88
|
+
[WORD, '*fn*'],
|
89
|
+
[
|
90
|
+
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
91
|
+
...args,
|
92
|
+
[
|
93
|
+
[APPLY, KEYWORDS.BLOCK],
|
94
|
+
[
|
95
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
96
|
+
[WORD, '*res*'],
|
97
|
+
[
|
98
|
+
[APPLY, KEYWORDS.CREATE_ARRAY],
|
99
|
+
[[APPLY, '*fn*'], ...args]
|
100
|
+
]
|
101
|
+
],
|
102
|
+
[
|
103
|
+
[APPLY, KEYWORDS.LOOP],
|
104
|
+
[
|
105
|
+
[APPLY, KEYWORDS.IS_LAMBDA],
|
106
|
+
[
|
107
|
+
[APPLY, KEYWORDS.GET_ARRAY],
|
108
|
+
[WORD, '*res*'],
|
109
|
+
[ATOM, 0]
|
110
|
+
]
|
111
|
+
],
|
112
|
+
[
|
113
|
+
[APPLY, KEYWORDS.SET_ARRAY],
|
114
|
+
[WORD, '*res*'],
|
115
|
+
[ATOM, 0],
|
116
|
+
[
|
117
|
+
[APPLY, KEYWORDS.CALL_FUNCTION],
|
118
|
+
[
|
119
|
+
[APPLY, KEYWORDS.GET_ARRAY],
|
120
|
+
[WORD, '*res*'],
|
121
|
+
[ATOM, 0]
|
122
|
+
]
|
123
|
+
]
|
124
|
+
]
|
125
|
+
],
|
126
|
+
[
|
127
|
+
[APPLY, KEYWORDS.GET_ARRAY],
|
128
|
+
[WORD, '*res*'],
|
129
|
+
[ATOM, 0]
|
130
|
+
]
|
131
|
+
]
|
132
|
+
]
|
133
|
+
]
|
134
|
+
]
|
135
|
+
]
|
136
|
+
]
|
137
|
+
]
|
138
|
+
|
139
|
+
evaluate(exp[exp.length - 1])
|
140
|
+
} else if (prefix === OPTIMIZATIONS.CACHE) {
|
141
|
+
const args = last.slice(1, -1)
|
142
|
+
const newName = `${OPTIMIZED_PREFIX}${name}::*${performance
|
143
|
+
.now()
|
144
|
+
.toString()
|
145
|
+
.replace('.', 0)}*`
|
146
|
+
deepTransform(
|
147
|
+
(leaf) =>
|
148
|
+
Array.isArray(leaf) &&
|
149
|
+
leaf[0] &&
|
150
|
+
leaf[0][TYPE] === APPLY &&
|
151
|
+
leaf[0][VALUE] === name,
|
152
|
+
(leaf) => (leaf[0][VALUE] = newName),
|
153
|
+
last
|
154
|
+
)
|
155
|
+
const memoName = newName + ':memo'
|
156
|
+
const keyName = newName + ':key'
|
157
|
+
|
158
|
+
exp[exp.length - 1] = [
|
159
|
+
[APPLY, KEYWORDS.CALL_FUNCTION],
|
160
|
+
[
|
161
|
+
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
162
|
+
[
|
163
|
+
[APPLY, KEYWORDS.BLOCK],
|
164
|
+
[
|
165
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
166
|
+
[WORD, memoName],
|
167
|
+
[[APPLY, 'new:map64']]
|
168
|
+
],
|
169
|
+
[
|
170
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
171
|
+
[WORD, newName],
|
172
|
+
[
|
173
|
+
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
174
|
+
...args,
|
175
|
+
[
|
176
|
+
[APPLY, KEYWORDS.BLOCK],
|
177
|
+
[
|
178
|
+
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
179
|
+
[WORD, keyName],
|
180
|
+
[
|
181
|
+
[APPLY, 'from:string-or-number->key'],
|
182
|
+
[[APPLY, KEYWORDS.CREATE_ARRAY], ...args]
|
183
|
+
]
|
184
|
+
],
|
185
|
+
[
|
186
|
+
[APPLY, KEYWORDS.IF],
|
187
|
+
[
|
188
|
+
[APPLY, 'map:exists?'],
|
189
|
+
[WORD, memoName],
|
190
|
+
[WORD, keyName]
|
191
|
+
],
|
192
|
+
[
|
193
|
+
[APPLY, 'map:get'],
|
194
|
+
[WORD, memoName],
|
195
|
+
[WORD, keyName]
|
196
|
+
],
|
197
|
+
[
|
198
|
+
[APPLY, 'map:set-and-get!'],
|
199
|
+
[WORD, memoName],
|
200
|
+
[WORD, keyName],
|
201
|
+
last.at(-1)
|
202
|
+
]
|
203
|
+
]
|
204
|
+
]
|
205
|
+
]
|
206
|
+
],
|
207
|
+
[WORD, newName]
|
208
|
+
]
|
209
|
+
]
|
210
|
+
]
|
211
|
+
evaluate(exp[exp.length - 1])
|
212
|
+
}
|
213
|
+
}
|
214
|
+
}
|
215
|
+
break
|
216
|
+
default:
|
217
|
+
break
|
218
|
+
}
|
219
|
+
}
|
220
|
+
break
|
221
|
+
default:
|
222
|
+
break
|
223
|
+
}
|
224
|
+
|
225
|
+
for (const r of rest) evaluate(r)
|
226
|
+
}
|
227
|
+
}
|
228
|
+
evaluate(AST.parse(AST.stringify(ast)))
|
229
|
+
const shaked = shake(ast[1][1].slice(1), std)
|
230
|
+
return wrapInBlock(shaked)
|
231
|
+
}
|
package/src/macros.js
CHANGED
@@ -30,20 +30,6 @@ export const SUGGAR = {
|
|
30
30
|
INTEGER_DEVISION: '//',
|
31
31
|
CONDITION: 'cond'
|
32
32
|
}
|
33
|
-
export const OPTIMIZATIONS = {
|
34
|
-
RECURSION: 'recursive',
|
35
|
-
CACHE: 'memoized'
|
36
|
-
}
|
37
|
-
export const OPTIMIZED_PREFIX = 'optimized-lambda::'
|
38
|
-
const deepTransform = (predicate, transform, tree) => {
|
39
|
-
if (!isLeaf(tree))
|
40
|
-
for (const leaf of tree) {
|
41
|
-
// Figure out a non mutable solution so
|
42
|
-
// I can get rid of deep clone AST.parse(AST.stringify(ast))
|
43
|
-
if (predicate(leaf)) transform(leaf)
|
44
|
-
else deepTransform(predicate, transform, leaf)
|
45
|
-
}
|
46
|
-
}
|
47
33
|
export const deSuggarAst = (ast, scope) => {
|
48
34
|
if (scope === undefined) scope = ast
|
49
35
|
if (ast.length === 0) throw new SyntaxError(`No expressions...`)
|
@@ -514,194 +500,6 @@ export const deSuggarAst = (ast, scope) => {
|
|
514
500
|
exp.iron = true
|
515
501
|
exp.push(newScope)
|
516
502
|
deSuggarAst(scope)
|
517
|
-
} else if (
|
518
|
-
!isLeaf(last) &&
|
519
|
-
Array.isArray(last) &&
|
520
|
-
last[0] &&
|
521
|
-
last[0][TYPE] === APPLY &&
|
522
|
-
last[0][VALUE] === KEYWORDS.ANONYMOUS_FUNCTION
|
523
|
-
) {
|
524
|
-
const name = exp[1][VALUE]
|
525
|
-
const prefix = name.split(':')[0]
|
526
|
-
if (prefix === OPTIMIZATIONS.RECURSION) {
|
527
|
-
if (getSuffix(name) === PREDICATE_SUFFIX) {
|
528
|
-
throw new TypeError(
|
529
|
-
`Optimized (lambda) ${name} can't be a (Predicate) as it will return a (lambda). Remove the (${PREDICATE_SUFFIX}) from the name`
|
530
|
-
)
|
531
|
-
}
|
532
|
-
const args = last.slice(1, -1)
|
533
|
-
const newName = `${OPTIMIZED_PREFIX}${name}::*${performance
|
534
|
-
.now()
|
535
|
-
.toString()
|
536
|
-
.replace('.', 0)}*`
|
537
|
-
deepTransform(
|
538
|
-
(leaf) =>
|
539
|
-
Array.isArray(leaf) &&
|
540
|
-
leaf[0] &&
|
541
|
-
leaf[0][TYPE] === APPLY &&
|
542
|
-
leaf[0][VALUE] === name,
|
543
|
-
(leaf) => {
|
544
|
-
const copy = [...leaf]
|
545
|
-
leaf.length = 0
|
546
|
-
copy[0][VALUE] = newName
|
547
|
-
leaf.push([APPLY, KEYWORDS.ANONYMOUS_FUNCTION], copy)
|
548
|
-
},
|
549
|
-
last
|
550
|
-
)
|
551
|
-
|
552
|
-
exp[exp.length - 1] = [
|
553
|
-
[APPLY, KEYWORDS.CALL_FUNCTION],
|
554
|
-
[
|
555
|
-
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
556
|
-
[
|
557
|
-
[APPLY, KEYWORDS.BLOCK],
|
558
|
-
[
|
559
|
-
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
560
|
-
[WORD, newName],
|
561
|
-
last
|
562
|
-
],
|
563
|
-
args.length < 5
|
564
|
-
? [
|
565
|
-
[
|
566
|
-
APPLY,
|
567
|
-
`optimization:tail-calls-${args.length}`
|
568
|
-
],
|
569
|
-
[WORD, newName]
|
570
|
-
]
|
571
|
-
: [
|
572
|
-
[APPLY, KEYWORDS.CALL_FUNCTION],
|
573
|
-
[WORD, newName],
|
574
|
-
[
|
575
|
-
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
576
|
-
[WORD, '*fn*'],
|
577
|
-
[
|
578
|
-
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
579
|
-
...args,
|
580
|
-
[
|
581
|
-
[APPLY, KEYWORDS.BLOCK],
|
582
|
-
[
|
583
|
-
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
584
|
-
[WORD, '*res*'],
|
585
|
-
[
|
586
|
-
[APPLY, KEYWORDS.CREATE_ARRAY],
|
587
|
-
[[APPLY, '*fn*'], ...args]
|
588
|
-
]
|
589
|
-
],
|
590
|
-
[
|
591
|
-
[APPLY, KEYWORDS.LOOP],
|
592
|
-
[
|
593
|
-
[APPLY, KEYWORDS.IS_LAMBDA],
|
594
|
-
[
|
595
|
-
[APPLY, KEYWORDS.GET_ARRAY],
|
596
|
-
[WORD, '*res*'],
|
597
|
-
[ATOM, 0]
|
598
|
-
]
|
599
|
-
],
|
600
|
-
[
|
601
|
-
[APPLY, KEYWORDS.SET_ARRAY],
|
602
|
-
[WORD, '*res*'],
|
603
|
-
[ATOM, 0],
|
604
|
-
[
|
605
|
-
[APPLY, KEYWORDS.CALL_FUNCTION],
|
606
|
-
[
|
607
|
-
[APPLY, KEYWORDS.GET_ARRAY],
|
608
|
-
[WORD, '*res*'],
|
609
|
-
[ATOM, 0]
|
610
|
-
]
|
611
|
-
]
|
612
|
-
]
|
613
|
-
],
|
614
|
-
[
|
615
|
-
[APPLY, KEYWORDS.GET_ARRAY],
|
616
|
-
[WORD, '*res*'],
|
617
|
-
[ATOM, 0]
|
618
|
-
]
|
619
|
-
]
|
620
|
-
]
|
621
|
-
]
|
622
|
-
]
|
623
|
-
]
|
624
|
-
]
|
625
|
-
]
|
626
|
-
deSuggarAst(exp[exp.length - 1])
|
627
|
-
} else if (prefix === OPTIMIZATIONS.CACHE) {
|
628
|
-
if (getSuffix(name) === PREDICATE_SUFFIX) {
|
629
|
-
throw new TypeError(
|
630
|
-
`Optimized (lambda) ${name} can't be a (Predicate) as it will return a (lambda). Remove the (${PREDICATE_SUFFIX}) from the name`
|
631
|
-
)
|
632
|
-
}
|
633
|
-
const args = last.slice(1, -1)
|
634
|
-
const newName = `${OPTIMIZED_PREFIX}${name}::*${performance
|
635
|
-
.now()
|
636
|
-
.toString()
|
637
|
-
.replace('.', 0)}*`
|
638
|
-
deepTransform(
|
639
|
-
(leaf) =>
|
640
|
-
Array.isArray(leaf) &&
|
641
|
-
leaf[0] &&
|
642
|
-
leaf[0][TYPE] === APPLY &&
|
643
|
-
leaf[0][VALUE] === name,
|
644
|
-
(leaf) => (leaf[0][VALUE] = newName),
|
645
|
-
last
|
646
|
-
)
|
647
|
-
const memoName = newName + ':memo'
|
648
|
-
const keyName = newName + ':key'
|
649
|
-
|
650
|
-
exp[exp.length - 1] = [
|
651
|
-
[APPLY, KEYWORDS.CALL_FUNCTION],
|
652
|
-
[
|
653
|
-
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
654
|
-
[
|
655
|
-
[APPLY, KEYWORDS.BLOCK],
|
656
|
-
[
|
657
|
-
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
658
|
-
[WORD, memoName],
|
659
|
-
[[APPLY, 'new:map64']]
|
660
|
-
],
|
661
|
-
[
|
662
|
-
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
663
|
-
[WORD, newName],
|
664
|
-
[
|
665
|
-
[APPLY, KEYWORDS.ANONYMOUS_FUNCTION],
|
666
|
-
...args,
|
667
|
-
[
|
668
|
-
[APPLY, KEYWORDS.BLOCK],
|
669
|
-
[
|
670
|
-
[APPLY, KEYWORDS.DEFINE_VARIABLE],
|
671
|
-
[WORD, keyName],
|
672
|
-
[
|
673
|
-
[APPLY, 'from:string-or-number->key'],
|
674
|
-
[[APPLY, KEYWORDS.CREATE_ARRAY], ...args]
|
675
|
-
]
|
676
|
-
],
|
677
|
-
[
|
678
|
-
[APPLY, KEYWORDS.IF],
|
679
|
-
[
|
680
|
-
[APPLY, 'map:exists?'],
|
681
|
-
[WORD, memoName],
|
682
|
-
[WORD, keyName]
|
683
|
-
],
|
684
|
-
[
|
685
|
-
[APPLY, 'map:get'],
|
686
|
-
[WORD, memoName],
|
687
|
-
[WORD, keyName]
|
688
|
-
],
|
689
|
-
[
|
690
|
-
[APPLY, 'map:set-and-get!'],
|
691
|
-
[WORD, memoName],
|
692
|
-
[WORD, keyName],
|
693
|
-
last.at(-1)
|
694
|
-
]
|
695
|
-
]
|
696
|
-
]
|
697
|
-
]
|
698
|
-
],
|
699
|
-
[WORD, newName]
|
700
|
-
]
|
701
|
-
]
|
702
|
-
]
|
703
|
-
deSuggarAst(exp[exp.length - 1])
|
704
|
-
}
|
705
503
|
}
|
706
504
|
}
|
707
505
|
break
|
package/src/utils.js
CHANGED
@@ -13,9 +13,9 @@ import { isLeaf, LISP } from './parser.js'
|
|
13
13
|
import {
|
14
14
|
deSuggarAst,
|
15
15
|
deSuggarSource,
|
16
|
-
handleUnbalancedQuotes
|
17
|
-
OPTIMIZATIONS
|
16
|
+
handleUnbalancedQuotes
|
18
17
|
} from './macros.js'
|
18
|
+
import { OPTIMIZATIONS } from './enchance.js'
|
19
19
|
export const logError = (error) =>
|
20
20
|
console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
|
21
21
|
export const logSuccess = (output) => console.log('\x1b[32m', output, '\x1b[0m')
|