fez-lisp 1.6.27 → 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/lib/baked/std.js +1 -1
- package/package.json +1 -1
- package/src/debugger.js +165 -0
- package/src/utils.js +11 -7
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/utils.js
CHANGED
@@ -26,6 +26,7 @@ import {
|
|
26
26
|
withCtxTypes
|
27
27
|
} from './types.js'
|
28
28
|
import { compile } from './compiler.js'
|
29
|
+
import { startDebug } from './debugger.js'
|
29
30
|
export const logError = (error) =>
|
30
31
|
console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
|
31
32
|
export const logSuccess = (output) => console.log('\x1b[32m', output, '\x1b[0m')
|
@@ -365,6 +366,7 @@ export const isInputVariable = (x) =>
|
|
365
366
|
x[1][VALUE] === 'INPUT'
|
366
367
|
|
367
368
|
export const UTILS = {
|
369
|
+
startDebug,
|
368
370
|
handleUnbalancedQuotes,
|
369
371
|
handleUnbalancedParens,
|
370
372
|
logError,
|
@@ -529,6 +531,13 @@ export const fez = (ast, c = false) => {
|
|
529
531
|
|
530
532
|
export const toTypedAst = (ast, userDefinedTypes) => {
|
531
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
|
+
}
|
532
541
|
const types = typeCheck(
|
533
542
|
ast,
|
534
543
|
withCtxTypes(
|
@@ -539,19 +548,14 @@ export const toTypedAst = (ast, userDefinedTypes) => {
|
|
539
548
|
}
|
540
549
|
: definedTypes(filteredDefinedTypes(ast, std, stdT))
|
541
550
|
),
|
542
|
-
|
543
|
-
Types.set(withScope(name, env), () => {
|
544
|
-
if (exp.at(-1)[TYPE] !== FLAG) exp.push(formatAstTypes(name, env))
|
545
|
-
else exp[exp.length - 1] = formatAstTypes(name, env)
|
546
|
-
return ''
|
547
|
-
})
|
548
|
-
}
|
551
|
+
typeSet
|
549
552
|
)
|
550
553
|
for (const v of types[1].values()) v()
|
551
554
|
// types[0][1][1].slice(1)
|
552
555
|
return types
|
553
556
|
} catch (error) {
|
554
557
|
logError(error.message)
|
558
|
+
return []
|
555
559
|
}
|
556
560
|
}
|
557
561
|
export const atst = (ast, ctx) => toTypedAst(ast, ctx)[0]
|