1
import type { NodePath } from "@babel/traverse";
2
import type * as t from "@babel/types";
3
import { CompilerError } from "../CompilerError";
4
+import { Set_union } from "../Utils/utils";
5
import { GeneratedSource } from "./HIR";
6
7
type FindContextIdentifierState = {
7
- inLambda: number;
8
currentLambda: Array<
9
| NodePath<t.FunctionDeclaration>
10
| NodePath<t.FunctionExpression>
11
| NodePath<t.ArrowFunctionExpression>
12
>;
13
- contextIdentifiers: Set<t.Identifier>;
13
+ reassigned: Set<t.Identifier>;
14
+ referenced: Set<t.Identifier>;
15
};
16
17
export function findContextIdentifiers(
18
func: NodePath<t.Function>
19
): Set<t.Identifier> {
20
const state: FindContextIdentifierState = {
20
- inLambda: 0,
21
currentLambda: [],
22
- contextIdentifiers: new Set(),
22
+ reassigned: new Set(),
23
+ referenced: new Set(),
24
};
25
26
func.traverse<FindContextIdentifierState>(
71
AssignmentExpression(
72
path: NodePath<t.AssignmentExpression>,
73
state: FindContextIdentifierState
74
+ ): void {
75
+ const left = path.get("left");
76
+ handleAssignment(state.reassigned, left);
77
+ },
78
+ Identifier(
79
+ path: NodePath<t.Identifier>,
80
+ state: FindContextIdentifierState
81
): void {
82
const currentLambda = state.currentLambda.at(-1);
75
- if (currentLambda) {
76
- const left = path.get("left");
77
- handleAssignment(currentLambda, state.contextIdentifiers, left);
78
- }
83
+ if (currentLambda !== undefined)
84
+ handleIdentifier(currentLambda, state.referenced, path);
85
},
86
},
87
state
88
);
83
- return state.contextIdentifiers;
89
+ return Set_union(state.reassigned, state.referenced);
90
}
91
86
-function handleAssignment(
92
+function handleIdentifier(
93
currentLambda:
94
| NodePath<t.FunctionDeclaration>
95
| NodePath<t.FunctionExpression>
96
| NodePath<t.ArrowFunctionExpression>,
91
- contextIdentifiers: Set<t.Identifier>,
97
+ referenced: Set<t.Identifier>,
98
+ path: NodePath<t.Identifier>
99
+): void {
100
+ const name = path.node.name;
101
+ const binding = path.scope.getBinding(name);
102
+ const bindingAboveLambdaScope = currentLambda.scope.parent.getBinding(name);
103
+
104
+ if (binding != null && binding === bindingAboveLambdaScope) {
105
+ referenced.add(binding.identifier);
106
+ }
107
+}
108
+
109
+function handleAssignment(
110
+ reassigned: Set<t.Identifier>,
111
lvalPath: NodePath<t.LVal>
112
): void {
113
// Find all reassignments to identifiers declared outside of currentLambda
117
case "Identifier": {
118
const path = lvalPath as NodePath<t.Identifier>;
119
const name = path.node.name;
101
- const ownBinding = path.scope.getBinding(name);
102
- const bindingAboveLambdaScope =
103
- currentLambda.scope.parent.getBinding(name);
104
-
105
- if (ownBinding != null && ownBinding === bindingAboveLambdaScope) {
106
- contextIdentifiers.add(ownBinding.identifier);
120
+ const binding = path.scope.getBinding(name);
121
+ if (binding != null) {
122
+ reassigned.add(binding.identifier);
123
}
124
break;
125
}
127
const path = lvalPath as NodePath<t.ArrayPattern>;
128
for (const element of path.get("elements")) {
129
if (nonNull(element)) {
114
- handleAssignment(currentLambda, contextIdentifiers, element);
130
+ handleAssignment(reassigned, element);
131
}
132
}
133
break;
143
valuePath.node.loc ?? GeneratedSource
144
);
145
}
130
- handleAssignment(currentLambda, contextIdentifiers, valuePath);
146
+ handleAssignment(reassigned, valuePath);
147
} else {
148
if (!property.isRestElement()) {
149
CompilerError.invariant(
151
property.node.loc ?? GeneratedSource
152
);
153
}
138
- handleAssignment(currentLambda, contextIdentifiers, property);
154
+ handleAssignment(reassigned, property);
155
}
156
}
157
break;
159
case "AssignmentPattern": {
160
const path = lvalPath as NodePath<t.AssignmentPattern>;
161
const left = path.get("left");
146
- handleAssignment(currentLambda, contextIdentifiers, left);
162
+ handleAssignment(reassigned, left);
163
break;
164
}
165
case "RestElement": {
166
const path = lvalPath as NodePath<t.RestElement>;
151
- handleAssignment(currentLambda, contextIdentifiers, path.get("argument"));
167
+ handleAssignment(reassigned, path.get("argument"));
168
break;
169
}
170
case "MemberExpression": {