forked from rollup/rollup
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUnaryExpression.ts
74 lines (66 loc) · 2.59 KB
/
UnaryExpression.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
import type { DeoptimizableEntity } from '../DeoptimizableEntity';
import type { HasEffectsContext } from '../ExecutionContext';
import type { NodeInteraction } from '../NodeInteractions';
import { INTERACTION_ACCESSED, NODE_INTERACTION_UNKNOWN_ASSIGNMENT } from '../NodeInteractions';
import { EMPTY_PATH, type ObjectPath, type PathTracker } from '../utils/PathTracker';
import Identifier from './Identifier';
import type { LiteralValue } from './Literal';
import type * as NodeType from './NodeType';
import { Flag, isFlagSet, setFlag } from './shared/BitFlags';
import { type LiteralValueOrUnknown, UnknownValue } from './shared/Expression';
import { type ExpressionNode, NodeBase } from './shared/Node';
const unaryOperators: {
[operator: string]: (value: LiteralValue) => LiteralValueOrUnknown;
} = {
'!': value => !value,
'+': value => +(value as NonNullable<LiteralValue>),
'-': value => -(value as NonNullable<LiteralValue>),
delete: () => UnknownValue,
typeof: value => typeof value,
void: () => undefined,
'~': value => ~(value as NonNullable<LiteralValue>)
};
export default class UnaryExpression extends NodeBase {
declare argument: ExpressionNode;
declare operator: '!' | '+' | '-' | 'delete' | 'typeof' | 'void' | '~';
declare type: NodeType.tUnaryExpression;
get prefix(): boolean {
return isFlagSet(this.flags, Flag.prefix);
}
set prefix(value: boolean) {
this.flags = setFlag(this.flags, Flag.prefix, value);
}
getLiteralValueAtPath(
path: ObjectPath,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): LiteralValueOrUnknown {
if (path.length > 0) return UnknownValue;
const argumentValue = this.argument.getLiteralValueAtPath(EMPTY_PATH, recursionTracker, origin);
if (typeof argumentValue === 'symbol') return UnknownValue;
return unaryOperators[this.operator](argumentValue);
}
hasEffects(context: HasEffectsContext): boolean {
if (!this.deoptimized) this.applyDeoptimizations();
if (this.operator === 'typeof' && this.argument instanceof Identifier) return false;
return (
this.argument.hasEffects(context) ||
(this.operator === 'delete' &&
this.argument.hasEffectsOnInteractionAtPath(
EMPTY_PATH,
NODE_INTERACTION_UNKNOWN_ASSIGNMENT,
context
))
);
}
hasEffectsOnInteractionAtPath(path: ObjectPath, { type }: NodeInteraction): boolean {
return type !== INTERACTION_ACCESSED || path.length > (this.operator === 'void' ? 0 : 1);
}
protected applyDeoptimizations(): void {
this.deoptimized = true;
if (this.operator === 'delete') {
this.argument.deoptimizePath(EMPTY_PATH);
this.scope.context.requestTreeshakingPass();
}
}
}