fez-lisp 1.6.26 → 1.6.28
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 -2
- package/lib/baked/std.js +1 -1
- package/package.json +1 -1
- package/src/debugger.js +165 -0
- package/src/keywords.js +1 -0
- package/src/types.js +36 -9
- package/src/utils.js +41 -2
package/package.json
CHANGED
package/src/debugger.js
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
import { serialise } from '../editor/utils.js'
|
2
|
+
import {
|
3
|
+
APPLY,
|
4
|
+
ATOM,
|
5
|
+
KEYWORDS,
|
6
|
+
TYPE,
|
7
|
+
VALUE,
|
8
|
+
WORD,
|
9
|
+
TRUE,
|
10
|
+
FALSE,
|
11
|
+
STATIC_TYPES
|
12
|
+
} from './keywords.js'
|
13
|
+
import { isLeaf, LISP } from './parser.js'
|
14
|
+
const keywords = {
|
15
|
+
[KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) =>
|
16
|
+
evaluate(args[0], env) % evaluate(args[1], env),
|
17
|
+
[KEYWORDS.DIVISION]: (args, env) =>
|
18
|
+
evaluate(args[0], env) / evaluate(args[1], env),
|
19
|
+
[KEYWORDS.ARRAY_LENGTH]: (args, env) => evaluate(args[0], env).length,
|
20
|
+
[KEYWORDS.IS_ATOM]: (args, env) =>
|
21
|
+
+(typeof evaluate(args[0], env) === 'number'),
|
22
|
+
[KEYWORDS.IS_LAMBDA]: (args, env) =>
|
23
|
+
+(typeof evaluate(args[0], env) === 'function'),
|
24
|
+
[KEYWORDS.ADDITION]: (args, env) =>
|
25
|
+
evaluate(args[0], env) + evaluate(args[1], env),
|
26
|
+
[KEYWORDS.MULTIPLICATION]: (args, env) =>
|
27
|
+
evaluate(args[0], env) * evaluate(args[1], env),
|
28
|
+
[KEYWORDS.SUBTRACTION]: (args, env) =>
|
29
|
+
evaluate(args[0], env) - evaluate(args[1], env),
|
30
|
+
[KEYWORDS.CREATE_ARRAY]: (args, env) =>
|
31
|
+
args.length ? args.map((x) => evaluate(x, env)) : [],
|
32
|
+
[KEYWORDS.GET_ARRAY]: (args, env) =>
|
33
|
+
evaluate(args[0], env)[evaluate(args[1], env)],
|
34
|
+
[KEYWORDS.BLOCK]: (args, env) =>
|
35
|
+
args.reduce((_, x) => evaluate(x, env), FALSE),
|
36
|
+
[KEYWORDS.NOT]: (args, env) => +!evaluate(args[0], env),
|
37
|
+
[KEYWORDS.EQUAL]: (args, env) =>
|
38
|
+
+(evaluate(args[0], env) === evaluate(args[1], env)),
|
39
|
+
[KEYWORDS.LESS_THAN]: (args, env) =>
|
40
|
+
+(evaluate(args[0], env) < evaluate(args[1], env)),
|
41
|
+
[KEYWORDS.GREATHER_THAN]: (args, env) =>
|
42
|
+
+(evaluate(args[0], env) > evaluate(args[1], env)),
|
43
|
+
[KEYWORDS.GREATHER_THAN_OR_EQUAL]: (args, env) =>
|
44
|
+
+(evaluate(args[0], env) >= evaluate(args[1], env)),
|
45
|
+
[KEYWORDS.LESS_THAN_OR_EQUAL]: (args, env) =>
|
46
|
+
+(evaluate(args[0], env) <= evaluate(args[1], env)),
|
47
|
+
[KEYWORDS.AND]: (args, env) =>
|
48
|
+
!evaluate(args[0], env) ? FALSE : evaluate(args[1], env),
|
49
|
+
[KEYWORDS.OR]: (args, env) =>
|
50
|
+
evaluate(args[0], env) ? TRUE : evaluate(args[1], env),
|
51
|
+
[KEYWORDS.CALL_FUNCTION]: (args, env) => evaluate(args.pop(), env)(args, env),
|
52
|
+
[KEYWORDS.DEFINE_VARIABLE]: (args, env) =>
|
53
|
+
(env[args[0][VALUE]] = evaluate(args[1], env)),
|
54
|
+
[KEYWORDS.BITWISE_AND]: (args, env) =>
|
55
|
+
evaluate(args[0], env) & evaluate(args[1], env),
|
56
|
+
[KEYWORDS.BITWISE_NOT]: (args, env) => ~evaluate(args[0], env),
|
57
|
+
[KEYWORDS.BITWISE_OR]: (args, env) =>
|
58
|
+
evaluate(args[0], env) | evaluate(args[1], env),
|
59
|
+
[KEYWORDS.BITWISE_XOR]: (args, env) =>
|
60
|
+
evaluate(args[0], env) ^ evaluate(args[1], env),
|
61
|
+
[KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) =>
|
62
|
+
evaluate(args[0], env) << evaluate(args[1], env),
|
63
|
+
[KEYWORDS.BITWISE_RIGHT_SHIFT]: (args, env) =>
|
64
|
+
evaluate(args[0], env) >> evaluate(args[1], env),
|
65
|
+
[KEYWORDS.IF]: (args, env) =>
|
66
|
+
evaluate(args[0], env) ? evaluate(args[1], env) : evaluate(args[2], env),
|
67
|
+
[KEYWORDS.LOOP]: (args, env) => {
|
68
|
+
while (evaluate(args[0], env) === TRUE) evaluate(args[1], env)
|
69
|
+
return -1
|
70
|
+
},
|
71
|
+
[KEYWORDS.SET_ARRAY]: (args, env) => {
|
72
|
+
const array = evaluate(args[0], env)
|
73
|
+
array[evaluate(args[1], env)] = evaluate(args[2], env)
|
74
|
+
return array
|
75
|
+
},
|
76
|
+
[KEYWORDS.POP_ARRAY]: (args, env) => {
|
77
|
+
const array = evaluate(args[0], env)
|
78
|
+
array.pop()
|
79
|
+
return array
|
80
|
+
},
|
81
|
+
[KEYWORDS.ANONYMOUS_FUNCTION]: (args, env) => {
|
82
|
+
const params = args.slice(0, -1)
|
83
|
+
return (props = [], scope) => {
|
84
|
+
const localEnv = Object.create(env)
|
85
|
+
for (let i = 0; i < props.length; ++i)
|
86
|
+
localEnv[params[i][VALUE]] = evaluate(props[i], scope)
|
87
|
+
return evaluate(args.at(-1), localEnv)
|
88
|
+
}
|
89
|
+
},
|
90
|
+
// Only for type checking
|
91
|
+
[STATIC_TYPES.UNKNOWN]: (args, env) => evaluate(args[0], env),
|
92
|
+
[STATIC_TYPES.ANY]: (args, env) => evaluate(args[0], env),
|
93
|
+
|
94
|
+
[STATIC_TYPES.ATOM]: (args, env) => evaluate(args[0], env),
|
95
|
+
[STATIC_TYPES.ABSTRACTION]: (args, env) => evaluate(args[0], env),
|
96
|
+
[STATIC_TYPES.COLLECTION]: (args, env) => evaluate(args[0], env),
|
97
|
+
|
98
|
+
[STATIC_TYPES.BOOLEAN]: (args, env) => evaluate(args[0], env),
|
99
|
+
[STATIC_TYPES.NUMBER]: (args, env) => evaluate(args[0], env),
|
100
|
+
[STATIC_TYPES.NUMBERS]: (args, env) => evaluate(args[0], env),
|
101
|
+
[STATIC_TYPES.COLLECTIONS]: (args, env) => evaluate(args[0], env),
|
102
|
+
[STATIC_TYPES.ABSTRACTIONS]: (args, env) => evaluate(args[0], env),
|
103
|
+
[STATIC_TYPES.BOOLEANS]: (args, env) => evaluate(args[0], env)
|
104
|
+
}
|
105
|
+
const debugStack = []
|
106
|
+
const evaluate = (exp, env = keywords) => {
|
107
|
+
const [head, ...tail] = isLeaf(exp) ? [exp] : exp
|
108
|
+
if (head == undefined) return []
|
109
|
+
const type = head[TYPE]
|
110
|
+
const value = head[VALUE]
|
111
|
+
let res
|
112
|
+
switch (type) {
|
113
|
+
case WORD:
|
114
|
+
res = env[value]
|
115
|
+
return res
|
116
|
+
case APPLY:
|
117
|
+
res = env[value](tail, env)
|
118
|
+
if (
|
119
|
+
value !== KEYWORDS.BLOCK &&
|
120
|
+
value !== KEYWORDS.CALL_FUNCTION &&
|
121
|
+
value !== KEYWORDS.ANONYMOUS_FUNCTION &&
|
122
|
+
value !== KEYWORDS.DEFINE_VARIABLE
|
123
|
+
) {
|
124
|
+
// debugStack.push(
|
125
|
+
// `\x1b[31m${LISP.source(exp)}\x1b[32m\n${
|
126
|
+
// typeof res === 'function' ? '(lambda)' : serialise(res)
|
127
|
+
// }\x1b[0m`
|
128
|
+
// )
|
129
|
+
const out = typeof res === 'function' ? '(lambda)' : serialise(res)
|
130
|
+
if (debugStack.at(-1)?.result !== out)
|
131
|
+
debugStack.push({
|
132
|
+
function: value,
|
133
|
+
source: LISP.source(exp),
|
134
|
+
result: out
|
135
|
+
})
|
136
|
+
// else debugStack[debugStack.length - 1].src += LISP.source(exp)
|
137
|
+
}
|
138
|
+
return res
|
139
|
+
case ATOM:
|
140
|
+
res = value
|
141
|
+
return res
|
142
|
+
}
|
143
|
+
}
|
144
|
+
export const debugStackToString = (stack) =>
|
145
|
+
stack.map(({ source, result }) => `${source}\n${result}`).join('\n')
|
146
|
+
export const startDebug = (ast, speed = 250, start, end) => {
|
147
|
+
debugStack.length = 0
|
148
|
+
evaluate(ast)
|
149
|
+
start = start ? debugStack.findIndex(start) : 0
|
150
|
+
end = end ? debugStack.findIndex(end) : debugStack.length
|
151
|
+
const stack = debugStack.slice(start, end).reverse()
|
152
|
+
if (speed !== 0) {
|
153
|
+
const rec = () => {
|
154
|
+
setTimeout(() => {
|
155
|
+
if (stack.length) {
|
156
|
+
const { source, result } = stack.pop()
|
157
|
+
console.log(`\x1b[31m${source}\x1b[32m\n${result}\x1b[0m`)
|
158
|
+
rec()
|
159
|
+
}
|
160
|
+
}, speed)
|
161
|
+
}
|
162
|
+
rec()
|
163
|
+
}
|
164
|
+
return stack
|
165
|
+
}
|
package/src/keywords.js
CHANGED
package/src/types.js
CHANGED
@@ -5,11 +5,13 @@ import {
|
|
5
5
|
APPLY,
|
6
6
|
ATOM,
|
7
7
|
DEBUG,
|
8
|
+
FLAG,
|
8
9
|
KEYWORDS,
|
9
10
|
PLACEHOLDER,
|
10
11
|
STATIC_TYPES,
|
11
12
|
TYPE,
|
12
|
-
VALUE
|
13
|
+
VALUE,
|
14
|
+
WORD
|
13
15
|
} from './keywords.js'
|
14
16
|
import { isLeaf } from './parser.js'
|
15
17
|
import { shakedList, stringifyArgs } from './utils.js'
|
@@ -1390,24 +1392,49 @@ export const formatInlineType = (name, env) => {
|
|
1390
1392
|
: formatSubType(getTypes(stats))
|
1391
1393
|
: name
|
1392
1394
|
}
|
1395
|
+
export const formatAstSubType = (T) => {
|
1396
|
+
switch (T[0]) {
|
1397
|
+
case COLLECTION:
|
1398
|
+
return `${
|
1399
|
+
T[1] instanceof Set
|
1400
|
+
? [...T[1]]
|
1401
|
+
.map((x) =>
|
1402
|
+
x === COLLECTION
|
1403
|
+
? formatAstSubType([x])
|
1404
|
+
: toTypeNamesAnyToUknown(x)
|
1405
|
+
)
|
1406
|
+
.join(' ') || toTypeNames(UNKNOWN)
|
1407
|
+
: toTypeNames(UNKNOWN)
|
1408
|
+
}[]`
|
1409
|
+
case ATOM:
|
1410
|
+
return `${
|
1411
|
+
T[1] instanceof Set
|
1412
|
+
? [...T[1]].map((x) => toTypeNamesAnyToUknown(x)).join(' ')
|
1413
|
+
: toTypeNamesAnyToUknown(NUMBER)
|
1414
|
+
}`
|
1415
|
+
default:
|
1416
|
+
return toTypeNamesAnyToUknown(T[0])
|
1417
|
+
}
|
1418
|
+
}
|
1393
1419
|
export const formatAstTypes = (name, env) => {
|
1394
1420
|
const stats = env[name][STATS]
|
1395
1421
|
return stats
|
1396
1422
|
? getType(stats) === APPLY
|
1397
1423
|
? [
|
1398
|
-
|
1399
|
-
|
1424
|
+
FLAG,
|
1425
|
+
...(stats[ARG_COUNT] === VARIADIC
|
1426
|
+
? []
|
1400
1427
|
: stats[ARGUMENTS]?.length
|
1401
1428
|
? stats[ARGUMENTS].map((x, i) =>
|
1402
1429
|
getType(x[STATS]) === APPLY
|
1403
|
-
?
|
1404
|
-
:
|
1430
|
+
? formatAstTypes(i, stats[ARGUMENTS])
|
1431
|
+
: formatAstSubType(getTypes(x[STATS]))
|
1405
1432
|
)
|
1406
|
-
:
|
1407
|
-
|
1433
|
+
: []),
|
1434
|
+
formatAstSubType(getReturns(stats))
|
1408
1435
|
]
|
1409
|
-
:
|
1410
|
-
: name
|
1436
|
+
: [FLAG, formatAstSubType(getTypes(stats))]
|
1437
|
+
: [FLAG, name]
|
1411
1438
|
}
|
1412
1439
|
export const validateLambda = (exp, name) => {
|
1413
1440
|
if (exp.length === 1)
|
package/src/utils.js
CHANGED
@@ -2,6 +2,7 @@ import std from '../lib/baked/std.js'
|
|
2
2
|
import {
|
3
3
|
APPLY,
|
4
4
|
ATOM,
|
5
|
+
FLAG,
|
5
6
|
KEYWORDS,
|
6
7
|
STATIC_TYPES,
|
7
8
|
TYPE,
|
@@ -16,10 +17,16 @@ import {
|
|
16
17
|
handleUnbalancedQuotes
|
17
18
|
} from './macros.js'
|
18
19
|
import { enhance, OPTIMIZATIONS } from './enhance.js'
|
19
|
-
import { type } from './check.js'
|
20
|
+
import { type, typeCheck, withScope } from './check.js'
|
20
21
|
import stdT from '../lib/baked/std-T.js'
|
21
|
-
import {
|
22
|
+
import {
|
23
|
+
definedTypes,
|
24
|
+
filteredDefinedTypes,
|
25
|
+
formatAstTypes,
|
26
|
+
withCtxTypes
|
27
|
+
} from './types.js'
|
22
28
|
import { compile } from './compiler.js'
|
29
|
+
import { startDebug } from './debugger.js'
|
23
30
|
export const logError = (error) =>
|
24
31
|
console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
|
25
32
|
export const logSuccess = (output) => console.log('\x1b[32m', output, '\x1b[0m')
|
@@ -359,6 +366,7 @@ export const isInputVariable = (x) =>
|
|
359
366
|
x[1][VALUE] === 'INPUT'
|
360
367
|
|
361
368
|
export const UTILS = {
|
369
|
+
startDebug,
|
362
370
|
handleUnbalancedQuotes,
|
363
371
|
handleUnbalancedParens,
|
364
372
|
logError,
|
@@ -520,3 +528,34 @@ export const fez = (ast, c = false) => {
|
|
520
528
|
return [null, err]
|
521
529
|
}
|
522
530
|
}
|
531
|
+
|
532
|
+
export const toTypedAst = (ast, userDefinedTypes) => {
|
533
|
+
try {
|
534
|
+
const typeSet = (Types, name, env, exp) => {
|
535
|
+
Types.set(withScope(name, env), () => {
|
536
|
+
if (exp.at(-1)[TYPE] !== FLAG) exp.push(formatAstTypes(name, env))
|
537
|
+
else exp[exp.length - 1] = formatAstTypes(name, env)
|
538
|
+
return ''
|
539
|
+
})
|
540
|
+
}
|
541
|
+
const types = typeCheck(
|
542
|
+
ast,
|
543
|
+
withCtxTypes(
|
544
|
+
userDefinedTypes
|
545
|
+
? {
|
546
|
+
...definedTypes(filteredDefinedTypes(ast, std, stdT)),
|
547
|
+
...definedTypes(LISP.parse(removeNoCode(userDefinedTypes)))
|
548
|
+
}
|
549
|
+
: definedTypes(filteredDefinedTypes(ast, std, stdT))
|
550
|
+
),
|
551
|
+
typeSet
|
552
|
+
)
|
553
|
+
for (const v of types[1].values()) v()
|
554
|
+
// types[0][1][1].slice(1)
|
555
|
+
return types
|
556
|
+
} catch (error) {
|
557
|
+
logError(error.message)
|
558
|
+
return []
|
559
|
+
}
|
560
|
+
}
|
561
|
+
export const atst = (ast, ctx) => toTypedAst(ast, ctx)[0]
|