forked from rollup/rollup
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBinaryExpression.ts
127 lines (115 loc) · 3.86 KB
/
BinaryExpression.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import type MagicString from 'magic-string';
import { BLANK } from '../../utils/blank';
import type { NodeRenderOptions, RenderOptions } from '../../utils/renderHelpers';
import type { DeoptimizableEntity } from '../DeoptimizableEntity';
import type { HasEffectsContext } from '../ExecutionContext';
import type { NodeInteraction } from '../NodeInteractions';
import { INTERACTION_ACCESSED } from '../NodeInteractions';
import {
EMPTY_PATH,
type ObjectPath,
type PathTracker,
SHARED_RECURSION_TRACKER
} from '../utils/PathTracker';
import ExpressionStatement from './ExpressionStatement';
import type { LiteralValue } from './Literal';
import type * as NodeType from './NodeType';
import { type LiteralValueOrUnknown, UnknownValue } from './shared/Expression';
import { type ExpressionNode, NodeBase } from './shared/Node';
type Operator =
| '!='
| '!=='
| '%'
| '&'
| '*'
| '**'
| '+'
| '-'
| '/'
| '<'
| '<<'
| '<='
| '=='
| '==='
| '>'
| '>='
| '>>'
| '>>>'
| '^'
| '|'
| 'in'
| 'instanceof';
const binaryOperators: {
[operator in Operator]?: (left: LiteralValue, right: LiteralValue) => LiteralValueOrUnknown;
} = {
'!=': (left, right) => left != right,
'!==': (left, right) => left !== right,
'%': (left: any, right: any) => left % right,
'&': (left: any, right: any) => left & right,
'*': (left: any, right: any) => left * right,
// At the moment, "**" will be transpiled to Math.pow
'**': (left: any, right: any) => left ** right,
'+': (left: any, right: any) => left + right,
'-': (left: any, right: any) => left - right,
'/': (left: any, right: any) => left / right,
'<': (left, right) => left! < right!,
'<<': (left: any, right: any) => left << right,
'<=': (left, right) => left! <= right!,
'==': (left, right) => left == right,
'===': (left, right) => left === right,
'>': (left, right) => left! > right!,
'>=': (left, right) => left! >= right!,
'>>': (left: any, right: any) => left >> right,
'>>>': (left: any, right: any) => left >>> right,
'^': (left: any, right: any) => left ^ right,
'|': (left: any, right: any) => left | right
// We use the fallback for cases where we return something unknown
// in: () => UnknownValue,
// instanceof: () => UnknownValue,
};
export default class BinaryExpression extends NodeBase implements DeoptimizableEntity {
declare left: ExpressionNode;
declare operator: keyof typeof binaryOperators;
declare right: ExpressionNode;
declare type: NodeType.tBinaryExpression;
deoptimizeCache(): void {}
getLiteralValueAtPath(
path: ObjectPath,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): LiteralValueOrUnknown {
if (path.length > 0) return UnknownValue;
const leftValue = this.left.getLiteralValueAtPath(EMPTY_PATH, recursionTracker, origin);
if (typeof leftValue === 'symbol') return UnknownValue;
const rightValue = this.right.getLiteralValueAtPath(EMPTY_PATH, recursionTracker, origin);
if (typeof rightValue === 'symbol') return UnknownValue;
const operatorFunction = binaryOperators[this.operator];
if (!operatorFunction) return UnknownValue;
return operatorFunction(leftValue, rightValue);
}
hasEffects(context: HasEffectsContext): boolean {
// support some implicit type coercion runtime errors
if (
this.operator === '+' &&
this.parent instanceof ExpressionStatement &&
this.left.getLiteralValueAtPath(EMPTY_PATH, SHARED_RECURSION_TRACKER, this) === ''
) {
return true;
}
return super.hasEffects(context);
}
hasEffectsOnInteractionAtPath(path: ObjectPath, { type }: NodeInteraction): boolean {
return type !== INTERACTION_ACCESSED || path.length > 1;
}
removeAnnotations(code: MagicString) {
this.left.removeAnnotations(code);
}
render(
code: MagicString,
options: RenderOptions,
{ renderedSurroundingElement }: NodeRenderOptions = BLANK
): void {
this.left.render(code, options, { renderedSurroundingElement });
this.right.render(code, options);
}
}