source: imaps-frontend/node_modules/@babel/traverse/lib/path/evaluation.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 9.8 KB
Line 
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.evaluate = evaluate;
7exports.evaluateTruthy = evaluateTruthy;
8const VALID_OBJECT_CALLEES = ["Number", "String", "Math"];
9const VALID_IDENTIFIER_CALLEES = ["isFinite", "isNaN", "parseFloat", "parseInt", "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", null, null];
10const INVALID_METHODS = ["random"];
11function isValidObjectCallee(val) {
12 return VALID_OBJECT_CALLEES.includes(val);
13}
14function isValidIdentifierCallee(val) {
15 return VALID_IDENTIFIER_CALLEES.includes(val);
16}
17function isInvalidMethod(val) {
18 return INVALID_METHODS.includes(val);
19}
20function evaluateTruthy() {
21 const res = this.evaluate();
22 if (res.confident) return !!res.value;
23}
24function deopt(path, state) {
25 if (!state.confident) return;
26 state.deoptPath = path;
27 state.confident = false;
28}
29const Globals = new Map([["undefined", undefined], ["Infinity", Infinity], ["NaN", NaN]]);
30function evaluateCached(path, state) {
31 const {
32 node
33 } = path;
34 const {
35 seen
36 } = state;
37 if (seen.has(node)) {
38 const existing = seen.get(node);
39 if (existing.resolved) {
40 return existing.value;
41 } else {
42 deopt(path, state);
43 return;
44 }
45 } else {
46 const item = {
47 resolved: false
48 };
49 seen.set(node, item);
50 const val = _evaluate(path, state);
51 if (state.confident) {
52 item.resolved = true;
53 item.value = val;
54 }
55 return val;
56 }
57}
58function _evaluate(path, state) {
59 if (!state.confident) return;
60 if (path.isSequenceExpression()) {
61 const exprs = path.get("expressions");
62 return evaluateCached(exprs[exprs.length - 1], state);
63 }
64 if (path.isStringLiteral() || path.isNumericLiteral() || path.isBooleanLiteral()) {
65 return path.node.value;
66 }
67 if (path.isNullLiteral()) {
68 return null;
69 }
70 if (path.isTemplateLiteral()) {
71 return evaluateQuasis(path, path.node.quasis, state);
72 }
73 if (path.isTaggedTemplateExpression() && path.get("tag").isMemberExpression()) {
74 const object = path.get("tag.object");
75 const {
76 node: {
77 name
78 }
79 } = object;
80 const property = path.get("tag.property");
81 if (object.isIdentifier() && name === "String" && !path.scope.getBinding(name) && property.isIdentifier() && property.node.name === "raw") {
82 return evaluateQuasis(path, path.node.quasi.quasis, state, true);
83 }
84 }
85 if (path.isConditionalExpression()) {
86 const testResult = evaluateCached(path.get("test"), state);
87 if (!state.confident) return;
88 if (testResult) {
89 return evaluateCached(path.get("consequent"), state);
90 } else {
91 return evaluateCached(path.get("alternate"), state);
92 }
93 }
94 if (path.isExpressionWrapper()) {
95 return evaluateCached(path.get("expression"), state);
96 }
97 if (path.isMemberExpression() && !path.parentPath.isCallExpression({
98 callee: path.node
99 })) {
100 const property = path.get("property");
101 const object = path.get("object");
102 if (object.isLiteral()) {
103 const value = object.node.value;
104 const type = typeof value;
105 let key = null;
106 if (path.node.computed) {
107 key = evaluateCached(property, state);
108 if (!state.confident) return;
109 } else if (property.isIdentifier()) {
110 key = property.node.name;
111 }
112 if ((type === "number" || type === "string") && key != null && (typeof key === "number" || typeof key === "string")) {
113 return value[key];
114 }
115 }
116 }
117 if (path.isReferencedIdentifier()) {
118 const binding = path.scope.getBinding(path.node.name);
119 if (binding) {
120 if (binding.constantViolations.length > 0 || path.node.start < binding.path.node.end) {
121 deopt(binding.path, state);
122 return;
123 }
124 if (binding.hasValue) {
125 return binding.value;
126 }
127 }
128 const name = path.node.name;
129 if (Globals.has(name)) {
130 if (!binding) {
131 return Globals.get(name);
132 }
133 deopt(binding.path, state);
134 return;
135 }
136 const resolved = path.resolve();
137 if (resolved === path) {
138 deopt(path, state);
139 return;
140 } else {
141 return evaluateCached(resolved, state);
142 }
143 }
144 if (path.isUnaryExpression({
145 prefix: true
146 })) {
147 if (path.node.operator === "void") {
148 return undefined;
149 }
150 const argument = path.get("argument");
151 if (path.node.operator === "typeof" && (argument.isFunction() || argument.isClass())) {
152 return "function";
153 }
154 const arg = evaluateCached(argument, state);
155 if (!state.confident) return;
156 switch (path.node.operator) {
157 case "!":
158 return !arg;
159 case "+":
160 return +arg;
161 case "-":
162 return -arg;
163 case "~":
164 return ~arg;
165 case "typeof":
166 return typeof arg;
167 }
168 }
169 if (path.isArrayExpression()) {
170 const arr = [];
171 const elems = path.get("elements");
172 for (const elem of elems) {
173 const elemValue = elem.evaluate();
174 if (elemValue.confident) {
175 arr.push(elemValue.value);
176 } else {
177 deopt(elemValue.deopt, state);
178 return;
179 }
180 }
181 return arr;
182 }
183 if (path.isObjectExpression()) {
184 const obj = {};
185 const props = path.get("properties");
186 for (const prop of props) {
187 if (prop.isObjectMethod() || prop.isSpreadElement()) {
188 deopt(prop, state);
189 return;
190 }
191 const keyPath = prop.get("key");
192 let key;
193 if (prop.node.computed) {
194 key = keyPath.evaluate();
195 if (!key.confident) {
196 deopt(key.deopt, state);
197 return;
198 }
199 key = key.value;
200 } else if (keyPath.isIdentifier()) {
201 key = keyPath.node.name;
202 } else {
203 key = keyPath.node.value;
204 }
205 const valuePath = prop.get("value");
206 let value = valuePath.evaluate();
207 if (!value.confident) {
208 deopt(value.deopt, state);
209 return;
210 }
211 value = value.value;
212 obj[key] = value;
213 }
214 return obj;
215 }
216 if (path.isLogicalExpression()) {
217 const wasConfident = state.confident;
218 const left = evaluateCached(path.get("left"), state);
219 const leftConfident = state.confident;
220 state.confident = wasConfident;
221 const right = evaluateCached(path.get("right"), state);
222 const rightConfident = state.confident;
223 switch (path.node.operator) {
224 case "||":
225 state.confident = leftConfident && (!!left || rightConfident);
226 if (!state.confident) return;
227 return left || right;
228 case "&&":
229 state.confident = leftConfident && (!left || rightConfident);
230 if (!state.confident) return;
231 return left && right;
232 case "??":
233 state.confident = leftConfident && (left != null || rightConfident);
234 if (!state.confident) return;
235 return left != null ? left : right;
236 }
237 }
238 if (path.isBinaryExpression()) {
239 const left = evaluateCached(path.get("left"), state);
240 if (!state.confident) return;
241 const right = evaluateCached(path.get("right"), state);
242 if (!state.confident) return;
243 switch (path.node.operator) {
244 case "-":
245 return left - right;
246 case "+":
247 return left + right;
248 case "/":
249 return left / right;
250 case "*":
251 return left * right;
252 case "%":
253 return left % right;
254 case "**":
255 return Math.pow(left, right);
256 case "<":
257 return left < right;
258 case ">":
259 return left > right;
260 case "<=":
261 return left <= right;
262 case ">=":
263 return left >= right;
264 case "==":
265 return left == right;
266 case "!=":
267 return left != right;
268 case "===":
269 return left === right;
270 case "!==":
271 return left !== right;
272 case "|":
273 return left | right;
274 case "&":
275 return left & right;
276 case "^":
277 return left ^ right;
278 case "<<":
279 return left << right;
280 case ">>":
281 return left >> right;
282 case ">>>":
283 return left >>> right;
284 }
285 }
286 if (path.isCallExpression()) {
287 const callee = path.get("callee");
288 let context;
289 let func;
290 if (callee.isIdentifier() && !path.scope.getBinding(callee.node.name) && (isValidObjectCallee(callee.node.name) || isValidIdentifierCallee(callee.node.name))) {
291 func = global[callee.node.name];
292 }
293 if (callee.isMemberExpression()) {
294 const object = callee.get("object");
295 const property = callee.get("property");
296 if (object.isIdentifier() && property.isIdentifier() && isValidObjectCallee(object.node.name) && !isInvalidMethod(property.node.name)) {
297 context = global[object.node.name];
298 const key = property.node.name;
299 if (hasOwnProperty.call(context, key)) {
300 func = context[key];
301 }
302 }
303 if (object.isLiteral() && property.isIdentifier()) {
304 const type = typeof object.node.value;
305 if (type === "string" || type === "number") {
306 context = object.node.value;
307 func = context[property.node.name];
308 }
309 }
310 }
311 if (func) {
312 const args = path.get("arguments").map(arg => evaluateCached(arg, state));
313 if (!state.confident) return;
314 return func.apply(context, args);
315 }
316 }
317 deopt(path, state);
318}
319function evaluateQuasis(path, quasis, state, raw = false) {
320 let str = "";
321 let i = 0;
322 const exprs = path.isTemplateLiteral() ? path.get("expressions") : path.get("quasi.expressions");
323 for (const elem of quasis) {
324 if (!state.confident) break;
325 str += raw ? elem.value.raw : elem.value.cooked;
326 const expr = exprs[i++];
327 if (expr) str += String(evaluateCached(expr, state));
328 }
329 if (!state.confident) return;
330 return str;
331}
332function evaluate() {
333 const state = {
334 confident: true,
335 deoptPath: null,
336 seen: new Map()
337 };
338 let value = evaluateCached(this, state);
339 if (!state.confident) value = undefined;
340 return {
341 confident: state.confident,
342 deopt: state.deoptPath,
343 value: value
344 };
345}
346
347//# sourceMappingURL=evaluation.js.map
Note: See TracBrowser for help on using the repository browser.