@typescript-guy/fn-monitor 1.0.0
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/ACKNOWLEDGEMENTS.md +10 -0
- package/LICENSE.md +10 -0
- package/README.md +201 -0
- package/dist/custom-types.d.ts +239 -0
- package/dist/custom-types.js +341 -0
- package/dist/evaluate/declaration.d.ts +27 -0
- package/dist/evaluate/declaration.js +289 -0
- package/dist/evaluate/expression.d.ts +40 -0
- package/dist/evaluate/expression.js +604 -0
- package/dist/evaluate/helper.d.ts +18 -0
- package/dist/evaluate/helper.js +270 -0
- package/dist/evaluate/identifier.d.ts +7 -0
- package/dist/evaluate/identifier.js +27 -0
- package/dist/evaluate/index.d.ts +3 -0
- package/dist/evaluate/index.js +112 -0
- package/dist/evaluate/literal.d.ts +3 -0
- package/dist/evaluate/literal.js +8 -0
- package/dist/evaluate/pattern.d.ts +13 -0
- package/dist/evaluate/pattern.js +118 -0
- package/dist/evaluate/program.d.ts +3 -0
- package/dist/evaluate/program.js +20 -0
- package/dist/evaluate/statement.d.ts +35 -0
- package/dist/evaluate/statement.js +323 -0
- package/dist/evaluate_n/declaration.d.ts +27 -0
- package/dist/evaluate_n/declaration.js +289 -0
- package/dist/evaluate_n/expression.d.ts +38 -0
- package/dist/evaluate_n/expression.js +596 -0
- package/dist/evaluate_n/helper.d.ts +18 -0
- package/dist/evaluate_n/helper.js +238 -0
- package/dist/evaluate_n/identifier.d.ts +7 -0
- package/dist/evaluate_n/identifier.js +27 -0
- package/dist/evaluate_n/index.d.ts +3 -0
- package/dist/evaluate_n/index.js +76 -0
- package/dist/evaluate_n/literal.d.ts +3 -0
- package/dist/evaluate_n/literal.js +8 -0
- package/dist/evaluate_n/pattern.d.ts +13 -0
- package/dist/evaluate_n/pattern.js +118 -0
- package/dist/evaluate_n/program.d.ts +3 -0
- package/dist/evaluate_n/program.js +20 -0
- package/dist/evaluate_n/statement.d.ts +35 -0
- package/dist/evaluate_n/statement.js +301 -0
- package/dist/examples/example-2.d.ts +1 -0
- package/dist/examples/example.d.ts +1 -0
- package/dist/helper-functions.d.ts +15 -0
- package/dist/helper-functions.js +104 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +312 -0
- package/dist/q-list.d.ts +39 -0
- package/dist/q-list.js +146 -0
- package/dist/scope/index.d.ts +81 -0
- package/dist/scope/index.js +168 -0
- package/dist/scope/variable.d.ts +20 -0
- package/dist/scope/variable.js +38 -0
- package/dist/share/async.d.ts +7 -0
- package/dist/share/async.js +43 -0
- package/dist/share/const.d.ts +25 -0
- package/dist/share/const.js +21 -0
- package/dist/share/util.d.ts +33 -0
- package/dist/share/util.js +379 -0
- package/dist/sval.d.ts +15 -0
- package/dist/sval.js +104 -0
- package/package.json +54 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { BREAK, CONTINUE, RETURN } from '../share/const.js';
|
|
2
|
+
import { hoist, ForXHandler, pattern } from './helper.js';
|
|
3
|
+
import Scope from '../scope/index.js';
|
|
4
|
+
import evaluate from './index.js';
|
|
5
|
+
|
|
6
|
+
function ExpressionStatement(node, scope) {
|
|
7
|
+
evaluate(node.expression, scope);
|
|
8
|
+
}
|
|
9
|
+
function BlockStatement(block, scope, options = {}) {
|
|
10
|
+
const {
|
|
11
|
+
invasived = false,
|
|
12
|
+
hoisted = false
|
|
13
|
+
} = options;
|
|
14
|
+
const subScope = invasived ? scope : new Scope(scope);
|
|
15
|
+
if (!hoisted) {
|
|
16
|
+
hoist(block, subScope, { onlyBlock: true });
|
|
17
|
+
}
|
|
18
|
+
for (let i = 0; i < block.body.length; i++) {
|
|
19
|
+
const result = evaluate(block.body[i], subScope);
|
|
20
|
+
if (result === BREAK) {
|
|
21
|
+
if (result.LABEL && result.LABEL === options.label) {
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
if (result === CONTINUE || result === RETURN) {
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function EmptyStatement() {
|
|
32
|
+
}
|
|
33
|
+
function DebuggerStatement() {
|
|
34
|
+
debugger;
|
|
35
|
+
}
|
|
36
|
+
function ReturnStatement(node, scope) {
|
|
37
|
+
RETURN.RES = node.argument ? evaluate(node.argument, scope) : void 0;
|
|
38
|
+
return RETURN;
|
|
39
|
+
}
|
|
40
|
+
function BreakStatement(node) {
|
|
41
|
+
BREAK.LABEL = node.label?.name;
|
|
42
|
+
return BREAK;
|
|
43
|
+
}
|
|
44
|
+
function ContinueStatement(node) {
|
|
45
|
+
CONTINUE.LABEL = node.label?.name;
|
|
46
|
+
return CONTINUE;
|
|
47
|
+
}
|
|
48
|
+
function LabeledStatement(node, scope) {
|
|
49
|
+
const label = node.label.name;
|
|
50
|
+
if (node.body.type === "WhileStatement") {
|
|
51
|
+
return WhileStatement(node.body, scope, { label });
|
|
52
|
+
}
|
|
53
|
+
if (node.body.type === "DoWhileStatement") {
|
|
54
|
+
return DoWhileStatement(node.body, scope, { label });
|
|
55
|
+
}
|
|
56
|
+
if (node.body.type === "ForStatement") {
|
|
57
|
+
return ForStatement(node.body, scope, { label });
|
|
58
|
+
}
|
|
59
|
+
if (node.body.type === "ForInStatement") {
|
|
60
|
+
return ForInStatement(node.body, scope, { label });
|
|
61
|
+
}
|
|
62
|
+
if (node.body.type === "ForOfStatement") {
|
|
63
|
+
return ForOfStatement(node.body, scope, { label });
|
|
64
|
+
}
|
|
65
|
+
if (node.body.type === "BlockStatement") {
|
|
66
|
+
return BlockStatement(node.body, scope, { label });
|
|
67
|
+
}
|
|
68
|
+
if (node.body.type === "WithStatement") {
|
|
69
|
+
return WithStatement(node.body, scope, { label });
|
|
70
|
+
}
|
|
71
|
+
if (node.body.type === "IfStatement") {
|
|
72
|
+
return IfStatement(node.body, scope, { label });
|
|
73
|
+
}
|
|
74
|
+
if (node.body.type === "SwitchStatement") {
|
|
75
|
+
return SwitchStatement(node.body, scope, { label });
|
|
76
|
+
}
|
|
77
|
+
if (node.body.type === "TryStatement") {
|
|
78
|
+
return TryStatement(node.body, scope, { label });
|
|
79
|
+
}
|
|
80
|
+
throw new SyntaxError(`${node.body.type} cannot be labeled`);
|
|
81
|
+
}
|
|
82
|
+
function WithStatement(node, scope, options = {}) {
|
|
83
|
+
const withScope = new Scope(scope);
|
|
84
|
+
withScope.with(evaluate(node.object, scope));
|
|
85
|
+
const result = evaluate(node.body, withScope);
|
|
86
|
+
if (result === BREAK) {
|
|
87
|
+
if (result.LABEL && result.LABEL === options.label) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
if (result === CONTINUE || result === RETURN) {
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function IfStatement(node, scope, options = {}) {
|
|
97
|
+
let result;
|
|
98
|
+
if (evaluate(node.test, scope)) {
|
|
99
|
+
result = evaluate(node.consequent, scope);
|
|
100
|
+
} else {
|
|
101
|
+
result = evaluate(node.alternate, scope);
|
|
102
|
+
}
|
|
103
|
+
if (result === BREAK) {
|
|
104
|
+
if (result.LABEL && result.LABEL === options.label) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
if (result === CONTINUE || result === RETURN) {
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function SwitchStatement(node, scope, options = {}) {
|
|
114
|
+
const discriminant = evaluate(node.discriminant, scope);
|
|
115
|
+
let matched = false;
|
|
116
|
+
let defaultIndex = -1;
|
|
117
|
+
for (let i = 0; i < node.cases.length; i++) {
|
|
118
|
+
const eachCase = node.cases[i];
|
|
119
|
+
if (!eachCase.test) {
|
|
120
|
+
defaultIndex = i;
|
|
121
|
+
} else if (!matched && evaluate(eachCase.test, scope) === discriminant) {
|
|
122
|
+
matched = true;
|
|
123
|
+
defaultIndex = -1;
|
|
124
|
+
}
|
|
125
|
+
if (matched) {
|
|
126
|
+
const result = SwitchCase(eachCase, scope);
|
|
127
|
+
if (result === BREAK) {
|
|
128
|
+
if (result.LABEL === options.label) {
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
if (result === CONTINUE || result === RETURN) {
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (!matched && defaultIndex !== -1) {
|
|
139
|
+
for (let i = defaultIndex; i < node.cases.length; i++) {
|
|
140
|
+
const result = SwitchCase(node.cases[i], scope);
|
|
141
|
+
if (result === BREAK) {
|
|
142
|
+
if (result.LABEL === options.label) {
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
if (result === CONTINUE || result === RETURN) {
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function SwitchCase(node, scope) {
|
|
154
|
+
for (let i = 0; i < node.consequent.length; i++) {
|
|
155
|
+
const result = evaluate(node.consequent[i], scope);
|
|
156
|
+
if (result === BREAK || result === CONTINUE || result === RETURN) {
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function ThrowStatement(node, scope) {
|
|
162
|
+
throw evaluate(node.argument, scope);
|
|
163
|
+
}
|
|
164
|
+
function TryStatement(node, scope, options = {}) {
|
|
165
|
+
let result;
|
|
166
|
+
try {
|
|
167
|
+
result = BlockStatement(node.block, scope);
|
|
168
|
+
} catch (err) {
|
|
169
|
+
if (node.handler) {
|
|
170
|
+
const subScope = new Scope(scope);
|
|
171
|
+
const param = node.handler.param;
|
|
172
|
+
if (param) {
|
|
173
|
+
if (param.type === "Identifier") {
|
|
174
|
+
const name = param.name;
|
|
175
|
+
subScope.var(name, err);
|
|
176
|
+
} else {
|
|
177
|
+
pattern(param, scope, { feed: err });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
result = CatchClause(node.handler, subScope);
|
|
181
|
+
} else {
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
} finally {
|
|
185
|
+
if (node.finalizer) {
|
|
186
|
+
result = BlockStatement(node.finalizer, scope);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (result === BREAK) {
|
|
190
|
+
if (result.LABEL && result.LABEL === options.label) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
if (result === CONTINUE || result === RETURN) {
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function CatchClause(node, scope) {
|
|
200
|
+
return BlockStatement(node.body, scope, { invasived: true });
|
|
201
|
+
}
|
|
202
|
+
function WhileStatement(node, scope, options = {}) {
|
|
203
|
+
while (evaluate(node.test, scope)) {
|
|
204
|
+
const result = evaluate(node.body, scope);
|
|
205
|
+
if (result === BREAK) {
|
|
206
|
+
if (result.LABEL === options.label) {
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
} else if (result === CONTINUE) {
|
|
211
|
+
if (result.LABEL === options.label) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
return result;
|
|
215
|
+
} else if (result === RETURN) {
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function DoWhileStatement(node, scope, options = {}) {
|
|
221
|
+
do {
|
|
222
|
+
const result = evaluate(node.body, scope);
|
|
223
|
+
if (result === BREAK) {
|
|
224
|
+
if (result.LABEL === options.label) {
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
} else if (result === CONTINUE) {
|
|
229
|
+
if (result.LABEL === options.label) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
return result;
|
|
233
|
+
} else if (result === RETURN) {
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
} while (evaluate(node.test, scope));
|
|
237
|
+
}
|
|
238
|
+
function ForStatement(node, scope, options = {}) {
|
|
239
|
+
const forScope = new Scope(scope);
|
|
240
|
+
for (node.init ? evaluate(node.init, forScope) : void 0; node.test ? evaluate(node.test, forScope) : true; node.update ? evaluate(node.update, forScope) : void 0) {
|
|
241
|
+
const subScope = new Scope(forScope);
|
|
242
|
+
let result;
|
|
243
|
+
if (node.body.type === "BlockStatement") {
|
|
244
|
+
result = BlockStatement(node.body, subScope, { invasived: true });
|
|
245
|
+
} else {
|
|
246
|
+
result = evaluate(node.body, subScope);
|
|
247
|
+
}
|
|
248
|
+
if (result === BREAK) {
|
|
249
|
+
if (result.LABEL === options.label) {
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
return result;
|
|
253
|
+
} else if (result === CONTINUE) {
|
|
254
|
+
if (result.LABEL === options.label) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
} else if (result === RETURN) {
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function ForInStatement(node, scope, options = {}) {
|
|
264
|
+
for (const value in evaluate(node.right, scope)) {
|
|
265
|
+
const result = ForXHandler(node, scope, { value });
|
|
266
|
+
if (result === BREAK) {
|
|
267
|
+
if (result.LABEL === options.label) {
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
return result;
|
|
271
|
+
} else if (result === CONTINUE) {
|
|
272
|
+
if (result.LABEL === options.label) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
return result;
|
|
276
|
+
} else if (result === RETURN) {
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function ForOfStatement(node, scope, options = {}) {
|
|
282
|
+
const right = evaluate(node.right, scope);
|
|
283
|
+
for (const value of right) {
|
|
284
|
+
const result = ForXHandler(node, scope, { value });
|
|
285
|
+
if (result === BREAK) {
|
|
286
|
+
if (result.LABEL === options.label) {
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
} else if (result === CONTINUE) {
|
|
291
|
+
if (result.LABEL === options.label) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
return result;
|
|
295
|
+
} else if (result === RETURN) {
|
|
296
|
+
return result;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export { BlockStatement, BreakStatement, CatchClause, ContinueStatement, DebuggerStatement, DoWhileStatement, EmptyStatement, ExpressionStatement, ForInStatement, ForOfStatement, ForStatement, IfStatement, LabeledStatement, ReturnStatement, SwitchCase, SwitchStatement, ThrowStatement, TryStatement, WhileStatement, WithStatement };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Node as AcornNode } from 'acorn';
|
|
2
|
+
import { default as Scope } from './scope/index.ts';
|
|
3
|
+
import { SvalPlus, Reusables } from './custom-types.ts';
|
|
4
|
+
export declare function isGenerator(obj: unknown): obj is Generator;
|
|
5
|
+
export declare function useModifiedEvaluator(scope: Scope): boolean;
|
|
6
|
+
export declare function callPerExe(interpreter: SvalPlus): void;
|
|
7
|
+
export declare function cleanStack(interpreter: SvalPlus, parentReusables: Reusables): void;
|
|
8
|
+
export declare function pushHandler(interpreter: SvalPlus, result: any, pushedManually: boolean): void;
|
|
9
|
+
export declare function pushResult(interpreter: SvalPlus, result: any): void;
|
|
10
|
+
/**It returns true if it was refreshed and false if it wasnt */
|
|
11
|
+
export declare function refreshExeStack(interpreter: SvalPlus): boolean;
|
|
12
|
+
export declare function callMonitor(acornNode: AcornNode, currentScope: Scope<SvalPlus>, handler: Reusables['handler']): void | import('./custom-types.ts').InspectorGenerator;
|
|
13
|
+
export declare function clearEvalStack(interpreter: SvalPlus): void;
|
|
14
|
+
export declare function captureReusables(interpreter: SvalPlus): Reusables;
|
|
15
|
+
export declare function restoreCapturedReusables(interpreter: SvalPlus, prevReusables: Reusables): void;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { UNASSIGNED, NOT_ALLOCATED } from './custom-types.js';
|
|
2
|
+
|
|
3
|
+
function isGenerator(obj) {
|
|
4
|
+
return Object.prototype.toString.call(obj) === "[object Generator]";
|
|
5
|
+
}
|
|
6
|
+
function useModifiedEvaluator(scope) {
|
|
7
|
+
const interpreter = scope.interpreter;
|
|
8
|
+
const inUserCode = scope.scopeDepth >= 2;
|
|
9
|
+
const availableInspector = typeof interpreter.inspector === "function";
|
|
10
|
+
const use = interpreter.stage === "MONITORING" && inUserCode && availableInspector;
|
|
11
|
+
return use;
|
|
12
|
+
}
|
|
13
|
+
function callPerExe(interpreter) {
|
|
14
|
+
const perExe = interpreter.reusables.shared.perExe;
|
|
15
|
+
const node = interpreter.reusables.node;
|
|
16
|
+
if (perExe) {
|
|
17
|
+
perExe.fn();
|
|
18
|
+
if (perExe.owner === node) {
|
|
19
|
+
interpreter.reusables.shared.perExe = null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function cleanStack(interpreter, parentReusables) {
|
|
24
|
+
interpreter.reusables.shared.evalStack.value -= 1;
|
|
25
|
+
const zeroNodesLeft = interpreter.reusables.shared.evalStack.value <= 0;
|
|
26
|
+
if (zeroNodesLeft) {
|
|
27
|
+
clearEvalStack(interpreter);
|
|
28
|
+
} else {
|
|
29
|
+
restoreCapturedReusables(interpreter, parentReusables);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function pushHandler(interpreter, result, pushedManually) {
|
|
33
|
+
if (!pushedManually) {
|
|
34
|
+
pushResult(interpreter, result);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function pushResult(interpreter, result) {
|
|
38
|
+
const currentEvent = interpreter.reusables.currentEvent;
|
|
39
|
+
const node = interpreter.reusables.node;
|
|
40
|
+
interpreter.reusables.shared.exeStack.unshift({
|
|
41
|
+
evaluation: result,
|
|
42
|
+
type: node.type,
|
|
43
|
+
node,
|
|
44
|
+
scope: currentEvent === NOT_ALLOCATED ? NOT_ALLOCATED : currentEvent.scope
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function refreshExeStack(interpreter) {
|
|
48
|
+
const OneNodeLeft = interpreter.reusables.shared.evalStack.value <= 1;
|
|
49
|
+
if (OneNodeLeft) {
|
|
50
|
+
interpreter.reusables.shared.exeStack.clear();
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
function callMonitor(acornNode, currentScope, handler) {
|
|
56
|
+
const interpreter = currentScope.interpreter;
|
|
57
|
+
refreshReusables(acornNode, currentScope, handler);
|
|
58
|
+
return interpreter.inspector(interpreter.visit);
|
|
59
|
+
}
|
|
60
|
+
function refreshReusables(acornNode, currentScope, handler) {
|
|
61
|
+
const interpreter = currentScope.interpreter;
|
|
62
|
+
interpreter.reusables.node = acornNode;
|
|
63
|
+
interpreter.reusables.currentScope = currentScope;
|
|
64
|
+
interpreter.reusables.handler = handler;
|
|
65
|
+
interpreter.reusables.result = UNASSIGNED;
|
|
66
|
+
interpreter.reusables.currentEvent = NOT_ALLOCATED;
|
|
67
|
+
}
|
|
68
|
+
function clearEvalStack(interpreter) {
|
|
69
|
+
interpreter.reusables.node = null;
|
|
70
|
+
interpreter.reusables.currentScope = null;
|
|
71
|
+
interpreter.reusables.handler = null;
|
|
72
|
+
interpreter.reusables.result = UNASSIGNED;
|
|
73
|
+
interpreter.reusables.currentEvent = NOT_ALLOCATED;
|
|
74
|
+
interpreter.reusables.shared.evalStack.value = 0;
|
|
75
|
+
}
|
|
76
|
+
function captureReusables(interpreter) {
|
|
77
|
+
return {
|
|
78
|
+
node: interpreter.reusables.node,
|
|
79
|
+
currentScope: interpreter.reusables.currentScope,
|
|
80
|
+
handler: interpreter.reusables.handler,
|
|
81
|
+
result: interpreter.reusables.result,
|
|
82
|
+
currentEvent: interpreter.reusables.currentEvent,
|
|
83
|
+
shared: {
|
|
84
|
+
evalStack: interpreter.reusables.shared.evalStack,
|
|
85
|
+
//the eval stack variable is a global tracker.so it cant be cleared or reset in local functions.
|
|
86
|
+
exeStack: interpreter.reusables.shared.exeStack,
|
|
87
|
+
readonlyExeStack: interpreter.reusables.shared.readonlyExeStack,
|
|
88
|
+
perExe: interpreter.reusables.shared.perExe
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function restoreCapturedReusables(interpreter, prevReusables) {
|
|
93
|
+
interpreter.reusables.node = prevReusables.node;
|
|
94
|
+
interpreter.reusables.currentScope = prevReusables.currentScope;
|
|
95
|
+
interpreter.reusables.handler = prevReusables.handler;
|
|
96
|
+
interpreter.reusables.result = prevReusables.result;
|
|
97
|
+
interpreter.reusables.currentEvent = prevReusables.currentEvent;
|
|
98
|
+
interpreter.reusables.shared.evalStack = prevReusables.shared.evalStack;
|
|
99
|
+
interpreter.reusables.shared.exeStack = prevReusables.shared.exeStack;
|
|
100
|
+
interpreter.reusables.shared.readonlyExeStack = prevReusables.shared.readonlyExeStack;
|
|
101
|
+
interpreter.reusables.shared.perExe = prevReusables.shared.perExe;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export { callMonitor, callPerExe, captureReusables, cleanStack, clearEvalStack, isGenerator, pushHandler, pushResult, refreshExeStack, restoreCapturedReusables, useModifiedEvaluator };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Inspector, Fn, OnStep } from './custom-types.ts';
|
|
2
|
+
export interface Metadata<T extends Fn> {
|
|
3
|
+
/**the reference to the function to be included in the interpreter context**/
|
|
4
|
+
ref: T;
|
|
5
|
+
/**
|
|
6
|
+
*Because the function runs in an isolated interpreter context,any data that it uses from the outside scope has to captured by mapping the variable names to their variables and passing the object here.
|
|
7
|
+
*It is important to keep in mind that the captures object itself follows the semantic of copy primitives by value and copy obects by reference.
|
|
8
|
+
*/
|
|
9
|
+
captures?: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
export interface MonitorFnSetup<T extends Fn> {
|
|
12
|
+
/**The configuration for the main function to monitor */
|
|
13
|
+
main: Metadata<T>;
|
|
14
|
+
/**
|
|
15
|
+
* If the main function calls another function outside of its scope,this is an alternative to capturing it by reference.
|
|
16
|
+
* Unlike reference capturing,this directly include a function's source code in the same interpreter context as the main function being monitored.It can also state its own captures as well or use other embedded functions.
|
|
17
|
+
*/
|
|
18
|
+
embed?: Record<string, Metadata<Fn>>;
|
|
19
|
+
/**
|
|
20
|
+
* The main hook that gets fed the interpreter's context as the function executes.The visit object is rich enough to inspect nodes and their scope,modify them before execution and execute nodes manually to see and change their results.
|
|
21
|
+
*/
|
|
22
|
+
inspector?: Inspector;
|
|
23
|
+
/**
|
|
24
|
+
*Like the inspector hook,this is called before each interpreted step.but it does not get the rich visit object to inspect or modify nodes
|
|
25
|
+
*Using this hook alone without the inspector will make the interpreter significantly faster because it removes all the allocations it will need to create the tools for the visit object
|
|
26
|
+
*Even without node information,it is useful for setting timers on the interpreted code by checking against a time after a number of steps.
|
|
27
|
+
*If the use case above is enough,use this hook and leave the inspector as undefined.Else,including the inspector,even as a no-op function,will cause several unnecessary allocations
|
|
28
|
+
*/
|
|
29
|
+
onStep?: OnStep;
|
|
30
|
+
/**It takes an object with a value property and overwrites it with the generated code used in the interpreter for a specific monitored function.It includes the code for all embedded functions as well */
|
|
31
|
+
sourceOut?: {
|
|
32
|
+
value: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The hook that is called before each call to the monitored function
|
|
36
|
+
* It gets the arguments passed to the function from the caller.It is useful for logging or inspecting the args before execution
|
|
37
|
+
*/
|
|
38
|
+
beforeEachCall?: (...args: Parameters<T>) => void;
|
|
39
|
+
/**
|
|
40
|
+
*The hook that is called after each call to the monitored function
|
|
41
|
+
*It gets the result returned from the function or an error if an error was thrown in the function.
|
|
42
|
+
*/
|
|
43
|
+
afterEachCall?: (result: ReturnType<T> | Error) => void;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* This function is the only export you need to get started.It accepts a brief config that includes a function and returns a new function that can be called exactly as the original.But it is executed by a custom interpreter rather than your js engine directly.
|
|
47
|
+
* The major advantage you get is that you can inject hooks at any part of the function's lifecyle and they are treated as first class citizens by the interpreter.Essentially making it a white-box.
|
|
48
|
+
*/
|
|
49
|
+
export declare function monitor<T extends Fn>(setup: MonitorFnSetup<T>): T & {
|
|
50
|
+
alreadyMonitored: true;
|
|
51
|
+
};
|
|
52
|
+
export { Var } from './scope/variable.ts';
|
|
53
|
+
export { QList, ReadonlyQList } from './q-list.ts';
|
|
54
|
+
export type { Inspector, OnStep, VariableForEvent, ScopeForEvent, Query, EventMap, Visit, InspectorGenerator, ExeResult, EsNode, } from './custom-types.ts';
|
|
55
|
+
export { NOT_ALLOCATED, LAZY_NODE, LangEvent, BinaryExprEvent, CallExprEvent, AssignmentExprEvent, UpdateExprEvent, LogicalExprEvent, MemberExprEvent, AwaitExprEvent, FuncExprEvent, NewExprEvent, ArrowFnExprEvent, TernaryExprEvent, YieldExprEvent, ExpressionStmtEvent, ArrayExprEvent, ObjectExprEvent, TemplateLiteralEvent, SequenceExprEvent, UnaryExprEvent, ReturnStmtEvent, IfStmtEvent, SwitchStmtEvent, ThrowStmtEvent, TryStmtEvent, CatchClauseEvent, LabeledStmtEvent, BreakStmtEvent, ContinueStmtEvent, VarDeclEvent, FuncDeclEvent, ForStmtEvent, WhileStmtEvent, DoWhileStmtEvent, ForOfStmtEvent, ForInStmtEvent, LiteralEvent } from './custom-types.ts';
|