/
binding.ts
111 lines (95 loc) 路 2.39 KB
/
binding.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
import type NodePath from "../path";
import type * as t from "@babel/types";
import type Scope from "./index";
type BindingKind =
| "var" /* var declarator */
| "let" /* let declarator, class declaration id, catch clause parameters */
| "const" /* const declarator */
| "module" /* import specifiers */
| "hoisted" /* function declaration id */
| "param" /* function declaration parameters */
| "local" /* function expression id, class expression id */
| "unknown"; /* export specifiers */
/**
* This class is responsible for a binding inside of a scope.
*
* It tracks the following:
*
* * Node path.
* * Amount of times referenced by other nodes.
* * Paths to nodes that reassign or modify this binding.
* * The kind of binding. (Is it a parameter, declaration etc)
*/
export default class Binding {
identifier: t.Identifier;
scope: Scope;
path: NodePath;
kind: BindingKind;
constructor({
identifier,
scope,
path,
kind,
}: {
identifier: t.Identifier;
scope: Scope;
path: NodePath;
kind: BindingKind;
}) {
this.identifier = identifier;
this.scope = scope;
this.path = path;
this.kind = kind;
this.clearValue();
}
constantViolations: Array<NodePath> = [];
constant: boolean = true;
referencePaths: Array<NodePath> = [];
referenced: boolean = false;
references: number = 0;
declare hasDeoptedValue: boolean;
declare hasValue: boolean;
declare value: any;
deoptValue() {
this.clearValue();
this.hasDeoptedValue = true;
}
setValue(value: any) {
if (this.hasDeoptedValue) return;
this.hasValue = true;
this.value = value;
}
clearValue() {
this.hasDeoptedValue = false;
this.hasValue = false;
this.value = null;
}
/**
* Register a constant violation with the provided `path`.
*/
reassign(path: any) {
this.constant = false;
if (this.constantViolations.indexOf(path) !== -1) {
return;
}
this.constantViolations.push(path);
}
/**
* Increment the amount of references to this binding.
*/
reference(path: NodePath) {
if (this.referencePaths.indexOf(path) !== -1) {
return;
}
this.referenced = true;
this.references++;
this.referencePaths.push(path);
}
/**
* Decrement the amount of references to this binding.
*/
dereference() {
this.references--;
this.referenced = !!this.references;
}
}