-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
create-node-evaluator.ts
104 lines (95 loc) · 3.84 KB
/
create-node-evaluator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import type {ICreateNodeEvaluatorOptions} from "./i-create-node-evaluator-options.js";
import type {NodeEvaluator} from "./node-evaluator.js";
import {MaxOpsExceededError} from "../../error/policy-error/max-ops-exceeded-error/max-ops-exceeded-error.js";
import {evaluateStatement} from "../evaluate-statement.js";
import {evaluateExpression} from "../evaluate-expression.js";
import type {EvaluatorOptions, NextEvaluatorOptions} from "../evaluator-options.js";
import {evaluateDeclaration} from "../evaluate-declaration.js";
import {evaluateNodeWithArgument} from "../evaluate-node-with-argument.js";
import {evaluateNodeWithValue} from "../evaluate-node-with-value.js";
import {createStatementTraversalStack} from "../../stack/traversal-stack/statement-traversal-stack.js";
import type {TS} from "../../../type/ts.js";
import type {EvaluationError} from "../../error/evaluation-error/evaluation-error.js";
import {isEvaluationError} from "../../error/evaluation-error/evaluation-error.js";
import type {Literal} from "../../literal/literal.js";
/**
* Creates a Node Evaluator
*/
export function createNodeEvaluator(options: ICreateNodeEvaluatorOptions): NodeEvaluator {
let ops = 0;
const {policy, reporting} = options;
const prequalifyNextNode = (node: TS.Node, nextOptions: NextEvaluatorOptions): EvaluationError | void => {
const {
environment = options.environment,
statementTraversalStack = options.statementTraversalStack,
getCurrentError = options.getCurrentError,
throwError = options.throwError
} = nextOptions ?? {};
const currentError = getCurrentError();
if (currentError != null) {
return currentError;
}
// Increment the amount of encountered ops
ops++;
// Throw an error if the maximum amount of operations has been exceeded
if (ops >= policy.maxOps) {
return throwError(new MaxOpsExceededError({ops, environment, node}));
}
// Update the statementTraversalStack with the node's kind
statementTraversalStack.push(node.kind);
if (reporting.reportTraversal != null) {
reporting.reportTraversal({node});
}
return undefined;
};
const evaluate: NodeEvaluator = {
statement: (node, nextOptions): void => {
const combinedNextOptions = {...nextOptions, statementTraversalStack: createStatementTraversalStack()};
const prequalifyResult = prequalifyNextNode(node, combinedNextOptions);
if (isEvaluationError(prequalifyResult)) {
return;
}
return evaluateStatement(getEvaluatorOptions(node, combinedNextOptions));
},
declaration: (node, nextOptions): void => {
const prequalifyResult = prequalifyNextNode(node, nextOptions);
if (isEvaluationError(prequalifyResult)) {
return;
}
return evaluateDeclaration(getEvaluatorOptions(node, nextOptions));
},
nodeWithArgument: (node, arg, nextOptions): void => {
const prequalifyResult = prequalifyNextNode(node, nextOptions);
if (isEvaluationError(prequalifyResult)) {
return;
}
return evaluateNodeWithArgument(getEvaluatorOptions(node, nextOptions), arg);
},
expression: (node, nextOptions): Literal | EvaluationError => {
const prequalifyResult = prequalifyNextNode(node, nextOptions);
if (isEvaluationError(prequalifyResult)) {
return prequalifyResult;
}
return evaluateExpression(getEvaluatorOptions(node, nextOptions));
},
nodeWithValue: (node, nextOptions): Literal | EvaluationError => {
const prequalifyResult = prequalifyNextNode(node, nextOptions);
if (isEvaluationError(prequalifyResult)) {
return prequalifyResult;
}
return evaluateNodeWithValue(getEvaluatorOptions(node, nextOptions));
}
};
/**
* Gets an IEvaluatorOptions object ready for passing to one of the evaluation functions
*/
function getEvaluatorOptions<T extends TS.Node>(node: T, nextOptions: NextEvaluatorOptions): EvaluatorOptions<T> {
return {
...options,
...nextOptions,
evaluate,
node
};
}
return evaluate;
}