@opencode/codemode 0.0.0-dev-19437 → 0.0.0-dev-19438
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/interpreter/runtime.js +83 -11
- package/package.json +1 -1
|
@@ -107,6 +107,53 @@ const collectPatternNames = (pattern, out = []) => {
|
|
|
107
107
|
}
|
|
108
108
|
return out;
|
|
109
109
|
};
|
|
110
|
+
// `var` names declared anywhere in a function body except inside nested functions, which own theirs.
|
|
111
|
+
const collectVarNames = (node, out = []) => {
|
|
112
|
+
if (!node)
|
|
113
|
+
return out;
|
|
114
|
+
switch (node.type) {
|
|
115
|
+
case "VariableDeclaration":
|
|
116
|
+
if (node.kind === "var")
|
|
117
|
+
for (const declaration of node.declarations)
|
|
118
|
+
collectPatternNames(declaration.id, out);
|
|
119
|
+
break;
|
|
120
|
+
case "BlockStatement":
|
|
121
|
+
for (const statement of node.body)
|
|
122
|
+
collectVarNames(statement, out);
|
|
123
|
+
break;
|
|
124
|
+
case "IfStatement":
|
|
125
|
+
collectVarNames(node.consequent, out);
|
|
126
|
+
collectVarNames(node.alternate, out);
|
|
127
|
+
break;
|
|
128
|
+
case "ForStatement":
|
|
129
|
+
if (node.init?.type === "VariableDeclaration")
|
|
130
|
+
collectVarNames(node.init, out);
|
|
131
|
+
collectVarNames(node.body, out);
|
|
132
|
+
break;
|
|
133
|
+
case "ForInStatement":
|
|
134
|
+
case "ForOfStatement":
|
|
135
|
+
if (node.left.type === "VariableDeclaration")
|
|
136
|
+
collectVarNames(node.left, out);
|
|
137
|
+
collectVarNames(node.body, out);
|
|
138
|
+
break;
|
|
139
|
+
case "WhileStatement":
|
|
140
|
+
case "DoWhileStatement":
|
|
141
|
+
case "LabeledStatement":
|
|
142
|
+
collectVarNames(node.body, out);
|
|
143
|
+
break;
|
|
144
|
+
case "SwitchStatement":
|
|
145
|
+
for (const item of node.cases)
|
|
146
|
+
for (const statement of item.consequent)
|
|
147
|
+
collectVarNames(statement, out);
|
|
148
|
+
break;
|
|
149
|
+
case "TryStatement":
|
|
150
|
+
collectVarNames(node.block, out);
|
|
151
|
+
collectVarNames(node.handler?.body, out);
|
|
152
|
+
collectVarNames(node.finalizer, out);
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
};
|
|
110
157
|
const loopDeclaration = (left, statement) => {
|
|
111
158
|
if (left.type !== "VariableDeclaration")
|
|
112
159
|
return undefined;
|
|
@@ -183,6 +230,7 @@ class Frame {
|
|
|
183
230
|
return Effect.gen(function* () {
|
|
184
231
|
self.predeclareLexical(program.body);
|
|
185
232
|
self.hoistFunctions(program.body);
|
|
233
|
+
self.hoistVars(program.body);
|
|
186
234
|
let value = undefined;
|
|
187
235
|
for (const [index, statement] of program.body.entries()) {
|
|
188
236
|
if (index === program.body.length - 1 && statement.type === "ExpressionStatement") {
|
|
@@ -290,6 +338,18 @@ class Frame {
|
|
|
290
338
|
this.scopes.declare(node.id.name, this.createFunction(node), true, node);
|
|
291
339
|
}
|
|
292
340
|
}
|
|
341
|
+
// Hoisted `var` bindings start undefined, or copy a same-named parameter. Function bodies hoist
|
|
342
|
+
// into their own scope above the parameters so closures in parameter defaults keep seeing outer names.
|
|
343
|
+
hoistVars(statements, parameters) {
|
|
344
|
+
const scope = this.scopes.current();
|
|
345
|
+
for (const statement of statements) {
|
|
346
|
+
for (const name of collectVarNames(statement)) {
|
|
347
|
+
if (scope.has(name))
|
|
348
|
+
continue;
|
|
349
|
+
scope.set(name, { mutable: true, value: parameters?.get(name)?.value, initialized: true });
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
293
353
|
predeclareLexical(statements) {
|
|
294
354
|
for (const statement of statements) {
|
|
295
355
|
if (statement.type !== "VariableDeclaration")
|
|
@@ -451,18 +511,20 @@ class Frame {
|
|
|
451
511
|
}
|
|
452
512
|
const assignment = left.type === "VariableDeclaration" ? undefined : left;
|
|
453
513
|
const evaluateBody = (value) => Effect.gen(function* () {
|
|
454
|
-
if (declared) {
|
|
514
|
+
if (declared?.lexical) {
|
|
455
515
|
self.scopes.push();
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
516
|
+
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
517
|
+
yield* self.declarePattern(declared.pattern, value, declared.mutable, left, true);
|
|
518
|
+
}
|
|
519
|
+
else if (declared) {
|
|
520
|
+
yield* self.assignPattern(declared.pattern, value, left);
|
|
459
521
|
}
|
|
460
522
|
else if (assignment) {
|
|
461
523
|
yield* self.assignPattern(assignment, value, left);
|
|
462
524
|
}
|
|
463
525
|
return yield* self.evaluateStatement(node.body);
|
|
464
526
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
465
|
-
if (declared)
|
|
527
|
+
if (declared?.lexical)
|
|
466
528
|
self.scopes.pop();
|
|
467
529
|
})));
|
|
468
530
|
while (true) {
|
|
@@ -662,18 +724,20 @@ class Frame {
|
|
|
662
724
|
const assignmentName = left.type === "Identifier" ? left.name : undefined;
|
|
663
725
|
for (const key of keys) {
|
|
664
726
|
const result = yield* Effect.gen(function* () {
|
|
665
|
-
if (declared) {
|
|
727
|
+
if (declared?.lexical) {
|
|
666
728
|
self.scopes.push();
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
729
|
+
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
730
|
+
yield* self.declarePattern(declared.pattern, key, declared.mutable, left, true);
|
|
731
|
+
}
|
|
732
|
+
else if (declared) {
|
|
733
|
+
yield* self.assignPattern(declared.pattern, key, left);
|
|
670
734
|
}
|
|
671
735
|
else if (assignmentName) {
|
|
672
736
|
self.scopes.set(assignmentName, key, left);
|
|
673
737
|
}
|
|
674
738
|
return yield* self.evaluateStatement(node.body);
|
|
675
739
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
676
|
-
if (declared)
|
|
740
|
+
if (declared?.lexical)
|
|
677
741
|
self.scopes.pop();
|
|
678
742
|
})));
|
|
679
743
|
const exit = loopExit(result, labels);
|
|
@@ -759,8 +823,14 @@ class Frame {
|
|
|
759
823
|
throw new InterpreterRuntimeError("Unsupported variable declaration shape.", declaration);
|
|
760
824
|
}
|
|
761
825
|
const init = declaration.init;
|
|
826
|
+
// `var x` alone is a no-op: the binding was hoisted on function entry.
|
|
827
|
+
if (kind === "var") {
|
|
828
|
+
if (init)
|
|
829
|
+
yield* self.assignPattern(declaration.id, yield* self.evaluateExpression(init), declaration);
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
762
832
|
const value = init ? yield* self.evaluateExpression(init) : undefined;
|
|
763
|
-
yield* self.declarePattern(declaration.id, value, kind !== "const", declaration,
|
|
833
|
+
yield* self.declarePattern(declaration.id, value, kind !== "const", declaration, true);
|
|
764
834
|
}
|
|
765
835
|
});
|
|
766
836
|
}
|
|
@@ -1318,6 +1388,8 @@ class Frame {
|
|
|
1318
1388
|
yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
|
|
1319
1389
|
}
|
|
1320
1390
|
if (fn.body.type === "BlockStatement") {
|
|
1391
|
+
invocation.scopes.push();
|
|
1392
|
+
invocation.hoistVars(fn.body.body, paramScope);
|
|
1321
1393
|
const result = yield* invocation.evaluateStatement(fn.body);
|
|
1322
1394
|
return result.kind === "return" ? result.value : undefined;
|
|
1323
1395
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@opencode/codemode",
|
|
4
|
-
"version": "0.0.0-dev-
|
|
4
|
+
"version": "0.0.0-dev-19438",
|
|
5
5
|
"description": "Effect-native confined code execution over schema-described tools",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|